diff -NU3 ./CHKUSER.automatic_patching ../netqmail-1.05-chkuser-2.0.9-release/CHKUSER.automatic_patching --- ./CHKUSER.automatic_patching Thu Jan 1 01:00:00 1970 +++ ../netqmail-1.05-chkuser-2.0.9-release/CHKUSER.automatic_patching Tue Mar 20 14:52:26 2007 @@ -0,0 +1,94 @@ +Chkuser 2.0.9 automatic patching + +When to use automatic patching +============================== + +The release.tar package contains some .patch files, ready for installation, +trying to semplify the most frequent situations. + +You may use one of these patches if you have these sources: + + - a clean qmail 1.03 or netqmail 1.05 + +You may also consider using one of these patches if you have additional compatible +patches installed. This means that these additional patches should not have changed +the same sources and lines which are going to be used by chkuser. + +If you have any doubt, backup your sources and try the automatic installation, +otherwise execute the manual installation (that's very easy). + +Backup +====== + +Save you qmail working sources before making any change. + +Basic installation +================== + +Download the newest release.tar package and untar it. It will create a directory +containing all release chkuser files and patches. + +Chose the most appropriate .patch file to be applied, according to your qmail +installation: .patch files names are self-describing. + +Position in the qmail/netqmail source directory: + + $ cd /usr/.../netqmail-1.05 + +Apply selected patch: + + $ patch < /path_to_chkuser_release_dir/netqmail-1.05_chkuser-2.x.x.patch + +No errors should be displayed. If you see any error, better you restore your +sources and go to manual editing. + +editing vpopmail home path + + If your production home path for vpopmail (or whatever you call him) user + is NOT /home/vpopmail, you must perform the following additional actions. + + Edit Makefile, changing the line referring to vpopmail's home path and + putting the right home path: + + VPOPMAIL_HOME=/home/vpopmail + + Edit conf-cc, changing the string referring to vpopmail's home path and + putting the right home path: + + cc -O2 -I/home/vpopmail/include + +chkuser settings +================ + +Edit chkuser_settings.h, uncommenting the options you prefer, and commenting the +ones you don't want. Default settings should cover the most of situations. + +See the related settings pages for more informations. + +Make +==== +Now, make (or gmake on *BSD) as your usual. No errors (just warnings) should +come out. If you see any error, better you restore your sources +and go to manual editing. + +Checking +======== +Select a domain, contained in your rcpthosts, for which bouncing is enabled, and run: + + $ ./qmail-smtpd + mail from + mail from + rcpt to: + rcpt to: + +You should see error and ok messages, depending on the addresses you typed. + +Install +======= +Copy the new executable in the /var/qmail/bin directory (or make install). + +Running +======= +This patched qmail-smtpd must be executed in a different way than the normal one. +See the running pages for detailed instructions. + diff -NU3 ./CHKUSER.changelog ../netqmail-1.05-chkuser-2.0.9-release/CHKUSER.changelog --- ./CHKUSER.changelog Thu Jan 1 01:00:00 1970 +++ ../netqmail-1.05-chkuser-2.0.9-release/CHKUSER.changelog Tue Mar 20 16:45:48 2007 @@ -0,0 +1,183 @@ + +CHKUSER 2.0 change log + +2.0.9 - 21 march 2007 + New features + - New variable for accepting only authorized senders: + #define CHKUSER_EXTRA_MUSTAUTH_VARIABLE "CHKUSER_MUSTAUTH" + if the variable exists, then messages are accepted only if RELAYCLIENT is set + If defined, it works always despite CHKUSER being ON/OFF + This feature can be used for a "submission port" (see RFC 2476) + - Improved checking of MySQL server availability (if MySQL is used as vpopmail user's DB) + - Introduction of a new variable for disabling chkuser on the fly: CHKUSER_DISABLE_VARIABLE + (can be used for single IP or defined as "RELAYCLIENT" for all authorized e-mail clients) + - Improved starting variables checking sequence + CHKUSER_ALWAYS_ON and CHKUSER_STARTING_VARIABLE cannot be defined together + and in such a case a fatal error is displayed; (in previous versions + CHKUSER_ALWAYS_ON would automatically disable CHKUSER_STARTING_VARIABLE definition). + CHKUSER_DISABLE_VARIABLE is always evaluated after CHKUSER_ALWAYS_ON is set or + CHKUSER_STARTING_VARIABLE is evaluated, so CHKUSER_ALWAYS_ON or + CHKUSER_STARTING_VARIABLE can set the general behaviour, while + CHKUSER_DISABLE_VARIABLE should be invoked to handle exceptions. + - New variable for accepting qmail doublebounces: CHKUSER_ENABLE_DOUBLEBOUNCE_VARIABLE + Sender "#@[]" will be accepted. It is used by qmail for doublebounces, and should be enabled for + selected IP senders. + - define CHKUSER_ENABLE_VAUTH_OPEN has been substituted by CHKUSER_VAUTH_OPEN_CALL: this new + define must contain the name of the call used to open the auth DB + + Updated features + - checking for ezmlm mailing list is now done looking for file "editor" + within mailing-list directory + - defines for allowed character within sender and rcpt addresses increased + up to CHKUSER_ALLOW_SENDER_CHAR_10 and CHKUSER_ALLOW_RCPT_CHAR_10 + - updated SMTP error strings; more exact and detailed error codes + (thanks to Olivier Dony and Dane Thorsen) + - logging of valid rcpt. If CHKUSER_LOG_VALID_RCPT is defined then all valid + recipients are logged, even if domain does not want bouncing or chkuser + is disabled + + Bugs corrected + - negative checking of backend DB connection did not report + DB unavailability in some situations + (thanks to Matt Brookings of Inter7) + - in check_rcpt_address_format format checking was done using defines + reserved for senders + +V 2.0.8 - 7 december 2004 + Features + Freeze of new features of 2.0.7, except null senders behaviour. + CHKUSER_ENABLE_NULL_SENDER_WITH_TCPREMOTEHOST is no more available + CHKUSER_ENABLE_NULL_SENDER is no more available + NULL SENDERS are now always accepted. No option is available to disable + this behaviour. Previous chkuser versions broke RFC compatibility on + null senders, and complicated real life e-mailing. + Logging of null senders <> is now available. + + Bugs corrected + Sender controls were not executed if CHKUSER_STARTING_VARIABLE was defined + (thanks to Charles Sprickman) + Domains not in control/virtualdomains are now explicitely excluded from + following cascade checks; in previous versions following cascade + checks were done using fake domains paths. + vget_assign is now handled correctly (a domain in rcpthosts but not + in virtualdomains could have an incorrect path in previous versions + (this bug is also in all chkusr versions) + + Defaults changed + CHKUSER_RCPT_FORMAT is now undefined as default + CHKUSER_RCPT_MX is now undefined as default. + CHKUSER_SENDER_FORMAT is now undefined as default + CHKUSER_SENDER_MX is now undefined as default. + CHKUSER_ERROR_DELAY_INCREASE new default is 300 milliseconds + +V 2.0.7 - 25 october 2004 + Features + added vclose() of DB auth connection, overriding + qmail-smtpd _exit call + improved MX checking; now SOFT failure is handled as + temporary error. + added #define CHKUSER_RCPTMX_TMP_STRING + added #define CHKUSER_SENDERMX_TMP_STRING + added handling of mailman mailing lists + (and related #define CHKUSER_ENABLE_MAILMAN_LISTS) + changed order of checking for recipients: + 1 - valias + 2 - alias + 3 - alias extensions + 4 - users + 5 - users extensions + 6 - lists + added #define CHKUSER_ACCEPT_NULL_SENDER (default defined) + added #define CHKUSER_ENABLE_ALIAS_DEFAULT (default not defined) + enables checking of .qmail-alias-default + added #define CHKUSER_IDENTIFY_REMOTE_VARIABLE "CHKUSER_IDENTIFY" + in order to allow a easy identification of remote IP + (substitutes RELAYCLIENT in chkuser logging) + added #define CHKUSER_ALLOW_RCPT_SRS + enable usage of "#" and "+" characters within rcpt address + added #define CHKUSER_ALLOW_RCPT_CHAR_1 '$' + added #define CHKUSER_ALLOW_RCPT_CHAR_2 '%' + added #define CHKUSER_ALLOW_RCPT_CHAR_3 '£' + added #define CHKUSER_ALLOW_RCPT_CHAR_4 '?' + added #define CHKUSER_ALLOW_RCPT_CHAR_5 '*' + #define CHKUSER_ENABLE_USERS_EXTENSIONS + substitutes #define CHKUSER_ENABLE_EXTENSIONS + #define CHKUSER_ENABLE_EZMLM_LISTS + substitutes #define CHKUSER_ENABLE_LISTS + #define CHKUSER_USERS_DASH + substitutes #define CHKUSER_EXTENSION_DASH + + Bugs corrected + sender address "name@" could cause a crash. Corrected + (Thanks to Dmitry Petukhov) + Corrected Makefile: now qmail-smtpd.c recompiles if chkuser.h + changes + Corrected a bug in #endif sequence related to + #define CHKUSER_RCPT_FORMAT (thanks to Alex Plainer) + Corrected a bug in chkuser_sender; now is not executed when + chkuser is disabled + Corrected check of format for domains: + "xn--" admitted as leading string + Deleted correction over usage of RELAYCLIENT variable + Previous correction could affect a special + feature of RELAYCLIENT (thanks to Alex Pleiner) + + Defaults changed + #define CHKUSER_ENABLE_NULL_SENDER_WITH_TCPREMOTEHOST (default undefined) + + +V 2.0.6 - 25 september 2004 + No bugs, just doc updates and an empty patch file corrected + + #define CHKUSER_ENABLE_VGET_REAL_DOMAIN was existing and working in code, + but not reported both in docs and inside chkuser_settings.h + (default is commented, but this #define is important) + patch for toaster-0.6-1 was empty. Now the correct one is provided + +V 2.0.5 - 23 september 2004 + This is the first public release. + + added #define CHKUSER_ALLOW_SENDER_CHAR_1 (default not defined) + added #define CHKUSER_ALLOW_SENDER_CHAR_2 (default not defined) + added #define CHKUSER_ALLOW_SENDER_CHAR_3 (default not defined) + added #define CHKUSER_ALLOW_SENDER_CHAR_4 (default not defined) + added #define CHKUSER_ALLOW_SENDER_CHAR_5 (default not defined) + added #define CHKUSER_MIN_DOMAIN_LEN (default defined 4) - + Previously it was hard coded as 5. Juergen Kendzorra + showed me some existing names long only 4 chars. + added #define CHKUSER_LOG_VALID_SENDER (default defined) + +V 2.0.4 - 15 september 2004 + + added #define CHKUSER_SENDER_NOCHECK_VARIABLE (default not defined) + added #define CHKUSER_DEBUG_STDERR (default not defined) + added #define CHKUSER_ALLOW_SENDER_SRS (default not defined) + cleaned some typos in code and documentation (thanks to Juergen + Kendzorra - http://www.kendzorra.de) + + +V 2.0.3 - 8 september 2004 + This is the first version released outside, for wider testing. + + Tested Makefile for netqmail 1.05 + Added Makefiles for applying over other patches + +V 2.0.0 - july 2004 + chkuser 2.0.0 starts here, and is a private internal release. + Version 2.0 is much more modular than previous one (named chkusr), + and has been designed with the goal of enabling more features and + semplifying installations and upgrades of the patch himself. + + chkusr changes his name, to reflect a deep change of the patch. + + Chkusr 1.0 received a lot of feedbacks and suggestions. + The most of these suggestions are now inside version 2.0. + + - Marcelo Coelho (marcelo at tpn.com.br), segnaled me some + unseen minor bugs of chkusr 1.0 (minor but very annoying to + my pride) and suggested some very interesting features + (some of them are now in chkuser 2.0). + - Iulian Margarintescu (http:://www.erata.net) suggested a + workable way of introducing quota check on recipients + (now in chkuser 2.0). + diff -NU3 ./CHKUSER.copyright ../netqmail-1.05-chkuser-2.0.9-release/CHKUSER.copyright --- ./CHKUSER.copyright Thu Jan 1 01:00:00 1970 +++ ../netqmail-1.05-chkuser-2.0.9-release/CHKUSER.copyright Tue Mar 20 14:50:44 2007 @@ -0,0 +1,15 @@ + +chkuser for qmail/netqmail > 1.0.3 and vpopmail > 5.3.x + +Author: Antonio Nati tonix@interazioni.it + +All rights on this software and +the identifying words chkusr and chkuser kept by the author + +This software may be freely used, modified and distributed, +but this lines must be kept in every original or derived version. + +Original author "Antonio Nati" and the web URL +"http://www.interazioni.it/opensource" +must be indicated in every related work or web page + diff -NU3 ./CHKUSER.log_format ../netqmail-1.05-chkuser-2.0.9-release/CHKUSER.log_format --- ./CHKUSER.log_format Thu Jan 1 01:00:00 1970 +++ ../netqmail-1.05-chkuser-2.0.9-release/CHKUSER.log_format Tue Mar 20 17:25:57 2007 @@ -0,0 +1,69 @@ + +chkuser 2.0.9 logging format + +When #defines for logging are enabled, chkuser patch emits log informations +on the same qmail-smtpd log destination + +This is the log format: + + CHKUSER "brief message": \ + from \ + remote \ + rcpt : "extended message" + +where + brief message + * accepted rcpt + * relaying rcpt + * rejected relaying + * rejected rcpt + * no auth resource + * mbx overquota + * rejected intrusion + * intrusion threshold + * accepted sender + * rejected sender + * must auth + + sender sender declared within "mail from" + + remoteinfo the value of "TCPREMOTEINFO" or the autenticated user + + relayclient the value of CHKUSER_IDENTIFY env variable (this name + is defined by #define CHKUSER_IDENTIFY_REMOTE_VARIABLE) + + helo helo declared from remote system + + hostname the value of "TCPREMOTEHOST" + + remotehostip the value of "TCPREMOTEIP" + + recipient recipient address + + extended message this field has more wide description for + some generic "brief message": + accepted rcpt found existing recipient + accepted rcpt accepted any recipient for any rcpt doman (from 2.0.9) + accepted rcpt accepted any recipient for this domain (from 2.0.9) + relaying rcpt client allowed to relay + rejected relaying client not allowed to relay + rejected rcpt not existing recipient + rejected rcpt max number of recipients + rejected rcpt max number of invalid recipients + rejected rcpt invalid rcpt address format + rejected rcpt invalid rcpt MX domain + rejected rcpt temporary DNS problem (from 2.0.9) + intrusion threshold max number of allowed rcpt + intrusion threshold max number of allowed invalid rcpt + rejected intrusion rcpt ignored, session over intrusion threshold + no auth resource no auth resource available + must auth sender not authenticated/authorized (from 2.0.9) + mbx overquota rcpt mailbox is overquota + accepted sender sender accepted (from 2.0.9) + accepted sender accepted any sender always (from 2.0.9) + accepted sender accepted null sender always (from 2.0.9) + accepted doublebounce accepted qmail doublebounce #@[] (from 2.0.9) + rejected sender invalid sender address format + rejected sender invalid sender MX domain + rejected sender temporary DNS problem (from 2.0.9) + diff -NU3 ./CHKUSER.manual_patching ../netqmail-1.05-chkuser-2.0.9-release/CHKUSER.manual_patching --- ./CHKUSER.manual_patching Thu Jan 1 01:00:00 1970 +++ ../netqmail-1.05-chkuser-2.0.9-release/CHKUSER.manual_patching Tue Mar 20 15:22:30 2007 @@ -0,0 +1,182 @@ +Chkuser 2.0 manual editing + +Manual editing is a very simple operation. + +Watching the patch design, shown in the patch design page, you may see that +only some simple changes must be done to qmail-smtpd.c and Makefile. + +Backup +====== + +Save you qmail working sources before making any change. + +Basic installation +================== + +Download the newest release.tar package and untar it. It will create a directory +containing all chkuser files and patches. + +Position in the qmail/netqmail source directory: + + $ cd /usr/.../netqmail-1.05 + +Copy all the chkuser sources: + + $ cp /path_to_release_tar/chkuser* . + +edit qmail-smtpd.c + within qmail-smtpd.c, change the following lines: + + At the end of initial #include declarations, add the following (+) lines: + + #include "timeoutwrite.h" + #include "commands.h" + ++ /* start chkuser code */ ++ #include "chkuser.h" ++ /* end chkuser code */ + + #define MAXHOPS 100 + +Within smtp_mail routine, add the following (+) lines + + void smtp_mail(arg) char *arg; + { + if (!addrparse(arg)) { err_syntax(); return; } ++ /* start chkuser code */ ++ if (chkuser_sender (&addr) != CHKUSER_OK) { return; } ++ /* end chkuser code */ + flagbarf = bmfcheck(); + + Within smtp_rcpt routine, delete the following (-) lines and substitute + them with the (+) ones: + +- if (relayclient) { +- --addr.len; +- if (!stralloc_cats(&addr,relayclient)) die_nomem(); +- } +- else +- if (!addrallowed()) { err_nogateway(); return; } + ++ /* start chkuser code */ ++ switch (chkuser_realrcpt (&mailfrom, &addr)) { ++ case CHKUSER_KO: ++ return; ++ break; ++ case CHKUSER_RELAYING: ++ --addr.len; ++ if (!stralloc_cats(&addr,relayclient)) die_nomem(); ++ if (!stralloc_0(&addr)) die_nomem(); ++ break; ++ } ++ /* end chkuser code */ + + if (!stralloc_cats(&rcptto,"T")) die_nomem(); + if (!stralloc_cats(&rcptto,addr.s)) die_nomem(); + if (!stralloc_0(&rcptto)) die_nomem(); + +edit Makefile + Within Makefile, change or add the following lines. + + At the begininng of the file: + + # Don't edit Makefile! Use conf-* for configuration. + ++ VPOPMAIL_HOME=/home/vpopmail ++ SMTPD_CHKUSER_OBJ=chkuser.o dns.o ++ VPOPMAIL_LIBS=`head -1 $(VPOPMAIL_HOME)/etc/lib_deps` `cat dns.lib` + + SHELL=/bin/sh + + Be carefule to use the right path, if your vpopmail production home + path is NOT "/home/vpopmail". + + dns.lib is added to qmail-smtpd building instructions, so, if you + have previously patched qmail-smtpd in order to include dns.lib, take + care to delete the duplication from the previous lines. + + Before "clean:" insert the chkuser.o definition: + + exit.h auto_spawn.h + ./compile chkspawn.c ++ chkuser.o: \ ++ compile chkuser.c chkuser.h chkuser_settings.h ++ ./compile chkuser.c + + clean: \ + + Beware: the "./compile chkuser.c" line has an heading TAB. + + Change the qmail-smtpd compiling and linking instructions, + deleting the (-) lines and adding the (+) ones. + + + 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 socket.lib ++ fs.a auto_qmail.o socket.lib $(SMTPD_CHKUSER_OBJ) +- ./load qmail-smtpd rcpthosts.o commands.o timeoutread.o \ ++ ./load qmail-smtpd $(SMTPD_CHKUSER_OBJ) 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 str.a fs.a auto_qmail.o \ ++ $(VPOPMAIL_LIBS) \ ++ `cat socket.lib` + + Beware: all the lines starting from and following "./load" have an heading TAB. + +edit TARGETS + Append the following blue line at the end of TARGETS file: + + man + setup + check ++ chkuser.o + +edit conf-cc + Edit conf-cc, adding the include path of production vpopmail: + + cc -O2 -I/home/vpopmail/include + + Be carefule to use the right path, if your vpopmail production home path + is NOT "/home/vpopmail". + +chkuser settings +================ +Edit chkuser_settings.h, uncommenting the options you prefer, and commenting the +ones you don't want. Default settings should cover the most of situations. + +See the related settings pages for more informations. + +Make +==== +Now, make (or gmake on *BSD) as your usual. No errors (just warnings) +should come out. If you see any error, check carefully edited lines. + +Checking +======== +Select a domain, contained in your rcpthosts, for which bouncing is enabled, and run: + + $ ./qmail-smtpd + mail from + mail from + rcpt to: + rcpt to: + +You should see error and ok messages, depending on the addresses you typed. + +Install +======= +Copy the new executable in the /var/qmail/bin directory (or make install). + +Running +======= +This patched qmail-smtpd must be executed in a different way than the normal one. +See the running pages for detailed instructions. + diff -NU3 ./CHKUSER.readme ../netqmail-1.05-chkuser-2.0.9-release/CHKUSER.readme --- ./CHKUSER.readme Thu Jan 1 01:00:00 1970 +++ ../netqmail-1.05-chkuser-2.0.9-release/CHKUSER.readme Tue Mar 20 15:56:50 2007 @@ -0,0 +1,54 @@ +chkuser 2.0 - README + +Description +=========== +The original qmail-smtpd accepts by default all messages, checking later for +the existence of the recipient. So, if the message is delivered to not existing +recipients a lot of additional system work and network traffic are generated, +with multiple expensive bouncing if the sender is a fake one. + +chkuser has been developed with the goal to improve the acceptance SMTP phase +of qmail-smtpd. qmail-smtpd patched with chkuser may check the existance of +e-mail recipients immediately in the SMTP acceptance phase of a message and +rejects istantly all messages not directed to existing users, avoiding +additional traffic, work and messages bounced more times. + +These goals are achieved enquirying the existing vpopmail archives (each +format is supported: cdb, MySQL, LDAP, etc.) by using standard vpopmail calls, +or using customized chkuser routines. + +Version 2.0 - From chkusr to chkuser +==================================== +Version 2.0 is a lot different from previous versions, so it deserves a more +evident change in the name. + +Version 2.0 has been designed with the goal to be modular, and to make more easy +both adding new features to chkuser code and semplifing code update. + +Patching over original qmail files is done over a few points, while the most of +chkuser code remains ouside, in dedicated chkuser's files. + +Same for settings, that are inside a dedicated chkuser_settings.h file. + +The intention is to semplify upgrading: for future chkuser releases, upgrading +will require only to update chkuser specific files, leaving all the rest +untouched, and changing chkuser_settings.h only if new features must be enabled. + +Logging and SPAM +================ +chkuser 2.0 has detailed logging of accepted and refused recipients and senders, +allowing a deep analysis of "who's sending to who". This can lead to more +sophisticated future enhancements of anti-SPAM features. + +Intrusion rejection +=================== +chkuser 2.0 can be tuned to reject sessions exceeding some recipients limits +(limits can be set for max recipients and max not existing recipients). + +URL Location +============ +For any new release, support, FAQ, mailing lists, or other information, see: + + http://www.interazioni.it/opensource + + diff -NU3 ./CHKUSER.running ../netqmail-1.05-chkuser-2.0.9-release/CHKUSER.running --- ./CHKUSER.running Thu Jan 1 01:00:00 1970 +++ ../netqmail-1.05-chkuser-2.0.9-release/CHKUSER.running Tue Mar 20 15:21:05 2007 @@ -0,0 +1,103 @@ + +CHKUSER 2.0.9 - Running instructions + +Chkuser may run using the most of security, following very strictly the sacurity +model used By Dan Berstein. To achieve this goal, chkuser may switch between +differents UID/GID, for differente purposes. + +However this is incompatible with TLS patches (like toaster-0.6-1), as these patches +want to run under a unique UID/GID. Luckily, qmail is enought robust to let us +run this way. + +To achieve both these goals, chkuser uses a #define (CHKUSER_ENABLE_UIDGID) +that indicates if UID/GID switching is wanted, and running instructions must +adapt to this way. + +Instead, when this define is not used, another way of running must be used. +(Just for precision, even if the CHKUSER_ENABLE_UIDGID define is used, chkuser +may be run without switching UID/GID). + +Running with UID/GID switch +=========================== + +If you want the most security when using chkuser, and you have enabled +CHKUSER_ENABLE_UIDGID within chkuser_settings.h (it's enabled by default), use +these instructions. + +Description. + qmail-smtpd-chkusr must be installed (by default in /var/qmail/bin) with + setuid (user qmaild) and setgid (group qnofiles), and executed by tcpserver + with -u vpopmail-user and -g vchkpw-group parameters. + + qmail-smtpd-chkusr starts running with the original qmail-smtpd uid and gid, + switching to needed uid and gid only for vpopmail checks on user existance, + turning back to the starting uid and gid. + +Instructions. + You have to set SUID (set-user-ID-on-execution) and SGID + (set-group-ID-on-execution) bits on qmail-smtpd-chkusr: + chown qmaild qmail-smtpd + chgrp nofiles qmail-smtpd + chmod 6555 qmail-smtpd + + and the result you see should be like (different size and date, of course): + -r-sr-sr-x 1 qmaild nofiles 57056 Feb 14 18:18 qmail-smtpd-chkusr + + Integrate qmail-smtpd in your start files: + + As example, a real start command for qmail-smtpd-chkusr may be + + #!/bin/sh -e + # + # Using splogger to send the log through syslog. + + exec env - PATH="/var/qmail/bin:/usr/local/bin" \ + tcpserver -t 5 -v -p -x \ + -u -g -l 0 smtp \ + qmail-smtpd-chkusr splogger smtpd & + + where + = vpopmail uid + = vchkpw gid + = your host.domain (!) + = your tcp.permission.to.relay cdb + + NOTE: if you are using more system users for your domains, the execution + uid (which I indicated as vpopmail) should be set to root. + + +Running with fixed UID/GID +========================== +You may use these instructions if you've not defined CHKUSER_ENABLE_UIDGID, or if +you want to run qmail-smtpd as unique user, despite of CHKUSER_ENABLE_UIDGID define. +qmail-smtpd is well safe and robust, and there is no risk running it directly as +vpopmail user, unless you use untrusted software layered down. + +Description. + qmail-smtpd must be installed normally (-r-xr-xr-x) and executed by tcpserver + with -u vpopmail-user and -g vchkpw-group parameters. + +Instructions. + Integrate qmail-smtpd-chkusr in your start files: + + As example, a real start command for qmail-smtpd-chkusr may be + + #!/bin/sh -e + # + # Using splogger to send the log through syslog. + + exec env - PATH="/var/qmail/bin:/usr/local/bin" \ + tcpserver -t 5 -v -p -x \ + -u -g -l 0 smtp \ + qmail-smtpd-chkusr splogger smtpd & + + where + = vpopmail uid + = vchkpw gid + = your host.domain (!) + = your tcp.permission.to.relay cdb + + NOTE: if you are using more system users for your domains, the execution user + (which I indicated as vpopmail) should be set to root. + + diff -NU3 ./Makefile ../netqmail-1.05-chkuser-2.0.9-release/Makefile --- ./Makefile Sun May 14 17:02:02 2006 +++ ../netqmail-1.05-chkuser-2.0.9-release/Makefile Tue Mar 20 14:49:55 2007 @@ -1,5 +1,9 @@ # Don't edit Makefile! Use conf-* for configuration. +VPOPMAIL_HOME=/home/vpopmail +SMTPD_CHKUSER_OBJ=chkuser.o dns.o +VPOPMAIL_LIBS=`head -1 $(VPOPMAIL_HOME)/etc/lib_deps` `cat dns.lib` + SHELL=/bin/sh default: it @@ -300,6 +304,10 @@ exit.h auto_spawn.h ./compile chkspawn.c +chkuser.o: \ +compile chkuser.c chkuser.h chkuser_settings.h + ./compile chkuser.c + clean: \ TARGETS rm -f `cat TARGETS` @@ -1536,20 +1544,21 @@ 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 - ./load qmail-smtpd rcpthosts.o commands.o timeoutread.o \ +fs.a auto_qmail.o socket.lib $(SMTPD_CHKUSER_OBJ) + ./load qmail-smtpd $(SMTPD_CHKUSER_OBJ) 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 str.a fs.a auto_qmail.o \ + $(VPOPMAIL_LIBS) \ + `cat socket.lib` 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 \ +compile qmail-smtpd.c chkuser.h 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 \ diff -NU3 ./TARGETS ../netqmail-1.05-chkuser-2.0.9-release/TARGETS --- ./TARGETS Mon Jun 15 12:53:16 1998 +++ ../netqmail-1.05-chkuser-2.0.9-release/TARGETS Tue Mar 20 14:49:55 2007 @@ -385,3 +385,4 @@ man setup check +chkuser.o diff -NU3 ./chkuser.c ../netqmail-1.05-chkuser-2.0.9-release/chkuser.c --- ./chkuser.c Thu Jan 1 01:00:00 1970 +++ ../netqmail-1.05-chkuser-2.0.9-release/chkuser.c Tue Mar 20 17:00:55 2007 @@ -0,0 +1,1258 @@ + +/* + * + * 'chkuser.c' v.2.0.9 + * for qmail/netqmail > 1.0.3 and vpopmail > 5.3.x + * + * Author: Antonio Nati tonix@interazioni.it + * All rights on this software and + * the identifying words chkusr and chkuser reserved by the author + * + * This software may be freely used, modified and distributed, + * but this lines must be kept in every original or derived version. + * Original author "Antonio Nati" and the web URL + * "http://www.interazioni.it/opensource" + * must be indicated in every related work or web page + * + */ + +#include + +/* required by vpopmail */ +#include + +#include +#include +#include + +#include "dns.h" +#include "env.h" +#include "ipme.h" +#include "now.h" +#include "str.h" +#include "open.h" +#include "subfd.h" +#include "substdio.h" +#include "stralloc.h" + +#include "vpopmail.h" +#include "vauth.h" +#include "vpopmail_config.h" + +#include "chkuser.h" +#include "chkuser_settings.h" + +#if defined _exit +#undef _exit +#endif + +extern void flush(); +extern void out (char *s); + +extern char *remotehost; +extern char *remoteip; +extern char *remoteinfo; +extern char *relayclient; +extern char *fakehelo; + +extern void die_nomem(); + +#define DIE_NOMEM() die_nomem() + +#if defined CHKUSER_DEBUG + +#if defined CHKUSER_DEBUG_STDERR + +#define CHKUSER_DBG(a) write (STDERR_FILENO, a, strlen (a)) +#define CHKUSER_DBG_INT(a) { int x; char str[30]; sprintf (str, "%d", a); write (STDERR_FILENO, str, strlen (str));} + +#else + +#define CHKUSER_DBG(a) write (STDOUT_FILENO, a, strlen (a)) +#define CHKUSER_DBG_INT(a) { int x; char str[30]; sprintf (str, "%d", a); write (STDOUT_FILENO, str, strlen (str));} + +#endif +#else + +#define CHKUSER_DBG(a) /* DBG dummy */ +#define CHKUSER_DBG_INT(a) /* DBG dummy */ + +#endif + +static int intrusion_threshold_reached = 0; +static int first_time_init_flag = 1; + +static int recipients = 0; +static int wrong_recipients = 0; + +static stralloc user = {0}; +static stralloc domain = {0}; +static stralloc domain_path = {0}; +static stralloc tmp_path = {0}; +static stralloc alias_path = {0}; + +#if defined CHKUSER_IDENTIFY_REMOTE_VARIABLE + static char *identify_remote; +#endif + +#if defined CHKUSER_ENABLE_EXTENSIONS +#define CHKUSER_ENABLE_USERS_EXTENSIONS +#endif + +#if defined CHKUSER_ENABLE_LISTS +#define CHKUSER_ENABLE_EZMLM_LISTS +#endif + +#if defined CHKUSER_EXTENSION_DASH +#define CHKUSER_USERS_DASH CHKUSER_EXTENSION_DASH +#endif + + +#if defined CHKUSER_ENABLE_VALIAS +#error "chkuser setting error: CHKUSER_ENABLE_VALIAS has been substituted by VALIAS (within vpopmail includes); you don't need anymore this define" +#endif + +#if defined CHKUSER_ENABLE_VAUTH_OPEN +#error "chkuser setting error: CHKUSER_ENABLE_VAUTH_OPEN has been substituted by CHKUSER_ENABLE_VAUTH_OPEN_CALL; edit chkuser_settings.h and change your settings" +#endif + +#if defined CHKUSER_ENABLE_VAUTH_OPEN_CALL + static int db_already_open = 0; +#endif + +#if defined CHKUSER_ALWAYS_ON && defined CHKUSER_STARTING_VARIABLE +#error "chkuser setting error: CHKUSER_ALWAYS_ON and CHKUSER_STARTING_VARIABLE are mutually esclusive. Edit your chkuser_settings.h and disable one of them" +#endif + + static int starting_value = 0; + +#if defined CHKUSER_STARTING_VARIABLE + static char *starting_string = 0; +#endif + +#if defined CHKUSER_EXTRA_MUSTAUTH_VARIABLE + static int mustauth_value = 0; +#endif + + +#if defined CHKUSER_RCPT_LIMIT_VARIABLE + static char *maxrcpt_string = 0; + static int maxrcpt_limit = 0; + static int maxrcpt_limit_reached = 0; +#endif + +#if defined CHKUSER_WRONGRCPT_LIMIT_VARIABLE + static char *maxwrongrcpt_string = 0; + static int maxwrongrcpt_limit = 0; + static int maxwrongrcpt_limit_reached = 0; +#endif + +#if defined CHKUSER_MBXQUOTA_VARIABLE + static char *maxmbxquota_string = 0; + static int maxmbxquota_limit = 0; +#endif + + static unsigned int sender_nocheck = 0; + +#if defined CHKUSER_SENDER_FORMAT || defined CHKUSER_SENDER_MX +static stralloc sender_user = {0}; +static stralloc sender_domain = {0}; +#endif + +#if defined CHKUSER_ENABLE_DOUBLEBOUNCE_VARIABLE +static unsigned int enable_doublebounce = 0; +#endif + +#if defined CHKUSER_ERROR_DELAY + + static int chkuser_delay_interval = CHKUSER_ERROR_DELAY * 1000; + +#define CHKUSER_DELAY() chkuser_delay() + +void chkuser_delay (void) { + + usleep (chkuser_delay_interval); + +#if defined CHKUSER_ERROR_DELAY_INCREASE + chkuser_delay_interval += CHKUSER_ERROR_DELAY_INCREASE * 1000; +#endif +} + +#if defined CHKUSER_RCPT_DELAY_ANYERROR +#define CHKUSER_RCPT_DELAY_ANY() chkuser_delay() +#else +#define CHKUSER_RCPT_DELAY_ANY() /* no delay for any error */ +#endif + +#if defined CHKUSER_SENDER_DELAY_ANYERROR +#define CHKUSER_SENDER_DELAY_ANY() chkuser_delay() +#else +#define CHKUSER_SENDER_DELAY_ANY() /* no delay for any error */ +#endif + + +#else +#define CHKUSER_DELAY() /* no delay */ +#define CHKUSER_RCPT_DELAY_ANY() /* no delay */ +#define CHKUSER_SENDER_DELAY_ANY() /* no delay */ +#endif + +#if defined CHKUSER_ENABLE_LOGGING + +static stralloc logstr = { 0 }; + +static void chkuser_commonlog (char *sender, char *rcpt, char *title, char *description) { + + substdio_puts (subfderr, "CHKUSER "); + substdio_puts (subfderr, title); + substdio_puts (subfderr, ": from <"); + substdio_puts (subfderr, sender); + substdio_puts (subfderr, ":" ); + if (remoteinfo) { + substdio_puts (subfderr, remoteinfo); + } + substdio_puts (subfderr, ":" ); +#if defined CHKUSER_IDENTIFY_REMOTE_VARIABLE + if (identify_remote) substdio_puts (subfderr, identify_remote); +#endif + substdio_puts (subfderr, "> remote <"); + if (fakehelo) substdio_puts (subfderr, fakehelo); + substdio_puts (subfderr, ":" ); + if (remotehost) substdio_puts (subfderr, remotehost); + substdio_puts (subfderr, ":" ); + if (remoteip) substdio_puts (subfderr, remoteip); + substdio_puts (subfderr, "> rcpt <"); + substdio_puts (subfderr, rcpt); + substdio_puts (subfderr, "> : "); + substdio_puts (subfderr, description); + substdio_puts (subfderr, "\n"); + substdio_flush (subfderr); +} + +#else +#define chkuser_commonlog(a,b,c,d) /* no log */ +#endif + +#if defined CHKUSER_SENDER_FORMAT + +static int check_sender_address_format (stralloc *user, stralloc *domain) { + + int x; + + for (x = 0; x < (user->len -1); ++x) { + if ((!isalnum (user->s[x])) + +#if defined CHKUSER_ALLOW_SENDER_SRS + && (user->s[x] != '#') + && (user->s[x] != '+') +#endif +#if defined CHKUSER_ALLOW_SENDER_CHAR_1 + && (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_1) +#endif +#if defined CHKUSER_ALLOW_SENDER_CHAR_2 + && (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_2) +#endif +#if defined CHKUSER_ALLOW_SENDER_CHAR_3 + && (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_3) +#endif +#if defined CHKUSER_ALLOW_SENDER_CHAR_4 + && (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_4) +#endif +#if defined CHKUSER_ALLOW_SENDER_CHAR_5 + && (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_5) +#endif +#if defined CHKUSER_ALLOW_SENDER_CHAR_6 + && (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_6) +#endif +#if defined CHKUSER_ALLOW_SENDER_CHAR_7 + && (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_7) +#endif +#if defined CHKUSER_ALLOW_SENDER_CHAR_8 + && (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_8) +#endif +#if defined CHKUSER_ALLOW_SENDER_CHAR_9 + && (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_9) +#endif +#if defined CHKUSER_ALLOW_SENDER_CHAR_10 + && (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_10) +#endif + && (user->s[x] != '_') && (user->s[x] != '-') && (user->s[x] != '.') && (user->s[x] != '=')) { + return 0; + } + } + +/* + * Be careful, this is a base check + * Minimum is x.xx + ending \0 + * Minimum characters needed are 5 + */ +#if defined CHKUSER_MIN_DOMAIN_LEN + if (domain->len < (CHKUSER_MIN_DOMAIN_LEN +1)) { + return 0; + } +#endif + +/* + * This is a safety check + */ +#if defined CHKUSER_MIN_DOMAIN_LEN + if (domain->len < 2) { + return 0; + } +#endif + + for (x = 0; x < (domain->len -1); ++x) { + if ((!isalnum (domain->s[x])) && (domain->s[x] != '-') && (domain->s[x] != '.')) { + return 0; + } + } + + if ((domain->s[0] == '-') || (domain->s[domain->len -2] == '-') || (domain->s[0] == '.') || (domain->s[domain->len -2] == '.')) { + return 0; + } + if (strstr (domain->s, "..") != NULL) { + return 0; + } + if (strncmp (domain->s, "xn--", 4) == 0) { + if (strstr (&domain->s[4], "--") != NULL) + return 0; + } else { + if (strstr (domain->s, "--") != NULL) + return 0; + } + if (strstr (domain->s, ".-") != NULL) { + return 0; + } + if (strstr (domain->s, "-.") != NULL) { + return 0; + } + if (strchr (domain->s, '.') == NULL) { + return 0; + } + + return 1; +} + +#endif + +#if defined CHKUSER_RCPT_FORMAT + +static int check_rcpt_address_format (stralloc *user, stralloc *domain) { + + int x; + + for (x = 0; x < (user->len -1); ++x) { + if ((!isalnum (user->s[x])) +#if defined CHKUSER_ALLOW_RCPT_SRS + && (user->s[x] != '#') + && (user->s[x] != '+') +#endif +#if defined CHKUSER_ALLOW_RCPT_CHAR_1 + && (user->s[x] != CHKUSER_ALLOW_RCPT_CHAR_1) +#endif +#if defined CHKUSER_ALLOW_RCPT_CHAR_2 + && (user->s[x] != CHKUSER_ALLOW_RCPT_CHAR_2) +#endif +#if defined CHKUSER_ALLOW_RCPT_CHAR_3 + && (user->s[x] != CHKUSER_ALLOW_RCPT_CHAR_3) +#endif +#if defined CHKUSER_ALLOW_RCPT_CHAR_4 + && (user->s[x] != CHKUSER_ALLOW_RCPT_CHAR_4) +#endif +#if defined CHKUSER_ALLOW_RCPT_CHAR_5 + && (user->s[x] != CHKUSER_ALLOW_RCPT_CHAR_5) +#endif +#if defined CHKUSER_ALLOW_RCPT_CHAR_6 + && (user->s[x] != CHKUSER_ALLOW_RCPT_CHAR_6) +#endif +#if defined CHKUSER_ALLOW_RCPT_CHAR_7 + && (user->s[x] != CHKUSER_ALLOW_RCPT_CHAR_7) +#endif +#if defined CHKUSER_ALLOW_RCPT_CHAR_8 + && (user->s[x] != CHKUSER_ALLOW_RCPT_CHAR_8) +#endif +#if defined CHKUSER_ALLOW_RCPT_CHAR_9 + && (user->s[x] != CHKUSER_ALLOW_RCPT_CHAR_9) +#endif +#if defined CHKUSER_ALLOW_RCPT_CHAR_10 + && (user->s[x] != CHKUSER_ALLOW_RCPT_CHAR_10) +#endif + && (user->s[x] != '_') && (user->s[x] != '-') && (user->s[x] != '.') && (user->s[x] != '=')) { + return 0; + } + } + +/* + * Be careful, this is a base check + * Minimum is x.xx + ending \0 + * Minimum characters needed are 5 + */ +#if defined CHKUSER_MIN_DOMAIN_LEN + if (domain->len < (CHKUSER_MIN_DOMAIN_LEN +1)) { + return 0; + } +#endif + +/* + * This is a safety check + */ +#if defined CHKUSER_MIN_DOMAIN_LEN + if (domain->len < 2) { + return 0; + } +#endif + for (x = 0; x < (domain->len -1); ++x) { + if ((!isalnum (domain->s[x])) && (domain->s[x] != '-') && (domain->s[x] != '.')) { + return 0; + } + } + + if ((domain->s[0] == '-') || (domain->s[domain->len -2] == '-') || (domain->s[0] == '.') || (domain->s[domain->len -2] == '.')) { + return 0; + } + if (strstr (domain->s, "..") != NULL) { + return 0; + } + if (strncmp (domain->s, "xn--", 4) == 0) { + if (strstr (&domain->s[4], "--") != NULL) + return 0; + } else { + if (strstr (domain->s, "--") != NULL) + return 0; + } + if (strstr (domain->s, ".-") != NULL) { + return 0; + } + if (strstr (domain->s, "-.") != NULL) { + return 0; + } + if (strchr (domain->s, '.') == NULL) { + return 0; + } + + return 1; +} + +#endif + +#if defined CHKUSER_SENDER_MX || defined CHKUSER_RCPT_MX + +static unsigned long mx_random; +static ipalloc mx_ip = {0}; + +static int chkuser_mx_lookup (stralloc *domain) { + + int status; + + mx_random = now() + getpid(); + dns_init(0); + status = dns_mxip (&mx_ip, domain, mx_random); + + if (status == DNS_MEM) DIE_NOMEM(); + + return status; +} + +#endif + + +void chkuser_cleanup (int exit_value) { + +#if defined CHKUSER_DB_CLEANUP + vclose (); +#endif + _exit (exit_value); +} + +static void first_time_init (void) { + + starting_value = 0; + +#if defined CHKUSER_ALWAYS_ON + starting_value = 1; +#endif + +#if defined CHKUSER_STARTING_VARIABLE + starting_string = env_get (CHKUSER_STARTING_VARIABLE); + if (starting_string) { + if (strcasecmp(starting_string, "ALWAYS") == 0) { + starting_value = 1; + } else if (strcasecmp(starting_string, "DOMAIN") == 0) { + starting_value = 0; + } + } else { + starting_string = ""; + starting_value = -1; + } +#endif + +#if defined CHKUSER_DISABLE_VARIABLE + if (env_get (CHKUSER_DISABLE_VARIABLE)) { + starting_value = -1; + } +#endif + +#if defined CHKUSER_EXTRA_MUSTAUTH_VARIABLE + if (env_get (CHKUSER_EXTRA_MUSTAUTH_VARIABLE)) { + if (relayclient) { + mustauth_value = 0; + } else { + mustauth_value = 1; + } + } +#endif + + +#if defined CHKUSER_RCPT_LIMIT_VARIABLE + maxrcpt_string = env_get (CHKUSER_RCPT_LIMIT_VARIABLE); + if (maxrcpt_string) { + maxrcpt_limit = atoi (maxrcpt_string); + if (maxrcpt_limit < 1) { + maxrcpt_limit = 0; + } + } else { + maxrcpt_string = "";; + } +#endif + +#if defined CHKUSER_WRONGRCPT_LIMIT_VARIABLE + maxwrongrcpt_string = env_get (CHKUSER_WRONGRCPT_LIMIT_VARIABLE); + if (maxwrongrcpt_string) { + maxwrongrcpt_limit = atoi (maxwrongrcpt_string); + if (maxwrongrcpt_limit < 1) { + maxwrongrcpt_limit = 0; + } + } else { + maxwrongrcpt_string = ""; + } +#endif + +#if defined CHKUSER_MBXQUOTA_VARIABLE + maxmbxquota_string = env_get (CHKUSER_MBXQUOTA_VARIABLE); + if (maxmbxquota_string) { + maxmbxquota_limit = atoi (maxmbxquota_string); + if (maxmbxquota_limit < 1) { + maxmbxquota_limit = 0; + } + } else { + maxmbxquota_string = ""; + } +#endif + +#if defined CHKUSER_SENDER_NOCHECK_VARIABLE + + if (env_get (CHKUSER_SENDER_NOCHECK_VARIABLE)) { + sender_nocheck = 1; + } else { + sender_nocheck = 0; + } +#endif + +#if defined CHKUSER_IDENTIFY_REMOTE_VARIABLE + + identify_remote = env_get (CHKUSER_IDENTIFY_REMOTE_VARIABLE); +#endif + + +#if defined CHKUSER_ENABLE_DOUBLEBOUNCE_VARIABLE + + if (env_get (CHKUSER_ENABLE_DOUBLEBOUNCE_VARIABLE)) { + enable_doublebounce = 1; + } else { + enable_doublebounce = 0; + } +#endif + + if (!stralloc_ready (&user, 300)) DIE_NOMEM(); + if (!stralloc_ready (&domain, 500)) DIE_NOMEM(); + if (!stralloc_ready (&domain_path, 1000)) DIE_NOMEM(); + if (!stralloc_ready (&tmp_path, 1000)) DIE_NOMEM(); + if (!stralloc_ready (&alias_path, 1000)) DIE_NOMEM(); + + first_time_init_flag = 0; + +} + +/* + * realrcpt () + * + * Returns: + * + * CHKUSER_OK = 1 = Ok, recipients does exists + * + * 0 = Not in rcpthosts + * + * < 0 various errors + * + * + * Parameters: + * stralloc *sender = sender address + * stralloc *rcpt = rcpt address to check + * + * +*/ + +static int realrcpt (stralloc *sender, stralloc *rcpt) +{ + int count; + int retstat = CHKUSER_KO; + struct vqpasswd *user_passwd = NULL; + int fd_file = -1; + int read_char; + int offset; + char read_buf[1024]; + +#if defined CHKUSER_ENABLE_UIDGID + uid_t eff_uid; + gid_t eff_gid; +#endif + +#if defined CHKUSER_EXTRA_MUSTAUTH_VARIABLE + if (mustauth_value == 1) { + return CHKUSER_ERR_MUSTAUTH; + } +#endif + + + if (starting_value == -1) { + if (addrallowed()) { + return CHKUSER_OK_NOCHECKALL; + } else { + if (relayclient) { + return CHKUSER_RELAYING; + } + return CHKUSER_NORCPTHOSTS; + } + } + + if (intrusion_threshold_reached == 1) { + return CHKUSER_ERR_INTRUSION_THRESHOLD; + } + +#if defined CHKUSER_RCPT_LIMIT_VARIABLE + + ++recipients; + if ((maxrcpt_limit > 0) && (recipients >= maxrcpt_limit)) { + chkuser_commonlog (sender->s, rcpt->s, "intrusion threshold", "max number of allowed rcpt"); + intrusion_threshold_reached = 1; + return CHKUSER_ERR_MAXRCPT; + } +#endif + +/* Search the '@' character */ + count = byte_rchr(rcpt->s,rcpt->len,'@'); + + if (count < rcpt->len) { + if (!stralloc_copyb (&user, rcpt->s, count)) DIE_NOMEM(); + if (!stralloc_copys (&domain, rcpt->s + count + 1)) DIE_NOMEM(); + } + else { + if (!stralloc_copys (&user, rcpt->s)) DIE_NOMEM(); + domain.len = 0; + } + if (!stralloc_0 (&user)) DIE_NOMEM(); + if (!stralloc_0 (&domain)) DIE_NOMEM(); + +#if defined CHKUSER_ENABLE_UIDGID + +/* qmail-smtpd is running now as (effective) qmaild:nofiles */ +/* Save the effective UID & GID (qmaild:nofiles) */ + eff_uid = geteuid (); + eff_gid = getegid (); + +/* Now set new effective UID & GID, getting it from real UID & GID (vpopmail:vchkpw) */ + setegid (getgid()); + seteuid (getuid()); + +/* qmail-smtpd is running now as effective vpopmail:vchkpw */ +#endif + + +/* + * + * Now let's start the test/setting suite + * + **/ + + switch (0) { + + case 0: +/* These are some preliminary settings */ + case_lowers (user.s); + case_lowers (domain.s); + + case 1: + + if (domain.len == 1) { +#if defined CHKUSER_DOMAIN_WANTED + retstat = CHKUSER_ERR_DOMAIN_MISSING; + break; +#else + if (!stralloc_copys (&domain, DEFAULT_DOMAIN)) DIE_NOMEM(); + if (!stralloc_0 (&domain)) DIE_NOMEM(); +#endif + } + + case 2: + +#if defined CHKUSER_RCPT_FORMAT + if (check_rcpt_address_format (&user, &domain) == 0) { + retstat = CHKUSER_ERR_RCPT_FORMAT; + break; + } +#endif + + case 3: + + if (!addrallowed()) { + +#if defined CHKUSER_RCPT_MX + switch (chkuser_mx_lookup(&domain)) { + + case DNS_HARD: + retstat = CHKUSER_ERR_RCPT_MX; + break; + + case DNS_SOFT: + retstat = CHKUSER_ERR_RCPT_MX_TMP; + break; + } + + if (retstat != CHKUSER_KO) { + break; + } +#endif + if (relayclient) { + retstat = CHKUSER_RELAYING; + break; + } + + retstat = CHKUSER_NORCPTHOSTS; + break; + } + + case 4: + +#if defined CHKUSER_ENABLE_VGET_REAL_DOMAIN +/* Check if domain is a real domain */ + + vget_real_domain(domain.s, domain.a); + + domain.len = strlen (domain.s) +1; + if (domain.len > (domain.a - 1)) DIE_NOMEM(); +#endif + +/* Let's get domain's real path */ + if (vget_assign(domain.s, domain_path.s, domain_path.a -1, NULL, NULL) == NULL) { + retstat = CHKUSER_OK; + break; + } + + domain_path.len = strlen (domain_path.s); + + case 5: + +/* Check if domain has bouncing enabled */ + + if (starting_value == 0) { + + if (!stralloc_copy (&tmp_path, &domain_path)) DIE_NOMEM(); + +#if defined CHKUSER_SPECIFIC_BOUNCING + if (!stralloc_cats (&tmp_path, "/")) DIE_NOMEM(); + if (!stralloc_cats (&tmp_path, CHKUSER_SPECIFIC_BOUNCING)) DIE_NOMEM(); + if (!stralloc_0 (&tmp_path)) DIE_NOMEM(); + fd_file = open_read (tmp_path.s); + if (fd_file != -1) { + close (fd_file); + } else { + retstat = CHKUSER_OK_NOCHECKDOMAIN; + break; + } +#else + if (!stralloc_cats (&tmp_path, "/.qmail-default")) DIE_NOMEM(); + if (!stralloc_0 (&tmp_path)) DIE_NOMEM(); + + read_char = 0; + fd_file = open_read (tmp_path.s); + if (fd_file != -1) { + read_char = read (fd_file, read_buf, sizeof(read_buf) - 1); + close (fd_file); + if (read_char < 0) read_char = 0; + } + read_buf[read_char] = 0; + + if ( strstr(read_buf, CHKUSER_BOUNCE_STRING) == NULL ) { + retstat = CHKUSER_OK_NOCHECKDOMAIN; + break; + } +#endif + } + + + case 6: + +#if defined CHKUSER_ENABLE_VAUTH_OPEN_CALL + if (db_already_open != 1) { + if (CHKUSER_VAUTH_OPEN_CALL () == 0) { + db_already_open == 1; + } else { + retstat = CHKUSER_ERR_AUTH_RESOURCE; + break; + } + } +#endif + + + case 7: +#if defined VALIAS +/* Check for aliases/forwards - valias*/ + + if (valias_select (user.s, domain.s) != NULL) { + retstat = CHKUSER_OK; + break; + } +#endif + + case 8: +#if defined CHKUSER_ENABLE_ALIAS +/* Check for aliases/forwards - .qmail.x files */ + + if (!stralloc_copy (&tmp_path, &user)) DIE_NOMEM(); + /* Change all '.' in ':' before continuing on aliases */ + for (count = 0; count < tmp_path.len; ++count) + if (*(tmp_path.s + count) == '.') *(tmp_path.s + count) = ':'; + + if (!stralloc_copy (&alias_path, &domain_path)) DIE_NOMEM(); + if (!stralloc_cats (&alias_path, "/.qmail-")) DIE_NOMEM(); + if (!stralloc_cats (&alias_path, tmp_path.s)) DIE_NOMEM(); + if (!stralloc_0 (&alias_path)) DIE_NOMEM(); + + fd_file = open_read (alias_path.s); + if (fd_file != -1) { + close (fd_file); + retstat = CHKUSER_OK; + break; + } +#endif + + case 9: + +#if defined CHKUSER_ENABLE_ALIAS_DEFAULT + + if (!stralloc_copy (&tmp_path, &user)) DIE_NOMEM(); + /* Change all '.' in ':' before continuing on aliases */ + for (count = 0; count < tmp_path.len; ++count) + if (*(tmp_path.s + count) == '.') *(tmp_path.s + count) = ':'; + + /* Search for the outer '-' character */ + for (offset = user.len - 1; offset > 0; --offset) { + if (*(user.s + offset) == CHKUSER_USERS_DASH) { + if (!stralloc_copy (&alias_path, &domain_path)) die_nomem(); + if (!stralloc_cats (&alias_path, "/.qmail-")) die_nomem(); + if (!stralloc_catb (&alias_path, user.s, offset)) die_nomem(); + if (!stralloc_cats (&alias_path, "-default")) die_nomem(); + if (!stralloc_0 (&alias_path)) die_nomem(); + + fd_file = open_read (alias_path.s); + if (fd_file != -1) { + close (fd_file); + retstat = CHKUSER_OK; + break; + } + } + } + if (retstat != CHKUSER_KO) { + break; + } + +#endif + + case 10: +#if defined CHKUSER_ENABLE_USERS +/* User control: check the existance of a real user */ + + user_passwd = vauth_getpw (user.s, domain.s); + +#if defined CHKUSER_ENABLE_USERS_EXTENSIONS + if (user_passwd == NULL) { + count = 0; + while ((count < (user.len -1)) && (user_passwd == NULL)) { + count += byte_chr(&user.s[count], user.len - count, CHKUSER_USERS_DASH); + if (count < user.len) { + if (!stralloc_copyb (&tmp_path, user.s, count)) DIE_NOMEM(); + if (!stralloc_0 (&tmp_path)) DIE_NOMEM(); + user_passwd = vauth_getpw (tmp_path.s, domain.s); + ++count; + } + } + } + +#endif + if (user_passwd != NULL) { + + /* If user exists check if he has BOUNCE_MAIL flag set */ + + if (user_passwd->pw_gid & BOUNCE_MAIL) + retstat = CHKUSER_KO; + else { + retstat = CHKUSER_OK; +#if defined CHKUSER_MBXQUOTA_VARIABLE + if ((maxmbxquota_limit > 0) && (strcasecmp(user_passwd->pw_shell, "NOQUOTA") != 0)) { + if (!stralloc_copys (&tmp_path, user_passwd->pw_dir)) DIE_NOMEM(); + if (!stralloc_cats (&tmp_path, "/Maildir")) DIE_NOMEM(); + if (!stralloc_0 (&tmp_path)) DIE_NOMEM(); + + if (vmaildir_readquota(tmp_path.s,format_maildirquota(user_passwd->pw_shell)) + >= maxmbxquota_limit) { + retstat = CHKUSER_ERR_MBXFULL; + } + } +#endif + } + break; + } +#endif + + case 11: +#if defined CHKUSER_ENABLE_EZMLM_LISTS +/* Let's check for mailing lists */ + + /* Search for the outer CHKUSER_EZMLM_DASH character */ + for (offset = user.len - 2; offset > 0; --offset) { + if (*(user.s + offset) == CHKUSER_EZMLM_DASH) { + if (!stralloc_copy (&tmp_path, &domain_path)) DIE_NOMEM(); + if (!stralloc_cats (&tmp_path, "/")) DIE_NOMEM(); + if (!stralloc_catb (&tmp_path, user.s, offset)) DIE_NOMEM(); + if (!stralloc_cats (&tmp_path, "/editor")) DIE_NOMEM(); + if (!stralloc_0 (&tmp_path)) DIE_NOMEM(); + fd_file = open_read (tmp_path.s); + if (fd_file != -1) { + close (fd_file); + retstat = CHKUSER_OK; + break; + } + } + } + if (retstat != CHKUSER_KO) { + break; + } +#endif + + case 12: +#if defined CHKUSER_ENABLE_MAILMAN_LISTS +/* Let's check for mailing lists */ + + /* Search for the outer CHKUSER_MAILMAN_DASH character */ + for (offset = user.len - 2; offset > 0; --offset) { + if (*(user.s + offset) == CHKUSER_MAILMAN_DASH) { + if (!stralloc_copy (&tmp_path, &domain_path)) DIE_NOMEM(); + if (!stralloc_cats (&tmp_path, "/")) DIE_NOMEM(); + if (!stralloc_cats (&alias_path, "/.qmail-")) DIE_NOMEM(); + if (!stralloc_catb (&tmp_path, user.s, offset)) DIE_NOMEM(); + if (!stralloc_0 (&tmp_path)) DIE_NOMEM(); + fd_file = open_read (tmp_path.s); + read_char = 0; + if (fd_file != -1) { + read_char = read (fd_file, read_buf, sizeof(read_buf) - 1); + close (fd_file); + if (read_char < 0) read_char = 0; + } + read_buf[read_char] = 0; + + if ( strstr(read_buf, CHKUSER_MAILMAN_STRING) == NULL ) { + retstat = CHKUSER_OK; + break; + } + + } + } + if (retstat != CHKUSER_KO) { + break; + } +#endif + +/* + * Add this code if another case is following + case xx: + code .... + code .... + code .... + code .... + + if (xxxxxxxx) { + retstat != CHKUSER_KO) + break; + } +*/ + + default: + retstat = CHKUSER_KO; + + } /* end switch */ + +#if defined CHKUSER_ENABLE_UIDGID +/* Now switch back effective to saved UID & GID (qmaild:nofiles) */ + + setegid (eff_gid); + seteuid (eff_uid); + +/* qmail-smtpd is running again as (effective) qmaild:nofiles */ +#endif + + return retstat; + +} + + + +/* + * chkuser_realrcpt () + * + * Returns a simple status: + * + * CHKUSER_OK = 1 = Ok, recipients does exists + * + * CHKUSER_NORCPTHOSTS = Not in rcpthosts + * + * CHKUSER_KO = ERROR + * + * + * Parameters: + * stralloc *sender = sender address + * stralloc *rcpt = rcpt address to check + * + * +*/ + +int chkuser_realrcpt (stralloc *sender, stralloc *rcpt) { + +int retstat; + + if (first_time_init_flag) { + first_time_init (); + } + + + retstat = realrcpt (sender, rcpt); + + switch (retstat) { + + case CHKUSER_OK: +#if defined CHKUSER_LOG_VALID_RCPT + chkuser_commonlog (sender->s, rcpt->s, "accepted rcpt", "found existing recipient"); +#endif + return CHKUSER_OK; + break; + + case CHKUSER_OK_NOCHECKALL: +#if defined CHKUSER_LOG_VALID_RCPT + chkuser_commonlog (sender->s, rcpt->s, "accepted any rcpt", "accepted any recipient for any rcpt domain"); +#endif + return CHKUSER_OK; + break; + + case CHKUSER_OK_NOCHECKDOMAIN: +#if defined CHKUSER_LOG_VALID_RCPT + chkuser_commonlog (sender->s, rcpt->s, "accepted any rcpt", "accepted any recipient for this domain"); +#endif + return CHKUSER_OK; + break; + + case CHKUSER_RELAYING: +#if defined CHKUSER_LOG_VALID_RCPT + chkuser_commonlog (sender->s, rcpt->s, "relaying rcpt", "client allowed to relay"); +#endif + return CHKUSER_RELAYING; + break; + + case CHKUSER_NORCPTHOSTS: + chkuser_commonlog (sender->s, rcpt->s, "rejected relaying", "client not allowed to relay"); + CHKUSER_RCPT_DELAY_ANY(); + out(CHKUSER_NORELAY_STRING); + break; + + case CHKUSER_KO: + chkuser_commonlog (sender->s, rcpt->s, "rejected rcpt", "not existing recipient"); + CHKUSER_DELAY(); + out(CHKUSER_NORCPT_STRING); + break; + + case CHKUSER_ERR_AUTH_RESOURCE: + chkuser_commonlog (sender->s, rcpt->s, "no auth resource", "no auth resource available"); + CHKUSER_RCPT_DELAY_ANY(); + out(CHKUSER_RESOURCE_STRING); + break; + + case CHKUSER_ERR_MUSTAUTH: + chkuser_commonlog (sender->s, rcpt->s, "must auth", "sender not authenticated/authorized"); + CHKUSER_RCPT_DELAY_ANY(); + out(CHKUSER_MUSTAUTH_STRING); + break; + + case CHKUSER_ERR_MBXFULL: + chkuser_commonlog (sender->s, rcpt->s, "mbx overquota", "rcpt mailbox is overquota"); + CHKUSER_RCPT_DELAY_ANY(); + out(CHKUSER_MBXFULL_STRING); + break; + + case CHKUSER_ERR_MAXRCPT: + chkuser_commonlog (sender->s, rcpt->s, "rejected rcpt", "max number of recipients"); + CHKUSER_DELAY (); + out(CHKUSER_MAXRCPT_STRING); + break; + + case CHKUSER_ERR_MAXWRONGRCPT: + chkuser_commonlog (sender->s, rcpt->s, "rejected rcpt", "max number of invalid recipients"); + CHKUSER_DELAY (); + out(CHKUSER_MAXWRONGRCPT_STRING); + break; + + case CHKUSER_ERR_INTRUSION_THRESHOLD: + chkuser_commonlog (sender->s, rcpt->s, "rejected intrusion", "rcpt ignored, session over intrusion threshold"); + CHKUSER_DELAY (); + out(CHKUSER_INTRUSIONTHRESHOLD_STRING); + break; + + case CHKUSER_ERR_DOMAIN_MISSING: + CHKUSER_DELAY (); + out(CHKUSER_DOMAINMISSING_STRING); + break; + + case CHKUSER_ERR_RCPT_FORMAT: + chkuser_commonlog (sender->s, rcpt->s, "rejected rcpt", "invalid rcpt address format"); + CHKUSER_RCPT_DELAY_ANY(); + out(CHKUSER_RCPTFORMAT_STRING); + break; + + case CHKUSER_ERR_RCPT_MX: + chkuser_commonlog (sender->s, rcpt->s, "rejected rcpt", "invalid rcpt MX domain"); + CHKUSER_RCPT_DELAY_ANY(); + out(CHKUSER_RCPTMX_STRING); + break; + + case CHKUSER_ERR_RCPT_MX_TMP: + chkuser_commonlog (sender->s, rcpt->s, "rejected rcpt", "temporary DNS problem"); + CHKUSER_RCPT_DELAY_ANY(); + out(CHKUSER_RCPTMX_TMP_STRING); + break; + } + + + +#if defined CHKUSER_WRONGRCPT_LIMIT_VARIABLE + if ((retstat == CHKUSER_KO) || (retstat == CHKUSER_ERR_DOMAIN_MISSING)) { + ++wrong_recipients; + if ((intrusion_threshold_reached == 0) && (maxwrongrcpt_limit > 0) && (wrong_recipients >= maxwrongrcpt_limit)) { + chkuser_commonlog (sender->s, rcpt->s, "intrusion threshold", "max number of allowed invalid rcpt"); + intrusion_threshold_reached = 1; + } + } +#endif + + return CHKUSER_KO; +} + + +/* + * + * This routine checks for sender format and MX + * + */ + + +int chkuser_sender (stralloc *sender) { + +int count; + + if (first_time_init_flag) { + first_time_init (); + } + +#if defined CHKUSER_EXTRA_MUSTAUTH_VARIABLE + if (mustauth_value == 1) { + out(CHKUSER_MUSTAUTH_STRING); +#if defined CHKUSER_LOG_VALID_SENDER + chkuser_commonlog (sender->s, "", "must auth", "sender not authenticated/authorized"); + CHKUSER_SENDER_DELAY_ANY(); +#endif + return CHKUSER_ERR_MUSTAUTH; + } +#endif + + if (sender->len <= 1) { +#if defined CHKUSER_LOG_VALID_SENDER + chkuser_commonlog (sender->s, "", "accepted sender", "accepted null sender always"); +#endif + return CHKUSER_OK; + } + + if ((starting_value == -1) || (sender_nocheck == 1)) { +#if defined CHKUSER_LOG_VALID_SENDER + chkuser_commonlog (sender->s, "", "accepted sender", "accepted any sender always"); +#endif + return CHKUSER_OK; + } + +#if defined CHKUSER_ENABLE_DOUBLEBOUNCE_VARIABLE + if ((enable_doublebounce) && str_equal(sender->s,"#@[]")) { +#if defined CHKUSER_LOG_VALID_SENDER + chkuser_commonlog (sender->s, "", "accepted doublebounce", "accepted qmail doublebounce #@[]"); +#endif + return CHKUSER_OK; + } +#endif + +#if defined CHKUSER_SENDER_FORMAT || defined CHKUSER_SENDER_MX + count = byte_rchr(sender->s,sender->len,'@'); + if (count < sender->len) { + if (!stralloc_copyb (&sender_user, sender->s, count)) DIE_NOMEM(); + if (!stralloc_copys (&sender_domain, sender->s + count + 1)) DIE_NOMEM(); + } else { + if (!stralloc_copys (&sender_user, sender->s)) DIE_NOMEM(); + sender_domain.len = 0; + } + if (!stralloc_0 (&sender_user)) DIE_NOMEM(); + if (!stralloc_0 (&sender_domain)) DIE_NOMEM(); + +#if defined CHKUSER_SENDER_FORMAT + if (check_sender_address_format (&sender_user, &sender_domain) == 0) { + chkuser_commonlog (sender->s, "", "rejected sender", "invalid sender address format"); + CHKUSER_SENDER_DELAY_ANY(); + out(CHKUSER_SENDERFORMAT_STRING); + return CHKUSER_ERR_SENDER_FORMAT; + } + +#endif + +#if defined CHKUSER_SENDER_MX + + switch (chkuser_mx_lookup(&sender_domain)) { + + case DNS_HARD: + CHKUSER_SENDER_DELAY_ANY(); + out(CHKUSER_SENDERMX_STRING); + chkuser_commonlog (sender->s, "", "rejected sender", "invalid sender MX domain"); + return CHKUSER_ERR_SENDER_MX; + break; + + case DNS_SOFT: + CHKUSER_SENDER_DELAY_ANY(); + out(CHKUSER_SENDERMX_TMP_STRING); + chkuser_commonlog (sender->s, "", "rejected sender", "temporary DNS problem"); + return CHKUSER_ERR_SENDER_MX_TMP; + break; + } + +#endif +#endif + +#if defined CHKUSER_LOG_VALID_SENDER + chkuser_commonlog (sender->s, "", "accepted sender", "sender accepted"); +#endif + + return CHKUSER_OK; + +} + + diff -NU3 ./chkuser.h ../netqmail-1.05-chkuser-2.0.9-release/chkuser.h --- ./chkuser.h Thu Jan 1 01:00:00 1970 +++ ../netqmail-1.05-chkuser-2.0.9-release/chkuser.h Tue Mar 20 16:02:15 2007 @@ -0,0 +1,55 @@ + +/* + * + * 'chkuser.h' v.2.0.9 + * for qmail/netqmail > 1.0.3 and vpopmail > 5.3.x + * + * Author: Antonio Nati tonix@interazioni.it + * All rights on this software and + * the identifying words chkusr and chkuser reserved by the author + * + * This software may be freely used, modified and distributed, + * but this lines must be kept in every original or derived version. + * Original author "Antonio Nati" and the web URL + * "http://www.interazioni.it/opensource" + * must be indicated in every related work or web page + * + */ + +#define CHKUSER +#define CHKUSER_VERSION "2.0.9" +#define CHKUSER_VERSION_RL 2 +#define CHKUSER_VERSION_MJ 0 +#define CHKUSER_VERSION_MN 9 + +#define CHKUSER_OK_NOCHECKALL 11 +#define CHKUSER_OK_NOCHECKDOMAIN 10 +#define CHKUSER_OK 1 +#define CHKUSER_RELAYING 0 +#define CHKUSER_KO -1 +#define CHKUSER_NORCPTHOSTS -10 +#define CHKUSER_ERR_MUSTAUTH -15 +#define CHKUSER_ERR_AUTH_RESOURCE -20 +#define CHKUSER_ERR_MBXFULL -30 +#define CHKUSER_ERR_MAXRCPT -40 +#define CHKUSER_ERR_MAXWRONGRCPT -50 +#define CHKUSER_ERR_DOMAIN_MISSING -60 +#define CHKUSER_ERR_RCPT_FORMAT -70 +#define CHKUSER_ERR_RCPT_MX -75 +#define CHKUSER_ERR_RCPT_MX_TMP -76 +#define CHKUSER_ERR_SENDER_FORMAT -80 +#define CHKUSER_ERR_SENDER_MX -85 +#define CHKUSER_ERR_SENDER_MX_TMP -86 +#define CHKUSER_ERR_INTRUSION_THRESHOLD -90 + + +void chkuser_cleanup (int exit_value); +int chkuser_realrcpt (stralloc *sender, stralloc *rcpt); +int chkuser_sender (stralloc *sender); + +#ifdef TLS_H +#undef _exit +#define _exit(value) { if (ssl) ssl_free(ssl); chkuser_cleanup(value); } +#else +#define _exit(value) chkuser_cleanup(value); +#endif diff -NU3 ./chkuser_settings.h ../netqmail-1.05-chkuser-2.0.9-release/chkuser_settings.h --- ./chkuser_settings.h Thu Jan 1 01:00:00 1970 +++ ../netqmail-1.05-chkuser-2.0.9-release/chkuser_settings.h Tue Mar 20 16:39:30 2007 @@ -0,0 +1,467 @@ +/* + * + * 'chkuser_settings.h' v.2.0.9 + * for qmail/netqmail > 1.0.3 and vpopmail > 5.3.x + * + * Author: Antonio Nati tonix@interazioni.it + * All rights on this software and + * the identifying words chkusr and chkuser reserved by the author + * + * This software may be freely used, modified and distributed, + * but this lines must be kept in every original or derived version. + * Original author "Antonio Nati" and the web URL + * "http://www.interazioni.it/opensource" + * must be indicated in every related work or web page + * + */ + +/* + * the following line enables debugging of chkuser + */ +/* #define CHKUSER_DEBUG */ + +/* + * The following line moves DEBUG output from STDOUT (default) to STDERR + * Example of usage within sh: ./qmail-smtpd 2> /var/log/smtpd-debug.log + */ +/* #define CHKUSER_DEBUG_STDERR */ + +/* + * Uncomment the following define if you want chkuser ALWAYS enabled. + * If uncommented, it will check for rcpt existance despite any .qmail-default + * setting. + * So, unsomments this if you are aware that ALL rcpt in all domains will be + * ALWAYS checked. + */ +/* #define CHKUSER_ALWAYS_ON */ + +/* + * The following defines which virtual manager is used. + * Up to know, only vpopmail, but versions with pure qmail are in the mind. + */ +#define CHKUSER_VPOPMAIL + +/* + * Uncomment the following line if you want chkuser to work depending on a VARIABLE setting + * VALUE HERE DEFINED is the name of the variable + * Values admitted inside the variable: NONE | ALWAYS | DOMAIN + * NONE = chkuser will not work + * ALWAYS = chkuser will work always + * DOMAIN = chkuser will work depending by single domain settings + * CHKUSER_STARTING_VARIABLE cannot be defined together with CHKUSER_ALWAYS_ON + * if CHKUSER_STARTING_VARIABLE is defined, and no variable or no value is set, then chkuser is disabled + */ +/* #define CHKUSER_STARTING_VARIABLE "CHKUSER_START" */ + +/* + * Uncomment this to enable uid/gid changing + * (switching UID/GID is NOT compatible with TLS; you may keep this commented if you have TLS) + */ +/* #define CHKUSER_ENABLE_UIDGID */ + +/* + * Uncomment this to check if a domain is ALWAYS specified in rcpt addresses + */ +#define CHKUSER_DOMAIN_WANTED + +/* + * Uncomment this to check for vpopmail users + */ +#define CHKUSER_ENABLE_USERS + +/* + * Uncomment this to check for alias + */ +#define CHKUSER_ENABLE_ALIAS + +/* + * The following #define set the character used for lists extensions + * be careful: this is a single char '-' definition, not a "string" + */ +#define CHKUSER_EZMLM_DASH '-' + +/* + * Uncomment this to set an alternative way to check for bouncing enabling; + * with this option enabled, the file here defined + * will be searched, inside the domain dir, in order to check if bouncing is enabled + * The content of this file is not important, just it's existence is enough + */ +/* #define CHKUSER_SPECIFIC_BOUNCING ".qmailchkuser-bouncing" */ + +/* + * This is the string to look for inside .qmail-default + * Be careful, chkuser looks within the first 1023 characters of .qmail-default for + * this string (despite the line containing the string is working or commented). + */ +#define CHKUSER_BOUNCE_STRING "bounce-no-mailbox" + + +/* + * Uncomment to enable logging of rejected recipients and variuos limits reached + */ +#define CHKUSER_ENABLE_LOGGING + +/* + * Uncomment to enable logging of "good" rcpts + * valid only if CHKUSER_ENABLE_LOGGING is defined + */ +#define CHKUSER_LOG_VALID_RCPT + +/* + * Uncomment to enable usage of a variable escluding any check on the sender. + * The variable should be set in tcp.smtp for clients, with static IP, whose mailer + * is composing bad sender addresses + * Defining it as "RELAYCLIENT" will avoid sender checking for authenticated/authorized users. + * Senders will be logged anyway if CHKUSER_LOG_VALID_SENDER is defined. + */ +/* #define CHKUSER_SENDER_NOCHECK_VARIABLE "RELAYCLIENT" */ + +/* + * Uncomment to enable usage of "#" and "+" characters within sender address + * This is used by SRS (Sender Rewriting Scheme) products + */ +/* #define CHKUSER_ALLOW_SENDER_SRS */ + +/* + * The following #define sets the minimum length of a domain: + * as far as I know, "k.st" is the shortest domain, so 4 characters is the + * minimum length. + * This value is used to check formally a domain name validity. + * if CHKUSER_SENDER_FORMAT is undefined, no check on length is done. + * If you comment this define, no check on length is done. + */ +#define CHKUSER_MIN_DOMAIN_LEN 4 + +/* + * Uncomment to enable logging of "good" senders + * valid only if CHKUSER_ENABLE_LOGGING is defined + */ +#define CHKUSER_LOG_VALID_SENDER + +/* + * Uncomment to define a variable which contains the max recipients number + * this will return always error if total recipients exceed this limit. + * The first reached, between CHKUSER_RCPT_LIMIT_VARIABLE and CHKUSER_WRONGRCPT_LIMIT_VARIABLE, + * makes chkuser rejecting everything else + */ +#define CHKUSER_RCPT_LIMIT_VARIABLE "CHKUSER_RCPTLIMIT" + +/* + * Uncomment to define a variable which contains the max unknown recipients number + * this will return always error if not existing recipients exceed this limit. + * The first reached, between CHKUSER_RCPT_LIMIT_VARIABLE and CHKUSER_WRONGRCPT_LIMIT_VARIABLE, + * makes chkuser rejecting everything else + */ +#define CHKUSER_WRONGRCPT_LIMIT_VARIABLE "CHKUSER_WRONGRCPTLIMIT" + +/* + * Uncomment to define the variable containing the percent to check for. + * Remember to define externally (i.e. in tcp.smtp) the environment variable containing + * the limit percent. + * If the variable is not defined, or it is <= 0, quota checking is not performed. + */ +#define CHKUSER_MBXQUOTA_VARIABLE "CHKUSER_MBXQUOTA" + +/* + * Delay to wait for each not existing recipient + * value is expressed in milliseconds + */ +#define CHKUSER_ERROR_DELAY 1000 + +/* + * Uncomment to consider rcpt errors on address format and MX as intrusive + * + */ +#define CHKUSER_RCPT_DELAY_ANYERROR + +/* + * Uncomment to consider sender errors on address format and MX as intrusive + * + */ +#define CHKUSER_SENDER_DELAY_ANYERROR + + +/*************************************************** + * + * new/modified defines in/from 2.0.6 + * + **************************************************/ + +/* + * Before version 5.3.25, vpopmail used the function vget_real_domain() + * to get the real name of a domain (useful if rcpt domain is aliasing + * another domain). + * From version 5.3.25, this call is not available and has been + * substituted by other calls. + * + * must be enabled if vpopmail version< 5.3.5 + * must be disabled if vpopmail version => 5.3.5 * + */ +/* #define CHKUSER_ENABLE_VGET_REAL_DOMAIN */ + +/*************************************************** + * + * new/modified defines in/from 2.0.7 + * + **************************************************/ + +/* + * Uncomment next define to accept recipients for + * aliases that have a -default extension + */ +/* #define CHKUSER_ENABLE_ALIAS_DEFAULT */ + + +/* + * Uncomment to enable usage of "#" and "+" characters within rcpt address + * This is used by SRS (Sender Rewriting Scheme) products + */ +/* #define CHKUSER_ALLOW_RCPT_SRS */ + +/* + * This define has been eliminated and its usage will generate an error. + * Turning it ON or OFF has no effect, as we consider the existence + * of #define VALIAS inside ~vpopmail/include/vpopmail_config.h + */ +/* #define CHKUSER_ENABLE_VALIAS */ + +/* + * Uncomment this to enable user extension on names (i.e. TMDA) + * (for mailing lists this is done without checking this define) + * This define substitutes #define CHKUSER_ENABLE_EXTENSIONS + */ +/* #define CHKUSER_ENABLE_USERS_EXTENSIONS */ + +/* + * Enables checking for EZMLM lists + * this define substitutes #define CHKUSER_ENABLE_LISTS + * + */ +#define CHKUSER_ENABLE_EZMLM_LISTS + +/* + * Help identifying remote authorized IPs giving them a descriptive name + * Can be put in tcp.smtp, and will be displayed inside chkuser log + */ +#define CHKUSER_IDENTIFY_REMOTE_VARIABLE "CHKUSER_IDENTIFY" + +/* + * The following #define set the character used for users extensions + * be careful: this is a single char '-' definition, not a "string" + * this define substitutes #define CHKUSER_EXTENSION_DASH + * MUST be defined if CHKUSER_ENABLE_USERS_EXTENSIONS is defined + */ +#define CHKUSER_USERS_DASH '-' + +/* + * Enables checking for mailman lists + * + */ +/* #define CHKUSER_ENABLE_MAILMAN_LISTS */ + +/* + * Identifies the pattern string to be searched within mailman aliases + * + */ +#define CHKUSER_MAILMAN_STRING "mailman" + +/* + * The following #define set the character used for mailman lists extensions + * be careful: this is a single char '-' definition, not a "string" + */ +#define CHKUSER_MAILMAN_DASH '-' + + +/* + * Enables final clean-up routine of chkuser + * This routine cleans open DB connections used for checking users and valiases + */ +#define CHKUSER_DB_CLEANUP + +/*************************************************** + * + * new/modified defines in/from 2.0.8 + * + **************************************************/ + +/* + * The following defines are NO MORE used. NULL SENDER rejecting breaks RFC + * compatibility, and makes harder to handle e-mail receipts. + * Please comment or delete them from your chkuser_settings.h. + */ +/* #define CHKUSER_ACCEPT_NULL_SENDER */ +/* #define CHKUSER_ENABLE_NULL_SENDER_WITH_TCPREMOTEHOST */ + +/* + * Uncomment to enable checking of user and domain format for rcpt addresses + * user = [a-z0-9_-] + * domain = [a-z0-9-.] with not consecutive "-.", not leading or ending "-." + */ +/* #define CHKUSER_RCPT_FORMAT */ + +/* + * Uncomment to enable checking of domain MX for rcpt addresses + * It works on any rcpt address domain that is not inside rcpthosts + */ +/* #define CHKUSER_RCPT_MX */ + +/* + * Uncomment to enable checking of user and domain format for sender address + * user = [a-z0-9_-] + * domain = [a-z0-9-.] with not consecutive "-.", not leading or ending "-." + */ +/* #define CHKUSER_SENDER_FORMAT */ + +/* + * Uncomment to enable checking of domain MX for sender address + * it works on the first rcpt address, despite of any domain setting on chkuser + */ +/*#define CHKUSER_SENDER_MX */ + +/* + * Delay to add, for each not existing recipient, to the initial CHKUSER_ERROR_DELAY value + * value is expressed in milliseconds + */ +#define CHKUSER_ERROR_DELAY_INCREASE 300 + +/*************************************************** + * + * new/modified defines in/from 2.0.9 + * + **************************************************/ + +/* + * A new class of defines is introduced + * CHKUSER_EXTRA_xxxxx + * + * These defines will be used for features/behaviours that may work despite of other CHKUSER enable/disable settings + * + */ + +/* + * If you want to accept only authenticated/authorized users you MUST enable this define and set the related variable. + * + * if this define is uncommented and the variable is set (to whatever value) then RELAYCLIENT must be set + * otherwise any message will be rejected giving "not authorized" error. + * + */ +/* #define CHKUSER_EXTRA_MUSTAUTH_VARIABLE "CHKUSER_MUSTAUTH" */ + + +/* + * This is to check DB availability + * It avoids bouncing messages with wrong codes if MySQL/LDAP/PostGRES/etc are down or not reachable + * + * If you are using MySQL in normal installation use #define CHKUSER_VAUTH_OPEN_CALL vauth_open_update + * If you are using MySQL with separate servers for read and write use #define CHKUSER_VAUTH_OPEN_CALL vauth_open + * If you are using other DB, check the most appropriate function for your DB within dedicated vpopmail module + * + * This define substitutes CHKUSER_ENABLE_VAUTH_OPEN + */ + +/* #define CHKUSER_VAUTH_OPEN_CALL vauth_open */ +/* #define CHKUSER_VAUTH_OPEN_CALL vauth_open_update */ + +/* + * Variable to be set in order to disable chkuser + * You may set it to any value you like. If it exists chkuser will be disabled. + * Setting it to RELAYCLIENT helps disabling chkuser when sender is a known/authenticated mail client + * This is useful because Outlook/Eudora and other clients are not able to handle a KO when multiple recipients + * are present in the message. They should always relay to a SMTP service accepting all. + * + * Recipients will be logged anyway if CHKUSER_LOG_VALID_RCPT is defined. + * + * Important changes from 2.0.9 + * CHKUSER_ALWAYS_ON and CHKUSER_STARTING_VARIABLE cannot be defined together and in such a case a fatal error is displayed + * (in the previous versions CHKUSER_ALWAYS_ON would automatically disable CHKUSER_STARTING_VARIABLE definition) + * + * CHKUSER_DISABLE_VARIABLE is always evaluated after CHKUSER_ALWAYS_ON is set or CHKUSER_STARTING_VARIABLE is evaluated, so + * CHKUSER_ALWAYS_ON or CHKUSER_STARTING_VARIABLE can set the general behaviour, while CHKUSER_DISABLE_VARIABLE + * should be invoked to handle exceptions. + * + */ +/* #define CHKUSER_DISABLE_VARIABLE "RELAYCLIENT" */ + + +/* + * Error strings (SMTP error answers) + * If you don't like these definitions you can change them here + * + */ +#define CHKUSER_NORCPT_STRING "550 5.1.1 sorry, no mailbox here by that name (chkuser)\r\n" +#define CHKUSER_RESOURCE_STRING "451 4.3.0 system temporary unavailable, try again later (chkuser)\r\n" +#define CHKUSER_MBXFULL_STRING "552 5.2.2 sorry, recipient mailbox is full (chkuser)\r\n" +#define CHKUSER_MAXRCPT_STRING "550 5.5.3 sorry, reached maximum number of recipients allowed in one session (chkuser)\r\n" +#define CHKUSER_MAXWRONGRCPT_STRING "550 5.5.3 sorry, you are violating our security policies (chkuser)\r\n" +#define CHKUSER_DOMAINMISSING_STRING "550 5.1.2 sorry, you must specify a domain (chkuser)\r\n" +#define CHKUSER_RCPTFORMAT_STRING "553 5.1.3 sorry, mailbox syntax not allowed (chkuser)\r\n" +#define CHKUSER_RCPTMX_STRING "550 5.1.2 sorry, can't find a valid MX for rcpt domain (chkuser)\r\n" +#define CHKUSER_SENDERFORMAT_STRING "553 5.1.7 sorry, mailbox syntax not allowed (chkuser)\r\n" +#define CHKUSER_SENDERMX_STRING "550 5.1.8 sorry, can't find a valid MX for sender domain (chkuser)\r\n" +#define CHKUSER_INTRUSIONTHRESHOLD_STRING "550 5.7.1 sorry, you are violating our security policies (chkuser)\r\n" +#define CHKUSER_NORELAY_STRING "553 5.7.1 sorry, that domain isn't in my list of allowed rcpthosts (chkuser)\r\n" + +#define CHKUSER_RCPTMX_TMP_STRING "451 4.4.0 DNS temporary failure (chkuser)\r\n" +#define CHKUSER_SENDERMX_TMP_STRING "451 4.4.0 DNS temporary failure (chkuser)\r\n" + +#define CHKUSER_MUSTAUTH_STRING "530 5.7.0 Authentication required (chkuser)\r\n" + +/* + * No more used defines + * Following defines are eliminated since 2.0.9 + * They will make compilation errors and must be deleted/commented + * + * #define CHKUSER_ENABLE_VAUTH_OPEN -> Substituted by CHKUSER_VAUTH_OPEN_CALL + */ + + +/* + * If you need more additional characters to be accepted within sender address + * uncomment one of the following #define and edit the character value. + * Be careful to use '*' (single hiphen) and NOT "*" (double hiphen) around the + * wanted char. + * + * Remember: '#' and '+' are accepted by CHKUSER_ALLOW_SENDER_SRS + * + */ +/* #define CHKUSER_ALLOW_SENDER_CHAR_1 '$' */ +/* #define CHKUSER_ALLOW_SENDER_CHAR_2 '%' */ +/* #define CHKUSER_ALLOW_SENDER_CHAR_3 '£' */ +/* #define CHKUSER_ALLOW_SENDER_CHAR_4 '?' */ +/* #define CHKUSER_ALLOW_SENDER_CHAR_5 '*' */ +/* #define CHKUSER_ALLOW_SENDER_CHAR_6 '^' */ +/* #define CHKUSER_ALLOW_SENDER_CHAR_7 '~' */ +/* #define CHKUSER_ALLOW_SENDER_CHAR_8 '&' */ /* available for other characters */ +/* #define CHKUSER_ALLOW_SENDER_CHAR_9 '#' */ /* available for other characters */ +/* #define CHKUSER_ALLOW_SENDER_CHAR_10 '=' */ /* available for other characters */ + + +/* + * If you need more additional characters to be accepted within rcpt address + * uncomment one of the following #define and edit the character value. + * Be careful to use '*' (single hiphen) and NOT "*" (double hiphen) around the + * wanted char. + * + * Remember: '#' and '+' are accepted by CHKUSER_ALLOW_RCPT_SRS + * + */ +/* #define CHKUSER_ALLOW_RCPT_CHAR_1 '$' */ +/* #define CHKUSER_ALLOW_RCPT_CHAR_2 '%' */ +/* #define CHKUSER_ALLOW_RCPT_CHAR_3 '£' */ +/* #define CHKUSER_ALLOW_RCPT_CHAR_4 '?' */ +/* #define CHKUSER_ALLOW_RCPT_CHAR_5 '*' */ +/* #define CHKUSER_ALLOW_RCPT_CHAR_6 '^' */ +/* #define CHKUSER_ALLOW_RCPT_CHAR_7 '~' */ +/* #define CHKUSER_ALLOW_RCPT_CHAR_8 '&' */ /* available for other characters */ +/* #define CHKUSER_ALLOW_RCPT_CHAR_9 '#' */ /* available for other characters */ +/* #define CHKUSER_ALLOW_RCPT_CHAR_10 '=' */ /* available for other characters */ + + +/* + * This define tells chkuser which variable must be set to accept a <#@[]> sender + * This kind of sender is usually generated from qmail when there is a doublebounce + * and all the job is done within the same system. + * You may need to accept double bounces from outside when you are migrating servers and + * doublebounces are forwarded between systems + */ +#define CHKUSER_ENABLE_DOUBLEBOUNCE_VARIABLE "CHKUSER_DOUBLEBOUNCE" diff -NU3 ./conf-cc ../netqmail-1.05-chkuser-2.0.9-release/conf-cc --- ./conf-cc Mon Jun 15 12:53:16 1998 +++ ../netqmail-1.05-chkuser-2.0.9-release/conf-cc Tue Mar 20 14:49:55 2007 @@ -1,3 +1,3 @@ -cc -O2 +cc -O2 -I/home/vpopmail/include This will be used to compile .c files. diff -NU3 ./qmail-smtpd.c ../netqmail-1.05-chkuser-2.0.9-release/qmail-smtpd.c --- ./qmail-smtpd.c Sun May 14 17:02:02 2006 +++ ../netqmail-1.05-chkuser-2.0.9-release/qmail-smtpd.c Tue Mar 20 14:49:55 2007 @@ -1,3 +1,13 @@ +/* + * + * includes chkuser v.2.0.8 + * for qmail/netqmail > 1.0.3 and vpopmail > 5.3.x + * + * Author: Antonio Nati tonix@interazioni.it + * www.interazioni.it/opensource + * + */ + #include "sig.h" #include "readwrite.h" #include "stralloc.h" @@ -24,6 +34,10 @@ #include "timeoutwrite.h" #include "commands.h" +/* start chkuser code */ +#include "chkuser.h" +/* end chkuser code */ + #define MAXHOPS 100 unsigned int databytes = 0; int timeout = 1200; @@ -240,6 +254,9 @@ void smtp_mail(arg) char *arg; { if (!addrparse(arg)) { err_syntax(); return; } +/* start chkuser code */ + if (chkuser_sender (&addr) != CHKUSER_OK) { return; } +/* end chkuser code */ flagbarf = bmfcheck(); seenmail = 1; if (!stralloc_copys(&rcptto,"")) die_nomem(); @@ -251,6 +268,10 @@ if (!seenmail) { err_wantmail(); return; } if (!addrparse(arg)) { err_syntax(); return; } if (flagbarf) { err_bmf(); return; } + +/* + * Original code substituted by chkuser code + if (relayclient) { --addr.len; if (!stralloc_cats(&addr,relayclient)) die_nomem(); @@ -258,6 +279,26 @@ } else if (!addrallowed()) { err_nogateway(); return; } + + * end of substituted code + */ + +/* start chkuser code */ + switch (chkuser_realrcpt (&mailfrom, &addr)) { + + case CHKUSER_KO: + return; + break; + + case CHKUSER_RELAYING: + --addr.len; + if (!stralloc_cats(&addr,relayclient)) die_nomem(); + if (!stralloc_0(&addr)) die_nomem(); + break; + + } +/* end chkuser code */ + if (!stralloc_cats(&rcptto,"T")) die_nomem(); if (!stralloc_cats(&rcptto,addr.s)) die_nomem(); if (!stralloc_0(&rcptto)) die_nomem();