This patch updates obtuse smtpd with all the features the OpenBSD team has added to smtpd im OpenBSD 3.0. Despite bugfixes this is logging to a file, binding to selected adresses, using an other port than 25, RBL usage and PID files. --drt@un.bewaff.net diff -urbBN smtpd-2.0/CREDITS smtpd-openbsd-3.0/CREDITS --- smtpd-2.0/CREDITS Mon Oct 13 03:40:34 1997 +++ smtpd-openbsd-3.0/CREDITS Tue Apr 30 20:59:36 2002 @@ -120,3 +120,10 @@ sending message body - could make smtpd exit and leave an incomplete spool file sitting in the spool dir. +Who: Simon J. Gerraty +What: Contributed new -q logging format and fixes for spaces within + quoted local-part so smtpd doesn't smack X400 messages. + +Who: Henning P. Schmiedehausen +What: Contributed -l option to allow for smtpd to be restricted to + answering on only one address on a box with many addresses. diff -urbBN smtpd-2.0/Makefile smtpd-openbsd-3.0/Makefile --- smtpd-2.0/Makefile Mon Oct 13 03:40:34 1997 +++ smtpd-openbsd-3.0/Makefile Tue Apr 30 20:59:36 2002 @@ -1,3 +1,5 @@ +# $Id: smtpd-2.0-to-openbsd-3.0.patch 750 2005-08-13 20:28:39Z md $ + ########################################################## ## Where do I get installed? ############################# ########################################################## @@ -93,7 +95,7 @@ # smtpfwdd. # N.B. MAXARGS must be at least 6, or 5 if SENDMAIL_OITRUE (above) is 1. # You may wish to change this to be 6 if you want your sendmail to be -# invoked seperately for each receipient. +# invoked separately for each receipient. MAXARGS = 100 # How long (in seconds) should smtpd block on a read() call to a @@ -118,7 +120,7 @@ VANILLA_MESSAGES = 0 # smtpd checks and clobbers and potentially "evil" characters in hostnames, -# and mail addresses recieved on FROM: and RCPT: lines. This clobbers things +# and mail addresses received on FROM: and RCPT: lines. This clobbers things # like a connection from hostname `/bin/rm -rf /`@evil.org, or mail to # "| /bin/sh". It also clobbers things like 8bit chars in such things. # smtpd always clobbers the characters it doesn't like, @@ -333,7 +335,7 @@ #LD_LIBS = -lsocket -lnsl -lresolv #SunOS 4.X. No regex lib here, so you will have to set USE_REGEX to 0 -#above unless you have built the regex lib seperately. +#above unless you have built the regex lib separately. #CFLAGS = -g -O -DUSE_FLOCK -DNO_MEMMOVE -DBSD_SIGNAL -DSUNOS_GETOPT $(OPTIONS) #Irix @@ -346,15 +348,17 @@ all: smtpd smtpfwdd -smtpd: smtpd.o address_check.o +smtpd: smtpd.o address_check.o accumlog.o $(CC) -o smtpd smtpd.o address_check.o $(LD_LIBS) -smtpfwdd: smtpfwdd.o +smtpfwdd: smtpfwdd.o accumlog.o $(CC) -o smtpfwdd smtpfwdd.o $(LD_LIBS) smtpd.o: smtpd.c smtpd.h smtp.h smtpfwdd.o: smtpfwdd.c smtp.h + +accumlog.o: accumlog.c indent: indent $(INDENT_ARGS) smtpd.c diff -urbBN smtpd-2.0/Makefile.default smtpd-openbsd-3.0/Makefile.default --- smtpd-2.0/Makefile.default Mon Oct 13 03:40:34 1997 +++ smtpd-openbsd-3.0/Makefile.default Tue Apr 30 20:59:36 2002 @@ -1,3 +1,5 @@ +# $Id: smtpd-2.0-to-openbsd-3.0.patch 750 2005-08-13 20:28:39Z md $ + ########################################################## ## Where do I get installed? ############################# ########################################################## @@ -93,7 +95,7 @@ # smtpfwdd. # N.B. MAXARGS must be at least 6, or 5 if SENDMAIL_OITRUE (above) is 1. # You may wish to change this to be 6 if you want your sendmail to be -# invoked seperately for each receipient. +# invoked separately for each receipient. MAXARGS = 100 # How long (in seconds) should smtpd block on a read() call to a @@ -118,7 +120,7 @@ VANILLA_MESSAGES = 0 # smtpd checks and clobbers and potentially "evil" characters in hostnames, -# and mail addresses recieved on FROM: and RCPT: lines. This clobbers things +# and mail addresses received on FROM: and RCPT: lines. This clobbers things # like a connection from hostname `/bin/rm -rf /`@evil.org, or mail to # "| /bin/sh". It also clobbers things like 8bit chars in such things. # smtpd always clobbers the characters it doesn't like, @@ -333,7 +335,7 @@ #LD_LIBS = -lsocket -lnsl -lresolv #SunOS 4.X. No regex lib here, so you will have to set USE_REGEX to 0 -#above unless you have built the regex lib seperately. +#above unless you have built the regex lib separately. #CFLAGS = -g -O -DUSE_FLOCK -DNO_MEMMOVE -DSUNOS_GETOPT $(OPTIONS) #Irix diff -urbBN smtpd-2.0/Makefile.inc smtpd-openbsd-3.0/Makefile.inc --- smtpd-2.0/Makefile.inc Thu Jan 1 01:00:00 1970 +++ smtpd-openbsd-3.0/Makefile.inc Tue Apr 30 20:59:36 2002 @@ -0,0 +1,311 @@ +# $Id: smtpd-2.0-to-openbsd-3.0.patch 750 2005-08-13 20:28:39Z md $ + +########################################################## +## Compile time options, These set defaults ############## +########################################################## +# What mail agent should smtpfwdd use? +# This must take arguments of the form: +# "mailprog -f fromaddr toaddr toaddr ..." +# to deliver mail. +MAIL_AGENT = /usr/sbin/sendmail +#MAIL_AGENT = /usr/lib/sendmail + +# What user and group should smtpfwdd and smtpd run as? +# This MUST NOT be root, and must be a user that is "trusted" by +# sendmail or whatever you are using as MAIL_AGENT above so that the user +# may use the "-f" flag to specify the sender of a mail message. +SMTP_USER = uucp +SMTP_GROUP = daemon + +# smtpd and smtpfwdd generate lots of syslogs, by design. +# +# What log facility should smtpd and smtpfwdd use for syslogs? The +# default is LOG_MAIL, which is also used by critters like sendmail. +# if you don't like this and want the logs going elsewhere for easy +# perusal change this to something else (like LOG_LOCAL5) and adjust +# your /etc/syslog.conf file to deal with it to your liking. +# +# LOG_FACILITY=LOG_LOCAL5 +LOG_FACILITY = LOG_MAIL + + +# Where is the spool directory located? +# This is the directory used by smtpd to chroot to and store +# messages. It is the directory watched for messages by smtpfwdd. This +# directory should be readable and writable only to the user specified +# in SMTP_USER above. +# +# The chroot directory +SPOOLDIR = /var/spool/smtpd +# Where to store messages, relative to SPOOLDIR above. +SPOOLSUBDIR = . +#Use below instead of above if you don't want smtpd to chroot. This +#isn't normally a good idea if security is your main goal. A nice +#chroot jail may be a pain to build but should give you enough of a +#warm fuzzy to make it worth your while. +#SPOOLDIR = / +#SPOOLSUBDIR = usr/spool/smtpd + +# How frequently (in seconds) should smtpfwdd wake up to check the +# spool directory for new mail? +POLL_TIME = 10 + +# What is the maximum number of children smtpfwdd should spawn at one time +# when delivering messages before waiting for some to complete? This ensures +# the arrival of hundreds of mail messages doesn't run you out of processes. +MAXCHILDREN = 10 + +# Should smtpfwdd check the exit code of sendmail? smtpfwdd checks any +# non-zero exit status from sendmail to see if it indicates that +# sendmail thinks the message might be deliverable later. Normally +# this should not be a problem, however if you are not running +# sendmail as your delivery agent, or if your sendmail is broken, the +# exit codes may not mean much. In such a case you may not want +# smtpfwdd to retry message delivery when the mta exits indicating a +# failure. Setting SENDMAIL_RETRY to 0 below will make sure smtpfwdd +# never retries delivery if the MTA returns a non-zero exit +# status. You probably shouldn't change this unless you are sure you +# know what you are doing. +SENDMAIL_RETRY = 1 + +# Sendmail has a feature/bug that when feeding a message to it it will +# stop if a line contains only a '.'. This is suppressed in smtpfwdd +# by invoking sendmail with the "-oiTrue" option if the mail agent's +# name ends in the string "sendmail". If your "sendmail" isn't really +# sendmail, you may not need or want this. If so, change the SENDMAIL_OITRUE +# below to 0. +SENDMAIL_OITRUE = 1 + +# Sendmail can handle addresses quoted in <> on the command line. Some +# MTA's (like qmail) can't. set STRIP_QUOTES to 1 if you want smtpfwdd +# to peel off the <> from mail addresses on the command line when +# invoking the mta +STRIP_QUOTES = 0 + +# How many arguments can your execv() call take at once? This can be a +# conservative estimate. It determines the maximum number of +# recipients at a time that MAIL_AGENT will be invoked with by +# smtpfwdd. +# N.B. MAXARGS must be at least 6, or 5 if SENDMAIL_OITRUE (above) is 1. +# You may wish to change this to be 6 if you want your sendmail to be +# invoked separately for each receipient. +MAXARGS = 100 + +# How long (in seconds) should smtpd block on a read() call to a +# connected client before giving up on the connection? +READ_TIMEOUT = 600 + +# Should smtpd check hostnames and ip addresses of a connection +# against the DNS to verify consistency, and report any inconsistencies? +# Set to 0 for hostchecks, 1 for no hostchecks. Set this to 1 only if +# you don't want any name lookups done. +# NO_HOSTCHECKS = 1 +NO_HOSTCHECKS = 0 + +# Smtpd's default informational status messages in the smtp dialogue +# are somewhat unique and interesting (see smtpd.h). Normally these +# are only seen by people telnetting to your smtp port, or debugging +# mail. While the author has no shame and won't change the default +# It's understandable that they aren't everyone's cup of tea. Set +# VANILLA_MESSAGES below to 1 and smtp will use plain old politically +# correct Sendmail/RFC 821 style status messages. +VANILLA_MESSAGES = 1 # Boring.... +# VANILLA_MESSAGES = 0 + +# smtpd checks and clobbers and potentially "evil" characters in hostnames, +# and mail addresses received on FROM: and RCPT: lines. This clobbers things +# like a connection from hostname `/bin/rm -rf /`@evil.org, or mail to +# "| /bin/sh". It also clobbers things like 8bit chars in such things. +# smtpd always clobbers the characters it doesn't like, +# and syslogs a note of the fact. The options below determine whether or +# not smtpd will also drop the connection. +# +# Beware of setting this to 1 if your receive mail from sites where +# it's considered ok to put 8 bit ascii chars in message headers. +# +# If PARANOID_SMTP is 1, smtpd will close connection on any client +# that puts characters it thinks may be evil in the smtp dialogue, +# (HELO, FROM, RCPT), or in the message headers. +# When PARANOID_SMTP is 0, smtpd will replace the characters it thinks +# are evil and continue. +# PARANOID_SMTP = 1 +PARANOID_SMTP = 0 + +# +# If PARANOID_DNS is 1, smtpd will close connection on any client that +# has characters it thinks may be evil in it's hostname as found by DNS, +# or any client whose DNS forward and reverse mappings are inconsistent +# indicating a DNS spoof of misconfiguration. +# If PARANOID_DNS is 0, smtpd will replace any evil characters it sees +# continue. +# PARANOID_DNS = 1 +PARANOID_DNS = 0 + +# The check above will clobber stuff in the headers from some +# non north-american localizations. +# If your operating system has localization support +# you can define LOCALIZATION below to be your localization. +# For this to work, your operating system must support localization +# with setlocale, and you must copy the appropriate localization +# files into the right place in smtpd's chroot directory. +# The result of this is that smtpd will use a +# setlocale(LC_CTYPE, LOCALIZATION) to hopefully make sure +# your normal stuff won't get clobbered. +# Leave this set to 0 for no localization support. +# +# +# SET_LOCALE = 1 # Use a setlocale call to set localization +SET_LOCALE = 0 # don't include localization support at all +#LOCALIZATION = lt_LN.ISO_8859-1 +LOCALIZATION = C +#LOCALIZATION = POSIX +#LOCALIZATION = ISO-8859-1 +#LOCALIZATION = KOI-8 + +# Some sites may wish to ensure smtpd does *not* get run with command +# line options to affect the compiled-in behaviours. Set +# NO_COMMANDLINE_OPTIONS to 1 to make smtpd and smtpfwdd ignore any command +# line options. +#NO_COMMANDLINE_OPTIONS=1 +NO_COMMANDLINE_OPTIONS=0 + +# Smtpd does not support ESMTP's EHLO command normally, as it shouldn't +# need to. According to RFC, if the EHLO is unrecognized the connecting +# agent should drop back to a HELO on the second attempt (and then be +# talking vanilla smtp). Unfortunately Netscape Communicator betas seem +# seem to have a bug in which they simply try the EHLO again. Sigh. +# setting EHLO_KLUDGE to 1 will make smtpd accept a second EHLO as a helo, +# thereby kludging around this bug in Communicator. +#EHLO_KLUDGE=1 +EHLO_KLUDGE=0 + + +# smtpd can check FROM and RCPT addresses, along with the connecting +# host info using an address check file. This can be used to only +# allow certain mail addresses on a FROM:, or certain combinations of +# FROM: and RCPT from certain hosts. It can be used to prevent third +# party relays, enforce outgoing address conventions, prevent outgoing +# SPAM/obvious forgeries, or block incoming SPAM. Setting this to 0 will +# mean that none of the address checking functionality is compiled in at +# all. (meaning all of address_check.c is #ifdefed out). +CHECK_ADDRESS = 1 +# CHECK_ADDRESS = 0 + +# Set This to 1 if you are running smtpd on a Juniper firewall machine. +# This enables smtpd to use juniper's trusted/untrusted interface +# mechanism, allowing you to use the UNTRUSTED or TRUSTED specials +# in address check rules to match based on what kind of interface +# a connection arrived on. +# +# You must set this to 0 this on a non-juniper machine or smtpd will not +# build with CHECK_ADDRESS set to 1. You will get an error about +# juniper_firewall.h not existing if you forget this. +# +#JUNIPER_SUPPORT=1 +JUNIPER_SUPPORT=0 + +# Use regexp's in patterns? If you have a POSIX and friends, +# and you trust the regex lib enough for use, you can set USE_REGEX to +# 1, this allows you to specify a pattern enclosed in "/" as a regular +# POSIX/henry-spencer style extended regex for case insensitive matching +# (what's between the "/" gets fed to regcomp with +# REG_EXTENDED|REG_ICASE|REG_NOSUB options, then matched against) +# +# Note that older beasts (like SunOS 4.X) usually don't have a regex +# library, so if you're using something that doesn't you should set this +# to 0. +# +#USE_REGEX=0 +USE_REGEX=1 + +# Enable checking namservers? with NS_MATCH set to 1, patterns of the +# form NS=pattern can be used to match rules against the nameservers +# and MX records of originating connections or mail addresses, rather +# than the connection itself. This allows for small rules to block out +# whole blocks of bozos from rogue providers such as ispam.net should +# you choose to do so. i.e. +# +#noto_delay:NS=205.199.212.0/24 NS=205.199.2.0/24 NS=207.124.161.0/24:ALL:ALL +#noto_delay:ALL:NS=205.199.212.0/24 NS=205.199.2.0/24 NS=207.124.161.0/24:ALL +# +# would effectively block off anything originiating from, or with a FROM: +# address looking like any of it's nameservers are on one of cyberpromo.com's +# addresses. +# +# uncomment the LD_LIBS line as well if you enable NS_MATCH unless your +# resolver routines are in libc (like they are on some Linuxes) +# +# The NS_MATCH feature is lovingly dedicated by Bob Beck to Spamford +# Wallace and ispam.net +# +#NS_MATCH=0 +NS_MATCH=1 +LD_LIBS+=-lresolv # you may or may not need this. + +# The rules file for address checking, if enabled, remember this file +# will be in the chroot jail, so the line below probably means +# /usr/spool/smtpd/etc/smtpd_check_rules, unless you changed the +# chroot directory above. +CHECK_FILE = /etc/smtpd_check_rules + +# address checking rules may want user information, gotten from an RFC +# 931 style ident. This info may be passed in the environment to smtpd +# (from juniperd or the tcp wrapper), or smtpd will do the ident +# request itself if required. CHECK_IDENT determines the timeout (in +# seconds) on an ident request. if CHECK_IDENT is 0, no ident +# requests will be made by smtpd even if it sees a rule that would +# normally make it perform one. +# CHECK_IDENT = 0 +CHECK_IDENT = 10 + +# If you use the address checks to block incoming mail from certain +# spam sites, you can set NOTO_DELAY and DENY_DELAY below to specify +# the time in seconds smtpd will go to sleep for after matching a +# "noto_delay" or "deny_delay" rule. This makes your site a small +# headache to the spammer since they have to wait before being denied, +# instead of immediately knowing so, and proceeding on to their next +# victim. +# NOTO_DELAY = 0 +# DENY_DELAY = 0 +# NOTO_DELAY = 300 +# DENY_DELAY = 300 +NOTO_DELAY = 50 +DENY_DELAY = 50 + +# Because CHECK_ADDRESS above is meant to be used as a nuisance filter +# the default is to ALLOW on failure rather than deny service when no +# match is found, or if something happens while attempting to match a +# rule (such as a system call failure, or you make a syntax error in the +# rules file). Change +# CHECK_ADDRESS_DENY_ON_FAILURE to 1 to have smtpd not allow anything +# not explicitly allowed by the rules. +# CHECK_ADDRESS_DENY_ON_FAILURE = 1 +CHECK_ADDRESS_DENY_ON_FAILURE = 0 + + + +########################################################## +## End of compile time options. ########################## +########################################################## + +OPTIONS = -DMAIL_AGENT=\"$(MAIL_AGENT)\" -DSMTP_USER=\"$(SMTP_USER)\" \ + -DSMTP_GROUP=\"$(SMTP_GROUP)\" \ + -DLOG_FACILITY=$(LOG_FACILITY) -DVANILLA_MESSAGES=$(VANILLA_MESSAGES) \ + -DSPOOLDIR=\"$(SPOOLDIR)\" -DSPOOLSUBDIR=\"$(SPOOLSUBDIR)\" \ + -DPOLL_TIME=$(POLL_TIME) -DSENDMAIL_RETRY=$(SENDMAIL_RETRY) \ + -DSENDMAIL_OITRUE=$(SENDMAIL_OITRUE) -DSTRIP_QUOTES=$(STRIP_QUOTES) \ + -DMAXCHILDREN=$(MAXCHILDREN) -DMAXARGS=$(MAXARGS) \ + -DREAD_TIMEOUT=$(READ_TIMEOUT) -DNO_HOSTCHECKS=$(NO_HOSTCHECKS) \ + -DPARANOID_SMTP=$(PARANOID_SMTP) -DPARANOID_DNS=$(PARANOID_DNS) \ + -DNO_COMMANDLINE_OPTIONS=$(NO_COMMANDLINE_OPTIONS) \ + -DEHLO_KLUDGE=$(EHLO_KLUDGE) \ + -DCHECK_ADDRESS=$(CHECK_ADDRESS) -DCHECK_FILE=\"$(CHECK_FILE)\" \ + -DCHECK_ADDRESS_DENY_ON_FAILURE=$(CHECK_ADDRESS_DENY_ON_FAILURE) \ + -DCHECK_IDENT=$(CHECK_IDENT) \ + -DNOTO_DELAY=$(NOTO_DELAY) -DDENY_DELAY=$(DENY_DELAY) \ + -DSET_LOCALE=$(SET_LOCALE) -DLOCALIZATION=\"$(LOCALIZATION)\" \ + -DJUNIPER_SUPPORT=$(JUNIPER_SUPPORT) -DNS_MATCH=$(NS_MATCH) \ + -DUSE_REGEX=$(USE_REGEX) + +CFLAGS += -g -O -Wall -DUSE_FLOCK -DUSE_MKSTEMP $(OPTIONS) + diff -urbBN smtpd-2.0/Makefile.minimal smtpd-openbsd-3.0/Makefile.minimal --- smtpd-2.0/Makefile.minimal Mon Oct 13 03:40:34 1997 +++ smtpd-openbsd-3.0/Makefile.minimal Tue Apr 30 20:59:36 2002 @@ -1,3 +1,5 @@ +# $Id: smtpd-2.0-to-openbsd-3.0.patch 750 2005-08-13 20:28:39Z md $ + ####### # Makefile.minimal # Make a completely minimal smtpd. Doesn't do reverse dns lookups on @@ -99,7 +101,7 @@ # smtpfwdd. # N.B. MAXARGS must be at least 6, or 5 if SENDMAIL_OITRUE (above) is 1. # You may wish to change this to be 6 if you want your sendmail to be -# invoked seperately for each receipient. +# invoked separately for each receipient. MAXARGS = 100 # How long (in seconds) should smtpd block on a read() call to a @@ -124,7 +126,7 @@ VANILLA_MESSAGES = 0 # smtpd checks and clobbers and potentially "evil" characters in hostnames, -# and mail addresses recieved on FROM: and RCPT: lines. This clobbers things +# and mail addresses received on FROM: and RCPT: lines. This clobbers things # like a connection from hostname `/bin/rm -rf /`@evil.org, or mail to # "| /bin/sh". It also clobbers things like 8bit chars in such things. # smtpd always clobbers the characters it doesn't like, @@ -339,7 +341,7 @@ #LD_LIBS = -lsocket -lnsl -lresolv #SunOS 4.X. No regex lib here, so you will have to set USE_REGEX to 0 -#above unless you have built the regex lib seperately. +#above unless you have built the regex lib separately. #CFLAGS = -g -O -DUSE_FLOCK -DNO_MEMMOVE -DSUNOS_GETOPT $(OPTIONS) #Irix diff -urbBN smtpd-2.0/Makefile.nochecks smtpd-openbsd-3.0/Makefile.nochecks --- smtpd-2.0/Makefile.nochecks Mon Oct 13 03:40:34 1997 +++ smtpd-openbsd-3.0/Makefile.nochecks Tue Apr 30 20:59:36 2002 @@ -1,3 +1,5 @@ +# $Id: smtpd-2.0-to-openbsd-3.0.patch 750 2005-08-13 20:28:39Z md $ + ###### #Makefile.nochecks - set to build smtpd WITHOUT the address checking #functionality in address_check.c. @@ -97,7 +99,7 @@ # smtpfwdd. # N.B. MAXARGS must be at least 6, or 5 if SENDMAIL_OITRUE (above) is 1. # You may wish to change this to be 6 if you want your sendmail to be -# invoked seperately for each receipient. +# invoked separately for each receipient. MAXARGS = 100 # How long (in seconds) should smtpd block on a read() call to a @@ -122,7 +124,7 @@ VANILLA_MESSAGES = 0 # smtpd checks and clobbers and potentially "evil" characters in hostnames, -# and mail addresses recieved on FROM: and RCPT: lines. This clobbers things +# and mail addresses received on FROM: and RCPT: lines. This clobbers things # like a connection from hostname `/bin/rm -rf /`@evil.org, or mail to # "| /bin/sh". It also clobbers things like 8bit chars in such things. # smtpd always clobbers the characters it doesn't like, @@ -337,7 +339,7 @@ #LD_LIBS = -lsocket -lnsl -lresolv #SunOS 4.X. No regex lib here, so you will have to set USE_REGEX to 0 -#above unless you have built the regex lib seperately. +#above unless you have built the regex lib separately. #CFLAGS = -g -O -DUSE_FLOCK -DNO_MEMMOVE -DSUNOS_GETOPT $(OPTIONS) #Irix diff -urbBN smtpd-2.0/README smtpd-openbsd-3.0/README --- smtpd-2.0/README Mon Oct 13 03:40:34 1997 +++ smtpd-openbsd-3.0/README Tue Apr 30 20:59:36 2002 @@ -15,7 +15,7 @@ smtpd implements a minimal subset of the Simple Mail Transfer Protocol as specified in RFC 821. This daemon is used to talk to other smtp -mailers on the internet so that the host may recieve mail. This is the +mailers on the internet so that the host may receive mail. This is the storing daemon. smtpd agressively checks the originating host and logs anything it knows about it. it also imposes the RFC mandated limits on the length of command lines, and checks the hostnames and mailnames given by the diff -urbBN smtpd-2.0/accumlog.c smtpd-openbsd-3.0/accumlog.c --- smtpd-2.0/accumlog.c Thu Jan 1 01:00:00 1970 +++ smtpd-openbsd-3.0/accumlog.c Tue Apr 30 20:59:36 2002 @@ -0,0 +1,168 @@ +/* $Id: smtpd-2.0-to-openbsd-3.0.patch 750 2005-08-13 20:28:39Z md $*/ + +/* + * + * Copyright (c) 1998 Obtuse Systems Corporation + * Copyright (c) 1998 Simon J. Gerraty + * From: accumlog.c,v 1.1 1998/03/29 07:47:02 sjg + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Obtuse Systems + * Corporation and its contributors. + * 4. Neither the name of the Obtuse Systems Corporation nor the names + * of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY OBTUSE SYSTEMS CORPORATION AND + * CONTRIBUTORS ``AS IS''AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL OBTUSE SYSTEMS CORPORATION OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + * NAME: + * accumlog - append info to log entry + * + * SYNOPSIS: + * int accumlog(level, fmt, ...) + * + * DESCRIPTION: + * If "fmt" is null we flush any accumulated log + * to syslog otherwise we just append it to an existing entry. + * + * AUTHOR: + * Simon J. Gerraty + */ + +/* + * @(#)Copyright (c) 1998 Simon J. Gerraty. + * + * This is free software. It comes with NO WARRANTY. + * Permission to use, modify and distribute this source code + * is granted subject to the following conditions. + * 1/ that the above copyright notice and this notice + * are preserved in all copies and that due credit be given + * to the author. + * 2/ that any changes to this code are clearly commented + * as such so that the author does not get blamed for bugs + * other than his own. + * + * Please send copies of changes and bug-fixes to: + * sjg@quick.com.au + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include +#include /* exit codes so smtpd/smtpfwdd can exit properly -BB */ +#ifdef HAVE_MALLOC_H +# include +#else +extern char *malloc(), *realloc(); +#endif + +#ifdef MAIN +# define LOG_HUNK 10 +#endif + +#ifndef LOG_HUNK +# define LOG_HUNK 128 +#endif +#ifndef MAX +# define MAX(a, b) (((a) < (b)) ? (b) : (a)) +#endif + +int +accumlog(int level, const char *fmt, ...) +{ + va_list va; + static char *log = 0; + static int lsz = 0; + static int lx = 0; + int i, x, space = 0; + + va_start(va, fmt); + if (log == 0) { + lsz = 2 * LOG_HUNK; + if ((log = (char *) malloc(lsz)) == 0) { + syslog(LOG_ERR, "accumlog: malloc(%d): %m", lsz); + exit(EX_OSERR); + } + } + if (fmt == 0) { + if (lx > 0) { + syslog(level, "%s", log); + space = lx; + lx = 0; + } + va_end(va); + return space; /* how much logged */ + } + do { + space = lsz - lx; + x = vsnprintf(&log[lx], space, fmt, va); + if (x < 0) { + syslog(LOG_ERR, "accumlog: vsnprintf(\"%s\", ...): %m", fmt); + lx = 0; /* lose */ + } + if (x > 0 && (i = x + (LOG_HUNK / 2)) > space) { + lsz += MAX(i, LOG_HUNK); + if ((log = realloc(log, lsz)) == 0) { + syslog(LOG_ERR, "accumlog: realloc(%d): %m", lsz); + exit(EX_OSERR); + } + + } + } while (x > 0 && x > space) ; + + if (x > 0) { + lx += x; + if (log[lx - 1] == '\n') + lx--; + } + + va_end(va); + return lx; +} + +#ifdef MAIN +int +main(argc, argv) + int argc; + char **argv; +{ + int i; + + openlog("accumlog", 0, LOG_LOCAL0); + accumlog(LOG_INFO, "PID=%d\n", getpid()); /* should lose the \n */ + + for (i = 1; i < argc; i++) + accumlog(LOG_INFO, ", argv[%d]='%s'", i, argv[i]); + accumlog(LOG_INFO, 0); + exit(EX_OK); +} +#endif diff -urbBN smtpd-2.0/address_check.c smtpd-openbsd-3.0/address_check.c --- smtpd-2.0/address_check.c Mon Oct 13 03:40:34 1997 +++ smtpd-openbsd-3.0/address_check.c Tue Apr 30 20:59:36 2002 @@ -1,5 +1,6 @@ +/* $Id: smtpd-2.0-to-openbsd-3.0.patch 750 2005-08-13 20:28:39Z md $ */ + /* - * $Id: smtpd-2.0-to-openbsd-3.0.patch 750 2005-08-13 20:28:39Z md $ * * Copyright (c) 1996, 1997 Obtuse Systems Corporation. All rights * reserved. @@ -241,12 +242,21 @@ sprintf(tbuf, "%u,%u\r\n", ntohs(pi->peer_sa->sin_port), ntohs(pi->my_sa->sin_port)); - if (write(fd, tbuf, strlen(tbuf)) != strlen(tbuf)) { + i=0; + while (i < strlen(tbuf)) { + int j; + j=write(fd, tbuf+i, (strlen(tbuf+i))); + if (j < 0) { + syslog(LOG_DEBUG, "write error sending ident request (%m)"); alarm(0); signal(SIGALRM, SIG_DFL); close(fd); return(0); } + else if (j > 0){ + i+=j; + } + } /* read the answer back */ @@ -480,10 +490,10 @@ char *p, *tbuf; int period_cnt, non_digit; - unsigned long adt, mat, madt; - unsigned long *addr, *mask; + in_addr_t adt, mat, madt; + in_addr_t *addr, *mask; - mat=0xffffffff; + mat=INADDR_BROADCAST; addr=&adt; mask=&mat; @@ -516,7 +526,7 @@ if ( period_cnt == 3 ) { int a1, a2, a3, a4; - sscanf(tbuf,"%d.%d.%d.%d",&a1,&a2,&a3,&a4); + sscanf(tbuf,"%u.%u.%u.%u",&a1,&a2,&a3,&a4); if ( a1 > 255 || a2 > 255 || a3 > 255 || a4 > 255 ) { return(0); } @@ -540,7 +550,7 @@ free(tbuf); if (*p == '/'){ - int bits; + long bits; char *end; p += 1; @@ -588,6 +598,40 @@ return(madt == adt); } +/* do a Vixie style rbl lookup for dotquad addr in rbl domain + * rbl_domain. + */ +int vixie_rbl_lookup(char * rbl_domain, char * addr) { + char *t, *d, *a; + t = strdup(addr); + if (t==NULL) { + syslog(LOG_ERR, "Malloc failed!"); + Failure = 1; + return(0); + } + d = (char *) malloc(strlen(t)+strlen(rbl_domain)+1); + if (d==NULL) { + syslog(LOG_ERR, "Malloc failed!"); + free(t); + Failure = 1; + return(0); + } + *d='\0'; + while((a = strrchr(t, '.'))) { + strcat(d, a+1); + strcat(d, "."); + *a='\0'; + } + strcat(d, t); + strcat(d, rbl_domain); + if (gethostbyname(d) != NULL) { + free(t); free(d); + return(1); + } + free(t); free(d); + return(0); +} + static int ip_match(char *tok, char *string) { /* @@ -601,6 +645,12 @@ else if ((string == NULL)) { return(0); } + else if (strncmp(tok, "RBL.", 4) == 0) { + /* do an rbl style lookup on the IP address in string usind + * rbl domain of whatever followed RBL in tok + */ + return(vixie_rbl_lookup(tok+3, string)); + } else { return(masked_ip_match(tok, string)); } diff -urbBN smtpd-2.0/antirelay_check_rules_example smtpd-openbsd-3.0/antirelay_check_rules_example --- smtpd-2.0/antirelay_check_rules_example Mon Oct 13 03:40:34 1997 +++ smtpd-openbsd-3.0/antirelay_check_rules_example Tue Apr 30 20:59:36 2002 @@ -1,3 +1,5 @@ +# $Id: smtpd-2.0-to-openbsd-3.0.patch 750 2005-08-13 20:28:39Z md $ + # A simple anti-relay only example. Make sure you don't get used as a third # party relay to spam other unfortunate people and grind your server # to a halt dealing with the complaints. @@ -8,6 +10,11 @@ # what sort of interface it arrived on. This says we will relay # for any connection on a trusted interface. #allow:TRUSTED:ALL:ALL + +# Don't allow people to %hack relay off of me. +noto:ALL:ALL:*%*@*:551 Sorry %H (%I), I don't allow unauthorized relaying. You can't use me to send mail from %F to %T. +noto:ALL:ALL:*!*@*:551 Sorry %H (%I), I don't allow unauthorized relaying. You can't use me to send mail from %F to %T. +noto:ALL:ALL:*@*@*:551 Sorry %H (%I), I don't allow unauthorized relaying. You can't use me to send mail from %F to %T. # If we have NS_MATCH=1 compiled in, we can do it this way, by allowing # the relay mail outbound from hosts that have dns.my.domain as one of diff -urbBN smtpd-2.0/antispam_check_rules.example smtpd-openbsd-3.0/antispam_check_rules.example --- smtpd-2.0/antispam_check_rules.example Mon Oct 13 03:40:34 1997 +++ smtpd-openbsd-3.0/antispam_check_rules.example Tue Apr 30 20:59:36 2002 @@ -1,3 +1,5 @@ +# $Id: smtpd-2.0-to-openbsd-3.0.patch 750 2005-08-13 20:28:39Z md $ + # # example smtpd_check_rules file. If you compiled smtpd with # CHECK_ADDRESS=1, this file goes in etc/smtpd_check_rules in your @@ -27,6 +29,10 @@ # otherwise, we'd do it like this: allow:*mydomain.com *otherdomain.com:ALL +# don't allow people to use %hack to relay off of me. +noto:ALL:ALL:*%*@*:551 Sorry %H (%I), I don't allow unauthorized relaying. You can't use me to send mail from %F to %T. +noto:ALL:ALL:*!*@*:551 Sorry %H (%I), I don't allow unauthorized relaying. You can't use me to send mail from %F to %T. +noto:ALL:ALL:*@*@*:551 Sorry %H (%I), I don't allow unauthorized relaying. You can't use me to send mail from %F to %T. # First, the exceptions. # "I'll have your spam dear, I love it!" @@ -38,6 +44,18 @@ allow:ALL:ALL:ALL@hormel.mydomain.com spamboy@otherdomain.com +# Block any connections from host in the MAPS rbl at rbl.maps.vix.com +# Beware that this can throw the baby out with the bathwater. +noto:RBL.rbl.maps.vix.com:ALL:ALL:550 Mail refused from host %I in MAPS RBL, see http%C//maps.vix.com/rbl/ + +# Block any connections from a host or connecting address who uses a +# nameserver for which the address is in the MAPS rbl at rbl.maps.vix.com. +# Note that this can *really* throw the baby out with the bathwater, +# be sure you understand the implications before using the two below. +noto:NS=RBL.rbl.maps.vix.com:ALL:ALL:550 Mail refused due to nameserver for %H(%I) in MAPS RBL, see http%C//maps.vix.com/rbl/ +noto:ALL:NS=RBL.rbl.maps.vix.com:ALL:550 Mail refused due to nameserver for %F in MAPS RBL, see http%C//maps.vix.com/rbl/ + + # block anyone who uses a major SPAM provider as a nameserver or MX. either # on a connection from one of their hosts, a connection from a host they act # as a nameserver for, or a connection with a FROM: address that uses @@ -86,8 +104,85 @@ noto:NS=206.85.231.0/24:ALL:ALL noto:ALL:NS=206.85.231.0/24:ALL #tnlb.com - "the national letter bureau" and "mako marketing" - yeesh.. -noto:NS=206.101.40.5:ALL:ALL -noto:ALL:NS=206.101.40.5:ALL +noto:206.101.40.0/24 206.101.58.0/24 208.230.127.0/24:ALL:ALL +noto:NS=206.101.40.0/24 NS=206.101.58.0/24 NS=208.230.127.0/24:ALL:ALL +noto:ALL:NS=206.101.40.0/24 NS=206.101.58.0/24 NS=208.230.127.0/24:ALL +#c-flash.net - yaash +noto:205.199.166.0/24:ALL:ALL +noto:NS=205.199.166.0/24:ALL:ALL +noto:ALL:NS=205.199.166.0/24:ALL +#directsend.com - Former Nancynet customer, now yaash +noto:206.84.21.0/24 207.201.213.0/24:ALL:ALL +noto:NS=206.84.21.0/24 NS=207.201.213.0/24:ALL:ALL +noto:ALL:NS=206.84.21.0/24 NS=207.201.213.0/24:ALL +noto:206.84.21.0/24:ALL:ALL +noto:NS=206.84.21.0/24:ALL:ALL +noto:ALL:NS=206.84.21.0/24:ALL +#we-deliver.net - yaash +noto:206.62.151.0/24:ALL:ALL +noto:NS=206.62.151.0/24:ALL:ALL +noto:ALL:NS=206.62.151.0/24:ALL +#savoynet.com - yaash +noto:204.157.255.0/24:ALL:ALL +noto:NS=204.157.255.0/24:ALL:ALL +noto:ALL:NS=204.157.255.0/24:ALL +#taizen.com - "grandbikes.com" and other spammers. No response to complaints. +noto:208.219.218.0/24:ALL:ALL +noto:NS=208.219.218.0/24:ALL:ALL +noto:ALL:NS=208.219.218.0/24:ALL +#edgetone.com and cyberserverscentral.com +noto:208.223.114.0/24 208.223.112.0/24 204.178.73.192/25:ALL:ALL +noto:NS=208.223.114.0/24 NS=208.223.112.0/24 NS=204.178.73.192/25:ALL:ALL +noto:ALL:NS=208.223.114.0/24 NS=208.223.112.0/24 NS=204.178.73.192/25:ALL +#icsinc.net and money-group.net +noto:151.201.64.0/24:ALL:ALL +noto:NS=151.201.64.0/24:ALL:ALL +noto:ALL:NS=151.201.64.0/24:ALL +#gil.net and firstgear.com +noto:207.100.79.0/24:ALL:ALL +noto:NS=207.100.79.0/24:ALL:ALL +noto:ALL:NS=207.100.79.0/24:ALL +#ultramax.net and friends +noto:207.201.213.0/24:ALL:ALL +noto:NS=207.201.213.0/24:ALL:ALL +noto:ALL:NS=207.201.213.0/24:ALL +#t-1net.com +noto:208.21.213.0/24:ALL:ALL +noto:NS=208.21.213.0/24:ALL:ALL +noto:ALL:NS=208.21.213.0/24:ALL +#ezmoney.com and pals +noto:204.212.245.0/24:ALL:ALL +noto:NS=204.212.245.0/24:ALL:ALL +noto:ALL:NS=204.212.245.0/24:ALL +#mail-response, hitrus, etc. +noto:209.136.134.0/24:ALL:ALL +noto:NS=209.136.134.0/24:ALL:ALL +noto:ALL:NS=209.136.134.0/24:ALL +#nevwest - the next generation, via ACSI. +noto:209.12.111.0/23:ALL:ALL +noto:NS=209.12.111.0/23:ALL:ALL +noto:ALL:NS=209.12.111.0/23:ALL +#gtwinc, gmds.com - spamhaus +noto:207.201.213.0/24 206.98.109.0/24:ALL:ALL +noto:NS=207.201.213.0/24 NS=206.98.109.0/24:ALL:ALL +noto:ALL:NS=207.201.213.0/24 NS=206.98.109.0/24:ALL +#goplay.com, mpx.com - many, many spams +noto:199.74.206.0/24:ALL:ALL +noto:NS=199.74.206.0/24:ALL:ALL +noto:ALL:NS=199.74.206.0/24:ALL +#silkspin.com spamhaus +noto:151.196.90.0/24 151.196.69.0/24:ALL:ALL +noto:NS=151.196.90.0/24 NS=151.196.69.0/24:ALL:ALL +noto:ALL:NS=151.196.90.0/24 NS=151.196.69.0/24:ALL +#uplinkpro.com +noto:206.30.95.0/24:ALL:ALL +noto:NS=206.30.95.0/24:ALL:ALL +noto:ALL:NS=206.30.95.0/24:ALL +#excite.com mailexcite.com +noto:198.3.102.0/24 198.3.98.0/24:ALL:ALL +noto:NS=198.3.102.0/24 NS=198.3.98.0/24:ALL:ALL +noto:ALL:NS=198.3.102.0/24 NS=198.3.98.0/24:ALL + # dump things with a bogus rhs to a FROM: addresses. usually spammers diff -urbBN smtpd-2.0/contrib/smtpfilter.c smtpd-openbsd-3.0/contrib/smtpfilter.c --- smtpd-2.0/contrib/smtpfilter.c Mon Oct 13 03:40:34 1997 +++ smtpd-openbsd-3.0/contrib/smtpfilter.c Fri Dec 7 19:45:33 2001 @@ -1,10 +1,11 @@ +/* $OpenBSD: smtpfilter.c,v 1.3 2001/12/07 18:45:33 mpech Exp $*/ + /* * smtpfilter, Filter for filtering headers during forwarding them between * smtpfwdd and sendmail. Also logs size of message to syslog; may only * be invoked with one recipient. * * OriginalId: smtpfilter.c,v 1.00 1997/3/28 11:04:08 andre Exp $ - * $Id: smtpd-2.0-to-openbsd-3.0.patch 750 2005-08-13 20:28:39Z md $ */ #define MAX_LINE 1024 @@ -124,7 +125,7 @@ while( (cp = cp2 = strstr( line, MY_INSIDE_DOMAIN )) != NULL ) { while( cp > line ) { - register char c; + char c; c = *(cp-1); if( ! isalnum( c ) && c != '.' && c != '-' ) break; diff -urbBN smtpd-2.0/smtp.h smtpd-openbsd-3.0/smtp.h --- smtpd-2.0/smtp.h Mon Oct 13 03:40:34 1997 +++ smtpd-openbsd-3.0/smtp.h Tue Apr 30 20:59:36 2002 @@ -1,7 +1,8 @@ +/* $Id: smtpd-2.0-to-openbsd-3.0.patch 750 2005-08-13 20:28:39Z md $ */ + /* * Obtuse smtp store/forward daemon include file * - * $Id: smtpd-2.0-to-openbsd-3.0.patch 750 2005-08-13 20:28:39Z md $ * * Copyright (c) 1996, 1997 Obtuse Systems Corporation. All rights * reserved. @@ -86,3 +87,5 @@ long location; /* start of RCPT line in spoolfile */ struct smtp_victim * next; }; + +extern int accumlog(int level, const char *fmt, ...); diff -urbBN smtpd-2.0/smtpd.8 smtpd-openbsd-3.0/smtpd.8 --- smtpd-2.0/smtpd.8 Thu Jan 1 01:00:00 1970 +++ smtpd-openbsd-3.0/smtpd.8 Tue Apr 30 20:59:36 2002 @@ -0,0 +1,185 @@ +.\" $Id: smtpd-2.0-to-openbsd-3.0.patch 750 2005-08-13 20:28:39Z md $ +.Dd December 10, 1997 +.Dt SMTPD 8 +.Os +.Sh NAME +.Nm smtpd +.Nd Obtuse Systems SMTPD message storing daemon +.Sh SYNOPSIS +.Nm smtpd +.Op Fl HPDLq +.Op Fl c Ar chrootdir +.Op Fl d Ar spooldir +.Op Fl u Ar user +.Op Fl g Ar group +.Op Fl m Ar myname +.Op Fl s Ar maxsize +.Op Fl l Ar listenip +.Op Fl p Ar listenport +.Op Fl i Ar pidfile +.Sh DESCRIPTION +.Nm +talks the Simple Mail Transfer Protocol (SMTP) with +other SMTP daemons to receive mail from them and saves it into a spool +directory for later processing. +It is the store portion of an SMTP store and forward proxy. +The symbiotic companion program +.Xr smtpfwdd 8 +is used to forward the spooled mail on to its eventual destination. +.Nm +is normally invoked from a super-server such as +.Xr inetd 8 . +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl c Ar chrootdir +Specify a different +.Ar chrootdir +directory to chroot into on startup. +The default is +.Pa /var/spool/smtpd . +This directory should be readable and writable only to the user that +.Nm +runs as. +.It Fl d Ar spooldir +Specify a different spool directory within the chrooted subtree. +The default is +.Dq \&. , +making +.Nm +spool files to the directory it chroots itself to. +.It Fl D +Tells +.Nm +to run as a daemon, listening on port 25. +The default is not to run as a daemon. +.It Fl g Ar group +Specify a +.Ar group +to run as. +.It Fl H +Disable host checking against the DNS. +By default, +.Nm +checks and will complain in the syslogs if the DNS information for +a host seems to indicate a possible spoof or misconfiguration. +.It Fl i Ar pidfile +Specify a filename that +.Nm +should lock and write its PID to when running as a daemon. +Doesn't do anything if running from inetd. +Default PID file in daemon mode is +.Pa /var/run/smtpd.pid +on BSD systems, or +.Pa /usr/spool/smtpd/smtpd.pid +on non-BSD systems. +.It Fl l Ar listenip +Specify an IP address in dotted quad format for +.Nm +to accept connections to. +In daemon mode this limits the address that +.Nm +listens on. +In inetd mode, +.Nm smtpd +will issue a 521 error code and exit if connected to an address other than +the specified one. +By default, +.Nm +accepts a connection no matter what address it is connected to. +.It Fl L +Suppress children in daemon mode (above) from doing an +openlog() call. +This means your syslogs won't have PID +information, but is useful if you don't want to have to set up +your chroot jail for +.Nm +in a manner that an openlog() call will work in it. +.It Fl m Ar myname +Specify +.Ar myname , +the hostname the daemon should announce itself as. +The default is whatever +.Fn gethostname +returns. +.It Fl p Ar listenport +Specify a decimal port number for +.Nm +to listen when running as a daemon. +Doesn't do anything if running +from inetd. +.It Fl P +Enable paranoid mode of operation. +In this mode connections are dropped from any client feeding +.Nm +a suspicious hostname, FROM: or RCPT: lines containing characters +indicative of an attempt to do something evil, or any message headers +that aren't 8-bit clean. +The default is to log such occurrences and +substitute for the offending characters, but not drop the connection. +.It Fl q +Tell +.Nm +to be quieter. +By default, +.Nm +emits very verbose syslog messages. +With this option it will emit one line of log for each normal message exchange. +.It Fl s Ar maxsize +Specify +.Ar maxsize , +the maximum size (in bytes) of mail message the daemon should accept. +The default is not to have a maximum size. +.It Fl u Ar user +Specify a +.Ar user +to run as. +This user must not be root but +should be a user that is able to run sendmail and use the +.Fl f +option to specify the sender of a mail message. +.El +.Sh FILES +The address checking file is normally +.Pa etc/smtpd_check_rules , +within the chroot directory. +.Pp +The address check file, when enabled, is read for each RCPT line in the +SMTP dialogue. +Each rule is checked with the current source (SMTP client machine and +possibly user from ident) and the current +.Dq FROM: +and +.Dq RCPT: +addresses. +.Sh SEE ALSO +.Xr inetd 8 , +.Xr sendmail 8 , +.Xr smtpfwdd 8 +.Pp +.Pa /usr/share/smtpd +\- example configuration files. +.Pp +.Pa http://www.obtuse.com/smtpd.html +\- more examples and rules file details. +.Sh BUGS +Mistakes in +.Pa /etc/smtpd_check_rules +can discard legitimate mail and annoy +your users and other postmasters a very great deal! When +combined with custom return codes it is possible to write rules +that completely break the smtp protocol. +It is important to test your rules out and be absolutely sure they do +exactly what you want and no more. +.Pp +If +.Xr sendmail 8 +is not run as a daemon when using +.Nm +and +.Xr smtpfwdd 8 , +one must use cron to periodically invoke sendmail -q so that +queued messages are retried for eventual delivery. +Alternatively, +.Xr sendmail 8 +may be run as a daemon, but configured not to listen to the network. diff -urbBN smtpd-2.0/smtpd.c smtpd-openbsd-3.0/smtpd.c --- smtpd-2.0/smtpd.c Mon Oct 13 03:40:34 1997 +++ smtpd-openbsd-3.0/smtpd.c Tue Apr 30 20:59:36 2002 @@ -1,8 +1,9 @@ +/* $Id: smtpd-2.0-to-openbsd-3.0.patch 750 2005-08-13 20:28:39Z md $*/ + /* * smtpd, Obtuse SMTP daemon, storing agent. does simple collection of * mail messages, for later forwarding by smtpfwdd. * - * $Id: smtpd-2.0-to-openbsd-3.0.patch 750 2005-08-13 20:28:39Z md $ * * Copyright (c) 1996, 1997 Obtuse Systems Corporation. All rights * reserved. @@ -40,7 +41,7 @@ char *obtuse_copyright = "Copyright 1996 - Obtuse Systems Corporation - All rights reserved."; -char *obtuse_rcsid = "$Id: smtpd-2.0-to-openbsd-3.0.patch 750 2005-08-13 20:28:39Z md $"; +char *obtuse_rcsid = "$Id: smtpd-2.0-to-openbsd-3.0.patch 750 2005-08-13 20:28:39Z md $"; #include #include @@ -140,7 +141,7 @@ char *spoolfile = NULL; char *spooldir = SPOOLSUBDIR; /* this is relative to our chroot. */ int read_timeout = READ_TIMEOUT; -int maxsize = 0; +long maxsize = 0; int outfd, replyfd; #ifdef SUNOS_GETOPT extern char *optarg; @@ -154,6 +155,20 @@ int Paranoid_Smtp = PARANOID_SMTP; int Paranoid_Dns = PARANOID_DNS; int exiting = 0; +int VerboseSyslog = 1; + +#ifndef SMTPD_PID_DIR +#if defined(OpenBSD) || defined(FreeBSD) || defined(NetBSD) +# define SMTPD_PID_DIR "/var/run" +#else +# define SMTPD_PID_DIR SPOOLDIR +#endif +#endif + +#ifndef SMTPD_PID_FILENAME +#define SMTPD_PID_FILENAME "smtpd.pid" +#endif + /* * Generate the usual cryptic usage statement @@ -209,6 +224,12 @@ int len; c++; switch (*c) { + case '%': + add = "%"; + break; + case 'C': + add = ":"; + break; case 'F': add = from; break; @@ -421,7 +442,7 @@ } } } else { - syslog(LOG_CRIT, "You can't write %d bytes from a buffer with only %d in it!", len, buf->offset); + syslog(LOG_CRIT, "You can't write %d bytes from a buffer with only %d in it!", len, (int) buf->offset); } } @@ -509,7 +530,7 @@ * let's hope there is enough to syslog :-) */ syslog(LOG_CRIT, "malloc said no to a %d byte buffer!", - (mbuf->size + len + 1024)); + (int)(mbuf->size + len + 1024)); return (0); } } @@ -545,7 +566,7 @@ * let's hope there is enough to syslog :-) */ syslog(LOG_ERR, "malloc said no to a %d byte buffer!", - (mbuf->size + len + 1024)); + (int)(mbuf->size + len + 1024)); errno = ENOMEM; return (-1); } @@ -553,6 +574,8 @@ /* * buffer is now big enough */ + + fflush(NULL); signal(SIGALRM, read_alarm_timeout); alarm(read_timeout); howmany = read(fd, mbuf->tail, len); @@ -628,6 +651,8 @@ strncat(spoolfile, "/smtpdXXXXXX", 12); if ((fd = mkstemp(spoolfile)) < 0) { syslog(LOG_CRIT, "Couldn't create spool file %s!", spoolfile); + free(spoolfile); + spoolfile=NULL; smtp_exit(EX_CONFIG); } #else /* USE_MKSTEMP */ @@ -798,6 +823,10 @@ flush_smtp_mbuf(reply_buf, replyfd, reply_buf->offset); } + if (!VerboseSyslog) { + accumlog(LOG_INFO, 0); /* flush? */ + } + exit(val); } @@ -957,7 +986,12 @@ *dst++ = '^'; *dst++ = '='; } - if (isalnum(ch) || strchr(" -,:=.@_!<>()[]/+%", ch) != NULL) { + /* + * RFC822 allows both ' and " in local-part. + * " is infact _required_ if local-part contains spaces as is + * common in x400 (yuk). + */ + if (isalnum(ch) || strchr(" -,:=.@_!<>()[]/+%'\"", ch) != NULL) { if (firstone && (ch == '-')) { arg_attempt = 1; *dst++ = '^'; @@ -1036,22 +1070,6 @@ /* - * does string s look like a source routed mail address? - */ - -int -is_src_route(const unsigned char *s) -{ - while (*s != '\0') { - if ( (*s == '%') || (*s == '!') ) - return 1; - s++; - } - return 0; -} - - -/* * is smtp command "cmd" legal in state "state" */ int @@ -1375,8 +1393,18 @@ /* * log the connection */ + if (VerboseSyslog) { syslog(LOG_INFO, "SMTP HELO from %s(%s) as \"%s\"", - peerinfo.peer_clean_reverse_name, peerinfo.peer_ok_addr, client_claimed_name); + peerinfo.peer_clean_reverse_name, + peerinfo.peer_ok_addr, client_claimed_name); + } + else { + accumlog(LOG_INFO, 0); /* flush anything left */ + accumlog(LOG_INFO, "relay=%s/%s", + peerinfo.peer_clean_reverse_name, peerinfo.peer_ok_addr); + if (strcasecmp(peerinfo.peer_clean_reverse_name, client_claimed_name)) + accumlog(LOG_INFO, " as \"%s\"", client_claimed_name); + } state_change(state, HELO, SUCCESS); } else if (strcasecmp(verb, "MAIL") == 0) { if (!cmd_ok(MAIL, state)) { @@ -1407,8 +1435,15 @@ } buf += 5; SPANBLANK(buf); + /* + * if local-part contains ", then spaces are allowed + */ cp = NULL; - cp = strchr(buf, ' '); + if (buf[0] == '"' || buf[1] == '"') + cp = strrchr(buf, '"'); /* REVISIT: find last " */ + if (cp == NULL) + cp = buf+1; + cp = strchr(cp+1, ' '); if (cp != NULL) { /* stuff on the end */ *cp = '\0'; @@ -1453,8 +1488,12 @@ /* * log the connection */ - syslog(LOG_INFO, "mail from %s", - current_from_mailpath); + if (VerboseSyslog) { + syslog(LOG_INFO, "mail from %s", current_from_mailpath); + } else { + accumlog(LOG_INFO, " from=%s", current_from_mailpath); + } + /* * put our output in the outbuf */ @@ -1498,8 +1537,15 @@ } buf += 3; SPANBLANK(buf); + /* + * if local-part contains ", then spaces are allowed + */ cp = NULL; - cp = strchr(buf, ' '); + if (buf[0] == '"' || buf[1] == '"') + cp = strrchr(buf, '"'); /* REVISIT: find last " */ + if (cp == NULL) + cp = buf; + cp = strchr(cp+1, ' '); if (cp != NULL) { /* stuff on the end */ *cp = '\0'; @@ -1614,7 +1660,14 @@ break; case 0: /* we matched a "deny" rule. syslog and send back failure message */ - syslog(LOG_INFO, "Forbidden FROM or RCPT for host %s(%s) - Abandoning session", peerinfo.peer_clean_reverse_name, peerinfo.peer_ok_addr); + if (VerboseSyslog) { + syslog(LOG_INFO, "Forbidden FROM or RCPT for host %s(%s) - Abandoning session", + peerinfo.peer_clean_reverse_name, peerinfo.peer_ok_addr); + } + else { + accumlog(LOG_INFO, " forbidden FROM or RCPT"); + accumlog(LOG_INFO, 0); /* flush it */ + } { char *c; c = make_check_fail_reply(peerinfo.peer_clean_ident, @@ -1645,7 +1698,12 @@ } } badrcpt = 1; + + if (VerboseSyslog) { syslog(LOG_INFO, "Discarded bad recipient %s", victim); + } else { + accumlog(LOG_INFO, " discarded bad recipient=%s", victim); + } state_change(state, RCPT, ERROR); break; @@ -1666,7 +1724,11 @@ /* * log the recipient. */ + if (VerboseSyslog) { syslog(LOG_INFO, "Recipient %s", victim); + } else { + accumlog(LOG_INFO, " to=%s", victim); + } if (write_smtp_mbuf(outbuf, "RCPT ", strlen("RCPT ")) && write_smtp_mbuf(outbuf, victim, strlen(victim)) && write_smtp_mbuf(outbuf, "\n", 1)) { @@ -1739,7 +1801,7 @@ /* * initial message size */ - max = (*size ? *size : INT_MAX); + max = (*size ? *size : LONG_MAX); /* @@ -1749,12 +1811,12 @@ * the program will probably die and the bug will (hopefully) get fixed). */ - buf = alloc_smtp_mbuf(64); + buf = alloc_smtp_mbuf(1024); if (buf == NULL) { syslog(LOG_DEBUG, "Couldn't allocate input buffer for data command"); return (5); } - outbuf = alloc_smtp_mbuf(64); + outbuf = alloc_smtp_mbuf(1024); if (outbuf == NULL) { syslog(LOG_DEBUG, "Couldn't allocate output buffer for data command"); return (5); @@ -1768,11 +1830,20 @@ snarfed = read_smtp_mbuf(buf, in, 1024); if (snarfed < 0) { + if (VerboseSyslog) { syslog(LOG_INFO, "read error receiving message body: %m"); + } else { + accumlog(LOG_INFO, " read error receiving message body: %s", + strerror(errno)); + } return (2); } if (snarfed == 0) { + if (VerboseSyslog) { syslog(LOG_INFO, "EOF while receiving message body"); + } else { + accumlog(LOG_INFO, " EOF while receiving message body"); + } return (2); } if (outbuf->size < buf->size) { @@ -1945,11 +2016,12 @@ * The brains of this operation */ -void +int main(int argc, char **argv) { int opt; - char *optstring = "xc:d:u:s:g:m:HPDL"; + long smtp_port = 25; + char *optstring = "l:p:d:u:s:g:m:i:c:HPDLq"; int i, k; smtp_state_set last_state_s, current_state_s; /* The real state vector. */ smtp_state last_state, current_state; /* Pointers to the state vector. */ @@ -1959,9 +2031,12 @@ char *groupname = SMTP_GROUP; struct passwd *user = NULL; struct group *group = NULL; - struct sigaction new_sa, old_sa; + struct sigaction new_sa; int daemon_mode = 0; int listen_fd = -1; /* make gcc be quiet */ + int pid_fd = -1; + char *pid_fname = NULL; + struct in_addr listen_addr; int child_no_openlog = 0; /* don't openlog() in children - use inherited * parent fd */ @@ -1974,6 +2049,7 @@ umask (077); openlog("smtpd", LOG_PID | LOG_NDELAY, LOG_FACILITY); + listen_addr.s_addr = INADDR_ANY; #if SET_LOCALE /* try to set our localization to the one specified */ @@ -1990,9 +2066,40 @@ #ifdef GETOPT_EOF while ((opt = getopt(argc, argv, optstring)) != EOF) { #else - while ((opt = getopt(argc, argv, optstring)) > 0) { + while ((opt = getopt(argc, argv, optstring)) != -1) { #endif switch (opt) { + case 'p': + { + char *foo; + smtp_port = strtol(optarg, &foo, 10); + if (*foo != '\0') { + /* this doesn't smell like a number. Bail */ + syslog(LOG_ERR, "Invalid port argument for the \"-p\" option"); + show_usage(); + exit(EX_USAGE); + } + } + break; + case 'l': + listen_addr.s_addr = inet_addr(optarg); + if (listen_addr.s_addr == htonl(INADDR_NONE)) { + syslog(LOG_ERR, "Invalid ip address given for the \"-l\" option"); + show_usage(); + exit(EX_USAGE); + } + break; + case 'i': + if (optarg[0] != '/') { + syslog(LOG_ERR, "The \"-i\" option requires an absolute pathname argument\n"); + show_usage(); + exit(EX_USAGE); + } + pid_fname = optarg; + break; + case 'q': + VerboseSyslog = 0; + break; case 'c': if (optarg[0] != '/') { syslog(LOG_ERR, "The \"-c\" option requires an absolute pathname argument\n"); @@ -2218,13 +2325,14 @@ memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; - sa.sin_port = htons(25); - sa.sin_addr.s_addr = INADDR_ANY; + sa.sin_port = htons(smtp_port); + sa.sin_addr.s_addr = listen_addr.s_addr; /* Need to do this while we're still root */ if ( bind(listen_fd, (struct sockaddr *)&sa, sizeof(sa)) < 0 ) { - syslog(LOG_ERR, "Can't bind listen socket to port 25 in daemon mode (%m)"); + syslog(LOG_ERR, "Can't bind listen socket to port %ld in daemon mode (%m)" + , smtp_port); exit(EX_OSERR); } @@ -2242,6 +2350,23 @@ syslog(LOG_INFO, "Log reopened."); } + if (daemon_mode) { + /* open pid file fd while we're still root. */ + + if ( (pid_fname == NULL) && + (((pid_fname = malloc(sizeof(SMTPD_PID_DIR) + + sizeof(SMTPD_PID_FILENAME) + 2))) + != NULL ) ) { + (void) sprintf(pid_fname, "%s/%s", SMTPD_PID_DIR, SMTPD_PID_FILENAME); + } + if (pid_fname != NULL) { + if ((pid_fd = open(pid_fname, O_CREAT | O_WRONLY, 0644)) < 0) { + syslog(LOG_ERR, "Couldn't create pid file %s: %m", pid_fname); + exit(EX_CONFIG); + } + } + } + if (chrootdir != NULL) { if (chdir(chrootdir) != 0) { syslog(LOG_CRIT, "Couldn't chdir to directory %s! (%m)", @@ -2290,6 +2416,26 @@ } setsid(); + /* write our pid into the (inherited) pid_fd */ + + if (pid_fd >= 0) { + char buf[80]; +#ifdef USE_FLOCK + if (lockf(pid_fd, F_TLOCK, 0) != 0) +#else + if (flock(pid_fd, LOCK_EX|LOCK_NB) != 0) +#endif + { + syslog(LOG_ERR, + "Couldn't get lock on pid file %s! Am I already running?", pid_fname); + exit(1); + } + sprintf(buf, "%d\n", getpid()); + write(pid_fd, buf, strlen(buf)); + /* do not close - leave this fd open to keep lock */ + } + + if ( listen(listen_fd,10) < 0 ) { syslog(LOG_ERR, "Can't listen on socket in daemon mode (%m)"); exit(EX_OSERR); @@ -2322,7 +2469,7 @@ failures = 0; rval = fork(); - if ( rval == 0 ) { + if ( rval > 0 ) { /* * Parent - close the accepted fd and continue the loop @@ -2330,13 +2477,14 @@ close(fd); - } else if ( rval > 0 ) { + } else if ( rval == 0 ) { /* * Child - make ourselves look like an inetd child * and break out of the loop to allow the regular inetd-style * processing to occur. */ + close(pid_fd); /* we don't need this anymore */ dup2(fd,0); dup2(fd,1); @@ -2365,13 +2513,11 @@ #ifdef BSD_SIGNAL signal(SIGPIPE, SIG_IGN); #else + memset(&new_sa, 0, sizeof(new_sa)); new_sa.sa_handler = SIG_IGN; (void)sigemptyset(&new_sa.sa_mask); new_sa.sa_flags = SA_RESTART; -#ifdef __linux__ - new_sa.sa_restorer = NULL; -#endif - if ( sigaction( SIGPIPE, &new_sa, &old_sa ) != 0 ) { + if ( sigaction( SIGPIPE, &new_sa, NULL ) != 0 ) { syslog(LOG_CRIT,"CRITICAL - sigaction failed (%m)"); exit(EX_OSERR); } @@ -2524,14 +2670,13 @@ * didn't get one from a getsockname. get our hostname and use * that. */ - char hname[66]; + char hname[MAXHOSTNAMELEN]; struct hostent *hp; - if (gethostname(hname, 65) != 0) { + if (gethostname(hname, sizeof hname) != 0) { syslog(LOG_ERR, "gethostname() call failed! (%m) Who am I?"); exit(EX_OSERR); } - hname[65] = '\0'; if ((hp = gethostbyname(hname)) != NULL) { peerinfo.my_clean_reverse_name = strdup(hp->h_name); } else { @@ -2567,6 +2712,30 @@ zap_state(current_state); zap_state(last_state); + if (!daemon_mode && listen_addr.s_addr != INADDR_ANY) { + /* Are we allowed to talk on the address we accepted this connection + * on? - check to see that we are the defined listening address, or + * the loopback. + */ + if ((listen_addr.s_addr != peerinfo.my_sa->sin_addr.s_addr) + && (listen_addr.s_addr != htonl(INADDR_LOOPBACK)) + ) + { + /* tell the client to go away - we're not allowed to talk. */ + writereply(reply_buf, 521, 0, + peerinfo.my_clean_reverse_name, + " ", + m521msg, + NULL); + flush_smtp_mbuf(reply_buf, replyfd, reply_buf->offset); + syslog(LOG_INFO, "Refused connection attempt from %s(%s) to %s(%s)", + peerinfo.peer_clean_reverse_name, peerinfo.peer_ok_addr, + peerinfo.my_clean_reverse_name, inet_ntoa(listen_addr)); + smtp_exit(EX_OK); + } + } + + writereply(reply_buf, 220, 0, peerinfo.my_clean_reverse_name, " ", @@ -2588,7 +2757,11 @@ /* * eof */ + if (VerboseSyslog) { syslog(LOG_INFO, "EOF on client fd. At least they could say goodbye!"); + } else { + accumlog(LOG_INFO, "EOF on client fd."); + } smtp_exit(EX_OSERR); } offset = 0; @@ -2646,8 +2819,14 @@ smtp_close_spoolfile(outfd); writereply(reply_buf, 250, 0, m250gotit, NULL); flush_smtp_mbuf(reply_buf, replyfd, reply_buf->offset); + if (VerboseSyslog) { syslog(LOG_INFO, "Received %ld bytes of message body from %s(%s)", - msize, peerinfo.peer_clean_reverse_name, peerinfo.peer_ok_addr); + msize, peerinfo.peer_clean_reverse_name, + peerinfo.peer_ok_addr); + } else { + accumlog(LOG_INFO, " bytes=%ld", msize); + accumlog(LOG_INFO, 0); /* flush */ + } clear_state(SNARF_DATA, current_state); clear_state(OK_RCPT, current_state); clear_state(OK_MAIL, current_state); diff -urbBN smtpd-2.0/smtpd.h smtpd-openbsd-3.0/smtpd.h --- smtpd-2.0/smtpd.h Mon Oct 13 03:40:34 1997 +++ smtpd-openbsd-3.0/smtpd.h Tue Apr 30 20:59:36 2002 @@ -1,6 +1,7 @@ +/* $Id: smtpd-2.0-to-openbsd-3.0.patch 750 2005-08-13 20:28:39Z md $ */ + /* Obtuse smtpd SMTP store daemon header file * - * $Id: smtpd-2.0-to-openbsd-3.0.patch 750 2005-08-13 20:28:39Z md $ * * Copyright (c) 1996, 1997 Obtuse Systems Corporation. All rights * reserved. @@ -164,13 +165,9 @@ #define m554msg "This daemon finds you amusing.. Go read the forging FAQ.." #define m554norcpt "I gotta know who gets this masterpiece of forgery!" #define m554nofrom "Yeesh! Ya gotta give a FROM when forging mail, that's the whole point!" - -#ifdef USE_521 -#define m521msg "doesn't talk SMTP, Sorry" -#define m521first "Sorry, I've been told I can't talk to you" -#endif +#define m521msg "says \"Go away or I shall taunt you a second time you second-hand electric donkey-bottom biters..\"" #else /* Boring sendmail/RFC821-ish messages */ -#define m220msg "Sendmail ready. " +#define m220msg "Sendmail 4.1/SMI-4.1 ready." #define m221msg "Closing connection" #define m250helook "pleased to meet you," #define m250fromok "sender OK" @@ -202,9 +199,5 @@ #define m554msg "Transaction failed" #define m554norcpt "Transaction failed" #define m554nofrom "Transaction failed" - -#ifdef USE_521 #define m521msg "Doesn't talk SMTP, Sorry" -#define m521first "Doesn't talk SMTP, Sorry" -#endif #endif diff -urbBN smtpd-2.0/smtpd_check_rules.example smtpd-openbsd-3.0/smtpd_check_rules.example --- smtpd-2.0/smtpd_check_rules.example Mon Oct 13 03:40:34 1997 +++ smtpd-openbsd-3.0/smtpd_check_rules.example Tue Apr 30 20:59:36 2002 @@ -1,3 +1,5 @@ +# $Id: smtpd-2.0-to-openbsd-3.0.patch 750 2005-08-13 20:28:39Z md $ + # # example smtpd_check_rules file. If you compiled smtpd with # CHECK_ADDRESS=1, this file goes in etc/smtpd_check_rules in your diff -urbBN smtpd-2.0/smtpfwdd.8 smtpd-openbsd-3.0/smtpfwdd.8 --- smtpd-2.0/smtpfwdd.8 Thu Jan 1 01:00:00 1970 +++ smtpd-openbsd-3.0/smtpfwdd.8 Tue Apr 30 20:59:36 2002 @@ -0,0 +1,121 @@ +.\" $Id: smtpd-2.0-to-openbsd-3.0.patch 750 2005-08-13 20:28:39Z md $ +.Dd December 10, 1997 +.Dt SMTPFWDD 8 +.Os +.Sh NAME +.Nm smtpfwdd +.Nd Obtuse Systems SMTPFWDD message forwarding daemon +.Sh SYNOPSIS +.Nm smtpfwdd +.Op Fl q +.Op Fl d Ar spooldir +.Op Fl u Ar user +.Op Fl g Ar group +.Op Fl s Ar mailprog +.Op Fl M Ar maxchildren +.Op Fl P Ar poll time +.Sh DESCRIPTION +The +.Nm +daemon forwards mail messages from a spool directory to +their eventual destinations. +It regularly scans the spool directory in +which its symboitic companion program +.Xr smtpd 8 +stores messages and invokes +a mail program (such as +.Xr sendmail 8 ) +to forward them. +It is the forward portion of an SMTP store and forward proxy. +.Nm +is a standalone daemon, usually invoked at system startup. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl d +Specify a different spool +.Ar directory . +This should be the same directory in which +.Xr smtpd 8 +is spooling files (usually +.Pa /var/spool/smtpd ) +.It Fl g +Specify a +.Ar group +to run as. +Same as user above. +.It Fl M +Specifies +.Ar maxchildren +as the maximum number of children +.Nm +should be allowed to spawn at once when delivering mail. +Default is 10. +.It Fl P +specifies a polling interval of +.Ar polltime +seconds indicating how often the master +.Nm +process should wake up and check the spool directory for new mail +to forward. +Default is 10 seconds. +.It Fl q +Tell +.Nm +to be quieter. +By default, +.Nm +emits very verbose syslog messages. +With +this option it will emit one line of log for each normal message exchange. +.It Fl s +Specify a different mail program to use to forward mail. +The default is +.Pa /usr/sbin/sendmail +Any replacement must be able to be invoked in the same manner as sendmail +with a -f fromaddress, followed by one or more destination addresses +on the command line. +.It Fl u +Specify a +.Ar user +to run as. +This user must not be root but should normally be a user that is able to run +.Xr sendmail 8 +and use the +.Fl f +option to specify the sender of a mail message. +.El +.Sh SEE ALSO +.Xr inetd 8 , +.Xr sendmail 8 , +.Xr smtpd 8 +.Sh BUGS +Since +.Xr sendmail 8 +is not normally running as a daemon when using +.Xr smtpd 8 +and +.Xr smtpfwdd 8 , +one must use cron to periodically invoke sendmail -q so that +queued messages are retried for eventual delivery, alternatively sendmail +may be run standalone, but not listening to the network if your version +of sendmail supports doing this correctly. +.Pp +There are many different variations of sendmail. +.Nm +will check +and pay attention to the exit status of the sendmail processes it +invokes, possibly retrying an invocation of sendmail. +If you aren't using real unadulterated Berkeley sendmail or a recent +vintage, you may need to disable the exit status checking at compile time. +.Pp +.Xr sendmail 8 +can't handle a +.Ql \&. +on one line in a message body. +This problem is bypassed in +.Nm +by giving sendmail the option +.Fl oitrue . +Again, if you aren't using genuine sendmail, you may need to disable this at +compile time. diff -urbBN smtpd-2.0/smtpfwdd.c smtpd-openbsd-3.0/smtpfwdd.c --- smtpd-2.0/smtpfwdd.c Mon Oct 13 03:40:34 1997 +++ smtpd-openbsd-3.0/smtpfwdd.c Tue Apr 30 20:59:36 2002 @@ -1,10 +1,11 @@ +/* $Id: smtpd-2.0-to-openbsd-3.0.patch 750 2005-08-13 20:28:39Z md $*/ + /* * smtpfwdd, Obtuse SMTP forward daemon, master process watches spool * directory for files spooled by smtpd. On seeing one, spawns a child * to pick it up and invokes sendmail (or sendmail-like agent) to * deliver it. * - * $Id: smtpd-2.0-to-openbsd-3.0.patch 750 2005-08-13 20:28:39Z md $ * * Copyright (c) 1996, 1997 Obtuse Systems Corporation. All rights * reserved. @@ -41,7 +42,7 @@ */ char *obtuse_copyright = "Copyright 1996 - Obtuse Systems Corporation - All rights reserved."; -char *obtuse_rcsid = "$Id: smtpd-2.0-to-openbsd-3.0.patch 750 2005-08-13 20:28:39Z md $"; +char *obtuse_rcsid = "$Id: smtpd-2.0-to-openbsd-3.0.patch 750 2005-08-13 20:28:39Z md $"; #include #include @@ -122,6 +123,8 @@ int maxchildren = MAXCHILDREN; int poll_time = POLL_TIME; int gc_int = COMPLETION_WAIT; +int VerboseSyslog = 1; + #ifdef SUNOS_GETOPT extern char *optarg; @@ -343,7 +346,7 @@ } /* - * forward a mail message recieved by smtpd contained in file fname. + * forward a mail message received by smtpd contained in file fname. * file is expected to be as follows: * ------------------- * FROM addr @@ -591,6 +594,9 @@ body = ftell(f); victim = victims; sentout = 0; + if (!VerboseSyslog) { + accumlog(LOG_INFO, "Forwading %s", fname); + } while (victim != NULL) { int status, pid, pidw, i, rstart; struct smtp_victim *sv = victim; @@ -616,7 +622,11 @@ av[i++] = from; rstart = i; while (i < MAXARGS - 2) { + if (VerboseSyslog) { syslog(LOG_INFO, "forwarding to recipient %s", victim->name); + } else { + accumlog(LOG_INFO, " to=%s", victim->name); + } av[i++] = victim->name; victim = victim->next; if (victim == NULL) { @@ -636,6 +646,19 @@ exit(EX_OSERR); } + /* + * Open /dev/null as stdout and as stderr so sendmail 8.12.1 (and + * above ?) won't complain about missing file descriptors. + */ + if (open("/dev/null", O_WRONLY | O_APPEND) < 0) { + syslog(LOG_ERR, "Couldn't open /dev/null as stdout (%m)"); + exit (EX_OSERR); + } + if (open("/dev/null", O_RDWR | O_APPEND) < 0) { + syslog(LOG_ERR, "Couldn't open /dev/null as stderr (%m)"); + exit (EX_OSERR); + } + fclose(f); closelog(); if (lseek(0, body, SEEK_SET) < 0) { @@ -671,7 +694,6 @@ case EX_OSERR: case EX_OSFILE: case EX_IOERR: - case EX_UNAVAILABLE: case EX_TEMPFAIL: syslog(LOG_INFO, "Temporary sendmail failure (status %d), will retry later", status); fail_retry(f, fname); @@ -731,8 +753,12 @@ /* * All seems to have worked */ - + if (VerboseSyslog) { syslog(LOG_INFO, "%s forwarded to %d recipients", fname, sentout); + } else { + accumlog(LOG_INFO, ", forwarded to %d recipients", sentout); + accumlog(LOG_INFO, 0); /* flush */ + } if (unlink(fname) != 0) { syslog(LOG_CRIT, "Couldn't remove spool file %s! (%m)", fname); exit(EX_CONFIG); @@ -760,11 +786,11 @@ * The brains of this operation */ -void +int main(int argc, char **argv) { int opt; - char *optstring = "u:g:d:s:C:M:P:"; + char *optstring = "qu:g:d:s:M:P:"; int pid; char *username = SMTP_USER; @@ -780,9 +806,12 @@ #ifdef GETOPT_EOF while ((opt = getopt(argc, argv, optstring)) != EOF) { #else - while ((opt = getopt(argc, argv, optstring)) > 0) { + while ((opt = getopt(argc, argv, optstring)) != -1) { #endif switch (opt) { + case 'q': + VerboseSyslog = 0; + break; case 'd': if (optarg[0] != '/') { fprintf(stderr, "The \"-d\" option requires an absolute pathname argument, \"%s\" is bogus\n", optarg); @@ -1101,6 +1130,10 @@ } sleep(1); reap_children(); + } + if (!VerboseSyslog) { + /* should be empty - but just in case */ + accumlog(LOG_INFO, 0); } /* * If we have a file with an appropriate name and it is