summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndreas Beckmann <debian@abeckmann.de>2012-10-01 19:58:42 +0200
committerAndreas Beckmann <debian@abeckmann.de>2012-10-01 19:58:42 +0200
commitdd994db23cb7f88732be927fad3a7039bd6301db (patch)
tree129f709c96e5b1fb46cf9d09fa2a73bdb5aa9d7a /src
parentb8f791c58c310a0a41181d66122d80dc9c2e11bc (diff)
parent809d17c01e6e9d15289bf36b8609fa7f9b97671e (diff)
downloadsendmail-dd994db23cb7f88732be927fad3a7039bd6301db.tar.gz
Merged Upstream version 8.12.3
Diffstat (limited to 'src')
l---------src/Build1
-rw-r--r--src/Makefile.m4152
-rw-r--r--src/README1464
-rw-r--r--src/TRACEFLAGS79
-rw-r--r--src/alias.c895
-rw-r--r--src/aliases53
-rw-r--r--src/aliases.048
-rw-r--r--src/aliases.585
-rw-r--r--src/arpadate.c202
-rw-r--r--src/cdefs.h123
-rw-r--r--src/clock.c267
-rw-r--r--src/collect.c772
-rw-r--r--src/conf.c4938
-rw-r--r--src/conf.h2522
-rw-r--r--src/control.c356
-rw-r--r--src/convtime.c183
-rw-r--r--src/daemon.c2154
-rw-r--r--src/deliver.c3758
-rw-r--r--src/domain.c912
-rw-r--r--src/envelope.c938
-rw-r--r--src/err.c767
-rw-r--r--src/headers.c1710
-rw-r--r--src/ldap_map.h91
-rw-r--r--src/macro.c437
-rw-r--r--src/mailq.041
-rw-r--r--src/mailq.167
-rw-r--r--src/mailstats.h34
-rw-r--r--src/main.c2748
l---------src/makesendmail1
-rw-r--r--src/map.c5209
-rw-r--r--src/mci.c1293
-rw-r--r--src/mime.c1190
-rw-r--r--src/newaliases.027
-rw-r--r--src/newaliases.147
-rw-r--r--src/parseaddr.c2555
-rw-r--r--src/pathnames.h32
-rw-r--r--src/queue.c2422
-rw-r--r--src/readcf.c2920
-rw-r--r--src/recipient.c1456
-rw-r--r--src/safefile.c751
-rw-r--r--src/savemail.c1486
-rw-r--r--src/sendmail.0356
-rw-r--r--src/sendmail.8580
-rw-r--r--src/sendmail.h1514
-rw-r--r--src/sendmail.hf124
-rw-r--r--src/snprintf.c428
-rw-r--r--src/srvrsmtp.c1532
-rw-r--r--src/stab.c219
-rw-r--r--src/stats.c135
-rw-r--r--src/sysexits.c162
-rw-r--r--src/sysexits.h118
-rw-r--r--src/trace.c111
-rw-r--r--src/udb.c1335
-rw-r--r--src/useful.h58
-rw-r--r--src/usersmtp.c1172
-rw-r--r--src/util.c2365
-rw-r--r--src/version.c17
57 files changed, 0 insertions, 55412 deletions
diff --git a/src/Build b/src/Build
deleted file mode 120000
index 6308dba..0000000
--- a/src/Build
+++ /dev/null
@@ -1 +0,0 @@
-../BuildTools/bin/Build \ No newline at end of file
diff --git a/src/Makefile.m4 b/src/Makefile.m4
deleted file mode 100644
index d88d35b..0000000
--- a/src/Makefile.m4
+++ /dev/null
@@ -1,152 +0,0 @@
-#
-# This Makefile is designed to work on any reasonably current version of
-# "make" program.
-#
-# @(#)Makefile.m4 8.26 (Berkeley) 1/23/1999
-#
-
-# C compiler
-CC= confCC
-
-# Shell
-SHELL= confSHELL
-
-# use O=-O (usual) or O=-g (debugging)
-O= ifdef(`confOPTIMIZE', `confOPTIMIZE', `-O')
-
-# location of sendmail source directory
-SRCDIR= .
-
-# define the database mechanisms available for map & alias lookups:
-# -DNDBM -- use new DBM
-# -DNEWDB -- use new Berkeley DB
-# -DNIS -- include NIS support
-# The really old (V7) DBM library is no longer supported.
-# See README for a description of how these flags interact.
-#
-MAPDEF= ifdef(`confMAPDEF', `confMAPDEF')
-
-# environment definitions (e.g., -D_AIX3)
-ENVDEF= ifdef(`confENVDEF', `confENVDEF')
-
-# see also conf.h for additional compilation flags
-
-# include directories
-INCDIRS=confINCDIRS
-
-# loader options
-LDOPTS= ifdef(`confLDOPTS', `confLDOPTS')
-
-# library directories
-LIBDIRS=confLIBDIRS
-
-# libraries required on your system
-# delete -l44bsd if you are not running BIND 4.9.x
-LIBS= ifdef(`confLIBS', `confLIBS')
-
-# location of sendmail binary (usually /usr/sbin or /usr/lib)
-BINDIR= ${DESTDIR}ifdef(`confMBINDIR', `confMBINDIR', `/usr/sbin')
-
-# location of "user" binaries (usually /usr/bin or /usr/ucb)
-UBINDIR=${DESTDIR}ifdef(`confUBINDIR', `confUBINDIR', `/usr/bin')
-
-# location of sendmail.st file (usually /var/log or /usr/lib)
-STDIR= ${DESTDIR}ifdef(`confSTDIR', `confSTDIR', `/var/log')
-
-# location of sendmail.hf file (usually /usr/share/misc or /usr/lib)
-HFDIR= ${DESTDIR}ifdef(`confHFDIR', `confHFDIR', `/usr/share/misc')
-
-# additional .o files needed
-OBJADD= ifdef(`confOBJADD', `confOBJADD') ifdef(`confSMOBJADD', `confSMOBJADD')
-
-undivert(1)
-
-################### end of user configuration flags ######################
-
-BUILDBIN=confBUILDBIN
-COPTS= -I. ${INCDIRS} ${MAPDEF} ${ENVDEF}
-CFLAGS= $O ${COPTS}
-
-BEFORE= confBEFORE
-OBJS= alias.o arpadate.o clock.o collect.o conf.o control.o convtime.o \
- daemon.o deliver.o domain.o envelope.o err.o headers.o macro.o \
- main.o map.o mci.o mime.o parseaddr.o queue.o readcf.o recipient.o \
- safefile.o savemail.o snprintf.o srvrsmtp.o stab.o stats.o \
- sysexits.o trace.o udb.o usersmtp.o util.o version.o ${OBJADD}
-
-LINKS= ifdef(`confLINKS', `confLINKS',
- `${UBINDIR}/newaliases \
- ${UBINDIR}/mailq \
- ${UBINDIR}/hoststat \
- ${UBINDIR}/purgestat')
-
-NROFF= ifdef(`confNROFF', `confNROFF', `groff -Tascii')
-MANDOC= ifdef(`confMANDOC', `confMANDOC', `-mandoc')
-
-INSTALL=ifdef(`confINSTALL', `confINSTALL', `install')
-BINOWN= ifdef(`confSBINOWN', `confSBINOWN', `root')
-BINGRP= ifdef(`confSBINGRP', `confSBINGRP', `kmem')
-BINMODE=ifdef(`confSBINMODE', `confSBINMODE', `4555')
-
-MANOWN= ifdef(`confMANOWN', `confMANOWN', `bin')
-MANGRP= ifdef(`confMANGRP', `confMANGRP', `bin')
-MANMODE=ifdef(`confMANMODE', `confMANMODE', `444')
-
-MANROOT=${DESTDIR}ifdef(`confMANROOT', `confMANROOT', `/usr/share/man/cat')
-MAN1= ${MANROOT}ifdef(`confMAN1', `confMAN1', `1')
-MAN1EXT=ifdef(`confMAN1EXT', `confMAN1EXT', `1')
-MAN1SRC=ifdef(`confMAN1SRC', `confMAN1SRC', `0')
-MAN5= ${MANROOT}ifdef(`confMAN5', `confMAN5', `5')
-MAN5EXT=ifdef(`confMAN5EXT', `confMAN5EXT', `5')
-MAN5SRC=ifdef(`confMAN5SRC', `confMAN5SRC', `0')
-MAN8= ${MANROOT}ifdef(`confMAN8', `confMAN8', `8')
-MAN8EXT=ifdef(`confMAN8EXT', `confMAN8EXT', `8')
-MAN8SRC=ifdef(`confMAN8SRC', `confMAN8SRC', `0')
-
-ALL= sendmail sendmail.st aliases.${MAN5SRC} mailq.${MAN1SRC} newaliases.${MAN1SRC} sendmail.${MAN8SRC}
-
-all: ${ALL}
-
-sendmail: ${BEFORE} ${OBJS}
- ${CC} -o sendmail ${LDOPTS} ${LIBDIRS} ${OBJS} ${LIBS}
-
-undivert(3)
-
-sendmail.st:
- cp /dev/null sendmail.st
-
-aliases.${MAN5SRC}: aliases.5
- ${NROFF} ${MANDOC} aliases.5 > aliases.${MAN5SRC}
-
-mailq.${MAN1SRC}: mailq.1
- ${NROFF} ${MANDOC} mailq.1 > mailq.${MAN1SRC}
-
-newaliases.${MAN1SRC}: newaliases.1
- ${NROFF} ${MANDOC} newaliases.1 > newaliases.${MAN1SRC}
-
-sendmail.${MAN8SRC}: sendmail.8
- ${NROFF} ${MANDOC} sendmail.8 > sendmail.${MAN8SRC}
-
-install: install-sendmail install-docs
-
-install-sendmail: sendmail
- ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} sendmail ${BINDIR}
- for i in ${LINKS}; do rm -f $$i; ln -s ${BINDIR}/sendmail $$i; done
- ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 444 sendmail.hf \
- ${HFDIR}/sendmail.hf
- ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 644 sendmail.st \
- ${STDIR}/sendmail.st
-
-install-docs: aliases.${MAN5SRC} mailq.${MAN1SRC} newaliases.${MAN1SRC} sendmail.${MAN8SRC}
-ifdef(`confNO_MAN_INSTALL', `dnl',
-` ${INSTALL} -c -o ${MANOWN} -g ${MANGRP} -m ${MANMODE} sendmail.${MAN8SRC} ${MAN8}/sendmail.${MAN8EXT}
- ${INSTALL} -c -o ${MANOWN} -g ${MANGRP} -m ${MANMODE} aliases.${MAN5SRC} ${MAN5}/aliases.${MAN5EXT}
- ${INSTALL} -c -o ${MANOWN} -g ${MANGRP} -m ${MANMODE} mailq.${MAN1SRC} ${MAN1}/mailq.${MAN1EXT}
- ${INSTALL} -c -o ${MANOWN} -g ${MANGRP} -m ${MANMODE} newaliases.${MAN1SRC} ${MAN1}/newaliases.${MAN1EXT}')
-
-clean:
- rm -f ${OBJS} sendmail aliases.${MAN5SRC} mailq.${MAN1SRC} newaliases.${MAN1SRC} sendmail.${MAN8SRC}
-
-################ Dependency scripts
-include(confBUILDTOOLSDIR/M4/depend/ifdef(`confDEPEND_TYPE', `confDEPEND_TYPE', `generic').m4)dnl
-################ End of dependency scripts
diff --git a/src/README b/src/README
deleted file mode 100644
index 7106e8c..0000000
--- a/src/README
+++ /dev/null
@@ -1,1464 +0,0 @@
-# Copyright (c) 1998 Sendmail, Inc. All rights reserved.
-# Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
-# Copyright (c) 1988
-# The Regents of the University of California. All rights reserved.
-#
-# By using this file, you agree to the terms and conditions set
-# forth in the LICENSE file which can be found at the top level of
-# the sendmail distribution.
-#
-#
-# @(#)README 8.211 (Berkeley) 2/2/1999
-#
-
-This directory contains the source files for sendmail(TM).
-
-*********************
-!! DO NOT USE MAKE !! in this directory to compile sendmail --
-********************* instead, use the "Build" script located in
-the src directory. It will build an appropriate Makefile, and
-create an appropriate obj.* subdirectory so that multiplatform
-support works easily.
-
- **********************************************************
- ** Read below for more details on building sendmail. **
- **********************************************************
-
-**************************************************************************
-** IMPORTANT: Read the appropriate paragraphs in the section on **
-** ``Operating System and Compile Quirks''. **
-**************************************************************************
-
-For detailed instructions, please read the document ../doc/op/op.me:
-
- eqn ../doc/op/op.me | pic | ditroff -me
-
-Sendmail is a trademark of Sendmail, Inc.
-
-
-+-------------------+
-| BUILDING SENDMAIL |
-+-------------------+
-
-By far, the easiest way to compile sendmail is to use the "Build"
-script:
-
- sh Build
-
-This uses the "uname" command to figure out what architecture you are
-on and creates a proper Makefile accordingly. It also creates a
-subdirectory per object format, so that multiarchitecture support is
-easy. In general this should be all you need. IRIX 6.x users should
-read the note below in the OPERATING SYSTEM AND COMPILE QUIRKS section.
-
-If you need to look at other include or library directories, use the
--I or -L flags on the command line, e.g.,
-
- sh Build -I/usr/sww/include -L/usr/sww/lib
-
-It's also possible to create local site configuration in the file
-site.config.m4 (or another file settable with the -f flag). This
-file contains M4 definitions for various compilation values; the
-most useful are:
-
-confMAPDEF -D flags to specify database types to be included
- (see below)
-confENVDEF -D flags to specify other environment information
-confINCDIRS -I flags for finding include files during compilation
-confLIBDIRS -L flags for finding libraries during linking
-confLIBS -l flags for selecting libraries during linking
-confLDOPTS other ld(1) linker options
-
-Others can be found by examining Makefile.m4. Please read
-../BuildTools/README for more information about the site.config.m4
-file.
-
-You can recompile from scratch using the -c flag with the Build
-command. This removes the existing compilation directory for the
-current platform and builds a new one.
-
-Porting to a new Unix-based system should be a matter of creating
-an appropriate configuration file in the BuildTools/OS/ directory.
-
-
-
-+----------------------+
-| DATABASE DEFINITIONS |
-+----------------------+
-
-There are several database formats that can be used for the alias files
-and for general maps. When used for alias files they interact in an
-attempt to be backward compatible.
-
-The options are:
-
-NEWDB The new Berkeley DB package. Some systems (e.g., BSD/OS and
- Digital UNIX 4.0) have some version of this package
- pre-installed. If your system does not have Berkeley DB
- pre-installed, or the version installed is not version 2.0
- or greater (e.g., is Berkeley DB 1.85 or 1.86), get the
- current version from http://www.sleepycat.com/. DO NOT
- use a version from any of the University of California,
- Berkeley "Net" or other distributions. If you are still
- running BSD/386 1.x, you will need to upgrade the included
- Berkeley DB library to a current version. NEWDB is included
- automatically if the Build script can find a library named
- libdb.a.
-NDBM The older NDBM implementation -- the very old V7 DBM
- implementation is no longer supported.
-NIS Network Information Services. To use this you must have
- NIS support on your system.
-NISPLUS NIS+ (the revised NIS released with Solaris 2). You must
- have NIS+ support on your system to use this flag.
-HESIOD Support for Hesiod (from the DEC/Athena distribution). You
- must already have Hesiod support on your system for this to
- work. You may be able to get this to work with the MIT/Athena
- version of Hesiod, but that's likely to be a lot of work.
-LDAPMAP Lightweight Directory Lookup Protocol support. You will
- have to install the UMich or OpenLDAP ldap and lber
- libraries to use this flag.
-MAP_REGEX Regular Expression support. You will need to use an
- operating system which comes with the POSIX regex()
- routines or install a regexp library such as libregex from
- the Free Software Foundation.
-
->>> NOTE WELL for NEWDB support: If you want to get ndbm support, for
->>> Berkeley DB versions under 2.0, it is CRITICAL that you remove
->>> ndbm.o from libdb.a before you install it and DO NOT install ndbm.h;
->>> for Berkeley DB versions 2.0 through 2.3.14, remove dbm.o from libdb.a
->>> before you install it. If you don't delete these, there is absolutely
->>> no point to including -DNDBM, since it will just get you another
->>> (inferior) API to the same format database. These files OVERRIDE
->>> calls to ndbm routines -- in particular, if you leave ndbm.h in,
->>> you can find yourself using the new db package even if you don't
->>> define NEWDB. Berkeley DB versions later than 2.3.14 do not need
->>> to be modified. Please also consult the README in the top level
->>> directory of the sendmail distribution for other important information.
->>>
->>> Further note: DO NOT remove your existing /usr/include/ndbm.h --
->>> you need that one. But do not install an updated ndbm.h in
->>> /usr/include, /usr/local/include, or anywhere else.
-
-If NEWDB and NDBM are defined (but not NIS), then sendmail will read
-NDBM format alias files, but the next time a newaliases is run the
-format will be converted to NEWDB; that format will be used forever
-more. This is intended as a transition feature.
-
-If NEWDB, NDBM, and NIS are all defined and the name of the file includes
-the string "/yp/", sendmail will rebuild BOTH the NEWDB and NDBM format
-alias files. However, it will only read the NEWDB file; the NDBM format
-file is used only by the NIS subsystem. This is needed because the NIS
-maps on an NIS server are built directly from the NDBM files.
-
-If NDBM and NIS are defined (regardless of the definition of NEWDB),
-and the filename includes the string "/yp/", sendmail adds the special
-tokens "YP_LAST_MODIFIED" and "YP_MASTER_NAME", both of which are
-required if the NDBM file is to be used as an NIS map.
-
-All of these flags are normally defined in the DBMDEF line in the
-Makefile.
-
-If you define NEWDB or HESIOD you get the User Database (USERDB)
-automatically. Generally you do want to have NEWDB for it to do
-anything interesting. See above for getting the Berkeley DB
-package (i.e., NEWDB). There is no separate "user database"
-package -- don't bother searching for it on the net.
-
-Hesiod and LDAP require libraries that may not be installed with your
-system. These are outside of my ability to provide support. See the
-"Quirks" section for more information.
-
-The regex map can be used to see if an address matches a certain regular
-expression. For example, all-numerics local parts are common spam
-addresses, so "^[0-9]+$" would match this. By using such a map in a
-check_* rule-set, you can block a certain range of addresses that would
-otherwise be considered valid.
-
-+---------------+
-| COMPILE FLAGS |
-+---------------+
-
-Wherever possible, I try to make sendmail pull in the correct
-compilation options needed to compile on various environments based on
-automatically defined symbols. Some machines don't seem to have useful
-symbols available, requiring that a compilation flag be defined in
-the Makefile; see the Buildtools/OS subdirectory for the supported
-architectures.
-
-If you are a system to which sendmail has already been ported you
-should not have to touch the following symbols. But if you are porting,
-you may have to tweak the following compilation flags in conf.h in order
-to get it to compile and link properly:
-
-SYSTEM5 Adjust for System V (not necessarily Release 4).
-SYS5SIGNALS Use System V signal semantics -- the signal handler
- is automatically dropped when the signal is caught.
- If this is not set, use POSIX/BSD semantics, where the
- signal handler stays in force until an exec or an
- explicit delete. Implied by SYSTEM5.
-SYS5SETPGRP Use System V setpgrp() semantics. Implied by SYSTEM5.
-HASFCHMOD Define this to one if you have the fchmod(2) system call.
- This improves security.
-HASFLOCK Set this if you prefer to use the flock(2) system call
- rather than using fcntl-based locking. Fcntl locking
- has some semantic gotchas, but many vendor systems
- also interface it to lockd(8) to do NFS-style locking.
- Unfortunately, may vendors implementations of fcntl locking
- is just plain broken (e.g., locks are never released,
- causing your sendmail to deadlock; when the kernel runs
- out of locks your system crashes). For this reason, I
- recommend always defining this unless you are absolutely
- certain that your fcntl locking implementation really works.
-HASUNAME Set if you have the "uname" system call. Implied by
- SYSTEM5.
-HASUNSETENV Define this if your system library has the "unsetenv"
- subroutine.
-HASSETSID Define this if you have the setsid(2) system call. This
- is implied if your system appears to be POSIX compliant.
-HASINITGROUPS Define this if you have the initgroups(3) routine.
-HASSETVBUF Define this if you have the setvbuf(3) library call.
- If you don't, setlinebuf will be used instead. This
- defaults on if your compiler defines __STDC__.
-HASSETREUID Define this if you have setreuid(2) ***AND*** root can
- use setreuid to change to an arbitrary user. This second
- condition is not satisfied on AIX 3.x. You may find that
- your system has setresuid(2), (for example, on HP-UX) in
- which case you will also have to #define setreuid(r, e)
- to be the appropriate call. Some systems (such as Solaris)
- have a compatibility routine that doesn't work properly,
- but may have "saved user ids" properly implemented so you
- can ``#define setreuid(r, e) seteuid(e)'' and have it work.
- The important thing is that you have a call that will set
- the effective uid independently of the real or saved uid
- and be able to set the effective uid back again when done.
- There's a test program in ../test/t_setreuid.c that will
- try things on your system. Setting this improves the
- security, since sendmail doesn't have to read .forward
- and :include: files as root. There are certain attacks
- that may be unpreventable without this call.
-USESETEUID Define this to 1 if you have a seteuid(2) system call that
- will allow root to set only the effective user id to an
- arbitrary value ***AND*** you have saved user ids. This is
- preferable to HASSETREUID if these conditions are fulfilled.
- These are the semantics of the to-be-released revision of
- Posix.1. The test program ../test/t_seteuid.c will try
- this out on your system. If you define both HASSETREUID
- and USESETEUID, the former is ignored.
-HASLSTAT Define this if you have symbolic links (and thus the
- lstat(2) system call). This improves security. Unlike
- most other options, this one is on by default, so you
- need to #undef it in conf.h if you don't have symbolic
- links (these days everyone does).
-HASSETRLIMIT Define this to 1 if you have the setrlimit(2) syscall.
- You can define it to 0 to force it off. It is assumed
- if you are running a BSD-like system.
-HASULIMIT Define this if you have the ulimit(2) syscall (System V
- style systems). HASSETRLIMIT overrides, as it is more
- general.
-HASWAITPID Define this if you have the waitpid(2) syscall.
-HASGETDTABLESIZE
- Define this if you have the getdtablesize(2) syscall.
-HAS_ST_GEN Define this to 1 if your system has the st_gen field in
- the stat structure (see stat(2)).
-USESTRERROR Define this if you have the libc strerror function (which
- should be declared in <errno.h>), and it should be used
- instead of sys_errlist.
-NEEDGETOPT Define this if you need a reimplementation of getopt(3).
- On some systems, getopt does very odd things if called
- to scan the arguments twice. This flag will ask sendmail
- to compile in a local version of getopt that works
- properly.
-NEEDSTRTOL Define this if your standard C library does not define
- strtol(3). This will compile in a local version.
-NEEDVPRINTF Define this if your standard C library does not define
- vprintf(3). Note that the resulting fake implementation
- is not very elegant and may not even work on some
- architectures.
-NEEDFSYNC Define this if your standard C library does not define
- fsync(2). This will try to simulate the operation using
- fcntl(2); if that is not available it does nothing, which
- isn't great, but at least it compiles and runs.
-HASGETUSERSHELL Define this to 1 if you have getusershell(3) in your
- standard C library. If this is not defined, or is defined
- to be 0, sendmail will scan the /etc/shells file (no
- NIS-style support, defaults to /bin/sh and /bin/csh if
- that file does not exist) to get a list of unrestricted
- user shells. This is used to determine whether users
- are allowed to forward their mail to a program or a file.
-NEEDPUTENV Define this if your system needs am emulation of the
- putenv(3) call. Define to 1 to implement it in terms
- of setenv(3) or to 2 to do it in terms of primitives.
-NOFTRUNCATE Define this if you don't have the ftruncate(2) syscall.
- If you don't have this system call, there is an unavoidable
- race condition that occurs when creating alias databases.
-GIDSET_T The type of entries in a gidset passed as the second
- argument to getgroups(2). Historically this has been an
- int, so this is the default, but some systems (such as
- IRIX) pass it as a gid_t, which is an unsigned short.
- This will make a difference, so it is important to get
- this right! However, it is only an issue if you have
- group sets.
-SLEEP_T The type returned by the system sleep() function.
- Defaults to "unsigned int". Don't worry about this
- if you don't have compilation problems.
-ARBPTR_T The type of an arbitrary pointer -- defaults to "void *".
- If you are an very old compiler you may need to define
- this to be "char *".
-SOCKADDR_LEN_T The type used for the third parameter to accept(2),
- getsockname(2), and getpeername(2), representing the
- length of a struct sockaddr. Defaults to int.
-SOCKOPT_LEN_T The type used for the fifth parameter to getsockopt(2)
- and setsockopt(2), representing the length of the option
- buffer. Defaults to int.
-LA_TYPE The type of load average your kernel supports. These
- can be one of:
- LA_ZERO (1) -- it always returns the load average as
- "zero" (and does so on all architectures).
- LA_INT (2) to read /dev/kmem for the symbol avenrun and
- interpret as a long integer.
- LA_FLOAT (3) same, but interpret the result as a floating
- point number.
- LA_SHORT (6) to interpret as a short integer.
- LA_SUBR (4) if you have the getloadavg(3) routine in your
- system library.
- LA_MACH (5) to use MACH-style load averages (calls
- processor_set_info()),
- LA_PROCSTR (7) to read /proc/loadavg and interpret it
- as a string representing a floating-point
- number (Linux-style).
- LA_READKSYM (8) is an implementation suitable for some
- versions of SVr4 that uses the MIOC_READKSYM ioctl
- call to read /dev/kmem.
- LA_DGUX (9) is a special implementation for DG/UX that uses
- the dg_sys_info system call.
- LA_HPUX (10) is an HP-UX specific version that uses the
- pstat_getdynamic system call.
- LA_IRIX6 (11) is an IRIX 6.x specific version that adapts
- to 32 or 64 bit kernels; it is otherwise very similar
- to LA_INT.
- LA_KSTAT (12) uses the (Solaris-specific) kstat(3k)
- implementation.
- LA_DEVSHORT (13) reads a short from a system file (default:
- /dev/table/avenrun) and scales it in the same manner
- as LA_SHORT.
- LA_INT, LA_SHORT, LA_FLOAT, and LA_READKSYM have several
- other parameters that they try to divine: the name of your
- kernel, the name of the variable in the kernel to examine,
- the number of bits of precision in a fixed point load average,
- and so forth. LA_DEVSHORT uses _PATH_AVENRUN to find the
- device to be read to find the load average.
- In desperation, use LA_ZERO. The actual code is in
- conf.c -- it can be tweaked if you are brave.
-FSHIFT For LA_INT, LA_SHORT, and LA_READKSYM, this is the number
- of bits of load average after the binary point -- i.e.,
- the number of bits to shift right in order to scale the
- integer to get the true integer load average. Defaults to 8.
-_PATH_UNIX The path to your kernel. Needed only for LA_INT, LA_SHORT,
- and LA_FLOAT. Defaults to "/unix" on System V, "/vmunix"
- everywhere else.
-LA_AVENRUN For LA_INT, LA_SHORT, and LA_FLOAT, the name of the kernel
- variable that holds the load average. Defaults to "avenrun"
- on System V, "_avenrun" everywhere else.
-SFS_TYPE Encodes how your kernel can locate the amount of free
- space on a disk partition. This can be set to SFS_NONE
- (0) if you have no way of getting this information,
- SFS_USTAT (1) if you have the ustat(2) system call,
- SFS_4ARGS (2) if you have a four-argument statfs(2)
- system call (and the include file is <sys/statfs.h>),
- SFS_VFS (3), SFS_MOUNT (4), SFS_STATFS (5) if you have
- the two-argument statfs(2) system call with includes in
- <sys/vfs.h>, <sys/mount.h>, or <sys/statfs.h> respectively,
- or SFS_STATVFS (6) if you have the two-argument statvfs(2)
- call. The default if nothing is defined is SFS_NONE.
-SFS_BAVAIL with SFS_4ARGS you can also set SFS_BAVAIL to the field name
- in the statfs structure that holds the useful information;
- this defaults to f_bavail.
-SPT_TYPE Encodes how your system can display what a process is doing
- on a ps(1) command (SPT stands for Set Process Title). Can
- be set to:
- SPT_NONE (0) -- Don't try to set the process title at all.
- SPT_REUSEARGV (1) -- Pad out your argv with the information;
- this is the default if none specified.
- SPT_BUILTIN (2) -- The system library has setproctitle.
- SPT_PSTAT (3) -- Use the PSTAT_SETCMD option to pstat(2)
- to set the process title; this is used by HP-UX.
- SPT_PSSTRINGS (4) -- Use the magic PS_STRINGS pointer (4.4BSD).
- SPT_SYSMIPS (5) -- Use sysmips() supported by NEWS-OS 6.
- SPT_SCO (6) -- Write kernel u. area.
- SPT_CHANGEARGV (7) -- Write pointers to our own strings into
- the existing argv vector.
-SPT_PADCHAR Character used to pad the process title; if undefined,
- the space character (0x20) is used. This is ignored if
- SPT_TYPE != SPT_REUSEARGV
-ERRLIST_PREDEFINED
- If set, assumes that some header file defines sys_errlist.
- This may be needed if you get type conflicts on this
- variable -- otherwise don't worry about it.
-WAITUNION The wait(2) routine takes a "union wait" argument instead
- of an integer argument. This is for compatibility with
- old versions of BSD.
-SCANF You can set this to extend the F command to accept a
- scanf string -- this gives you a primitive parser for
- class definitions -- BUT it can make you vulnerable to
- core dumps if the target file is poorly formed.
-SYSLOG_BUFSIZE You can define this to be the size of the buffer that
- syslog accepts. If it is not defined, it assumes a
- 1024-byte buffer. If the buffer is very small (under
- 256 bytes) the log message format changes -- each
- e-mail message will log many more messages, since it
- will log each piece of information as a separate line
- in syslog.
-BROKEN_RES_SEARCH
- On Ultrix (and maybe other systems?) if you use the
- res_search routine with an unknown host name, it returns
- -1 but sets h_errno to 0 instead of HOST_NOT_FOUND. If
- you set this, sendmail considers 0 to be the same as
- HOST_NOT_FOUND.
-NAMELISTMASK If defined, values returned by nlist(3) are masked
- against this value before use -- a common value is
- 0x7fffffff to strip off the top bit.
-BSD4_4_SOCKADDR If defined, socket addresses have an sa_len field that
- defines the length of this address.
-SAFENFSPATHCONF Set this to 1 if and only if you have verified that a
- pathconf(2) call with _PC_CHOWN_RESTRICTED argument on an
- NFS filesystem where the underlying system allows users to
- give away files to other users returns <= 0. Be sure you
- try both on NFS V2 and V3. Some systems assume that their
- local policy apply to NFS servers -- this is a bad
- assumption! The test/t_pathconf.c program will try this
- for you -- you have to run it in a directory that is
- mounted from a server that allows file giveaway.
-SIOCGIFCONF_IS_BROKEN
- Set this if your system has an SIOCGIFCONF ioctl defined,
- but it doesn't behave the same way as "most" systems (BSD,
- Solaris, SunOS, HP-UX, etc.)
-SIOCGIFNUM_IS_BROKEN
- Set this if your system has an SIOCGIFNUM ioctl defined,
- but it doesn't behave the same way as "most" systems
- (Solaris, HP-UX).
-NEED_PERCENTQ Set this if your system doesn't support the printf
- format strings %lld or %llu. If this is set, %qd and
- %qu are used instead.
-
-
-
-+-----------------------+
-| COMPILE-TIME FEATURES |
-+-----------------------+
-
-There are a bunch of features that you can decide to compile in, such
-as selecting various database packages and special protocol support.
-Several are assumed based on other compilation flags -- if you want to
-"un-assume" something, you probably need to edit conf.h. Compilation
-flags that add support for special features include:
-
-NDBM Include support for "new" DBM library for aliases and maps.
- Normally defined in the Makefile.
-NEWDB Include support for Berkeley DB package (hash & btree)
- for aliases and maps. Normally defined in the Makefile.
- If the version of NEWDB you have is the old one that does
- not include the "fd" call (this call was added in version
- 1.5 of the Berkeley DB code), you must upgrade to the
- current version of Berkeley DB.
-NIS Define this to get NIS (YP) support for aliases and maps.
- Normally defined in the Makefile.
-NISPLUS Define this to get NIS+ support for aliases and maps.
- Normally defined in the Makefile.
-HESIOD Define this to get Hesiod support for aliases and maps.
- Normally defined in the Makefile.
-NETINFO Define this to get NeXT NetInfo support for aliases and maps.
- Normally defined in the Makefile.
-USERDB Define this to 1 to include support for the User Information
- Database. Implied by NEWDB or HESIOD. You can use
- -DUSERDB=0 to explicitly turn it off.
-IDENTPROTO Define this as 1 to get IDENT (RFC 1413) protocol support.
- This is assumed unless you are running on Ultrix or
- HP-UX, both of which have a problem in the UDP
- implementation. You can define it to be 0 to explicitly
- turn off IDENT protocol support. If defined off, the code
- is actually still compiled in, but it defaults off; you
- can turn it on by setting the IDENT timeout to 30s in the
- configuration file.
-IP_SRCROUTE Define this to 1 to get IP source routing information
- displayed in the Received: header. This is assumed on
- most systems, but some (e.g., Ultrix) apparently have a
- broken version of getsockopt that doesn't properly
- support the IP_OPTIONS call. You probably want this if
- your OS can cope with it. Symptoms of failure will be that
- it won't compile properly (that is, no support for fetching
- IP_OPTIONs), or it compiles but source-routed TCP connections
- either refuse to open or open and hang for no apparent reason.
- Ultrix and AIX3 are known to fail this way.
-LOG Set this to get syslog(3) support. Defined by default
- in conf.h. You want this if at all possible.
-NETINET Set this to get TCP/IP support. Defined by default
- in conf.h. You probably want this.
-NETISO Define this to get ISO networking support.
-NETUNIX Define this to get Unix domain networking support. Defined
- by default. A few bizarre systems (SCO, ISC, Altos) don't
- support this networking domain.
-SMTP Define this to get the SMTP code. Implied by NETINET
- or NETISO.
-NAMED_BIND If non-zero, include DNS (name daemon) support, including
- MX support. The specs say you must use this if you run
- SMTP. You don't have to be running a name server daemon
- on your machine to need this -- any use of the DNS resolver,
- including remote access to another machine, requires this
- option. Defined by default in conf.h. Define it to zero
- ONLY on machines that do not use DNS in any way.
-QUEUE Define this to get queueing code. Implied by NETINET
- or NETISO; required by SMTP. This gives you other good
- stuff -- it should be on.
-DAEMON Define this to get general network support. Implied by
- NETINET or NETISO. Defined by default in conf.h. You
- almost certainly want it on.
-MATCHGECOS Permit fuzzy matching of user names against the full
- name (GECOS) field in the /etc/passwd file. This should
- probably be on, since you can disable it from the config
- file if you want to. Defined by default in conf.h.
-MIME8TO7 If non-zero, include 8 to 7 bit MIME conversions. This
- also controls advertisement of 8BITMIME in the ESMTP
- startup dialogue.
-MIME7TO8 If non-zero, include 7 to 8 bit MIME conversions.
-HES_GETMAILHOST Define this to 1 if you are using Hesiod with the
- hes_getmailhost() routine. This is included with the MIT
- Hesiod distribution, but not with the DEC Hesiod distribution.
-XDEBUG Do additional internal checking. These don't cost too
- much; you might as well leave this on.
-TCPWRAPPERS Turns on support for the TCP wrappers library (-lwrap).
- See below for further information.
-SECUREWARE Enable calls to the SecureWare luid enabling/changing routines.
- SecureWare is a C2 security package added to several UNIX's
- (notably ConvexOS) to get a C2 Secure system. This
- option causes mail delivery to be done with the luid of the
- recipient.
-SHARE_V1 Support for the fair share scheduler, version 1. Setting to
- 1 causes final delivery to be done using the recipients
- resource limitations. So far as I know, this is only
- supported on ConvexOS.
-
-
-+---------------------+
-| DNS/RESOLVER ISSUES |
-+---------------------+
-
-Many systems have old versions of the resolver library. At a minimum,
-you should be running BIND 4.8.3; older versions may compile, but they
-have known bugs that should give you pause.
-
-Common problems in old versions include "undefined" errors for
-dn_skipname.
-
-Some people have had a problem with BIND 4.9; it uses some routines
-that it expects to be externally defined such as strerror(). It may
-help to link with "-l44bsd" to solve this problem. This has apparently
-been fixed in later versions of BIND, starting around 4.9.3. In other
-words, if you use 4.9.0 through 4.9.2, you need -l44bsd; for earlier or
-later versions, you do not.
-
-!PLEASE! be sure to link with the same version of the resolver as
-the header files you used -- some people have used the 4.9 headers
-and linked with BIND 4.8 or vice versa, and it doesn't work.
-Unfortunately, it doesn't fail in an obvious way -- things just
-subtly don't work.
-
-WILDCARD MX RECORDS ARE A BAD IDEA! The only situation in which they
-work reliably is if you have two versions of DNS, one in the real world
-which has a wildcard pointing to your firewall, and a completely
-different version of the database internally that does not include
-wildcard MX records that match your domain. ANYTHING ELSE WILL GIVE
-YOU HEADACHES!
-
-
-+-------------------------------------+
-| OPERATING SYSTEM AND COMPILE QUIRKS |
-+-------------------------------------+
-
-GCC problems
- *****************************************************************
- ** IMPORTANT: DO NOT USE OPTIMIZATION (``-O'') IF YOU ARE **
- ** RUNNING GCC 2.4.x or 2.5.x. THERE IS A BUG IN THE GCC **
- ** OPTIMIZER THAT CAUSES SENDMAIL COMPILES TO FAIL MISERABLY. **
- *****************************************************************
-
- Jim Wilson of Cygnus believes he has found the problem -- it will
- probably be fixed in GCC 2.5.6 -- but until this is verified, be
- very suspicious of gcc -O. This problem is reported to have been
- fixed in gcc 2.6.
-
- A bug in gcc 2.5.5 caused problems compiling sendmail 8.6.5 with
- optimization on a Sparc. If you are using gcc 2.5.5, youi should
- upgrade to the latest version of gcc.
-
- Apparently GCC 2.7.0 on the Pentium processor has optimization
- problems. I recommend against using -O on that architecture. This
- has been seen on FreeBSD 2.0.5 RELEASE.
-
- Solaris 2.X users should use version 2.7.2.3 over 2.7.2.
-
- We have been told there are problems with gcc 2.8.0. If you are
- using this version, you should upgrade to 2.8.1 or later.
-
-GDBM GDBM does not work with sendmail 8.8 because the additional
- security checks and file locking cause problems. Unfortunately,
- gdbm does not provide a compile flag in its version of ndbm.h so
- the code can adapt. Until the GDBM authors can fix these problems,
- GDBM will not be supported. Please use Berkeley DB instead.
-
-Configuration file location
- Up to 8.6, sendmail tried to find the sendmail.cf file in the same
- place as the vendors had put it, even when this was obviously
- stupid. As of 8.7, sendmail ALWAYS looks for /etc/sendmail.cf.
- Beginning with 8.10, sendmail will use /etc/mail/sendmail.cf.
- You can get sendmail to use the stupid vendor .cf location by
- adding -DUSE_VENDOR_CF_PATH during compilation, but this may break
- support programs and scripts that need to find sendmail.cf. You
- are STRONGLY urged to use symbolic links if you want to use the
- vendor location rather than changing the location in the sendmail
- binary.
-
-SunOS 4.x (Solaris 1.x)
- You may have to use -lresolv on SunOS. However, beware that
- this links in a new version of gethostbyname that does not
- understand NIS, so you must have all of your hosts in DNS.
-
- Some people have reported problems with the SunOS version of
- -lresolv and/or in.named, and suggest that you get a newer
- version. The symptoms are delays when you connect to the
- SMTP server on a SunOS machine or having your domain added to
- addresses inappropriately. There is a version of BIND
- version 4.9 on gatekeeper.DEC.COM in pub/BSD/bind/4.9.
-
- There is substantial disagreement about whether you can make
- this work with resolv+, which allows you to specify a search-path
- of services. Some people report that it works fine, others
- claim it doesn't work at all (including causing sendmail to
- drop core when it tries to do multiple resolv+ lookups for a
- single job). I haven't tried resolv+, as we use DNS exclusively.
-
- Should you want to try resolv+, it is on ftp.uu.net in
- /networking/ip/dns.
-
- Apparently getservbyname() can fail under moderate to high
- load under some circumstances. This will exhibit itself as
- the message ``554 makeconnection: service "smtp" unknown''.
- The problem has been traced to one or more blank lines in
- /etc/services on the NIS server machine. Delete these
- and it should work. This info is thanks to Brian Bartholomew
- <bb@math.ufl.edu> of I-Kinetics, Inc.
-
-SunOS 4.0.2 (Sun 386i)
- Date: Fri, 25 Aug 1995 11:13:58 +0200 (MET DST)
- From: teus@oce.nl
-
- Sendmail 8.7.Beta.12 compiles and runs nearly out of the box with the
- following changes:
- * Don't use /usr/5bin in your PATH, but make /usr/5bin/uname
- available as "uname" command.
- * Use the defines "-DBSD4_3 -DNAMED_BIND=0" in
- BuildTools/OS/SunOS.4.0, which is selected via the "uname" command.
- I recommend to make available the db-library on the system first
- (and change the Makefile to use this library).
- Note that the sendmail.cf and aliases files are found in /etc.
-
-SunOS 4.1.3, 4.1.3_U1
- Sendmail causes crashes on SunOS 4.1.3 and 4.1.3_U1. According
- to Sun bug number 1077939:
-
- If an application does a getsockopt() on a SOCK_STREAM (TCP) socket
- after the other side of the connection has sent a TCP RESET for
- the stream, the kernel gets a Bus Trap in the tcp_ctloutput() or
- ip_ctloutput() routine.
-
- For 4.1.3, this is fixed in patch 100584-08, available on the
- Sunsolve 2.7.1 or later CDs. For 4.1.3_U1, this was fixed in patch
- 101790-01 (SunOS 4.1.3_U1: TCP socket and reset problems), later
- obsoleted by patch 102010-05.
-
- Sun patch 100584-08 is not currently publicly available on their
- ftp site but a user has reported it can be found at other sites
- using a web search engine.
-
-Solaris 2.x (SunOS 5.x)
- To compile for Solaris, the Makefile built by Build must
- include a SOLARIS definition which reflects the Solaris version
- (i.e. -DSOLARIS=20400 for 2.4 or -DSOLARIS=20501 for 2.5.1).
- If you are using gcc, make sure -I/usr/include is not used (or
- it might complain about TopFrame). If you are using Sun's cc,
- make sure /opt/SUNWspro/bin/cc is used instead of /usr/ucb/cc
- (or it might complain about tm_zone).
-
- To the best of my knowledge, Solaris does not have the
- gethostbyname problem described above. However, it does
- have another one:
-
- From a correspondent:
-
- For solaris 2.2, I have
-
- hosts: files dns
-
- in /etc/nsswitch.conf and /etc/hosts has to have the fully
- qualified host name. I think "files" has to be before "dns"
- in /etc/nsswitch.conf during bootup.
-
- From another correspondent:
-
- When running sendmail under Solaris, the gethostbyname()
- hack in conf.c which should perform proper canonicalization
- of host names could fail. Result: the host name is not
- canonicalized despite the hack, and you'll have to define $j
- and $m in sendmail.cf somewhere.
-
- The reason could be that /etc/nsswitch.conf is improperly
- configured (at least from sendmail's point of view). For
- example, the line
-
- hosts: files nisplus dns
-
- will make gethostbyname() look in /etc/hosts first, then ask
- nisplus, then dns. However, if /etc/hosts does not contain
- the full canonicalized hostname, then no amount of
- gethostbyname()s will work.
-
- Solution (or rather, a workaround): Ask nisplus first, then
- dns, then local files:
-
- hosts: nisplus dns [NOTFOUND=return] files
-
- The Solaris "syslog" function is apparently limited to something
- about 90 characters because of a kernel limitation. If you have
- source code, you can probably up this number. You can get patches
- that fix this problem: the patch ids are:
-
- Solaris 2.1 100834
- Solaris 2.2 100999
- Solaris 2.3 101318
-
- Be sure you have the appropriate patch installed or you won't
- see system logging.
-
-Solaris 2.4 (SunOS 5.4)
- If you include /usr/lib at the end of your LD_LIBRARY_PATH you run
- the risk of getting the wrong libraries under some circumstances.
- This is because of a new feature in Solaris 2.4, described by
- Rod.Evans@Eng.Sun.COM:
-
- >> Prior to SunOS 5.4, any LD_LIBRARY_PATH setting was ignored by the
- >> runtime linker if the application was setxid (secure), thus your
- >> applications search path would be:
- >>
- >> /usr/local/lib LD_LIBRARY_PATH component - IGNORED
- >> /usr/lib LD_LIBRARY_PATH component - IGNORED
- >> /usr/local/lib RPATH - honored
- >> /usr/lib RPATH - honored
- >>
- >> the effect is that path 3 would be the first used, and this would
- >> satisfy your resolv.so lookup.
- >>
- >> In SunOS 5.4 we made the LD_LIBRARY_PATH a little more flexible.
- >> People who developed setxid applications wanted to be able to alter
- >> the library search path to some degree to allow for their own
- >> testing and debugging mechanisms. It was decided that the only
- >> secure way to do this was to allow a `trusted' path to be used in
- >> LD_LIBRARY_PATH. The only trusted directory we presently define
- >> is /usr/lib. Thus a setuid root developer could play with some
- >> alternative shared object implementations and place them in
- >> /usr/lib (being root we assume they'ed have access to write in this
- >> directory). This change was made as part of 1155380 - after a
- >> *huge* amount of discussion regarding the security aspect of things.
- >>
- >> So, in SunOS 5.4 your applications search path would be:
- >>
- >> /usr/local/lib from LD_LIBRARY_PATH - IGNORED (untrustworthy)
- >> /usr/lib from LD_LIBRARY_PATH - honored (trustworthy)
- >> /usr/local/lib from RPATH - honored
- >> /usr/lib from RPATH - honored
- >>
- >> here, path 2 would be the first used.
-
-Solaris 2.6 (SunOS 5.6)
- If you built sendmail 8.8.1 through 8.8.4 inclusive on a Solaris 2.5
- system, that binary will not run on Solaris 2.6, due to problems with
- incompatible snprintf(3s) calls. This problem is fixed in sendmail
- 8.8.5.
-
-Solaris 2.5.1 (SunOS 5.5.1) and 2.6 (SunOS 5.6)
- Apparently Solaris 2.5.1 patch 103663-01 installs a new
- /usr/include/resolv.h file that defines the __P macro without
- checking to see if it is already defined. This new resolv.h is also
- included in the Solaris 2.6 distribution. This causes compile
- warnings such as:
-
- In file included from daemon.c:51:
- /usr/include/resolv.h:208: warning: `__P' redefined
- cdefs.h:58: warning: this is the location of the previous definition
-
- These warnings can be safely ignored or you can create a resolv.h
- file in the obj.SunOS.5.5.1.* or obj.SunOS.5.6.* directory that reads:
-
- #undef __P
- #include "/usr/include/resolv.h"
-
- Sun is aware of the problem (Sun bug ID 4081053) and it will be fixed
- in Solaris 2.7.
-
-Ultrix
- By default, the IDENT protocol is turned off on Ultrix. If you
- are running Ultrix 4.4 or later, or if you have included patch
- CXO-8919 for Ultrix 4.2 or 4.3 to fix the TCP problem, you can turn
- IDENT on in the configuration file by setting the "ident" timeout
- to 30 seconds.
-
-Digital UNIX (formerly DEC OSF/1)
- If you are compiling on OSF/1 (DEC Alpha), you must use
- -L/usr/shlib (otherwise it core dumps on startup). You may also
- need -mld to get the nlist() function, although some versions
- apparently don't need this.
-
- Also, the enclosed makefile removed /usr/sbin/smtpd; if you need
- it, just create the link to the sendmail binary.
-
- On DEC OSF/1 3.2 or earlier, the MatchGECOS option doesn't work
- properly due to a bug in the getpw* routines. If you want to use
- this, use -DDEC_OSF_BROKEN_GETPWENT=1. The problem is fixed in 3.2C.
-
- Digital's mail delivery agent, /bin/mail (aka /bin/binmail), will
- only preserve the envelope sender in the "From " header if
- DefaultUserID is set to daemon. Setting this to mailnull will
- cause all mail to have the header "From mailnull ...". To use
- a different DefaultUserID, you will need to use a different mail
- delivery agent (such as mail.local found in the sendmail
- distribution).
-
- On Digital UNIX 4.0 and later, Berkeley DB 1.85 is included with the
- operating system and already has the ndbm.o module removed. However,
- Digital has modified the original Berkeley DB db.h include file.
- This results in the following warning while compiling map.c and udb.c:
-
- cc: Warning: /usr/include/db.h, line 74: The redefinition of the macro
- "__signed" conflicts with a current definition because the replacement
- lists differ. The redefinition is now in effect.
- #define __signed signed
- ------------------------^
-
- This warning can be ignored.
-
- Digital UNIX's linker checks /usr/ccs/lib/ before /usr/lib/.
- If you have installed a new version of BIND in /usr/include
- and /usr/lib, you will experience difficulties as Digital ships
- libresolv.a in /usr/ccs/lib/ as well. Be sure to replace both
- copies of libresolv.a.
-
-IRIX
- The header files on SGI IRIX are completely prototyped, and as
- a result you can sometimes get some warning messages during
- compilation. These can be ignored. There are two errors in
- deliver only if you are using gcc, both of the form ``warning:
- passing arg N of `execve' from incompatible pointer type''.
- Also, if you compile with -DNIS, you will get a complaint
- about a declaration of struct dom_binding in a prototype
- when compiling map.c; this is not important because the
- function being prototyped is not used in that file.
-
- In order to compile sendmail you will have had to install
- the developers' option in order to get the necessary include
- files.
-
- If you compile with -lmalloc (the fast memory allocator), you may
- get warning messages such as the following:
-
- ld32: WARNING 85: definition of _calloc in /usr/lib32/libmalloc.so
- preempts that definition in /usr/lib32/mips3/libc.so.
- ld32: WARNING 85: definition of _malloc in /usr/lib32/libmalloc.so
- preempts that definition in /usr/lib32/mips3/libc.so.
- ld32: WARNING 85: definition of _realloc in /usr/lib32/libmalloc.so
- preempts that definition in /usr/lib32/mips3/libc.so.
- ld32: WARNING 85: definition of _free in /usr/lib32/libmalloc.so
- preempts that definition in /usr/lib32/mips3/libc.so.
- ld32: WARNING 85: definition of _cfree in /usr/lib32/libmalloc.so
- preempts that definition in /usr/lib32/mips3/libc.so.
-
- These are unavoidable and innocuous -- just ignore them.
-
- According to Dave Sill <de5@ornl.gov>, there is a version of the
- Berkeley DB library patched to run on Irix 6.2 available from
- http://reality.sgi.com/ariel/freeware/#db .
-
-IRIX 6.x
- It is important that on IRIX 6.x you give used ABI in command
- line of Build, otherwise configuration script does not work
- correctly, e.g.,
-
- sh Build -E ABI=-n32
-
- If you are using XFS filesystem, avoid using ABI=-32 if possible.
-
-NeXT or NEXTSTEP
- NEXTSTEP 3.3 and earlier ship with the old DBM library. Also,
- Berkeley DB does not currently run on NEXTSTEP.
-
- If you are compiling on NEXTSTEP, you will have to create an
- empty file "unistd.h" and create a file "dirent.h" containing:
-
- #include <sys/dir.h>
- #define dirent direct
-
- (BuildTools/OS/NeXT should try to do both of these for you.)
-
- Apparently, there is a bug in getservbyname on Nextstep 3.0
- that causes it to fail under some circumstances with the
- message "SYSERR: service "smtp" unknown" logged. You should
- be able to work around this by including the line:
-
- OOPort=25
-
- in your .cf file.
-
- You may have to use -DNeXT.
-
-BSDI (BSD/386) 1.0, NetBSD 0.9, FreeBSD 1.0
- The "m4" from BSDI won't handle the config files properly.
- I haven't had a chance to test this myself.
-
- The M4 shipped in FreeBSD and NetBSD 0.9 don't handle the config
- files properly. One must use either GNU m4 1.1 or the PD-M4
- recently posted in comp.os.386bsd.bugs (and maybe others).
- NetBSD-current includes the PD-M4 (as stated in the NetBSD file
- CHANGES).
-
- FreeBSD 1.0 RELEASE has uname(2) now. Use -DUSEUNAME in order to
- use it (look into BuildTools/OS/FreeBSD). NetBSD-current may have
- it too but it has not been verified.
-
- The latest version of Berkeley DB uses a different naming
- scheme than the version that is supplied with your release. This
- means you will be able to use the current version of Berkeley DB
- with sendmail as long you use the new db.h when compiling
- sendmail and link it against the new libdb.a. You should probably
- keep the original db.h in /usr/include and the new db.h in
- /usr/local/include.
-
-4.3BSD
- If you are running a "virgin" version of 4.3BSD, you'll have
- a very old resolver and be missing some header files. The
- header files are simple -- create empty versions and everything
- will work fine. For the resolver you should really port a new
- version (4.8.3 or later) of the resolver; 4.9 is available on
- gatekeeper.DEC.COM in pub/BSD/bind/4.9. If you are really
- determined to continue to use your old, buggy version (or as
- a shortcut to get sendmail working -- I'm sure you have the
- best intentions to port a modern version of BIND), you can
- copy ../contrib/oldbind.compat.c into src and add
- oldbind.compat.o to OBJADD in the Makefile.
-
-A/UX
- Date: Tue, 12 Oct 1993 18:28:28 -0400 (EDT)
- From: "Eric C. Hagberg" <hagberg@med.cornell.edu>
- Subject: Fix for A/UX ndbm
-
- I guess this isn't really a sendmail bug, however, it is something
- that A/UX users should be aware of when compiling sendmail 8.6.
-
- Apparently, the calls that sendmail is using to the ndbm routines
- in A/UX 3.0.x contain calls to "broken" routines, in that the
- aliases database will break when it gets "just a little big"
- (sorry I don't have exact numbers here, but it broke somewhere
- around 20-25 aliases for me.), making all aliases non-functional
- after exceeding this point.
-
- What I did was to get the gnu-dbm-1.6 package, compile it, and
- then re-compile sendmail with "-lgdbm", "-DNDBM", and using the
- ndbm.h header file that comes with the gnu-package. This makes
- things behave properly.
- [NOTE: see comment above about GDBM]
-
- I suppose porting the New Berkeley DB package is another route,
- however, I made a quick attempt at it, and found it difficult
- (not easy at least); the gnu-dbm package "configured" and
- compiled easily.
-
- [NOTE: Berkeley DB version 2.X runs on A/UX and can be used for
- database maps.]
-
-SCO Unix
- From: Thomas Essebier <tom@stallion.oz.au>
- Organisation: Stallion Technologies Pty Ltd.
-
- It will probably help those who are trying to configure sendmail 8.6.9
- to know that if they are on SCO, they had better set
- OI-dnsrch
- or they will core dump as soon as they try to use the resolver.
- ie. although SCO has _res.dnsrch defined, and is kinda BIND 4.8.3, it
- does not inititialise it, nor does it understand 'search' in
- /etc/named.boot.
- - sigh -
-
- According to SCO, the m4 which ships with UnixWare 2.1.2 is broken.
- We recommend installing GNU m4 before attempting to build sendmail.
-
-DG/UX
- Doug Anderson <dlander@afterlife.ncsc.mil> has successfully run
- V8 on the DG/UX 5.4.2 and 5.4R3.x platforms under heavy usage.
- Originally, the DG /bin/mail program wasn't compatible with
- the V8 sendmail, since the DG /bin/mail requires the environment
- variable "_FORCE_MAIL_LOCAL_=yes" be set. Version 8.7 now includes
- this in the environment before invoking the local mailer. Some
- have used procmail to avoid this problem in the past. It works
- but some have experienced file locking problems with their DG/UX
- ports of procmail.
-
-Apollo DomainOS
- If you are compiling on Apollo, you will have to create an empty
- file "unistd.h" (for DomainOS 10.3 and earlier) and create a file
- "dirent.h" containing:
-
- #include <sys/dir.h>
- #define dirent direct
-
- (BuildTools/OS/DomainOS will attempt to do both of these for you.)
-
-HP-UX 8.00
- Date: Mon, 24 Jan 1994 13:25:45 +0200
- From: Kimmo Suominen <Kimmo.Suominen@lut.fi>
- Subject: 8.6.5 w/ HP-UX 8.00 on s300
-
- Just compiled and fought with sendmail 8.6.5 on a HP9000/360 (ie. a
- series 300 machine) running HP-UX 8.00.
-
- I was getting segmentation fault when delivering to a local user.
- With debugging I saw it was faulting when doing _free@libc... *sigh*
- It seems the new implementation of malloc on s300 is buggy as of 8.0,
- so I tried out the one in -lmalloc (malloc(3X)). With that it seems
- to work just dandy.
-
- When linking, you will get the following error:
-
- ld: multiply defined symbol _freespace in file /usr/lib/libmalloc.a
-
- but you can just ignore it. You might want to add this info to the
- README file for the future...
-
-Linux
- Something broke between versions 0.99.13 and 0.99.14 of Linux:
- the flock() system call gives errors. If you are running .14,
- you must not use flock. You can do this with -DHASFLOCK=0.
-
- Around the inclusion of bind-4.9.3 & Linux libc-4.6.20, the
- initialization of the _res structure changed. If /etc/hosts.conf
- was configured as "hosts, bind" the resolver code could return
- "Name server failure" errors. This is supposedly fixed in
- later versions of libc (>= 4.6.29?), and later versions of
- sendmail (> 8.6.10) try to work around the problem.
-
- Some older versions (< 4.6.20?) of the libc/include files conflict
- with sendmail's version of cdefs.h. Deleting sendmail's version
- on those systems should be non-harmful, and new versions don't care.
-
- Sendmail assumes that libc has snprintf, which has been true since
- libc 4.7.0. If you are running an older version, you will need to
- use -DHASSNPRINTF=0 in the Makefile. If may be able to use -lbsd
- (which includes snprintf) instead of turning this off on versions
- of libc between 4.4.4 and 4.7.0 (snprintf improves security, so
- you want to use this if at all possible).
-
- NOTE ON LINUX & BIND: By default, the Makefile generated for Linux
- includes header files in /usr/local/include and libraries in
- /usr/local/lib. If you've installed BIND on your system, the header
- files typically end up in the search path and you need to add
- "-lresolv" to the LIBS line in your Makefile. Really old versions
- may need to include "-l44bsd" as well (particularly if the link phase
- complains about missing strcasecmp, strncasecmp or strpbrk).
- Complaints about an undefined reference to `__dn_skipname' in
- domain.o are a sure sign that you need to add -lresolv to LIBS.
- Newer versions of Linux are basically threaded BIND, so you may or
- may not see complaints if you accidentally mix BIND
- headers/libraries with virginal libc. If you have BIND headers in
- /usr/local/include (resolv.h, etc) you *should* be adding -lresolv
- to LIBS. Data structures may change and you'd be asking for a
- core dump.
-
- A number of problems have been reported regarding the Linux 2.2.0
- kernel. So far, these problems have been tracked down to syslog()
- and DNS resolution. We believe the problem is with the poll()
- implementation in the Linux 2.2.0 kernel and poll()-aware versions
- of glib (at least up to 2.0.111).
-
-AIX 4.2
- The AIX m4 implements a different mechanism for ifdef which is
- inconsistent with other versions of m4. Therefore, it will not
- work properly with the sendmail Build architecture or m4
- configuration method. To work around this problem, please use
- GNU m4 from ftp://ftp.gnu.org/pub/gnu/.
-
-AIX 3.x
- This version of sendmail does not support MB, MG, and MR resource
- records, which are supported by AIX sendmail.
-
- Several people have reported that the IBM-supplied named returns
- fairly random results -- the named should be replaced. It is not
- necessary to replace the resolver, which will simplify installation.
- A new BIND resolver can be found at http://www.isc.org/isc/.
-
-AIX 3.1.x
- The supplied load average code only works correctly for AIX 3.2.x.
- For 3.1, use -DLA_TYPE=LA_SUBR and get the latest ``monitor''
- package by Jussi Maki <jmaki@hut.fi> from ftp.funet.fi in the
- directory pub/unix/AIX/rs6000/monitor-1.12.tar.Z; use the loadavgd
- daemon, and the getloadavg subroutine supplied with that package.
- If you don't care about load average throttling, just turn off
- load average checking using -DLA_TYPE=LA_ZERO.
-
-AIX 2.2.1
- Date: Mon Dec 4 14:14:56 CST 1995
- From: Mark Whetzel <markw@antimatr.houston.tx.us>
- Subject: Porting sendmail 8.7.2 to AIX V2 on the RT.
-
- This version of sendmail does not support MB, MG, and MR resource
- records, which are supported by AIX sendmail.
-
- AIX V2 on the RT does not have 'paths.h'. Create a null
- file in the 'obj' directory to remove this compile error.
-
- A patch file is needed to get the BSD 'db' library to compile
- for AIX/RT. I have sent the necessary updates to the author,
- but they may not be immediately available.
- [NOTE: Berkeley DB version 2.X runs on AIX/RT.]
-
- The original AIX/RT resolver libraries are very old, and you
- should get the latest BIND to replace it. The 4.8.3 version
- has been tested, but 4.9.x is out and should work.
-
- To make the load average code work correctly requires an
- external routine, as the kernel does not maintain system
- load averages, similar to AIX V3.1.x. A reverse port of the
- older 1.05 'monitor' load average daemon code written by
- Jussi Maki that will work on AIX V2 for the RT is available
- by E-mail to Mark Whetzel <markw@antimatr.houston.tx.us>.
- That code depends on an external daemon to collect system
- load information, and the external routine 'getloadavg',
- that will return that information. The 'LA_SUBR' define
- will handle this for AIX V2 on the RT.
-
- Note: You will have to change BuildTools/OS/AIX.2 to correctly
- point to the locatons of the updated BIND source tree and
- the location of the 'newdb' tree and library location.
- You will also have to change BuildTools/OS/AIX.2 to know
- about the location of the 'getloadavg' routine if you use
- the LA_SUBR define.
-
-
- Manual pages will format correctly if given the mandoc macros
- and used with nroff. I have not tried groff.
-
-RISC/os
- RISC/os from MIPS is a merged AT&T/Berkeley system. When you
- compile on that platform you will get duplicate definitions
- on many files. You can ignore these.
-
-System V Release 4 Based Systems
- There is a single BuildTools OS that is intended for all SVR4-based
- systems (built from BuildTools/OS/SVR4). It defines __svr4__,
- which is predefined by some compilers. If your compiler already
- defines this compile variable, you can delete the definition from
- the generated Makefile or create a BuildTools/Site/site.config.m4
- file.
-
- It's been tested on Dell Issue 2.2.
-
-DELL SVR4
- Date: Mon, 06 Dec 1993 10:42:29 EST
- From: "Kimmo Suominen" <kim@grendel.lut.fi>
- Message-ID: <2d0352f9.lento29@lento29.UUCP>
- To: eric@cs.berkeley.edu
- Cc: sendmail@cs.berkeley.edu
- Subject: Notes for DELL SVR4
-
- Eric,
-
- Here are some notes for compiling Sendmail 8.6.4 on DELL SVR4. I ran
- across these things when helping out some people who contacted me by
- e-mail.
-
- 1) Use gcc 2.4.5 (or later?). Dell distributes gcc 2.1 with their
- Issue 2.2 Unix. It is too old, and gives you problems with
- clock.c, because sigset_t won't get defined in <sys/signal.h>.
- This is due to a problematic protection rule in there, and is
- fixed with gcc 2.4.5.
-
- 2) If you don't use the new Berkeley DB (-DNEWDB), then you need
- to add "-lc -lucb" to the libraries to link with. This is because
- the -ldbm distributed by Dell needs the bcopy, bcmp and bzero
- functions. It is important that you specify both libraries in
- the given order to be sure you only get the BSTRING functions
- from the UCB library (and not the signal routines etc.).
-
- 3) Don't leave out "-lelf" even if compiling with "-lc -lucb".
- The UCB library also has another copy of the nlist routines,
- but we do want the ones from "-lelf".
-
- If anyone needs a compiled gcc 2.4.5 and/or a ported DB library, they
- can use anonymous ftp to fetch them from lut.fi in the /kim directory.
- They are copies of what I use on grendel.lut.fi, and offering them
- does not imply that I would also support them. I have sent the DB
- port for SVR4 back to Keith Bostic for inclusion in the official
- distribution, but I haven't heard anything from him as of today.
-
- - gcc-2.4.5-svr4.tar.gz (gcc 2.4.5 and the corresponding libg++)
- - db-1.72.tar.gz (with source, objects and a installed copy)
-
- Cheers
- + Kim
- --
- * Kimmo.Suominen@lut.fi * SysVr4 enthusiast at GRENDEL.LUT.FI *
- * KIM@FINFILES.BITNET * Postmaster and Hostmaster at LUT.FI *
- * + 358 200 865 718 * Unix area moderator at NIC.FUNET.FI *
-
-ConvexOS 10.1 and below
- In order to use the name server, you must create the file
- /etc/use_nameserver. If this file does not exist, the call
- to res_init() will fail and you will have absolutely no
- access to DNS, including MX records.
-
-Amdahl UTS 2.1.5
- In order to get UTS to work, you will have to port BIND 4.9.
- The vendor's BIND is reported to be ``totally inadequate.''
- See sendmail/contrib/AmdahlUTS.patch for the patches necessary
- to get BIND 4.9 compiled for UTS.
-
-UnixWare
- According to Alexander Kolbasov <sasha@unitech.gamma.ru>,
- the m4 on UnixWare 2.0 (still in Beta) will core dump on the
- config files. GNU m4 and the m4 from UnixWare 1.x both work.
-
- According to Larry Rosenman <ler@lerami.lerctr.org>:
-
- UnixWare 2.1.[23]'s m4 chokes (not obviously) when
- processing the 8.9.0 cf files.
-
- I had a LOCAL_RULE_0 that wound up AFTER the
- SBasic_check_rcpt rules using the SCO supplied M4.
- GNU M4 works fine.
-
-UNICOS 8.0.3.4
- Some people have reported that the -O flag on UNICOS can cause
- problems. You may want to turn this off if you have problems
- running sendmail. Reported by Jerry G. DeLapp <jgd@acl.lanl.gov>.
-
-GNU getopt
- I'm told that GNU getopt has a problem in that it gets confused
- by the double call. Use the version in conf.c instead.
-
-BIND 4.9.2 and Ultrix
- If you are running on Ultrix, be sure you read conf/Info.Ultrix
- in the BIND distribution very carefully -- there is information
- in there that you need to know in order to avoid errors of the
- form:
-
- /lib/libc.a(gethostent.o): sethostent: multiply defined
- /lib/libc.a(gethostent.o): endhostent: multiply defined
- /lib/libc.a(gethostent.o): gethostbyname: multiply defined
- /lib/libc.a(gethostent.o): gethostbyaddr: multiply defined
-
- during the link stage.
-
-strtoul
- Some compilers (notably gcc) claim to be ANSI C but do not
- include the ANSI-required routine "strtoul". If your compiler
- has this problem, you will get an error in srvrsmtp.c on the
- code:
-
- # ifdef defined(__STDC__) && !defined(BROKEN_ANSI_LIBRARY)
- e->e_msgsize = strtoul(vp, (char **) NULL, 10);
- # else
- e->e_msgsize = strtol(vp, (char **) NULL, 10);
- # endif
-
- You can use -DBROKEN_ANSI_LIBRARY to get around this problem.
-
-Listproc 6.0c
- Date: 23 Sep 1995 23:56:07 GMT
- Message-ID: <95925101334.~INN-AUMa00187.comp-news@dl.ac.uk>
- From: alansz@mellers1.psych.berkeley.edu (Alan Schwartz)
- Subject: Listproc 6.0c + Sendmail 8.7 [Helpful hint]
-
- Just upgraded to sendmail 8.7, and discovered that listproc 6.0c
- breaks, because it, by default, sends a blank "HELO" rather than
- a "HELO hostname" when using the 'system' or 'telnet' mailmethod.
-
- The fix is to include -DZMAILER in the compilation, which will
- cause it to use "HELO hostname" (which Z-mail apparently requires
- as well. :)
-
-LDAP
- LDAP was provided by Booker Bense <bbense+ldap@stanford.edu> of
- Stanford University. From Booker:
-
- - The patch attached to this message implements an Ldap map class.
- Currently we are using this at stanford to support campus-wide
- email addressing. More information can be found at
- http://www.stanford.edu/~bbense/Inst.html.
-
- - Currently we are using the ldap map as follows:
-
- Kluser ldapx
- -h"localhost borax.stanford.edu borate.stanford.edu boron.stanford.edu"
- -k"mailacceptinggeneralid=%s" -v maildrop
-
- and in Rule set S5
-
- # Now attempt to lookup in luser (ldap map)
- R< $L > $+ $: < $L > $( luser $1 $)
- R< $* > $+ @ $+ $: < $3 > $2 Rewrite if forward
-
- - The map definition supports most of the standard Map args plus most
- of the command line options of ldapsearch. The software is currently
- limited to only accepting the first entry returned. It expects that
- the map defines an ldap filter that returns at most 1 valid entry.
- It requires the ldap and lber libraries from the Umich Ldap3.2
- release.
-
- The software has been in production on Solaris.2.5.1 at Stanford
- for over 2 years.
-
- The LDAP map supports both the UMich LDAP 3.2 and 3.3 libraries as
- well as the OpenLDAP (http://www.openldap.org/) libraries.
-
-TCP Wrappers
- If you are using -DTCPWRAPPERS to get TCP Wrappers support you will
- also need to install libwrap.a and modify your site.config.m4 file
- or the generated Makefile to include -lwrap in the LIBS line
- (make sure that INCDIRS and LIBDIRS point to where the tcpd.h and
- libwrap.a can be found).
-
- TCP Wrappers is available on ftp.win.tue.nl in /pub/security;
- grab tcp_wrappers_<VER>.tar.gz (where <VER> is the highest
- numbered version).
-
- If you have alternate MX sites for your site, be sure that all of
- your MX sites reject the same set of hosts. If not, a bad guy whom
- you reject will connect to your site, fail, and move on to the next
- MX site, which will accept the mail for you and forward it on to you.
-
-Regular Expressions (MAP_REGEX)
- If sendmail linking fails with:
-
- undefined reference to 'regcomp'
-
- or sendmail gives an error about a regular expression with:
-
- pattern-compile-error: : Operation not applicable
-
- Your libc does not include a running version of POSIX-regex. Use
- librx or regex.o from the GNU Free Software Foundation,
- ftp://ftp.gnu.org/pub/gnu/rx-?.?.tar.gz or
- ftp://ftp.gnu.org/pub/gnu/regex-?.?.tar.gz.
- You can also use the regex-lib by Henry Spencer,
- ftp://ftp.funet.fi/pub/languages/C/spencer/regex.shar.gz
- Make sure, your compiler reads regex.h from the distribution,
- not from /usr/include, otherwise sendmail will dump a core.
-
-
-+--------------+
-| MANUAL PAGES |
-+--------------+
-
-The manual pages have been written against the -mandoc macros
-instead of the -man macros. The latest version of groff has them
-included. You can also get a copy from FTP.UU.NET in the directory
-/systems/unix/bsd-sources/share/tmac. groff is available from
-ftp.gnu.org in the /pub/gnu directory.
-
-
-+-----------------+
-| DEBUGGING HOOKS |
-+-----------------+
-
-As of 8.6.5, sendmail daemons will catch a SIGUSR1 signal and log
-some debugging output (logged at LOG_DEBUG severity). The
-information dumped is:
-
- * The value of the $j macro.
- * A warning if $j is not in the set $=w.
- * A list of the open file descriptors.
- * The contents of the connection cache.
- * If ruleset 89 is defined, it is evaluated and the results printed.
-
-This allows you to get information regarding the runtime state of the
-daemon on the fly. This should not be done too frequently, since
-the process of rewriting may lose memory which will not be recovered.
-Also, ruleset 89 may call non-reentrant routines, so there is a small
-non-zero probability that this will cause other problems. It is
-really only for debugging serious problems.
-
-A typical formulation of ruleset 89 would be:
-
- R$* $@ $>0 some test address
-
-
-+-----------------------------+
-| DESCRIPTION OF SOURCE FILES |
-+-----------------------------+
-
-The following list describes the files in this directory:
-
-Makefile.m4 A template for constructing a makefile based on the
- information in the BuildTools directory.
-README This file.
-TRACEFLAGS My own personal list of the trace flags -- not guaranteed
- to be particularly up to date.
-alias.c Does name aliasing in all forms.
-arpadate.c A subroutine which creates ARPANET standard dates.
-clock.c Routines to implement real-time oriented functions
- in sendmail -- e.g., timeouts.
-collect.c The routine that actually reads the mail into a temp
- file. It also does a certain amount of parsing of
- the header, etc.
-conf.c The configuration file. This contains information
- that is presumed to be quite static and non-
- controversial, or code compiled in for efficiency
- reasons. Most of the configuration is in sendmail.cf.
-conf.h Configuration that must be known everywhere.
-convtime.c A routine to sanely process times.
-daemon.c Routines to implement daemon mode. This version is
- specifically for Berkeley 4.1 IPC.
-deliver.c Routines to deliver mail.
-domain.c Routines that interface with DNS (the Domain Name
- System).
-err.c Routines to print error messages.
-envelope.c Routines to manipulate the envelope structure.
-headers.c Routines to process message headers.
-macro.c The macro expander. This is used internally to
- insert information from the configuration file.
-main.c The main routine to sendmail. This file also
- contains some miscellaneous routines.
-map.c Support for database maps.
-mci.c Routines that handle mail connection information caching.
-mime.c MIME conversion routines.
-parseaddr.c The routines which do address parsing.
-queue.c Routines to implement message queueing.
-readcf.c The routine that reads the configuration file and
- translates it to internal form.
-recipient.c Routines that manipulate the recipient list.
-safefile.c Routines to do careful checking of file modes and permissions
- when opening or creating files.
-savemail.c Routines which save the letter on processing errors.
-sendmail.h Main header file for sendmail.
-snprintf.c Routines to manipulate strings but prevent buffer overflows.
-srvrsmtp.c Routines to implement server SMTP.
-stab.c Routines to manage the symbol table.
-stats.c Routines to collect and post the statistics.
-sysexits.c List of error messages associated with error codes
- in sysexits.h.
-trace.c The trace package. These routines allow setting and
- testing of trace flags with a high granularity.
-udb.c The user database interface module.
-usersmtp.c Routines to implement user SMTP.
-util.c Some general purpose routines used by sendmail.
-version.c The version number and information about this
- version of sendmail. Theoretically, this gets
- modified on every change.
-
-Eric Allman
-
-(Version 8.211, last update 2/2/1999 15:28:18)
diff --git a/src/TRACEFLAGS b/src/TRACEFLAGS
deleted file mode 100644
index 04b9b3c..0000000
--- a/src/TRACEFLAGS
+++ /dev/null
@@ -1,79 +0,0 @@
-# @(#)TRACEFLAGS 8.21 (Berkeley) 4/27/1998
-0, 1 main.c main skip background fork
-0, 4 main.c main canonical name, UUCP node name, a.k.a.s
-0, 15 main.c main print configuration
-0, 44 util.c printav print address of each string
-0, 101 main.c main print version and exit
-1 main.c main print from person
-2 main.c finis
-3 conf.c getla, shouldqueue
-4 conf.c enoughspace
-5 clock.c setevent, clrevent, tick
-6 savemail.c savemail, returntosender
-7 queue.c queuename
-8 domain.c getmxrr, getcanonname
-9 daemon.c getauthinfo IDENT protocol
-9 daemon.c maphostname
-10 deliver.c deliver
-11 deliver.c openmailer, mailfile
-12 parseaddr.c remotename
-13 deliver.c sendall, sendenvelope
-14 headers.c commaize
-15 daemon.c getrequests
-16 daemon.c makeconnection
-17 deliver.c hostsignature
-17 domain.c mxrand
-18 usersmtp.c reply, smtpmessage, smtpinit, smtpmailfrom
-19 srvrsmtp.c smtp
-20 parseaddr.c parseaddr
-21 parseaddr.c rewrite
-22 parseaddr.c prescan
-24 parseaddr.c buildaddr, allocaddr
-25 recipient.c sendtolist
-26 recipient.c recipient
-27 alias.c alias
-27 alias.c readaliases
-27 alias.c forward
-27 recipient.c include
-28 udb.c udbexpand, udbsender
-29 parseaddr.c maplocaluser
-29 recipient.c recipient (local users), finduser
-30 collect.c collect
-30 collect.c eatfrom
-31 headers.c chompheader
-32 headers.c eatheader
-33 headers.c crackaddr
-34 headers.c putheader
-35 macro.c expand, define
-36 stab.c stab
-37 readcf.c (many)
-38 map.c initmaps
-39 map.c map_rewrite
-40 queue.c queueup, orderq, dowork
-41 queue.c orderq
-42 mci.c mci_get
-43 mime.c mime8to7
-44 recipient.c writeable
-44 safefile.c safefile, safedirpath, filechanged
-45 envelope.c setsender
-46 envelope.c openxscript
-47 main.c drop_privileges
-48 parseaddr.c rscheck
-48 conf.c validate_connection
-49 conf.c checkcompat
-50 envelope.c dropenvelope
-51 queue.c unlockqueue
-52 main.c disconnect
-53 util.c xfclose
-54 err.c putoutmsg
-55 conf.c lockfile
-56 mci.c persistent host status
-57 util.c snprintf
-60 map.c
-61 conf.c sm_gethostbyname
-62 multiple file descriptor checking
-80 content length
-81 sun remote mode
-91 mci.c syslogging of MCI cache information
-94 srvrsmtp.c cause commands to fail (for protocol testing)
-99 main.c avoid backgrounding (no printed output)
diff --git a/src/alias.c b/src/alias.c
deleted file mode 100644
index a7149f2..0000000
--- a/src/alias.c
+++ /dev/null
@@ -1,895 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- */
-
-# include "sendmail.h"
-
-#ifndef lint
-static char sccsid[] = "@(#)alias.c 8.96 (Berkeley) 12/18/1998";
-#endif /* not lint */
-
-
-MAP *AliasFileMap = NULL; /* the actual aliases.files map */
-int NAliasFileMaps; /* the number of entries in AliasFileMap */
- /*
-** ALIAS -- Compute aliases.
-**
-** Scans the alias file for an alias for the given address.
-** If found, it arranges to deliver to the alias list instead.
-** Uses libdbm database if -DDBM.
-**
-** Parameters:
-** a -- address to alias.
-** sendq -- a pointer to the head of the send queue
-** to put the aliases in.
-** aliaslevel -- the current alias nesting depth.
-** e -- the current envelope.
-**
-** Returns:
-** none
-**
-** Side Effects:
-** Aliases found are expanded.
-**
-** Deficiencies:
-** It should complain about names that are aliased to
-** nothing.
-*/
-
-void
-alias(a, sendq, aliaslevel, e)
- register ADDRESS *a;
- ADDRESS **sendq;
- int aliaslevel;
- register ENVELOPE *e;
-{
- register char *p;
- char *owner;
- auto int stat = EX_OK;
- char obuf[MAXNAME + 7];
- extern char *aliaslookup __P((char *, int *, ENVELOPE *));
-
- if (tTd(27, 1))
- printf("alias(%s)\n", a->q_user);
-
- /* don't realias already aliased names */
- if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags))
- return;
-
- if (NoAlias)
- return;
-
- e->e_to = a->q_paddr;
-
- /*
- ** Look up this name.
- **
- ** If the map was unavailable, we will queue this message
- ** until the map becomes available; otherwise, we could
- ** bounce messages inappropriately.
- */
-
- p = aliaslookup(a->q_user, &stat, e);
- if (stat == EX_TEMPFAIL || stat == EX_UNAVAILABLE)
- {
- a->q_flags |= QQUEUEUP;
- if (e->e_message == NULL)
- e->e_message = newstr("alias database unavailable");
- return;
- }
- if (p == NULL)
- return;
-
- /*
- ** Match on Alias.
- ** Deliver to the target list.
- */
-
- if (tTd(27, 1))
- printf("%s (%s, %s) aliased to %s\n",
- a->q_paddr, a->q_host, a->q_user, p);
- if (bitset(EF_VRFYONLY, e->e_flags))
- {
- a->q_flags |= QVERIFIED;
- return;
- }
- message("aliased to %s", shortenstring(p, MAXSHORTSTR));
- if (LogLevel > 9)
- sm_syslog(LOG_INFO, e->e_id,
- "alias %.100s => %s",
- a->q_paddr, shortenstring(p, MAXSHORTSTR));
- a->q_flags &= ~QSELFREF;
- if (tTd(27, 5))
- {
- printf("alias: QDONTSEND ");
- printaddr(a, FALSE);
- }
- a->q_flags |= QDONTSEND;
- (void) sendtolist(p, a, sendq, aliaslevel + 1, e);
- if (bitset(QSELFREF, a->q_flags))
- a->q_flags &= ~QDONTSEND;
-
- /*
- ** Look for owner of alias
- */
-
- (void) strcpy(obuf, "owner-");
- if (strncmp(a->q_user, "owner-", 6) == 0 ||
- strlen(a->q_user) > (SIZE_T) sizeof obuf - 7)
- (void) strcat(obuf, "owner");
- else
- (void) strcat(obuf, a->q_user);
- owner = aliaslookup(obuf, &stat, e);
- if (owner == NULL)
- return;
-
- /* reflect owner into envelope sender */
- if (strpbrk(owner, ",:/|\"") != NULL)
- owner = obuf;
- a->q_owner = newstr(owner);
-
- /* announce delivery to this alias; NORECEIPT bit set later */
- if (e->e_xfp != NULL)
- fprintf(e->e_xfp, "Message delivered to mailing list %s\n",
- a->q_paddr);
- e->e_flags |= EF_SENDRECEIPT;
- a->q_flags |= QDELIVERED|QEXPANDED;
-}
- /*
-** ALIASLOOKUP -- look up a name in the alias file.
-**
-** Parameters:
-** name -- the name to look up.
-** pstat -- a pointer to a place to put the status.
-** e -- the current envelope.
-**
-** Returns:
-** the value of name.
-** NULL if unknown.
-**
-** Side Effects:
-** none.
-**
-** Warnings:
-** The return value will be trashed across calls.
-*/
-
-char *
-aliaslookup(name, pstat, e)
- char *name;
- int *pstat;
- ENVELOPE *e;
-{
- static MAP *map = NULL;
-
- if (map == NULL)
- {
- STAB *s = stab("aliases", ST_MAP, ST_FIND);
-
- if (s == NULL)
- return NULL;
- map = &s->s_map;
- }
- if (!bitset(MF_OPEN, map->map_mflags))
- return NULL;
-
- /* special case POstMastER -- always use lower case */
- if (strcasecmp(name, "postmaster") == 0)
- name = "postmaster";
-
- return (*map->map_class->map_lookup)(map, name, NULL, pstat);
-}
- /*
-** SETALIAS -- set up an alias map
-**
-** Called when reading configuration file.
-**
-** Parameters:
-** spec -- the alias specification
-**
-** Returns:
-** none.
-*/
-
-void
-setalias(spec)
- char *spec;
-{
- register char *p;
- register MAP *map;
- char *class;
- STAB *s;
-
- if (tTd(27, 8))
- printf("setalias(%s)\n", spec);
-
- for (p = spec; p != NULL; )
- {
- char buf[50];
-
- while (isascii(*p) && isspace(*p))
- p++;
- if (*p == '\0')
- break;
- spec = p;
-
- if (NAliasFileMaps >= MAXMAPSTACK)
- {
- syserr("Too many alias databases defined, %d max",
- MAXMAPSTACK);
- return;
- }
- if (AliasFileMap == NULL)
- {
- strcpy(buf, "aliases.files sequence");
- AliasFileMap = makemapentry(buf);
- if (AliasFileMap == NULL)
- {
- syserr("setalias: cannot create aliases.files map");
- return;
- }
- }
- (void) snprintf(buf, sizeof buf, "Alias%d", NAliasFileMaps);
- s = stab(buf, ST_MAP, ST_ENTER);
- map = &s->s_map;
- bzero(map, sizeof *map);
- map->map_mname = s->s_name;
-
- p = strpbrk(p, " ,/:");
- if (p != NULL && *p == ':')
- {
- /* map name */
- *p++ = '\0';
- class = spec;
- spec = p;
- }
- else
- {
- class = "implicit";
- map->map_mflags = MF_INCLNULL;
- }
-
- /* find end of spec */
- if (p != NULL)
- p = strchr(p, ',');
- if (p != NULL)
- *p++ = '\0';
-
- if (tTd(27, 20))
- printf(" map %s:%s %s\n", class, s->s_name, spec);
-
- /* look up class */
- s = stab(class, ST_MAPCLASS, ST_FIND);
- if (s == NULL)
- {
- syserr("setalias: unknown alias class %s", class);
- }
- else if (!bitset(MCF_ALIASOK, s->s_mapclass.map_cflags))
- {
- syserr("setalias: map class %s can't handle aliases",
- class);
- }
- else
- {
- map->map_class = &s->s_mapclass;
- if (map->map_class->map_parse(map, spec))
- {
- map->map_mflags |= MF_VALID|MF_ALIAS;
- AliasFileMap->map_stack[NAliasFileMaps++] = map;
- }
- }
- }
-}
- /*
-** ALIASWAIT -- wait for distinguished @:@ token to appear.
-**
-** This can decide to reopen or rebuild the alias file
-**
-** Parameters:
-** map -- a pointer to the map descriptor for this alias file.
-** ext -- the filename extension (e.g., ".db") for the
-** database file.
-** isopen -- if set, the database is already open, and we
-** should check for validity; otherwise, we are
-** just checking to see if it should be created.
-**
-** Returns:
-** TRUE -- if the database is open when we return.
-** FALSE -- if the database is closed when we return.
-*/
-
-bool
-aliaswait(map, ext, isopen)
- MAP *map;
- char *ext;
- int isopen;
-{
- bool attimeout = FALSE;
- time_t mtime;
- struct stat stb;
- char buf[MAXNAME + 1];
-
- if (tTd(27, 3))
- printf("aliaswait(%s:%s)\n",
- map->map_class->map_cname, map->map_file);
- if (bitset(MF_ALIASWAIT, map->map_mflags))
- return isopen;
- map->map_mflags |= MF_ALIASWAIT;
-
- if (SafeAlias > 0)
- {
- auto int st;
- time_t toolong = curtime() + SafeAlias;
- unsigned int sleeptime = 2;
-
- while (isopen &&
- map->map_class->map_lookup(map, "@", NULL, &st) == NULL)
- {
- if (curtime() > toolong)
- {
- /* we timed out */
- attimeout = TRUE;
- break;
- }
-
- /*
- ** Close and re-open the alias database in case
- ** the one is mv'ed instead of cp'ed in.
- */
-
- if (tTd(27, 2))
- printf("aliaswait: sleeping for %d seconds\n",
- sleeptime);
-
- map->map_class->map_close(map);
- map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
- sleep(sleeptime);
- sleeptime *= 2;
- if (sleeptime > 60)
- sleeptime = 60;
- isopen = map->map_class->map_open(map, O_RDONLY);
- }
- }
-
- /* see if we need to go into auto-rebuild mode */
- if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
- {
- if (tTd(27, 3))
- printf("aliaswait: not rebuildable\n");
- map->map_mflags &= ~MF_ALIASWAIT;
- return isopen;
- }
- if (stat(map->map_file, &stb) < 0)
- {
- if (tTd(27, 3))
- printf("aliaswait: no source file\n");
- map->map_mflags &= ~MF_ALIASWAIT;
- return isopen;
- }
- mtime = stb.st_mtime;
- snprintf(buf, sizeof buf, "%s%s",
- map->map_file, ext == NULL ? "" : ext);
- if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || attimeout)
- {
- /* database is out of date */
- if (AutoRebuild && stb.st_ino != 0 &&
- (stb.st_uid == geteuid() ||
- (geteuid() == 0 && stb.st_uid == TrustedUid)))
- {
- bool oldSuprErrs;
-
- message("auto-rebuilding alias database %s", buf);
- oldSuprErrs = SuprErrs;
- SuprErrs = TRUE;
- if (isopen)
- {
- map->map_class->map_close(map);
- map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
- }
- (void) rebuildaliases(map, TRUE);
- isopen = map->map_class->map_open(map, O_RDONLY);
- SuprErrs = oldSuprErrs;
- }
- else
- {
- if (LogLevel > 3)
- sm_syslog(LOG_INFO, NOQID,
- "alias database %s out of date",
- buf);
- message("Warning: alias database %s out of date", buf);
- }
- }
- map->map_mflags &= ~MF_ALIASWAIT;
- return isopen;
-}
- /*
-** REBUILDALIASES -- rebuild the alias database.
-**
-** Parameters:
-** map -- the database to rebuild.
-** automatic -- set if this was automatically generated.
-**
-** Returns:
-** TRUE if successful; FALSE otherwise.
-**
-** Side Effects:
-** Reads the text version of the database, builds the
-** DBM or DB version.
-*/
-
-bool
-rebuildaliases(map, automatic)
- register MAP *map;
- bool automatic;
-{
- FILE *af;
- bool nolock = FALSE;
- bool success = FALSE;
- int sff = SFF_OPENASROOT|SFF_REGONLY|SFF_NOLOCK;
- sigfunc_t oldsigint, oldsigquit;
-#ifdef SIGTSTP
- sigfunc_t oldsigtstp;
-#endif
-
- if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
- return FALSE;
-
- if (!bitset(DBS_LINKEDALIASFILEINWRITABLEDIR, DontBlameSendmail))
- sff |= SFF_NOWLINK;
- if (!bitset(DBS_GROUPWRITABLEALIASFILE, DontBlameSendmail))
- sff |= SFF_NOGWFILES;
- if (!bitset(DBS_WORLDWRITABLEALIASFILE, DontBlameSendmail))
- sff |= SFF_NOWWFILES;
-
- /* try to lock the source file */
- if ((af = safefopen(map->map_file, O_RDWR, 0, sff)) == NULL)
- {
- struct stat stb;
-
- if ((errno != EACCES && errno != EROFS) || automatic ||
- (af = safefopen(map->map_file, O_RDONLY, 0, sff)) == NULL)
- {
- int saveerr = errno;
-
- if (tTd(27, 1))
- printf("Can't open %s: %s\n",
- map->map_file, errstring(saveerr));
- if (!automatic && !bitset(MF_OPTIONAL, map->map_mflags))
- message("newaliases: cannot open %s: %s",
- map->map_file, errstring(saveerr));
- errno = 0;
- return FALSE;
- }
- nolock = TRUE;
- if (tTd(27, 1) ||
- fstat(fileno(af), &stb) < 0 ||
- bitset(S_IWUSR|S_IWGRP|S_IWOTH, stb.st_mode))
- message("warning: cannot lock %s: %s",
- map->map_file, errstring(errno));
- }
-
- /* see if someone else is rebuilding the alias file */
- if (!nolock &&
- !lockfile(fileno(af), map->map_file, NULL, LOCK_EX|LOCK_NB))
- {
- /* yes, they are -- wait until done */
- message("Alias file %s is locked (maybe being rebuilt)",
- map->map_file);
- if (OpMode != MD_INITALIAS)
- {
- /* wait for other rebuild to complete */
- (void) lockfile(fileno(af), map->map_file, NULL,
- LOCK_EX);
- }
- (void) xfclose(af, "rebuildaliases1", map->map_file);
- errno = 0;
- return FALSE;
- }
-
- oldsigint = setsignal(SIGINT, SIG_IGN);
- oldsigquit = setsignal(SIGQUIT, SIG_IGN);
-#ifdef SIGTSTP
- oldsigtstp = setsignal(SIGTSTP, SIG_IGN);
-#endif
-
- if (map->map_class->map_open(map, O_RDWR))
- {
- if (LogLevel > 7)
- {
- sm_syslog(LOG_NOTICE, NOQID,
- "alias database %s %srebuilt by %s",
- map->map_file, automatic ? "auto" : "",
- username());
- }
- map->map_mflags |= MF_OPEN|MF_WRITABLE;
- map->map_pid = getpid();
- readaliases(map, af, !automatic, TRUE);
- success = TRUE;
- }
- else
- {
- if (tTd(27, 1))
- printf("Can't create database for %s: %s\n",
- map->map_file, errstring(errno));
- if (!automatic)
- syserr("Cannot create database for alias file %s",
- map->map_file);
- }
-
- /* close the file, thus releasing locks */
- xfclose(af, "rebuildaliases2", map->map_file);
-
- /* add distinguished entries and close the database */
- if (bitset(MF_OPEN, map->map_mflags))
- {
- map->map_class->map_close(map);
- map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
- }
-
- /* restore the old signals */
- (void) setsignal(SIGINT, oldsigint);
- (void) setsignal(SIGQUIT, oldsigquit);
-#ifdef SIGTSTP
- (void) setsignal(SIGTSTP, oldsigtstp);
-#endif
- return success;
-}
- /*
-** READALIASES -- read and process the alias file.
-**
-** This routine implements the part of initaliases that occurs
-** when we are not going to use the DBM stuff.
-**
-** Parameters:
-** map -- the alias database descriptor.
-** af -- file to read the aliases from.
-** announcestats -- anounce statistics regarding number of
-** aliases, longest alias, etc.
-** logstats -- lot the same info.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Reads aliasfile into the symbol table.
-** Optionally, builds the .dir & .pag files.
-*/
-
-void
-readaliases(map, af, announcestats, logstats)
- register MAP *map;
- FILE *af;
- bool announcestats;
- bool logstats;
-{
- register char *p;
- char *rhs;
- bool skipping;
- long naliases, bytes, longest;
- ADDRESS al, bl;
- char line[BUFSIZ];
-
- /*
- ** Read and interpret lines
- */
-
- FileName = map->map_file;
- LineNumber = 0;
- naliases = bytes = longest = 0;
- skipping = FALSE;
- while (fgets(line, sizeof (line), af) != NULL)
- {
- int lhssize, rhssize;
- int c;
-
- LineNumber++;
- p = strchr(line, '\n');
-#if _FFR_BACKSLASH_IN_ALIASES
- while (p != NULL && p > line && p[-1] == '\\')
- {
- p--;
- if (fgets(p, SPACELEFT(line, p), af) == NULL)
- break;
- LineNumber++;
- p = strchr(p, '\n');
- }
-#endif
- if (p != NULL)
- *p = '\0';
- else if (!feof(af))
- {
- syserr("554 alias line too long");
-
- /* flush to end of line */
- while ((c = getc(af)) != EOF && c != '\n')
- continue;
-
- /* skip any continuation lines */
- skipping = TRUE;
- continue;
- }
- switch (line[0])
- {
- case '#':
- case '\0':
- skipping = FALSE;
- continue;
-
- case ' ':
- case '\t':
- if (!skipping)
- syserr("554 Non-continuation line starts with space");
- skipping = TRUE;
- continue;
- }
- skipping = FALSE;
-
- /*
- ** Process the LHS
- ** Find the colon separator, and parse the address.
- ** It should resolve to a local name -- this will
- ** be checked later (we want to optionally do
- ** parsing of the RHS first to maximize error
- ** detection).
- */
-
- for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
- continue;
- if (*p++ != ':')
- {
- syserr("554 missing colon");
- continue;
- }
- if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv) == NULL)
- {
- syserr("554 %.40s... illegal alias name", line);
- continue;
- }
-
- /*
- ** Process the RHS.
- ** 'al' is the internal form of the LHS address.
- ** 'p' points to the text of the RHS.
- */
-
- while (isascii(*p) && isspace(*p))
- p++;
- rhs = p;
- for (;;)
- {
- register char *nlp;
-
- nlp = &p[strlen(p)];
- if (nlp[-1] == '\n')
- *--nlp = '\0';
-
- if (CheckAliases)
- {
- /* do parsing & compression of addresses */
- while (*p != '\0')
- {
- auto char *delimptr;
-
- while ((isascii(*p) && isspace(*p)) ||
- *p == ',')
- p++;
- if (*p == '\0')
- break;
- if (parseaddr(p, &bl, RF_COPYNONE, ',',
- &delimptr, CurEnv) == NULL)
- usrerr("553 %s... bad address", p);
- p = delimptr;
- }
- }
- else
- {
- p = nlp;
- }
-
- /* see if there should be a continuation line */
- c = getc(af);
- if (!feof(af))
- (void) ungetc(c, af);
- if (c != ' ' && c != '\t')
- break;
-
- /* read continuation line */
- if (fgets(p, sizeof line - (p - line), af) == NULL)
- break;
- LineNumber++;
-
- /* check for line overflow */
- if (strchr(p, '\n') == NULL && !feof(af))
- {
- usrerr("554 alias too long");
- while ((c = fgetc(af)) != EOF && c != '\n')
- continue;
- skipping = TRUE;
- break;
- }
- }
-
- if (skipping)
- continue;
-
- if (!bitnset(M_ALIASABLE, al.q_mailer->m_flags))
- {
- syserr("554 %s... cannot alias non-local names",
- al.q_paddr);
- continue;
- }
-
- /*
- ** Insert alias into symbol table or database file.
- **
- ** Special case pOStmaStER -- always make it lower case.
- */
-
- if (strcasecmp(al.q_user, "postmaster") == 0)
- makelower(al.q_user);
-
- lhssize = strlen(al.q_user);
- rhssize = strlen(rhs);
- map->map_class->map_store(map, al.q_user, rhs);
-
- if (al.q_paddr != NULL)
- free(al.q_paddr);
- if (al.q_host != NULL)
- free(al.q_host);
- if (al.q_user != NULL)
- free(al.q_user);
-
- /* statistics */
- naliases++;
- bytes += lhssize + rhssize;
- if (rhssize > longest)
- longest = rhssize;
- }
-
- CurEnv->e_to = NULL;
- FileName = NULL;
- if (Verbose || announcestats)
- message("%s: %d aliases, longest %d bytes, %d bytes total",
- map->map_file, naliases, longest, bytes);
- if (LogLevel > 7 && logstats)
- sm_syslog(LOG_INFO, NOQID,
- "%s: %d aliases, longest %d bytes, %d bytes total",
- map->map_file, naliases, longest, bytes);
-}
- /*
-** FORWARD -- Try to forward mail
-**
-** This is similar but not identical to aliasing.
-**
-** Parameters:
-** user -- the name of the user who's mail we would like
-** to forward to. It must have been verified --
-** i.e., the q_home field must have been filled
-** in.
-** sendq -- a pointer to the head of the send queue to
-** put this user's aliases in.
-** aliaslevel -- the current alias nesting depth.
-** e -- the current envelope.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** New names are added to send queues.
-*/
-
-void
-forward(user, sendq, aliaslevel, e)
- ADDRESS *user;
- ADDRESS **sendq;
- int aliaslevel;
- register ENVELOPE *e;
-{
- char *pp;
- char *ep;
- bool got_transient;
-
- if (tTd(27, 1))
- printf("forward(%s)\n", user->q_paddr);
-
- if (!bitnset(M_HASPWENT, user->q_mailer->m_flags) ||
- bitset(QBADADDR, user->q_flags))
- return;
- if (user->q_home == NULL)
- {
- syserr("554 forward: no home");
- user->q_home = "/no/such/directory";
- }
-
- /* good address -- look for .forward file in home */
- define('z', user->q_home, e);
- define('u', user->q_user, e);
- define('h', user->q_host, e);
- if (ForwardPath == NULL)
- ForwardPath = newstr("\201z/.forward");
-
- got_transient = FALSE;
- for (pp = ForwardPath; pp != NULL; pp = ep)
- {
- int err;
- char buf[MAXPATHLEN+1];
-
- ep = strchr(pp, ':');
- if (ep != NULL)
- *ep = '\0';
- expand(pp, buf, sizeof buf, e);
- if (ep != NULL)
- *ep++ = ':';
- if (buf[0] == '\0')
- continue;
- if (tTd(27, 3))
- printf("forward: trying %s\n", buf);
-
- err = include(buf, TRUE, user, sendq, aliaslevel, e);
- if (err == 0)
- break;
- else if (transienterror(err))
- {
- /* we may have to suspend this message */
- got_transient = TRUE;
- if (tTd(27, 2))
- printf("forward: transient error on %s\n", buf);
- if (LogLevel > 2)
- sm_syslog(LOG_ERR, e->e_id,
- "forward %s: transient error: %s",
- buf, errstring(err));
- }
- else
- {
- switch (err)
- {
- case ENOENT:
- break;
-
-#if _FFR_FORWARD_SYSERR
- case E_SM_NOSLINK:
- case E_SM_NOHLINK:
- case E_SM_REGONLY:
- case E_SM_ISEXEC:
- case E_SM_WWDIR:
- case E_SM_GWDIR:
- case E_SM_WWFILE:
- case E_SM_GWFILE:
- syserr("forward: %s: %s", buf, errstring(err));
- break;
-#endif
-
- default:
- if (LogLevel > (RunAsUid == 0 ? 2 : 10))
- sm_syslog(LOG_WARNING, e->e_id,
- "forward %s: %s", buf,
- errstring(err));
- if (Verbose)
- message("forward: %s: %s",
- buf,
- errstring(err));
- break;
- }
- }
- }
- if (pp == NULL && got_transient)
- {
- /*
- ** There was no successful .forward open and at least one
- ** transient open. We have to defer this address for
- ** further delivery.
- */
-
- message("transient .forward open error: message queued");
- user->q_flags |= QQUEUEUP;
- return;
- }
-}
diff --git a/src/aliases b/src/aliases
deleted file mode 100644
index 7540eea..0000000
--- a/src/aliases
+++ /dev/null
@@ -1,53 +0,0 @@
-#
-# @(#)aliases 8.2 (Berkeley) 3/5/94
-#
-# Aliases in this file will NOT be expanded in the header from
-# Mail, but WILL be visible over networks or from /bin/mail.
-#
-# >>>>>>>>>> The program "newaliases" must be run after
-# >> NOTE >> this file is updated for any changes to
-# >>>>>>>>>> show through to sendmail.
-#
-
-# Basic system aliases -- these MUST be present.
-MAILER-DAEMON: postmaster
-postmaster: root
-
-# General redirections for pseudo accounts.
-bin: root
-daemon: root
-games: root
-ingres: root
-nobody: root
-system: root
-toor: root
-uucp: root
-
-# Well-known aliases.
-manager: root
-dumper: root
-operator: root
-
-# trap decode to catch security attacks
-decode: root
-
-# OFFICIAL CSRG/BUG ADDRESSES
-
-# Ftp maintainer.
-ftp: ftp-bugs
-ftp-bugs: bigbug@cs.berkeley.edu
-
-# Distribution office.
-bsd-dist: bsd-dist@cs.berkeley.edu
-
-# Fortune maintainer.
-fortune: fortune@cs.berkeley.edu
-
-# Termcap maintainer.
-termcap: termcap@cs.berkeley.edu
-
-# General bug address.
-ucb-fixes: bigbug@cs.berkeley.edu
-ucb-fixes-request: bigbug@cs.berkeley.edu
-bugs: bugs@cs.berkeley.edu
-# END OFFICIAL BUG ADDRESSES
diff --git a/src/aliases.0 b/src/aliases.0
deleted file mode 100644
index 1163f42..0000000
--- a/src/aliases.0
+++ /dev/null
@@ -1,48 +0,0 @@
-ALIASES(5) BSD Programmer's Manual ALIASES(5)
-
-NNAAMMEE
- aalliiaasseess - aliases file for sendmail
-
-SSYYNNOOPPSSIISS
- aalliiaasseess
-
-DDEESSCCRRIIPPTTIIOONN
- This file describes user ID aliases used by _/_u_s_r_/_s_b_i_n_/_s_e_n_d_m_a_i_l. The file
- resides in _/_e_t_c and is formatted as a series of lines of the form
-
- name: name_1, name2, name_3, . . .
-
- The _n_a_m_e is the name to alias, and the _n_a_m_e___n are the aliases for that
- name. Lines beginning with white space are continuation lines. Lines
- beginning with `#' are comments.
-
- Aliasing occurs only on local names. Loops can not occur, since no mes-
- sage will be sent to any person more than once.
-
- After aliasing has been done, local and valid recipients who have a
- ``_._f_o_r_w_a_r_d'' file in their home directory have messages forwarded to the
- list of users defined in that file.
-
- This is only the raw data file; the actual aliasing information is placed
- into a binary format in the file _/_e_t_c_/_a_l_i_a_s_e_s_._d_b using the program
- newaliases(1). A newaliases command should be executed each time the
- aliases file is changed for the change to take effect.
-
-SSEEEE AALLSSOO
- newaliases(1), dbopen(3), dbm(3), sendmail(8)
-
- _S_E_N_D_M_A_I_L _I_n_s_t_a_l_l_a_t_i_o_n _a_n_d _O_p_e_r_a_t_i_o_n _G_u_i_d_e.
-
- _S_E_N_D_M_A_I_L _A_n _I_n_t_e_r_n_e_t_w_o_r_k _M_a_i_l _R_o_u_t_e_r.
-
-BBUUGGSS
- If you have compiled sendmail with DBM support instead of NEWDB, you may
- have encountered problems in dbm(3) restricting a single alias to about
- 1000 bytes of information. You can get longer aliases by ``chaining'';
- that is, make the last name in the alias be a dummy name which is a con-
- tinuation alias.
-
-HHIISSTTOORRYY
- The aalliiaasseess file format appeared in 4.0BSD.
-
-4th Berkeley Distribution May 19, 1998 1
diff --git a/src/aliases.5 b/src/aliases.5
deleted file mode 100644
index bf45838..0000000
--- a/src/aliases.5
+++ /dev/null
@@ -1,85 +0,0 @@
-.\" Copyright (c) 1998 Sendmail, Inc. All rights reserved.
-.\" Copyright (c) 1983, 1997 Eric P. Allman. All rights reserved.
-.\" Copyright (c) 1985, 1991, 1993
-.\" The Regents of the University of California. All rights reserved.
-.\"
-.\" By using this file, you agree to the terms and conditions set
-.\" forth in the LICENSE file which can be found at the top level of
-.\" the sendmail distribution.
-.\"
-.\"
-.\" @(#)aliases.5 8.8 (Berkeley) 5/19/1998
-.\"
-.Dd May 19, 1998
-.Dt ALIASES 5
-.Os BSD 4
-.Sh NAME
-.Nm aliases
-.Nd aliases file for sendmail
-.Sh SYNOPSIS
-.Nm aliases
-.Sh DESCRIPTION
-This file describes user
-.Tn ID
-aliases used by
-.Pa /usr/sbin/sendmail .
-The file resides in
-.Pa /etc
-and
-is formatted as a series of lines of the form
-.Bd -filled -offset indent
-name: name_1, name2, name_3, . . .
-.Ed
-.Pp
-The
-.Em name
-is the name to alias, and the
-.Em name_n
-are the aliases for that name.
-Lines beginning with white space are continuation lines.
-Lines beginning with
-.Ql #
-are comments.
-.Pp
-Aliasing occurs only on local names.
-Loops can not occur, since no message will be sent to any person more than once.
-.Pp
-After aliasing has been done, local and valid recipients who have a
-.Dq Pa .forward
-file in their home directory have messages forwarded to the
-list of users defined in that file.
-.Pp
-This is only the raw data file; the actual aliasing information is
-placed into a binary format in the file
-.Pa /etc/aliases.db
-using the program
-.Xr newaliases 1 .
-A
-.Xr newaliases
-command should be executed each time the aliases file is changed for the
-change to take effect.
-.Sh SEE ALSO
-.Xr newaliases 1 ,
-.Xr dbopen 3 ,
-.Xr dbm 3 ,
-.Xr sendmail 8
-.Rs
-.%T "SENDMAIL Installation and Operation Guide"
-.Re
-.Rs
-.%T "SENDMAIL An Internetwork Mail Router"
-.Re
-.Sh BUGS
-If you have compiled
-.Xr sendmail
-with DBM support instead of NEWDB,
-you may have encountered problems in
-.Xr dbm 3
-restricting a single alias to about 1000 bytes of information.
-You can get longer aliases by ``chaining''; that is, make the last name in
-the alias be a dummy name which is a continuation alias.
-.Sh HISTORY
-The
-.Nm
-file format appeared in
-.Bx 4.0 .
diff --git a/src/arpadate.c b/src/arpadate.c
deleted file mode 100644
index c02decd..0000000
--- a/src/arpadate.c
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)arpadate.c 8.14 (Berkeley) 2/2/1999";
-#endif /* not lint */
-
-# include "sendmail.h"
-
-/*
-** ARPADATE -- Create date in ARPANET format
-**
-** Parameters:
-** ud -- unix style date string. if NULL, one is created.
-**
-** Returns:
-** pointer to an ARPANET date field
-**
-** Side Effects:
-** none
-**
-** WARNING:
-** date is stored in a local buffer -- subsequent
-** calls will overwrite.
-**
-** Bugs:
-** Timezone is computed from local time, rather than
-** from whereever (and whenever) the message was sent.
-** To do better is very hard.
-**
-** Some sites are now inserting the timezone into the
-** local date. This routine should figure out what
-** the format is and work appropriately.
-*/
-
-#ifndef TZNAME_MAX
-# define TZNAME_MAX 50 /* max size of timezone */
-#endif
-
-/* values for TZ_TYPE */
-#define TZ_NONE 0 /* no character timezone support */
-#define TZ_TM_NAME 1 /* use tm->tm_name */
-#define TZ_TM_ZONE 2 /* use tm->tm_zone */
-#define TZ_TZNAME 3 /* use tzname[] */
-#define TZ_TIMEZONE 4 /* use timezone() */
-
-char *
-arpadate(ud)
- register char *ud;
-{
- register char *p;
- register char *q;
- register int off;
- register int i;
- register struct tm *lt;
- time_t t;
- struct tm gmt;
- char *tz;
- static char b[43 + TZNAME_MAX];
-
- /*
- ** Get current time.
- ** This will be used if a null argument is passed and
- ** to resolve the timezone.
- */
-
- t = curtime();
- if (ud == NULL)
- ud = ctime(&t);
-
- /*
- ** Crack the UNIX date line in a singularly unoriginal way.
- */
-
- q = b;
-
- p = &ud[0]; /* Mon */
- *q++ = *p++;
- *q++ = *p++;
- *q++ = *p++;
- *q++ = ',';
- *q++ = ' ';
-
- p = &ud[8]; /* 16 */
- if (*p == ' ')
- p++;
- else
- *q++ = *p++;
- *q++ = *p++;
- *q++ = ' ';
-
- p = &ud[4]; /* Sep */
- *q++ = *p++;
- *q++ = *p++;
- *q++ = *p++;
- *q++ = ' ';
-
- p = &ud[20]; /* 1979 */
- *q++ = *p++;
- *q++ = *p++;
- *q++ = *p++;
- *q++ = *p++;
- *q++ = ' ';
-
- p = &ud[11]; /* 01:03:52 */
- for (i = 8; i > 0; i--)
- *q++ = *p++;
-
- /*
- * should really get the timezone from the time in "ud" (which
- * is only different if a non-null arg was passed which is different
- * from the current time), but for all practical purposes, returning
- * the current local zone will do (its all that is ever needed).
- */
- gmt = *gmtime(&t);
- lt = localtime(&t);
-
- off = (lt->tm_hour - gmt.tm_hour) * 60 + lt->tm_min - gmt.tm_min;
-
- /* assume that offset isn't more than a day ... */
- if (lt->tm_year < gmt.tm_year)
- off -= 24 * 60;
- else if (lt->tm_year > gmt.tm_year)
- off += 24 * 60;
- else if (lt->tm_yday < gmt.tm_yday)
- off -= 24 * 60;
- else if (lt->tm_yday > gmt.tm_yday)
- off += 24 * 60;
-
- *q++ = ' ';
- if (off == 0)
- {
- *q++ = 'G';
- *q++ = 'M';
- *q++ = 'T';
- }
- else
- {
- tz = NULL;
-#if TZ_TYPE == TZ_TM_NAME
- tz = lt->tm_name;
-#endif
-#if TZ_TYPE == TZ_TM_ZONE
- tz = lt->tm_zone;
-#endif
-#if TZ_TYPE == TZ_TZNAME
- {
- extern char *tzname[];
-
- if (lt->tm_isdst > 0)
- tz = tzname[1];
- else if (lt->tm_isdst == 0)
- tz = tzname[0];
- else
- tz = NULL;
- }
-#endif
-#if TZ_TYPE == TZ_TIMEZONE
- {
- extern char *timezone();
-
- tz = timezone(off, lt->tm_isdst);
- }
-#endif
- if (off < 0)
- {
- off = -off;
- *q++ = '-';
- }
- else
- *q++ = '+';
-
- if (off >= 24*60) /* should be impossible */
- off = 23*60+59; /* if not, insert silly value */
-
- *q++ = (off / 600) + '0';
- *q++ = (off / 60) % 10 + '0';
- off %= 60;
- *q++ = (off / 10) + '0';
- *q++ = (off % 10) + '0';
- if (tz != NULL && *tz != '\0')
- {
- *q++ = ' ';
- *q++ = '(';
- while (*tz != '\0' && q < &b[sizeof b - 3])
- *q++ = *tz++;
- *q++ = ')';
- }
- }
- *q = '\0';
-
- return (b);
-}
diff --git a/src/cdefs.h b/src/cdefs.h
deleted file mode 100644
index e586cbf..0000000
--- a/src/cdefs.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Berkeley Software Design, Inc.
- *
- * 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 the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University 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 THE REGENTS 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 THE REGENTS 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.
- *
- * @(#)cdefs.h 8.8 (Berkeley) 1/9/95
- */
-
-#ifndef _CDEFS_H_
-#define _CDEFS_H_
-
-#if defined(__cplusplus)
-#define __BEGIN_DECLS extern "C" {
-#define __END_DECLS };
-#else
-#define __BEGIN_DECLS
-#define __END_DECLS
-#endif
-
-/*
- * The __CONCAT macro is used to concatenate parts of symbol names, e.g.
- * with "#define OLD(foo) __CONCAT(old,foo)", OLD(foo) produces oldfoo.
- * The __CONCAT macro is a bit tricky -- make sure you don't put spaces
- * in between its arguments. __CONCAT can also concatenate double-quoted
- * strings produced by the __STRING macro, but this only works with ANSI C.
- */
-#if defined(__STDC__) || defined(__cplusplus)
-#define __P(protos) protos /* full-blown ANSI C */
-#define __CONCAT(x,y) x ## y
-#define __STRING(x) #x
-
-#define __const const /* define reserved names to standard */
-#define __signed signed
-#define __volatile volatile
-#if defined(__cplusplus)
-#define __inline inline /* convert to C++ keyword */
-#else
-#ifndef __GNUC__
-#define __inline /* delete GCC keyword */
-#endif /* !__GNUC__ */
-#endif /* !__cplusplus */
-
-#else /* !(__STDC__ || __cplusplus) */
-#define __P(protos) () /* traditional C preprocessor */
-#define __CONCAT(x,y) x/**/y
-#define __STRING(x) "x"
-
-#ifndef __GNUC__
-#define __const /* delete pseudo-ANSI C keywords */
-#define __inline
-#define __signed
-#define __volatile
-/*
- * In non-ANSI C environments, new programs will want ANSI-only C keywords
- * deleted from the program and old programs will want them left alone.
- * When using a compiler other than gcc, programs using the ANSI C keywords
- * const, inline etc. as normal identifiers should define -DNO_ANSI_KEYWORDS.
- * When using "gcc -traditional", we assume that this is the intent; if
- * __GNUC__ is defined but __STDC__ is not, we leave the new keywords alone.
- */
-#ifndef NO_ANSI_KEYWORDS
-#define const /* delete ANSI C keywords */
-#define inline
-#define signed
-#define volatile
-#endif
-#endif /* !__GNUC__ */
-#endif /* !(__STDC__ || __cplusplus) */
-
-/*
- * GCC1 and some versions of GCC2 declare dead (non-returning) and
- * pure (no side effects) functions using "volatile" and "const";
- * unfortunately, these then cause warnings under "-ansi -pedantic".
- * GCC2 uses a new, peculiar __attribute__((attrs)) style. All of
- * these work for GNU C++ (modulo a slight glitch in the C++ grammar
- * in the distribution version of 2.5.5).
- */
-#if !defined(__GNUC__) || __GNUC__ < 2 || \
- (__GNUC__ == 2 && __GNUC_MINOR__ < 5)
-#define __attribute__(x) /* delete __attribute__ if non-gcc or gcc1 */
-#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
-#define __dead __volatile
-#define __pure __const
-#endif
-#endif
-
-/* Delete pseudo-keywords wherever they are not available or needed. */
-#ifndef __dead
-#define __dead
-#define __pure
-#endif
-
-#endif /* !_CDEFS_H_ */
diff --git a/src/clock.c b/src/clock.c
deleted file mode 100644
index e6466e6..0000000
--- a/src/clock.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)clock.c 8.35 (Berkeley) 2/2/1999";
-#endif /* not lint */
-
-# include "sendmail.h"
-
-# ifndef sigmask
-# define sigmask(s) (1 << ((s) - 1))
-# endif
-
-/*
-** SETEVENT -- set an event to happen at a specific time.
-**
-** Events are stored in a sorted list for fast processing.
-** An event only applies to the process that set it.
-**
-** Parameters:
-** intvl -- intvl until next event occurs.
-** func -- function to call on event.
-** arg -- argument to func on event.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** none.
-*/
-
-EVENT *FreeEventList; /* list of free events */
-
-static SIGFUNC_DECL tick __P((int));
-
-EVENT *
-setevent(intvl, func, arg)
- time_t intvl;
- void (*func)();
- int arg;
-{
- register EVENT **evp;
- register EVENT *ev;
- auto time_t now;
- int wasblocked;
-
- if (intvl <= 0)
- {
- syserr("554 setevent: intvl=%ld\n", intvl);
- return (NULL);
- }
-
- wasblocked = blocksignal(SIGALRM);
- now = curtime();
-
- /* search event queue for correct position */
- for (evp = &EventQueue; (ev = *evp) != NULL; evp = &ev->ev_link)
- {
- if (ev->ev_time >= now + intvl)
- break;
- }
-
- /* insert new event */
- ev = FreeEventList;
- if (ev == NULL)
- ev = (EVENT *) xalloc(sizeof *ev);
- else
- FreeEventList = ev->ev_link;
- ev->ev_time = now + intvl;
- ev->ev_func = func;
- ev->ev_arg = arg;
- ev->ev_pid = getpid();
- ev->ev_link = *evp;
- *evp = ev;
-
- if (tTd(5, 5))
- printf("setevent: intvl=%ld, for=%ld, func=%lx, arg=%d, ev=%lx\n",
- (long) intvl, (long)(now + intvl), (u_long) func,
- arg, (u_long) ev);
-
- setsignal(SIGALRM, tick);
- intvl = EventQueue->ev_time - now;
- (void) alarm((unsigned) intvl < 1 ? 1 : intvl);
- if (wasblocked == 0)
- (void) releasesignal(SIGALRM);
- return (ev);
-}
- /*
-** CLREVENT -- remove an event from the event queue.
-**
-** Parameters:
-** ev -- pointer to event to remove.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** arranges for event ev to not happen.
-*/
-
-void
-clrevent(ev)
- register EVENT *ev;
-{
- register EVENT **evp;
- int wasblocked;
-
- if (tTd(5, 5))
- printf("clrevent: ev=%lx\n", (u_long) ev);
- if (ev == NULL)
- return;
-
- /* find the parent event */
- wasblocked = blocksignal(SIGALRM);
- for (evp = &EventQueue; *evp != NULL; evp = &(*evp)->ev_link)
- {
- if (*evp == ev)
- break;
- }
-
- /* now remove it */
- if (*evp != NULL)
- {
- *evp = ev->ev_link;
- ev->ev_link = FreeEventList;
- FreeEventList = ev;
- }
-
- /* restore clocks and pick up anything spare */
- if (wasblocked == 0)
- releasesignal(SIGALRM);
- if (EventQueue != NULL)
- kill(getpid(), SIGALRM);
-}
- /*
-** TICK -- take a clock tick
-**
-** Called by the alarm clock. This routine runs events as needed.
-** Always called as a signal handler, so we assume that SIGALRM
-** has been blocked.
-**
-** Parameters:
-** One that is ignored; for compatibility with signal handlers.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** calls the next function in EventQueue.
-*/
-
-/* ARGSUSED */
-static SIGFUNC_DECL
-tick(sig)
- int sig;
-{
- register time_t now;
- register EVENT *ev;
- int mypid = getpid();
- int olderrno = errno;
-
- (void) alarm(0);
- now = curtime();
-
- if (tTd(5, 4))
- printf("tick: now=%ld\n", (long) now);
-
- /* reset signal in case System V semantics */
- (void) setsignal(SIGALRM, tick);
- while ((ev = EventQueue) != NULL &&
- (ev->ev_time <= now || ev->ev_pid != mypid))
- {
- void (*f)();
- int arg;
- int pid;
-
- /* process the event on the top of the queue */
- ev = EventQueue;
- EventQueue = EventQueue->ev_link;
- if (tTd(5, 6))
- printf("tick: ev=%lx, func=%lx, arg=%d, pid=%d\n",
- (u_long) ev, (u_long) ev->ev_func,
- ev->ev_arg, ev->ev_pid);
-
- /* we must be careful in here because ev_func may not return */
- f = ev->ev_func;
- arg = ev->ev_arg;
- pid = ev->ev_pid;
- ev->ev_link = FreeEventList;
- FreeEventList = ev;
- if (pid != getpid())
- continue;
- if (EventQueue != NULL)
- {
- if (EventQueue->ev_time > now)
- (void) alarm((unsigned) (EventQueue->ev_time - now));
- else
- (void) alarm(3);
- }
-
- /* call ev_func */
- errno = olderrno;
- (*f)(arg);
- (void) alarm(0);
- now = curtime();
- }
- if (EventQueue != NULL)
- (void) alarm((unsigned) (EventQueue->ev_time - now));
- errno = olderrno;
- return SIGFUNC_RETURN;
-}
- /*
-** SLEEP -- a version of sleep that works with this stuff
-**
-** Because sleep uses the alarm facility, I must reimplement
-** it here.
-**
-** Parameters:
-** intvl -- time to sleep.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** waits for intvl time. However, other events can
-** be run during that interval.
-*/
-
-static bool SleepDone;
-static void endsleep __P((void));
-
-#ifndef SLEEP_T
-# define SLEEP_T unsigned int
-#endif
-
-SLEEP_T
-sleep(intvl)
- unsigned int intvl;
-{
- int was_held;
-
- if (intvl == 0)
- return (SLEEP_T) 0;
- SleepDone = FALSE;
- (void) setevent((time_t) intvl, endsleep, 0);
- was_held = releasesignal(SIGALRM);
- while (!SleepDone)
- pause();
- if (was_held > 0)
- blocksignal(SIGALRM);
- return (SLEEP_T) 0;
-}
-
-static void
-endsleep()
-{
- SleepDone = TRUE;
-}
diff --git a/src/collect.c b/src/collect.c
deleted file mode 100644
index a8916b1..0000000
--- a/src/collect.c
+++ /dev/null
@@ -1,772 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)collect.c 8.93 (Berkeley) 1/26/1999";
-#endif /* not lint */
-
-# include <errno.h>
-# include "sendmail.h"
-
-/*
-** COLLECT -- read & parse message header & make temp file.
-**
-** Creates a temporary file name and copies the standard
-** input to that file. Leading UNIX-style "From" lines are
-** stripped off (after important information is extracted).
-**
-** Parameters:
-** fp -- file to read.
-** smtpmode -- if set, we are running SMTP: give an RFC821
-** style message to say we are ready to collect
-** input, and never ignore a single dot to mean
-** end of message.
-** hdrp -- the location to stash the header.
-** e -- the current envelope.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Temp file is created and filled.
-** The from person may be set.
-*/
-
-static jmp_buf CtxCollectTimeout;
-static void collecttimeout __P((time_t));
-static bool CollectProgress;
-static EVENT *CollectTimeout;
-
-/* values for input state machine */
-#define IS_NORM 0 /* middle of line */
-#define IS_BOL 1 /* beginning of line */
-#define IS_DOT 2 /* read a dot at beginning of line */
-#define IS_DOTCR 3 /* read ".\r" at beginning of line */
-#define IS_CR 4 /* read a carriage return */
-
-/* values for message state machine */
-#define MS_UFROM 0 /* reading Unix from line */
-#define MS_HEADER 1 /* reading message header */
-#define MS_BODY 2 /* reading message body */
-#define MS_DISCARD 3 /* discarding rest of message */
-
-void
-collect(fp, smtpmode, hdrp, e)
- FILE *fp;
- bool smtpmode;
- HDR **hdrp;
- register ENVELOPE *e;
-{
- register FILE *volatile tf;
- volatile bool ignrdot = smtpmode ? FALSE : IgnrDot;
- volatile time_t dbto = smtpmode ? TimeOuts.to_datablock : 0;
- register char *volatile bp;
- volatile int c = EOF;
- volatile bool inputerr = FALSE;
- bool headeronly;
- char *volatile buf;
- volatile int buflen;
- volatile int istate;
- volatile int mstate;
- u_char *volatile pbp;
- int hdrslen = 0;
- u_char peekbuf[8];
- char dfname[MAXQFNAME];
- char bufbuf[MAXLINE];
- extern bool isheader __P((char *));
- extern void tferror __P((FILE *volatile, ENVELOPE *));
-
- headeronly = hdrp != NULL;
-
- /*
- ** Create the temp file name and create the file.
- */
-
- if (!headeronly)
- {
- int tfd;
- struct stat stbuf;
-
- strcpy(dfname, queuename(e, 'd'));
- tfd = dfopen(dfname, O_WRONLY|O_CREAT|O_TRUNC, FileMode, SFF_ANYFILE);
- if (tfd < 0 || (tf = fdopen(tfd, "w")) == NULL)
- {
- syserr("Cannot create %s", dfname);
- e->e_flags |= EF_NO_BODY_RETN;
- finis(TRUE, ExitStat);
- }
- if (fstat(fileno(tf), &stbuf) < 0)
- e->e_dfino = -1;
- else
- {
- e->e_dfdev = stbuf.st_dev;
- e->e_dfino = stbuf.st_ino;
- }
- HasEightBits = FALSE;
- e->e_msgsize = 0;
- e->e_flags |= EF_HAS_DF;
- }
-
- /*
- ** Tell ARPANET to go ahead.
- */
-
- if (smtpmode)
- message("354 Enter mail, end with \".\" on a line by itself");
-
- if (tTd(30, 2))
- printf("collect\n");
-
- /*
- ** Read the message.
- **
- ** This is done using two interleaved state machines.
- ** The input state machine is looking for things like
- ** hidden dots; the message state machine is handling
- ** the larger picture (e.g., header versus body).
- */
-
- buf = bp = bufbuf;
- buflen = sizeof bufbuf;
- pbp = peekbuf;
- istate = IS_BOL;
- mstate = SaveFrom ? MS_HEADER : MS_UFROM;
- CollectProgress = FALSE;
-
- if (dbto != 0)
- {
- /* handle possible input timeout */
- if (setjmp(CtxCollectTimeout) != 0)
- {
- if (LogLevel > 2)
- sm_syslog(LOG_NOTICE, e->e_id,
- "timeout waiting for input from %s during message collect",
- CurHostName ? CurHostName : "<local machine>");
- errno = 0;
- usrerr("451 timeout waiting for input during message collect");
- goto readerr;
- }
- CollectTimeout = setevent(dbto, collecttimeout, dbto);
- }
-
- for (;;)
- {
- if (tTd(30, 35))
- printf("top, istate=%d, mstate=%d\n", istate, mstate);
- for (;;)
- {
- if (pbp > peekbuf)
- c = *--pbp;
- else
- {
- while (!feof(fp) && !ferror(fp))
- {
- errno = 0;
- c = getc(fp);
- if (errno != EINTR)
- break;
- clearerr(fp);
- }
- CollectProgress = TRUE;
- if (TrafficLogFile != NULL && !headeronly)
- {
- if (istate == IS_BOL)
- fprintf(TrafficLogFile, "%05d <<< ",
- (int) getpid());
- if (c == EOF)
- fprintf(TrafficLogFile, "[EOF]\n");
- else
- putc(c, TrafficLogFile);
- }
- if (c == EOF)
- goto readerr;
- if (SevenBitInput)
- c &= 0x7f;
- else
- HasEightBits |= bitset(0x80, c);
- }
- if (tTd(30, 94))
- printf("istate=%d, c=%c (0x%x)\n",
- istate, c, c);
- switch (istate)
- {
- case IS_BOL:
- if (c == '.')
- {
- istate = IS_DOT;
- continue;
- }
- break;
-
- case IS_DOT:
- if (c == '\n' && !ignrdot &&
- !bitset(EF_NL_NOT_EOL, e->e_flags))
- goto readerr;
- else if (c == '\r' &&
- !bitset(EF_CRLF_NOT_EOL, e->e_flags))
- {
- istate = IS_DOTCR;
- continue;
- }
- else if (c != '.' ||
- (OpMode != MD_SMTP &&
- OpMode != MD_DAEMON &&
- OpMode != MD_ARPAFTP))
- {
- *pbp++ = c;
- c = '.';
- }
- break;
-
- case IS_DOTCR:
- if (c == '\n' && !ignrdot)
- goto readerr;
- else
- {
- /* push back the ".\rx" */
- *pbp++ = c;
- *pbp++ = '\r';
- c = '.';
- }
- break;
-
- case IS_CR:
- if (c == '\n')
- istate = IS_BOL;
- else
- {
- ungetc(c, fp);
- c = '\r';
- istate = IS_NORM;
- }
- goto bufferchar;
- }
-
- if (c == '\r' && !bitset(EF_CRLF_NOT_EOL, e->e_flags))
- {
- istate = IS_CR;
- continue;
- }
- else if (c == '\n' && !bitset(EF_NL_NOT_EOL, e->e_flags))
- istate = IS_BOL;
- else
- istate = IS_NORM;
-
-bufferchar:
- if (!headeronly)
- e->e_msgsize++;
- switch (mstate)
- {
- case MS_BODY:
- /* just put the character out */
- if (MaxMessageSize <= 0 ||
- e->e_msgsize <= MaxMessageSize)
- putc(c, tf);
-
- /* fall through */
-
- case MS_DISCARD:
- continue;
- }
-
- /* header -- buffer up */
- if (bp >= &buf[buflen - 2])
- {
- char *obuf;
-
- if (mstate != MS_HEADER)
- break;
-
- /* out of space for header */
- obuf = buf;
- if (buflen < MEMCHUNKSIZE)
- buflen *= 2;
- else
- buflen += MEMCHUNKSIZE;
- buf = xalloc(buflen);
- bcopy(obuf, buf, bp - obuf);
- bp = &buf[bp - obuf];
- if (obuf != bufbuf)
- free(obuf);
- }
- if (c >= 0200 && c <= 0237)
- {
-#if 0 /* causes complaints -- figure out something for 8.9 */
- usrerr("Illegal character 0x%x in header", c);
-#endif
- }
- else if (c != '\0')
- {
- *bp++ = c;
- if (MaxHeadersLength > 0 &&
- ++hdrslen > MaxHeadersLength)
- {
- sm_syslog(LOG_NOTICE, e->e_id,
- "headers too large (%d max) from %s during message collect",
- MaxHeadersLength,
- CurHostName != NULL ? CurHostName : "localhost");
- errno = 0;
- e->e_flags |= EF_CLRQUEUE;
- e->e_status = "5.6.0";
- usrerr("552 Headers too large (%d max)",
- MaxHeadersLength);
- mstate = MS_DISCARD;
- }
- }
- if (istate == IS_BOL)
- break;
- }
- *bp = '\0';
-
-nextstate:
- if (tTd(30, 35))
- printf("nextstate, istate=%d, mstate=%d, line = \"%s\"\n",
- istate, mstate, buf);
- switch (mstate)
- {
- case MS_UFROM:
- mstate = MS_HEADER;
-#ifndef NOTUNIX
- if (strncmp(buf, "From ", 5) == 0)
- {
- extern void eatfrom __P((char *volatile, ENVELOPE *));
-
- bp = buf;
- eatfrom(buf, e);
- continue;
- }
-#endif
- /* fall through */
-
- case MS_HEADER:
- if (!isheader(buf))
- {
- mstate = MS_BODY;
- goto nextstate;
- }
-
- /* check for possible continuation line */
- do
- {
- clearerr(fp);
- errno = 0;
- c = getc(fp);
- } while (errno == EINTR);
- if (c != EOF)
- ungetc(c, fp);
- if (c == ' ' || c == '\t')
- {
- /* yep -- defer this */
- continue;
- }
-
- /* trim off trailing CRLF or NL */
- if (*--bp != '\n' || *--bp != '\r')
- bp++;
- *bp = '\0';
-
- if (bitset(H_EOH, chompheader(buf, FALSE, hdrp, e)))
- {
- mstate = MS_BODY;
- goto nextstate;
- }
- break;
-
- case MS_BODY:
- if (tTd(30, 1))
- printf("EOH\n");
- if (headeronly)
- goto readerr;
- bp = buf;
-
- /* toss blank line */
- if ((!bitset(EF_CRLF_NOT_EOL, e->e_flags) &&
- bp[0] == '\r' && bp[1] == '\n') ||
- (!bitset(EF_NL_NOT_EOL, e->e_flags) &&
- bp[0] == '\n'))
- {
- break;
- }
-
- /* if not a blank separator, write it out */
- if (MaxMessageSize <= 0 ||
- e->e_msgsize <= MaxMessageSize)
- {
- while (*bp != '\0')
- putc(*bp++, tf);
- }
- break;
- }
- bp = buf;
- }
-
-readerr:
- if ((feof(fp) && smtpmode) || ferror(fp))
- {
- const char *errmsg = errstring(errno);
-
- if (tTd(30, 1))
- printf("collect: premature EOM: %s\n", errmsg);
- if (LogLevel >= 2)
- sm_syslog(LOG_WARNING, e->e_id,
- "collect: premature EOM: %s", errmsg);
- inputerr = TRUE;
- }
-
- /* reset global timer */
- clrevent(CollectTimeout);
-
- if (headeronly)
- return;
-
- if (tf != NULL &&
- (fflush(tf) != 0 || ferror(tf) ||
- (SuperSafe && fsync(fileno(tf)) < 0) ||
- fclose(tf) < 0))
- {
- tferror(tf, e);
- flush_errors(TRUE);
- finis(TRUE, ExitStat);
- }
-
- /* An EOF when running SMTP is an error */
- if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
- {
- char *host;
- char *problem;
-
- host = RealHostName;
- if (host == NULL)
- host = "localhost";
-
- if (feof(fp))
- problem = "unexpected close";
- else if (ferror(fp))
- problem = "I/O error";
- else
- problem = "read timeout";
- if (LogLevel > 0 && feof(fp))
- sm_syslog(LOG_NOTICE, e->e_id,
- "collect: %s on connection from %.100s, sender=%s: %s",
- problem, host,
- shortenstring(e->e_from.q_paddr, MAXSHORTSTR),
- errstring(errno));
- if (feof(fp))
- usrerr("451 collect: %s on connection from %s, from=%s",
- problem, host,
- shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
- else
- syserr("451 collect: %s on connection from %s, from=%s",
- problem, host,
- shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
-
- /* don't return an error indication */
- e->e_to = NULL;
- e->e_flags &= ~EF_FATALERRS;
- e->e_flags |= EF_CLRQUEUE;
-
- /* and don't try to deliver the partial message either */
- if (InChild)
- ExitStat = EX_QUIT;
- finis(TRUE, ExitStat);
- }
-
- /*
- ** Find out some information from the headers.
- ** Examples are who is the from person & the date.
- */
-
- eatheader(e, TRUE);
-
- if (GrabTo && e->e_sendqueue == NULL)
- usrerr("No recipient addresses found in header");
-
- /* collect statistics */
- if (OpMode != MD_VERIFY)
- markstats(e, (ADDRESS *) NULL, FALSE);
-
-#if _FFR_DSN_RRT_OPTION
- /*
- ** If we have a Return-Receipt-To:, turn it into a DSN.
- */
-
- if (RrtImpliesDsn && hvalue("return-receipt-to", e->e_header) != NULL)
- {
- ADDRESS *q;
-
- for (q = e->e_sendqueue; q != NULL; q = q->q_next)
- if (!bitset(QHASNOTIFY, q->q_flags))
- q->q_flags |= QHASNOTIFY|QPINGONSUCCESS;
- }
-#endif
-
- /*
- ** Add an Apparently-To: line if we have no recipient lines.
- */
-
- if (hvalue("to", e->e_header) != NULL ||
- hvalue("cc", e->e_header) != NULL ||
- hvalue("apparently-to", e->e_header) != NULL)
- {
- /* have a valid recipient header -- delete Bcc: headers */
- e->e_flags |= EF_DELETE_BCC;
- }
- else if (hvalue("bcc", e->e_header) == NULL)
- {
- /* no valid recipient headers */
- register ADDRESS *q;
- char *hdr = NULL;
-
- /* create an Apparently-To: field */
- /* that or reject the message.... */
- switch (NoRecipientAction)
- {
- case NRA_ADD_APPARENTLY_TO:
- hdr = "Apparently-To";
- break;
-
- case NRA_ADD_TO:
- hdr = "To";
- break;
-
- case NRA_ADD_BCC:
- addheader("Bcc", " ", &e->e_header);
- break;
-
- case NRA_ADD_TO_UNDISCLOSED:
- addheader("To", "undisclosed-recipients:;", &e->e_header);
- break;
- }
-
- if (hdr != NULL)
- {
- for (q = e->e_sendqueue; q != NULL; q = q->q_next)
- {
- if (q->q_alias != NULL)
- continue;
- if (tTd(30, 3))
- printf("Adding %s: %s\n",
- hdr, q->q_paddr);
- addheader(hdr, q->q_paddr, &e->e_header);
- }
- }
- }
-
- /* check for message too large */
- if (MaxMessageSize > 0 && e->e_msgsize > MaxMessageSize)
- {
- e->e_flags |= EF_NO_BODY_RETN|EF_CLRQUEUE;
- e->e_status = "5.2.3";
- usrerr("552 Message exceeds maximum fixed size (%ld)",
- MaxMessageSize);
- if (LogLevel > 6)
- sm_syslog(LOG_NOTICE, e->e_id,
- "message size (%ld) exceeds maximum (%ld)",
- e->e_msgsize, MaxMessageSize);
- }
-
- /* check for illegal 8-bit data */
- if (HasEightBits)
- {
- e->e_flags |= EF_HAS8BIT;
- if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode) &&
- !bitset(EF_IS_MIME, e->e_flags))
- {
- e->e_status = "5.6.1";
- usrerr("554 Eight bit data not allowed");
- }
- }
- else
- {
- /* if it claimed to be 8 bits, well, it lied.... */
- if (e->e_bodytype != NULL &&
- strcasecmp(e->e_bodytype, "8BITMIME") == 0)
- e->e_bodytype = "7BIT";
- }
-
- if ((e->e_dfp = fopen(dfname, "r")) == NULL)
- {
- /* we haven't acked receipt yet, so just chuck this */
- syserr("Cannot reopen %s", dfname);
- finis(TRUE, ExitStat);
- }
-}
-
-
-static void
-collecttimeout(timeout)
- time_t timeout;
-{
- /* if no progress was made, die now */
- if (!CollectProgress)
- longjmp(CtxCollectTimeout, 1);
-
- /* otherwise reset the timeout */
- CollectTimeout = setevent(timeout, collecttimeout, timeout);
- CollectProgress = FALSE;
-}
- /*
-** TFERROR -- signal error on writing the temporary file.
-**
-** Parameters:
-** tf -- the file pointer for the temporary file.
-** e -- the current envelope.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Gives an error message.
-** Arranges for following output to go elsewhere.
-*/
-
-void
-tferror(tf, e)
- FILE *volatile tf;
- register ENVELOPE *e;
-{
- setstat(EX_IOERR);
- if (errno == ENOSPC)
- {
-#if STAT64 > 0
- struct stat64 st;
-#else
- struct stat st;
-#endif
- long avail;
- long bsize;
- extern long freediskspace __P((char *, long *));
-
- e->e_flags |= EF_NO_BODY_RETN;
-
- if (
-#if STAT64 > 0
- fstat64(fileno(tf), &st)
-#else
- fstat(fileno(tf), &st)
-#endif
- < 0)
- st.st_size = 0;
- (void) freopen(queuename(e, 'd'), "w", tf);
- if (st.st_size <= 0)
- fprintf(tf, "\n*** Mail could not be accepted");
- else if (sizeof st.st_size > sizeof (long))
- fprintf(tf, "\n*** Mail of at least %s bytes could not be accepted\n",
- quad_to_string(st.st_size));
- else
- fprintf(tf, "\n*** Mail of at least %lu bytes could not be accepted\n",
- (unsigned long) st.st_size);
- fprintf(tf, "*** at %s due to lack of disk space for temp file.\n",
- MyHostName);
- avail = freediskspace(QueueDir, &bsize);
- if (avail > 0)
- {
- if (bsize > 1024)
- avail *= bsize / 1024;
- else if (bsize < 1024)
- avail /= 1024 / bsize;
- fprintf(tf, "*** Currently, %ld kilobytes are available for mail temp files.\n",
- avail);
- }
- e->e_status = "4.3.1";
- usrerr("452 Out of disk space for temp file");
- }
- else
- syserr("collect: Cannot write tf%s", e->e_id);
- if (freopen("/dev/null", "w", tf) == NULL)
- sm_syslog(LOG_ERR, e->e_id,
- "tferror: freopen(\"/dev/null\") failed: %s",
- errstring(errno));
-}
- /*
-** EATFROM -- chew up a UNIX style from line and process
-**
-** This does indeed make some assumptions about the format
-** of UNIX messages.
-**
-** Parameters:
-** fm -- the from line.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** extracts what information it can from the header,
-** such as the date.
-*/
-
-# ifndef NOTUNIX
-
-char *DowList[] =
-{
- "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
-};
-
-char *MonthList[] =
-{
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
- NULL
-};
-
-void
-eatfrom(fm, e)
- char *volatile fm;
- register ENVELOPE *e;
-{
- register char *p;
- register char **dt;
-
- if (tTd(30, 2))
- printf("eatfrom(%s)\n", fm);
-
- /* find the date part */
- p = fm;
- while (*p != '\0')
- {
- /* skip a word */
- while (*p != '\0' && *p != ' ')
- p++;
- while (*p == ' ')
- p++;
- if (!(isascii(*p) && isupper(*p)) ||
- p[3] != ' ' || p[13] != ':' || p[16] != ':')
- continue;
-
- /* we have a possible date */
- for (dt = DowList; *dt != NULL; dt++)
- if (strncmp(*dt, p, 3) == 0)
- break;
- if (*dt == NULL)
- continue;
-
- for (dt = MonthList; *dt != NULL; dt++)
- if (strncmp(*dt, &p[4], 3) == 0)
- break;
- if (*dt != NULL)
- break;
- }
-
- if (*p != '\0')
- {
- char *q;
-
- /* we have found a date */
- q = xalloc(25);
- (void) strncpy(q, p, 25);
- q[24] = '\0';
- q = arpadate(q);
- define('a', newstr(q), e);
- }
-}
-
-# endif /* NOTUNIX */
diff --git a/src/conf.c b/src/conf.c
deleted file mode 100644
index 3cfa73b..0000000
--- a/src/conf.c
+++ /dev/null
@@ -1,4938 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)conf.c 8.452 (Berkeley) 1/26/1999";
-#endif /* not lint */
-
-# include "sendmail.h"
-# include "pathnames.h"
-# include <sys/ioctl.h>
-# include <sys/param.h>
-# include <limits.h>
-
-/*
-** CONF.C -- Sendmail Configuration Tables.
-**
-** Defines the configuration of this installation.
-**
-** Configuration Variables:
-** HdrInfo -- a table describing well-known header fields.
-** Each entry has the field name and some flags,
-** which are described in sendmail.h.
-**
-** Notes:
-** I have tried to put almost all the reasonable
-** configuration information into the configuration
-** file read at runtime. My intent is that anything
-** here is a function of the version of UNIX you
-** are running, or is really static -- for example
-** the headers are a superset of widely used
-** protocols. If you find yourself playing with
-** this file too much, you may be making a mistake!
-*/
-
-
-/*
-** Header info table
-** Final (null) entry contains the flags used for any other field.
-**
-** Not all of these are actually handled specially by sendmail
-** at this time. They are included as placeholders, to let
-** you know that "someday" I intend to have sendmail do
-** something with them.
-*/
-
-struct hdrinfo HdrInfo[] =
-{
- /* originator fields, most to least significant */
- { "resent-sender", H_FROM|H_RESENT },
- { "resent-from", H_FROM|H_RESENT },
- { "resent-reply-to", H_FROM|H_RESENT },
- { "sender", H_FROM },
- { "from", H_FROM },
- { "reply-to", H_FROM },
- { "errors-to", H_FROM|H_ERRORSTO },
- { "full-name", H_ACHECK },
- { "return-receipt-to", H_RECEIPTTO },
-
- /* destination fields */
- { "to", H_RCPT },
- { "resent-to", H_RCPT|H_RESENT },
- { "cc", H_RCPT },
- { "resent-cc", H_RCPT|H_RESENT },
- { "bcc", H_RCPT|H_BCC },
- { "resent-bcc", H_RCPT|H_BCC|H_RESENT },
- { "apparently-to", H_RCPT },
-
- /* message identification and control */
- { "message-id", 0 },
- { "resent-message-id", H_RESENT },
- { "message", H_EOH },
- { "text", H_EOH },
-
- /* date fields */
- { "date", 0 },
- { "resent-date", H_RESENT },
-
- /* trace fields */
- { "received", H_TRACE|H_FORCE },
- { "x400-received", H_TRACE|H_FORCE },
- { "via", H_TRACE|H_FORCE },
- { "mail-from", H_TRACE|H_FORCE },
-
- /* miscellaneous fields */
- { "comments", H_FORCE|H_ENCODABLE },
- { "return-path", H_FORCE|H_ACHECK },
- { "content-transfer-encoding", H_CTE },
- { "content-type", H_CTYPE },
- { "content-length", H_ACHECK },
- { "subject", H_ENCODABLE },
-
- { NULL, 0 }
-};
-
-
-
-/*
-** Privacy values
-*/
-
-struct prival PrivacyValues[] =
-{
- { "public", PRIV_PUBLIC },
- { "needmailhelo", PRIV_NEEDMAILHELO },
- { "needexpnhelo", PRIV_NEEDEXPNHELO },
- { "needvrfyhelo", PRIV_NEEDVRFYHELO },
- { "noexpn", PRIV_NOEXPN },
- { "novrfy", PRIV_NOVRFY },
- { "restrictmailq", PRIV_RESTRICTMAILQ },
- { "restrictqrun", PRIV_RESTRICTQRUN },
- { "noetrn", PRIV_NOETRN },
- { "noverb", PRIV_NOVERB },
- { "authwarnings", PRIV_AUTHWARNINGS },
- { "noreceipts", PRIV_NORECEIPTS },
- { "goaway", PRIV_GOAWAY },
- { NULL, 0 }
-};
-
-/*
-** DontBlameSendmail values
-*/
-struct dbsval DontBlameSendmailValues[] =
-{
- { "safe", DBS_SAFE },
- { "assumesafechown", DBS_ASSUMESAFECHOWN },
- { "groupwritabledirpathsafe", DBS_GROUPWRITABLEDIRPATHSAFE },
- { "groupwritableforwardfilesafe",
- DBS_GROUPWRITABLEFORWARDFILESAFE },
- { "groupwritableincludefilesafe",
- DBS_GROUPWRITABLEINCLUDEFILESAFE },
- { "groupwritablealiasfile", DBS_GROUPWRITABLEALIASFILE },
- { "worldwritablealiasfile", DBS_WORLDWRITABLEALIASFILE },
- { "forwardfileinunsafedirpath", DBS_FORWARDFILEINUNSAFEDIRPATH },
- { "includefileinunsafedirpath", DBS_INCLUDEFILEINUNSAFEDIRPATH },
- { "mapinunsafedirpath", DBS_MAPINUNSAFEDIRPATH },
- { "linkedaliasfileinwritabledir",
- DBS_LINKEDALIASFILEINWRITABLEDIR },
- { "linkedclassfileinwritabledir",
- DBS_LINKEDCLASSFILEINWRITABLEDIR },
- { "linkedforwardfileinwritabledir",
- DBS_LINKEDFORWARDFILEINWRITABLEDIR },
- { "linkedincludefileinwritabledir",
- DBS_LINKEDINCLUDEFILEINWRITABLEDIR },
- { "linkedmapinwritabledir", DBS_LINKEDMAPINWRITABLEDIR },
- { "linkedserviceswitchfileinwritabledir",
- DBS_LINKEDSERVICESWITCHFILEINWRITABLEDIR },
- { "filedeliverytohardlink", DBS_FILEDELIVERYTOHARDLINK },
- { "filedeliverytosymlink", DBS_FILEDELIVERYTOSYMLINK },
- { "writemaptohardlink", DBS_WRITEMAPTOHARDLINK },
- { "writemaptosymlink", DBS_WRITEMAPTOSYMLINK },
- { "writestatstohardlink", DBS_WRITESTATSTOHARDLINK },
- { "writestatstosymlink", DBS_WRITESTATSTOSYMLINK },
- { "forwardfileingroupwritabledirpath",
- DBS_FORWARDFILEINGROUPWRITABLEDIRPATH },
- { "includefileingroupwritabledirpath",
- DBS_INCLUDEFILEINGROUPWRITABLEDIRPATH },
- { "classfileinunsafedirpath", DBS_CLASSFILEINUNSAFEDIRPATH },
- { "errorheaderinunsafedirpath", DBS_ERRORHEADERINUNSAFEDIRPATH },
- { "helpfileinunsafedirpath", DBS_HELPFILEINUNSAFEDIRPATH },
- { "forwardfileinunsafedirpathsafe",
- DBS_FORWARDFILEINUNSAFEDIRPATHSAFE },
- { "includefileinunsafedirpathsafe",
- DBS_INCLUDEFILEINUNSAFEDIRPATHSAFE },
- { "runprograminunsafedirpath", DBS_RUNPROGRAMINUNSAFEDIRPATH },
- { "runwritableprogram", DBS_RUNWRITABLEPROGRAM },
- { NULL, 0 }
-};
-
-
-/*
-** Miscellaneous stuff.
-*/
-
-int DtableSize = 50; /* max open files; reset in 4.2bsd */
- /*
-** SETDEFAULTS -- set default values
-**
-** Because of the way freezing is done, these must be initialized
-** using direct code.
-**
-** Parameters:
-** e -- the default envelope.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Initializes a bunch of global variables to their
-** default values.
-*/
-
-#define MINUTES * 60
-#define HOURS * 60 MINUTES
-#define DAYS * 24 HOURS
-
-#ifndef _PATH_VARTMP
-# define _PATH_VARTMP "/usr/tmp/"
-#endif
-
-#ifndef MAXRULERECURSION
-# define MAXRULERECURSION 50 /* max ruleset recursion depth */
-#endif
-
-void
-setdefaults(e)
- register ENVELOPE *e;
-{
- int i;
- struct passwd *pw;
- char buf[MAXNAME];
- extern void setdefuser __P((void));
- extern void setupmaps __P((void));
- extern void setupmailers __P((void));
- extern void setupheaders __P((void));
-
- SpaceSub = ' '; /* option B */
- QueueLA = 8; /* option x */
- RefuseLA = 12; /* option X */
- WkRecipFact = 30000L; /* option y */
- WkClassFact = 1800L; /* option z */
- WkTimeFact = 90000L; /* option Z */
- QueueFactor = WkRecipFact * 20; /* option q */
- FileMode = (RealUid != geteuid()) ? 0644 : 0600;
- /* option F */
-
- if (((pw = getpwnam("mailnull")) != NULL && pw->pw_uid != 0) ||
- ((pw = getpwnam("sendmail")) != NULL && pw->pw_uid != 0) ||
- ((pw = getpwnam("daemon")) != NULL && pw->pw_uid != 0))
- {
- DefUid = pw->pw_uid; /* option u */
- DefGid = pw->pw_gid; /* option g */
- DefUser = newstr(pw->pw_name);
- }
- else
- {
- DefUid = 1; /* option u */
- DefGid = 1; /* option g */
- setdefuser();
- }
- TrustedUid = 0;
- if (tTd(37, 4))
- printf("setdefaults: DefUser=%s, DefUid=%d, DefGid=%d\n",
- DefUser != NULL ? DefUser : "<1:1>",
- (int) DefUid, (int) DefGid);
- CheckpointInterval = 10; /* option C */
- MaxHopCount = 25; /* option h */
- e->e_sendmode = SM_FORK; /* option d */
- e->e_errormode = EM_PRINT; /* option e */
- SevenBitInput = FALSE; /* option 7 */
- MaxMciCache = 1; /* option k */
- MciCacheTimeout = 5 MINUTES; /* option K */
- LogLevel = 9; /* option L */
- inittimeouts(NULL); /* option r */
- PrivacyFlags = PRIV_PUBLIC; /* option p */
- DontBlameSendmail = DBS_SAFE; /* DontBlameSendmail option */
-#if MIME8TO7
- MimeMode = MM_CVTMIME|MM_PASS8BIT; /* option 8 */
-#else
- MimeMode = MM_PASS8BIT;
-#endif
- for (i = 0; i < MAXTOCLASS; i++)
- {
- TimeOuts.to_q_return[i] = 5 DAYS; /* option T */
- TimeOuts.to_q_warning[i] = 0; /* option T */
- }
- ServiceSwitchFile = "/etc/service.switch";
- ServiceCacheMaxAge = (time_t) 10;
- HostsFile = _PATH_HOSTS;
- PidFile = newstr(_PATH_SENDMAILPID);
- MustQuoteChars = "@,;:\\()[].'";
- MciInfoTimeout = 30 MINUTES;
- MaxRuleRecursion = MAXRULERECURSION;
- MaxAliasRecursion = 10;
- MaxMacroRecursion = 10;
- ColonOkInAddr = TRUE;
- DontLockReadFiles = TRUE;
- DoubleBounceAddr = "postmaster";
- MaxHeadersLength = MAXHDRSLEN;
- snprintf(buf, sizeof buf, "%s%sdead.letter",
- _PATH_VARTMP,
- _PATH_VARTMP[sizeof _PATH_VARTMP - 2] == '/' ? "" : "/");
- DeadLetterDrop = newstr(buf);
-#ifdef HESIOD_INIT
- HesiodContext = NULL;
-#endif
- ControlSocketName = NULL;
- setupmaps();
- setupmailers();
- setupheaders();
-}
-
-
-/*
-** SETDEFUSER -- set/reset DefUser using DefUid (for initgroups())
-*/
-
-void
-setdefuser()
-{
- struct passwd *defpwent;
- static char defuserbuf[40];
-
- DefUser = defuserbuf;
- defpwent = sm_getpwuid(DefUid);
- snprintf(defuserbuf, sizeof defuserbuf, "%s",
- defpwent == NULL ? "nobody" : defpwent->pw_name);
- if (tTd(37, 4))
- printf("setdefuser: DefUid=%d, DefUser=%s\n",
- (int) DefUid, DefUser);
-}
- /*
-** SETUPMAILERS -- initialize default mailers
-*/
-
-void
-setupmailers()
-{
- char buf[100];
-
- strcpy(buf, "prog, P=/bin/sh, F=lsoDq9, T=DNS/RFC822/X-Unix, A=sh -c \201u");
- makemailer(buf);
-
- strcpy(buf, "*file*, P=[FILE], F=lsDFMPEouq9, T=DNS/RFC822/X-Unix, A=FILE \201u");
- makemailer(buf);
-
- strcpy(buf, "*include*, P=/dev/null, F=su, A=INCLUDE \201u");
- makemailer(buf);
-}
- /*
-** SETUPMAPS -- set up map classes
-*/
-
-#define MAPDEF(name, ext, flags, parse, open, close, lookup, store) \
- { \
- extern bool parse __P((MAP *, char *)); \
- extern bool open __P((MAP *, int)); \
- extern void close __P((MAP *)); \
- extern char *lookup __P((MAP *, char *, char **, int *)); \
- extern void store __P((MAP *, char *, char *)); \
- s = stab(name, ST_MAPCLASS, ST_ENTER); \
- s->s_mapclass.map_cname = name; \
- s->s_mapclass.map_ext = ext; \
- s->s_mapclass.map_cflags = flags; \
- s->s_mapclass.map_parse = parse; \
- s->s_mapclass.map_open = open; \
- s->s_mapclass.map_close = close; \
- s->s_mapclass.map_lookup = lookup; \
- s->s_mapclass.map_store = store; \
- }
-
-void
-setupmaps()
-{
- register STAB *s;
-
-#ifdef NEWDB
- MAPDEF("hash", ".db", MCF_ALIASOK|MCF_REBUILDABLE,
- map_parseargs, hash_map_open, db_map_close,
- db_map_lookup, db_map_store);
-
- MAPDEF("btree", ".db", MCF_ALIASOK|MCF_REBUILDABLE,
- map_parseargs, bt_map_open, db_map_close,
- db_map_lookup, db_map_store);
-#endif
-
-#ifdef NDBM
- MAPDEF("dbm", ".dir", MCF_ALIASOK|MCF_REBUILDABLE,
- map_parseargs, ndbm_map_open, ndbm_map_close,
- ndbm_map_lookup, ndbm_map_store);
-#endif
-
-#ifdef NIS
- MAPDEF("nis", NULL, MCF_ALIASOK,
- map_parseargs, nis_map_open, null_map_close,
- nis_map_lookup, null_map_store);
-#endif
-
-#ifdef NISPLUS
- MAPDEF("nisplus", NULL, MCF_ALIASOK,
- map_parseargs, nisplus_map_open, null_map_close,
- nisplus_map_lookup, null_map_store);
-#endif
-#ifdef LDAPMAP
- MAPDEF("ldapx", NULL, 0,
- ldap_map_parseargs, ldap_map_open, ldap_map_close,
- ldap_map_lookup, null_map_store);
-#endif
-
-#ifdef HESIOD
- MAPDEF("hesiod", NULL, MCF_ALIASOK|MCF_ALIASONLY,
- map_parseargs, hes_map_open, null_map_close,
- hes_map_lookup, null_map_store);
-#endif
-
-#if NETINFO
- MAPDEF("netinfo", NULL, MCF_ALIASOK,
- map_parseargs, ni_map_open, null_map_close,
- ni_map_lookup, null_map_store);
-#endif
-
-#if 0
- MAPDEF("dns", NULL, 0,
- dns_map_init, null_map_open, null_map_close,
- dns_map_lookup, null_map_store);
-#endif
-
-#if NAMED_BIND
- /* best MX DNS lookup */
- MAPDEF("bestmx", NULL, MCF_OPTFILE,
- map_parseargs, null_map_open, null_map_close,
- bestmx_map_lookup, null_map_store);
-#endif
-
- MAPDEF("host", NULL, 0,
- host_map_init, null_map_open, null_map_close,
- host_map_lookup, null_map_store);
-
- MAPDEF("text", NULL, MCF_ALIASOK,
- map_parseargs, text_map_open, null_map_close,
- text_map_lookup, null_map_store);
-
- MAPDEF("stab", NULL, MCF_ALIASOK|MCF_ALIASONLY,
- map_parseargs, stab_map_open, null_map_close,
- stab_map_lookup, stab_map_store);
-
- MAPDEF("implicit", NULL, MCF_ALIASOK|MCF_ALIASONLY|MCF_REBUILDABLE,
- map_parseargs, impl_map_open, impl_map_close,
- impl_map_lookup, impl_map_store);
-
- /* access to system passwd file */
- MAPDEF("user", NULL, MCF_OPTFILE,
- map_parseargs, user_map_open, null_map_close,
- user_map_lookup, null_map_store);
-
- /* dequote map */
- MAPDEF("dequote", NULL, 0,
- dequote_init, null_map_open, null_map_close,
- dequote_map, null_map_store);
-
-#ifdef MAP_REGEX
- MAPDEF("regex", NULL, 0,
- regex_map_init, null_map_open, null_map_close,
- regex_map_lookup, null_map_store);
-#endif
-
-#if USERDB
- /* user database */
- MAPDEF("userdb", ".db", 0,
- map_parseargs, null_map_open, null_map_close,
- udb_map_lookup, null_map_store);
-#endif
-
- /* arbitrary programs */
- MAPDEF("program", NULL, MCF_ALIASOK,
- map_parseargs, null_map_open, null_map_close,
- prog_map_lookup, null_map_store);
-
- /* sequenced maps */
- MAPDEF("sequence", NULL, MCF_ALIASOK,
- seq_map_parse, null_map_open, null_map_close,
- seq_map_lookup, seq_map_store);
-
- /* switched interface to sequenced maps */
- MAPDEF("switch", NULL, MCF_ALIASOK,
- map_parseargs, switch_map_open, null_map_close,
- seq_map_lookup, seq_map_store);
-
- /* null map lookup -- really for internal use only */
- MAPDEF("null", NULL, MCF_ALIASOK|MCF_OPTFILE,
- map_parseargs, null_map_open, null_map_close,
- null_map_lookup, null_map_store);
-
-#if _FFR_MAP_SYSLOG
- /* syslog map -- logs information to syslog */
- MAPDEF("syslog", NULL, 0,
- syslog_map_parseargs, null_map_open, null_map_close,
- syslog_map_lookup, null_map_store);
-#endif
-}
-
-#undef MAPDEF
- /*
-** INITHOSTMAPS -- initial host-dependent maps
-**
-** This should act as an interface to any local service switch
-** provided by the host operating system.
-**
-** Parameters:
-** none
-**
-** Returns:
-** none
-**
-** Side Effects:
-** Should define maps "host" and "users" as necessary
-** for this OS. If they are not defined, they will get
-** a default value later. It should check to make sure
-** they are not defined first, since it's possible that
-** the config file has provided an override.
-*/
-
-void
-inithostmaps()
-{
- register int i;
- int nmaps;
- char *maptype[MAXMAPSTACK];
- short mapreturn[MAXMAPACTIONS];
- char buf[MAXLINE];
-
- /*
- ** Set up default hosts maps.
- */
-
-#if 0
- nmaps = switch_map_find("hosts", maptype, mapreturn);
- for (i = 0; i < nmaps; i++)
- {
- if (strcmp(maptype[i], "files") == 0 &&
- stab("hosts.files", ST_MAP, ST_FIND) == NULL)
- {
- strcpy(buf, "hosts.files text -k 0 -v 1 /etc/hosts");
- (void) makemapentry(buf);
- }
-#if NAMED_BIND
- else if (strcmp(maptype[i], "dns") == 0 &&
- stab("hosts.dns", ST_MAP, ST_FIND) == NULL)
- {
- strcpy(buf, "hosts.dns dns A");
- (void) makemapentry(buf);
- }
-#endif
-#ifdef NISPLUS
- else if (strcmp(maptype[i], "nisplus") == 0 &&
- stab("hosts.nisplus", ST_MAP, ST_FIND) == NULL)
- {
- strcpy(buf, "hosts.nisplus nisplus -k name -v address -d hosts.org_dir");
- (void) makemapentry(buf);
- }
-#endif
-#ifdef NIS
- else if (strcmp(maptype[i], "nis") == 0 &&
- stab("hosts.nis", ST_MAP, ST_FIND) == NULL)
- {
- strcpy(buf, "hosts.nis nis -d -k 0 -v 1 hosts.byname");
- (void) makemapentry(buf);
- }
-#endif
-#if NETINFO
- else if (strcmp(maptype[i], "netinfo") == 0) &&
- stab("hosts.netinfo", ST_MAP, ST_FIND) == NULL)
- {
- strcpy(buf, "hosts.netinfo netinfo -v name /machines");
- (void) makemapentry(buf);
- }
-#endif
- }
-#endif
-
- /*
- ** Make sure we have a host map.
- */
-
- if (stab("host", ST_MAP, ST_FIND) == NULL)
- {
- /* user didn't initialize: set up host map */
- strcpy(buf, "host host");
-#if NAMED_BIND
- if (ConfigLevel >= 2)
- strcat(buf, " -a.");
-#endif
- (void) makemapentry(buf);
- }
-
- /*
- ** Set up default aliases maps
- */
-
- nmaps = switch_map_find("aliases", maptype, mapreturn);
- for (i = 0; i < nmaps; i++)
- {
- if (strcmp(maptype[i], "files") == 0 &&
- stab("aliases.files", ST_MAP, ST_FIND) == NULL)
- {
- strcpy(buf, "aliases.files null");
- (void) makemapentry(buf);
- }
-#ifdef NISPLUS
- else if (strcmp(maptype[i], "nisplus") == 0 &&
- stab("aliases.nisplus", ST_MAP, ST_FIND) == NULL)
- {
- strcpy(buf, "aliases.nisplus nisplus -kalias -vexpansion -d mail_aliases.org_dir");
- (void) makemapentry(buf);
- }
-#endif
-#ifdef NIS
- else if (strcmp(maptype[i], "nis") == 0 &&
- stab("aliases.nis", ST_MAP, ST_FIND) == NULL)
- {
- strcpy(buf, "aliases.nis nis -d mail.aliases");
- (void) makemapentry(buf);
- }
-#endif
-#ifdef NETINFO
- else if (strcmp(maptype[i], "netinfo") == 0 &&
- stab("aliases.netinfo", ST_MAP, ST_FIND) == NULL)
- {
- strcpy(buf, "aliases.netinfo netinfo -z, /aliases");
- (void) makemapentry(buf);
- }
-#endif
-#ifdef HESIOD
- else if (strcmp(maptype[i], "hesiod") == 0 &&
- stab("aliases.hesiod", ST_MAP, ST_FIND) == NULL)
- {
- strcpy(buf, "aliases.hesiod hesiod aliases");
- (void) makemapentry(buf);
- }
-#endif
- }
- if (stab("aliases", ST_MAP, ST_FIND) == NULL)
- {
- strcpy(buf, "aliases switch aliases");
- (void) makemapentry(buf);
- }
-
-#if 0 /* "user" map class is a better choice */
- /*
- ** Set up default users maps.
- */
-
- nmaps = switch_map_find("passwd", maptype, mapreturn);
- for (i = 0; i < nmaps; i++)
- {
- if (strcmp(maptype[i], "files") == 0 &&
- stab("users.files", ST_MAP, ST_FIND) == NULL)
- {
- strcpy(buf, "users.files text -m -z: -k0 -v6 /etc/passwd");
- (void) makemapentry(buf);
- }
-#ifdef NISPLUS
- else if (strcmp(maptype[i], "nisplus") == 0 &&
- stab("users.nisplus", ST_MAP, ST_FIND) == NULL)
- {
- strcpy(buf, "users.nisplus nisplus -m -kname -vhome -d passwd.org_dir");
- (void) makemapentry(buf);
- }
-#endif
-#ifdef NIS
- else if (strcmp(maptype[i], "nis") == 0 &&
- stab("users.nis", ST_MAP, ST_FIND) == NULL)
- {
- strcpy(buf, "users.nis nis -m -d passwd.byname");
- (void) makemapentry(buf);
- }
-#endif
-#ifdef HESIOD
- else if (strcmp(maptype[i], "hesiod") == 0) &&
- stab("users.hesiod", ST_MAP, ST_FIND) == NULL)
- {
- strcpy(buf, "users.hesiod hesiod");
- (void) makemapentry(buf);
- }
-#endif
- }
- if (stab("users", ST_MAP, ST_FIND) == NULL)
- {
- strcpy(buf, "users switch -m passwd");
- (void) makemapentry(buf);
- }
-#endif
-}
- /*
-** SWITCH_MAP_FIND -- find the list of types associated with a map
-**
-** This is the system-dependent interface to the service switch.
-**
-** Parameters:
-** service -- the name of the service of interest.
-** maptype -- an out-array of strings containing the types
-** of access to use for this service. There can
-** be at most MAXMAPSTACK types for a single service.
-** mapreturn -- an out-array of return information bitmaps
-** for the map.
-**
-** Returns:
-** The number of map types filled in, or -1 for failure.
-*/
-
-#if defined(SOLARIS) || (defined(sony_news) && defined(__svr4))
-# define _USE_SUN_NSSWITCH_
-#endif
-
-#ifdef _USE_SUN_NSSWITCH_
-# include <nsswitch.h>
-#endif
-
-#if defined(ultrix) || (defined(__osf__) && defined(__alpha))
-# define _USE_DEC_SVC_CONF_
-#endif
-
-#ifdef _USE_DEC_SVC_CONF_
-# include <sys/svcinfo.h>
-#endif
-
-int
-switch_map_find(service, maptype, mapreturn)
- char *service;
- char *maptype[MAXMAPSTACK];
- short mapreturn[MAXMAPACTIONS];
-{
- int svcno;
-
-#ifdef _USE_SUN_NSSWITCH_
- struct __nsw_switchconfig *nsw_conf;
- enum __nsw_parse_err pserr;
- struct __nsw_lookup *lk;
- static struct __nsw_lookup lkp0 =
- { "files", {1, 0, 0, 0}, NULL, NULL };
- static struct __nsw_switchconfig lkp_default =
- { 0, "sendmail", 3, &lkp0 };
-
- for (svcno = 0; svcno < MAXMAPACTIONS; svcno++)
- mapreturn[svcno] = 0;
-
- if ((nsw_conf = __nsw_getconfig(service, &pserr)) == NULL)
- lk = lkp_default.lookups;
- else
- lk = nsw_conf->lookups;
- svcno = 0;
- while (lk != NULL)
- {
- maptype[svcno] = lk->service_name;
- if (lk->actions[__NSW_NOTFOUND] == __NSW_RETURN)
- mapreturn[MA_NOTFOUND] |= 1 << svcno;
- if (lk->actions[__NSW_TRYAGAIN] == __NSW_RETURN)
- mapreturn[MA_TRYAGAIN] |= 1 << svcno;
- if (lk->actions[__NSW_UNAVAIL] == __NSW_RETURN)
- mapreturn[MA_TRYAGAIN] |= 1 << svcno;
- svcno++;
- lk = lk->next;
- }
- return svcno;
-#endif
-
-#ifdef _USE_DEC_SVC_CONF_
- struct svcinfo *svcinfo;
- int svc;
-
- for (svcno = 0; svcno < MAXMAPACTIONS; svcno++)
- mapreturn[svcno] = 0;
-
- svcinfo = getsvc();
- if (svcinfo == NULL)
- goto punt;
- if (strcmp(service, "hosts") == 0)
- svc = SVC_HOSTS;
- else if (strcmp(service, "aliases") == 0)
- svc = SVC_ALIASES;
- else if (strcmp(service, "passwd") == 0)
- svc = SVC_PASSWD;
- else
- return -1;
- for (svcno = 0; svcno < SVC_PATHSIZE; svcno++)
- {
- switch (svcinfo->svcpath[svc][svcno])
- {
- case SVC_LOCAL:
- maptype[svcno] = "files";
- break;
-
- case SVC_YP:
- maptype[svcno] = "nis";
- break;
-
- case SVC_BIND:
- maptype[svcno] = "dns";
- break;
-
-#ifdef SVC_HESIOD
- case SVC_HESIOD:
- maptype[svcno] = "hesiod";
- break;
-#endif
-
- case SVC_LAST:
- return svcno;
- }
- }
- return svcno;
-#endif
-
-#if !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_)
- /*
- ** Fall-back mechanism.
- */
-
- STAB *st;
- time_t now = curtime();
-
- for (svcno = 0; svcno < MAXMAPACTIONS; svcno++)
- mapreturn[svcno] = 0;
-
- if ((now - ServiceCacheTime) > (time_t) ServiceCacheMaxAge)
- {
- /* (re)read service switch */
- register FILE *fp;
- int sff = SFF_REGONLY|SFF_OPENASROOT|SFF_NOLOCK;
-
- if (!bitset(DBS_LINKEDSERVICESWITCHFILEINWRITABLEDIR, DontBlameSendmail))
- sff |= SFF_NOWLINK;
-
- if (ConfigFileRead)
- ServiceCacheTime = now;
- fp = safefopen(ServiceSwitchFile, O_RDONLY, 0, sff);
- if (fp != NULL)
- {
- char buf[MAXLINE];
-
- while (fgets(buf, sizeof buf, fp) != NULL)
- {
- register char *p;
-
- p = strpbrk(buf, "#\n");
- if (p != NULL)
- *p = '\0';
- p = strpbrk(buf, " \t");
- if (p != NULL)
- *p++ = '\0';
- if (buf[0] == '\0')
- continue;
- if (p == NULL)
- {
- sm_syslog(LOG_ERR, NOQID,
- "Bad line on %.100s: %.100s",
- ServiceSwitchFile,
- buf);
- continue;
- }
- while (isspace(*p))
- p++;
- if (*p == '\0')
- continue;
-
- /*
- ** Find/allocate space for this service entry.
- ** Space for all of the service strings
- ** are allocated at once. This means
- ** that we only have to free the first
- ** one to free all of them.
- */
-
- st = stab(buf, ST_SERVICE, ST_ENTER);
- if (st->s_service[0] != NULL)
- free((void *) st->s_service[0]);
- p = newstr(p);
- for (svcno = 0; svcno < MAXMAPSTACK; )
- {
- if (*p == '\0')
- break;
- st->s_service[svcno++] = p;
- p = strpbrk(p, " \t");
- if (p == NULL)
- break;
- *p++ = '\0';
- while (isspace(*p))
- p++;
- }
- if (svcno < MAXMAPSTACK)
- st->s_service[svcno] = NULL;
- }
- fclose(fp);
- }
- }
-
- /* look up entry in cache */
- st = stab(service, ST_SERVICE, ST_FIND);
- if (st != NULL && st->s_service[0] != NULL)
- {
- /* extract data */
- svcno = 0;
- while (svcno < MAXMAPSTACK)
- {
- maptype[svcno] = st->s_service[svcno];
- if (maptype[svcno++] == NULL)
- break;
- }
- return --svcno;
- }
-#endif
-
-#if !defined(_USE_SUN_NSSWITCH_)
- /* if the service file doesn't work, use an absolute fallback */
-# ifdef _USE_DEC_SVC_CONF_
- punt:
-# endif
- for (svcno = 0; svcno < MAXMAPACTIONS; svcno++)
- mapreturn[svcno] = 0;
- svcno = 0;
- if (strcmp(service, "aliases") == 0)
- {
- maptype[svcno++] = "files";
-# ifdef AUTO_NIS_ALIASES
-# ifdef NISPLUS
- maptype[svcno++] = "nisplus";
-# endif
-# ifdef NIS
- maptype[svcno++] = "nis";
-# endif
-# endif
- return svcno;
- }
- if (strcmp(service, "hosts") == 0)
- {
-# if NAMED_BIND
- maptype[svcno++] = "dns";
-# else
-# if defined(sun) && !defined(BSD)
- /* SunOS */
- maptype[svcno++] = "nis";
-# endif
-# endif
- maptype[svcno++] = "files";
- return svcno;
- }
- return -1;
-#endif
-}
- /*
-** USERNAME -- return the user id of the logged in user.
-**
-** Parameters:
-** none.
-**
-** Returns:
-** The login name of the logged in user.
-**
-** Side Effects:
-** none.
-**
-** Notes:
-** The return value is statically allocated.
-*/
-
-char *
-username()
-{
- static char *myname = NULL;
- extern char *getlogin();
- register struct passwd *pw;
-
- /* cache the result */
- if (myname == NULL)
- {
- myname = getlogin();
- if (myname == NULL || myname[0] == '\0')
- {
- pw = sm_getpwuid(RealUid);
- if (pw != NULL)
- myname = newstr(pw->pw_name);
- }
- else
- {
- uid_t uid = RealUid;
-
- myname = newstr(myname);
- if ((pw = sm_getpwnam(myname)) == NULL ||
- (uid != 0 && uid != pw->pw_uid))
- {
- pw = sm_getpwuid(uid);
- if (pw != NULL)
- myname = newstr(pw->pw_name);
- }
- }
- if (myname == NULL || myname[0] == '\0')
- {
- syserr("554 Who are you?");
- myname = "postmaster";
- }
- }
-
- return (myname);
-}
- /*
-** TTYPATH -- Get the path of the user's tty
-**
-** Returns the pathname of the user's tty. Returns NULL if
-** the user is not logged in or if s/he has write permission
-** denied.
-**
-** Parameters:
-** none
-**
-** Returns:
-** pathname of the user's tty.
-** NULL if not logged in or write permission denied.
-**
-** Side Effects:
-** none.
-**
-** WARNING:
-** Return value is in a local buffer.
-**
-** Called By:
-** savemail
-*/
-
-char *
-ttypath()
-{
- struct stat stbuf;
- register char *pathn;
- extern char *ttyname();
- extern char *getlogin();
-
- /* compute the pathname of the controlling tty */
- if ((pathn = ttyname(2)) == NULL && (pathn = ttyname(1)) == NULL &&
- (pathn = ttyname(0)) == NULL)
- {
- errno = 0;
- return (NULL);
- }
-
- /* see if we have write permission */
- if (stat(pathn, &stbuf) < 0 || !bitset(S_IWOTH, stbuf.st_mode))
- {
- errno = 0;
- return (NULL);
- }
-
- /* see if the user is logged in */
- if (getlogin() == NULL)
- return (NULL);
-
- /* looks good */
- return (pathn);
-}
- /*
-** CHECKCOMPAT -- check for From and To person compatible.
-**
-** This routine can be supplied on a per-installation basis
-** to determine whether a person is allowed to send a message.
-** This allows restriction of certain types of internet
-** forwarding or registration of users.
-**
-** If the hosts are found to be incompatible, an error
-** message should be given using "usrerr" and an EX_ code
-** should be returned. You can also set to->q_status to
-** a DSN-style status code.
-**
-** EF_NO_BODY_RETN can be set in e->e_flags to suppress the
-** body during the return-to-sender function; this should be done
-** on huge messages. This bit may already be set by the ESMTP
-** protocol.
-**
-** Parameters:
-** to -- the person being sent to.
-**
-** Returns:
-** an exit status
-**
-** Side Effects:
-** none (unless you include the usrerr stuff)
-*/
-
-int
-checkcompat(to, e)
- register ADDRESS *to;
- register ENVELOPE *e;
-{
-# ifdef lint
- if (to == NULL)
- to++;
-# endif /* lint */
-
- if (tTd(49, 1))
- printf("checkcompat(to=%s, from=%s)\n",
- to->q_paddr, e->e_from.q_paddr);
-
-# ifdef EXAMPLE_CODE
- /* this code is intended as an example only */
- register STAB *s;
-
- s = stab("arpa", ST_MAILER, ST_FIND);
- if (s != NULL && strcmp(e->e_from.q_mailer->m_name, "local") != 0 &&
- to->q_mailer == s->s_mailer)
- {
- usrerr("553 No ARPA mail through this machine: see your system administration");
- /* e->e_flags |= EF_NO_BODY_RETN; to supress body on return */
- to->q_status = "5.7.1";
- return (EX_UNAVAILABLE);
- }
-# endif /* EXAMPLE_CODE */
- return (EX_OK);
-}
- /*
-** SETSIGNAL -- set a signal handler
-**
-** This is essentially old BSD "signal(3)".
-*/
-
-sigfunc_t
-setsignal(sig, handler)
- int sig;
- sigfunc_t handler;
-{
-#if defined(SYS5SIGNALS) || defined(BSD4_3)
-# ifdef BSD4_3
- return signal(sig, handler);
-# else
- return sigset(sig, handler);
-# endif
-#else
- struct sigaction n, o;
-
- bzero(&n, sizeof n);
-# if USE_SA_SIGACTION
- n.sa_sigaction = (void(*)(int, siginfo_t *, void *)) handler;
- n.sa_flags = SA_RESTART|SA_SIGINFO;
-# else
- n.sa_handler = handler;
-# ifdef SA_RESTART
- n.sa_flags = SA_RESTART;
-# endif
-# endif
- if (sigaction(sig, &n, &o) < 0)
- return SIG_ERR;
- return o.sa_handler;
-#endif
-}
- /*
-** BLOCKSIGNAL -- hold a signal to prevent delivery
-**
-** Parameters:
-** sig -- the signal to block.
-**
-** Returns:
-** 1 signal was previously blocked
-** 0 signal was not previously blocked
-** -1 on failure.
-*/
-
-int
-blocksignal(sig)
- int sig;
-{
-#ifdef BSD4_3
-# ifndef sigmask
-# define sigmask(s) (1 << ((s) - 1))
-# endif
- return (sigblock(sigmask(sig)) & sigmask(sig)) != 0;
-#else
-# ifdef ALTOS_SYSTEM_V
- sigfunc_t handler;
-
- handler = sigset(sig, SIG_HOLD);
- if (handler == SIG_ERR)
- return -1;
- else
- return handler == SIG_HOLD;
-# else
- sigset_t sset, oset;
-
- sigemptyset(&sset);
- sigaddset(&sset, sig);
- if (sigprocmask(SIG_BLOCK, &sset, &oset) < 0)
- return -1;
- else
- return sigismember(&oset, sig);
-# endif
-#endif
-}
- /*
-** RELEASESIGNAL -- release a held signal
-**
-** Parameters:
-** sig -- the signal to release.
-**
-** Returns:
-** 1 signal was previously blocked
-** 0 signal was not previously blocked
-** -1 on failure.
-*/
-
-int
-releasesignal(sig)
- int sig;
-{
-#ifdef BSD4_3
- return (sigsetmask(sigblock(0) & ~sigmask(sig)) & sigmask(sig)) != 0;
-#else
-# ifdef ALTOS_SYSTEM_V
- sigfunc_t handler;
-
- handler = sigset(sig, SIG_HOLD);
- if (sigrelse(sig) < 0)
- return -1;
- else
- return handler == SIG_HOLD;
-# else
- sigset_t sset, oset;
-
- sigemptyset(&sset);
- sigaddset(&sset, sig);
- if (sigprocmask(SIG_UNBLOCK, &sset, &oset) < 0)
- return -1;
- else
- return sigismember(&oset, sig);
-# endif
-#endif
-}
- /*
-** HOLDSIGS -- arrange to hold all signals
-**
-** Parameters:
-** none.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Arranges that signals are held.
-*/
-
-void
-holdsigs()
-{
-}
- /*
-** RLSESIGS -- arrange to release all signals
-**
-** This undoes the effect of holdsigs.
-**
-** Parameters:
-** none.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Arranges that signals are released.
-*/
-
-void
-rlsesigs()
-{
-}
- /*
-** INIT_MD -- do machine dependent initializations
-**
-** Systems that have global modes that should be set should do
-** them here rather than in main.
-*/
-
-#ifdef _AUX_SOURCE
-# include <compat.h>
-#endif
-
-#if SHARE_V1
-# include <shares.h>
-#endif
-
-void
-init_md(argc, argv)
- int argc;
- char **argv;
-{
-#ifdef _AUX_SOURCE
- setcompat(getcompat() | COMPAT_BSDPROT);
-#endif
-
-#ifdef SUN_EXTENSIONS
- init_md_sun();
-#endif
-
-#if _CONVEX_SOURCE
- /* keep gethostby*() from stripping the local domain name */
- set_domain_trim_off();
-#endif
-#ifdef __QNX__
- /*
- ** Due to QNX's network distributed nature, you can target a tcpip
- ** stack on a different node in the qnx network; this patch lets
- ** this feature work. The __sock_locate() must be done before the
- ** environment is clear.
- */
- __sock_locate();
-#endif
-#if SECUREWARE || defined(_SCO_unix_)
- set_auth_parameters(argc, argv);
-
-# ifdef _SCO_unix_
- /*
- ** This is required for highest security levels (the kernel
- ** won't let it call set*uid() or run setuid binaries without
- ** it). It may be necessary on other SECUREWARE systems.
- */
-
- if (getluid() == -1)
- setluid(0);
-# endif
-#endif
-
-#ifdef VENDOR_DEFAULT
- VendorCode = VENDOR_DEFAULT;
-#else
- VendorCode = VENDOR_BERKELEY;
-#endif
-}
- /*
-** INIT_VENDOR_MACROS -- vendor-dependent macro initializations
-**
-** Called once, on startup.
-**
-** Parameters:
-** e -- the global envelope.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** vendor-dependent.
-*/
-
-void
-init_vendor_macros(e)
- register ENVELOPE *e;
-{
-}
- /*
-** GETLA -- get the current load average
-**
-** This code stolen from la.c.
-**
-** Parameters:
-** none.
-**
-** Returns:
-** The current load average as an integer.
-**
-** Side Effects:
-** none.
-*/
-
-/* try to guess what style of load average we have */
-#define LA_ZERO 1 /* always return load average as zero */
-#define LA_INT 2 /* read kmem for avenrun; interpret as long */
-#define LA_FLOAT 3 /* read kmem for avenrun; interpret as float */
-#define LA_SUBR 4 /* call getloadavg */
-#define LA_MACH 5 /* MACH load averages (as on NeXT boxes) */
-#define LA_SHORT 6 /* read kmem for avenrun; interpret as short */
-#define LA_PROCSTR 7 /* read string ("1.17") from /proc/loadavg */
-#define LA_READKSYM 8 /* SVR4: use MIOC_READKSYM ioctl call */
-#define LA_DGUX 9 /* special DGUX implementation */
-#define LA_HPUX 10 /* special HPUX implementation */
-#define LA_IRIX6 11 /* special IRIX 6.2 implementation */
-#define LA_KSTAT 12 /* special Solaris kstat(3k) implementation */
-#define LA_DEVSHORT 13 /* read short from a device */
-#define LA_ALPHAOSF 14 /* Digital UNIX (OSF/1 on Alpha) table() call */
-
-/* do guesses based on general OS type */
-#ifndef LA_TYPE
-# define LA_TYPE LA_ZERO
-#endif
-
-#ifndef FSHIFT
-# if defined(unixpc)
-# define FSHIFT 5
-# endif
-
-# if defined(__alpha) || defined(IRIX)
-# define FSHIFT 10
-# endif
-
-#endif
-
-#ifndef FSHIFT
-# define FSHIFT 8
-#endif
-
-#ifndef FSCALE
-# define FSCALE (1 << FSHIFT)
-#endif
-
-#ifndef LA_AVENRUN
-# ifdef SYSTEM5
-# define LA_AVENRUN "avenrun"
-# else
-# define LA_AVENRUN "_avenrun"
-# endif
-#endif
-
-/* _PATH_KMEM should be defined in <paths.h> */
-#ifndef _PATH_KMEM
-# define _PATH_KMEM "/dev/kmem"
-#endif
-
-#if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) || (LA_TYPE == LA_SHORT)
-
-#include <nlist.h>
-
-/* _PATH_UNIX should be defined in <paths.h> */
-#ifndef _PATH_UNIX
-# if defined(SYSTEM5)
-# define _PATH_UNIX "/unix"
-# else
-# define _PATH_UNIX "/vmunix"
-# endif
-#endif
-
-#ifdef _AUX_SOURCE
-struct nlist Nl[2];
-#else
-struct nlist Nl[] =
-{
- { LA_AVENRUN },
- { 0 },
-};
-#endif
-#define X_AVENRUN 0
-
-int
-getla()
-{
- static int kmem = -1;
-#if LA_TYPE == LA_INT
- long avenrun[3];
-#else
-# if LA_TYPE == LA_SHORT
- short avenrun[3];
-# else
- double avenrun[3];
-# endif
-#endif
- extern int errno;
- extern off_t lseek();
-
- if (kmem < 0)
- {
-#ifdef _AUX_SOURCE
- strcpy(Nl[X_AVENRUN].n_name, LA_AVENRUN);
- Nl[1].n_name[0] = '\0';
-#endif
-
-#if defined(_AIX3) || defined(_AIX4)
- if (knlist(Nl, 1, sizeof Nl[0]) < 0)
-#else
- if (nlist(_PATH_UNIX, Nl) < 0)
-#endif
- {
- if (tTd(3, 1))
- printf("getla: nlist(%s): %s\n", _PATH_UNIX,
- errstring(errno));
- return (-1);
- }
- if (Nl[X_AVENRUN].n_value == 0)
- {
- if (tTd(3, 1))
- printf("getla: nlist(%s, %s) ==> 0\n",
- _PATH_UNIX, LA_AVENRUN);
- return (-1);
- }
-#ifdef NAMELISTMASK
- Nl[X_AVENRUN].n_value &= NAMELISTMASK;
-#endif
-
- kmem = open(_PATH_KMEM, 0, 0);
- if (kmem < 0)
- {
- if (tTd(3, 1))
- printf("getla: open(/dev/kmem): %s\n",
- errstring(errno));
- return (-1);
- }
- (void) fcntl(kmem, F_SETFD, 1);
- }
- if (tTd(3, 20))
- printf("getla: symbol address = %#lx\n",
- (u_long) Nl[X_AVENRUN].n_value);
- if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, SEEK_SET) == -1 ||
- read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun))
- {
- /* thank you Ian */
- if (tTd(3, 1))
- printf("getla: lseek or read: %s\n", errstring(errno));
- return (-1);
- }
-# if (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT)
- if (tTd(3, 5))
- {
-# if LA_TYPE == LA_SHORT
- printf("getla: avenrun = %d", avenrun[0]);
- if (tTd(3, 15))
- printf(", %d, %d", avenrun[1], avenrun[2]);
-# else
- printf("getla: avenrun = %ld", avenrun[0]);
- if (tTd(3, 15))
- printf(", %ld, %ld", avenrun[1], avenrun[2]);
-# endif
- printf("\n");
- }
- if (tTd(3, 1))
- printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT);
- return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
-# else /* LA_TYPE == LA_FLOAT */
- if (tTd(3, 5))
- {
- printf("getla: avenrun = %g", avenrun[0]);
- if (tTd(3, 15))
- printf(", %g, %g", avenrun[1], avenrun[2]);
- printf("\n");
- }
- if (tTd(3, 1))
- printf("getla: %d\n", (int) (avenrun[0] +0.5));
- return ((int) (avenrun[0] + 0.5));
-# endif
-}
-
-#endif /* LA_TYPE == LA_INT or LA_SHORT or LA_FLOAT */
-
-#if LA_TYPE == LA_READKSYM
-
-# include <sys/ksym.h>
-
-getla()
-{
- static int kmem = -1;
- long avenrun[3];
- extern int errno;
- struct mioc_rksym mirk;
-
- if (kmem < 0)
- {
- kmem = open("/dev/kmem", 0, 0);
- if (kmem < 0)
- {
- if (tTd(3, 1))
- printf("getla: open(/dev/kmem): %s\n",
- errstring(errno));
- return (-1);
- }
- (void) fcntl(kmem, F_SETFD, 1);
- }
- mirk.mirk_symname = LA_AVENRUN;
- mirk.mirk_buf = avenrun;
- mirk.mirk_buflen = sizeof(avenrun);
- if (ioctl(kmem, MIOC_READKSYM, &mirk) < 0)
- {
- if (tTd(3, 1))
- printf("getla: ioctl(MIOC_READKSYM) failed: %s\n",
- errstring(errno));
- return -1;
- }
- if (tTd(3, 5))
- {
- printf("getla: avenrun = %d", avenrun[0]);
- if (tTd(3, 15))
- printf(", %d, %d", avenrun[1], avenrun[2]);
- printf("\n");
- }
- if (tTd(3, 1))
- printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT);
- return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
-}
-
-#endif /* LA_TYPE == LA_READKSYM */
-
-#if LA_TYPE == LA_DGUX
-
-# include <sys/dg_sys_info.h>
-
-int
-getla()
-{
- struct dg_sys_info_load_info load_info;
-
- dg_sys_info((long *)&load_info,
- DG_SYS_INFO_LOAD_INFO_TYPE, DG_SYS_INFO_LOAD_VERSION_0);
-
- if (tTd(3, 1))
- printf("getla: %d\n", (int) (load_info.one_minute + 0.5));
-
- return((int) (load_info.one_minute + 0.5));
-}
-
-#endif /* LA_TYPE == LA_DGUX */
-
-#if LA_TYPE == LA_HPUX
-
-/* forward declarations to keep gcc from complaining */
-struct pst_dynamic;
-struct pst_status;
-struct pst_static;
-struct pst_vminfo;
-struct pst_diskinfo;
-struct pst_processor;
-struct pst_lv;
-struct pst_swapinfo;
-
-# include <sys/param.h>
-# include <sys/pstat.h>
-
-int
-getla()
-{
- struct pst_dynamic pstd;
-
- if (pstat_getdynamic(&pstd, sizeof(struct pst_dynamic),
- (size_t) 1, 0) == -1)
- return 0;
-
- if (tTd(3, 1))
- printf("getla: %d\n", (int) (pstd.psd_avg_1_min + 0.5));
-
- return (int) (pstd.psd_avg_1_min + 0.5);
-}
-
-#endif /* LA_TYPE == LA_HPUX */
-
-#if LA_TYPE == LA_SUBR
-
-int
-getla()
-{
- double avenrun[3];
-
- if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0)
- {
- if (tTd(3, 1))
- perror("getla: getloadavg failed:");
- return (-1);
- }
- if (tTd(3, 1))
- printf("getla: %d\n", (int) (avenrun[0] +0.5));
- return ((int) (avenrun[0] + 0.5));
-}
-
-#endif /* LA_TYPE == LA_SUBR */
-
-#if LA_TYPE == LA_MACH
-
-/*
-** This has been tested on NEXTSTEP release 2.1/3.X.
-*/
-
-#if defined(NX_CURRENT_COMPILER_RELEASE) && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_0
-# include <mach/mach.h>
-#else
-# include <mach.h>
-#endif
-
-int
-getla()
-{
- processor_set_t default_set;
- kern_return_t error;
- unsigned int info_count;
- struct processor_set_basic_info info;
- host_t host;
-
- error = processor_set_default(host_self(), &default_set);
- if (error != KERN_SUCCESS)
- {
- if (tTd(3, 1))
- perror("getla: processor_set_default failed:");
- return -1;
- }
- info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
- if (processor_set_info(default_set, PROCESSOR_SET_BASIC_INFO,
- &host, (processor_set_info_t)&info,
- &info_count) != KERN_SUCCESS)
- {
- if (tTd(3, 1))
- perror("getla: processor_set_info failed:");
- return -1;
- }
- if (tTd(3, 1))
- printf("getla: %d\n", (int) (info.load_average + (LOAD_SCALE / 2)) / LOAD_SCALE);
- return (int) (info.load_average + (LOAD_SCALE / 2)) / LOAD_SCALE;
-}
-
-#endif /* LA_TYPE == LA_MACH */
-
-#if LA_TYPE == LA_PROCSTR
-
-/*
-** Read /proc/loadavg for the load average. This is assumed to be
-** in a format like "0.15 0.12 0.06".
-**
-** Initially intended for Linux. This has been in the kernel
-** since at least 0.99.15.
-*/
-
-# ifndef _PATH_LOADAVG
-# define _PATH_LOADAVG "/proc/loadavg"
-# endif
-
-int
-getla()
-{
- double avenrun;
- register int result;
- FILE *fp;
-
- fp = fopen(_PATH_LOADAVG, "r");
- if (fp == NULL)
- {
- if (tTd(3, 1))
- printf("getla: fopen(%s): %s\n",
- _PATH_LOADAVG, errstring(errno));
- return -1;
- }
- result = fscanf(fp, "%lf", &avenrun);
- fclose(fp);
- if (result != 1)
- {
- if (tTd(3, 1))
- printf("getla: fscanf() = %d: %s\n",
- result, errstring(errno));
- return -1;
- }
-
- if (tTd(3, 1))
- printf("getla(): %.2f\n", avenrun);
-
- return ((int) (avenrun + 0.5));
-}
-
-#endif /* LA_TYPE == LA_PROCSTR */
-
-#if LA_TYPE == LA_IRIX6
-#include <sys/sysmp.h>
-
-int getla(void)
-{
- static int kmem = -1;
- int avenrun[3];
-
- if (kmem < 0)
- {
- kmem = open(_PATH_KMEM, 0, 0);
- if (kmem < 0)
- {
- if (tTd(3, 1))
- printf("getla: open(%s): %s\n", _PATH_KMEM,
- errstring(errno));
- return -1;
- }
- (void) fcntl(kmem, F_SETFD, 1);
- }
-
- if (lseek(kmem, (sysmp(MP_KERNADDR, MPKA_AVENRUN) & 0x7fffffff), SEEK_SET) == -1 ||
- read(kmem, (char *)avenrun, sizeof(avenrun)) < sizeof(avenrun))
- {
- if (tTd(3, 1))
- printf("getla: lseek or read: %s\n",
- errstring(errno));
- return -1;
- }
- if (tTd(3, 5))
- {
- printf("getla: avenrun = %ld", (long int) avenrun[0]);
- if (tTd(3, 15))
- printf(", %ld, %ld",
- (long int) avenrun[1], (long int) avenrun[2]);
- printf("\n");
- }
-
- if (tTd(3, 1))
- printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT);
- return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
-
-}
-#endif
-
-#if LA_TYPE == LA_KSTAT
-
-#include <kstat.h>
-
-int
-getla()
-{
- static kstat_ctl_t *kc = NULL;
- static kstat_t *ksp = NULL;
- kstat_named_t *ksn;
- int la;
-
- if (kc == NULL) /* if not initialized before */
- kc = kstat_open();
- if (kc == NULL)
- {
- if (tTd(3, 1))
- printf("getla: kstat_open(): %s\n",
- errstring(errno));
- return -1;
- }
- if (ksp == NULL)
- ksp = kstat_lookup(kc, "unix", 0, "system_misc");
- if (ksp == NULL)
- {
- if (tTd(3, 1))
- printf("getla: kstat_lookup(): %s\n",
- errstring(errno));
- return -1;
- }
- if (kstat_read(kc, ksp, NULL) < 0)
- {
- if (tTd(3, 1))
- printf("getla: kstat_read(): %s\n",
- errstring(errno));
- return -1;
- }
- ksn = (kstat_named_t *) kstat_data_lookup(ksp, "avenrun_1min");
- la = ((double)ksn->value.ul + FSCALE/2) / FSCALE;
- /* kstat_close(kc); /o do not close for fast access */
- return la;
-}
-
-#endif /* LA_TYPE == LA_KSTAT */
-
-#if LA_TYPE == LA_DEVSHORT
-
-/*
-** Read /dev/table/avenrun for the load average. This should contain
-** three shorts for the 1, 5, and 15 minute loads. We only read the
-** first, since that's all we care about.
-**
-** Intended for SCO OpenServer 5.
-*/
-
-# ifndef _PATH_AVENRUN
-# define _PATH_AVENRUN "/dev/table/avenrun"
-# endif
-
-int
-getla()
-{
- static int afd = -1;
- short avenrun;
- int loadav;
- int r;
-
- errno = EBADF;
-
- if (afd == -1 || lseek(afd, 0L, SEEK_SET) == -1)
- {
- if (errno != EBADF)
- return -1;
- afd = open(_PATH_AVENRUN, O_RDONLY|O_SYNC);
- if (afd < 0)
- {
- sm_syslog(LOG_ERR, NOQID,
- "can't open %s: %m",
- _PATH_AVENRUN);
- return -1;
- }
- }
-
- r = read(afd, &avenrun, sizeof avenrun);
-
- if (tTd(3, 5))
- printf("getla: avenrun = %d\n", avenrun);
- loadav = (int) (avenrun + FSCALE/2) >> FSHIFT;
- if (tTd(3, 1))
- printf("getla: %d\n", loadav);
- return loadav;
-}
-
-#endif /* LA_TYPE == LA_DEVSHORT */
-
-#if LA_TYPE == LA_ALPHAOSF
-struct rtentry;
-struct mbuf;
-# include <sys/table.h>
-
-int getla()
-{
- int ave = 0;
- struct tbl_loadavg tab;
-
- if (table(TBL_LOADAVG, 0, &tab, 1, sizeof(tab)) == -1)
- {
- if (tTd(3, 1))
- printf("getla: table %s\n", errstring(errno));
- return (-1);
- }
-
- if (tTd(3, 1))
- printf("getla: scale = %d\n", tab.tl_lscale);
-
- if (tab.tl_lscale)
- ave = (tab.tl_avenrun.l[0] + (tab.tl_lscale/2)) / tab.tl_lscale;
- else
- ave = (int) (tab.tl_avenrun.d[0] + 0.5);
-
- if (tTd(3, 1))
- printf("getla: %d\n", ave);
-
- return ave;
-}
-
-#endif
-
-#if LA_TYPE == LA_ZERO
-
-int
-getla()
-{
- if (tTd(3, 1))
- printf("getla: ZERO\n");
- return (0);
-}
-
-#endif /* LA_TYPE == LA_ZERO */
-
-/*
- * Copyright 1989 Massachusetts Institute of Technology
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of M.I.T. not be used in advertising or
- * publicity pertaining to distribution of the software without specific,
- * written prior permission. M.I.T. makes no representations about the
- * suitability of this software for any purpose. It is provided "as is"
- * without express or implied warranty.
- *
- * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
- * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Authors: Many and varied...
- */
-
-/* Non Apollo stuff removed by Don Lewis 11/15/93 */
-#ifndef lint
-static char rcsid[] = "@(#)$Id: getloadavg.c,v 1.16 1991/06/21 12:51:15 paul Exp $";
-#endif /* !lint */
-
-#ifdef apollo
-# undef volatile
-# include <apollo/base.h>
-
-/* ARGSUSED */
-int getloadavg( call_data )
- caddr_t call_data; /* pointer to (double) return value */
-{
- double *avenrun = (double *) call_data;
- int i;
- status_$t st;
- long loadav[3];
- proc1_$get_loadav(loadav, &st);
- *avenrun = loadav[0] / (double) (1 << 16);
- return(0);
-}
-# endif /* apollo */
- /*
-** SHOULDQUEUE -- should this message be queued or sent?
-**
-** Compares the message cost to the load average to decide.
-**
-** Parameters:
-** pri -- the priority of the message in question.
-** ctime -- the message creation time.
-**
-** Returns:
-** TRUE -- if this message should be queued up for the
-** time being.
-** FALSE -- if the load is low enough to send this message.
-**
-** Side Effects:
-** none.
-*/
-
-extern int get_num_procs_online __P((void));
-
-bool
-shouldqueue(pri, ctime)
- long pri;
- time_t ctime;
-{
- bool rval;
- int queuela = QueueLA * get_num_procs_online();
-
- if (tTd(3, 30))
- printf("shouldqueue: CurrentLA=%d, pri=%ld: ", CurrentLA, pri);
- if (CurrentLA < queuela)
- {
- if (tTd(3, 30))
- printf("FALSE (CurrentLA < QueueLA)\n");
- return (FALSE);
- }
-#if 0 /* this code is reported to cause oscillation around RefuseLA */
- if (CurrentLA >= RefuseLA && QueueLA < RefuseLA)
- {
- if (tTd(3, 30))
- printf("TRUE (CurrentLA >= RefuseLA)\n");
- return (TRUE);
- }
-#endif
- rval = pri > (QueueFactor / (CurrentLA - queuela + 1));
- if (tTd(3, 30))
- printf("%s (by calculation)\n", rval ? "TRUE" : "FALSE");
- return rval;
-}
- /*
-** REFUSECONNECTIONS -- decide if connections should be refused
-**
-** Parameters:
-** port -- port number (for error messages only)
-**
-** Returns:
-** TRUE if incoming SMTP connections should be refused
-** (for now).
-** FALSE if we should accept new work.
-**
-** Side Effects:
-** Sets process title when it is rejecting connections.
-*/
-
-bool
-refuseconnections(port)
- int port;
-{
- int refusela = RefuseLA * get_num_procs_online();
- time_t now;
- static time_t lastconn = (time_t) 0;
- static int conncnt = 0;
- extern bool enoughdiskspace __P((long));
-
-#ifdef XLA
- if (!xla_smtp_ok())
- return TRUE;
-#endif
-
- now = curtime();
- if (now != lastconn)
- {
- lastconn = now;
- conncnt = 0;
- }
- else if (conncnt++ > ConnRateThrottle && ConnRateThrottle > 0)
- {
- /* sleep to flatten out connection load */
- sm_setproctitle(TRUE, "deferring connections on port %d: %d per second",
- port, ConnRateThrottle);
- if (LogLevel >= 14)
- sm_syslog(LOG_INFO, NOQID,
- "deferring connections on port %d: %d per second",
- port, ConnRateThrottle);
- sleep(1);
- }
-
- CurrentLA = getla();
- if (CurrentLA >= refusela)
- {
- sm_setproctitle(TRUE, "rejecting connections on port %d: load average: %d",
- port, CurrentLA);
- if (LogLevel >= 14)
- sm_syslog(LOG_INFO, NOQID,
- "rejecting connections on port %d: load average: %d",
- port, CurrentLA);
- return TRUE;
- }
-
- if (!enoughdiskspace(MinBlocksFree + 1))
- {
- sm_setproctitle(TRUE, "rejecting connections on port %d: min free: %d",
- port, MinBlocksFree);
- if (LogLevel >= 14)
- sm_syslog(LOG_INFO, NOQID,
- "rejecting connections on port %d: min free: %d",
- port, MinBlocksFree);
- return TRUE;
- }
-
- if (MaxChildren > 0 && CurChildren >= MaxChildren)
- {
- proc_list_probe();
- if (CurChildren >= MaxChildren)
- {
- sm_setproctitle(TRUE, "rejecting connections on port %d: %d children, max %d",
- port, CurChildren, MaxChildren);
- if (LogLevel >= 14)
- sm_syslog(LOG_INFO, NOQID,
- "rejecting connections on port %d: %d children, max %d",
- port, CurChildren, MaxChildren);
- return TRUE;
- }
- }
-
- return FALSE;
-}
- /*
-** SETPROCTITLE -- set process title for ps
-**
-** Parameters:
-** fmt -- a printf style format string.
-** a, b, c -- possible parameters to fmt.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Clobbers argv of our main procedure so ps(1) will
-** display the title.
-*/
-
-#define SPT_NONE 0 /* don't use it at all */
-#define SPT_REUSEARGV 1 /* cover argv with title information */
-#define SPT_BUILTIN 2 /* use libc builtin */
-#define SPT_PSTAT 3 /* use pstat(PSTAT_SETCMD, ...) */
-#define SPT_PSSTRINGS 4 /* use PS_STRINGS->... */
-#define SPT_SYSMIPS 5 /* use sysmips() supported by NEWS-OS 6 */
-#define SPT_SCO 6 /* write kernel u. area */
-#define SPT_CHANGEARGV 7 /* write our own strings into argv[] */
-
-#ifndef SPT_TYPE
-# define SPT_TYPE SPT_REUSEARGV
-#endif
-
-#if SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN
-
-# if SPT_TYPE == SPT_PSTAT
-# include <sys/pstat.h>
-# endif
-# if SPT_TYPE == SPT_PSSTRINGS
-# include <machine/vmparam.h>
-# include <sys/exec.h>
-# ifndef PS_STRINGS /* hmmmm.... apparently not available after all */
-# undef SPT_TYPE
-# define SPT_TYPE SPT_REUSEARGV
-# else
-# ifndef NKPDE /* FreeBSD 2.0 */
-# define NKPDE 63
-typedef unsigned int *pt_entry_t;
-# endif
-# endif
-# endif
-
-# if SPT_TYPE == SPT_PSSTRINGS || SPT_TYPE == SPT_CHANGEARGV
-# define SETPROC_STATIC static
-# else
-# define SETPROC_STATIC
-# endif
-
-# if SPT_TYPE == SPT_SYSMIPS
-# include <sys/sysmips.h>
-# include <sys/sysnews.h>
-# endif
-
-# if SPT_TYPE == SPT_SCO
-# include <sys/immu.h>
-# include <sys/dir.h>
-# include <sys/user.h>
-# include <sys/fs/s5param.h>
-# if PSARGSZ > MAXLINE
-# define SPT_BUFSIZE PSARGSZ
-# endif
-# endif
-
-# ifndef SPT_PADCHAR
-# define SPT_PADCHAR ' '
-# endif
-
-#endif /* SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN */
-
-# ifndef SPT_BUFSIZE
-# define SPT_BUFSIZE MAXLINE
-# endif
-
-/*
-** Pointers for setproctitle.
-** This allows "ps" listings to give more useful information.
-*/
-
-char **Argv = NULL; /* pointer to argument vector */
-char *LastArgv = NULL; /* end of argv */
-
-void
-initsetproctitle(argc, argv, envp)
- int argc;
- char **argv;
- char **envp;
-{
- register int i, envpsize = 0;
- extern char **environ;
-
- /*
- ** Move the environment so setproctitle can use the space at
- ** the top of memory.
- */
-
- for (i = 0; envp[i] != NULL; i++)
- envpsize += strlen(envp[i]) + 1;
- environ = (char **) xalloc(sizeof (char *) * (i + 1));
- for (i = 0; envp[i] != NULL; i++)
- environ[i] = newstr(envp[i]);
- environ[i] = NULL;
-
- /*
- ** Save start and extent of argv for setproctitle.
- */
-
- Argv = argv;
-
- /*
- ** Determine how much space we can use for setproctitle.
- ** Use all contiguous argv and envp pointers starting at argv[0]
- */
- for (i = 0; i < argc; i++)
- {
- if (i==0 || LastArgv + 1 == argv[i])
- LastArgv = argv[i] + strlen(argv[i]);
- else
- continue;
- }
- for (i=0; envp[i] != NULL; i++)
- {
- if (LastArgv + 1 == envp[i])
- LastArgv = envp[i] + strlen(envp[i]);
- else
- continue;
- }
-}
-
-#if SPT_TYPE != SPT_BUILTIN
-
-
-/*VARARGS1*/
-void
-# ifdef __STDC__
-setproctitle(const char *fmt, ...)
-# else
-setproctitle(fmt, va_alist)
- const char *fmt;
- va_dcl
-# endif
-{
-# if SPT_TYPE != SPT_NONE
- register char *p;
- register int i;
- SETPROC_STATIC char buf[SPT_BUFSIZE];
- VA_LOCAL_DECL
-# if SPT_TYPE == SPT_PSTAT
- union pstun pst;
-# endif
-# if SPT_TYPE == SPT_SCO
- off_t seek_off;
- static int kmem = -1;
- static int kmempid = -1;
- struct user u;
-# endif
-
- p = buf;
-
- /* print sendmail: heading for grep */
- (void) strcpy(p, "sendmail: ");
- p += strlen(p);
-
- /* print the argument string */
- VA_START(fmt);
- (void) vsnprintf(p, SPACELEFT(buf, p), fmt, ap);
- VA_END;
-
- i = strlen(buf);
-
-# if SPT_TYPE == SPT_PSTAT
- pst.pst_command = buf;
- pstat(PSTAT_SETCMD, pst, i, 0, 0);
-# endif
-# if SPT_TYPE == SPT_PSSTRINGS
- PS_STRINGS->ps_nargvstr = 1;
- PS_STRINGS->ps_argvstr = buf;
-# endif
-# if SPT_TYPE == SPT_SYSMIPS
- sysmips(SONY_SYSNEWS, NEWS_SETPSARGS, buf);
-# endif
-# if SPT_TYPE == SPT_SCO
- if (kmem < 0 || kmempid != getpid())
- {
- if (kmem >= 0)
- close(kmem);
- kmem = open(_PATH_KMEM, O_RDWR, 0);
- if (kmem < 0)
- return;
- (void) fcntl(kmem, F_SETFD, 1);
- kmempid = getpid();
- }
- buf[PSARGSZ - 1] = '\0';
- seek_off = UVUBLK + (off_t) u.u_psargs - (off_t) &u;
- if (lseek(kmem, (off_t) seek_off, SEEK_SET) == seek_off)
- (void) write(kmem, buf, PSARGSZ);
-# endif
-# if SPT_TYPE == SPT_REUSEARGV
- if (i > LastArgv - Argv[0] - 2)
- {
- i = LastArgv - Argv[0] - 2;
- buf[i] = '\0';
- }
- (void) strcpy(Argv[0], buf);
- p = &Argv[0][i];
- while (p < LastArgv)
- *p++ = SPT_PADCHAR;
- Argv[1] = NULL;
-# endif
-# if SPT_TYPE == SPT_CHANGEARGV
- Argv[0] = buf;
- Argv[1] = 0;
-# endif
-# endif /* SPT_TYPE != SPT_NONE */
-}
-
-#endif /* SPT_TYPE != SPT_BUILTIN */
- /*
-** SM_SETPROCTITLE -- set process task and set process title for ps
-**
-** Possibly set process status and call setproctitle() to
-** change the ps display.
-**
-** Parameters:
-** status -- whether or not to store as process status
-** fmt -- a printf style format string.
-** a, b, c -- possible parameters to fmt.
-**
-** Returns:
-** none.
-*/
-
-/*VARARGS2*/
-void
-# ifdef __STDC__
-sm_setproctitle(bool status, const char *fmt, ...)
-# else
-sm_setproctitle(status, fmt, va_alist)
- bool status;
- const char *fmt;
- va_dcl
-#endif
-{
- char buf[SPT_BUFSIZE];
-
- VA_LOCAL_DECL
- /* print the argument string */
- VA_START(fmt);
- (void) vsnprintf(buf, SPT_BUFSIZE, fmt, ap);
- VA_END;
-
- if (status)
- proc_list_set(getpid(), buf);
- setproctitle("%s", buf);
-}
- /*
-** WAITFOR -- wait for a particular process id.
-**
-** Parameters:
-** pid -- process id to wait for.
-**
-** Returns:
-** status of pid.
-** -1 if pid never shows up.
-**
-** Side Effects:
-** none.
-*/
-
-int
-waitfor(pid)
- pid_t pid;
-{
-#ifdef WAITUNION
- union wait st;
-#else
- auto int st;
-#endif
- pid_t i;
-#if defined(ISC_UNIX) || defined(_SCO_unix_)
- int savesig;
-#endif
-
- do
- {
- errno = 0;
-#if defined(ISC_UNIX) || defined(_SCO_unix_)
- savesig = releasesignal(SIGCHLD);
-#endif
- i = wait(&st);
-#if defined(ISC_UNIX) || defined(_SCO_unix_)
- if (savesig > 0)
- blocksignal(SIGCHLD);
-#endif
- if (i > 0)
- proc_list_drop(i);
- } while ((i >= 0 || errno == EINTR) && i != pid);
- if (i < 0)
- return -1;
-#ifdef WAITUNION
- return st.w_status;
-#else
- return st;
-#endif
-}
- /*
-** REAPCHILD -- pick up the body of my child, lest it become a zombie
-**
-** Parameters:
-** sig -- the signal that got us here (unused).
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Picks up extant zombies.
-*/
-
-SIGFUNC_DECL
-reapchild(sig)
- int sig;
-{
- int olderrno = errno;
- pid_t pid;
-# ifdef HASWAITPID
- auto int status;
- int count;
-
- count = 0;
- while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
- {
- if (count++ > 1000)
- {
- if (LogLevel > 0)
- sm_syslog(LOG_ALERT, NOQID,
- "reapchild: waitpid loop: pid=%d, status=%x",
- pid, status);
- break;
- }
- proc_list_drop(pid);
- }
-# else
-# ifdef WNOHANG
- union wait status;
-
- while ((pid = wait3(&status, WNOHANG, (struct rusage *) NULL)) > 0)
- proc_list_drop(pid);
-# else /* WNOHANG */
- auto int status;
-
- /*
- ** Catch one zombie -- we will be re-invoked (we hope) if there
- ** are more. Unreliable signals probably break this, but this
- ** is the "old system" situation -- waitpid or wait3 are to be
- ** strongly preferred.
- */
-
- if ((pid = wait(&status)) > 0)
- proc_list_drop(pid);
-# endif /* WNOHANG */
-# endif
-# ifdef SYS5SIGNALS
- (void) setsignal(SIGCHLD, reapchild);
-# endif
- errno = olderrno;
- return SIGFUNC_RETURN;
-}
- /*
-** PUTENV -- emulation of putenv() in terms of setenv()
-**
-** Not needed on Posix-compliant systems.
-** This doesn't have full Posix semantics, but it's good enough
-** for sendmail.
-**
-** Parameter:
-** env -- the environment to put.
-**
-** Returns:
-** none.
-*/
-
-#ifdef NEEDPUTENV
-
-# if NEEDPUTENV == 2 /* no setenv(3) call available */
-
-int
-putenv(str)
- char *str;
-{
- char **current;
- int matchlen, envlen=0;
- char *tmp;
- char **newenv;
- static int first=1;
- extern char **environ;
-
- /*
- * find out how much of str to match when searching
- * for a string to replace.
- */
- if ((tmp = strchr(str, '=')) == NULL || tmp == str)
- matchlen = strlen(str);
- else
- matchlen = (int) (tmp - str);
- ++matchlen;
-
- /*
- * Search for an existing string in the environment and find the
- * length of environ. If found, replace and exit.
- */
- for (current=environ; *current; current++) {
- ++envlen;
-
- if (strncmp(str, *current, matchlen) == 0) {
- /* found it, now insert the new version */
- *current = (char *)str;
- return(0);
- }
- }
-
- /*
- * There wasn't already a slot so add space for a new slot.
- * If this is our first time through, use malloc(), else realloc().
- */
- if (first) {
- newenv = (char **) malloc(sizeof(char *) * (envlen + 2));
- if (newenv == NULL)
- return(-1);
-
- first=0;
- (void) memcpy(newenv, environ, sizeof(char *) * envlen);
- } else {
- newenv = (char **) realloc((char *)environ, sizeof(char *) * (envlen + 2));
- if (newenv == NULL)
- return(-1);
- }
-
- /* actually add in the new entry */
- environ = newenv;
- environ[envlen] = (char *)str;
- environ[envlen+1] = NULL;
-
- return(0);
-}
-
-#else /* implement putenv() in terms of setenv() */
-
-int
-putenv(env)
- char *env;
-{
- char *p;
- int l;
- char nbuf[100];
-
- p = strchr(env, '=');
- if (p == NULL)
- return 0;
- l = p - env;
- if (l > sizeof nbuf - 1)
- l = sizeof nbuf - 1;
- bcopy(env, nbuf, l);
- nbuf[l] = '\0';
- return setenv(nbuf, ++p, 1);
-}
-
-# endif
-#endif
- /*
-** UNSETENV -- remove a variable from the environment
-**
-** Not needed on newer systems.
-**
-** Parameters:
-** name -- the string name of the environment variable to be
-** deleted from the current environment.
-**
-** Returns:
-** none.
-**
-** Globals:
-** environ -- a pointer to the current environment.
-**
-** Side Effects:
-** Modifies environ.
-*/
-
-#ifndef HASUNSETENV
-
-void
-unsetenv(name)
- char *name;
-{
- extern char **environ;
- register char **pp;
- int len = strlen(name);
-
- for (pp = environ; *pp != NULL; pp++)
- {
- if (strncmp(name, *pp, len) == 0 &&
- ((*pp)[len] == '=' || (*pp)[len] == '\0'))
- break;
- }
-
- for (; *pp != NULL; pp++)
- *pp = pp[1];
-}
-
-#endif
- /*
-** GETDTABLESIZE -- return number of file descriptors
-**
-** Only on non-BSD systems
-**
-** Parameters:
-** none
-**
-** Returns:
-** size of file descriptor table
-**
-** Side Effects:
-** none
-*/
-
-#ifdef SOLARIS
-# include <sys/resource.h>
-#endif
-
-int
-getdtsize()
-{
-#ifdef RLIMIT_NOFILE
- struct rlimit rl;
-
- if (getrlimit(RLIMIT_NOFILE, &rl) >= 0)
- return rl.rlim_cur;
-#endif
-
-# ifdef HASGETDTABLESIZE
- return getdtablesize();
-# else
-# ifdef _SC_OPEN_MAX
- return sysconf(_SC_OPEN_MAX);
-# else
- return NOFILE;
-# endif
-# endif
-}
- /*
-** UNAME -- get the UUCP name of this system.
-*/
-
-#ifndef HASUNAME
-
-int
-uname(name)
- struct utsname *name;
-{
- FILE *file;
- char *n;
-
- name->nodename[0] = '\0';
-
- /* try /etc/whoami -- one line with the node name */
- if ((file = fopen("/etc/whoami", "r")) != NULL)
- {
- (void) fgets(name->nodename, NODE_LENGTH + 1, file);
- (void) fclose(file);
- n = strchr(name->nodename, '\n');
- if (n != NULL)
- *n = '\0';
- if (name->nodename[0] != '\0')
- return (0);
- }
-
- /* try /usr/include/whoami.h -- has a #define somewhere */
- if ((file = fopen("/usr/include/whoami.h", "r")) != NULL)
- {
- char buf[MAXLINE];
-
- while (fgets(buf, MAXLINE, file) != NULL)
- if (sscanf(buf, "#define sysname \"%*[^\"]\"",
- NODE_LENGTH, name->nodename) > 0)
- break;
- (void) fclose(file);
- if (name->nodename[0] != '\0')
- return (0);
- }
-
-#ifdef TRUST_POPEN
- /*
- ** Popen is known to have security holes.
- */
-
- /* try uuname -l to return local name */
- if ((file = popen("uuname -l", "r")) != NULL)
- {
- (void) fgets(name, NODE_LENGTH + 1, file);
- (void) pclose(file);
- n = strchr(name, '\n');
- if (n != NULL)
- *n = '\0';
- if (name->nodename[0] != '\0')
- return (0);
- }
-#endif
-
- return (-1);
-}
-#endif /* HASUNAME */
- /*
-** INITGROUPS -- initialize groups
-**
-** Stub implementation for System V style systems
-*/
-
-#ifndef HASINITGROUPS
-
-initgroups(name, basegid)
- char *name;
- int basegid;
-{
- return 0;
-}
-
-#endif
- /*
-** SETGROUPS -- set group list
-**
-** Stub implementation for systems that don't have group lists
-*/
-
-#ifndef NGROUPS_MAX
-
-int
-setgroups(ngroups, grouplist)
- int ngroups;
- GIDSET_T grouplist[];
-{
- return 0;
-}
-
-#endif
- /*
-** SETSID -- set session id (for non-POSIX systems)
-*/
-
-#ifndef HASSETSID
-
-pid_t
-setsid __P ((void))
-{
-#ifdef TIOCNOTTY
- int fd;
-
- fd = open("/dev/tty", O_RDWR, 0);
- if (fd >= 0)
- {
- (void) ioctl(fd, (int) TIOCNOTTY, (char *) 0);
- (void) close(fd);
- }
-#endif /* TIOCNOTTY */
-# ifdef SYS5SETPGRP
- return setpgrp();
-# else
- return setpgid(0, getpid());
-# endif
-}
-
-#endif
- /*
-** FSYNC -- dummy fsync
-*/
-
-#ifdef NEEDFSYNC
-
-fsync(fd)
- int fd;
-{
-# ifdef O_SYNC
- return fcntl(fd, F_SETFL, O_SYNC);
-# else
- /* nothing we can do */
- return 0;
-# endif
-}
-
-#endif
- /*
-** DGUX_INET_ADDR -- inet_addr for DG/UX
-**
-** Data General DG/UX version of inet_addr returns a struct in_addr
-** instead of a long. This patches things. Only needed on versions
-** prior to 5.4.3.
-*/
-
-#ifdef DGUX_5_4_2
-
-#undef inet_addr
-
-long
-dgux_inet_addr(host)
- char *host;
-{
- struct in_addr haddr;
-
- haddr = inet_addr(host);
- return haddr.s_addr;
-}
-
-#endif
- /*
-** GETOPT -- for old systems or systems with bogus implementations
-*/
-
-#ifdef NEEDGETOPT
-
-/*
- * Copyright (c) 1985 Regents of the University of California.
- * All rights reserved. The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
- */
-
-
-/*
-** this version hacked to add `atend' flag to allow state machine
-** to reset if invoked by the program to scan args for a 2nd time
-*/
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)getopt.c 4.3 (Berkeley) 3/9/86";
-#endif /* LIBC_SCCS and not lint */
-
-#include <stdio.h>
-
-/*
- * get option letter from argument vector
- */
-#ifdef _CONVEX_SOURCE
-extern int optind, opterr, optopt;
-extern char *optarg;
-#else
-int opterr = 1; /* if error message should be printed */
-int optind = 1; /* index into parent argv vector */
-int optopt = 0; /* character checked for validity */
-char *optarg = NULL; /* argument associated with option */
-#endif
-
-#define BADCH (int)'?'
-#define EMSG ""
-#define tell(s) if (opterr) {fputs(*nargv,stderr);fputs(s,stderr); \
- fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);}
-
-int
-getopt(nargc,nargv,ostr)
- int nargc;
- char *const *nargv;
- const char *ostr;
-{
- static char *place = EMSG; /* option letter processing */
- static char atend = 0;
- register char *oli = NULL; /* option letter list index */
-
- if (atend) {
- atend = 0;
- place = EMSG;
- }
- if(!*place) { /* update scanning pointer */
- if (optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) {
- atend++;
- return -1;
- }
- if (*place == '-') { /* found "--" */
- ++optind;
- atend++;
- return -1;
- }
- } /* option letter okay? */
- if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr,optopt))) {
- if (!*place) ++optind;
- tell(": illegal option -- ");
- }
- if (oli && *++oli != ':') { /* don't need argument */
- optarg = NULL;
- if (!*place) ++optind;
- }
- else { /* need an argument */
- if (*place) optarg = place; /* no white space */
- else if (nargc <= ++optind) { /* no arg */
- place = EMSG;
- tell(": option requires an argument -- ");
- }
- else optarg = nargv[optind]; /* white space */
- place = EMSG;
- ++optind;
- }
- return(optopt); /* dump back option letter */
-}
-
-#endif
- /*
-** VFPRINTF, VSPRINTF -- for old 4.3 BSD systems missing a real version
-*/
-
-#ifdef NEEDVPRINTF
-
-#define MAXARG 16
-
-vfprintf(fp, fmt, ap)
- FILE *fp;
- char *fmt;
- char **ap;
-{
- char *bp[MAXARG];
- int i = 0;
-
- while (*ap && i < MAXARG)
- bp[i++] = *ap++;
- fprintf(fp, fmt, bp[0], bp[1], bp[2], bp[3],
- bp[4], bp[5], bp[6], bp[7],
- bp[8], bp[9], bp[10], bp[11],
- bp[12], bp[13], bp[14], bp[15]);
-}
-
-vsprintf(s, fmt, ap)
- char *s;
- char *fmt;
- char **ap;
-{
- char *bp[MAXARG];
- int i = 0;
-
- while (*ap && i < MAXARG)
- bp[i++] = *ap++;
- sprintf(s, fmt, bp[0], bp[1], bp[2], bp[3],
- bp[4], bp[5], bp[6], bp[7],
- bp[8], bp[9], bp[10], bp[11],
- bp[12], bp[13], bp[14], bp[15]);
-}
-
-#endif
- /*
-** USERSHELLOK -- tell if a user's shell is ok for unrestricted use
-**
-** Parameters:
-** user -- the name of the user we are checking.
-** shell -- the user's shell from /etc/passwd
-**
-** Returns:
-** TRUE -- if it is ok to use this for unrestricted access.
-** FALSE -- if the shell is restricted.
-*/
-
-#if !HASGETUSERSHELL
-
-# ifndef _PATH_SHELLS
-# define _PATH_SHELLS "/etc/shells"
-# endif
-
-# if defined(_AIX3) || defined(_AIX4)
-# include <userconf.h>
-# if _AIX4 >= 40200
-# include <userpw.h>
-# endif
-# include <usersec.h>
-# endif
-
-char *DefaultUserShells[] =
-{
- "/bin/sh", /* standard shell */
- "/usr/bin/sh",
- "/bin/csh", /* C shell */
- "/usr/bin/csh",
-#ifdef __hpux
-# ifdef V4FS
- "/usr/bin/rsh", /* restricted Bourne shell */
- "/usr/bin/ksh", /* Korn shell */
- "/usr/bin/rksh", /* restricted Korn shell */
- "/usr/bin/pam",
- "/usr/bin/keysh", /* key shell (extended Korn shell) */
- "/usr/bin/posix/sh",
-# else
- "/bin/rsh", /* restricted Bourne shell */
- "/bin/ksh", /* Korn shell */
- "/bin/rksh", /* restricted Korn shell */
- "/bin/pam",
- "/usr/bin/keysh", /* key shell (extended Korn shell) */
- "/bin/posix/sh",
-# endif
-#endif
-#if defined(_AIX3) || defined(_AIX4)
- "/bin/ksh", /* Korn shell */
- "/usr/bin/ksh",
- "/bin/tsh", /* trusted shell */
- "/usr/bin/tsh",
- "/bin/bsh", /* Bourne shell */
- "/usr/bin/bsh",
-#endif
-#if defined(__svr4__) || defined(__svr5__)
- "/bin/ksh", /* Korn shell */
- "/usr/bin/ksh",
-#endif
-#ifdef sgi
- "/sbin/sh", /* SGI's shells really live in /sbin */
- "/sbin/csh",
- "/bin/ksh", /* Korn shell */
- "/sbin/ksh",
- "/usr/bin/ksh",
- "/bin/tcsh", /* Extended csh */
- "/usr/bin/tcsh",
-#endif
- NULL
-};
-
-#endif
-
-#define WILDCARD_SHELL "/SENDMAIL/ANY/SHELL/"
-
-bool
-usershellok(user, shell)
- char *user;
- char *shell;
-{
-#if HASGETUSERSHELL
- register char *p;
- extern char *getusershell();
-
- if (shell == NULL || shell[0] == '\0' || wordinclass(user, 't') ||
- ConfigLevel <= 1)
- return TRUE;
-
- setusershell();
- while ((p = getusershell()) != NULL)
- if (strcmp(p, shell) == 0 || strcmp(p, WILDCARD_SHELL) == 0)
- break;
- endusershell();
- return p != NULL;
-#else
-# if USEGETCONFATTR
- auto char *v;
-# endif
- register FILE *shellf;
- char buf[MAXLINE];
-
- if (shell == NULL || shell[0] == '\0' || wordinclass(user, 't') ||
- ConfigLevel <= 1)
- return TRUE;
-
-# if USEGETCONFATTR
- /*
- ** Naturally IBM has a "better" idea.....
- **
- ** What a crock. This interface isn't documented, it is
- ** considered part of the security library (-ls), and it
- ** only works if you are running as root (since the list
- ** of valid shells is obviously a source of great concern).
- ** I recommend that you do NOT define USEGETCONFATTR,
- ** especially since you are going to have to set up an
- ** /etc/shells anyhow to handle the cases where getconfattr
- ** fails.
- */
-
- if (getconfattr(SC_SYS_LOGIN, SC_SHELLS, &v, SEC_LIST) == 0 && v != NULL)
- {
- while (*v != '\0')
- {
- if (strcmp(v, shell) == 0 || strcmp(v, WILDCARD_SHELL) == 0)
- return TRUE;
- v += strlen(v) + 1;
- }
- return FALSE;
- }
-# endif
-
- shellf = fopen(_PATH_SHELLS, "r");
- if (shellf == NULL)
- {
- /* no /etc/shells; see if it is one of the std shells */
- char **d;
-
- if (errno != ENOENT && LogLevel > 3)
- sm_syslog(LOG_ERR, NOQID,
- "usershellok: cannot open %s: %s",
- _PATH_SHELLS, errstring(errno));
-
- for (d = DefaultUserShells; *d != NULL; d++)
- {
- if (strcmp(shell, *d) == 0)
- return TRUE;
- }
- return FALSE;
- }
-
- while (fgets(buf, sizeof buf, shellf) != NULL)
- {
- register char *p, *q;
-
- p = buf;
- while (*p != '\0' && *p != '#' && *p != '/')
- p++;
- if (*p == '#' || *p == '\0')
- continue;
- q = p;
- while (*p != '\0' && *p != '#' && !(isascii(*p) && isspace(*p)))
- p++;
- *p = '\0';
- if (strcmp(shell, q) == 0 || strcmp(WILDCARD_SHELL, q) == 0)
- {
- fclose(shellf);
- return TRUE;
- }
- }
- fclose(shellf);
- return FALSE;
-#endif
-}
- /*
-** FREEDISKSPACE -- see how much free space is on the queue filesystem
-**
-** Only implemented if you have statfs.
-**
-** Parameters:
-** dir -- the directory in question.
-** bsize -- a variable into which the filesystem
-** block size is stored.
-**
-** Returns:
-** The number of bytes free on the queue filesystem.
-** -1 if the statfs call fails.
-**
-** Side effects:
-** Puts the filesystem block size into bsize.
-*/
-
-/* statfs types */
-#define SFS_NONE 0 /* no statfs implementation */
-#define SFS_USTAT 1 /* use ustat */
-#define SFS_4ARGS 2 /* use four-argument statfs call */
-#define SFS_VFS 3 /* use <sys/vfs.h> implementation */
-#define SFS_MOUNT 4 /* use <sys/mount.h> implementation */
-#define SFS_STATFS 5 /* use <sys/statfs.h> implementation */
-#define SFS_STATVFS 6 /* use <sys/statvfs.h> implementation */
-
-#ifndef SFS_TYPE
-# define SFS_TYPE SFS_NONE
-#endif
-
-#if SFS_TYPE == SFS_USTAT
-# include <ustat.h>
-#endif
-#if SFS_TYPE == SFS_4ARGS || SFS_TYPE == SFS_STATFS
-# include <sys/statfs.h>
-#endif
-#if SFS_TYPE == SFS_VFS
-# include <sys/vfs.h>
-#endif
-#if SFS_TYPE == SFS_MOUNT
-# include <sys/mount.h>
-#endif
-#if SFS_TYPE == SFS_STATVFS
-# include <sys/statvfs.h>
-#endif
-
-long
-freediskspace(dir, bsize)
- char *dir;
- long *bsize;
-{
-#if SFS_TYPE != SFS_NONE
-# if SFS_TYPE == SFS_USTAT
- struct ustat fs;
- struct stat statbuf;
-# define FSBLOCKSIZE DEV_BSIZE
-# define SFS_BAVAIL f_tfree
-# else
-# if defined(ultrix)
- struct fs_data fs;
-# define SFS_BAVAIL fd_bfreen
-# define FSBLOCKSIZE 1024L
-# else
-# if SFS_TYPE == SFS_STATVFS
- struct statvfs fs;
-# define FSBLOCKSIZE fs.f_frsize
-# else
- struct statfs fs;
-# define FSBLOCKSIZE fs.f_bsize
-# endif
-# endif
-# endif
-# ifndef SFS_BAVAIL
-# define SFS_BAVAIL f_bavail
-# endif
-
-# if SFS_TYPE == SFS_USTAT
- if (stat(dir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0)
-# else
-# if SFS_TYPE == SFS_4ARGS
- if (statfs(dir, &fs, sizeof fs, 0) == 0)
-# else
-# if SFS_TYPE == SFS_STATVFS
- if (statvfs(dir, &fs) == 0)
-# else
-# if defined(ultrix)
- if (statfs(dir, &fs) > 0)
-# else
- if (statfs(dir, &fs) == 0)
-# endif
-# endif
-# endif
-# endif
- {
- if (bsize != NULL)
- *bsize = FSBLOCKSIZE;
- if (fs.SFS_BAVAIL <= 0)
- return 0;
- else if (fs.SFS_BAVAIL > LONG_MAX)
- return LONG_MAX;
- else
- return (long) fs.SFS_BAVAIL;
- }
-#endif
- return (-1);
-}
- /*
-** ENOUGHDISKSPACE -- is there enough free space on the queue fs?
-**
-** Only implemented if you have statfs.
-**
-** Parameters:
-** msize -- the size to check against. If zero, we don't yet
-** know how big the message will be, so just check for
-** a "reasonable" amount.
-**
-** Returns:
-** TRUE if there is enough space.
-** FALSE otherwise.
-*/
-
-bool
-enoughdiskspace(msize)
- long msize;
-{
- long bfree, bsize;
-
- if (MinBlocksFree <= 0 && msize <= 0)
- {
- if (tTd(4, 80))
- printf("enoughdiskspace: no threshold\n");
- return TRUE;
- }
-
- if ((bfree = freediskspace(QueueDir, &bsize)) >= 0)
- {
- if (tTd(4, 80))
- printf("enoughdiskspace: bavail=%ld, need=%ld\n",
- bfree, msize);
-
- /* convert msize to block count */
- msize = msize / bsize + 1;
- if (MinBlocksFree >= 0)
- msize += MinBlocksFree;
-
- if (bfree < msize)
- {
- if (LogLevel > 0)
- sm_syslog(LOG_ALERT, CurEnv->e_id,
- "low on space (have %ld, %s needs %ld in %s)",
- bfree,
- CurHostName == NULL ? "SMTP-DAEMON" : CurHostName,
- msize, QueueDir);
- return FALSE;
- }
- }
- else if (tTd(4, 80))
- printf("enoughdiskspace failure: min=%ld, need=%ld: %s\n",
- MinBlocksFree, msize, errstring(errno));
- return TRUE;
-}
- /*
-** TRANSIENTERROR -- tell if an error code indicates a transient failure
-**
-** This looks at an errno value and tells if this is likely to
-** go away if retried later.
-**
-** Parameters:
-** err -- the errno code to classify.
-**
-** Returns:
-** TRUE if this is probably transient.
-** FALSE otherwise.
-*/
-
-bool
-transienterror(err)
- int err;
-{
- switch (err)
- {
- case EIO: /* I/O error */
- case ENXIO: /* Device not configured */
- case EAGAIN: /* Resource temporarily unavailable */
- case ENOMEM: /* Cannot allocate memory */
- case ENODEV: /* Operation not supported by device */
- case ENFILE: /* Too many open files in system */
- case EMFILE: /* Too many open files */
- case ENOSPC: /* No space left on device */
-#ifdef ETIMEDOUT
- case ETIMEDOUT: /* Connection timed out */
-#endif
-#ifdef ESTALE
- case ESTALE: /* Stale NFS file handle */
-#endif
-#ifdef ENETDOWN
- case ENETDOWN: /* Network is down */
-#endif
-#ifdef ENETUNREACH
- case ENETUNREACH: /* Network is unreachable */
-#endif
-#ifdef ENETRESET
- case ENETRESET: /* Network dropped connection on reset */
-#endif
-#ifdef ECONNABORTED
- case ECONNABORTED: /* Software caused connection abort */
-#endif
-#ifdef ECONNRESET
- case ECONNRESET: /* Connection reset by peer */
-#endif
-#ifdef ENOBUFS
- case ENOBUFS: /* No buffer space available */
-#endif
-#ifdef ESHUTDOWN
- case ESHUTDOWN: /* Can't send after socket shutdown */
-#endif
-#ifdef ECONNREFUSED
- case ECONNREFUSED: /* Connection refused */
-#endif
-#ifdef EHOSTDOWN
- case EHOSTDOWN: /* Host is down */
-#endif
-#ifdef EHOSTUNREACH
- case EHOSTUNREACH: /* No route to host */
-#endif
-#ifdef EDQUOT
- case EDQUOT: /* Disc quota exceeded */
-#endif
-#ifdef EPROCLIM
- case EPROCLIM: /* Too many processes */
-#endif
-#ifdef EUSERS
- case EUSERS: /* Too many users */
-#endif
-#ifdef EDEADLK
- case EDEADLK: /* Resource deadlock avoided */
-#endif
-#ifdef EISCONN
- case EISCONN: /* Socket already connected */
-#endif
-#ifdef EINPROGRESS
- case EINPROGRESS: /* Operation now in progress */
-#endif
-#ifdef EALREADY
- case EALREADY: /* Operation already in progress */
-#endif
-#ifdef EADDRINUSE
- case EADDRINUSE: /* Address already in use */
-#endif
-#ifdef EADDRNOTAVAIL
- case EADDRNOTAVAIL: /* Can't assign requested address */
-#endif
-#ifdef ETXTBSY
- case ETXTBSY: /* (Apollo) file locked */
-#endif
-#if defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR))
- case ENOSR: /* Out of streams resources */
-#endif
- case E_SM_OPENTIMEOUT: /* PSEUDO: open timed out */
- return TRUE;
- }
-
- /* nope, must be permanent */
- return FALSE;
-}
- /*
-** LOCKFILE -- lock a file using flock or (shudder) fcntl locking
-**
-** Parameters:
-** fd -- the file descriptor of the file.
-** filename -- the file name (for error messages).
-** ext -- the filename extension.
-** type -- type of the lock. Bits can be:
-** LOCK_EX -- exclusive lock.
-** LOCK_NB -- non-blocking.
-**
-** Returns:
-** TRUE if the lock was acquired.
-** FALSE otherwise.
-*/
-
-bool
-lockfile(fd, filename, ext, type)
- int fd;
- char *filename;
- char *ext;
- int type;
-{
- int i;
- int save_errno;
-# if !HASFLOCK
- int action;
- struct flock lfd;
-
- if (ext == NULL)
- ext = "";
-
- bzero(&lfd, sizeof lfd);
- if (bitset(LOCK_UN, type))
- lfd.l_type = F_UNLCK;
- else if (bitset(LOCK_EX, type))
- lfd.l_type = F_WRLCK;
- else
- lfd.l_type = F_RDLCK;
-
- if (bitset(LOCK_NB, type))
- action = F_SETLK;
- else
- action = F_SETLKW;
-
- if (tTd(55, 60))
- printf("lockfile(%s%s, action=%d, type=%d): ",
- filename, ext, action, lfd.l_type);
-
- while ((i = fcntl(fd, action, &lfd)) < 0 && errno == EINTR)
- continue;
- if (i >= 0)
- {
- if (tTd(55, 60))
- printf("SUCCESS\n");
- return TRUE;
- }
- save_errno = errno;
-
- if (tTd(55, 60))
- printf("(%s) ", errstring(save_errno));
-
- /*
- ** On SunOS, if you are testing using -oQ/tmp/mqueue or
- ** -oA/tmp/aliases or anything like that, and /tmp is mounted
- ** as type "tmp" (that is, served from swap space), the
- ** previous fcntl will fail with "Invalid argument" errors.
- ** Since this is fairly common during testing, we will assume
- ** that this indicates that the lock is successfully grabbed.
- */
-
- if (save_errno == EINVAL)
- {
- if (tTd(55, 60))
- printf("SUCCESS\n");
- return TRUE;
- }
-
- if (!bitset(LOCK_NB, type) || (save_errno != EACCES && save_errno != EAGAIN))
- {
- int omode = -1;
-# ifdef F_GETFL
- (void) fcntl(fd, F_GETFL, &omode);
- errno = save_errno;
-# endif
- syserr("cannot lockf(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
- filename, ext, fd, type, omode, geteuid());
- dumpfd(fd, TRUE, TRUE);
- }
-# else
- if (ext == NULL)
- ext = "";
-
- if (tTd(55, 60))
- printf("lockfile(%s%s, type=%o): ", filename, ext, type);
-
- while ((i = flock(fd, type)) < 0 && errno == EINTR)
- continue;
- if (i >= 0)
- {
- if (tTd(55, 60))
- printf("SUCCESS\n");
- return TRUE;
- }
- save_errno = errno;
-
- if (tTd(55, 60))
- printf("(%s) ", errstring(save_errno));
-
- if (!bitset(LOCK_NB, type) || save_errno != EWOULDBLOCK)
- {
- int omode = -1;
-# ifdef F_GETFL
- (void) fcntl(fd, F_GETFL, &omode);
- errno = save_errno;
-# endif
- syserr("cannot flock(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
- filename, ext, fd, type, omode, geteuid());
- dumpfd(fd, TRUE, TRUE);
- }
-# endif
- if (tTd(55, 60))
- printf("FAIL\n");
- errno = save_errno;
- return FALSE;
-}
- /*
-** CHOWNSAFE -- tell if chown is "safe" (executable only by root)
-**
-** Unfortunately, given that we can't predict other systems on which
-** a remote mounted (NFS) filesystem will be mounted, the answer is
-** almost always that this is unsafe.
-**
-** Note also that many operating systems have non-compliant
-** implementations of the _POSIX_CHOWN_RESTRICTED variable and the
-** fpathconf() routine. According to IEEE 1003.1-1990, if
-** _POSIX_CHOWN_RESTRICTED is defined and not equal to -1, then
-** no non-root process can give away the file. However, vendors
-** don't take NFS into account, so a comfortable value of
-** _POSIX_CHOWN_RESTRICTED tells us nothing.
-**
-** Also, some systems (e.g., IRIX 6.2) return 1 from fpathconf()
-** even on files where chown is not restricted. Many systems get
-** this wrong on NFS-based filesystems (that is, they say that chown
-** is restricted [safe] on NFS filesystems where it may not be, since
-** other systems can access the same filesystem and do file giveaway;
-** only the NFS server knows for sure!) Hence, it is important to
-** get the value of SAFENFSPATHCONF correct -- it should be defined
-** _only_ after testing (see test/t_pathconf.c) a system on an unsafe
-** NFS-based filesystem to ensure that you can get meaningful results.
-** If in doubt, assume unsafe!
-**
-** You may also need to tweak IS_SAFE_CHOWN -- it should be a
-** condition indicating whether the return from pathconf indicates
-** that chown is safe (typically either > 0 or >= 0 -- there isn't
-** even any agreement about whether a zero return means that a file
-** is or is not safe). It defaults to "> 0".
-**
-** If the parent directory is safe (writable only by owner back
-** to the root) then we can relax slightly and trust fpathconf
-** in more circumstances. This is really a crock -- if this is an
-** NFS mounted filesystem then we really know nothing about the
-** underlying implementation. However, most systems pessimize and
-** return an error (EINVAL or EOPNOTSUPP) on NFS filesystems, which
-** we interpret as unsafe, as we should. Thus, this heuristic gets
-** us into a possible problem only on systems that have a broken
-** pathconf implementation and which are also poorly configured
-** (have :include: files in group- or world-writable directories).
-**
-** Parameters:
-** fd -- the file descriptor to check.
-** safedir -- set if the parent directory is safe.
-**
-** Returns:
-** TRUE -- if the chown(2) operation is "safe" -- that is,
-** only root can chown the file to an arbitrary user.
-** FALSE -- if an arbitrary user can give away a file.
-*/
-
-#ifndef IS_SAFE_CHOWN
-# define IS_SAFE_CHOWN > 0
-#endif
-
-bool
-chownsafe(fd, safedir)
- int fd;
- bool safedir;
-{
-#if (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && \
- (defined(_PC_CHOWN_RESTRICTED) || defined(_GNU_TYPES_H))
- int rval;
-
- /* give the system administrator a chance to override */
- if (bitset(DBS_ASSUMESAFECHOWN, DontBlameSendmail))
- return TRUE;
-
- /*
- ** Some systems (e.g., SunOS) seem to have the call and the
- ** #define _PC_CHOWN_RESTRICTED, but don't actually implement
- ** the call. This heuristic checks for that.
- */
-
- errno = 0;
- rval = fpathconf(fd, _PC_CHOWN_RESTRICTED);
-# if SAFENFSPATHCONF
- return errno == 0 && rval IS_SAFE_CHOWN;
-# else
- return safedir && errno == 0 && rval IS_SAFE_CHOWN;
-# endif
-#else
- return bitset(DBS_ASSUMESAFECHOWN, DontBlameSendmail);
-#endif
-}
- /*
-** RESETLIMITS -- reset system controlled resource limits
-**
-** This is to avoid denial-of-service attacks
-**
-** Parameters:
-** none
-**
-** Returns:
-** none
-*/
-
-#if HASSETRLIMIT
-# ifdef RLIMIT_NEEDS_SYS_TIME_H
-# include <sys/time.h>
-# endif
-# include <sys/resource.h>
-#endif
-#ifndef FD_SETSIZE
-# define FD_SETSIZE 256
-#endif
-
-void
-resetlimits()
-{
-#if HASSETRLIMIT
- struct rlimit lim;
-
- lim.rlim_cur = lim.rlim_max = RLIM_INFINITY;
- (void) setrlimit(RLIMIT_CPU, &lim);
- (void) setrlimit(RLIMIT_FSIZE, &lim);
-# ifdef RLIMIT_NOFILE
- lim.rlim_cur = lim.rlim_max = FD_SETSIZE;
- (void) setrlimit(RLIMIT_NOFILE, &lim);
-# endif
-#else
-# if HASULIMIT
- (void) ulimit(2, 0x3fffff);
- (void) ulimit(4, FD_SETSIZE);
-# endif
-#endif
- errno = 0;
-}
- /*
-** GETCFNAME -- return the name of the .cf file.
-**
-** Some systems (e.g., NeXT) determine this dynamically.
-*/
-
-char *
-getcfname()
-{
-
- if (ConfFile != NULL)
- return ConfFile;
-#if NETINFO
- {
- extern char *ni_propval __P((char *, char *, char *, char *, int));
- char *cflocation;
-
- cflocation = ni_propval("/locations", NULL, "sendmail",
- "sendmail.cf", '\0');
- if (cflocation != NULL)
- return cflocation;
- }
-#endif
-
- return _PATH_SENDMAILCF;
-}
- /*
-** SETVENDOR -- process vendor code from V configuration line
-**
-** Parameters:
-** vendor -- string representation of vendor.
-**
-** Returns:
-** TRUE -- if ok.
-** FALSE -- if vendor code could not be processed.
-**
-** Side Effects:
-** It is reasonable to set mode flags here to tweak
-** processing in other parts of the code if necessary.
-** For example, if you are a vendor that uses $%y to
-** indicate YP lookups, you could enable that here.
-*/
-
-bool
-setvendor(vendor)
- char *vendor;
-{
- if (strcasecmp(vendor, "Berkeley") == 0)
- {
- VendorCode = VENDOR_BERKELEY;
- return TRUE;
- }
-
- /* add vendor extensions here */
-
-#ifdef SUN_EXTENSIONS
- if (strcasecmp(vendor, "Sun") == 0)
- {
- VendorCode = VENDOR_SUN;
- return TRUE;
- }
-#endif
-
-#if defined(VENDOR_NAME) && defined(VENDOR_CODE)
- if (strcasecmp(vendor, VENDOR_NAME) == 0)
- {
- VendorCode = VENDOR_CODE;
- return TRUE;
- }
-#endif
-
- return FALSE;
-}
- /*
-** GETVENDOR -- return vendor name based on vendor code
-**
-** Parameters:
-** vendorcode -- numeric representation of vendor.
-**
-** Returns:
-** string containing vendor name.
-*/
-
-char *
-getvendor(vendorcode)
- int vendorcode;
-{
-#if defined(VENDOR_NAME) && defined(VENDOR_CODE)
- /*
- ** Can't have the same switch case twice so need to
- ** handle VENDOR_CODE outside of switch. It might
- ** match one of the existing VENDOR_* codes.
- */
-
- if (vendorcode == VENDOR_CODE)
- return VENDOR_NAME;
-#endif
-
- switch (vendorcode)
- {
- case VENDOR_BERKELEY:
- return "Berkeley";
-
- case VENDOR_SUN:
- return "Sun";
-
- case VENDOR_HP:
- return "HP";
-
- case VENDOR_IBM:
- return "IBM";
-
- case VENDOR_SENDMAIL:
- return "Sendmail";
-
- default:
- return "Unknown";
- }
-}
- /*
-** VENDOR_PRE_DEFAULTS, VENDOR_POST_DEFAULTS -- set vendor-specific defaults
-**
-** Vendor_pre_defaults is called before reading the configuration
-** file; vendor_post_defaults is called immediately after.
-**
-** Parameters:
-** e -- the global environment to initialize.
-**
-** Returns:
-** none.
-*/
-
-#if SHARE_V1
-int DefShareUid; /* default share uid to run as -- unused??? */
-#endif
-
-void
-vendor_pre_defaults(e)
- ENVELOPE *e;
-{
-#if SHARE_V1
- /* OTHERUID is defined in shares.h, do not be alarmed */
- DefShareUid = OTHERUID;
-#endif
-#if defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES)
- sun_pre_defaults(e);
-#endif
-#ifdef apollo
- /* stupid domain/os can't even open /etc/sendmail.cf without this */
- setuserenv("ISP", NULL);
- setuserenv("SYSTYPE", NULL);
-#endif
-}
-
-
-void
-vendor_post_defaults(e)
- ENVELOPE *e;
-{
-#ifdef __QNX__
- char *p;
-
- /* Makes sure the SOCK environment variable remains */
- if (p = getextenv("SOCK"))
- setuserenv("SOCK", p);
-#endif
-#if defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES)
- sun_post_defaults(e);
-#endif
-}
- /*
-** VENDOR_DAEMON_SETUP -- special vendor setup needed for daemon mode
-*/
-
-void
-vendor_daemon_setup(e)
- ENVELOPE *e;
-{
-#if SECUREWARE
- if (getluid() != -1)
- {
- usrerr("Daemon cannot have LUID");
- finis(FALSE, EX_USAGE);
- }
-#endif /* SECUREWARE */
-}
- /*
-** VENDOR_SET_UID -- do setup for setting a user id
-**
-** This is called when we are still root.
-**
-** Parameters:
-** uid -- the uid we are about to become.
-**
-** Returns:
-** none.
-*/
-
-void
-vendor_set_uid(uid)
- UID_T uid;
-{
- /*
- ** We need to setup the share groups (lnodes)
- ** and and auditing inforation (luid's)
- ** before we loose our ``root''ness.
- */
-#if SHARE_V1
- if (setupshares(uid, syserr) != 0)
- syserr("Unable to set up shares");
-#endif
-#if SECUREWARE
- (void) setup_secure(uid);
-#endif
-}
- /*
-** VALIDATE_CONNECTION -- check connection for rationality
-**
-** If the connection is rejected, this routine should log an
-** appropriate message -- but should never issue any SMTP protocol.
-**
-** Parameters:
-** sap -- a pointer to a SOCKADDR naming the peer.
-** hostname -- the name corresponding to sap.
-** e -- the current envelope.
-**
-** Returns:
-** error message from rejection.
-** NULL if not rejected.
-*/
-
-#if TCPWRAPPERS
-# include <tcpd.h>
-
-/* tcpwrappers does no logging, but you still have to declare these -- ugh */
-int allow_severity = LOG_INFO;
-int deny_severity = LOG_NOTICE;
-#endif
-
-#if DAEMON
-char *
-validate_connection(sap, hostname, e)
- SOCKADDR *sap;
- char *hostname;
- ENVELOPE *e;
-{
-#if TCPWRAPPERS
- char *host;
-#endif
-
- if (tTd(48, 3))
- printf("validate_connection(%s, %s)\n",
- hostname, anynet_ntoa(sap));
-
- if (rscheck("check_relay", hostname, anynet_ntoa(sap), e) != EX_OK)
- {
- static char reject[BUFSIZ*2];
- extern char MsgBuf[];
-
- if (tTd(48, 4))
- printf(" ... validate_connection: BAD (rscheck)\n");
-
- if (strlen(MsgBuf) > 5)
- {
- if (isascii(MsgBuf[0]) && isdigit(MsgBuf[0]) &&
- isascii(MsgBuf[1]) && isdigit(MsgBuf[1]) &&
- isascii(MsgBuf[2]) && isdigit(MsgBuf[2]))
- strcpy(reject, &MsgBuf[4]);
- else
- strcpy(reject, MsgBuf);
- }
- else
- strcpy(reject, "Access denied");
-
- return reject;
- }
-
-#if TCPWRAPPERS
- if (hostname[0] == '[' && hostname[strlen(hostname) - 1] == ']')
- host = "unknown";
- else
- host = hostname;
- if (!hosts_ctl("sendmail", host, anynet_ntoa(sap), STRING_UNKNOWN))
- {
- if (tTd(48, 4))
- printf(" ... validate_connection: BAD (tcpwrappers)\n");
- if (LogLevel >= 4)
- sm_syslog(LOG_NOTICE, NOQID,
- "tcpwrappers (%s, %s) rejection",
- host, anynet_ntoa(sap));
- return "Access denied";
- }
-#endif
- if (tTd(48, 4))
- printf(" ... validate_connection: OK\n");
- return NULL;
-}
-
-#endif
- /*
-** STRTOL -- convert string to long integer
-**
-** For systems that don't have it in the C library.
-**
-** This is taken verbatim from the 4.4-Lite C library.
-*/
-
-#ifdef NEEDSTRTOL
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93";
-#endif /* LIBC_SCCS and not lint */
-
-/*
- * Convert a string to a long integer.
- *
- * Ignores `locale' stuff. Assumes that the upper and lower case
- * alphabets and digits are each contiguous.
- */
-
-long
-strtol(nptr, endptr, base)
- const char *nptr;
- char **endptr;
- register int base;
-{
- register const char *s = nptr;
- register unsigned long acc;
- register int c;
- register unsigned long cutoff;
- register int neg = 0, any, cutlim;
-
- /*
- * Skip white space and pick up leading +/- sign if any.
- * If base is 0, allow 0x for hex and 0 for octal, else
- * assume decimal; if base is already 16, allow 0x.
- */
- do {
- c = *s++;
- } while (isspace(c));
- if (c == '-') {
- neg = 1;
- c = *s++;
- } else if (c == '+')
- c = *s++;
- if ((base == 0 || base == 16) &&
- c == '0' && (*s == 'x' || *s == 'X')) {
- c = s[1];
- s += 2;
- base = 16;
- }
- if (base == 0)
- base = c == '0' ? 8 : 10;
-
- /*
- * Compute the cutoff value between legal numbers and illegal
- * numbers. That is the largest legal value, divided by the
- * base. An input number that is greater than this value, if
- * followed by a legal input character, is too big. One that
- * is equal to this value may be valid or not; the limit
- * between valid and invalid numbers is then based on the last
- * digit. For instance, if the range for longs is
- * [-2147483648..2147483647] and the input base is 10,
- * cutoff will be set to 214748364 and cutlim to either
- * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
- * a value > 214748364, or equal but the next digit is > 7 (or 8),
- * the number is too big, and we will return a range error.
- *
- * Set any if any `digits' consumed; make it negative to indicate
- * overflow.
- */
- cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
- cutlim = cutoff % (unsigned long)base;
- cutoff /= (unsigned long)base;
- for (acc = 0, any = 0;; c = *s++) {
- if (isdigit(c))
- c -= '0';
- else if (isalpha(c))
- c -= isupper(c) ? 'A' - 10 : 'a' - 10;
- else
- break;
- if (c >= base)
- break;
- if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
- any = -1;
- else {
- any = 1;
- acc *= base;
- acc += c;
- }
- }
- if (any < 0) {
- acc = neg ? LONG_MIN : LONG_MAX;
- errno = ERANGE;
- } else if (neg)
- acc = -acc;
- if (endptr != 0)
- *endptr = (char *)(any ? s - 1 : nptr);
- return (acc);
-}
-
-#endif
- /*
-** STRSTR -- find first substring in string
-**
-** Parameters:
-** big -- the big (full) string.
-** little -- the little (sub) string.
-**
-** Returns:
-** A pointer to the first instance of little in big.
-** big if little is the null string.
-** NULL if little is not contained in big.
-*/
-
-#ifdef NEEDSTRSTR
-
-char *
-strstr(big, little)
- char *big;
- char *little;
-{
- register char *p = big;
- int l;
-
- if (*little == '\0')
- return big;
- l = strlen(little);
-
- while ((p = strchr(p, *little)) != NULL)
- {
- if (strncmp(p, little, l) == 0)
- return p;
- p++;
- }
- return NULL;
-}
-
-#endif
- /*
-** SM_GETHOSTBY{NAME,ADDR} -- compatibility routines for gethostbyXXX
-**
-** Some operating systems have wierd problems with the gethostbyXXX
-** routines. For example, Solaris versions at least through 2.3
-** don't properly deliver a canonical h_name field. This tries to
-** work around these problems.
-*/
-
-struct hostent *
-sm_gethostbyname(name)
- char *name;
-{
- struct hostent *h;
-#if (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4))
-# if SOLARIS == 20300 || SOLARIS == 203
- static struct hostent hp;
- static char buf[1000];
- extern struct hostent *_switch_gethostbyname_r();
-
- if (tTd(61, 10))
- printf("_switch_gethostbyname_r(%s)... ", name);
- h = _switch_gethostbyname_r(name, &hp, buf, sizeof(buf), &h_errno);
-# else
- extern struct hostent *__switch_gethostbyname();
-
- if (tTd(61, 10))
- printf("__switch_gethostbyname(%s)... ", name);
- h = __switch_gethostbyname(name);
-# endif
-#else
- int nmaps;
- char *maptype[MAXMAPSTACK];
- short mapreturn[MAXMAPACTIONS];
- char hbuf[MAXNAME];
-
- if (tTd(61, 10))
- printf("gethostbyname(%s)... ", name);
- h = gethostbyname(name);
- if (h == NULL)
- {
- if (tTd(61, 10))
- printf("failure\n");
-
- nmaps = switch_map_find("hosts", maptype, mapreturn);
- while (--nmaps >= 0)
- if (strcmp(maptype[nmaps], "nis") == 0 ||
- strcmp(maptype[nmaps], "files") == 0)
- break;
- if (nmaps >= 0)
- {
- /* try short name */
- if (strlen(name) > (SIZE_T) sizeof hbuf - 1)
- return NULL;
- strcpy(hbuf, name);
- shorten_hostname(hbuf);
-
- /* if it hasn't been shortened, there's no point */
- if (strcmp(hbuf, name) != 0)
- {
- if (tTd(61, 10))
- printf("gethostbyname(%s)... ", hbuf);
- h = gethostbyname(hbuf);
- }
- }
- }
-#endif
- if (tTd(61, 10))
- {
- if (h == NULL)
- printf("failure\n");
- else
- printf("%s\n", h->h_name);
- }
- return h;
-}
-
-struct hostent *
-sm_gethostbyaddr(addr, len, type)
- char *addr;
- int len;
- int type;
-{
-#if (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204)
-# if SOLARIS == 20300 || SOLARIS == 203
- static struct hostent hp;
- static char buf[1000];
- extern struct hostent *_switch_gethostbyaddr_r();
-
- return _switch_gethostbyaddr_r(addr, len, type, &hp, buf, sizeof(buf), &h_errno);
-# else
- extern struct hostent *__switch_gethostbyaddr();
-
- return __switch_gethostbyaddr(addr, len, type);
-# endif
-#else
- return gethostbyaddr(addr, len, type);
-#endif
-}
- /*
-** SM_GETPW{NAM,UID} -- wrapper for getpwnam and getpwuid
-*/
-
-struct passwd *
-sm_getpwnam(user)
- char *user;
-{
-#ifdef _AIX4
- extern struct passwd *_getpwnam_shadow(const char *, const int);
-
- return _getpwnam_shadow(user, 0);
-#else
- return getpwnam(user);
-#endif
-}
-
-struct passwd *
-sm_getpwuid(uid)
- UID_T uid;
-{
-#if defined(_AIX4) && 0
- extern struct passwd *_getpwuid_shadow(const int, const int);
-
- return _getpwuid_shadow(uid,0);
-#else
- return getpwuid(uid);
-#endif
-}
- /*
-** SECUREWARE_SETUP_SECURE -- Convex SecureWare setup
-**
-** Set up the trusted computing environment for C2 level security
-** under SecureWare.
-**
-** Parameters:
-** uid -- uid of the user to initialize in the TCB
-**
-** Returns:
-** none
-**
-** Side Effects:
-** Initialized the user in the trusted computing base
-*/
-
-#if SECUREWARE
-
-# include <sys/security.h>
-# include <prot.h>
-
-void
-secureware_setup_secure(uid)
- UID_T uid;
-{
- int rc;
-
- if (getluid() != -1)
- return;
-
- if ((rc = set_secure_info(uid)) != SSI_GOOD_RETURN)
- {
- switch (rc)
- {
- case SSI_NO_PRPW_ENTRY:
- syserr("No protected passwd entry, uid = %d", uid);
- break;
-
- case SSI_LOCKED:
- syserr("Account has been disabled, uid = %d", uid);
- break;
-
- case SSI_RETIRED:
- syserr("Account has been retired, uid = %d", uid);
- break;
-
- case SSI_BAD_SET_LUID:
- syserr("Could not set LUID, uid = %d", uid);
- break;
-
- case SSI_BAD_SET_PRIVS:
- syserr("Could not set kernel privs, uid = %d", uid);
-
- default:
- syserr("Unknown return code (%d) from set_secure_info(%d)",
- rc, uid);
- break;
- }
- finis(FALSE, EX_NOPERM);
- }
-}
-#endif /* SECUREWARE */
- /*
-** ADD_LOCAL_HOST_NAMES -- Add a hostname to class 'w' based on IP address
-**
-** Add hostnames to class 'w' based on the IP address read from
-** the network interface.
-**
-** Parameters:
-** sa -- a pointer to a SOCKADDR containing the address
-**
-** Returns:
-** 0 if successful, -1 if host lookup fails.
-*/
-
-int
-add_hostnames(sa)
- SOCKADDR *sa;
-{
- struct hostent *hp;
-
- /* lookup name with IP address */
- switch (sa->sa.sa_family)
- {
- case AF_INET:
- hp = sm_gethostbyaddr((char *) &sa->sin.sin_addr,
- sizeof(sa->sin.sin_addr), sa->sa.sa_family);
- break;
-
- default:
-#if _FFR_LOG_UNSUPPORTED_FAMILIES
- /* XXX: Give warning about unsupported family */
- if (LogLevel > 3)
- sm_syslog(LOG_WARNING, NOQID,
- "Unsupported address family %d: %.100s",
- sa->sa.sa_family, anynet_ntoa(sa));
-#endif
- return -1;
- }
-
- if (hp == NULL)
- {
- int save_errno = errno;
-
- if (LogLevel > 3)
- sm_syslog(LOG_WARNING, NOQID,
- "gethostbyaddr(%.100s) failed: %d\n",
- anynet_ntoa(sa),
-#if NAMED_BIND
- h_errno
-#else
- -1
-#endif
- );
- errno = save_errno;
- return -1;
- }
-
- /* save its cname */
- if (!wordinclass((char *) hp->h_name, 'w'))
- {
- setclass('w', (char *) hp->h_name);
- if (tTd(0, 4))
- printf("\ta.k.a.: %s\n", hp->h_name);
- }
-
- /* save all it aliases name */
- while (*hp->h_aliases)
- {
- if (!wordinclass(*hp->h_aliases, 'w'))
- {
- setclass('w', *hp->h_aliases);
- if (tTd(0, 4))
- printf("\ta.k.a.: %s\n", *hp->h_aliases);
- }
- hp->h_aliases++;
- }
- return 0;
-}
- /*
-** LOAD_IF_NAMES -- load interface-specific names into $=w
-**
-** Parameters:
-** none.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Loads $=w with the names of all the interfaces.
-*/
-
-#if defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN
-struct rtentry;
-struct mbuf;
-# include <arpa/inet.h>
-# ifndef SUNOS403
-# include <sys/time.h>
-# endif
-# if _AIX4 >= 40300
-# undef __P
-# endif
-# include <net/if.h>
-#endif
-
-void
-load_if_names()
-{
-#if defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN
- int s;
- int i;
- struct ifconf ifc;
- int numifs;
-
- s = socket(AF_INET, SOCK_DGRAM, 0);
- if (s == -1)
- return;
-
- /* get the list of known IP address from the kernel */
-# if defined(SIOCGIFNUM) && !SIOCGIFNUM_IS_BROKEN
- if (ioctl(s, SIOCGIFNUM, (char *) &numifs) < 0)
- {
- /* can't get number of interfaces -- fall back */
- if (tTd(0, 4))
- printf("SIOCGIFNUM failed: %s\n", errstring(errno));
- numifs = -1;
- }
- else if (tTd(0, 42))
- printf("system has %d interfaces\n", numifs);
- if (numifs < 0)
-# endif
- numifs = 512;
-
- if (numifs <= 0)
- {
- close(s);
- return;
- }
- ifc.ifc_len = numifs * sizeof (struct ifreq);
- ifc.ifc_buf = xalloc(ifc.ifc_len);
- if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0)
- {
- if (tTd(0, 4))
- printf("SIOGIFCONF failed: %s\n", errstring(errno));
- close(s);
- return;
- }
-
- /* scan the list of IP address */
- if (tTd(0, 40))
- printf("scanning for interface specific names, ifc_len=%d\n",
- ifc.ifc_len);
-
- for (i = 0; i < ifc.ifc_len; )
- {
- struct ifreq *ifr = (struct ifreq *) &ifc.ifc_buf[i];
- SOCKADDR *sa = (SOCKADDR *) &ifr->ifr_addr;
- struct in_addr ia;
-#ifdef SIOCGIFFLAGS
- struct ifreq ifrf;
-#endif
- char ip_addr[256];
- extern char *inet_ntoa();
-
-#ifdef BSD4_4_SOCKADDR
- if (sa->sa.sa_len > sizeof ifr->ifr_addr)
- i += sizeof ifr->ifr_name + sa->sa.sa_len;
- else
-#endif
- i += sizeof *ifr;
-
- if (tTd(0, 20))
- printf("%s\n", anynet_ntoa(sa));
-
- if (ifr->ifr_addr.sa_family != AF_INET)
- continue;
-
-#ifdef SIOCGIFFLAGS
- bzero(&ifrf, sizeof(struct ifreq));
- strncpy(ifrf.ifr_name, ifr->ifr_name, sizeof(ifrf.ifr_name));
- ioctl(s, SIOCGIFFLAGS, (char *) &ifrf);
- if (tTd(0, 41))
- printf("\tflags: %x\n", ifrf.ifr_flags);
-# define IFRFREF ifrf
-#else
-# define IFRFREF (*ifr)
-#endif
- if (!bitset(IFF_UP, IFRFREF.ifr_flags))
- continue;
-
- /* extract IP address from the list*/
- ia = sa->sin.sin_addr;
- if (ia.s_addr == INADDR_ANY || ia.s_addr == INADDR_NONE)
- {
- message("WARNING: interface %s is UP with %s address",
- ifr->ifr_name, inet_ntoa(ia));
- continue;
- }
-
- /* save IP address in text from */
- (void) snprintf(ip_addr, sizeof ip_addr, "[%.*s]",
- sizeof ip_addr - 3,
- inet_ntoa(ia));
- if (!wordinclass(ip_addr, 'w'))
- {
- setclass('w', ip_addr);
- if (tTd(0, 4))
- printf("\ta.k.a.: %s\n", ip_addr);
- }
-
- /* skip "loopback" interface "lo" */
- if (bitset(IFF_LOOPBACK, IFRFREF.ifr_flags))
- continue;
-
- (void) add_hostnames(sa);
- }
- free(ifc.ifc_buf);
- close(s);
-# undef IFRFREF
-#endif
-}
- /*
-** GET_NUM_PROCS_ONLINE -- return the number of processors currently online
-**
-** Parameters:
-** none.
-**
-** Returns:
-** The number of processors online.
-*/
-
-int
-get_num_procs_online()
-{
- int nproc = 0;
-
-#if _FFR_SCALE_LA_BY_NUM_PROCS
-#ifdef _SC_NPROCESSORS_ONLN
- nproc = (int) sysconf(_SC_NPROCESSORS_ONLN);
-#endif
-#endif
- if (nproc <= 0)
- nproc = 1;
- return nproc;
-}
- /*
-** SM_SYSLOG -- syslog wrapper to keep messages under SYSLOG_BUFSIZE
-**
-** Parameters:
-** level -- syslog level
-** id -- envelope ID or NULL (NOQUEUE)
-** fmt -- format string
-** arg... -- arguments as implied by fmt.
-**
-** Returns:
-** none
-*/
-
-/* VARARGS3 */
-void
-# ifdef __STDC__
-sm_syslog(int level, const char *id, const char *fmt, ...)
-# else
-sm_syslog(level, id, fmt, va_alist)
- int level;
- const char *id;
- const char *fmt;
- va_dcl
-#endif
-{
- static char *buf = NULL;
- static size_t bufsize = MAXLINE;
- char *begin, *end;
- int seq = 1;
- int idlen;
- extern int SnprfOverflow;
- extern int SyslogErrno;
- extern char *DoprEnd;
- VA_LOCAL_DECL
- extern void sm_dopr __P((char *, const char *, va_list));
-
- SyslogErrno = errno;
- if (id == NULL)
- {
- id = "NOQUEUE";
- idlen = 9;
- }
- else if (strcmp(id, NOQID) == 0)
- {
- id = "";
- idlen = 0;
- }
- else
- idlen = strlen(id + 2);
-bufalloc:
- if (buf == NULL)
- buf = (char *) xalloc(sizeof(char) * bufsize);
-
- /* do a virtual vsnprintf into buf */
- VA_START(fmt);
- buf[0] = 0;
- DoprEnd = buf + bufsize - 1;
- SnprfOverflow = 0;
- sm_dopr(buf, fmt, ap);
- *DoprEnd = '\0';
- VA_END;
- /* end of virtual vsnprintf */
-
- if (SnprfOverflow)
- {
- /* String too small, redo with correct size */
- bufsize += SnprfOverflow + 1;
- free(buf);
- buf = NULL;
- goto bufalloc;
- }
- if ((strlen(buf) + idlen + 1) < SYSLOG_BUFSIZE)
- {
-#if LOG
- if (*id == '\0')
- syslog(level, "%s", buf);
- else
- syslog(level, "%s: %s", id, buf);
-#else
- /*XXX should do something more sensible */
- if (*id == '\0')
- fprintf(stderr, "%s\n", buf);
- else
- fprintf(stderr, "%s: %s\n", id, buf);
-#endif
- return;
- }
-
- begin = buf;
- while (*begin != '\0' &&
- (strlen(begin) + idlen + 5) > SYSLOG_BUFSIZE)
- {
- char save;
-
- if (seq == 999)
- {
- /* Too many messages */
- break;
- }
- end = begin + SYSLOG_BUFSIZE - idlen - 12;
- while (end > begin)
- {
- /* Break on comma or space */
- if (*end == ',' || *end == ' ')
- {
- end++; /* Include separator */
- break;
- }
- end--;
- }
- /* No separator, break midstring... */
- if (end == begin)
- end = begin + SYSLOG_BUFSIZE - idlen - 12;
- save = *end;
- *end = 0;
-#if LOG
- syslog(level, "%s[%d]: %s ...", id, seq++, begin);
-#else
- fprintf(stderr, "%s[%d]: %s ...\n", id, seq++, begin);
-#endif
- *end = save;
- begin = end;
- }
- if (seq == 999)
-#if LOG
- syslog(level, "%s[%d]: log terminated, too many parts", id, seq);
-#else
- fprintf(stderr, "%s[%d]: log terminated, too many parts\n", id, seq);
-#endif
- else if (*begin != '\0')
-#if LOG
- syslog(level, "%s[%d]: %s", id, seq, begin);
-#else
- fprintf(stderr, "%s[%d]: %s\n", id, seq, begin);
-#endif
-}
- /*
-** HARD_SYSLOG -- call syslog repeatedly until it works
-**
-** Needed on HP-UX, which apparently doesn't guarantee that
-** syslog succeeds during interrupt handlers.
-*/
-
-#if defined(__hpux) && !defined(HPUX11)
-
-# define MAXSYSLOGTRIES 100
-# undef syslog
-# ifdef V4FS
-# define XCNST const
-# define CAST (const char *)
-# else
-# define XCNST
-# define CAST
-# endif
-
-void
-# ifdef __STDC__
-hard_syslog(int pri, XCNST char *msg, ...)
-# else
-hard_syslog(pri, msg, va_alist)
- int pri;
- XCNST char *msg;
- va_dcl
-# endif
-{
- int i;
- char buf[SYSLOG_BUFSIZE];
- VA_LOCAL_DECL;
-
- VA_START(msg);
- vsnprintf(buf, sizeof buf, msg, ap);
- VA_END;
-
- for (i = MAXSYSLOGTRIES; --i >= 0 && syslog(pri, CAST "%s", buf) < 0; )
- continue;
-}
-
-# undef CAST
-#endif
- /*
-** LOCAL_HOSTNAME_LENGTH
-**
-** This is required to get sendmail to compile against BIND 4.9.x
-** on Ultrix.
-*/
-
-#if defined(ultrix) && NAMED_BIND
-
-# include <resolv.h>
-# if __RES >= 19931104 && __RES < 19950621
-
-int
-local_hostname_length(hostname)
- char *hostname;
-{
- int len_host, len_domain;
-
- if (!*_res.defdname)
- res_init();
- len_host = strlen(hostname);
- len_domain = strlen(_res.defdname);
- if (len_host > len_domain &&
- (strcasecmp(hostname + len_host - len_domain,_res.defdname) == 0) &&
- hostname[len_host - len_domain - 1] == '.')
- return len_host - len_domain - 1;
- else
- return 0;
-}
-
-# endif
-#endif
- /*
-** Compile-Time options
-*/
-
-char *CompileOptions[] =
-{
-#ifdef HESIOD
- "HESIOD",
-#endif
-#if HES_GETMAILHOST
- "HES_GETMAILHOST",
-#endif
-#ifdef LDAPMAP
- "LDAPMAP",
-#endif
-#ifdef MAP_REGEX
- "MAP_REGEX",
-#endif
-#if LOG
- "LOG",
-#endif
-#if MATCHGECOS
- "MATCHGECOS",
-#endif
-#if MIME7TO8
- "MIME7TO8",
-#endif
-#if MIME8TO7
- "MIME8TO7",
-#endif
-#if NAMED_BIND
- "NAMED_BIND",
-#endif
-#ifdef NDBM
- "NDBM",
-#endif
-#if NETINET
- "NETINET",
-#endif
-#if NETINFO
- "NETINFO",
-#endif
-#if NETISO
- "NETISO",
-#endif
-#if NETNS
- "NETNS",
-#endif
-#if NETUNIX
- "NETUNIX",
-#endif
-#if NETX25
- "NETX25",
-#endif
-#ifdef NEWDB
- "NEWDB",
-#endif
-#ifdef NIS
- "NIS",
-#endif
-#ifdef NISPLUS
- "NISPLUS",
-#endif
-#if QUEUE
- "QUEUE",
-#endif
-#if SCANF
- "SCANF",
-#endif
-#if SMTP
- "SMTP",
-#endif
-#if SMTPDEBUG
- "SMTPDEBUG",
-#endif
-#ifdef SUID_ROOT_FILES_OK
- "SUID_ROOT_FILES_OK",
-#endif
-#if TCPWRAPPERS
- "TCPWRAPPERS",
-#endif
-#if USERDB
- "USERDB",
-#endif
-#if XDEBUG
- "XDEBUG",
-#endif
-#ifdef XLA
- "XLA",
-#endif
- NULL
-};
-
-
-/*
-** OS compile options.
-*/
-
-char *OsCompileOptions[] =
-{
-#if BOGUS_O_EXCL
- "BOGUS_O_EXCL",
-#endif
-#if HASFCHMOD
- "HASFCHMOD",
-#endif
-#if HASFLOCK
- "HASFLOCK",
-#endif
-#if HASGETDTABLESIZE
- "HASGETDTABLESIZE",
-#endif
-#if HASGETUSERSHELL
- "HASGETUSERSHELL",
-#endif
-#if HASINITGROUPS
- "HASINITGROUPS",
-#endif
-#if HASLSTAT
- "HASLSTAT",
-#endif
-#if HASSETREUID
- "HASSETREUID",
-#endif
-#if HASSETRLIMIT
- "HASSETRLIMIT",
-#endif
-#if HASSETSID
- "HASSETSID",
-#endif
-#if HASSETUSERCONTEXT
- "HASSETUSERCONTEXT",
-#endif
-#if HASSETVBUF
- "HASSETVBUF",
-#endif
-#if HASSNPRINTF
- "HASSNPRINTF",
-#endif
-#if HAS_ST_GEN
- "HAS_ST_GEN",
-#endif
-#if HASSTRERROR
- "HASSTRERROR",
-#endif
-#if HASULIMIT
- "HASULIMIT",
-#endif
-#if HASUNAME
- "HASUNAME",
-#endif
-#if HASUNSETENV
- "HASUNSETENV",
-#endif
-#if HASWAITPID
- "HASWAITPID",
-#endif
-#if IDENTPROTO
- "IDENTPROTO",
-#endif
-#if IP_SRCROUTE
- "IP_SRCROUTE",
-#endif
-#if O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL
- "LOCK_ON_OPEN",
-#endif
-#if NEEDFSYNC
- "NEEDFSYNC",
-#endif
-#if NOFTRUNCATE
- "NOFTRUNCATE",
-#endif
-#if RLIMIT_NEEDS_SYS_TIME_H
- "RLIMIT_NEEDS_SYS_TIME_H",
-#endif
-#if SAFENFSPATHCONF
- "SAFENFSPATHCONF",
-#endif
-#if SECUREWARE
- "SECUREWARE",
-#endif
-#if SHARE_V1
- "SHARE_V1",
-#endif
-#if SIOCGIFCONF_IS_BROKEN
- "SIOCGIFCONF_IS_BROKEN",
-#endif
-#if SIOCGIFNUM_IS_BROKEN
- "SIOCGIFNUM_IS_BROKEN",
-#endif
-#if SYS5SETPGRP
- "SYS5SETPGRP",
-#endif
-#if SYSTEM5
- "SYSTEM5",
-#endif
-#if USE_SA_SIGACTION
- "USE_SA_SIGACTION",
-#endif
-#if USE_SIGLONGJMP
- "USE_SIGLONGJMP",
-#endif
-#if USESETEUID
- "USESETEUID",
-#endif
- NULL
-};
diff --git a/src/conf.h b/src/conf.h
deleted file mode 100644
index 6097c27..0000000
--- a/src/conf.h
+++ /dev/null
@@ -1,2522 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- *
- * @(#)conf.h 8.385 (Berkeley) 1/28/1999
- */
-
-/*
-** CONF.H -- All user-configurable parameters for sendmail
-**
-** Send updates to sendmail@Sendmail.ORG so they will be
-** included in the next release.
-*/
-
-#ifdef __GNUC__
-struct rusage; /* forward declaration to get gcc to shut up in wait.h */
-#endif
-
-# include <sys/param.h>
-# include <sys/types.h>
-# include <sys/stat.h>
-#ifndef __QNX__
-/* in QNX this grabs bogus LOCK_* manifests */
-# include <sys/file.h>
-#endif
-# include <sys/wait.h>
-# include <limits.h>
-# include <fcntl.h>
-# include <signal.h>
-# include <netdb.h>
-# include <pwd.h>
-
-/**********************************************************************
-** Table sizes, etc....
-** There shouldn't be much need to change these....
-**********************************************************************/
-
-# define MAXLINE 2048 /* max line length */
-# define MAXNAME 256 /* max length of a name */
-# define MAXPV 40 /* max # of parms to mailers */
-# define MAXATOM 200 /* max atoms per address */
-# define MAXMAILERS 25 /* maximum mailers known to system */
-# define MAXRWSETS 200 /* max # of sets of rewriting rules */
-# define MAXPRIORITIES 25 /* max values for Precedence: field */
-# define MAXMXHOSTS 100 /* max # of MX records for one host */
-# define SMTPLINELIM 990 /* maximum SMTP line length */
-# define MAXKEY 128 /* maximum size of a database key */
-# define MEMCHUNKSIZE 1024 /* chunk size for memory allocation */
-# define MAXUSERENVIRON 100 /* max envars saved, must be >= 3 */
-# define MAXALIASDB 12 /* max # of alias databases */
-# define MAXMAPSTACK 12 /* max # of stacked or sequenced maps */
-# define MAXTOCLASS 8 /* max # of message timeout classes */
-# define MAXMIMEARGS 20 /* max args in Content-Type: */
-# define MAXMIMENESTING 20 /* max MIME multipart nesting */
-# define QUEUESEGSIZE 1000 /* increment for queue size */
-# define MAXQFNAME 20 /* max qf file name length */
-# define MACBUFSIZE 4096 /* max expanded macro buffer size */
-# define TOBUFSIZE 512 /* max buffer to hold address list */
-# define MAXSHORTSTR 203 /* max short string length */
-# if _FFR_MAX_MIME_HEADER_LENGTH
-# define MAXMACNAMELEN 25 /* max macro name length */
-# else
-# define MAXMACNAMELEN 20 /* max macro name length */
-# endif
-# ifndef MAXHDRSLEN
-# define MAXHDRSLEN (32 * 1024) /* max size of message headers */
-# endif
-
-/**********************************************************************
-** Compilation options.
-** #define these to 1 if they are available;
-** #define them to 0 otherwise.
-** All can be overridden from Makefile.
-**********************************************************************/
-
-# ifndef NETINET
-# define NETINET 1 /* include internet support */
-# endif
-
-# ifndef NETISO
-# define NETISO 0 /* do not include ISO socket support */
-# endif
-
-# ifndef NAMED_BIND
-# define NAMED_BIND 1 /* use Berkeley Internet Domain Server */
-# endif
-
-# ifndef XDEBUG
-# define XDEBUG 1 /* enable extended debugging */
-# endif
-
-# ifndef MATCHGECOS
-# define MATCHGECOS 1 /* match user names from gecos field */
-# endif
-
-# ifndef DSN
-# define DSN 1 /* include delivery status notification code */
-# endif
-
-# if !defined(USERDB) && (defined(NEWDB) || defined(HESIOD))
-# define USERDB 1 /* look in user database */
-# endif
-
-# ifndef MIME8TO7
-# define MIME8TO7 1 /* 8->7 bit MIME conversions */
-# endif
-
-# ifndef MIME7TO8
-# define MIME7TO8 1 /* 7->8 bit MIME conversions */
-# endif
-
-/**********************************************************************
-** "Hard" compilation options.
-** #define these if they are available; comment them out otherwise.
-** These cannot be overridden from the Makefile, and should really not
-** be turned off unless absolutely necessary.
-**********************************************************************/
-
-# define LOG 1 /* enable logging -- don't turn off */
-
-/**********************************************************************
-** End of site-specific configuration.
-**********************************************************************/
- /*
-** General "standard C" defines.
-**
-** These may be undone later, to cope with systems that claim to
-** be Standard C but aren't. Gcc is the biggest offender -- it
-** doesn't realize that the library is part of the language.
-**
-** Life would be much easier if we could get rid of this sort
-** of bozo problems.
-*/
-
-#ifdef __STDC__
-# define HASSETVBUF 1 /* we have setvbuf(3) in libc */
-#endif
-
-/*
-** Assume you have standard calls; can be #undefed below if necessary.
-*/
-
-# define HASLSTAT 1 /* has lstat(2) call */
- /**********************************************************************
-** Operating system configuration.
-**
-** Unless you are porting to a new OS, you shouldn't have to
-** change these.
-**********************************************************************/
-
-/*
-** HP-UX -- tested for 8.07, 9.00, and 9.01.
-**
-** If V4FS is defined, compile for HP-UX 10.0.
-** 11.x support from Richard Allen <ra@hp.is>.
-*/
-
-#ifdef __hpux
- /* common definitions for HP-UX 9.x and 10.x */
-# undef m_flags /* conflict between Berkeley DB 1.85 db.h & sys/sysmacros.h on HP 300 */
-# define SYSTEM5 1 /* include all the System V defines */
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define HASFCHMOD 1 /* has fchmod(2) syscall */
-# define USESETEUID 1 /* has useable seteuid(2) call */
-# define BOGUS_O_EXCL 1 /* exclusive open follows symlinks */
-# define seteuid(e) setresuid(-1, e, -1)
-# define IP_SRCROUTE 1 /* can check IP source routing */
-# define LA_TYPE LA_HPUX
-# define SPT_TYPE SPT_PSTAT
-# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
-# define GIDSET_T gid_t
-# ifndef HASGETUSERSHELL
-# define HASGETUSERSHELL 0 /* getusershell(3) causes core dumps */
-# endif
-# ifndef HPUX11
-# define syslog hard_syslog
-# endif
-# define SAFENFSPATHCONF 1 /* pathconf(2) pessimizes on NFS filesystems */
-
-# ifdef V4FS
- /* HP-UX 10.x */
-# define _PATH_UNIX "/stand/vmunix"
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/etc/mail/sendmail.cf"
-# endif
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/etc/mail/sendmail.pid"
-# endif
-# ifndef IDENTPROTO
-# define IDENTPROTO 1 /* TCP/IP implementation fixed in 10.0 */
-# endif
-
-# else
- /* HP-UX 9.x */
-# define _PATH_UNIX "/hp-ux"
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
-# endif
-# ifndef IDENTPROTO
-# define IDENTPROTO 0 /* TCP/IP implementation is broken */
-# endif
-# ifdef __STDC__
-extern void hard_syslog(int, char *, ...);
-# else
-extern void hard_syslog();
-# endif
-# define FDSET_CAST (int *) /* cast for fd_set parameters to select */
-# endif
-
-#endif
-
-
-/*
-** IBM AIX 4.x
-*/
-
-#ifdef _AIX4
-# define _AIX3 1 /* pull in AIX3 stuff */
-# define USESETEUID 1 /* seteuid(2) works */
-# define TZ_TYPE TZ_NAME /* use tzname[] vector */
-# define SOCKOPT_LEN_T size_t /* arg#5 to getsockopt */
-# if _AIX4 >= 40200
-# define HASSETREUID 1 /* setreuid(2) works as of AIX 4.2 */
-# define SOCKADDR_LEN_T size_t /* e.g., arg#3 to accept, getsockname */
-# endif
-# if defined(_ILS_MACROS) /* IBM versions aren't side-effect clean */
-# undef isascii
-# define isascii(c) !(c & ~0177)
-# undef isdigit
-# define isdigit(__a) (_IS(__a,_ISDIGIT))
-# undef isspace
-# define isspace(__a) (_IS(__a,_ISSPACE))
-# endif
-#endif
-
-
-/*
-** IBM AIX 3.x -- actually tested for 3.2.3
-*/
-
-#ifdef _AIX3
-# include <paths.h>
-# include <sys/machine.h> /* to get byte order */
-# include <sys/select.h>
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define HASUNAME 1 /* use System V uname(2) system call */
-# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
-# define HASFCHMOD 1 /* has fchmod(2) syscall */
-# define IP_SRCROUTE 0 /* Something is broken with getsockopt() */
-# define GIDSET_T gid_t
-# define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */
-# define SPT_PADCHAR '\0' /* pad process title with nulls */
-# define LA_TYPE LA_INT
-# define FSHIFT 16
-# define LA_AVENRUN "avenrun"
-#endif
-
-
-/*
-** IBM AIX 2.2.1 -- actually tested for osupdate level 2706+1773
-**
-** From Mark Whetzel <markw@wg.waii.com>.
-*/
-
-#ifdef AIX /* AIX/RT compiler pre-defines this */
-# include <paths.h>
-# include <sys/time.h> /* AIX/RT resource.h does NOT include this */
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define HASUNAME 1 /* use System V uname(2) system call */
-# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
-# define HASFCHMOD 0 /* does not have fchmod(2) syscall */
-# define HASSETREUID 1 /* use setreuid(2) -lbsd system call */
-# define HASSETVBUF 1 /* use setvbuf(2) system call */
-# define HASSETRLIMIT 0 /* does not have setrlimit call */
-# define HASFLOCK 0 /* does not have flock call - use fcntl */
-# define HASULIMIT 1 /* use ulimit instead of setrlimit call */
-# define NEEDGETOPT 1 /* Do we need theirs or ours */
-# define SYS5SETPGRP 1 /* don't have setpgid on AIX/RT */
-# define IP_SRCROUTE 0 /* Something is broken with getsockopt() */
-# define BSD4_3 1 /* NOT bsd 4.4 or posix signals */
-# define GIDSET_T int
-# define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */
-# define SPT_PADCHAR '\0' /* pad process title with nulls */
-# define LA_TYPE LA_SUBR /* use our ported loadavgd daemon */
-# define TZ_TYPE TZ_TZNAME /* use tzname[] vector */
-# define ARBPTR_T int *
-# define void int
-typedef int pid_t;
-/* RTisms for BSD compatibility, specified in the Makefile
- define BSD 1
- define BSD_INCLUDES 1
- define BSD_REMAP_SIGNAL_TO_SIGVEC
- RTisms needed above */
-/* make this sendmail in a completely different place */
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/local/newmail/sendmail.cf"
-# endif
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/usr/local/newmail/sendmail.pid"
-# endif
-#endif
-
-
-/*
-** Silicon Graphics IRIX
-**
-** Compiles on 4.0.1.
-**
-** Use IRIX64 instead of IRIX for 64-bit IRIX (6.0).
-** Use IRIX5 instead of IRIX for IRIX 5.x.
-**
-** This version tries to be adaptive using _MIPS_SIM:
-** _MIPS_SIM == _ABIO32 (= 1) Abi: -32 on IRIX 6.2
-** _MIPS_SIM == _ABIN32 (= 2) Abi: -n32 on IRIX 6.2
-** _MIPS_SIM == _ABI64 (= 3) Abi: -64 on IRIX 6.2
-**
-** _MIPS_SIM is 1 also on IRIX 5.3
-**
-** IRIX64 changes from Mark R. Levinson <ml@cvdev.rochester.edu>.
-** IRIX5 changes from Kari E. Hurtta <Kari.Hurtta@fmi.fi>.
-** Adaptive changes from Kari E. Hurtta <Kari.Hurtta@fmi.fi>.
-*/
-
-#if defined(__sgi)
-# ifndef IRIX
-# define IRIX
-# endif
-# if _MIPS_SIM > 0 && !defined(IRIX5)
-# define IRIX5 /* IRIX5 or IRIX6 */
-# endif
-# if _MIPS_SIM > 1 && !defined(IRIX6) && !defined(IRIX64)
-# define IRIX6 /* IRIX6 */
-# endif
-
-#endif
-
-#ifdef IRIX
-# define SYSTEM5 1 /* this is a System-V derived system */
-# define HASSETREUID 1 /* has setreuid(2) call */
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define HASFCHMOD 1 /* has fchmod(2) syscall */
-# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
-# define IP_SRCROUTE 1 /* can check IP source routing */
-# define setpgid BSDsetpgrp
-# define GIDSET_T gid_t
-# define SFS_TYPE SFS_4ARGS /* four argument statfs() call */
-# define SFS_BAVAIL f_bfree /* alternate field name */
-# define SYSLOG_BUFSIZE 512
-# ifdef IRIX6
-# define STAT64 1
-# define QUAD_T unsigned long long
-# define LA_TYPE LA_IRIX6 /* figure out at run time */
-# define SAFENFSPATHCONF 0 /* pathconf(2) lies on NFS filesystems */
-# else
-# define LA_TYPE LA_INT
-
-# ifdef IRIX64
-# define STAT64 1
-# define QUAD_T unsigned long long
-# define NAMELISTMASK 0x7fffffffffffffff /* mask for nlist() values */
-# else
-# define STAT64 0
-# define NAMELISTMASK 0x7fffffff /* mask for nlist() values */
-# endif
-# endif
-# if defined(IRIX64) || defined(IRIX5) || defined(IRIX6)
-# include <sys/cdefs.h>
-# include <paths.h>
-# define ARGV_T char *const *
-# define HASSETRLIMIT 1 /* has setrlimit(2) syscall */
-# define HASGETDTABLESIZE 1 /* has getdtablesize(2) syscall */
-# define HASSTRERROR 1 /* has strerror(3) */
-# else
-# define ARGV_T const char **
-# define WAITUNION 1 /* use "union wait" as wait argument type */
-# endif
-#endif
-
-
-/*
-** SunOS and Solaris
-**
-** Tested on SunOS 4.1.x (a.k.a. Solaris 1.1.x) and
-** Solaris 2.4 (a.k.a. SunOS 5.4).
-*/
-
-#if defined(sun) && !defined(BSD)
-
-# include <sys/time.h>
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define HASUNAME 1 /* use System V uname(2) system call */
-# define HASFCHMOD 1 /* has fchmod(2) syscall */
-# define IP_SRCROUTE 1 /* can check IP source routing */
-# define SAFENFSPATHCONF 1 /* pathconf(2) pessimizes on NFS filesystems */
-
-# ifdef SOLARIS_2_3
-# define SOLARIS 20300 /* for back compat only -- use -DSOLARIS=20300 */
-# endif
-
-# if defined(NOT_SENDMAIL) && !defined(SOLARIS) && defined(sun) && (defined(__svr4__) || defined(__SVR4))
-# define SOLARIS 1 /* unknown Solaris version */
-# endif
-
-# ifdef SOLARIS
- /* Solaris 2.x (a.k.a. SunOS 5.x) */
-# ifndef __svr4__
-# define __svr4__ /* use all System V Releae 4 defines below */
-# endif
-# define GIDSET_T gid_t
-# define USE_SA_SIGACTION 1 /* use sa_sigaction field */
-# ifndef _PATH_UNIX
-# define _PATH_UNIX "/dev/ksyms"
-# endif
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/etc/mail/sendmail.cf"
-# endif
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/etc/mail/sendmail.pid"
-# endif
-# ifndef _PATH_HOSTS
-# define _PATH_HOSTS "/etc/inet/hosts"
-# endif
-# ifndef SYSLOG_BUFSIZE
-# define SYSLOG_BUFSIZE 1024 /* allow full size syslog buffer */
-# endif
-# ifndef TZ_TYPE
-# define TZ_TYPE TZ_TZNAME
-# endif
-# if SOLARIS >= 20300 || (SOLARIS < 10000 && SOLARIS >= 203)
-# define USESETEUID 1 /* seteuid works as of 2.3 */
-# endif
-# if SOLARIS >= 20500 || (SOLARIS < 10000 && SOLARIS >= 205)
-# define HASSETREUID 1 /* setreuid works as of 2.5 */
-# if SOLARIS < 207 || (SOLARIS > 10000 && SOLARIS < 20700)
-# ifndef LA_TYPE
-# define LA_TYPE LA_KSTAT /* use kstat(3k) -- may work in < 2.5 */
-# endif
-# endif
-# endif
-# if SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206)
-# define HASSNPRINTF 1 /* has snprintf starting in 2.6 */
-# endif
-# if SOLARIS >= 20700 || (SOLARIS < 10000 && SOLARIS >= 207)
-# ifndef LA_TYPE
-# define LA_TYPE LA_SUBR /* getloadavg(3c) appears in 2.7 */
-# endif
-# define HASGETUSERSHELL 1 /* getusershell(3c) bug fixed in 2.7 */
-# endif
-# ifndef HASGETUSERSHELL
-# define HASGETUSERSHELL 0 /* getusershell(3) causes core dumps pre-2.7 */
-# endif
-
-# else
- /* SunOS 4.0.3 or 4.1.x */
-# define HASGETUSERSHELL 1 /* DOES have getusershell(3) call in libc */
-# define HASSETREUID 1 /* has setreuid(2) call */
-# ifndef HASFLOCK
-# define HASFLOCK 1 /* has flock(2) call */
-# endif
-# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
-# define TZ_TYPE TZ_TM_ZONE /* use tm->tm_zone */
-# include <memory.h>
-# include <vfork.h>
-# ifdef __GNUC__
-# define strtoul strtol /* gcc library bogosity */
-# endif
-
-# ifdef SUNOS403
- /* special tweaking for SunOS 4.0.3 */
-# include <malloc.h>
-# define BSD4_3 1 /* 4.3 BSD-based */
-# define NEEDSTRSTR 1 /* need emulation of strstr(3) routine */
-# define WAITUNION 1 /* use "union wait" as wait argument type */
-# undef WIFEXITED
-# undef WEXITSTATUS
-# undef HASUNAME
-# define setpgid setpgrp
-# define MODE_T int
-typedef int pid_t;
-extern char *getenv();
-
-# else
- /* 4.1.x specifics */
-# define HASSETSID 1 /* has Posix setsid(2) call */
-# define HASSETVBUF 1 /* we have setvbuf(3) in libc */
-
-# endif
-# endif
-
-# ifndef LA_TYPE
-# define LA_TYPE LA_INT
-# endif
-
-#endif /* sun && !BSD */
-
-/*
-** DG/UX
-**
-** Tested on 5.4.2 and 5.4.3. Use DGUX_5_4_2 to get the
-** older support.
-** 5.4.3 changes from Mark T. Robinson <mtr@ornl.gov>.
-*/
-
-#ifdef DGUX_5_4_2
-# define DGUX 1
-#endif
-
-#ifdef DGUX
-# define SYSTEM5 1
-# define LA_TYPE LA_DGUX
-# define HASSETREUID 1 /* has setreuid(2) call */
-# define HASUNAME 1 /* use System V uname(2) system call */
-# define HASSETSID 1 /* has Posix setsid(2) call */
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define IP_SRCROUTE 0 /* does not have <netinet/ip_var.h> */
-# define HASGETUSERSHELL 0 /* does not have getusershell(3) */
-# define HASSNPRINTF 1 /* has snprintf(3) */
-# ifndef IDENTPROTO
-# define IDENTPROTO 0 /* TCP/IP implementation is broken */
-# endif
-# define SPT_TYPE SPT_NONE /* don't use setproctitle */
-# define SFS_TYPE SFS_4ARGS /* four argument statfs() call */
-
-/* these include files must be included early on DG/UX */
-# include <netinet/in.h>
-# include <arpa/inet.h>
-
-/* compiler doesn't understand const? */
-# define const
-
-# ifdef DGUX_5_4_2
-# define inet_addr dgux_inet_addr
-extern long dgux_inet_addr();
-# endif
-#endif
-
-
-/*
-** Digital Ultrix 4.2A or 4.3
-**
-** Apparently, fcntl locking is broken on 4.2A, in that locks are
-** not dropped when the process exits. This causes major problems,
-** so flock is the only alternative.
-*/
-
-#ifdef ultrix
-# define HASSETREUID 1 /* has setreuid(2) call */
-# define HASUNSETENV 1 /* has unsetenv(3) call */
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define HASUNAME 1 /* use System V uname(2) system call */
-# define HASFCHMOD 1 /* has fchmod(2) syscall */
-# ifndef HASFLOCK
-# define HASFLOCK 1 /* has flock(2) call */
-# endif
-# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
-# ifndef BROKEN_RES_SEARCH
-# define BROKEN_RES_SEARCH 1 /* res_search(unknown) returns h_errno=0 */
-# endif
-# ifdef vax
-# define LA_TYPE LA_FLOAT
-# else
-# define LA_TYPE LA_INT
-# define LA_AVENRUN "avenrun"
-# endif
-# define SFS_TYPE SFS_MOUNT /* use <sys/mount.h> statfs() impl */
-# ifndef IDENTPROTO
-# define IDENTPROTO 0 /* pre-4.4 TCP/IP implementation is broken */
-# endif
-# define SYSLOG_BUFSIZE 256
-#endif
-
-
-/*
-** OSF/1 for KSR.
-**
-** Contributed by Todd C. Miller <Todd.Miller@cs.colorado.edu>
-*/
-
-#ifdef __ksr__
-# define __osf__ 1 /* get OSF/1 defines below */
-# ifndef TZ_TYPE
-# define TZ_TYPE TZ_TZNAME /* use tzname[] vector */
-# endif
-#endif
-
-
-/*
-** OSF/1 for Intel Paragon.
-**
-** Contributed by Jeff A. Earickson <jeff@ssd.intel.com>
-** of Intel Scalable Systems Divison.
-*/
-
-#ifdef __PARAGON__
-# define __osf__ 1 /* get OSF/1 defines below */
-# ifndef TZ_TYPE
-# define TZ_TYPE TZ_TZNAME /* use tzname[] vector */
-# endif
-# define GIDSET_T gid_t
-# define MAXNAMLEN NAME_MAX
-#endif
-
-
-/*
-** OSF/1 (tested on Alpha) -- now known as Digital UNIX.
-**
-** Tested for 3.2 and 4.0.
-*/
-
-#ifdef __osf__
-# define HASUNSETENV 1 /* has unsetenv(3) call */
-# define USESETEUID 1 /* has useable seteuid(2) call */
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define HASFCHMOD 1 /* has fchmod(2) syscall */
-# define IP_SRCROUTE 1 /* can check IP source routing */
-# define HAS_ST_GEN 1 /* has st_gen field in stat struct */
-# ifndef HASFLOCK
-# define HASFLOCK 1 /* has flock(2) call */
-# endif
-# define LA_TYPE LA_ALPHAOSF
-# define SFS_TYPE SFS_STATVFS /* use <sys/statvfs.h> statfs() impl */
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/var/adm/sendmail/sendmail.cf"
-# endif
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/var/run/sendmail.pid"
-# endif
-# define bcopy(s, d, l) (memmove((d), (s), (l)))
-# define bzero(d, l) (memset((d), '\0', (l)))
-# define bcmp(s, d, l) (memcmp((s), (d), (l)))
-#endif
-
-
-/*
-** NeXTstep
-*/
-
-#ifdef NeXT
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define NEEDPUTENV 2 /* need putenv(3) call; no setenv(3) call */
-# ifndef HASFLOCK
-# define HASFLOCK 1 /* has flock(2) call */
-# endif
-# define NEEDGETOPT 1 /* need a replacement for getopt(3) */
-# define WAITUNION 1 /* use "union wait" as wait argument type */
-# define UID_T int /* compiler gripes on uid_t */
-# define GID_T int /* ditto for gid_t */
-# define MODE_T int /* and mode_t */
-# define setpgid setpgrp
-# ifndef NOT_SENDMAIL
-# define sleep sleepX
-# endif
-# ifndef LA_TYPE
-# define LA_TYPE LA_MACH
-# endif
-# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
-# ifndef _POSIX_SOURCE
-typedef int pid_t;
-# undef WEXITSTATUS
-# undef WIFEXITED
-# endif
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/etc/sendmail/sendmail.cf"
-# endif
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/etc/sendmail/sendmail.pid"
-# endif
-
-# ifdef TCPWRAPPERS
-# ifndef HASUNSETENV
-# define HASUNSETENV 1
-# endif
-# undef NEEDPUTENV
-# endif
-
-#endif
-
-/*
-** Apple Rhapsody
-** Contributed by Wilfredo Sanchez <wsanchez@apple.com>
-*/
-
-#ifdef __APPLE__
-# define HASFCHMOD 1 /* has fchmod(2) syscall */
-# define HASFLOCK 1 /* has flock(2) syscall */
-# define HASUNAME 1 /* has uname(2) syscall */
-# define HASUNSETENV 1
-# define HASSETSID 1 /* has the setsid(2) POSIX syscall */
-# define HASINITGROUPS 1
-# define HASSETVBUF 1
-# define HASSETREUID 1
-# define USESETEUID 1 /* has useable seteuid(2) call */
-# define HASLSTAT 1
-# define HASSETRLIMIT 1
-# define HASWAITPID 1
-# define HASSTRERROR 1 /* has strerror(3) */
-# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */
-# define USESTRERROR 1 /* has strerror(3) */
-# define HASGETDTABLESIZE 1
-# define HASGETUSERSHELL 1
-# define NEEDGETOPT 1 /* need a replacement for getopt(3) */
-# define BSD4_4_SOCKADDR /* has sa_len */
-# define NETLINK 1 /* supports AF_LINK */
-# define HAS_ST_GEN 1 /* has st_gen field in stat struct */
-# define GIDSET_T gid_t
-# define LA_TYPE LA_SUBR /* use getloadavg(3) */
-# define SFS_TYPE SFS_MOUNT /* use <sys/mount.h> statfs() impl */
-# define SPT_TYPE SPT_PSSTRINGS
-# define SPT_PADCHAR '\0' /* pad process title with nulls */
-# define ERRLIST_PREDEFINED /* don't declare sys_errlist */
-#endif
-
-
-/*
-** 4.4 BSD
-**
-** See also BSD defines.
-*/
-
-#if defined(BSD4_4) && !defined(__bsdi__) && !defined(__GNU__)
-# include <paths.h>
-# define HASUNSETENV 1 /* has unsetenv(3) call */
-# define USESETEUID 1 /* has useable seteuid(2) call */
-# define HASFCHMOD 1 /* has fchmod(2) syscall */
-# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */
-# define HASSTRERROR 1 /* has strerror(3) */
-# define HAS_ST_GEN 1 /* has st_gen field in stat struct */
-# include <sys/cdefs.h>
-# define ERRLIST_PREDEFINED /* don't declare sys_errlist */
-# define BSD4_4_SOCKADDR /* has sa_len */
-# define NEED_PRINTF_PERCENTQ 1 /* doesn't have %lld */
-# define NETLINK 1 /* supports AF_LINK */
-# ifndef LA_TYPE
-# define LA_TYPE LA_SUBR
-# endif
-# define SFS_TYPE SFS_MOUNT /* use <sys/mount.h> statfs() impl */
-# define SPT_TYPE SPT_PSSTRINGS /* use PS_STRINGS pointer */
-#endif
-
-
-/*
-** BSD/OS (was BSD/386) (all versions)
-** From Tony Sanders, BSDI
-*/
-
-#ifdef __bsdi__
-# include <paths.h>
-# define HASUNSETENV 1 /* has the unsetenv(3) call */
-# define HASSETSID 1 /* has the setsid(2) POSIX syscall */
-# define USESETEUID 1 /* has useable seteuid(2) call */
-# define HASFCHMOD 1 /* has fchmod(2) syscall */
-# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */
-# define HASUNAME 1 /* has uname(2) syscall */
-# define HASSTRERROR 1 /* has strerror(3) */
-# define HAS_ST_GEN 1 /* has st_gen field in stat struct */
-# include <sys/cdefs.h>
-# define ERRLIST_PREDEFINED /* don't declare sys_errlist */
-# define BSD4_4_SOCKADDR /* has sa_len */
-# define NETLINK 1 /* supports AF_LINK */
-# define SFS_TYPE SFS_MOUNT /* use <sys/mount.h> statfs() impl */
-# ifndef LA_TYPE
-# define LA_TYPE LA_SUBR
-# endif
-# define GIDSET_T gid_t
-# define QUAD_T quad_t
-# if defined(_BSDI_VERSION) && _BSDI_VERSION >= 199312
- /* version 1.1 or later */
-# undef SPT_TYPE
-# define SPT_TYPE SPT_BUILTIN /* setproctitle is in libc */
-# else
- /* version 1.0 or earlier */
-# define SPT_PADCHAR '\0' /* pad process title with nulls */
-# endif
-# if defined(_BSDI_VERSION) && _BSDI_VERSION >= 199701 /* on 3.x */
-# define HASSETUSERCONTEXT 1 /* has setusercontext */
-# endif
-#endif
-
-
-/*
-** QNX 4.2x
-** Contributed by Glen McCready <glen@qnx.com>.
-**
-** Should work with all versions of QNX.
-*/
-
-#if defined(__QNX__)
-# include <unix.h>
-# include <sys/select.h>
-# undef NGROUPS_MAX
-# define HASSETSID 1 /* has the setsid(2) POSIX syscall */
-# define USESETEUID 1 /* has useable seteuid(2) call */
-# define HASFCHMOD 1 /* has fchmod(2) syscall */
-# define HASGETDTABLESIZE 1 /* has getdtablesize(2) call */
-# define HASSETREUID 1 /* has setreuid(2) call */
-# define HASSTRERROR 1 /* has strerror(3) */
-# define HASFLOCK 0
-# undef HASINITGROUPS /* has initgroups(3) call */
-# define NEEDGETOPT 1 /* use sendmail's getopt */
-# define IP_SRCROUTE 1 /* can check IP source routing */
-# define TZ_TYPE TZ_TMNAME /* use tmname variable */
-# define GIDSET_T gid_t
-# define LA_TYPE LA_ZERO
-# define SFS_TYPE SFS_NONE
-# define SPT_TYPE SPT_REUSEARGV
-# define SPT_PADCHAR '\0' /* pad process title with nulls */
-# define HASGETUSERSHELL 0
-# define E_PSEUDOBASE 512
-# define bcopy(s, d, l) (memmove((d), (s), (l)))
-# define bzero(d, l) (memset((d), '\0', (l)))
-# define bcmp(s, d, l) (memcmp((s), (d), (l)))
-# define _FILE_H_INCLUDED
-#endif
-
-
-/*
-** FreeBSD / NetBSD / OpenBSD (all architectures, all versions)
-**
-** 4.3BSD clone, closer to 4.4BSD for FreeBSD 1.x and NetBSD 0.9x
-** 4.4BSD-Lite based for FreeBSD 2.x and NetBSD 1.x
-**
-** See also BSD defines.
-*/
-
-#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
-# include <paths.h>
-# define HASUNSETENV 1 /* has unsetenv(3) call */
-# define HASSETSID 1 /* has the setsid(2) POSIX syscall */
-# define USESETEUID 1 /* has useable seteuid(2) call */
-# define HASFCHMOD 1 /* has fchmod(2) syscall */
-# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */
-# define HASUNAME 1 /* has uname(2) syscall */
-# define HASSTRERROR 1 /* has strerror(3) */
-# define HAS_ST_GEN 1 /* has st_gen field in stat struct */
-# define NEED_PRINTF_PERCENTQ 1 /* doesn't have %lld */
-# include <sys/cdefs.h>
-# define ERRLIST_PREDEFINED /* don't declare sys_errlist */
-# define BSD4_4_SOCKADDR /* has sa_len */
-# define NETLINK 1 /* supports AF_LINK */
-# define SAFENFSPATHCONF 1 /* pathconf(2) pessimizes on NFS filesystems */
-# define GIDSET_T gid_t
-# define QUAD_T unsigned long long
-# ifndef LA_TYPE
-# define LA_TYPE LA_SUBR
-# endif
-# define SFS_TYPE SFS_MOUNT /* use <sys/mount.h> statfs() impl */
-# if defined(__NetBSD__) && (NetBSD > 199307 || NetBSD0_9 > 1)
-# undef SPT_TYPE
-# define SPT_TYPE SPT_BUILTIN /* setproctitle is in libc */
-# endif
-# if defined(__FreeBSD__)
-# undef SPT_TYPE
-# if __FreeBSD__ >= 2
-# include <osreldate.h>
-# if __FreeBSD_version >= 199512 /* 2.2-current when it appeared */
-# include <libutil.h>
-# define SPT_TYPE SPT_BUILTIN
-# endif
-# if __FreeBSD_version >= 222000 /* 2.2.2-release and later */
-# define HASSETUSERCONTEXT 1 /* BSDI-style login classes */
-# endif
-# endif
-# ifndef SPT_TYPE
-# define SPT_TYPE SPT_REUSEARGV
-# define SPT_PADCHAR '\0' /* pad process title with nulls */
-# endif
-# endif
-# if defined(__OpenBSD__)
-# undef SPT_TYPE
-# define SPT_TYPE SPT_BUILTIN /* setproctitle is in libc */
-# endif
-#endif
-
-
-
-/*
-** Mach386
-**
-** For mt Xinu's Mach386 system.
-*/
-
-#if defined(MACH) && defined(i386) && !defined(__GNU__)
-# define MACH386 1
-# define HASUNSETENV 1 /* has unsetenv(3) call */
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# ifndef HASFLOCK
-# define HASFLOCK 1 /* has flock(2) call */
-# endif
-# define NEEDGETOPT 1 /* need a replacement for getopt(3) */
-# define NEEDSTRTOL 1 /* need the strtol() function */
-# define setpgid setpgrp
-# ifndef LA_TYPE
-# define LA_TYPE LA_FLOAT
-# endif
-# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
-# undef HASSETVBUF /* don't actually have setvbuf(3) */
-# undef WEXITSTATUS
-# undef WIFEXITED
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
-# endif
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/etc/sendmail.pid"
-# endif
-#endif
-
-
-
-/*
-** GNU OS (hurd)
-** Largely BSD & posix compatible.
-** Port contributed by Miles Bader <miles@gnu.ai.mit.edu>.
-*/
-
-#ifdef __GNU_HURD__
-# define SIOCGIFCONF_IS_BROKEN 1
-# define IP_SRCROUTE 0
-# define HASFCHMOD 1
-# define HASFLOCK 1
-# define HASUNAME 1
-# define HASUNSETENV 1
-# define HASSETSID 1
-# define HASINITGROUPS 1
-# define HASSETVBUF 1
-# define HASSETREUID 1
-# define USESETEUID 1
-# define HASLSTAT 1
-# define HASSETRLIMIT 1
-# define HASWAITPID 1
-# define HASGETDTABLESIZE 1
-# define HASSTRERROR 1
-/* # define NEEDGETOPT 1 */
-# define HASGETUSERSHELL 1
-# define ERRLIST_PREDEFINED 1
-# define BSD4_4_SOCKADDR 1
-# define GIDSET_T gid_t
-# define LA_TYPE LA_MACH
-
-/* GNU uses mach[34], which renames some rpcs from mach2.x. */
-# define host_self mach_host_self
-# define SFS_TYPE SFS_STATFS
-# define SPT_TYPE SPT_CHANGEARGV
-
-/* GNU has no MAXPATHLEN; ideally the code should be changed to not use it. */
-# define MAXPATHLEN 2048
-
-/* Define device num frobbing macros. */
-# define major(x) ((x)>>8)
-# define minor(x) ((x)&0xFF)
-#endif /* GNU */
-
-/*
-** 4.3 BSD -- this is for very old systems
-**
-** Should work for mt Xinu MORE/BSD and Mips UMIPS-BSD 2.1.
-**
-** You'll also have to install a new resolver library.
-** I don't guarantee that support for this environment is complete.
-*/
-
-#if defined(oldBSD43) || defined(MORE_BSD) || defined(umipsbsd)
-# define NEEDVPRINTF 1 /* need a replacement for vprintf(3) */
-# define NEEDGETOPT 1 /* need a replacement for getopt(3) */
-# define ARBPTR_T char *
-# define setpgid setpgrp
-# ifndef LA_TYPE
-# define LA_TYPE LA_FLOAT
-# endif
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
-# endif
-# ifndef IDENTPROTO
-# define IDENTPROTO 0 /* TCP/IP implementation is broken */
-# endif
-# undef WEXITSTATUS
-# undef WIFEXITED
-typedef short pid_t;
-extern int errno;
-#endif
-
-
-/*
-** SCO Unix
-**
-** This includes three parts:
-**
-** The first is for SCO OpenServer 5.
-** (Contributed by Keith Reynolds <keithr@sco.COM>).
-**
-** SCO OpenServer 5 has a compiler version number macro,
-** which we can use to figure out what version we're on.
-** This may have to change in future releases.
-**
-** The second is for SCO UNIX 3.2v4.2/Open Desktop 3.0.
-** (Contributed by Philippe Brand <phb@colombo.telesys-innov.fr>).
-**
-** The third is for SCO UNIX 3.2v4.0/Open Desktop 2.0 and earlier.
-*/
-
-/* SCO OpenServer 5 */
-#if _SCO_DS >= 1
-# include <paths.h>
-# define SIOCGIFNUM_IS_BROKEN 1 /* SIOCGIFNUM returns bogus value */
-# define HASSNPRINTF 1 /* has snprintf(3) call */
-# define HASFCHMOD 1 /* has fchmod(2) call */
-# define HASSETRLIMIT 1 /* has setrlimit(2) call */
-# define USESETEUID 1 /* has seteuid(2) call */
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define HASGETDTABLESIZE 1 /* has getdtablesize(2) call */
-# define RLIMIT_NEEDS_SYS_TIME_H 1
-# ifndef LA_TYPE
-# define LA_TYPE LA_DEVSHORT
-# endif
-# define _PATH_AVENRUN "/dev/table/avenrun"
-# ifndef _SCO_unix_4_2
-# define _SCO_unix_4_2
-# else
-# define SOCKADDR_LEN_T size_t /* e.g., arg#3 to accept, getsockname */
-# define SOCKOPT_LEN_T size_t /* arg#5 to getsockopt */
-# endif
-#endif
-
-/* SCO UNIX 3.2v4.2/Open Desktop 3.0 */
-#ifdef _SCO_unix_4_2
-# define _SCO_unix_
-# define HASSETREUID 1 /* has setreuid(2) call */
-#endif
-
-/* SCO UNIX 3.2v4.0 Open Desktop 2.0 and earlier */
-#ifdef _SCO_unix_
-# include <sys/stream.h> /* needed for IP_SRCROUTE */
-# define SYSTEM5 1 /* include all the System V defines */
-# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
-# define NOFTRUNCATE 0 /* has (simulated) ftruncate call */
-# define USE_SIGLONGJMP 1 /* sigsetjmp needed for signal handling */
-# define MAXPATHLEN PATHSIZE
-# define SFS_TYPE SFS_4ARGS /* use <sys/statfs.h> 4-arg impl */
-# define SFS_BAVAIL f_bfree /* alternate field name */
-# define SPT_TYPE SPT_SCO /* write kernel u. area */
-# define TZ_TYPE TZ_TM_NAME /* use tm->tm_name */
-# define UID_T uid_t
-# define GID_T gid_t
-# define GIDSET_T gid_t
-# define _PATH_UNIX "/unix"
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
-# endif
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/etc/sendmail.pid"
-# endif
-
-/* stuff fixed in later releases */
-# ifndef _SCO_unix_4_2
-# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
-# endif
-
-# ifndef _SCO_DS
-# define ftruncate chsize /* use chsize(2) to emulate ftruncate */
-# define NEEDFSYNC 1 /* needs the fsync(2) call stub */
-# define NETUNIX 0 /* no unix domain socket support */
-# define LA_TYPE LA_SHORT
-# endif
-
-#endif
-
-
-/*
-** ISC (SunSoft) Unix.
-**
-** Contributed by J.J. Bailey <jjb@jagware.bcc.com>
-*/
-
-#ifdef ISC_UNIX
-# include <net/errno.h>
-# include <sys/stream.h> /* needed for IP_SRCROUTE */
-# include <sys/bsdtypes.h>
-# define SYSTEM5 1 /* include all the System V defines */
-# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
-# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
-# define HASSETREUID 1 /* has setreuid(2) call */
-# define NEEDFSYNC 1 /* needs the fsync(2) call stub */
-# define NETUNIX 0 /* no unix domain socket support */
-# define MAXPATHLEN 1024
-# define LA_TYPE LA_SHORT
-# define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */
-# define SFS_BAVAIL f_bfree /* alternate field name */
-# define _PATH_UNIX "/unix"
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
-# endif
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/etc/sendmail.pid"
-# endif
-
-#endif
-
-
-/*
-** Altos System V (5.3.1)
-** Contributed by Tim Rice <tim@trr.metro.net>.
-*/
-
-#ifdef ALTOS_SYSTEM_V
-# include <sys/stream.h>
-# include <limits.h>
-# define SYSTEM5 1 /* include all the System V defines */
-# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
-# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
-# define WAITUNION 1 /* use "union wait" as wait argument type */
-# define NEEDFSYNC 1 /* no fsync(2) in system library */
-# define NEEDSTRSTR 1 /* need emulation of the strstr(3) call */
-# define NOFTRUNCATE 1 /* do not have ftruncate(2) */
-# define MAXPATHLEN PATH_MAX
-# define LA_TYPE LA_SHORT
-# define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */
-# define SFS_BAVAIL f_bfree /* alternate field name */
-# define TZ_TYPE TZ_TZNAME /* use tzname[] vector */
-# define NETUNIX 0 /* no unix domain socket support */
-# undef WIFEXITED
-# undef WEXITSTATUS
-# define strtoul strtol /* gcc library bogosity */
-
-typedef unsigned short uid_t;
-typedef unsigned short gid_t;
-typedef short pid_t;
-typedef unsigned long mode_t;
-
-/* some stuff that should have been in the include files */
-# include <grp.h>
-extern char *malloc();
-extern struct passwd *getpwent();
-extern struct passwd *getpwnam();
-extern struct passwd *getpwuid();
-extern char *getenv();
-extern struct group *getgrgid();
-extern struct group *getgrnam();
-
-#endif
-
-
-/*
-** ConvexOS 11.0 and later
-**
-** "Todd C. Miller" <millert@mroe.cs.colorado.edu> claims this
-** works on 9.1 as well.
-**
-** ConvexOS 11.5 and later, should work on 11.0 as defined.
-** For pre-ConvexOOS 11.0, define NEEDGETOPT, undef IDENTPROTO
-**
-** Eric Schnoebelen (eric@cirr.com) For CONVEX Computer Corp.
-** (now the CONVEX Technologies Center of Hewlett Packard)
-*/
-
-#ifdef _CONVEX_SOURCE
-# define HASGETDTABLESIZE 1 /* has getdtablesize(2) */
-# define HASINITGROUPS 1 /* has initgroups(3) */
-# define HASUNAME 1 /* use System V uname(2) system call */
-# define HASSETSID 1 /* has POSIX setsid(2) call */
-# define HASUNSETENV 1 /* has unsetenv(3) */
-# define HASFLOCK 1 /* has flock(2) */
-# define HASSETRLIMIT 1 /* has setrlimit(2) */
-# define HASSETREUID 1 /* has setreuid(2) */
-# define BROKEN_RES_SEARCH 1 /* res_search(unknown) returns h_error=0 */
-# define NEEDPUTENV 1 /* needs putenv (written in terms of setenv) */
-# define NEEDGETOPT 0 /* need replacement for getopt(3) */
-# define IP_SRCROUTE 0 /* Something is broken with getsockopt() */
-# define LA_TYPE LA_FLOAT
-# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
-# endif
-# ifndef S_IREAD
-# define S_IREAD _S_IREAD
-# define S_IWRITE _S_IWRITE
-# define S_IEXEC _S_IEXEC
-# define S_IFMT _S_IFMT
-# define S_IFCHR _S_IFCHR
-# define S_IFBLK _S_IFBLK
-# endif
-# ifndef TZ_TYPE
-# define TZ_TYPE TZ_TIMEZONE
-# endif
-# ifndef IDENTPROTO
-# define IDENTPROTO 1
-# endif
-# ifndef SHARE_V1
-# define SHARE_V1 1 /* version 1 of the fair share scheduler */
-# endif
-# if !defined(__GNUC__ )
-# define UID_T int /* GNUC gets it right, ConvexC botches */
-# define GID_T int /* GNUC gets it right, ConvexC botches */
-# endif
-# if SECUREWARE
-# define FORK fork /* SecureWare wants the real fork! */
-# else
-# define FORK vfork /* the rest of the OS versions don't care */
-# endif
-#endif
-
-
-/*
-** RISC/os 4.52
-**
-** Gives a ton of warning messages, but otherwise compiles.
-*/
-
-#ifdef RISCOS
-
-# define HASUNSETENV 1 /* has unsetenv(3) call */
-# ifndef HASFLOCK
-# define HASFLOCK 1 /* has flock(2) call */
-# endif
-# define WAITUNION 1 /* use "union wait" as wait argument type */
-# define NEEDGETOPT 1 /* need a replacement for getopt(3) */
-# define NEEDPUTENV 1 /* need putenv(3) call */
-# define NEEDSTRSTR 1 /* need emulation of the strstr(3) call */
-# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
-# define LA_TYPE LA_INT
-# define LA_AVENRUN "avenrun"
-# define _PATH_UNIX "/unix"
-# undef WIFEXITED
-
-# define setpgid setpgrp
-
-extern int errno;
-typedef int pid_t;
-# define SIGFUNC_DEFINED
-# define SIGFUNC_RETURN (0)
-# define SIGFUNC_DECL int
-typedef int (*sigfunc_t)();
-extern char *getenv();
-extern void *malloc();
-
-/* added for RISC/os 4.01...which is dumber than 4.50 */
-# ifdef RISCOS_4_0
-# ifndef ARBPTR_T
-# define ARBPTR_T char *
-# endif
-# undef HASFLOCK
-# define HASFLOCK 0
-# endif /* RISCOS_4_0 */
-
-# include <sys/time.h>
-
-#endif
-
-
-/*
-** Linux 0.99pl10 and above...
-**
-** Thanks to, in reverse order of contact:
-**
-** John Kennedy <warlock@csuchico.edu>
-** Andrew Pam <avatar@aus.xanadu.com>
-** Florian La Roche <rzsfl@rz.uni-sb.de>
-** Karl London <karl@borg.demon.co.uk>
-**
-** Last compiled against: [07/21/98 @ 11:47:34 AM (Tuesday)]
-** sendmail 8.9.1 bind-8.1.2 db-2.4.14
-** gcc-2.8.1 glibc-2.0.94 linux-2.1.109
-**
-** NOTE: Override HASFLOCK as you will but, as of 1.99.6, mixed-style
-** file locking is no longer allowed. In particular, make sure
-** your DBM library and sendmail are both using either flock(2)
-** *or* fcntl(2) file locking, but not both.
-*/
-
-#ifdef __linux__
-# define BSD 1 /* include BSD defines */
-# define USESETEUID 0 /* Have it due to POSIX, but doesn't work */
-# define NEEDGETOPT 1 /* need a replacement for getopt(3) */
-# define HASUNAME 1 /* use System V uname(2) system call */
-# define HASUNSETENV 1 /* has unsetenv(3) call */
-# ifndef HASSNPRINTF
-# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */
-# endif
-# define ERRLIST_PREDEFINED /* don't declare sys_errlist */
-# define GIDSET_T gid_t /* from <linux/types.h> */
-# define HASGETUSERSHELL 0 /* getusershell(3) broken in Slackware 2.0 */
-# define IP_SRCROUTE 0 /* linux <= 1.2.8 doesn't support IP_OPTIONS */
-# define USE_SIGLONGJMP 1 /* sigsetjmp needed for signal handling */
-# ifndef HASFLOCK
-# include <linux/version.h>
-# if LINUX_VERSION_CODE < 66399
-# define HASFLOCK 0 /* flock(2) is broken after 0.99.13 */
-# else
-# define HASFLOCK 1 /* flock(2) fixed after 1.3.95 */
-# endif
-# endif
-# ifndef LA_TYPE
-# define LA_TYPE LA_PROCSTR
-# endif
-# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() impl */
-# define SPT_PADCHAR '\0' /* pad process title with nulls */
-# ifndef TZ_TYPE
-# define TZ_TYPE TZ_NONE /* no standard for Linux */
-# endif
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/var/run/sendmail.pid"
-# endif
-# include <sys/sysmacros.h>
-# undef atol /* wounded in <stdlib.h> */
-#endif
-
-
-/*
-** DELL SVR4 Issue 2.2, and others
-** From Kimmo Suominen <kim@grendel.lut.fi>
-**
-** It's on #ifdef DELL_SVR4 because Solaris also gets __svr4__
-** defined, and the definitions conflict.
-**
-** Peter Wemm <peter@perth.DIALix.oz.au> claims that the setreuid
-** trick works on DELL 2.2 (SVR4.0/386 version 4.0) and ESIX 4.0.3A
-** (SVR4.0/386 version 3.0).
-*/
-
-#ifdef DELL_SVR4
- /* no changes necessary */
- /* see general __svr4__ defines below */
-#endif
-
-
-/*
-** Apple A/UX 3.0
-*/
-
-#ifdef _AUX_SOURCE
-# include <sys/sysmacros.h>
-# define BSD /* has BSD routines */
-# define HASSETRLIMIT 0 /* ... but not setrlimit(2) */
-# define BROKEN_RES_SEARCH 1 /* res_search(unknown) returns h_errno=0 */
-# define BOGUS_O_EXCL 1 /* exclusive open follows symlinks */
-# define HASUNAME 1 /* use System V uname(2) system call */
-# define HASFCHMOD 1 /* has fchmod(2) syscall */
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define HASSETVBUF 1 /* has setvbuf(3) in libc */
-# define HASSTRERROR 1 /* has strerror(3) */
-# define SIGFUNC_DEFINED /* sigfunc_t already defined */
-# define SIGFUNC_RETURN /* POSIX-mode */
-# define SIGFUNC_DECL void /* POSIX-mode */
-# define ERRLIST_PREDEFINED 1
-# ifndef IDENTPROTO
-# define IDENTPROTO 0 /* TCP/IP implementation is broken */
-# endif
-# ifndef LA_TYPE
-# define LA_TYPE LA_INT
-# define FSHIFT 16
-# endif
-# define LA_AVENRUN "avenrun"
-# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
-# define TZ_TYPE TZ_TZNAME
-# ifndef _PATH_UNIX
-# define _PATH_UNIX "/unix" /* should be in <paths.h> */
-# endif
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
-# endif
-# undef WIFEXITED
-# undef WEXITSTATUS
-#endif
-
-
-/*
-** Encore UMAX V
-**
-** Not extensively tested.
-*/
-
-#ifdef UMAXV
-# define HASUNAME 1 /* use System V uname(2) system call */
-# define HASSETVBUF 1 /* we have setvbuf(3) in libc */
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
-# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
-# define SYS5SETPGRP 1 /* use System V setpgrp(2) syscall */
-# define SFS_TYPE SFS_4ARGS /* four argument statfs() call */
-# define MAXPATHLEN PATH_MAX
-extern struct passwd *getpwent(), *getpwnam(), *getpwuid();
-extern struct group *getgrent(), *getgrnam(), *getgrgid();
-# undef WIFEXITED
-# undef WEXITSTATUS
-#endif
-
-
-/*
-** Stardent Titan 3000 running TitanOS 4.2.
-**
-** Must be compiled in "cc -43" mode.
-**
-** From Kate Hedstrom <kate@ahab.rutgers.edu>.
-**
-** Note the tweaking below after the BSD defines are set.
-*/
-
-#ifdef titan
-# define setpgid setpgrp
-typedef int pid_t;
-# undef WIFEXITED
-# undef WEXITSTATUS
-#endif
-
-
-/*
-** Sequent DYNIX 3.2.0
-**
-** From Jim Davis <jdavis@cs.arizona.edu>.
-*/
-
-#ifdef sequent
-
-# define BSD 1
-# define HASUNSETENV 1
-# define BSD4_3 1 /* to get signal() in conf.c */
-# define WAITUNION 1
-# define LA_TYPE LA_FLOAT
-# ifdef _POSIX_VERSION
-# undef _POSIX_VERSION /* set in <unistd.h> */
-# endif
-# undef HASSETVBUF /* don't actually have setvbuf(3) */
-# define setpgid setpgrp
-
-/* Have to redefine WIFEXITED to take an int, to work with waitfor() */
-# undef WIFEXITED
-# define WIFEXITED(s) (((union wait*)&(s))->w_stopval != WSTOPPED && \
- ((union wait*)&(s))->w_termsig == 0)
-# define WEXITSTATUS(s) (((union wait*)&(s))->w_retcode)
-typedef int pid_t;
-# define isgraph(c) (isprint(c) && (c != ' '))
-
-# ifndef IDENTPROTO
-# define IDENTPROTO 0 /* TCP/IP implementation is broken */
-# endif
-
-# ifndef _PATH_UNIX
-# define _PATH_UNIX "/dynix"
-# endif
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
-# endif
-#endif
-
-
-/*
-** Sequent DYNIX/ptx v2.0 (and higher)
-**
-** For DYNIX/ptx v1.x, undefine HASSETREUID.
-**
-** From Tim Wright <timw@sequent.com>.
-** Update from Jack Woolley <jwoolley@sctcorp.com>, 26 Dec 1995,
-** for DYNIX/ptx 4.0.2.
-*/
-
-#ifdef _SEQUENT_
-# include <sys/stream.h>
-# define SYSTEM5 1 /* include all the System V defines */
-# define HASSETSID 1 /* has POSIX setsid(2) call */
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define HASSETREUID 1 /* has setreuid(2) call */
-# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
-# define GIDSET_T gid_t
-# define LA_TYPE LA_INT
-# define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */
-# define SPT_TYPE SPT_NONE /* don't use setproctitle */
-# ifndef IDENTPROTO
-# define IDENTPROTO 0 /* TCP/IP implementation is broken */
-# endif
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
-# endif
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/etc/sendmail.pid"
-# endif
-#endif
-
-
-/*
-** Cray Unicos
-**
-** Ported by David L. Kensiski, Sterling Sofware <kensiski@nas.nasa.gov>
-*/
-
-#ifdef UNICOS
-# define SYSTEM5 1 /* include all the System V defines */
-# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
-# define MAXPATHLEN PATHSIZE
-# define LA_TYPE LA_ZERO
-# define SFS_TYPE SFS_4ARGS /* four argument statfs() call */
-# define SFS_BAVAIL f_bfree /* alternate field name */
-#endif
-
-
-/*
-** Apollo DomainOS
-**
-** From Todd Martin <tmartint@tus.ssi1.com> & Don Lewis <gdonl@gv.ssi1.com>
-**
-** 15 Jan 1994; updated 2 Aug 1995
-**
-*/
-
-#ifdef apollo
-# define HASSETREUID 1 /* has setreuid(2) call */
-# define HASINITGROUPS 1 /* has initgroups(2) call */
-# define IP_SRCROUTE 0 /* does not have <netinet/ip_var.h> */
-# define SPT_TYPE SPT_NONE /* don't use setproctitle */
-# define LA_TYPE LA_SUBR /* use getloadavg.c */
-# define SFS_TYPE SFS_4ARGS /* four argument statfs() call */
-# define SFS_BAVAIL f_bfree /* alternate field name */
-# define TZ_TYPE TZ_TZNAME
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
-# endif
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/etc/sendmail.pid"
-# endif
-# undef S_IFSOCK /* S_IFSOCK and S_IFIFO are the same */
-# undef S_IFIFO
-# define S_IFIFO 0010000
-# ifndef IDENTPROTO
-# define IDENTPROTO 0 /* TCP/IP implementation is broken */
-# endif
-# define RLIMIT_NEEDS_SYS_TIME_H 1
-# if defined(NGROUPS_MAX) && !NGROUPS_MAX
-# undef NGROUPS_MAX
-# endif
-#endif
-
-/*
-** System V Rel 5.x (a.k.a Unixware7 w/o BSD-Compatiblity Libs ie. native)
-**
-** Contributed by Paul Gampe <paulg@apnic.net>
-*/
-
-#ifdef __svr5__
-# include <sys/mkdev.h>
-# define __svr4__
-# define SYS5SIGNALS 1
-# define HASSETSID 1
-# define HASSETREUID 1
-# define HASWAITPID 1
-# define HASGETDTABLESIZE 1
-# define GIDSET_T gid_t
-# define SOCKADDR_LEN_T size_t
-# define SOCKOPT_LEN_T size_t
-# ifndef _PATH_UNIX
-# define _PATH_UNIX "/stand/unix"
-# endif
-# define SPT_PADCHAR '\0' /* pad process title with nulls */
-# define SYSLOG_BUFSIZE 1024 /* unsure */
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/etc/sendmail.cf"
-# endif
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/etc/sendmail.pid"
-# endif
-#endif
-
-/* ###################################################################### */
-
-/*
-** UnixWare 2.x
-*/
-
-#ifdef UNIXWARE2
-# define UNIXWARE 1
-# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */
-# undef offsetof /* avoid stddefs.h, sys/sysmacros.h conflict */
-#endif
-
-
-/*
-** UnixWare 1.1.2.
-**
-** Updated by Petr Lampa <lampa@fee.vutbr.cz>.
-** From Evan Champion <evanc@spatial.synapse.org>.
-*/
-
-#ifdef UNIXWARE
-# include <sys/mkdev.h>
-# define SYSTEM5 1
-# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
-# define HASSETREUID 1
-# define HASSETSID 1
-# define HASINITGROUPS 1
-# define GIDSET_T gid_t
-# define SLEEP_T unsigned
-# define SFS_TYPE SFS_STATVFS
-# define LA_TYPE LA_ZERO
-# undef WIFEXITED
-# undef WEXITSTATUS
-# ifndef _PATH_UNIX
-# define _PATH_UNIX "/unix"
-# endif
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/ucblib/sendmail.cf"
-# endif
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/usr/ucblib/sendmail.pid"
-# endif
-# define SYSLOG_BUFSIZE 128
-#endif
-
-
-/*
-** Intergraph CLIX 3.1
-**
-** From Paul Southworth <pauls@locust.cic.net>
-*/
-
-#ifdef CLIX
-# define SYSTEM5 1 /* looks like System V */
-# ifndef HASGETUSERSHELL
-# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
-# endif
-# define DEV_BSIZE 512 /* device block size not defined */
-# define GIDSET_T gid_t
-# undef LOG /* syslog not available */
-# define NEEDFSYNC 1 /* no fsync in system library */
-# define GETSHORT _getshort
-#endif
-
-
-/*
-** NCR MP-RAS 2.x (SysVr4) with Wollongong TCP/IP
-**
-** From Kevin Darcy <kevin@tech.mis.cfc.com>.
-*/
-
-#ifdef NCR_MP_RAS2
-# include <sys/sockio.h>
-# define __svr4__
-# define IP_SRCROUTE 0 /* Something is broken with getsockopt() */
-# define SYSLOG_BUFSIZE 1024
-# define SPT_TYPE SPT_NONE
-#endif
-
-
-/*
-** NCR MP-RAS 3.x (SysVr4) with STREAMware TCP/IP
-**
-** From Tom Moore <Tom.Moore@DaytonOH.NCR.COM>
-*/
-
-#ifdef NCR_MP_RAS3
-# define __svr4__
-# define SIOCGIFNUM_IS_BROKEN 1 /* SIOCGIFNUM has non-std interface */
-# define SYSLOG_BUFSIZE 1024
-# define SPT_TYPE SPT_NONE
-#endif
-
-
-/*
-** Tandem NonStop-UX SVR4
-**
-** From Rick McCarty <mccarty@mpd.tandem.com>.
-*/
-
-#ifdef NonStop_UX_BXX
-# define __svr4__
-#endif
-
-
-/*
-** Hitachi 3050R & 3050RX Workstations running HI-UX/WE2.
-**
-** Tested for 1.04 and 1.03
-** From Akihiro Hashimoto ("Hash") <hash@dominic.ipc.chiba-u.ac.jp>.
-*/
-
-#ifdef __H3050R
-# define SYSTEM5 1 /* include all the System V defines */
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define setreuid(r, e) setresuid(r, e, -1)
-# define LA_TYPE LA_FLOAT
-# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
-# define HASSETVBUF /* HI-UX has no setlinebuf */
-# ifndef GIDSET_T
-# define GIDSET_T gid_t
-# endif
-# ifndef _PATH_UNIX
-# define _PATH_UNIX "/HI-UX"
-# endif
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
-# endif
-# ifndef IDENTPROTO
-# define IDENTPROTO 0 /* TCP/IP implementation is broken */
-# endif
-# ifndef HASGETUSERSHELL
-# define HASGETUSERSHELL 0 /* getusershell(3) causes core dumps */
-# endif
-
-/*
-** avoid m_flags conflict between Berkeley DB 1.85 db.h & sys/sysmacros.h
-** on HIUX 3050
-*/
-# undef m_flags
-
-# ifdef __STDC__
-extern int syslog(int, char *, ...);
-#else
-extern int syslog();
-# endif
-
-#endif
-
-
-/*
-** Amdahl UTS System V 2.1.5 (SVr3-based)
-**
-** From: Janet Jackson <janet@dialix.oz.au>.
-*/
-
-#ifdef _UTS
-# include <sys/sysmacros.h>
-# undef HASLSTAT /* has symlinks, but they cause problems */
-# define NEEDFSYNC 1 /* system fsync(2) fails on non-EFS filesys */
-# define SYS5SIGNALS 1 /* System V signal semantics */
-# define SYS5SETPGRP 1 /* use System V setpgrp(2) syscall */
-# define HASUNAME 1 /* use System V uname(2) system call */
-# define HASINITGROUPS 1 /* has initgroups(3) function */
-# define HASSETVBUF 1 /* has setvbuf(3) function */
-# ifndef HASGETUSERSHELL
-# define HASGETUSERSHELL 0 /* does not have getusershell(3) function */
-# endif
-# define GIDSET_T gid_t /* type of 2nd arg to getgroups(2) isn't int */
-# define LA_TYPE LA_ZERO /* doesn't have load average */
-# define SFS_TYPE SFS_4ARGS /* use 4-arg statfs() */
-# define SFS_BAVAIL f_bfree /* alternate field name */
-# define _PATH_UNIX "/unix"
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
-# endif
-#endif
-
-/*
-** Cray Computer Corporation's CSOS
-**
-** From Scott Bolte <scott@craycos.com>.
-*/
-
-#ifdef _CRAYCOM
-# define SYSTEM5 1 /* include all the System V defines */
-# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
-# define NEEDFSYNC 1 /* no fsync in system library */
-# define MAXPATHLEN PATHSIZE
-# define LA_TYPE LA_ZERO
-# define SFS_TYPE SFS_4ARGS /* four argument statfs() call */
-# define SFS_BAVAIL f_bfree /* alternate field name */
-# define _POSIX_CHOWN_RESTRICTED -1
-extern struct group *getgrent(), *getgrnam(), *getgrgid();
-#endif
-
-
-/*
-** Sony NEWS-OS 4.2.1R and 6.0.3
-**
-** From Motonori NAKAMURA <motonori@cs.ritsumei.ac.jp>.
-*/
-
-#ifdef sony_news
-# ifndef __svr4
- /* NEWS-OS 4.2.1R */
-# ifndef BSD
-# define BSD /* has BSD routines */
-# endif
-# define HASUNSETENV 1 /* has unsetenv(2) call */
-# undef HASSETVBUF /* don't actually have setvbuf(3) */
-# define WAITUNION 1 /* use "union wait" as wait argument type */
-# define LA_TYPE LA_INT
-# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
-# ifndef HASFLOCK
-# define HASFLOCK 1 /* has flock(2) call */
-# endif
-# define setpgid setpgrp
-# undef WIFEXITED
-# undef WEXITSTATUS
-# define MODE_T int /* system include files have no mode_t */
-typedef int pid_t;
-typedef int (*sigfunc_t)();
-# define SIGFUNC_DEFINED
-# define SIGFUNC_RETURN (0)
-# define SIGFUNC_DECL int
-
-# else
- /* NEWS-OS 6.0.3 with /bin/cc */
-# ifndef __svr4__
-# define __svr4__ /* use all System V Releae 4 defines below */
-# endif
-# define HASSETSID 1 /* has Posix setsid(2) call */
-# define HASGETUSERSHELL 1 /* DOES have getusershell(3) call in libc */
-# define LA_TYPE LA_READKSYM /* use MIOC_READKSYM ioctl */
-# ifndef SPT_TYPE
-# define SPT_TYPE SPT_SYSMIPS /* use sysmips() (OS 6.0.2 or later) */
-# endif
-# define GIDSET_T gid_t
-# undef WIFEXITED
-# undef WEXITSTATUS
-# ifndef SYSLOG_BUFSIZE
-# define SYSLOG_BUFSIZE 1024
-# endif
-# define _PATH_UNIX "/stand/unix"
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/etc/mail/sendmail.cf"
-# endif
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/etc/mail/sendmail.pid"
-# endif
-
-# endif
-#endif
-
-
-/*
-** Omron LUNA/UNIOS-B 3.0, LUNA2/Mach and LUNA88K Mach
-**
-** From Motonori NAKAMURA <motonori@cs.ritsumei.ac.jp>.
-*/
-
-#ifdef luna
-# ifndef IDENTPROTO
-# define IDENTPROTO 0 /* TCP/IP implementation is broken */
-# endif
-# define HASUNSETENV 1 /* has unsetenv(2) call */
-# define NEEDPUTENV 1 /* need putenv(3) call */
-# define NEEDGETOPT 1 /* need a replacement for getopt(3) */
-# define NEEDSTRSTR 1 /* need emulation of the strstr(3) call */
-# define WAITUNION 1 /* use "union wait" as wait argument type */
-# ifdef uniosb
-# include <sys/time.h>
-# define NEEDVPRINTF 1 /* need a replacement for vprintf(3) */
-# define LA_TYPE LA_INT
-# define TZ_TYPE TZ_TM_ZONE /* use tm->tm_zone */
-# endif
-# ifdef luna2
-# define LA_TYPE LA_SUBR
-# define TZ_TYPE TZ_TM_ZONE /* use tm->tm_zone */
-# endif
-# ifdef luna88k
-# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */
-# define LA_TYPE LA_INT
-# endif
-# define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */
-# define setpgid setpgrp
-# undef WIFEXITED
-# undef WEXITSTATUS
-typedef int pid_t;
-typedef int (*sigfunc_t)();
-# define SIGFUNC_DEFINED
-# define SIGFUNC_RETURN (0)
-# define SIGFUNC_DECL int
-extern char *getenv();
-extern int errno;
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf"
-# endif
-#endif
-
-
-/*
-** NEC EWS-UX/V 4.2 (with /usr/ucb/cc)
-**
-** From Motonori NAKAMURA <motonori@cs.ritsumei.ac.jp>.
-*/
-
-#if defined(nec_ews_svr4) || defined(_nec_ews_svr4)
-# ifndef __svr4__
-# define __svr4__ /* use all System V Releae 4 defines below */
-# endif
-# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */
-# define HASSETSID 1 /* has Posix setsid(2) call */
-# define LA_TYPE LA_READKSYM /* use MIOC_READSYM ioctl */
-# define SFS_TYPE SFS_USTAT /* use System V ustat(2) syscall */
-# define GIDSET_T gid_t
-# undef WIFEXITED
-# undef WEXITSTATUS
-# define NAMELISTMASK 0x7fffffff /* mask for nlist() values */
-# ifndef SYSLOG_BUFSIZE
-# define SYSLOG_BUFSIZE 1024 /* allow full size syslog buffer */
-# endif
-#endif
-
-
-/*
-** Fujitsu/ICL UXP/DS (For the DS/90 Series)
-**
-** From Diego R. Lopez <drlopez@cica.es>.
-** Additional changes from Fumio Moriya and Toshiaki Nomura of the
-** Fujitsu Fresoftware gruop <dsfrsoft@oai6.yk.fujitsu.co.jp>.
-*/
-
-#ifdef __uxp__
-# include <arpa/nameser.h>
-# include <sys/sysmacros.h>
-# include <sys/mkdev.h>
-# define __svr4__
-# define HASGETUSERSHELL 0
-# define HASFLOCK 0
-# if UXPDS == 10
-# define HASSNPRINTF 0 /* no snprintf(3) or vsnprintf(3) */
-# else
-# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */
-# endif
-# define _PATH_UNIX "/stand/unix"
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/ucblib/sendmail.cf"
-# endif
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/usr/ucblib/sendmail.pid"
-# endif
-#endif
-
-/*
-** Pyramid DC/OSx
-**
-** From Earle Ake <akee@wpdiss1.wpafb.af.mil>.
-*/
-
-#ifdef DCOSx
-# define GIDSET_T gid_t
-# ifndef IDENTPROTO
-# define IDENTPROTO 0 /* TCP/IP implementation is broken */
-# endif
-#endif
-
-/*
-** Concurrent Computer Corporation Maxion
-**
-** From Donald R. Laster Jr. <laster@access.digex.net>.
-*/
-
-#ifdef __MAXION__
-
-# include <sys/stream.h>
-# define __svr4__ 1 /* SVR4.2MP */
-# define HASSETREUID 1 /* have setreuid(2) */
-# define HASLSTAT 1 /* have lstat(2) */
-# define HASSETRLIMIT 1 /* have setrlimit(2) */
-# define HASGETDTABLESIZE 1 /* have getdtablesize(2) */
-# define HASSNPRINTF 1 /* have snprintf(3) */
-# define HASGETUSERSHELL 1 /* have getusershell(3) */
-# define NOFTRUNCATE 1 /* do not have ftruncate(2) */
-# define SLEEP_T unsigned
-# define SFS_TYPE SFS_STATVFS
-# define SFS_BAVAIL f_bavail
-# ifndef SYSLOG_BUFSIZE
-# define SYSLOG_BUFSIZE 256 /* Use 256 bytes */
-# endif
-
-# undef WUNTRACED
-# undef WIFEXITED
-# undef WIFSIGNALED
-# undef WIFSTOPPED
-# undef WEXITSTATUS
-# undef WTERMSIG
-# undef WSTOPSIG
-
-#endif
-
-/*
-** Harris Nighthawk PowerUX (nh6000 box)
-**
-** Contributed by Bob Miorelli, Pratt & Whitney <miorelli@pweh.com>
-*/
-
-#ifdef _PowerUX
-# ifndef __svr4__
-# define __svr4__
-# endif
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/etc/mail/sendmail.cf"
-# endif
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/etc/mail/sendmail.pid"
-# endif
-# define SYSLOG_BUFSIZE 1024
-# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */
-# define LA_TYPE LA_ZERO
-typedef struct msgb mblk_t;
-# undef offsetof /* avoid stddefs.h and sys/sysmacros.h conflict */
-#endif
-
-/*
-** Siemens Nixdorf Informationssysteme AG SINIX
-**
-** Contributed by Gerald Rinske <Gerald.Rinske@mch.sni.de>
-** of Siemens Business Services VAS.
-*/
-#ifdef sinix
-# define SYSLOG_BUFSIZE 1024
-#endif
-
-/*
-** CRAY T3E
-**
-** Contributed by Manu Mahonen <mailadm@csc.fi>
-** of Center for Scientific Computing.
-*/
-#ifdef _CRAY
-# define GET_IPOPT_DST(dst) *(struct in_addr *)&(dst)
-#endif
-
-/**********************************************************************
-** End of Per-Operating System defines
-**********************************************************************/
- /**********************************************************************
-** More general defines
-**********************************************************************/
-
-/* general BSD defines */
-#ifdef BSD
-# define HASGETDTABLESIZE 1 /* has getdtablesize(2) call */
-# define HASSETREUID 1 /* has setreuid(2) call */
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# ifndef IP_SRCROUTE
-# define IP_SRCROUTE 1 /* can check IP source routing */
-# endif
-# ifndef HASSETRLIMIT
-# define HASSETRLIMIT 1 /* has setrlimit(2) call */
-# endif
-# ifndef HASFLOCK
-# define HASFLOCK 1 /* has flock(2) call */
-# endif
-# ifndef TZ_TYPE
-# define TZ_TYPE TZ_TM_ZONE /* use tm->tm_zone variable */
-# endif
-#endif
-
-/* general System V Release 4 defines */
-#ifdef __svr4__
-# define SYSTEM5 1
-# define USESETEUID 1 /* has useable seteuid(2) call */
-# define HASINITGROUPS 1 /* has initgroups(3) call */
-# define BSD_COMP 1 /* get BSD ioctl calls */
-# ifndef HASSETRLIMIT
-# define HASSETRLIMIT 1 /* has setrlimit(2) call */
-# endif
-# ifndef HASGETUSERSHELL
-# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */
-# endif
-# ifndef HASFCHMOD
-# define HASFCHMOD 1 /* most (all?) SVr4s seem to have fchmod(2) */
-# endif
-
-# ifndef _PATH_UNIX
-# define _PATH_UNIX "/unix"
-# endif
-# ifndef _PATH_VENDOR_CF
-# define _PATH_VENDOR_CF "/usr/ucblib/sendmail.cf"
-# endif
-# ifndef _PATH_SENDMAILPID
-# define _PATH_SENDMAILPID "/usr/ucblib/sendmail.pid"
-# endif
-# ifndef SYSLOG_BUFSIZE
-# define SYSLOG_BUFSIZE 128
-# endif
-# ifndef SFS_TYPE
-# define SFS_TYPE SFS_STATVFS
-# endif
-
-# define USE_SIGLONGJMP 1 /* sigsetjmp needed for signal handling */
-#endif
-
-/* general System V defines */
-#ifdef SYSTEM5
-# include <sys/sysmacros.h>
-# define HASUNAME 1 /* use System V uname(2) system call */
-# define SYS5SETPGRP 1 /* use System V setpgrp(2) syscall */
-# define HASSETVBUF 1 /* we have setvbuf(3) in libc */
-# ifndef HASULIMIT
-# define HASULIMIT 1 /* has the ulimit(2) syscall */
-# endif
-# ifndef LA_TYPE
-# ifdef MIOC_READKSYM
-# define LA_TYPE LA_READKSYM /* use MIOC_READKSYM ioctl */
-# else
-# define LA_TYPE LA_INT /* assume integer load average */
-# endif
-# endif
-# ifndef SFS_TYPE
-# define SFS_TYPE SFS_USTAT /* use System V ustat(2) syscall */
-# endif
-# ifndef TZ_TYPE
-# define TZ_TYPE TZ_TZNAME /* use tzname[] vector */
-# endif
-# define bcopy(s, d, l) (memmove((d), (s), (l)))
-# define bzero(d, l) (memset((d), '\0', (l)))
-# define bcmp(s, d, l) (memcmp((s), (d), (l)))
-#endif
-
-/* general POSIX defines */
-#ifdef _POSIX_VERSION
-# define HASSETSID 1 /* has Posix setsid(2) call */
-# define HASWAITPID 1 /* has Posix waitpid(2) call */
-# if _POSIX_VERSION >= 199500 && !defined(USESETEUID)
-# define USESETEUID 1 /* has useable seteuid(2) call */
-# endif
-# ifndef bcopy
-# define bcopy(s, d, l) (memmove((d), (s), (l)))
-# define bzero(d, l) (memset((d), '\0', (l)))
-# define bcmp(s, d, l) (memcmp((s), (d), (l)))
-# endif
-#endif
- /*
-** Tweaking for systems that (for example) claim to be BSD or POSIX
-** but don't have all the standard BSD or POSIX routines (boo hiss).
-*/
-
-#ifdef titan
-# undef HASINITGROUPS /* doesn't have initgroups(3) call */
-#endif
-
-#ifdef _CRAYCOM
-# undef HASSETSID /* despite POSIX claim, doesn't have setsid */
-#endif
-
-#ifdef ISC_UNIX
-# undef bcopy /* despite SystemV claim, uses BSD bcopy */
-#endif
-
-#ifdef ALTOS_SYSTEM_V
-# undef bcopy /* despite SystemV claim, uses BSD bcopy */
-# undef bzero /* despite SystemV claim, uses BSD bzero */
-# undef bcmp /* despite SystemV claim, uses BSD bcmp */
-#endif
-
-#if defined(sun) && !defined(BSD) && !defined(SOLARIS) && !defined(__svr4__) && !defined(__SVR4)
-# undef bcopy /* SunOS 4 doesn't have memmove() */
-#endif
-
-
-/*
-** Due to a "feature" in some operating systems such as Ultrix 4.3 and
-** HPUX 8.0, if you receive a "No route to host" message (ICMP message
-** ICMP_UNREACH_HOST) on _any_ connection, all connections to that host
-** are closed. Some firewalls return this error if you try to connect
-** to the IDENT port (113), so you can't receive email from these hosts
-** on these systems. The firewall really should use a more specific
-** message such as ICMP_UNREACH_PROTOCOL or _PORT or _FILTER_PROHIB. If
-** not explicitly set to zero above, default it on.
-*/
-
-#ifndef IDENTPROTO
-# define IDENTPROTO 1 /* use IDENT proto (RFC 1413) */
-#endif
-
-#ifndef IP_SRCROUTE
-# define IP_SRCROUTE 1 /* Detect IP source routing */
-#endif
-
-#ifndef HASGETUSERSHELL
-# define HASGETUSERSHELL 1 /* libc has getusershell(3) call */
-#endif
-
-#ifndef NETUNIX
-# define NETUNIX 1 /* include unix domain support */
-#endif
-
-#ifndef HASFLOCK
-# define HASFLOCK 0 /* assume no flock(2) support */
-#endif
-
-#ifndef HASSETREUID
-# define HASSETREUID 0 /* assume no setreuid(2) call */
-#endif
-
-#ifndef HASFCHMOD
-# define HASFCHMOD 0 /* assume no fchmod(2) syscall */
-#endif
-
-#ifndef USESETEUID
-# define USESETEUID 0 /* assume no seteuid(2) call or no saved ids */
-#endif
-
-#ifndef HASSETRLIMIT
-# define HASSETRLIMIT 0 /* assume no setrlimit(2) support */
-#endif
-
-#ifndef HASULIMIT
-# define HASULIMIT 0 /* assume no ulimit(2) support */
-#endif
-
-#ifndef SECUREWARE
-# define SECUREWARE 0 /* assume no SecureWare C2 auditing hooks */
-#endif
-
-#ifndef USE_SIGLONGJMP
-# define USE_SIGLONGJMP 0 /* assume setjmp handles signals properly */
-#endif
-
-#ifndef FDSET_CAST
-# define FDSET_CAST /* (empty) cast for fd_set arg to select */
-#endif
-
-/*
-** If no type for argument two of getgroups call is defined, assume
-** it's an integer -- unfortunately, there seem to be several choices
-** here.
-*/
-
-#ifndef GIDSET_T
-# define GIDSET_T int
-#endif
-
-#ifndef UID_T
-# define UID_T uid_t
-#endif
-
-#ifndef GID_T
-# define GID_T gid_t
-#endif
-
-#ifndef SIZE_T
-# define SIZE_T size_t
-#endif
-
-#ifndef MODE_T
-# define MODE_T mode_t
-#endif
-
-#ifndef ARGV_T
-# define ARGV_T char **
-#endif
-
-#ifndef SOCKADDR_LEN_T
-# define SOCKADDR_LEN_T int
-#endif
-
-#ifndef SOCKOPT_LEN_T
-# define SOCKOPT_LEN_T int
-#endif
-
-#ifndef QUAD_T
-# define QUAD_T unsigned long
-#endif
- /**********************************************************************
-** Remaining definitions should never have to be changed. They are
-** primarily to provide back compatibility for older systems -- for
-** example, it includes some POSIX compatibility definitions
-**********************************************************************/
-
-/* System 5 compatibility */
-#ifndef S_ISREG
-# define S_ISREG(foo) ((foo & S_IFMT) == S_IFREG)
-#endif
-#ifndef S_ISDIR
-# define S_ISDIR(foo) ((foo & S_IFMT) == S_IFDIR)
-#endif
-#if !defined(S_ISLNK) && defined(S_IFLNK)
-# define S_ISLNK(foo) ((foo & S_IFMT) == S_IFLNK)
-#endif
-#ifndef S_IRUSR
-# define S_IRUSR 0400
-#endif
-#ifndef S_IWUSR
-# define S_IWUSR 0200
-#endif
-#ifndef S_IRGRP
-# define S_IRGRP 0040
-#endif
-#ifndef S_IWGRP
-# define S_IWGRP 0020
-#endif
-#ifndef S_IROTH
-# define S_IROTH 0004
-#endif
-#ifndef S_IWOTH
-# define S_IWOTH 0002
-#endif
-
-/*
-** Older systems don't have this error code -- it should be in
-** /usr/include/sysexits.h.
-*/
-
-# ifndef EX_CONFIG
-# define EX_CONFIG 78 /* configuration error */
-# endif
-
-/* pseudo-code used in server SMTP */
-# define EX_QUIT 22 /* drop out of server immediately */
-
-/* pseudo-code used for mci_setstat */
-# define EX_NOTSTICKY -5 /* don't save persistent status */
-
-
-/*
-** An "impossible" file mode to indicate that the file does not exist.
-*/
-
-#define ST_MODE_NOFILE 0171147 /* unlikely to occur */
-
-
-/*
-** These are used in a few cases where we need some special
-** error codes, but where the system doesn't provide something
-** reasonable. They are printed in errstring.
-*/
-
-#ifndef E_PSEUDOBASE
-# define E_PSEUDOBASE 256
-#endif
-
-#define E_SM_OPENTIMEOUT (E_PSEUDOBASE + 0) /* Timeout on file open */
-#define E_SM_NOSLINK (E_PSEUDOBASE + 1) /* Symbolic links not allowed */
-#define E_SM_NOHLINK (E_PSEUDOBASE + 2) /* Hard links not allowed */
-#define E_SM_REGONLY (E_PSEUDOBASE + 3) /* Regular files only */
-#define E_SM_ISEXEC (E_PSEUDOBASE + 4) /* Executable files not allowed */
-#define E_SM_WWDIR (E_PSEUDOBASE + 5) /* World writable directory */
-#define E_SM_GWDIR (E_PSEUDOBASE + 6) /* Group writable directory */
-#define E_SM_FILECHANGE (E_PSEUDOBASE + 7) /* File changed after open */
-#define E_SM_WWFILE (E_PSEUDOBASE + 8) /* World writable file */
-#define E_SM_GWFILE (E_PSEUDOBASE + 9) /* Group writable file */
-#define E_DNSBASE (E_PSEUDOBASE + 20) /* base for DNS h_errno */
-
-/* type of arbitrary pointer */
-#ifndef ARBPTR_T
-# define ARBPTR_T void *
-#endif
-
-#ifndef __P
-# include "cdefs.h"
-#endif
-
-#if HESIOD && !defined(NAMED_BIND)
-# define NAMED_BIND 1 /* not one without the other */
-#endif
-
-#if NAMED_BIND && !defined(__ksr__) && !defined(h_errno)
-extern int h_errno;
-#endif
-
-/*
-** Do some required dependencies
-*/
-
-#if NETINET || NETISO
-# ifndef SMTP
-# define SMTP 1 /* enable user and server SMTP */
-# endif
-# ifndef QUEUE
-# define QUEUE 1 /* enable queueing */
-# endif
-# ifndef DAEMON
-# define DAEMON 1 /* include the daemon (requires IPC & SMTP) */
-# endif
-#endif
-
-
-/*
-** Arrange to use either varargs or stdargs
-*/
-
-# ifdef __STDC__
-
-# include <stdarg.h>
-
-# define VA_LOCAL_DECL va_list ap;
-# define VA_START(f) va_start(ap, f)
-# define VA_END va_end(ap)
-
-# else
-
-# include <varargs.h>
-
-# define VA_LOCAL_DECL va_list ap;
-# define VA_START(f) va_start(ap)
-# define VA_END va_end(ap)
-
-# endif
-
-#ifdef HASUNAME
-# include <sys/utsname.h>
-# ifdef newstr
-# undef newstr
-# endif
-#else /* ! HASUNAME */
-# define NODE_LENGTH 32
-struct utsname
-{
- char nodename[NODE_LENGTH+1];
-};
-#endif /* HASUNAME */
-
-#if !defined(MAXHOSTNAMELEN) && !defined(_SCO_unix_) && !defined(NonStop_UX_BXX) && !defined(ALTOS_SYSTEM_V)
-# define MAXHOSTNAMELEN 256
-#endif
-
-#if !defined(SIGCHLD) && defined(SIGCLD)
-# define SIGCHLD SIGCLD
-#endif
-
-#ifndef STDIN_FILENO
-# define STDIN_FILENO 0
-#endif
-
-#ifndef STDOUT_FILENO
-# define STDOUT_FILENO 1
-#endif
-
-#ifndef STDERR_FILENO
-# define STDERR_FILENO 2
-#endif
-
-#ifndef LOCK_SH
-# define LOCK_SH 0x01 /* shared lock */
-# define LOCK_EX 0x02 /* exclusive lock */
-# define LOCK_NB 0x04 /* non-blocking lock */
-# define LOCK_UN 0x08 /* unlock */
-#endif
-
-#ifndef S_IXOTH
-# define S_IXOTH (S_IEXEC >> 6)
-#endif
-
-#ifndef S_IXGRP
-# define S_IXGRP (S_IEXEC >> 3)
-#endif
-
-#ifndef S_IXUSR
-# define S_IXUSR (S_IEXEC)
-#endif
-
-#ifndef SEEK_SET
-# define SEEK_SET 0
-# define SEEK_CUR 1
-# define SEEK_END 2
-#endif
-
-#ifndef SIG_ERR
-# define SIG_ERR ((void (*)()) -1)
-#endif
-
-#ifndef WEXITSTATUS
-# define WEXITSTATUS(st) (((st) >> 8) & 0377)
-#endif
-#ifndef WIFEXITED
-# define WIFEXITED(st) (((st) & 0377) == 0)
-#endif
-
-#ifndef SIGFUNC_DEFINED
-typedef void (*sigfunc_t) __P((int));
-#endif
-#ifndef SIGFUNC_RETURN
-# define SIGFUNC_RETURN
-#endif
-#ifndef SIGFUNC_DECL
-# define SIGFUNC_DECL void
-#endif
-
-/* size of syslog buffer */
-#ifndef SYSLOG_BUFSIZE
-# define SYSLOG_BUFSIZE 1024
-#endif
-
-/*
-** Size of prescan buffer.
-** Despite comments in the _sendmail_ book, this probably should
-** not be changed; there are some hard-to-define dependencies.
-*/
-
-# define PSBUFSIZE (MAXNAME + MAXATOM) /* size of prescan buffer */
-
-/* fork routine -- set above using #ifdef _osname_ or in Makefile */
-# ifndef FORK
-# define FORK fork /* function to call to fork mailer */
-# endif
-
-/*
-** Default to using scanf in readcf.
-*/
-
-#ifndef SCANF
-# define SCANF 1
-#endif
-
-/*
-** SVr4 and similar systems use different routines for setjmp/longjmp
-** with signal support
-*/
-
-#if USE_SIGLONGJMP
-# ifdef jmp_buf
-# undef jmp_buf
-# endif
-# define jmp_buf sigjmp_buf
-# ifdef setjmp
-# undef setjmp
-# endif
-# define setjmp(env) sigsetjmp(env, 1)
-# ifdef longjmp
-# undef longjmp
-# endif
-# define longjmp(env, val) siglongjmp(env, val)
-#endif
-
-#if !defined(NGROUPS_MAX) && defined(NGROUPS)
-# define NGROUPS_MAX NGROUPS /* POSIX naming convention */
-#endif
-
-/*
-** If we don't have a system syslog, simulate it.
-*/
-
-#if !LOG
-# define LOG_EMERG 0 /* system is unusable */
-# define LOG_ALERT 1 /* action must be taken immediately */
-# define LOG_CRIT 2 /* critical conditions */
-# define LOG_ERR 3 /* error conditions */
-# define LOG_WARNING 4 /* warning conditions */
-# define LOG_NOTICE 5 /* normal but significant condition */
-# define LOG_INFO 6 /* informational */
-# define LOG_DEBUG 7 /* debug-level messages */
-#endif
diff --git a/src/control.c b/src/control.c
deleted file mode 100644
index 415818c..0000000
--- a/src/control.c
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)control.c 8.18 (Berkeley) 1/17/1999";
-#endif /* not lint */
-
-#include "sendmail.h"
-
-int ControlSocket = -1;
-
- /*
-** OPENCONTROLSOCKET -- create/open the daemon control named socket
-**
-** Creates and opens a named socket for external control over
-** the sendmail daemon.
-**
-** Parameters:
-** none.
-**
-** Returns:
-** 0 if successful, -1 otherwise
-*/
-
-int
-opencontrolsocket()
-{
-#ifdef NETUNIX
-# if _FFR_CONTROL_SOCKET
- int rval;
- int sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN;
- struct sockaddr_un controladdr;
-
- if (ControlSocketName == NULL)
- return 0;
-
- if (strlen(ControlSocketName) >= sizeof controladdr.sun_path)
- {
- errno = ENAMETOOLONG;
- return -1;
- }
-
- rval = safefile(ControlSocketName, RunAsUid, RunAsGid, RunAsUserName,
- sff, S_IRUSR|S_IWUSR, NULL);
-
- /* if not safe, don't create */
- if (rval != 0)
- {
- errno = rval;
- return -1;
- }
-
- ControlSocket = socket(AF_UNIX, SOCK_STREAM, 0);
- if (ControlSocket < 0)
- return -1;
-
- unlink(ControlSocketName);
- bzero(&controladdr, sizeof controladdr);
- controladdr.sun_family = AF_UNIX;
- strcpy(controladdr.sun_path, ControlSocketName);
-
- if (bind(ControlSocket, (struct sockaddr *) &controladdr,
- sizeof controladdr) < 0)
- {
- int save_errno = errno;
-
- clrcontrol();
- errno = save_errno;
- return -1;
- }
-
-# if _FFR_TRUSTED_USER
- if (geteuid() == 0 && TrustedUid != 0)
- {
- if (chown(ControlSocketName, TrustedUid, -1) < 0)
- {
- int save_errno = errno;
-
- sm_syslog(LOG_ALERT, NOQID,
- "ownership change on %s failed: %s",
- ControlSocketName, errstring(save_errno));
- message("050 ownership change on %s failed: %s",
- ControlSocketName, errstring(save_errno));
- closecontrolsocket(TRUE);
- errno = save_errno;
- return -1;
- }
- }
-# endif
-
- if (chmod(ControlSocketName, S_IRUSR|S_IWUSR) < 0)
- {
- int save_errno = errno;
-
- closecontrolsocket(TRUE);
- errno = save_errno;
- return -1;
- }
-
- if (listen(ControlSocket, 8) < 0)
- {
- int save_errno = errno;
-
- closecontrolsocket(TRUE);
- errno = save_errno;
- return -1;
- }
-# endif
-#endif
- return 0;
-}
- /*
-** CLOSECONTROLSOCKET -- close the daemon control named socket
-**
-** Close a named socket.
-**
-** Parameters:
-** fullclose -- if set, close the socket and remove it;
-** otherwise, just remove it
-**
-** Returns:
-** none.
-*/
-
-void
-closecontrolsocket(fullclose)
- bool fullclose;
-{
-#ifdef NETUNIX
-# if _FFR_CONTROL_SOCKET
- int sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN;
-
- if (ControlSocket >= 0)
- {
- int rval;
-
- if (fullclose)
- {
- (void) close(ControlSocket);
- ControlSocket = -1;
- }
-
- rval = safefile(ControlSocketName, RunAsUid, RunAsGid, RunAsUserName,
- sff, S_IRUSR|S_IWUSR, NULL);
-
- /* if not safe, don't unlink */
- if (rval != 0)
- return;
-
- if (unlink(ControlSocketName) < 0)
- {
- sm_syslog(LOG_WARNING, NOQID,
- "Could not remove control socket: %s",
- errstring(errno));
- return;
- }
- }
-# endif
-#endif
- return;
-}
- /*
-** CLRCONTROL -- reset the control connection
-**
-** Parameters:
-** none.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** releases any resources used by the control interface.
-*/
-
-void
-clrcontrol()
-{
-#ifdef NETUNIX
-# if _FFR_CONTROL_SOCKET
- if (ControlSocket >= 0)
- (void) close(ControlSocket);
- ControlSocket = -1;
-# endif
-#endif
-}
-
-#ifndef NOT_SENDMAIL
-
- /*
-** CONTROL_COMMAND -- read and process command from named socket
-**
-** Read and process the command from the opened socket.
-** Return the results down the same socket.
-**
-** Parameters:
-** sock -- the opened socket from getrequests()
-** e -- the current envelope
-**
-** Returns:
-** none.
-*/
-
-struct cmd
-{
- char *cmdname; /* command name */
- int cmdcode; /* internal code, see below */
-};
-
-/* values for cmdcode */
-# define CMDERROR 0 /* bad command */
-# define CMDRESTART 1 /* restart daemon */
-# define CMDSHUTDOWN 2 /* end daemon */
-# define CMDHELP 3 /* help */
-# define CMDSTATUS 4 /* daemon status */
-
-static struct cmd CmdTab[] =
-{
- { "help", CMDHELP },
- { "restart", CMDRESTART },
- { "shutdown", CMDSHUTDOWN },
- { "status", CMDSTATUS },
- { NULL, CMDERROR }
-};
-
-void
-control_command(sock, e)
- int sock;
- ENVELOPE *e;
-{
- FILE *s;
- FILE *traffic;
- FILE *oldout;
- char *cmd;
- char *p;
- struct cmd *c;
- char cmdbuf[MAXLINE];
- char inp[MAXLINE];
- extern char **SaveArgv;
- extern void help __P((char *));
-
- sm_setproctitle(FALSE, "control cmd read");
-
- s = fdopen(sock, "r+");
- if (s == NULL)
- {
- int save_errno = errno;
-
- close(sock);
- errno = save_errno;
- return;
- }
- setbuf(s, NULL);
-
- if (fgets(inp, sizeof inp, s) == NULL)
- {
- fclose(s);
- return;
- }
- (void) fflush(s);
-
- /* clean up end of line */
- fixcrlf(inp, TRUE);
-
- sm_setproctitle(FALSE, "control: %s", inp);
-
- /* break off command */
- for (p = inp; isascii(*p) && isspace(*p); p++)
- continue;
- cmd = cmdbuf;
- while (*p != '\0' &&
- !(isascii(*p) && isspace(*p)) &&
- cmd < &cmdbuf[sizeof cmdbuf - 2])
- *cmd++ = *p++;
- *cmd = '\0';
-
- /* throw away leading whitespace */
- while (isascii(*p) && isspace(*p))
- p++;
-
- /* decode command */
- for (c = CmdTab; c->cmdname != NULL; c++)
- {
- if (!strcasecmp(c->cmdname, cmdbuf))
- break;
- }
-
- switch (c->cmdcode)
- {
- case CMDHELP: /* get help */
- traffic = TrafficLogFile;
- TrafficLogFile = NULL;
- oldout = OutChannel;
- OutChannel = s;
- help("control");
- TrafficLogFile = traffic;
- OutChannel = oldout;
- break;
-
- case CMDRESTART: /* restart the daemon */
- if (SaveArgv[0][0] != '/')
- {
- fprintf(s, "ERROR: could not restart: need full path\r\n");
- break;
- }
- if (LogLevel > 3)
- sm_syslog(LOG_INFO, NOQID,
- "restarting %s on due to control command",
- SaveArgv[0]);
- closecontrolsocket(FALSE);
- if (drop_privileges(TRUE) != EX_OK)
- {
- if (LogLevel > 0)
- sm_syslog(LOG_ALERT, NOQID,
- "could not set[ug]id(%d, %d): %m",
- RunAsUid, RunAsGid);
-
- fprintf(s, "ERROR: could not set[ug]id(%d, %d): %s, exiting...\r\n",
- (int)RunAsUid, (int)RunAsGid, errstring(errno));
- finis(FALSE, EX_OSERR);
- }
- fprintf(s, "OK\r\n");
- clrcontrol();
- (void) fcntl(sock, F_SETFD, 1);
- execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron);
- if (LogLevel > 0)
- sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %m",
- SaveArgv[0]);
- fprintf(s, "ERROR: could not exec %s: %s, exiting...\r\n",
- SaveArgv[0], errstring(errno));
- finis(FALSE, EX_OSFILE);
- break;
-
- case CMDSHUTDOWN: /* kill the daemon */
- fprintf(s, "OK\r\n");
- finis(FALSE, EX_OK);
- break;
-
- case CMDSTATUS: /* daemon status */
- proc_list_probe();
- fprintf(s, "%d/%d\r\n", CurChildren, MaxChildren);
- proc_list_display(s);
- break;
-
- case CMDERROR: /* unknown command */
- fprintf(s, "Bad command (%s)\r\n", cmdbuf);
- break;
- }
- fclose(s);
-}
-#endif
diff --git a/src/convtime.c b/src/convtime.c
deleted file mode 100644
index ab8591d..0000000
--- a/src/convtime.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)convtime.c 8.14 (Berkeley) 5/19/1998";
-#endif /* not lint */
-
-# include "sendmail.h"
-
-/*
-** CONVTIME -- convert time
-**
-** Takes a time as an ascii string with a trailing character
-** giving units:
-** s -- seconds
-** m -- minutes
-** h -- hours
-** d -- days (default)
-** w -- weeks
-** For example, "3d12h" is three and a half days.
-**
-** Parameters:
-** p -- pointer to ascii time.
-** units -- default units if none specified.
-**
-** Returns:
-** time in seconds.
-**
-** Side Effects:
-** none.
-*/
-
-time_t
-convtime(p, units)
- char *p;
- char units;
-{
- register time_t t, r;
- register char c;
-
- r = 0;
- while (*p != '\0')
- {
- t = 0;
- while ((c = *p++) != '\0' && isascii(c) && isdigit(c))
- t = t * 10 + (c - '0');
- if (c == '\0')
- {
- c = units;
- p--;
- }
- else if (strchr("wdhms", c) == NULL)
- {
- usrerr("Invalid time unit `%c'", c);
- c = units;
- }
- switch (c)
- {
- case 'w': /* weeks */
- t *= 7;
-
- case 'd': /* days */
- default:
- t *= 24;
-
- case 'h': /* hours */
- t *= 60;
-
- case 'm': /* minutes */
- t *= 60;
-
- case 's': /* seconds */
- break;
- }
- r += t;
- }
-
- return (r);
-}
- /*
-** PINTVL -- produce printable version of a time interval
-**
-** Parameters:
-** intvl -- the interval to be converted
-** brief -- if TRUE, print this in an extremely compact form
-** (basically used for logging).
-**
-** Returns:
-** A pointer to a string version of intvl suitable for
-** printing or framing.
-**
-** Side Effects:
-** none.
-**
-** Warning:
-** The string returned is in a static buffer.
-*/
-
-# define PLURAL(n) ((n) == 1 ? "" : "s")
-
-char *
-pintvl(intvl, brief)
- time_t intvl;
- bool brief;
-{
- static char buf[256];
- register char *p;
- int wk, dy, hr, mi, se;
-
- if (intvl == 0 && !brief)
- return ("zero seconds");
-
- /* decode the interval into weeks, days, hours, minutes, seconds */
- se = intvl % 60;
- intvl /= 60;
- mi = intvl % 60;
- intvl /= 60;
- hr = intvl % 24;
- intvl /= 24;
- if (brief)
- {
- dy = intvl;
- wk = 0;
- }
- else
- {
- dy = intvl % 7;
- intvl /= 7;
- wk = intvl;
- }
-
- /* now turn it into a sexy form */
- p = buf;
- if (brief)
- {
- if (dy > 0)
- {
- (void) snprintf(p, SPACELEFT(buf, p), "%d+", dy);
- p += strlen(p);
- }
- (void) snprintf(p, SPACELEFT(buf, p), "%02d:%02d:%02d",
- hr, mi, se);
- return (buf);
- }
-
- /* use the verbose form */
- if (wk > 0)
- {
- (void) snprintf(p, SPACELEFT(buf, p), ", %d week%s", wk, PLURAL(wk));
- p += strlen(p);
- }
- if (dy > 0)
- {
- (void) snprintf(p, SPACELEFT(buf, p), ", %d day%s", dy, PLURAL(dy));
- p += strlen(p);
- }
- if (hr > 0)
- {
- (void) snprintf(p, SPACELEFT(buf, p), ", %d hour%s", hr, PLURAL(hr));
- p += strlen(p);
- }
- if (mi > 0)
- {
- (void) snprintf(p, SPACELEFT(buf, p), ", %d minute%s", mi, PLURAL(mi));
- p += strlen(p);
- }
- if (se > 0)
- {
- (void) snprintf(p, SPACELEFT(buf, p), ", %d second%s", se, PLURAL(se));
- p += strlen(p);
- }
-
- return (buf + 2);
-}
diff --git a/src/daemon.c b/src/daemon.c
deleted file mode 100644
index ae6b004..0000000
--- a/src/daemon.c
+++ /dev/null
@@ -1,2154 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-#include <errno.h>
-#include "sendmail.h"
-
-#ifndef lint
-#ifdef DAEMON
-static char sccsid[] = "@(#)daemon.c 8.236 (Berkeley) 1/25/1999 (with daemon mode)";
-#else
-static char sccsid[] = "@(#)daemon.c 8.236 (Berkeley) 1/25/1999 (without daemon mode)";
-#endif
-#endif /* not lint */
-
-#if defined(SOCK_STREAM) || defined(__GNU_LIBRARY__)
-# define USE_SOCK_STREAM 1
-#endif
-
-#if DAEMON || defined(USE_SOCK_STREAM)
-# include <arpa/inet.h>
-# if NAMED_BIND
-# include <resolv.h>
-# ifndef NO_DATA
-# define NO_DATA NO_ADDRESS
-# endif
-# endif
-#endif
-
-#if DAEMON
-
-# include <sys/time.h>
-
-# if IP_SRCROUTE
-# include <netinet/in_systm.h>
-# include <netinet/ip.h>
-# include <netinet/ip_var.h>
-# endif
-
-/*
-** DAEMON.C -- routines to use when running as a daemon.
-**
-** This entire file is highly dependent on the 4.2 BSD
-** interprocess communication primitives. No attempt has
-** been made to make this file portable to Version 7,
-** Version 6, MPX files, etc. If you should try such a
-** thing yourself, I recommend chucking the entire file
-** and starting from scratch. Basic semantics are:
-**
-** getrequests(e)
-** Opens a port and initiates a connection.
-** Returns in a child. Must set InChannel and
-** OutChannel appropriately.
-** clrdaemon()
-** Close any open files associated with getting
-** the connection; this is used when running the queue,
-** etc., to avoid having extra file descriptors during
-** the queue run and to avoid confusing the network
-** code (if it cares).
-** makeconnection(host, port, outfile, infile, e)
-** Make a connection to the named host on the given
-** port. Set *outfile and *infile to the files
-** appropriate for communication. Returns zero on
-** success, else an exit status describing the
-** error.
-** host_map_lookup(map, hbuf, avp, pstat)
-** Convert the entry in hbuf into a canonical form.
-*/
- /*
-** GETREQUESTS -- open mail IPC port and get requests.
-**
-** Parameters:
-** e -- the current envelope.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Waits until some interesting activity occurs. When
-** it does, a child is created to process it, and the
-** parent waits for completion. Return from this
-** routine is always in the child. The file pointers
-** "InChannel" and "OutChannel" should be set to point
-** to the communication channel.
-*/
-
-int DaemonSocket = -1; /* fd describing socket */
-SOCKADDR DaemonAddr; /* socket for incoming */
-int ListenQueueSize = 10; /* size of listen queue */
-int TcpRcvBufferSize = 0; /* size of TCP receive buffer */
-int TcpSndBufferSize = 0; /* size of TCP send buffer */
-
-void
-getrequests(e)
- ENVELOPE *e;
-{
- int t;
- time_t refuse_connections_until = 0;
- bool firsttime = TRUE;
- FILE *pidf;
- int sff;
- int socksize;
- u_short port;
-#if XDEBUG
- bool j_has_dot;
-#endif
- char status[MAXLINE];
- extern void reapchild __P((int));
-#ifdef NETUNIX
- extern int ControlSocket;
-#endif
- extern int opendaemonsocket __P((bool));
- extern int opencontrolsocket __P((void));
-
- /*
- ** Set up the address for the mailer.
- */
-
- switch (DaemonAddr.sa.sa_family)
- {
- case AF_UNSPEC:
- DaemonAddr.sa.sa_family = AF_INET;
- /* fall through ... */
-
- case AF_INET:
- if (DaemonAddr.sin.sin_addr.s_addr == 0)
- DaemonAddr.sin.sin_addr.s_addr = INADDR_ANY;
- port = DaemonAddr.sin.sin_port;
- break;
-
- default:
- /* unknown protocol */
- port = 0;
- break;
- }
- if (port == 0)
- {
- register struct servent *sp;
-
- sp = getservbyname("smtp", "tcp");
- if (sp == NULL)
- {
- syserr("554 service \"smtp\" unknown");
- port = htons(25);
- }
- else
- port = sp->s_port;
- }
-
- switch (DaemonAddr.sa.sa_family)
- {
- case AF_INET:
- DaemonAddr.sin.sin_port = port;
- break;
-
- default:
- /* unknown protocol */
- break;
- }
-
- /*
- ** Try to actually open the connection.
- */
-
- if (tTd(15, 1))
- printf("getrequests: port 0x%x\n", port);
-
- /* get a socket for the SMTP connection */
- socksize = opendaemonsocket(TRUE);
-
- if (opencontrolsocket() < 0)
- sm_syslog(LOG_WARNING, NOQID,
- "daemon could not open control socket %s: %s",
- ControlSocketName, errstring(errno));
-
- (void) setsignal(SIGCHLD, reapchild);
-
- /* write the pid to the log file for posterity */
- sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT;
- if (TrustedUid != 0 && RealUid == TrustedUid)
- sff |= SFF_OPENASROOT;
- pidf = safefopen(PidFile, O_WRONLY|O_TRUNC, 0644, sff);
- if (pidf == NULL)
- {
- sm_syslog(LOG_ERR, NOQID, "unable to write %s", PidFile);
- }
- else
- {
- extern char *CommandLineArgs;
-
- /* write the process id on line 1 */
- fprintf(pidf, "%ld\n", (long) getpid());
-
- /* line 2 contains all command line flags */
- fprintf(pidf, "%s\n", CommandLineArgs);
-
- /* flush and close */
- fclose(pidf);
- }
-
-#if XDEBUG
- {
- char jbuf[MAXHOSTNAMELEN];
-
- expand("\201j", jbuf, sizeof jbuf, e);
- j_has_dot = strchr(jbuf, '.') != NULL;
- }
-#endif
-
- /* Add parent process as first item */
- proc_list_add(getpid(), "Sendmail daemon");
-
- if (tTd(15, 1))
- printf("getrequests: %d\n", DaemonSocket);
-
- for (;;)
- {
- register pid_t pid;
- auto SOCKADDR_LEN_T lotherend;
- bool timedout = FALSE;
- bool control = FALSE;
- int savederrno;
- int pipefd[2];
- extern bool refuseconnections __P((int));
-
- /* see if we are rejecting connections */
- (void) blocksignal(SIGALRM);
- if (curtime() >= refuse_connections_until)
- {
- if (refuseconnections(ntohs(port)))
- {
- if (DaemonSocket >= 0)
- {
- /* close socket so peer fails quickly */
- (void) close(DaemonSocket);
- DaemonSocket = -1;
- }
-
- /* refuse connections for next 15 seconds */
- refuse_connections_until = curtime() + 15;
- }
- else if (DaemonSocket < 0 || firsttime)
- {
- /* arrange to (re)open the socket if needed */
- (void) opendaemonsocket(FALSE);
- firsttime = FALSE;
- }
- }
-
-#if XDEBUG
- /* check for disaster */
- {
- char jbuf[MAXHOSTNAMELEN];
- extern void dumpstate __P((char *));
-
- expand("\201j", jbuf, sizeof jbuf, e);
- if (!wordinclass(jbuf, 'w'))
- {
- dumpstate("daemon lost $j");
- sm_syslog(LOG_ALERT, NOQID,
- "daemon process doesn't have $j in $=w; see syslog");
- abort();
- }
- else if (j_has_dot && strchr(jbuf, '.') == NULL)
- {
- dumpstate("daemon $j lost dot");
- sm_syslog(LOG_ALERT, NOQID,
- "daemon process $j lost dot; see syslog");
- abort();
- }
- }
-#endif
-
-#if 0
- /*
- ** Andrew Sun <asun@ieps-sun.ml.com> claims that this will
- ** fix the SVr4 problem. But it seems to have gone away,
- ** so is it worth doing this?
- */
-
- if (DaemonSocket >= 0 &&
- SetNonBlocking(DaemonSocket, FALSE) < 0)
- log an error here;
-#endif
- (void) releasesignal(SIGALRM);
- for (;;)
- {
- int highest = -1;
- fd_set readfds;
- struct timeval timeout;
-
- FD_ZERO(&readfds);
-
- /* wait for a connection */
- if (DaemonSocket >= 0)
- {
- sm_setproctitle(TRUE,
- "accepting connections on port %d",
- ntohs(port));
- if (DaemonSocket > highest)
- highest = DaemonSocket;
- FD_SET(DaemonSocket, &readfds);
- }
-#ifdef NETUNIX
- if (ControlSocket >= 0)
- {
- if (ControlSocket > highest)
- highest = ControlSocket;
- FD_SET(ControlSocket, &readfds);
- }
-#endif
- if (DaemonSocket >= 0)
- timeout.tv_sec = 60;
- else
- timeout.tv_sec = 5;
- timeout.tv_usec = 0;
-
- t = select(highest + 1, FDSET_CAST &readfds,
- NULL, NULL, &timeout);
-
- if (DoQueueRun)
- (void) runqueue(TRUE, FALSE);
- if (t <= 0)
- {
- timedout = TRUE;
- break;
- }
-
- control = FALSE;
- errno = 0;
- if (DaemonSocket >= 0 &&
- FD_ISSET(DaemonSocket, &readfds))
- {
- lotherend = socksize;
- t = accept(DaemonSocket,
- (struct sockaddr *)&RealHostAddr,
- &lotherend);
- }
-#ifdef NETUNIX
- else if (ControlSocket >= 0 &&
- FD_ISSET(ControlSocket, &readfds))
- {
- struct sockaddr_un sa_un;
-
- lotherend = sizeof sa_un;
- t = accept(ControlSocket,
- (struct sockaddr *)&sa_un,
- &lotherend);
- control = TRUE;
- }
-#endif
- if (t >= 0 || errno != EINTR)
- break;
- }
- if (timedout)
- {
- timedout = FALSE;
- continue;
- }
- if (control)
- {
- if (t >= 0)
- {
- extern void control_command __P((int, ENVELOPE *));
-
- control_command(t, e);
- }
- else
- syserr("getrequests: control accept");
- continue;
- }
- savederrno = errno;
- (void) blocksignal(SIGALRM);
- if (t < 0)
- {
- errno = savederrno;
- syserr("getrequests: accept");
-
- /* arrange to re-open the socket next time around */
- (void) close(DaemonSocket);
- DaemonSocket = -1;
- continue;
- }
-
- /*
- ** Create a subprocess to process the mail.
- */
-
- if (tTd(15, 2))
- printf("getrequests: forking (fd = %d)\n", t);
-
- /*
- ** Create a pipe to keep the child from writing to the
- ** socket until after the parent has closed it. Otherwise
- ** the parent may hang if the child has closed it first.
- */
-
- if (pipe(pipefd) < 0)
- pipefd[0] = pipefd[1] = -1;
-
- blocksignal(SIGCHLD);
- pid = fork();
- if (pid < 0)
- {
- syserr("daemon: cannot fork");
- if (pipefd[0] != -1)
- {
- (void) close(pipefd[0]);
- (void) close(pipefd[1]);
- }
- (void) releasesignal(SIGCHLD);
- sleep(10);
- (void) close(t);
- continue;
- }
-
- if (pid == 0)
- {
- char *p;
- extern SIGFUNC_DECL intsig __P((int));
- FILE *inchannel, *outchannel;
-
- /*
- ** CHILD -- return to caller.
- ** Collect verified idea of sending host.
- ** Verify calling user id if possible here.
- */
-
- (void) releasesignal(SIGALRM);
- (void) releasesignal(SIGCHLD);
- (void) setsignal(SIGCHLD, SIG_DFL);
- (void) setsignal(SIGHUP, intsig);
- (void) close(DaemonSocket);
- clrcontrol();
- proc_list_clear();
-
- /* Add parent process as first child item */
- proc_list_add(getpid(), "daemon child");
-
- /* don't schedule queue runs if we are told to ETRN */
- QueueIntvl = 0;
-
- sm_setproctitle(TRUE, "startup with %s",
- anynet_ntoa(&RealHostAddr));
-
- if (pipefd[0] != -1)
- {
- auto char c;
-
- /*
- ** Wait for the parent to close the write end
- ** of the pipe, which we will see as an EOF.
- ** This guarantees that we won't write to the
- ** socket until after the parent has closed
- ** the pipe.
- */
-
- /* close the write end of the pipe */
- (void) close(pipefd[1]);
-
- /* we shouldn't be interrupted, but ... */
- while (read(pipefd[0], &c, 1) < 0 &&
- errno == EINTR)
- continue;
- (void) close(pipefd[0]);
- }
-
- /* determine host name */
- p = hostnamebyanyaddr(&RealHostAddr);
- if (strlen(p) > (SIZE_T) MAXNAME)
- p[MAXNAME] = '\0';
- RealHostName = newstr(p);
- sm_setproctitle(TRUE, "startup with %s", p);
-
- if ((inchannel = fdopen(t, "r")) == NULL ||
- (t = dup(t)) < 0 ||
- (outchannel = fdopen(t, "w")) == NULL)
- {
- syserr("cannot open SMTP server channel, fd=%d", t);
- finis(FALSE, EX_OK);
- }
-
- InChannel = inchannel;
- OutChannel = outchannel;
- DisConnected = FALSE;
-
-#ifdef XLA
- if (!xla_host_ok(RealHostName))
- {
- message("421 Too many SMTP sessions for this host");
- finis(FALSE, EX_OK);
- }
-#endif
- break;
- }
-
- /* parent -- keep track of children */
- snprintf(status, sizeof status, "SMTP server child for %s",
- anynet_ntoa(&RealHostAddr));
- proc_list_add(pid, status);
- (void) releasesignal(SIGCHLD);
-
- /* close the read end of the synchronization pipe */
- if (pipefd[0] != -1)
- (void) close(pipefd[0]);
-
- /* close the port so that others will hang (for a while) */
- (void) close(t);
-
- /* release the child by closing the read end of the sync pipe */
- if (pipefd[1] != -1)
- (void) close(pipefd[1]);
- }
- if (tTd(15, 2))
- printf("getreq: returning\n");
- return;
-}
- /*
-** OPENDAEMONSOCKET -- open the SMTP socket
-**
-** Deals with setting all appropriate options. DaemonAddr must
-** be set up in advance.
-**
-** Parameters:
-** firsttime -- set if this is the initial open.
-**
-** Returns:
-** Size in bytes of the daemon socket addr.
-**
-** Side Effects:
-** Leaves DaemonSocket set to the open socket.
-** Exits if the socket cannot be created.
-*/
-
-#define MAXOPENTRIES 10 /* maximum number of tries to open connection */
-
-int
-opendaemonsocket(firsttime)
- bool firsttime;
-{
- int on = 1;
- int socksize = 0;
- int ntries = 0;
- int saveerrno;
-
- if (tTd(15, 2))
- printf("opendaemonsocket()\n");
-
- do
- {
- if (ntries > 0)
- sleep(5);
- if (firsttime || DaemonSocket < 0)
- {
- DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0);
- if (DaemonSocket < 0)
- {
- saveerrno = errno;
- syserr("opendaemonsocket: can't create server SMTP socket");
- severe:
- if (LogLevel > 0)
- sm_syslog(LOG_ALERT, NOQID,
- "problem creating SMTP socket");
- DaemonSocket = -1;
- continue;
- }
-
- /* turn on network debugging? */
- if (tTd(15, 101))
- (void) setsockopt(DaemonSocket, SOL_SOCKET,
- SO_DEBUG, (char *)&on,
- sizeof on);
-
- (void) setsockopt(DaemonSocket, SOL_SOCKET,
- SO_REUSEADDR, (char *)&on, sizeof on);
- (void) setsockopt(DaemonSocket, SOL_SOCKET,
- SO_KEEPALIVE, (char *)&on, sizeof on);
-
-#ifdef SO_RCVBUF
- if (TcpRcvBufferSize > 0)
- {
- if (setsockopt(DaemonSocket, SOL_SOCKET,
- SO_RCVBUF,
- (char *) &TcpRcvBufferSize,
- sizeof(TcpRcvBufferSize)) < 0)
- syserr("opendaemonsocket: setsockopt(SO_RCVBUF)");
- }
-#endif
-
- switch (DaemonAddr.sa.sa_family)
- {
-# if NETINET
- case AF_INET:
- socksize = sizeof DaemonAddr.sin;
- break;
-# endif
-
-# if NETISO
- case AF_ISO:
- socksize = sizeof DaemonAddr.siso;
- break;
-# endif
-
- default:
- socksize = sizeof DaemonAddr;
- break;
- }
-
- if (bind(DaemonSocket, &DaemonAddr.sa, socksize) < 0)
- {
- /* probably another daemon already */
- saveerrno = errno;
- syserr("opendaemonsocket: cannot bind");
- (void) close(DaemonSocket);
- goto severe;
- }
- }
- if (!firsttime && listen(DaemonSocket, ListenQueueSize) < 0)
- {
- saveerrno = errno;
- syserr("opendaemonsocket: cannot listen");
- (void) close(DaemonSocket);
- goto severe;
- }
- return socksize;
- } while (ntries++ < MAXOPENTRIES && transienterror(saveerrno));
- syserr("!opendaemonsocket: server SMTP socket wedged: exiting");
- /*NOTREACHED*/
- return -1; /* avoid compiler warning on IRIX */
-}
- /*
-** CLRDAEMON -- reset the daemon connection
-**
-** Parameters:
-** none.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** releases any resources used by the passive daemon.
-*/
-
-void
-clrdaemon()
-{
- if (DaemonSocket >= 0)
- (void) close(DaemonSocket);
- DaemonSocket = -1;
-}
- /*
-** SETDAEMONOPTIONS -- set options for running the daemon
-**
-** Parameters:
-** p -- the options line.
-**
-** Returns:
-** none.
-*/
-
-void
-setdaemonoptions(p)
- register char *p;
-{
- if (DaemonAddr.sa.sa_family == AF_UNSPEC)
- DaemonAddr.sa.sa_family = AF_INET;
-
- while (p != NULL)
- {
- register char *f;
- register char *v;
-
- while (isascii(*p) && isspace(*p))
- p++;
- if (*p == '\0')
- break;
- f = p;
- p = strchr(p, ',');
- if (p != NULL)
- *p++ = '\0';
- v = strchr(f, '=');
- if (v == NULL)
- continue;
- while (isascii(*++v) && isspace(*v))
- continue;
- if (isascii(*f) && islower(*f))
- *f = toupper(*f);
-
- switch (*f)
- {
- case 'F': /* address family */
- if (isascii(*v) && isdigit(*v))
- DaemonAddr.sa.sa_family = atoi(v);
-#if NETINET
- else if (strcasecmp(v, "inet") == 0)
- DaemonAddr.sa.sa_family = AF_INET;
-#endif
-#if NETISO
- else if (strcasecmp(v, "iso") == 0)
- DaemonAddr.sa.sa_family = AF_ISO;
-#endif
-#if NETNS
- else if (strcasecmp(v, "ns") == 0)
- DaemonAddr.sa.sa_family = AF_NS;
-#endif
-#if NETX25
- else if (strcasecmp(v, "x.25") == 0)
- DaemonAddr.sa.sa_family = AF_CCITT;
-#endif
- else
- syserr("554 Unknown address family %s in Family=option", v);
- break;
-
- case 'A': /* address */
- switch (DaemonAddr.sa.sa_family)
- {
-#if NETINET
- case AF_INET:
- if (isascii(*v) && isdigit(*v))
- DaemonAddr.sin.sin_addr.s_addr = inet_addr(v);
- else
- {
- register struct hostent *hp;
-
- hp = sm_gethostbyname(v);
- if (hp == NULL)
- syserr("554 host \"%s\" unknown", v);
- else
- bcopy(hp->h_addr, &DaemonAddr.sin.sin_addr, INADDRSZ);
- }
- break;
-#endif
-
- default:
- syserr("554 Address= option unsupported for family %d",
- DaemonAddr.sa.sa_family);
- break;
- }
- break;
-
- case 'P': /* port */
- switch (DaemonAddr.sa.sa_family)
- {
-#if NETISO
- short port;
-#endif
-
-#if NETINET
- case AF_INET:
- if (isascii(*v) && isdigit(*v))
- DaemonAddr.sin.sin_port = htons(atoi(v));
- else
- {
- register struct servent *sp;
-
- sp = getservbyname(v, "tcp");
- if (sp == NULL)
- syserr("554 service \"%s\" unknown", v);
- else
- DaemonAddr.sin.sin_port = sp->s_port;
- }
- break;
-#endif
-
-#if NETISO
- case AF_ISO:
- /* assume two byte transport selector */
- if (isascii(*v) && isdigit(*v))
- port = htons(atoi(v));
- else
- {
- register struct servent *sp;
-
- sp = getservbyname(v, "tcp");
- if (sp == NULL)
- syserr("554 service \"%s\" unknown", v);
- else
- port = sp->s_port;
- }
- bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2);
- break;
-#endif
-
- default:
- syserr("554 Port= option unsupported for family %d",
- DaemonAddr.sa.sa_family);
- break;
- }
- break;
-
- case 'L': /* listen queue size */
- ListenQueueSize = atoi(v);
- break;
-
- case 'S': /* send buffer size */
- TcpSndBufferSize = atoi(v);
- break;
-
- case 'R': /* receive buffer size */
- TcpRcvBufferSize = atoi(v);
- break;
-
- default:
- syserr("554 DaemonPortOptions parameter \"%s\" unknown", f);
- }
- }
-}
- /*
-** MAKECONNECTION -- make a connection to an SMTP socket on another machine.
-**
-** Parameters:
-** host -- the name of the host.
-** port -- the port number to connect to.
-** mci -- a pointer to the mail connection information
-** structure to be filled in.
-** e -- the current envelope.
-**
-** Returns:
-** An exit code telling whether the connection could be
-** made and if not why not.
-**
-** Side Effects:
-** none.
-*/
-
-static jmp_buf CtxConnectTimeout;
-
-static void
-connecttimeout()
-{
- errno = ETIMEDOUT;
- longjmp(CtxConnectTimeout, 1);
-}
-
-SOCKADDR CurHostAddr; /* address of current host */
-
-int
-makeconnection(host, port, mci, e)
- char *host;
- u_short port;
- register MCI *mci;
- ENVELOPE *e;
-{
- register volatile int addrno = 0;
- register volatile int s;
- register struct hostent *volatile hp = (struct hostent *)NULL;
- SOCKADDR addr;
- int sav_errno;
- volatile int addrlen;
- volatile bool firstconnect;
- EVENT *volatile ev = NULL;
-
- /*
- ** Set up the address for the mailer.
- ** Accept "[a.b.c.d]" syntax for host name.
- */
-
-#if NAMED_BIND
- h_errno = 0;
-#endif
- errno = 0;
- bzero(&CurHostAddr, sizeof CurHostAddr);
- SmtpPhase = mci->mci_phase = "initial connection";
- CurHostName = host;
-
- if (host[0] == '[')
- {
-#if NETINET
- unsigned long hid = INADDR_NONE;
-#endif
- register char *p = strchr(host, ']');
-
- if (p != NULL)
- {
- *p = '\0';
-#if NETINET
- hid = inet_addr(&host[1]);
- if (hid == INADDR_NONE)
-#endif
- {
- /* try it as a host name (avoid MX lookup) */
- hp = sm_gethostbyname(&host[1]);
- if (hp == NULL && p[-1] == '.')
- {
-#if NAMED_BIND
- int oldopts = _res.options;
-
- _res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
-#endif
- p[-1] = '\0';
- hp = sm_gethostbyname(&host[1]);
- p[-1] = '.';
-#if NAMED_BIND
- _res.options = oldopts;
-#endif
- }
- *p = ']';
- goto gothostent;
- }
- *p = ']';
- }
- if (p == NULL)
- {
- extern char MsgBuf[];
-
- usrerr("553 Invalid numeric domain spec \"%s\"", host);
- mci_setstat(mci, EX_NOHOST, "5.1.2", MsgBuf);
- return EX_NOHOST;
- }
-#if NETINET
- addr.sin.sin_family = AF_INET; /*XXX*/
- addr.sin.sin_addr.s_addr = hid;
-#endif
- }
- else
- {
- /* contortion to get around SGI cc complaints */
- {
- register char *p = &host[strlen(host) - 1];
-
- hp = sm_gethostbyname(host);
- if (hp == NULL && *p == '.')
- {
-#if NAMED_BIND
- int oldopts = _res.options;
-
- _res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
-#endif
- *p = '\0';
- hp = sm_gethostbyname(host);
- *p = '.';
-#if NAMED_BIND
- _res.options = oldopts;
-#endif
- }
- }
-gothostent:
- if (hp == NULL)
- {
-#if NAMED_BIND
- /* check for name server timeouts */
- if (errno == ETIMEDOUT || h_errno == TRY_AGAIN ||
- (errno == ECONNREFUSED && UseNameServer))
- {
- mci_setstat(mci, EX_TEMPFAIL, "4.4.3", NULL);
- return EX_TEMPFAIL;
- }
-#endif
- mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
- return (EX_NOHOST);
- }
- addr.sa.sa_family = hp->h_addrtype;
- switch (hp->h_addrtype)
- {
-#if NETINET
- case AF_INET:
- bcopy(hp->h_addr,
- &addr.sin.sin_addr,
- INADDRSZ);
- break;
-#endif
-
- default:
- if (hp->h_length > sizeof addr.sa.sa_data)
- {
- syserr("makeconnection: long sa_data: family %d len %d",
- hp->h_addrtype, hp->h_length);
- mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
- return EX_NOHOST;
- }
- bcopy(hp->h_addr,
- addr.sa.sa_data,
- hp->h_length);
- break;
- }
- addrno = 1;
- }
-
- /*
- ** Determine the port number.
- */
-
- if (port == 0)
- {
- register struct servent *sp = getservbyname("smtp", "tcp");
-
- if (sp == NULL)
- {
- if (LogLevel > 2)
- sm_syslog(LOG_ERR, NOQID,
- "makeconnection: service \"smtp\" unknown");
- port = htons(25);
- }
- else
- port = sp->s_port;
- }
-
- switch (addr.sa.sa_family)
- {
-#if NETINET
- case AF_INET:
- addr.sin.sin_port = port;
- addrlen = sizeof (struct sockaddr_in);
- break;
-#endif
-
-#if NETISO
- case AF_ISO:
- /* assume two byte transport selector */
- bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2);
- addrlen = sizeof (struct sockaddr_iso);
- break;
-#endif
-
- default:
- syserr("Can't connect to address family %d", addr.sa.sa_family);
- mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
- return (EX_NOHOST);
- }
-
- /*
- ** Try to actually open the connection.
- */
-
-#ifdef XLA
- /* if too many connections, don't bother trying */
- if (!xla_noqueue_ok(host))
- return EX_TEMPFAIL;
-#endif
-
- firstconnect = TRUE;
- for (;;)
- {
- if (tTd(16, 1))
- printf("makeconnection (%s [%s])\n",
- host, anynet_ntoa(&addr));
-
- /* save for logging */
- CurHostAddr = addr;
-
- if (bitnset(M_SECURE_PORT, mci->mci_mailer->m_flags))
- {
- int rport = IPPORT_RESERVED - 1;
-
- s = rresvport(&rport);
- }
- else
- {
- s = socket(addr.sa.sa_family, SOCK_STREAM, 0);
- }
- if (s < 0)
- {
- sav_errno = errno;
- syserr("makeconnection: cannot create socket");
-#ifdef XLA
- xla_host_end(host);
-#endif
- mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
- return EX_TEMPFAIL;
- }
-
-#ifdef SO_SNDBUF
- if (TcpSndBufferSize > 0)
- {
- if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
- (char *) &TcpSndBufferSize,
- sizeof(TcpSndBufferSize)) < 0)
- syserr("makeconnection: setsockopt(SO_SNDBUF)");
- }
-#endif
-
- if (tTd(16, 1))
- printf("makeconnection: fd=%d\n", s);
-
- /* turn on network debugging? */
- if (tTd(16, 101))
- {
- int on = 1;
- (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
- (char *)&on, sizeof on);
- }
- if (e->e_xfp != NULL)
- (void) fflush(e->e_xfp); /* for debugging */
- errno = 0; /* for debugging */
-
- /*
- ** Linux seems to hang in connect for 90 minutes (!!!).
- ** Time out the connect to avoid this problem.
- */
-
- if (setjmp(CtxConnectTimeout) == 0)
- {
- int i;
-
- if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0)
- ev = setevent(TimeOuts.to_iconnect, connecttimeout, 0);
- else if (TimeOuts.to_connect != 0)
- ev = setevent(TimeOuts.to_connect, connecttimeout, 0);
- else
- ev = NULL;
-
-#if _FFR_CONNECTONLYTO_OPTION
- /* for testing */
- if (ConnectOnlyTo != 0)
- addr.sin.sin_addr.s_addr = ConnectOnlyTo;
-#endif
- i = connect(s, (struct sockaddr *) &addr, addrlen);
- sav_errno = errno;
- if (ev != NULL)
- clrevent(ev);
- if (i >= 0)
- break;
- }
- else
- sav_errno = errno;
-
- /* if running demand-dialed connection, try again */
- if (DialDelay > 0 && firstconnect)
- {
- if (tTd(16, 1))
- printf("Connect failed (%s); trying again...\n",
- errstring(sav_errno));
- firstconnect = FALSE;
- sleep(DialDelay);
- continue;
- }
-
- /* couldn't connect.... figure out why */
- (void) close(s);
-
- if (LogLevel >= 14)
- sm_syslog(LOG_INFO, e->e_id,
- "makeconnection (%s [%s]) failed: %s",
- host, anynet_ntoa(&addr),
- errstring(sav_errno));
-
- if (hp != NULL && hp->h_addr_list[addrno] != NULL)
- {
- if (tTd(16, 1))
- printf("Connect failed (%s); trying new address....\n",
- errstring(sav_errno));
- switch (addr.sa.sa_family)
- {
-#if NETINET
- case AF_INET:
- bcopy(hp->h_addr_list[addrno++],
- &addr.sin.sin_addr,
- INADDRSZ);
- break;
-#endif
-
- default:
- bcopy(hp->h_addr_list[addrno++],
- addr.sa.sa_data,
- hp->h_length);
- break;
- }
- continue;
- }
-
- /* couldn't open connection */
-#ifdef XLA
- xla_host_end(host);
-#endif
- mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL);
- return EX_TEMPFAIL;
- }
-
- /* connection ok, put it into canonical form */
- if ((mci->mci_out = fdopen(s, "w")) == NULL ||
- (s = dup(s)) < 0 ||
- (mci->mci_in = fdopen(s, "r")) == NULL)
- {
- syserr("cannot open SMTP client channel, fd=%d", s);
- mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
- return EX_TEMPFAIL;
- }
-
- mci_setstat(mci, EX_OK, NULL, NULL);
- return (EX_OK);
-}
- /*
-** MYHOSTNAME -- return the name of this host.
-**
-** Parameters:
-** hostbuf -- a place to return the name of this host.
-** size -- the size of hostbuf.
-**
-** Returns:
-** A list of aliases for this host.
-**
-** Side Effects:
-** Adds numeric codes to $=w.
-*/
-
-struct hostent *
-myhostname(hostbuf, size)
- char hostbuf[];
- int size;
-{
- register struct hostent *hp;
-
- if (gethostname(hostbuf, size) < 0)
- {
- (void) strcpy(hostbuf, "localhost");
- }
- hp = sm_gethostbyname(hostbuf);
- if (hp == NULL)
- return NULL;
- if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL)
- {
- (void) strncpy(hostbuf, hp->h_name, size - 1);
- hostbuf[size - 1] = '\0';
- }
-
- /*
- ** If there is still no dot in the name, try looking for a
- ** dotted alias.
- */
-
- if (strchr(hostbuf, '.') == NULL)
- {
- char **ha;
-
- for (ha = hp->h_aliases; *ha != NULL; ha++)
- {
- if (strchr(*ha, '.') != NULL)
- {
- (void) strncpy(hostbuf, *ha, size - 1);
- hostbuf[size - 1] = '\0';
- break;
- }
- }
- }
-
- /*
- ** If _still_ no dot, wait for a while and try again -- it is
- ** possible that some service is starting up. This can result
- ** in excessive delays if the system is badly configured, but
- ** there really isn't a way around that, particularly given that
- ** the config file hasn't been read at this point.
- ** All in all, a bit of a mess.
- */
-
- if (strchr(hostbuf, '.') == NULL &&
- !getcanonname(hostbuf, size, TRUE))
- {
- sm_syslog(LOG_CRIT, NOQID,
- "My unqualified host name (%s) unknown; sleeping for retry",
- hostbuf);
- message("My unqualified host name (%s) unknown; sleeping for retry",
- hostbuf);
- sleep(60);
- if (!getcanonname(hostbuf, size, TRUE))
- {
- sm_syslog(LOG_ALERT, NOQID,
- "unable to qualify my own domain name (%s) -- using short name",
- hostbuf);
- message("WARNING: unable to qualify my own domain name (%s) -- using short name",
- hostbuf);
- }
- }
- return (hp);
-}
- /*
-** ADDRCMP -- compare two host addresses
-**
-** Parameters:
-** hp -- hostent structure for the first address
-** ha -- actual first address
-** sa -- second address
-**
-** Returns:
-** 0 -- if ha and sa match
-** else -- they don't match
-*/
-
-int
-addrcmp(hp, ha, sa)
- struct hostent *hp;
- char *ha;
- SOCKADDR *sa;
-{
- switch (sa->sa.sa_family)
- {
- case AF_INET:
- if (hp->h_addrtype == AF_INET)
- return bcmp(ha, (char *) &sa->sin.sin_addr, hp->h_length);
- break;
-
- }
- return -1;
-}
- /*
-** GETAUTHINFO -- get the real host name asociated with a file descriptor
-**
-** Uses RFC1413 protocol to try to get info from the other end.
-**
-** Parameters:
-** fd -- the descriptor
-** may_be_forged -- an outage that is set to TRUE if the
-** forward lookup of RealHostName does not match
-** RealHostAddr; set to FALSE if they do match.
-**
-** Returns:
-** The user@host information associated with this descriptor.
-*/
-
-static jmp_buf CtxAuthTimeout;
-
-static void
-authtimeout()
-{
- longjmp(CtxAuthTimeout, 1);
-}
-
-char *
-getauthinfo(fd, may_be_forged)
- int fd;
- bool *may_be_forged;
-{
- SOCKADDR_LEN_T falen;
- register char *volatile p = NULL;
- SOCKADDR la;
- SOCKADDR_LEN_T lalen;
- register struct servent *sp;
- volatile int s;
- int i = 0;
- EVENT *ev;
- int nleft;
- struct hostent *hp;
- char *ostype = NULL;
- char **ha;
- char ibuf[MAXNAME + 1];
- static char hbuf[MAXNAME * 2 + 11];
-
- *may_be_forged = FALSE;
- falen = sizeof RealHostAddr;
- if (isatty(fd) || (i = getpeername(fd, &RealHostAddr.sa, &falen)) < 0 ||
- falen <= 0 || RealHostAddr.sa.sa_family == 0)
- {
- if (i < 0 && errno != ENOTSOCK)
- return NULL;
- (void) snprintf(hbuf, sizeof hbuf, "%s@localhost",
- RealUserName);
- if (tTd(9, 1))
- printf("getauthinfo: %s\n", hbuf);
- return hbuf;
- }
-
- if (RealHostName == NULL)
- {
- /* translate that to a host name */
- RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr));
- if (strlen(RealHostName) > MAXNAME)
- RealHostName[MAXNAME] = '\0';
- }
-
- /* cross check RealHostName with forward DNS lookup */
- if (anynet_ntoa(&RealHostAddr)[0] == '[' ||
- RealHostName[0] == '[')
- {
- /*
- ** address is not a socket or have an
- ** IP address with no forward lookup
- */
- *may_be_forged = FALSE;
- }
- else
- {
- /* try to match the reverse against the forward lookup */
- hp = sm_gethostbyname(RealHostName);
-
- if (hp == NULL)
- *may_be_forged = TRUE;
- else
- {
- for (ha = hp->h_addr_list; *ha != NULL; ha++)
- if (addrcmp(hp, *ha, &RealHostAddr) == 0)
- break;
- *may_be_forged = *ha == NULL;
- }
- }
-
- if (TimeOuts.to_ident == 0)
- goto noident;
-
- lalen = sizeof la;
- if (RealHostAddr.sa.sa_family != AF_INET ||
- getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 ||
- la.sa.sa_family != AF_INET)
- {
- /* no ident info */
- goto noident;
- }
-
- /* create ident query */
- (void) snprintf(ibuf, sizeof ibuf, "%d,%d\r\n",
- ntohs(RealHostAddr.sin.sin_port), ntohs(la.sin.sin_port));
-
- /* create local address */
- la.sin.sin_port = 0;
-
- /* create foreign address */
- sp = getservbyname("auth", "tcp");
- if (sp != NULL)
- RealHostAddr.sin.sin_port = sp->s_port;
- else
- RealHostAddr.sin.sin_port = htons(113);
-
- s = -1;
- if (setjmp(CtxAuthTimeout) != 0)
- {
- if (s >= 0)
- (void) close(s);
- goto noident;
- }
-
- /* put a timeout around the whole thing */
- ev = setevent(TimeOuts.to_ident, authtimeout, 0);
-
- /* connect to foreign IDENT server using same address as SMTP socket */
- s = socket(AF_INET, SOCK_STREAM, 0);
- if (s < 0)
- {
- clrevent(ev);
- goto noident;
- }
- if (bind(s, &la.sa, sizeof la.sin) < 0 ||
- connect(s, &RealHostAddr.sa, sizeof RealHostAddr.sin) < 0)
- {
- goto closeident;
- }
-
- if (tTd(9, 10))
- printf("getauthinfo: sent %s", ibuf);
-
- /* send query */
- if (write(s, ibuf, strlen(ibuf)) < 0)
- goto closeident;
-
- /* get result */
- p = &ibuf[0];
- nleft = sizeof ibuf - 1;
- while ((i = read(s, p, nleft)) > 0)
- {
- p += i;
- nleft -= i;
- *p = '\0';
- if (strchr(ibuf, '\n') != NULL)
- break;
- }
- (void) close(s);
- clrevent(ev);
- if (i < 0 || p == &ibuf[0])
- goto noident;
-
- if (*--p == '\n' && *--p == '\r')
- p--;
- *++p = '\0';
-
- if (tTd(9, 3))
- printf("getauthinfo: got %s\n", ibuf);
-
- /* parse result */
- p = strchr(ibuf, ':');
- if (p == NULL)
- {
- /* malformed response */
- goto noident;
- }
- while (isascii(*++p) && isspace(*p))
- continue;
- if (strncasecmp(p, "userid", 6) != 0)
- {
- /* presumably an error string */
- goto noident;
- }
- p += 6;
- while (isascii(*p) && isspace(*p))
- p++;
- if (*p++ != ':')
- {
- /* either useridxx or malformed response */
- goto noident;
- }
-
- /* p now points to the OSTYPE field */
- while (isascii(*p) && isspace(*p))
- p++;
- ostype = p;
- p = strchr(p, ':');
- if (p == NULL)
- {
- /* malformed response */
- goto noident;
- }
- else
- {
- char *charset;
-
- *p = '\0';
- charset = strchr(ostype, ',');
- if (charset != NULL)
- *charset = '\0';
- }
-
- /* 1413 says don't do this -- but it's broken otherwise */
- while (isascii(*++p) && isspace(*p))
- continue;
-
- /* p now points to the authenticated name -- copy carefully */
- if (strncasecmp(ostype, "other", 5) == 0 &&
- (ostype[5] == ' ' || ostype[5] == '\0'))
- {
- snprintf(hbuf, sizeof hbuf, "IDENT:");
- cleanstrcpy(&hbuf[6], p, MAXNAME);
- }
- else
- cleanstrcpy(hbuf, p, MAXNAME);
- i = strlen(hbuf);
- snprintf(&hbuf[i], sizeof hbuf - i, "@%s",
- RealHostName == NULL ? "localhost" : RealHostName);
- goto postident;
-
-closeident:
- (void) close(s);
- clrevent(ev);
-
-noident:
- if (RealHostName == NULL)
- {
- if (tTd(9, 1))
- printf("getauthinfo: NULL\n");
- return NULL;
- }
- snprintf(hbuf, sizeof hbuf, "%s", RealHostName);
-
-postident:
-#if IP_SRCROUTE
-# ifndef GET_IPOPT_DST
-# define GET_IPOPT_DST(dst) (dst)
-# endif
- /*
- ** Extract IP source routing information.
- **
- ** Format of output for a connection from site a through b
- ** through c to d:
- ** loose: @site-c@site-b:site-a
- ** strict: !@site-c@site-b:site-a
- **
- ** o - pointer within ipopt_list structure.
- ** q - pointer within ls/ss rr route data
- ** p - pointer to hbuf
- */
-
- if (RealHostAddr.sa.sa_family == AF_INET)
- {
- SOCKOPT_LEN_T ipoptlen;
- int j;
- u_char *q;
- u_char *o;
- int l;
- struct in_addr addr;
- struct ipoption ipopt;
-
- ipoptlen = sizeof ipopt;
- if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS,
- (char *) &ipopt, &ipoptlen) < 0)
- goto noipsr;
- if (ipoptlen == 0)
- goto noipsr;
- o = (u_char *) ipopt.ipopt_list;
- while (o != NULL && o < (u_char *) &ipopt + ipoptlen)
- {
- switch (*o)
- {
- case IPOPT_EOL:
- o = NULL;
- break;
-
- case IPOPT_NOP:
- o++;
- break;
-
- case IPOPT_SSRR:
- case IPOPT_LSRR:
- /*
- ** Source routing.
- ** o[0] is the option type (loose/strict).
- ** o[1] is the length of this option,
- ** including option type and
- ** length.
- ** o[2] is the pointer into the route
- ** data.
- ** o[3] begins the route data.
- */
-
- p = &hbuf[strlen(hbuf)];
- l = sizeof hbuf - (hbuf - p) - 6;
- snprintf(p, SPACELEFT(hbuf, p), " [%s@%.*s",
- *o == IPOPT_SSRR ? "!" : "",
- l > 240 ? 120 : l / 2,
- inet_ntoa(GET_IPOPT_DST(ipopt.ipopt_dst)));
- i = strlen(p);
- p += i;
- l -= strlen(p);
-
- j = o[1] / sizeof(struct in_addr) - 1;
-
- /* q skips length and router pointer to data */
- q = &o[3];
- for ( ; j >= 0; j--)
- {
- memcpy(&addr, q, sizeof(addr));
- snprintf(p, SPACELEFT(hbuf, p),
- "%c%.*s",
- j != 0 ? '@' : ':',
- l > 240 ? 120 :
- j == 0 ? l : l / 2,
- inet_ntoa(addr));
- i = strlen(p);
- p += i;
- l -= i + 1;
- q += sizeof(struct in_addr);
- }
- o += o[1];
- break;
-
- default:
- /* Skip over option */
- o += o[1];
- break;
- }
- }
- snprintf(p, SPACELEFT(hbuf, p), "]");
- goto postipsr;
- }
-
-noipsr:
-#endif
- if (RealHostName != NULL && RealHostName[0] != '[')
- {
- p = &hbuf[strlen(hbuf)];
- (void) snprintf(p, SPACELEFT(hbuf, p), " [%.100s]",
- anynet_ntoa(&RealHostAddr));
- }
- if (*may_be_forged)
- {
- p = &hbuf[strlen(hbuf)];
- (void) snprintf(p, SPACELEFT(hbuf, p), " (may be forged)");
- }
-
-#if IP_SRCROUTE
-postipsr:
-#endif
- if (tTd(9, 1))
- printf("getauthinfo: %s\n", hbuf);
- return hbuf;
-}
- /*
-** HOST_MAP_LOOKUP -- turn a hostname into canonical form
-**
-** Parameters:
-** map -- a pointer to this map.
-** name -- the (presumably unqualified) hostname.
-** av -- unused -- for compatibility with other mapping
-** functions.
-** statp -- an exit status (out parameter) -- set to
-** EX_TEMPFAIL if the name server is unavailable.
-**
-** Returns:
-** The mapping, if found.
-** NULL if no mapping found.
-**
-** Side Effects:
-** Looks up the host specified in hbuf. If it is not
-** the canonical name for that host, return the canonical
-** name (unless MF_MATCHONLY is set, which will cause the
-** status only to be returned).
-*/
-
-char *
-host_map_lookup(map, name, av, statp)
- MAP *map;
- char *name;
- char **av;
- int *statp;
-{
- register struct hostent *hp;
- struct in_addr in_addr;
- char *cp;
- register STAB *s;
- char hbuf[MAXNAME + 1];
-
- /*
- ** See if we have already looked up this name. If so, just
- ** return it.
- */
-
- s = stab(name, ST_NAMECANON, ST_ENTER);
- if (bitset(NCF_VALID, s->s_namecanon.nc_flags))
- {
- if (tTd(9, 1))
- printf("host_map_lookup(%s) => CACHE %s\n",
- name,
- s->s_namecanon.nc_cname == NULL
- ? "NULL"
- : s->s_namecanon.nc_cname);
- errno = s->s_namecanon.nc_errno;
-#if NAMED_BIND
- h_errno = s->s_namecanon.nc_herrno;
-#endif
- *statp = s->s_namecanon.nc_stat;
- if (*statp == EX_TEMPFAIL)
- {
- CurEnv->e_status = "4.4.3";
- message("851 %s: Name server timeout",
- shortenstring(name, 33));
- }
- if (*statp != EX_OK)
- return NULL;
- if (s->s_namecanon.nc_cname == NULL)
- {
- syserr("host_map_lookup(%s): bogus NULL cache entry, errno = %d, h_errno = %d",
- name,
- s->s_namecanon.nc_errno,
- s->s_namecanon.nc_herrno);
- return NULL;
- }
- if (bitset(MF_MATCHONLY, map->map_mflags))
- cp = map_rewrite(map, name, strlen(name), NULL);
- else
- cp = map_rewrite(map,
- s->s_namecanon.nc_cname,
- strlen(s->s_namecanon.nc_cname),
- av);
- return cp;
- }
-
- /*
- ** If we are running without a regular network connection (usually
- ** dial-on-demand) and we are just queueing, we want to avoid DNS
- ** lookups because those could try to connect to a server.
- */
-
- if (CurEnv->e_sendmode == SM_DEFER)
- {
- if (tTd(9, 1))
- printf("host_map_lookup(%s) => DEFERRED\n", name);
- *statp = EX_TEMPFAIL;
- return NULL;
- }
-
- /*
- ** If first character is a bracket, then it is an address
- ** lookup. Address is copied into a temporary buffer to
- ** strip the brackets and to preserve name if address is
- ** unknown.
- */
-
- if (*name != '[')
- {
- if (tTd(9, 1))
- printf("host_map_lookup(%s) => ", name);
- s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */
- snprintf(hbuf, sizeof hbuf, "%s", name);
- if (getcanonname(hbuf, sizeof hbuf - 1, !HasWildcardMX))
- {
- if (tTd(9, 1))
- printf("%s\n", hbuf);
- s->s_namecanon.nc_stat = EX_OK;
- s->s_namecanon.nc_cname = newstr(hbuf);
- if (bitset(MF_MATCHONLY, map->map_mflags))
- cp = map_rewrite(map, name, strlen(name), NULL);
- else
- cp = map_rewrite(map, hbuf, strlen(hbuf), av);
- return cp;
- }
- else
- {
- s->s_namecanon.nc_errno = errno;
-#if NAMED_BIND
- s->s_namecanon.nc_herrno = h_errno;
- if (tTd(9, 1))
- printf("FAIL (%d)\n", h_errno);
- switch (h_errno)
- {
- case TRY_AGAIN:
- if (UseNameServer)
- {
- CurEnv->e_status = "4.4.3";
- message("851 %s: Name server timeout",
- shortenstring(name, 33));
- }
- *statp = EX_TEMPFAIL;
- break;
-
- case HOST_NOT_FOUND:
- case NO_DATA:
- *statp = EX_NOHOST;
- break;
-
- case NO_RECOVERY:
- *statp = EX_SOFTWARE;
- break;
-
- default:
- *statp = EX_UNAVAILABLE;
- break;
- }
-#else
- if (tTd(9, 1))
- printf("FAIL\n");
- *statp = EX_NOHOST;
-#endif
- s->s_namecanon.nc_stat = *statp;
- return NULL;
- }
- }
- if ((cp = strchr(name, ']')) == NULL)
- return (NULL);
- *cp = '\0';
- in_addr.s_addr = inet_addr(&name[1]);
- *cp = ']';
-
- /* nope -- ask the name server */
- hp = sm_gethostbyaddr((char *)&in_addr, INADDRSZ, AF_INET);
- s->s_namecanon.nc_errno = errno;
-#if NAMED_BIND
- s->s_namecanon.nc_herrno = h_errno;
-#endif
- s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */
- if (hp == NULL)
- {
- s->s_namecanon.nc_stat = *statp = EX_NOHOST;
- return (NULL);
- }
-
- /* found a match -- copy out */
- hp->h_name = denlstring((char *) hp->h_name, TRUE, TRUE);
- s->s_namecanon.nc_stat = *statp = EX_OK;
- s->s_namecanon.nc_cname = newstr(hp->h_name);
- if (bitset(MF_MATCHONLY, map->map_mflags))
- cp = map_rewrite(map, name, strlen(name), NULL);
- else
- cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av);
- return cp;
-}
-
-# else /* DAEMON */
-/* code for systems without sophisticated networking */
-
-/*
-** MYHOSTNAME -- stub version for case of no daemon code.
-**
-** Can't convert to upper case here because might be a UUCP name.
-**
-** Mark, you can change this to be anything you want......
-*/
-
-char **
-myhostname(hostbuf, size)
- char hostbuf[];
- int size;
-{
- register FILE *f;
-
- hostbuf[0] = '\0';
- f = fopen("/usr/include/whoami", "r");
- if (f != NULL)
- {
- (void) fgets(hostbuf, size, f);
- fixcrlf(hostbuf, TRUE);
- (void) fclose(f);
- }
- return (NULL);
-}
- /*
-** GETAUTHINFO -- get the real host name asociated with a file descriptor
-**
-** Parameters:
-** fd -- the descriptor
-** may_be_forged -- an outage that is set to TRUE if the
-** forward lookup of RealHostName does not match
-** RealHostAddr; set to FALSE if they do match.
-**
-** Returns:
-** The host name associated with this descriptor, if it can
-** be determined.
-** NULL otherwise.
-**
-** Side Effects:
-** none
-*/
-
-char *
-getauthinfo(fd, may_be_forged)
- int fd;
- bool *may_be_forged;
-{
- *may_be_forged = FALSE;
- return NULL;
-}
- /*
-** MAPHOSTNAME -- turn a hostname into canonical form
-**
-** Parameters:
-** map -- a pointer to the database map.
-** name -- a buffer containing a hostname.
-** avp -- a pointer to a (cf file defined) argument vector.
-** statp -- an exit status (out parameter).
-**
-** Returns:
-** mapped host name
-** FALSE otherwise.
-**
-** Side Effects:
-** Looks up the host specified in name. If it is not
-** the canonical name for that host, replace it with
-** the canonical name. If the name is unknown, or it
-** is already the canonical name, leave it unchanged.
-*/
-
-/*ARGSUSED*/
-char *
-host_map_lookup(map, name, avp, statp)
- MAP *map;
- char *name;
- char **avp;
- char *statp;
-{
- register struct hostent *hp;
- char *cp;
-
- hp = sm_gethostbyname(name);
- if (hp == NULL)
- {
- *statp = EX_NOHOST;
- return NULL;
- }
- if (bitset(MF_MATCHONLY, map->map_mflags))
- cp = map_rewrite(map, name, strlen(name), NULL);
- else
- cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), avp);
- return cp;
-}
-
-#endif /* DAEMON */
- /*
-** HOST_MAP_INIT -- initialize host class structures
-*/
-
-bool
-host_map_init(map, args)
- MAP *map;
- char *args;
-{
- register char *p = args;
-
- for (;;)
- {
- while (isascii(*p) && isspace(*p))
- p++;
- if (*p != '-')
- break;
- switch (*++p)
- {
- case 'a':
- map->map_app = ++p;
- break;
-
- case 'T':
- map->map_tapp = ++p;
- break;
-
- case 'm':
- map->map_mflags |= MF_MATCHONLY;
- break;
-
- case 't':
- map->map_mflags |= MF_NODEFER;
- break;
- }
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
- p++;
- if (*p != '\0')
- *p++ = '\0';
- }
- if (map->map_app != NULL)
- map->map_app = newstr(map->map_app);
- if (map->map_tapp != NULL)
- map->map_tapp = newstr(map->map_tapp);
- return TRUE;
-}
- /*
-** ANYNET_NTOA -- convert a network address to printable form.
-**
-** Parameters:
-** sap -- a pointer to a sockaddr structure.
-**
-** Returns:
-** A printable version of that sockaddr.
-*/
-
-#ifdef USE_SOCK_STREAM
-
-#if NETLINK
-# include <net/if_dl.h>
-#endif
-
-char *
-anynet_ntoa(sap)
- register SOCKADDR *sap;
-{
- register char *bp;
- register char *ap;
- int l;
- static char buf[100];
-
- /* check for null/zero family */
- if (sap == NULL)
- return "NULLADDR";
- if (sap->sa.sa_family == 0)
- return "0";
-
- switch (sap->sa.sa_family)
- {
-#if NETUNIX
- case AF_UNIX:
- if (sap->sunix.sun_path[0] != '\0')
- snprintf(buf, sizeof buf, "[UNIX: %.64s]",
- sap->sunix.sun_path);
- else
- snprintf(buf, sizeof buf, "[UNIX: localhost]");
- return buf;
-#endif
-
-#if NETINET
- case AF_INET:
- return inet_ntoa(sap->sin.sin_addr);
-#endif
-
-#if NETLINK
- case AF_LINK:
- snprintf(buf, sizeof buf, "[LINK: %s]",
- link_ntoa((struct sockaddr_dl *) &sap->sa));
- return buf;
-#endif
- default:
- /* this case is needed when nothing is #defined */
- /* in order to keep the switch syntactically correct */
- break;
- }
-
- /* unknown family -- just dump bytes */
- (void) snprintf(buf, sizeof buf, "Family %d: ", sap->sa.sa_family);
- bp = &buf[strlen(buf)];
- ap = sap->sa.sa_data;
- for (l = sizeof sap->sa.sa_data; --l >= 0; )
- {
- (void) snprintf(bp, SPACELEFT(buf, bp), "%02x:", *ap++ & 0377);
- bp += 3;
- }
- *--bp = '\0';
- return buf;
-}
- /*
-** HOSTNAMEBYANYADDR -- return name of host based on address
-**
-** Parameters:
-** sap -- SOCKADDR pointer
-**
-** Returns:
-** text representation of host name.
-**
-** Side Effects:
-** none.
-*/
-
-char *
-hostnamebyanyaddr(sap)
- register SOCKADDR *sap;
-{
- register struct hostent *hp;
- int saveretry;
-
-#if NAMED_BIND
- /* shorten name server timeout to avoid higher level timeouts */
- saveretry = _res.retry;
- _res.retry = 3;
-#endif /* NAMED_BIND */
-
- switch (sap->sa.sa_family)
- {
-#if NETINET
- case AF_INET:
- hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr,
- INADDRSZ,
- AF_INET);
- break;
-#endif
-
-#if NETISO
- case AF_ISO:
- hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr,
- sizeof sap->siso.siso_addr,
- AF_ISO);
- break;
-#endif
-
-#if NETUNIX
- case AF_UNIX:
- hp = NULL;
- break;
-#endif
-
- default:
- hp = sm_gethostbyaddr(sap->sa.sa_data,
- sizeof sap->sa.sa_data,
- sap->sa.sa_family);
- break;
- }
-
-#if NAMED_BIND
- _res.retry = saveretry;
-#endif /* NAMED_BIND */
-
- if (hp != NULL && hp->h_name[0] != '[' &&
- inet_addr(hp->h_name) == INADDR_NONE)
- return denlstring((char *) hp->h_name, TRUE, TRUE);
-#if NETUNIX
- else if (sap->sa.sa_family == AF_UNIX && sap->sunix.sun_path[0] == '\0')
- return "localhost";
-#endif
- else
- {
- /* produce a dotted quad */
- static char buf[203];
-
- (void) snprintf(buf, sizeof buf, "[%.200s]", anynet_ntoa(sap));
- return buf;
- }
-}
-
-#endif /* SOCK_STREAM */
diff --git a/src/deliver.c b/src/deliver.c
deleted file mode 100644
index ed03328..0000000
--- a/src/deliver.c
+++ /dev/null
@@ -1,3758 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)deliver.c 8.367 (Berkeley) 1/18/1999";
-#endif /* not lint */
-
-#include "sendmail.h"
-#include <errno.h>
-#include <grp.h>
-#if NAMED_BIND
-#include <resolv.h>
-#endif
-
-#if HASSETUSERCONTEXT
-# include <login_cap.h>
-#endif
-
-#if SMTP
-extern char SmtpError[];
-#endif
-
-/*
-** SENDALL -- actually send all the messages.
-**
-** Parameters:
-** e -- the envelope to send.
-** mode -- the delivery mode to use. If SM_DEFAULT, use
-** the current e->e_sendmode.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Scans the send lists and sends everything it finds.
-** Delivers any appropriate error messages.
-** If we are running in a non-interactive mode, takes the
-** appropriate action.
-*/
-
-void
-sendall(e, mode)
- ENVELOPE *e;
- int mode;
-{
- register ADDRESS *q;
- char *owner;
- int otherowners;
- register ENVELOPE *ee;
- ENVELOPE *splitenv = NULL;
- int oldverbose = Verbose;
- bool somedeliveries = FALSE, expensive = FALSE;
- pid_t pid;
- void sendenvelope __P((ENVELOPE *, int));
-
- /*
- ** If this message is to be discarded, don't bother sending
- ** the message at all.
- */
-
- if (bitset(EF_DISCARD, e->e_flags))
- {
- if (tTd(13, 1))
- printf("sendall: discarding id %s\n", e->e_id);
- e->e_flags |= EF_CLRQUEUE;
- if (LogLevel > 4)
- sm_syslog(LOG_INFO, e->e_id, "discarded");
- markstats(e, NULL, TRUE);
- return;
- }
-
- /*
- ** If we have had global, fatal errors, don't bother sending
- ** the message at all if we are in SMTP mode. Local errors
- ** (e.g., a single address failing) will still cause the other
- ** addresses to be sent.
- */
-
- if (bitset(EF_FATALERRS, e->e_flags) &&
- (OpMode == MD_SMTP || OpMode == MD_DAEMON))
- {
- e->e_flags |= EF_CLRQUEUE;
- return;
- }
-
- /* determine actual delivery mode */
- if (mode == SM_DEFAULT)
- {
- mode = e->e_sendmode;
- if (mode != SM_VERIFY && mode != SM_DEFER &&
- shouldqueue(e->e_msgpriority, e->e_ctime))
- mode = SM_QUEUE;
- }
-
- if (tTd(13, 1))
- {
- extern void printenvflags __P((ENVELOPE *));
-
- printf("\n===== SENDALL: mode %c, id %s, e_from ",
- mode, e->e_id);
- printaddr(&e->e_from, FALSE);
- printf("\te_flags = ");
- printenvflags(e);
- printf("sendqueue:\n");
- printaddr(e->e_sendqueue, TRUE);
- }
-
- /*
- ** Do any preprocessing necessary for the mode we are running.
- ** Check to make sure the hop count is reasonable.
- ** Delete sends to the sender in mailing lists.
- */
-
- CurEnv = e;
- if (tTd(62, 1))
- checkfds(NULL);
-
- if (e->e_hopcount > MaxHopCount)
- {
- errno = 0;
-#if QUEUE
- queueup(e, mode == SM_QUEUE || mode == SM_DEFER);
-#endif
- e->e_flags |= EF_FATALERRS|EF_PM_NOTIFY|EF_CLRQUEUE;
- syserr("554 Too many hops %d (%d max): from %s via %s, to %s",
- e->e_hopcount, MaxHopCount, e->e_from.q_paddr,
- RealHostName == NULL ? "localhost" : RealHostName,
- e->e_sendqueue->q_paddr);
- e->e_sendqueue->q_status = "5.4.6";
- return;
- }
-
- /*
- ** Do sender deletion.
- **
- ** If the sender has the QQUEUEUP flag set, skip this.
- ** This can happen if the name server is hosed when you
- ** are trying to send mail. The result is that the sender
- ** is instantiated in the queue as a recipient.
- */
-
- if (!bitset(EF_METOO, e->e_flags) &&
- !bitset(QQUEUEUP, e->e_from.q_flags))
- {
- if (tTd(13, 5))
- {
- printf("sendall: QDONTSEND ");
- printaddr(&e->e_from, FALSE);
- }
- e->e_from.q_flags |= QDONTSEND;
- (void) recipient(&e->e_from, &e->e_sendqueue, 0, e);
- }
-
- /*
- ** Handle alias owners.
- **
- ** We scan up the q_alias chain looking for owners.
- ** We discard owners that are the same as the return path.
- */
-
- for (q = e->e_sendqueue; q != NULL; q = q->q_next)
- {
- register struct address *a;
-
- for (a = q; a != NULL && a->q_owner == NULL; a = a->q_alias)
- continue;
- if (a != NULL)
- q->q_owner = a->q_owner;
-
- if (q->q_owner != NULL &&
- !bitset(QDONTSEND, q->q_flags) &&
- strcmp(q->q_owner, e->e_from.q_paddr) == 0)
- q->q_owner = NULL;
- }
-
- if (tTd(13, 25))
- {
- printf("\nAfter first owner pass, sendq =\n");
- printaddr(e->e_sendqueue, TRUE);
- }
-
- owner = "";
- otherowners = 1;
- while (owner != NULL && otherowners > 0)
- {
- if (tTd(13, 28))
- printf("owner = \"%s\", otherowners = %d\n",
- owner, otherowners);
- owner = NULL;
- otherowners = bitset(EF_SENDRECEIPT, e->e_flags) ? 1 : 0;
-
- for (q = e->e_sendqueue; q != NULL; q = q->q_next)
- {
- if (tTd(13, 30))
- {
- printf("Checking ");
- printaddr(q, FALSE);
- }
- if (bitset(QDONTSEND, q->q_flags))
- {
- if (tTd(13, 30))
- printf(" ... QDONTSEND\n");
- continue;
- }
- if (tTd(13, 29) && !tTd(13, 30))
- {
- printf("Checking ");
- printaddr(q, FALSE);
- }
-
- if (q->q_owner != NULL)
- {
- if (owner == NULL)
- {
- if (tTd(13, 40))
- printf(" ... First owner = \"%s\"\n",
- q->q_owner);
- owner = q->q_owner;
- }
- else if (owner != q->q_owner)
- {
- if (strcmp(owner, q->q_owner) == 0)
- {
- if (tTd(13, 40))
- printf(" ... Same owner = \"%s\"\n",
- owner);
-
- /* make future comparisons cheap */
- q->q_owner = owner;
- }
- else
- {
- if (tTd(13, 40))
- printf(" ... Another owner \"%s\"\n",
- q->q_owner);
- otherowners++;
- }
- owner = q->q_owner;
- }
- else if (tTd(13, 40))
- printf(" ... Same owner = \"%s\"\n",
- owner);
- }
- else
- {
- if (tTd(13, 40))
- printf(" ... Null owner\n");
- otherowners++;
- }
-
- /*
- ** If this mailer is expensive, and if we don't
- ** want to make connections now, just mark these
- ** addresses and return. This is useful if we
- ** want to batch connections to reduce load. This
- ** will cause the messages to be queued up, and a
- ** daemon will come along to send the messages later.
- */
-
- if (bitset(QBADADDR|QQUEUEUP, q->q_flags))
- {
- if (tTd(13, 30))
- printf(" ... QBADADDR|QQUEUEUP\n");
- continue;
- }
- if (NoConnect && !Verbose &&
- bitnset(M_EXPENSIVE, q->q_mailer->m_flags))
- {
- if (tTd(13, 30))
- printf(" ... expensive\n");
- q->q_flags |= QQUEUEUP;
- expensive = TRUE;
- }
- else
- {
- if (tTd(13, 30))
- printf(" ... deliverable\n");
- somedeliveries = TRUE;
- }
- }
-
- if (owner != NULL && otherowners > 0)
- {
- extern HDR *copyheader __P((HDR *));
- extern ADDRESS *copyqueue __P((ADDRESS *));
- extern void dup_queue_file __P((ENVELOPE *, ENVELOPE *, int));
-
- /*
- ** Split this envelope into two.
- */
-
- ee = (ENVELOPE *) xalloc(sizeof(ENVELOPE));
- *ee = *e;
- ee->e_id = NULL;
- (void) queuename(ee, '\0');
-
- if (tTd(13, 1))
- printf("sendall: split %s into %s, owner = \"%s\", otherowners = %d\n",
- e->e_id, ee->e_id, owner, otherowners);
-
- ee->e_header = copyheader(e->e_header);
- ee->e_sendqueue = copyqueue(e->e_sendqueue);
- ee->e_errorqueue = copyqueue(e->e_errorqueue);
- ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS|EF_SENDRECEIPT|EF_RET_PARAM);
- ee->e_flags |= EF_NORECEIPT;
- setsender(owner, ee, NULL, '\0', TRUE);
- if (tTd(13, 5))
- {
- printf("sendall(split): QDONTSEND ");
- printaddr(&ee->e_from, FALSE);
- }
- ee->e_from.q_flags |= QDONTSEND;
- ee->e_dfp = NULL;
- ee->e_xfp = NULL;
- ee->e_errormode = EM_MAIL;
- ee->e_sibling = splitenv;
- splitenv = ee;
-
- for (q = e->e_sendqueue; q != NULL; q = q->q_next)
- {
- if (q->q_owner == owner)
- {
- q->q_flags |= QDONTSEND;
- q->q_flags &= ~(QQUEUEUP|QBADADDR);
- if (tTd(13, 6))
- printf("\t... stripping %s from original envelope\n",
- q->q_paddr);
- }
- }
- for (q = ee->e_sendqueue; q != NULL; q = q->q_next)
- {
- if (q->q_owner != owner)
- {
- q->q_flags |= QDONTSEND;
- q->q_flags &= ~(QQUEUEUP|QBADADDR);
- if (tTd(13, 6))
- printf("\t... dropping %s from cloned envelope\n",
- q->q_paddr);
- }
- else
- {
- /* clear DSN parameters */
- q->q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS);
- q->q_flags |= DefaultNotify & ~QPINGONSUCCESS;
- if (tTd(13, 6))
- printf("\t... moving %s to cloned envelope\n",
- q->q_paddr);
- }
- }
-
- if (mode != SM_VERIFY && bitset(EF_HAS_DF, e->e_flags))
- dup_queue_file(e, ee, 'd');
- openxscript(ee);
- if (mode != SM_VERIFY && LogLevel > 4)
- sm_syslog(LOG_INFO, ee->e_id,
- "clone %s, owner=%s",
- e->e_id, owner);
- }
- }
-
- if (owner != NULL)
- {
- setsender(owner, e, NULL, '\0', TRUE);
- if (tTd(13, 5))
- {
- printf("sendall(owner): QDONTSEND ");
- printaddr(&e->e_from, FALSE);
- }
- e->e_from.q_flags |= QDONTSEND;
- e->e_errormode = EM_MAIL;
- e->e_flags |= EF_NORECEIPT;
- e->e_flags &= ~EF_FATALERRS;
- }
-
- /* if nothing to be delivered, just queue up everything */
- if (!somedeliveries && mode != SM_QUEUE && mode != SM_DEFER &&
- mode != SM_VERIFY)
- {
- if (tTd(13, 29))
- printf("No deliveries: auto-queuing\n");
- mode = SM_QUEUE;
-
- /* treat this as a delivery in terms of counting tries */
- e->e_dtime = curtime();
- if (!expensive)
- e->e_ntries++;
- for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
- {
- ee->e_dtime = curtime();
- if (!expensive)
- ee->e_ntries++;
- }
- }
-
-# if QUEUE
- if ((mode == SM_QUEUE || mode == SM_DEFER || mode == SM_FORK ||
- (mode != SM_VERIFY && SuperSafe)) &&
- (!bitset(EF_INQUEUE, e->e_flags) || splitenv != NULL))
- {
- /* be sure everything is instantiated in the queue */
- queueup(e, mode == SM_QUEUE || mode == SM_DEFER);
- for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
- queueup(ee, mode == SM_QUEUE || mode == SM_DEFER);
- }
-#endif /* QUEUE */
-
- if (tTd(62, 10))
- checkfds("after envelope splitting");
-
- /*
- ** If we belong in background, fork now.
- */
-
- if (tTd(13, 20))
- {
- printf("sendall: final mode = %c\n", mode);
- if (tTd(13, 21))
- {
- printf("\n================ Final Send Queue(s) =====================\n");
- printf("\n *** Envelope %s, e_from=%s ***\n",
- e->e_id, e->e_from.q_paddr);
- printaddr(e->e_sendqueue, TRUE);
- for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
- {
- printf("\n *** Envelope %s, e_from=%s ***\n",
- ee->e_id, ee->e_from.q_paddr);
- printaddr(ee->e_sendqueue, TRUE);
- }
- printf("==========================================================\n\n");
- }
- }
- switch (mode)
- {
- case SM_VERIFY:
- Verbose = 2;
- break;
-
- case SM_QUEUE:
- case SM_DEFER:
-# if HASFLOCK
- queueonly:
-# endif
- if (e->e_nrcpts > 0)
- e->e_flags |= EF_INQUEUE;
- dropenvelope(e, splitenv != NULL);
- for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
- {
- if (ee->e_nrcpts > 0)
- ee->e_flags |= EF_INQUEUE;
- dropenvelope(ee, FALSE);
- }
- return;
-
- case SM_FORK:
- if (e->e_xfp != NULL)
- (void) fflush(e->e_xfp);
-
-# if !HASFLOCK
- /*
- ** Since fcntl locking has the interesting semantic that
- ** the lock is owned by a process, not by an open file
- ** descriptor, we have to flush this to the queue, and
- ** then restart from scratch in the child.
- */
-
- {
- /* save id for future use */
- char *qid = e->e_id;
-
- /* now drop the envelope in the parent */
- e->e_flags |= EF_INQUEUE;
- dropenvelope(e, splitenv != NULL);
-
- /* arrange to reacquire lock after fork */
- e->e_id = qid;
- }
-
- for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
- {
- /* save id for future use */
- char *qid = ee->e_id;
-
- /* drop envelope in parent */
- ee->e_flags |= EF_INQUEUE;
- dropenvelope(ee, FALSE);
-
- /* and save qid for reacquisition */
- ee->e_id = qid;
- }
-
-# endif /* !HASFLOCK */
-
- pid = fork();
- if (pid < 0)
- {
-# if HASFLOCK
- goto queueonly;
-# else
- e->e_id = NULL;
- for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
- ee->e_id = NULL;
- return;
-# endif /* HASFLOCK */
- }
- else if (pid > 0)
- {
-# if HASFLOCK
- /* be sure we leave the temp files to our child */
- /* close any random open files in the envelope */
- closexscript(e);
- if (e->e_dfp != NULL)
- (void) xfclose(e->e_dfp, "sendenvelope dfp", e->e_id);
- e->e_dfp = NULL;
- e->e_flags &= ~EF_HAS_DF;
-
- /* can't call unlockqueue to avoid unlink of xfp */
- if (e->e_lockfp != NULL)
- (void) xfclose(e->e_lockfp, "sendenvelope lockfp", e->e_id);
- e->e_lockfp = NULL;
-# endif
-
- /* make sure the parent doesn't own the envelope */
- e->e_id = NULL;
-
- /* catch intermediate zombie */
- (void) waitfor(pid);
- return;
- }
-
- /* double fork to avoid zombies */
- pid = fork();
- if (pid > 0)
- exit(EX_OK);
-
- /* be sure we are immune from the terminal */
- disconnect(2, e);
-
- /* prevent parent from waiting if there was an error */
- if (pid < 0)
- {
-# if HASFLOCK
- e->e_flags |= EF_INQUEUE;
-# else
- e->e_id = NULL;
-# endif /* HASFLOCK */
- finis(TRUE, ExitStat);
- }
-
- /* be sure to give error messages in child */
- QuickAbort = FALSE;
-
- /*
- ** Close any cached connections.
- **
- ** We don't send the QUIT protocol because the parent
- ** still knows about the connection.
- **
- ** This should only happen when delivering an error
- ** message.
- */
-
- mci_flush(FALSE, NULL);
-
- /*
- ** Since the delivery may happen in a child and the parent
- ** does not wait, the parent may close the maps thereby
- ** removing any shared memory used by the map. Therefore,
- ** open a copy of the maps for the delivery process.
- */
-
- initmaps(FALSE, e);
-
-# if HASFLOCK
- break;
-# else
-
- /*
- ** Now reacquire and run the various queue files.
- */
-
- for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
- {
- ENVELOPE *sibling = ee->e_sibling;
-
- (void) dowork(ee->e_id, FALSE, FALSE, ee);
- ee->e_sibling = sibling;
- }
- (void) dowork(e->e_id, FALSE, FALSE, e);
- finis(TRUE, ExitStat);
-# endif /* !HASFLOCK */
- }
-
- sendenvelope(e, mode);
- dropenvelope(e, TRUE);
- for (ee = splitenv; ee != NULL; ee = ee->e_sibling)
- {
- CurEnv = ee;
- if (mode != SM_VERIFY)
- openxscript(ee);
- sendenvelope(ee, mode);
- dropenvelope(ee, TRUE);
- }
- CurEnv = e;
-
- Verbose = oldverbose;
- if (mode == SM_FORK)
- finis(TRUE, ExitStat);
-}
-
-void
-sendenvelope(e, mode)
- register ENVELOPE *e;
- int mode;
-{
- register ADDRESS *q;
- bool didany;
-
- if (tTd(13, 10))
- printf("sendenvelope(%s) e_flags=0x%lx\n",
- e->e_id == NULL ? "[NOQUEUE]" : e->e_id,
- e->e_flags);
- if (LogLevel > 80)
- sm_syslog(LOG_DEBUG, e->e_id,
- "sendenvelope, flags=0x%x",
- e->e_flags);
-
- /*
- ** If we have had global, fatal errors, don't bother sending
- ** the message at all if we are in SMTP mode. Local errors
- ** (e.g., a single address failing) will still cause the other
- ** addresses to be sent.
- */
-
- if (bitset(EF_FATALERRS, e->e_flags) &&
- (OpMode == MD_SMTP || OpMode == MD_DAEMON))
- {
- e->e_flags |= EF_CLRQUEUE;
- return;
- }
-
- /*
- ** Run through the list and send everything.
- **
- ** Set EF_GLOBALERRS so that error messages during delivery
- ** result in returned mail.
- */
-
- e->e_nsent = 0;
- e->e_flags |= EF_GLOBALERRS;
- define(macid("{envid}", NULL), e->e_envid, e);
- define(macid("{bodytype}", NULL), e->e_bodytype, e);
- didany = FALSE;
-
- /* now run through the queue */
- for (q = e->e_sendqueue; q != NULL; q = q->q_next)
- {
-#if XDEBUG
- char wbuf[MAXNAME + 20];
-
- (void) snprintf(wbuf, sizeof wbuf, "sendall(%.*s)",
- MAXNAME, q->q_paddr);
- checkfd012(wbuf);
-#endif
- if (mode == SM_VERIFY)
- {
- e->e_to = q->q_paddr;
- if (!bitset(QDONTSEND|QBADADDR, q->q_flags))
- {
- if (q->q_host != NULL && q->q_host[0] != '\0')
- message("deliverable: mailer %s, host %s, user %s",
- q->q_mailer->m_name,
- q->q_host,
- q->q_user);
- else
- message("deliverable: mailer %s, user %s",
- q->q_mailer->m_name,
- q->q_user);
- }
- }
- else if (!bitset(QDONTSEND|QBADADDR, q->q_flags))
- {
- extern int deliver __P((ENVELOPE *, ADDRESS *));
-
-# if QUEUE
- /*
- ** Checkpoint the send list every few addresses
- */
-
- if (e->e_nsent >= CheckpointInterval)
- {
- queueup(e, FALSE);
- e->e_nsent = 0;
- }
-# endif /* QUEUE */
- (void) deliver(e, q);
- didany = TRUE;
- }
- }
- if (didany)
- {
- e->e_dtime = curtime();
- e->e_ntries++;
- }
-
-#if XDEBUG
- checkfd012("end of sendenvelope");
-#endif
-}
- /*
-** DUP_QUEUE_FILE -- duplicate a queue file into a split queue
-**
-** Parameters:
-** e -- the existing envelope
-** ee -- the new envelope
-** type -- the queue file type (e.g., 'd')
-**
-** Returns:
-** none
-*/
-
-void
-dup_queue_file(e, ee, type)
- struct envelope *e, *ee;
- int type;
-{
- char f1buf[MAXQFNAME], f2buf[MAXQFNAME];
-
- ee->e_dfp = NULL;
- ee->e_xfp = NULL;
- snprintf(f1buf, sizeof f1buf, "%s", queuename(e, type));
- snprintf(f2buf, sizeof f2buf, "%s", queuename(ee, type));
- if (link(f1buf, f2buf) < 0)
- {
- int saverrno = errno;
-
- syserr("sendall: link(%s, %s)", f1buf, f2buf);
- if (saverrno == EEXIST)
- {
- if (unlink(f2buf) < 0)
- {
- syserr("!sendall: unlink(%s): permanent",
- f2buf);
- /*NOTREACHED*/
- }
- if (link(f1buf, f2buf) < 0)
- {
- syserr("!sendall: link(%s, %s): permanent",
- f1buf, f2buf);
- /*NOTREACHED*/
- }
- }
- }
-}
- /*
-** DOFORK -- do a fork, retrying a couple of times on failure.
-**
-** This MUST be a macro, since after a vfork we are running
-** two processes on the same stack!!!
-**
-** Parameters:
-** none.
-**
-** Returns:
-** From a macro??? You've got to be kidding!
-**
-** Side Effects:
-** Modifies the ==> LOCAL <== variable 'pid', leaving:
-** pid of child in parent, zero in child.
-** -1 on unrecoverable error.
-**
-** Notes:
-** I'm awfully sorry this looks so awful. That's
-** vfork for you.....
-*/
-
-# define NFORKTRIES 5
-
-# ifndef FORK
-# define FORK fork
-# endif
-
-# define DOFORK(fORKfN) \
-{\
- register int i;\
-\
- for (i = NFORKTRIES; --i >= 0; )\
- {\
- pid = fORKfN();\
- if (pid >= 0)\
- break;\
- if (i > 0)\
- sleep((unsigned) NFORKTRIES - i);\
- }\
-}
- /*
-** DOFORK -- simple fork interface to DOFORK.
-**
-** Parameters:
-** none.
-**
-** Returns:
-** pid of child in parent.
-** zero in child.
-** -1 on error.
-**
-** Side Effects:
-** returns twice, once in parent and once in child.
-*/
-
-int
-dofork()
-{
- register pid_t pid = -1;
-
- DOFORK(fork);
- return (pid);
-}
- /*
-** DELIVER -- Deliver a message to a list of addresses.
-**
-** This routine delivers to everyone on the same host as the
-** user on the head of the list. It is clever about mailers
-** that don't handle multiple users. It is NOT guaranteed
-** that it will deliver to all these addresses however -- so
-** deliver should be called once for each address on the
-** list.
-**
-** Parameters:
-** e -- the envelope to deliver.
-** firstto -- head of the address list to deliver to.
-**
-** Returns:
-** zero -- successfully delivered.
-** else -- some failure, see ExitStat for more info.
-**
-** Side Effects:
-** The standard input is passed off to someone.
-*/
-
-#ifndef NO_UID
-# define NO_UID -1
-#endif
-#ifndef NO_GID
-# define NO_GID -1
-#endif
-
-int
-deliver(e, firstto)
- register ENVELOPE *e;
- ADDRESS *firstto;
-{
- char *host; /* host being sent to */
- char *user; /* user being sent to */
- char **pvp;
- register char **mvp;
- register char *p;
- register MAILER *m; /* mailer for this recipient */
- ADDRESS *volatile ctladdr;
- ADDRESS *volatile contextaddr = NULL;
- register MCI *volatile mci;
- register ADDRESS *to = firstto;
- volatile bool clever = FALSE; /* running user smtp to this mailer */
- ADDRESS *volatile tochain = NULL; /* users chain in this mailer call */
- int rcode; /* response code */
- int lmtp_rcode = EX_OK;
- char *firstsig; /* signature of firstto */
- pid_t pid = -1;
- char *volatile curhost;
- register u_short port = 0;
- time_t xstart;
- bool suidwarn;
- bool anyok; /* at least one address was OK */
- bool goodmxfound = FALSE; /* at least one MX was OK */
- int mpvect[2];
- int rpvect[2];
- char *pv[MAXPV+1];
- char tobuf[TOBUFSIZE]; /* text line of to people */
- char buf[MAXNAME + 1];
- char rpathbuf[MAXNAME + 1]; /* translated return path */
- extern int checkcompat __P((ADDRESS *, ENVELOPE *));
- extern void markfailure __P((ENVELOPE *, ADDRESS *, MCI *, int));
-
- errno = 0;
- if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags))
- return (0);
-
- suidwarn = geteuid() == 0;
-
-#if NAMED_BIND
- /* unless interactive, try twice, over a minute */
- if (OpMode == MD_DAEMON || OpMode == MD_SMTP)
- {
- _res.retrans = 30;
- _res.retry = 2;
- }
-#endif
-
- m = to->q_mailer;
- host = to->q_host;
- CurEnv = e; /* just in case */
- e->e_statmsg = NULL;
-#if SMTP
- SmtpError[0] = '\0';
-#endif
- xstart = curtime();
-
- if (tTd(10, 1))
- printf("\n--deliver, id=%s, mailer=%s, host=`%s', first user=`%s'\n",
- e->e_id, m->m_name, host, to->q_user);
- if (tTd(10, 100))
- printopenfds(FALSE);
-
- /*
- ** Clear $&{client_*} macros if this is a bounce message to
- ** prevent rejection by check_compat ruleset.
- */
-
- if (bitset(EF_RESPONSE, e->e_flags))
- {
- define(macid("{client_name}", NULL), "", e);
- define(macid("{client_addr}", NULL), "", e);
- define(macid("{client_port}", NULL), "", e);
- }
-
- /*
- ** Do initial argv setup.
- ** Insert the mailer name. Notice that $x expansion is
- ** NOT done on the mailer name. Then, if the mailer has
- ** a picky -f flag, we insert it as appropriate. This
- ** code does not check for 'pv' overflow; this places a
- ** manifest lower limit of 4 for MAXPV.
- ** The from address rewrite is expected to make
- ** the address relative to the other end.
- */
-
- /* rewrite from address, using rewriting rules */
- rcode = EX_OK;
- if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags))
- p = e->e_sender;
- else
- p = e->e_from.q_paddr;
- p = remotename(p, m, RF_SENDERADDR|RF_CANONICAL, &rcode, e);
- if (strlen(p) >= (SIZE_T) sizeof rpathbuf)
- {
- p = shortenstring(p, MAXSHORTSTR);
- syserr("remotename: huge return %s", p);
- }
- snprintf(rpathbuf, sizeof rpathbuf, "%s", p);
- define('g', rpathbuf, e); /* translated return path */
- define('h', host, e); /* to host */
- Errors = 0;
- pvp = pv;
- *pvp++ = m->m_argv[0];
-
- /* insert -f or -r flag as appropriate */
- if (FromFlag && (bitnset(M_FOPT, m->m_flags) || bitnset(M_ROPT, m->m_flags)))
- {
- if (bitnset(M_FOPT, m->m_flags))
- *pvp++ = "-f";
- else
- *pvp++ = "-r";
- *pvp++ = newstr(rpathbuf);
- }
-
- /*
- ** Append the other fixed parts of the argv. These run
- ** up to the first entry containing "$u". There can only
- ** be one of these, and there are only a few more slots
- ** in the pv after it.
- */
-
- for (mvp = m->m_argv; (p = *++mvp) != NULL; )
- {
- /* can't use strchr here because of sign extension problems */
- while (*p != '\0')
- {
- if ((*p++ & 0377) == MACROEXPAND)
- {
- if (*p == 'u')
- break;
- }
- }
-
- if (*p != '\0')
- break;
-
- /* this entry is safe -- go ahead and process it */
- expand(*mvp, buf, sizeof buf, e);
- *pvp++ = newstr(buf);
- if (pvp >= &pv[MAXPV - 3])
- {
- syserr("554 Too many parameters to %s before $u", pv[0]);
- return (-1);
- }
- }
-
- /*
- ** If we have no substitution for the user name in the argument
- ** list, we know that we must supply the names otherwise -- and
- ** SMTP is the answer!!
- */
-
- if (*mvp == NULL)
- {
- /* running SMTP */
-# if SMTP
- clever = TRUE;
- *pvp = NULL;
-# else /* SMTP */
- /* oops! we don't implement SMTP */
- syserr("554 SMTP style mailer not implemented");
- return (EX_SOFTWARE);
-# endif /* SMTP */
- }
-
- /*
- ** At this point *mvp points to the argument with $u. We
- ** run through our address list and append all the addresses
- ** we can. If we run out of space, do not fret! We can
- ** always send another copy later.
- */
-
- tobuf[0] = '\0';
- e->e_to = tobuf;
- ctladdr = NULL;
- firstsig = hostsignature(firstto->q_mailer, firstto->q_host, e);
- for (; to != NULL; to = to->q_next)
- {
- /* avoid sending multiple recipients to dumb mailers */
- if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags))
- break;
-
- /* if already sent or not for this host, don't send */
- if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags) ||
- to->q_mailer != firstto->q_mailer ||
- strcmp(hostsignature(to->q_mailer, to->q_host, e), firstsig) != 0)
- continue;
-
- /* avoid overflowing tobuf */
- if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2))
- break;
-
- if (tTd(10, 1))
- {
- printf("\nsend to ");
- printaddr(to, FALSE);
- }
-
- /* compute effective uid/gid when sending */
- if (bitnset(M_RUNASRCPT, to->q_mailer->m_flags))
- contextaddr = ctladdr = getctladdr(to);
-
- if (tTd(10, 2))
- {
- printf("ctladdr=");
- printaddr(ctladdr, FALSE);
- }
-
- user = to->q_user;
- e->e_to = to->q_paddr;
- if (tTd(10, 5))
- {
- printf("deliver: QDONTSEND ");
- printaddr(to, FALSE);
- }
- to->q_flags |= QDONTSEND;
-
- /*
- ** Check to see that these people are allowed to
- ** talk to each other.
- */
-
- if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize)
- {
- e->e_flags |= EF_NO_BODY_RETN;
- if (bitnset(M_LOCALMAILER, to->q_mailer->m_flags))
- to->q_status = "5.2.3";
- else
- to->q_status = "5.3.4";
- usrerr("552 Message is too large; %ld bytes max", m->m_maxsize);
- markfailure(e, to, NULL, EX_UNAVAILABLE);
- giveresponse(EX_UNAVAILABLE, m, NULL, ctladdr, xstart, e);
- continue;
- }
-#if NAMED_BIND
- h_errno = 0;
-#endif
-
- /* do config file checking of compatibility */
- rcode = rscheck("check_compat",
- e->e_from.q_paddr, to->q_paddr, e);
- if (rcode == EX_OK)
- {
- /* do in-code checking if not discarding */
- if (!bitset(EF_DISCARD, e->e_flags))
- rcode = checkcompat(to, e);
- }
- if (rcode != EX_OK)
- {
- markfailure(e, to, NULL, rcode);
- giveresponse(rcode, m, NULL, ctladdr, xstart, e);
- continue;
- }
- if (bitset(EF_DISCARD, e->e_flags))
- {
- if (tTd(10, 5))
- {
- printf("deliver: discarding recipient ");
- printaddr(to, FALSE);
- }
-
- /*
- ** Remove discard bit to prevent discard of
- ** future recipients
- */
- e->e_flags &= ~EF_DISCARD;
-
- continue;
- }
-
- /*
- ** Strip quote bits from names if the mailer is dumb
- ** about them.
- */
-
- if (bitnset(M_STRIPQ, m->m_flags))
- {
- stripquotes(user);
- stripquotes(host);
- }
-
- /* hack attack -- delivermail compatibility */
- if (m == ProgMailer && *user == '|')
- user++;
-
- /*
- ** If an error message has already been given, don't
- ** bother to send to this address.
- **
- ** >>>>>>>>>> This clause assumes that the local mailer
- ** >> NOTE >> cannot do any further aliasing; that
- ** >>>>>>>>>> function is subsumed by sendmail.
- */
-
- if (bitset(QBADADDR|QQUEUEUP, to->q_flags))
- continue;
-
- /*
- ** See if this user name is "special".
- ** If the user name has a slash in it, assume that this
- ** is a file -- send it off without further ado. Note
- ** that this type of addresses is not processed along
- ** with the others, so we fudge on the To person.
- */
-
- if (strcmp(m->m_mailer, "[FILE]") == 0)
- {
- define('u', user, e); /* to user */
- p = to->q_home;
- if (p == NULL && ctladdr != NULL)
- p = ctladdr->q_home;
- define('z', p, e); /* user's home */
- expand(m->m_argv[1], buf, sizeof buf, e);
- if (strlen(buf) > 0)
- rcode = mailfile(buf, m, ctladdr, SFF_CREAT, e);
- else
- {
- syserr("empty filename specification for mailer %s",
- m->m_name);
- rcode = EX_CONFIG;
- }
- giveresponse(rcode, m, NULL, ctladdr, xstart, e);
- markfailure(e, to, NULL, rcode);
- e->e_nsent++;
- if (rcode == EX_OK)
- {
- to->q_flags |= QSENT;
- if (bitnset(M_LOCALMAILER, m->m_flags) &&
- bitset(QPINGONSUCCESS, to->q_flags))
- {
- to->q_flags |= QDELIVERED;
- to->q_status = "2.1.5";
- fprintf(e->e_xfp, "%s... Successfully delivered\n",
- to->q_paddr);
- }
- }
- to->q_statdate = curtime();
- markstats(e, to, FALSE);
- continue;
- }
-
- /*
- ** Address is verified -- add this user to mailer
- ** argv, and add it to the print list of recipients.
- */
-
- /* link together the chain of recipients */
- to->q_tchain = tochain;
- tochain = to;
-
- /* create list of users for error messages */
- (void) strcat(tobuf, ",");
- (void) strcat(tobuf, to->q_paddr);
- define('u', user, e); /* to user */
- p = to->q_home;
- if (p == NULL && ctladdr != NULL)
- p = ctladdr->q_home;
- define('z', p, e); /* user's home */
-
- /*
- ** Expand out this user into argument list.
- */
-
- if (!clever)
- {
- expand(*mvp, buf, sizeof buf, e);
- *pvp++ = newstr(buf);
- if (pvp >= &pv[MAXPV - 2])
- {
- /* allow some space for trailing parms */
- break;
- }
- }
- }
-
- /* see if any addresses still exist */
- if (tobuf[0] == '\0')
- {
- define('g', (char *) NULL, e);
- return (0);
- }
-
- /* print out messages as full list */
- e->e_to = tobuf + 1;
-
- /*
- ** Fill out any parameters after the $u parameter.
- */
-
- while (!clever && *++mvp != NULL)
- {
- expand(*mvp, buf, sizeof buf, e);
- *pvp++ = newstr(buf);
- if (pvp >= &pv[MAXPV])
- syserr("554 deliver: pv overflow after $u for %s", pv[0]);
- }
- *pvp++ = NULL;
-
- /*
- ** Call the mailer.
- ** The argument vector gets built, pipes
- ** are created as necessary, and we fork & exec as
- ** appropriate.
- ** If we are running SMTP, we just need to clean up.
- */
-
- /*XXX this seems a bit wierd */
- if (ctladdr == NULL && m != ProgMailer && m != FileMailer &&
- bitset(QGOODUID, e->e_from.q_flags))
- ctladdr = &e->e_from;
-
-#if NAMED_BIND
- if (ConfigLevel < 2)
- _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */
-#endif
-
- if (tTd(11, 1))
- {
- printf("openmailer:");
- printav(pv);
- }
- errno = 0;
-#if NAMED_BIND
- h_errno = 0;
-#endif
-
- CurHostName = NULL;
-
- /*
- ** Deal with the special case of mail handled through an IPC
- ** connection.
- ** In this case we don't actually fork. We must be
- ** running SMTP for this to work. We will return a
- ** zero pid to indicate that we are running IPC.
- ** We also handle a debug version that just talks to stdin/out.
- */
-
- curhost = NULL;
- SmtpPhase = NULL;
- mci = NULL;
-
-#if XDEBUG
- {
- char wbuf[MAXLINE];
-
- /* make absolutely certain 0, 1, and 2 are in use */
- snprintf(wbuf, sizeof wbuf, "%s... openmailer(%s)",
- shortenstring(e->e_to, MAXSHORTSTR), m->m_name);
- checkfd012(wbuf);
- }
-#endif
-
- /* check for 8-bit available */
- if (bitset(EF_HAS8BIT, e->e_flags) &&
- bitnset(M_7BITS, m->m_flags) &&
- (bitset(EF_DONT_MIME, e->e_flags) ||
- !(bitset(MM_MIME8BIT, MimeMode) ||
- (bitset(EF_IS_MIME, e->e_flags) &&
- bitset(MM_CVTMIME, MimeMode)))))
- {
- usrerr("554 Cannot send 8-bit data to 7-bit destination");
- rcode = EX_DATAERR;
- e->e_status = "5.6.3";
- goto give_up;
- }
-
- if (tTd(62, 8))
- checkfds("before delivery");
-
- /* check for Local Person Communication -- not for mortals!!! */
- if (strcmp(m->m_mailer, "[LPC]") == 0)
- {
- mci = (MCI *) xalloc(sizeof *mci);
- bzero((char *) mci, sizeof *mci);
- mci->mci_in = stdin;
- mci->mci_out = stdout;
- mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN;
- mci->mci_mailer = m;
- }
- else if (strcmp(m->m_mailer, "[IPC]") == 0 ||
- strcmp(m->m_mailer, "[TCP]") == 0)
- {
-#if DAEMON
- register int i;
-
- if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0')
- {
- syserr("null host name for %s mailer", m->m_mailer);
- rcode = EX_CONFIG;
- goto give_up;
- }
-
- CurHostName = pv[1];
- curhost = hostsignature(m, pv[1], e);
-
- if (curhost == NULL || curhost[0] == '\0')
- {
- syserr("null host signature for %s", pv[1]);
- rcode = EX_CONFIG;
- goto give_up;
- }
-
- if (!clever)
- {
- syserr("554 non-clever IPC");
- rcode = EX_CONFIG;
- goto give_up;
- }
- if (pv[2] != NULL)
- {
- port = htons(atoi(pv[2]));
- if (port == 0)
- {
- struct servent *sp = getservbyname(pv[2], "tcp");
-
- if (sp == NULL)
- syserr("Service %s unknown", pv[2]);
- else
- port = sp->s_port;
- }
- }
-tryhost:
- while (*curhost != '\0')
- {
- static char hostbuf[MAXNAME + 1];
- extern int makeconnection __P((char *, u_short, MCI *, ENVELOPE *));
-
- /* pull the next host from the signature */
- p = strchr(curhost, ':');
- if (p == NULL)
- p = (char *) &curhost[strlen(curhost)];
- if (p == curhost)
- {
- syserr("deliver: null host name in signature");
- curhost++;
- continue;
- }
- i = p - curhost;
- if (i >= sizeof hostbuf)
- i = sizeof hostbuf - 1;
- strncpy(hostbuf, curhost, i);
- hostbuf[i] = '\0';
- if (*p != '\0')
- p++;
- curhost = p;
-
- /* see if we already know that this host is fried */
- CurHostName = hostbuf;
- mci = mci_get(hostbuf, m);
- if (mci->mci_state != MCIS_CLOSED)
- {
- if (tTd(11, 1))
- {
- printf("openmailer: ");
- mci_dump(mci, FALSE);
- }
- CurHostName = mci->mci_host;
- message("Using cached %sSMTP connection to %s via %s...",
- bitset(MCIF_ESMTP, mci->mci_flags) ? "E" : "",
- hostbuf, m->m_name);
- break;
- }
- mci->mci_mailer = m;
- if (mci->mci_exitstat != EX_OK)
- {
- if (mci->mci_exitstat == EX_TEMPFAIL)
- goodmxfound = TRUE;
- continue;
- }
-
- if (mci_lock_host(mci) != EX_OK)
- {
- mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
- goodmxfound = TRUE;
- continue;
- }
-
- /* try the connection */
- sm_setproctitle(TRUE, "%s %s: %s", e->e_id, hostbuf, "user open");
- if (port == 0)
- message("Connecting to %s via %s...",
- hostbuf, m->m_name);
- else
- message("Connecting to %s port %d via %s...",
- hostbuf, ntohs(port), m->m_name);
- i = makeconnection(hostbuf, port, mci, e);
- mci->mci_lastuse = curtime();
- mci->mci_exitstat = i;
- mci->mci_errno = errno;
-#if NAMED_BIND
- mci->mci_herrno = h_errno;
-#endif
- if (i == EX_OK)
- {
- goodmxfound = TRUE;
- mci->mci_state = MCIS_OPENING;
- mci_cache(mci);
- if (TrafficLogFile != NULL)
- fprintf(TrafficLogFile, "%05d === CONNECT %s\n",
- (int) getpid(), hostbuf);
- break;
- }
- else
- {
- if (tTd(11, 1))
- printf("openmailer: makeconnection => stat=%d, errno=%d\n",
- i, errno);
- if (i == EX_TEMPFAIL)
- goodmxfound = TRUE;
- mci_unlock_host(mci);
- }
-
- /* enter status of this host */
- setstat(i);
-
- /* should print some message here for -v mode */
- }
- if (mci == NULL)
- {
- syserr("deliver: no host name");
- rcode = EX_SOFTWARE;
- goto give_up;
- }
- mci->mci_pid = 0;
-#else /* no DAEMON */
- syserr("554 openmailer: no IPC");
- if (tTd(11, 1))
- printf("openmailer: NULL\n");
- rcode = EX_UNAVAILABLE;
- goto give_up;
-#endif /* DAEMON */
- }
- else
- {
- /* flush any expired connections */
- (void) mci_scan(NULL);
- mci = NULL;
-
-#if SMTP
- if (bitnset(M_LMTP, m->m_flags))
- {
- /* try to get a cached connection */
- mci = mci_get(m->m_name, m);
- if (mci->mci_host == NULL)
- mci->mci_host = m->m_name;
- CurHostName = mci->mci_host;
- if (mci->mci_state != MCIS_CLOSED)
- {
- message("Using cached LMTP connection for %s...",
- m->m_name);
- goto do_transfer;
- }
- }
-#endif
-
- /* announce the connection to verbose listeners */
- if (host == NULL || host[0] == '\0')
- message("Connecting to %s...", m->m_name);
- else
- message("Connecting to %s via %s...", host, m->m_name);
- if (TrafficLogFile != NULL)
- {
- char **av;
-
- fprintf(TrafficLogFile, "%05d === EXEC", (int) getpid());
- for (av = pv; *av != NULL; av++)
- fprintf(TrafficLogFile, " %s", *av);
- fprintf(TrafficLogFile, "\n");
- }
-
-#if XDEBUG
- checkfd012("before creating mail pipe");
-#endif
-
- /* create a pipe to shove the mail through */
- if (pipe(mpvect) < 0)
- {
- syserr("%s... openmailer(%s): pipe (to mailer)",
- shortenstring(e->e_to, MAXSHORTSTR), m->m_name);
- if (tTd(11, 1))
- printf("openmailer: NULL\n");
- rcode = EX_OSERR;
- goto give_up;
- }
-
-#if XDEBUG
- /* make sure we didn't get one of the standard I/O files */
- if (mpvect[0] < 3 || mpvect[1] < 3)
- {
- syserr("%s... openmailer(%s): bogus mpvect %d %d",
- shortenstring(e->e_to, MAXSHORTSTR), m->m_name,
- mpvect[0], mpvect[1]);
- printopenfds(TRUE);
- if (tTd(11, 1))
- printf("openmailer: NULL\n");
- rcode = EX_OSERR;
- goto give_up;
- }
-
- /* make sure system call isn't dead meat */
- checkfdopen(mpvect[0], "mpvect[0]");
- checkfdopen(mpvect[1], "mpvect[1]");
- if (mpvect[0] == mpvect[1] ||
- (e->e_lockfp != NULL &&
- (mpvect[0] == fileno(e->e_lockfp) ||
- mpvect[1] == fileno(e->e_lockfp))))
- {
- if (e->e_lockfp == NULL)
- syserr("%s... openmailer(%s): overlapping mpvect %d %d",
- shortenstring(e->e_to, MAXSHORTSTR),
- m->m_name, mpvect[0], mpvect[1]);
- else
- syserr("%s... openmailer(%s): overlapping mpvect %d %d, lockfp = %d",
- shortenstring(e->e_to, MAXSHORTSTR),
- m->m_name, mpvect[0], mpvect[1],
- fileno(e->e_lockfp));
- }
-#endif
-
- /* if this mailer speaks smtp, create a return pipe */
-#if SMTP
- if (clever)
- {
- if (pipe(rpvect) < 0)
- {
- syserr("%s... openmailer(%s): pipe (from mailer)",
- shortenstring(e->e_to, MAXSHORTSTR),
- m->m_name);
- (void) close(mpvect[0]);
- (void) close(mpvect[1]);
- if (tTd(11, 1))
- printf("openmailer: NULL\n");
- rcode = EX_OSERR;
- goto give_up;
- }
-# if XDEBUG
- checkfdopen(rpvect[0], "rpvect[0]");
- checkfdopen(rpvect[1], "rpvect[1]");
-# endif
- }
-#endif
-
- /*
- ** Actually fork the mailer process.
- ** DOFORK is clever about retrying.
- **
- ** Dispose of SIGCHLD signal catchers that may be laying
- ** around so that endmail will get it.
- */
-
- if (e->e_xfp != NULL)
- (void) fflush(e->e_xfp); /* for debugging */
- (void) fflush(stdout);
- (void) setsignal(SIGCHLD, SIG_DFL);
- DOFORK(FORK);
- /* pid is set by DOFORK */
- if (pid < 0)
- {
- /* failure */
- syserr("%s... openmailer(%s): cannot fork",
- shortenstring(e->e_to, MAXSHORTSTR), m->m_name);
- (void) close(mpvect[0]);
- (void) close(mpvect[1]);
-#if SMTP
- if (clever)
- {
- (void) close(rpvect[0]);
- (void) close(rpvect[1]);
- }
-#endif
- if (tTd(11, 1))
- printf("openmailer: NULL\n");
- rcode = EX_OSERR;
- goto give_up;
- }
- else if (pid == 0)
- {
- int i;
- int saveerrno;
- int new_euid = NO_UID;
- int new_ruid = NO_UID;
- int new_gid = NO_GID;
- struct stat stb;
- extern int DtableSize;
-
- if (e->e_lockfp != NULL)
- (void) close(fileno(e->e_lockfp));
-
- /* child -- set up input & exec mailer */
- (void) setsignal(SIGINT, SIG_IGN);
- (void) setsignal(SIGHUP, SIG_IGN);
- (void) setsignal(SIGTERM, SIG_DFL);
-
- if (m != FileMailer || stat(tochain->q_user, &stb) < 0)
- stb.st_mode = 0;
-
-#if HASSETUSERCONTEXT
- /*
- ** Set user resources.
- */
-
- if (contextaddr != NULL)
- {
- struct passwd *pwd;
-
- if (contextaddr->q_ruser != NULL)
- pwd = sm_getpwnam(contextaddr->q_ruser);
- else
- pwd = sm_getpwnam(contextaddr->q_user);
- if (pwd != NULL)
- (void) setusercontext(NULL,
- pwd, pwd->pw_uid,
- LOGIN_SETRESOURCES|LOGIN_SETPRIORITY);
- }
-#endif
-
- /* tweak niceness */
- if (m->m_nice != 0)
- nice(m->m_nice);
-
- /* reset group id */
- if (bitnset(M_SPECIFIC_UID, m->m_flags))
- new_gid = m->m_gid;
- else if (bitset(S_ISGID, stb.st_mode))
- new_gid = stb.st_gid;
- else if (ctladdr != NULL && ctladdr->q_gid != 0)
- {
- if (!DontInitGroups)
- {
- char *u = ctladdr->q_ruser;
-
- if (u == NULL)
- u = ctladdr->q_user;
-
- if (initgroups(u, ctladdr->q_gid) == -1 && suidwarn)
- syserr("openmailer: initgroups(%s, %d) failed",
- u, ctladdr->q_gid);
- }
- else
- {
- GIDSET_T gidset[1];
-
- gidset[0] = ctladdr->q_gid;
- if (setgroups(1, gidset) == -1 && suidwarn)
- syserr("openmailer: setgroups() failed");
- }
- new_gid = ctladdr->q_gid;
- }
- else
- {
- if (!DontInitGroups)
- {
- if (initgroups(DefUser, DefGid) == -1 && suidwarn)
- syserr("openmailer: initgroups(%s, %d) failed",
- DefUser, DefGid);
- }
- else
- {
- GIDSET_T gidset[1];
-
- gidset[0] = DefGid;
- if (setgroups(1, gidset) == -1 && suidwarn)
- syserr("openmailer: setgroups() failed");
- }
- if (m->m_gid == 0)
- new_gid = DefGid;
- else
- new_gid = m->m_gid;
- }
- if (new_gid != NO_GID && setgid(new_gid) < 0 && suidwarn)
- syserr("openmailer: setgid(%ld) failed",
- (long) new_gid);
-
- /* reset user id */
- endpwent();
- if (bitnset(M_SPECIFIC_UID, m->m_flags))
- new_euid = m->m_uid;
- else if (bitset(S_ISUID, stb.st_mode))
- new_ruid = stb.st_uid;
- else if (ctladdr != NULL && ctladdr->q_uid != 0)
- new_ruid = ctladdr->q_uid;
- else if (m->m_uid != 0)
- new_ruid = m->m_uid;
- else
- new_ruid = DefUid;
- if (new_euid != NO_UID)
- {
- vendor_set_uid(new_euid);
-#if USESETEUID
- if (seteuid(new_euid) < 0 && suidwarn)
- syserr("openmailer: seteuid(%ld) failed",
- (long) new_euid);
-#else
-# if HASSETREUID
- if (setreuid(new_ruid, new_euid) < 0 && suidwarn)
- syserr("openmailer: setreuid(%ld, %ld) failed",
- (long) new_ruid, (long) new_euid);
-# else
- if (new_euid != geteuid() && setuid(new_euid) < 0 && suidwarn)
- syserr("openmailer: setuid(%ld) failed",
- (long) new_euid);
-# endif
-#endif
- }
- else if (new_ruid != NO_UID)
- {
- vendor_set_uid(new_ruid);
- if (setuid(new_ruid) < 0 && suidwarn)
- syserr("openmailer: setuid(%ld) failed",
- (long) new_ruid);
- }
-
- if (tTd(11, 2))
- printf("openmailer: running as r/euid=%d/%d\n",
- (int) getuid(), (int) geteuid());
-
- /* move into some "safe" directory */
- if (m->m_execdir != NULL)
- {
- char *q;
- char buf[MAXLINE + 1];
-
- for (p = m->m_execdir; p != NULL; p = q)
- {
- q = strchr(p, ':');
- if (q != NULL)
- *q = '\0';
- expand(p, buf, sizeof buf, e);
- if (q != NULL)
- *q++ = ':';
- if (tTd(11, 20))
- printf("openmailer: trydir %s\n",
- buf);
- if (buf[0] != '\0' && chdir(buf) >= 0)
- break;
- }
- }
-
- /* arrange to filter std & diag output of command */
-#if SMTP
- if (clever)
- {
- (void) close(rpvect[0]);
- if (dup2(rpvect[1], STDOUT_FILENO) < 0)
- {
- syserr("%s... openmailer(%s): cannot dup pipe %d for stdout",
- shortenstring(e->e_to, MAXSHORTSTR),
- m->m_name, rpvect[1]);
- _exit(EX_OSERR);
- }
- (void) close(rpvect[1]);
- }
- else
- {
- /* put mailer output in transcript */
- if (dup2(fileno(e->e_xfp), STDOUT_FILENO) < 0)
- {
- syserr("%s... openmailer(%s): cannot dup xscript %d for stdout",
- shortenstring(e->e_to, MAXSHORTSTR),
- m->m_name, fileno(e->e_xfp));
- _exit(EX_OSERR);
- }
- }
-#endif
- if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0)
- {
- syserr("%s... openmailer(%s): cannot dup stdout for stderr",
- shortenstring(e->e_to, MAXSHORTSTR),
- m->m_name);
- _exit(EX_OSERR);
- }
-
- /* arrange to get standard input */
- (void) close(mpvect[1]);
- if (dup2(mpvect[0], STDIN_FILENO) < 0)
- {
- syserr("%s... openmailer(%s): cannot dup pipe %d for stdin",
- shortenstring(e->e_to, MAXSHORTSTR),
- m->m_name, mpvect[0]);
- _exit(EX_OSERR);
- }
- (void) close(mpvect[0]);
-
- /* arrange for all the files to be closed */
- for (i = 3; i < DtableSize; i++)
- {
- register int j;
-
- if ((j = fcntl(i, F_GETFD, 0)) != -1)
- (void) fcntl(i, F_SETFD, j | 1);
- }
-
- /* run disconnected from terminal */
- (void) setsid();
-
- /* try to execute the mailer */
- execve(m->m_mailer, (ARGV_T) pv, (ARGV_T) UserEnviron);
- saveerrno = errno;
- syserr("Cannot exec %s", m->m_mailer);
- if (bitnset(M_LOCALMAILER, m->m_flags) ||
- transienterror(saveerrno))
- _exit(EX_OSERR);
- _exit(EX_UNAVAILABLE);
- }
-
- /*
- ** Set up return value.
- */
-
- if (mci == NULL)
- {
- mci = (MCI *) xalloc(sizeof *mci);
- bzero((char *) mci, sizeof *mci);
- }
- mci->mci_mailer = m;
- if (clever)
- {
- mci->mci_state = MCIS_OPENING;
- mci_cache(mci);
- }
- else
- {
- mci->mci_state = MCIS_OPEN;
- }
- mci->mci_pid = pid;
- (void) close(mpvect[0]);
- mci->mci_out = fdopen(mpvect[1], "w");
- if (mci->mci_out == NULL)
- {
- syserr("deliver: cannot create mailer output channel, fd=%d",
- mpvect[1]);
- (void) close(mpvect[1]);
-#if SMTP
- if (clever)
- {
- (void) close(rpvect[0]);
- (void) close(rpvect[1]);
- }
-#endif
- rcode = EX_OSERR;
- goto give_up;
- }
-#if SMTP
- if (clever)
- {
- (void) close(rpvect[1]);
- mci->mci_in = fdopen(rpvect[0], "r");
- if (mci->mci_in == NULL)
- {
- syserr("deliver: cannot create mailer input channel, fd=%d",
- mpvect[1]);
- (void) close(rpvect[0]);
- fclose(mci->mci_out);
- mci->mci_out = NULL;
- rcode = EX_OSERR;
- goto give_up;
- }
- }
- else
-#endif
- {
- mci->mci_flags |= MCIF_TEMP;
- mci->mci_in = NULL;
- }
- }
-
- /*
- ** If we are in SMTP opening state, send initial protocol.
- */
-
- if (bitnset(M_7BITS, m->m_flags) &&
- (!clever || mci->mci_state == MCIS_OPENING))
- mci->mci_flags |= MCIF_7BIT;
-#if SMTP
- if (clever && mci->mci_state != MCIS_CLOSED)
- {
- extern void smtpinit __P((MAILER *, MCI *, ENVELOPE *));
-
- smtpinit(m, mci, e);
- }
-#endif
-
-do_transfer:
- /* clear out per-message flags from connection structure */
- mci->mci_flags &= ~(MCIF_CVT7TO8|MCIF_CVT8TO7);
-
- if (bitset(EF_HAS8BIT, e->e_flags) &&
- !bitset(EF_DONT_MIME, e->e_flags) &&
- bitnset(M_7BITS, m->m_flags))
- mci->mci_flags |= MCIF_CVT8TO7;
-
-#if MIME7TO8
- if (bitnset(M_MAKE8BIT, m->m_flags) &&
- !bitset(MCIF_7BIT, mci->mci_flags) &&
- (p = hvalue("Content-Transfer-Encoding", e->e_header)) != NULL &&
- (strcasecmp(p, "quoted-printable") == 0 ||
- strcasecmp(p, "base64") == 0) &&
- (p = hvalue("Content-Type", e->e_header)) != NULL)
- {
- /* may want to convert 7 -> 8 */
- /* XXX should really parse it here -- and use a class XXX */
- if (strncasecmp(p, "text/plain", 10) == 0 &&
- (p[10] == '\0' || p[10] == ' ' || p[10] == ';'))
- mci->mci_flags |= MCIF_CVT7TO8;
- }
-#endif
-
- if (tTd(11, 1))
- {
- printf("openmailer: ");
- mci_dump(mci, FALSE);
- }
-
- if (mci->mci_state != MCIS_OPEN)
- {
- /* couldn't open the mailer */
- rcode = mci->mci_exitstat;
- errno = mci->mci_errno;
-#if NAMED_BIND
- h_errno = mci->mci_herrno;
-#endif
- if (rcode == EX_OK)
- {
- /* shouldn't happen */
- syserr("554 deliver: mci=%lx rcode=%d errno=%d state=%d sig=%s",
- (long) mci, rcode, errno, mci->mci_state,
- firstsig);
- mci_dump_all(TRUE);
- rcode = EX_SOFTWARE;
- }
-#if DAEMON
- else if (curhost != NULL && *curhost != '\0')
- {
- /* try next MX site */
- goto tryhost;
- }
-#endif
- }
- else if (!clever)
- {
- /*
- ** Format and send message.
- */
-
- mci->mci_contentlen = 0;
- putfromline(mci, e);
- (*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER);
- (*e->e_putbody)(mci, e, NULL);
-
- /* get the exit status */
- rcode = endmailer(mci, e, pv);
- }
- else
-#if SMTP
- {
- extern int smtpmailfrom __P((MAILER *, MCI *, ENVELOPE *));
- extern int smtprcpt __P((ADDRESS *, MAILER *, MCI *, ENVELOPE *));
- extern int smtpdata __P((MAILER *, MCI *, ENVELOPE *));
-
- /*
- ** Send the MAIL FROM: protocol
- */
-
- rcode = smtpmailfrom(m, mci, e);
- if (rcode == EX_OK)
- {
- register char *t = tobuf;
- register int i;
-
- /* send the recipient list */
- tobuf[0] = '\0';
- for (to = tochain; to != NULL; to = to->q_tchain)
- {
- e->e_to = to->q_paddr;
- if (strlen(to->q_paddr) + (t - tobuf) + 2 > sizeof tobuf)
- {
- /* not enough room */
- continue;
- }
- else if ((i = smtprcpt(to, m, mci, e)) != EX_OK)
- {
- markfailure(e, to, mci, i);
- giveresponse(i, m, mci, ctladdr, xstart, e);
- }
- else
- {
- *t++ = ',';
- for (p = to->q_paddr; *p; *t++ = *p++)
- continue;
- *t = '\0';
- }
- }
-
- /* now send the data */
- if (tobuf[0] == '\0')
- {
- rcode = EX_OK;
- e->e_to = NULL;
- if (bitset(MCIF_CACHED, mci->mci_flags))
- smtprset(m, mci, e);
- }
- else
- {
- e->e_to = tobuf + 1;
- rcode = smtpdata(m, mci, e);
- }
- }
-# if DAEMON
- if (rcode == EX_TEMPFAIL && curhost != NULL && *curhost != '\0')
- {
- /* try next MX site */
- goto tryhost;
- }
-# endif
- }
-#else /* not SMTP */
- {
- syserr("554 deliver: need SMTP compiled to use clever mailer");
- rcode = EX_CONFIG;
- goto give_up;
- }
-#endif /* SMTP */
-#if NAMED_BIND
- if (ConfigLevel < 2)
- _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */
-#endif
-
- if (tTd(62, 1))
- checkfds("after delivery");
-
- /*
- ** Do final status disposal.
- ** We check for something in tobuf for the SMTP case.
- ** If we got a temporary failure, arrange to queue the
- ** addressees.
- */
-
- give_up:
-#if SMTP
- if (bitnset(M_LMTP, m->m_flags))
- {
- lmtp_rcode = rcode;
- tobuf[0] = '\0';
- anyok = FALSE;
- }
- else
-#endif
- anyok = rcode == EX_OK;
-
- for (to = tochain; to != NULL; to = to->q_tchain)
- {
- /* see if address already marked */
- if (bitset(QBADADDR|QQUEUEUP, to->q_flags))
- continue;
-
-#if SMTP
- /* if running LMTP, get the status for each address */
- if (bitnset(M_LMTP, m->m_flags))
- {
- extern int smtpgetstat __P((MAILER *, MCI *, ENVELOPE *));
-
- if (lmtp_rcode == EX_OK)
- rcode = smtpgetstat(m, mci, e);
- if (rcode == EX_OK)
- {
- if (strlen(to->q_paddr) + strlen(tobuf) + 2 > sizeof tobuf)
- {
- syserr("LMTP tobuf overflow");
- }
- else
- {
- strcat(tobuf, ",");
- strcat(tobuf, to->q_paddr);
- }
- anyok = TRUE;
- }
- else
- {
- e->e_to = to->q_paddr;
- markfailure(e, to, mci, rcode);
- giveresponse(rcode, m, mci, ctladdr, xstart, e);
- e->e_to = tobuf + 1;
- continue;
- }
- }
- else
-#endif
- {
- /* mark bad addresses */
- if (rcode != EX_OK)
- {
- if (goodmxfound && rcode == EX_NOHOST)
- rcode = EX_TEMPFAIL;
- markfailure(e, to, mci, rcode);
- continue;
- }
- }
-
- /* successful delivery */
- to->q_flags |= QSENT;
- to->q_statdate = curtime();
- e->e_nsent++;
- if (bitnset(M_LOCALMAILER, m->m_flags) &&
- bitset(QPINGONSUCCESS, to->q_flags))
- {
- to->q_flags |= QDELIVERED;
- to->q_status = "2.1.5";
- fprintf(e->e_xfp, "%s... Successfully delivered\n",
- to->q_paddr);
- }
- else if (bitset(QPINGONSUCCESS, to->q_flags) &&
- bitset(QPRIMARY, to->q_flags) &&
- !bitset(MCIF_DSN, mci->mci_flags))
- {
- to->q_flags |= QRELAYED;
- fprintf(e->e_xfp, "%s... relayed; expect no further notifications\n",
- to->q_paddr);
- }
- }
-
-#if SMTP
- if (bitnset(M_LMTP, m->m_flags))
- {
- /*
- ** Global information applies to the last recipient only;
- ** clear it out to avoid bogus errors.
- */
-
- rcode = EX_OK;
- e->e_statmsg = NULL;
-
- /* reset the mci state for the next transaction */
- if (mci != NULL && mci->mci_state == MCIS_ACTIVE)
- mci->mci_state = MCIS_OPEN;
- }
-#endif
-
- if (tobuf[0] != '\0')
- giveresponse(rcode, m, mci, ctladdr, xstart, e);
- if (anyok)
- markstats(e, tochain, FALSE);
- mci_store_persistent(mci);
-
-#if SMTP
- /* now close the connection */
- if (clever && mci != NULL && mci->mci_state != MCIS_CLOSED &&
- !bitset(MCIF_CACHED, mci->mci_flags))
- smtpquit(m, mci, e);
-#endif
-
- /*
- ** Restore state and return.
- */
-
-#if XDEBUG
- {
- char wbuf[MAXLINE];
-
- /* make absolutely certain 0, 1, and 2 are in use */
- snprintf(wbuf, sizeof wbuf, "%s... end of deliver(%s)",
- e->e_to == NULL ? "NO-TO-LIST"
- : shortenstring(e->e_to, MAXSHORTSTR),
- m->m_name);
- checkfd012(wbuf);
- }
-#endif
-
- errno = 0;
- define('g', (char *) NULL, e);
- return (rcode);
-}
- /*
-** MARKFAILURE -- mark a failure on a specific address.
-**
-** Parameters:
-** e -- the envelope we are sending.
-** q -- the address to mark.
-** mci -- mailer connection information.
-** rcode -- the code signifying the particular failure.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** marks the address (and possibly the envelope) with the
-** failure so that an error will be returned or
-** the message will be queued, as appropriate.
-*/
-
-void
-markfailure(e, q, mci, rcode)
- register ENVELOPE *e;
- register ADDRESS *q;
- register MCI *mci;
- int rcode;
-{
- char *stat = NULL;
-
- switch (rcode)
- {
- case EX_OK:
- break;
-
- case EX_TEMPFAIL:
- case EX_IOERR:
- case EX_OSERR:
- q->q_flags |= QQUEUEUP;
- q->q_flags &= ~QDONTSEND;
- break;
-
- default:
- q->q_flags |= QBADADDR;
- break;
- }
-
- /* find most specific error code possible */
- if (mci != NULL && mci->mci_status != NULL)
- {
- q->q_status = mci->mci_status;
- if (mci->mci_rstatus != NULL)
- q->q_rstatus = newstr(mci->mci_rstatus);
- else
- q->q_rstatus = NULL;
- }
- else if (e->e_status != NULL)
- {
- q->q_status = e->e_status;
- q->q_rstatus = NULL;
- }
- else
- {
- switch (rcode)
- {
- case EX_USAGE:
- stat = "5.5.4";
- break;
-
- case EX_DATAERR:
- stat = "5.5.2";
- break;
-
- case EX_NOUSER:
- stat = "5.1.1";
- break;
-
- case EX_NOHOST:
- stat = "5.1.2";
- break;
-
- case EX_NOINPUT:
- case EX_CANTCREAT:
- case EX_NOPERM:
- stat = "5.3.0";
- break;
-
- case EX_UNAVAILABLE:
- case EX_SOFTWARE:
- case EX_OSFILE:
- case EX_PROTOCOL:
- case EX_CONFIG:
- stat = "5.5.0";
- break;
-
- case EX_OSERR:
- case EX_IOERR:
- stat = "4.5.0";
- break;
-
- case EX_TEMPFAIL:
- stat = "4.2.0";
- break;
- }
- if (stat != NULL)
- q->q_status = stat;
- }
-
- q->q_statdate = curtime();
- if (CurHostName != NULL && CurHostName[0] != '\0')
- q->q_statmta = newstr(CurHostName);
- if (rcode != EX_OK && q->q_rstatus == NULL &&
- q->q_mailer != NULL && q->q_mailer->m_diagtype != NULL &&
- strcasecmp(q->q_mailer->m_diagtype, "UNIX") == 0)
- {
- char buf[30];
-
- (void) snprintf(buf, sizeof buf, "%d", rcode);
- q->q_rstatus = newstr(buf);
- }
-}
- /*
-** ENDMAILER -- Wait for mailer to terminate.
-**
-** We should never get fatal errors (e.g., segmentation
-** violation), so we report those specially. For other
-** errors, we choose a status message (into statmsg),
-** and if it represents an error, we print it.
-**
-** Parameters:
-** pid -- pid of mailer.
-** e -- the current envelope.
-** pv -- the parameter vector that invoked the mailer
-** (for error messages).
-**
-** Returns:
-** exit code of mailer.
-**
-** Side Effects:
-** none.
-*/
-
-int
-endmailer(mci, e, pv)
- register MCI *mci;
- register ENVELOPE *e;
- char **pv;
-{
- int st;
-
- mci_unlock_host(mci);
-
- /* close any connections */
- if (mci->mci_in != NULL)
- (void) xfclose(mci->mci_in, mci->mci_mailer->m_name, "mci_in");
- if (mci->mci_out != NULL)
- (void) xfclose(mci->mci_out, mci->mci_mailer->m_name, "mci_out");
- mci->mci_in = mci->mci_out = NULL;
- mci->mci_state = MCIS_CLOSED;
-
- /* in the IPC case there is nothing to wait for */
- if (mci->mci_pid == 0)
- return (EX_OK);
-
-#if _FFR_TIMEOUT_WAIT
- put a timeout around the wait
-#endif
-
- /* wait for the mailer process to die and collect status */
- st = waitfor(mci->mci_pid);
- if (st == -1)
- {
- syserr("endmailer %s: wait", mci->mci_mailer->m_name);
- return (EX_SOFTWARE);
- }
-
- if (WIFEXITED(st))
- {
- /* normal death -- return status */
- return (WEXITSTATUS(st));
- }
-
- /* it died a horrid death */
- syserr("451 mailer %s died with signal %o",
- mci->mci_mailer->m_name, st);
-
- /* log the arguments */
- if (pv != NULL && e->e_xfp != NULL)
- {
- register char **av;
-
- fprintf(e->e_xfp, "Arguments:");
- for (av = pv; *av != NULL; av++)
- fprintf(e->e_xfp, " %s", *av);
- fprintf(e->e_xfp, "\n");
- }
-
- ExitStat = EX_TEMPFAIL;
- return (EX_TEMPFAIL);
-}
- /*
-** GIVERESPONSE -- Interpret an error response from a mailer
-**
-** Parameters:
-** stat -- the status code from the mailer (high byte
-** only; core dumps must have been taken care of
-** already).
-** m -- the mailer info for this mailer.
-** mci -- the mailer connection info -- can be NULL if the
-** response is given before the connection is made.
-** ctladdr -- the controlling address for the recipient
-** address(es).
-** xstart -- the transaction start time, for computing
-** transaction delays.
-** e -- the current envelope.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Errors may be incremented.
-** ExitStat may be set.
-*/
-
-void
-giveresponse(stat, m, mci, ctladdr, xstart, e)
- int stat;
- register MAILER *m;
- register MCI *mci;
- ADDRESS *ctladdr;
- time_t xstart;
- ENVELOPE *e;
-{
- register const char *statmsg;
- extern char *SysExMsg[];
- register int i;
- extern int N_SysEx;
- char buf[MAXLINE];
-
- if (e == NULL)
- syserr("giveresponse: null envelope");
-
- /*
- ** Compute status message from code.
- */
-
- i = stat - EX__BASE;
- if (stat == 0)
- {
- statmsg = "250 Sent";
- if (e->e_statmsg != NULL)
- {
- (void) snprintf(buf, sizeof buf, "%s (%s)",
- statmsg, shortenstring(e->e_statmsg, 403));
- statmsg = buf;
- }
- }
- else if (i < 0 || i >= N_SysEx)
- {
- (void) snprintf(buf, sizeof buf, "554 unknown mailer error %d",
- stat);
- stat = EX_UNAVAILABLE;
- statmsg = buf;
- }
- else if (stat == EX_TEMPFAIL)
- {
- char *bp = buf;
-
- snprintf(bp, SPACELEFT(buf, bp), "%s", SysExMsg[i] + 1);
- bp += strlen(bp);
-#if NAMED_BIND
- if (h_errno == TRY_AGAIN)
- statmsg = errstring(h_errno+E_DNSBASE);
- else
-#endif
- {
- if (errno != 0)
- statmsg = errstring(errno);
- else
- {
-#if SMTP
- statmsg = SmtpError;
-#else /* SMTP */
- statmsg = NULL;
-#endif /* SMTP */
- }
- }
- if (statmsg != NULL && statmsg[0] != '\0')
- snprintf(bp, SPACELEFT(buf, bp), ": %s", statmsg);
- statmsg = buf;
- }
-#if NAMED_BIND
- else if (stat == EX_NOHOST && h_errno != 0)
- {
- statmsg = errstring(h_errno + E_DNSBASE);
- (void) snprintf(buf, sizeof buf, "%s (%s)",
- SysExMsg[i] + 1, statmsg);
- statmsg = buf;
- }
-#endif
- else
- {
- statmsg = SysExMsg[i];
- if (*statmsg++ == ':' && errno != 0)
- {
- (void) snprintf(buf, sizeof buf, "%s: %s",
- statmsg, errstring(errno));
- statmsg = buf;
- }
- }
-
- /*
- ** Print the message as appropriate
- */
-
- if (stat == EX_OK || stat == EX_TEMPFAIL)
- {
- extern char MsgBuf[];
-
- message("%s", &statmsg[4]);
- if (stat == EX_TEMPFAIL && e->e_xfp != NULL)
- fprintf(e->e_xfp, "%s\n", &MsgBuf[4]);
- }
- else
- {
- char mbuf[8];
-
- Errors++;
- snprintf(mbuf, sizeof mbuf, "%.3s %%s", statmsg);
- usrerr(mbuf, &statmsg[4]);
- }
-
- /*
- ** Final cleanup.
- ** Log a record of the transaction. Compute the new
- ** ExitStat -- if we already had an error, stick with
- ** that.
- */
-
- if (OpMode != MD_VERIFY && !bitset(EF_VRFYONLY, e->e_flags) &&
- LogLevel > ((stat == EX_TEMPFAIL) ? 8 : (stat == EX_OK) ? 7 : 6))
- logdelivery(m, mci, &statmsg[4], ctladdr, xstart, e);
-
- if (tTd(11, 2))
- printf("giveresponse: stat=%d, e->e_message=%s\n",
- stat, e->e_message == NULL ? "<NULL>" : e->e_message);
-
- if (stat != EX_TEMPFAIL)
- setstat(stat);
- if (stat != EX_OK && (stat != EX_TEMPFAIL || e->e_message == NULL))
- {
- if (e->e_message != NULL)
- free(e->e_message);
- e->e_message = newstr(&statmsg[4]);
- }
- errno = 0;
-#if NAMED_BIND
- h_errno = 0;
-#endif
-}
- /*
-** LOGDELIVERY -- log the delivery in the system log
-**
-** Care is taken to avoid logging lines that are too long, because
-** some versions of syslog have an unfortunate proclivity for core
-** dumping. This is a hack, to be sure, that is at best empirical.
-**
-** Parameters:
-** m -- the mailer info. Can be NULL for initial queue.
-** mci -- the mailer connection info -- can be NULL if the
-** log is occuring when no connection is active.
-** stat -- the message to print for the status.
-** ctladdr -- the controlling address for the to list.
-** xstart -- the transaction start time, used for
-** computing transaction delay.
-** e -- the current envelope.
-**
-** Returns:
-** none
-**
-** Side Effects:
-** none
-*/
-
-void
-logdelivery(m, mci, stat, ctladdr, xstart, e)
- MAILER *m;
- register MCI *mci;
- const char *stat;
- ADDRESS *ctladdr;
- time_t xstart;
- register ENVELOPE *e;
-{
- register char *bp;
- register char *p;
- int l;
- char buf[1024];
-
-# if (SYSLOG_BUFSIZE) >= 256
- /* ctladdr: max 106 bytes */
- bp = buf;
- if (ctladdr != NULL)
- {
- snprintf(bp, SPACELEFT(buf, bp), ", ctladdr=%s",
- shortenstring(ctladdr->q_paddr, 83));
- bp += strlen(bp);
- if (bitset(QGOODUID, ctladdr->q_flags))
- {
- (void) snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)",
- ctladdr->q_uid, ctladdr->q_gid);
- bp += strlen(bp);
- }
- }
-
- /* delay & xdelay: max 41 bytes */
- snprintf(bp, SPACELEFT(buf, bp), ", delay=%s",
- pintvl(curtime() - e->e_ctime, TRUE));
- bp += strlen(bp);
-
- if (xstart != (time_t) 0)
- {
- snprintf(bp, SPACELEFT(buf, bp), ", xdelay=%s",
- pintvl(curtime() - xstart, TRUE));
- bp += strlen(bp);
- }
-
- /* mailer: assume about 19 bytes (max 10 byte mailer name) */
- if (m != NULL)
- {
- snprintf(bp, SPACELEFT(buf, bp), ", mailer=%s", m->m_name);
- bp += strlen(bp);
- }
-
- /* relay: max 66 bytes for IPv4 addresses */
- if (mci != NULL && mci->mci_host != NULL)
- {
-# if DAEMON
- extern SOCKADDR CurHostAddr;
-# endif
-
- snprintf(bp, SPACELEFT(buf, bp), ", relay=%s",
- shortenstring(mci->mci_host, 40));
- bp += strlen(bp);
-
-# if DAEMON
- if (CurHostAddr.sa.sa_family != 0)
- {
- snprintf(bp, SPACELEFT(buf, bp), " [%s]",
- anynet_ntoa(&CurHostAddr));
- }
-# endif
- }
- else if (strcmp(stat, "queued") != 0)
- {
- p = macvalue('h', e);
- if (p != NULL && p[0] != '\0')
- {
- snprintf(bp, SPACELEFT(buf, bp), ", relay=%s",
- shortenstring(p, 40));
- }
- }
- bp += strlen(bp);
-
-#define STATLEN (((SYSLOG_BUFSIZE) - 100) / 4)
-#if (STATLEN) < 63
-# undef STATLEN
-# define STATLEN 63
-#endif
-#if (STATLEN) > 203
-# undef STATLEN
-# define STATLEN 203
-#endif
-
- /* stat: max 210 bytes */
- if ((bp - buf) > (sizeof buf - ((STATLEN) + 20)))
- {
- /* desperation move -- truncate data */
- bp = buf + sizeof buf - ((STATLEN) + 17);
- strcpy(bp, "...");
- bp += 3;
- }
-
- (void) strcpy(bp, ", stat=");
- bp += strlen(bp);
-
- (void) strcpy(bp, shortenstring(stat, (STATLEN)));
-
- /* id, to: max 13 + TOBUFSIZE bytes */
- l = SYSLOG_BUFSIZE - 100 - strlen(buf);
- p = e->e_to;
- while (strlen(p) >= (SIZE_T) l)
- {
- register char *q = strchr(p + l, ',');
-
- if (q == NULL)
- break;
- sm_syslog(LOG_INFO, e->e_id,
- "to=%.*s [more]%s",
- ++q - p, p, buf);
- p = q;
- }
- sm_syslog(LOG_INFO, e->e_id, "to=%s%s", p, buf);
-
-# else /* we have a very short log buffer size */
-
- l = SYSLOG_BUFSIZE - 85;
- p = e->e_to;
- while (strlen(p) >= (SIZE_T) l)
- {
- register char *q = strchr(p + l, ',');
-
- if (q == NULL)
- break;
- sm_syslog(LOG_INFO, e->e_id,
- "to=%.*s [more]",
- ++q - p, p);
- p = q;
- }
- sm_syslog(LOG_INFO, e->e_id, "to=%s", p);
-
- if (ctladdr != NULL)
- {
- bp = buf;
- snprintf(bp, SPACELEFT(buf, bp), "ctladdr=%s",
- shortenstring(ctladdr->q_paddr, 83));
- bp += strlen(bp);
- if (bitset(QGOODUID, ctladdr->q_flags))
- {
- (void) snprintf(bp, SPACELEFT(buf, bp), " (%d/%d)",
- ctladdr->q_uid, ctladdr->q_gid);
- bp += strlen(bp);
- }
- sm_syslog(LOG_INFO, e->e_id, "%s", buf);
- }
- bp = buf;
- snprintf(bp, SPACELEFT(buf, bp), "delay=%s",
- pintvl(curtime() - e->e_ctime, TRUE));
- bp += strlen(bp);
- if (xstart != (time_t) 0)
- {
- snprintf(bp, SPACELEFT(buf, bp), ", xdelay=%s",
- pintvl(curtime() - xstart, TRUE));
- bp += strlen(bp);
- }
-
- if (m != NULL)
- {
- snprintf(bp, SPACELEFT(buf, bp), ", mailer=%s", m->m_name);
- bp += strlen(bp);
- }
- sm_syslog(LOG_INFO, e->e_id, "%.1000s", buf);
-
- buf[0] = '\0';
- bp = buf;
- if (mci != NULL && mci->mci_host != NULL)
- {
-# if DAEMON
- extern SOCKADDR CurHostAddr;
-# endif
-
- snprintf(bp, SPACELEFT(buf, bp), "relay=%.100s", mci->mci_host);
- bp += strlen(bp);
-
-# if DAEMON
- if (CurHostAddr.sa.sa_family != 0)
- snprintf(bp, SPACELEFT(buf, bp), " [%.100s]",
- anynet_ntoa(&CurHostAddr));
-# endif
- }
- else if (strcmp(stat, "queued") != 0)
- {
- p = macvalue('h', e);
- if (p != NULL && p[0] != '\0')
- snprintf(buf, sizeof buf, "relay=%.100s", p);
- }
- if (buf[0] != '\0')
- sm_syslog(LOG_INFO, e->e_id, "%.1000s", buf);
-
- sm_syslog(LOG_INFO, e->e_id, "stat=%s", shortenstring(stat, 63));
-# endif /* short log buffer */
-}
- /*
-** PUTFROMLINE -- output a UNIX-style from line (or whatever)
-**
-** This can be made an arbitrary message separator by changing $l
-**
-** One of the ugliest hacks seen by human eyes is contained herein:
-** UUCP wants those stupid "remote from <host>" lines. Why oh why
-** does a well-meaning programmer such as myself have to deal with
-** this kind of antique garbage????
-**
-** Parameters:
-** mci -- the connection information.
-** e -- the envelope.
-**
-** Returns:
-** none
-**
-** Side Effects:
-** outputs some text to fp.
-*/
-
-void
-putfromline(mci, e)
- register MCI *mci;
- ENVELOPE *e;
-{
- char *template = UnixFromLine;
- char buf[MAXLINE];
- char xbuf[MAXLINE];
-
- if (bitnset(M_NHDR, mci->mci_mailer->m_flags))
- return;
-
- mci->mci_flags |= MCIF_INHEADER;
-
- if (bitnset(M_UGLYUUCP, mci->mci_mailer->m_flags))
- {
- char *bang;
-
- expand("\201g", buf, sizeof buf, e);
- bang = strchr(buf, '!');
- if (bang == NULL)
- {
- char *at;
- char hname[MAXNAME];
-
- /*
- ** If we can construct a UUCP path, do so
- */
-
- at = strrchr(buf, '@');
- if (at == NULL)
- {
- expand( "\201k", hname, sizeof hname, e);
- at = hname;
- }
- else
- *at++ = '\0';
- (void) snprintf(xbuf, sizeof xbuf,
- "From %.800s \201d remote from %.100s\n",
- buf, at);
- }
- else
- {
- *bang++ = '\0';
- (void) snprintf(xbuf, sizeof xbuf,
- "From %.800s \201d remote from %.100s\n",
- bang, buf);
- template = xbuf;
- }
- }
- expand(template, buf, sizeof buf, e);
- putxline(buf, strlen(buf), mci, PXLF_HEADER);
-}
- /*
-** PUTBODY -- put the body of a message.
-**
-** Parameters:
-** mci -- the connection information.
-** e -- the envelope to put out.
-** separator -- if non-NULL, a message separator that must
-** not be permitted in the resulting message.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** The message is written onto fp.
-*/
-
-/* values for output state variable */
-#define OS_HEAD 0 /* at beginning of line */
-#define OS_CR 1 /* read a carriage return */
-#define OS_INLINE 2 /* putting rest of line */
-
-void
-putbody(mci, e, separator)
- register MCI *mci;
- register ENVELOPE *e;
- char *separator;
-{
- char buf[MAXLINE];
- char *boundaries[MAXMIMENESTING + 1];
-
- /*
- ** Output the body of the message
- */
-
- if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags))
- {
- char *df = queuename(e, 'd');
-
- e->e_dfp = fopen(df, "r");
- if (e->e_dfp == NULL)
- syserr("putbody: Cannot open %s for %s from %s",
- df, e->e_to, e->e_from.q_paddr);
- }
- if (e->e_dfp == NULL)
- {
- if (bitset(MCIF_INHEADER, mci->mci_flags))
- {
- putline("", mci);
- mci->mci_flags &= ~MCIF_INHEADER;
- }
- putline("<<< No Message Collected >>>", mci);
- goto endofmessage;
- }
- if (e->e_dfino == (ino_t) 0)
- {
- struct stat stbuf;
-
- if (fstat(fileno(e->e_dfp), &stbuf) < 0)
- e->e_dfino = -1;
- else
- {
- e->e_dfdev = stbuf.st_dev;
- e->e_dfino = stbuf.st_ino;
- }
- }
- rewind(e->e_dfp);
-
-#if MIME8TO7
- if (bitset(MCIF_CVT8TO7, mci->mci_flags))
- {
- /*
- ** Do 8 to 7 bit MIME conversion.
- */
-
- /* make sure it looks like a MIME message */
- if (hvalue("MIME-Version", e->e_header) == NULL)
- putline("MIME-Version: 1.0", mci);
-
- if (hvalue("Content-Type", e->e_header) == NULL)
- {
- snprintf(buf, sizeof buf,
- "Content-Type: text/plain; charset=%s",
- defcharset(e));
- putline(buf, mci);
- }
-
- /* now do the hard work */
- boundaries[0] = NULL;
- mci->mci_flags |= MCIF_INHEADER;
- mime8to7(mci, e->e_header, e, boundaries, M87F_OUTER);
- }
-# if MIME7TO8
- else if (bitset(MCIF_CVT7TO8, mci->mci_flags))
- {
- mime7to8(mci, e->e_header, e);
- }
-# endif
- else if (MaxMimeHeaderLength > 0 || MaxMimeFieldLength > 0)
- {
- /* Use mime8to7 to check multipart for MIME header overflows */
- boundaries[0] = NULL;
- mci->mci_flags |= MCIF_INHEADER;
- mime8to7(mci, e->e_header, e, boundaries, M87F_OUTER|M87F_NO8TO7);
- }
- else
-#endif
- {
- int ostate;
- register char *bp;
- register char *pbp;
- register int c;
- register char *xp;
- int padc;
- char *buflim;
- int pos = 0;
- size_t eol_len;
- char peekbuf[10];
-
- if (bitset(MCIF_INHEADER, mci->mci_flags))
- {
- putline("", mci);
- mci->mci_flags &= ~MCIF_INHEADER;
- }
-
- /* determine end of buffer; allow for short mailer lines */
- buflim = &buf[sizeof buf - 1];
- if (mci->mci_mailer->m_linelimit > 0 &&
- mci->mci_mailer->m_linelimit < sizeof buf - 1)
- buflim = &buf[mci->mci_mailer->m_linelimit - 1];
- eol_len = strlen(mci->mci_mailer->m_eol);
-
- /* copy temp file to output with mapping */
- ostate = OS_HEAD;
- bp = buf;
- pbp = peekbuf;
- while (!ferror(mci->mci_out))
- {
- if (pbp > peekbuf)
- c = *--pbp;
- else if ((c = getc(e->e_dfp)) == EOF)
- break;
- if (bitset(MCIF_7BIT, mci->mci_flags))
- c &= 0x7f;
- switch (ostate)
- {
- case OS_HEAD:
-#if _FFR_NONULLS
- if (c == '\0' &&
- bitnset(M_NONULLS, mci->mci_mailer->m_flags))
- break;
-#endif
- if (c != '\r' && c != '\n' && bp < buflim)
- {
- *bp++ = c;
- break;
- }
-
- /* check beginning of line for special cases */
- *bp = '\0';
- pos = 0;
- padc = EOF;
- if (buf[0] == 'F' &&
- bitnset(M_ESCFROM, mci->mci_mailer->m_flags) &&
- strncmp(buf, "From ", 5) == 0)
- {
- padc = '>';
- }
- if (buf[0] == '-' && buf[1] == '-' &&
- separator != NULL)
- {
- /* possible separator */
- int sl = strlen(separator);
-
- if (strncmp(&buf[2], separator, sl) == 0)
- padc = ' ';
- }
- if (buf[0] == '.' &&
- bitnset(M_XDOT, mci->mci_mailer->m_flags))
- {
- padc = '.';
- }
-
- /* now copy out saved line */
- if (TrafficLogFile != NULL)
- {
- fprintf(TrafficLogFile, "%05d >>> ",
- (int) getpid());
- if (padc != EOF)
- putc(padc, TrafficLogFile);
- for (xp = buf; xp < bp; xp++)
- putc(*xp, TrafficLogFile);
- if (c == '\n')
- fputs(mci->mci_mailer->m_eol,
- TrafficLogFile);
- }
- if (padc != EOF)
- {
- putc(padc, mci->mci_out);
- mci->mci_contentlen++;
- pos++;
- }
- for (xp = buf; xp < bp; xp++)
- {
- putc(*xp, mci->mci_out);
- mci->mci_contentlen++;
- }
- if (c == '\n')
- {
- fputs(mci->mci_mailer->m_eol,
- mci->mci_out);
- mci->mci_contentlen += eol_len;
- pos = 0;
- }
- else
- {
- pos += bp - buf;
- if (c != '\r')
- *pbp++ = c;
- }
- bp = buf;
-
- /* determine next state */
- if (c == '\n')
- ostate = OS_HEAD;
- else if (c == '\r')
- ostate = OS_CR;
- else
- ostate = OS_INLINE;
- continue;
-
- case OS_CR:
- if (c == '\n')
- {
- /* got CRLF */
- fputs(mci->mci_mailer->m_eol, mci->mci_out);
- mci->mci_contentlen += eol_len;
- if (TrafficLogFile != NULL)
- {
- fputs(mci->mci_mailer->m_eol,
- TrafficLogFile);
- }
- ostate = OS_HEAD;
- continue;
- }
-
- /* had a naked carriage return */
- *pbp++ = c;
- c = '\r';
- ostate = OS_INLINE;
- goto putch;
-
- case OS_INLINE:
- if (c == '\r')
- {
- ostate = OS_CR;
- continue;
- }
-#if _FFR_NONULLS
- if (c == '\0' &&
- bitnset(M_NONULLS, mci->mci_mailer->m_flags))
- break;
-#endif
-putch:
- if (mci->mci_mailer->m_linelimit > 0 &&
- pos > mci->mci_mailer->m_linelimit &&
- c != '\n')
- {
- putc('!', mci->mci_out);
- mci->mci_contentlen++;
- fputs(mci->mci_mailer->m_eol, mci->mci_out);
- mci->mci_contentlen += eol_len;
- if (TrafficLogFile != NULL)
- {
- fprintf(TrafficLogFile, "!%s",
- mci->mci_mailer->m_eol);
- }
- ostate = OS_HEAD;
- *pbp++ = c;
- continue;
- }
- if (c == '\n')
- {
- if (TrafficLogFile != NULL)
- fputs(mci->mci_mailer->m_eol,
- TrafficLogFile);
- fputs(mci->mci_mailer->m_eol, mci->mci_out);
- mci->mci_contentlen += eol_len;
- pos = 0;
- ostate = OS_HEAD;
- }
- else
- {
- if (TrafficLogFile != NULL)
- putc(c, TrafficLogFile);
- putc(c, mci->mci_out);
- mci->mci_contentlen++;
- pos++;
- ostate = OS_INLINE;
- }
- break;
- }
- }
-
- /* make sure we are at the beginning of a line */
- if (bp > buf)
- {
- if (TrafficLogFile != NULL)
- {
- for (xp = buf; xp < bp; xp++)
- putc(*xp, TrafficLogFile);
- }
- for (xp = buf; xp < bp; xp++)
- {
- putc(*xp, mci->mci_out);
- mci->mci_contentlen++;
- }
- pos += bp - buf;
- }
- if (pos > 0)
- {
- if (TrafficLogFile != NULL)
- fputs(mci->mci_mailer->m_eol, TrafficLogFile);
- fputs(mci->mci_mailer->m_eol, mci->mci_out);
- mci->mci_contentlen += eol_len;
- }
- }
-
- if (ferror(e->e_dfp))
- {
- syserr("putbody: df%s: read error", e->e_id);
- ExitStat = EX_IOERR;
- }
-
-endofmessage:
- /* some mailers want extra blank line at end of message */
- if (bitnset(M_BLANKEND, mci->mci_mailer->m_flags) &&
- buf[0] != '\0' && buf[0] != '\n')
- putline("", mci);
-
- (void) fflush(mci->mci_out);
- if (ferror(mci->mci_out) && errno != EPIPE)
- {
- syserr("putbody: write error");
- ExitStat = EX_IOERR;
- }
- errno = 0;
-}
- /*
-** MAILFILE -- Send a message to a file.
-**
-** If the file has the setuid/setgid bits set, but NO execute
-** bits, sendmail will try to become the owner of that file
-** rather than the real user. Obviously, this only works if
-** sendmail runs as root.
-**
-** This could be done as a subordinate mailer, except that it
-** is used implicitly to save messages in ~/dead.letter. We
-** view this as being sufficiently important as to include it
-** here. For example, if the system is dying, we shouldn't have
-** to create another process plus some pipes to save the message.
-**
-** Parameters:
-** filename -- the name of the file to send to.
-** mailer -- mailer definition for recipient -- if NULL,
-** use FileMailer.
-** ctladdr -- the controlling address header -- includes
-** the userid/groupid to be when sending.
-** sfflags -- flags for opening.
-** e -- the current envelope.
-**
-** Returns:
-** The exit code associated with the operation.
-**
-** Side Effects:
-** none.
-*/
-
-static jmp_buf CtxMailfileTimeout;
-static void mailfiletimeout __P((void));
-
-int
-mailfile(filename, mailer, ctladdr, sfflags, e)
- char *volatile filename;
- MAILER *volatile mailer;
- ADDRESS *ctladdr;
- volatile int sfflags;
- register ENVELOPE *e;
-{
- register FILE *f;
- register pid_t pid = -1;
- volatile int mode = ST_MODE_NOFILE;
- bool suidwarn = geteuid() == 0;
- char *p;
- EVENT *ev;
-
- if (tTd(11, 1))
- {
- printf("mailfile %s\n ctladdr=", filename);
- printaddr(ctladdr, FALSE);
- }
-
- if (mailer == NULL)
- mailer = FileMailer;
-
- if (e->e_xfp != NULL)
- fflush(e->e_xfp);
-
- /*
- ** Special case /dev/null. This allows us to restrict file
- ** delivery to regular files only.
- */
-
- if (strcmp(filename, "/dev/null") == 0)
- return EX_OK;
-
- /* check for 8-bit available */
- if (bitset(EF_HAS8BIT, e->e_flags) &&
- bitnset(M_7BITS, mailer->m_flags) &&
- (bitset(EF_DONT_MIME, e->e_flags) ||
- !(bitset(MM_MIME8BIT, MimeMode) ||
- (bitset(EF_IS_MIME, e->e_flags) &&
- bitset(MM_CVTMIME, MimeMode)))))
- {
- usrerr("554 Cannot send 8-bit data to 7-bit destination");
- e->e_status = "5.6.3";
- return(EX_DATAERR);
- }
-
- /*
- ** Fork so we can change permissions here.
- ** Note that we MUST use fork, not vfork, because of
- ** the complications of calling subroutines, etc.
- */
-
- DOFORK(fork);
-
- if (pid < 0)
- return (EX_OSERR);
- else if (pid == 0)
- {
- /* child -- actually write to file */
- struct stat stb;
- MCI mcibuf;
- int err;
- volatile int oflags = O_WRONLY|O_APPEND;
-
- if (e->e_lockfp != NULL)
- (void) close(fileno(e->e_lockfp));
-
- (void) setsignal(SIGINT, SIG_DFL);
- (void) setsignal(SIGHUP, SIG_DFL);
- (void) setsignal(SIGTERM, SIG_DFL);
- (void) umask(OldUmask);
- e->e_to = filename;
- ExitStat = EX_OK;
-
- if (setjmp(CtxMailfileTimeout) != 0)
- {
- exit(EX_TEMPFAIL);
- }
-
- if (TimeOuts.to_fileopen > 0)
- ev = setevent(TimeOuts.to_fileopen, mailfiletimeout, 0);
- else
- ev = NULL;
-
-#ifdef HASLSTAT
- if (bitset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail))
- err = stat(filename, &stb);
- else
- err = lstat(filename, &stb);
- if (err < 0)
-#else
- if (stat(filename, &stb) < 0)
-#endif
- {
- stb.st_mode = ST_MODE_NOFILE;
- mode = FileMode;
- oflags |= O_CREAT|O_EXCL;
- }
- else if (bitset(S_IXUSR|S_IXGRP|S_IXOTH, stb.st_mode) ||
- (!bitset(DBS_FILEDELIVERYTOHARDLINK, DontBlameSendmail) &&
- stb.st_nlink != 1) ||
- (SafeFileEnv != NULL && !S_ISREG(stb.st_mode)))
- exit(EX_CANTCREAT);
- if (mode == ST_MODE_NOFILE)
- mode = stb.st_mode;
-
- /* limit the errors to those actually caused in the child */
- errno = 0;
- ExitStat = EX_OK;
-
- if (ctladdr != NULL || bitset(SFF_RUNASREALUID, sfflags))
- {
- /* ignore setuid and setgid bits */
- mode &= ~(S_ISGID|S_ISUID);
- }
-
- /* we have to open the dfile BEFORE setuid */
- if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags))
- {
- char *df = queuename(e, 'd');
-
- e->e_dfp = fopen(df, "r");
- if (e->e_dfp == NULL)
- {
- syserr("mailfile: Cannot open %s for %s from %s",
- df, e->e_to, e->e_from.q_paddr);
- }
- }
-
- /* select a new user to run as */
- if (!bitset(SFF_RUNASREALUID, sfflags))
- {
- if (bitnset(M_SPECIFIC_UID, mailer->m_flags))
- {
- RealUserName = NULL;
- RealUid = mailer->m_uid;
- }
- else if (bitset(S_ISUID, mode))
- {
- RealUserName = NULL;
- RealUid = stb.st_uid;
- }
- else if (ctladdr != NULL && ctladdr->q_uid != 0)
- {
- if (ctladdr->q_ruser != NULL)
- RealUserName = ctladdr->q_ruser;
- else
- RealUserName = ctladdr->q_user;
- RealUid = ctladdr->q_uid;
- }
- else if (mailer != NULL && mailer->m_uid != 0)
- {
- RealUserName = DefUser;
- RealUid = mailer->m_uid;
- }
- else
- {
- RealUserName = DefUser;
- RealUid = DefUid;
- }
-
- /* select a new group to run as */
- if (bitnset(M_SPECIFIC_UID, mailer->m_flags))
- RealGid = mailer->m_gid;
- else if (bitset(S_ISGID, mode))
- RealGid = stb.st_gid;
- else if (ctladdr != NULL && ctladdr->q_uid != 0)
- RealGid = ctladdr->q_gid;
- else if (mailer != NULL && mailer->m_gid != 0)
- RealGid = mailer->m_gid;
- else
- RealGid = DefGid;
- }
-
- /* last ditch */
- if (!bitset(SFF_ROOTOK, sfflags))
- {
- if (RealUid == 0)
- RealUid = DefUid;
- if (RealGid == 0)
- RealGid = DefGid;
- }
-
- /* set group id list (needs /etc/group access) */
- if (RealUserName != NULL && !DontInitGroups)
- {
- if (initgroups(RealUserName, RealGid) == -1 && suidwarn)
- syserr("mailfile: initgroups(%s, %d) failed",
- RealUserName, RealGid);
- }
- else
- {
- GIDSET_T gidset[1];
-
- gidset[0] = RealGid;
- if (setgroups(1, gidset) == -1 && suidwarn)
- syserr("mailfile: setgroups() failed");
- }
-
- /* if you have a safe environment, go into it */
- if (SafeFileEnv != NULL && SafeFileEnv[0] != '\0')
- {
- int i;
-
- if (chroot(SafeFileEnv) < 0)
- {
- syserr("mailfile: Cannot chroot(%s)",
- SafeFileEnv);
- exit(EX_CANTCREAT);
- }
- i = strlen(SafeFileEnv);
- if (strncmp(SafeFileEnv, filename, i) == 0)
- filename += i;
- }
- if (chdir("/") < 0)
- syserr("mailfile: cannot chdir(/)");
-
- /* now reset the group and user ids */
- endpwent();
- if (setgid(RealGid) < 0 && suidwarn)
- syserr("mailfile: setgid(%ld) failed", (long) RealGid);
- vendor_set_uid(RealUid);
- if (setuid(RealUid) < 0 && suidwarn)
- syserr("mailfile: setuid(%ld) failed", (long) RealUid);
-
- /* move into some "safe" directory */
- if (mailer->m_execdir != NULL)
- {
- char *q;
- char buf[MAXLINE + 1];
-
- for (p = mailer->m_execdir; p != NULL; p = q)
- {
- q = strchr(p, ':');
- if (q != NULL)
- *q = '\0';
- expand(p, buf, sizeof buf, e);
- if (q != NULL)
- *q++ = ':';
- if (tTd(11, 20))
- printf("mailfile: trydir %s\n",
- buf);
- if (buf[0] != '\0' && chdir(buf) >= 0)
- break;
- }
- }
-
- sfflags |= SFF_NOPATHCHECK;
- if (!bitset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail))
- sfflags |= SFF_NOSLINK;
- if (!bitset(DBS_FILEDELIVERYTOHARDLINK, DontBlameSendmail))
- sfflags |= SFF_NOHLINK;
- sfflags &= ~SFF_OPENASROOT;
- f = safefopen(filename, oflags, FileMode, sfflags);
- if (f == NULL)
- {
- message("554 cannot open %s: %s",
- shortenstring(filename, MAXSHORTSTR),
- errstring(errno));
- exit(EX_CANTCREAT);
- }
- if (filechanged(filename, fileno(f), &stb))
- {
- message("554 file changed after open");
- exit(EX_CANTCREAT);
- }
- if (fstat(fileno(f), &stb) < 0)
- {
- message("554 cannot fstat %s", errstring(errno));
- exit(EX_CANTCREAT);
- }
-
- if (ev != NULL)
- clrevent(ev);
-
- bzero(&mcibuf, sizeof mcibuf);
- mcibuf.mci_mailer = mailer;
- mcibuf.mci_out = f;
- mcibuf.mci_contentlen = 0;
- if (bitnset(M_7BITS, mailer->m_flags))
- mcibuf.mci_flags |= MCIF_7BIT;
-
- /* clear out per-message flags from connection structure */
- mcibuf.mci_flags &= ~(MCIF_CVT7TO8|MCIF_CVT8TO7);
-
- if (bitset(EF_HAS8BIT, e->e_flags) &&
- !bitset(EF_DONT_MIME, e->e_flags) &&
- bitnset(M_7BITS, mailer->m_flags))
- mcibuf.mci_flags |= MCIF_CVT8TO7;
-
-#if MIME7TO8
- if (bitnset(M_MAKE8BIT, mailer->m_flags) &&
- !bitset(MCIF_7BIT, mcibuf.mci_flags) &&
- (p = hvalue("Content-Transfer-Encoding", e->e_header)) != NULL &&
- (strcasecmp(p, "quoted-printable") == 0 ||
- strcasecmp(p, "base64") == 0) &&
- (p = hvalue("Content-Type", e->e_header)) != NULL)
- {
- /* may want to convert 7 -> 8 */
- /* XXX should really parse it here -- and use a class XXX */
- if (strncasecmp(p, "text/plain", 10) == 0 &&
- (p[10] == '\0' || p[10] == ' ' || p[10] == ';'))
- mcibuf.mci_flags |= MCIF_CVT7TO8;
- }
-#endif
-
- putfromline(&mcibuf, e);
- (*e->e_puthdr)(&mcibuf, e->e_header, e, M87F_OUTER);
- (*e->e_putbody)(&mcibuf, e, NULL);
- putline("\n", &mcibuf);
- if (fflush(f) < 0 || ferror(f))
- {
- message("451 I/O error: %s", errstring(errno));
- setstat(EX_IOERR);
- }
-
- /* reset ISUID & ISGID bits for paranoid systems */
-#if HASFCHMOD
- (void) fchmod(fileno(f), (MODE_T) stb.st_mode);
-#else
- (void) chmod(filename, (MODE_T) stb.st_mode);
-#endif
- (void) xfclose(f, "mailfile", filename);
- (void) fflush(stdout);
- setuid(RealUid);
- exit(ExitStat);
- /*NOTREACHED*/
- }
- else
- {
- /* parent -- wait for exit status */
- int st;
-
- st = waitfor(pid);
- if (st == -1)
- {
- syserr("mailfile: %s: wait", mailer->m_name);
- return (EX_SOFTWARE);
- }
- if (WIFEXITED(st))
- return (WEXITSTATUS(st));
- else
- {
- syserr("mailfile: %s: child died on signal %d",
- mailer->m_name, st);
- return (EX_UNAVAILABLE);
- }
- /*NOTREACHED*/
- }
- return EX_UNAVAILABLE; /* avoid compiler warning on IRIX */
-}
-
-static void
-mailfiletimeout()
-{
- longjmp(CtxMailfileTimeout, 1);
-}
- /*
-** HOSTSIGNATURE -- return the "signature" for a host.
-**
-** The signature describes how we are going to send this -- it
-** can be just the hostname (for non-Internet hosts) or can be
-** an ordered list of MX hosts.
-**
-** Parameters:
-** m -- the mailer describing this host.
-** host -- the host name.
-** e -- the current envelope.
-**
-** Returns:
-** The signature for this host.
-**
-** Side Effects:
-** Can tweak the symbol table.
-*/
-
-char *
-hostsignature(m, host, e)
- register MAILER *m;
- char *host;
- ENVELOPE *e;
-{
- register char *p;
- register STAB *s;
- int i;
- int len;
-#if NAMED_BIND
- int nmx;
- char *hp;
- char *endp;
- int oldoptions = _res.options;
- char *mxhosts[MAXMXHOSTS + 1];
-#endif
-
- /*
- ** Check to see if this uses IPC -- if not, it can't have MX records.
- */
-
- p = m->m_mailer;
- if (strcmp(p, "[IPC]") != 0 && strcmp(p, "[TCP]") != 0)
- {
- /* just an ordinary mailer */
- return host;
- }
-
- /*
- ** Look it up in the symbol table.
- */
-
- s = stab(host, ST_HOSTSIG, ST_ENTER);
- if (s->s_hostsig != NULL)
- return s->s_hostsig;
-
- /*
- ** Not already there -- create a signature.
- */
-
-#if NAMED_BIND
- if (ConfigLevel < 2)
- _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */
-
- for (hp = host; hp != NULL; hp = endp)
- {
- endp = strchr(hp, ':');
- if (endp != NULL)
- *endp = '\0';
-
- if (bitnset(M_NOMX, m->m_flags))
- {
- /* skip MX lookups */
- nmx = 1;
- mxhosts[0] = hp;
- }
- else
- {
- auto int rcode;
-
- nmx = getmxrr(hp, mxhosts, TRUE, &rcode);
- if (nmx <= 0)
- {
- register MCI *mci;
-
- /* update the connection info for this host */
- mci = mci_get(hp, m);
- mci->mci_errno = errno;
- mci->mci_herrno = h_errno;
- mci->mci_lastuse = curtime();
- mci_setstat(mci, rcode, NULL, NULL);
-
- /* use the original host name as signature */
- nmx = 1;
- mxhosts[0] = hp;
- }
- }
-
- len = 0;
- for (i = 0; i < nmx; i++)
- {
- len += strlen(mxhosts[i]) + 1;
- }
- if (s->s_hostsig != NULL)
- len += strlen(s->s_hostsig) + 1;
- p = xalloc(len);
- if (s->s_hostsig != NULL)
- {
- (void) strcpy(p, s->s_hostsig);
- free(s->s_hostsig);
- s->s_hostsig = p;
- p += strlen(p);
- *p++ = ':';
- }
- else
- s->s_hostsig = p;
- for (i = 0; i < nmx; i++)
- {
- if (i != 0)
- *p++ = ':';
- strcpy(p, mxhosts[i]);
- p += strlen(p);
- }
- if (endp != NULL)
- *endp++ = ':';
- }
- makelower(s->s_hostsig);
- if (ConfigLevel < 2)
- _res.options = oldoptions;
-#else
- /* not using BIND -- the signature is just the host name */
- s->s_hostsig = host;
-#endif
- if (tTd(17, 1))
- printf("hostsignature(%s) = %s\n", host, s->s_hostsig);
- return s->s_hostsig;
-}
diff --git a/src/domain.c b/src/domain.c
deleted file mode 100644
index ec79be8..0000000
--- a/src/domain.c
+++ /dev/null
@@ -1,912 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1986, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-#include "sendmail.h"
-
-#ifndef lint
-#if NAMED_BIND
-static char sccsid[] = "@(#)domain.c 8.81 (Berkeley) 1/21/1999 (with name server)";
-#else
-static char sccsid[] = "@(#)domain.c 8.81 (Berkeley) 1/21/1999 (without name server)";
-#endif
-#endif /* not lint */
-
-#if NAMED_BIND
-
-#include <errno.h>
-#include <resolv.h>
-#include <arpa/inet.h>
-
-/*
-** The standard udp packet size PACKETSZ (512) is not sufficient for some
-** nameserver answers containing very many resource records. The resolver
-** may switch to tcp and retry if it detects udp packet overflow.
-** Also note that the resolver routines res_query and res_search return
-** the size of the *un*truncated answer in case the supplied answer buffer
-** it not big enough to accommodate the entire answer.
-*/
-
-#ifndef MAXPACKET
-# define MAXPACKET 8192 /* max packet size used internally by BIND */
-#endif
-
-typedef union
-{
- HEADER qb1;
- u_char qb2[MAXPACKET];
-} querybuf;
-
-#ifndef MXHOSTBUFSIZE
-# define MXHOSTBUFSIZE (128 * MAXMXHOSTS)
-#endif
-
-static char MXHostBuf[MXHOSTBUFSIZE];
-
-#ifndef MAXDNSRCH
-# define MAXDNSRCH 6 /* number of possible domains to search */
-#endif
-
-#ifndef MAX
-# define MAX(a, b) ((a) > (b) ? (a) : (b))
-#endif
-
-#ifndef NO_DATA
-# define NO_DATA NO_ADDRESS
-#endif
-
-#ifndef HFIXEDSZ
-# define HFIXEDSZ 12 /* sizeof(HEADER) */
-#endif
-
-#define MAXCNAMEDEPTH 10 /* maximum depth of CNAME recursion */
-
-#if defined(__RES) && (__RES >= 19940415)
-# define RES_UNC_T char *
-#else
-# define RES_UNC_T u_char *
-#endif
- /*
-** GETMXRR -- get MX resource records for a domain
-**
-** Parameters:
-** host -- the name of the host to MX.
-** mxhosts -- a pointer to a return buffer of MX records.
-** droplocalhost -- If TRUE, all MX records less preferred
-** than the local host (as determined by $=w) will
-** be discarded.
-** rcode -- a pointer to an EX_ status code.
-**
-** Returns:
-** The number of MX records found.
-** -1 if there is an internal failure.
-** If no MX records are found, mxhosts[0] is set to host
-** and 1 is returned.
-*/
-
-int
-getmxrr(host, mxhosts, droplocalhost, rcode)
- char *host;
- char **mxhosts;
- bool droplocalhost;
- int *rcode;
-{
- register u_char *eom, *cp;
- register int i, j, n;
- int nmx = 0;
- register char *bp;
- HEADER *hp;
- querybuf answer;
- int ancount, qdcount, buflen;
- bool seenlocal = FALSE;
- u_short pref, type;
- u_short localpref = 256;
- char *fallbackMX = FallBackMX;
- bool trycanon = FALSE;
- int (*resfunc)();
- extern int res_query(), res_search();
- u_short prefer[MAXMXHOSTS];
- int weight[MAXMXHOSTS];
- extern int mxrand __P((char *));
-
- if (tTd(8, 2))
- printf("getmxrr(%s, droplocalhost=%d)\n", host, droplocalhost);
-
- if (fallbackMX != NULL && droplocalhost &&
- wordinclass(fallbackMX, 'w'))
- {
- /* don't use fallback for this pass */
- fallbackMX = NULL;
- }
-
- *rcode = EX_OK;
-
- /* efficiency hack -- numeric or non-MX lookups */
- if (host[0] == '[')
- goto punt;
-
- /*
- ** If we don't have MX records in our host switch, don't
- ** try for MX records. Note that this really isn't "right",
- ** since we might be set up to try NIS first and then DNS;
- ** if the host is found in NIS we really shouldn't be doing
- ** MX lookups. However, that should be a degenerate case.
- */
-
- if (!UseNameServer)
- goto punt;
- if (HasWildcardMX && ConfigLevel >= 6)
- resfunc = res_query;
- else
- resfunc = res_search;
-
- errno = 0;
- n = (*resfunc)(host, C_IN, T_MX, (u_char *) &answer, sizeof(answer));
- if (n < 0)
- {
- if (tTd(8, 1))
- printf("getmxrr: res_search(%s) failed (errno=%d, h_errno=%d)\n",
- (host == NULL) ? "<NULL>" : host, errno, h_errno);
- switch (h_errno)
- {
- case NO_DATA:
- trycanon = TRUE;
- /* fall through */
-
- case NO_RECOVERY:
- /* no MX data on this host */
- goto punt;
-
- case HOST_NOT_FOUND:
-#if BROKEN_RES_SEARCH
- case 0: /* Ultrix resolver retns failure w/ h_errno=0 */
-#endif
- /* host doesn't exist in DNS; might be in /etc/hosts */
- trycanon = TRUE;
- *rcode = EX_NOHOST;
- goto punt;
-
- case TRY_AGAIN:
- case -1:
- /* couldn't connect to the name server */
- if (fallbackMX != NULL)
- {
- /* name server is hosed -- push to fallback */
- mxhosts[nmx++] = fallbackMX;
- return nmx;
- }
- /* it might come up later; better queue it up */
- *rcode = EX_TEMPFAIL;
- break;
-
- default:
- syserr("getmxrr: res_search (%s) failed with impossible h_errno (%d)\n",
- host, h_errno);
- *rcode = EX_OSERR;
- break;
- }
-
- /* irreconcilable differences */
- return (-1);
- }
-
- /* avoid problems after truncation in tcp packets */
- if (n > sizeof(answer))
- n = sizeof(answer);
-
- /* find first satisfactory answer */
- hp = (HEADER *)&answer;
- cp = (u_char *)&answer + HFIXEDSZ;
- eom = (u_char *)&answer + n;
- for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ)
- if ((n = dn_skipname(cp, eom)) < 0)
- goto punt;
- buflen = sizeof(MXHostBuf) - 1;
- bp = MXHostBuf;
- ancount = ntohs(hp->ancount);
- while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS - 1)
- {
- if ((n = dn_expand((u_char *)&answer,
- eom, cp, (RES_UNC_T) bp, buflen)) < 0)
- break;
- cp += n;
- GETSHORT(type, cp);
- cp += INT16SZ + INT32SZ;
- GETSHORT(n, cp);
- if (type != T_MX)
- {
- if (tTd(8, 8) || _res.options & RES_DEBUG)
- printf("unexpected answer type %d, size %d\n",
- type, n);
- cp += n;
- continue;
- }
- GETSHORT(pref, cp);
- if ((n = dn_expand((u_char *)&answer, eom, cp,
- (RES_UNC_T) bp, buflen)) < 0)
- break;
- cp += n;
- if (wordinclass(bp, 'w'))
- {
- if (tTd(8, 3))
- printf("found localhost (%s) in MX list, pref=%d\n",
- bp, pref);
- if (droplocalhost)
- {
- if (!seenlocal || pref < localpref)
- localpref = pref;
- seenlocal = TRUE;
- continue;
- }
- weight[nmx] = 0;
- }
- else
- weight[nmx] = mxrand(bp);
- prefer[nmx] = pref;
- mxhosts[nmx++] = bp;
- n = strlen(bp);
- bp += n;
- if (bp[-1] != '.')
- {
- *bp++ = '.';
- n++;
- }
- *bp++ = '\0';
- buflen -= n + 1;
- }
-
- /* sort the records */
- for (i = 0; i < nmx; i++)
- {
- for (j = i + 1; j < nmx; j++)
- {
- if (prefer[i] > prefer[j] ||
- (prefer[i] == prefer[j] && weight[i] > weight[j]))
- {
- register int temp;
- register char *temp1;
-
- temp = prefer[i];
- prefer[i] = prefer[j];
- prefer[j] = temp;
- temp1 = mxhosts[i];
- mxhosts[i] = mxhosts[j];
- mxhosts[j] = temp1;
- temp = weight[i];
- weight[i] = weight[j];
- weight[j] = temp;
- }
- }
- if (seenlocal && prefer[i] >= localpref)
- {
- /* truncate higher preference part of list */
- nmx = i;
- }
- }
-
- /* delete duplicates from list (yes, some bozos have duplicates) */
- for (i = 0; i < nmx - 1; )
- {
- if (strcasecmp(mxhosts[i], mxhosts[i + 1]) != 0)
- i++;
- else
- {
- /* compress out duplicate */
- for (j = i + 1; j < nmx; j++)
- mxhosts[j] = mxhosts[j + 1];
- nmx--;
- }
- }
-
- if (nmx == 0)
- {
-punt:
- if (seenlocal &&
- (!TryNullMXList || sm_gethostbyname(host) == NULL))
- {
- /*
- ** If we have deleted all MX entries, this is
- ** an error -- we should NEVER send to a host that
- ** has an MX, and this should have been caught
- ** earlier in the config file.
- **
- ** Some sites prefer to go ahead and try the
- ** A record anyway; that case is handled by
- ** setting TryNullMXList. I believe this is a
- ** bad idea, but it's up to you....
- */
-
- *rcode = EX_CONFIG;
- syserr("MX list for %s points back to %s",
- host, MyHostName);
- return -1;
- }
- if (strlen(host) >= (SIZE_T) sizeof MXHostBuf)
- {
- *rcode = EX_CONFIG;
- syserr("Host name %s too long",
- shortenstring(host, MAXSHORTSTR));
- return -1;
- }
- snprintf(MXHostBuf, sizeof MXHostBuf, "%s", host);
- mxhosts[0] = MXHostBuf;
- if (host[0] == '[')
- {
- register char *p;
-
- /* this may be an MX suppression-style address */
- p = strchr(MXHostBuf, ']');
- if (p != NULL)
- {
- *p = '\0';
- if (inet_addr(&MXHostBuf[1]) != INADDR_NONE)
- {
- nmx++;
- *p = ']';
- }
- else
- {
- trycanon = TRUE;
- mxhosts[0]++;
- }
- }
- }
- if (trycanon &&
- getcanonname(mxhosts[0], sizeof MXHostBuf - 2, FALSE))
- {
- bp = &MXHostBuf[strlen(MXHostBuf)];
- if (bp[-1] != '.')
- {
- *bp++ = '.';
- *bp = '\0';
- }
- nmx = 1;
- }
- }
-
- /* if we have a default lowest preference, include that */
- if (fallbackMX != NULL && !seenlocal)
- mxhosts[nmx++] = fallbackMX;
-
- return (nmx);
-}
- /*
-** MXRAND -- create a randomizer for equal MX preferences
-**
-** If two MX hosts have equal preferences we want to randomize
-** the selection. But in order for signatures to be the same,
-** we need to randomize the same way each time. This function
-** computes a pseudo-random hash function from the host name.
-**
-** Parameters:
-** host -- the name of the host.
-**
-** Returns:
-** A random but repeatable value based on the host name.
-**
-** Side Effects:
-** none.
-*/
-
-int
-mxrand(host)
- register char *host;
-{
- int hfunc;
- static unsigned int seed;
-
- if (seed == 0)
- {
- seed = (int) curtime() & 0xffff;
- if (seed == 0)
- seed++;
- }
-
- if (tTd(17, 9))
- printf("mxrand(%s)", host);
-
- hfunc = seed;
- while (*host != '\0')
- {
- int c = *host++;
-
- if (isascii(c) && isupper(c))
- c = tolower(c);
- hfunc = ((hfunc << 1) ^ c) % 2003;
- }
-
- hfunc &= 0xff;
- hfunc++;
-
- if (tTd(17, 9))
- printf(" = %d\n", hfunc);
- return hfunc;
-}
- /*
-** BESTMX -- find the best MX for a name
-**
-** This is really a hack, but I don't see any obvious way
-** to generalize it at the moment.
-*/
-
-/* ARGSUSED3 */
-char *
-bestmx_map_lookup(map, name, av, statp)
- MAP *map;
- char *name;
- char **av;
- int *statp;
-{
- int nmx;
- int saveopts = _res.options;
- int i, len = 0;
- char *p;
- char *mxhosts[MAXMXHOSTS + 1];
- char buf[PSBUFSIZE / 2];
-
- _res.options &= ~(RES_DNSRCH|RES_DEFNAMES);
- nmx = getmxrr(name, mxhosts, FALSE, statp);
- _res.options = saveopts;
- if (nmx <= 0)
- return NULL;
- if (bitset(MF_MATCHONLY, map->map_mflags))
- return map_rewrite(map, name, strlen(name), NULL);
- if ((map->map_coldelim == '\0') || (nmx == 1))
- return map_rewrite(map, mxhosts[0], strlen(mxhosts[0]), av);
-
- /*
- ** We were given a -z flag (return all MXs) and there are multiple
- ** ones. We need to build them all into a list.
- */
- p = buf;
- for (i = 0; i < nmx; i++)
- {
- int slen;
-
- if (strchr(mxhosts[i], map->map_coldelim) != NULL)
- {
- syserr("bestmx_map_lookup: MX host %.64s includes map delimiter character 0x%02X",
- mxhosts[i], map->map_coldelim);
- return NULL;
- }
- slen = strlen(mxhosts[i]);
- if (len + slen + 2 > sizeof buf)
- break;
- if (i > 0)
- {
- *p++ = map->map_coldelim;
- len++;
- }
- strcpy(p, mxhosts[i]);
- p += slen;
- len += slen;
- }
- return map_rewrite(map, buf, len, av);
-}
- /*
-** DNS_GETCANONNAME -- get the canonical name for named host using DNS
-**
-** This algorithm tries to be smart about wildcard MX records.
-** This is hard to do because DNS doesn't tell is if we matched
-** against a wildcard or a specific MX.
-**
-** We always prefer A & CNAME records, since these are presumed
-** to be specific.
-**
-** If we match an MX in one pass and lose it in the next, we use
-** the old one. For example, consider an MX matching *.FOO.BAR.COM.
-** A hostname bletch.foo.bar.com will match against this MX, but
-** will stop matching when we try bletch.bar.com -- so we know
-** that bletch.foo.bar.com must have been right. This fails if
-** there was also an MX record matching *.BAR.COM, but there are
-** some things that just can't be fixed.
-**
-** Parameters:
-** host -- a buffer containing the name of the host.
-** This is a value-result parameter.
-** hbsize -- the size of the host buffer.
-** trymx -- if set, try MX records as well as A and CNAME.
-** statp -- pointer to place to store status.
-**
-** Returns:
-** TRUE -- if the host matched.
-** FALSE -- otherwise.
-*/
-
-bool
-dns_getcanonname(host, hbsize, trymx, statp)
- char *host;
- int hbsize;
- bool trymx;
- int *statp;
-{
- register u_char *eom, *ap;
- register char *cp;
- register int n;
- HEADER *hp;
- querybuf answer;
- int ancount, qdcount;
- int ret;
- char **domain;
- int type;
- char **dp;
- char *mxmatch;
- bool amatch;
- bool gotmx = FALSE;
- int qtype;
- int loopcnt;
- char *xp;
- char nbuf[MAX(MAXPACKET, MAXDNAME*2+2)];
- char *searchlist[MAXDNSRCH+2];
- extern char *gethostalias __P((char *));
-
- if (tTd(8, 2))
- printf("dns_getcanonname(%s, trymx=%d)\n", host, trymx);
-
- if ((_res.options & RES_INIT) == 0 && res_init() == -1)
- {
- *statp = EX_UNAVAILABLE;
- return FALSE;
- }
-
- /*
- ** Initialize domain search list. If there is at least one
- ** dot in the name, search the unmodified name first so we
- ** find "vse.CS" in Czechoslovakia instead of in the local
- ** domain (e.g., vse.CS.Berkeley.EDU).
- **
- ** Older versions of the resolver could create this
- ** list by tearing apart the host name.
- */
-
- loopcnt = 0;
-cnameloop:
- /* Check for dots in the name */
- for (cp = host, n = 0; *cp != '\0'; cp++)
- if (*cp == '.')
- n++;
-
- /*
- ** If this is a simple name, determine whether it matches an
- ** alias in the file defined by the environment variable HOSTALIASES.
- */
- if (n == 0 && (xp = gethostalias(host)) != NULL)
- {
- if (loopcnt++ > MAXCNAMEDEPTH)
- {
- syserr("loop in ${HOSTALIASES} file");
- }
- else
- {
- strncpy(host, xp, hbsize);
- host[hbsize - 1] = '\0';
- goto cnameloop;
- }
- }
-
- /*
- ** Build the search list.
- ** If there is at least one dot in name, start with a null
- ** domain to search the unmodified name first.
- ** If name does not end with a dot and search up local domain
- ** tree desired, append each local domain component to the
- ** search list; if name contains no dots and default domain
- ** name is desired, append default domain name to search list;
- ** else if name ends in a dot, remove that dot.
- */
-
- dp = searchlist;
- if (n > 0)
- *dp++ = "";
- if (n >= 0 && *--cp != '.' && bitset(RES_DNSRCH, _res.options))
- {
- for (domain = _res.dnsrch; *domain != NULL; )
- *dp++ = *domain++;
- }
- else if (n == 0 && bitset(RES_DEFNAMES, _res.options))
- {
- *dp++ = _res.defdname;
- }
- else if (*cp == '.')
- {
- *cp = '\0';
- }
- *dp = NULL;
-
- /*
- ** Now loop through the search list, appending each domain in turn
- ** name and searching for a match.
- */
-
- mxmatch = NULL;
- qtype = T_ANY;
-
- for (dp = searchlist; *dp != NULL; )
- {
- if (qtype == T_ANY)
- gotmx = FALSE;
- if (tTd(8, 5))
- printf("dns_getcanonname: trying %s.%s (%s)\n",
- host, *dp,
- qtype == T_ANY ? "ANY" : qtype == T_A ? "A" :
- qtype == T_MX ? "MX" : "???");
- ret = res_querydomain(host, *dp, C_IN, qtype,
- answer.qb2, sizeof(answer.qb2));
- if (ret <= 0)
- {
- if (tTd(8, 7))
- printf("\tNO: errno=%d, h_errno=%d\n",
- errno, h_errno);
-
- if (errno == ECONNREFUSED || h_errno == TRY_AGAIN)
- {
- /* the name server seems to be down */
- h_errno = TRY_AGAIN;
- *statp = EX_TEMPFAIL;
- return FALSE;
- }
-
- if (h_errno != HOST_NOT_FOUND)
- {
- /* might have another type of interest */
- if (qtype == T_ANY)
- {
- qtype = T_A;
- continue;
- }
- else if (qtype == T_A && !gotmx && (trymx || **dp == '\0'))
- {
- qtype = T_MX;
- continue;
- }
- }
-
- /* definite no -- try the next domain */
- dp++;
- qtype = T_ANY;
- continue;
- }
- else if (tTd(8, 7))
- printf("\tYES\n");
-
- /* avoid problems after truncation in tcp packets */
- if (ret > sizeof(answer))
- ret = sizeof(answer);
-
- /*
- ** Appear to have a match. Confirm it by searching for A or
- ** CNAME records. If we don't have a local domain
- ** wild card MX record, we will accept MX as well.
- */
-
- hp = (HEADER *) &answer;
- ap = (u_char *) &answer + HFIXEDSZ;
- eom = (u_char *) &answer + ret;
-
- /* skip question part of response -- we know what we asked */
- for (qdcount = ntohs(hp->qdcount); qdcount--; ap += ret + QFIXEDSZ)
- {
- if ((ret = dn_skipname(ap, eom)) < 0)
- {
- if (tTd(8, 20))
- printf("qdcount failure (%d)\n",
- ntohs(hp->qdcount));
- *statp = EX_SOFTWARE;
- return FALSE; /* ???XXX??? */
- }
- }
-
- amatch = FALSE;
- for (ancount = ntohs(hp->ancount); --ancount >= 0 && ap < eom;
- ap += n)
- {
- n = dn_expand((u_char *) &answer, eom, ap,
- (RES_UNC_T) nbuf, sizeof nbuf);
- if (n < 0)
- break;
- ap += n;
- GETSHORT(type, ap);
- ap += INT16SZ + INT32SZ;
- GETSHORT(n, ap);
- switch (type)
- {
- case T_MX:
- gotmx = TRUE;
- if (**dp != '\0' && HasWildcardMX)
- {
- /*
- ** If we are using MX matches and have
- ** not yet gotten one, save this one
- ** but keep searching for an A or
- ** CNAME match.
- */
-
- if (trymx && mxmatch == NULL)
- mxmatch = *dp;
- continue;
- }
-
- /*
- ** If we did not append a domain name, this
- ** must have been a canonical name to start
- ** with. Even if we did append a domain name,
- ** in the absence of a wildcard MX this must
- ** still be a real MX match.
- ** Such MX matches are as good as an A match,
- ** fall through.
- */
-
- case T_A:
- /* Flag that a good match was found */
- amatch = TRUE;
-
- /* continue in case a CNAME also exists */
- continue;
-
- case T_CNAME:
- if (DontExpandCnames)
- {
- /* got CNAME -- guaranteed canonical */
- amatch = TRUE;
- break;
- }
-
- if (loopcnt++ > MAXCNAMEDEPTH)
- {
- /*XXX should notify postmaster XXX*/
- message("DNS failure: CNAME loop for %s",
- host);
- if (CurEnv->e_message == NULL)
- {
- char ebuf[MAXLINE];
-
- snprintf(ebuf, sizeof ebuf,
- "Deferred: DNS failure: CNAME loop for %.100s",
- host);
- CurEnv->e_message = newstr(ebuf);
- }
- h_errno = NO_RECOVERY;
- *statp = EX_CONFIG;
- return FALSE;
- }
-
- /* value points at name */
- if ((ret = dn_expand((u_char *)&answer,
- eom, ap, (RES_UNC_T) nbuf, sizeof(nbuf))) < 0)
- break;
- (void)strncpy(host, nbuf, hbsize); /* XXX */
- host[hbsize - 1] = '\0';
-
- /*
- ** RFC 1034 section 3.6 specifies that CNAME
- ** should point at the canonical name -- but
- ** urges software to try again anyway.
- */
-
- goto cnameloop;
-
- default:
- /* not a record of interest */
- continue;
- }
- }
-
- if (amatch)
- {
- /*
- ** Got a good match -- either an A, CNAME, or an
- ** exact MX record. Save it and get out of here.
- */
-
- mxmatch = *dp;
- break;
- }
-
- /*
- ** Nothing definitive yet.
- ** If this was a T_ANY query, we don't really know what
- ** was returned -- it might have been a T_NS,
- ** for example. Try T_A to be more specific
- ** during the next pass.
- ** If this was a T_A query and we haven't yet found a MX
- ** match, try T_MX if allowed to do so.
- ** Otherwise, try the next domain.
- */
-
- if (qtype == T_ANY)
- qtype = T_A;
- else if (qtype == T_A && !gotmx && (trymx || **dp == '\0'))
- qtype = T_MX;
- else
- {
- qtype = T_ANY;
- dp++;
- }
- }
-
- /* if nothing was found, we are done */
- if (mxmatch == NULL)
- {
- *statp = EX_NOHOST;
- return FALSE;
- }
-
- /*
- ** Create canonical name and return.
- ** If saved domain name is null, name was already canonical.
- ** Otherwise append the saved domain name.
- */
-
- (void) snprintf(nbuf, sizeof nbuf, "%.*s%s%.*s", MAXDNAME, host,
- *mxmatch == '\0' ? "" : ".",
- MAXDNAME, mxmatch);
- strncpy(host, nbuf, hbsize);
- host[hbsize - 1] = '\0';
- if (tTd(8, 5))
- printf("dns_getcanonname: %s\n", host);
- *statp = EX_OK;
- return TRUE;
-}
-
-
-
-char *
-gethostalias(host)
- char *host;
-{
- char *fname;
- FILE *fp;
- register char *p = NULL;
- int sff = SFF_REGONLY;
- char buf[MAXLINE];
- static char hbuf[MAXDNAME];
-
- if (DontLockReadFiles)
- sff |= SFF_NOLOCK;
- fname = getenv("HOSTALIASES");
- if (fname == NULL ||
- (fp = safefopen(fname, O_RDONLY, 0, sff)) == NULL)
- return NULL;
- while (fgets(buf, sizeof buf, fp) != NULL)
- {
- for (p = buf; p != '\0' && !(isascii(*p) && isspace(*p)); p++)
- continue;
- if (*p == 0)
- {
- /* syntax error */
- continue;
- }
- *p++ = '\0';
- if (strcasecmp(buf, host) == 0)
- break;
- }
-
- if (feof(fp))
- {
- /* no match */
- fclose(fp);
- return NULL;
- }
- fclose(fp);
-
- /* got a match; extract the equivalent name */
- while (*p != '\0' && isascii(*p) && isspace(*p))
- p++;
- host = p;
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
- p++;
- *p = '\0';
- strncpy(hbuf, host, sizeof hbuf - 1);
- hbuf[sizeof hbuf - 1] = '\0';
- return hbuf;
-}
-
-#endif /* NAMED_BIND */
diff --git a/src/envelope.c b/src/envelope.c
deleted file mode 100644
index 2cc90d6..0000000
--- a/src/envelope.c
+++ /dev/null
@@ -1,938 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)envelope.c 8.122 (Berkeley) 1/25/1999";
-#endif /* not lint */
-
-#include "sendmail.h"
-
-/*
-** NEWENVELOPE -- allocate a new envelope
-**
-** Supports inheritance.
-**
-** Parameters:
-** e -- the new envelope to fill in.
-** parent -- the envelope to be the parent of e.
-**
-** Returns:
-** e.
-**
-** Side Effects:
-** none.
-*/
-
-ENVELOPE *
-newenvelope(e, parent)
- register ENVELOPE *e;
- register ENVELOPE *parent;
-{
- if (e == parent && e->e_parent != NULL)
- parent = e->e_parent;
- clearenvelope(e, TRUE);
- if (e == CurEnv)
- bcopy((char *) &NullAddress, (char *) &e->e_from, sizeof e->e_from);
- else
- bcopy((char *) &CurEnv->e_from, (char *) &e->e_from, sizeof e->e_from);
- e->e_parent = parent;
- e->e_ctime = curtime();
- if (parent != NULL)
- e->e_msgpriority = parent->e_msgsize;
- e->e_puthdr = putheader;
- e->e_putbody = putbody;
- if (CurEnv->e_xfp != NULL)
- (void) fflush(CurEnv->e_xfp);
-
- return (e);
-}
- /*
-** DROPENVELOPE -- deallocate an envelope.
-**
-** Parameters:
-** e -- the envelope to deallocate.
-** fulldrop -- if set, do return receipts.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** housekeeping necessary to dispose of an envelope.
-** Unlocks this queue file.
-*/
-
-void
-dropenvelope(e, fulldrop)
- register ENVELOPE *e;
- bool fulldrop;
-{
- bool queueit = FALSE;
- bool message_timeout = FALSE;
- bool failure_return = FALSE;
- bool delay_return = FALSE;
- bool success_return = FALSE;
- register ADDRESS *q;
- char *id = e->e_id;
- char buf[MAXLINE];
-
- if (tTd(50, 1))
- {
- extern void printenvflags __P((ENVELOPE *));
-
- printf("dropenvelope %lx: id=", (u_long) e);
- xputs(e->e_id);
- printf(", flags=");
- printenvflags(e);
- if (tTd(50, 10))
- {
- printf("sendq=");
- printaddr(e->e_sendqueue, TRUE);
- }
- }
-
- if (LogLevel > 84)
- sm_syslog(LOG_DEBUG, id,
- "dropenvelope, e_flags=0x%x, OpMode=%c, pid=%d",
- e->e_flags, OpMode, getpid());
-
- /* we must have an id to remove disk files */
- if (id == NULL)
- return;
-
- /* if verify-only mode, we can skip most of this */
- if (OpMode == MD_VERIFY)
- goto simpledrop;
-
- if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags))
- logsender(e, NULL);
- e->e_flags &= ~EF_LOGSENDER;
-
- /* post statistics */
- poststats(StatFile);
-
- /*
- ** Extract state information from dregs of send list.
- */
-
- if (curtime() > e->e_ctime + TimeOuts.to_q_return[e->e_timeoutclass])
- message_timeout = TRUE;
-
- e->e_flags &= ~EF_QUEUERUN;
- for (q = e->e_sendqueue; q != NULL; q = q->q_next)
- {
- if (bitset(QQUEUEUP, q->q_flags) &&
- bitset(QDONTSEND, q->q_flags))
- {
- /* I'm not sure how this happens..... */
- if (tTd(50, 2))
- {
- printf("Bogus flags: ");
- printaddr(q, FALSE);
- }
- q->q_flags &= ~QDONTSEND;
- }
- if (!bitset(QBADADDR|QDONTSEND|QSENT, q->q_flags))
- queueit = TRUE;
-#if XDEBUG
- else if (bitset(QQUEUEUP, q->q_flags))
- sm_syslog(LOG_DEBUG, e->e_id,
- "dropenvelope: q_flags = %x, paddr = %s",
- q->q_flags, q->q_paddr);
-#endif
-
- /* see if a notification is needed */
- if (bitset(QPINGONFAILURE, q->q_flags) &&
- ((message_timeout && bitset(QQUEUEUP, q->q_flags)) ||
- bitset(QBADADDR, q->q_flags)))
- {
- failure_return = TRUE;
- if (q->q_owner == NULL && !emptyaddr(&e->e_from))
- (void) sendtolist(e->e_from.q_paddr, NULLADDR,
- &e->e_errorqueue, 0, e);
- }
- else if (bitset(QPINGONSUCCESS, q->q_flags) &&
- ((bitset(QSENT, q->q_flags) &&
- bitnset(M_LOCALMAILER, q->q_mailer->m_flags)) ||
- bitset(QRELAYED|QEXPANDED|QDELIVERED, q->q_flags)))
- {
- success_return = TRUE;
- }
- }
-
- if (e->e_class < 0)
- e->e_flags |= EF_NO_BODY_RETN;
-
- /*
- ** See if the message timed out.
- */
-
- if (!queueit)
- /* nothing to do */ ;
- else if (message_timeout)
- {
- if (failure_return)
- {
- (void) snprintf(buf, sizeof buf,
- "Cannot send message within %s",
- pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE));
- if (e->e_message != NULL)
- free(e->e_message);
- e->e_message = newstr(buf);
- message(buf);
- e->e_flags |= EF_CLRQUEUE;
- }
- fprintf(e->e_xfp, "Message could not be delivered for %s\n",
- pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE));
- fprintf(e->e_xfp, "Message will be deleted from queue\n");
- for (q = e->e_sendqueue; q != NULL; q = q->q_next)
- {
- if (!bitset(QBADADDR|QDONTSEND|QSENT, q->q_flags))
- {
- q->q_flags |= QBADADDR;
- q->q_status = "4.4.7";
- }
- }
- }
- else if (TimeOuts.to_q_warning[e->e_timeoutclass] > 0 &&
- curtime() > e->e_ctime + TimeOuts.to_q_warning[e->e_timeoutclass])
- {
- if (!bitset(EF_WARNING|EF_RESPONSE, e->e_flags) &&
- e->e_class >= 0 &&
- e->e_from.q_paddr != NULL &&
- strcmp(e->e_from.q_paddr, "<>") != 0 &&
- strncasecmp(e->e_from.q_paddr, "owner-", 6) != 0 &&
- (strlen(e->e_from.q_paddr) <= (SIZE_T) 8 ||
- strcasecmp(&e->e_from.q_paddr[strlen(e->e_from.q_paddr) - 8], "-request") != 0))
- {
- for (q = e->e_sendqueue; q != NULL; q = q->q_next)
- {
- if (bitset(QQUEUEUP, q->q_flags) &&
- bitset(QPINGONDELAY, q->q_flags))
- {
- q->q_flags |= QDELAYED;
- delay_return = TRUE;
- }
- }
- }
- if (delay_return)
- {
- (void) snprintf(buf, sizeof buf,
- "Warning: could not send message for past %s",
- pintvl(TimeOuts.to_q_warning[e->e_timeoutclass], FALSE));
- if (e->e_message != NULL)
- free(e->e_message);
- e->e_message = newstr(buf);
- message(buf);
- e->e_flags |= EF_WARNING;
- }
- fprintf(e->e_xfp,
- "Warning: message still undelivered after %s\n",
- pintvl(TimeOuts.to_q_warning[e->e_timeoutclass], FALSE));
- fprintf(e->e_xfp, "Will keep trying until message is %s old\n",
- pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE));
- }
-
- if (tTd(50, 2))
- printf("failure_return=%d delay_return=%d success_return=%d queueit=%d\n",
- failure_return, delay_return, success_return, queueit);
-
- /*
- ** If we had some fatal error, but no addresses are marked as
- ** bad, mark them _all_ as bad.
- */
-
- if (bitset(EF_FATALERRS, e->e_flags) && !failure_return)
- {
- for (q = e->e_sendqueue; q != NULL; q = q->q_next)
- {
- if (!bitset(QDONTSEND, q->q_flags) &&
- bitset(QPINGONFAILURE, q->q_flags))
- {
- failure_return = TRUE;
- q->q_flags |= QBADADDR;
- }
- }
- }
-
- /*
- ** Send back return receipts as requested.
- */
-
- if (success_return && !failure_return && !delay_return && fulldrop &&
- !bitset(PRIV_NORECEIPTS, PrivacyFlags) &&
- strcmp(e->e_from.q_paddr, "<>") != 0)
- {
- auto ADDRESS *rlist = NULL;
-
- if (tTd(50, 8))
- printf("dropenvelope(%s): sending return receipt\n", id);
- e->e_flags |= EF_SENDRECEIPT;
- (void) sendtolist(e->e_from.q_paddr, NULLADDR, &rlist, 0, e);
- (void) returntosender("Return receipt", rlist, RTSF_NO_BODY, e);
- }
- e->e_flags &= ~EF_SENDRECEIPT;
-
- /*
- ** Arrange to send error messages if there are fatal errors.
- */
-
- if ((failure_return || delay_return) && e->e_errormode != EM_QUIET)
- {
- extern void savemail __P((ENVELOPE *, bool));
-
- if (tTd(50, 8))
- printf("dropenvelope(%s): saving mail\n", id);
- savemail(e, !bitset(EF_NO_BODY_RETN, e->e_flags));
- }
-
- /*
- ** Arrange to send warning messages to postmaster as requested.
- */
-
- if ((failure_return || bitset(EF_PM_NOTIFY, e->e_flags)) &&
- PostMasterCopy != NULL &&
- !bitset(EF_RESPONSE, e->e_flags) && e->e_class >= 0)
- {
- auto ADDRESS *rlist = NULL;
-
- if (tTd(50, 8))
- printf("dropenvelope(%s): sending postmaster copy\n", id);
- (void) sendtolist(PostMasterCopy, NULLADDR, &rlist, 0, e);
- (void) returntosender(e->e_message, rlist, RTSF_PM_BOUNCE, e);
- }
-
- /*
- ** Instantiate or deinstantiate the queue.
- */
-
-simpledrop:
- if (tTd(50, 8))
- printf("dropenvelope(%s): at simpledrop, queueit=%d\n",
- id, queueit);
- if (!queueit || bitset(EF_CLRQUEUE, e->e_flags))
- {
- if (tTd(50, 1))
- {
- extern void printenvflags __P((ENVELOPE *));
-
- printf("\n===== Dropping [dq]f%s... queueit=%d, e_flags=",
- e->e_id, queueit);
- printenvflags(e);
- }
- xunlink(queuename(e, 'd'));
- xunlink(queuename(e, 'q'));
-
- if (LogLevel > 10)
- sm_syslog(LOG_INFO, id, "done");
- }
- else if (queueit || !bitset(EF_INQUEUE, e->e_flags))
- {
-#if QUEUE
- queueup(e, FALSE);
-#else /* QUEUE */
- syserr("554 dropenvelope: queueup");
-#endif /* QUEUE */
- }
-
- /* now unlock the job */
- if (tTd(50, 8))
- printf("dropenvelope(%s): unlocking job\n", id);
- closexscript(e);
- unlockqueue(e);
-
- /* make sure that this envelope is marked unused */
- if (e->e_dfp != NULL)
- (void) xfclose(e->e_dfp, "dropenvelope df", e->e_id);
- e->e_dfp = NULL;
- e->e_id = NULL;
- e->e_flags &= ~EF_HAS_DF;
-}
- /*
-** CLEARENVELOPE -- clear an envelope without unlocking
-**
-** This is normally used by a child process to get a clean
-** envelope without disturbing the parent.
-**
-** Parameters:
-** e -- the envelope to clear.
-** fullclear - if set, the current envelope is total
-** garbage and should be ignored; otherwise,
-** release any resources it may indicate.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Closes files associated with the envelope.
-** Marks the envelope as unallocated.
-*/
-
-void
-clearenvelope(e, fullclear)
- register ENVELOPE *e;
- bool fullclear;
-{
- register HDR *bh;
- register HDR **nhp;
- extern ENVELOPE BlankEnvelope;
-
- if (!fullclear)
- {
- /* clear out any file information */
- if (e->e_xfp != NULL)
- (void) xfclose(e->e_xfp, "clearenvelope xfp", e->e_id);
- if (e->e_dfp != NULL)
- (void) xfclose(e->e_dfp, "clearenvelope dfp", e->e_id);
- e->e_xfp = e->e_dfp = NULL;
- }
-
- /* now clear out the data */
- STRUCTCOPY(BlankEnvelope, *e);
- e->e_message = NULL;
- if (Verbose)
- e->e_sendmode = SM_DELIVER;
- bh = BlankEnvelope.e_header;
- nhp = &e->e_header;
- while (bh != NULL)
- {
- *nhp = (HDR *) xalloc(sizeof *bh);
- bcopy((char *) bh, (char *) *nhp, sizeof *bh);
- bh = bh->h_link;
- nhp = &(*nhp)->h_link;
- }
-}
- /*
-** INITSYS -- initialize instantiation of system
-**
-** In Daemon mode, this is done in the child.
-**
-** Parameters:
-** none.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Initializes the system macros, some global variables,
-** etc. In particular, the current time in various
-** forms is set.
-*/
-
-void
-initsys(e)
- register ENVELOPE *e;
-{
- char cbuf[5]; /* holds hop count */
- char pbuf[10]; /* holds pid */
-#ifdef TTYNAME
- static char ybuf[60]; /* holds tty id */
- register char *p;
- extern char *ttyname();
-#endif /* TTYNAME */
- extern void settime __P((ENVELOPE *));
-
- /*
- ** Give this envelope a reality.
- ** I.e., an id, a transcript, and a creation time.
- */
-
- openxscript(e);
- e->e_ctime = curtime();
-
- /*
- ** Set OutChannel to something useful if stdout isn't it.
- ** This arranges that any extra stuff the mailer produces
- ** gets sent back to the user on error (because it is
- ** tucked away in the transcript).
- */
-
- if (OpMode == MD_DAEMON && bitset(EF_QUEUERUN, e->e_flags) &&
- e->e_xfp != NULL)
- OutChannel = e->e_xfp;
-
- /*
- ** Set up some basic system macros.
- */
-
- /* process id */
- (void) snprintf(pbuf, sizeof pbuf, "%d", getpid());
- define('p', newstr(pbuf), e);
-
- /* hop count */
- (void) snprintf(cbuf, sizeof cbuf, "%d", e->e_hopcount);
- define('c', newstr(cbuf), e);
-
- /* time as integer, unix time, arpa time */
- settime(e);
-
-#ifdef TTYNAME
- /* tty name */
- if (macvalue('y', e) == NULL)
- {
- p = ttyname(2);
- if (p != NULL)
- {
- if (strrchr(p, '/') != NULL)
- p = strrchr(p, '/') + 1;
- snprintf(ybuf, sizeof ybuf, "%s", p);
- define('y', ybuf, e);
- }
- }
-#endif /* TTYNAME */
-}
- /*
-** SETTIME -- set the current time.
-**
-** Parameters:
-** none.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Sets the various time macros -- $a, $b, $d, $t.
-*/
-
-void
-settime(e)
- register ENVELOPE *e;
-{
- register char *p;
- auto time_t now;
- char tbuf[20]; /* holds "current" time */
- char dbuf[30]; /* holds ctime(tbuf) */
- register struct tm *tm;
- extern struct tm *gmtime();
-
- now = curtime();
- tm = gmtime(&now);
- (void) snprintf(tbuf, sizeof tbuf, "%04d%02d%02d%02d%02d", tm->tm_year + 1900,
- tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min);
- define('t', newstr(tbuf), e);
- (void) strcpy(dbuf, ctime(&now));
- p = strchr(dbuf, '\n');
- if (p != NULL)
- *p = '\0';
- define('d', newstr(dbuf), e);
- p = arpadate(dbuf);
- p = newstr(p);
- if (macvalue('a', e) == NULL)
- define('a', p, e);
- define('b', p, e);
-}
- /*
-** OPENXSCRIPT -- Open transcript file
-**
-** Creates a transcript file for possible eventual mailing or
-** sending back.
-**
-** Parameters:
-** e -- the envelope to create the transcript in/for.
-**
-** Returns:
-** none
-**
-** Side Effects:
-** Creates the transcript file.
-*/
-
-#ifndef O_APPEND
-#define O_APPEND 0
-#endif
-
-void
-openxscript(e)
- register ENVELOPE *e;
-{
- register char *p;
- int fd;
-
- if (e->e_xfp != NULL)
- return;
- p = queuename(e, 'x');
- fd = open(p, O_WRONLY|O_CREAT|O_APPEND, FileMode);
- if (fd < 0)
- {
- syserr("Can't create transcript file %s", p);
- fd = open("/dev/null", O_WRONLY, 0644);
- if (fd < 0)
- syserr("!Can't open /dev/null");
- }
- e->e_xfp = fdopen(fd, "a");
- if (e->e_xfp == NULL)
- syserr("!Can't create transcript stream %s", p);
-#ifdef HASSETVBUF
- setvbuf(e->e_xfp, NULL, _IOLBF, 0);
-#else
- setlinebuf(e->e_xfp);
-#endif
- if (tTd(46, 9))
- {
- printf("openxscript(%s):\n ", p);
- dumpfd(fileno(e->e_xfp), TRUE, FALSE);
- }
-}
- /*
-** CLOSEXSCRIPT -- close the transcript file.
-**
-** Parameters:
-** e -- the envelope containing the transcript to close.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** none.
-*/
-
-void
-closexscript(e)
- register ENVELOPE *e;
-{
- if (e->e_xfp == NULL)
- return;
- (void) xfclose(e->e_xfp, "closexscript", e->e_id);
- e->e_xfp = NULL;
-}
- /*
-** SETSENDER -- set the person who this message is from
-**
-** Under certain circumstances allow the user to say who
-** s/he is (using -f or -r). These are:
-** 1. The user's uid is zero (root).
-** 2. The user's login name is in an approved list (typically
-** from a network server).
-** 3. The address the user is trying to claim has a
-** "!" character in it (since #2 doesn't do it for
-** us if we are dialing out for UUCP).
-** A better check to replace #3 would be if the
-** effective uid is "UUCP" -- this would require me
-** to rewrite getpwent to "grab" uucp as it went by,
-** make getname more nasty, do another passwd file
-** scan, or compile the UID of "UUCP" into the code,
-** all of which are reprehensible.
-**
-** Assuming all of these fail, we figure out something
-** ourselves.
-**
-** Parameters:
-** from -- the person we would like to believe this message
-** is from, as specified on the command line.
-** e -- the envelope in which we would like the sender set.
-** delimptr -- if non-NULL, set to the location of the
-** trailing delimiter.
-** delimchar -- the character that will delimit the sender
-** address.
-** internal -- set if this address is coming from an internal
-** source such as an owner alias.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** sets sendmail's notion of who the from person is.
-*/
-
-void
-setsender(from, e, delimptr, delimchar, internal)
- char *from;
- register ENVELOPE *e;
- char **delimptr;
- int delimchar;
- bool internal;
-{
- register char **pvp;
- char *realname = NULL;
- register struct passwd *pw;
- char *bp;
- char buf[MAXNAME + 2];
- char pvpbuf[PSBUFSIZE];
- extern char *FullName;
-
- if (tTd(45, 1))
- printf("setsender(%s)\n", from == NULL ? "" : from);
-
- /*
- ** Figure out the real user executing us.
- ** Username can return errno != 0 on non-errors.
- */
-
- if (bitset(EF_QUEUERUN, e->e_flags) || OpMode == MD_SMTP ||
- OpMode == MD_ARPAFTP || OpMode == MD_DAEMON)
- realname = from;
- if (realname == NULL || realname[0] == '\0')
- realname = username();
-
- if (ConfigLevel < 2)
- SuprErrs = TRUE;
-
- e->e_from.q_flags = QBADADDR;
- if (from == NULL ||
- parseaddr(from, &e->e_from, RF_COPYALL|RF_SENDERADDR,
- delimchar, delimptr, e) == NULL ||
- bitset(QBADADDR, e->e_from.q_flags) ||
- e->e_from.q_mailer == ProgMailer ||
- e->e_from.q_mailer == FileMailer ||
- e->e_from.q_mailer == InclMailer)
- {
- /* log garbage addresses for traceback */
- if (from != NULL && LogLevel > 2)
- {
- char *p;
- char ebuf[MAXNAME * 2 + 2];
-
- p = macvalue('_', e);
- if (p == NULL)
- {
- char *host = RealHostName;
-
- if (host == NULL)
- host = MyHostName;
- (void) snprintf(ebuf, sizeof ebuf, "%.*s@%.*s",
- MAXNAME, realname,
- MAXNAME, host);
- p = ebuf;
- }
- sm_syslog(LOG_NOTICE, e->e_id,
- "setsender: %s: invalid or unparseable, received from %s",
- shortenstring(from, 83), p);
- }
- if (from != NULL)
- {
- if (!bitset(QBADADDR, e->e_from.q_flags))
- {
- /* it was a bogus mailer in the from addr */
- e->e_status = "5.1.7";
- usrerr("553 Invalid sender address");
- }
- SuprErrs = TRUE;
- }
- if (from == realname ||
- parseaddr(from = newstr(realname), &e->e_from,
- RF_COPYALL|RF_SENDERADDR, ' ', NULL, e) == NULL)
- {
- char nbuf[100];
-
- SuprErrs = TRUE;
- expand("\201n", nbuf, sizeof nbuf, e);
- if (parseaddr(from = newstr(nbuf), &e->e_from,
- RF_COPYALL, ' ', NULL, e) == NULL &&
- parseaddr(from = "postmaster", &e->e_from,
- RF_COPYALL, ' ', NULL, e) == NULL)
- syserr("553 setsender: can't even parse postmaster!");
- }
- }
- else
- FromFlag = TRUE;
- e->e_from.q_flags |= QDONTSEND;
- if (tTd(45, 5))
- {
- printf("setsender: QDONTSEND ");
- printaddr(&e->e_from, FALSE);
- }
- SuprErrs = FALSE;
-
-# if USERDB
- if (bitnset(M_CHECKUDB, e->e_from.q_mailer->m_flags))
- {
- register char *p;
- extern char *udbsender __P((char *));
-
- p = udbsender(e->e_from.q_user);
- if (p != NULL)
- from = p;
- }
-# endif /* USERDB */
-
- if (bitnset(M_HASPWENT, e->e_from.q_mailer->m_flags))
- {
- if (!internal)
- {
- /* if the user already given fullname don't redefine */
- if (FullName == NULL)
- FullName = macvalue('x', e);
- if (FullName != NULL && FullName[0] == '\0')
- FullName = NULL;
- }
-
- if (e->e_from.q_user[0] != '\0' &&
- (pw = sm_getpwnam(e->e_from.q_user)) != NULL)
- {
- /*
- ** Process passwd file entry.
- */
-
- /* extract home directory */
- if (strcmp(pw->pw_dir, "/") == 0)
- e->e_from.q_home = newstr("");
- else
- e->e_from.q_home = newstr(pw->pw_dir);
- define('z', e->e_from.q_home, e);
-
- /* extract user and group id */
- e->e_from.q_uid = pw->pw_uid;
- e->e_from.q_gid = pw->pw_gid;
- e->e_from.q_flags |= QGOODUID;
-
- /* extract full name from passwd file */
- if (FullName == NULL && pw->pw_gecos != NULL &&
- strcmp(pw->pw_name, e->e_from.q_user) == 0 &&
- !internal)
- {
- buildfname(pw->pw_gecos, e->e_from.q_user, buf, sizeof buf);
- if (buf[0] != '\0')
- FullName = newstr(buf);
- }
- }
- else
- {
- e->e_from.q_home = "/no/such/directory";
- }
- if (FullName != NULL && !internal)
- define('x', FullName, e);
- }
- else if (!internal && OpMode != MD_DAEMON && OpMode != MD_SMTP)
- {
- if (e->e_from.q_home == NULL)
- {
- e->e_from.q_home = getenv("HOME");
- if (e->e_from.q_home != NULL &&
- strcmp(e->e_from.q_home, "/") == 0)
- e->e_from.q_home++;
- }
- e->e_from.q_uid = RealUid;
- e->e_from.q_gid = RealGid;
- e->e_from.q_flags |= QGOODUID;
- }
-
- /*
- ** Rewrite the from person to dispose of possible implicit
- ** links in the net.
- */
-
- pvp = prescan(from, delimchar, pvpbuf, sizeof pvpbuf, NULL, NULL);
- if (pvp == NULL)
- {
- /* don't need to give error -- prescan did that already */
- if (LogLevel > 2)
- sm_syslog(LOG_NOTICE, e->e_id,
- "cannot prescan from (%s)",
- shortenstring(from, MAXSHORTSTR));
- finis(TRUE, ExitStat);
- }
- (void) rewrite(pvp, 3, 0, e);
- (void) rewrite(pvp, 1, 0, e);
- (void) rewrite(pvp, 4, 0, e);
- bp = buf + 1;
- cataddr(pvp, NULL, bp, sizeof buf - 2, '\0');
- if (*bp == '@' && !bitnset(M_NOBRACKET, e->e_from.q_mailer->m_flags))
- {
- /* heuristic: route-addr: add angle brackets */
- strcat(bp, ">");
- *--bp = '<';
- }
- e->e_sender = newstr(bp);
- define('f', e->e_sender, e);
-
- /* save the domain spec if this mailer wants it */
- if (e->e_from.q_mailer != NULL &&
- bitnset(M_CANONICAL, e->e_from.q_mailer->m_flags))
- {
- char **lastat;
- extern char **copyplist __P((char **, bool));
-
- /* get rid of any pesky angle brackets */
- (void) rewrite(pvp, 3, 0, e);
- (void) rewrite(pvp, 1, 0, e);
- (void) rewrite(pvp, 4, 0, e);
-
- /* strip off to the last "@" sign */
- for (lastat = NULL; *pvp != NULL; pvp++)
- if (strcmp(*pvp, "@") == 0)
- lastat = pvp;
- if (lastat != NULL)
- {
- e->e_fromdomain = copyplist(lastat, TRUE);
- if (tTd(45, 3))
- {
- printf("Saving from domain: ");
- printav(e->e_fromdomain);
- }
- }
- }
-}
- /*
-** PRINTENVFLAGS -- print envelope flags for debugging
-**
-** Parameters:
-** e -- the envelope with the flags to be printed.
-**
-** Returns:
-** none.
-*/
-
-struct eflags
-{
- char *ef_name;
- u_long ef_bit;
-};
-
-struct eflags EnvelopeFlags[] =
-{
- { "OLDSTYLE", EF_OLDSTYLE },
- { "INQUEUE", EF_INQUEUE },
- { "NO_BODY_RETN", EF_NO_BODY_RETN },
- { "CLRQUEUE", EF_CLRQUEUE },
- { "SENDRECEIPT", EF_SENDRECEIPT },
- { "FATALERRS", EF_FATALERRS },
- { "DELETE_BCC", EF_DELETE_BCC },
- { "RESPONSE", EF_RESPONSE },
- { "RESENT", EF_RESENT },
- { "VRFYONLY", EF_VRFYONLY },
- { "WARNING", EF_WARNING },
- { "QUEUERUN", EF_QUEUERUN },
- { "GLOBALERRS", EF_GLOBALERRS },
- { "PM_NOTIFY", EF_PM_NOTIFY },
- { "METOO", EF_METOO },
- { "LOGSENDER", EF_LOGSENDER },
- { "NORECEIPT", EF_NORECEIPT },
- { "HAS8BIT", EF_HAS8BIT },
- { "NL_NOT_EOL", EF_NL_NOT_EOL },
- { "CRLF_NOT_EOL", EF_CRLF_NOT_EOL },
- { "RET_PARAM", EF_RET_PARAM },
- { "HAS_DF", EF_HAS_DF },
- { "IS_MIME", EF_IS_MIME },
- { "DONT_MIME", EF_DONT_MIME },
- { NULL }
-};
-
-void
-printenvflags(e)
- register ENVELOPE *e;
-{
- register struct eflags *ef;
- bool first = TRUE;
-
- printf("%lx", e->e_flags);
- for (ef = EnvelopeFlags; ef->ef_name != NULL; ef++)
- {
- if (!bitset(ef->ef_bit, e->e_flags))
- continue;
- if (first)
- printf("<%s", ef->ef_name);
- else
- printf(",%s", ef->ef_name);
- first = FALSE;
- }
- if (!first)
- printf(">\n");
-}
diff --git a/src/err.c b/src/err.c
deleted file mode 100644
index 1a875a2..0000000
--- a/src/err.c
+++ /dev/null
@@ -1,767 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)err.c 8.74 (Berkeley) 6/4/1998";
-#endif /* not lint */
-
-# include "sendmail.h"
-# include <errno.h>
-
-/*
-** SYSERR -- Print error message.
-**
-** Prints an error message via printf to the diagnostic output.
-**
-** If the first character of the syserr message is `!' it will
-** log this as an ALERT message and exit immediately. This can
-** leave queue files in an indeterminate state, so it should not
-** be used lightly.
-**
-** Parameters:
-** fmt -- the format string. If it does not begin with
-** a three-digit SMTP reply code, either 554 or
-** 451 is assumed depending on whether errno
-** is set.
-** (others) -- parameters
-**
-** Returns:
-** none
-** Through TopFrame if QuickAbort is set.
-**
-** Side Effects:
-** increments Errors.
-** sets ExitStat.
-*/
-
-char MsgBuf[BUFSIZ*2]; /* text of most recent message */
-char HeldMessageBuf[sizeof MsgBuf]; /* for held messages */
-
-extern void putoutmsg __P((char *, bool, bool));
-extern void puterrmsg __P((char *));
-static void fmtmsg __P((char *, const char *, const char *, int, const char *, va_list));
-
-#if NAMED_BIND && !defined(NO_DATA)
-# define NO_DATA NO_ADDRESS
-#endif
-
-void
-/*VARARGS1*/
-#ifdef __STDC__
-syserr(const char *fmt, ...)
-#else
-syserr(fmt, va_alist)
- const char *fmt;
- va_dcl
-#endif
-{
- register char *p;
- int olderrno = errno;
- bool panic;
- char *uname;
- struct passwd *pw;
- char ubuf[80];
- VA_LOCAL_DECL
-
- panic = *fmt == '!';
- if (panic)
- {
- fmt++;
- HoldErrs = FALSE;
- }
-
- /* format and output the error message */
- if (olderrno == 0)
- p = "554";
- else
- p = "451";
- VA_START(fmt);
- fmtmsg(MsgBuf, (char *) NULL, p, olderrno, fmt, ap);
- VA_END;
- puterrmsg(MsgBuf);
-
- /* save this message for mailq printing */
- if (!panic && CurEnv != NULL)
- {
- if (CurEnv->e_message != NULL)
- free(CurEnv->e_message);
- CurEnv->e_message = newstr(MsgBuf + 4);
- }
-
- /* determine exit status if not already set */
- if (ExitStat == EX_OK)
- {
- if (olderrno == 0)
- ExitStat = EX_SOFTWARE;
- else
- ExitStat = EX_OSERR;
- if (tTd(54, 1))
- printf("syserr: ExitStat = %d\n", ExitStat);
- }
-
- pw = sm_getpwuid(getuid());
- if (pw != NULL)
- uname = pw->pw_name;
- else
- {
- uname = ubuf;
- snprintf(ubuf, sizeof ubuf, "UID%d", getuid());
- }
-
- if (LogLevel > 0)
- sm_syslog(panic ? LOG_ALERT : LOG_CRIT,
- CurEnv == NULL ? NOQID : CurEnv->e_id,
- "SYSERR(%s): %.900s",
- uname, &MsgBuf[4]);
- switch (olderrno)
- {
- case EBADF:
- case ENFILE:
- case EMFILE:
- case ENOTTY:
-#ifdef EFBIG
- case EFBIG:
-#endif
-#ifdef ESPIPE
- case ESPIPE:
-#endif
-#ifdef EPIPE
- case EPIPE:
-#endif
-#ifdef ENOBUFS
- case ENOBUFS:
-#endif
-#ifdef ESTALE
- case ESTALE:
-#endif
- printopenfds(TRUE);
- mci_dump_all(TRUE);
- break;
- }
- if (panic)
- {
-#ifdef XLA
- xla_all_end();
-#endif
- if (tTd(0, 1))
- abort();
- exit(EX_OSERR);
- }
- errno = 0;
- if (QuickAbort)
- longjmp(TopFrame, 2);
-}
- /*
-** USRERR -- Signal user error.
-**
-** This is much like syserr except it is for user errors.
-**
-** Parameters:
-** fmt -- the format string. If it does not begin with
-** a three-digit SMTP reply code, 501 is assumed.
-** (others) -- printf strings
-**
-** Returns:
-** none
-** Through TopFrame if QuickAbort is set.
-**
-** Side Effects:
-** increments Errors.
-*/
-
-/*VARARGS1*/
-void
-#ifdef __STDC__
-usrerr(const char *fmt, ...)
-#else
-usrerr(fmt, va_alist)
- const char *fmt;
- va_dcl
-#endif
-{
- VA_LOCAL_DECL
-
- if (SuprErrs)
- return;
-
- VA_START(fmt);
- fmtmsg(MsgBuf, CurEnv->e_to, "501", 0, fmt, ap);
- VA_END;
-
- /* save this message for mailq printing */
- switch (MsgBuf[0])
- {
- case '4':
- case '8':
- if (CurEnv->e_message != NULL)
- break;
-
- /* fall through.... */
-
- case '5':
- case '6':
- if (CurEnv->e_message != NULL)
- free(CurEnv->e_message);
- if (MsgBuf[0] == '6')
- {
- char buf[MAXLINE];
-
- snprintf(buf, sizeof buf, "Postmaster warning: %.*s",
- sizeof buf - 22, MsgBuf + 4);
- CurEnv->e_message = newstr(buf);
- }
- else
- {
- CurEnv->e_message = newstr(MsgBuf + 4);
- }
- break;
- }
-
- puterrmsg(MsgBuf);
-
- if (LogLevel > 3 && LogUsrErrs)
- sm_syslog(LOG_NOTICE, CurEnv->e_id,
- "%.900s",
- &MsgBuf[4]);
-
- if (QuickAbort)
- longjmp(TopFrame, 1);
-}
- /*
-** MESSAGE -- print message (not necessarily an error)
-**
-** Parameters:
-** msg -- the message (printf fmt) -- it can begin with
-** an SMTP reply code. If not, 050 is assumed.
-** (others) -- printf arguments
-**
-** Returns:
-** none
-**
-** Side Effects:
-** none.
-*/
-
-/*VARARGS1*/
-void
-#ifdef __STDC__
-message(const char *msg, ...)
-#else
-message(msg, va_alist)
- const char *msg;
- va_dcl
-#endif
-{
- VA_LOCAL_DECL
-
- errno = 0;
- VA_START(msg);
- fmtmsg(MsgBuf, CurEnv->e_to, "050", 0, msg, ap);
- VA_END;
- putoutmsg(MsgBuf, FALSE, FALSE);
-
- /* save this message for mailq printing */
- switch (MsgBuf[0])
- {
- case '4':
- case '8':
- if (CurEnv->e_message != NULL)
- break;
- /* fall through.... */
-
- case '5':
- if (CurEnv->e_message != NULL)
- free(CurEnv->e_message);
- CurEnv->e_message = newstr(MsgBuf + 4);
- break;
- }
-}
- /*
-** NMESSAGE -- print message (not necessarily an error)
-**
-** Just like "message" except it never puts the to... tag on.
-**
-** Parameters:
-** msg -- the message (printf fmt) -- if it begins
-** with a three digit SMTP reply code, that is used,
-** otherwise 050 is assumed.
-** (others) -- printf arguments
-**
-** Returns:
-** none
-**
-** Side Effects:
-** none.
-*/
-
-/*VARARGS1*/
-void
-#ifdef __STDC__
-nmessage(const char *msg, ...)
-#else
-nmessage(msg, va_alist)
- const char *msg;
- va_dcl
-#endif
-{
- VA_LOCAL_DECL
-
- errno = 0;
- VA_START(msg);
- fmtmsg(MsgBuf, (char *) NULL, "050", 0, msg, ap);
- VA_END;
- putoutmsg(MsgBuf, FALSE, FALSE);
-
- /* save this message for mailq printing */
- switch (MsgBuf[0])
- {
- case '4':
- case '8':
- if (CurEnv->e_message != NULL)
- break;
- /* fall through.... */
-
- case '5':
- if (CurEnv->e_message != NULL)
- free(CurEnv->e_message);
- CurEnv->e_message = newstr(MsgBuf + 4);
- break;
- }
-}
- /*
-** PUTOUTMSG -- output error message to transcript and channel
-**
-** Parameters:
-** msg -- message to output (in SMTP format).
-** holdmsg -- if TRUE, don't output a copy of the message to
-** our output channel.
-** heldmsg -- if TRUE, this is a previously held message;
-** don't log it to the transcript file.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Outputs msg to the transcript.
-** If appropriate, outputs it to the channel.
-** Deletes SMTP reply code number as appropriate.
-*/
-
-void
-putoutmsg(msg, holdmsg, heldmsg)
- char *msg;
- bool holdmsg;
- bool heldmsg;
-{
- char msgcode = msg[0];
-
- /* display for debugging */
- if (tTd(54, 8))
- printf("--- %s%s%s\n", msg, holdmsg ? " (hold)" : "",
- heldmsg ? " (held)" : "");
-
- /* map warnings to something SMTP can handle */
- if (msgcode == '6')
- msg[0] = '5';
- else if (msgcode == '8')
- msg[0] = '4';
-
- /* output to transcript if serious */
- if (!heldmsg && CurEnv != NULL && CurEnv->e_xfp != NULL &&
- strchr("45", msg[0]) != NULL)
- fprintf(CurEnv->e_xfp, "%s\n", msg);
-
- if (LogLevel >= 15 && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
- sm_syslog(LOG_INFO, CurEnv->e_id,
- "--> %s%s",
- msg, holdmsg ? " (held)" : "");
-
- if (msgcode == '8')
- msg[0] = '0';
-
- /* output to channel if appropriate */
- if (!Verbose && msg[0] == '0')
- return;
- if (holdmsg)
- {
- /* save for possible future display */
- msg[0] = msgcode;
- snprintf(HeldMessageBuf, sizeof HeldMessageBuf, "%s", msg);
- return;
- }
-
- (void) fflush(stdout);
-
- if (OutChannel == NULL)
- return;
-
- /* if DisConnected, OutChannel now points to the transcript */
- if (!DisConnected &&
- (OpMode == MD_SMTP || OpMode == MD_DAEMON || OpMode == MD_ARPAFTP))
- fprintf(OutChannel, "%s\r\n", msg);
- else
- fprintf(OutChannel, "%s\n", &msg[4]);
- if (TrafficLogFile != NULL)
- fprintf(TrafficLogFile, "%05d >>> %s\n", (int) getpid(),
- (OpMode == MD_SMTP || OpMode == MD_DAEMON) ? msg : &msg[4]);
- if (msg[3] == ' ')
- (void) fflush(OutChannel);
- if (!ferror(OutChannel) || DisConnected)
- return;
-
- /*
- ** Error on output -- if reporting lost channel, just ignore it.
- ** Also, ignore errors from QUIT response (221 message) -- some
- ** rude servers don't read result.
- */
-
- if (InChannel == NULL || feof(InChannel) || ferror(InChannel) ||
- strncmp(msg, "221", 3) == 0)
- return;
-
- /* can't call syserr, 'cause we are using MsgBuf */
- HoldErrs = TRUE;
- if (LogLevel > 0)
- sm_syslog(LOG_CRIT, CurEnv->e_id,
- "SYSERR: putoutmsg (%s): error on output channel sending \"%s\": %s",
- CurHostName == NULL ? "NO-HOST" : CurHostName,
- shortenstring(msg, MAXSHORTSTR), errstring(errno));
-}
- /*
-** PUTERRMSG -- like putoutmsg, but does special processing for error messages
-**
-** Parameters:
-** msg -- the message to output.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Sets the fatal error bit in the envelope as appropriate.
-*/
-
-void
-puterrmsg(msg)
- char *msg;
-{
- char msgcode = msg[0];
-
- /* output the message as usual */
- putoutmsg(msg, HoldErrs, FALSE);
-
- /* be careful about multiple error messages */
- if (OnlyOneError)
- HoldErrs = TRUE;
-
- /* signal the error */
- Errors++;
-
- if (CurEnv == NULL)
- return;
-
- if (msgcode == '6')
- {
- /* notify the postmaster */
- CurEnv->e_flags |= EF_PM_NOTIFY;
- }
- else if (msgcode == '5' && bitset(EF_GLOBALERRS, CurEnv->e_flags))
- {
- /* mark long-term fatal errors */
- CurEnv->e_flags |= EF_FATALERRS;
- }
-}
- /*
-** FMTMSG -- format a message into buffer.
-**
-** Parameters:
-** eb -- error buffer to get result.
-** to -- the recipient tag for this message.
-** num -- arpanet error number.
-** en -- the error number to display.
-** fmt -- format of string.
-** a, b, c, d, e -- arguments.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** none.
-*/
-
-static void
-fmtmsg(eb, to, num, eno, fmt, ap)
- register char *eb;
- const char *to;
- const char *num;
- int eno;
- const char *fmt;
- va_list ap;
-{
- char del;
- int l;
- int spaceleft = sizeof MsgBuf;
-
- /* output the reply code */
- if (isascii(fmt[0]) && isdigit(fmt[0]) &&
- isascii(fmt[1]) && isdigit(fmt[1]) &&
- isascii(fmt[2]) && isdigit(fmt[2]))
- {
- num = fmt;
- fmt += 4;
- }
- if (num[3] == '-')
- del = '-';
- else
- del = ' ';
- (void) snprintf(eb, spaceleft, "%3.3s%c", num, del);
- eb += 4;
- spaceleft -= 4;
-
- /* output the file name and line number */
- if (FileName != NULL)
- {
- (void) snprintf(eb, spaceleft, "%s: line %d: ",
- shortenstring(FileName, 83), LineNumber);
- eb += (l = strlen(eb));
- spaceleft -= l;
- }
-
- /* output the "to" person */
- if (to != NULL && to[0] != '\0' &&
- strncmp(num, "551", 3) != 0 &&
- strncmp(num, "251", 3) != 0)
- {
- (void) snprintf(eb, spaceleft, "%s... ",
- shortenstring(to, MAXSHORTSTR));
- spaceleft -= strlen(eb);
- while (*eb != '\0')
- *eb++ &= 0177;
- }
-
- /* output the message */
- (void) vsnprintf(eb, spaceleft, fmt, ap);
- spaceleft -= strlen(eb);
- while (*eb != '\0')
- *eb++ &= 0177;
-
- /* output the error code, if any */
- if (eno != 0)
- (void) snprintf(eb, spaceleft, ": %s", errstring(eno));
-}
- /*
-** BUFFER_ERRORS -- arrange to buffer future error messages
-**
-** Parameters:
-** none
-**
-** Returns:
-** none.
-*/
-
-void
-buffer_errors()
-{
- HeldMessageBuf[0] = '\0';
- HoldErrs = TRUE;
-}
- /*
-** FLUSH_ERRORS -- flush the held error message buffer
-**
-** Parameters:
-** print -- if set, print the message, otherwise just
-** delete it.
-**
-** Returns:
-** none.
-*/
-
-void
-flush_errors(print)
- bool print;
-{
- if (print && HeldMessageBuf[0] != '\0')
- putoutmsg(HeldMessageBuf, FALSE, TRUE);
- HeldMessageBuf[0] = '\0';
- HoldErrs = FALSE;
-}
- /*
-** ERRSTRING -- return string description of error code
-**
-** Parameters:
-** errnum -- the error number to translate
-**
-** Returns:
-** A string description of errnum.
-**
-** Side Effects:
-** none.
-*/
-
-const char *
-errstring(errnum)
- int errnum;
-{
- char *dnsmsg;
- char *bp;
- static char buf[MAXLINE];
-# if !HASSTRERROR && !defined(ERRLIST_PREDEFINED)
- extern char *sys_errlist[];
- extern int sys_nerr;
-# endif
-# if SMTP
- extern char *SmtpPhase;
-# endif /* SMTP */
-
- /*
- ** Handle special network error codes.
- **
- ** These are 4.2/4.3bsd specific; they should be in daemon.c.
- */
-
- dnsmsg = NULL;
- switch (errnum)
- {
-# if defined(DAEMON) && defined(ETIMEDOUT)
- case ETIMEDOUT:
- case ECONNRESET:
- bp = buf;
-#if HASSTRERROR
- snprintf(bp, SPACELEFT(buf, bp), "%s", strerror(errnum));
-#else
- if (errnum >= 0 && errnum < sys_nerr)
- snprintf(bp, SPACELEFT(buf, bp), "%s", sys_errlist[errnum]);
- else
- snprintf(bp, SPACELEFT(buf, bp), "Error %d", errnum);
-#endif
- bp += strlen(bp);
- if (CurHostName != NULL)
- {
- if (errnum == ETIMEDOUT)
- {
- snprintf(bp, SPACELEFT(buf, bp), " with ");
- bp += strlen(bp);
- }
- else
- {
- bp = buf;
- snprintf(bp, SPACELEFT(buf, bp),
- "Connection reset by ");
- bp += strlen(bp);
- }
- snprintf(bp, SPACELEFT(buf, bp), "%s",
- shortenstring(CurHostName, MAXSHORTSTR));
- bp += strlen(buf);
- }
- if (SmtpPhase != NULL)
- {
- snprintf(bp, SPACELEFT(buf, bp), " during %s",
- SmtpPhase);
- }
- return (buf);
-
- case EHOSTDOWN:
- if (CurHostName == NULL)
- break;
- (void) snprintf(buf, sizeof buf, "Host %s is down",
- shortenstring(CurHostName, MAXSHORTSTR));
- return (buf);
-
- case ECONNREFUSED:
- if (CurHostName == NULL)
- break;
- (void) snprintf(buf, sizeof buf, "Connection refused by %s",
- shortenstring(CurHostName, MAXSHORTSTR));
- return (buf);
-# endif
-
-# if NAMED_BIND
- case HOST_NOT_FOUND + E_DNSBASE:
- dnsmsg = "host not found";
- break;
-
- case TRY_AGAIN + E_DNSBASE:
- dnsmsg = "host name lookup failure";
- break;
-
- case NO_RECOVERY + E_DNSBASE:
- dnsmsg = "non-recoverable error";
- break;
-
- case NO_DATA + E_DNSBASE:
- dnsmsg = "no data known";
- break;
-# endif
-
- case EPERM:
- /* SunOS gives "Not owner" -- this is the POSIX message */
- return "Operation not permitted";
-
- /*
- ** Error messages used internally in sendmail.
- */
-
- case E_SM_OPENTIMEOUT:
- return "Timeout on file open";
-
- case E_SM_NOSLINK:
- return "Symbolic links not allowed";
-
- case E_SM_NOHLINK:
- return "Hard links not allowed";
-
- case E_SM_REGONLY:
- return "Regular files only";
-
- case E_SM_ISEXEC:
- return "Executable files not allowed";
-
- case E_SM_WWDIR:
- return "World writable directory";
-
- case E_SM_GWDIR:
- return "Group writable directory";
-
- case E_SM_FILECHANGE:
- return "File changed after open";
-
- case E_SM_WWFILE:
- return "World writable file";
-
- case E_SM_GWFILE:
- return "Group writable file";
- }
-
- if (dnsmsg != NULL)
- {
- bp = buf;
- strcpy(bp, "Name server: ");
- bp += strlen(bp);
- if (CurHostName != NULL)
- {
- snprintf(bp, SPACELEFT(buf, bp), "%s: ",
- shortenstring(CurHostName, MAXSHORTSTR));
- bp += strlen(bp);
- }
- snprintf(bp, SPACELEFT(buf, bp), "%s", dnsmsg);
- return buf;
- }
-
-#if HASSTRERROR
- return strerror(errnum);
-#else
- if (errnum > 0 && errnum < sys_nerr)
- return (sys_errlist[errnum]);
-
- (void) snprintf(buf, sizeof buf, "Error %d", errnum);
- return (buf);
-#endif
-}
diff --git a/src/headers.c b/src/headers.c
deleted file mode 100644
index 6c43dcb..0000000
--- a/src/headers.c
+++ /dev/null
@@ -1,1710 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)headers.c 8.136 (Berkeley) 1/26/1999";
-#endif /* not lint */
-
-# include <errno.h>
-# include "sendmail.h"
-
-/*
-** SETUPHEADERS -- initialize headers in symbol table
-**
-** Parameters:
-** none
-**
-** Returns:
-** none
-*/
-
-void
-setupheaders()
-{
- struct hdrinfo *hi;
- STAB *s;
-
- for (hi = HdrInfo; hi->hi_field != NULL; hi++)
- {
- s = stab(hi->hi_field, ST_HEADER, ST_ENTER);
- s->s_header.hi_flags = hi->hi_flags;
- s->s_header.hi_ruleset = NULL;
- }
-}
- /*
-** CHOMPHEADER -- process and save a header line.
-**
-** Called by collect and by readcf to deal with header lines.
-**
-** Parameters:
-** line -- header as a text line.
-** def -- if set, this is a default value.
-** hdrp -- a pointer to the place to save the header.
-** e -- the envelope including this header.
-**
-** Returns:
-** flags for this header.
-**
-** Side Effects:
-** The header is saved on the header list.
-** Contents of 'line' are destroyed.
-*/
-
-struct hdrinfo NormalHeader = { NULL, 0, NULL };
-
-int
-chompheader(line, def, hdrp, e)
- char *line;
- bool def;
- HDR **hdrp;
- register ENVELOPE *e;
-{
- register char *p;
- register HDR *h;
- HDR **hp;
- char *fname;
- char *fvalue;
- bool cond = FALSE;
- bool headeronly;
- STAB *s;
- struct hdrinfo *hi;
- bool nullheader = FALSE;
- BITMAP mopts;
-
- if (tTd(31, 6))
- {
- printf("chompheader: ");
- xputs(line);
- printf("\n");
- }
-
- headeronly = hdrp != NULL;
- if (!headeronly)
- hdrp = &e->e_header;
-
- /* strip off options */
- clrbitmap(mopts);
- p = line;
- if (*p == '?')
- {
- /* have some */
- register char *q = strchr(p + 1, *p);
-
- if (q != NULL)
- {
- *q++ = '\0';
- while (*++p != '\0')
- setbitn(*p, mopts);
- p = q;
- }
- else
- syserr("553 header syntax error, line \"%s\"", line);
- cond = TRUE;
- }
-
- /* find canonical name */
- fname = p;
- while (isascii(*p) && isgraph(*p) && *p != ':')
- p++;
- fvalue = p;
- while (isascii(*p) && isspace(*p))
- p++;
- if (*p++ != ':' || fname == fvalue)
- {
- syserr("553 header syntax error, line \"%s\"", line);
- return 0;
- }
- *fvalue = '\0';
-
- /* strip field value on front */
- if (*p == ' ')
- p++;
- fvalue = p;
-
- /* if the field is null, go ahead and use the default */
- while (isascii(*p) && isspace(*p))
- p++;
- if (*p == '\0')
- nullheader = TRUE;
-
- /* security scan: long field names are end-of-header */
- if (strlen(fname) > 100)
- return H_EOH;
-
- /* check to see if it represents a ruleset call */
- if (def)
- {
- char hbuf[50];
-
- (void) expand(fvalue, hbuf, sizeof hbuf, e);
- for (p = hbuf; isascii(*p) && isspace(*p); )
- p++;
- if ((*p++ & 0377) == CALLSUBR)
- {
- auto char *endp;
-
- if (strtorwset(p, &endp, ST_ENTER) > 0)
- {
- *endp = '\0';
- s = stab(fname, ST_HEADER, ST_ENTER);
- s->s_header.hi_ruleset = newstr(p);
- }
- return 0;
- }
- }
-
- /* see if it is a known type */
- s = stab(fname, ST_HEADER, ST_FIND);
- if (s != NULL)
- hi = &s->s_header;
- else
- hi = &NormalHeader;
-
- if (tTd(31, 9))
- {
- if (s == NULL)
- printf("no header flags match\n");
- else
- printf("header match, flags=%x, ruleset=%s\n",
- hi->hi_flags,
- hi->hi_ruleset == NULL ? "<NULL>" : hi->hi_ruleset);
- }
-
- /* see if this is a resent message */
- if (!def && !headeronly && bitset(H_RESENT, hi->hi_flags))
- e->e_flags |= EF_RESENT;
-
- /* if this is an Errors-To: header keep track of it now */
- if (UseErrorsTo && !def && !headeronly &&
- bitset(H_ERRORSTO, hi->hi_flags))
- (void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e);
-
- /* if this means "end of header" quit now */
- if (!headeronly && bitset(H_EOH, hi->hi_flags))
- return hi->hi_flags;
-
- /*
- ** Horrible hack to work around problem with Lotus Notes SMTP
- ** mail gateway, which generates From: headers with newlines in
- ** them and the <address> on the second line. Although this is
- ** legal RFC 822, many MUAs don't handle this properly and thus
- ** never find the actual address.
- */
-
- if (bitset(H_FROM, hi->hi_flags) && SingleLineFromHeader)
- {
- while ((p = strchr(fvalue, '\n')) != NULL)
- *p = ' ';
- }
-
- /*
- ** If there is a check ruleset, verify it against the header.
- */
-
- if (!def && hi->hi_ruleset != NULL)
- (void) rscheck(hi->hi_ruleset, fvalue, NULL, e);
-
- /*
- ** Drop explicit From: if same as what we would generate.
- ** This is to make MH (which doesn't always give a full name)
- ** insert the full name information in all circumstances.
- */
-
- p = "resent-from";
- if (!bitset(EF_RESENT, e->e_flags))
- p += 7;
- if (!def && !headeronly && !bitset(EF_QUEUERUN, e->e_flags) &&
- strcasecmp(fname, p) == 0)
- {
- if (tTd(31, 2))
- {
- printf("comparing header from (%s) against default (%s or %s)\n",
- fvalue, e->e_from.q_paddr, e->e_from.q_user);
- }
- if (e->e_from.q_paddr != NULL &&
- (strcmp(fvalue, e->e_from.q_paddr) == 0 ||
- strcmp(fvalue, e->e_from.q_user) == 0))
- return hi->hi_flags;
- }
-
- /* delete default value for this header */
- for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link)
- {
- if (strcasecmp(fname, h->h_field) == 0 &&
- bitset(H_DEFAULT, h->h_flags) &&
- !bitset(H_FORCE, h->h_flags))
- {
- if (nullheader)
- {
- /* user-supplied value was null */
- return 0;
- }
- h->h_value = NULL;
- if (!cond)
- {
- /* copy conditions from default case */
- bcopy((char *)h->h_mflags, (char *)mopts,
- sizeof mopts);
- }
- }
- }
-
- /* create a new node */
- h = (HDR *) xalloc(sizeof *h);
- h->h_field = newstr(fname);
- h->h_value = newstr(fvalue);
- h->h_link = NULL;
- bcopy((char *) mopts, (char *) h->h_mflags, sizeof mopts);
- *hp = h;
- h->h_flags = hi->hi_flags;
-
- /* strip EOH flag if parsing MIME headers */
- if (headeronly)
- h->h_flags &= ~H_EOH;
- if (def)
- h->h_flags |= H_DEFAULT;
- if (cond)
- h->h_flags |= H_CHECK;
-
- /* hack to see if this is a new format message */
- if (!def && !headeronly && bitset(H_RCPT|H_FROM, h->h_flags) &&
- (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL ||
- strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL))
- {
- e->e_flags &= ~EF_OLDSTYLE;
- }
-
- return h->h_flags;
-}
- /*
-** ADDHEADER -- add a header entry to the end of the queue.
-**
-** This bypasses the special checking of chompheader.
-**
-** Parameters:
-** field -- the name of the header field.
-** value -- the value of the field.
-** hp -- an indirect pointer to the header structure list.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** adds the field on the list of headers for this envelope.
-*/
-
-void
-addheader(field, value, hdrlist)
- char *field;
- char *value;
- HDR **hdrlist;
-{
- register HDR *h;
- STAB *s;
- HDR **hp;
-
- /* find info struct */
- s = stab(field, ST_HEADER, ST_FIND);
-
- /* find current place in list -- keep back pointer? */
- for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link)
- {
- if (strcasecmp(field, h->h_field) == 0)
- break;
- }
-
- /* allocate space for new header */
- h = (HDR *) xalloc(sizeof *h);
- h->h_field = field;
- h->h_value = newstr(value);
- h->h_link = *hp;
- h->h_flags = H_DEFAULT;
- if (s != NULL)
- h->h_flags |= s->s_header.hi_flags;
- clrbitmap(h->h_mflags);
- *hp = h;
-}
- /*
-** HVALUE -- return value of a header.
-**
-** Only "real" fields (i.e., ones that have not been supplied
-** as a default) are used.
-**
-** Parameters:
-** field -- the field name.
-** header -- the header list.
-**
-** Returns:
-** pointer to the value part.
-** NULL if not found.
-**
-** Side Effects:
-** none.
-*/
-
-char *
-hvalue(field, header)
- char *field;
- HDR *header;
-{
- register HDR *h;
-
- for (h = header; h != NULL; h = h->h_link)
- {
- if (!bitset(H_DEFAULT, h->h_flags) &&
- strcasecmp(h->h_field, field) == 0)
- return (h->h_value);
- }
- return (NULL);
-}
- /*
-** ISHEADER -- predicate telling if argument is a header.
-**
-** A line is a header if it has a single word followed by
-** optional white space followed by a colon.
-**
-** Header fields beginning with two dashes, although technically
-** permitted by RFC822, are automatically rejected in order
-** to make MIME work out. Without this we could have a technically
-** legal header such as ``--"foo:bar"'' that would also be a legal
-** MIME separator.
-**
-** Parameters:
-** h -- string to check for possible headerness.
-**
-** Returns:
-** TRUE if h is a header.
-** FALSE otherwise.
-**
-** Side Effects:
-** none.
-*/
-
-bool
-isheader(h)
- char *h;
-{
- register char *s = h;
-
- if (s[0] == '-' && s[1] == '-')
- return FALSE;
-
- while (*s > ' ' && *s != ':' && *s != '\0')
- s++;
-
- if (h == s)
- return FALSE;
-
- /* following technically violates RFC822 */
- while (isascii(*s) && isspace(*s))
- s++;
-
- return (*s == ':');
-}
- /*
-** EATHEADER -- run through the stored header and extract info.
-**
-** Parameters:
-** e -- the envelope to process.
-** full -- if set, do full processing (e.g., compute
-** message priority). This should not be set
-** when reading a queue file because some info
-** needed to compute the priority is wrong.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Sets a bunch of global variables from information
-** in the collected header.
-** Aborts the message if the hop count is exceeded.
-*/
-
-void
-eatheader(e, full)
- register ENVELOPE *e;
- bool full;
-{
- register HDR *h;
- register char *p;
- int hopcnt = 0;
- char *msgid;
- char buf[MAXLINE];
- extern int priencode __P((char *));
-
- /*
- ** Set up macros for possible expansion in headers.
- */
-
- define('f', e->e_sender, e);
- define('g', e->e_sender, e);
- if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0')
- define('u', e->e_origrcpt, e);
- else
- define('u', NULL, e);
-
- /* full name of from person */
- p = hvalue("full-name", e->e_header);
- if (p != NULL)
- {
- extern bool rfc822_string __P((char *));
-
- if (!rfc822_string(p))
- {
- extern char *addquotes __P((char *));
-
- /*
- ** Quote a full name with special characters
- ** as a comment so crackaddr() doesn't destroy
- ** the name portion of the address.
- */
- p = addquotes(p);
- }
- define('x', p, e);
- }
-
- if (tTd(32, 1))
- printf("----- collected header -----\n");
- msgid = NULL;
- for (h = e->e_header; h != NULL; h = h->h_link)
- {
- if (tTd(32, 1))
- printf("%s: ", h->h_field);
- if (h->h_value == NULL)
- {
- if (tTd(32, 1))
- printf("<NULL>\n");
- continue;
- }
-
- /* do early binding */
- if (bitset(H_DEFAULT, h->h_flags))
- {
- if (tTd(32, 1))
- {
- printf("(");
- xputs(h->h_value);
- printf(") ");
- }
- expand(h->h_value, buf, sizeof buf, e);
- if (buf[0] != '\0')
- {
- if (bitset(H_FROM, h->h_flags))
- {
- extern char *crackaddr __P((char *));
-
- expand(crackaddr(buf), buf, sizeof buf, e);
- }
- h->h_value = newstr(buf);
- h->h_flags &= ~H_DEFAULT;
- }
- }
-
- if (tTd(32, 1))
- {
- xputs(h->h_value);
- printf("\n");
- }
-
- /* count the number of times it has been processed */
- if (bitset(H_TRACE, h->h_flags))
- hopcnt++;
-
- /* send to this person if we so desire */
- if (GrabTo && bitset(H_RCPT, h->h_flags) &&
- !bitset(H_DEFAULT, h->h_flags) &&
- (!bitset(EF_RESENT, e->e_flags) || bitset(H_RESENT, h->h_flags)))
- {
-#if 0
- int saveflags = e->e_flags;
-#endif
-
- (void) sendtolist(h->h_value, NULLADDR,
- &e->e_sendqueue, 0, e);
-
-#if 0
- /*
- ** Change functionality so a fatal error on an
- ** address doesn't affect the entire envelope.
- */
-
- /* delete fatal errors generated by this address */
- if (!bitset(EF_FATALERRS, saveflags))
- e->e_flags &= ~EF_FATALERRS;
-#endif
- }
-
- /* save the message-id for logging */
- p = "resent-message-id";
- if (!bitset(EF_RESENT, e->e_flags))
- p += 7;
- if (strcasecmp(h->h_field, p) == 0)
- {
- msgid = h->h_value;
- while (isascii(*msgid) && isspace(*msgid))
- msgid++;
- }
- }
- if (tTd(32, 1))
- printf("----------------------------\n");
-
- /* if we are just verifying (that is, sendmail -t -bv), drop out now */
- if (OpMode == MD_VERIFY)
- return;
-
- /* store hop count */
- if (hopcnt > e->e_hopcount)
- e->e_hopcount = hopcnt;
-
- /* message priority */
- p = hvalue("precedence", e->e_header);
- if (p != NULL)
- e->e_class = priencode(p);
- if (e->e_class < 0)
- e->e_timeoutclass = TOC_NONURGENT;
- else if (e->e_class > 0)
- e->e_timeoutclass = TOC_URGENT;
- if (full)
- {
- e->e_msgpriority = e->e_msgsize
- - e->e_class * WkClassFact
- + e->e_nrcpts * WkRecipFact;
- }
-
- /* message timeout priority */
- p = hvalue("priority", e->e_header);
- if (p != NULL)
- {
- /* (this should be in the configuration file) */
- if (strcasecmp(p, "urgent") == 0)
- e->e_timeoutclass = TOC_URGENT;
- else if (strcasecmp(p, "normal") == 0)
- e->e_timeoutclass = TOC_NORMAL;
- else if (strcasecmp(p, "non-urgent") == 0)
- e->e_timeoutclass = TOC_NONURGENT;
- }
-
- /* date message originated */
- p = hvalue("posted-date", e->e_header);
- if (p == NULL)
- p = hvalue("date", e->e_header);
- if (p != NULL)
- define('a', p, e);
-
- /* check to see if this is a MIME message */
- if ((e->e_bodytype != NULL &&
- strcasecmp(e->e_bodytype, "8BITMIME") == 0) ||
- hvalue("MIME-Version", e->e_header) != NULL)
- {
- e->e_flags |= EF_IS_MIME;
- if (HasEightBits)
- e->e_bodytype = "8BITMIME";
- }
- else if ((p = hvalue("Content-Type", e->e_header)) != NULL)
- {
- /* this may be an RFC 1049 message */
- p = strpbrk(p, ";/");
- if (p == NULL || *p == ';')
- {
- /* yep, it is */
- e->e_flags |= EF_DONT_MIME;
- }
- }
-
- /*
- ** From person in antiquated ARPANET mode
- ** required by UK Grey Book e-mail gateways (sigh)
- */
-
- if (OpMode == MD_ARPAFTP)
- {
- register struct hdrinfo *hi;
-
- for (hi = HdrInfo; hi->hi_field != NULL; hi++)
- {
- if (bitset(H_FROM, hi->hi_flags) &&
- (!bitset(H_RESENT, hi->hi_flags) ||
- bitset(EF_RESENT, e->e_flags)) &&
- (p = hvalue(hi->hi_field, e->e_header)) != NULL)
- break;
- }
- if (hi->hi_field != NULL)
- {
- if (tTd(32, 2))
- printf("eatheader: setsender(*%s == %s)\n",
- hi->hi_field, p);
- setsender(p, e, NULL, '\0', TRUE);
- }
- }
-
- /*
- ** Log collection information.
- */
-
- if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4)
- logsender(e, msgid);
- e->e_flags &= ~EF_LOGSENDER;
-}
- /*
-** LOGSENDER -- log sender information
-**
-** Parameters:
-** e -- the envelope to log
-** msgid -- the message id
-**
-** Returns:
-** none
-*/
-
-void
-logsender(e, msgid)
- register ENVELOPE *e;
- char *msgid;
-{
- char *name;
- register char *sbp;
- register char *p;
- int l;
- char hbuf[MAXNAME + 1];
- char sbuf[MAXLINE + 1];
- char mbuf[MAXNAME + 1];
-
- /* don't allow newlines in the message-id */
- if (msgid != NULL)
- {
- l = strlen(msgid);
- if (l > sizeof mbuf - 1)
- l = sizeof mbuf - 1;
- bcopy(msgid, mbuf, l);
- mbuf[l] = '\0';
- p = mbuf;
- while ((p = strchr(p, '\n')) != NULL)
- *p++ = ' ';
- }
-
- if (bitset(EF_RESPONSE, e->e_flags))
- name = "[RESPONSE]";
- else if ((name = macvalue('_', e)) != NULL)
- ;
- else if (RealHostName == NULL)
- name = "localhost";
- else if (RealHostName[0] == '[')
- name = RealHostName;
- else
- {
- name = hbuf;
- (void) snprintf(hbuf, sizeof hbuf, "%.80s", RealHostName);
- if (RealHostAddr.sa.sa_family != 0)
- {
- p = &hbuf[strlen(hbuf)];
- (void) snprintf(p, SPACELEFT(hbuf, p), " (%.100s)",
- anynet_ntoa(&RealHostAddr));
- }
- }
-
- /* some versions of syslog only take 5 printf args */
-# if (SYSLOG_BUFSIZE) >= 256
- sbp = sbuf;
- snprintf(sbp, SPACELEFT(sbuf, sbp),
- "from=%.200s, size=%ld, class=%d, pri=%ld, nrcpts=%d",
- e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr,
- e->e_msgsize, e->e_class, e->e_msgpriority, e->e_nrcpts);
- sbp += strlen(sbp);
- if (msgid != NULL)
- {
- snprintf(sbp, SPACELEFT(sbuf, sbp), ", msgid=%.100s", mbuf);
- sbp += strlen(sbp);
- }
- if (e->e_bodytype != NULL)
- {
- (void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", bodytype=%.20s",
- e->e_bodytype);
- sbp += strlen(sbp);
- }
- p = macvalue('r', e);
- if (p != NULL)
- (void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", proto=%.20s", p);
- sm_syslog(LOG_INFO, e->e_id,
- "%.850s, relay=%.100s",
- sbuf, name);
-
-# else /* short syslog buffer */
-
- sm_syslog(LOG_INFO, e->e_id,
- "from=%s",
- e->e_from.q_paddr == NULL ? "<NONE>"
- : shortenstring(e->e_from.q_paddr, 83));
- sm_syslog(LOG_INFO, e->e_id,
- "size=%ld, class=%ld, pri=%ld, nrcpts=%d",
- e->e_msgsize, e->e_class, e->e_msgpriority, e->e_nrcpts);
- if (msgid != NULL)
- sm_syslog(LOG_INFO, e->e_id,
- "msgid=%s",
- shortenstring(mbuf, 83));
- sbp = sbuf;
- *sbp = '\0';
- if (e->e_bodytype != NULL)
- {
- snprintf(sbp, SPACELEFT(sbuf, sbp), "bodytype=%.20s, ", e->e_bodytype);
- sbp += strlen(sbp);
- }
- p = macvalue('r', e);
- if (p != NULL)
- {
- snprintf(sbp, SPACELEFT(sbuf, sbp), "proto=%.20s, ", p);
- sbp += strlen(sbp);
- }
- sm_syslog(LOG_INFO, e->e_id,
- "%.400srelay=%.100s", sbuf, name);
-# endif
-}
- /*
-** PRIENCODE -- encode external priority names into internal values.
-**
-** Parameters:
-** p -- priority in ascii.
-**
-** Returns:
-** priority as a numeric level.
-**
-** Side Effects:
-** none.
-*/
-
-int
-priencode(p)
- char *p;
-{
- register int i;
-
- for (i = 0; i < NumPriorities; i++)
- {
- if (!strcasecmp(p, Priorities[i].pri_name))
- return (Priorities[i].pri_val);
- }
-
- /* unknown priority */
- return (0);
-}
- /*
-** CRACKADDR -- parse an address and turn it into a macro
-**
-** This doesn't actually parse the address -- it just extracts
-** it and replaces it with "$g". The parse is totally ad hoc
-** and isn't even guaranteed to leave something syntactically
-** identical to what it started with. However, it does leave
-** something semantically identical.
-**
-** This algorithm has been cleaned up to handle a wider range
-** of cases -- notably quoted and backslash escaped strings.
-** This modification makes it substantially better at preserving
-** the original syntax.
-**
-** Parameters:
-** addr -- the address to be cracked.
-**
-** Returns:
-** a pointer to the new version.
-**
-** Side Effects:
-** none.
-**
-** Warning:
-** The return value is saved in local storage and should
-** be copied if it is to be reused.
-*/
-
-char *
-crackaddr(addr)
- register char *addr;
-{
- register char *p;
- register char c;
- int cmtlev;
- int realcmtlev;
- int anglelev, realanglelev;
- int copylev;
- int bracklev;
- bool qmode;
- bool realqmode;
- bool skipping;
- bool putgmac = FALSE;
- bool quoteit = FALSE;
- bool gotangle = FALSE;
- bool gotcolon = FALSE;
- register char *bp;
- char *buflim;
- char *bufhead;
- char *addrhead;
- static char buf[MAXNAME + 1];
-
- if (tTd(33, 1))
- printf("crackaddr(%s)\n", addr);
-
- /* strip leading spaces */
- while (*addr != '\0' && isascii(*addr) && isspace(*addr))
- addr++;
-
- /*
- ** Start by assuming we have no angle brackets. This will be
- ** adjusted later if we find them.
- */
-
- bp = bufhead = buf;
- buflim = &buf[sizeof buf - 7];
- p = addrhead = addr;
- copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0;
- bracklev = 0;
- qmode = realqmode = FALSE;
-
- while ((c = *p++) != '\0')
- {
- /*
- ** If the buffer is overful, go into a special "skipping"
- ** mode that tries to keep legal syntax but doesn't actually
- ** output things.
- */
-
- skipping = bp >= buflim;
-
- if (copylev > 0 && !skipping)
- *bp++ = c;
-
- /* check for backslash escapes */
- if (c == '\\')
- {
- /* arrange to quote the address */
- if (cmtlev <= 0 && !qmode)
- quoteit = TRUE;
-
- if ((c = *p++) == '\0')
- {
- /* too far */
- p--;
- goto putg;
- }
- if (copylev > 0 && !skipping)
- *bp++ = c;
- goto putg;
- }
-
- /* check for quoted strings */
- if (c == '"' && cmtlev <= 0)
- {
- qmode = !qmode;
- if (copylev > 0 && !skipping)
- realqmode = !realqmode;
- continue;
- }
- if (qmode)
- goto putg;
-
- /* check for comments */
- if (c == '(')
- {
- cmtlev++;
-
- /* allow space for closing paren */
- if (!skipping)
- {
- buflim--;
- realcmtlev++;
- if (copylev++ <= 0)
- {
- if (bp != bufhead)
- *bp++ = ' ';
- *bp++ = c;
- }
- }
- }
- if (cmtlev > 0)
- {
- if (c == ')')
- {
- cmtlev--;
- copylev--;
- if (!skipping)
- {
- realcmtlev--;
- buflim++;
- }
- }
- continue;
- }
- else if (c == ')')
- {
- /* syntax error: unmatched ) */
- if (copylev > 0 && !skipping)
- bp--;
- }
-
- /* count nesting on [ ... ] (for IPv6 domain literals) */
- if (c == '[')
- bracklev++;
- else if (c == ']')
- bracklev--;
-
- /* check for group: list; syntax */
- if (c == ':' && anglelev <= 0 && bracklev <= 0 &&
- !gotcolon && !ColonOkInAddr)
- {
- register char *q;
-
- /*
- ** Check for DECnet phase IV ``::'' (host::user)
- ** or ** DECnet phase V ``:.'' syntaxes. The latter
- ** covers ``user@DEC:.tay.myhost'' and
- ** ``DEC:.tay.myhost::user'' syntaxes (bletch).
- */
-
- if (*p == ':' || *p == '.')
- {
- if (cmtlev <= 0 && !qmode)
- quoteit = TRUE;
- if (copylev > 0 && !skipping)
- {
- *bp++ = c;
- *bp++ = *p;
- }
- p++;
- goto putg;
- }
-
- gotcolon = TRUE;
-
- bp = bufhead;
- if (quoteit)
- {
- *bp++ = '"';
-
- /* back up over the ':' and any spaces */
- --p;
- while (isascii(*--p) && isspace(*p))
- continue;
- p++;
- }
- for (q = addrhead; q < p; )
- {
- c = *q++;
- if (bp < buflim)
- {
- if (quoteit && c == '"')
- *bp++ = '\\';
- *bp++ = c;
- }
- }
- if (quoteit)
- {
- if (bp == &bufhead[1])
- bp--;
- else
- *bp++ = '"';
- while ((c = *p++) != ':')
- {
- if (bp < buflim)
- *bp++ = c;
- }
- *bp++ = c;
- }
-
- /* any trailing white space is part of group: */
- while (isascii(*p) && isspace(*p) && bp < buflim)
- *bp++ = *p++;
- copylev = 0;
- putgmac = quoteit = FALSE;
- bufhead = bp;
- addrhead = p;
- continue;
- }
-
- if (c == ';' && copylev <= 0 && !ColonOkInAddr)
- {
- if (bp < buflim)
- *bp++ = c;
- }
-
- /* check for characters that may have to be quoted */
- if (strchr(MustQuoteChars, c) != NULL)
- {
- /*
- ** If these occur as the phrase part of a <>
- ** construct, but are not inside of () or already
- ** quoted, they will have to be quoted. Note that
- ** now (but don't actually do the quoting).
- */
-
- if (cmtlev <= 0 && !qmode)
- quoteit = TRUE;
- }
-
- /* check for angle brackets */
- if (c == '<')
- {
- register char *q;
-
- /* assume first of two angles is bogus */
- if (gotangle)
- quoteit = TRUE;
- gotangle = TRUE;
-
- /* oops -- have to change our mind */
- anglelev = 1;
- if (!skipping)
- realanglelev = 1;
-
- bp = bufhead;
- if (quoteit)
- {
- *bp++ = '"';
-
- /* back up over the '<' and any spaces */
- --p;
- while (isascii(*--p) && isspace(*p))
- continue;
- p++;
- }
- for (q = addrhead; q < p; )
- {
- c = *q++;
- if (bp < buflim)
- {
- if (quoteit && c == '"')
- *bp++ = '\\';
- *bp++ = c;
- }
- }
- if (quoteit)
- {
- if (bp == &buf[1])
- bp--;
- else
- *bp++ = '"';
- while ((c = *p++) != '<')
- {
- if (bp < buflim)
- *bp++ = c;
- }
- *bp++ = c;
- }
- copylev = 0;
- putgmac = quoteit = FALSE;
- continue;
- }
-
- if (c == '>')
- {
- if (anglelev > 0)
- {
- anglelev--;
- if (!skipping)
- {
- realanglelev--;
- buflim++;
- }
- }
- else if (!skipping)
- {
- /* syntax error: unmatched > */
- if (copylev > 0)
- bp--;
- quoteit = TRUE;
- continue;
- }
- if (copylev++ <= 0)
- *bp++ = c;
- continue;
- }
-
- /* must be a real address character */
- putg:
- if (copylev <= 0 && !putgmac)
- {
- if (bp > bufhead && bp[-1] == ')')
- *bp++ = ' ';
- *bp++ = MACROEXPAND;
- *bp++ = 'g';
- putgmac = TRUE;
- }
- }
-
- /* repair any syntactic damage */
- if (realqmode)
- *bp++ = '"';
- while (realcmtlev-- > 0)
- *bp++ = ')';
- while (realanglelev-- > 0)
- *bp++ = '>';
- *bp++ = '\0';
-
- if (tTd(33, 1))
- {
- printf("crackaddr=>`");
- xputs(buf);
- printf("'\n");
- }
-
- return (buf);
-}
- /*
-** PUTHEADER -- put the header part of a message from the in-core copy
-**
-** Parameters:
-** mci -- the connection information.
-** h -- the header to put.
-** e -- envelope to use.
-** flags -- MIME conversion flags.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** none.
-*/
-
-/*
- * Macro for fast max (not available in e.g. DG/UX, 386/ix).
- */
-#ifndef MAX
-# define MAX(a,b) (((a)>(b))?(a):(b))
-#endif
-
-void
-putheader(mci, hdr, e, flags)
- register MCI *mci;
- HDR *hdr;
- register ENVELOPE *e;
- int flags;
-{
- register HDR *h;
- char buf[MAX(MAXLINE,BUFSIZ)];
- char obuf[MAXLINE];
-
- if (tTd(34, 1))
- printf("--- putheader, mailer = %s ---\n",
- mci->mci_mailer->m_name);
-
- /*
- ** If we're in MIME mode, we're not really in the header of the
- ** message, just the header of one of the parts of the body of
- ** the message. Therefore MCIF_INHEADER should not be turned on.
- */
-
- if (!bitset(MCIF_INMIME, mci->mci_flags))
- mci->mci_flags |= MCIF_INHEADER;
-
- for (h = hdr; h != NULL; h = h->h_link)
- {
- register char *p = h->h_value;
- extern bool bitintersect __P((BITMAP, BITMAP));
-
- if (tTd(34, 11))
- {
- printf(" %s: ", h->h_field);
- xputs(p);
- }
-
-#if _FFR_MAX_MIME_HEADER_LENGTH
- /* heuristic shortening of MIME fields to avoid MUA overflows */
- if (MaxMimeFieldLength > 0 &&
- wordinclass(h->h_field,
- macid("{checkMIMEFieldHeaders}", NULL)))
- {
- extern bool fix_mime_header __P((char *));
-
- if (fix_mime_header(h->h_value))
- {
- sm_syslog(LOG_ALERT, e->e_id,
- "Truncated MIME %s header due to field size (possible attack)",
- h->h_field);
- if (tTd(34, 11))
- printf(" truncated MIME %s header due to field size (possible attack)\n",
- h->h_field);
- }
- }
-
- if (MaxMimeHeaderLength > 0 &&
- wordinclass(h->h_field,
- macid("{checkMIMETextHeaders}", NULL)))
- {
- if (strlen(h->h_value) > MaxMimeHeaderLength)
- {
- h->h_value[MaxMimeHeaderLength - 1] = '\0';
- sm_syslog(LOG_ALERT, e->e_id,
- "Truncated long MIME %s header (possible attack)",
- h->h_field);
- if (tTd(34, 11))
- printf(" truncated long MIME %s header (possible attack)\n",
- h->h_field);
- }
- }
-
- if (MaxMimeHeaderLength > 0 &&
- wordinclass(h->h_field,
- macid("{checkMIMEHeaders}", NULL)))
- {
- extern bool shorten_rfc822_string __P((char *, int));
-
- if (shorten_rfc822_string(h->h_value, MaxMimeHeaderLength))
- {
- sm_syslog(LOG_ALERT, e->e_id,
- "Truncated long MIME %s header (possible attack)",
- h->h_field);
- if (tTd(34, 11))
- printf(" truncated long MIME %s header (possible attack)\n",
- h->h_field);
- }
- }
-#endif
-
- /*
- ** Suppress Content-Transfer-Encoding: if we are MIMEing
- ** and we are potentially converting from 8 bit to 7 bit
- ** MIME. If converting, add a new CTE header in
- ** mime8to7().
- */
- if (bitset(H_CTE, h->h_flags) &&
- bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME,
- mci->mci_flags) &&
- !bitset(M87F_NO8TO7, flags))
- {
- if (tTd(34, 11))
- printf(" (skipped (content-transfer-encoding))\n");
- continue;
- }
-
- if (bitset(MCIF_INMIME, mci->mci_flags))
- {
- if (tTd(34, 11))
- printf("\n");
- put_vanilla_header(h, p, mci);
- continue;
- }
-
- if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
- !bitintersect(h->h_mflags, mci->mci_mailer->m_flags))
- {
- if (tTd(34, 11))
- printf(" (skipped)\n");
- continue;
- }
-
- /* handle Resent-... headers specially */
- if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
- {
- if (tTd(34, 11))
- printf(" (skipped (resent))\n");
- continue;
- }
-
- /* suppress return receipts if requested */
- if (bitset(H_RECEIPTTO, h->h_flags) &&
-#if _FFR_DSN_RRT_OPTION
- (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags)))
-#else
- bitset(EF_NORECEIPT, e->e_flags))
-#endif
- {
- if (tTd(34, 11))
- printf(" (skipped (receipt))\n");
- continue;
- }
-
- /* macro expand value if generated internally */
- if (bitset(H_DEFAULT, h->h_flags))
- {
- expand(p, buf, sizeof buf, e);
- p = buf;
- if (*p == '\0')
- {
- if (tTd(34, 11))
- printf(" (skipped -- null value)\n");
- continue;
- }
- }
-
- if (bitset(H_BCC, h->h_flags))
- {
- /* Bcc: field -- either truncate or delete */
- if (bitset(EF_DELETE_BCC, e->e_flags))
- {
- if (tTd(34, 11))
- printf(" (skipped -- bcc)\n");
- }
- else
- {
- /* no other recipient headers: truncate value */
- (void) snprintf(obuf, sizeof obuf, "%s:",
- h->h_field);
- putline(obuf, mci);
- }
- continue;
- }
-
- if (tTd(34, 11))
- printf("\n");
-
- if (bitset(H_FROM|H_RCPT, h->h_flags))
- {
- /* address field */
- bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
-
- if (bitset(H_FROM, h->h_flags))
- oldstyle = FALSE;
- commaize(h, p, oldstyle, mci, e);
- }
- else
- {
- put_vanilla_header(h, p, mci);
- }
- }
-
- /*
- ** If we are converting this to a MIME message, add the
- ** MIME headers.
- */
-
-#if MIME8TO7
- if (bitset(MM_MIME8BIT, MimeMode) &&
- bitset(EF_HAS8BIT, e->e_flags) &&
- !bitset(EF_DONT_MIME, e->e_flags) &&
- !bitnset(M_8BITS, mci->mci_mailer->m_flags) &&
- !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8, mci->mci_flags))
- {
- if (hvalue("MIME-Version", e->e_header) == NULL)
- putline("MIME-Version: 1.0", mci);
- if (hvalue("Content-Type", e->e_header) == NULL)
- {
- snprintf(obuf, sizeof obuf,
- "Content-Type: text/plain; charset=%s",
- defcharset(e));
- putline(obuf, mci);
- }
- if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL)
- putline("Content-Transfer-Encoding: 8bit", mci);
- }
-#endif
-}
- /*
-** PUT_VANILLA_HEADER -- output a fairly ordinary header
-**
-** Parameters:
-** h -- the structure describing this header
-** v -- the value of this header
-** mci -- the connection info for output
-**
-** Returns:
-** none.
-*/
-
-void
-put_vanilla_header(h, v, mci)
- HDR *h;
- char *v;
- MCI *mci;
-{
- register char *nlp;
- register char *obp;
- int putflags;
- char obuf[MAXLINE];
-
- putflags = PXLF_HEADER;
-#if _FFR_7BITHDRS
- if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
- putflags |= PXLF_STRIP8BIT;
-#endif
- (void) snprintf(obuf, sizeof obuf, "%.200s: ", h->h_field);
- obp = obuf + strlen(obuf);
- while ((nlp = strchr(v, '\n')) != NULL)
- {
- int l;
-
- l = nlp - v;
- if (SPACELEFT(obuf, obp) - 1 < l)
- l = SPACELEFT(obuf, obp) - 1;
-
- snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v);
- putxline(obuf, strlen(obuf), mci, putflags);
- v += l + 1;
- obp = obuf;
- if (*v != ' ' && *v != '\t')
- *obp++ = ' ';
- }
- snprintf(obp, SPACELEFT(obuf, obp), "%.*s",
- sizeof obuf - (obp - obuf) - 1, v);
- putxline(obuf, strlen(obuf), mci, putflags);
-}
- /*
-** COMMAIZE -- output a header field, making a comma-translated list.
-**
-** Parameters:
-** h -- the header field to output.
-** p -- the value to put in it.
-** oldstyle -- TRUE if this is an old style header.
-** mci -- the connection information.
-** e -- the envelope containing the message.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** outputs "p" to file "fp".
-*/
-
-void
-commaize(h, p, oldstyle, mci, e)
- register HDR *h;
- register char *p;
- bool oldstyle;
- register MCI *mci;
- register ENVELOPE *e;
-{
- register char *obp;
- int opos;
- int omax;
- bool firstone = TRUE;
- int putflags = PXLF_HEADER;
- char obuf[MAXLINE + 3];
-
- /*
- ** Output the address list translated by the
- ** mailer and with commas.
- */
-
- if (tTd(14, 2))
- printf("commaize(%s: %s)\n", h->h_field, p);
-
-#if _FFR_7BITHDRS
- if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
- putflags |= PXLF_STRIP8BIT;
-#endif
-
- obp = obuf;
- (void) snprintf(obp, SPACELEFT(obuf, obp), "%.200s: ", h->h_field);
- opos = strlen(h->h_field) + 2;
- if (opos > 202)
- opos = 202;
- obp += opos;
- omax = mci->mci_mailer->m_linelimit - 2;
- if (omax < 0 || omax > 78)
- omax = 78;
-
- /*
- ** Run through the list of values.
- */
-
- while (*p != '\0')
- {
- register char *name;
- register int c;
- char savechar;
- int flags;
- auto int stat;
-
- /*
- ** Find the end of the name. New style names
- ** end with a comma, old style names end with
- ** a space character. However, spaces do not
- ** necessarily delimit an old-style name -- at
- ** signs mean keep going.
- */
-
- /* find end of name */
- while ((isascii(*p) && isspace(*p)) || *p == ',')
- p++;
- name = p;
- for (;;)
- {
- auto char *oldp;
- char pvpbuf[PSBUFSIZE];
-
- (void) prescan(p, oldstyle ? ' ' : ',', pvpbuf,
- sizeof pvpbuf, &oldp, NULL);
- p = oldp;
-
- /* look to see if we have an at sign */
- while (*p != '\0' && isascii(*p) && isspace(*p))
- p++;
-
- if (*p != '@')
- {
- p = oldp;
- break;
- }
- p += *p == '@' ? 1 : 2;
- while (*p != '\0' && isascii(*p) && isspace(*p))
- p++;
- }
- /* at the end of one complete name */
-
- /* strip off trailing white space */
- while (p >= name &&
- ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
- p--;
- if (++p == name)
- continue;
- savechar = *p;
- *p = '\0';
-
- /* translate the name to be relative */
- flags = RF_HEADERADDR|RF_ADDDOMAIN;
- if (bitset(H_FROM, h->h_flags))
- flags |= RF_SENDERADDR;
-#if USERDB
- else if (e->e_from.q_mailer != NULL &&
- bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags))
- {
- extern char *udbsender __P((char *));
- char *q;
-
- q = udbsender(name);
- if (q != NULL)
- name = q;
- }
-#endif
- stat = EX_OK;
- name = remotename(name, mci->mci_mailer, flags, &stat, e);
- if (*name == '\0')
- {
- *p = savechar;
- continue;
- }
- name = denlstring(name, FALSE, TRUE);
-
- /* output the name with nice formatting */
- opos += strlen(name);
- if (!firstone)
- opos += 2;
- if (opos > omax && !firstone)
- {
- snprintf(obp, SPACELEFT(obuf, obp), ",\n");
- putxline(obuf, strlen(obuf), mci, putflags);
- obp = obuf;
- (void) strcpy(obp, " ");
- opos = strlen(obp);
- obp += opos;
- opos += strlen(name);
- }
- else if (!firstone)
- {
- snprintf(obp, SPACELEFT(obuf, obp), ", ");
- obp += 2;
- }
-
- while ((c = *name++) != '\0' && obp < &obuf[MAXLINE])
- *obp++ = c;
- firstone = FALSE;
- *p = savechar;
- }
- *obp = '\0';
- putxline(obuf, strlen(obuf), mci, putflags);
-}
- /*
-** COPYHEADER -- copy header list
-**
-** This routine is the equivalent of newstr for header lists
-**
-** Parameters:
-** header -- list of header structures to copy.
-**
-** Returns:
-** a copy of 'header'.
-**
-** Side Effects:
-** none.
-*/
-
-HDR *
-copyheader(header)
- register HDR *header;
-{
- register HDR *newhdr;
- HDR *ret;
- register HDR **tail = &ret;
-
- while (header != NULL)
- {
- newhdr = (HDR *) xalloc(sizeof(HDR));
- STRUCTCOPY(*header, *newhdr);
- *tail = newhdr;
- tail = &newhdr->h_link;
- header = header->h_link;
- }
- *tail = NULL;
-
- return ret;
-}
- /*
-** FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header
-**
-** Run through all of the parameters of a MIME header and
-** possibly truncate and rebalance the parameter according
-** to MaxMimeFieldLength.
-**
-** Parameters:
-** string -- the full header
-**
-** Returns:
-** TRUE if the header was modified, FALSE otherwise
-**
-** Side Effects:
-** string modified in place
-*/
-
-bool
-fix_mime_header(string)
- char *string;
-{
- bool modified = FALSE;
- char *begin = string;
- char *end;
- extern char *find_character __P((char *, char));
- extern bool shorten_rfc822_string __P((char *, int));
-
- if (string == NULL || *string == '\0')
- return FALSE;
-
- /* Split on each ';' */
- while ((end = find_character(begin, ';')) != NULL)
- {
- char save = *end;
- char *bp;
-
- *end = '\0';
-
- /* Shorten individual parameter */
- if (shorten_rfc822_string(begin, MaxMimeFieldLength))
- modified = TRUE;
-
- /* Collapse the possibly shortened string with rest */
- bp = begin + strlen(begin);
- if (bp != end)
- {
- char *ep = end;
-
- *end = save;
- end = bp;
-
- /* copy character by character due to overlap */
- while (*ep != '\0')
- *bp++ = *ep++;
- *bp = '\0';
- }
- else
- *end = save;
- if (*end == '\0')
- break;
-
- /* Move past ';' */
- begin = end + 1;
- }
- return modified;
-}
diff --git a/src/ldap_map.h b/src/ldap_map.h
deleted file mode 100644
index 7d40329..0000000
--- a/src/ldap_map.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-/*
-** Support for LDAP.
-**
-** Contributed by Booker C. Bense <bbense+ldap@stanford.edu>.
-** Please go to him for support -- since I (Eric) don't run LDAP, I
-** can't help you at all.
-**
-** @(#)ldap_map.h 8.12 (Berkeley) 2/2/1999
-*/
-
-#ifndef _LDAP_MAP_H
-#define _LDAP_MAP_H
-
-#include <sys/time.h>
-
-struct ldap_map_struct
-{
- /* needed for ldap_open */
- char *ldaphost;
- int ldapport;
-
- /* Options set in ld struct before ldap_bind_s */
- int deref;
- int timelimit;
- int sizelimit;
- int ldap_options;
-
- /* args for ldap_bind_s */
- LDAP *ld;
- char *binddn;
- char *passwd;
- int method;
-
- /* args for ldap_search_st */
- char *base;
- int scope;
- char *filter;
- char *attr[2];
- int attrsonly;
- struct timeval timeout;
- LDAPMessage *res;
-};
-
-typedef struct ldap_map_struct LDAP_MAP_STRUCT;
-
-#define DEFAULT_LDAP_MAP_PORT LDAP_PORT
-#define DEFAULT_LDAP_MAP_SCOPE LDAP_SCOPE_SUBTREE
-#define DEFAULT_LDAP_MAP_BINDDN NULL
-#define DEFAULT_LDAP_MAP_PASSWD NULL
-#define DEFAULT_LDAP_MAP_METHOD LDAP_AUTH_SIMPLE
-#define DEFAULT_LDAP_MAP_TIMELIMIT 5
-#define DEFAULT_LDAP_MAP_DEREF LDAP_DEREF_NEVER
-#define DEFAULT_LDAP_MAP_SIZELIMIT 0
-#define DEFAULT_LDAP_MAP_ATTRSONLY 0
-#define LDAP_MAP_MAX_FILTER 1024
-#ifdef LDAP_REFERRALS
-# define DEFAULT_LDAP_MAP_LDAP_OPTIONS LDAP_OPT_REFERRALS
-#else /* LDAP_REFERRALS */
-# define DEFAULT_LDAP_MAP_LDAP_OPTIONS 0
-#endif /* LDAP_REFERRALS */
-
-/*
-** ldap_init(3) is broken in Umich 3.x and OpenLDAP 1.0/1.1.
-** Use the lack of LDAP_OPT_SIZELIMIT to detect old API implementations
-** and assume (falsely) that all old API implementations are broken.
-** (OpenLDAP 1.2 and later have a working ldap_init(), add -DUSE_LDAP_INIT)
-*/
-
-#if defined(LDAP_OPT_SIZELIMIT) && !defined(USE_LDAP_INIT)
-# define USE_LDAP_INIT 1
-#endif
-
-/*
-** LDAP_OPT_SIZELIMIT is not defined under Umich 3.x nor OpenLDAP 1.x,
-** hence ldap_set_option() must not exist.
-*/
-
-#if defined(LDAP_OPT_SIZELIMIT) && !defined(USE_LDAP_SET_OPTION)
-# define USE_LDAP_SET_OPTION 1
-#endif
-
-#endif /* _LDAP_MAP_H */
diff --git a/src/macro.c b/src/macro.c
deleted file mode 100644
index d45a0c7..0000000
--- a/src/macro.c
+++ /dev/null
@@ -1,437 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)macro.c 8.26 (Berkeley) 11/8/1998";
-#endif /* not lint */
-
-# include "sendmail.h"
-
-char *MacroName[256]; /* macro id to name table */
-int NextMacroId = 0240; /* codes for long named macros */
-
-
-/*
-** EXPAND -- macro expand a string using $x escapes.
-**
-** Parameters:
-** s -- the string to expand.
-** buf -- the place to put the expansion.
-** bufsize -- the size of the buffer.
-** e -- envelope in which to work.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** none.
-*/
-
-void
-expand(s, buf, bufsize, e)
- register char *s;
- register char *buf;
- size_t bufsize;
- register ENVELOPE *e;
-{
- register char *xp;
- register char *q;
- bool skipping; /* set if conditionally skipping output */
- bool recurse = FALSE; /* set if recursion required */
- int i;
- int skiplev; /* skipping nesting level */
- int iflev; /* if nesting level */
- char xbuf[MACBUFSIZE];
- static int explevel = 0;
-
- if (tTd(35, 24))
- {
- printf("expand(");
- xputs(s);
- printf(")\n");
- }
-
- skipping = FALSE;
- skiplev = 0;
- iflev = 0;
- if (s == NULL)
- s = "";
- for (xp = xbuf; *s != '\0'; s++)
- {
- int c;
-
- /*
- ** Check for non-ordinary (special?) character.
- ** 'q' will be the interpolated quantity.
- */
-
- q = NULL;
- c = *s;
- switch (c & 0377)
- {
- case CONDIF: /* see if var set */
- iflev++;
- c = *++s;
- if (skipping)
- skiplev++;
- else
- skipping = macvalue(c, e) == NULL;
- continue;
-
- case CONDELSE: /* change state of skipping */
- if (iflev == 0)
- break;
- if (skiplev == 0)
- skipping = !skipping;
- continue;
-
- case CONDFI: /* stop skipping */
- if (iflev == 0)
- break;
- iflev--;
- if (skiplev == 0)
- skipping = FALSE;
- if (skipping)
- skiplev--;
- continue;
-
- case MACROEXPAND: /* macro interpolation */
- c = *++s & 0377;
- if (c != '\0')
- q = macvalue(c, e);
- else
- {
- s--;
- q = NULL;
- }
- if (q == NULL)
- continue;
- break;
- }
-
- /*
- ** Interpolate q or output one character
- */
-
- if (skipping || xp >= &xbuf[sizeof xbuf - 1])
- continue;
- if (q == NULL)
- *xp++ = c;
- else
- {
- /* copy to end of q or max space remaining in buf */
- while ((c = *q++) != '\0' && xp < &xbuf[sizeof xbuf - 1])
- {
- /* check for any sendmail metacharacters */
- if ((c & 0340) == 0200)
- recurse = TRUE;
- *xp++ = c;
- }
- }
- }
- *xp = '\0';
-
- if (tTd(35, 24))
- {
- printf("expand ==> ");
- xputs(xbuf);
- printf("\n");
- }
-
- /* recurse as appropriate */
- if (recurse)
- {
- if (explevel < MaxMacroRecursion)
- {
- explevel++;
- expand(xbuf, buf, bufsize, e);
- explevel--;
- return;
- }
- syserr("expand: recursion too deep (%d max)",
- MaxMacroRecursion);
- }
-
- /* copy results out */
- i = xp - xbuf;
- if (i >= bufsize)
- i = bufsize - 1;
- bcopy(xbuf, buf, i);
- buf[i] = '\0';
-}
- /*
-** DEFINE -- define a macro.
-**
-** this would be better done using a #define macro.
-**
-** Parameters:
-** n -- the macro name.
-** v -- the macro value.
-** e -- the envelope to store the definition in.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** e->e_macro[n] is defined.
-**
-** Notes:
-** There is one macro for each ASCII character,
-** although they are not all used. The currently
-** defined macros are:
-**
-** $a date in ARPANET format (preferring the Date: line
-** of the message)
-** $b the current date (as opposed to the date as found
-** the message) in ARPANET format
-** $c hop count
-** $d (current) date in UNIX (ctime) format
-** $e the SMTP entry message+
-** $f raw from address
-** $g translated from address
-** $h to host
-** $i queue id
-** $j official SMTP hostname, used in messages+
-** $k UUCP node name
-** $l UNIX-style from line+
-** $m The domain part of our full name.
-** $n name of sendmail ("MAILER-DAEMON" on local
-** net typically)+
-** $o delimiters ("operators") for address tokens+
-** (set via OperatorChars option in V6 or later
-** sendmail.cf files)
-** $p my process id in decimal
-** $q the string that becomes an address -- this is
-** normally used to combine $g & $x.
-** $r protocol used to talk to sender
-** $s sender's host name
-** $t the current time in seconds since 1/1/1970
-** $u to user
-** $v version number of sendmail
-** $w our host name (if it can be determined)
-** $x signature (full name) of from person
-** $y the tty id of our terminal
-** $z home directory of to person
-** $_ RFC1413 authenticated sender address
-**
-** Macros marked with + must be defined in the
-** configuration file and are used internally, but
-** are not set.
-**
-** There are also some macros that can be used
-** arbitrarily to make the configuration file
-** cleaner. In general all upper-case letters
-** are available.
-*/
-
-void
-define(n, v, e)
- int n;
- char *v;
- register ENVELOPE *e;
-{
- if (tTd(35, 9))
- {
- printf("%sdefine(%s as ",
- (e->e_macro[n & 0377] == NULL) ? "" : "re", macname(n));
- xputs(v);
- printf(")\n");
- }
- e->e_macro[n & 0377] = v;
-}
- /*
-** MACVALUE -- return uninterpreted value of a macro.
-**
-** Parameters:
-** n -- the name of the macro.
-**
-** Returns:
-** The value of n.
-**
-** Side Effects:
-** none.
-*/
-
-char *
-macvalue(n, e)
- int n;
- register ENVELOPE *e;
-{
- n &= 0377;
- while (e != NULL)
- {
- register char *p = e->e_macro[n];
-
- if (p != NULL)
- return (p);
- e = e->e_parent;
- }
- return (NULL);
-}
- /*
-** MACNAME -- return the name of a macro given its internal id
-**
-** Parameter:
-** n -- the id of the macro
-**
-** Returns:
-** The name of n.
-**
-** Side Effects:
-** none.
-*/
-
-char *
-macname(n)
- int n;
-{
- static char mbuf[2];
-
- n &= 0377;
- if (bitset(0200, n))
- {
- char *p = MacroName[n];
-
- if (p != NULL)
- return p;
- return "***UNDEFINED MACRO***";
- }
- mbuf[0] = n;
- mbuf[1] = '\0';
- return mbuf;
-}
- /*
-** MACID -- return id of macro identified by its name
-**
-** Parameters:
-** p -- pointer to name string -- either a single
-** character or {name}.
-** ep -- filled in with the pointer to the byte
-** after the name.
-**
-** Returns:
-** The internal id code for this macro. This will
-** fit into a single byte.
-**
-** Side Effects:
-** If this is a new macro name, a new id is allocated.
-*/
-
-int
-macid(p, ep)
- register char *p;
- char **ep;
-{
- int mid;
- register char *bp;
- char mbuf[MAXMACNAMELEN + 1];
-
- if (tTd(35, 14))
- {
- printf("macid(");
- xputs(p);
- printf(") => ");
- }
-
- if (*p == '\0' || (p[0] == '{' && p[1] == '}'))
- {
- syserr("Name required for macro/class");
- if (ep != NULL)
- *ep = p;
- if (tTd(35, 14))
- printf("NULL\n");
- return '\0';
- }
- if (*p != '{')
- {
- /* the macro is its own code */
- if (ep != NULL)
- *ep = p + 1;
- if (tTd(35, 14))
- printf("%c\n", *p);
- return *p;
- }
- bp = mbuf;
- while (*++p != '\0' && *p != '}' && bp < &mbuf[sizeof mbuf - 1])
- {
- if (isascii(*p) && (isalnum(*p) || *p == '_'))
- *bp++ = *p;
- else
- syserr("Invalid macro/class character %c", *p);
- }
- *bp = '\0';
- mid = -1;
- if (*p == '\0')
- {
- syserr("Unbalanced { on %s", mbuf); /* missing } */
- }
- else if (*p != '}')
- {
- syserr("Macro/class name ({%s}) too long (%d chars max)",
- mbuf, sizeof mbuf - 1);
- }
- else if (mbuf[1] == '\0')
- {
- /* ${x} == $x */
- mid = mbuf[0];
- p++;
- }
- else
- {
- register STAB *s;
-
- s = stab(mbuf, ST_MACRO, ST_ENTER);
- if (s->s_macro != 0)
- mid = s->s_macro;
- else
- {
- if (NextMacroId > 0377)
- {
- syserr("Macro/class {%s}: too many long names", mbuf);
- s->s_macro = -1;
- }
- else
- {
- MacroName[NextMacroId] = s->s_name;
- s->s_macro = mid = NextMacroId++;
- }
- }
- p++;
- }
- if (ep != NULL)
- *ep = p;
- if (tTd(35, 14))
- printf("0x%x\n", mid);
- return mid;
-}
- /*
-** WORDINCLASS -- tell if a word is in a specific class
-**
-** Parameters:
-** str -- the name of the word to look up.
-** cl -- the class name.
-**
-** Returns:
-** TRUE if str can be found in cl.
-** FALSE otherwise.
-*/
-
-bool
-wordinclass(str, cl)
- char *str;
- int cl;
-{
- register STAB *s;
-
- s = stab(str, ST_CLASS, ST_FIND);
- return s != NULL && bitnset(cl & 0xff, s->s_class);
-}
diff --git a/src/mailq.0 b/src/mailq.0
deleted file mode 100644
index 0f6c376..0000000
--- a/src/mailq.0
+++ /dev/null
@@ -1,41 +0,0 @@
-MAILQ(1) BSD Reference Manual MAILQ(1)
-
-NNAAMMEE
- mmaaiillqq - print the mail queue
-
-SSYYNNOOPPSSIISS
- mmaaiillqq [--vv]
-
-DDEESSCCRRIIPPTTIIOONN
- MMaaiillqq prints a summary of the mail messages queued for future delivery.
-
- The first line printed for each message shows the internal identifier
- used on this host for the message, the size of the message in bytes, the
- date and time the message was accepted into the queue, and the envelope
- sender of the message. The second line shows the error message that
- caused this message to be retained in the queue; it will not be present
- if the message is being processed for the first time. The following
- lines show message recipients, one per line.
-
- MMaaiillqq is identical to ``sendmail -bp''.
-
- The options are as follows:
-
- --vv Print verbose information. This adds the priority of the message
- and a single character indicator (``+'' or blank) indicating
- whether a warning message has been sent on the first line of the
- message. Additionally, extra lines may be intermixed with the
- recipients indicating the ``controlling user'' information; this
- shows who will own any programs that are executed on behalf of
- this message and the name of the alias this command expanded
- from, if any.
-
- The mmaaiillqq utility exits 0 on success, and >0 if an error occurs.
-
-SSEEEE AALLSSOO
- sendmail(8)
-
-HHIISSTTOORRYY
- The mmaaiillqq command appeared in 4.0BSD.
-
-4th Berkeley Distribution May 19, 1998 1
diff --git a/src/mailq.1 b/src/mailq.1
deleted file mode 100644
index 8b6e63a..0000000
--- a/src/mailq.1
+++ /dev/null
@@ -1,67 +0,0 @@
-.\" Copyright (c) 1998 Sendmail, Inc. All rights reserved.
-.\" Copyright (c) 1983, 1997 Eric P. Allman. All rights reserved.
-.\" Copyright (c) 1985, 1990, 1993
-.\" The Regents of the University of California. All rights reserved.
-.\"
-.\" By using this file, you agree to the terms and conditions set
-.\" forth in the LICENSE file which can be found at the top level of
-.\" the sendmail distribution.
-.\"
-.\"
-.\" @(#)mailq.1 8.10 (Berkeley) 5/19/1998
-.\"
-.Dd May 19, 1998
-.Dt MAILQ 1
-.Os BSD 4
-.Sh NAME
-.Nm mailq
-.Nd print the mail queue
-.Sh SYNOPSIS
-.Nm mailq
-.Op Fl v
-.Sh DESCRIPTION
-.Nm Mailq
-prints a summary of the mail messages queued for future delivery.
-.Pp
-The first line printed for each message
-shows the internal identifier used on this host
-for the message,
-the size of the message in bytes,
-the date and time the message was accepted into the queue,
-and the envelope sender of the message.
-The second line shows the error message that caused this message
-to be retained in the queue;
-it will not be present if the message is being processed
-for the first time.
-The following lines show message recipients,
-one per line.
-.Pp
-.Nm Mailq
-is identical to
-.Dq Li "sendmail -bp" .
-.Pp
-The options are as follows:
-.Bl -tag -width Ds
-.It Fl v
-Print verbose information.
-This adds the priority of the message and
-a single character indicator (``+'' or blank)
-indicating whether a warning message has been sent
-on the first line of the message.
-Additionally, extra lines may be intermixed with the recipients
-indicating the ``controlling user'' information;
-this shows who will own any programs that are executed
-on behalf of this message
-and the name of the alias this command expanded from, if any.
-.El
-.Pp
-The
-.Nm mailq
-utility exits 0 on success, and >0 if an error occurs.
-.Sh SEE ALSO
-.Xr sendmail 8
-.Sh HISTORY
-The
-.Nm mailq
-command appeared in
-.Bx 4.0 .
diff --git a/src/mailstats.h b/src/mailstats.h
deleted file mode 100644
index 86390b3..0000000
--- a/src/mailstats.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- *
- * @(#)mailstats.h 8.8 (Berkeley) 5/19/1998
- */
-
-#define STAT_VERSION 2
-#define STAT_MAGIC 0x1B1DE
-
-/*
-** Statistics structure.
-*/
-
-struct statistics
-{
- int stat_magic; /* magic number */
- int stat_version; /* stat file version */
- time_t stat_itime; /* file initialization time */
- short stat_size; /* size of this structure */
- long stat_nf[MAXMAILERS]; /* # msgs from each mailer */
- long stat_bf[MAXMAILERS]; /* kbytes from each mailer */
- long stat_nt[MAXMAILERS]; /* # msgs to each mailer */
- long stat_bt[MAXMAILERS]; /* kbytes to each mailer */
- long stat_nr[MAXMAILERS]; /* # rejects by each mailer */
- long stat_nd[MAXMAILERS]; /* # discards by each mailer */
-};
diff --git a/src/main.c b/src/main.c
deleted file mode 100644
index cea9d15..0000000
--- a/src/main.c
+++ /dev/null
@@ -1,2748 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-#ifndef lint
-static char copyright[] =
-"@(#) Copyright (c) 1998 Sendmail, Inc. All rights reserved.\n\
- Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.\n\
- Copyright (c) 1988, 1993\n\
- The Regents of the University of California. All rights reserved.\n";
-#endif /* not lint */
-
-#ifndef lint
-static char sccsid[] = "@(#)main.c 8.322 (Berkeley) 12/18/1998";
-#endif /* not lint */
-
-#define _DEFINE
-
-#include "sendmail.h"
-#include <arpa/inet.h>
-#include <grp.h>
-#if NAMED_BIND
-#include <resolv.h>
-#endif
-
-/*
-** SENDMAIL -- Post mail to a set of destinations.
-**
-** This is the basic mail router. All user mail programs should
-** call this routine to actually deliver mail. Sendmail in
-** turn calls a bunch of mail servers that do the real work of
-** delivering the mail.
-**
-** Sendmail is driven by settings read in from /etc/sendmail.cf
-** (read by readcf.c).
-**
-** Usage:
-** /usr/lib/sendmail [flags] addr ...
-**
-** See the associated documentation for details.
-**
-** Author:
-** Eric Allman, UCB/INGRES (until 10/81).
-** Britton-Lee, Inc., purveyors of fine
-** database computers (11/81 - 10/88).
-** International Computer Science Institute
-** (11/88 - 9/89).
-** UCB/Mammoth Project (10/89 - 7/95).
-** InReference, Inc. (8/95 - 1/97).
-** Sendmail, Inc. (1/98 - present).
-** The support of the my employers is gratefully acknowledged.
-** Few of them (Britton-Lee in particular) have had
-** anything to gain from my involvement in this project.
-*/
-
-
-int NextMailer; /* "free" index into Mailer struct */
-char *FullName; /* sender's full name */
-ENVELOPE BlankEnvelope; /* a "blank" envelope */
-ENVELOPE MainEnvelope; /* the envelope around the basic letter */
-ADDRESS NullAddress = /* a null address */
- { "", "", NULL, "" };
-char *CommandLineArgs; /* command line args for pid file */
-bool Warn_Q_option = FALSE; /* warn about Q option use */
-char **SaveArgv; /* argument vector for re-execing */
-int MissingFds = 0; /* bit map of fds missing on startup */
-
-#ifdef NGROUPS_MAX
-GIDSET_T InitialGidSet[NGROUPS_MAX];
-#endif
-
-static void obsolete __P((char **));
-extern void printmailer __P((MAILER *));
-extern void tTflag __P((char *));
-
-#if DAEMON && !SMTP
-ERROR %%%% Cannot have DAEMON mode without SMTP %%%% ERROR
-#endif /* DAEMON && !SMTP */
-#if SMTP && !QUEUE
-ERROR %%%% Cannot have SMTP mode without QUEUE %%%% ERROR
-#endif /* DAEMON && !SMTP */
-
-#define MAXCONFIGLEVEL 8 /* highest config version level known */
-
-int
-main(argc, argv, envp)
- int argc;
- char **argv;
- char **envp;
-{
- register char *p;
- char **av;
- extern char Version[];
- char *ep, *from;
- STAB *st;
- register int i;
- int j;
- bool queuemode = FALSE; /* process queue requests */
- bool safecf = TRUE;
- bool warn_C_flag = FALSE;
- char warn_f_flag = '\0';
- bool run_in_foreground = FALSE; /* -bD mode */
- static bool reenter = FALSE;
- struct passwd *pw;
- struct hostent *hp;
- char *nullserver = NULL;
- bool forged;
- char jbuf[MAXHOSTNAMELEN]; /* holds MyHostName */
- static char rnamebuf[MAXNAME]; /* holds RealUserName */
- char *emptyenviron[1];
- QUEUE_CHAR *new;
- extern int DtableSize;
- extern int optind;
- extern int opterr;
- extern char *optarg;
- extern char **environ;
- extern time_t convtime __P((char *, char));
- extern SIGFUNC_DECL intsig __P((int));
- extern struct hostent *myhostname __P((char *, int));
- extern char *getauthinfo __P((int, bool *));
- extern char *getcfname __P((void));
- extern SIGFUNC_DECL sigusr1 __P((int));
- extern SIGFUNC_DECL sighup __P((int));
- extern SIGFUNC_DECL quiesce __P((int));
- extern void initmacros __P((ENVELOPE *));
- extern void init_md __P((int, char **));
- extern int getdtsize __P((void));
- extern void tTsetup __P((u_char *, int, char *));
- extern void setdefaults __P((ENVELOPE *));
- extern void initsetproctitle __P((int, char **, char **));
- extern void init_vendor_macros __P((ENVELOPE *));
- extern void load_if_names __P((void));
- extern void vendor_pre_defaults __P((ENVELOPE *));
- extern void vendor_post_defaults __P((ENVELOPE *));
- extern void readcf __P((char *, bool, ENVELOPE *));
- extern void printqueue __P((void));
- extern void sendtoargv __P((char **, ENVELOPE *));
- extern void resetlimits __P((void));
-#ifndef HASUNSETENV
- extern void unsetenv __P((char *));
-#endif
-
- /*
- ** Check to see if we reentered.
- ** This would normally happen if e_putheader or e_putbody
- ** were NULL when invoked.
- */
-
- if (reenter)
- {
- syserr("main: reentered!");
- abort();
- }
- reenter = TRUE;
-
- /* avoid null pointer dereferences */
- TermEscape.te_rv_on = TermEscape.te_rv_off = "";
-
- /* do machine-dependent initializations */
- init_md(argc, argv);
-
- /* in 4.4BSD, the table can be huge; impose a reasonable limit */
- DtableSize = getdtsize();
- if (DtableSize > 256)
- DtableSize = 256;
-
- /*
- ** Be sure we have enough file descriptors.
- ** But also be sure that 0, 1, & 2 are open.
- */
-
- fill_fd(STDIN_FILENO, NULL);
- fill_fd(STDOUT_FILENO, NULL);
- fill_fd(STDERR_FILENO, NULL);
-
- i = DtableSize;
- while (--i > 0)
- {
- if (i != STDIN_FILENO && i != STDOUT_FILENO && i != STDERR_FILENO)
- (void) close(i);
- }
- errno = 0;
-
-#if LOG
-# ifdef LOG_MAIL
- openlog("sendmail", LOG_PID, LOG_MAIL);
-# else
- openlog("sendmail", LOG_PID);
-# endif
-#endif
-
- if (MissingFds != 0)
- {
- char mbuf[MAXLINE];
-
- mbuf[0] = '\0';
- if (bitset(1 << STDIN_FILENO, MissingFds))
- strcat(mbuf, ", stdin");
- if (bitset(1 << STDOUT_FILENO, MissingFds))
- strcat(mbuf, ", stdout");
- if (bitset(1 << STDERR_FILENO, MissingFds))
- strcat(mbuf, ", stderr");
- syserr("File descriptors missing on startup: %s", &mbuf[2]);
- }
-
- /* reset status from syserr() calls for missing file descriptors */
- Errors = 0;
- ExitStat = EX_OK;
-
-#if XDEBUG
- checkfd012("after openlog");
-#endif
-
- tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
-
-#ifdef NGROUPS_MAX
- /* save initial group set for future checks */
- i = getgroups(NGROUPS_MAX, InitialGidSet);
- if (i == 0)
- InitialGidSet[0] = (GID_T) -1;
- while (i < NGROUPS_MAX)
- InitialGidSet[i++] = InitialGidSet[0];
-#endif
-
- /* drop group id privileges (RunAsUser not yet set) */
- (void) drop_privileges(FALSE);
-
-#ifdef SIGUSR1
- /* arrange to dump state on user-1 signal */
- setsignal(SIGUSR1, sigusr1);
-#endif
-
- /* initialize for setproctitle */
- initsetproctitle(argc, argv, envp);
-
- /* Handle any non-getoptable constructions. */
- obsolete(argv);
-
- /*
- ** Do a quick prescan of the argument list.
- */
-
-#if defined(__osf__) || defined(_AIX3)
-# define OPTIONS "B:b:C:cd:e:F:f:h:IiM:mN:nO:o:p:q:R:r:sTtUV:vX:x"
-#endif
-#if defined(sony_news)
-# define OPTIONS "B:b:C:cd:E:e:F:f:h:IiJ:M:mN:nO:o:p:q:R:r:sTtUV:vX:"
-#endif
-#ifndef OPTIONS
-# define OPTIONS "B:b:C:cd:e:F:f:h:IiM:mN:nO:o:p:q:R:r:sTtUV:vX:"
-#endif
- opterr = 0;
- while ((j = getopt(argc, argv, OPTIONS)) != -1)
- {
- switch (j)
- {
- case 'd':
- /* hack attack -- see if should use ANSI mode */
- if (strcmp(optarg, "ANSI") == 0)
- {
- TermEscape.te_rv_on = "\033[7m";
- TermEscape.te_rv_off = "\033[0m";
- break;
- }
- tTflag(optarg);
- setbuf(stdout, (char *) NULL);
- break;
- }
- }
- opterr = 1;
-
- /* set up the blank envelope */
- BlankEnvelope.e_puthdr = putheader;
- BlankEnvelope.e_putbody = putbody;
- BlankEnvelope.e_xfp = NULL;
- STRUCTCOPY(NullAddress, BlankEnvelope.e_from);
- CurEnv = &BlankEnvelope;
- STRUCTCOPY(NullAddress, MainEnvelope.e_from);
-
- /*
- ** Set default values for variables.
- ** These cannot be in initialized data space.
- */
-
- setdefaults(&BlankEnvelope);
-
- RealUid = getuid();
- RealGid = getgid();
-
- pw = sm_getpwuid(RealUid);
- if (pw != NULL)
- (void) snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name);
- else
- (void) snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d", RealUid);
- RealUserName = rnamebuf;
-
- if (tTd(0, 101))
- {
- printf("Version %s\n", Version);
- finis(FALSE, EX_OK);
- }
-
- /*
- ** if running non-setuid binary as non-root, pretend
- ** we are the RunAsUid
- */
- if (RealUid != 0 && geteuid() == RealUid)
- {
- if (tTd(47, 1))
- printf("Non-setuid binary: RunAsUid = RealUid = %d\n",
- (int)RealUid);
- RunAsUid = RealUid;
- }
- else if (geteuid() != 0)
- RunAsUid = geteuid();
-
- if (RealUid != 0 && getegid() == RealGid)
- RunAsGid = RealGid;
-
- if (tTd(47, 5))
- {
- printf("main: e/ruid = %d/%d e/rgid = %d/%d\n",
- (int)geteuid(), (int)getuid(), (int)getegid(), (int)getgid());
- printf("main: RunAsUser = %d:%d\n", (int)RunAsUid, (int)RunAsGid);
- }
-
- /* save command line arguments */
- i = 0;
- for (av = argv; *av != NULL; )
- i += strlen(*av++) + 1;
- SaveArgv = (char **) xalloc(sizeof (char *) * (argc + 1));
- CommandLineArgs = xalloc(i);
- p = CommandLineArgs;
- for (av = argv, i = 0; *av != NULL; )
- {
- SaveArgv[i++] = newstr(*av);
- if (av != argv)
- *p++ = ' ';
- strcpy(p, *av++);
- p += strlen(p);
- }
- SaveArgv[i] = NULL;
-
- if (tTd(0, 1))
- {
- int ll;
- extern char *CompileOptions[];
-
- printf("Version %s\n Compiled with:", Version);
- av = CompileOptions;
- ll = 7;
- while (*av != NULL)
- {
- if (ll + strlen(*av) > 63)
- {
- putchar('\n');
- ll = 0;
- }
- if (ll == 0)
- {
- putchar('\t');
- putchar('\t');
- }
- else
- putchar(' ');
- printf("%s", *av);
- ll += strlen(*av++) + 1;
- }
- putchar('\n');
- }
- if (tTd(0, 10))
- {
- int ll;
- extern char *OsCompileOptions[];
-
- printf(" OS Defines:");
- av = OsCompileOptions;
- ll = 7;
- while (*av != NULL)
- {
- if (ll + strlen(*av) > 63)
- {
- putchar('\n');
- ll = 0;
- }
- if (ll == 0)
- {
- putchar('\t');
- putchar('\t');
- }
- else
- putchar(' ');
- printf("%s", *av);
- ll += strlen(*av++) + 1;
- }
- putchar('\n');
-#ifdef _PATH_UNIX
- printf("Kernel symbols:\t%s\n", _PATH_UNIX);
-#endif
- printf(" Def Conf file:\t%s\n", getcfname());
- printf(" Pid file:\t%s\n", PidFile);
- }
-
- InChannel = stdin;
- OutChannel = stdout;
-
- /* clear sendmail's environment */
- ExternalEnviron = environ;
- emptyenviron[0] = NULL;
- environ = emptyenviron;
-
- /*
- ** restore any original TZ setting until TimeZoneSpec has been
- ** determined - or early log messages may get bogus time stamps
- */
- if ((p = getextenv("TZ")) != NULL)
- {
- char *tz;
- int tzlen;
-
- tzlen = strlen(p) + 4;
- tz = xalloc(tzlen);
- snprintf(tz, tzlen, "TZ=%s", p);
- putenv(tz);
- }
-
- /* prime the child environment */
- setuserenv("AGENT", "sendmail");
-
- if (setsignal(SIGINT, SIG_IGN) != SIG_IGN)
- (void) setsignal(SIGINT, intsig);
- (void) setsignal(SIGTERM, intsig);
- (void) setsignal(SIGPIPE, SIG_IGN);
- OldUmask = umask(022);
- OpMode = MD_DELIVER;
- FullName = getextenv("NAME");
-
- /*
- ** Initialize name server if it is going to be used.
- */
-
-#if NAMED_BIND
- if (!bitset(RES_INIT, _res.options))
- res_init();
- if (tTd(8, 8))
- _res.options |= RES_DEBUG;
- else
- _res.options &= ~RES_DEBUG;
-# ifdef RES_NOALIASES
- _res.options |= RES_NOALIASES;
-# endif
-#endif
-
- errno = 0;
- from = NULL;
-
- /* initialize some macros, etc. */
- initmacros(CurEnv);
- init_vendor_macros(CurEnv);
-
- /* version */
- define('v', Version, CurEnv);
-
- /* hostname */
- hp = myhostname(jbuf, sizeof jbuf);
- if (jbuf[0] != '\0')
- {
- struct utsname utsname;
-
- if (tTd(0, 4))
- printf("canonical name: %s\n", jbuf);
- define('w', newstr(jbuf), CurEnv); /* must be new string */
- define('j', newstr(jbuf), CurEnv);
- setclass('w', jbuf);
-
- p = strchr(jbuf, '.');
- if (p != NULL)
- {
- if (p[1] != '\0')
- {
- define('m', newstr(&p[1]), CurEnv);
- }
- while (p != NULL && strchr(&p[1], '.') != NULL)
- {
- *p = '\0';
- if (tTd(0, 4))
- printf("\ta.k.a.: %s\n", jbuf);
- setclass('w', jbuf);
- *p++ = '.';
- p = strchr(p, '.');
- }
- }
-
- if (uname(&utsname) >= 0)
- p = utsname.nodename;
- else
- {
- if (tTd(0, 22))
- printf("uname failed (%s)\n", errstring(errno));
- makelower(jbuf);
- p = jbuf;
- }
- if (tTd(0, 4))
- printf(" UUCP nodename: %s\n", p);
- p = newstr(p);
- define('k', p, CurEnv);
- setclass('k', p);
- setclass('w', p);
- }
- if (hp != NULL)
- {
- for (av = hp->h_aliases; av != NULL && *av != NULL; av++)
- {
- if (tTd(0, 4))
- printf("\ta.k.a.: %s\n", *av);
- setclass('w', *av);
- }
-#if NETINET
- if (hp->h_addrtype == AF_INET && hp->h_length == INADDRSZ)
- {
- for (i = 0; hp->h_addr_list[i] != NULL; i++)
- {
- char ipbuf[103];
-
- snprintf(ipbuf, sizeof ipbuf, "[%.100s]",
- inet_ntoa(*((struct in_addr *) hp->h_addr_list[i])));
- if (tTd(0, 4))
- printf("\ta.k.a.: %s\n", ipbuf);
- setclass('w', ipbuf);
- }
- }
-#endif
- }
-
- /* current time */
- define('b', arpadate((char *) NULL), CurEnv);
-
- QueueLimitRecipient = (QUEUE_CHAR *) NULL;
- QueueLimitSender = (QUEUE_CHAR *) NULL;
- QueueLimitId = (QUEUE_CHAR *) NULL;
-
- /*
- ** Crack argv.
- */
-
- av = argv;
- p = strrchr(*av, '/');
- if (p++ == NULL)
- p = *av;
- if (strcmp(p, "newaliases") == 0)
- OpMode = MD_INITALIAS;
- else if (strcmp(p, "mailq") == 0)
- OpMode = MD_PRINT;
- else if (strcmp(p, "smtpd") == 0)
- OpMode = MD_DAEMON;
- else if (strcmp(p, "hoststat") == 0)
- OpMode = MD_HOSTSTAT;
- else if (strcmp(p, "purgestat") == 0)
- OpMode = MD_PURGESTAT;
-
- optind = 1;
- while ((j = getopt(argc, argv, OPTIONS)) != -1)
- {
- switch (j)
- {
- case 'b': /* operations mode */
- switch (j = *optarg)
- {
- case MD_DAEMON:
- case MD_FGDAEMON:
-# if !DAEMON
- usrerr("Daemon mode not implemented");
- ExitStat = EX_USAGE;
- break;
-# endif /* DAEMON */
- case MD_SMTP:
-# if !SMTP
- usrerr("I don't speak SMTP");
- ExitStat = EX_USAGE;
- break;
-# endif /* SMTP */
-
- case MD_INITALIAS:
- case MD_DELIVER:
- case MD_VERIFY:
- case MD_TEST:
- case MD_PRINT:
- case MD_HOSTSTAT:
- case MD_PURGESTAT:
- case MD_ARPAFTP:
- OpMode = j;
- break;
-
- case MD_FREEZE:
- usrerr("Frozen configurations unsupported");
- ExitStat = EX_USAGE;
- break;
-
- default:
- usrerr("Invalid operation mode %c", j);
- ExitStat = EX_USAGE;
- break;
- }
- break;
-
- case 'B': /* body type */
- CurEnv->e_bodytype = optarg;
- break;
-
- case 'C': /* select configuration file (already done) */
- if (RealUid != 0)
- warn_C_flag = TRUE;
- ConfFile = optarg;
- (void) drop_privileges(TRUE);
- safecf = FALSE;
- break;
-
- case 'd': /* debugging -- already done */
- break;
-
- case 'f': /* from address */
- case 'r': /* obsolete -f flag */
- if (from != NULL)
- {
- usrerr("More than one \"from\" person");
- ExitStat = EX_USAGE;
- break;
- }
- from = newstr(denlstring(optarg, TRUE, TRUE));
- if (strcmp(RealUserName, from) != 0)
- warn_f_flag = j;
- break;
-
- case 'F': /* set full name */
- FullName = newstr(optarg);
- break;
-
- case 'h': /* hop count */
- CurEnv->e_hopcount = strtol(optarg, &ep, 10);
- if (*ep)
- {
- usrerr("Bad hop count (%s)", optarg);
- ExitStat = EX_USAGE;
- }
- break;
-
- case 'n': /* don't alias */
- NoAlias = TRUE;
- break;
-
- case 'N': /* delivery status notifications */
- DefaultNotify |= QHASNOTIFY;
- if (strcasecmp(optarg, "never") == 0)
- break;
- for (p = optarg; p != NULL; optarg = p)
- {
- p = strchr(p, ',');
- if (p != NULL)
- *p++ = '\0';
- if (strcasecmp(optarg, "success") == 0)
- DefaultNotify |= QPINGONSUCCESS;
- else if (strcasecmp(optarg, "failure") == 0)
- DefaultNotify |= QPINGONFAILURE;
- else if (strcasecmp(optarg, "delay") == 0)
- DefaultNotify |= QPINGONDELAY;
- else
- {
- usrerr("Invalid -N argument");
- ExitStat = EX_USAGE;
- }
- }
- break;
-
- case 'o': /* set option */
- setoption(*optarg, optarg + 1, FALSE, TRUE, CurEnv);
- break;
-
- case 'O': /* set option (long form) */
- setoption(' ', optarg, FALSE, TRUE, CurEnv);
- break;
-
- case 'p': /* set protocol */
- p = strchr(optarg, ':');
- if (p != NULL)
- {
- *p++ = '\0';
- if (*p != '\0')
- {
- ep = xalloc(strlen(p) + 1);
- cleanstrcpy(ep, p, MAXNAME);
- define('s', ep, CurEnv);
- }
- }
- if (*optarg != '\0')
- {
- ep = xalloc(strlen(optarg) + 1);
- cleanstrcpy(ep, optarg, MAXNAME);
- define('r', ep, CurEnv);
- }
- break;
-
- case 'q': /* run queue files at intervals */
-# if QUEUE
- FullName = NULL;
- queuemode = TRUE;
- switch (optarg[0])
- {
- case 'I':
- if ((new = (QUEUE_CHAR *)malloc(sizeof(QUEUE_CHAR))) == NULL)
- syserr("!Out of memory!!");
- new->queue_match = newstr(&optarg[1]);
- new->queue_next = QueueLimitId;
- QueueLimitId = new;
- break;
-
- case 'R':
- if ((new = (QUEUE_CHAR *)malloc(sizeof(QUEUE_CHAR))) == NULL)
- syserr("!Out of memory!!");
- new->queue_match = newstr(&optarg[1]);
- new->queue_next = QueueLimitRecipient;
- QueueLimitRecipient = new;
- break;
-
- case 'S':
- if ((new = (QUEUE_CHAR *)malloc(sizeof(QUEUE_CHAR))) == NULL)
- syserr("!Out of memory!!");
- new->queue_match = newstr(&optarg[1]);
- new->queue_next = QueueLimitSender;
- QueueLimitSender = new;
- break;
-
- default:
- QueueIntvl = convtime(optarg, 'm');
- break;
- }
-# else /* QUEUE */
- usrerr("I don't know about queues");
- ExitStat = EX_USAGE;
-# endif /* QUEUE */
- break;
-
- case 'R': /* DSN RET: what to return */
- if (bitset(EF_RET_PARAM, CurEnv->e_flags))
- {
- usrerr("Duplicate -R flag");
- ExitStat = EX_USAGE;
- break;
- }
- CurEnv->e_flags |= EF_RET_PARAM;
- if (strcasecmp(optarg, "hdrs") == 0)
- CurEnv->e_flags |= EF_NO_BODY_RETN;
- else if (strcasecmp(optarg, "full") != 0)
- {
- usrerr("Invalid -R value");
- ExitStat = EX_USAGE;
- }
- break;
-
- case 't': /* read recipients from message */
- GrabTo = TRUE;
- break;
-
- case 'U': /* initial (user) submission */
- UserSubmission = TRUE;
- break;
-
- case 'V': /* DSN ENVID: set "original" envelope id */
- if (!xtextok(optarg))
- {
- usrerr("Invalid syntax in -V flag");
- ExitStat = EX_USAGE;
- }
- else
- CurEnv->e_envid = newstr(optarg);
- break;
-
- case 'X': /* traffic log file */
- (void) drop_privileges(TRUE);
- TrafficLogFile = fopen(optarg, "a");
- if (TrafficLogFile == NULL)
- {
- syserr("cannot open %s", optarg);
- ExitStat = EX_CANTCREAT;
- break;
- }
-#ifdef HASSETVBUF
- setvbuf(TrafficLogFile, NULL, _IOLBF, 0);
-#else
- setlinebuf(TrafficLogFile);
-#endif
- break;
-
- /* compatibility flags */
- case 'c': /* connect to non-local mailers */
- case 'i': /* don't let dot stop me */
- case 'm': /* send to me too */
- case 'T': /* set timeout interval */
- case 'v': /* give blow-by-blow description */
- setoption(j, "T", FALSE, TRUE, CurEnv);
- break;
-
- case 'e': /* error message disposition */
- case 'M': /* define macro */
- setoption(j, optarg, FALSE, TRUE, CurEnv);
- break;
-
- case 's': /* save From lines in headers */
- setoption('f', "T", FALSE, TRUE, CurEnv);
- break;
-
-# ifdef DBM
- case 'I': /* initialize alias DBM file */
- OpMode = MD_INITALIAS;
- break;
-# endif /* DBM */
-
-# if defined(__osf__) || defined(_AIX3)
- case 'x': /* random flag that OSF/1 & AIX mailx passes */
- break;
-# endif
-# if defined(sony_news)
- case 'E':
- case 'J': /* ignore flags for Japanese code conversion
- impremented on Sony NEWS */
- break;
-# endif
-
- default:
- finis(TRUE, EX_USAGE);
- break;
- }
- }
- av += optind;
-
- /*
- ** Do basic initialization.
- ** Read system control file.
- ** Extract special fields for local use.
- */
-
- /* set up ${opMode} for use in config file */
- {
- char mbuf[2];
-
- mbuf[0] = OpMode;
- mbuf[1] = '\0';
- define(MID_OPMODE, newstr(mbuf), CurEnv);
- }
-
-#if XDEBUG
- checkfd012("before readcf");
-#endif
- vendor_pre_defaults(CurEnv);
- readcf(getcfname(), safecf, CurEnv);
- ConfigFileRead = TRUE;
- vendor_post_defaults(CurEnv);
-
- /* Enforce use of local time (null string overrides this) */
- if (TimeZoneSpec == NULL)
- unsetenv("TZ");
- else if (TimeZoneSpec[0] != '\0')
- setuserenv("TZ", TimeZoneSpec);
- else
- setuserenv("TZ", NULL);
- tzset();
-
- /* avoid denial-of-service attacks */
- resetlimits();
-
- if (OpMode != MD_DAEMON && OpMode != MD_FGDAEMON)
- {
- /* drop privileges -- daemon mode done after socket/bind */
- (void) drop_privileges(FALSE);
- }
-
- /*
- ** Find our real host name for future logging.
- */
-
- p = getauthinfo(STDIN_FILENO, &forged);
- define('_', p, CurEnv);
-
- /* suppress error printing if errors mailed back or whatever */
- if (CurEnv->e_errormode != EM_PRINT)
- HoldErrs = TRUE;
-
- /* set up the $=m class now, after .cf has a chance to redefine $m */
- expand("\201m", jbuf, sizeof jbuf, CurEnv);
- setclass('m', jbuf);
-
- /* probe interfaces and locate any additional names */
- if (!DontProbeInterfaces)
- load_if_names();
-
- if (tTd(0, 1))
- {
- printf("\n============ SYSTEM IDENTITY (after readcf) ============");
- printf("\n (short domain name) $w = ");
- xputs(macvalue('w', CurEnv));
- printf("\n (canonical domain name) $j = ");
- xputs(macvalue('j', CurEnv));
- printf("\n (subdomain name) $m = ");
- xputs(macvalue('m', CurEnv));
- printf("\n (node name) $k = ");
- xputs(macvalue('k', CurEnv));
- printf("\n========================================================\n\n");
- }
-
- /*
- ** Do more command line checking -- these are things that
- ** have to modify the results of reading the config file.
- */
-
- /* process authorization warnings from command line */
- if (warn_C_flag)
- auth_warning(CurEnv, "Processed by %s with -C %s",
- RealUserName, ConfFile);
- if (Warn_Q_option)
- auth_warning(CurEnv, "Processed from queue %s", QueueDir);
-
- /* check body type for legality */
- if (CurEnv->e_bodytype == NULL)
- /* nothing */ ;
- else if (strcasecmp(CurEnv->e_bodytype, "7BIT") == 0)
- SevenBitInput = TRUE;
- else if (strcasecmp(CurEnv->e_bodytype, "8BITMIME") == 0)
- SevenBitInput = FALSE;
- else
- {
- usrerr("Illegal body type %s", CurEnv->e_bodytype);
- CurEnv->e_bodytype = NULL;
- }
-
- /* tweak default DSN notifications */
- if (DefaultNotify == 0)
- DefaultNotify = QPINGONFAILURE|QPINGONDELAY;
-
- /* be sure we don't pick up bogus HOSTALIASES environment variable */
- if (queuemode && RealUid != 0)
- (void) unsetenv("HOSTALIASES");
-
- /* check for sane configuration level */
- if (ConfigLevel > MAXCONFIGLEVEL)
- {
- syserr("Warning: .cf version level (%d) exceeds sendmail version %s functionality (%d)",
- ConfigLevel, Version, MAXCONFIGLEVEL);
- }
-
- /* need MCI cache to have persistence */
- if (HostStatDir != NULL && MaxMciCache == 0)
- {
- HostStatDir = NULL;
- printf("Warning: HostStatusDirectory disabled with ConnectionCacheSize = 0\n");
- }
-
- /* need HostStatusDir in order to have SingleThreadDelivery */
- if (SingleThreadDelivery && HostStatDir == NULL)
- {
- SingleThreadDelivery = FALSE;
- printf("Warning: HostStatusDirectory required for SingleThreadDelivery\n");
- }
-
- /* check for permissions */
- if ((OpMode == MD_DAEMON ||
- OpMode == MD_FGDAEMON ||
- OpMode == MD_PURGESTAT) &&
- RealUid != 0 &&
- RealUid != TrustedUid)
- {
- if (LogLevel > 1)
- sm_syslog(LOG_ALERT, NOQID,
- "user %d attempted to %s",
- RealUid,
- OpMode != MD_PURGESTAT ? "run daemon"
- : "purge host status");
- usrerr("Permission denied");
- finis(FALSE, EX_USAGE);
- }
-
- if (MeToo)
- BlankEnvelope.e_flags |= EF_METOO;
-
- switch (OpMode)
- {
- case MD_TEST:
- /* don't have persistent host status in test mode */
- HostStatDir = NULL;
- if (Verbose == 0)
- Verbose = 2;
- CurEnv->e_errormode = EM_PRINT;
- HoldErrs = FALSE;
- break;
-
- case MD_VERIFY:
- CurEnv->e_errormode = EM_PRINT;
- HoldErrs = FALSE;
- /* arrange to exit cleanly on hangup signal */
- if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)
- setsignal(SIGHUP, intsig);
- break;
-
- case MD_FGDAEMON:
- run_in_foreground = TRUE;
- OpMode = MD_DAEMON;
- /* fall through ... */
-
- case MD_DAEMON:
- vendor_daemon_setup(CurEnv);
-
- /* remove things that don't make sense in daemon mode */
- FullName = NULL;
- GrabTo = FALSE;
-
- /* arrange to restart on hangup signal */
- if (SaveArgv[0] == NULL || SaveArgv[0][0] != '/')
- sm_syslog(LOG_WARNING, NOQID,
- "daemon invoked without full pathname; kill -1 won't work");
- setsignal(SIGHUP, sighup);
-
- /* workaround: can't seem to release the signal in the parent */
- releasesignal(SIGHUP);
- break;
-
- case MD_INITALIAS:
- Verbose = 2;
- CurEnv->e_errormode = EM_PRINT;
- HoldErrs = FALSE;
- /* fall through... */
-
- case MD_PRINT:
- /* to handle sendmail -bp -qSfoobar properly */
- queuemode = FALSE;
- /* fall through... */
-
- default:
- /* arrange to exit cleanly on hangup signal */
- if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)
- setsignal(SIGHUP, intsig);
- break;
- }
-
- /* special considerations for FullName */
- if (FullName != NULL)
- {
- char *full = NULL;
- extern bool rfc822_string __P((char *));
-
- /* full names can't have newlines */
- if (strchr(FullName, '\n') != NULL)
- {
- FullName = full = newstr(denlstring(FullName, TRUE, TRUE));
- }
- /* check for characters that may have to be quoted */
- if (!rfc822_string(FullName))
- {
- extern char *addquotes __P((char *));
-
- /*
- ** Quote a full name with special characters
- ** as a comment so crackaddr() doesn't destroy
- ** the name portion of the address.
- */
- FullName = addquotes(FullName);
- if (full != NULL)
- free(full);
- }
- }
-
- /* do heuristic mode adjustment */
- if (Verbose)
- {
- /* turn off noconnect option */
- setoption('c', "F", TRUE, FALSE, CurEnv);
-
- /* turn on interactive delivery */
- setoption('d', "", TRUE, FALSE, CurEnv);
- }
-
-#ifdef VENDOR_CODE
- /* check for vendor mismatch */
- if (VendorCode != VENDOR_CODE)
- {
- extern char *getvendor __P((int));
-
- message("Warning: .cf file vendor code mismatch: sendmail expects vendor %s, .cf file vendor is %s",
- getvendor(VENDOR_CODE), getvendor(VendorCode));
- }
-#endif
-
- /* check for out of date configuration level */
- if (ConfigLevel < MAXCONFIGLEVEL)
- {
- message("Warning: .cf file is out of date: sendmail %s supports version %d, .cf file is version %d",
- Version, MAXCONFIGLEVEL, ConfigLevel);
- }
-
- if (ConfigLevel < 3)
- {
- UseErrorsTo = TRUE;
- }
-
- /* set options that were previous macros */
- if (SmtpGreeting == NULL)
- {
- if (ConfigLevel < 7 && (p = macvalue('e', CurEnv)) != NULL)
- SmtpGreeting = newstr(p);
- else
- SmtpGreeting = "\201j Sendmail \201v ready at \201b";
- }
- if (UnixFromLine == NULL)
- {
- if (ConfigLevel < 7 && (p = macvalue('l', CurEnv)) != NULL)
- UnixFromLine = newstr(p);
- else
- UnixFromLine = "From \201g \201d";
- }
-
- /* our name for SMTP codes */
- expand("\201j", jbuf, sizeof jbuf, CurEnv);
- MyHostName = jbuf;
- if (strchr(jbuf, '.') == NULL)
- message("WARNING: local host name (%s) is not qualified; fix $j in config file",
- jbuf);
-
- /* make certain that this name is part of the $=w class */
- setclass('w', MyHostName);
-
- /* the indices of built-in mailers */
- st = stab("local", ST_MAILER, ST_FIND);
- if (st != NULL)
- LocalMailer = st->s_mailer;
- else if (OpMode != MD_TEST || !warn_C_flag)
- syserr("No local mailer defined");
-
- st = stab("prog", ST_MAILER, ST_FIND);
- if (st == NULL)
- syserr("No prog mailer defined");
- else
- {
- ProgMailer = st->s_mailer;
- clrbitn(M_MUSER, ProgMailer->m_flags);
- }
-
- st = stab("*file*", ST_MAILER, ST_FIND);
- if (st == NULL)
- syserr("No *file* mailer defined");
- else
- {
- FileMailer = st->s_mailer;
- clrbitn(M_MUSER, FileMailer->m_flags);
- }
-
- st = stab("*include*", ST_MAILER, ST_FIND);
- if (st == NULL)
- syserr("No *include* mailer defined");
- else
- InclMailer = st->s_mailer;
-
- if (ConfigLevel < 6)
- {
- /* heuristic tweaking of local mailer for back compat */
- if (LocalMailer != NULL)
- {
- setbitn(M_ALIASABLE, LocalMailer->m_flags);
- setbitn(M_HASPWENT, LocalMailer->m_flags);
- setbitn(M_TRYRULESET5, LocalMailer->m_flags);
- setbitn(M_CHECKINCLUDE, LocalMailer->m_flags);
- setbitn(M_CHECKPROG, LocalMailer->m_flags);
- setbitn(M_CHECKFILE, LocalMailer->m_flags);
- setbitn(M_CHECKUDB, LocalMailer->m_flags);
- }
- if (ProgMailer != NULL)
- setbitn(M_RUNASRCPT, ProgMailer->m_flags);
- if (FileMailer != NULL)
- setbitn(M_RUNASRCPT, FileMailer->m_flags);
- }
- if (ConfigLevel < 7)
- {
- if (LocalMailer != NULL)
- setbitn(M_VRFY250, LocalMailer->m_flags);
- if (ProgMailer != NULL)
- setbitn(M_VRFY250, ProgMailer->m_flags);
- if (FileMailer != NULL)
- setbitn(M_VRFY250, FileMailer->m_flags);
- }
-
- /* MIME Content-Types that cannot be transfer encoded */
- setclass('n', "multipart/signed");
-
- /* MIME message/xxx subtypes that can be treated as messages */
- setclass('s', "rfc822");
-
- /* MIME Content-Transfer-Encodings that can be encoded */
- setclass('e', "7bit");
- setclass('e', "8bit");
- setclass('e', "binary");
-
-#ifdef USE_B_CLASS
- /* MIME Content-Types that should be treated as binary */
- setclass('b', "image");
- setclass('b', "audio");
- setclass('b', "video");
- setclass('b', "application/octet-stream");
-#endif
-
-#if _FFR_MAX_MIME_HEADER_LENGTH
- /* MIME headers which have fields to check for overflow */
- setclass(macid("{checkMIMEFieldHeaders}", NULL), "content-disposition");
- setclass(macid("{checkMIMEFieldHeaders}", NULL), "content-type");
-
- /* MIME headers to check for length overflow */
- setclass(macid("{checkMIMETextHeaders}", NULL), "content-description");
-
- /* MIME headers to check for overflow and rebalance */
- setclass(macid("{checkMIMEHeaders}", NULL), "content-disposition");
- setclass(macid("{checkMIMEHeaders}", NULL), "content-id");
- setclass(macid("{checkMIMEHeaders}", NULL), "content-transfer-encoding");
- setclass(macid("{checkMIMEHeaders}", NULL), "content-type");
- setclass(macid("{checkMIMEHeaders}", NULL), "mime-version");
-#endif
-
- /* operate in queue directory */
- if (QueueDir == NULL)
- {
- if (OpMode != MD_TEST)
- {
- syserr("QueueDirectory (Q) option must be set");
- ExitStat = EX_CONFIG;
- }
- }
- else
- {
- /* test path to get warning messages */
- (void) safedirpath(QueueDir, (uid_t) 0, (gid_t) 0, NULL, SFF_ANYFILE);
- if (OpMode != MD_TEST && chdir(QueueDir) < 0)
- {
- syserr("cannot chdir(%s)", QueueDir);
- ExitStat = EX_CONFIG;
- }
- }
-
- /* check host status directory for validity */
- if (HostStatDir != NULL && !path_is_dir(HostStatDir, FALSE))
- {
- /* cannot use this value */
- if (tTd(0, 2))
- printf("Cannot use HostStatusDirectory = %s: %s\n",
- HostStatDir, errstring(errno));
- HostStatDir = NULL;
- }
-
-# if QUEUE
- if (queuemode && RealUid != 0 && bitset(PRIV_RESTRICTQRUN, PrivacyFlags))
- {
- struct stat stbuf;
-
- /* check to see if we own the queue directory */
- if (stat(".", &stbuf) < 0)
- syserr("main: cannot stat %s", QueueDir);
- if (stbuf.st_uid != RealUid)
- {
- /* nope, really a botch */
- usrerr("You do not have permission to process the queue");
- finis(FALSE, EX_NOPERM);
- }
- }
-# endif /* QUEUE */
-
- /* if we've had errors so far, exit now */
- if (ExitStat != EX_OK && OpMode != MD_TEST)
- finis(FALSE, ExitStat);
-
-#if XDEBUG
- checkfd012("before main() initmaps");
-#endif
-
- /*
- ** Do operation-mode-dependent initialization.
- */
-
- switch (OpMode)
- {
- case MD_PRINT:
- /* print the queue */
-#if QUEUE
- dropenvelope(CurEnv, TRUE);
- signal(SIGPIPE, quiesce);
- printqueue();
- finis(FALSE, EX_OK);
-#else /* QUEUE */
- usrerr("No queue to print");
- finis(FALSE, ExitStat);
-#endif /* QUEUE */
- break;
-
- case MD_HOSTSTAT:
- signal(SIGPIPE, quiesce);
- mci_traverse_persistent(mci_print_persistent, NULL);
- finis(FALSE, EX_OK);
- break;
-
- case MD_PURGESTAT:
- mci_traverse_persistent(mci_purge_persistent, NULL);
- finis(FALSE, EX_OK);
- break;
-
- case MD_INITALIAS:
- /* initialize maps */
- initmaps(TRUE, CurEnv);
- finis(FALSE, ExitStat);
- break;
-
- case MD_SMTP:
- case MD_DAEMON:
- /* reset DSN parameters */
- DefaultNotify = QPINGONFAILURE|QPINGONDELAY;
- CurEnv->e_envid = NULL;
- CurEnv->e_flags &= ~(EF_RET_PARAM|EF_NO_BODY_RETN);
-
- /* don't open maps for daemon -- done below in child */
- break;
-
- default:
- /* open the maps */
- initmaps(FALSE, CurEnv);
- break;
- }
-
- if (tTd(0, 15))
- {
- extern void printrules __P((void));
-
- /* print configuration table (or at least part of it) */
- if (tTd(0, 90))
- printrules();
- for (i = 0; i < MAXMAILERS; i++)
- {
- if (Mailer[i] != NULL)
- printmailer(Mailer[i]);
- }
- }
-
- /*
- ** Switch to the main envelope.
- */
-
- CurEnv = newenvelope(&MainEnvelope, CurEnv);
- MainEnvelope.e_flags = BlankEnvelope.e_flags;
-
- /*
- ** If test mode, read addresses from stdin and process.
- */
-
- if (OpMode == MD_TEST)
- {
- char buf[MAXLINE];
- SIGFUNC_DECL intindebug __P((int));
-
- if (isatty(fileno(stdin)))
- Verbose = 2;
-
- if (Verbose)
- {
- printf("ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n");
- printf("Enter <ruleset> <address>\n");
- }
- if (setjmp(TopFrame) > 0)
- printf("\n");
- (void) setsignal(SIGINT, intindebug);
- for (;;)
- {
- extern void testmodeline __P((char *, ENVELOPE *));
-
- if (Verbose == 2)
- printf("> ");
- (void) fflush(stdout);
- if (fgets(buf, sizeof buf, stdin) == NULL)
- finis(TRUE, ExitStat);
- p = strchr(buf, '\n');
- if (p != NULL)
- *p = '\0';
- if (Verbose < 2)
- printf("> %s\n", buf);
- testmodeline(buf, CurEnv);
- }
- }
-
-# if QUEUE
- /*
- ** If collecting stuff from the queue, go start doing that.
- */
-
- if (queuemode && OpMode != MD_DAEMON && QueueIntvl == 0)
- {
- (void) runqueue(FALSE, Verbose);
- finis(TRUE, ExitStat);
- }
-# endif /* QUEUE */
-
- /*
- ** If a daemon, wait for a request.
- ** getrequests will always return in a child.
- ** If we should also be processing the queue, start
- ** doing it in background.
- ** We check for any errors that might have happened
- ** during startup.
- */
-
- if (OpMode == MD_DAEMON || QueueIntvl != 0)
- {
- char dtype[200];
- extern void getrequests __P((ENVELOPE *));
-
- if (!run_in_foreground && !tTd(99, 100))
- {
- /* put us in background */
- i = fork();
- if (i < 0)
- syserr("daemon: cannot fork");
- if (i != 0)
- finis(FALSE, EX_OK);
-
- /* disconnect from our controlling tty */
- disconnect(2, CurEnv);
- }
-
- dtype[0] = '\0';
- if (OpMode == MD_DAEMON)
- strcat(dtype, "+SMTP");
- if (QueueIntvl != 0)
- {
- strcat(dtype, "+queueing@");
- strcat(dtype, pintvl(QueueIntvl, TRUE));
- }
- if (tTd(0, 1))
- strcat(dtype, "+debugging");
-
- sm_syslog(LOG_INFO, NOQID,
- "starting daemon (%s): %s", Version, dtype + 1);
-#ifdef XLA
- xla_create_file();
-#endif
-
-# if QUEUE
- if (queuemode)
- {
- (void) runqueue(TRUE, FALSE);
- if (OpMode != MD_DAEMON)
- {
- for (;;)
- {
- pause();
- if (DoQueueRun)
- (void) runqueue(TRUE, FALSE);
- }
- }
- }
-# endif /* QUEUE */
- dropenvelope(CurEnv, TRUE);
-
-#if DAEMON
- getrequests(CurEnv);
-
- /* drop privileges */
- (void) drop_privileges(FALSE);
-
- /* at this point we are in a child: reset state */
- (void) newenvelope(CurEnv, CurEnv);
-
- /*
- ** Get authentication data
- */
-
- p = getauthinfo(fileno(InChannel), &forged);
- define('_', p, &BlankEnvelope);
-#endif /* DAEMON */
- }
-
-# if SMTP
- /*
- ** If running SMTP protocol, start collecting and executing
- ** commands. This will never return.
- */
-
- if (OpMode == MD_SMTP || OpMode == MD_DAEMON)
- {
- char pbuf[20];
- extern void smtp __P((char *, ENVELOPE *));
-
- /*
- ** Save some macros for check_* rulesets.
- */
-
- if (forged)
- {
- char ipbuf[103];
-
- snprintf(ipbuf, sizeof ipbuf, "[%.100s]",
- inet_ntoa(RealHostAddr.sin.sin_addr));
-
- define(macid("{client_name}", NULL),
- newstr(ipbuf), &BlankEnvelope);
- }
- else
- define(macid("{client_name}", NULL), RealHostName, &BlankEnvelope);
- define(macid("{client_addr}", NULL),
- newstr(anynet_ntoa(&RealHostAddr)), &BlankEnvelope);
- if (RealHostAddr.sa.sa_family == AF_INET)
- snprintf(pbuf, sizeof pbuf, "%d", RealHostAddr.sin.sin_port);
- else
- snprintf(pbuf, sizeof pbuf, "0");
- define(macid("{client_port}", NULL), newstr(pbuf), &BlankEnvelope);
-
- /* initialize maps now for check_relay ruleset */
- initmaps(FALSE, CurEnv);
-
- if (OpMode == MD_DAEMON)
- {
- /* validate the connection */
- HoldErrs = TRUE;
- nullserver = validate_connection(&RealHostAddr,
- RealHostName, CurEnv);
- HoldErrs = FALSE;
- }
- smtp(nullserver, CurEnv);
- }
-# endif /* SMTP */
-
- clearenvelope(CurEnv, FALSE);
- if (OpMode == MD_VERIFY)
- {
- CurEnv->e_sendmode = SM_VERIFY;
- PostMasterCopy = NULL;
- }
- else
- {
- /* interactive -- all errors are global */
- CurEnv->e_flags |= EF_GLOBALERRS|EF_LOGSENDER;
- }
-
- /*
- ** Do basic system initialization and set the sender
- */
-
- initsys(CurEnv);
- if (warn_f_flag != '\0' && !wordinclass(RealUserName, 't'))
- auth_warning(CurEnv, "%s set sender to %s using -%c",
- RealUserName, from, warn_f_flag);
- setsender(from, CurEnv, NULL, '\0', FALSE);
- if (macvalue('s', CurEnv) == NULL)
- define('s', RealHostName, CurEnv);
-
- if (*av == NULL && !GrabTo)
- {
- CurEnv->e_flags |= EF_GLOBALERRS;
- usrerr("Recipient names must be specified");
-
- /* collect body for UUCP return */
- if (OpMode != MD_VERIFY)
- collect(InChannel, FALSE, NULL, CurEnv);
- finis(TRUE, ExitStat);
- }
-
- /*
- ** Scan argv and deliver the message to everyone.
- */
-
- sendtoargv(av, CurEnv);
-
- /* if we have had errors sofar, arrange a meaningful exit stat */
- if (Errors > 0 && ExitStat == EX_OK)
- ExitStat = EX_USAGE;
-
-#if _FFR_FIX_DASHT
- /*
- ** If using -t, force not sending to argv recipients, even
- ** if they are mentioned in the headers.
- */
-
- if (GrabTo)
- {
- ADDRESS *q;
-
- for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next)
- q->q_flags |= QDONTSEND;
- }
-#endif
-
- /*
- ** Read the input mail.
- */
-
- CurEnv->e_to = NULL;
- if (OpMode != MD_VERIFY || GrabTo)
- {
- long savedflags = CurEnv->e_flags & EF_FATALERRS;
-
- CurEnv->e_flags |= EF_GLOBALERRS;
- CurEnv->e_flags &= ~EF_FATALERRS;
- collect(InChannel, FALSE, NULL, CurEnv);
-
- /* bail out if message too large */
- if (bitset(EF_CLRQUEUE, CurEnv->e_flags))
- {
- finis(TRUE, ExitStat);
- /*NOTREACHED*/
- return -1;
- }
- CurEnv->e_flags |= savedflags;
- }
- errno = 0;
-
- if (tTd(1, 1))
- printf("From person = \"%s\"\n", CurEnv->e_from.q_paddr);
-
- /*
- ** Actually send everything.
- ** If verifying, just ack.
- */
-
- CurEnv->e_from.q_flags |= QDONTSEND;
- if (tTd(1, 5))
- {
- printf("main: QDONTSEND ");
- printaddr(&CurEnv->e_from, FALSE);
- }
- CurEnv->e_to = NULL;
- CurrentLA = getla();
- GrabTo = FALSE;
- sendall(CurEnv, SM_DEFAULT);
-
- /*
- ** All done.
- ** Don't send return error message if in VERIFY mode.
- */
-
- finis(TRUE, ExitStat);
- /*NOTREACHED*/
- return -1;
-}
-
-/* ARGSUSED */
-SIGFUNC_DECL
-quiesce(sig)
- int sig;
-{
- finis(FALSE, EX_OK);
-}
-
-/* ARGSUSED */
-SIGFUNC_DECL
-intindebug(sig)
- int sig;
-{
- longjmp(TopFrame, 1);
- return SIGFUNC_RETURN;
-}
-
-
- /*
-** FINIS -- Clean up and exit.
-**
-** Parameters:
-** drop -- whether or not to drop CurEnv envelope
-** exitstat -- exit status to use for exit() call
-**
-** Returns:
-** never
-**
-** Side Effects:
-** exits sendmail
-*/
-
-void
-finis(drop, exitstat)
- bool drop;
- volatile int exitstat;
-{
- extern void closemaps __P((void));
-#ifdef USERDB
- extern void _udbx_close __P((void));
-#endif
-
- if (tTd(2, 1))
- {
- extern void printenvflags __P((ENVELOPE *));
-
- printf("\n====finis: stat %d e_id=%s e_flags=",
- exitstat,
- CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id);
- printenvflags(CurEnv);
- }
- if (tTd(2, 9))
- printopenfds(FALSE);
-
- /* if we fail in finis(), just exit */
- if (setjmp(TopFrame) != 0)
- {
- /* failed -- just give it up */
- goto forceexit;
- }
-
- /* clean up temp files */
- CurEnv->e_to = NULL;
- if (drop && CurEnv->e_id != NULL)
- dropenvelope(CurEnv, TRUE);
-
- /* flush any cached connections */
- mci_flush(TRUE, NULL);
-
- /* close maps belonging to this pid */
- closemaps();
-
-#ifdef USERDB
- /* close UserDatabase */
- _udbx_close();
-#endif
-
-# ifdef XLA
- /* clean up extended load average stuff */
- xla_all_end();
-# endif
-
- /* and exit */
- forceexit:
- if (LogLevel > 78)
- sm_syslog(LOG_DEBUG, CurEnv->e_id,
- "finis, pid=%d",
- getpid());
- if (exitstat == EX_TEMPFAIL || CurEnv->e_errormode == EM_BERKNET)
- exitstat = EX_OK;
-
- /* reset uid for process accounting */
- endpwent();
- setuid(RealUid);
-
- exit(exitstat);
-}
- /*
-** INTSIG -- clean up on interrupt
-**
-** This just arranges to exit. It pessimises in that it
-** may resend a message.
-**
-** Parameters:
-** none.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Unlocks the current job.
-*/
-
-/* ARGSUSED */
-SIGFUNC_DECL
-intsig(sig)
- int sig;
-{
- if (LogLevel > 79)
- sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt");
- FileName = NULL;
- unlockqueue(CurEnv);
- closecontrolsocket(TRUE);
-#ifdef XLA
- xla_all_end();
-#endif
- finis(FALSE, EX_OK);
-}
- /*
-** INITMACROS -- initialize the macro system
-**
-** This just involves defining some macros that are actually
-** used internally as metasymbols to be themselves.
-**
-** Parameters:
-** none.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** initializes several macros to be themselves.
-*/
-
-struct metamac MetaMacros[] =
-{
- /* LHS pattern matching characters */
- { '*', MATCHZANY }, { '+', MATCHANY }, { '-', MATCHONE },
- { '=', MATCHCLASS }, { '~', MATCHNCLASS },
-
- /* these are RHS metasymbols */
- { '#', CANONNET }, { '@', CANONHOST }, { ':', CANONUSER },
- { '>', CALLSUBR },
-
- /* the conditional operations */
- { '?', CONDIF }, { '|', CONDELSE }, { '.', CONDFI },
-
- /* the hostname lookup characters */
- { '[', HOSTBEGIN }, { ']', HOSTEND },
- { '(', LOOKUPBEGIN }, { ')', LOOKUPEND },
-
- /* miscellaneous control characters */
- { '&', MACRODEXPAND },
-
- { '\0' }
-};
-
-#define MACBINDING(name, mid) \
- stab(name, ST_MACRO, ST_ENTER)->s_macro = mid; \
- MacroName[mid] = name;
-
-void
-initmacros(e)
- register ENVELOPE *e;
-{
- register struct metamac *m;
- register int c;
- char buf[5];
- extern char *MacroName[256];
-
- for (m = MetaMacros; m->metaname != '\0'; m++)
- {
- buf[0] = m->metaval;
- buf[1] = '\0';
- define(m->metaname, newstr(buf), e);
- }
- buf[0] = MATCHREPL;
- buf[2] = '\0';
- for (c = '0'; c <= '9'; c++)
- {
- buf[1] = c;
- define(c, newstr(buf), e);
- }
-
- /* set defaults for some macros sendmail will use later */
- define('n', "MAILER-DAEMON", e);
-
- /* set up external names for some internal macros */
- MACBINDING("opMode", MID_OPMODE);
- /*XXX should probably add equivalents for all short macros here XXX*/
-}
- /*
-** DISCONNECT -- remove our connection with any foreground process
-**
-** Parameters:
-** droplev -- how "deeply" we should drop the line.
-** 0 -- ignore signals, mail back errors, make sure
-** output goes to stdout.
-** 1 -- also, make stdout go to transcript.
-** 2 -- also, disconnect from controlling terminal
-** (only for daemon mode).
-** e -- the current envelope.
-**
-** Returns:
-** none
-**
-** Side Effects:
-** Trys to insure that we are immune to vagaries of
-** the controlling tty.
-*/
-
-void
-disconnect(droplev, e)
- int droplev;
- register ENVELOPE *e;
-{
- int fd;
-
- if (tTd(52, 1))
- printf("disconnect: In %d Out %d, e=%lx\n",
- fileno(InChannel), fileno(OutChannel), (u_long) e);
- if (tTd(52, 100))
- {
- printf("don't\n");
- return;
- }
- if (LogLevel > 93)
- sm_syslog(LOG_DEBUG, e->e_id,
- "disconnect level %d",
- droplev);
-
- /* be sure we don't get nasty signals */
- (void) setsignal(SIGINT, SIG_IGN);
- (void) setsignal(SIGQUIT, SIG_IGN);
-
- /* we can't communicate with our caller, so.... */
- HoldErrs = TRUE;
- CurEnv->e_errormode = EM_MAIL;
- Verbose = 0;
- DisConnected = TRUE;
-
- /* all input from /dev/null */
- if (InChannel != stdin)
- {
- (void) fclose(InChannel);
- InChannel = stdin;
- }
- if (freopen("/dev/null", "r", stdin) == NULL)
- sm_syslog(LOG_ERR, e->e_id,
- "disconnect: freopen(\"/dev/null\") failed: %s",
- errstring(errno));
-
- /* output to the transcript */
- if (OutChannel != stdout)
- {
- (void) fclose(OutChannel);
- OutChannel = stdout;
- }
- if (droplev > 0)
- {
- if (e->e_xfp == NULL)
- {
- fd = open("/dev/null", O_WRONLY, 0666);
- if (fd == -1)
- sm_syslog(LOG_ERR, e->e_id,
- "disconnect: open(\"/dev/null\") failed: %s",
- errstring(errno));
- }
- else
- {
- fd = fileno(e->e_xfp);
- if (fd == -1)
- sm_syslog(LOG_ERR, e->e_id,
- "disconnect: fileno(e->e_xfp) failed: %s",
- errstring(errno));
- }
- (void) fflush(stdout);
- dup2(fd, STDOUT_FILENO);
- dup2(fd, STDERR_FILENO);
- if (e->e_xfp == NULL)
- close(fd);
- }
-
- /* drop our controlling TTY completely if possible */
- if (droplev > 1)
- {
- (void) setsid();
- errno = 0;
- }
-
-#if XDEBUG
- checkfd012("disconnect");
-#endif
-
- if (LogLevel > 71)
- sm_syslog(LOG_DEBUG, e->e_id,
- "in background, pid=%d",
- getpid());
-
- errno = 0;
-}
-
-static void
-obsolete(argv)
- char *argv[];
-{
- register char *ap;
- register char *op;
-
- while ((ap = *++argv) != NULL)
- {
- /* Return if "--" or not an option of any form. */
- if (ap[0] != '-' || ap[1] == '-')
- return;
-
- /* skip over options that do have a value */
- op = strchr(OPTIONS, ap[1]);
- if (op != NULL && *++op == ':' && ap[2] == '\0' &&
- ap[1] != 'd' &&
-#if defined(sony_news)
- ap[1] != 'E' && ap[1] != 'J' &&
-#endif
- argv[1] != NULL && argv[1][0] != '-')
- {
- argv++;
- continue;
- }
-
- /* If -C doesn't have an argument, use sendmail.cf. */
-#define __DEFPATH "sendmail.cf"
- if (ap[1] == 'C' && ap[2] == '\0')
- {
- *argv = xalloc(sizeof(__DEFPATH) + 2);
- argv[0][0] = '-';
- argv[0][1] = 'C';
- (void)strcpy(&argv[0][2], __DEFPATH);
- }
-
- /* If -q doesn't have an argument, run it once. */
- if (ap[1] == 'q' && ap[2] == '\0')
- *argv = "-q0";
-
- /* if -d doesn't have an argument, use 0-99.1 */
- if (ap[1] == 'd' && ap[2] == '\0')
- *argv = "-d0-99.1";
-
-# if defined(sony_news)
- /* if -E doesn't have an argument, use -EC */
- if (ap[1] == 'E' && ap[2] == '\0')
- *argv = "-EC";
-
- /* if -J doesn't have an argument, use -JJ */
- if (ap[1] == 'J' && ap[2] == '\0')
- *argv = "-JJ";
-# endif
- }
-}
- /*
-** AUTH_WARNING -- specify authorization warning
-**
-** Parameters:
-** e -- the current envelope.
-** msg -- the text of the message.
-** args -- arguments to the message.
-**
-** Returns:
-** none.
-*/
-
-void
-#ifdef __STDC__
-auth_warning(register ENVELOPE *e, const char *msg, ...)
-#else
-auth_warning(e, msg, va_alist)
- register ENVELOPE *e;
- const char *msg;
- va_dcl
-#endif
-{
- char buf[MAXLINE];
- VA_LOCAL_DECL
-
- if (bitset(PRIV_AUTHWARNINGS, PrivacyFlags))
- {
- register char *p;
- static char hostbuf[48];
- extern struct hostent *myhostname __P((char *, int));
-
- if (hostbuf[0] == '\0')
- (void) myhostname(hostbuf, sizeof hostbuf);
-
- (void) snprintf(buf, sizeof buf, "%s: ", hostbuf);
- p = &buf[strlen(buf)];
- VA_START(msg);
- vsnprintf(p, SPACELEFT(buf, p), msg, ap);
- VA_END;
- addheader("X-Authentication-Warning", buf, &e->e_header);
- if (LogLevel > 3)
- sm_syslog(LOG_INFO, e->e_id,
- "Authentication-Warning: %.400s",
- buf);
- }
-}
- /*
-** GETEXTENV -- get from external environment
-**
-** Parameters:
-** envar -- the name of the variable to retrieve
-**
-** Returns:
-** The value, if any.
-*/
-
-char *
-getextenv(envar)
- const char *envar;
-{
- char **envp;
- int l;
-
- l = strlen(envar);
- for (envp = ExternalEnviron; *envp != NULL; envp++)
- {
- if (strncmp(*envp, envar, l) == 0 && (*envp)[l] == '=')
- return &(*envp)[l + 1];
- }
- return NULL;
-}
- /*
-** SETUSERENV -- set an environment in the propogated environment
-**
-** Parameters:
-** envar -- the name of the environment variable.
-** value -- the value to which it should be set. If
-** null, this is extracted from the incoming
-** environment. If that is not set, the call
-** to setuserenv is ignored.
-**
-** Returns:
-** none.
-*/
-
-void
-setuserenv(envar, value)
- const char *envar;
- const char *value;
-{
- int i;
- char **evp = UserEnviron;
- char *p;
-
- if (value == NULL)
- {
- value = getextenv(envar);
- if (value == NULL)
- return;
- }
-
- i = strlen(envar);
- p = (char *) xalloc(strlen(value) + i + 2);
- strcpy(p, envar);
- p[i++] = '=';
- strcpy(&p[i], value);
-
- while (*evp != NULL && strncmp(*evp, p, i) != 0)
- evp++;
- if (*evp != NULL)
- {
- *evp++ = p;
- }
- else if (evp < &UserEnviron[MAXUSERENVIRON])
- {
- *evp++ = p;
- *evp = NULL;
- }
-
- /* make sure it is in our environment as well */
- if (putenv(p) < 0)
- syserr("setuserenv: putenv(%s) failed", p);
-}
- /*
-** DUMPSTATE -- dump state
-**
-** For debugging.
-*/
-
-void
-dumpstate(when)
- char *when;
-{
- register char *j = macvalue('j', CurEnv);
- int rs;
-
- sm_syslog(LOG_DEBUG, CurEnv->e_id,
- "--- dumping state on %s: $j = %s ---",
- when,
- j == NULL ? "<NULL>" : j);
- if (j != NULL)
- {
- if (!wordinclass(j, 'w'))
- sm_syslog(LOG_DEBUG, CurEnv->e_id,
- "*** $j not in $=w ***");
- }
- sm_syslog(LOG_DEBUG, CurEnv->e_id, "CurChildren = %d", CurChildren);
- sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- open file descriptors: ---");
- printopenfds(TRUE);
- sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- connection cache: ---");
- mci_dump_all(TRUE);
- rs = strtorwset("debug_dumpstate", NULL, ST_FIND);
- if (rs > 0)
- {
- int stat;
- register char **pvp;
- char *pv[MAXATOM + 1];
-
- pv[0] = NULL;
- stat = rewrite(pv, rs, 0, CurEnv);
- sm_syslog(LOG_DEBUG, CurEnv->e_id,
- "--- ruleset debug_dumpstate returns stat %d, pv: ---",
- stat);
- for (pvp = pv; *pvp != NULL; pvp++)
- sm_syslog(LOG_DEBUG, CurEnv->e_id, "%s", *pvp);
- }
- sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- end of state dump ---");
-}
-
-
-/* ARGSUSED */
-SIGFUNC_DECL
-sigusr1(sig)
- int sig;
-{
- dumpstate("user signal");
- return SIGFUNC_RETURN;
-}
-
-
-/* ARGSUSED */
-SIGFUNC_DECL
-sighup(sig)
- int sig;
-{
- if (SaveArgv[0][0] != '/')
- {
- if (LogLevel > 3)
- sm_syslog(LOG_INFO, NOQID, "could not restart: need full path");
- finis(FALSE, EX_OSFILE);
- }
- if (LogLevel > 3)
- sm_syslog(LOG_INFO, NOQID, "restarting %s on signal", SaveArgv[0]);
- alarm(0);
- releasesignal(SIGHUP);
- closecontrolsocket(TRUE);
- if (drop_privileges(TRUE) != EX_OK)
- {
- if (LogLevel > 0)
- sm_syslog(LOG_ALERT, NOQID, "could not set[ug]id(%d, %d): %m",
- RunAsUid, RunAsGid);
- finis(FALSE, EX_OSERR);
- }
- execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron);
- if (LogLevel > 0)
- sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %m", SaveArgv[0]);
- finis(FALSE, EX_OSFILE);
-}
- /*
-** DROP_PRIVILEGES -- reduce privileges to those of the RunAsUser option
-**
-** Parameters:
-** to_real_uid -- if set, drop to the real uid instead
-** of the RunAsUser.
-**
-** Returns:
-** EX_OSERR if the setuid failed.
-** EX_OK otherwise.
-*/
-
-int
-drop_privileges(to_real_uid)
- bool to_real_uid;
-{
- int rval = EX_OK;
- GIDSET_T emptygidset[1];
-
- if (tTd(47, 1))
- printf("drop_privileges(%d): Real[UG]id=%d:%d, RunAs[UG]id=%d:%d\n",
- (int)to_real_uid, (int)RealUid, (int)RealGid, (int)RunAsUid, (int)RunAsGid);
-
- if (to_real_uid)
- {
- RunAsUserName = RealUserName;
- RunAsUid = RealUid;
- RunAsGid = RealGid;
- }
-
- /* make sure no one can grab open descriptors for secret files */
- endpwent();
-
- /* reset group permissions; these can be set later */
- emptygidset[0] = (to_real_uid || RunAsGid != 0) ? RunAsGid : getegid();
- if (setgroups(1, emptygidset) == -1 && geteuid() == 0)
- rval = EX_OSERR;
-
- /* reset primary group and user id */
- if ((to_real_uid || RunAsGid != 0) && setgid(RunAsGid) < 0)
- rval = EX_OSERR;
- if ((to_real_uid || RunAsUid != 0) && setuid(RunAsUid) < 0)
- rval = EX_OSERR;
- if (tTd(47, 5))
- {
- printf("drop_privileges: e/ruid = %d/%d e/rgid = %d/%d\n",
- (int)geteuid(), (int)getuid(), (int)getegid(), (int)getgid());
- printf("drop_privileges: RunAsUser = %d:%d\n", (int)RunAsUid, (int)RunAsGid);
- }
- return rval;
-}
- /*
-** FILL_FD -- make sure a file descriptor has been properly allocated
-**
-** Used to make sure that stdin/out/err are allocated on startup
-**
-** Parameters:
-** fd -- the file descriptor to be filled.
-** where -- a string used for logging. If NULL, this is
-** being called on startup, and logging should
-** not be done.
-**
-** Returns:
-** none
-*/
-
-void
-fill_fd(fd, where)
- int fd;
- char *where;
-{
- int i;
- struct stat stbuf;
-
- if (fstat(fd, &stbuf) >= 0 || errno != EBADF)
- return;
-
- if (where != NULL)
- syserr("fill_fd: %s: fd %d not open", where, fd);
- else
- MissingFds |= 1 << fd;
- i = open("/dev/null", fd == 0 ? O_RDONLY : O_WRONLY, 0666);
- if (i < 0)
- {
- syserr("!fill_fd: %s: cannot open /dev/null",
- where == NULL ? "startup" : where);
- }
- if (fd != i)
- {
- (void) dup2(i, fd);
- (void) close(i);
- }
-}
- /*
-** TESTMODELINE -- process a test mode input line
-**
-** Parameters:
-** line -- the input line.
-** e -- the current environment.
-** Syntax:
-** # a comment
-** .X process X as a configuration line
-** =X dump a configuration item (such as mailers)
-** $X dump a macro or class
-** /X try an activity
-** X normal process through rule set X
-*/
-
-void
-testmodeline(line, e)
- char *line;
- ENVELOPE *e;
-{
- register char *p;
- char *q;
- auto char *delimptr;
- int mid;
- int i, rs;
- STAB *map;
- char **s;
- struct rewrite *rw;
- ADDRESS a;
- static int tryflags = RF_COPYNONE;
- char exbuf[MAXLINE];
- extern bool invalidaddr __P((char *, char *));
- extern char *crackaddr __P((char *));
- extern void dump_class __P((STAB *, int));
- extern void translate_dollars __P((char *));
- extern void help __P((char *));
-
- switch (line[0])
- {
- case '#':
- case 0:
- return;
-
- case '?':
- help("-bt");
- return;
-
- case '.': /* config-style settings */
- switch (line[1])
- {
- case 'D':
- mid = macid(&line[2], &delimptr);
- if (mid == '\0')
- return;
- translate_dollars(delimptr);
- define(mid, newstr(delimptr), e);
- break;
-
- case 'C':
- if (line[2] == '\0') /* not to call syserr() */
- return;
-
- mid = macid(&line[2], &delimptr);
- if (mid == '\0')
- return;
- translate_dollars(delimptr);
- expand(delimptr, exbuf, sizeof exbuf, e);
- p = exbuf;
- while (*p != '\0')
- {
- register char *wd;
- char delim;
-
- while (*p != '\0' && isascii(*p) && isspace(*p))
- p++;
- wd = p;
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
- p++;
- delim = *p;
- *p = '\0';
- if (wd[0] != '\0')
- setclass(mid, wd);
- *p = delim;
- }
- break;
-
- case '\0':
- printf("Usage: .[DC]macro value(s)\n");
- break;
-
- default:
- printf("Unknown \".\" command %s\n", line);
- break;
- }
- return;
-
- case '=': /* config-style settings */
- switch (line[1])
- {
- case 'S': /* dump rule set */
- rs = strtorwset(&line[2], NULL, ST_FIND);
- if (rs < 0)
- {
- printf("Undefined ruleset %s\n", &line[2]);
- return;
- }
- rw = RewriteRules[rs];
- if (rw == NULL)
- return;
- do
- {
- putchar('R');
- s = rw->r_lhs;
- while (*s != NULL)
- {
- xputs(*s++);
- putchar(' ');
- }
- putchar('\t');
- putchar('\t');
- s = rw->r_rhs;
- while (*s != NULL)
- {
- xputs(*s++);
- putchar(' ');
- }
- putchar('\n');
- } while ((rw = rw->r_next) != NULL);
- break;
-
- case 'M':
- for (i = 0; i < MAXMAILERS; i++)
- {
- if (Mailer[i] != NULL)
- printmailer(Mailer[i]);
- }
- break;
-
- case '\0':
- printf("Usage: =Sruleset or =M\n");
- break;
-
- default:
- printf("Unknown \"=\" command %s\n", line);
- break;
- }
- return;
-
- case '-': /* set command-line-like opts */
- switch (line[1])
- {
- case 'd':
- tTflag(&line[2]);
- break;
-
- case '\0':
- printf("Usage: -d{debug arguments}\n");
- break;
-
- default:
- printf("Unknown \"-\" command %s\n", line);
- break;
- }
- return;
-
- case '$':
- if (line[1] == '=')
- {
- mid = macid(&line[2], NULL);
- if (mid != '\0')
- stabapply(dump_class, mid);
- return;
- }
- mid = macid(&line[1], NULL);
- if (mid == '\0')
- return;
- p = macvalue(mid, e);
- if (p == NULL)
- printf("Undefined\n");
- else
- {
- xputs(p);
- printf("\n");
- }
- return;
-
- case '/': /* miscellaneous commands */
- p = &line[strlen(line)];
- while (--p >= line && isascii(*p) && isspace(*p))
- *p = '\0';
- p = strpbrk(line, " \t");
- if (p != NULL)
- {
- while (isascii(*p) && isspace(*p))
- *p++ = '\0';
- }
- else
- p = "";
- if (line[1] == '\0')
- {
- printf("Usage: /[canon|map|mx|parse|try|tryflags]\n");
- return;
- }
- if (strcasecmp(&line[1], "mx") == 0)
- {
-#if NAMED_BIND
- /* look up MX records */
- int nmx;
- auto int rcode;
- char *mxhosts[MAXMXHOSTS + 1];
-
- if (*p == '\0')
- {
- printf("Usage: /mx address\n");
- return;
- }
- nmx = getmxrr(p, mxhosts, FALSE, &rcode);
- printf("getmxrr(%s) returns %d value(s):\n", p, nmx);
- for (i = 0; i < nmx; i++)
- printf("\t%s\n", mxhosts[i]);
-#else
- printf("No MX code compiled in\n");
-#endif
- }
- else if (strcasecmp(&line[1], "canon") == 0)
- {
- char host[MAXHOSTNAMELEN];
-
- if (*p == '\0')
- {
- printf("Usage: /canon address\n");
- return;
- }
- else if (strlen(p) >= sizeof host)
- {
- printf("Name too long\n");
- return;
- }
- strcpy(host, p);
- (void) getcanonname(host, sizeof(host), HasWildcardMX);
- printf("getcanonname(%s) returns %s\n", p, host);
- }
- else if (strcasecmp(&line[1], "map") == 0)
- {
- auto int rcode = EX_OK;
- char *av[2];
-
- if (*p == '\0')
- {
- printf("Usage: /map mapname key\n");
- return;
- }
- for (q = p; *q != '\0' && !(isascii(*q) && isspace(*q)); q++)
- continue;
- if (*q == '\0')
- {
- printf("No key specified\n");
- return;
- }
- *q++ = '\0';
- map = stab(p, ST_MAP, ST_FIND);
- if (map == NULL)
- {
- printf("Map named \"%s\" not found\n", p);
- return;
- }
- if (!bitset(MF_OPEN, map->s_map.map_mflags))
- {
- printf("Map named \"%s\" not open\n", p);
- return;
- }
- printf("map_lookup: %s (%s) ", p, q);
- av[0] = q;
- av[1] = NULL;
- p = (*map->s_map.map_class->map_lookup)
- (&map->s_map, q, av, &rcode);
- if (p == NULL)
- printf("no match (%d)\n", rcode);
- else
- printf("returns %s (%d)\n", p, rcode);
- }
- else if (strcasecmp(&line[1], "try") == 0)
- {
- MAILER *m;
- STAB *s;
- auto int rcode = EX_OK;
-
- q = strpbrk(p, " \t");
- if (q != NULL)
- {
- while (isascii(*q) && isspace(*q))
- *q++ = '\0';
- }
- if (q == NULL || *q == '\0')
- {
- printf("Usage: /try mailer address\n");
- return;
- }
- s = stab(p, ST_MAILER, ST_FIND);
- if (s == NULL)
- {
- printf("Unknown mailer %s\n", p);
- return;
- }
- m = s->s_mailer;
- printf("Trying %s %s address %s for mailer %s\n",
- bitset(RF_HEADERADDR, tryflags) ? "header" : "envelope",
- bitset(RF_SENDERADDR, tryflags) ? "sender" : "recipient",
- q, p);
- p = remotename(q, m, tryflags, &rcode, CurEnv);
- printf("Rcode = %d, addr = %s\n",
- rcode, p == NULL ? "<NULL>" : p);
- e->e_to = NULL;
- }
- else if (strcasecmp(&line[1], "tryflags") == 0)
- {
- if (*p == '\0')
- {
- printf("Usage: /tryflags [Hh|Ee][Ss|Rr]\n");
- return;
- }
- for (; *p != '\0'; p++)
- {
- switch (*p)
- {
- case 'H':
- case 'h':
- tryflags |= RF_HEADERADDR;
- break;
-
- case 'E':
- case 'e':
- tryflags &= ~RF_HEADERADDR;
- break;
-
- case 'S':
- case 's':
- tryflags |= RF_SENDERADDR;
- break;
-
- case 'R':
- case 'r':
- tryflags &= ~RF_SENDERADDR;
- break;
- }
- }
- }
- else if (strcasecmp(&line[1], "parse") == 0)
- {
- if (*p == '\0')
- {
- printf("Usage: /parse address\n");
- return;
- }
- q = crackaddr(p);
- printf("Cracked address = ");
- xputs(q);
- printf("\nParsing %s %s address\n",
- bitset(RF_HEADERADDR, tryflags) ? "header" : "envelope",
- bitset(RF_SENDERADDR, tryflags) ? "sender" : "recipient");
- if (parseaddr(p, &a, tryflags, '\0', NULL, e) == NULL)
- printf("Cannot parse\n");
- else if (a.q_host != NULL && a.q_host[0] != '\0')
- printf("mailer %s, host %s, user %s\n",
- a.q_mailer->m_name, a.q_host, a.q_user);
- else
- printf("mailer %s, user %s\n",
- a.q_mailer->m_name, a.q_user);
- e->e_to = NULL;
- }
- else
- {
- printf("Unknown \"/\" command %s\n", line);
- }
- return;
- }
-
- for (p = line; isascii(*p) && isspace(*p); p++)
- continue;
- q = p;
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
- p++;
- if (*p == '\0')
- {
- printf("No address!\n");
- return;
- }
- *p = '\0';
- if (invalidaddr(p + 1, NULL))
- return;
- do
- {
- register char **pvp;
- char pvpbuf[PSBUFSIZE];
-
- pvp = prescan(++p, ',', pvpbuf, sizeof pvpbuf,
- &delimptr, NULL);
- if (pvp == NULL)
- continue;
- p = q;
- while (*p != '\0')
- {
- int stat;
-
- rs = strtorwset(p, NULL, ST_FIND);
- if (rs < 0)
- {
- printf("Undefined ruleset %s\n", p);
- break;
- }
- stat = rewrite(pvp, rs, 0, e);
- if (stat != EX_OK)
- printf("== Ruleset %s (%d) status %d\n",
- p, rs, stat);
- while (*p != '\0' && *p++ != ',')
- continue;
- }
- } while (*(p = delimptr) != '\0');
-}
-
-
-void
-dump_class(s, id)
- register STAB *s;
- int id;
-{
- if (s->s_type != ST_CLASS)
- return;
- if (bitnset(id & 0xff, s->s_class))
- printf("%s\n", s->s_name);
-}
diff --git a/src/makesendmail b/src/makesendmail
deleted file mode 120000
index 6308dba..0000000
--- a/src/makesendmail
+++ /dev/null
@@ -1 +0,0 @@
-../BuildTools/bin/Build \ No newline at end of file
diff --git a/src/map.c b/src/map.c
deleted file mode 100644
index 8fc3387..0000000
--- a/src/map.c
+++ /dev/null
@@ -1,5209 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1992, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)map.c 8.261 (Berkeley) 2/2/1999";
-#endif /* not lint */
-
-#include "sendmail.h"
-
-#ifdef NDBM
-# include <ndbm.h>
-# ifdef R_FIRST
- ERROR README: You are running the Berkeley DB version of ndbm.h. See
- ERROR README: the README file about tweaking Berkeley DB so it can
- ERROR README: coexist with NDBM, or delete -DNDBM from the Makefile
- ERROR README: and use -DNEWDB instead.
-# endif
-#endif
-#ifdef NEWDB
-# include <db.h>
-# ifndef DB_VERSION_MAJOR
-# define DB_VERSION_MAJOR 1
-# endif
-#endif
-#ifdef NIS
- struct dom_binding; /* forward reference needed on IRIX */
-# include <rpcsvc/ypclnt.h>
-# ifdef NDBM
-# define NDBM_YP_COMPAT /* create YP-compatible NDBM files */
-# endif
-#endif
-
-/*
-** MAP.C -- implementations for various map classes.
-**
-** Each map class implements a series of functions:
-**
-** bool map_parse(MAP *map, char *args)
-** Parse the arguments from the config file. Return TRUE
-** if they were ok, FALSE otherwise. Fill in map with the
-** values.
-**
-** char *map_lookup(MAP *map, char *key, char **args, int *pstat)
-** Look up the key in the given map. If found, do any
-** rewriting the map wants (including "args" if desired)
-** and return the value. Set *pstat to the appropriate status
-** on error and return NULL. Args will be NULL if called
-** from the alias routines, although this should probably
-** not be relied upon. It is suggested you call map_rewrite
-** to return the results -- it takes care of null termination
-** and uses a dynamically expanded buffer as needed.
-**
-** void map_store(MAP *map, char *key, char *value)
-** Store the key:value pair in the map.
-**
-** bool map_open(MAP *map, int mode)
-** Open the map for the indicated mode. Mode should
-** be either O_RDONLY or O_RDWR. Return TRUE if it
-** was opened successfully, FALSE otherwise. If the open
-** failed an the MF_OPTIONAL flag is not set, it should
-** also print an error. If the MF_ALIAS bit is set
-** and this map class understands the @:@ convention, it
-** should call aliaswait() before returning.
-**
-** void map_close(MAP *map)
-** Close the map.
-**
-** This file also includes the implementation for getcanonname.
-** It is currently implemented in a pretty ad-hoc manner; it ought
-** to be more properly integrated into the map structure.
-*/
-
-#define DBMMODE 0644
-
-#ifndef EX_NOTFOUND
-# define EX_NOTFOUND EX_NOHOST
-#endif
-
-extern bool aliaswait __P((MAP *, char *, int));
-extern bool extract_canonname __P((char *, char *, char[], int));
-
-#if O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL
-# define LOCK_ON_OPEN 1 /* we can open/create a locked file */
-#else
-# define LOCK_ON_OPEN 0 /* no such luck -- bend over backwards */
-#endif
-
-#ifndef O_ACCMODE
-# define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR)
-#endif
- /*
-** MAP_PARSEARGS -- parse config line arguments for database lookup
-**
-** This is a generic version of the map_parse method.
-**
-** Parameters:
-** map -- the map being initialized.
-** ap -- a pointer to the args on the config line.
-**
-** Returns:
-** TRUE -- if everything parsed OK.
-** FALSE -- otherwise.
-**
-** Side Effects:
-** null terminates the filename; stores it in map
-*/
-
-bool
-map_parseargs(map, ap)
- MAP *map;
- char *ap;
-{
- register char *p = ap;
-
- map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL;
- for (;;)
- {
- while (isascii(*p) && isspace(*p))
- p++;
- if (*p != '-')
- break;
- switch (*++p)
- {
- case 'N':
- map->map_mflags |= MF_INCLNULL;
- map->map_mflags &= ~MF_TRY0NULL;
- break;
-
- case 'O':
- map->map_mflags &= ~MF_TRY1NULL;
- break;
-
- case 'o':
- map->map_mflags |= MF_OPTIONAL;
- break;
-
- case 'f':
- map->map_mflags |= MF_NOFOLDCASE;
- break;
-
- case 'm':
- map->map_mflags |= MF_MATCHONLY;
- break;
-
- case 'A':
- map->map_mflags |= MF_APPEND;
- break;
-
- case 'q':
- map->map_mflags |= MF_KEEPQUOTES;
- break;
-
- case 'a':
- map->map_app = ++p;
- break;
-
- case 'T':
- map->map_tapp = ++p;
- break;
-
- case 'k':
- while (isascii(*++p) && isspace(*p))
- continue;
- map->map_keycolnm = p;
- break;
-
- case 'v':
- while (isascii(*++p) && isspace(*p))
- continue;
- map->map_valcolnm = p;
- break;
-
- case 'z':
- if (*++p != '\\')
- map->map_coldelim = *p;
- else
- {
- switch (*++p)
- {
- case 'n':
- map->map_coldelim = '\n';
- break;
-
- case 't':
- map->map_coldelim = '\t';
- break;
-
- default:
- map->map_coldelim = '\\';
- }
- }
- break;
-
- case 't':
- map->map_mflags |= MF_NODEFER;
- break;
-
-#ifdef RESERVED_FOR_SUN
- case 'd':
- map->map_mflags |= MF_DOMAIN_WIDE;
- break;
-
- case 's':
- /* info type */
- break;
-#endif
- }
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
- p++;
- if (*p != '\0')
- *p++ = '\0';
- }
- if (map->map_app != NULL)
- map->map_app = newstr(map->map_app);
- if (map->map_tapp != NULL)
- map->map_tapp = newstr(map->map_tapp);
- if (map->map_keycolnm != NULL)
- map->map_keycolnm = newstr(map->map_keycolnm);
- if (map->map_valcolnm != NULL)
- map->map_valcolnm = newstr(map->map_valcolnm);
-
- if (*p != '\0')
- {
- map->map_file = p;
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
- p++;
- if (*p != '\0')
- *p++ = '\0';
- map->map_file = newstr(map->map_file);
- }
-
- while (*p != '\0' && isascii(*p) && isspace(*p))
- p++;
- if (*p != '\0')
- map->map_rebuild = newstr(p);
-
- if (map->map_file == NULL &&
- !bitset(MCF_OPTFILE, map->map_class->map_cflags))
- {
- syserr("No file name for %s map %s",
- map->map_class->map_cname, map->map_mname);
- return FALSE;
- }
- return TRUE;
-}
- /*
-** MAP_REWRITE -- rewrite a database key, interpolating %n indications.
-**
-** It also adds the map_app string. It can be used as a utility
-** in the map_lookup method.
-**
-** Parameters:
-** map -- the map that causes this.
-** s -- the string to rewrite, NOT necessarily null terminated.
-** slen -- the length of s.
-** av -- arguments to interpolate into buf.
-**
-** Returns:
-** Pointer to rewritten result. This is static data that
-** should be copied if it is to be saved!
-**
-** Side Effects:
-** none.
-*/
-
-char *
-map_rewrite(map, s, slen, av)
- register MAP *map;
- register const char *s;
- size_t slen;
- char **av;
-{
- register char *bp;
- register char c;
- char **avp;
- register char *ap;
- size_t l;
- size_t len;
- static size_t buflen = 0;
- static char *buf = NULL;
-
- if (tTd(39, 1))
- {
- printf("map_rewrite(%.*s), av =", (int)slen, s);
- if (av == NULL)
- printf(" (nullv)");
- else
- {
- for (avp = av; *avp != NULL; avp++)
- printf("\n\t%s", *avp);
- }
- printf("\n");
- }
-
- /* count expected size of output (can safely overestimate) */
- l = len = slen;
- if (av != NULL)
- {
- const char *sp = s;
-
- while (l-- > 0 && (c = *sp++) != '\0')
- {
- if (c != '%')
- continue;
- if (l-- <= 0)
- break;
- c = *sp++;
- if (!(isascii(c) && isdigit(c)))
- continue;
- for (avp = av; --c >= '0' && *avp != NULL; avp++)
- continue;
- if (*avp == NULL)
- continue;
- len += strlen(*avp);
- }
- }
- if (map->map_app != NULL)
- len += strlen(map->map_app);
- if (buflen < ++len)
- {
- /* need to malloc additional space */
- buflen = len;
- if (buf != NULL)
- free(buf);
- buf = xalloc(buflen);
- }
-
- bp = buf;
- if (av == NULL)
- {
- bcopy(s, bp, slen);
- bp += slen;
- }
- else
- {
- while (slen-- > 0 && (c = *s++) != '\0')
- {
- if (c != '%')
- {
- pushc:
- *bp++ = c;
- continue;
- }
- if (slen-- <= 0 || (c = *s++) == '\0')
- c = '%';
- if (c == '%')
- goto pushc;
- if (!(isascii(c) && isdigit(c)))
- {
- *bp++ = '%';
- goto pushc;
- }
- for (avp = av; --c >= '0' && *avp != NULL; avp++)
- continue;
- if (*avp == NULL)
- continue;
-
- /* transliterate argument into output string */
- for (ap = *avp; (c = *ap++) != '\0'; )
- *bp++ = c;
- }
- }
- if (map->map_app != NULL)
- strcpy(bp, map->map_app);
- else
- *bp = '\0';
- if (tTd(39, 1))
- printf("map_rewrite => %s\n", buf);
- return buf;
-}
- /*
-** INITMAPS -- initialize for aliasing
-**
-** Parameters:
-** rebuild -- if TRUE, this rebuilds the cached versions.
-** e -- current envelope.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** initializes aliases:
-** if alias database: opens the database.
-** if no database available: reads aliases into the symbol table.
-*/
-
-void
-initmaps(rebuild, e)
- bool rebuild;
- register ENVELOPE *e;
-{
- extern void map_init __P((STAB *, int));
-
-#if XDEBUG
- checkfd012("entering initmaps");
-#endif
- CurEnv = e;
-
- stabapply(map_init, 0);
- stabapply(map_init, rebuild ? 2 : 1);
-#if XDEBUG
- checkfd012("exiting initmaps");
-#endif
-}
-
-void
-map_init(s, pass)
- register STAB *s;
- int pass;
-{
- bool rebuildable;
- register MAP *map;
-
- /* has to be a map */
- if (s->s_type != ST_MAP)
- return;
-
- map = &s->s_map;
- if (!bitset(MF_VALID, map->map_mflags))
- return;
-
- if (tTd(38, 2))
- printf("map_init(%s:%s, %s, %d)\n",
- map->map_class->map_cname == NULL ? "NULL" :
- map->map_class->map_cname,
- map->map_mname == NULL ? "NULL" : map->map_mname,
- map->map_file == NULL ? "NULL" : map->map_file,
- pass);
-
- /*
- ** Pass 0 opens all non-rebuildable maps.
- ** Pass 1 opens all rebuildable maps for read.
- ** Pass 2 rebuilds all rebuildable maps.
- */
-
- rebuildable = (bitset(MF_ALIAS, map->map_mflags) &&
- bitset(MCF_REBUILDABLE, map->map_class->map_cflags));
-
- if ((pass == 0 && rebuildable) ||
- ((pass == 1 || pass == 2) && !rebuildable))
- {
- if (tTd(38, 3))
- printf("\twrong pass (pass = %d, rebuildable = %d)\n",
- pass, rebuildable);
- return;
- }
-
- /* if already open, close it (for nested open) */
- if (bitset(MF_OPEN, map->map_mflags))
- {
- map->map_class->map_close(map);
- map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
- }
-
- if (pass == 2)
- {
- (void) rebuildaliases(map, FALSE);
- return;
- }
-
- if (map->map_class->map_open(map, O_RDONLY))
- {
- if (tTd(38, 4))
- printf("\t%s:%s %s: valid\n",
- map->map_class->map_cname == NULL ? "NULL" :
- map->map_class->map_cname,
- map->map_mname == NULL ? "NULL" :
- map->map_mname,
- map->map_file == NULL ? "NULL" :
- map->map_file);
- map->map_mflags |= MF_OPEN;
- map->map_pid = getpid();
- }
- else
- {
- if (tTd(38, 4))
- printf("\t%s:%s %s: invalid: %s\n",
- map->map_class->map_cname == NULL ? "NULL" :
- map->map_class->map_cname,
- map->map_mname == NULL ? "NULL" :
- map->map_mname,
- map->map_file == NULL ? "NULL" :
- map->map_file,
- errstring(errno));
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- {
- extern MAPCLASS BogusMapClass;
-
- map->map_class = &BogusMapClass;
- map->map_mflags |= MF_OPEN;
- map->map_pid = getpid();
- }
- }
-}
- /*
-** CLOSEMAPS -- close all open maps opened by the current pid.
-**
-** Parameters:
-** none
-**
-** Returns:
-** none.
-*/
-
-void
-closemaps()
-{
- extern void map_close __P((STAB *, int));
-
- stabapply(map_close, 0);
-}
-
-/* ARGSUSED1 */
-void
-map_close(s, unused)
- register STAB *s;
- int unused;
-{
- MAP *map;
-
- if (s->s_type != ST_MAP)
- return;
-
- map = &s->s_map;
-
- if (!bitset(MF_VALID, map->map_mflags) ||
- !bitset(MF_OPEN, map->map_mflags) ||
- map->map_pid != getpid())
- return;
-
- if (tTd(38, 5))
- printf("closemaps: closing %s (%s)\n",
- map->map_mname == NULL ? "NULL" : map->map_mname,
- map->map_file == NULL ? "NULL" : map->map_file);
-
- map->map_class->map_close(map);
- map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
-}
- /*
-** GETCANONNAME -- look up name using service switch
-**
-** Parameters:
-** host -- the host name to look up.
-** hbsize -- the size of the host buffer.
-** trymx -- if set, try MX records.
-**
-** Returns:
-** TRUE -- if the host was found.
-** FALSE -- otherwise.
-*/
-
-bool
-getcanonname(host, hbsize, trymx)
- char *host;
- int hbsize;
- bool trymx;
-{
- int nmaps;
- int mapno;
- bool found = FALSE;
- bool got_tempfail = FALSE;
- auto int stat;
- char *maptype[MAXMAPSTACK];
- short mapreturn[MAXMAPACTIONS];
-
- nmaps = switch_map_find("hosts", maptype, mapreturn);
- for (mapno = 0; mapno < nmaps; mapno++)
- {
- int i;
-
- if (tTd(38, 20))
- printf("getcanonname(%s), trying %s\n",
- host, maptype[mapno]);
- if (strcmp("files", maptype[mapno]) == 0)
- {
- extern bool text_getcanonname __P((char *, int, int *));
-
- found = text_getcanonname(host, hbsize, &stat);
- }
-#ifdef NIS
- else if (strcmp("nis", maptype[mapno]) == 0)
- {
- extern bool nis_getcanonname __P((char *, int, int *));
-
- found = nis_getcanonname(host, hbsize, &stat);
- }
-#endif
-#ifdef NISPLUS
- else if (strcmp("nisplus", maptype[mapno]) == 0)
- {
- extern bool nisplus_getcanonname __P((char *, int, int *));
-
- found = nisplus_getcanonname(host, hbsize, &stat);
- }
-#endif
-#if NAMED_BIND
- else if (strcmp("dns", maptype[mapno]) == 0)
- {
- extern bool dns_getcanonname __P((char *, int, bool, int *));
-
- found = dns_getcanonname(host, hbsize, trymx, &stat);
- }
-#endif
-#if NETINFO
- else if (strcmp("netinfo", maptype[mapno]) == 0)
- {
- extern bool ni_getcanonname __P((char *, int, int *));
-
- found = ni_getcanonname(host, hbsize, &stat);
- }
-#endif
- else
- {
- found = FALSE;
- stat = EX_UNAVAILABLE;
- }
-
- /*
- ** Heuristic: if $m is not set, we are running during system
- ** startup. In this case, when a name is apparently found
- ** but has no dot, treat is as not found. This avoids
- ** problems if /etc/hosts has no FQDN but is listed first
- ** in the service switch.
- */
-
- if (found &&
- (macvalue('m', CurEnv) != NULL || strchr(host, '.') != NULL))
- break;
-
- /* see if we should continue */
- if (stat == EX_TEMPFAIL)
- {
- i = MA_TRYAGAIN;
- got_tempfail = TRUE;
- }
- else if (stat == EX_NOTFOUND)
- i = MA_NOTFOUND;
- else
- i = MA_UNAVAIL;
- if (bitset(1 << mapno, mapreturn[i]))
- break;
- }
-
- if (found)
- {
- char *d;
-
- if (tTd(38, 20))
- printf("getcanonname(%s), found\n", host);
-
- /*
- ** If returned name is still single token, compensate
- ** by tagging on $m. This is because some sites set
- ** up their DNS or NIS databases wrong.
- */
-
- if ((d = strchr(host, '.')) == NULL || d[1] == '\0')
- {
- d = macvalue('m', CurEnv);
- if (d != NULL &&
- hbsize > (int) (strlen(host) + strlen(d) + 1))
- {
- if (host[strlen(host) - 1] != '.')
- strcat(host, ".");
- strcat(host, d);
- }
- else
- {
- return FALSE;
- }
- }
- return TRUE;
- }
-
- if (tTd(38, 20))
- printf("getcanonname(%s), failed, stat=%d\n", host, stat);
-
-#if NAMED_BIND
- if (got_tempfail)
- h_errno = TRY_AGAIN;
- else
- h_errno = HOST_NOT_FOUND;
-#endif
-
- return FALSE;
-}
- /*
-** EXTRACT_CANONNAME -- extract canonical name from /etc/hosts entry
-**
-** Parameters:
-** name -- the name against which to match.
-** line -- the /etc/hosts line.
-** cbuf -- the location to store the result.
-** cbuflen -- the size of cbuf.
-**
-** Returns:
-** TRUE -- if the line matched the desired name.
-** FALSE -- otherwise.
-*/
-
-bool
-extract_canonname(name, line, cbuf, cbuflen)
- char *name;
- char *line;
- char cbuf[];
- int cbuflen;
-{
- int i;
- char *p;
- bool found = FALSE;
- extern char *get_column __P((char *, int, char, char *, int));
-
- cbuf[0] = '\0';
- if (line[0] == '#')
- return FALSE;
-
- for (i = 1; ; i++)
- {
- char nbuf[MAXNAME + 1];
-
- p = get_column(line, i, '\0', nbuf, sizeof nbuf);
- if (p == NULL)
- break;
- if (*p == '\0')
- continue;
- if (cbuf[0] == '\0' ||
- (strchr(cbuf, '.') == NULL && strchr(p, '.') != NULL))
- {
- snprintf(cbuf, cbuflen, "%s", p);
- }
- if (strcasecmp(name, p) == 0)
- found = TRUE;
- }
- if (found && strchr(cbuf, '.') == NULL)
- {
- /* try to add a domain on the end of the name */
- char *domain = macvalue('m', CurEnv);
-
- if (domain != NULL &&
- strlen(domain) + strlen(cbuf) + 1 < cbuflen)
- {
- p = &cbuf[strlen(cbuf)];
- *p++ = '.';
- strcpy(p, domain);
- }
- }
- return found;
-}
- /*
-** NDBM modules
-*/
-
-#ifdef NDBM
-
-/*
-** NDBM_MAP_OPEN -- DBM-style map open
-*/
-
-bool
-ndbm_map_open(map, mode)
- MAP *map;
- int mode;
-{
- register DBM *dbm;
- struct stat st;
- int dfd;
- int pfd;
- int sff;
- int ret;
- int smode = S_IREAD;
- char dirfile[MAXNAME + 1];
- char pagfile[MAXNAME + 1];
- struct stat std, stp;
-
- if (tTd(38, 2))
- printf("ndbm_map_open(%s, %s, %d)\n",
- map->map_mname, map->map_file, mode);
- map->map_lockfd = -1;
- mode &= O_ACCMODE;
-
- /* do initial file and directory checks */
- snprintf(dirfile, sizeof dirfile, "%s.dir", map->map_file);
- snprintf(pagfile, sizeof pagfile, "%s.pag", map->map_file);
- sff = SFF_ROOTOK|SFF_REGONLY;
- if (mode == O_RDWR)
- {
- sff |= SFF_CREAT;
- if (!bitset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
- sff |= SFF_NOSLINK;
- if (!bitset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
- sff |= SFF_NOHLINK;
- smode = S_IWRITE;
- }
- else
- {
- if (!bitset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
- sff |= SFF_NOWLINK;
- }
- if (!bitset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
- sff |= SFF_SAFEDIRPATH;
- ret = safefile(dirfile, RunAsUid, RunAsGid, RunAsUserName,
- sff, smode, &std);
- if (ret == 0)
- ret = safefile(pagfile, RunAsUid, RunAsGid, RunAsUserName,
- sff, smode, &stp);
- if (ret == ENOENT && AutoRebuild &&
- bitset(MCF_REBUILDABLE, map->map_class->map_cflags) &&
- (bitset(MF_IMPL_NDBM, map->map_mflags) ||
- bitset(MF_ALIAS, map->map_mflags)) &&
- mode == O_RDONLY)
- {
- bool impl = bitset(MF_IMPL_NDBM, map->map_mflags);
- extern bool impl_map_open __P((MAP *, int));
-
- /* may be able to rebuild */
- map->map_mflags &= ~MF_IMPL_NDBM;
- if (!rebuildaliases(map, TRUE))
- return FALSE;
- if (impl)
- return impl_map_open(map, O_RDONLY);
- else
- return ndbm_map_open(map, O_RDONLY);
- }
- if (ret != 0)
- {
- char *prob = "unsafe";
-
- /* cannot open this map */
- if (ret == ENOENT)
- prob = "missing";
- if (tTd(38, 2))
- printf("\t%s map file: %d\n", prob, ret);
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("dbm map \"%s\": %s map file %s",
- map->map_mname, prob, map->map_file);
- return FALSE;
- }
- if (std.st_mode == ST_MODE_NOFILE)
- mode |= O_CREAT|O_EXCL;
-
-#if LOCK_ON_OPEN
- if (mode == O_RDONLY)
- mode |= O_SHLOCK;
- else
- mode |= O_TRUNC|O_EXLOCK;
-#else
- if ((mode & O_ACCMODE) == O_RDWR)
- {
-# if NOFTRUNCATE
- /*
- ** Warning: race condition. Try to lock the file as
- ** quickly as possible after opening it.
- ** This may also have security problems on some systems,
- ** but there isn't anything we can do about it.
- */
-
- mode |= O_TRUNC;
-# else
- /*
- ** This ugly code opens the map without truncating it,
- ** locks the file, then truncates it. Necessary to
- ** avoid race conditions.
- */
-
- int dirfd;
- int pagfd;
- int sff = SFF_CREAT|SFF_OPENASROOT;
-
- if (!bitset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
- sff |= SFF_NOSLINK;
- if (!bitset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
- sff |= SFF_NOHLINK;
-
- dirfd = safeopen(dirfile, mode, DBMMODE, sff);
- pagfd = safeopen(pagfile, mode, DBMMODE, sff);
-
- if (dirfd < 0 || pagfd < 0)
- {
- int save_errno = errno;
-
- if (dirfd >= 0)
- (void) close(dirfd);
- if (pagfd >= 0)
- (void) close(pagfd);
- errno = save_errno;
- syserr("ndbm_map_open: cannot create database %s",
- map->map_file);
- return FALSE;
- }
- if (ftruncate(dirfd, (off_t) 0) < 0 ||
- ftruncate(pagfd, (off_t) 0) < 0)
- {
- int save_errno = errno;
-
- (void) close(dirfd);
- (void) close(pagfd);
- errno = save_errno;
- syserr("ndbm_map_open: cannot truncate %s.{dir,pag}",
- map->map_file);
- return FALSE;
- }
-
- /* if new file, get "before" bits for later filechanged check */
- if (std.st_mode == ST_MODE_NOFILE &&
- (fstat(dirfd, &std) < 0 || fstat(pagfd, &stp) < 0))
- {
- int save_errno = errno;
-
- (void) close(dirfd);
- (void) close(pagfd);
- errno = save_errno;
- syserr("ndbm_map_open(%s.{dir,pag}): cannot fstat pre-opened file",
- map->map_file);
- return FALSE;
- }
-
- /* have to save the lock for the duration (bletch) */
- map->map_lockfd = dirfd;
- close(pagfd);
-
- /* twiddle bits for dbm_open */
- mode &= ~(O_CREAT|O_EXCL);
-# endif
- }
-#endif
-
- /* open the database */
- dbm = dbm_open(map->map_file, mode, DBMMODE);
- if (dbm == NULL)
- {
- int save_errno = errno;
-
- if (bitset(MF_ALIAS, map->map_mflags) &&
- aliaswait(map, ".pag", FALSE))
- return TRUE;
-#if !LOCK_ON_OPEN && !NOFTRUNCATE
- if (map->map_lockfd >= 0)
- close(map->map_lockfd);
-#endif
- errno = save_errno;
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("Cannot open DBM database %s", map->map_file);
- return FALSE;
- }
- dfd = dbm_dirfno(dbm);
- pfd = dbm_pagfno(dbm);
- if (dfd == pfd)
- {
- /* heuristic: if files are linked, this is actually gdbm */
- dbm_close(dbm);
-#if !LOCK_ON_OPEN && !NOFTRUNCATE
- if (map->map_lockfd >= 0)
- close(map->map_lockfd);
-#endif
- errno = 0;
- syserr("dbm map \"%s\": cannot support GDBM",
- map->map_mname);
- return FALSE;
- }
-
- if (filechanged(dirfile, dfd, &std) ||
- filechanged(pagfile, pfd, &stp))
- {
- int save_errno = errno;
-
- dbm_close(dbm);
-#if !LOCK_ON_OPEN && !NOFTRUNCATE
- if (map->map_lockfd >= 0)
- close(map->map_lockfd);
-#endif
- errno = save_errno;
- syserr("ndbm_map_open(%s): file changed after open",
- map->map_file);
- return FALSE;
- }
-
- map->map_db1 = (ARBPTR_T) dbm;
- if (mode == O_RDONLY)
- {
-#if LOCK_ON_OPEN
- if (dfd >= 0)
- (void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
- if (pfd >= 0)
- (void) lockfile(pfd, map->map_file, ".pag", LOCK_UN);
-#endif
- if (bitset(MF_ALIAS, map->map_mflags) &&
- !aliaswait(map, ".pag", TRUE))
- return FALSE;
- }
- else
- {
- map->map_mflags |= MF_LOCKED;
-#if _FFR_TRUSTED_USER
- if (geteuid() == 0 && TrustedUid != 0)
- {
- if (fchown(dfd, TrustedUid, -1) < 0 ||
- fchown(pfd, TrustedUid, -1) < 0)
- {
- int err = errno;
-
- sm_syslog(LOG_ALERT, NOQID,
- "ownership change on %s failed: %s",
- map->map_file, errstring(err));
- message("050 ownership change on %s failed: %s",
- map->map_file, errstring(err));
- }
- }
-#endif
- }
- if (fstat(dfd, &st) >= 0)
- map->map_mtime = st.st_mtime;
- return TRUE;
-}
-
-
-/*
-** NDBM_MAP_LOOKUP -- look up a datum in a DBM-type map
-*/
-
-char *
-ndbm_map_lookup(map, name, av, statp)
- MAP *map;
- char *name;
- char **av;
- int *statp;
-{
- datum key, val;
- int fd;
- char keybuf[MAXNAME + 1];
- struct stat stbuf;
-
- if (tTd(38, 20))
- printf("ndbm_map_lookup(%s, %s)\n",
- map->map_mname, name);
-
- key.dptr = name;
- key.dsize = strlen(name);
- if (!bitset(MF_NOFOLDCASE, map->map_mflags))
- {
- if (key.dsize > sizeof keybuf - 1)
- key.dsize = sizeof keybuf - 1;
- bcopy(key.dptr, keybuf, key.dsize);
- keybuf[key.dsize] = '\0';
- makelower(keybuf);
- key.dptr = keybuf;
- }
-lockdbm:
- fd = dbm_dirfno((DBM *) map->map_db1);
- if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
- (void) lockfile(fd, map->map_file, ".dir", LOCK_SH);
- if (fd < 0 || fstat(fd, &stbuf) < 0 || stbuf.st_mtime > map->map_mtime)
- {
- /* Reopen the database to sync the cache */
- int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR
- : O_RDONLY;
-
- map->map_class->map_close(map);
- map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
- if (map->map_class->map_open(map, omode))
- {
- map->map_mflags |= MF_OPEN;
- map->map_pid = getpid();
- if ((omode && O_ACCMODE) == O_RDWR)
- map->map_mflags |= MF_WRITABLE;
- goto lockdbm;
- }
- else
- {
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- {
- extern MAPCLASS BogusMapClass;
-
- *statp = EX_TEMPFAIL;
- map->map_class = &BogusMapClass;
- map->map_mflags |= MF_OPEN;
- map->map_pid = getpid();
- syserr("Cannot reopen NDBM database %s",
- map->map_file);
- }
- return NULL;
- }
- }
- val.dptr = NULL;
- if (bitset(MF_TRY0NULL, map->map_mflags))
- {
- val = dbm_fetch((DBM *) map->map_db1, key);
- if (val.dptr != NULL)
- map->map_mflags &= ~MF_TRY1NULL;
- }
- if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags))
- {
- key.dsize++;
- val = dbm_fetch((DBM *) map->map_db1, key);
- if (val.dptr != NULL)
- map->map_mflags &= ~MF_TRY0NULL;
- }
- if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
- (void) lockfile(fd, map->map_file, ".dir", LOCK_UN);
- if (val.dptr == NULL)
- return NULL;
- if (bitset(MF_MATCHONLY, map->map_mflags))
- return map_rewrite(map, name, strlen(name), NULL);
- else
- return map_rewrite(map, val.dptr, val.dsize, av);
-}
-
-
-/*
-** NDBM_MAP_STORE -- store a datum in the database
-*/
-
-void
-ndbm_map_store(map, lhs, rhs)
- register MAP *map;
- char *lhs;
- char *rhs;
-{
- datum key;
- datum data;
- int stat;
- char keybuf[MAXNAME + 1];
-
- if (tTd(38, 12))
- printf("ndbm_map_store(%s, %s, %s)\n",
- map->map_mname, lhs, rhs);
-
- key.dsize = strlen(lhs);
- key.dptr = lhs;
- if (!bitset(MF_NOFOLDCASE, map->map_mflags))
- {
- if (key.dsize > sizeof keybuf - 1)
- key.dsize = sizeof keybuf - 1;
- bcopy(key.dptr, keybuf, key.dsize);
- keybuf[key.dsize] = '\0';
- makelower(keybuf);
- key.dptr = keybuf;
- }
-
- data.dsize = strlen(rhs);
- data.dptr = rhs;
-
- if (bitset(MF_INCLNULL, map->map_mflags))
- {
- key.dsize++;
- data.dsize++;
- }
-
- stat = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT);
- if (stat > 0)
- {
- if (!bitset(MF_APPEND, map->map_mflags))
- message("050 Warning: duplicate alias name %s", lhs);
- else
- {
- static char *buf = NULL;
- static int bufsiz = 0;
- auto int xstat;
- datum old;
-
- old.dptr = ndbm_map_lookup(map, key.dptr,
- (char **)NULL, &xstat);
- if (old.dptr != NULL && *(char *) old.dptr != '\0')
- {
- old.dsize = strlen(old.dptr);
- if (data.dsize + old.dsize + 2 > bufsiz)
- {
- if (buf != NULL)
- (void) free(buf);
- bufsiz = data.dsize + old.dsize + 2;
- buf = xalloc(bufsiz);
- }
- snprintf(buf, bufsiz, "%s,%s",
- data.dptr, old.dptr);
- data.dsize = data.dsize + old.dsize + 1;
- data.dptr = buf;
- if (tTd(38, 9))
- printf("ndbm_map_store append=%s\n", data.dptr);
- }
- }
- stat = dbm_store((DBM *) map->map_db1, key, data, DBM_REPLACE);
- }
- if (stat != 0)
- syserr("readaliases: dbm put (%s)", lhs);
-}
-
-
-/*
-** NDBM_MAP_CLOSE -- close the database
-*/
-
-void
-ndbm_map_close(map)
- register MAP *map;
-{
- if (tTd(38, 9))
- printf("ndbm_map_close(%s, %s, %lx)\n",
- map->map_mname, map->map_file, map->map_mflags);
-
- if (bitset(MF_WRITABLE, map->map_mflags))
- {
-#ifdef NDBM_YP_COMPAT
- bool inclnull;
- char buf[MAXHOSTNAMELEN];
-
- inclnull = bitset(MF_INCLNULL, map->map_mflags);
- map->map_mflags &= ~MF_INCLNULL;
-
- if (strstr(map->map_file, "/yp/") != NULL)
- {
- long save_mflags = map->map_mflags;
-
- map->map_mflags |= MF_NOFOLDCASE;
-
- (void) snprintf(buf, sizeof buf, "%010ld", curtime());
- ndbm_map_store(map, "YP_LAST_MODIFIED", buf);
-
- (void) gethostname(buf, sizeof buf);
- ndbm_map_store(map, "YP_MASTER_NAME", buf);
-
- map->map_mflags = save_mflags;
- }
-
- if (inclnull)
- map->map_mflags |= MF_INCLNULL;
-#endif
-
- /* write out the distinguished alias */
- ndbm_map_store(map, "@", "@");
- }
- dbm_close((DBM *) map->map_db1);
-
- /* release lock (if needed) */
-#if !LOCK_ON_OPEN
- if (map->map_lockfd >= 0)
- (void) close(map->map_lockfd);
-#endif
-}
-
-#endif
- /*
-** NEWDB (Hash and BTree) Modules
-*/
-
-#ifdef NEWDB
-
-/*
-** BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.
-**
-** These do rather bizarre locking. If you can lock on open,
-** do that to avoid the condition of opening a database that
-** is being rebuilt. If you don't, we'll try to fake it, but
-** there will be a race condition. If opening for read-only,
-** we immediately release the lock to avoid freezing things up.
-** We really ought to hold the lock, but guarantee that we won't
-** be pokey about it. That's hard to do.
-*/
-
-#if DB_VERSION_MAJOR < 2
-extern bool db_map_open __P((MAP *, int, char *, DBTYPE, const void *));
-#else
-extern bool db_map_open __P((MAP *, int, char *, DBTYPE, DB_INFO *));
-#endif
-
-/* these should be K line arguments */
-#if DB_VERSION_MAJOR < 2
-# define db_cachesize cachesize
-# define h_nelem nelem
-# ifndef DB_CACHE_SIZE
-# define DB_CACHE_SIZE (1024 * 1024) /* database memory cache size */
-# endif
-# ifndef DB_HASH_NELEM
-# define DB_HASH_NELEM 4096 /* (starting) size of hash table */
-# endif
-#endif
-
-bool
-bt_map_open(map, mode)
- MAP *map;
- int mode;
-{
-#if DB_VERSION_MAJOR < 2
- BTREEINFO btinfo;
-#else
- DB_INFO btinfo;
-#endif
-
- if (tTd(38, 2))
- printf("bt_map_open(%s, %s, %d)\n",
- map->map_mname, map->map_file, mode);
-
- bzero(&btinfo, sizeof btinfo);
-#ifdef DB_CACHE_SIZE
- btinfo.db_cachesize = DB_CACHE_SIZE;
-#endif
- return db_map_open(map, mode, "btree", DB_BTREE, &btinfo);
-}
-
-bool
-hash_map_open(map, mode)
- MAP *map;
- int mode;
-{
-#if DB_VERSION_MAJOR < 2
- HASHINFO hinfo;
-#else
- DB_INFO hinfo;
-#endif
-
- if (tTd(38, 2))
- printf("hash_map_open(%s, %s, %d)\n",
- map->map_mname, map->map_file, mode);
-
- bzero(&hinfo, sizeof hinfo);
-#ifdef DB_HASH_NELEM
- hinfo.h_nelem = DB_HASH_NELEM;
-#endif
-#ifdef DB_CACHE_SIZE
- hinfo.db_cachesize = DB_CACHE_SIZE;
-#endif
- return db_map_open(map, mode, "hash", DB_HASH, &hinfo);
-}
-
-bool
-db_map_open(map, mode, mapclassname, dbtype, openinfo)
- MAP *map;
- int mode;
- char *mapclassname;
- DBTYPE dbtype;
-#if DB_VERSION_MAJOR < 2
- const void *openinfo;
-#else
- DB_INFO *openinfo;
-#endif
-{
- DB *db = NULL;
- int i;
- int omode;
- int smode = S_IREAD;
- int fd;
- int sff;
- int saveerrno;
- struct stat st;
- char buf[MAXNAME + 1];
-
- /* do initial file and directory checks */
- snprintf(buf, sizeof buf - 3, "%s", map->map_file);
- i = strlen(buf);
- if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
- (void) strcat(buf, ".db");
-
- mode &= O_ACCMODE;
- omode = mode;
-
- sff = SFF_ROOTOK|SFF_REGONLY;
- if (mode == O_RDWR)
- {
- sff |= SFF_CREAT;
- if (!bitset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
- sff |= SFF_NOSLINK;
- if (!bitset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
- sff |= SFF_NOHLINK;
- smode = S_IWRITE;
- }
- else
- {
- if (!bitset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
- sff |= SFF_NOWLINK;
- }
- if (!bitset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
- sff |= SFF_SAFEDIRPATH;
- i = safefile(buf, RunAsUid, RunAsGid, RunAsUserName, sff, smode, &st);
- if (i == ENOENT && AutoRebuild &&
- bitset(MCF_REBUILDABLE, map->map_class->map_cflags) &&
- (bitset(MF_IMPL_HASH, map->map_mflags) ||
- bitset(MF_ALIAS, map->map_mflags)) &&
- mode == O_RDONLY)
- {
- bool impl = bitset(MF_IMPL_HASH, map->map_mflags);
- extern bool impl_map_open __P((MAP *, int));
-
- /* may be able to rebuild */
- map->map_mflags &= ~MF_IMPL_HASH;
- if (!rebuildaliases(map, TRUE))
- return FALSE;
- if (impl)
- return impl_map_open(map, O_RDONLY);
- else
- return db_map_open(map, O_RDONLY, mapclassname,
- dbtype, openinfo);
- }
-
- if (i != 0)
- {
- char *prob = "unsafe";
-
- /* cannot open this map */
- if (i == ENOENT)
- prob = "missing";
- if (tTd(38, 2))
- printf("\t%s map file: %s\n", prob, errstring(i));
- errno = i;
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("%s map \"%s\": %s map file %s",
- mapclassname, map->map_mname, prob, buf);
- return FALSE;
- }
- if (st.st_mode == ST_MODE_NOFILE)
- omode |= O_CREAT|O_EXCL;
-
- map->map_lockfd = -1;
-
-#if LOCK_ON_OPEN
- if (mode == O_RDWR)
- omode |= O_TRUNC|O_EXLOCK;
- else
- omode |= O_SHLOCK;
-#else
- /*
- ** Pre-lock the file to avoid race conditions. In particular,
- ** since dbopen returns NULL if the file is zero length, we
- ** must have a locked instance around the dbopen.
- */
-
- fd = open(buf, omode, DBMMODE);
- if (fd < 0)
- {
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("db_map_open: cannot pre-open database %s", buf);
- return FALSE;
- }
-
- /* make sure no baddies slipped in just before the open... */
- if (filechanged(buf, fd, &st))
- {
- int save_errno = errno;
-
- (void) close(fd);
- errno = save_errno;
- syserr("db_map_open(%s): file changed after pre-open", buf);
- return FALSE;
- }
-
- /* if new file, get the "before" bits for later filechanged check */
- if (st.st_mode == ST_MODE_NOFILE && fstat(fd, &st) < 0)
- {
- int save_errno = errno;
-
- (void) close(fd);
- errno = save_errno;
- syserr("db_map_open(%s): cannot fstat pre-opened file",
- buf);
- return FALSE;
- }
-
- /* actually lock the pre-opened file */
- if (!lockfile(fd, buf, NULL, mode == O_RDONLY ? LOCK_SH : LOCK_EX))
- syserr("db_map_open: cannot lock %s", buf);
-
- /* set up mode bits for dbopen */
- if (mode == O_RDWR)
- omode |= O_TRUNC;
- omode &= ~(O_EXCL|O_CREAT);
-#endif
-
-#if DB_VERSION_MAJOR < 2
- db = dbopen(buf, omode, DBMMODE, dbtype, openinfo);
-#else
- {
- int flags = 0;
-
- if (mode == O_RDONLY)
- flags |= DB_RDONLY;
- if (bitset(O_CREAT, omode))
- flags |= DB_CREATE;
- if (bitset(O_TRUNC, omode))
- flags |= DB_TRUNCATE;
-
- errno = db_open(buf, dbtype, flags, DBMMODE,
- NULL, openinfo, &db);
- }
-#endif
- saveerrno = errno;
-
-#if !LOCK_ON_OPEN
- if (mode == O_RDWR)
- map->map_lockfd = fd;
- else
- (void) close(fd);
-#endif
-
- if (db == NULL)
- {
- if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
- aliaswait(map, ".db", FALSE))
- return TRUE;
-#if !LOCK_ON_OPEN
- if (map->map_lockfd >= 0)
- (void) close(map->map_lockfd);
-#endif
- errno = saveerrno;
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("Cannot open %s database %s",
- mapclassname, buf);
- return FALSE;
- }
-
-#if DB_VERSION_MAJOR < 2
- fd = db->fd(db);
-#else
- fd = -1;
- errno = db->fd(db, &fd);
-#endif
- if (filechanged(buf, fd, &st))
- {
- int save_errno = errno;
-
-#if DB_VERSION_MAJOR < 2
- db->close(db);
-#else
- errno = db->close(db, 0);
-#endif
-#if !LOCK_ON_OPEN
- if (map->map_lockfd >= 0)
- close(map->map_lockfd);
-#endif
- errno = save_errno;
- syserr("db_map_open(%s): file changed after open", buf);
- return FALSE;
- }
-
- if (mode == O_RDWR)
- map->map_mflags |= MF_LOCKED;
-#if LOCK_ON_OPEN
- if (fd >= 0 && mode == O_RDONLY)
- {
- (void) lockfile(fd, buf, NULL, LOCK_UN);
- }
-#endif
-
- /* try to make sure that at least the database header is on disk */
- if (mode == O_RDWR)
- {
- (void) db->sync(db, 0);
-#if _FFR_TRUSTED_USER
- if (geteuid() == 0 && TrustedUid != 0)
- {
- if (fchown(fd, TrustedUid, -1) < 0)
- {
- int err = errno;
-
- sm_syslog(LOG_ALERT, NOQID,
- "ownership change on %s failed: %s",
- buf, errstring(err));
- message("050 ownership change on %s failed: %s",
- buf, errstring(err));
- }
- }
-#endif
- }
-
- if (fd >= 0 && fstat(fd, &st) >= 0)
- map->map_mtime = st.st_mtime;
-
- map->map_db2 = (ARBPTR_T) db;
- if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
- !aliaswait(map, ".db", TRUE))
- return FALSE;
- return TRUE;
-}
-
-
-/*
-** DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
-*/
-
-char *
-db_map_lookup(map, name, av, statp)
- MAP *map;
- char *name;
- char **av;
- int *statp;
-{
- DBT key, val;
- register DB *db = (DB *) map->map_db2;
- int i;
- int st;
- int saveerrno;
- int fd;
- struct stat stbuf;
- char keybuf[MAXNAME + 1];
- char buf[MAXNAME + 1];
-
- bzero(&key, sizeof key);
- bzero(&val, sizeof val);
-
- if (tTd(38, 20))
- printf("db_map_lookup(%s, %s)\n",
- map->map_mname, name);
-
- i = strlen(map->map_file);
- if (i > MAXNAME)
- i = MAXNAME;
- strncpy(buf, map->map_file, i);
- buf[i] = '\0';
- if (i > 3 && strcmp(&buf[i - 3], ".db") == 0)
- buf[i - 3] = '\0';
-
- key.size = strlen(name);
- if (key.size > sizeof keybuf - 1)
- key.size = sizeof keybuf - 1;
- key.data = keybuf;
- bcopy(name, keybuf, key.size);
- keybuf[key.size] = '\0';
- if (!bitset(MF_NOFOLDCASE, map->map_mflags))
- makelower(keybuf);
- lockdb:
-#if DB_VERSION_MAJOR < 2
- fd = db->fd(db);
-#else
- fd = -1;
- errno = db->fd(db, &fd);
-#endif
- if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
- (void) lockfile(fd, buf, ".db", LOCK_SH);
- if (fd < 0 || fstat(fd, &stbuf) < 0 || stbuf.st_mtime > map->map_mtime)
- {
- /* Reopen the database to sync the cache */
- int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR
- : O_RDONLY;
-
- map->map_class->map_close(map);
- map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
- if (map->map_class->map_open(map, omode))
- {
- map->map_mflags |= MF_OPEN;
- map->map_pid = getpid();
- if ((omode && O_ACCMODE) == O_RDWR)
- map->map_mflags |= MF_WRITABLE;
- db = (DB *) map->map_db2;
- goto lockdb;
- }
- else
- {
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- {
- extern MAPCLASS BogusMapClass;
-
- *statp = EX_TEMPFAIL;
- map->map_class = &BogusMapClass;
- map->map_mflags |= MF_OPEN;
- map->map_pid = getpid();
- syserr("Cannot reopen DB database %s",
- map->map_file);
- }
- return NULL;
- }
- }
-
- st = 1;
- if (bitset(MF_TRY0NULL, map->map_mflags))
- {
-#if DB_VERSION_MAJOR < 2
- st = db->get(db, &key, &val, 0);
-#else
- errno = db->get(db, NULL, &key, &val, 0);
- switch (errno)
- {
- case DB_NOTFOUND:
- case DB_KEYEMPTY:
- st = 1;
- break;
-
- case 0:
- st = 0;
- break;
-
- default:
- st = -1;
- break;
- }
-#endif
- if (st == 0)
- map->map_mflags &= ~MF_TRY1NULL;
- }
- if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags))
- {
- key.size++;
-#if DB_VERSION_MAJOR < 2
- st = db->get(db, &key, &val, 0);
-#else
- errno = db->get(db, NULL, &key, &val, 0);
- switch (errno)
- {
- case DB_NOTFOUND:
- case DB_KEYEMPTY:
- st = 1;
- break;
-
- case 0:
- st = 0;
- break;
-
- default:
- st = -1;
- break;
- }
-#endif
- if (st == 0)
- map->map_mflags &= ~MF_TRY0NULL;
- }
- saveerrno = errno;
- if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
- (void) lockfile(fd, buf, ".db", LOCK_UN);
- if (st != 0)
- {
- errno = saveerrno;
- if (st < 0)
- syserr("db_map_lookup: get (%s)", name);
- return NULL;
- }
- if (bitset(MF_MATCHONLY, map->map_mflags))
- return map_rewrite(map, name, strlen(name), NULL);
- else
- return map_rewrite(map, val.data, val.size, av);
-}
-
-
-/*
-** DB_MAP_STORE -- store a datum in the NEWDB database
-*/
-
-void
-db_map_store(map, lhs, rhs)
- register MAP *map;
- char *lhs;
- char *rhs;
-{
- int stat;
- DBT key;
- DBT data;
- register DB *db = map->map_db2;
- char keybuf[MAXNAME + 1];
-
- bzero(&key, sizeof key);
- bzero(&data, sizeof data);
-
- if (tTd(38, 12))
- printf("db_map_store(%s, %s, %s)\n",
- map->map_mname, lhs, rhs);
-
- key.size = strlen(lhs);
- key.data = lhs;
- if (!bitset(MF_NOFOLDCASE, map->map_mflags))
- {
- if (key.size > sizeof keybuf - 1)
- key.size = sizeof keybuf - 1;
- bcopy(key.data, keybuf, key.size);
- keybuf[key.size] = '\0';
- makelower(keybuf);
- key.data = keybuf;
- }
-
- data.size = strlen(rhs);
- data.data = rhs;
-
- if (bitset(MF_INCLNULL, map->map_mflags))
- {
- key.size++;
- data.size++;
- }
-
-#if DB_VERSION_MAJOR < 2
- stat = db->put(db, &key, &data, R_NOOVERWRITE);
-#else
- errno = db->put(db, NULL, &key, &data, DB_NOOVERWRITE);
- switch (errno)
- {
- case DB_KEYEXIST:
- stat = 1;
- break;
-
- case 0:
- stat = 0;
- break;
-
- default:
- stat = -1;
- break;
- }
-#endif
- if (stat > 0)
- {
- if (!bitset(MF_APPEND, map->map_mflags))
- message("050 Warning: duplicate alias name %s", lhs);
- else
- {
- static char *buf = NULL;
- static int bufsiz = 0;
- DBT old;
-
- bzero(&old, sizeof old);
-
- old.data = db_map_lookup(map, key.data,
- (char **)NULL, &stat);
- if (old.data != NULL)
- {
- old.size = strlen(old.data);
- if (data.size + old.size + 2 > bufsiz)
- {
- if (buf != NULL)
- (void) free(buf);
- bufsiz = data.size + old.size + 2;
- buf = xalloc(bufsiz);
- }
- snprintf(buf, bufsiz, "%s,%s",
- (char *) data.data, (char *) old.data);
- data.size = data.size + old.size + 1;
- data.data = buf;
- if (tTd(38, 9))
- printf("db_map_store append=%s\n",
- (char *) data.data);
- }
- }
-#if DB_VERSION_MAJOR < 2
- stat = db->put(db, &key, &data, 0);
-#else
- stat = errno = db->put(db, NULL, &key, &data, 0);
-#endif
- }
- if (stat != 0)
- syserr("readaliases: db put (%s)", lhs);
-}
-
-
-/*
-** DB_MAP_CLOSE -- add distinguished entries and close the database
-*/
-
-void
-db_map_close(map)
- MAP *map;
-{
- register DB *db = map->map_db2;
-
- if (tTd(38, 9))
- printf("db_map_close(%s, %s, %lx)\n",
- map->map_mname, map->map_file, map->map_mflags);
-
- if (bitset(MF_WRITABLE, map->map_mflags))
- {
- /* write out the distinguished alias */
- db_map_store(map, "@", "@");
- }
-
- (void) db->sync(db, 0);
-
-#if !LOCK_ON_OPEN
- if (map->map_lockfd >= 0)
- (void) close(map->map_lockfd);
-#endif
-
-#if DB_VERSION_MAJOR < 2
- if (db->close(db) != 0)
-#else
- /*
- ** Berkeley DB can use internal shared memory
- ** locking for its memory pool. Closing a map
- ** opened by another process will interfere
- ** with the shared memory and locks of the parent
- ** process leaving things in a bad state.
- */
-
- /*
- ** If this map was not opened by the current
- ** process, do not close the map but recover
- ** the file descriptor.
- */
- if (map->map_pid != getpid())
- {
- int fd = -1;
-
- errno = db->fd(db, &fd);
- if (fd >= 0)
- (void) close(fd);
- return;
- }
-
- if ((errno = db->close(db, 0)) != 0)
-#endif
- syserr("db_map_close(%s, %s, %lx): db close failure",
- map->map_mname, map->map_file, map->map_mflags);
-}
-
-#endif
- /*
-** NIS Modules
-*/
-
-# ifdef NIS
-
-# ifndef YPERR_BUSY
-# define YPERR_BUSY 16
-# endif
-
-/*
-** NIS_MAP_OPEN -- open DBM map
-*/
-
-bool
-nis_map_open(map, mode)
- MAP *map;
- int mode;
-{
- int yperr;
- register char *p;
- auto char *vp;
- auto int vsize;
-
- if (tTd(38, 2))
- printf("nis_map_open(%s, %s, %d)\n",
- map->map_mname, map->map_file, mode);
-
- mode &= O_ACCMODE;
- if (mode != O_RDONLY)
- {
- /* issue a pseudo-error message */
-#ifdef ENOSYS
- errno = ENOSYS;
-#else
-# ifdef EFTYPE
- errno = EFTYPE;
-# else
- errno = ENXIO;
-# endif
-#endif
- return FALSE;
- }
-
- p = strchr(map->map_file, '@');
- if (p != NULL)
- {
- *p++ = '\0';
- if (*p != '\0')
- map->map_domain = p;
- }
-
- if (*map->map_file == '\0')
- map->map_file = "mail.aliases";
-
- if (map->map_domain == NULL)
- {
- yperr = yp_get_default_domain(&map->map_domain);
- if (yperr != 0)
- {
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("421 NIS map %s specified, but NIS not running",
- map->map_file);
- return FALSE;
- }
- }
-
- /* check to see if this map actually exists */
- yperr = yp_match(map->map_domain, map->map_file, "@", 1,
- &vp, &vsize);
- if (tTd(38, 10))
- printf("nis_map_open: yp_match(@, %s, %s) => %s\n",
- map->map_domain, map->map_file, yperr_string(yperr));
- if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY)
- {
- /*
- ** We ought to be calling aliaswait() here if this is an
- ** alias file, but powerful HP-UX NIS servers apparently
- ** don't insert the @:@ token into the alias map when it
- ** is rebuilt, so aliaswait() just hangs. I hate HP-UX.
- */
-
-#if 0
- if (!bitset(MF_ALIAS, map->map_mflags) ||
- aliaswait(map, NULL, TRUE))
-#endif
- return TRUE;
- }
-
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- {
- syserr("421 Cannot bind to map %s in domain %s: %s",
- map->map_file, map->map_domain, yperr_string(yperr));
- }
-
- return FALSE;
-}
-
-
-/*
-** NIS_MAP_LOOKUP -- look up a datum in a NIS map
-*/
-
-/* ARGSUSED3 */
-char *
-nis_map_lookup(map, name, av, statp)
- MAP *map;
- char *name;
- char **av;
- int *statp;
-{
- char *vp;
- auto int vsize;
- int buflen;
- int yperr;
- char keybuf[MAXNAME + 1];
-
- if (tTd(38, 20))
- printf("nis_map_lookup(%s, %s)\n",
- map->map_mname, name);
-
- buflen = strlen(name);
- if (buflen > sizeof keybuf - 1)
- buflen = sizeof keybuf - 1;
- bcopy(name, keybuf, buflen);
- keybuf[buflen] = '\0';
- if (!bitset(MF_NOFOLDCASE, map->map_mflags))
- makelower(keybuf);
- yperr = YPERR_KEY;
- if (bitset(MF_TRY0NULL, map->map_mflags))
- {
- yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
- &vp, &vsize);
- if (yperr == 0)
- map->map_mflags &= ~MF_TRY1NULL;
- }
- if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags))
- {
- buflen++;
- yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
- &vp, &vsize);
- if (yperr == 0)
- map->map_mflags &= ~MF_TRY0NULL;
- }
- if (yperr != 0)
- {
- if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
- map->map_mflags &= ~(MF_VALID|MF_OPEN);
- return NULL;
- }
- if (bitset(MF_MATCHONLY, map->map_mflags))
- return map_rewrite(map, name, strlen(name), NULL);
- else
- return map_rewrite(map, vp, vsize, av);
-}
-
-
-/*
-** NIS_GETCANONNAME -- look up canonical name in NIS
-*/
-
-bool
-nis_getcanonname(name, hbsize, statp)
- char *name;
- int hbsize;
- int *statp;
-{
- char *vp;
- auto int vsize;
- int keylen;
- int yperr;
- static bool try0null = TRUE;
- static bool try1null = TRUE;
- static char *yp_domain = NULL;
- char host_record[MAXLINE];
- char cbuf[MAXNAME];
- char nbuf[MAXNAME + 1];
-
- if (tTd(38, 20))
- printf("nis_getcanonname(%s)\n", name);
-
- if (strlen(name) >= sizeof nbuf)
- {
- *statp = EX_UNAVAILABLE;
- return FALSE;
- }
- (void) strcpy(nbuf, name);
- shorten_hostname(nbuf);
- keylen = strlen(nbuf);
-
- if (yp_domain == NULL)
- yp_get_default_domain(&yp_domain);
- makelower(nbuf);
- yperr = YPERR_KEY;
- if (try0null)
- {
- yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
- &vp, &vsize);
- if (yperr == 0)
- try1null = FALSE;
- }
- if (yperr == YPERR_KEY && try1null)
- {
- keylen++;
- yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
- &vp, &vsize);
- if (yperr == 0)
- try0null = FALSE;
- }
- if (yperr != 0)
- {
- if (yperr == YPERR_KEY)
- *statp = EX_NOHOST;
- else if (yperr == YPERR_BUSY)
- *statp = EX_TEMPFAIL;
- else
- *statp = EX_UNAVAILABLE;
- return FALSE;
- }
- if (vsize >= sizeof host_record)
- vsize = sizeof host_record - 1;
- strncpy(host_record, vp, vsize);
- host_record[vsize] = '\0';
- if (tTd(38, 44))
- printf("got record `%s'\n", host_record);
- if (!extract_canonname(nbuf, host_record, cbuf, sizeof cbuf))
- {
- /* this should not happen, but.... */
- *statp = EX_NOHOST;
- return FALSE;
- }
- if (hbsize < strlen(cbuf))
- {
- *statp = EX_UNAVAILABLE;
- return FALSE;
- }
- strcpy(name, cbuf);
- *statp = EX_OK;
- return TRUE;
-}
-
-#endif
- /*
-** NISPLUS Modules
-**
-** This code donated by Sun Microsystems.
-*/
-
-#ifdef NISPLUS
-
-#undef NIS /* symbol conflict in nis.h */
-#undef T_UNSPEC /* symbol conflict in nis.h -> ... -> sys/tiuser.h */
-#include <rpcsvc/nis.h>
-#include <rpcsvc/nislib.h>
-
-#define EN_col(col) zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val
-#define COL_NAME(res,i) ((res->objects.objects_val)->TA_data.ta_cols.ta_cols_val)[i].tc_name
-#define COL_MAX(res) ((res->objects.objects_val)->TA_data.ta_cols.ta_cols_len)
-#define PARTIAL_NAME(x) ((x)[strlen(x) - 1] != '.')
-
-/*
-** NISPLUS_MAP_OPEN -- open nisplus table
-*/
-
-bool
-nisplus_map_open(map, mode)
- MAP *map;
- int mode;
-{
- nis_result *res = NULL;
- int retry_cnt, max_col, i;
- char qbuf[MAXLINE + NIS_MAXNAMELEN];
-
- if (tTd(38, 2))
- printf("nisplus_map_open(%s, %s, %d)\n",
- map->map_mname, map->map_file, mode);
-
- mode &= O_ACCMODE;
- if (mode != O_RDONLY)
- {
- errno = EPERM;
- return FALSE;
- }
-
- if (*map->map_file == '\0')
- map->map_file = "mail_aliases.org_dir";
-
- if (PARTIAL_NAME(map->map_file) && map->map_domain == NULL)
- {
- /* set default NISPLUS Domain to $m */
- extern char *nisplus_default_domain __P((void));
-
- map->map_domain = newstr(nisplus_default_domain());
- if (tTd(38, 2))
- printf("nisplus_map_open(%s): using domain %s\n",
- map->map_file, map->map_domain);
- }
- if (!PARTIAL_NAME(map->map_file))
- {
- map->map_domain = newstr("");
- snprintf(qbuf, sizeof qbuf, "%s", map->map_file);
- }
- else
- {
- /* check to see if this map actually exists */
- snprintf(qbuf, sizeof qbuf, "%s.%s",
- map->map_file, map->map_domain);
- }
-
- retry_cnt = 0;
- while (res == NULL || res->status != NIS_SUCCESS)
- {
- res = nis_lookup(qbuf, FOLLOW_LINKS);
- switch (res->status)
- {
- case NIS_SUCCESS:
- break;
-
- case NIS_TRYAGAIN:
- case NIS_RPCERROR:
- case NIS_NAMEUNREACHABLE:
- if (retry_cnt++ > 4)
- {
- errno = EAGAIN;
- return FALSE;
- }
- /* try not to overwhelm hosed server */
- sleep(2);
- break;
-
- default: /* all other nisplus errors */
-#if 0
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("421 Cannot find table %s.%s: %s",
- map->map_file, map->map_domain,
- nis_sperrno(res->status));
-#endif
- errno = EAGAIN;
- return FALSE;
- }
- }
-
- if (NIS_RES_NUMOBJ(res) != 1 ||
- (NIS_RES_OBJECT(res)->zo_data.zo_type != TABLE_OBJ))
- {
- if (tTd(38, 10))
- printf("nisplus_map_open: %s is not a table\n", qbuf);
-#if 0
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("421 %s.%s: %s is not a table",
- map->map_file, map->map_domain,
- nis_sperrno(res->status));
-#endif
- errno = EBADF;
- return FALSE;
- }
- /* default key column is column 0 */
- if (map->map_keycolnm == NULL)
- map->map_keycolnm = newstr(COL_NAME(res,0));
-
- max_col = COL_MAX(res);
-
- /* verify the key column exist */
- for (i=0; i< max_col; i++)
- {
- if (!strcmp(map->map_keycolnm, COL_NAME(res,i)))
- break;
- }
- if (i == max_col)
- {
- if (tTd(38, 2))
- printf("nisplus_map_open(%s): can not find key column %s\n",
- map->map_file, map->map_keycolnm);
- errno = ENOENT;
- return FALSE;
- }
-
- /* default value column is the last column */
- if (map->map_valcolnm == NULL)
- {
- map->map_valcolno = max_col - 1;
- return TRUE;
- }
-
- for (i=0; i< max_col; i++)
- {
- if (strcmp(map->map_valcolnm, COL_NAME(res,i)) == 0)
- {
- map->map_valcolno = i;
- return TRUE;
- }
- }
-
- if (tTd(38, 2))
- printf("nisplus_map_open(%s): can not find column %s\n",
- map->map_file, map->map_keycolnm);
- errno = ENOENT;
- return FALSE;
-}
-
-
-/*
-** NISPLUS_MAP_LOOKUP -- look up a datum in a NISPLUS table
-*/
-
-char *
-nisplus_map_lookup(map, name, av, statp)
- MAP *map;
- char *name;
- char **av;
- int *statp;
-{
- char *p;
- auto int vsize;
- char *skp;
- int skleft;
- char search_key[MAXNAME + 4];
- char qbuf[MAXLINE + NIS_MAXNAMELEN];
- nis_result *result;
-
- if (tTd(38, 20))
- printf("nisplus_map_lookup(%s, %s)\n",
- map->map_mname, name);
-
- if (!bitset(MF_OPEN, map->map_mflags))
- {
- if (nisplus_map_open(map, O_RDONLY))
- {
- map->map_mflags |= MF_OPEN;
- map->map_pid = getpid();
- }
- else
- {
- *statp = EX_UNAVAILABLE;
- return NULL;
- }
- }
-
- /*
- ** Copy the name to the key buffer, escaping double quote characters
- ** by doubling them and quoting "]" and "," to avoid having the
- ** NIS+ parser choke on them.
- */
-
- skleft = sizeof search_key - 4;
- skp = search_key;
- for (p = name; *p != '\0' && skleft > 0; p++)
- {
- switch (*p)
- {
- case ']':
- case ',':
- /* quote the character */
- *skp++ = '"';
- *skp++ = *p;
- *skp++ = '"';
- skleft -= 3;
- break;
-
- case '"':
- /* double the quote */
- *skp++ = '"';
- skleft--;
- /* fall through... */
-
- default:
- *skp++ = *p;
- skleft--;
- break;
- }
- }
- *skp = '\0';
- if (!bitset(MF_NOFOLDCASE, map->map_mflags))
- makelower(search_key);
-
- /* construct the query */
- if (PARTIAL_NAME(map->map_file))
- snprintf(qbuf, sizeof qbuf, "[%s=%s],%s.%s",
- map->map_keycolnm, search_key, map->map_file,
- map->map_domain);
- else
- snprintf(qbuf, sizeof qbuf, "[%s=%s],%s",
- map->map_keycolnm, search_key, map->map_file);
-
- if (tTd(38, 20))
- printf("qbuf=%s\n", qbuf);
- result = nis_list(qbuf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
- if (result->status == NIS_SUCCESS)
- {
- int count;
- char *str;
-
- if ((count = NIS_RES_NUMOBJ(result)) != 1)
- {
- if (LogLevel > 10)
- sm_syslog(LOG_WARNING, CurEnv->e_id,
- "%s: lookup error, expected 1 entry, got %d",
- map->map_file, count);
-
- /* ignore second entry */
- if (tTd(38, 20))
- printf("nisplus_map_lookup(%s), got %d entries, additional entries ignored\n",
- name, count);
- }
-
- p = ((NIS_RES_OBJECT(result))->EN_col(map->map_valcolno));
- /* set the length of the result */
- if (p == NULL)
- p = "";
- vsize = strlen(p);
- if (tTd(38, 20))
- printf("nisplus_map_lookup(%s), found %s\n",
- name, p);
- if (bitset(MF_MATCHONLY, map->map_mflags))
- str = map_rewrite(map, name, strlen(name), NULL);
- else
- str = map_rewrite(map, p, vsize, av);
- nis_freeresult(result);
- *statp = EX_OK;
- return str;
- }
- else
- {
- if (result->status == NIS_NOTFOUND)
- *statp = EX_NOTFOUND;
- else if (result->status == NIS_TRYAGAIN)
- *statp = EX_TEMPFAIL;
- else
- {
- *statp = EX_UNAVAILABLE;
- map->map_mflags &= ~(MF_VALID|MF_OPEN);
- }
- }
- if (tTd(38, 20))
- printf("nisplus_map_lookup(%s), failed\n", name);
- nis_freeresult(result);
- return NULL;
-}
-
-
-
-/*
-** NISPLUS_GETCANONNAME -- look up canonical name in NIS+
-*/
-
-bool
-nisplus_getcanonname(name, hbsize, statp)
- char *name;
- int hbsize;
- int *statp;
-{
- char *vp;
- auto int vsize;
- nis_result *result;
- char *p;
- char nbuf[MAXNAME + 1];
- char qbuf[MAXLINE + NIS_MAXNAMELEN];
-
- if (strlen(name) >= sizeof nbuf)
- {
- *statp = EX_UNAVAILABLE;
- return FALSE;
- }
- (void) strcpy(nbuf, name);
- shorten_hostname(nbuf);
-
- p = strchr(nbuf, '.');
- if (p == NULL)
- {
- /* single token */
- snprintf(qbuf, sizeof qbuf, "[name=%s],hosts.org_dir", nbuf);
- }
- else if (p[1] != '\0')
- {
- /* multi token -- take only first token in nbuf */
- *p = '\0';
- snprintf(qbuf, sizeof qbuf, "[name=%s],hosts.org_dir.%s",
- nbuf, &p[1]);
- }
- else
- {
- *statp = EX_NOHOST;
- return FALSE;
- }
-
- if (tTd(38, 20))
- printf("\nnisplus_getcanoname(%s), qbuf=%s\n",
- name, qbuf);
-
- result = nis_list(qbuf, EXPAND_NAME|FOLLOW_LINKS|FOLLOW_PATH,
- NULL, NULL);
-
- if (result->status == NIS_SUCCESS)
- {
- int count;
- char *domain;
-
- if ((count = NIS_RES_NUMOBJ(result)) != 1)
- {
- if (LogLevel > 10)
- sm_syslog(LOG_WARNING, CurEnv->e_id,
- "nisplus_getcanonname: lookup error, expected 1 entry, got %d",
- count);
-
- /* ignore second entry */
- if (tTd(38, 20))
- printf("nisplus_getcanoname(%s), got %d entries, all but first ignored\n",
- name, count);
- }
-
- if (tTd(38, 20))
- printf("nisplus_getcanoname(%s), found in directory \"%s\"\n",
- name, (NIS_RES_OBJECT(result))->zo_domain);
-
-
- vp = ((NIS_RES_OBJECT(result))->EN_col(0));
- vsize = strlen(vp);
- if (tTd(38, 20))
- printf("nisplus_getcanonname(%s), found %s\n",
- name, vp);
- if (strchr(vp, '.') != NULL)
- {
- domain = "";
- }
- else
- {
- domain = macvalue('m', CurEnv);
- if (domain == NULL)
- domain = "";
- }
- if (hbsize > vsize + (int) strlen(domain) + 1)
- {
- if (domain[0] == '\0')
- strcpy(name, vp);
- else
- snprintf(name, hbsize, "%s.%s", vp, domain);
- *statp = EX_OK;
- }
- else
- *statp = EX_NOHOST;
- nis_freeresult(result);
- return TRUE;
- }
- else
- {
- if (result->status == NIS_NOTFOUND)
- *statp = EX_NOHOST;
- else if (result->status == NIS_TRYAGAIN)
- *statp = EX_TEMPFAIL;
- else
- *statp = EX_UNAVAILABLE;
- }
- if (tTd(38, 20))
- printf("nisplus_getcanonname(%s), failed, status=%d, nsw_stat=%d\n",
- name, result->status, *statp);
- nis_freeresult(result);
- return FALSE;
-}
-
-
-char *
-nisplus_default_domain()
-{
- static char default_domain[MAXNAME + 1] = "";
- char *p;
-
- if (default_domain[0] != '\0')
- return(default_domain);
-
- p = nis_local_directory();
- snprintf(default_domain, sizeof default_domain, "%s", p);
- return default_domain;
-}
-
-#endif /* NISPLUS */
- /*
-** LDAP Modules
-**
-** Contributed by Booker C. Bense <bbense@networking.stanford.edu>.
-** Get your support from him.
-*/
-
-#ifdef LDAPMAP
-
-# undef NEEDGETOPT /* used for something else in LDAP */
-
-# include <lber.h>
-# include <ldap.h>
-# include "ldap_map.h"
-
-/*
-** LDAP_MAP_OPEN -- open LDAP map
-**
-** Since LDAP is TCP-based there is not much we can or should do
-** here. It might be a good idea to attempt an open/close here.
-*/
-
-bool
-ldap_map_open(map, mode)
- MAP *map;
- int mode;
-{
- if (tTd(38, 2))
- printf("ldap_map_open(%s, %d)\n", map->map_mname, mode);
-
- mode &= O_ACCMODE;
- if (mode != O_RDONLY)
- {
- /* issue a pseudo-error message */
-#ifdef ENOSYS
- errno = ENOSYS;
-#else
-# ifdef EFTYPE
- errno = EFTYPE;
-# else
- errno = ENXIO;
-# endif
-#endif
- return FALSE;
- }
- return TRUE;
-}
-
-
-/*
-** LDAP_MAP_START -- actually open LDAP map
-**
-** Caching should be investigated.
-*/
-
-static jmp_buf LDAPTimeout;
-
-static void
-ldaptimeout(sig_no)
- int sig_no;
-{
- longjmp(LDAPTimeout, 1);
-}
-
-bool
-ldap_map_start(map)
- MAP *map;
-{
- LDAP_MAP_STRUCT *lmap;
- LDAP *ld;
- register EVENT *ev = NULL;
-
- if (tTd(38, 2))
- printf("ldap_map_start(%s)\n", map->map_mname);
-
- lmap = (LDAP_MAP_STRUCT *) map->map_db1;
-
- if (tTd(38,9))
- printf("ldap_open(%s, %d)\n", lmap->ldaphost, lmap->ldapport);
-
- /* Need to set an alarm here, ldap_open is hopelessly broken. */
-
- /* set the timeout */
- if (lmap->timeout.tv_sec != 0)
- {
- if (setjmp(LDAPTimeout) != 0)
- {
- if (LogLevel > 1)
- sm_syslog(LOG_NOTICE, CurEnv->e_id,
- "timeout waiting for ldap_open to %.100s",
- lmap->ldaphost);
- return (FALSE);
- }
- ev = setevent(lmap->timeout.tv_sec, ldaptimeout, 0);
- }
-
-#ifdef USE_LDAP_INIT
- ld = ldap_init(lmap->ldaphost,lmap->ldapport);
-#else
- ld = ldap_open(lmap->ldaphost,lmap->ldapport);
-#endif
-
- /* clear the event if it has not sprung */
- if (lmap->timeout.tv_sec != 0)
- clrevent(ev);
-
- if (ld == NULL)
- {
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- {
- syserr("%sldapopen failed to %s in map %s",
- bitset(MF_NODEFER, map->map_mflags) ? "" : "421 ",
- lmap->ldaphost, map->map_mname);
- }
- return FALSE;
- }
-
-#ifdef USE_LDAP_SET_OPTION
- ldap_set_option(ld, LDAP_OPT_DEREF, &lmap->deref);
- ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &lmap->timelimit);
- ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &lmap->sizelimit);
- ldap_set_option(ld, LDAP_OPT_REFERRALS,
- bitset(LDAP_OPT_REFERRALS, lmap->ldap_options) ?
- LDAP_OPT_ON : LDAP_OPT_OFF);
-#else
- /* From here on in we can use ldap internal timelimits */
- ld->ld_deref = lmap->deref;
- ld->ld_timelimit = lmap->timelimit;
- ld->ld_sizelimit = lmap->sizelimit;
- ld->ld_options = lmap->ldap_options;
-#endif
-
-#ifdef USE_LDAP_INIT
- /* ld needs to be cast into the map struct */
- lmap->ld = ld;
- return TRUE;
-#else
- if (ldap_bind_s(ld, lmap->binddn,lmap->passwd,lmap->method) != LDAP_SUCCESS)
- {
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- {
- syserr("421 Cannot bind to map %s in ldap server %s",
- map->map_mname, lmap->ldaphost);
- }
- }
- else
- {
- /* We need to cast ld into the map structure */
- lmap->ld = ld;
- return TRUE;
- }
-
- return FALSE;
-#endif
-}
-
-
-/*
-** LDAP_MAP_STOP -- close the ldap connection
-*/
-
-void
-ldap_map_stop(map)
- MAP *map;
-{
- LDAP_MAP_STRUCT *lmap;
-
- lmap = (LDAP_MAP_STRUCT *) map->map_db1;
- if (lmap->ld != NULL)
- {
- ldap_unbind(lmap->ld);
- lmap->ld = NULL;
- }
-}
-
-/*
-** LDAP_MAP_CLOSE -- close ldap map
-*/
-
-void
-ldap_map_close(map)
- MAP *map;
-{
- ldap_map_stop(map);
-}
-
-#ifdef SUNET_ID
-/*
-** SUNET_ID_HASH -- Convert a string to it's Sunet_id canonical form
-** This only makes sense at Stanford University.
-*/
-
-char *
-sunet_id_hash(str)
- char *str;
-{
- char *p, *p_last;
-
- p = str;
- p_last = p;
- while (*p != '\0')
- {
- if (islower(*p) || isdigit(*p))
- {
- *p_last = *p;
- p_last++;
- }
- else if (isupper(*p))
- {
- *p_last = tolower(*p);
- p_last++;
- }
- ++p;
- }
- if (*p_last != '\0')
- *p_last = '\0';
- return (str);
-}
-
-
-
-#endif /* SUNET_ID */
-/*
-** LDAP_MAP_LOOKUP -- look up a datum in a LDAP map
-*/
-
-char *
-ldap_map_lookup(map, name, av, statp)
- MAP *map;
- char *name;
- char **av;
- int *statp;
-{
- LDAP_MAP_STRUCT *lmap = NULL;
- LDAPMessage *entry;
- char *vp;
- auto int vsize;
- char keybuf[MAXNAME + 1];
- char filter[LDAP_MAP_MAX_FILTER + 1];
- char **attr_values = NULL;
- char *result;
- int name_len;
- char *fp, *p, *q;
-
- if (tTd(38, 20))
- printf("ldap_map_lookup(%s, %s)\n", map->map_mname, name);
-
- /* actually open the map */
- if (!ldap_map_start(map))
- {
- result = NULL;
- *statp = EX_TEMPFAIL;
- goto quick_exit;
- }
-
- /* Get ldap struct pointer from map */
- lmap = (LDAP_MAP_STRUCT *) map->map_db1;
-
- name_len = strlen(name);
- if (name_len > MAXNAME)
- name_len = MAXNAME;
- strncpy(keybuf, name, name_len);
- keybuf[name_len] = '\0';
-
- if (!bitset(MF_NOFOLDCASE, map->map_mflags))
-#ifdef SUNET_ID
- sunet_id_hash(keybuf);
-#else
- makelower(keybuf);
-#endif /*SUNET_ID */
-
- /* substitute keybuf into filter, perhaps multiple times */
- fp = filter;
- p = lmap->filter;
- while ((q = strchr(p, '%')) != NULL)
- {
- if (q[1] == 's')
- {
- snprintf(fp, SPACELEFT(filter, fp), "%.*s%s",
- q - p, p, keybuf);
- p = q + 2;
- }
- else
- {
- snprintf(fp, SPACELEFT(filter, fp), "%.*s",
- q - p + 1, p);
- p = q + (q[1] == '%' ? 2 : 1);
- }
- fp += strlen(fp);
- }
- snprintf(fp, SPACELEFT(filter, fp), "%s", p);
- if (tTd(38, 20))
- printf("ldap search filter=%s\n", filter);
-
- if (ldap_search_st(lmap->ld, lmap->base,lmap->scope,filter,
- lmap->attr, lmap->attrsonly, &(lmap->timeout),
- &(lmap->res)) != LDAP_SUCCESS)
- {
- /* try stopping/starting map */
- ldap_map_stop(map);
- if (!ldap_map_start(map))
- {
- result = NULL;
- *statp = EX_TEMPFAIL;
- goto quick_exit;
- }
- if (ldap_search_st(lmap->ld, lmap->base, lmap->scope, filter,
- lmap->attr, lmap->attrsonly,
- &(lmap->timeout), &(lmap->res))
- != LDAP_SUCCESS)
- {
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- {
- syserr("%sError in ldap_search_st using %s in map %s",
- bitset(MF_NODEFER, map->map_mflags) ? "" : "421 ",
- filter, map->map_mname);
- }
- result = NULL;
- *statp = EX_TEMPFAIL;
- goto quick_exit;
- }
- }
-
- entry = ldap_first_entry(lmap->ld,lmap->res);
- if (entry == NULL)
- {
- result = NULL;
- *statp = EX_NOTFOUND;
- goto quick_exit;
- }
-
- /* Need to build the args for map_rewrite here */
- attr_values = ldap_get_values(lmap->ld,entry,lmap->attr[0]);
- if (attr_values == NULL)
- {
- /* bad things happened */
- result = NULL;
- *statp = EX_NOTFOUND;
- goto quick_exit;
- }
-
- *statp = EX_OK;
-
- /* If there is more that one use the first */
- vp = attr_values[0];
- vsize = strlen(vp);
-
- if (LogLevel > 9)
- sm_syslog(LOG_INFO, CurEnv->e_id,
- "ldap %.100s => %s",
- name, vp);
- if (bitset(MF_MATCHONLY, map->map_mflags))
- result = map_rewrite(map, name, strlen(name), NULL);
- else
- result = map_rewrite(map, vp, vsize, av);
-
- quick_exit:
- if (attr_values != NULL)
- ldap_value_free(attr_values);
- if (lmap != NULL)
- ldap_msgfree(lmap->res);
- ldap_map_stop(map);
- return result ;
-}
-
-
-/*
-** LDAP_MAP_DEQUOTE - helper routine for ldap_map_parseargs
-*/
-
-char *
-ldap_map_dequote(str)
- char *str;
-{
- char *p;
- char *start;
- p = str;
-
- if (*p == '"')
- {
- start = ++p;
- /* Should probably swallow initial whitespace here */
- }
- else
- {
- return(str);
- }
- while (*p != '"' && *p != '\0')
- {
- p++;
- }
- if (*p != '\0')
- *p = '\0';
- return start;
-}
-
-/*
-** LDAP_MAP_PARSEARGS -- parse ldap map definition args.
-*/
-
-bool
-ldap_map_parseargs(map,args)
- MAP *map;
- char *args;
-{
- register char *p = args;
- register int done;
- LDAP_MAP_STRUCT *lmap;
-
- /* We need to alloc an LDAP_MAP_STRUCT struct */
- lmap = (LDAP_MAP_STRUCT *) xalloc(sizeof(LDAP_MAP_STRUCT));
-
- /* Set default int's here , default strings below */
- lmap->ldapport = DEFAULT_LDAP_MAP_PORT;
- lmap->deref = DEFAULT_LDAP_MAP_DEREF;
- lmap->timelimit = DEFAULT_LDAP_MAP_TIMELIMIT;
- lmap->sizelimit = DEFAULT_LDAP_MAP_SIZELIMIT;
- lmap->ldap_options = DEFAULT_LDAP_MAP_LDAP_OPTIONS;
- lmap->method = DEFAULT_LDAP_MAP_METHOD;
- lmap->scope = DEFAULT_LDAP_MAP_SCOPE;
- lmap->attrsonly = DEFAULT_LDAP_MAP_ATTRSONLY;
- lmap->timeout.tv_sec = DEFAULT_LDAP_MAP_TIMELIMIT;
- lmap->timeout.tv_usec = 0;
-
- /* Default char ptrs to NULL */
- lmap->binddn = NULL;
- lmap->passwd = NULL;
- lmap->base = NULL;
- lmap->ldaphost = NULL;
-
- /* Default general ptrs to NULL */
- lmap->ld = NULL;
- lmap->res = NULL;
-
- map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL;
- for (;;)
- {
- while (isascii(*p) && isspace(*p))
- p++;
- if (*p != '-')
- break;
- switch (*++p)
- {
- case 'N':
- map->map_mflags |= MF_INCLNULL;
- map->map_mflags &= ~MF_TRY0NULL;
- break;
-
- case 'O':
- map->map_mflags &= ~MF_TRY1NULL;
- break;
-
- case 'o':
- map->map_mflags |= MF_OPTIONAL;
- break;
-
- case 'f':
- map->map_mflags |= MF_NOFOLDCASE;
- break;
-
- case 'm':
- map->map_mflags |= MF_MATCHONLY;
- break;
-
- case 'A':
- map->map_mflags |= MF_APPEND;
- break;
-
- case 'q':
- map->map_mflags |= MF_KEEPQUOTES;
- break;
-
- case 't':
- map->map_mflags |= MF_NODEFER;
- break;
-
- case 'a':
- map->map_app = ++p;
- break;
-
- case 'T':
- map->map_tapp = ++p;
- break;
-
- /* Start of ldap_map specific args */
- case 'k': /* search field */
- while (isascii(*++p) && isspace(*p))
- continue;
- lmap->filter = p;
- break;
-
- case 'v': /* attr to return */
- while (isascii(*++p) && isspace(*p))
- continue;
- lmap->attr[0] = p;
- lmap->attr[1] = NULL;
- break;
-
- /* args stolen from ldapsearch.c */
- case 'R': /* don't auto chase referrals */
-#ifdef LDAP_REFERRALS
- lmap->ldap_options &= ~LDAP_OPT_REFERRALS;
-#else /* LDAP_REFERRALS */
- syserr("compile with -DLDAP_REFERRALS for referral support\n");
-#endif /* LDAP_REFERRALS */
- break;
-
- case 'n': /* retrieve attribute names only -- no values */
- lmap->attrsonly += 1;
- break;
-
- case 's': /* search scope */
- if (strncasecmp(++p, "base", 4) == 0)
- {
- lmap->scope = LDAP_SCOPE_BASE;
- }
- else if (strncasecmp(p, "one", 3) == 0)
- {
- lmap->scope = LDAP_SCOPE_ONELEVEL;
- }
- else if (strncasecmp(p, "sub", 3) == 0)
- {
- lmap->scope = LDAP_SCOPE_SUBTREE;
- }
- else
- { /* bad config line */
- if (!bitset(MCF_OPTFILE, map->map_class->map_cflags))
- {
- char *ptr;
-
- if ((ptr = strchr(p, ' ')) != NULL)
- *ptr = '\0';
- syserr("Scope must be [base|one|sub] not %s in map %s",
- p, map->map_mname);
- if (ptr != NULL)
- *ptr = ' ';
- return FALSE;
- }
- }
- break;
-
- case 'h': /* ldap host */
- while (isascii(*++p) && isspace(*p))
- continue;
- map->map_domain = p;
- lmap->ldaphost = p;
- break;
-
- case 'b': /* search base */
- while (isascii(*++p) && isspace(*p))
- continue;
- lmap->base = p;
- break;
-
- case 'p': /* ldap port */
- while (isascii(*++p) && isspace(*p))
- continue;
- lmap->ldapport = atoi(p);
- break;
-
- case 'l': /* time limit */
- while (isascii(*++p) && isspace(*p))
- continue;
- lmap->timelimit = atoi(p);
- lmap->timeout.tv_sec = lmap->timelimit;
- break;
-
- }
-
- /* need to account for quoted strings here arggg... */
- done = isascii(*p) && isspace(*p);
- while (*p != '\0' && !done)
- {
- if (*p == '"')
- {
- while (*++p != '"' && *p != '\0')
- {
- continue;
- }
- if (*p != '\0')
- p++;
- }
- else
- {
- p++;
- }
- done = isascii(*p) && isspace(*p);
- }
-
- if (*p != '\0')
- *p++ = '\0';
- }
-
- if (map->map_app != NULL)
- map->map_app = newstr(ldap_map_dequote(map->map_app));
- if (map->map_tapp != NULL)
- map->map_tapp = newstr(ldap_map_dequote(map->map_tapp));
- if (map->map_domain != NULL)
- map->map_domain = newstr(ldap_map_dequote(map->map_domain));
-
- /*
- ** We need to swallow up all the stuff into a struct
- ** and dump it into map->map_dbptr1
- */
-
- if (lmap->ldaphost != NULL)
- lmap->ldaphost = newstr(ldap_map_dequote(lmap->ldaphost));
- else
- {
- syserr("LDAP map: -h flag is required");
- return FALSE;
- }
-
- if (lmap->binddn != NULL)
- lmap->binddn = newstr(ldap_map_dequote(lmap->binddn));
- else
- lmap->binddn = DEFAULT_LDAP_MAP_BINDDN;
-
-
- if (lmap->passwd != NULL)
- lmap->passwd = newstr(ldap_map_dequote(lmap->passwd));
- else
- lmap->passwd = DEFAULT_LDAP_MAP_PASSWD;
-
- if (lmap->base != NULL)
- lmap->base = newstr(ldap_map_dequote(lmap->base));
- else
- {
- syserr("LDAP map: -b flag is required");
- return FALSE;
- }
-
-
- if (lmap->filter != NULL)
- lmap->filter = newstr(ldap_map_dequote(lmap->filter));
- else
- {
- if (!bitset(MCF_OPTFILE, map->map_class->map_cflags))
- {
- syserr("No filter given in map %s", map->map_mname);
- return FALSE;
- }
- }
- if (lmap->attr[0] != NULL)
- lmap->attr[0] = newstr(ldap_map_dequote(lmap->attr[0]));
- else
- {
- if (!bitset(MCF_OPTFILE, map->map_class->map_cflags))
- {
- syserr("No return attribute in %s", map->map_mname);
- return FALSE;
- }
- }
-
- map->map_db1 = (ARBPTR_T) lmap;
- return TRUE;
-}
-
-#endif /* LDAP Modules */
- /*
-** syslog map
-*/
-
-#if _FFR_MAP_SYSLOG
-
-#define map_prio map_lockfd /* overload field */
-
-/*
-** SYSLOG_MAP_PARSEARGS -- check for priority level to syslog messages.
-*/
-
-bool
-syslog_map_parseargs(map, args)
- MAP *map;
- char *args;
-{
- char *p = args;
- char *priority = NULL;
-
- for (;;)
- {
- while (isascii(*p) && isspace(*p))
- p++;
- if (*p != '-')
- break;
- if (*++p == 'L')
- priority = ++p;
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
- p++;
- if (*p != '\0')
- *p++ = '\0';
- }
-
- if (priority == NULL)
- map->map_prio = LOG_INFO;
- else
- {
- if (strncasecmp("LOG_", priority, 4) == 0)
- priority += 4;
-
-#ifdef LOG_EMERG
- if (strcasecmp("EMERG", priority) == 0)
- map->map_prio = LOG_EMERG;
- else
-#endif
-#ifdef LOG_ALERT
- if (strcasecmp("ALERT", priority) == 0)
- map->map_prio = LOG_ALERT;
- else
-#endif
-#ifdef LOG_CRIT
- if (strcasecmp("CRIT", priority) == 0)
- map->map_prio = LOG_CRIT;
- else
-#endif
-#ifdef LOG_ERR
- if (strcasecmp("ERR", priority) == 0)
- map->map_prio = LOG_ERR;
- else
-#endif
-#ifdef LOG_WARNING
- if (strcasecmp("WARNING", priority) == 0)
- map->map_prio = LOG_WARNING;
- else
-#endif
-#ifdef LOG_NOTICE
- if (strcasecmp("NOTICE", priority) == 0)
- map->map_prio = LOG_NOTICE;
- else
-#endif
-#ifdef LOG_INFO
- if (strcasecmp("INFO", priority) == 0)
- map->map_prio = LOG_INFO;
- else
-#endif
-#ifdef LOG_DEBUG
- if (strcasecmp("DEBUG", priority) == 0)
- map->map_prio = LOG_DEBUG;
- else
-#endif
- {
- syserr("syslog_map_parseargs: Unknown priority %s\n",
- priority);
- return FALSE;
- }
- }
- return TRUE;
-}
-
-/*
-** SYSLOG_MAP_LOOKUP -- rewrite and syslog message. Always return empty string
-*/
-
-char *
-syslog_map_lookup(map, string, args, statp)
- MAP *map;
- char *string;
- char **args;
- int *statp;
-{
- char *ptr = map_rewrite(map, string, strlen(string), args);
-
- if (ptr != NULL)
- {
- if (tTd(38, 20))
- printf("syslog_map_lookup(%s (priority %d): %s\n",
- map->map_mname, map->map_prio, ptr);
-
- sm_syslog(map->map_prio, CurEnv->e_id, "%s", ptr);
- }
-
- *statp = EX_OK;
- return "";
-}
-
-#endif /* _FFR_MAP_SYSLOG */
- /*
-** HESIOD Modules
-*/
-
-#ifdef HESIOD
-
-bool
-hes_map_open(map, mode)
- MAP *map;
- int mode;
-{
- if (tTd(38, 2))
- printf("hes_map_open(%s, %s, %d)\n",
- map->map_mname, map->map_file, mode);
-
- if (mode != O_RDONLY)
- {
- /* issue a pseudo-error message */
-#ifdef ENOSYS
- errno = ENOSYS;
-#else
-# ifdef EFTYPE
- errno = EFTYPE;
-# else
- errno = ENXIO;
-# endif
-#endif
- return FALSE;
- }
-
-#ifdef HESIOD_INIT
- if (HesiodContext != NULL || hesiod_init(&HesiodContext) == 0)
- return TRUE;
-
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("421 cannot initialize Hesiod map (%s)",
- errstring(errno));
- return FALSE;
-#else
- if (hes_error() == HES_ER_UNINIT)
- hes_init();
- switch (hes_error())
- {
- case HES_ER_OK:
- case HES_ER_NOTFOUND:
- return TRUE;
- }
-
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("421 cannot initialize Hesiod map (%d)", hes_error());
-
- return FALSE;
-#endif /* HESIOD_INIT */
-}
-
-char *
-hes_map_lookup(map, name, av, statp)
- MAP *map;
- char *name;
- char **av;
- int *statp;
-{
- char **hp;
-
- if (tTd(38, 20))
- printf("hes_map_lookup(%s, %s)\n", map->map_file, name);
-
- if (name[0] == '\\')
- {
- char *np;
- int nl;
- char nbuf[MAXNAME];
-
- nl = strlen(name);
- if (nl < sizeof nbuf - 1)
- np = nbuf;
- else
- np = xalloc(strlen(name) + 2);
- np[0] = '\\';
- strcpy(&np[1], name);
-#ifdef HESIOD_INIT
- hp = hesiod_resolve(HesiodContext, np, map->map_file);
-#else
- hp = hes_resolve(np, map->map_file);
-#endif /* HESIOD_INIT */
- if (np != nbuf)
- free(np);
- }
- else
- {
-#ifdef HESIOD_INIT
- hp = hesiod_resolve(HesiodContext, name, map->map_file);
-#else
- hp = hes_resolve(name, map->map_file);
-#endif /* HESIOD_INIT */
- }
-#ifdef HESIOD_INIT
- if (hp == NULL)
- return NULL;
- if (*hp == NULL)
- {
- hesiod_free_list(HesiodContext, hp);
- switch (errno)
- {
- case ENOENT:
- *statp = EX_NOTFOUND;
- break;
- case ECONNREFUSED:
- case EMSGSIZE:
- *statp = EX_TEMPFAIL;
- break;
- case ENOMEM:
- default:
- *statp = EX_UNAVAILABLE;
- break;
- }
- return NULL;
- }
-#else
- if (hp == NULL || hp[0] == NULL)
- {
- switch (hes_error())
- {
- case HES_ER_OK:
- *statp = EX_OK;
- break;
-
- case HES_ER_NOTFOUND:
- *statp = EX_NOTFOUND;
- break;
-
- case HES_ER_CONFIG:
- *statp = EX_UNAVAILABLE;
- break;
-
- case HES_ER_NET:
- *statp = EX_TEMPFAIL;
- break;
- }
- return NULL;
- }
-#endif /* HESIOD_INIT */
-
- if (bitset(MF_MATCHONLY, map->map_mflags))
- return map_rewrite(map, name, strlen(name), NULL);
- else
- return map_rewrite(map, hp[0], strlen(hp[0]), av);
-}
-
-#endif
- /*
-** NeXT NETINFO Modules
-*/
-
-#if NETINFO
-
-# define NETINFO_DEFAULT_DIR "/aliases"
-# define NETINFO_DEFAULT_PROPERTY "members"
-
-extern char *ni_propval __P((char *, char *, char *, char *, int));
-
-
-/*
-** NI_MAP_OPEN -- open NetInfo Aliases
-*/
-
-bool
-ni_map_open(map, mode)
- MAP *map;
- int mode;
-{
- if (tTd(38, 2))
- printf("ni_map_open(%s, %s, %d)\n",
- map->map_mname, map->map_file, mode);
- mode &= O_ACCMODE;
-
- if (*map->map_file == '\0')
- map->map_file = NETINFO_DEFAULT_DIR;
-
- if (map->map_valcolnm == NULL)
- map->map_valcolnm = NETINFO_DEFAULT_PROPERTY;
-
- if (map->map_coldelim == '\0' && bitset(MF_ALIAS, map->map_mflags))
- map->map_coldelim = ',';
-
- return TRUE;
-}
-
-
-/*
-** NI_MAP_LOOKUP -- look up a datum in NetInfo
-*/
-
-char *
-ni_map_lookup(map, name, av, statp)
- MAP *map;
- char *name;
- char **av;
- int *statp;
-{
- char *res;
- char *propval;
-
- if (tTd(38, 20))
- printf("ni_map_lookup(%s, %s)\n", map->map_mname, name);
-
- propval = ni_propval(map->map_file, map->map_keycolnm, name,
- map->map_valcolnm, map->map_coldelim);
-
- if (propval == NULL)
- return NULL;
-
- if (bitset(MF_MATCHONLY, map->map_mflags))
- res = map_rewrite(map, name, strlen(name), NULL);
- else
- res = map_rewrite(map, propval, strlen(propval), av);
- free(propval);
- return res;
-}
-
-
-bool
-ni_getcanonname(name, hbsize, statp)
- char *name;
- int hbsize;
- int *statp;
-{
- char *vptr;
- char *ptr;
- char nbuf[MAXNAME + 1];
-
- if (tTd(38, 20))
- printf("ni_getcanonname(%s)\n", name);
-
- if (strlen(name) >= sizeof nbuf)
- {
- *statp = EX_UNAVAILABLE;
- return FALSE;
- }
- (void) strcpy(nbuf, name);
- shorten_hostname(nbuf);
-
- /* we only accept single token search key */
- if (strchr(nbuf, '.'))
- {
- *statp = EX_NOHOST;
- return FALSE;
- }
-
- /* Do the search */
- vptr = ni_propval("/machines", NULL, nbuf, "name", '\n');
-
- if (vptr == NULL)
- {
- *statp = EX_NOHOST;
- return FALSE;
- }
-
- /* Only want the first machine name */
- if ((ptr = strchr(vptr, '\n')) != NULL)
- *ptr = '\0';
-
- if (hbsize >= strlen(vptr))
- {
- strcpy(name, vptr);
- *statp = EX_OK;
- return TRUE;
- }
- *statp = EX_UNAVAILABLE;
- free(vptr);
- return FALSE;
-}
-
-
-/*
-** NI_PROPVAL -- NetInfo property value lookup routine
-**
-** Parameters:
-** keydir -- the NetInfo directory name in which to search
-** for the key.
-** keyprop -- the name of the property in which to find the
-** property we are interested. Defaults to "name".
-** keyval -- the value for which we are really searching.
-** valprop -- the property name for the value in which we
-** are interested.
-** sepchar -- if non-nil, this can be multiple-valued, and
-** we should return a string separated by this
-** character.
-**
-** Returns:
-** NULL -- if:
-** 1. the directory is not found
-** 2. the property name is not found
-** 3. the property contains multiple values
-** 4. some error occured
-** else -- the value of the lookup.
-**
-** Example:
-** To search for an alias value, use:
-** ni_propval("/aliases", "name", aliasname, "members", ',')
-**
-** Notes:
-** Caller should free the return value of ni_proval
-*/
-
-# include <netinfo/ni.h>
-
-# define LOCAL_NETINFO_DOMAIN "."
-# define PARENT_NETINFO_DOMAIN ".."
-# define MAX_NI_LEVELS 256
-
-char *
-ni_propval(keydir, keyprop, keyval, valprop, sepchar)
- char *keydir;
- char *keyprop;
- char *keyval;
- char *valprop;
- int sepchar;
-{
- char *propval = NULL;
- int i;
- int j, alen;
- void *ni = NULL;
- void *lastni = NULL;
- ni_status nis;
- ni_id nid;
- ni_namelist ninl;
- register char *p;
- char keybuf[1024];
-
- /*
- ** Create the full key from the two parts.
- **
- ** Note that directory can end with, e.g., "name=" to specify
- ** an alternate search property.
- */
-
- i = strlen(keydir) + strlen(keyval) + 2;
- if (keyprop != NULL)
- i += strlen(keyprop) + 1;
- if (i > sizeof keybuf)
- return NULL;
- strcpy(keybuf, keydir);
- strcat(keybuf, "/");
- if (keyprop != NULL)
- {
- strcat(keybuf, keyprop);
- strcat(keybuf, "=");
- }
- strcat(keybuf, keyval);
-
- if (tTd(38, 21))
- printf("ni_propval(%s, %s, %s, %s, %d) keybuf='%s'\n",
- keydir, keyprop, keyval, valprop, sepchar, keybuf);
- /*
- ** If the passed directory and property name are found
- ** in one of netinfo domains we need to search (starting
- ** from the local domain moving all the way back to the
- ** root domain) set propval to the property's value
- ** and return it.
- */
-
- for (i = 0; i < MAX_NI_LEVELS && propval == NULL; i++)
- {
- if (i == 0)
- {
- nis = ni_open(NULL, LOCAL_NETINFO_DOMAIN, &ni);
- if (tTd(38, 20))
- printf("ni_open(LOCAL) = %d\n", nis);
- }
- else
- {
- if (lastni != NULL)
- ni_free(lastni);
- lastni = ni;
- nis = ni_open(lastni, PARENT_NETINFO_DOMAIN, &ni);
- if (tTd(38, 20))
- printf("ni_open(PARENT) = %d\n", nis);
- }
-
- /*
- ** Don't bother if we didn't get a handle on a
- ** proper domain. This is not necessarily an error.
- ** We would get a positive ni_status if, for instance
- ** we never found the directory or property and tried
- ** to open the parent of the root domain!
- */
-
- if (nis != 0)
- break;
-
- /*
- ** Find the path to the server information.
- */
-
- if (ni_pathsearch(ni, &nid, keybuf) != 0)
- continue;
-
- /*
- ** Find associated value information.
- */
-
- if (ni_lookupprop(ni, &nid, valprop, &ninl) != 0)
- continue;
-
- if (tTd(38, 20))
- printf("ni_lookupprop: len=%d\n", ninl.ni_namelist_len);
- /*
- ** See if we have an acceptable number of values.
- */
-
- if (ninl.ni_namelist_len <= 0)
- continue;
-
- if (sepchar == '\0' && ninl.ni_namelist_len > 1)
- {
- ni_namelist_free(&ninl);
- continue;
- }
-
- /*
- ** Calculate number of bytes needed and build result
- */
-
- alen = 1;
- for (j = 0; j < ninl.ni_namelist_len; j++)
- alen += strlen(ninl.ni_namelist_val[j]) + 1;
- propval = p = xalloc(alen);
- for (j = 0; j < ninl.ni_namelist_len; j++)
- {
- strcpy(p, ninl.ni_namelist_val[j]);
- p += strlen(p);
- *p++ = sepchar;
- }
- *--p = '\0';
-
- ni_namelist_free(&ninl);
- }
-
- /*
- ** Clean up.
- */
-
- if (ni != NULL)
- ni_free(ni);
- if (lastni != NULL && ni != lastni)
- ni_free(lastni);
- if (tTd(38, 20))
- printf("ni_propval returns: '%s'\n", propval);
-
- return propval;
-}
-
-#endif /* NETINFO */
- /*
-** TEXT (unindexed text file) Modules
-**
-** This code donated by Sun Microsystems.
-*/
-
-#define map_sff map_lockfd /* overload field */
-
-
-/*
-** TEXT_MAP_OPEN -- open text table
-*/
-
-bool
-text_map_open(map, mode)
- MAP *map;
- int mode;
-{
- int sff;
- int i;
-
- if (tTd(38, 2))
- printf("text_map_open(%s, %s, %d)\n",
- map->map_mname, map->map_file, mode);
-
- mode &= O_ACCMODE;
- if (mode != O_RDONLY)
- {
- errno = EPERM;
- return FALSE;
- }
-
- if (*map->map_file == '\0')
- {
- syserr("text map \"%s\": file name required",
- map->map_mname);
- return FALSE;
- }
-
- if (map->map_file[0] != '/')
- {
- syserr("text map \"%s\": file name must be fully qualified",
- map->map_mname);
- return FALSE;
- }
-
- sff = SFF_ROOTOK|SFF_REGONLY;
- if (!bitset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
- sff |= SFF_NOWLINK;
- if (!bitset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
- sff |= SFF_SAFEDIRPATH;
- if ((i = safefile(map->map_file, RunAsUid, RunAsGid, RunAsUserName,
- sff, S_IRUSR, NULL)) != 0)
- {
- /* cannot open this map */
- if (tTd(38, 2))
- printf("\tunsafe map file: %d\n", i);
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("text map \"%s\": unsafe map file %s",
- map->map_mname, map->map_file);
- return FALSE;
- }
-
- if (map->map_keycolnm == NULL)
- map->map_keycolno = 0;
- else
- {
- if (!(isascii(*map->map_keycolnm) && isdigit(*map->map_keycolnm)))
- {
- syserr("text map \"%s\", file %s: -k should specify a number, not %s",
- map->map_mname, map->map_file,
- map->map_keycolnm);
- return FALSE;
- }
- map->map_keycolno = atoi(map->map_keycolnm);
- }
-
- if (map->map_valcolnm == NULL)
- map->map_valcolno = 0;
- else
- {
- if (!(isascii(*map->map_valcolnm) && isdigit(*map->map_valcolnm)))
- {
- syserr("text map \"%s\", file %s: -v should specify a number, not %s",
- map->map_mname, map->map_file,
- map->map_valcolnm);
- return FALSE;
- }
- map->map_valcolno = atoi(map->map_valcolnm);
- }
-
- if (tTd(38, 2))
- {
- printf("text_map_open(%s, %s): delimiter = ",
- map->map_mname, map->map_file);
- if (map->map_coldelim == '\0')
- printf("(white space)\n");
- else
- printf("%c\n", map->map_coldelim);
- }
-
- map->map_sff = sff;
- return TRUE;
-}
-
-
-/*
-** TEXT_MAP_LOOKUP -- look up a datum in a TEXT table
-*/
-
-char *
-text_map_lookup(map, name, av, statp)
- MAP *map;
- char *name;
- char **av;
- int *statp;
-{
- char *vp;
- auto int vsize;
- int buflen;
- FILE *f;
- char delim;
- int key_idx;
- bool found_it;
- int sff = map->map_sff;
- char search_key[MAXNAME + 1];
- char linebuf[MAXLINE];
- char buf[MAXNAME + 1];
- extern char *get_column __P((char *, int, char, char *, int));
-
- found_it = FALSE;
- if (tTd(38, 20))
- printf("text_map_lookup(%s, %s)\n", map->map_mname, name);
-
- buflen = strlen(name);
- if (buflen > sizeof search_key - 1)
- buflen = sizeof search_key - 1;
- bcopy(name, search_key, buflen);
- search_key[buflen] = '\0';
- if (!bitset(MF_NOFOLDCASE, map->map_mflags))
- makelower(search_key);
-
- f = safefopen(map->map_file, O_RDONLY, FileMode, sff);
- if (f == NULL)
- {
- map->map_mflags &= ~(MF_VALID|MF_OPEN);
- *statp = EX_UNAVAILABLE;
- return NULL;
- }
- key_idx = map->map_keycolno;
- delim = map->map_coldelim;
- while (fgets(linebuf, MAXLINE, f) != NULL)
- {
- char *p;
-
- /* skip comment line */
- if (linebuf[0] == '#')
- continue;
- p = strchr(linebuf, '\n');
- if (p != NULL)
- *p = '\0';
- p = get_column(linebuf, key_idx, delim, buf, sizeof buf);
- if (p != NULL && strcasecmp(search_key, p) == 0)
- {
- found_it = TRUE;
- break;
- }
- }
- fclose(f);
- if (!found_it)
- {
- *statp = EX_NOTFOUND;
- return NULL;
- }
- vp = get_column(linebuf, map->map_valcolno, delim, buf, sizeof buf);
- if (vp == NULL)
- {
- *statp = EX_NOTFOUND;
- return NULL;
- }
- vsize = strlen(vp);
- *statp = EX_OK;
- if (bitset(MF_MATCHONLY, map->map_mflags))
- return map_rewrite(map, name, strlen(name), NULL);
- else
- return map_rewrite(map, vp, vsize, av);
-}
-
-
-/*
-** TEXT_GETCANONNAME -- look up canonical name in hosts file
-*/
-
-bool
-text_getcanonname(name, hbsize, statp)
- char *name;
- int hbsize;
- int *statp;
-{
- bool found;
- FILE *f;
- char linebuf[MAXLINE];
- char cbuf[MAXNAME + 1];
- char nbuf[MAXNAME + 1];
-
- if (tTd(38, 20))
- printf("text_getcanonname(%s)\n", name);
-
- if (strlen(name) >= (SIZE_T) sizeof nbuf)
- {
- *statp = EX_UNAVAILABLE;
- return FALSE;
- }
- (void) strcpy(nbuf, name);
- shorten_hostname(nbuf);
-
- f = fopen(HostsFile, "r");
- if (f == NULL)
- {
- *statp = EX_UNAVAILABLE;
- return FALSE;
- }
- found = FALSE;
- while (!found && fgets(linebuf, MAXLINE, f) != NULL)
- {
- char *p = strpbrk(linebuf, "#\n");
-
- if (p != NULL)
- *p = '\0';
- if (linebuf[0] != '\0')
- found = extract_canonname(nbuf, linebuf, cbuf, sizeof cbuf);
- }
- fclose(f);
- if (!found)
- {
- *statp = EX_NOHOST;
- return FALSE;
- }
-
- if ((SIZE_T) hbsize >= strlen(cbuf))
- {
- strcpy(name, cbuf);
- *statp = EX_OK;
- return TRUE;
- }
- *statp = EX_UNAVAILABLE;
- return FALSE;
-}
- /*
-** STAB (Symbol Table) Modules
-*/
-
-
-/*
-** STAB_MAP_LOOKUP -- look up alias in symbol table
-*/
-
-/* ARGSUSED2 */
-char *
-stab_map_lookup(map, name, av, pstat)
- register MAP *map;
- char *name;
- char **av;
- int *pstat;
-{
- register STAB *s;
-
- if (tTd(38, 20))
- printf("stab_lookup(%s, %s)\n",
- map->map_mname, name);
-
- s = stab(name, ST_ALIAS, ST_FIND);
- if (s != NULL)
- return (s->s_alias);
- return (NULL);
-}
-
-
-/*
-** STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
-*/
-
-void
-stab_map_store(map, lhs, rhs)
- register MAP *map;
- char *lhs;
- char *rhs;
-{
- register STAB *s;
-
- s = stab(lhs, ST_ALIAS, ST_ENTER);
- s->s_alias = newstr(rhs);
-}
-
-
-/*
-** STAB_MAP_OPEN -- initialize (reads data file)
-**
-** This is a wierd case -- it is only intended as a fallback for
-** aliases. For this reason, opens for write (only during a
-** "newaliases") always fails, and opens for read open the
-** actual underlying text file instead of the database.
-*/
-
-bool
-stab_map_open(map, mode)
- register MAP *map;
- int mode;
-{
- FILE *af;
- int sff;
- struct stat st;
-
- if (tTd(38, 2))
- printf("stab_map_open(%s, %s, %d)\n",
- map->map_mname, map->map_file, mode);
-
- mode &= O_ACCMODE;
- if (mode != O_RDONLY)
- {
- errno = EPERM;
- return FALSE;
- }
-
- sff = SFF_ROOTOK|SFF_REGONLY;
- if (!bitset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
- sff |= SFF_NOWLINK;
- if (!bitset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
- sff |= SFF_SAFEDIRPATH;
- af = safefopen(map->map_file, O_RDONLY, 0444, sff);
- if (af == NULL)
- return FALSE;
- readaliases(map, af, FALSE, FALSE);
-
- if (fstat(fileno(af), &st) >= 0)
- map->map_mtime = st.st_mtime;
- fclose(af);
-
- return TRUE;
-}
- /*
-** Implicit Modules
-**
-** Tries several types. For back compatibility of aliases.
-*/
-
-
-/*
-** IMPL_MAP_LOOKUP -- lookup in best open database
-*/
-
-char *
-impl_map_lookup(map, name, av, pstat)
- MAP *map;
- char *name;
- char **av;
- int *pstat;
-{
- if (tTd(38, 20))
- printf("impl_map_lookup(%s, %s)\n",
- map->map_mname, name);
-
-#ifdef NEWDB
- if (bitset(MF_IMPL_HASH, map->map_mflags))
- return db_map_lookup(map, name, av, pstat);
-#endif
-#ifdef NDBM
- if (bitset(MF_IMPL_NDBM, map->map_mflags))
- return ndbm_map_lookup(map, name, av, pstat);
-#endif
- return stab_map_lookup(map, name, av, pstat);
-}
-
-/*
-** IMPL_MAP_STORE -- store in open databases
-*/
-
-void
-impl_map_store(map, lhs, rhs)
- MAP *map;
- char *lhs;
- char *rhs;
-{
- if (tTd(38, 12))
- printf("impl_map_store(%s, %s, %s)\n",
- map->map_mname, lhs, rhs);
-#ifdef NEWDB
- if (bitset(MF_IMPL_HASH, map->map_mflags))
- db_map_store(map, lhs, rhs);
-#endif
-#ifdef NDBM
- if (bitset(MF_IMPL_NDBM, map->map_mflags))
- ndbm_map_store(map, lhs, rhs);
-#endif
- stab_map_store(map, lhs, rhs);
-}
-
-/*
-** IMPL_MAP_OPEN -- implicit database open
-*/
-
-bool
-impl_map_open(map, mode)
- MAP *map;
- int mode;
-{
- if (tTd(38, 2))
- printf("impl_map_open(%s, %s, %d)\n",
- map->map_mname, map->map_file, mode);
-
- mode &= O_ACCMODE;
-#ifdef NEWDB
- map->map_mflags |= MF_IMPL_HASH;
- if (hash_map_open(map, mode))
- {
-# ifdef NDBM_YP_COMPAT
- if (mode == O_RDONLY || strstr(map->map_file, "/yp/") == NULL)
-# endif
- return TRUE;
- }
- else
- map->map_mflags &= ~MF_IMPL_HASH;
-#endif
-#ifdef NDBM
- map->map_mflags |= MF_IMPL_NDBM;
- if (ndbm_map_open(map, mode))
- {
- return TRUE;
- }
- else
- map->map_mflags &= ~MF_IMPL_NDBM;
-#endif
-
-#if defined(NEWDB) || defined(NDBM)
- if (Verbose)
- message("WARNING: cannot open alias database %s%s",
- map->map_file,
- mode == O_RDONLY ? "; reading text version" : "");
-#else
- if (mode != O_RDONLY)
- usrerr("Cannot rebuild aliases: no database format defined");
-#endif
-
- if (mode == O_RDONLY)
- return stab_map_open(map, mode);
- else
- return FALSE;
-}
-
-
-/*
-** IMPL_MAP_CLOSE -- close any open database(s)
-*/
-
-void
-impl_map_close(map)
- MAP *map;
-{
- if (tTd(38, 9))
- printf("impl_map_close(%s, %s, %lx)\n",
- map->map_mname, map->map_file, map->map_mflags);
-#ifdef NEWDB
- if (bitset(MF_IMPL_HASH, map->map_mflags))
- {
- db_map_close(map);
- map->map_mflags &= ~MF_IMPL_HASH;
- }
-#endif
-
-#ifdef NDBM
- if (bitset(MF_IMPL_NDBM, map->map_mflags))
- {
- ndbm_map_close(map);
- map->map_mflags &= ~MF_IMPL_NDBM;
- }
-#endif
-}
- /*
-** User map class.
-**
-** Provides access to the system password file.
-*/
-
-/*
-** USER_MAP_OPEN -- open user map
-**
-** Really just binds field names to field numbers.
-*/
-
-bool
-user_map_open(map, mode)
- MAP *map;
- int mode;
-{
- if (tTd(38, 2))
- printf("user_map_open(%s, %d)\n",
- map->map_mname, mode);
-
- mode &= O_ACCMODE;
- if (mode != O_RDONLY)
- {
- /* issue a pseudo-error message */
-#ifdef ENOSYS
- errno = ENOSYS;
-#else
-# ifdef EFTYPE
- errno = EFTYPE;
-# else
- errno = ENXIO;
-# endif
-#endif
- return FALSE;
- }
- if (map->map_valcolnm == NULL)
- /* nothing */ ;
- else if (strcasecmp(map->map_valcolnm, "name") == 0)
- map->map_valcolno = 1;
- else if (strcasecmp(map->map_valcolnm, "passwd") == 0)
- map->map_valcolno = 2;
- else if (strcasecmp(map->map_valcolnm, "uid") == 0)
- map->map_valcolno = 3;
- else if (strcasecmp(map->map_valcolnm, "gid") == 0)
- map->map_valcolno = 4;
- else if (strcasecmp(map->map_valcolnm, "gecos") == 0)
- map->map_valcolno = 5;
- else if (strcasecmp(map->map_valcolnm, "dir") == 0)
- map->map_valcolno = 6;
- else if (strcasecmp(map->map_valcolnm, "shell") == 0)
- map->map_valcolno = 7;
- else
- {
- syserr("User map %s: unknown column name %s",
- map->map_mname, map->map_valcolnm);
- return FALSE;
- }
- return TRUE;
-}
-
-
-/*
-** USER_MAP_LOOKUP -- look up a user in the passwd file.
-*/
-
-/* ARGSUSED3 */
-char *
-user_map_lookup(map, key, av, statp)
- MAP *map;
- char *key;
- char **av;
- int *statp;
-{
- struct passwd *pw;
- auto bool fuzzy;
-
- if (tTd(38, 20))
- printf("user_map_lookup(%s, %s)\n",
- map->map_mname, key);
-
- pw = finduser(key, &fuzzy);
- if (pw == NULL)
- return NULL;
- if (bitset(MF_MATCHONLY, map->map_mflags))
- return map_rewrite(map, key, strlen(key), NULL);
- else
- {
- char *rwval = NULL;
- char buf[30];
-
- switch (map->map_valcolno)
- {
- case 0:
- case 1:
- rwval = pw->pw_name;
- break;
-
- case 2:
- rwval = pw->pw_passwd;
- break;
-
- case 3:
- snprintf(buf, sizeof buf, "%d", pw->pw_uid);
- rwval = buf;
- break;
-
- case 4:
- snprintf(buf, sizeof buf, "%d", pw->pw_gid);
- rwval = buf;
- break;
-
- case 5:
- rwval = pw->pw_gecos;
- break;
-
- case 6:
- rwval = pw->pw_dir;
- break;
-
- case 7:
- rwval = pw->pw_shell;
- break;
- }
- return map_rewrite(map, rwval, strlen(rwval), av);
- }
-}
- /*
-** Program map type.
-**
-** This provides access to arbitrary programs. It should be used
-** only very sparingly, since there is no way to bound the cost
-** of invoking an arbitrary program.
-*/
-
-char *
-prog_map_lookup(map, name, av, statp)
- MAP *map;
- char *name;
- char **av;
- int *statp;
-{
- int i;
- register char *p;
- int fd;
- auto pid_t pid;
- char *rval;
- int stat;
- char *argv[MAXPV + 1];
- char buf[MAXLINE];
-
- if (tTd(38, 20))
- printf("prog_map_lookup(%s, %s) %s\n",
- map->map_mname, name, map->map_file);
-
- i = 0;
- argv[i++] = map->map_file;
- if (map->map_rebuild != NULL)
- {
- snprintf(buf, sizeof buf, "%s", map->map_rebuild);
- for (p = strtok(buf, " \t"); p != NULL; p = strtok(NULL, " \t"))
- {
- if (i >= MAXPV - 1)
- break;
- argv[i++] = p;
- }
- }
- argv[i++] = name;
- argv[i] = NULL;
- if (tTd(38, 21))
- {
- printf("prog_open:");
- for (i = 0; argv[i] != NULL; i++)
- printf(" %s", argv[i]);
- printf("\n");
- }
- (void) blocksignal(SIGCHLD);
- pid = prog_open(argv, &fd, CurEnv);
- if (pid < 0)
- {
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("prog_map_lookup(%s) failed (%s) -- closing",
- map->map_mname, errstring(errno));
- else if (tTd(38, 9))
- printf("prog_map_lookup(%s) failed (%s) -- closing",
- map->map_mname, errstring(errno));
- map->map_mflags &= ~(MF_VALID|MF_OPEN);
- *statp = EX_OSFILE;
- return NULL;
- }
- i = read(fd, buf, sizeof buf - 1);
- if (i < 0)
- {
- syserr("prog_map_lookup(%s): read error %s\n",
- map->map_mname, errstring(errno));
- rval = NULL;
- }
- else if (i == 0)
- {
- if (tTd(38, 20))
- printf("prog_map_lookup(%s): empty answer\n",
- map->map_mname);
- rval = NULL;
- }
- else
- {
- buf[i] = '\0';
- p = strchr(buf, '\n');
- if (p != NULL)
- *p = '\0';
-
- /* collect the return value */
- if (bitset(MF_MATCHONLY, map->map_mflags))
- rval = map_rewrite(map, name, strlen(name), NULL);
- else
- rval = map_rewrite(map, buf, strlen(buf), NULL);
-
- /* now flush any additional output */
- while ((i = read(fd, buf, sizeof buf)) > 0)
- continue;
- }
-
- /* wait for the process to terminate */
- close(fd);
- stat = waitfor(pid);
- (void) releasesignal(SIGCHLD);
-
- if (stat == -1)
- {
- syserr("prog_map_lookup(%s): wait error %s\n",
- map->map_mname, errstring(errno));
- *statp = EX_SOFTWARE;
- rval = NULL;
- }
- else if (WIFEXITED(stat))
- {
- if ((*statp = WEXITSTATUS(stat)) != EX_OK)
- rval = NULL;
- }
- else
- {
- syserr("prog_map_lookup(%s): child died on signal %d",
- map->map_mname, stat);
- *statp = EX_UNAVAILABLE;
- rval = NULL;
- }
- return rval;
-}
- /*
-** Sequenced map type.
-**
-** Tries each map in order until something matches, much like
-** implicit. Stores go to the first map in the list that can
-** support storing.
-**
-** This is slightly unusual in that there are two interfaces.
-** The "sequence" interface lets you stack maps arbitrarily.
-** The "switch" interface builds a sequence map by looking
-** at a system-dependent configuration file such as
-** /etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix.
-**
-** We don't need an explicit open, since all maps are
-** opened during startup, including underlying maps.
-*/
-
-/*
-** SEQ_MAP_PARSE -- Sequenced map parsing
-*/
-
-bool
-seq_map_parse(map, ap)
- MAP *map;
- char *ap;
-{
- int maxmap;
-
- if (tTd(38, 2))
- printf("seq_map_parse(%s, %s)\n", map->map_mname, ap);
- maxmap = 0;
- while (*ap != '\0')
- {
- register char *p;
- STAB *s;
-
- /* find beginning of map name */
- while (isascii(*ap) && isspace(*ap))
- ap++;
- for (p = ap; isascii(*p) && isalnum(*p); p++)
- continue;
- if (*p != '\0')
- *p++ = '\0';
- while (*p != '\0' && (!isascii(*p) || !isalnum(*p)))
- p++;
- if (*ap == '\0')
- {
- ap = p;
- continue;
- }
- s = stab(ap, ST_MAP, ST_FIND);
- if (s == NULL)
- {
- syserr("Sequence map %s: unknown member map %s",
- map->map_mname, ap);
- }
- else if (maxmap == MAXMAPSTACK)
- {
- syserr("Sequence map %s: too many member maps (%d max)",
- map->map_mname, MAXMAPSTACK);
- maxmap++;
- }
- else if (maxmap < MAXMAPSTACK)
- {
- map->map_stack[maxmap++] = &s->s_map;
- }
- ap = p;
- }
- return TRUE;
-}
-
-
-/*
-** SWITCH_MAP_OPEN -- open a switched map
-**
-** This looks at the system-dependent configuration and builds
-** a sequence map that does the same thing.
-**
-** Every system must define a switch_map_find routine in conf.c
-** that will return the list of service types associated with a
-** given service class.
-*/
-
-bool
-switch_map_open(map, mode)
- MAP *map;
- int mode;
-{
- int mapno;
- int nmaps;
- char *maptype[MAXMAPSTACK];
-
- if (tTd(38, 2))
- printf("switch_map_open(%s, %s, %d)\n",
- map->map_mname, map->map_file, mode);
-
- mode &= O_ACCMODE;
- nmaps = switch_map_find(map->map_file, maptype, map->map_return);
- if (tTd(38, 19))
- {
- printf("\tswitch_map_find => %d\n", nmaps);
- for (mapno = 0; mapno < nmaps; mapno++)
- printf("\t\t%s\n", maptype[mapno]);
- }
- if (nmaps <= 0 || nmaps > MAXMAPSTACK)
- return FALSE;
-
- for (mapno = 0; mapno < nmaps; mapno++)
- {
- register STAB *s;
- char nbuf[MAXNAME + 1];
-
- if (maptype[mapno] == NULL)
- continue;
- (void) snprintf(nbuf, sizeof nbuf, "%s.%s",
- map->map_mname, maptype[mapno]);
- s = stab(nbuf, ST_MAP, ST_FIND);
- if (s == NULL)
- {
- syserr("Switch map %s: unknown member map %s",
- map->map_mname, nbuf);
- }
- else
- {
- map->map_stack[mapno] = &s->s_map;
- if (tTd(38, 4))
- printf("\tmap_stack[%d] = %s:%s\n",
- mapno, s->s_map.map_class->map_cname,
- nbuf);
- }
- }
- return TRUE;
-}
-
-
-/*
-** SEQ_MAP_CLOSE -- close all underlying maps
-*/
-
-void
-seq_map_close(map)
- MAP *map;
-{
- int mapno;
-
- if (tTd(38, 9))
- printf("seq_map_close(%s)\n", map->map_mname);
-
- for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
- {
- MAP *mm = map->map_stack[mapno];
-
- if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags))
- continue;
- mm->map_class->map_close(mm);
- mm->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
- }
-}
-
-
-/*
-** SEQ_MAP_LOOKUP -- sequenced map lookup
-*/
-
-char *
-seq_map_lookup(map, key, args, pstat)
- MAP *map;
- char *key;
- char **args;
- int *pstat;
-{
- int mapno;
- int mapbit = 0x01;
- bool tempfail = FALSE;
-
- if (tTd(38, 20))
- printf("seq_map_lookup(%s, %s)\n", map->map_mname, key);
-
- for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++)
- {
- MAP *mm = map->map_stack[mapno];
- char *rv;
-
- if (mm == NULL)
- continue;
- if (!bitset(MF_OPEN, mm->map_mflags))
- {
- if (bitset(mapbit, map->map_return[MA_UNAVAIL]))
- {
- *pstat = EX_UNAVAILABLE;
- return NULL;
- }
- continue;
- }
- *pstat = EX_OK;
- rv = mm->map_class->map_lookup(mm, key, args, pstat);
- if (rv != NULL)
- return rv;
- if (*pstat == EX_TEMPFAIL)
- {
- if (bitset(mapbit, map->map_return[MA_TRYAGAIN]))
- return NULL;
- tempfail = TRUE;
- }
- else if (bitset(mapbit, map->map_return[MA_NOTFOUND]))
- break;
- }
- if (tempfail)
- *pstat = EX_TEMPFAIL;
- else if (*pstat == EX_OK)
- *pstat = EX_NOTFOUND;
- return NULL;
-}
-
-
-/*
-** SEQ_MAP_STORE -- sequenced map store
-*/
-
-void
-seq_map_store(map, key, val)
- MAP *map;
- char *key;
- char *val;
-{
- int mapno;
-
- if (tTd(38, 12))
- printf("seq_map_store(%s, %s, %s)\n",
- map->map_mname, key, val);
-
- for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
- {
- MAP *mm = map->map_stack[mapno];
-
- if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags))
- continue;
-
- mm->map_class->map_store(mm, key, val);
- return;
- }
- syserr("seq_map_store(%s, %s, %s): no writable map",
- map->map_mname, key, val);
-}
- /*
-** NULL stubs
-*/
-
-/* ARGSUSED */
-bool
-null_map_open(map, mode)
- MAP *map;
- int mode;
-{
- return TRUE;
-}
-
-/* ARGSUSED */
-void
-null_map_close(map)
- MAP *map;
-{
- return;
-}
-
-char *
-null_map_lookup(map, key, args, pstat)
- MAP *map;
- char *key;
- char **args;
- int *pstat;
-{
- *pstat = EX_NOTFOUND;
- return NULL;
-}
-
-/* ARGSUSED */
-void
-null_map_store(map, key, val)
- MAP *map;
- char *key;
- char *val;
-{
- return;
-}
-
-
-/*
-** BOGUS stubs
-*/
-
-char *
-bogus_map_lookup(map, key, args, pstat)
- MAP *map;
- char *key;
- char **args;
- int *pstat;
-{
- *pstat = EX_TEMPFAIL;
- return NULL;
-}
-
-MAPCLASS BogusMapClass =
-{
- "bogus-map", NULL, 0,
- NULL, bogus_map_lookup, null_map_store,
- null_map_open, null_map_close,
-};
- /*
-** REGEX modules
-*/
-
-#ifdef MAP_REGEX
-
-# include <regex.h>
-
-# define DEFAULT_DELIM CONDELSE
-
-# define END_OF_FIELDS -1
-
-# define ERRBUF_SIZE 80
-# define MAX_MATCH 32
-
-# define xnalloc(s) memset(xalloc(s), 0, s);
-
-struct regex_map
-{
- regex_t pattern_buf; /* xalloc it */
- int *regex_subfields; /* move to type MAP */
- char *delim; /* move to type MAP */
-};
-
-static int
-parse_fields(s, ibuf, blen, nr_substrings)
- char *s;
- int *ibuf; /* array */
- int blen; /* number of elements in ibuf */
- int nr_substrings; /* number of substrings in the pattern */
-{
- register char *cp;
- int i = 0;
- bool lastone = FALSE;
-
- blen--; /* for terminating END_OF_FIELDS */
- cp = s;
- do
- {
- for (;; cp++)
- {
- if (*cp == ',')
- {
- *cp = '\0';
- break;
- }
- if (*cp == '\0')
- {
- lastone = TRUE;
- break;
- }
- }
- if (i < blen)
- {
- int val = atoi(s);
-
- if (val < 0 || val >= nr_substrings)
- {
- syserr("field (%d) out of range, only %d substrings in pattern",
- val, nr_substrings);
- return -1;
- }
- ibuf[i++] = val;
- }
- else
- {
- syserr("too many fields, %d max\n", blen);
- return -1;
- }
- s = ++cp;
- } while (!lastone);
- ibuf[i] = END_OF_FIELDS;
- return i;
-}
-
-bool
-regex_map_init(map, ap)
- MAP *map;
- char *ap;
-{
- int regerr;
- struct regex_map *map_p;
- register char *p;
- char *sub_param = NULL;
- int pflags;
- static char defdstr[] = { (char)DEFAULT_DELIM, '\0' };
-
- if (tTd(38, 2))
- printf("regex_map_init: mapname '%s', args '%s'\n",
- map->map_mname, ap);
-
- pflags = REG_ICASE | REG_EXTENDED | REG_NOSUB;
-
- p = ap;
-
- map_p = (struct regex_map *) xnalloc(sizeof(struct regex_map));
-
- for (;;)
- {
- while (isascii(*p) && isspace(*p))
- p++;
- if (*p != '-')
- break;
- switch (*++p)
- {
- case 'n': /* not */
- map->map_mflags |= MF_REGEX_NOT;
- break;
-
- case 'f': /* case sensitive */
- map->map_mflags |= MF_NOFOLDCASE;
- pflags &= ~REG_ICASE;
- break;
-
- case 'b': /* basic regular expressions */
- pflags &= ~REG_EXTENDED;
- break;
-
- case 's': /* substring match () syntax */
- sub_param = ++p;
- pflags &= ~REG_NOSUB;
- break;
-
- case 'd': /* delimiter */
- map_p->delim = ++p;
- break;
-
- case 'a': /* map append */
- map->map_app = ++p;
- break;
-
- case 'm': /* matchonly */
- map->map_mflags |= MF_MATCHONLY;
- break;
-
- }
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
- p++;
- if (*p != '\0')
- *p++ = '\0';
- }
- if (tTd(38, 3))
- printf("regex_map_init: compile '%s' 0x%x\n", p, pflags);
-
- if ((regerr = regcomp(&(map_p->pattern_buf), p, pflags)) != 0)
- {
- /* Errorhandling */
- char errbuf[ERRBUF_SIZE];
-
- regerror(regerr, &(map_p->pattern_buf), errbuf, ERRBUF_SIZE);
- syserr("pattern-compile-error: %s\n", errbuf);
- free(map_p);
- return FALSE;
- }
-
- if (map->map_app != NULL)
- map->map_app = newstr(map->map_app);
- if (map_p->delim != NULL)
- map_p->delim = newstr(map_p->delim);
- else
- map_p->delim = defdstr;
-
- if (!bitset(REG_NOSUB, pflags))
- {
- /* substring matching */
- int substrings;
- int *fields = (int *)xalloc(sizeof(int) * (MAX_MATCH + 1));
-
- substrings = map_p->pattern_buf.re_nsub + 1;
-
- if (tTd(38, 3))
- printf("regex_map_init: nr of substrings %d\n", substrings);
-
- if (substrings >= MAX_MATCH)
- {
- syserr("too many substrings, %d max\n", MAX_MATCH);
- free(map_p);
- return FALSE;
- }
- if (sub_param != NULL && sub_param[0] != '\0')
- {
- /* optional parameter -sfields */
- if (parse_fields(sub_param, fields,
- MAX_MATCH + 1, substrings) == -1)
- return FALSE;
- }
- else
- {
- /* set default fields */
- int i;
-
- for (i = 0; i < substrings; i++)
- fields[i] = i;
- fields[i] = END_OF_FIELDS;
- }
- map_p->regex_subfields = fields;
- if (tTd(38, 3))
- {
- int *ip;
-
- printf("regex_map_init: subfields");
- for (ip = fields; *ip != END_OF_FIELDS; ip++)
- printf(" %d", *ip);
- printf("\n");
- }
- }
- map->map_db1 = (ARBPTR_T)map_p; /* dirty hack */
-
- return TRUE;
-}
-
-static char *
-regex_map_rewrite(map, s, slen, av)
- MAP *map;
- const char *s;
- size_t slen;
- char **av;
-{
- if (bitset(MF_MATCHONLY, map->map_mflags))
- return map_rewrite(map, av[0], strlen(av[0]), NULL);
- else
- return map_rewrite(map, s, slen, NULL);
-}
-
-char *
-regex_map_lookup(map, name, av, statp)
- MAP *map;
- char *name;
- char **av;
- int *statp;
-{
- int reg_res;
- struct regex_map *map_p;
- regmatch_t pmatch[MAX_MATCH];
-
- if (tTd(38, 20))
- {
- char **cpp;
-
- printf("regex_map_lookup: key '%s'\n", name);
- for (cpp = av; cpp && *cpp; cpp++)
- printf("regex_map_lookup: arg '%s'\n", *cpp);
- }
-
- map_p = (struct regex_map *)(map->map_db1);
- reg_res = regexec(&(map_p->pattern_buf), name, MAX_MATCH, pmatch, 0);
-
- if (bitset(MF_REGEX_NOT, map->map_mflags))
- {
- /* option -n */
- if (reg_res == REG_NOMATCH)
- return regex_map_rewrite(map, "", (size_t)0, av);
- else
- return NULL;
- }
- if (reg_res == REG_NOMATCH)
- return NULL;
-
- if (map_p->regex_subfields != NULL)
- {
- /* option -s */
- static char retbuf[MAXNAME];
- int fields[MAX_MATCH + 1];
- bool first = TRUE;
- int anglecnt = 0, cmntcnt = 0, spacecnt = 0;
- bool quotemode = FALSE, bslashmode = FALSE;
- register char *dp, *sp;
- char *endp, *ldp;
- int *ip;
-
- dp = retbuf;
- ldp = retbuf + sizeof(retbuf) - 1;
-
- if (av[1] != NULL)
- {
- if (parse_fields(av[1], fields, MAX_MATCH + 1,
- (int) map_p->pattern_buf.re_nsub + 1) == -1)
- {
- *statp = EX_CONFIG;
- return NULL;
- }
- ip = fields;
- }
- else
- ip = map_p->regex_subfields;
-
- for ( ; *ip != END_OF_FIELDS; ip++)
- {
- if (!first)
- {
- for (sp = map_p->delim; *sp; sp++)
- {
- if (dp < ldp)
- *dp++ = *sp;
- }
- }
- else
- first = FALSE;
-
-
- if (pmatch[*ip].rm_so < 0 || pmatch[*ip].rm_eo < 0)
- continue;
-
- sp = name + pmatch[*ip].rm_so;
- endp = name + pmatch[*ip].rm_eo;
- for (; endp > sp; sp++)
- {
- if (dp < ldp)
- {
- if(bslashmode)
- {
- *dp++ = *sp;
- bslashmode = FALSE;
- }
- else if(quotemode && *sp != '"' &&
- *sp != '\\')
- {
- *dp++ = *sp;
- }
- else switch(*dp++ = *sp)
- {
- case '\\':
- bslashmode = TRUE;
- break;
-
- case '(':
- cmntcnt++;
- break;
-
- case ')':
- cmntcnt--;
- break;
-
- case '<':
- anglecnt++;
- break;
-
- case '>':
- anglecnt--;
- break;
-
- case ' ':
- spacecnt++;
- break;
-
- case '"':
- quotemode = !quotemode;
- break;
- }
- }
- }
- }
- if (anglecnt != 0 || cmntcnt != 0 || quotemode ||
- bslashmode || spacecnt != 0)
- {
- sm_syslog(LOG_WARNING, NOQID,
- "Warning: regex may cause prescan() failure map=%s lookup=%s",
- map->map_mname, name);
- return NULL;
- }
-
- *dp = '\0';
-
- return regex_map_rewrite(map, retbuf, strlen(retbuf), av);
- }
- return regex_map_rewrite(map, "", (size_t)0, av);
-}
-#endif /* MAP_REGEX */
diff --git a/src/mci.c b/src/mci.c
deleted file mode 100644
index 41649a2..0000000
--- a/src/mci.c
+++ /dev/null
@@ -1,1293 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)mci.c 8.83 (Berkeley) 10/13/1998";
-#endif /* not lint */
-
-#include "sendmail.h"
-#include <arpa/inet.h>
-#include <dirent.h>
-
-/*
-** Mail Connection Information (MCI) Caching Module.
-**
-** There are actually two separate things cached. The first is
-** the set of all open connections -- these are stored in a
-** (small) list. The second is stored in the symbol table; it
-** has the overall status for all hosts, whether or not there
-** is a connection open currently.
-**
-** There should never be too many connections open (since this
-** could flood the socket table), nor should a connection be
-** allowed to sit idly for too long.
-**
-** MaxMciCache is the maximum number of open connections that
-** will be supported.
-**
-** MciCacheTimeout is the time (in seconds) that a connection
-** is permitted to survive without activity.
-**
-** We actually try any cached connections by sending a NOOP
-** before we use them; if the NOOP fails we close down the
-** connection and reopen it. Note that this means that a
-** server SMTP that doesn't support NOOP will hose the
-** algorithm -- but that doesn't seem too likely.
-**
-** The persistent MCI code is donated by Mark Lovell and Paul
-** Vixie. It is based on the long term host status code in KJS
-** written by Paul but has been adapted by Mark to fit into the
-** MCI structure.
-*/
-
-MCI **MciCache; /* the open connection cache */
-
-extern int mci_generate_persistent_path __P((const char *, char *, int, bool));
-extern bool mci_load_persistent __P((MCI *));
-extern void mci_uncache __P((MCI **, bool));
- /*
-** MCI_CACHE -- enter a connection structure into the open connection cache
-**
-** This may cause something else to be flushed.
-**
-** Parameters:
-** mci -- the connection to cache.
-**
-** Returns:
-** none.
-*/
-
-void
-mci_cache(mci)
- register MCI *mci;
-{
- register MCI **mcislot;
-
- /*
- ** Find the best slot. This may cause expired connections
- ** to be closed.
- */
-
- mcislot = mci_scan(mci);
- if (mcislot == NULL)
- {
- /* we don't support caching */
- return;
- }
-
- if (mci->mci_host == NULL)
- return;
-
- /* if this is already cached, we are done */
- if (bitset(MCIF_CACHED, mci->mci_flags))
- return;
-
- /* otherwise we may have to clear the slot */
- if (*mcislot != NULL)
- mci_uncache(mcislot, TRUE);
-
- if (tTd(42, 5))
- printf("mci_cache: caching %lx (%s) in slot %d\n",
- (u_long) mci, mci->mci_host, (int)(mcislot - MciCache));
- if (tTd(91, 100))
- sm_syslog(LOG_DEBUG, CurEnv->e_id,
- "mci_cache: caching %x (%.100s) in slot %d",
- mci, mci->mci_host, mcislot - MciCache);
-
- *mcislot = mci;
- mci->mci_flags |= MCIF_CACHED;
-}
- /*
-** MCI_SCAN -- scan the cache, flush junk, and return best slot
-**
-** Parameters:
-** savemci -- never flush this one. Can be null.
-**
-** Returns:
-** The LRU (or empty) slot.
-*/
-
-MCI **
-mci_scan(savemci)
- MCI *savemci;
-{
- time_t now;
- register MCI **bestmci;
- register MCI *mci;
- register int i;
-
- if (MaxMciCache <= 0)
- {
- /* we don't support caching */
- return NULL;
- }
-
- if (MciCache == NULL)
- {
- /* first call */
- MciCache = (MCI **) xalloc(MaxMciCache * sizeof *MciCache);
- bzero((char *) MciCache, MaxMciCache * sizeof *MciCache);
- return (&MciCache[0]);
- }
-
- now = curtime();
- bestmci = &MciCache[0];
- for (i = 0; i < MaxMciCache; i++)
- {
- mci = MciCache[i];
- if (mci == NULL || mci->mci_state == MCIS_CLOSED)
- {
- bestmci = &MciCache[i];
- continue;
- }
- if (mci->mci_lastuse + MciCacheTimeout < now && mci != savemci)
- {
- /* connection idle too long -- close it */
- bestmci = &MciCache[i];
- mci_uncache(bestmci, TRUE);
- continue;
- }
- if (*bestmci == NULL)
- continue;
- if (mci->mci_lastuse < (*bestmci)->mci_lastuse)
- bestmci = &MciCache[i];
- }
- return bestmci;
-}
- /*
-** MCI_UNCACHE -- remove a connection from a slot.
-**
-** May close a connection.
-**
-** Parameters:
-** mcislot -- the slot to empty.
-** doquit -- if TRUE, send QUIT protocol on this connection.
-** if FALSE, we are assumed to be in a forked child;
-** all we want to do is close the file(s).
-**
-** Returns:
-** none.
-*/
-
-void
-mci_uncache(mcislot, doquit)
- register MCI **mcislot;
- bool doquit;
-{
- register MCI *mci;
- extern ENVELOPE BlankEnvelope;
-
- mci = *mcislot;
- if (mci == NULL)
- return;
- *mcislot = NULL;
- if (mci->mci_host == NULL)
- return;
-
- mci_unlock_host(mci);
-
- if (tTd(42, 5))
- printf("mci_uncache: uncaching %lx (%s) from slot %d (%d)\n",
- (u_long) mci, mci->mci_host,
- (int)(mcislot - MciCache), doquit);
- if (tTd(91, 100))
- sm_syslog(LOG_DEBUG, CurEnv->e_id,
- "mci_uncache: uncaching %x (%.100s) from slot %d (%d)",
- mci, mci->mci_host, mcislot - MciCache, doquit);
-
-#if SMTP
- if (doquit)
- {
- message("Closing connection to %s", mci->mci_host);
-
- mci->mci_flags &= ~MCIF_CACHED;
-
- /* only uses the envelope to flush the transcript file */
- if (mci->mci_state != MCIS_CLOSED)
- smtpquit(mci->mci_mailer, mci, &BlankEnvelope);
-#ifdef XLA
- xla_host_end(mci->mci_host);
-#endif
- }
- else
-#endif
- {
- if (mci->mci_in != NULL)
- xfclose(mci->mci_in, "mci_uncache", "mci_in");
- if (mci->mci_out != NULL)
- xfclose(mci->mci_out, "mci_uncache", "mci_out");
- mci->mci_in = mci->mci_out = NULL;
- mci->mci_state = MCIS_CLOSED;
- mci->mci_exitstat = EX_OK;
- mci->mci_errno = 0;
- mci->mci_flags = 0;
- }
-}
- /*
-** MCI_FLUSH -- flush the entire cache
-**
-** Parameters:
-** doquit -- if TRUE, send QUIT protocol.
-** if FALSE, just close the connection.
-** allbut -- but leave this one open.
-**
-** Returns:
-** none.
-*/
-
-void
-mci_flush(doquit, allbut)
- bool doquit;
- MCI *allbut;
-{
- register int i;
-
- if (MciCache == NULL)
- return;
-
- for (i = 0; i < MaxMciCache; i++)
- if (allbut != MciCache[i])
- mci_uncache(&MciCache[i], doquit);
-}
- /*
-** MCI_GET -- get information about a particular host
-*/
-
-MCI *
-mci_get(host, m)
- char *host;
- MAILER *m;
-{
- register MCI *mci;
- register STAB *s;
-
-#if DAEMON
- extern SOCKADDR CurHostAddr;
-
- /* clear CurHostAddr so we don't get a bogus address with this name */
- bzero(&CurHostAddr, sizeof CurHostAddr);
-#endif
-
- /* clear out any expired connections */
- (void) mci_scan(NULL);
-
- if (m->m_mno < 0)
- syserr("negative mno %d (%s)", m->m_mno, m->m_name);
- s = stab(host, ST_MCI + m->m_mno, ST_ENTER);
- mci = &s->s_mci;
- mci->mci_host = s->s_name;
-
- if (!mci_load_persistent(mci))
- {
- if (tTd(42, 2))
- printf("mci_get(%s %s): lock failed\n", host, m->m_name);
- mci->mci_exitstat = EX_TEMPFAIL;
- mci->mci_state = MCIS_CLOSED;
- mci->mci_statfile = NULL;
- return mci;
- }
-
- if (tTd(42, 2))
- {
- printf("mci_get(%s %s): mci_state=%d, _flags=%x, _exitstat=%d, _errno=%d\n",
- host, m->m_name, mci->mci_state, mci->mci_flags,
- mci->mci_exitstat, mci->mci_errno);
- }
-
-#if SMTP
- if (mci->mci_state == MCIS_OPEN)
- {
- extern int smtpprobe __P((MCI *));
-
- /* poke the connection to see if it's still alive */
- (void) smtpprobe(mci);
-
- /* reset the stored state in the event of a timeout */
- if (mci->mci_state != MCIS_OPEN)
- {
- mci->mci_errno = 0;
- mci->mci_exitstat = EX_OK;
- mci->mci_state = MCIS_CLOSED;
- }
-# if DAEMON
- else
- {
- /* get peer host address for logging reasons only */
- /* (this should really be in the mci struct) */
- SOCKADDR_LEN_T socklen = sizeof CurHostAddr;
-
- (void) getpeername(fileno(mci->mci_in),
- (struct sockaddr *) &CurHostAddr, &socklen);
- }
-# endif
- }
-#endif
- if (mci->mci_state == MCIS_CLOSED)
- {
- time_t now = curtime();
-
- /* if this info is stale, ignore it */
- if (now > mci->mci_lastuse + MciInfoTimeout)
- {
- mci->mci_lastuse = now;
- mci->mci_errno = 0;
- mci->mci_exitstat = EX_OK;
- }
- }
-
- return mci;
-}
- /*
-** MCI_SETSTAT -- set status codes in MCI structure.
-**
-** Parameters:
-** mci -- the MCI structure to set.
-** xstat -- the exit status code.
-** dstat -- the DSN status code.
-** rstat -- the SMTP status code.
-**
-** Returns:
-** none.
-*/
-
-void
-mci_setstat(mci, xstat, dstat, rstat)
- MCI *mci;
- int xstat;
- char *dstat;
- char *rstat;
-{
- /* protocol errors should never be interpreted as sticky */
- if (xstat != EX_NOTSTICKY && xstat != EX_PROTOCOL)
- mci->mci_exitstat = xstat;
-
- mci->mci_status = dstat;
- if (mci->mci_rstatus != NULL)
- free(mci->mci_rstatus);
- if (rstat != NULL)
- rstat = newstr(rstat);
- mci->mci_rstatus = rstat;
-}
- /*
-** MCI_DUMP -- dump the contents of an MCI structure.
-**
-** Parameters:
-** mci -- the MCI structure to dump.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** none.
-*/
-
-struct mcifbits
-{
- int mcif_bit; /* flag bit */
- char *mcif_name; /* flag name */
-};
-struct mcifbits MciFlags[] =
-{
- { MCIF_VALID, "VALID" },
- { MCIF_TEMP, "TEMP" },
- { MCIF_CACHED, "CACHED" },
- { MCIF_ESMTP, "ESMTP" },
- { MCIF_EXPN, "EXPN" },
- { MCIF_SIZE, "SIZE" },
- { MCIF_8BITMIME, "8BITMIME" },
- { MCIF_7BIT, "7BIT" },
- { MCIF_MULTSTAT, "MULTSTAT" },
- { MCIF_INHEADER, "INHEADER" },
- { MCIF_CVT8TO7, "CVT8TO7" },
- { MCIF_DSN, "DSN" },
- { MCIF_8BITOK, "8BITOK" },
- { MCIF_CVT7TO8, "CVT7TO8" },
- { MCIF_INMIME, "INMIME" },
- { 0, NULL }
-};
-
-
-void
-mci_dump(mci, logit)
- register MCI *mci;
- bool logit;
-{
- register char *p;
- char *sep;
- char buf[4000];
- extern char *ctime();
-
- sep = logit ? " " : "\n\t";
- p = buf;
- snprintf(p, SPACELEFT(buf, p), "MCI@%x: ", mci);
- p += strlen(p);
- if (mci == NULL)
- {
- snprintf(p, SPACELEFT(buf, p), "NULL");
- goto printit;
- }
- snprintf(p, SPACELEFT(buf, p), "flags=%x", mci->mci_flags);
- p += strlen(p);
- if (mci->mci_flags != 0)
- {
- struct mcifbits *f;
-
- *p++ = '<';
- for (f = MciFlags; f->mcif_bit != 0; f++)
- {
- if (!bitset(f->mcif_bit, mci->mci_flags))
- continue;
- snprintf(p, SPACELEFT(buf, p), "%s,", f->mcif_name);
- p += strlen(p);
- }
- p[-1] = '>';
- }
- snprintf(p, SPACELEFT(buf, p),
- ",%serrno=%d, herrno=%d, exitstat=%d, state=%d, pid=%d,%s",
- sep, mci->mci_errno, mci->mci_herrno,
- mci->mci_exitstat, mci->mci_state, mci->mci_pid, sep);
- p += strlen(p);
- snprintf(p, SPACELEFT(buf, p),
- "maxsize=%ld, phase=%s, mailer=%s,%s",
- mci->mci_maxsize,
- mci->mci_phase == NULL ? "NULL" : mci->mci_phase,
- mci->mci_mailer == NULL ? "NULL" : mci->mci_mailer->m_name,
- sep);
- p += strlen(p);
- snprintf(p, SPACELEFT(buf, p),
- "status=%s, rstatus=%s,%s",
- mci->mci_status == NULL ? "NULL" : mci->mci_status,
- mci->mci_rstatus == NULL ? "NULL" : mci->mci_rstatus,
- sep);
- p += strlen(p);
- snprintf(p, SPACELEFT(buf, p),
- "host=%s, lastuse=%s",
- mci->mci_host == NULL ? "NULL" : mci->mci_host,
- ctime(&mci->mci_lastuse));
-printit:
- if (logit)
- sm_syslog(LOG_DEBUG, CurEnv->e_id, "%.1000s", buf);
- else
- printf("%s\n", buf);
-}
- /*
-** MCI_DUMP_ALL -- print the entire MCI cache
-**
-** Parameters:
-** logit -- if set, log the result instead of printing
-** to stdout.
-**
-** Returns:
-** none.
-*/
-
-void
-mci_dump_all(logit)
- bool logit;
-{
- register int i;
-
- if (MciCache == NULL)
- return;
-
- for (i = 0; i < MaxMciCache; i++)
- mci_dump(MciCache[i], logit);
-}
- /*
-** MCI_LOCK_HOST -- Lock host while sending.
-**
-** If we are contacting a host, we'll need to
-** update the status information in the host status
-** file, and if we want to do that, we ought to have
-** locked it. This has the (according to some)
-** desirable effect of serializing connectivity with
-** remote hosts -- i.e.: one connection to a give
-** host at a time.
-**
-** Parameters:
-** mci -- containing the host we want to lock.
-**
-** Returns:
-** EX_OK -- got the lock.
-** EX_TEMPFAIL -- didn't get the lock.
-*/
-
-int
-mci_lock_host(mci)
- MCI *mci;
-{
- if (mci == NULL)
- {
- if (tTd(56, 1))
- printf("mci_lock_host: NULL mci\n");
- return EX_OK;
- }
-
- if (!SingleThreadDelivery)
- return EX_OK;
-
- return mci_lock_host_statfile(mci);
-}
-
-int
-mci_lock_host_statfile(mci)
- MCI *mci;
-{
- int savedErrno = errno;
- int retVal = EX_OK;
- char fname[MAXPATHLEN+1];
-
- if (HostStatDir == NULL || mci->mci_host == NULL)
- return EX_OK;
-
- if (tTd(56, 2))
- printf("mci_lock_host: attempting to lock %s\n",
- mci->mci_host);
-
- if (mci_generate_persistent_path(mci->mci_host, fname, sizeof fname, TRUE) < 0)
- {
- /* of course this should never happen */
- if (tTd(56, 2))
- printf("mci_lock_host: Failed to generate host path for %s\n",
- mci->mci_host);
-
- retVal = EX_TEMPFAIL;
- goto cleanup;
- }
-
- mci->mci_statfile = safefopen(fname, O_RDWR, FileMode,
- SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH|SFF_CREAT);
-
- if (mci->mci_statfile == NULL)
- {
- syserr("mci_lock_host: cannot create host lock file %s",
- fname);
- goto cleanup;
- }
-
- if (!lockfile(fileno(mci->mci_statfile), fname, "", LOCK_EX|LOCK_NB))
- {
- if (tTd(56, 2))
- printf("mci_lock_host: couldn't get lock on %s\n",
- fname);
- fclose(mci->mci_statfile);
- mci->mci_statfile = NULL;
- retVal = EX_TEMPFAIL;
- goto cleanup;
- }
-
- if (tTd(56, 12) && mci->mci_statfile != NULL)
- printf("mci_lock_host: Sanity check -- lock is good\n");
-
-cleanup:
- errno = savedErrno;
- return retVal;
-}
- /*
-** MCI_UNLOCK_HOST -- unlock host
-**
-** Clean up the lock on a host, close the file, let
-** someone else use it.
-**
-** Parameters:
-** mci -- us.
-**
-** Returns:
-** nothing.
-*/
-
-void
-mci_unlock_host(mci)
- MCI *mci;
-{
- int saveErrno = errno;
-
- if (mci == NULL)
- {
- if (tTd(56, 1))
- printf("mci_unlock_host: NULL mci\n");
- return;
- }
-
- if (HostStatDir == NULL || mci->mci_host == NULL)
- return;
-
- if (!SingleThreadDelivery && mci_lock_host_statfile(mci) == EX_TEMPFAIL)
- {
- if (tTd(56, 1))
- printf("mci_unlock_host: stat file already locked\n");
- }
- else
- {
- if (tTd(56, 2))
- printf("mci_unlock_host: store prior to unlock\n");
-
- mci_store_persistent(mci);
- }
-
- if (mci->mci_statfile != NULL)
- {
- fclose(mci->mci_statfile);
- mci->mci_statfile = NULL;
- }
-
- errno = saveErrno;
-}
- /*
-** MCI_LOAD_PERSISTENT -- load persistent host info
-**
-** Load information about host that is kept
-** in common for all running sendmails.
-**
-** Parameters:
-** mci -- the host/connection to load persistent info
-** for.
-**
-** Returns:
-** TRUE -- lock was successful
-** FALSE -- lock failed
-*/
-
-bool
-mci_load_persistent(mci)
- MCI *mci;
-{
- int saveErrno = errno;
- bool locked = TRUE;
- FILE *fp;
- char fname[MAXPATHLEN+1];
-
- if (mci == NULL)
- {
- if (tTd(56, 1))
- printf("mci_load_persistent: NULL mci\n");
- return TRUE;
- }
-
- if (IgnoreHostStatus || HostStatDir == NULL || mci->mci_host == NULL)
- return TRUE;
-
- /* Already have the persistent information in memory */
- if (SingleThreadDelivery && mci->mci_statfile != NULL)
- return TRUE;
-
- if (tTd(56, 1))
- printf("mci_load_persistent: Attempting to load persistent information for %s\n",
- mci->mci_host);
-
- if (mci_generate_persistent_path(mci->mci_host, fname, sizeof fname, FALSE) < 0)
- {
- /* Not much we can do if the file isn't there... */
- if (tTd(56, 1))
- printf("mci_load_persistent: Couldn't generate host path\n");
- goto cleanup;
- }
-
- fp = safefopen(fname, O_RDONLY, FileMode,
- SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH);
- if (fp == NULL)
- {
- /* I can't think of any reason this should ever happen */
- if (tTd(56, 1))
- printf("mci_load_persistent: open(%s): %s\n",
- fname, errstring(errno));
- goto cleanup;
- }
-
- FileName = fname;
- locked = lockfile(fileno(fp), fname, "", LOCK_SH|LOCK_NB);
- (void) mci_read_persistent(fp, mci);
- FileName = NULL;
- if (locked)
- lockfile(fileno(fp), fname, "", LOCK_UN);
- fclose(fp);
-
-cleanup:
- errno = saveErrno;
- return locked;
-}
- /*
-** MCI_READ_PERSISTENT -- read persistent host status file
-**
-** Parameters:
-** fp -- the file pointer to read.
-** mci -- the pointer to fill in.
-**
-** Returns:
-** -1 -- if the file was corrupt.
-** 0 -- otherwise.
-**
-** Warning:
-** This code makes the assumption that this data
-** will be read in an atomic fashion, and that the data
-** was written in an atomic fashion. Any other functioning
-** may lead to some form of insanity. This should be
-** perfectly safe due to underlying stdio buffering.
-*/
-
-int
-mci_read_persistent(fp, mci)
- FILE *fp;
- register MCI *mci;
-{
- int ver;
- register char *p;
- int saveLineNumber = LineNumber;
- char buf[MAXLINE];
-
- if (fp == NULL)
- syserr("mci_read_persistent: NULL fp");
- if (mci == NULL)
- syserr("mci_read_persistent: NULL mci");
- if (tTd(56, 93))
- {
- printf("mci_read_persistent: fp=%lx, mci=", (u_long) fp);
- mci_dump(mci, FALSE);
- }
-
- mci->mci_status = NULL;
- if (mci->mci_rstatus != NULL)
- free(mci->mci_rstatus);
- mci->mci_rstatus = NULL;
-
- rewind(fp);
- ver = -1;
- LineNumber = 0;
- while (fgets(buf, sizeof buf, fp) != NULL)
- {
- LineNumber++;
- p = strchr(buf, '\n');
- if (p != NULL)
- *p = '\0';
- switch (buf[0])
- {
- case 'V': /* version stamp */
- ver = atoi(&buf[1]);
- if (ver < 0 || ver > 0)
- syserr("Unknown host status version %d: %d max",
- ver, 0);
- break;
-
- case 'E': /* UNIX error number */
- mci->mci_errno = atoi(&buf[1]);
- break;
-
- case 'H': /* DNS error number */
- mci->mci_herrno = atoi(&buf[1]);
- break;
-
- case 'S': /* UNIX exit status */
- mci->mci_exitstat = atoi(&buf[1]);
- break;
-
- case 'D': /* DSN status */
- mci->mci_status = newstr(&buf[1]);
- break;
-
- case 'R': /* SMTP status */
- mci->mci_rstatus = newstr(&buf[1]);
- break;
-
- case 'U': /* last usage time */
- mci->mci_lastuse = atol(&buf[1]);
- break;
-
- case '.': /* end of file */
- return 0;
-
- default:
- sm_syslog(LOG_CRIT, NOQID,
- "%s: line %d: Unknown host status line \"%s\"",
- FileName == NULL ? mci->mci_host : FileName,
- LineNumber, buf);
- LineNumber = saveLineNumber;
- return -1;
- }
- }
- LineNumber = saveLineNumber;
- if (ver < 0)
- return -1;
- return 0;
-}
- /*
-** MCI_STORE_PERSISTENT -- Store persistent MCI information
-**
-** Store information about host that is kept
-** in common for all running sendmails.
-**
-** Parameters:
-** mci -- the host/connection to store persistent info for.
-**
-** Returns:
-** none.
-*/
-
-void
-mci_store_persistent(mci)
- MCI *mci;
-{
- int saveErrno = errno;
-
- if (mci == NULL)
- {
- if (tTd(56, 1))
- printf("mci_store_persistent: NULL mci\n");
- return;
- }
-
- if (HostStatDir == NULL || mci->mci_host == NULL)
- return;
-
- if (tTd(56, 1))
- printf("mci_store_persistent: Storing information for %s\n",
- mci->mci_host);
-
- if (mci->mci_statfile == NULL)
- {
- if (tTd(56, 1))
- printf("mci_store_persistent: no statfile\n");
- return;
- }
-
- rewind(mci->mci_statfile);
-#if !NOFTRUNCATE
- (void) ftruncate(fileno(mci->mci_statfile), (off_t) 0);
-#endif
-
- fprintf(mci->mci_statfile, "V0\n");
- fprintf(mci->mci_statfile, "E%d\n", mci->mci_errno);
- fprintf(mci->mci_statfile, "H%d\n", mci->mci_herrno);
- fprintf(mci->mci_statfile, "S%d\n", mci->mci_exitstat);
- if (mci->mci_status != NULL)
- fprintf(mci->mci_statfile, "D%.80s\n",
- denlstring(mci->mci_status, TRUE, FALSE));
- if (mci->mci_rstatus != NULL)
- fprintf(mci->mci_statfile, "R%.80s\n",
- denlstring(mci->mci_rstatus, TRUE, FALSE));
- fprintf(mci->mci_statfile, "U%ld\n", (long)(mci->mci_lastuse));
- fprintf(mci->mci_statfile, ".\n");
-
- fflush(mci->mci_statfile);
-
- errno = saveErrno;
- return;
-}
- /*
-** MCI_TRAVERSE_PERSISTENT -- walk persistent status tree
-**
-** Recursively find all the mci host files in `pathname'. Default to
-** main host status directory if no path is provided.
-** Call (*action)(pathname, host) for each file found.
-**
-** Note: all information is collected in a list before it is processed.
-** This may not be the best way to do it, but it seems safest, since
-** the file system would be touched while we are attempting to traverse
-** the directory tree otherwise (during purges).
-**
-** Parameters:
-** action -- function to call on each node. If returns < 0,
-** return immediately.
-** pathname -- root of tree. If null, use main host status
-** directory.
-**
-** Returns:
-** < 0 -- if any action routine returns a negative value, that
-** value is returned.
-** 0 -- if we successfully went to completion.
-*/
-
-int
-mci_traverse_persistent(action, pathname)
- int (*action)();
- char *pathname;
-{
- struct stat statbuf;
- DIR *d;
- int ret;
-
- if (pathname == NULL)
- pathname = HostStatDir;
- if (pathname == NULL)
- return -1;
-
- if (tTd(56, 1))
- printf("mci_traverse: pathname is %s\n", pathname);
-
- ret = stat(pathname, &statbuf);
- if (ret < 0)
- {
- if (tTd(56, 2))
- printf("mci_traverse: Failed to stat %s: %s\n",
- pathname, errstring(errno));
- return ret;
- }
- if (S_ISDIR(statbuf.st_mode))
- {
- struct dirent *e;
- char *newptr;
- char newpath[MAXPATHLEN+1];
-
- if ((d = opendir(pathname)) == NULL)
- {
- if (tTd(56, 2))
- printf("mci_traverse: opendir %s: %s\n",
- pathname, errstring(errno));
- return -1;
- }
-
- if (strlen(pathname) >= sizeof newpath - MAXNAMLEN - 3)
- {
- if (tTd(56, 2))
- printf("mci_traverse: path \"%s\" too long",
- pathname);
- return -1;
- }
- strcpy(newpath, pathname);
- newptr = newpath + strlen(newpath);
- *newptr++ = '/';
-
- while ((e = readdir(d)) != NULL)
- {
- if (e->d_name[0] == '.')
- continue;
-
- strncpy(newptr, e->d_name,
- sizeof newpath - (newptr - newpath) - 1);
- newpath[sizeof newpath - 1] = '\0';
-
- ret = mci_traverse_persistent(action, newpath);
- if (ret < 0)
- break;
-
- /*
- ** The following appears to be
- ** necessary during purges, since
- ** we modify the directory structure
- */
-
- if (action == mci_purge_persistent)
- rewinddir(d);
- }
-
- /* purge (or whatever) the directory proper */
- *--newptr = '\0';
- ret = (*action)(newpath, NULL);
- closedir(d);
- }
- else if (S_ISREG(statbuf.st_mode))
- {
- char *end = pathname + strlen(pathname) - 1;
- char *start;
- char *scan;
- char host[MAXHOSTNAMELEN];
- char *hostptr = host;
-
- /*
- ** Reconstruct the host name from the path to the
- ** persistent information.
- */
-
- do
- {
- if (hostptr != host)
- *(hostptr++) = '.';
- start = end;
- while (*(start - 1) != '/')
- start--;
-
- if (*end == '.')
- end--;
-
- for (scan = start; scan <= end; scan++)
- *(hostptr++) = *scan;
-
- end = start - 2;
- } while (*end == '.');
-
- *hostptr = '\0';
-
- /*
- ** Do something with the file containing the persistent
- ** information.
- */
- ret = (*action)(pathname, host);
- }
-
- return ret;
-}
- /*
-** MCI_PRINT_PERSISTENT -- print persisten info
-**
-** Dump the persistent information in the file 'pathname'
-**
-** Parameters:
-** pathname -- the pathname to the status file.
-** hostname -- the corresponding host name.
-**
-** Returns:
-** 0
-*/
-
-int
-mci_print_persistent(pathname, hostname)
- char *pathname;
- char *hostname;
-{
- static int initflag = FALSE;
- FILE *fp;
- int width = Verbose ? 78 : 25;
- bool locked;
- MCI mcib;
-
- /* skip directories */
- if (hostname == NULL)
- return 0;
-
- if (!initflag)
- {
- initflag = TRUE;
- printf(" -------------- Hostname --------------- How long ago ---------Results---------\n");
- }
-
- fp = safefopen(pathname, O_RDWR, FileMode,
- SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH);
-
- if (fp == NULL)
- {
- if (tTd(56, 1))
- printf("mci_print_persistent: cannot open %s: %s\n",
- pathname, errstring(errno));
- return 0;
- }
-
- FileName = pathname;
- bzero(&mcib, sizeof mcib);
- if (mci_read_persistent(fp, &mcib) < 0)
- {
- syserr("%s: could not read status file", pathname);
- fclose(fp);
- FileName = NULL;
- return 0;
- }
-
- locked = !lockfile(fileno(fp), pathname, "", LOCK_EX|LOCK_NB);
- fclose(fp);
- FileName = NULL;
-
- printf("%c%-39s %12s ",
- locked ? '*' : ' ', hostname,
- pintvl(curtime() - mcib.mci_lastuse, TRUE));
- if (mcib.mci_rstatus != NULL)
- printf("%.*s\n", width, mcib.mci_rstatus);
- else if (mcib.mci_exitstat == EX_TEMPFAIL && mcib.mci_errno != 0)
- printf("Deferred: %.*s\n", width - 10, errstring(mcib.mci_errno));
- else if (mcib.mci_exitstat != 0)
- {
- int i = mcib.mci_exitstat - EX__BASE;
- extern int N_SysEx;
- extern char *SysExMsg[];
-
- if (i < 0 || i >= N_SysEx)
- {
- char buf[80];
-
- snprintf(buf, sizeof buf, "Unknown mailer error %d",
- mcib.mci_exitstat);
- printf("%.*s\n", width, buf);
- }
- else
- printf("%.*s\n", width, &(SysExMsg[i])[5]);
- }
- else if (mcib.mci_errno == 0)
- printf("OK\n");
- else
- printf("OK: %.*s\n", width - 4, errstring(mcib.mci_errno));
-
- return 0;
-}
- /*
-** MCI_PURGE_PERSISTENT -- Remove a persistence status file.
-**
-** Parameters:
-** pathname -- path to the status file.
-** hostname -- name of host corresponding to that file.
-** NULL if this is a directory (domain).
-**
-** Returns:
-** 0
-*/
-
-int
-mci_purge_persistent(pathname, hostname)
- char *pathname;
- char *hostname;
-{
- char *end = pathname + strlen(pathname) - 1;
-
- if (tTd(56, 1))
- printf("mci_purge_persistent: purging %s\n", pathname);
-
- if (hostname != NULL)
- {
- /* remove the file */
- if (unlink(pathname) < 0)
- {
- if (tTd(56, 2))
- printf("mci_purge_persistent: failed to unlink %s: %s\n",
- pathname, errstring(errno));
- }
- }
- else
- {
- /* remove the directory */
- if (*end != '.')
- return 0;
-
- if (tTd(56, 1))
- printf("mci_purge_persistent: dpurge %s\n", pathname);
-
- if (rmdir(pathname) < 0)
- {
- if (tTd(56, 2))
- printf("mci_purge_persistent: rmdir %s: %s\n",
- pathname, errstring(errno));
- }
-
- }
-
- return 0;
-}
- /*
-** MCI_GENERATE_PERSISTENT_PATH -- generate path from hostname
-**
-** Given `host', convert from a.b.c to $QueueDir/.hoststat/c./b./a,
-** putting the result into `path'. if `createflag' is set, intervening
-** directories will be created as needed.
-**
-** Parameters:
-** host -- host name to convert from.
-** path -- place to store result.
-** pathlen -- length of path buffer.
-** createflag -- if set, create intervening directories as
-** needed.
-**
-** Returns:
-** 0 -- success
-** -1 -- failure
-*/
-
-int
-mci_generate_persistent_path(host, path, pathlen, createflag)
- const char *host;
- char *path;
- int pathlen;
- bool createflag;
-{
- char *elem, *p, *x, ch;
- int ret = 0;
- int len;
- char t_host[MAXHOSTNAMELEN];
-
- /*
- ** Rationality check the arguments.
- */
-
- if (host == NULL)
- {
- syserr("mci_generate_persistent_path: null host");
- return -1;
- }
- if (path == NULL)
- {
- syserr("mci_generate_persistent_path: null path");
- return -1;
- }
-
- if (tTd(56, 80))
- printf("mci_generate_persistent_path(%s): ", host);
-
- if (*host == '\0' || *host == '.')
- return -1;
-
- /* make certain this is not a bracketed host number */
- if (strlen(host) > sizeof t_host - 1)
- return -1;
- if (host[0] == '[')
- strcpy(t_host, host + 1);
- else
- strcpy(t_host, host);
-
- /*
- ** Delete any trailing dots from the hostname.
- ** Leave 'elem' pointing at the \0.
- */
-
- elem = t_host + strlen(t_host);
- while (elem > t_host &&
- (elem[-1] == '.' || (host[0] == '[' && elem[-1] == ']')))
- *--elem = '\0';
-
- /* check for bogus bracketed address */
- if (host[0] == '[' && inet_addr(t_host) == INADDR_NONE)
- return -1;
-
- /* check for what will be the final length of the path */
- len = strlen(HostStatDir) + 2;
- for (p = (char *) t_host; *p != '\0'; p++)
- {
- if (*p == '.')
- len++;
- len++;
- if (p[0] == '.' && p[1] == '.')
- return -1;
- }
- if (len > pathlen || len < 1)
- return -1;
-
- strcpy(path, HostStatDir);
- p = path + strlen(path);
-
- while (elem > t_host)
- {
- if (!path_is_dir(path, createflag))
- {
- ret = -1;
- break;
- }
- elem--;
- while (elem >= t_host && *elem != '.')
- elem--;
- *p++ = '/';
- x = elem + 1;
- while ((ch = *x++) != '\0' && ch != '.')
- {
- if (isascii(ch) && isupper(ch))
- ch = tolower(ch);
- if (ch == '/')
- ch = ':'; /* / -> : */
- *p++ = ch;
- }
- if (elem >= t_host)
- *p++ = '.';
- *p = '\0';
- }
-
- if (tTd(56, 80))
- {
- if (ret < 0)
- printf("FAILURE %d\n", ret);
- else
- printf("SUCCESS %s\n", path);
- }
-
- return (ret);
-}
diff --git a/src/mime.c b/src/mime.c
deleted file mode 100644
index aea8f7e..0000000
--- a/src/mime.c
+++ /dev/null
@@ -1,1190 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1994, 1996-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1994
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-# include "sendmail.h"
-# include <string.h>
-
-#ifndef lint
-static char sccsid[] = "@(#)mime.c 8.71 (Berkeley) 1/18/1999";
-#endif /* not lint */
-
-/*
-** MIME support.
-**
-** I am indebted to John Beck of Hewlett-Packard, who contributed
-** his code to me for inclusion. As it turns out, I did not use
-** his code since he used a "minimum change" approach that used
-** several temp files, and I wanted a "minimum impact" approach
-** that would avoid copying. However, looking over his code
-** helped me cement my understanding of the problem.
-**
-** I also looked at, but did not directly use, Nathaniel
-** Borenstein's "code.c" module. Again, it functioned as
-** a file-to-file translator, which did not fit within my
-** design bounds, but it was a useful base for understanding
-** the problem.
-*/
-
-#if MIME8TO7
-
-/* character set for hex and base64 encoding */
-char Base16Code[] = "0123456789ABCDEF";
-char Base64Code[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-/* types of MIME boundaries */
-#define MBT_SYNTAX 0 /* syntax error */
-#define MBT_NOTSEP 1 /* not a boundary */
-#define MBT_INTERMED 2 /* intermediate boundary (no trailing --) */
-#define MBT_FINAL 3 /* final boundary (trailing -- included) */
-
-static char *MimeBoundaryNames[] =
-{
- "SYNTAX", "NOTSEP", "INTERMED", "FINAL"
-};
-
-bool MapNLtoCRLF;
-
-extern int mimeboundary __P((char *, char **));
- /*
-** MIME8TO7 -- output 8 bit body in 7 bit format
-**
-** The header has already been output -- this has to do the
-** 8 to 7 bit conversion. It would be easy if we didn't have
-** to deal with nested formats (multipart/xxx and message/rfc822).
-**
-** We won't be called if we don't have to do a conversion, and
-** appropriate MIME-Version: and Content-Type: fields have been
-** output. Any Content-Transfer-Encoding: field has not been
-** output, and we can add it here.
-**
-** Parameters:
-** mci -- mailer connection information.
-** header -- the header for this body part.
-** e -- envelope.
-** boundaries -- the currently pending message boundaries.
-** NULL if we are processing the outer portion.
-** flags -- to tweak processing.
-**
-** Returns:
-** An indicator of what terminated the message part:
-** MBT_FINAL -- the final boundary
-** MBT_INTERMED -- an intermediate boundary
-** MBT_NOTSEP -- an end of file
-*/
-
-struct args
-{
- char *field; /* name of field */
- char *value; /* value of that field */
-};
-
-int
-mime8to7(mci, header, e, boundaries, flags)
- register MCI *mci;
- HDR *header;
- register ENVELOPE *e;
- char **boundaries;
- int flags;
-{
- register char *p;
- int linelen;
- int bt;
- off_t offset;
- size_t sectionsize, sectionhighbits;
- int i;
- char *type;
- char *subtype;
- char *cte;
- char **pvp;
- int argc = 0;
- char *bp;
- bool use_qp = FALSE;
- struct args argv[MAXMIMEARGS];
- char bbuf[128];
- char buf[MAXLINE];
- char pvpbuf[MAXLINE];
- extern u_char MimeTokenTab[256];
- extern int mime_getchar __P((FILE *, char **, int *));
- extern int mime_getchar_crlf __P((FILE *, char **, int *));
-
- if (tTd(43, 1))
- {
- printf("mime8to7: flags = %x, boundaries =", flags);
- if (boundaries[0] == NULL)
- printf(" <none>");
- else
- {
- for (i = 0; boundaries[i] != NULL; i++)
- printf(" %s", boundaries[i]);
- }
- printf("\n");
- }
- MapNLtoCRLF = TRUE;
- p = hvalue("Content-Transfer-Encoding", header);
- if (p == NULL ||
- (pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL,
- MimeTokenTab)) == NULL ||
- pvp[0] == NULL)
- {
- cte = NULL;
- }
- else
- {
- cataddr(pvp, NULL, buf, sizeof buf, '\0');
- cte = newstr(buf);
- }
-
- type = subtype = NULL;
- p = hvalue("Content-Type", header);
- if (p == NULL)
- {
- if (bitset(M87F_DIGEST, flags))
- p = "message/rfc822";
- else
- p = "text/plain";
- }
- if (p != NULL &&
- (pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL,
- MimeTokenTab)) != NULL &&
- pvp[0] != NULL)
- {
- if (tTd(43, 40))
- {
- for (i = 0; pvp[i] != NULL; i++)
- printf("pvp[%d] = \"%s\"\n", i, pvp[i]);
- }
- type = *pvp++;
- if (*pvp != NULL && strcmp(*pvp, "/") == 0 &&
- *++pvp != NULL)
- {
- subtype = *pvp++;
- }
-
- /* break out parameters */
- while (*pvp != NULL && argc < MAXMIMEARGS)
- {
- /* skip to semicolon separator */
- while (*pvp != NULL && strcmp(*pvp, ";") != 0)
- pvp++;
- if (*pvp++ == NULL || *pvp == NULL)
- break;
-
- /* extract field name */
- argv[argc].field = *pvp++;
-
- /* see if there is a value */
- if (*pvp != NULL && strcmp(*pvp, "=") == 0 &&
- (*++pvp == NULL || strcmp(*pvp, ";") != 0))
- {
- argv[argc].value = *pvp;
- argc++;
- }
- }
- }
-
- /* check for disaster cases */
- if (type == NULL)
- type = "-none-";
- if (subtype == NULL)
- subtype = "-none-";
-
- /* don't propogate some flags more than one level into the message */
- flags &= ~M87F_DIGEST;
-
- /*
- ** Check for cases that can not be encoded.
- **
- ** For example, you can't encode certain kinds of types
- ** or already-encoded messages. If we find this case,
- ** just copy it through.
- */
-
- snprintf(buf, sizeof buf, "%.100s/%.100s", type, subtype);
- if (wordinclass(buf, 'n') || (cte != NULL && !wordinclass(cte, 'e')))
- flags |= M87F_NO8BIT;
-
-#ifdef USE_B_CLASS
- if (wordinclass(buf, 'b') || wordinclass(type, 'b'))
- MapNLtoCRLF = FALSE;
-#endif
- if (wordinclass(buf, 'q') || wordinclass(type, 'q'))
- use_qp = TRUE;
-
- /*
- ** Multipart requires special processing.
- **
- ** Do a recursive descent into the message.
- */
-
- if (strcasecmp(type, "multipart") == 0 &&
- (!bitset(M87F_NO8BIT, flags) || bitset(M87F_NO8TO7, flags)))
- {
- int blen;
-
- if (strcasecmp(subtype, "digest") == 0)
- flags |= M87F_DIGEST;
-
- for (i = 0; i < argc; i++)
- {
- if (strcasecmp(argv[i].field, "boundary") == 0)
- break;
- }
- if (i >= argc || argv[i].value == NULL)
- {
- syserr("mime8to7: Content-Type: \"%s\": %s boundary",
- i >= argc ? "missing" : "bogus", p);
- p = "---";
-
- /* avoid bounce loops */
- e->e_flags |= EF_DONT_MIME;
- }
- else
- {
- p = argv[i].value;
- stripquotes(p);
- }
- blen = strlen(p);
- if (blen > sizeof bbuf - 1)
- {
- syserr("mime8to7: multipart boundary \"%s\" too long",
- p);
- blen = sizeof bbuf - 1;
-
- /* avoid bounce loops */
- e->e_flags |= EF_DONT_MIME;
- }
- strncpy(bbuf, p, blen);
- bbuf[blen] = '\0';
- if (tTd(43, 1))
- printf("mime8to7: multipart boundary \"%s\"\n", bbuf);
- for (i = 0; i < MAXMIMENESTING; i++)
- if (boundaries[i] == NULL)
- break;
- if (i >= MAXMIMENESTING)
- {
- syserr("mime8to7: multipart nesting boundary too deep");
-
- /* avoid bounce loops */
- e->e_flags |= EF_DONT_MIME;
- }
- else
- {
- boundaries[i] = bbuf;
- boundaries[i + 1] = NULL;
- }
- mci->mci_flags |= MCIF_INMIME;
-
- /* skip the early "comment" prologue */
- putline("", mci);
- mci->mci_flags &= ~MCIF_INHEADER;
- while (fgets(buf, sizeof buf, e->e_dfp) != NULL)
- {
- bt = mimeboundary(buf, boundaries);
- if (bt != MBT_NOTSEP)
- break;
- putxline(buf, strlen(buf), mci, PXLF_MAPFROM|PXLF_STRIP8BIT);
- if (tTd(43, 99))
- printf(" ...%s", buf);
- }
- if (feof(e->e_dfp))
- bt = MBT_FINAL;
- while (bt != MBT_FINAL)
- {
- auto HDR *hdr = NULL;
-
- snprintf(buf, sizeof buf, "--%s", bbuf);
- putline(buf, mci);
- if (tTd(43, 35))
- printf(" ...%s\n", buf);
- collect(e->e_dfp, FALSE, &hdr, e);
- if (tTd(43, 101))
- putline("+++after collect", mci);
- putheader(mci, hdr, e, flags);
- if (tTd(43, 101))
- putline("+++after putheader", mci);
- bt = mime8to7(mci, hdr, e, boundaries, flags);
- }
- snprintf(buf, sizeof buf, "--%s--", bbuf);
- putline(buf, mci);
- if (tTd(43, 35))
- printf(" ...%s\n", buf);
- boundaries[i] = NULL;
- mci->mci_flags &= ~MCIF_INMIME;
-
- /* skip the late "comment" epilogue */
- while (fgets(buf, sizeof buf, e->e_dfp) != NULL)
- {
- bt = mimeboundary(buf, boundaries);
- if (bt != MBT_NOTSEP)
- break;
- putxline(buf, strlen(buf), mci, PXLF_MAPFROM|PXLF_STRIP8BIT);
- if (tTd(43, 99))
- printf(" ...%s", buf);
- }
- if (feof(e->e_dfp))
- bt = MBT_FINAL;
- if (tTd(43, 3))
- printf("\t\t\tmime8to7=>%s (multipart)\n",
- MimeBoundaryNames[bt]);
- return bt;
- }
-
- /*
- ** Message/xxx types -- recurse exactly once.
- **
- ** Class 's' is predefined to have "rfc822" only.
- */
-
- if (strcasecmp(type, "message") == 0)
- {
- if (!wordinclass(subtype, 's'))
- {
- flags |= M87F_NO8BIT;
- }
- else
- {
- auto HDR *hdr = NULL;
-
- putline("", mci);
-
- mci->mci_flags |= MCIF_INMIME;
- collect(e->e_dfp, FALSE, &hdr, e);
- if (tTd(43, 101))
- putline("+++after collect", mci);
- putheader(mci, hdr, e, flags);
- if (tTd(43, 101))
- putline("+++after putheader", mci);
- if (hvalue("MIME-Version", hdr) == NULL)
- putline("MIME-Version: 1.0", mci);
- bt = mime8to7(mci, hdr, e, boundaries, flags);
- mci->mci_flags &= ~MCIF_INMIME;
- return bt;
- }
- }
-
- /*
- ** Non-compound body type
- **
- ** Compute the ratio of seven to eight bit characters;
- ** use that as a heuristic to decide how to do the
- ** encoding.
- */
-
- sectionsize = sectionhighbits = 0;
- if (!bitset(M87F_NO8BIT|M87F_NO8TO7, flags))
- {
- /* remember where we were */
- offset = ftell(e->e_dfp);
- if (offset == -1)
- syserr("mime8to7: cannot ftell on df%s", e->e_id);
-
- /* do a scan of this body type to count character types */
- while (fgets(buf, sizeof buf, e->e_dfp) != NULL)
- {
- if (mimeboundary(buf, boundaries) != MBT_NOTSEP)
- break;
- for (p = buf; *p != '\0'; p++)
- {
- /* count bytes with the high bit set */
- sectionsize++;
- if (bitset(0200, *p))
- sectionhighbits++;
- }
-
- /*
- ** Heuristic: if 1/4 of the first 4K bytes are 8-bit,
- ** assume base64. This heuristic avoids double-reading
- ** large graphics or video files.
- */
-
- if (sectionsize >= 4096 &&
- sectionhighbits > sectionsize / 4)
- break;
- }
-
- /* return to the original offset for processing */
- /* XXX use relative seeks to handle >31 bit file sizes? */
- if (fseek(e->e_dfp, offset, SEEK_SET) < 0)
- syserr("mime8to7: cannot fseek on df%s", e->e_id);
- else
- clearerr(e->e_dfp);
- }
-
- /*
- ** Heuristically determine encoding method.
- ** If more than 1/8 of the total characters have the
- ** eighth bit set, use base64; else use quoted-printable.
- ** However, only encode binary encoded data as base64,
- ** since otherwise the NL=>CRLF mapping will be a problem.
- */
-
- if (tTd(43, 8))
- {
- printf("mime8to7: %ld high bit(s) in %ld byte(s), cte=%s, type=%s/%s\n",
- (long) sectionhighbits, (long) sectionsize,
- cte == NULL ? "[none]" : cte,
- type == NULL ? "[none]" : type,
- subtype == NULL ? "[none]" : subtype);
- }
- if (cte != NULL && strcasecmp(cte, "binary") == 0)
- sectionsize = sectionhighbits;
- linelen = 0;
- bp = buf;
- if (sectionhighbits == 0)
- {
- /* no encoding necessary */
- if (cte != NULL &&
- bitset(MCIF_INMIME, mci->mci_flags) &&
- !bitset(M87F_NO8TO7, flags))
- {
- /*
- ** Skip _unless_ in MIME mode and potentially
- ** converting from 8 bit to 7 bit MIME. See
- ** putheader() for the counterpart where the
- ** CTE header is skipped in the opposite
- ** situation.
- */
-
- snprintf(buf, sizeof buf,
- "Content-Transfer-Encoding: %.200s", cte);
- putline(buf, mci);
- if (tTd(43, 36))
- printf(" ...%s\n", buf);
- }
- putline("", mci);
- mci->mci_flags &= ~MCIF_INHEADER;
- while (fgets(buf, sizeof buf, e->e_dfp) != NULL)
- {
- bt = mimeboundary(buf, boundaries);
- if (bt != MBT_NOTSEP)
- break;
- putline(buf, mci);
- }
- if (feof(e->e_dfp))
- bt = MBT_FINAL;
- }
- else if (!MapNLtoCRLF ||
- (sectionsize / 8 < sectionhighbits && !use_qp))
- {
- /* use base64 encoding */
- int c1, c2;
-
- if (tTd(43, 36))
- printf(" ...Content-Transfer-Encoding: base64\n");
- putline("Content-Transfer-Encoding: base64", mci);
- snprintf(buf, sizeof buf,
- "X-MIME-Autoconverted: from 8bit to base64 by %s id %s",
- MyHostName, e->e_id);
- putline(buf, mci);
- putline("", mci);
- mci->mci_flags &= ~MCIF_INHEADER;
- while ((c1 = mime_getchar_crlf(e->e_dfp, boundaries, &bt)) != EOF)
- {
- if (linelen > 71)
- {
- *bp = '\0';
- putline(buf, mci);
- linelen = 0;
- bp = buf;
- }
- linelen += 4;
- *bp++ = Base64Code[(c1 >> 2)];
- c1 = (c1 & 0x03) << 4;
- c2 = mime_getchar_crlf(e->e_dfp, boundaries, &bt);
- if (c2 == EOF)
- {
- *bp++ = Base64Code[c1];
- *bp++ = '=';
- *bp++ = '=';
- break;
- }
- c1 |= (c2 >> 4) & 0x0f;
- *bp++ = Base64Code[c1];
- c1 = (c2 & 0x0f) << 2;
- c2 = mime_getchar_crlf(e->e_dfp, boundaries, &bt);
- if (c2 == EOF)
- {
- *bp++ = Base64Code[c1];
- *bp++ = '=';
- break;
- }
- c1 |= (c2 >> 6) & 0x03;
- *bp++ = Base64Code[c1];
- *bp++ = Base64Code[c2 & 0x3f];
- }
- *bp = '\0';
- putline(buf, mci);
- }
- else
- {
- /* use quoted-printable encoding */
- int c1, c2;
- int fromstate;
- BITMAP badchars;
-
- /* set up map of characters that must be mapped */
- clrbitmap(badchars);
- for (c1 = 0x00; c1 < 0x20; c1++)
- setbitn(c1, badchars);
- clrbitn('\t', badchars);
- for (c1 = 0x7f; c1 < 0x100; c1++)
- setbitn(c1, badchars);
- setbitn('=', badchars);
- if (bitnset(M_EBCDIC, mci->mci_mailer->m_flags))
- for (p = "!\"#$@[\\]^`{|}~"; *p != '\0'; p++)
- setbitn(*p, badchars);
-
- if (tTd(43, 36))
- printf(" ...Content-Transfer-Encoding: quoted-printable\n");
- putline("Content-Transfer-Encoding: quoted-printable", mci);
- snprintf(buf, sizeof buf,
- "X-MIME-Autoconverted: from 8bit to quoted-printable by %s id %s",
- MyHostName, e->e_id);
- putline(buf, mci);
- putline("", mci);
- mci->mci_flags &= ~MCIF_INHEADER;
- fromstate = 0;
- c2 = '\n';
- while ((c1 = mime_getchar(e->e_dfp, boundaries, &bt)) != EOF)
- {
- if (c1 == '\n')
- {
- if (c2 == ' ' || c2 == '\t')
- {
- *bp++ = '=';
- *bp++ = Base16Code[(c2 >> 4) & 0x0f];
- *bp++ = Base16Code[c2 & 0x0f];
- }
- if (buf[0] == '.' && bp == &buf[1])
- {
- buf[0] = '=';
- *bp++ = Base16Code[('.' >> 4) & 0x0f];
- *bp++ = Base16Code['.' & 0x0f];
- }
- *bp = '\0';
- putline(buf, mci);
- linelen = fromstate = 0;
- bp = buf;
- c2 = c1;
- continue;
- }
- if (c2 == ' ' && linelen == 4 && fromstate == 4 &&
- bitnset(M_ESCFROM, mci->mci_mailer->m_flags))
- {
- *bp++ = '=';
- *bp++ = '2';
- *bp++ = '0';
- linelen += 3;
- }
- else if (c2 == ' ' || c2 == '\t')
- {
- *bp++ = c2;
- linelen++;
- }
- if (linelen > 72 &&
- (linelen > 75 || c1 != '.' ||
- (linelen > 73 && c2 == '.')))
- {
- if (linelen > 73 && c2 == '.')
- bp--;
- else
- c2 = '\n';
- *bp++ = '=';
- *bp = '\0';
- putline(buf, mci);
- linelen = fromstate = 0;
- bp = buf;
- if (c2 == '.')
- {
- *bp++ = '.';
- linelen++;
- }
- }
- if (bitnset(c1 & 0xff, badchars))
- {
- *bp++ = '=';
- *bp++ = Base16Code[(c1 >> 4) & 0x0f];
- *bp++ = Base16Code[c1 & 0x0f];
- linelen += 3;
- }
- else if (c1 != ' ' && c1 != '\t')
- {
- if (linelen < 4 && c1 == "From"[linelen])
- fromstate++;
- *bp++ = c1;
- linelen++;
- }
- c2 = c1;
- }
-
- /* output any saved character */
- if (c2 == ' ' || c2 == '\t')
- {
- *bp++ = '=';
- *bp++ = Base16Code[(c2 >> 4) & 0x0f];
- *bp++ = Base16Code[c2 & 0x0f];
- linelen += 3;
- }
-
- if (linelen > 0 || boundaries[0] != NULL)
- {
- *bp = '\0';
- putline(buf, mci);
- }
-
- }
- if (tTd(43, 3))
- printf("\t\t\tmime8to7=>%s (basic)\n", MimeBoundaryNames[bt]);
- return bt;
-}
- /*
-** MIME_GETCHAR -- get a character for MIME processing
-**
-** Treats boundaries as EOF.
-**
-** Parameters:
-** fp -- the input file.
-** boundaries -- the current MIME boundaries.
-** btp -- if the return value is EOF, *btp is set to
-** the type of the boundary.
-**
-** Returns:
-** The next character in the input stream.
-*/
-
-int
-mime_getchar(fp, boundaries, btp)
- register FILE *fp;
- char **boundaries;
- int *btp;
-{
- int c;
- static u_char *bp = NULL;
- static int buflen = 0;
- static bool atbol = TRUE; /* at beginning of line */
- static int bt = MBT_SYNTAX; /* boundary type of next EOF */
- static u_char buf[128]; /* need not be a full line */
- int start = 0; /* indicates position of - in buffer */
-
- if (buflen == 1 && *bp == '\n')
- {
- /* last \n in buffer may be part of next MIME boundary */
- c = *bp;
- }
- else if (buflen > 0)
- {
- buflen--;
- return *bp++;
- }
- else
- c = getc(fp);
- bp = buf;
- buflen = 0;
- if (c == '\n')
- {
- /* might be part of a MIME boundary */
- *bp++ = c;
- atbol = TRUE;
- c = getc(fp);
- if (c == '\n')
- {
- ungetc(c, fp);
- return c;
- }
- start = 1;
- }
- if (c != EOF)
- *bp++ = c;
- else
- bt = MBT_FINAL;
- if (atbol && c == '-')
- {
- /* check for a message boundary */
- c = getc(fp);
- if (c != '-')
- {
- if (c != EOF)
- *bp++ = c;
- else
- bt = MBT_FINAL;
- buflen = bp - buf - 1;
- bp = buf;
- return *bp++;
- }
-
- /* got "--", now check for rest of separator */
- *bp++ = '-';
- while (bp < &buf[sizeof buf - 2] &&
- (c = getc(fp)) != EOF && c != '\n')
- {
- *bp++ = c;
- }
- *bp = '\0';
- bt = mimeboundary((char *) &buf[start], boundaries);
- switch (bt)
- {
- case MBT_FINAL:
- case MBT_INTERMED:
- /* we have a message boundary */
- buflen = 0;
- *btp = bt;
- return EOF;
- }
-
- atbol = c == '\n';
- if (c != EOF)
- *bp++ = c;
- }
-
- buflen = bp - buf - 1;
- if (buflen < 0)
- {
- *btp = bt;
- return EOF;
- }
- bp = buf;
- return *bp++;
-}
- /*
-** MIME_GETCHAR_CRLF -- do mime_getchar, but translate NL => CRLF
-**
-** Parameters:
-** fp -- the input file.
-** boundaries -- the current MIME boundaries.
-** btp -- if the return value is EOF, *btp is set to
-** the type of the boundary.
-**
-** Returns:
-** The next character in the input stream.
-*/
-
-int
-mime_getchar_crlf(fp, boundaries, btp)
- register FILE *fp;
- char **boundaries;
- int *btp;
-{
- static bool sendlf = FALSE;
- int c;
-
- if (sendlf)
- {
- sendlf = FALSE;
- return '\n';
- }
- c = mime_getchar(fp, boundaries, btp);
- if (c == '\n' && MapNLtoCRLF)
- {
- sendlf = TRUE;
- return '\r';
- }
- return c;
-}
- /*
-** MIMEBOUNDARY -- determine if this line is a MIME boundary & its type
-**
-** Parameters:
-** line -- the input line.
-** boundaries -- the set of currently pending boundaries.
-**
-** Returns:
-** MBT_NOTSEP -- if this is not a separator line
-** MBT_INTERMED -- if this is an intermediate separator
-** MBT_FINAL -- if this is a final boundary
-** MBT_SYNTAX -- if this is a boundary for the wrong
-** enclosure -- i.e., a syntax error.
-*/
-
-int
-mimeboundary(line, boundaries)
- register char *line;
- char **boundaries;
-{
- int type = MBT_NOTSEP;
- int i;
- int savec;
- extern int isboundary __P((char *, char **));
-
- if (line[0] != '-' || line[1] != '-' || boundaries == NULL)
- return MBT_NOTSEP;
- i = strlen(line);
- if (line[i - 1] == '\n')
- i--;
-
- /* strip off trailing whitespace */
- while (line[i - 1] == ' ' || line[i - 1] == '\t')
- i--;
- savec = line[i];
- line[i] = '\0';
-
- if (tTd(43, 5))
- printf("mimeboundary: line=\"%s\"... ", line);
-
- /* check for this as an intermediate boundary */
- if (isboundary(&line[2], boundaries) >= 0)
- type = MBT_INTERMED;
- else if (i > 2 && strncmp(&line[i - 2], "--", 2) == 0)
- {
- /* check for a final boundary */
- line[i - 2] = '\0';
- if (isboundary(&line[2], boundaries) >= 0)
- type = MBT_FINAL;
- line[i - 2] = '-';
- }
-
- line[i] = savec;
- if (tTd(43, 5))
- printf("%s\n", MimeBoundaryNames[type]);
- return type;
-}
- /*
-** DEFCHARSET -- return default character set for message
-**
-** The first choice for character set is for the mailer
-** corresponding to the envelope sender. If neither that
-** nor the global configuration file has a default character
-** set defined, return "unknown-8bit" as recommended by
-** RFC 1428 section 3.
-**
-** Parameters:
-** e -- the envelope for this message.
-**
-** Returns:
-** The default character set for that mailer.
-*/
-
-char *
-defcharset(e)
- register ENVELOPE *e;
-{
- if (e != NULL && e->e_from.q_mailer != NULL &&
- e->e_from.q_mailer->m_defcharset != NULL)
- return e->e_from.q_mailer->m_defcharset;
- if (DefaultCharSet != NULL)
- return DefaultCharSet;
- return "unknown-8bit";
-}
- /*
-** ISBOUNDARY -- is a given string a currently valid boundary?
-**
-** Parameters:
-** line -- the current input line.
-** boundaries -- the list of valid boundaries.
-**
-** Returns:
-** The index number in boundaries if the line is found.
-** -1 -- otherwise.
-**
-*/
-
-int
-isboundary(line, boundaries)
- char *line;
- char **boundaries;
-{
- register int i;
-
- for (i = 0; boundaries[i] != NULL; i++)
- {
- if (strcmp(line, boundaries[i]) == 0)
- return i;
- }
- return -1;
-}
-
-#endif /* MIME8TO7 */
-
-#if MIME7TO8
-
-/*
-** MIME7TO8 -- output 7 bit encoded MIME body in 8 bit format
-**
-** This is a hack. Supports translating the two 7-bit body-encodings
-** (quoted-printable and base64) to 8-bit coded bodies.
-**
-** There is not much point in supporting multipart here, as the UA
-** will be able to deal with encoded MIME bodies if it can parse MIME
-** multipart messages.
-**
-** Note also that we wont be called unless it is a text/plain MIME
-** message, encoded base64 or QP and mailer flag '9' has been defined
-** on mailer.
-**
-** Contributed by Marius Olaffson <marius@rhi.hi.is>.
-**
-** Parameters:
-** mci -- mailer connection information.
-** header -- the header for this body part.
-** e -- envelope.
-**
-** Returns:
-** none.
-*/
-
-extern int mime_fromqp __P((u_char *, u_char **, int, int));
-
-static char index_64[128] =
-{
- -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
- -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
- -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
- 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
- -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
- 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
- -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
- 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
-};
-
-#define CHAR64(c) (((c) < 0 || (c) > 127) ? -1 : index_64[(c)])
-
-
-void
-mime7to8(mci, header, e)
- register MCI *mci;
- HDR *header;
- register ENVELOPE *e;
-{
- register char *p;
- char *cte;
- char **pvp;
- u_char *fbufp;
- char buf[MAXLINE];
- u_char fbuf[MAXLINE + 1];
- char pvpbuf[MAXLINE];
- extern u_char MimeTokenTab[256];
-
- p = hvalue("Content-Transfer-Encoding", header);
- if (p == NULL ||
- (pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL,
- MimeTokenTab)) == NULL ||
- pvp[0] == NULL)
- {
- /* "can't happen" -- upper level should have caught this */
- syserr("mime7to8: unparsable CTE %s", p == NULL ? "<NULL>" : p);
-
- /* avoid bounce loops */
- e->e_flags |= EF_DONT_MIME;
-
- /* cheap failsafe algorithm -- should work on text/plain */
- if (p != NULL)
- {
- snprintf(buf, sizeof buf,
- "Content-Transfer-Encoding: %s", p);
- putline(buf, mci);
- }
- putline("", mci);
- mci->mci_flags &= ~MCIF_INHEADER;
- while (fgets(buf, sizeof buf, e->e_dfp) != NULL)
- putline(buf, mci);
- return;
- }
- cataddr(pvp, NULL, buf, sizeof buf, '\0');
- cte = newstr(buf);
-
- mci->mci_flags |= MCIF_INHEADER;
- putline("Content-Transfer-Encoding: 8bit", mci);
- snprintf(buf, sizeof buf,
- "X-MIME-Autoconverted: from %.200s to 8bit by %s id %s",
- cte, MyHostName, e->e_id);
- putline(buf, mci);
- putline("", mci);
- mci->mci_flags &= ~MCIF_INHEADER;
-
- /*
- ** Translate body encoding to 8-bit. Supports two types of
- ** encodings; "base64" and "quoted-printable". Assume qp if
- ** it is not base64.
- */
-
- if (strcasecmp(cte, "base64") == 0)
- {
- int c1, c2, c3, c4;
-
- fbufp = fbuf;
- while ((c1 = fgetc(e->e_dfp)) != EOF)
- {
- if (isascii(c1) && isspace(c1))
- continue;
-
- do
- {
- c2 = fgetc(e->e_dfp);
- } while (isascii(c2) && isspace(c2));
- if (c2 == EOF)
- break;
-
- do
- {
- c3 = fgetc(e->e_dfp);
- } while (isascii(c3) && isspace(c3));
- if (c3 == EOF)
- break;
-
- do
- {
- c4 = fgetc(e->e_dfp);
- } while (isascii(c4) && isspace(c4));
- if (c4 == EOF)
- break;
-
- if (c1 == '=' || c2 == '=')
- continue;
- c1 = CHAR64(c1);
- c2 = CHAR64(c2);
-
- *fbufp = (c1 << 2) | ((c2 & 0x30) >> 4);
- if (*fbufp++ == '\n' || fbufp >= &fbuf[MAXLINE])
- {
- if (*--fbufp != '\n' ||
- (fbufp > fbuf && *--fbufp != '\r'))
- fbufp++;
- putxline((char *) fbuf, fbufp - fbuf,
- mci, PXLF_MAPFROM);
- fbufp = fbuf;
- }
- if (c3 == '=')
- continue;
- c3 = CHAR64(c3);
- *fbufp = ((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2);
- if (*fbufp++ == '\n' || fbufp >= &fbuf[MAXLINE])
- {
- if (*--fbufp != '\n' ||
- (fbufp > fbuf && *--fbufp != '\r'))
- fbufp++;
- putxline((char *) fbuf, fbufp - fbuf,
- mci, PXLF_MAPFROM);
- fbufp = fbuf;
- }
- if (c4 == '=')
- continue;
- c4 = CHAR64(c4);
- *fbufp = ((c3 & 0x03) << 6) | c4;
- if (*fbufp++ == '\n' || fbufp >= &fbuf[MAXLINE])
- {
- if (*--fbufp != '\n' ||
- (fbufp > fbuf && *--fbufp != '\r'))
- fbufp++;
- putxline((char *) fbuf, fbufp - fbuf,
- mci, PXLF_MAPFROM);
- fbufp = fbuf;
- }
- }
- }
- else
- {
- /* quoted-printable */
- fbufp = fbuf;
- while (fgets(buf, sizeof buf, e->e_dfp) != NULL)
- {
- if (mime_fromqp((u_char *) buf, &fbufp, 0,
- &fbuf[MAXLINE] - fbufp) == 0)
- continue;
-
- if (fbufp - fbuf > 0)
- putxline((char *) fbuf, fbufp - fbuf - 1, mci,
- PXLF_MAPFROM);
- fbufp = fbuf;
- }
- }
-
- /* force out partial last line */
- if (fbufp > fbuf)
- {
- *fbufp = '\0';
- putxline((char *) fbuf, fbufp - fbuf, mci, PXLF_MAPFROM);
- }
- if (tTd(43, 3))
- printf("\t\t\tmime7to8 => %s to 8bit done\n", cte);
-}
- /*
-** The following is based on Borenstein's "codes.c" module, with simplifying
-** changes as we do not deal with multipart, and to do the translation in-core,
-** with an attempt to prevent overrun of output buffers.
-**
-** What is needed here are changes to defned this code better against
-** bad encodings. Questionable to always return 0xFF for bad mappings.
-*/
-
-static char index_hex[128] =
-{
- -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
- -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
- -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1, -1,-1,-1,-1,
- -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
- -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
- -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
- -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1
-};
-
-#define HEXCHAR(c) (((c) < 0 || (c) > 127) ? -1 : index_hex[(c)])
-
-int
-mime_fromqp(infile, outfile, state, maxlen)
- u_char *infile;
- u_char **outfile;
- int state; /* Decoding body (0) or header (1) */
- int maxlen; /* Max # of chars allowed in outfile */
-{
- int c1, c2;
- int nchar = 0;
-
- while ((c1 = *infile++) != '\0')
- {
- if (c1 == '=')
- {
- if ((c1 = *infile++) == 0)
- break;
-
- if (c1 == '\n' || (c1 = HEXCHAR(c1)) == -1)
- {
- /* ignore it */
- if (state == 0)
- return 0;
- }
- else
- {
- do
- {
- if ((c2 = *infile++) == '\0')
- {
- c2 = -1;
- break;
- }
- } while ((c2 = HEXCHAR(c2)) == -1);
-
- if (c2 == -1 || ++nchar > maxlen)
- break;
-
- *(*outfile)++ = c1 << 4 | c2;
- }
- }
- else
- {
- if (state == 1 && c1 == '_')
- c1 = ' ';
-
- if (++nchar > maxlen)
- break;
-
- *(*outfile)++ = c1;
-
- if (c1 == '\n')
- break;
- }
- }
- *(*outfile)++ = '\0';
- return 1;
-}
-
-
-#endif /* MIME7TO8 */
diff --git a/src/newaliases.0 b/src/newaliases.0
deleted file mode 100644
index 25b0285..0000000
--- a/src/newaliases.0
+++ /dev/null
@@ -1,27 +0,0 @@
-NEWALIASES(1) BSD Reference Manual NEWALIASES(1)
-
-NNAAMMEE
- nneewwaalliiaasseess - rebuild the data base for the mail aliases file
-
-SSYYNNOOPPSSIISS
- nneewwaalliiaasseess
-
-DDEESSCCRRIIPPTTIIOONN
- NNeewwaalliiaasseess rebuilds the random access data base for the mail aliases file
- _/_e_t_c_/_a_l_i_a_s_e_s. It must be run each time this file is changed in order for
- the change to take effect.
-
- NNeewwaalliiaasseess is identical to ``sendmail -bi''.
-
- The nneewwaalliiaasseess utility exits 0 on success, and >0 if an error occurs.
-
-FFIILLEESS
- /etc/aliases The mail aliases file
-
-SSEEEE AALLSSOO
- aliases(5), sendmail(8)
-
-HHIISSTTOORRYY
- The nneewwaalliiaasseess command appeared in 4.0BSD.
-
-4th Berkeley Distribution May 19, 1998 1
diff --git a/src/newaliases.1 b/src/newaliases.1
deleted file mode 100644
index b9673cd..0000000
--- a/src/newaliases.1
+++ /dev/null
@@ -1,47 +0,0 @@
-.\" Copyright (c) 1998 Sendmail, Inc. All rights reserved.
-.\" Copyright (c) 1983, 1997 Eric P. Allman. All rights reserved.
-.\" Copyright (c) 1985, 1990, 1993
-.\" The Regents of the University of California. All rights reserved.
-.\"
-.\" By using this file, you agree to the terms and conditions set
-.\" forth in the LICENSE file which can be found at the top level of
-.\" the sendmail distribution.
-.\"
-.\"
-.\" @(#)newaliases.1 8.10 (Berkeley) 5/19/1998
-.\"
-.Dd May 19, 1998
-.Dt NEWALIASES 1
-.Os BSD 4
-.Sh NAME
-.Nm newaliases
-.Nd rebuild the data base for the mail aliases file
-.Sh SYNOPSIS
-.Nm newaliases
-.Sh DESCRIPTION
-.Nm Newaliases
-rebuilds the random access data base for the mail aliases file
-.Pa /etc/aliases .
-It must be run each time this file is changed in order
-for the change to take effect.
-.Pp
-.Nm Newaliases
-is identical to
-.Dq Li "sendmail -bi" .
-.Pp
-The
-.Nm newaliases
-utility exits 0 on success, and >0 if an error occurs.
-.Sh FILES
-.Bl -tag -width /etc/aliases -compact
-.It Pa /etc/aliases
-The mail aliases file
-.El
-.Sh SEE ALSO
-.Xr aliases 5 ,
-.Xr sendmail 8
-.Sh HISTORY
-The
-.Nm newaliases
-command appeared in
-.Bx 4.0 .
diff --git a/src/parseaddr.c b/src/parseaddr.c
deleted file mode 100644
index 86762fd..0000000
--- a/src/parseaddr.c
+++ /dev/null
@@ -1,2555 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)parseaddr.c 8.156 (Berkeley) 10/27/1998";
-#endif /* not lint */
-
-# include "sendmail.h"
-
-/*
-** PARSEADDR -- Parse an address
-**
-** Parses an address and breaks it up into three parts: a
-** net to transmit the message on, the host to transmit it
-** to, and a user on that host. These are loaded into an
-** ADDRESS header with the values squirreled away if necessary.
-** The "user" part may not be a real user; the process may
-** just reoccur on that machine. For example, on a machine
-** with an arpanet connection, the address
-** csvax.bill@berkeley
-** will break up to a "user" of 'csvax.bill' and a host
-** of 'berkeley' -- to be transmitted over the arpanet.
-**
-** Parameters:
-** addr -- the address to parse.
-** a -- a pointer to the address descriptor buffer.
-** If NULL, a header will be created.
-** flags -- describe detail for parsing. See RF_ definitions
-** in sendmail.h.
-** delim -- the character to terminate the address, passed
-** to prescan.
-** delimptr -- if non-NULL, set to the location of the
-** delim character that was found.
-** e -- the envelope that will contain this address.
-**
-** Returns:
-** A pointer to the address descriptor header (`a' if
-** `a' is non-NULL).
-** NULL on error.
-**
-** Side Effects:
-** none
-*/
-
-/* following delimiters are inherent to the internal algorithms */
-# define DELIMCHARS "()<>,;\r\n" /* default word delimiters */
-
-ADDRESS *
-parseaddr(addr, a, flags, delim, delimptr, e)
- char *addr;
- register ADDRESS *a;
- int flags;
- int delim;
- char **delimptr;
- register ENVELOPE *e;
-{
- register char **pvp;
- auto char *delimptrbuf;
- bool queueup;
- char pvpbuf[PSBUFSIZE];
- extern bool invalidaddr __P((char *, char *));
- extern void allocaddr __P((ADDRESS *, int, char *));
-
- /*
- ** Initialize and prescan address.
- */
-
- e->e_to = addr;
- if (tTd(20, 1))
- printf("\n--parseaddr(%s)\n", addr);
-
- if (delimptr == NULL)
- delimptr = &delimptrbuf;
-
- pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr, NULL);
- if (pvp == NULL)
- {
- if (tTd(20, 1))
- printf("parseaddr-->NULL\n");
- return (NULL);
- }
-
- if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr))
- {
- if (tTd(20, 1))
- printf("parseaddr-->bad address\n");
- return NULL;
- }
-
- /*
- ** Save addr if we are going to have to.
- **
- ** We have to do this early because there is a chance that
- ** the map lookups in the rewriting rules could clobber
- ** static memory somewhere.
- */
-
- if (bitset(RF_COPYPADDR, flags) && addr != NULL)
- {
- char savec = **delimptr;
-
- if (savec != '\0')
- **delimptr = '\0';
- e->e_to = addr = newstr(addr);
- if (savec != '\0')
- **delimptr = savec;
- }
-
- /*
- ** Apply rewriting rules.
- ** Ruleset 0 does basic parsing. It must resolve.
- */
-
- queueup = FALSE;
- if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
- queueup = TRUE;
- if (rewrite(pvp, 0, 0, e) == EX_TEMPFAIL)
- queueup = TRUE;
-
-
- /*
- ** Build canonical address from pvp.
- */
-
- a = buildaddr(pvp, a, flags, e);
-
- /*
- ** Make local copies of the host & user and then
- ** transport them out.
- */
-
- allocaddr(a, flags, addr);
- if (bitset(QBADADDR, a->q_flags))
- return a;
-
- /*
- ** If there was a parsing failure, mark it for queueing.
- */
-
- if (queueup && OpMode != MD_INITALIAS)
- {
- char *msg = "Transient parse error -- message queued for future delivery";
-
- if (e->e_sendmode == SM_DEFER)
- msg = "Deferring message until queue run";
- if (tTd(20, 1))
- printf("parseaddr: queuing message\n");
- message(msg);
- if (e->e_message == NULL && e->e_sendmode != SM_DEFER)
- e->e_message = newstr(msg);
- a->q_flags |= QQUEUEUP;
- a->q_status = "4.4.3";
- }
-
- /*
- ** Compute return value.
- */
-
- if (tTd(20, 1))
- {
- printf("parseaddr-->");
- printaddr(a, FALSE);
- }
-
- return (a);
-}
- /*
-** INVALIDADDR -- check for address containing meta-characters
-**
-** Parameters:
-** addr -- the address to check.
-**
-** Returns:
-** TRUE -- if the address has any "wierd" characters
-** FALSE -- otherwise.
-*/
-
-bool
-invalidaddr(addr, delimptr)
- register char *addr;
- char *delimptr;
-{
- char savedelim = '\0';
-
- if (delimptr != NULL)
- {
- savedelim = *delimptr;
- if (savedelim != '\0')
- *delimptr = '\0';
- }
- if (strlen(addr) > TOBUFSIZE - 2)
- {
- usrerr("553 Address too long (%d bytes max)", TOBUFSIZE - 2);
- goto failure;
- }
- for (; *addr != '\0'; addr++)
- {
- if ((*addr & 0340) == 0200)
- break;
- }
- if (*addr == '\0')
- {
- if (delimptr != NULL && savedelim != '\0')
- *delimptr = savedelim;
- return FALSE;
- }
- setstat(EX_USAGE);
- usrerr("553 Address contained invalid control characters");
-failure:
- if (delimptr != NULL && savedelim != '\0')
- *delimptr = savedelim;
- return TRUE;
-}
- /*
-** ALLOCADDR -- do local allocations of address on demand.
-**
-** Also lowercases the host name if requested.
-**
-** Parameters:
-** a -- the address to reallocate.
-** flags -- the copy flag (see RF_ definitions in sendmail.h
-** for a description).
-** paddr -- the printname of the address.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Copies portions of a into local buffers as requested.
-*/
-
-void
-allocaddr(a, flags, paddr)
- register ADDRESS *a;
- int flags;
- char *paddr;
-{
- if (tTd(24, 4))
- printf("allocaddr(flags=%x, paddr=%s)\n", flags, paddr);
-
- a->q_paddr = paddr;
-
- if (a->q_user == NULL)
- a->q_user = "";
- if (a->q_host == NULL)
- a->q_host = "";
-
- if (bitset(RF_COPYPARSE, flags))
- {
- a->q_host = newstr(a->q_host);
- if (a->q_user != a->q_paddr)
- a->q_user = newstr(a->q_user);
- }
-
- if (a->q_paddr == NULL)
- a->q_paddr = a->q_user;
-}
- /*
-** PRESCAN -- Prescan name and make it canonical
-**
-** Scans a name and turns it into a set of tokens. This process
-** deletes blanks and comments (in parentheses).
-**
-** This routine knows about quoted strings and angle brackets.
-**
-** There are certain subtleties to this routine. The one that
-** comes to mind now is that backslashes on the ends of names
-** are silently stripped off; this is intentional. The problem
-** is that some versions of sndmsg (like at LBL) set the kill
-** character to something other than @ when reading addresses;
-** so people type "csvax.eric\@berkeley" -- which screws up the
-** berknet mailer.
-**
-** Parameters:
-** addr -- the name to chomp.
-** delim -- the delimiter for the address, normally
-** '\0' or ','; \0 is accepted in any case.
-** If '\t' then we are reading the .cf file.
-** pvpbuf -- place to put the saved text -- note that
-** the pointers are static.
-** pvpbsize -- size of pvpbuf.
-** delimptr -- if non-NULL, set to the location of the
-** terminating delimiter.
-** toktab -- if set, a token table to use for parsing.
-** If NULL, use the default table.
-**
-** Returns:
-** A pointer to a vector of tokens.
-** NULL on error.
-*/
-
-/* states and character types */
-# define OPR 0 /* operator */
-# define ATM 1 /* atom */
-# define QST 2 /* in quoted string */
-# define SPC 3 /* chewing up spaces */
-# define ONE 4 /* pick up one character */
-# define ILL 5 /* illegal character */
-
-# define NSTATES 6 /* number of states */
-# define TYPE 017 /* mask to select state type */
-
-/* meta bits for table */
-# define M 020 /* meta character; don't pass through */
-# define B 040 /* cause a break */
-# define MB M|B /* meta-break */
-
-static short StateTab[NSTATES][NSTATES] =
-{
- /* oldst chtype> OPR ATM QST SPC ONE ILL */
- /*OPR*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|MB },
- /*ATM*/ { OPR|B, ATM, QST|B, SPC|MB, ONE|B, ILL|MB },
- /*QST*/ { QST, QST, OPR, QST, QST, QST },
- /*SPC*/ { OPR, ATM, QST, SPC|M, ONE, ILL|MB },
- /*ONE*/ { OPR, OPR, OPR, OPR, OPR, ILL|MB },
- /*ILL*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|M },
-};
-
-/* token type table -- it gets modified with $o characters */
-static u_char TokTypeTab[256] =
-{
- /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
- ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM,
- /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
- ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
- /* sp ! " # $ % & ' ( ) * + , - . / */
- SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, ATM,SPC,ATM,ATM,ATM,ATM,ATM,ATM,
- /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
- ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
- /* @ A B C D E F G H I J K L M N O */
- ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
- /* P Q R S T U V W X Y Z [ \ ] ^ _ */
- ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
- /* ` a b c d e f g h i j k l m n o */
- ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
- /* p q r s t u v w x y z { | } ~ del */
- ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
-
- /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
- OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
- /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
- OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
- /* sp ! " # $ % & ' ( ) * + , - . / */
- ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
- /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
- ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
- /* @ A B C D E F G H I J K L M N O */
- ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
- /* P Q R S T U V W X Y Z [ \ ] ^ _ */
- ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
- /* ` a b c d e f g h i j k l m n o */
- ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
- /* p q r s t u v w x y z { | } ~ del */
- ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
-};
-
-/* token type table for MIME parsing */
-u_char MimeTokenTab[256] =
-{
- /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
- ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,SPC,SPC,SPC,SPC,SPC,ILL,ILL,
- /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
- ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
- /* sp ! " # $ % & ' ( ) * + , - . / */
- SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, ATM,SPC,ATM,ATM,OPR,ATM,ATM,OPR,
- /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
- ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,OPR,OPR,OPR,OPR,OPR,OPR,
- /* @ A B C D E F G H I J K L M N O */
- OPR,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
- /* P Q R S T U V W X Y Z [ \ ] ^ _ */
- ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,OPR,OPR,OPR,ATM,ATM,
- /* ` a b c d e f g h i j k l m n o */
- ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
- /* p q r s t u v w x y z { | } ~ del */
- ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
-
- /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
- ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
- /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
- ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
- /* sp ! " # $ % & ' ( ) * + , - . / */
- ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
- /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
- ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
- /* @ A B C D E F G H I J K L M N O */
- ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
- /* P Q R S T U V W X Y Z [ \ ] ^ _ */
- ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
- /* ` a b c d e f g h i j k l m n o */
- ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
- /* p q r s t u v w x y z { | } ~ del */
- ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
-};
-
-
-# define NOCHAR -1 /* signal nothing in lookahead token */
-
-char **
-prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab)
- char *addr;
- int delim;
- char pvpbuf[];
- int pvpbsize;
- char **delimptr;
- u_char *toktab;
-{
- register char *p;
- register char *q;
- register int c;
- char **avp;
- bool bslashmode;
- bool route_syntax;
- int cmntcnt;
- int anglecnt;
- char *tok;
- int state;
- int newstate;
- char *saveto = CurEnv->e_to;
- static char *av[MAXATOM+1];
- static char firsttime = TRUE;
- extern int errno;
-
- if (firsttime)
- {
- /* initialize the token type table */
- char obuf[50];
-
- firsttime = FALSE;
- if (OperatorChars == NULL)
- {
- if (ConfigLevel < 7)
- OperatorChars = macvalue('o', CurEnv);
- if (OperatorChars == NULL)
- OperatorChars = ".:@[]";
- }
- expand(OperatorChars, obuf, sizeof obuf - sizeof DELIMCHARS, CurEnv);
- strcat(obuf, DELIMCHARS);
- for (p = obuf; *p != '\0'; p++)
- {
- if (TokTypeTab[*p & 0xff] == ATM)
- TokTypeTab[*p & 0xff] = OPR;
- }
- }
- if (toktab == NULL)
- toktab = TokTypeTab;
-
- /* make sure error messages don't have garbage on them */
- errno = 0;
-
- q = pvpbuf;
- bslashmode = FALSE;
- route_syntax = FALSE;
- cmntcnt = 0;
- anglecnt = 0;
- avp = av;
- state = ATM;
- c = NOCHAR;
- p = addr;
- CurEnv->e_to = p;
- if (tTd(22, 11))
- {
- printf("prescan: ");
- xputs(p);
- (void) putchar('\n');
- }
-
- do
- {
- /* read a token */
- tok = q;
- for (;;)
- {
- /* store away any old lookahead character */
- if (c != NOCHAR && !bslashmode)
- {
- /* see if there is room */
- if (q >= &pvpbuf[pvpbsize - 5])
- {
- usrerr("553 Address too long");
- if (strlen(addr) > (SIZE_T) MAXNAME)
- addr[MAXNAME] = '\0';
- returnnull:
- if (delimptr != NULL)
- *delimptr = p;
- CurEnv->e_to = saveto;
- return (NULL);
- }
-
- /* squirrel it away */
- *q++ = c;
- }
-
- /* read a new input character */
- c = *p++;
- if (c == '\0')
- {
- /* diagnose and patch up bad syntax */
- if (state == QST)
- {
- usrerr("653 Unbalanced '\"'");
- c = '"';
- }
- else if (cmntcnt > 0)
- {
- usrerr("653 Unbalanced '('");
- c = ')';
- }
- else if (anglecnt > 0)
- {
- c = '>';
- usrerr("653 Unbalanced '<'");
- }
- else
- break;
-
- p--;
- }
- else if (c == delim && cmntcnt <= 0 && state != QST)
- {
- if (anglecnt <= 0)
- break;
-
- /* special case for better error management */
- if (delim == ',' && !route_syntax)
- {
- usrerr("653 Unbalanced '<'");
- c = '>';
- p--;
- }
- }
-
- if (tTd(22, 101))
- printf("c=%c, s=%d; ", c, state);
-
- /* chew up special characters */
- *q = '\0';
- if (bslashmode)
- {
- bslashmode = FALSE;
-
- /* kludge \! for naive users */
- if (cmntcnt > 0)
- {
- c = NOCHAR;
- continue;
- }
- else if (c != '!' || state == QST)
- {
- *q++ = '\\';
- continue;
- }
- }
-
- if (c == '\\')
- {
- bslashmode = TRUE;
- }
- else if (state == QST)
- {
- /* do nothing, just avoid next clauses */
- }
- else if (c == '(')
- {
- cmntcnt++;
- c = NOCHAR;
- }
- else if (c == ')')
- {
- if (cmntcnt <= 0)
- {
- usrerr("653 Unbalanced ')'");
- c = NOCHAR;
- }
- else
- cmntcnt--;
- }
- else if (cmntcnt > 0)
- c = NOCHAR;
- else if (c == '<')
- {
- char *q = p;
-
- anglecnt++;
- while (isascii(*q) && isspace(*q))
- q++;
- if (*q == '@')
- route_syntax = TRUE;
- }
- else if (c == '>')
- {
- if (anglecnt <= 0)
- {
- usrerr("653 Unbalanced '>'");
- c = NOCHAR;
- }
- else
- anglecnt--;
- route_syntax = FALSE;
- }
- else if (delim == ' ' && isascii(c) && isspace(c))
- c = ' ';
-
- if (c == NOCHAR)
- continue;
-
- /* see if this is end of input */
- if (c == delim && anglecnt <= 0 && state != QST)
- break;
-
- newstate = StateTab[state][toktab[c & 0xff]];
- if (tTd(22, 101))
- printf("ns=%02o\n", newstate);
- state = newstate & TYPE;
- if (state == ILL)
- {
- if (isascii(c) && isprint(c))
- usrerr("653 Illegal character %c", c);
- else
- usrerr("653 Illegal character 0x%02x", c);
- }
- if (bitset(M, newstate))
- c = NOCHAR;
- if (bitset(B, newstate))
- break;
- }
-
- /* new token */
- if (tok != q)
- {
- *q++ = '\0';
- if (tTd(22, 36))
- {
- printf("tok=");
- xputs(tok);
- (void) putchar('\n');
- }
- if (avp >= &av[MAXATOM])
- {
- usrerr("553 prescan: too many tokens");
- goto returnnull;
- }
- if (q - tok > MAXNAME)
- {
- usrerr("553 prescan: token too long");
- goto returnnull;
- }
- *avp++ = tok;
- }
- } while (c != '\0' && (c != delim || anglecnt > 0));
- *avp = NULL;
- p--;
- if (delimptr != NULL)
- *delimptr = p;
- if (tTd(22, 12))
- {
- printf("prescan==>");
- printav(av);
- }
- CurEnv->e_to = saveto;
- if (av[0] == NULL)
- {
- if (tTd(22, 1))
- printf("prescan: null leading token\n");
- return (NULL);
- }
- return (av);
-}
- /*
-** REWRITE -- apply rewrite rules to token vector.
-**
-** This routine is an ordered production system. Each rewrite
-** rule has a LHS (called the pattern) and a RHS (called the
-** rewrite); 'rwr' points the the current rewrite rule.
-**
-** For each rewrite rule, 'avp' points the address vector we
-** are trying to match against, and 'pvp' points to the pattern.
-** If pvp points to a special match value (MATCHZANY, MATCHANY,
-** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp
-** matched is saved away in the match vector (pointed to by 'mvp').
-**
-** When a match between avp & pvp does not match, we try to
-** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS
-** we must also back out the match in mvp. If we reach a
-** MATCHANY or MATCHZANY we just extend the match and start
-** over again.
-**
-** When we finally match, we rewrite the address vector
-** and try over again.
-**
-** Parameters:
-** pvp -- pointer to token vector.
-** ruleset -- the ruleset to use for rewriting.
-** reclevel -- recursion level (to catch loops).
-** e -- the current envelope.
-**
-** Returns:
-** A status code. If EX_TEMPFAIL, higher level code should
-** attempt recovery.
-**
-** Side Effects:
-** pvp is modified.
-*/
-
-struct match
-{
- char **first; /* first token matched */
- char **last; /* last token matched */
- char **pattern; /* pointer to pattern */
-};
-
-# define MAXMATCH 9 /* max params per rewrite */
-
-
-int
-rewrite(pvp, ruleset, reclevel, e)
- char **pvp;
- int ruleset;
- int reclevel;
- register ENVELOPE *e;
-{
- register char *ap; /* address pointer */
- register char *rp; /* rewrite pointer */
- register char **avp; /* address vector pointer */
- register char **rvp; /* rewrite vector pointer */
- register struct match *mlp; /* cur ptr into mlist */
- register struct rewrite *rwr; /* pointer to current rewrite rule */
- int ruleno; /* current rule number */
- int rstat = EX_OK; /* return status */
- int loopcount;
- struct match mlist[MAXMATCH]; /* stores match on LHS */
- char *npvp[MAXATOM+1]; /* temporary space for rebuild */
- char buf[MAXLINE];
- extern int callsubr __P((char**, int, ENVELOPE *));
- extern int sm_strcasecmp __P((char *, char *));
-
- if (OpMode == MD_TEST || tTd(21, 1))
- {
- printf("rewrite: ruleset %3d input:", ruleset);
- printav(pvp);
- }
- if (ruleset < 0 || ruleset >= MAXRWSETS)
- {
- syserr("554 rewrite: illegal ruleset number %d", ruleset);
- return EX_CONFIG;
- }
- if (reclevel++ > MaxRuleRecursion)
- {
- syserr("rewrite: excessive recursion (max %d), ruleset %d",
- MaxRuleRecursion, ruleset);
- return EX_CONFIG;
- }
- if (pvp == NULL)
- return EX_USAGE;
-
- /*
- ** Run through the list of rewrite rules, applying
- ** any that match.
- */
-
- ruleno = 1;
- loopcount = 0;
- for (rwr = RewriteRules[ruleset]; rwr != NULL; )
- {
- int stat;
-
- /* if already canonical, quit now */
- if (pvp[0] != NULL && (pvp[0][0] & 0377) == CANONNET)
- break;
-
- if (tTd(21, 12))
- {
- printf("-----trying rule:");
- printav(rwr->r_lhs);
- }
-
- /* try to match on this rule */
- mlp = mlist;
- rvp = rwr->r_lhs;
- avp = pvp;
- if (++loopcount > 100)
- {
- syserr("554 Infinite loop in ruleset %d, rule %d",
- ruleset, ruleno);
- if (tTd(21, 1))
- {
- printf("workspace: ");
- printav(pvp);
- }
- break;
- }
-
- while ((ap = *avp) != NULL || *rvp != NULL)
- {
- rp = *rvp;
- if (tTd(21, 35))
- {
- printf("ADVANCE rp=");
- xputs(rp);
- printf(", ap=");
- xputs(ap);
- printf("\n");
- }
- if (rp == NULL)
- {
- /* end-of-pattern before end-of-address */
- goto backup;
- }
- if (ap == NULL && (*rp & 0377) != MATCHZANY &&
- (*rp & 0377) != MATCHZERO)
- {
- /* end-of-input with patterns left */
- goto backup;
- }
-
- switch (*rp & 0377)
- {
- case MATCHCLASS:
- /* match any phrase in a class */
- mlp->pattern = rvp;
- mlp->first = avp;
- extendclass:
- ap = *avp;
- if (ap == NULL)
- goto backup;
- mlp->last = avp++;
- cataddr(mlp->first, mlp->last, buf, sizeof buf, '\0');
- if (!wordinclass(buf, rp[1]))
- {
- if (tTd(21, 36))
- {
- printf("EXTEND rp=");
- xputs(rp);
- printf(", ap=");
- xputs(ap);
- printf("\n");
- }
- goto extendclass;
- }
- if (tTd(21, 36))
- printf("CLMATCH\n");
- mlp++;
- break;
-
- case MATCHNCLASS:
- /* match any token not in a class */
- if (wordinclass(ap, rp[1]))
- goto backup;
-
- /* fall through */
-
- case MATCHONE:
- case MATCHANY:
- /* match exactly one token */
- mlp->pattern = rvp;
- mlp->first = avp;
- mlp->last = avp++;
- mlp++;
- break;
-
- case MATCHZANY:
- /* match zero or more tokens */
- mlp->pattern = rvp;
- mlp->first = avp;
- mlp->last = avp - 1;
- mlp++;
- break;
-
- case MATCHZERO:
- /* match zero tokens */
- break;
-
- case MACRODEXPAND:
- /*
- ** Match against run-time macro.
- ** This algorithm is broken for the
- ** general case (no recursive macros,
- ** improper tokenization) but should
- ** work for the usual cases.
- */
-
- ap = macvalue(rp[1], e);
- mlp->first = avp;
- if (tTd(21, 2))
- printf("rewrite: LHS $&%s => \"%s\"\n",
- macname(rp[1]),
- ap == NULL ? "(NULL)" : ap);
-
- if (ap == NULL)
- break;
- while (*ap != '\0')
- {
- if (*avp == NULL ||
- strncasecmp(ap, *avp, strlen(*avp)) != 0)
- {
- /* no match */
- avp = mlp->first;
- goto backup;
- }
- ap += strlen(*avp++);
- }
-
- /* match */
- break;
-
- default:
- /* must have exact match */
- if (sm_strcasecmp(rp, ap))
- goto backup;
- avp++;
- break;
- }
-
- /* successful match on this token */
- rvp++;
- continue;
-
- backup:
- /* match failed -- back up */
- while (--mlp >= mlist)
- {
- rvp = mlp->pattern;
- rp = *rvp;
- avp = mlp->last + 1;
- ap = *avp;
-
- if (tTd(21, 36))
- {
- printf("BACKUP rp=");
- xputs(rp);
- printf(", ap=");
- xputs(ap);
- printf("\n");
- }
-
- if (ap == NULL)
- {
- /* run off the end -- back up again */
- continue;
- }
- if ((*rp & 0377) == MATCHANY ||
- (*rp & 0377) == MATCHZANY)
- {
- /* extend binding and continue */
- mlp->last = avp++;
- rvp++;
- mlp++;
- break;
- }
- if ((*rp & 0377) == MATCHCLASS)
- {
- /* extend binding and try again */
- mlp->last = avp;
- goto extendclass;
- }
- }
-
- if (mlp < mlist)
- {
- /* total failure to match */
- break;
- }
- }
-
- /*
- ** See if we successfully matched
- */
-
- if (mlp < mlist || *rvp != NULL)
- {
- if (tTd(21, 10))
- printf("----- rule fails\n");
- rwr = rwr->r_next;
- ruleno++;
- loopcount = 0;
- continue;
- }
-
- rvp = rwr->r_rhs;
- if (tTd(21, 12))
- {
- printf("-----rule matches:");
- printav(rvp);
- }
-
- rp = *rvp;
- if ((*rp & 0377) == CANONUSER)
- {
- rvp++;
- rwr = rwr->r_next;
- ruleno++;
- loopcount = 0;
- }
- else if ((*rp & 0377) == CANONHOST)
- {
- rvp++;
- rwr = NULL;
- }
-
- /* substitute */
- for (avp = npvp; *rvp != NULL; rvp++)
- {
- register struct match *m;
- register char **pp;
-
- rp = *rvp;
- if ((*rp & 0377) == MATCHREPL)
- {
- /* substitute from LHS */
- m = &mlist[rp[1] - '1'];
- if (m < mlist || m >= mlp)
- {
- syserr("554 rewrite: ruleset %d: replacement $%c out of bounds",
- ruleset, rp[1]);
- return EX_CONFIG;
- }
- if (tTd(21, 15))
- {
- printf("$%c:", rp[1]);
- pp = m->first;
- while (pp <= m->last)
- {
- printf(" %lx=\"", (u_long) *pp);
- (void) fflush(stdout);
- printf("%s\"", *pp++);
- }
- printf("\n");
- }
- pp = m->first;
- while (pp <= m->last)
- {
- if (avp >= &npvp[MAXATOM])
- {
- syserr("554 rewrite: expansion too long");
- return EX_DATAERR;
- }
- *avp++ = *pp++;
- }
- }
- else
- {
- /* some sort of replacement */
- if (avp >= &npvp[MAXATOM])
- {
- toolong:
- syserr("554 rewrite: expansion too long");
- return EX_DATAERR;
- }
- if ((*rp & 0377) != MACRODEXPAND)
- {
- /* vanilla replacement */
- *avp++ = rp;
- }
- else
- {
- /* $&x replacement */
- char *mval = macvalue(rp[1], e);
- char **xpvp;
- int trsize = 0;
- static size_t pvpb1_size = 0;
- static char **pvpb1 = NULL;
- char pvpbuf[PSBUFSIZE];
-
- if (tTd(21, 2))
- printf("rewrite: RHS $&%s => \"%s\"\n",
- macname(rp[1]),
- mval == NULL ? "(NULL)" : mval);
- if (mval == NULL || *mval == '\0')
- continue;
-
- /* save the remainder of the input */
- for (xpvp = pvp; *xpvp != NULL; xpvp++)
- trsize += sizeof *xpvp;
- if (trsize > pvpb1_size)
- {
- if (pvpb1 != NULL)
- free(pvpb1);
- pvpb1 = (char **)xalloc(trsize);
- pvpb1_size = trsize;
- }
-
- bcopy((char *) pvp, (char *) pvpb1, trsize);
-
- /* scan the new replacement */
- xpvp = prescan(mval, '\0', pvpbuf,
- sizeof pvpbuf, NULL, NULL);
- if (xpvp == NULL)
- {
- /* prescan pre-printed error */
- return EX_DATAERR;
- }
-
- /* insert it into the output stream */
- while (*xpvp != NULL)
- {
- if (tTd(21, 19))
- printf(" ... %s\n", *xpvp);
- *avp++ = newstr(*xpvp);
- if (avp >= &npvp[MAXATOM])
- goto toolong;
- xpvp++;
- }
- if (tTd(21, 19))
- printf(" ... DONE\n");
-
- /* restore the old trailing input */
- bcopy((char *) pvpb1, (char *) pvp, trsize);
- }
- }
- }
- *avp++ = NULL;
-
- /*
- ** Check for any hostname/keyword lookups.
- */
-
- for (rvp = npvp; *rvp != NULL; rvp++)
- {
- char **hbrvp;
- char **xpvp;
- int trsize;
- char *replac;
- int endtoken;
- STAB *map;
- char *mapname;
- char **key_rvp;
- char **arg_rvp;
- char **default_rvp;
- char buf[MAXNAME + 1];
- char *pvpb1[MAXATOM + 1];
- char *argvect[10];
- char pvpbuf[PSBUFSIZE];
- char *nullpvp[1];
- extern char *map_lookup __P((STAB *, char *, char **, int *, ENVELOPE *));
-
- if ((**rvp & 0377) != HOSTBEGIN &&
- (**rvp & 0377) != LOOKUPBEGIN)
- continue;
-
- /*
- ** Got a hostname/keyword lookup.
- **
- ** This could be optimized fairly easily.
- */
-
- hbrvp = rvp;
- if ((**rvp & 0377) == HOSTBEGIN)
- {
- endtoken = HOSTEND;
- mapname = "host";
- }
- else
- {
- endtoken = LOOKUPEND;
- mapname = *++rvp;
- }
- map = stab(mapname, ST_MAP, ST_FIND);
- if (map == NULL)
- syserr("554 rewrite: map %s not found", mapname);
-
- /* extract the match part */
- key_rvp = ++rvp;
- default_rvp = NULL;
- arg_rvp = argvect;
- xpvp = NULL;
- replac = pvpbuf;
- while (*rvp != NULL && (**rvp & 0377) != endtoken)
- {
- int nodetype = **rvp & 0377;
-
- if (nodetype != CANONHOST && nodetype != CANONUSER)
- {
- rvp++;
- continue;
- }
-
- *rvp++ = NULL;
-
- if (xpvp != NULL)
- {
- cataddr(xpvp, NULL, replac,
- &pvpbuf[sizeof pvpbuf] - replac,
- '\0');
- *++arg_rvp = replac;
- replac += strlen(replac) + 1;
- xpvp = NULL;
- }
- switch (nodetype)
- {
- case CANONHOST:
- xpvp = rvp;
- break;
-
- case CANONUSER:
- default_rvp = rvp;
- break;
- }
- }
- if (*rvp != NULL)
- *rvp++ = NULL;
- if (xpvp != NULL)
- {
- cataddr(xpvp, NULL, replac,
- &pvpbuf[sizeof pvpbuf] - replac,
- '\0');
- *++arg_rvp = replac;
- }
- *++arg_rvp = NULL;
-
- /* save the remainder of the input string */
- trsize = (int) (avp - rvp + 1) * sizeof *rvp;
- bcopy((char *) rvp, (char *) pvpb1, trsize);
-
- /* look it up */
- cataddr(key_rvp, NULL, buf, sizeof buf, '\0');
- argvect[0] = buf;
- replac = map_lookup(map, buf, argvect, &rstat, e);
-
- /* if no replacement, use default */
- if (replac == NULL && default_rvp != NULL)
- {
- /* create the default */
- cataddr(default_rvp, NULL, buf, sizeof buf, '\0');
- replac = buf;
- }
-
- if (replac == NULL)
- {
- xpvp = key_rvp;
- }
- else if (*replac == '\0')
- {
- /* null replacement */
- nullpvp[0] = NULL;
- xpvp = nullpvp;
- }
- else
- {
- /* scan the new replacement */
- xpvp = prescan(replac, '\0', pvpbuf,
- sizeof pvpbuf, NULL, NULL);
- if (xpvp == NULL)
- {
- /* prescan already printed error */
- return EX_DATAERR;
- }
- }
-
- /* append it to the token list */
- for (avp = hbrvp; *xpvp != NULL; xpvp++)
- {
- *avp++ = newstr(*xpvp);
- if (avp >= &npvp[MAXATOM])
- goto toolong;
- }
-
- /* restore the old trailing information */
- rvp = avp - 1;
- for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; )
- if (avp >= &npvp[MAXATOM])
- goto toolong;
- }
-
- /*
- ** Check for subroutine calls.
- */
-
- stat = callsubr(npvp, reclevel, e);
- if (rstat == EX_OK || stat == EX_TEMPFAIL)
- rstat = stat;
-
- /* copy vector back into original space. */
- for (avp = npvp; *avp++ != NULL;)
- continue;
- bcopy((char *) npvp, (char *) pvp,
- (int) (avp - npvp) * sizeof *avp);
-
- if (tTd(21, 4))
- {
- printf("rewritten as:");
- printav(pvp);
- }
- }
-
- if (OpMode == MD_TEST || tTd(21, 1))
- {
- printf("rewrite: ruleset %3d returns:", ruleset);
- printav(pvp);
- }
-
- return rstat;
-}
- /*
-** CALLSUBR -- call subroutines in rewrite vector
-**
-** Parameters:
-** pvp -- pointer to token vector.
-** reclevel -- the current recursion level.
-** e -- the current envelope.
-**
-** Returns:
-** The status from the subroutine call.
-**
-** Side Effects:
-** pvp is modified.
-*/
-
-int
-callsubr(pvp, reclevel, e)
- char **pvp;
- int reclevel;
- ENVELOPE *e;
-{
- char **avp;
- char **rvp;
- register int i;
- int subr;
- int stat;
- int rstat = EX_OK;
- char *tpvp[MAXATOM + 1];
-
- for (avp = pvp; *avp != NULL; avp++)
- {
- if ((**avp & 0377) == CALLSUBR && avp[1] != NULL)
- {
- stripquotes(avp[1]);
- subr = strtorwset(avp[1], NULL, ST_FIND);
- if (subr < 0)
- {
- syserr("Unknown ruleset %s", avp[1]);
- return EX_CONFIG;
- }
-
- if (tTd(21, 3))
- printf("-----callsubr %s (%d)\n", avp[1], subr);
-
- /*
- ** Take care of possible inner calls first.
- ** use a full size temporary buffer to avoid
- ** overflows in rewrite, but strip off the
- ** subroutine call.
- */
-
- for (i = 2; avp[i] != NULL; i++)
- tpvp[i - 2] = avp[i];
- tpvp[i - 2] = NULL;
-
- stat = callsubr(tpvp, reclevel, e);
- if (rstat == EX_OK || stat == EX_TEMPFAIL)
- rstat = stat;
-
- /*
- ** Now we need to call the ruleset specified for
- ** the subroutine. we can do this with the
- ** temporary buffer that we set up earlier,
- ** since it has all the data we want to rewrite.
- */
-
- stat = rewrite(tpvp, subr, reclevel, e);
- if (rstat == EX_OK || stat == EX_TEMPFAIL)
- rstat = stat;
-
- /*
- ** Find length of tpvp and current offset into
- ** pvp, if the total is greater than MAXATOM,
- ** then it would overflow the buffer if we copied
- ** it back in to pvp, in which case we throw a
- ** fit.
- */
-
- for (rvp = tpvp; *rvp != NULL; rvp++)
- continue;
- if (((rvp - tpvp) + (avp - pvp)) > MAXATOM)
- {
- syserr("554 callsubr: expansion too long");
- return EX_DATAERR;
- }
-
- /*
- ** Now we can copy the rewritten code over
- ** the initial subroutine call in the buffer.
- */
-
- for (i = 0; tpvp[i] != NULL; i++)
- avp[i] = tpvp[i];
- avp[i] = NULL;
-
- /*
- ** If we got this far, we've processed the left
- ** most subroutine, and recursively called ourselves
- ** to handle any other subroutines. We're done.
- */
-
- break;
- }
- }
- return rstat;
-}
- /*
-** MAP_LOOKUP -- do lookup in map
-**
-** Parameters:
-** map -- the map to use for the lookup.
-** key -- the key to look up.
-** argvect -- arguments to pass to the map lookup.
-** pstat -- a pointer to an integer in which to store the
-** status from the lookup.
-** e -- the current envelope.
-**
-** Returns:
-** The result of the lookup.
-** NULL -- if there was no data for the given key.
-*/
-
-char *
-map_lookup(map, key, argvect, pstat, e)
- STAB *map;
- char key[];
- char **argvect;
- int *pstat;
- ENVELOPE *e;
-{
- auto int stat = EX_OK;
- char *replac;
-
- if (e->e_sendmode == SM_DEFER)
- {
- /* don't do any map lookups */
- if (tTd(60, 1))
- printf("map_lookup(%s, %s) => DEFERRED\n",
- map->s_name, key);
- *pstat = EX_TEMPFAIL;
- return NULL;
- }
- if (map == NULL || !bitset(MF_OPEN, map->s_map.map_mflags))
- return NULL;
-
- if (!bitset(MF_KEEPQUOTES, map->s_map.map_mflags))
- stripquotes(key);
-
- /* XXX should try to auto-open the map here */
-
- if (tTd(60, 1))
- {
- printf("map_lookup(%s, %s", map->s_name, key);
- if (tTd(60, 5))
- {
- int i;
-
- for (i = 0; argvect[i] != NULL; i++)
- printf(", %%%d=%s", i, argvect[i]);
- }
- printf(") => ");
- }
- replac = (*map->s_map.map_class->map_lookup)(&map->s_map,
- key, argvect, &stat);
- if (tTd(60, 1))
- printf("%s (%d)\n",
- replac != NULL ? replac : "NOT FOUND",
- stat);
-
- /* should recover if stat == EX_TEMPFAIL */
- if (stat == EX_TEMPFAIL && !bitset(MF_NODEFER, map->s_map.map_mflags))
- {
- *pstat = EX_TEMPFAIL;
- if (tTd(60, 1))
- printf("map_lookup(%s, %s) tempfail: errno=%d\n",
- map->s_name, key, errno);
- if (e->e_message == NULL)
- {
- char mbuf[320];
-
- snprintf(mbuf, sizeof mbuf,
- "%.80s map: lookup (%s): deferred",
- map->s_name,
- shortenstring(key, MAXSHORTSTR));
- e->e_message = newstr(mbuf);
- }
- }
- if (stat == EX_TEMPFAIL && map->s_map.map_tapp != NULL)
- {
- size_t i = strlen(key) + strlen(map->s_map.map_tapp) + 1;
- static char *rwbuf = NULL;
- static size_t rwbuflen = 0;
-
- if (i > rwbuflen)
- {
- if (rwbuf != NULL)
- free(rwbuf);
- rwbuflen = i;
- rwbuf = (char *) xalloc(rwbuflen);
- }
- snprintf(rwbuf, rwbuflen, "%s%s", key, map->s_map.map_tapp);
- if (tTd(60, 4))
- printf("map_lookup tempfail: returning \"%s\"\n",
- rwbuf);
- return rwbuf;
- }
- return replac;
-}
- /*
-** BUILDADDR -- build address from token vector.
-**
-** Parameters:
-** tv -- token vector.
-** a -- pointer to address descriptor to fill.
-** If NULL, one will be allocated.
-** flags -- info regarding whether this is a sender or
-** a recipient.
-** e -- the current envelope.
-**
-** Returns:
-** NULL if there was an error.
-** 'a' otherwise.
-**
-** Side Effects:
-** fills in 'a'
-*/
-
-struct errcodes
-{
- char *ec_name; /* name of error code */
- int ec_code; /* numeric code */
-} ErrorCodes[] =
-{
- { "usage", EX_USAGE },
- { "nouser", EX_NOUSER },
- { "nohost", EX_NOHOST },
- { "unavailable", EX_UNAVAILABLE },
- { "software", EX_SOFTWARE },
- { "tempfail", EX_TEMPFAIL },
- { "protocol", EX_PROTOCOL },
-#ifdef EX_CONFIG
- { "config", EX_CONFIG },
-#endif
- { NULL, EX_UNAVAILABLE }
-};
-
-ADDRESS *
-buildaddr(tv, a, flags, e)
- register char **tv;
- register ADDRESS *a;
- int flags;
- register ENVELOPE *e;
-{
- struct mailer **mp;
- register struct mailer *m;
- register char *p;
- char *mname;
- char **hostp;
- char hbuf[MAXNAME + 1];
- static MAILER discardmailer;
- static MAILER errormailer;
- static char *discardargv[] = { "DISCARD", NULL };
- static char *errorargv[] = { "ERROR", NULL };
- static char ubuf[MAXNAME + 2];
-
- if (tTd(24, 5))
- {
- printf("buildaddr, flags=%x, tv=", flags);
- printav(tv);
- }
-
- if (a == NULL)
- a = (ADDRESS *) xalloc(sizeof *a);
- bzero((char *) a, sizeof *a);
-
- /* set up default error return flags */
- a->q_flags |= DefaultNotify;
-
- if (discardmailer.m_name == NULL)
- {
- /* initialize the discard mailer */
- discardmailer.m_name = "*discard*";
- discardmailer.m_mailer = "DISCARD";
- discardmailer.m_argv = discardargv;
- }
-
- /* figure out what net/mailer to use */
- if (*tv == NULL || (**tv & 0377) != CANONNET)
- {
- syserr("554 buildaddr: no mailer in parsed address");
-badaddr:
- a->q_flags |= QBADADDR;
- a->q_mailer = &errormailer;
- if (errormailer.m_name == NULL)
- {
- /* initialize the bogus mailer */
- errormailer.m_name = "*error*";
- errormailer.m_mailer = "ERROR";
- errormailer.m_argv = errorargv;
- }
- return a;
- }
- mname = *++tv;
-
- /* extract host and user portions */
- if (*++tv != NULL && (**tv & 0377) == CANONHOST)
- hostp = ++tv;
- else
- hostp = NULL;
- while (*tv != NULL && (**tv & 0377) != CANONUSER)
- tv++;
- if (*tv == NULL)
- {
- syserr("554 buildaddr: no user");
- goto badaddr;
- }
- if (tv == hostp)
- hostp = NULL;
- else if (hostp != NULL)
- cataddr(hostp, tv - 1, hbuf, sizeof hbuf, '\0');
- cataddr(++tv, NULL, ubuf, sizeof ubuf, ' ');
-
- /* save away the host name */
- if (strcasecmp(mname, "error") == 0)
- {
- if (hostp != NULL)
- {
- register struct errcodes *ep;
-
- if (strchr(hbuf, '.') != NULL)
- {
- extern int dsntoexitstat __P((char *));
-
- a->q_status = newstr(hbuf);
- setstat(dsntoexitstat(hbuf));
- }
- else if (isascii(hbuf[0]) && isdigit(hbuf[0]))
- {
- setstat(atoi(hbuf));
- }
- else
- {
- for (ep = ErrorCodes; ep->ec_name != NULL; ep++)
- if (strcasecmp(ep->ec_name, hbuf) == 0)
- break;
- setstat(ep->ec_code);
- }
- }
- else
- setstat(EX_UNAVAILABLE);
- stripquotes(ubuf);
- if (isascii(ubuf[0]) && isdigit(ubuf[0]) &&
- isascii(ubuf[1]) && isdigit(ubuf[1]) &&
- isascii(ubuf[2]) && isdigit(ubuf[2]) &&
- ubuf[3] == ' ')
- {
- char fmt[10];
-
- strncpy(fmt, ubuf, 3);
- strcpy(&fmt[3], " %s");
- usrerr(fmt, ubuf + 4);
-
- /*
- ** If this is a 4xx code and we aren't running
- ** SMTP on our input, bounce this message;
- ** otherwise it disappears without a trace.
- */
-
- if (fmt[0] == '4' && OpMode != MD_SMTP &&
- OpMode != MD_DAEMON)
- {
- e->e_flags |= EF_FATALERRS;
- }
- }
- else
- {
- usrerr("553 %s", ubuf);
- }
- goto badaddr;
- }
-
- for (mp = Mailer; (m = *mp++) != NULL; )
- {
- if (strcasecmp(m->m_name, mname) == 0)
- break;
- }
- if (m == NULL)
- {
- syserr("554 buildaddr: unknown mailer %s", mname);
- goto badaddr;
- }
- a->q_mailer = m;
-
- /* figure out what host (if any) */
- if (hostp == NULL)
- {
- if (!bitnset(M_LOCALMAILER, m->m_flags))
- {
- syserr("554 buildaddr: no host");
- goto badaddr;
- }
- a->q_host = NULL;
- }
- else
- a->q_host = newstr(hbuf);
-
- /* figure out the user */
- p = ubuf;
- if (bitnset(M_CHECKUDB, m->m_flags) && *p == '@')
- {
- p++;
- tv++;
- a->q_flags |= QNOTREMOTE;
- }
-
- /* do special mapping for local mailer */
- if (*p == '"')
- p++;
- if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags))
- a->q_mailer = m = ProgMailer;
- else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags))
- a->q_mailer = m = FileMailer;
- else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags))
- {
- /* may be :include: */
- stripquotes(ubuf);
- if (strncasecmp(ubuf, ":include:", 9) == 0)
- {
- /* if :include:, don't need further rewriting */
- a->q_mailer = m = InclMailer;
- a->q_user = newstr(&ubuf[9]);
- return a;
- }
- }
-
- /* rewrite according recipient mailer rewriting rules */
- define('h', a->q_host, e);
- if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags))
- {
- /* sender addresses done later */
- (void) rewrite(tv, 2, 0, e);
- if (m->m_re_rwset > 0)
- (void) rewrite(tv, m->m_re_rwset, 0, e);
- }
- (void) rewrite(tv, 4, 0, e);
-
- /* save the result for the command line/RCPT argument */
- cataddr(tv, NULL, ubuf, sizeof ubuf, '\0');
- a->q_user = ubuf;
-
- /*
- ** Do mapping to lower case as requested by mailer
- */
-
- if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags))
- makelower(a->q_host);
- if (!bitnset(M_USR_UPPER, m->m_flags))
- makelower(a->q_user);
-
- if (tTd(24, 6))
- {
- printf("buildaddr => ");
- printaddr(a, FALSE);
- }
- return a;
-}
- /*
-** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs)
-**
-** Parameters:
-** pvp -- parameter vector to rebuild.
-** evp -- last parameter to include. Can be NULL to
-** use entire pvp.
-** buf -- buffer to build the string into.
-** sz -- size of buf.
-** spacesub -- the space separator character; if null,
-** use SpaceSub.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Destroys buf.
-*/
-
-void
-cataddr(pvp, evp, buf, sz, spacesub)
- char **pvp;
- char **evp;
- char *buf;
- register int sz;
- int spacesub;
-{
- bool oatomtok = FALSE;
- bool natomtok = FALSE;
- register int i;
- register char *p;
-
- if (spacesub == '\0')
- spacesub = SpaceSub;
-
- if (pvp == NULL)
- {
- (void) strcpy(buf, "");
- return;
- }
- p = buf;
- sz -= 2;
- while (*pvp != NULL && (i = strlen(*pvp)) < sz)
- {
- natomtok = (TokTypeTab[**pvp & 0xff] == ATM);
- if (oatomtok && natomtok)
- *p++ = spacesub;
- (void) strcpy(p, *pvp);
- oatomtok = natomtok;
- p += i;
- sz -= i + 1;
- if (pvp++ == evp)
- break;
- }
- *p = '\0';
-}
- /*
-** SAMEADDR -- Determine if two addresses are the same
-**
-** This is not just a straight comparison -- if the mailer doesn't
-** care about the host we just ignore it, etc.
-**
-** Parameters:
-** a, b -- pointers to the internal forms to compare.
-**
-** Returns:
-** TRUE -- they represent the same mailbox.
-** FALSE -- they don't.
-**
-** Side Effects:
-** none.
-*/
-
-bool
-sameaddr(a, b)
- register ADDRESS *a;
- register ADDRESS *b;
-{
- register ADDRESS *ca, *cb;
-
- /* if they don't have the same mailer, forget it */
- if (a->q_mailer != b->q_mailer)
- return (FALSE);
-
- /* if the user isn't the same, we can drop out */
- if (strcmp(a->q_user, b->q_user) != 0)
- return (FALSE);
-
- /* if we have good uids for both but they differ, these are different */
- if (a->q_mailer == ProgMailer)
- {
- ca = getctladdr(a);
- cb = getctladdr(b);
- if (ca != NULL && cb != NULL &&
- bitset(QGOODUID, ca->q_flags & cb->q_flags) &&
- ca->q_uid != cb->q_uid)
- return (FALSE);
- }
-
- /* otherwise compare hosts (but be careful for NULL ptrs) */
- if (a->q_host == b->q_host)
- {
- /* probably both null pointers */
- return (TRUE);
- }
- if (a->q_host == NULL || b->q_host == NULL)
- {
- /* only one is a null pointer */
- return (FALSE);
- }
- if (strcmp(a->q_host, b->q_host) != 0)
- return (FALSE);
-
- return (TRUE);
-}
- /*
-** PRINTADDR -- print address (for debugging)
-**
-** Parameters:
-** a -- the address to print
-** follow -- follow the q_next chain.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** none.
-*/
-
-struct qflags
-{
- char *qf_name;
- u_long qf_bit;
-};
-
-struct qflags AddressFlags[] =
-{
- { "QDONTSEND", QDONTSEND },
- { "QBADADDR", QBADADDR },
- { "QGOODUID", QGOODUID },
- { "QPRIMARY", QPRIMARY },
- { "QQUEUEUP", QQUEUEUP },
- { "QSENT", QSENT },
- { "QNOTREMOTE", QNOTREMOTE },
- { "QSELFREF", QSELFREF },
- { "QVERIFIED", QVERIFIED },
- { "QBOGUSSHELL", QBOGUSSHELL },
- { "QUNSAFEADDR", QUNSAFEADDR },
- { "QPINGONSUCCESS", QPINGONSUCCESS },
- { "QPINGONFAILURE", QPINGONFAILURE },
- { "QPINGONDELAY", QPINGONDELAY },
- { "QHASNOTIFY", QHASNOTIFY },
- { "QRELAYED", QRELAYED },
- { "QEXPANDED", QEXPANDED },
- { "QDELIVERED", QDELIVERED },
- { "QDELAYED", QDELAYED },
- { "QTHISPASS", QTHISPASS },
- { "QRCPTOK", QRCPTOK },
- { NULL }
-};
-
-void
-printaddr(a, follow)
- register ADDRESS *a;
- bool follow;
-{
- register MAILER *m;
- MAILER pseudomailer;
- register struct qflags *qfp;
- bool firstone;
-
- if (a == NULL)
- {
- printf("[NULL]\n");
- return;
- }
-
- while (a != NULL)
- {
- printf("%lx=", (u_long) a);
- (void) fflush(stdout);
-
- /* find the mailer -- carefully */
- m = a->q_mailer;
- if (m == NULL)
- {
- m = &pseudomailer;
- m->m_mno = -1;
- m->m_name = "NULL";
- }
-
- printf("%s:\n\tmailer %d (%s), host `%s'\n",
- a->q_paddr == NULL ? "<null>" : a->q_paddr,
- m->m_mno, m->m_name,
- a->q_host == NULL ? "<null>" : a->q_host);
- printf("\tuser `%s', ruser `%s'\n",
- a->q_user,
- a->q_ruser == NULL ? "<null>" : a->q_ruser);
- printf("\tnext=%lx, alias %lx, uid %d, gid %d\n",
- (u_long) a->q_next, (u_long) a->q_alias,
- (int) a->q_uid, (int) a->q_gid);
- printf("\tflags=%lx<", a->q_flags);
- firstone = TRUE;
- for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++)
- {
- if (!bitset(qfp->qf_bit, a->q_flags))
- continue;
- if (!firstone)
- printf(",");
- firstone = FALSE;
- printf("%s", qfp->qf_name);
- }
- printf(">\n");
- printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n",
- a->q_owner == NULL ? "(none)" : a->q_owner,
- a->q_home == NULL ? "(none)" : a->q_home,
- a->q_fullname == NULL ? "(none)" : a->q_fullname);
- printf("\torcpt=\"%s\", statmta=%s, status=%s\n",
- a->q_orcpt == NULL ? "(none)" : a->q_orcpt,
- a->q_statmta == NULL ? "(none)" : a->q_statmta,
- a->q_status == NULL ? "(none)" : a->q_status);
- printf("\trstatus=\"%s\"\n",
- a->q_rstatus == NULL ? "(none)" : a->q_rstatus);
- printf("\tspecificity=%d, statdate=%s\n",
- a->q_specificity, ctime(&a->q_statdate));
-
- if (!follow)
- return;
- a = a->q_next;
- }
-}
- /*
-** EMPTYADDR -- return TRUE if this address is empty (``<>'')
-**
-** Parameters:
-** a -- pointer to the address
-**
-** Returns:
-** TRUE -- if this address is "empty" (i.e., no one should
-** ever generate replies to it.
-** FALSE -- if it is a "regular" (read: replyable) address.
-*/
-
-bool
-emptyaddr(a)
- register ADDRESS *a;
-{
- return a->q_paddr == NULL || strcmp(a->q_paddr, "<>") == 0 ||
- a->q_user == NULL || strcmp(a->q_user, "<>") == 0;
-}
- /*
-** REMOTENAME -- return the name relative to the current mailer
-**
-** Parameters:
-** name -- the name to translate.
-** m -- the mailer that we want to do rewriting relative
-** to.
-** flags -- fine tune operations.
-** pstat -- pointer to status word.
-** e -- the current envelope.
-**
-** Returns:
-** the text string representing this address relative to
-** the receiving mailer.
-**
-** Side Effects:
-** none.
-**
-** Warnings:
-** The text string returned is tucked away locally;
-** copy it if you intend to save it.
-*/
-
-char *
-remotename(name, m, flags, pstat, e)
- char *name;
- struct mailer *m;
- int flags;
- int *pstat;
- register ENVELOPE *e;
-{
- register char **pvp;
- char *fancy;
- char *oldg = macvalue('g', e);
- int rwset;
- static char buf[MAXNAME + 1];
- char lbuf[MAXNAME + 1];
- char pvpbuf[PSBUFSIZE];
- extern char *crackaddr __P((char *));
-
- if (tTd(12, 1))
- printf("remotename(%s)\n", name);
-
- /* don't do anything if we are tagging it as special */
- if (bitset(RF_SENDERADDR, flags))
- rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset
- : m->m_se_rwset;
- else
- rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset
- : m->m_re_rwset;
- if (rwset < 0)
- return (name);
-
- /*
- ** Do a heuristic crack of this name to extract any comment info.
- ** This will leave the name as a comment and a $g macro.
- */
-
- if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags))
- fancy = "\201g";
- else
- fancy = crackaddr(name);
-
- /*
- ** Turn the name into canonical form.
- ** Normally this will be RFC 822 style, i.e., "user@domain".
- ** If this only resolves to "user", and the "C" flag is
- ** specified in the sending mailer, then the sender's
- ** domain will be appended.
- */
-
- pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL);
- if (pvp == NULL)
- return (name);
- if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
- *pstat = EX_TEMPFAIL;
- if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL)
- {
- /* append from domain to this address */
- register char **pxp = pvp;
-
- /* see if there is an "@domain" in the current name */
- while (*pxp != NULL && strcmp(*pxp, "@") != 0)
- pxp++;
- if (*pxp == NULL)
- {
- /* no.... append the "@domain" from the sender */
- register char **qxq = e->e_fromdomain;
-
- while ((*pxp++ = *qxq++) != NULL)
- continue;
- if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
- *pstat = EX_TEMPFAIL;
- }
- }
-
- /*
- ** Do more specific rewriting.
- ** Rewrite using ruleset 1 or 2 depending on whether this is
- ** a sender address or not.
- ** Then run it through any receiving-mailer-specific rulesets.
- */
-
- if (bitset(RF_SENDERADDR, flags))
- {
- if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL)
- *pstat = EX_TEMPFAIL;
- }
- else
- {
- if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL)
- *pstat = EX_TEMPFAIL;
- }
- if (rwset > 0)
- {
- if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL)
- *pstat = EX_TEMPFAIL;
- }
-
- /*
- ** Do any final sanitation the address may require.
- ** This will normally be used to turn internal forms
- ** (e.g., user@host.LOCAL) into external form. This
- ** may be used as a default to the above rules.
- */
-
- if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL)
- *pstat = EX_TEMPFAIL;
-
- /*
- ** Now restore the comment information we had at the beginning.
- */
-
- cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0');
- define('g', lbuf, e);
-
- /* need to make sure route-addrs have <angle brackets> */
- if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@')
- expand("<\201g>", buf, sizeof buf, e);
- else
- expand(fancy, buf, sizeof buf, e);
-
- define('g', oldg, e);
-
- if (tTd(12, 1))
- printf("remotename => `%s'\n", buf);
- return (buf);
-}
- /*
-** MAPLOCALUSER -- run local username through ruleset 5 for final redirection
-**
-** Parameters:
-** a -- the address to map (but just the user name part).
-** sendq -- the sendq in which to install any replacement
-** addresses.
-** aliaslevel -- the alias nesting depth.
-** e -- the envelope.
-**
-** Returns:
-** none.
-*/
-
-#define Q_COPYFLAGS (QPRIMARY|QBOGUSSHELL|QUNSAFEADDR|\
- Q_PINGFLAGS|QHASNOTIFY|\
- QRELAYED|QEXPANDED|QDELIVERED|QDELAYED)
-
-void
-maplocaluser(a, sendq, aliaslevel, e)
- register ADDRESS *a;
- ADDRESS **sendq;
- int aliaslevel;
- ENVELOPE *e;
-{
- register char **pvp;
- register ADDRESS *a1 = NULL;
- auto char *delimptr;
- char pvpbuf[PSBUFSIZE];
-
- if (tTd(29, 1))
- {
- printf("maplocaluser: ");
- printaddr(a, FALSE);
- }
- pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr, NULL);
- if (pvp == NULL)
- {
- if (tTd(29, 9))
- printf("maplocaluser: cannot prescan %s\n", a->q_user);
- return;
- }
-
- define('h', a->q_host, e);
- define('u', a->q_user, e);
- define('z', a->q_home, e);
-
- if (rewrite(pvp, 5, 0, e) == EX_TEMPFAIL)
- {
- if (tTd(29, 9))
- printf("maplocaluser: rewrite tempfail\n");
- a->q_flags |= QQUEUEUP;
- a->q_status = "4.4.3";
- return;
- }
- if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
- {
- if (tTd(29, 9))
- printf("maplocaluser: doesn't resolve\n");
- return;
- }
-
- /* if non-null, mailer destination specified -- has it changed? */
- a1 = buildaddr(pvp, NULL, 0, e);
- if (a1 == NULL || sameaddr(a, a1))
- {
- if (tTd(29, 9))
- printf("maplocaluser: address unchanged\n");
- if (a1 != NULL)
- free(a1);
- return;
- }
-
- /* make new address take on flags and print attributes of old */
- a1->q_flags &= ~Q_COPYFLAGS;
- a1->q_flags |= a->q_flags & Q_COPYFLAGS;
- a1->q_paddr = a->q_paddr;
-
- /* mark old address as dead; insert new address */
- a->q_flags |= QDONTSEND;
- if (tTd(29, 5))
- {
- printf("maplocaluser: QDONTSEND ");
- printaddr(a, FALSE);
- }
- a1->q_alias = a;
- allocaddr(a1, RF_COPYALL, a->q_paddr);
- (void) recipient(a1, sendq, aliaslevel, e);
-}
- /*
-** DEQUOTE_INIT -- initialize dequote map
-**
-** This is a no-op.
-**
-** Parameters:
-** map -- the internal map structure.
-** args -- arguments.
-**
-** Returns:
-** TRUE.
-*/
-
-bool
-dequote_init(map, args)
- MAP *map;
- char *args;
-{
- register char *p = args;
-
- map->map_mflags |= MF_KEEPQUOTES;
- for (;;)
- {
- while (isascii(*p) && isspace(*p))
- p++;
- if (*p != '-')
- break;
- switch (*++p)
- {
- case 'a':
- map->map_app = ++p;
- break;
-
- case 's':
- map->map_coldelim = *++p;
- break;
- }
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
- p++;
- if (*p != '\0')
- *p = '\0';
- }
- if (map->map_app != NULL)
- map->map_app = newstr(map->map_app);
-
- return TRUE;
-}
- /*
-** DEQUOTE_MAP -- unquote an address
-**
-** Parameters:
-** map -- the internal map structure (ignored).
-** name -- the name to dequote.
-** av -- arguments (ignored).
-** statp -- pointer to status out-parameter.
-**
-** Returns:
-** NULL -- if there were no quotes, or if the resulting
-** unquoted buffer would not be acceptable to prescan.
-** else -- The dequoted buffer.
-*/
-
-/* ARGSUSED2 */
-char *
-dequote_map(map, name, av, statp)
- MAP *map;
- char *name;
- char **av;
- int *statp;
-{
- register char *p;
- register char *q;
- register char c;
- int anglecnt = 0;
- int cmntcnt = 0;
- int quotecnt = 0;
- int spacecnt = 0;
- bool quotemode = FALSE;
- bool bslashmode = FALSE;
- char spacesub = map->map_coldelim;
-
- for (p = q = name; (c = *p++) != '\0'; )
- {
- if (bslashmode)
- {
- bslashmode = FALSE;
- *q++ = c;
- continue;
- }
-
- if (c == ' ' && spacesub != '\0')
- c = spacesub;
-
- switch (c)
- {
- case '\\':
- bslashmode = TRUE;
- break;
-
- case '(':
- cmntcnt++;
- break;
-
- case ')':
- if (cmntcnt-- <= 0)
- return NULL;
- break;
-
- case ' ':
- spacecnt++;
- break;
- }
-
- if (cmntcnt > 0)
- {
- *q++ = c;
- continue;
- }
-
- switch (c)
- {
- case '"':
- quotemode = !quotemode;
- quotecnt++;
- continue;
-
- case '<':
- anglecnt++;
- break;
-
- case '>':
- if (anglecnt-- <= 0)
- return NULL;
- break;
- }
- *q++ = c;
- }
-
- if (anglecnt != 0 || cmntcnt != 0 || bslashmode ||
- quotemode || quotecnt <= 0 || spacecnt != 0)
- return NULL;
- *q++ = '\0';
- return map_rewrite(map, name, strlen(name), NULL);
-}
- /*
-** RSCHECK -- check string(s) for validity using rewriting sets
-**
-** Parameters:
-** rwset -- the rewriting set to use.
-** p1 -- the first string to check.
-** p2 -- the second string to check -- may be null.
-** e -- the current envelope.
-**
-** Returns:
-** EX_OK -- if the rwset doesn't resolve to $#error
-** else -- the failure status (message printed)
-*/
-
-int
-rscheck(rwset, p1, p2, e)
- char *rwset;
- char *p1;
- char *p2;
- ENVELOPE *e;
-{
- char *buf;
- int bufsize;
- int saveexitstat;
- int rstat = EX_OK;
- char **pvp;
- int rsno;
- bool discard = FALSE;
- auto ADDRESS a1;
- bool saveQuickAbort = QuickAbort;
- bool saveSuprErrs = SuprErrs;
- char buf0[MAXLINE];
- char pvpbuf[PSBUFSIZE];
- extern char MsgBuf[];
-
- if (tTd(48, 2))
- printf("rscheck(%s, %s, %s)\n", rwset, p1,
- p2 == NULL ? "(NULL)" : p2);
-
- rsno = strtorwset(rwset, NULL, ST_FIND);
- if (rsno < 0)
- return EX_OK;
-
- if (p2 != NULL)
- {
- bufsize = strlen(p1) + strlen(p2) + 2;
- if (bufsize > sizeof buf0)
- buf = xalloc(bufsize);
- else
- {
- buf = buf0;
- bufsize = sizeof buf0;
- }
- (void) snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2);
- }
- else
- {
- bufsize = strlen(p1) + 1;
- if (bufsize > sizeof buf0)
- buf = xalloc(bufsize);
- else
- {
- buf = buf0;
- bufsize = sizeof buf0;
- }
- (void) snprintf(buf, bufsize, "%s", p1);
- }
- SuprErrs = TRUE;
- QuickAbort = FALSE;
- pvp = prescan(buf, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL);
- SuprErrs = saveSuprErrs;
- if (pvp == NULL)
- {
- if (tTd(48, 2))
- printf("rscheck: cannot prescan input\n");
-/*
- syserr("rscheck: cannot prescan input: \"%s\"",
- shortenstring(buf, MAXSHORTSTR));
- rstat = EX_DATAERR;
-*/
- goto finis;
- }
- (void) rewrite(pvp, rsno, 0, e);
- if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET ||
- pvp[1] == NULL || (strcmp(pvp[1], "error") != 0 &&
- strcmp(pvp[1], "discard") != 0))
- {
- goto finis;
- }
-
- if (strcmp(pvp[1], "discard") == 0)
- {
- if (tTd(48, 2))
- printf("rscheck: discard mailer selected\n");
- e->e_flags |= EF_DISCARD;
- discard = TRUE;
- }
- else
- {
- int savelogusrerrs = LogUsrErrs;
- static bool logged = FALSE;
-
- /* got an error -- process it */
- saveexitstat = ExitStat;
- LogUsrErrs = FALSE;
- (void) buildaddr(pvp, &a1, 0, e);
- LogUsrErrs = savelogusrerrs;
- rstat = ExitStat;
- ExitStat = saveexitstat;
- if (!logged)
- {
- markstats(e, &a1, TRUE);
- logged = TRUE;
- }
- }
-
- if (LogLevel >= 4)
- {
- char *relay;
- char *p;
- char lbuf[MAXLINE];
-
- p = lbuf;
- if (p2 != NULL)
- {
- snprintf(p, SPACELEFT(lbuf, p),
- ", arg2=%s",
- p2);
- p += strlen(p);
- }
- if ((relay = macvalue('_', e)) != NULL)
- {
- snprintf(p, SPACELEFT(lbuf, p),
- ", relay=%s", relay);
- p += strlen(p);
- }
- *p = '\0';
- if (discard)
- sm_syslog(LOG_NOTICE, e->e_id,
- "ruleset=%s, arg1=%s%s, discard",
- rwset, p1, lbuf);
- else
- sm_syslog(LOG_NOTICE, e->e_id,
- "ruleset=%s, arg1=%s%s, reject=%s",
- rwset, p1, lbuf, MsgBuf);
- }
-
- finis:
- /* clean up */
- QuickAbort = saveQuickAbort;
- setstat(rstat);
- if (buf != buf0)
- free(buf);
-
- if (rstat != EX_OK && QuickAbort)
- longjmp(TopFrame, 2);
- return rstat;
-}
diff --git a/src/pathnames.h b/src/pathnames.h
deleted file mode 100644
index 7a06b12..0000000
--- a/src/pathnames.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*-
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- *
- * @(#)pathnames.h 8.8 (Berkeley) 5/19/1998
- */
-
-#ifndef _PATH_SENDMAILCF
-# if defined(USE_VENDOR_CF_PATH) && defined(_PATH_VENDOR_CF)
-# define _PATH_SENDMAILCF _PATH_VENDOR_CF
-# else
-# define _PATH_SENDMAILCF "/etc/sendmail.cf"
-# endif
-#endif
-
-#ifndef _PATH_SENDMAILPID
-# ifdef BSD4_4
-# define _PATH_SENDMAILPID "/var/run/sendmail.pid"
-# else
-# define _PATH_SENDMAILPID "/etc/sendmail.pid"
-# endif
-#endif
-
-#ifndef _PATH_HOSTS
-# define _PATH_HOSTS "/etc/hosts"
-#endif
diff --git a/src/queue.c b/src/queue.c
deleted file mode 100644
index b02fc08..0000000
--- a/src/queue.c
+++ /dev/null
@@ -1,2422 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-# include "sendmail.h"
-
-#ifndef lint
-#if QUEUE
-static char sccsid[] = "@(#)queue.c 8.211 (Berkeley) 1/25/1999 (with queueing)";
-#else
-static char sccsid[] = "@(#)queue.c 8.211 (Berkeley) 1/25/1999 (without queueing)";
-#endif
-#endif /* not lint */
-
-# include <errno.h>
-# include <dirent.h>
-
-# if QUEUE
-
-/*
-** Work queue.
-*/
-
-struct work
-{
- char *w_name; /* name of control file */
- char *w_host; /* name of recipient host */
- bool w_lock; /* is message locked? */
- bool w_tooyoung; /* is it too young to run? */
- long w_pri; /* priority of message, see below */
- time_t w_ctime; /* creation time of message */
- struct work *w_next; /* next in queue */
-};
-
-typedef struct work WORK;
-
-WORK *WorkQ; /* queue of things to be done */
-
-#define QF_VERSION 2 /* version number of this queue format */
-
-extern int orderq __P((bool));
- /*
-** QUEUEUP -- queue a message up for future transmission.
-**
-** Parameters:
-** e -- the envelope to queue up.
-** announce -- if TRUE, tell when you are queueing up.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** The current request are saved in a control file.
-** The queue file is left locked.
-*/
-
-void
-queueup(e, announce)
- register ENVELOPE *e;
- bool announce;
-{
- char *qf;
- register FILE *tfp;
- register HDR *h;
- register ADDRESS *q;
- int fd;
- int i;
- bool newid;
- register char *p;
- MAILER nullmailer;
- MCI mcibuf;
- char tf[MAXQFNAME];
- char buf[MAXLINE];
- extern void printctladdr __P((ADDRESS *, FILE *));
-
- /*
- ** Create control file.
- */
-
- newid = (e->e_id == NULL) || !bitset(EF_INQUEUE, e->e_flags);
-
- /* if newid, queuename will create a locked qf file in e->lockfp */
- strcpy(tf, queuename(e, 't'));
- tfp = e->e_lockfp;
- if (tfp == NULL)
- newid = FALSE;
-
- /* if newid, just write the qf file directly (instead of tf file) */
- if (!newid)
- {
- /* get a locked tf file */
- for (i = 0; i < 128; i++)
- {
- fd = open(tf, O_CREAT|O_WRONLY|O_EXCL, FileMode);
- if (fd < 0)
- {
- if (errno != EEXIST)
- break;
- if (LogLevel > 0 && (i % 32) == 0)
- sm_syslog(LOG_ALERT, e->e_id,
- "queueup: cannot create %s, uid=%d: %s",
- tf, geteuid(), errstring(errno));
- }
- else
- {
- if (lockfile(fd, tf, NULL, LOCK_EX|LOCK_NB))
- break;
- else if (LogLevel > 0 && (i % 32) == 0)
- sm_syslog(LOG_ALERT, e->e_id,
- "queueup: cannot lock %s: %s",
- tf, errstring(errno));
- close(fd);
- }
-
- if ((i % 32) == 31)
- {
- /* save the old temp file away */
- (void) rename(tf, queuename(e, 'T'));
- }
- else
- sleep(i % 32);
- }
- if (fd < 0 || (tfp = fdopen(fd, "w")) == NULL)
- {
- printopenfds(TRUE);
- syserr("!queueup: cannot create queue temp file %s, uid=%d",
- tf, geteuid());
- }
- }
-
- if (tTd(40, 1))
- printf("\n>>>>> queueing %s%s >>>>>\n", e->e_id,
- newid ? " (new id)" : "");
- if (tTd(40, 3))
- {
- extern void printenvflags __P((ENVELOPE *));
-
- printf(" e_flags=");
- printenvflags(e);
- }
- if (tTd(40, 32))
- {
- printf(" sendq=");
- printaddr(e->e_sendqueue, TRUE);
- }
- if (tTd(40, 9))
- {
- printf(" tfp=");
- dumpfd(fileno(tfp), TRUE, FALSE);
- printf(" lockfp=");
- if (e->e_lockfp == NULL)
- printf("NULL\n");
- else
- dumpfd(fileno(e->e_lockfp), TRUE, FALSE);
- }
-
- /*
- ** If there is no data file yet, create one.
- */
-
- if (!bitset(EF_HAS_DF, e->e_flags))
- {
- register FILE *dfp = NULL;
- char dfname[MAXQFNAME];
- struct stat stbuf;
-
- strcpy(dfname, queuename(e, 'd'));
- fd = open(dfname, O_WRONLY|O_CREAT|O_TRUNC, FileMode);
- if (fd < 0 || (dfp = fdopen(fd, "w")) == NULL)
- syserr("!queueup: cannot create data temp file %s, uid=%d",
- dfname, geteuid());
- if (fstat(fd, &stbuf) < 0)
- e->e_dfino = -1;
- else
- {
- e->e_dfdev = stbuf.st_dev;
- e->e_dfino = stbuf.st_ino;
- }
- e->e_flags |= EF_HAS_DF;
- bzero(&mcibuf, sizeof mcibuf);
- mcibuf.mci_out = dfp;
- mcibuf.mci_mailer = FileMailer;
- (*e->e_putbody)(&mcibuf, e, NULL);
- (void) xfclose(dfp, "queueup dfp", e->e_id);
- e->e_putbody = putbody;
- }
-
- /*
- ** Output future work requests.
- ** Priority and creation time should be first, since
- ** they are required by orderq.
- */
-
- /* output queue version number (must be first!) */
- fprintf(tfp, "V%d\n", QF_VERSION);
-
- /* output creation time */
- fprintf(tfp, "T%ld\n", (long) e->e_ctime);
-
- /* output last delivery time */
- fprintf(tfp, "K%ld\n", (long) e->e_dtime);
-
- /* output number of delivery attempts */
- fprintf(tfp, "N%d\n", e->e_ntries);
-
- /* output message priority */
- fprintf(tfp, "P%ld\n", e->e_msgpriority);
-
- /* output inode number of data file */
- /* XXX should probably include device major/minor too */
- if (e->e_dfino != -1)
- {
- if (sizeof e->e_dfino > sizeof(long))
- fprintf(tfp, "I%d/%d/%s\n",
- major(e->e_dfdev), minor(e->e_dfdev),
- quad_to_string(e->e_dfino));
- else
- fprintf(tfp, "I%d/%d/%lu\n",
- major(e->e_dfdev), minor(e->e_dfdev),
- (unsigned long) e->e_dfino);
- }
-
- /* output body type */
- if (e->e_bodytype != NULL)
- fprintf(tfp, "B%s\n", denlstring(e->e_bodytype, TRUE, FALSE));
-
-#if _FFR_SAVE_CHARSET
- if (e->e_charset != NULL)
- fprintf(tfp, "X%s\n", denlstring(e->e_charset, TRUE, FALSE));
-#endif
-
- /* message from envelope, if it exists */
- if (e->e_message != NULL)
- fprintf(tfp, "M%s\n", denlstring(e->e_message, TRUE, FALSE));
-
- /* send various flag bits through */
- p = buf;
- if (bitset(EF_WARNING, e->e_flags))
- *p++ = 'w';
- if (bitset(EF_RESPONSE, e->e_flags))
- *p++ = 'r';
- if (bitset(EF_HAS8BIT, e->e_flags))
- *p++ = '8';
- if (bitset(EF_DELETE_BCC, e->e_flags))
- *p++ = 'b';
- if (bitset(EF_RET_PARAM, e->e_flags))
- *p++ = 'd';
- if (bitset(EF_NO_BODY_RETN, e->e_flags))
- *p++ = 'n';
- *p++ = '\0';
- if (buf[0] != '\0')
- fprintf(tfp, "F%s\n", buf);
-
- /* $r and $s and $_ macro values */
- if ((p = macvalue('r', e)) != NULL)
- fprintf(tfp, "$r%s\n", denlstring(p, TRUE, FALSE));
- if ((p = macvalue('s', e)) != NULL)
- fprintf(tfp, "$s%s\n", denlstring(p, TRUE, FALSE));
- if ((p = macvalue('_', e)) != NULL)
- fprintf(tfp, "$_%s\n", denlstring(p, TRUE, FALSE));
-
- /* output name of sender */
- if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags))
- p = e->e_sender;
- else
- p = e->e_from.q_paddr;
- fprintf(tfp, "S%s\n", denlstring(p, TRUE, FALSE));
-
- /* output ESMTP-supplied "original" information */
- if (e->e_envid != NULL)
- fprintf(tfp, "Z%s\n", denlstring(e->e_envid, TRUE, FALSE));
-
- /* output list of recipient addresses */
- printctladdr(NULL, NULL);
- for (q = e->e_sendqueue; q != NULL; q = q->q_next)
- {
- if (bitset(QDONTSEND|QBADADDR|QSENT, q->q_flags))
- {
-#if XDEBUG
- if (bitset(QQUEUEUP, q->q_flags))
- sm_syslog(LOG_DEBUG, e->e_id,
- "dropenvelope: q_flags = %x, paddr = %s",
- q->q_flags, q->q_paddr);
-#endif
- continue;
- }
- printctladdr(q, tfp);
- if (q->q_orcpt != NULL)
- fprintf(tfp, "Q%s\n",
- denlstring(q->q_orcpt, TRUE, FALSE));
- putc('R', tfp);
- if (bitset(QPRIMARY, q->q_flags))
- putc('P', tfp);
- if (bitset(QHASNOTIFY, q->q_flags))
- putc('N', tfp);
- if (bitset(QPINGONSUCCESS, q->q_flags))
- putc('S', tfp);
- if (bitset(QPINGONFAILURE, q->q_flags))
- putc('F', tfp);
- if (bitset(QPINGONDELAY, q->q_flags))
- putc('D', tfp);
- putc(':', tfp);
- fprintf(tfp, "%s\n", denlstring(q->q_paddr, TRUE, FALSE));
- if (announce)
- {
- e->e_to = q->q_paddr;
- message("queued");
- if (LogLevel > 8)
- logdelivery(q->q_mailer, NULL, "queued",
- NULL, (time_t) 0, e);
- e->e_to = NULL;
- }
- if (tTd(40, 1))
- {
- printf("queueing ");
- printaddr(q, FALSE);
- }
- }
-
- /*
- ** Output headers for this message.
- ** Expand macros completely here. Queue run will deal with
- ** everything as absolute headers.
- ** All headers that must be relative to the recipient
- ** can be cracked later.
- ** We set up a "null mailer" -- i.e., a mailer that will have
- ** no effect on the addresses as they are output.
- */
-
- bzero((char *) &nullmailer, sizeof nullmailer);
- nullmailer.m_re_rwset = nullmailer.m_rh_rwset =
- nullmailer.m_se_rwset = nullmailer.m_sh_rwset = -1;
- nullmailer.m_eol = "\n";
- bzero(&mcibuf, sizeof mcibuf);
- mcibuf.mci_mailer = &nullmailer;
- mcibuf.mci_out = tfp;
-
- define('g', "\201f", e);
- for (h = e->e_header; h != NULL; h = h->h_link)
- {
- extern bool bitzerop __P((BITMAP));
-
- if (h->h_value == NULL)
- continue;
-
- /* don't output resent headers on non-resent messages */
- if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
- continue;
-
- /* expand macros; if null, don't output header at all */
- if (bitset(H_DEFAULT, h->h_flags))
- {
- (void) expand(h->h_value, buf, sizeof buf, e);
- if (buf[0] == '\0')
- continue;
- }
-
- /* output this header */
- fprintf(tfp, "H");
-
- /* if conditional, output the set of conditions */
- if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags))
- {
- int j;
-
- (void) putc('?', tfp);
- for (j = '\0'; j <= '\177'; j++)
- if (bitnset(j, h->h_mflags))
- (void) putc(j, tfp);
- (void) putc('?', tfp);
- }
-
- /* output the header: expand macros, convert addresses */
- if (bitset(H_DEFAULT, h->h_flags))
- {
- fprintf(tfp, "%s: %s\n",
- h->h_field,
- denlstring(buf, FALSE, TRUE));
- }
- else if (bitset(H_FROM|H_RCPT, h->h_flags))
- {
- bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
- FILE *savetrace = TrafficLogFile;
-
- TrafficLogFile = NULL;
-
- if (bitset(H_FROM, h->h_flags))
- oldstyle = FALSE;
-
- commaize(h, h->h_value, oldstyle, &mcibuf, e);
-
- TrafficLogFile = savetrace;
- }
- else
- {
- fprintf(tfp, "%s: %s\n",
- h->h_field,
- denlstring(h->h_value, FALSE, TRUE));
- }
- }
-
- /*
- ** Clean up.
- **
- ** Write a terminator record -- this is to prevent
- ** scurrilous crackers from appending any data.
- */
-
- fprintf(tfp, ".\n");
-
- if (fflush(tfp) < 0 ||
- (SuperSafe && fsync(fileno(tfp)) < 0) ||
- ferror(tfp))
- {
- if (newid)
- syserr("!552 Error writing control file %s", tf);
- else
- syserr("!452 Error writing control file %s", tf);
- }
-
- if (!newid)
- {
- /* rename (locked) tf to be (locked) qf */
- qf = queuename(e, 'q');
- if (rename(tf, qf) < 0)
- syserr("cannot rename(%s, %s), uid=%d",
- tf, qf, geteuid());
-
- /* close and unlock old (locked) qf */
- if (e->e_lockfp != NULL)
- (void) xfclose(e->e_lockfp, "queueup lockfp", e->e_id);
- e->e_lockfp = tfp;
- }
- else
- qf = tf;
- errno = 0;
- e->e_flags |= EF_INQUEUE;
-
- /* save log info */
- if (LogLevel > 79)
- sm_syslog(LOG_DEBUG, e->e_id, "queueup, qf=%s", qf);
-
- if (tTd(40, 1))
- printf("<<<<< done queueing %s <<<<<\n\n", e->e_id);
- return;
-}
-
-void
-printctladdr(a, tfp)
- register ADDRESS *a;
- FILE *tfp;
-{
- char *uname;
- register ADDRESS *q;
- uid_t uid;
- gid_t gid;
- static ADDRESS *lastctladdr = NULL;
- static uid_t lastuid;
-
- /* initialization */
- if (a == NULL || a->q_alias == NULL || tfp == NULL)
- {
- if (lastctladdr != NULL && tfp != NULL)
- fprintf(tfp, "C\n");
- lastctladdr = NULL;
- lastuid = 0;
- return;
- }
-
- /* find the active uid */
- q = getctladdr(a);
- if (q == NULL)
- {
- uname = NULL;
- uid = 0;
- gid = 0;
- }
- else
- {
- uname = q->q_ruser != NULL ? q->q_ruser : q->q_user;
- uid = q->q_uid;
- gid = q->q_gid;
- }
- a = a->q_alias;
-
- /* check to see if this is the same as last time */
- if (lastctladdr != NULL && uid == lastuid &&
- strcmp(lastctladdr->q_paddr, a->q_paddr) == 0)
- return;
- lastuid = uid;
- lastctladdr = a;
-
- if (uid == 0 || uname == NULL || uname[0] == '\0')
- fprintf(tfp, "C");
- else
- fprintf(tfp, "C%s:%ld:%ld",
- denlstring(uname, TRUE, FALSE), (long) uid, (long) gid);
- fprintf(tfp, ":%s\n", denlstring(a->q_paddr, TRUE, FALSE));
-}
- /*
-** RUNQUEUE -- run the jobs in the queue.
-**
-** Gets the stuff out of the queue in some presumably logical
-** order and processes them.
-**
-** Parameters:
-** forkflag -- TRUE if the queue scanning should be done in
-** a child process. We double-fork so it is not our
-** child and we don't have to clean up after it.
-** verbose -- if TRUE, print out status information.
-**
-** Returns:
-** TRUE if the queue run successfully began.
-**
-** Side Effects:
-** runs things in the mail queue.
-*/
-
-ENVELOPE QueueEnvelope; /* the queue run envelope */
-extern int get_num_procs_online __P((void));
-
-bool
-runqueue(forkflag, verbose)
- bool forkflag;
- bool verbose;
-{
- register ENVELOPE *e;
- int njobs;
- int sequenceno = 0;
- time_t current_la_time;
- extern ENVELOPE BlankEnvelope;
- extern void clrdaemon __P((void));
- extern void runqueueevent __P((void));
-
- DoQueueRun = FALSE;
-
- /*
- ** If no work will ever be selected, don't even bother reading
- ** the queue.
- */
-
- CurrentLA = getla(); /* get load average */
- current_la_time = curtime();
-
- if (shouldqueue(WkRecipFact, current_la_time))
- {
- char *msg = "Skipping queue run -- load average too high";
-
- if (verbose)
- message("458 %s\n", msg);
- if (LogLevel > 8)
- sm_syslog(LOG_INFO, NOQID,
- "runqueue: %s",
- msg);
- if (forkflag && QueueIntvl != 0)
- (void) setevent(QueueIntvl, runqueueevent, 0);
- return FALSE;
- }
-
- /*
- ** See if we already have too many children.
- */
-
- if (forkflag && QueueIntvl != 0 &&
- MaxChildren > 0 && CurChildren >= MaxChildren)
- {
- (void) setevent(QueueIntvl, runqueueevent, 0);
- return FALSE;
- }
-
- /*
- ** See if we want to go off and do other useful work.
- */
-
- if (forkflag)
- {
- pid_t pid;
- extern SIGFUNC_DECL intsig __P((int));
- extern SIGFUNC_DECL reapchild __P((int));
-
- blocksignal(SIGCHLD);
- (void) setsignal(SIGCHLD, reapchild);
-
- pid = dofork();
- if (pid == -1)
- {
- const char *msg = "Skipping queue run -- fork() failed";
- const char *err = errstring(errno);
-
- if (verbose)
- message("458 %s: %s\n", msg, err);
- if (LogLevel > 8)
- sm_syslog(LOG_INFO, NOQID,
- "runqueue: %s: %s",
- msg, err);
- if (QueueIntvl != 0)
- (void) setevent(QueueIntvl, runqueueevent, 0);
- (void) releasesignal(SIGCHLD);
- return FALSE;
- }
- if (pid != 0)
- {
- /* parent -- pick up intermediate zombie */
- (void) blocksignal(SIGALRM);
- proc_list_add(pid, "Queue runner");
- (void) releasesignal(SIGALRM);
- releasesignal(SIGCHLD);
- if (QueueIntvl != 0)
- (void) setevent(QueueIntvl, runqueueevent, 0);
- return TRUE;
- }
- /* child -- double fork and clean up signals */
- clrcontrol();
- proc_list_clear();
-
- /* Add parent process as first child item */
- proc_list_add(getpid(), "Queue runner child process");
- releasesignal(SIGCHLD);
- (void) setsignal(SIGCHLD, SIG_DFL);
- (void) setsignal(SIGHUP, intsig);
- }
-
- sm_setproctitle(TRUE, "running queue: %s", QueueDir);
-
- if (LogLevel > 69)
- sm_syslog(LOG_DEBUG, NOQID,
- "runqueue %s, pid=%d, forkflag=%d",
- QueueDir, getpid(), forkflag);
-
- /*
- ** Release any resources used by the daemon code.
- */
-
-# if DAEMON
- clrdaemon();
-# endif /* DAEMON */
-
- /* force it to run expensive jobs */
- NoConnect = FALSE;
-
- /* drop privileges */
- if (geteuid() == (uid_t) 0)
- (void) drop_privileges(FALSE);
-
- /*
- ** Create ourselves an envelope
- */
-
- CurEnv = &QueueEnvelope;
- e = newenvelope(&QueueEnvelope, CurEnv);
- e->e_flags = BlankEnvelope.e_flags;
-
- /* make sure we have disconnected from parent */
- if (forkflag)
- {
- disconnect(1, e);
- QuickAbort = FALSE;
- }
-
- /*
- ** Make sure the alias database is open.
- */
-
- initmaps(FALSE, e);
-
- /*
- ** If we are running part of the queue, always ignore stored
- ** host status.
- */
-
- if (QueueLimitId != NULL || QueueLimitSender != NULL ||
- QueueLimitRecipient != NULL)
- {
- IgnoreHostStatus = TRUE;
- MinQueueAge = 0;
- }
-
- /*
- ** Start making passes through the queue.
- ** First, read and sort the entire queue.
- ** Then, process the work in that order.
- ** But if you take too long, start over.
- */
-
- /* order the existing work requests */
- njobs = orderq(FALSE);
-
- /* process them once at a time */
- while (WorkQ != NULL)
- {
- WORK *w = WorkQ;
-
- WorkQ = WorkQ->w_next;
- e->e_to = NULL;
-
- /*
- ** Ignore jobs that are too expensive for the moment.
- **
- ** Get new load average every 30 seconds.
- */
-
- if (current_la_time < curtime() - 30)
- {
- CurrentLA = getla();
- current_la_time = curtime();
- }
- if (shouldqueue(WkRecipFact, current_la_time))
- {
- char *msg = "Aborting queue run: load average too high";
-
- if (Verbose)
- message("%s", msg);
- if (LogLevel > 8)
- sm_syslog(LOG_INFO, NOQID,
- "runqueue: %s",
- msg);
- break;
- }
- sequenceno++;
- if (shouldqueue(w->w_pri, w->w_ctime))
- {
- if (Verbose)
- message("");
- if (QueueSortOrder == QS_BYPRIORITY)
- {
- if (Verbose)
- message("Skipping %s (sequence %d of %d) and flushing rest of queue",
- w->w_name + 2,
- sequenceno,
- njobs);
- if (LogLevel > 8)
- sm_syslog(LOG_INFO, NOQID,
- "runqueue: Flushing queue from %s (pri %ld, LA %d, %d of %d)",
- w->w_name + 2,
- w->w_pri,
- CurrentLA,
- sequenceno,
- njobs);
- break;
- }
- else if (Verbose)
- message("Skipping %s (sequence %d of %d)",
- w->w_name + 2, sequenceno, njobs);
- }
- else
- {
- pid_t pid;
-
- if (Verbose)
- {
- message("");
- message("Running %s (sequence %d of %d)",
- w->w_name + 2, sequenceno, njobs);
- }
- pid = dowork(w->w_name + 2, ForkQueueRuns, FALSE, e);
- errno = 0;
- if (pid != 0)
- (void) waitfor(pid);
- }
- free(w->w_name);
- if (w->w_host)
- free(w->w_host);
- free((char *) w);
- }
-
- /* exit without the usual cleanup */
- e->e_id = NULL;
- finis(TRUE, ExitStat);
- /*NOTREACHED*/
- return TRUE;
-}
-
-
-/*
-** RUNQUEUEEVENT -- stub for use in setevent
-*/
-
-void
-runqueueevent()
-{
- DoQueueRun = TRUE;
-}
- /*
-** ORDERQ -- order the work queue.
-**
-** Parameters:
-** doall -- if set, include everything in the queue (even
-** the jobs that cannot be run because the load
-** average is too high). Otherwise, exclude those
-** jobs.
-**
-** Returns:
-** The number of request in the queue (not necessarily
-** the number of requests in WorkQ however).
-**
-** Side Effects:
-** Sets WorkQ to the queue of available work, in order.
-*/
-
-# define NEED_P 001
-# define NEED_T 002
-# define NEED_R 004
-# define NEED_S 010
-
-static WORK *WorkList = NULL;
-static int WorkListSize = 0;
-
-int
-orderq(doall)
- bool doall;
-{
- register struct dirent *d;
- register WORK *w;
- register char *p;
- DIR *f;
- register int i;
- int wn = -1;
- int wc;
- QUEUE_CHAR *check;
-
- if (tTd(41, 1))
- {
- printf("orderq:\n");
-
- check = QueueLimitId;
- while (check != NULL)
- {
- printf("\tQueueLimitId = %s\n",
- check->queue_match);
- check = check->queue_next;
- }
-
- check = QueueLimitSender;
- while (check != NULL)
- {
- printf("\tQueueLimitSender = %s\n",
- check->queue_match);
- check = check->queue_next;
- }
-
- check = QueueLimitRecipient;
- while (check != NULL)
- {
- printf("\tQueueLimitRecipient = %s\n",
- check->queue_match);
- check = check->queue_next;
- }
- }
-
- /* clear out old WorkQ */
- for (w = WorkQ; w != NULL; )
- {
- register WORK *nw = w->w_next;
-
- WorkQ = nw;
- free(w->w_name);
- if (w->w_host)
- free(w->w_host);
- free((char *) w);
- w = nw;
- }
-
- /* open the queue directory */
- f = opendir(".");
- if (f == NULL)
- {
- syserr("orderq: cannot open \"%s\" as \".\"", QueueDir);
- return (0);
- }
-
- /*
- ** Read the work directory.
- */
-
- while ((d = readdir(f)) != NULL)
- {
- FILE *cf;
- int qfver = 0;
- char lbuf[MAXNAME + 1];
- extern bool strcontainedin __P((char *, char *));
-
- if (tTd(41, 50))
- printf("orderq: checking %s\n", d->d_name);
-
- /* is this an interesting entry? */
- if (d->d_name[0] != 'q' || d->d_name[1] != 'f')
- continue;
-
- if (strlen(d->d_name) > MAXQFNAME)
- {
- if (Verbose)
- printf("orderq: %s too long, %d max characters\n",
- d->d_name, MAXQFNAME);
- if (LogLevel > 0)
- sm_syslog(LOG_ALERT, NOQID,
- "orderq: %s too long, %d max characters",
- d->d_name, MAXQFNAME);
- continue;
- }
-
- check = QueueLimitId;
- while (check != NULL)
- {
- if (strcontainedin(check->queue_match, d->d_name))
- break;
- else
- check = check->queue_next;
- }
- if (QueueLimitId != NULL && check == NULL)
- continue;
-
-#ifdef PICKY_QF_NAME_CHECK
- /*
- ** Check queue name for plausibility. This handles
- ** both old and new type ids.
- */
-
- p = d->d_name + 2;
- if (isupper(p[0]) && isupper(p[2]))
- p += 3;
- else if (isupper(p[1]))
- p += 2;
- else
- p = d->d_name;
- for (i = 0; isdigit(*p); p++)
- i++;
- if (i < 5 || *p != '\0')
- {
- if (Verbose)
- printf("orderq: bogus qf name %s\n", d->d_name);
- if (LogLevel > 0)
- sm_syslog(LOG_ALERT, NOQID,
- "orderq: bogus qf name %s",
- d->d_name);
- if (strlen(d->d_name) > (SIZE_T) MAXNAME)
- d->d_name[MAXNAME] = '\0';
- strcpy(lbuf, d->d_name);
- lbuf[0] = 'Q';
- (void) rename(d->d_name, lbuf);
- continue;
- }
-#endif
-
- /* open control file (if not too many files) */
- if (++wn >= MaxQueueRun && MaxQueueRun > 0)
- {
- if (wn == MaxQueueRun && LogLevel > 0)
- sm_syslog(LOG_ALERT, NOQID,
- "WorkList for %s maxed out at %d",
- QueueDir, MaxQueueRun);
- continue;
- }
- if (wn >= WorkListSize)
- {
- extern void grow_wlist __P((void));
-
- grow_wlist();
- if (wn >= WorkListSize)
- continue;
- }
-
- cf = fopen(d->d_name, "r");
- if (cf == NULL)
- {
- /* this may be some random person sending hir msgs */
- /* syserr("orderq: cannot open %s", cbuf); */
- if (tTd(41, 2))
- printf("orderq: cannot open %s: %s\n",
- d->d_name, errstring(errno));
- errno = 0;
- wn--;
- continue;
- }
- w = &WorkList[wn];
- w->w_name = newstr(d->d_name);
- w->w_host = NULL;
- w->w_lock = !lockfile(fileno(cf), w->w_name, NULL, LOCK_SH|LOCK_NB);
- w->w_tooyoung = FALSE;
-
- /* make sure jobs in creation don't clog queue */
- w->w_pri = 0x7fffffff;
- w->w_ctime = 0;
-
- /* extract useful information */
- i = NEED_P | NEED_T;
- if (QueueLimitSender != NULL)
- i |= NEED_S;
- if (QueueSortOrder == QS_BYHOST || QueueLimitRecipient != NULL)
- i |= NEED_R;
- while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL)
- {
- int c;
- time_t age;
- extern bool strcontainedin __P((char *, char *));
-
- p = strchr(lbuf, '\n');
- if (p != NULL)
- *p = '\0';
- else
- {
- /* flush rest of overly long line */
- while ((c = getc(cf)) != EOF && c != '\n')
- continue;
- }
-
- switch (lbuf[0])
- {
- case 'V':
- qfver = atoi(&lbuf[1]);
- break;
-
- case 'P':
- w->w_pri = atol(&lbuf[1]);
- i &= ~NEED_P;
- break;
-
- case 'T':
- w->w_ctime = atol(&lbuf[1]);
- i &= ~NEED_T;
- break;
-
- case 'R':
- if (w->w_host == NULL &&
- (p = strrchr(&lbuf[1], '@')) != NULL)
- w->w_host = newstr(&p[1]);
- if (QueueLimitRecipient == NULL)
- {
- i &= ~NEED_R;
- break;
- }
- if (qfver > 0)
- {
- p = strchr(&lbuf[1], ':');
- if (p == NULL)
- p = &lbuf[1];
- }
- else
- p = &lbuf[1];
- check = QueueLimitRecipient;
- while (check != NULL)
- {
- if (strcontainedin(check->queue_match,
- p))
- break;
- else
- check = check->queue_next;
- }
- if (check != NULL)
- i &= ~NEED_R;
- break;
-
- case 'S':
- check = QueueLimitSender;
- while (check != NULL)
- {
- if (strcontainedin(check->queue_match,
- &lbuf[1]))
- break;
- else
- check = check->queue_next;
- }
- if (check != NULL)
- i &= ~NEED_S;
- break;
-
- case 'K':
- age = curtime() - (time_t) atol(&lbuf[1]);
- if (age >= 0 && MinQueueAge > 0 &&
- age < MinQueueAge)
- w->w_tooyoung = TRUE;
- break;
-
- case 'N':
- if (atol(&lbuf[1]) == 0)
- w->w_tooyoung = FALSE;
- break;
- }
- }
- (void) fclose(cf);
-
- if ((!doall && shouldqueue(w->w_pri, w->w_ctime)) ||
- bitset(NEED_R|NEED_S, i))
- {
- /* don't even bother sorting this job in */
- if (tTd(41, 49))
- printf("skipping %s (%x)\n", w->w_name, i);
- free(w->w_name);
- if (w->w_host)
- free(w->w_host);
- wn--;
- }
- }
- (void) closedir(f);
- wn++;
-
- wc = min(wn, WorkListSize);
- if (wc > MaxQueueRun && MaxQueueRun > 0)
- wc = MaxQueueRun;
-
- if (QueueSortOrder == QS_BYHOST)
- {
- extern int workcmpf1();
- extern int workcmpf2();
-
- /*
- ** Sort the work directory for the first time,
- ** based on host name, lock status, and priority.
- */
-
- qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf1);
-
- /*
- ** If one message to host is locked, "lock" all messages
- ** to that host.
- */
-
- i = 0;
- while (i < wc)
- {
- if (!WorkList[i].w_lock)
- {
- i++;
- continue;
- }
- w = &WorkList[i];
- while (++i < wc)
- {
- extern int sm_strcasecmp __P((char *, char *));
-
- if (WorkList[i].w_host == NULL &&
- w->w_host == NULL)
- WorkList[i].w_lock = TRUE;
- else if (WorkList[i].w_host != NULL &&
- w->w_host != NULL &&
- sm_strcasecmp(WorkList[i].w_host, w->w_host) == 0)
- WorkList[i].w_lock = TRUE;
- else
- break;
- }
- }
-
- /*
- ** Sort the work directory for the second time,
- ** based on lock status, host name, and priority.
- */
-
- qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf2);
- }
- else if (QueueSortOrder == QS_BYTIME)
- {
- extern int workcmpf3();
-
- /*
- ** Simple sort based on submission time only.
- */
-
- qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf3);
- }
- else
- {
- extern int workcmpf0();
-
- /*
- ** Simple sort based on queue priority only.
- */
-
- qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf0);
- }
-
- /*
- ** Convert the work list into canonical form.
- ** Should be turning it into a list of envelopes here perhaps.
- */
-
- WorkQ = NULL;
- for (i = wc; --i >= 0; )
- {
- w = (WORK *) xalloc(sizeof *w);
- w->w_name = WorkList[i].w_name;
- w->w_host = WorkList[i].w_host;
- w->w_lock = WorkList[i].w_lock;
- w->w_tooyoung = WorkList[i].w_tooyoung;
- w->w_pri = WorkList[i].w_pri;
- w->w_ctime = WorkList[i].w_ctime;
- w->w_next = WorkQ;
- WorkQ = w;
- }
- if (WorkList != NULL)
- free(WorkList);
- WorkList = NULL;
- WorkListSize = 0;
-
- if (tTd(40, 1))
- {
- for (w = WorkQ; w != NULL; w = w->w_next)
- printf("%32s: pri=%ld\n", w->w_name, w->w_pri);
- }
-
- return (wn);
-}
- /*
-** GROW_WLIST -- make the work list larger
-**
-** Parameters:
-** none.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Adds another QUEUESEGSIZE entries to WorkList if possible.
-** It can fail if there isn't enough memory, so WorkListSize
-** should be checked again upon return.
-*/
-
-void
-grow_wlist()
-{
- if (tTd(41, 1))
- printf("grow_wlist: WorkListSize=%d\n", WorkListSize);
- if (WorkList == NULL)
- {
- WorkList = (WORK *) xalloc(sizeof(WORK) * (QUEUESEGSIZE + 1));
- WorkListSize = QUEUESEGSIZE;
- }
- else
- {
- int newsize = WorkListSize + QUEUESEGSIZE;
- WORK *newlist = (WORK *) realloc((char *)WorkList,
- (unsigned)sizeof(WORK) * (newsize + 1));
-
- if (newlist != NULL)
- {
- WorkListSize = newsize;
- WorkList = newlist;
- if (LogLevel > 1)
- {
- sm_syslog(LOG_NOTICE, NOQID,
- "grew WorkList for %s to %d",
- QueueDir, WorkListSize);
- }
- }
- else if (LogLevel > 0)
- {
- sm_syslog(LOG_ALERT, NOQID,
- "FAILED to grow WorkList for %s to %d",
- QueueDir, newsize);
- }
- }
- if (tTd(41, 1))
- printf("grow_wlist: WorkListSize now %d\n", WorkListSize);
-}
- /*
-** WORKCMPF0 -- simple priority-only compare function.
-**
-** Parameters:
-** a -- the first argument.
-** b -- the second argument.
-**
-** Returns:
-** -1 if a < b
-** 0 if a == b
-** +1 if a > b
-**
-** Side Effects:
-** none.
-*/
-
-int
-workcmpf0(a, b)
- register WORK *a;
- register WORK *b;
-{
- long pa = a->w_pri;
- long pb = b->w_pri;
-
- if (pa == pb)
- return 0;
- else if (pa > pb)
- return 1;
- else
- return -1;
-}
- /*
-** WORKCMPF1 -- first compare function for ordering work based on host name.
-**
-** Sorts on host name, lock status, and priority in that order.
-**
-** Parameters:
-** a -- the first argument.
-** b -- the second argument.
-**
-** Returns:
-** <0 if a < b
-** 0 if a == b
-** >0 if a > b
-**
-** Side Effects:
-** none.
-*/
-
-int
-workcmpf1(a, b)
- register WORK *a;
- register WORK *b;
-{
- int i;
- extern int sm_strcasecmp __P((char *, char *));
-
- /* host name */
- if (a->w_host != NULL && b->w_host == NULL)
- return 1;
- else if (a->w_host == NULL && b->w_host != NULL)
- return -1;
- if (a->w_host != NULL && b->w_host != NULL &&
- (i = sm_strcasecmp(a->w_host, b->w_host)) != 0)
- return i;
-
- /* lock status */
- if (a->w_lock != b->w_lock)
- return b->w_lock - a->w_lock;
-
- /* job priority */
- return a->w_pri - b->w_pri;
-}
- /*
-** WORKCMPF2 -- second compare function for ordering work based on host name.
-**
-** Sorts on lock status, host name, and priority in that order.
-**
-** Parameters:
-** a -- the first argument.
-** b -- the second argument.
-**
-** Returns:
-** <0 if a < b
-** 0 if a == b
-** >0 if a > b
-**
-** Side Effects:
-** none.
-*/
-
-int
-workcmpf2(a, b)
- register WORK *a;
- register WORK *b;
-{
- int i;
- extern int sm_strcasecmp __P((char *, char *));
-
- /* lock status */
- if (a->w_lock != b->w_lock)
- return a->w_lock - b->w_lock;
-
- /* host name */
- if (a->w_host != NULL && b->w_host == NULL)
- return 1;
- else if (a->w_host == NULL && b->w_host != NULL)
- return -1;
- if (a->w_host != NULL && b->w_host != NULL &&
- (i = sm_strcasecmp(a->w_host, b->w_host)) != 0)
- return i;
-
- /* job priority */
- return a->w_pri - b->w_pri;
-}
- /*
-** WORKCMPF3 -- simple submission-time-only compare function.
-**
-** Parameters:
-** a -- the first argument.
-** b -- the second argument.
-**
-** Returns:
-** -1 if a < b
-** 0 if a == b
-** +1 if a > b
-**
-** Side Effects:
-** none.
-*/
-
-int
-workcmpf3(a, b)
- register WORK *a;
- register WORK *b;
-{
- if (a->w_ctime > b->w_ctime)
- return 1;
- else if (a->w_ctime < b->w_ctime)
- return -1;
- else
- return 0;
-}
- /*
-** DOWORK -- do a work request.
-**
-** Parameters:
-** id -- the ID of the job to run.
-** forkflag -- if set, run this in background.
-** requeueflag -- if set, reinstantiate the queue quickly.
-** This is used when expanding aliases in the queue.
-** If forkflag is also set, it doesn't wait for the
-** child.
-** e - the envelope in which to run it.
-**
-** Returns:
-** process id of process that is running the queue job.
-**
-** Side Effects:
-** The work request is satisfied if possible.
-*/
-
-pid_t
-dowork(id, forkflag, requeueflag, e)
- char *id;
- bool forkflag;
- bool requeueflag;
- register ENVELOPE *e;
-{
- register pid_t pid;
- extern bool readqf __P((ENVELOPE *));
-
- if (tTd(40, 1))
- printf("dowork(%s)\n", id);
-
- /*
- ** Fork for work.
- */
-
- if (forkflag)
- {
- pid = fork();
- if (pid < 0)
- {
- syserr("dowork: cannot fork");
- return 0;
- }
- else if (pid > 0)
- {
- /* parent -- clean out connection cache */
- mci_flush(FALSE, NULL);
- }
- else
- {
- /* child -- error messages to the transcript */
- QuickAbort = OnlyOneError = FALSE;
-
- /*
- ** Since the delivery may happen in a child and the
- ** parent does not wait, the parent may close the
- ** maps thereby removing any shared memory used by
- ** the map. Therefore, open a copy of the maps for
- ** the delivery process.
- */
-
- initmaps(FALSE, e);
- }
- }
- else
- {
- pid = 0;
- }
-
- if (pid == 0)
- {
- /*
- ** CHILD
- ** Lock the control file to avoid duplicate deliveries.
- ** Then run the file as though we had just read it.
- ** We save an idea of the temporary name so we
- ** can recover on interrupt.
- */
-
- /* set basic modes, etc. */
- (void) alarm(0);
- clearenvelope(e, FALSE);
- e->e_flags |= EF_QUEUERUN|EF_GLOBALERRS;
- e->e_sendmode = SM_DELIVER;
- e->e_errormode = EM_MAIL;
- e->e_id = id;
- GrabTo = UseErrorsTo = FALSE;
- ExitStat = EX_OK;
- if (forkflag)
- {
- disconnect(1, e);
- OpMode = MD_DELIVER;
- }
- sm_setproctitle(TRUE, "%s: from queue", id);
- if (LogLevel > 76)
- sm_syslog(LOG_DEBUG, e->e_id,
- "dowork, pid=%d",
- getpid());
-
- /* don't use the headers from sendmail.cf... */
- e->e_header = NULL;
-
- /* read the queue control file -- return if locked */
- if (!readqf(e))
- {
- if (tTd(40, 4) && e->e_id != NULL)
- printf("readqf(%s) failed\n", e->e_id);
- e->e_id = NULL;
- if (forkflag)
- finis(FALSE, EX_OK);
- else
- return 0;
- }
-
- e->e_flags |= EF_INQUEUE;
- eatheader(e, requeueflag);
-
- if (requeueflag)
- queueup(e, FALSE);
-
- /* do the delivery */
- sendall(e, SM_DELIVER);
-
- /* finish up and exit */
- if (forkflag)
- finis(TRUE, ExitStat);
- else
- dropenvelope(e, TRUE);
- }
- e->e_id = NULL;
- return pid;
-}
- /*
-** READQF -- read queue file and set up environment.
-**
-** Parameters:
-** e -- the envelope of the job to run.
-**
-** Returns:
-** TRUE if it successfully read the queue file.
-** FALSE otherwise.
-**
-** Side Effects:
-** The queue file is returned locked.
-*/
-
-bool
-readqf(e)
- register ENVELOPE *e;
-{
- register FILE *qfp;
- ADDRESS *ctladdr;
- struct stat st;
- char *bp;
- int qfver = 0;
- long hdrsize = 0;
- register char *p;
- char *orcpt = NULL;
- bool nomore = FALSE;
- char qf[MAXQFNAME];
- char buf[MAXLINE];
- extern ADDRESS *setctluser __P((char *, int));
-
- /*
- ** Read and process the file.
- */
-
- strcpy(qf, queuename(e, 'q'));
- qfp = fopen(qf, "r+");
- if (qfp == NULL)
- {
- if (tTd(40, 8))
- printf("readqf(%s): fopen failure (%s)\n",
- qf, errstring(errno));
- if (errno != ENOENT)
- syserr("readqf: no control file %s", qf);
- return FALSE;
- }
-
- if (!lockfile(fileno(qfp), qf, NULL, LOCK_EX|LOCK_NB))
- {
- /* being processed by another queuer */
- if (Verbose || tTd(40, 8))
- printf("%s: locked\n", e->e_id);
- if (LogLevel > 19)
- sm_syslog(LOG_DEBUG, e->e_id, "locked");
- (void) fclose(qfp);
- return FALSE;
- }
-
- /*
- ** Check the queue file for plausibility to avoid attacks.
- */
-
- if (fstat(fileno(qfp), &st) < 0)
- {
- /* must have been being processed by someone else */
- if (tTd(40, 8))
- printf("readqf(%s): fstat failure (%s)\n",
- qf, errstring(errno));
- fclose(qfp);
- return FALSE;
- }
-
- if ((st.st_uid != geteuid() && geteuid() != RealUid) ||
- bitset(S_IWOTH|S_IWGRP, st.st_mode))
- {
- if (LogLevel > 0)
- {
- sm_syslog(LOG_ALERT, e->e_id,
- "bogus queue file, uid=%d, mode=%o",
- st.st_uid, st.st_mode);
- }
- if (tTd(40, 8))
- printf("readqf(%s): bogus file\n", qf);
- loseqfile(e, "bogus file uid in mqueue");
- fclose(qfp);
- return FALSE;
- }
-
- if (st.st_size == 0)
- {
- /* must be a bogus file -- if also old, just remove it */
- if (st.st_ctime + 10 * 60 < curtime())
- {
- qf[0] = 'd';
- (void) unlink(qf);
- qf[0] = 'q';
- (void) unlink(qf);
- }
- fclose(qfp);
- return FALSE;
- }
-
- if (st.st_nlink == 0)
- {
- /*
- ** Race condition -- we got a file just as it was being
- ** unlinked. Just assume it is zero length.
- */
-
- fclose(qfp);
- return FALSE;
- }
-
- /* good file -- save this lock */
- e->e_lockfp = qfp;
-
- /* do basic system initialization */
- initsys(e);
- define('i', e->e_id, e);
-
- LineNumber = 0;
- e->e_flags |= EF_GLOBALERRS;
- OpMode = MD_DELIVER;
- ctladdr = NULL;
- e->e_dfino = -1;
- e->e_msgsize = -1;
- while ((bp = fgetfolded(buf, sizeof buf, qfp)) != NULL)
- {
- register char *p;
- u_long qflags;
- ADDRESS *q;
- int mid;
- auto char *ep;
-
- if (tTd(40, 4))
- printf("+++++ %s\n", bp);
- if (nomore)
- {
- /* hack attack */
- syserr("SECURITY ALERT: extra data in qf: %s", bp);
- fclose(qfp);
- loseqfile(e, "bogus queue line");
- return FALSE;
- }
- switch (bp[0])
- {
- case 'V': /* queue file version number */
- qfver = atoi(&bp[1]);
- if (qfver <= QF_VERSION)
- break;
- syserr("Version number in qf (%d) greater than max (%d)",
- qfver, QF_VERSION);
- fclose(qfp);
- loseqfile(e, "unsupported qf file version");
- return FALSE;
-
- case 'C': /* specify controlling user */
- ctladdr = setctluser(&bp[1], qfver);
- break;
-
- case 'Q': /* original recipient */
- orcpt = newstr(&bp[1]);
- break;
-
- case 'R': /* specify recipient */
- p = bp;
- qflags = 0;
- if (qfver >= 1)
- {
- /* get flag bits */
- while (*++p != '\0' && *p != ':')
- {
- switch (*p)
- {
- case 'N':
- qflags |= QHASNOTIFY;
- break;
-
- case 'S':
- qflags |= QPINGONSUCCESS;
- break;
-
- case 'F':
- qflags |= QPINGONFAILURE;
- break;
-
- case 'D':
- qflags |= QPINGONDELAY;
- break;
-
- case 'P':
- qflags |= QPRIMARY;
- break;
- }
- }
- }
- else
- qflags |= QPRIMARY;
- q = parseaddr(++p, NULLADDR, RF_COPYALL, '\0', NULL, e);
- if (q != NULL)
- {
- q->q_alias = ctladdr;
- if (qfver >= 1)
- q->q_flags &= ~Q_PINGFLAGS;
- q->q_flags |= qflags;
- q->q_orcpt = orcpt;
- (void) recipient(q, &e->e_sendqueue, 0, e);
- }
- orcpt = NULL;
- break;
-
- case 'E': /* specify error recipient */
- /* no longer used */
- break;
-
- case 'H': /* header */
- (void) chompheader(&bp[1], FALSE, NULL, e);
- hdrsize += strlen(&bp[1]);
- break;
-
- case 'L': /* Solaris Content-Length: */
- case 'M': /* message */
- /* ignore this; we want a new message next time */
- break;
-
- case 'S': /* sender */
- setsender(newstr(&bp[1]), e, NULL, '\0', TRUE);
- break;
-
- case 'B': /* body type */
- e->e_bodytype = newstr(&bp[1]);
- break;
-
-#if _FFR_SAVE_CHARSET
- case 'X': /* character set */
- e->e_charset = newstr(&bp[1]);
- break;
-#endif
-
- case 'D': /* data file name */
- /* obsolete -- ignore */
- break;
-
- case 'T': /* init time */
- e->e_ctime = atol(&bp[1]);
- break;
-
- case 'I': /* data file's inode number */
- /* regenerated below */
- break;
-
- case 'K': /* time of last deliver attempt */
- e->e_dtime = atol(&buf[1]);
- break;
-
- case 'N': /* number of delivery attempts */
- e->e_ntries = atoi(&buf[1]);
-
- /* if this has been tried recently, let it be */
- if (e->e_ntries > 0 &&
- MinQueueAge > 0 && e->e_dtime <= curtime() &&
- curtime() < e->e_dtime + MinQueueAge)
- {
- char *howlong = pintvl(curtime() - e->e_dtime, TRUE);
-
- if (Verbose || tTd(40, 8))
- printf("%s: too young (%s)\n",
- e->e_id, howlong);
- if (LogLevel > 19)
- sm_syslog(LOG_DEBUG, e->e_id,
- "too young (%s)",
- howlong);
- e->e_id = NULL;
- unlockqueue(e);
- return FALSE;
- }
- break;
-
- case 'P': /* message priority */
- e->e_msgpriority = atol(&bp[1]) + WkTimeFact;
- break;
-
- case 'F': /* flag bits */
- if (strncmp(bp, "From ", 5) == 0)
- {
- /* we are being spoofed! */
- syserr("SECURITY ALERT: bogus qf line %s", bp);
- fclose(qfp);
- loseqfile(e, "bogus queue line");
- return FALSE;
- }
- for (p = &bp[1]; *p != '\0'; p++)
- {
- switch (*p)
- {
- case 'w': /* warning sent */
- e->e_flags |= EF_WARNING;
- break;
-
- case 'r': /* response */
- e->e_flags |= EF_RESPONSE;
- break;
-
- case '8': /* has 8 bit data */
- e->e_flags |= EF_HAS8BIT;
- break;
-
- case 'b': /* delete Bcc: header */
- e->e_flags |= EF_DELETE_BCC;
- break;
-
- case 'd': /* envelope has DSN RET= */
- e->e_flags |= EF_RET_PARAM;
- break;
-
- case 'n': /* don't return body */
- e->e_flags |= EF_NO_BODY_RETN;
- break;
- }
- }
- break;
-
- case 'Z': /* original envelope id from ESMTP */
- e->e_envid = newstr(&bp[1]);
- break;
-
- case '$': /* define macro */
- mid = macid(&bp[1], &ep);
- define(mid, newstr(ep), e);
- break;
-
- case '.': /* terminate file */
- nomore = TRUE;
- break;
-
- default:
- syserr("readqf: %s: line %d: bad line \"%s\"",
- qf, LineNumber, shortenstring(bp, MAXSHORTSTR));
- fclose(qfp);
- loseqfile(e, "unrecognized line");
- return FALSE;
- }
-
- if (bp != buf)
- free(bp);
- }
-
- /*
- ** If we haven't read any lines, this queue file is empty.
- ** Arrange to remove it without referencing any null pointers.
- */
-
- if (LineNumber == 0)
- {
- errno = 0;
- e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE;
- return TRUE;
- }
-
- /*
- ** Arrange to read the data file.
- */
-
- p = queuename(e, 'd');
- e->e_dfp = fopen(p, "r");
- if (e->e_dfp == NULL)
- {
- syserr("readqf: cannot open %s", p);
- }
- else
- {
- e->e_flags |= EF_HAS_DF;
- if (fstat(fileno(e->e_dfp), &st) >= 0)
- {
- e->e_msgsize = st.st_size + hdrsize;
- e->e_dfdev = st.st_dev;
- e->e_dfino = st.st_ino;
- }
- }
-
- return TRUE;
-}
- /*
-** PRINTQUEUE -- print out a representation of the mail queue
-**
-** Parameters:
-** none.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Prints a listing of the mail queue on the standard output.
-*/
-
-void
-printqueue()
-{
- register WORK *w;
- FILE *f;
- int nrequests;
- char buf[MAXLINE];
-
- /*
- ** Check for permission to print the queue
- */
-
- if (bitset(PRIV_RESTRICTMAILQ, PrivacyFlags) && RealUid != 0)
- {
- struct stat st;
-# ifdef NGROUPS_MAX
- int n;
- extern GIDSET_T InitialGidSet[NGROUPS_MAX];
-# endif
-
- if (stat(QueueDir, &st) < 0)
- {
- syserr("Cannot stat %s", QueueDir);
- return;
- }
-# ifdef NGROUPS_MAX
- n = NGROUPS_MAX;
- while (--n >= 0)
- {
- if (InitialGidSet[n] == st.st_gid)
- break;
- }
- if (n < 0 && RealGid != st.st_gid)
-# else
- if (RealGid != st.st_gid)
-# endif
- {
- usrerr("510 You are not permitted to see the queue");
- setstat(EX_NOPERM);
- return;
- }
- }
-
- /*
- ** Read and order the queue.
- */
-
- nrequests = orderq(TRUE);
-
- /*
- ** Print the work list that we have read.
- */
-
- /* first see if there is anything */
- if (nrequests <= 0)
- {
- printf("Mail queue is empty\n");
- return;
- }
-
- CurrentLA = getla(); /* get load average */
-
- printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s");
- if (MaxQueueRun > 0 && nrequests > MaxQueueRun)
- printf(", only %d printed", MaxQueueRun);
- if (Verbose)
- printf(")\n--Q-ID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n");
- else
- printf(")\n--Q-ID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n");
- for (w = WorkQ; w != NULL; w = w->w_next)
- {
- struct stat st;
- auto time_t submittime = 0;
- long dfsize;
- int flags = 0;
- int qfver;
- char statmsg[MAXLINE];
- char bodytype[MAXNAME + 1];
-
- printf("%8s", w->w_name + 2);
- f = fopen(w->w_name, "r");
- if (f == NULL)
- {
- printf(" (job completed)\n");
- errno = 0;
- continue;
- }
- w->w_name[0] = 'd';
- if (stat(w->w_name, &st) >= 0)
- dfsize = st.st_size;
- else
- dfsize = -1;
- if (w->w_lock)
- printf("*");
- else if (w->w_tooyoung)
- printf("-");
- else if (shouldqueue(w->w_pri, w->w_ctime))
- printf("X");
- else
- printf(" ");
- errno = 0;
-
- statmsg[0] = bodytype[0] = '\0';
- qfver = 0;
- while (fgets(buf, sizeof buf, f) != NULL)
- {
- register int i;
- register char *p;
-
- fixcrlf(buf, TRUE);
- switch (buf[0])
- {
- case 'V': /* queue file version */
- qfver = atoi(&buf[1]);
- break;
-
- case 'M': /* error message */
- if ((i = strlen(&buf[1])) >= sizeof statmsg)
- i = sizeof statmsg - 1;
- bcopy(&buf[1], statmsg, i);
- statmsg[i] = '\0';
- break;
-
- case 'B': /* body type */
- if ((i = strlen(&buf[1])) >= sizeof bodytype)
- i = sizeof bodytype - 1;
- bcopy(&buf[1], bodytype, i);
- bodytype[i] = '\0';
- break;
-
- case 'S': /* sender name */
- if (Verbose)
- printf("%8ld %10ld%c%.12s %.78s",
- dfsize,
- w->w_pri,
- bitset(EF_WARNING, flags) ? '+' : ' ',
- ctime(&submittime) + 4,
- &buf[1]);
- else
- printf("%8ld %.16s %.45s", dfsize,
- ctime(&submittime), &buf[1]);
- if (statmsg[0] != '\0' || bodytype[0] != '\0')
- {
- printf("\n %10.10s", bodytype);
- if (statmsg[0] != '\0')
- printf(" (%.*s)",
- Verbose ? 100 : 60,
- statmsg);
- }
- break;
-
- case 'C': /* controlling user */
- if (Verbose)
- printf("\n\t\t\t\t (---%.74s---)",
- &buf[1]);
- break;
-
- case 'R': /* recipient name */
- p = &buf[1];
- if (qfver >= 1)
- {
- p = strchr(p, ':');
- if (p == NULL)
- break;
- p++;
- }
- if (Verbose)
- printf("\n\t\t\t\t\t %.78s", p);
- else
- printf("\n\t\t\t\t %.45s", p);
- break;
-
- case 'T': /* creation time */
- submittime = atol(&buf[1]);
- break;
-
- case 'F': /* flag bits */
- for (p = &buf[1]; *p != '\0'; p++)
- {
- switch (*p)
- {
- case 'w':
- flags |= EF_WARNING;
- break;
- }
- }
- }
- }
- if (submittime == (time_t) 0)
- printf(" (no control file)");
- printf("\n");
- (void) fclose(f);
- }
-}
-
-# endif /* QUEUE */
- /*
-** QUEUENAME -- build a file name in the queue directory for this envelope.
-**
-** Assigns an id code if one does not already exist.
-** This code is very careful to avoid trashing existing files
-** under any circumstances.
-**
-** Parameters:
-** e -- envelope to build it in/from.
-** type -- the file type, used as the first character
-** of the file name.
-**
-** Returns:
-** a pointer to the new file name (in a static buffer).
-**
-** Side Effects:
-** If no id code is already assigned, queuename will
-** assign an id code, create a qf file, and leave a
-** locked, open-for-write file pointer in the envelope.
-*/
-
-#ifndef ENOLCK
-# define ENOLCK -1
-#endif
-#ifndef ENOSPC
-# define ENOSPC -1
-#endif
-
-char *
-queuename(e, type)
- register ENVELOPE *e;
- int type;
-{
- static pid_t pid = -1;
- static char c0;
- static char c1;
- static char c2;
- time_t now;
- struct tm *tm;
- static char buf[MAXNAME + 1];
-
- if (e->e_id == NULL)
- {
- char qf[MAXQFNAME];
-
- /* find a unique id */
- if (pid != getpid())
- {
- /* new process -- start back at "AA" */
- pid = getpid();
- now = curtime();
- tm = localtime(&now);
- c0 = 'A' + tm->tm_hour;
- c1 = 'A';
- c2 = 'A' - 1;
- }
- (void) snprintf(qf, sizeof qf, "qf%cAA%05d", c0, pid);
-
- while (c1 < '~' || c2 < 'Z')
- {
- int i;
- int attempts = 0;
-
- if (c2 >= 'Z')
- {
- c1++;
- c2 = 'A' - 1;
- }
- qf[3] = c1;
- qf[4] = ++c2;
- if (tTd(7, 20))
- printf("queuename: trying \"%s\"\n", qf);
-
- i = open(qf, O_WRONLY|O_CREAT|O_EXCL, FileMode);
- if (i < 0)
- {
- if (errno == EEXIST)
- continue;
- syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)",
- qf, QueueDir, geteuid());
- finis(FALSE, EX_UNAVAILABLE);
- }
- do
- {
- if (attempts > 0)
- sleep(attempts);
- e->e_lockfp = 0;
- if (lockfile(i, qf, NULL, LOCK_EX|LOCK_NB))
- {
- e->e_lockfp = fdopen(i, "w");
- break;
- }
- } while ((errno == ENOLCK || errno == ENOSPC) &&
- attempts++ < 4);
-
- /* Successful lock */
- if (e->e_lockfp != 0)
- break;
-
-#if !HASFLOCK
- if (errno != EAGAIN && errno != EACCES)
-#else
- if (errno != EWOULDBLOCK)
-#endif
- {
- syserr("queuename: Cannot lock \"%s\" in \"%s\" (euid=%d)",
- qf, QueueDir, geteuid());
- finis(FALSE, EX_OSERR);
- }
-
- /* a reader got the file; abandon it and try again */
- (void) close(i);
- }
- if (c1 >= '~' && c2 >= 'Z')
- {
- syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)",
- qf, QueueDir, geteuid());
- finis(FALSE, EX_OSERR);
- }
- e->e_id = newstr(&qf[2]);
- define('i', e->e_id, e);
- if (tTd(7, 1))
- printf("queuename: assigned id %s, env=%lx\n",
- e->e_id, (u_long) e);
- if (tTd(7, 9))
- {
- printf(" lockfd=");
- dumpfd(fileno(e->e_lockfp), TRUE, FALSE);
- }
- if (LogLevel > 93)
- sm_syslog(LOG_DEBUG, e->e_id, "assigned id");
- }
-
- if (type == '\0')
- return (NULL);
- (void) snprintf(buf, sizeof buf, "%cf%s", type, e->e_id);
- if (tTd(7, 2))
- printf("queuename: %s\n", buf);
- return (buf);
-}
- /*
-** UNLOCKQUEUE -- unlock the queue entry for a specified envelope
-**
-** Parameters:
-** e -- the envelope to unlock.
-**
-** Returns:
-** none
-**
-** Side Effects:
-** unlocks the queue for `e'.
-*/
-
-void
-unlockqueue(e)
- ENVELOPE *e;
-{
- if (tTd(51, 4))
- printf("unlockqueue(%s)\n",
- e->e_id == NULL ? "NOQUEUE" : e->e_id);
-
- /* if there is a lock file in the envelope, close it */
- if (e->e_lockfp != NULL)
- xfclose(e->e_lockfp, "unlockqueue", e->e_id);
- e->e_lockfp = NULL;
-
- /* don't create a queue id if we don't already have one */
- if (e->e_id == NULL)
- return;
-
- /* remove the transcript */
- if (LogLevel > 87)
- sm_syslog(LOG_DEBUG, e->e_id, "unlock");
- if (!tTd(51, 104))
- xunlink(queuename(e, 'x'));
-
-}
- /*
-** SETCTLUSER -- create a controlling address
-**
-** Create a fake "address" given only a local login name; this is
-** used as a "controlling user" for future recipient addresses.
-**
-** Parameters:
-** user -- the user name of the controlling user.
-** qfver -- the version stamp of this qf file.
-**
-** Returns:
-** An address descriptor for the controlling user.
-**
-** Side Effects:
-** none.
-*/
-
-ADDRESS *
-setctluser(user, qfver)
- char *user;
- int qfver;
-{
- register ADDRESS *a;
- struct passwd *pw;
- char *p;
-
- /*
- ** See if this clears our concept of controlling user.
- */
-
- if (user == NULL || *user == '\0')
- return NULL;
-
- /*
- ** Set up addr fields for controlling user.
- */
-
- a = (ADDRESS *) xalloc(sizeof *a);
- bzero((char *) a, sizeof *a);
-
- if (*user == '\0')
- {
- p = NULL;
- a->q_user = newstr(DefUser);
- }
- else if (*user == ':')
- {
- p = &user[1];
- a->q_user = newstr(p);
- }
- else
- {
- p = strtok(user, ":");
- a->q_user = newstr(user);
- if (qfver >= 2)
- {
- if ((p = strtok(NULL, ":")) != NULL)
- a->q_uid = atoi(p);
- if ((p = strtok(NULL, ":")) != NULL)
- a->q_gid = atoi(p);
- if ((p = strtok(NULL, ":")) != NULL)
- a->q_flags |= QGOODUID;
- }
- else if ((pw = sm_getpwnam(user)) != NULL)
- {
- if (strcmp(pw->pw_dir, "/") == 0)
- a->q_home = "";
- else
- a->q_home = newstr(pw->pw_dir);
- a->q_uid = pw->pw_uid;
- a->q_gid = pw->pw_gid;
- a->q_flags |= QGOODUID;
- }
- }
-
- a->q_flags |= QPRIMARY; /* flag as a "ctladdr" */
- a->q_mailer = LocalMailer;
- if (p == NULL)
- a->q_paddr = a->q_user;
- else
- a->q_paddr = newstr(p);
- return a;
-}
- /*
-** LOSEQFILE -- save the qf as Qf and try to let someone know
-**
-** Parameters:
-** e -- the envelope (e->e_id will be used).
-** why -- reported to whomever can hear.
-**
-** Returns:
-** none.
-*/
-
-void
-loseqfile(e, why)
- register ENVELOPE *e;
- char *why;
-{
- char *p;
- char buf[MAXQFNAME + 1];
-
- if (e == NULL || e->e_id == NULL)
- return;
- p = queuename(e, 'q');
- if (strlen(p) > MAXQFNAME)
- {
- syserr("loseqfile: queuename (%s) too long", p);
- return;
- }
- strcpy(buf, p);
- p = queuename(e, 'Q');
- if (rename(buf, p) < 0)
- syserr("cannot rename(%s, %s), uid=%d", buf, p, geteuid());
- else if (LogLevel > 0)
- sm_syslog(LOG_ALERT, e->e_id,
- "Losing %s: %s", buf, why);
-}
diff --git a/src/readcf.c b/src/readcf.c
deleted file mode 100644
index df40097..0000000
--- a/src/readcf.c
+++ /dev/null
@@ -1,2920 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)readcf.c 8.238 (Berkeley) 1/28/1999";
-#endif /* not lint */
-
-# include "sendmail.h"
-# include <grp.h>
-#if NAMED_BIND
-# include <resolv.h>
-#endif
-
-/*
-** READCF -- read configuration file.
-**
-** This routine reads the configuration file and builds the internal
-** form.
-**
-** The file is formatted as a sequence of lines, each taken
-** atomically. The first character of each line describes how
-** the line is to be interpreted. The lines are:
-** Dxval Define macro x to have value val.
-** Cxword Put word into class x.
-** Fxfile [fmt] Read file for lines to put into
-** class x. Use scanf string 'fmt'
-** or "%s" if not present. Fmt should
-** only produce one string-valued result.
-** Hname: value Define header with field-name 'name'
-** and value as specified; this will be
-** macro expanded immediately before
-** use.
-** Sn Use rewriting set n.
-** Rlhs rhs Rewrite addresses that match lhs to
-** be rhs.
-** Mn arg=val... Define mailer. n is the internal name.
-** Args specify mailer parameters.
-** Oxvalue Set option x to value.
-** Pname=value Set precedence name to value.
-** Vversioncode[/vendorcode]
-** Version level/vendor name of
-** configuration syntax.
-** Kmapname mapclass arguments....
-** Define keyed lookup of a given class.
-** Arguments are class dependent.
-** Eenvar=value Set the environment value to the given value.
-**
-** Parameters:
-** cfname -- configuration file name.
-** safe -- TRUE if this is the system config file;
-** FALSE otherwise.
-** e -- the main envelope.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Builds several internal tables.
-*/
-
-void
-readcf(cfname, safe, e)
- char *cfname;
- bool safe;
- register ENVELOPE *e;
-{
- FILE *cf;
- int ruleset = 0;
- char *q;
- struct rewrite *rwp = NULL;
- char *bp;
- auto char *ep;
- int nfuzzy;
- char *file;
- bool optional;
- int mid;
- register char *p;
- int sff = SFF_OPENASROOT;
- struct stat statb;
- char buf[MAXLINE];
- char exbuf[MAXLINE];
- char pvpbuf[MAXLINE + MAXATOM];
- static char *null_list[1] = { NULL };
- extern char **copyplist __P((char **, bool));
- extern char *munchstring __P((char *, char **, int));
- extern void fileclass __P((int, char *, char *, bool, bool));
- extern void toomany __P((int, int));
- extern void translate_dollars __P((char *));
- extern void inithostmaps __P((void));
-
- FileName = cfname;
- LineNumber = 0;
-
- if (DontLockReadFiles)
- sff |= SFF_NOLOCK;
- cf = safefopen(cfname, O_RDONLY, 0444, sff);
- if (cf == NULL)
- {
- syserr("cannot open");
- finis(FALSE, EX_OSFILE);
- }
-
- if (fstat(fileno(cf), &statb) < 0)
- {
- syserr("cannot fstat");
- finis(FALSE, EX_OSFILE);
- }
-
- if (!S_ISREG(statb.st_mode))
- {
- syserr("not a plain file");
- finis(FALSE, EX_OSFILE);
- }
-
- if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode))
- {
- if (OpMode == MD_DAEMON || OpMode == MD_INITALIAS)
- fprintf(stderr, "%s: WARNING: dangerous write permissions\n",
- FileName);
- if (LogLevel > 0)
- sm_syslog(LOG_CRIT, NOQID,
- "%s: WARNING: dangerous write permissions",
- FileName);
- }
-
-#ifdef XLA
- xla_zero();
-#endif
-
- while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL)
- {
- if (bp[0] == '#')
- {
- if (bp != buf)
- free(bp);
- continue;
- }
-
- /* do macro expansion mappings */
- translate_dollars(bp);
-
- /* interpret this line */
- errno = 0;
- switch (bp[0])
- {
- case '\0':
- case '#': /* comment */
- break;
-
- case 'R': /* rewriting rule */
- for (p = &bp[1]; *p != '\0' && *p != '\t'; p++)
- continue;
-
- if (*p == '\0')
- {
- syserr("invalid rewrite line \"%s\" (tab expected)", bp);
- break;
- }
-
- /* allocate space for the rule header */
- if (rwp == NULL)
- {
- RewriteRules[ruleset] = rwp =
- (struct rewrite *) xalloc(sizeof *rwp);
- }
- else
- {
- rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp);
- rwp = rwp->r_next;
- }
- rwp->r_next = NULL;
-
- /* expand and save the LHS */
- *p = '\0';
- expand(&bp[1], exbuf, sizeof exbuf, e);
- rwp->r_lhs = prescan(exbuf, '\t', pvpbuf,
- sizeof pvpbuf, NULL, NULL);
- nfuzzy = 0;
- if (rwp->r_lhs != NULL)
- {
- register char **ap;
-
- rwp->r_lhs = copyplist(rwp->r_lhs, TRUE);
-
- /* count the number of fuzzy matches in LHS */
- for (ap = rwp->r_lhs; *ap != NULL; ap++)
- {
- char *botch;
-
- botch = NULL;
- switch (**ap & 0377)
- {
- case MATCHZANY:
- case MATCHANY:
- case MATCHONE:
- case MATCHCLASS:
- case MATCHNCLASS:
- nfuzzy++;
- break;
-
- case MATCHREPL:
- botch = "$0-$9";
- break;
-
- case CANONUSER:
- botch = "$:";
- break;
-
- case CALLSUBR:
- botch = "$>";
- break;
-
- case CONDIF:
- botch = "$?";
- break;
-
- case CONDFI:
- botch = "$.";
- break;
-
- case HOSTBEGIN:
- botch = "$[";
- break;
-
- case HOSTEND:
- botch = "$]";
- break;
-
- case LOOKUPBEGIN:
- botch = "$(";
- break;
-
- case LOOKUPEND:
- botch = "$)";
- break;
- }
- if (botch != NULL)
- syserr("Inappropriate use of %s on LHS",
- botch);
- }
- }
- else
- {
- syserr("R line: null LHS");
- rwp->r_lhs = null_list;
- }
-
- /* expand and save the RHS */
- while (*++p == '\t')
- continue;
- q = p;
- while (*p != '\0' && *p != '\t')
- p++;
- *p = '\0';
- expand(q, exbuf, sizeof exbuf, e);
- rwp->r_rhs = prescan(exbuf, '\t', pvpbuf,
- sizeof pvpbuf, NULL, NULL);
- if (rwp->r_rhs != NULL)
- {
- register char **ap;
-
- rwp->r_rhs = copyplist(rwp->r_rhs, TRUE);
-
- /* check no out-of-bounds replacements */
- nfuzzy += '0';
- for (ap = rwp->r_rhs; *ap != NULL; ap++)
- {
- char *botch;
-
- botch = NULL;
- switch (**ap & 0377)
- {
- case MATCHREPL:
- if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy)
- {
- syserr("replacement $%c out of bounds",
- (*ap)[1]);
- }
- break;
-
- case MATCHZANY:
- botch = "$*";
- break;
-
- case MATCHANY:
- botch = "$+";
- break;
-
- case MATCHONE:
- botch = "$-";
- break;
-
- case MATCHCLASS:
- botch = "$=";
- break;
-
- case MATCHNCLASS:
- botch = "$~";
- break;
- }
- if (botch != NULL)
- syserr("Inappropriate use of %s on RHS",
- botch);
- }
- }
- else
- {
- syserr("R line: null RHS");
- rwp->r_rhs = null_list;
- }
- break;
-
- case 'S': /* select rewriting set */
- expand(&bp[1], exbuf, sizeof exbuf, e);
- ruleset = strtorwset(exbuf, NULL, ST_ENTER);
- if (ruleset < 0)
- break;
- rwp = RewriteRules[ruleset];
- if (rwp != NULL)
- {
- if (OpMode == MD_TEST || tTd(37, 1))
- printf("WARNING: Ruleset %s has multiple definitions\n",
- &bp[1]);
- while (rwp->r_next != NULL)
- rwp = rwp->r_next;
- }
- break;
-
- case 'D': /* macro definition */
- mid = macid(&bp[1], &ep);
- p = munchstring(ep, NULL, '\0');
- define(mid, newstr(p), e);
- break;
-
- case 'H': /* required header line */
- (void) chompheader(&bp[1], TRUE, NULL, e);
- break;
-
- case 'C': /* word class */
- case 'T': /* trusted user (set class `t') */
- if (bp[0] == 'C')
- {
- mid = macid(&bp[1], &ep);
- expand(ep, exbuf, sizeof exbuf, e);
- p = exbuf;
- }
- else
- {
- mid = 't';
- p = &bp[1];
- }
- while (*p != '\0')
- {
- register char *wd;
- char delim;
-
- while (*p != '\0' && isascii(*p) && isspace(*p))
- p++;
- wd = p;
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
- p++;
- delim = *p;
- *p = '\0';
- if (wd[0] != '\0')
- setclass(mid, wd);
- *p = delim;
- }
- break;
-
- case 'F': /* word class from file */
- mid = macid(&bp[1], &ep);
- for (p = ep; isascii(*p) && isspace(*p); )
- p++;
- if (p[0] == '-' && p[1] == 'o')
- {
- optional = TRUE;
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
- p++;
- while (isascii(*p) && isspace(*p))
- p++;
- }
- else
- optional = FALSE;
- file = p;
- if (*file == '|')
- p = "%s";
- else
- {
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
- p++;
- if (*p == '\0')
- p = "%s";
- else
- {
- *p = '\0';
- while (isascii(*++p) && isspace(*p))
- continue;
- }
- }
- fileclass(mid, file, p, safe, optional);
- break;
-
-#ifdef XLA
- case 'L': /* extended load average description */
- xla_init(&bp[1]);
- break;
-#endif
-
-#if defined(SUN_EXTENSIONS) && defined(SUN_LOOKUP_MACRO)
- case 'L': /* lookup macro */
- case 'G': /* lookup class */
- /* reserved for Sun -- NIS+ database lookup */
- if (VendorCode != VENDOR_SUN)
- goto badline;
- sun_lg_config_line(bp, e);
- break;
-#endif
-
- case 'M': /* define mailer */
- makemailer(&bp[1]);
- break;
-
- case 'O': /* set option */
- setoption(bp[1], &bp[2], safe, FALSE, e);
- break;
-
- case 'P': /* set precedence */
- if (NumPriorities >= MAXPRIORITIES)
- {
- toomany('P', MAXPRIORITIES);
- break;
- }
- for (p = &bp[1]; *p != '\0' && *p != '='; p++)
- continue;
- if (*p == '\0')
- goto badline;
- *p = '\0';
- Priorities[NumPriorities].pri_name = newstr(&bp[1]);
- Priorities[NumPriorities].pri_val = atoi(++p);
- NumPriorities++;
- break;
-
- case 'V': /* configuration syntax version */
- for (p = &bp[1]; isascii(*p) && isspace(*p); p++)
- continue;
- if (!isascii(*p) || !isdigit(*p))
- {
- syserr("invalid argument to V line: \"%.20s\"",
- &bp[1]);
- break;
- }
- ConfigLevel = strtol(p, &ep, 10);
-
- /*
- ** Do heuristic tweaking for back compatibility.
- */
-
- if (ConfigLevel >= 5)
- {
- /* level 5 configs have short name in $w */
- p = macvalue('w', e);
- if (p != NULL && (p = strchr(p, '.')) != NULL)
- *p = '\0';
- define('w', macvalue('w', e), e);
- }
- if (ConfigLevel >= 6)
- {
- ColonOkInAddr = FALSE;
- }
-
- /*
- ** Look for vendor code.
- */
-
- if (*ep++ == '/')
- {
- extern bool setvendor __P((char *));
-
- /* extract vendor code */
- for (p = ep; isascii(*p) && isalpha(*p); )
- p++;
- *p = '\0';
-
- if (!setvendor(ep))
- syserr("invalid V line vendor code: \"%s\"",
- ep);
- }
- break;
-
- case 'K':
- expand(&bp[1], exbuf, sizeof exbuf, e);
- (void) makemapentry(exbuf);
- break;
-
- case 'E':
- p = strchr(bp, '=');
- if (p != NULL)
- *p++ = '\0';
- setuserenv(&bp[1], p);
- break;
-
- default:
- badline:
- syserr("unknown configuration line \"%s\"", bp);
- }
- if (bp != buf)
- free(bp);
- }
- if (ferror(cf))
- {
- syserr("I/O read error");
- finis(FALSE, EX_OSFILE);
- }
- fclose(cf);
- FileName = NULL;
-
- /* initialize host maps from local service tables */
- inithostmaps();
-
- /* determine if we need to do special name-server frotz */
- {
- int nmaps;
- char *maptype[MAXMAPSTACK];
- short mapreturn[MAXMAPACTIONS];
-
- nmaps = switch_map_find("hosts", maptype, mapreturn);
- UseNameServer = FALSE;
- if (nmaps > 0 && nmaps <= MAXMAPSTACK)
- {
- register int mapno;
-
- for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++)
- {
- if (strcmp(maptype[mapno], "dns") == 0)
- UseNameServer = TRUE;
- }
- }
-
-#ifdef HESIOD
- nmaps = switch_map_find("passwd", maptype, mapreturn);
- UseHesiod = FALSE;
- if (nmaps > 0 && nmaps <= MAXMAPSTACK)
- {
- register int mapno;
-
- for (mapno = 0; mapno < nmaps && !UseHesiod; mapno++)
- {
- if (strcmp(maptype[mapno], "hesiod") == 0)
- UseHesiod = TRUE;
- }
- }
-#endif
- }
-}
- /*
-** TRANSLATE_DOLLARS -- convert $x into internal form
-**
-** Actually does all appropriate pre-processing of a config line
-** to turn it into internal form.
-**
-** Parameters:
-** bp -- the buffer to translate.
-**
-** Returns:
-** None. The buffer is translated in place. Since the
-** translations always make the buffer shorter, this is
-** safe without a size parameter.
-*/
-
-void
-translate_dollars(bp)
- char *bp;
-{
- register char *p;
- auto char *ep;
-
- for (p = bp; *p != '\0'; p++)
- {
- if (*p == '#' && p > bp && ConfigLevel >= 3)
- {
- /* this is an on-line comment */
- register char *e;
-
- switch (*--p & 0377)
- {
- case MACROEXPAND:
- /* it's from $# -- let it go through */
- p++;
- break;
-
- case '\\':
- /* it's backslash escaped */
- (void) strcpy(p, p + 1);
- break;
-
- default:
- /* delete preceeding white space */
- while (isascii(*p) && isspace(*p) &&
- *p != '\n' && p > bp)
- p--;
- if ((e = strchr(++p, '\n')) != NULL)
- (void) strcpy(p, e);
- else
- *p-- = '\0';
- break;
- }
- continue;
- }
-
- if (*p != '$' || p[1] == '\0')
- continue;
-
- if (p[1] == '$')
- {
- /* actual dollar sign.... */
- (void) strcpy(p, p + 1);
- continue;
- }
-
- /* convert to macro expansion character */
- *p++ = MACROEXPAND;
-
- /* special handling for $=, $~, $&, and $? */
- if (*p == '=' || *p == '~' || *p == '&' || *p == '?')
- p++;
-
- /* convert macro name to code */
- *p = macid(p, &ep);
- if (ep != p)
- strcpy(p + 1, ep);
- }
-
- /* strip trailing white space from the line */
- while (--p > bp && isascii(*p) && isspace(*p))
- *p = '\0';
-}
- /*
-** TOOMANY -- signal too many of some option
-**
-** Parameters:
-** id -- the id of the error line
-** maxcnt -- the maximum possible values
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** gives a syserr.
-*/
-
-void
-toomany(id, maxcnt)
- int id;
- int maxcnt;
-{
- syserr("too many %c lines, %d max", id, maxcnt);
-}
- /*
-** FILECLASS -- read members of a class from a file
-**
-** Parameters:
-** class -- class to define.
-** filename -- name of file to read.
-** fmt -- scanf string to use for match.
-** safe -- if set, this is a safe read.
-** optional -- if set, it is not an error for the file to
-** not exist.
-**
-** Returns:
-** none
-**
-** Side Effects:
-**
-** puts all lines in filename that match a scanf into
-** the named class.
-*/
-
-void
-fileclass(class, filename, fmt, safe, optional)
- int class;
- char *filename;
- char *fmt;
- bool safe;
- bool optional;
-{
- FILE *f;
- int sff;
- pid_t pid;
- register char *p;
- char buf[MAXLINE];
-
- if (tTd(37, 2))
- printf("fileclass(%s, fmt=%s)\n", filename, fmt);
-
- if (filename[0] == '|')
- {
- auto int fd;
- int i;
- char *argv[MAXPV + 1];
-
- i = 0;
- for (p = strtok(&filename[1], " \t"); p != NULL; p = strtok(NULL, " \t"))
- {
- if (i >= MAXPV)
- break;
- argv[i++] = p;
- }
- argv[i] = NULL;
- pid = prog_open(argv, &fd, CurEnv);
- if (pid < 0)
- f = NULL;
- else
- f = fdopen(fd, "r");
- }
- else
- {
- pid = -1;
- sff = SFF_REGONLY;
- if (!bitset(DBS_CLASSFILEINUNSAFEDIRPATH, DontBlameSendmail))
- sff |= SFF_SAFEDIRPATH;
- if (!bitset(DBS_LINKEDCLASSFILEINWRITABLEDIR, DontBlameSendmail))
- sff |= SFF_NOWLINK;
- if (safe)
- sff |= SFF_OPENASROOT;
- if (DontLockReadFiles)
- sff |= SFF_NOLOCK;
- f = safefopen(filename, O_RDONLY, 0, sff);
- }
- if (f == NULL)
- {
- if (!optional)
- syserr("fileclass: cannot open %s", filename);
- return;
- }
-
- while (fgets(buf, sizeof buf, f) != NULL)
- {
- register char *p;
-# if SCANF
- char wordbuf[MAXLINE + 1];
-# endif
-
- if (buf[0] == '#')
- continue;
-# if SCANF
- if (sscanf(buf, fmt, wordbuf) != 1)
- continue;
- p = wordbuf;
-# else /* SCANF */
- p = buf;
-# endif /* SCANF */
-
- /*
- ** Break up the match into words.
- */
-
- while (*p != '\0')
- {
- register char *q;
-
- /* strip leading spaces */
- while (isascii(*p) && isspace(*p))
- p++;
- if (*p == '\0')
- break;
-
- /* find the end of the word */
- q = p;
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
- p++;
- if (*p != '\0')
- *p++ = '\0';
-
- /* enter the word in the symbol table */
- setclass(class, q);
- }
- }
-
- (void) fclose(f);
- if (pid > 0)
- (void) waitfor(pid);
-}
- /*
-** MAKEMAILER -- define a new mailer.
-**
-** Parameters:
-** line -- description of mailer. This is in labeled
-** fields. The fields are:
-** A -- the argv for this mailer
-** C -- the character set for MIME conversions
-** D -- the directory to run in
-** E -- the eol string
-** F -- the flags associated with the mailer
-** L -- the maximum line length
-** M -- the maximum message size
-** N -- the niceness at which to run
-** P -- the path to the mailer
-** R -- the recipient rewriting set
-** S -- the sender rewriting set
-** T -- the mailer type (for DSNs)
-** U -- the uid to run as
-** The first word is the canonical name of the mailer.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** enters the mailer into the mailer table.
-*/
-
-void
-makemailer(line)
- char *line;
-{
- register char *p;
- register struct mailer *m;
- register STAB *s;
- int i;
- char fcode;
- auto char *endp;
- extern int NextMailer;
- extern char **makeargv __P((char *));
- extern char *munchstring __P((char *, char **, int));
-
- /* allocate a mailer and set up defaults */
- m = (struct mailer *) xalloc(sizeof *m);
- bzero((char *) m, sizeof *m);
-
- /* collect the mailer name */
- for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++)
- continue;
- if (*p != '\0')
- *p++ = '\0';
- if (line[0] == '\0')
- syserr("name required for mailer");
- m->m_name = newstr(line);
-
- /* now scan through and assign info from the fields */
- while (*p != '\0')
- {
- auto char *delimptr;
-
- while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p))))
- p++;
-
- /* p now points to field code */
- fcode = *p;
- while (*p != '\0' && *p != '=' && *p != ',')
- p++;
- if (*p++ != '=')
- {
- syserr("mailer %s: `=' expected", m->m_name);
- return;
- }
- while (isascii(*p) && isspace(*p))
- p++;
-
- /* p now points to the field body */
- p = munchstring(p, &delimptr, ',');
-
- /* install the field into the mailer struct */
- switch (fcode)
- {
- case 'P': /* pathname */
- if (*p == '\0')
- syserr("mailer %s: empty path name", m->m_name);
- m->m_mailer = newstr(p);
- break;
-
- case 'F': /* flags */
- for (; *p != '\0'; p++)
- if (!(isascii(*p) && isspace(*p)))
- setbitn(*p, m->m_flags);
- break;
-
- case 'S': /* sender rewriting ruleset */
- case 'R': /* recipient rewriting ruleset */
- i = strtorwset(p, &endp, ST_ENTER);
- if (i < 0)
- return;
- if (fcode == 'S')
- m->m_sh_rwset = m->m_se_rwset = i;
- else
- m->m_rh_rwset = m->m_re_rwset = i;
-
- p = endp;
- if (*p++ == '/')
- {
- i = strtorwset(p, NULL, ST_ENTER);
- if (i < 0)
- return;
- if (fcode == 'S')
- m->m_sh_rwset = i;
- else
- m->m_rh_rwset = i;
- }
- break;
-
- case 'E': /* end of line string */
- if (*p == '\0')
- syserr("mailer %s: null end-of-line string",
- m->m_name);
- m->m_eol = newstr(p);
- break;
-
- case 'A': /* argument vector */
- if (*p == '\0')
- syserr("mailer %s: null argument vector",
- m->m_name);
- m->m_argv = makeargv(p);
- break;
-
- case 'M': /* maximum message size */
- m->m_maxsize = atol(p);
- break;
-
- case 'L': /* maximum line length */
- m->m_linelimit = atoi(p);
- if (m->m_linelimit < 0)
- m->m_linelimit = 0;
- break;
-
- case 'N': /* run niceness */
- m->m_nice = atoi(p);
- break;
-
- case 'D': /* working directory */
- if (*p == '\0')
- syserr("mailer %s: null working directory",
- m->m_name);
- m->m_execdir = newstr(p);
- break;
-
- case 'C': /* default charset */
- if (*p == '\0')
- syserr("mailer %s: null charset", m->m_name);
- m->m_defcharset = newstr(p);
- break;
-
- case 'T': /* MTA-Name/Address/Diagnostic types */
- /* extract MTA name type; default to "dns" */
- m->m_mtatype = newstr(p);
- p = strchr(m->m_mtatype, '/');
- if (p != NULL)
- {
- *p++ = '\0';
- if (*p == '\0')
- p = NULL;
- }
- if (*m->m_mtatype == '\0')
- m->m_mtatype = "dns";
-
- /* extract address type; default to "rfc822" */
- m->m_addrtype = p;
- if (p != NULL)
- p = strchr(p, '/');
- if (p != NULL)
- {
- *p++ = '\0';
- if (*p == '\0')
- p = NULL;
- }
- if (m->m_addrtype == NULL || *m->m_addrtype == '\0')
- m->m_addrtype = "rfc822";
-
- /* extract diagnostic type; default to "smtp" */
- m->m_diagtype = p;
- if (m->m_diagtype == NULL || *m->m_diagtype == '\0')
- m->m_diagtype = "smtp";
- break;
-
- case 'U': /* user id */
- if (isascii(*p) && !isdigit(*p))
- {
- char *q = p;
- struct passwd *pw;
-
- while (*p != '\0' && isascii(*p) &&
- (isalnum(*p) || strchr("-_", *p) != NULL))
- p++;
- while (isascii(*p) && isspace(*p))
- *p++ = '\0';
- if (*p != '\0')
- *p++ = '\0';
- if (*q == '\0')
- syserr("mailer %s: null user name",
- m->m_name);
- pw = sm_getpwnam(q);
- if (pw == NULL)
- syserr("readcf: mailer U= flag: unknown user %s", q);
- else
- {
- m->m_uid = pw->pw_uid;
- m->m_gid = pw->pw_gid;
- }
- }
- else
- {
- auto char *q;
-
- m->m_uid = strtol(p, &q, 0);
- p = q;
- while (isascii(*p) && isspace(*p))
- p++;
- if (*p != '\0')
- p++;
- }
- while (isascii(*p) && isspace(*p))
- p++;
- if (*p == '\0')
- break;
- if (isascii(*p) && !isdigit(*p))
- {
- char *q = p;
- struct group *gr;
-
- while (isascii(*p) && isalnum(*p))
- p++;
- *p++ = '\0';
- if (*q == '\0')
- syserr("mailer %s: null group name",
- m->m_name);
- gr = getgrnam(q);
- if (gr == NULL)
- syserr("readcf: mailer U= flag: unknown group %s", q);
- else
- m->m_gid = gr->gr_gid;
- }
- else
- {
- m->m_gid = strtol(p, NULL, 0);
- }
- break;
- }
-
- p = delimptr;
- }
-
- /* do some rationality checking */
- if (m->m_argv == NULL)
- {
- syserr("M%s: A= argument required", m->m_name);
- return;
- }
- if (m->m_mailer == NULL)
- {
- syserr("M%s: P= argument required", m->m_name);
- return;
- }
-
- if (NextMailer >= MAXMAILERS)
- {
- syserr("too many mailers defined (%d max)", MAXMAILERS);
- return;
- }
-
- /* do some heuristic cleanup for back compatibility */
- if (bitnset(M_LIMITS, m->m_flags))
- {
- if (m->m_linelimit == 0)
- m->m_linelimit = SMTPLINELIM;
- if (ConfigLevel < 2)
- setbitn(M_7BITS, m->m_flags);
- }
-
- if (strcmp(m->m_mailer, "[IPC]") == 0 ||
- strcmp(m->m_mailer, "[TCP]") == 0)
- {
- if (m->m_mtatype == NULL)
- m->m_mtatype = "dns";
- if (m->m_addrtype == NULL)
- m->m_addrtype = "rfc822";
- if (m->m_diagtype == NULL)
- m->m_diagtype = "smtp";
- }
-
- if (strcmp(m->m_mailer, "[FILE]") == 0)
- {
- /* Use the second argument for filename */
- if (m->m_argv[0] == NULL || m->m_argv[1] == NULL ||
- m->m_argv[2] != NULL)
- {
- syserr("M%s: too %s parameters for [FILE] mailer",
- m->m_name,
- (m->m_argv[0] == NULL ||
- m->m_argv[1] == NULL) ? "few" : "many");
- }
- else if (strcmp(m->m_argv[0], "FILE") != 0)
- {
- syserr("M%s: first argument in [FILE] mailer must be FILE",
- m->m_name);
- }
- }
-
- if (m->m_eol == NULL)
- {
- char **pp;
-
- /* default for SMTP is \r\n; use \n for local delivery */
- for (pp = m->m_argv; *pp != NULL; pp++)
- {
- char *p;
-
- for (p = *pp; *p != '\0'; )
- {
- if ((*p++ & 0377) == MACROEXPAND && *p == 'u')
- break;
- }
- if (*p != '\0')
- break;
- }
- if (*pp == NULL)
- m->m_eol = "\r\n";
- else
- m->m_eol = "\n";
- }
-
- /* enter the mailer into the symbol table */
- s = stab(m->m_name, ST_MAILER, ST_ENTER);
- if (s->s_mailer != NULL)
- {
- i = s->s_mailer->m_mno;
- free(s->s_mailer);
- }
- else
- {
- i = NextMailer++;
- }
- Mailer[i] = s->s_mailer = m;
- m->m_mno = i;
-}
- /*
-** MUNCHSTRING -- translate a string into internal form.
-**
-** Parameters:
-** p -- the string to munch.
-** delimptr -- if non-NULL, set to the pointer of the
-** field delimiter character.
-** delim -- the delimiter for the field.
-**
-** Returns:
-** the munched string.
-*/
-
-char *
-munchstring(p, delimptr, delim)
- register char *p;
- char **delimptr;
- int delim;
-{
- register char *q;
- bool backslash = FALSE;
- bool quotemode = FALSE;
- static char buf[MAXLINE];
-
- for (q = buf; *p != '\0' && q < &buf[sizeof buf - 1]; p++)
- {
- if (backslash)
- {
- /* everything is roughly literal */
- backslash = FALSE;
- switch (*p)
- {
- case 'r': /* carriage return */
- *q++ = '\r';
- continue;
-
- case 'n': /* newline */
- *q++ = '\n';
- continue;
-
- case 'f': /* form feed */
- *q++ = '\f';
- continue;
-
- case 'b': /* backspace */
- *q++ = '\b';
- continue;
- }
- *q++ = *p;
- }
- else
- {
- if (*p == '\\')
- backslash = TRUE;
- else if (*p == '"')
- quotemode = !quotemode;
- else if (quotemode || *p != delim)
- *q++ = *p;
- else
- break;
- }
- }
-
- if (delimptr != NULL)
- *delimptr = p;
- *q++ = '\0';
- return (buf);
-}
- /*
-** MAKEARGV -- break up a string into words
-**
-** Parameters:
-** p -- the string to break up.
-**
-** Returns:
-** a char **argv (dynamically allocated)
-**
-** Side Effects:
-** munges p.
-*/
-
-char **
-makeargv(p)
- register char *p;
-{
- char *q;
- int i;
- char **avp;
- char *argv[MAXPV + 1];
-
- /* take apart the words */
- i = 0;
- while (*p != '\0' && i < MAXPV)
- {
- q = p;
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
- p++;
- while (isascii(*p) && isspace(*p))
- *p++ = '\0';
- argv[i++] = newstr(q);
- }
- argv[i++] = NULL;
-
- /* now make a copy of the argv */
- avp = (char **) xalloc(sizeof *avp * i);
- bcopy((char *) argv, (char *) avp, sizeof *avp * i);
-
- return (avp);
-}
- /*
-** PRINTRULES -- print rewrite rules (for debugging)
-**
-** Parameters:
-** none.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** prints rewrite rules.
-*/
-
-void
-printrules()
-{
- register struct rewrite *rwp;
- register int ruleset;
-
- for (ruleset = 0; ruleset < 10; ruleset++)
- {
- if (RewriteRules[ruleset] == NULL)
- continue;
- printf("\n----Rule Set %d:", ruleset);
-
- for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next)
- {
- printf("\nLHS:");
- printav(rwp->r_lhs);
- printf("RHS:");
- printav(rwp->r_rhs);
- }
- }
-}
- /*
-** PRINTMAILER -- print mailer structure (for debugging)
-**
-** Parameters:
-** m -- the mailer to print
-**
-** Returns:
-** none.
-*/
-
-void
-printmailer(m)
- register MAILER *m;
-{
- int j;
-
- printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld U=%d:%d F=",
- m->m_mno, m->m_name,
- m->m_mailer, m->m_se_rwset, m->m_sh_rwset,
- m->m_re_rwset, m->m_rh_rwset, m->m_maxsize,
- (int) m->m_uid, (int) m->m_gid);
- for (j = '\0'; j <= '\177'; j++)
- if (bitnset(j, m->m_flags))
- (void) putchar(j);
- printf(" L=%d E=", m->m_linelimit);
- xputs(m->m_eol);
- if (m->m_defcharset != NULL)
- printf(" C=%s", m->m_defcharset);
- printf(" T=%s/%s/%s",
- m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype,
- m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype,
- m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype);
- if (m->m_argv != NULL)
- {
- char **a = m->m_argv;
-
- printf(" A=");
- while (*a != NULL)
- {
- if (a != m->m_argv)
- printf(" ");
- xputs(*a++);
- }
- }
- printf("\n");
-}
- /*
-** SETOPTION -- set global processing option
-**
-** Parameters:
-** opt -- option name.
-** val -- option value (as a text string).
-** safe -- set if this came from a configuration file.
-** Some options (if set from the command line) will
-** reset the user id to avoid security problems.
-** sticky -- if set, don't let other setoptions override
-** this value.
-** e -- the main envelope.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Sets options as implied by the arguments.
-*/
-
-static BITMAP StickyOpt; /* set if option is stuck */
-extern void settimeout __P((char *, char *));
-
-
-#if NAMED_BIND
-
-struct resolverflags
-{
- char *rf_name; /* name of the flag */
- long rf_bits; /* bits to set/clear */
-} ResolverFlags[] =
-{
- { "debug", RES_DEBUG },
- { "aaonly", RES_AAONLY },
- { "usevc", RES_USEVC },
- { "primary", RES_PRIMARY },
- { "igntc", RES_IGNTC },
- { "recurse", RES_RECURSE },
- { "defnames", RES_DEFNAMES },
- { "stayopen", RES_STAYOPEN },
- { "dnsrch", RES_DNSRCH },
- { "true", 0 }, /* avoid error on old syntax */
- { NULL, 0 }
-};
-
-#endif
-
-struct optioninfo
-{
- char *o_name; /* long name of option */
- u_char o_code; /* short name of option */
- bool o_safe; /* safe for random people to use */
-} OptionTab[] =
-{
- { "SevenBitInput", '7', TRUE },
-#if MIME8TO7
- { "EightBitMode", '8', TRUE },
-#endif
- { "AliasFile", 'A', FALSE },
- { "AliasWait", 'a', FALSE },
- { "BlankSub", 'B', FALSE },
- { "MinFreeBlocks", 'b', TRUE },
- { "CheckpointInterval", 'C', TRUE },
- { "HoldExpensive", 'c', FALSE },
- { "AutoRebuildAliases", 'D', FALSE },
- { "DeliveryMode", 'd', TRUE },
- { "ErrorHeader", 'E', FALSE },
- { "ErrorMode", 'e', TRUE },
- { "TempFileMode", 'F', FALSE },
- { "SaveFromLine", 'f', FALSE },
- { "MatchGECOS", 'G', FALSE },
- { "HelpFile", 'H', FALSE },
- { "MaxHopCount", 'h', FALSE },
- { "ResolverOptions", 'I', FALSE },
- { "IgnoreDots", 'i', TRUE },
- { "ForwardPath", 'J', FALSE },
- { "SendMimeErrors", 'j', TRUE },
- { "ConnectionCacheSize", 'k', FALSE },
- { "ConnectionCacheTimeout", 'K', FALSE },
- { "UseErrorsTo", 'l', FALSE },
- { "LogLevel", 'L', TRUE },
- { "MeToo", 'm', TRUE },
- { "CheckAliases", 'n', FALSE },
- { "OldStyleHeaders", 'o', TRUE },
- { "DaemonPortOptions", 'O', FALSE },
- { "PrivacyOptions", 'p', TRUE },
- { "PostmasterCopy", 'P', FALSE },
- { "QueueFactor", 'q', FALSE },
- { "QueueDirectory", 'Q', FALSE },
- { "DontPruneRoutes", 'R', FALSE },
- { "Timeout", 'r', FALSE },
- { "StatusFile", 'S', FALSE },
- { "SuperSafe", 's', TRUE },
- { "QueueTimeout", 'T', FALSE },
- { "TimeZoneSpec", 't', FALSE },
- { "UserDatabaseSpec", 'U', FALSE },
- { "DefaultUser", 'u', FALSE },
- { "FallbackMXhost", 'V', FALSE },
- { "Verbose", 'v', TRUE },
- { "TryNullMXList", 'w', FALSE },
- { "QueueLA", 'x', FALSE },
- { "RefuseLA", 'X', FALSE },
- { "RecipientFactor", 'y', FALSE },
- { "ForkEachJob", 'Y', FALSE },
- { "ClassFactor", 'z', FALSE },
- { "RetryFactor", 'Z', FALSE },
-#define O_QUEUESORTORD 0x81
- { "QueueSortOrder", O_QUEUESORTORD, TRUE },
-#define O_HOSTSFILE 0x82
- { "HostsFile", O_HOSTSFILE, FALSE },
-#define O_MQA 0x83
- { "MinQueueAge", O_MQA, TRUE },
-#define O_DEFCHARSET 0x85
- { "DefaultCharSet", O_DEFCHARSET, TRUE },
-#define O_SSFILE 0x86
- { "ServiceSwitchFile", O_SSFILE, FALSE },
-#define O_DIALDELAY 0x87
- { "DialDelay", O_DIALDELAY, TRUE },
-#define O_NORCPTACTION 0x88
- { "NoRecipientAction", O_NORCPTACTION, TRUE },
-#define O_SAFEFILEENV 0x89
- { "SafeFileEnvironment", O_SAFEFILEENV, FALSE },
-#define O_MAXMSGSIZE 0x8a
- { "MaxMessageSize", O_MAXMSGSIZE, FALSE },
-#define O_COLONOKINADDR 0x8b
- { "ColonOkInAddr", O_COLONOKINADDR, TRUE },
-#define O_MAXQUEUERUN 0x8c
- { "MaxQueueRunSize", O_MAXQUEUERUN, TRUE },
-#define O_MAXCHILDREN 0x8d
- { "MaxDaemonChildren", O_MAXCHILDREN, FALSE },
-#define O_KEEPCNAMES 0x8e
- { "DontExpandCnames", O_KEEPCNAMES, FALSE },
-#define O_MUSTQUOTE 0x8f
- { "MustQuoteChars", O_MUSTQUOTE, FALSE },
-#define O_SMTPGREETING 0x90
- { "SmtpGreetingMessage", O_SMTPGREETING, FALSE },
-#define O_UNIXFROM 0x91
- { "UnixFromLine", O_UNIXFROM, FALSE },
-#define O_OPCHARS 0x92
- { "OperatorChars", O_OPCHARS, FALSE },
-#define O_DONTINITGRPS 0x93
- { "DontInitGroups", O_DONTINITGRPS, FALSE },
-#define O_SLFH 0x94
- { "SingleLineFromHeader", O_SLFH, TRUE },
-#define O_ABH 0x95
- { "AllowBogusHELO", O_ABH, TRUE },
-#define O_CONNTHROT 0x97
- { "ConnectionRateThrottle", O_CONNTHROT, FALSE },
-#define O_UGW 0x99
- { "UnsafeGroupWrites", O_UGW, FALSE },
-#define O_DBLBOUNCE 0x9a
- { "DoubleBounceAddress", O_DBLBOUNCE, FALSE },
-#define O_HSDIR 0x9b
- { "HostStatusDirectory", O_HSDIR, FALSE },
-#define O_SINGTHREAD 0x9c
- { "SingleThreadDelivery", O_SINGTHREAD, FALSE },
-#define O_RUNASUSER 0x9d
- { "RunAsUser", O_RUNASUSER, FALSE },
-#if _FFR_DSN_RRT_OPTION
-#define O_DSN_RRT 0x9e
- { "RrtImpliesDsn", O_DSN_RRT, FALSE },
-#endif
-#if _FFR_PIDFILE_OPTION
-#define O_PIDFILE 0x9f
- { "PidFile", O_PIDFILE, FALSE },
-#endif
-#define O_DONTBLAMESENDMAIL 0xa0
- { "DontBlameSendmail", O_DONTBLAMESENDMAIL, FALSE },
-#define O_DPI 0xa1
- { "DontProbeInterfaces", O_DPI, FALSE },
-#define O_MAXRCPT 0xa2
- { "MaxRecipientsPerMessage", O_MAXRCPT, FALSE },
-#if _FFR_DEADLETTERDROP_OPTION
-#define O_DEADLETTER 0xa3
- { "DeadLetterDrop", O_DEADLETTER, FALSE },
-#endif
-#if _FFR_DONTLOCKFILESFORREAD_OPTION
-#define O_DONTLOCK 0xa4
- { "DontLockFilesForRead", O_DONTLOCK, FALSE },
-#endif
-#if _FFR_MAXALIASRECURSION_OPTION
-#define O_MAXALIASRCSN 0xa5
- { "MaxAliasRecursion", O_MAXALIASRCSN, FALSE },
-#endif
-#if _FFR_CONNECTONLYTO_OPTION
-#define O_CNCTONLYTO 0xa6
- { "ConnectOnlyTo", O_CNCTONLYTO, FALSE },
-#endif
-#if _FFR_TRUSTED_USER
-#define O_TRUSTUSER 0xa7
- { "TrustedUser", O_TRUSTUSER, FALSE },
-#endif
-#if _FFR_MAX_MIME_HEADER_LENGTH
-#define O_MAXMIMEHDRLEN 0xa8
- { "MaxMimeHeaderLength", O_MAXMIMEHDRLEN, FALSE },
-#endif
-#if _FFR_CONTROL_SOCKET
-#define O_CONTROLSOCKET 0xa9
- { "ControlSocketName", O_CONTROLSOCKET, FALSE },
-#endif
-#if _FFR_MAX_HEADERS_LENGTH
-#define O_MAXHDRSLEN 0xaa
- { "MaxHeadersLength", O_MAXHDRSLEN, FALSE },
-#endif
- { NULL, '\0', FALSE }
-};
-
-
-
-void
-setoption(opt, val, safe, sticky, e)
- int opt;
- char *val;
- bool safe;
- bool sticky;
- register ENVELOPE *e;
-{
- register char *p;
- register struct optioninfo *o;
- char *subopt;
- int mid;
- bool can_setuid = RunAsUid == 0;
- auto char *ep;
- char buf[50];
- extern bool atobool __P((char *));
- extern time_t convtime __P((char *, char));
- extern int QueueLA;
- extern int RefuseLA;
- extern bool Warn_Q_option;
- extern void setalias __P((char *));
- extern int atooct __P((char *));
- extern void setdefuser __P((void));
- extern void setdaemonoptions __P((char *));
-
- errno = 0;
- if (opt == ' ')
- {
- /* full word options */
- struct optioninfo *sel;
-
- p = strchr(val, '=');
- if (p == NULL)
- p = &val[strlen(val)];
- while (*--p == ' ')
- continue;
- while (*++p == ' ')
- *p = '\0';
- if (p == val)
- {
- syserr("readcf: null option name");
- return;
- }
- if (*p == '=')
- *p++ = '\0';
- while (*p == ' ')
- p++;
- subopt = strchr(val, '.');
- if (subopt != NULL)
- *subopt++ = '\0';
- sel = NULL;
- for (o = OptionTab; o->o_name != NULL; o++)
- {
- if (strncasecmp(o->o_name, val, strlen(val)) != 0)
- continue;
- if (strlen(o->o_name) == strlen(val))
- {
- /* completely specified -- this must be it */
- sel = NULL;
- break;
- }
- if (sel != NULL)
- break;
- sel = o;
- }
- if (sel != NULL && o->o_name == NULL)
- o = sel;
- else if (o->o_name == NULL)
- {
- syserr("readcf: unknown option name %s", val);
- return;
- }
- else if (sel != NULL)
- {
- syserr("readcf: ambiguous option name %s (matches %s and %s)",
- val, sel->o_name, o->o_name);
- return;
- }
- if (strlen(val) != strlen(o->o_name))
- {
- int oldVerbose = Verbose;
-
- Verbose = 1;
- message("Option %s used as abbreviation for %s",
- val, o->o_name);
- Verbose = oldVerbose;
- }
- opt = o->o_code;
- val = p;
- }
- else
- {
- for (o = OptionTab; o->o_name != NULL; o++)
- {
- if (o->o_code == opt)
- break;
- }
- subopt = NULL;
- }
-
- if (tTd(37, 1))
- {
- printf(isascii(opt) && isprint(opt) ?
- "setoption %s (%c).%s=" :
- "setoption %s (0x%x).%s=",
- o->o_name == NULL ? "<unknown>" : o->o_name,
- opt,
- subopt == NULL ? "" : subopt);
- xputs(val);
- }
-
- /*
- ** See if this option is preset for us.
- */
-
- if (!sticky && bitnset(opt, StickyOpt))
- {
- if (tTd(37, 1))
- printf(" (ignored)\n");
- return;
- }
-
- /*
- ** Check to see if this option can be specified by this user.
- */
-
- if (!safe && RealUid == 0)
- safe = TRUE;
- if (!safe && !o->o_safe)
- {
- if (opt != 'M' || (val[0] != 'r' && val[0] != 's'))
- {
- if (tTd(37, 1))
- printf(" (unsafe)");
- (void) drop_privileges(TRUE);
- }
- }
- if (tTd(37, 1))
- printf("\n");
-
- switch (opt & 0xff)
- {
- case '7': /* force seven-bit input */
- SevenBitInput = atobool(val);
- break;
-
-#if MIME8TO7
- case '8': /* handling of 8-bit input */
- switch (*val)
- {
- case 'm': /* convert 8-bit, convert MIME */
- MimeMode = MM_CVTMIME|MM_MIME8BIT;
- break;
-
- case 'p': /* pass 8 bit, convert MIME */
- MimeMode = MM_CVTMIME|MM_PASS8BIT;
- break;
-
- case 's': /* strict adherence */
- MimeMode = MM_CVTMIME;
- break;
-
-#if 0
- case 'r': /* reject 8-bit, don't convert MIME */
- MimeMode = 0;
- break;
-
- case 'j': /* "just send 8" */
- MimeMode = MM_PASS8BIT;
- break;
-
- case 'a': /* encode 8 bit if available */
- MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME;
- break;
-
- case 'c': /* convert 8 bit to MIME, never 7 bit */
- MimeMode = MM_MIME8BIT;
- break;
-#endif
-
- default:
- syserr("Unknown 8-bit mode %c", *val);
- finis(FALSE, EX_USAGE);
- }
- break;
-#endif
-
- case 'A': /* set default alias file */
- if (val[0] == '\0')
- setalias("aliases");
- else
- setalias(val);
- break;
-
- case 'a': /* look N minutes for "@:@" in alias file */
- if (val[0] == '\0')
- SafeAlias = 5 * 60; /* five minutes */
- else
- SafeAlias = convtime(val, 'm');
- break;
-
- case 'B': /* substitution for blank character */
- SpaceSub = val[0];
- if (SpaceSub == '\0')
- SpaceSub = ' ';
- break;
-
- case 'b': /* min blocks free on queue fs/max msg size */
- p = strchr(val, '/');
- if (p != NULL)
- {
- *p++ = '\0';
- MaxMessageSize = atol(p);
- }
- MinBlocksFree = atol(val);
- break;
-
- case 'c': /* don't connect to "expensive" mailers */
- NoConnect = atobool(val);
- break;
-
- case 'C': /* checkpoint every N addresses */
- CheckpointInterval = atoi(val);
- break;
-
- case 'd': /* delivery mode */
- switch (*val)
- {
- case '\0':
- e->e_sendmode = SM_DELIVER;
- break;
-
- case SM_QUEUE: /* queue only */
- case SM_DEFER: /* queue only and defer map lookups */
-#if !QUEUE
- syserr("need QUEUE to set -odqueue or -oddefer");
-#endif /* QUEUE */
- /* fall through..... */
-
- case SM_DELIVER: /* do everything */
- case SM_FORK: /* fork after verification */
- e->e_sendmode = *val;
- break;
-
- default:
- syserr("Unknown delivery mode %c", *val);
- finis(FALSE, EX_USAGE);
- }
- buf[0] = (char)e->e_sendmode;
- buf[1] = '\0';
- define(macid("{deliveryMode}", NULL), newstr(buf), e);
- break;
-
- case 'D': /* rebuild alias database as needed */
- AutoRebuild = atobool(val);
- break;
-
- case 'E': /* error message header/header file */
- if (*val != '\0')
- ErrMsgFile = newstr(val);
- break;
-
- case 'e': /* set error processing mode */
- switch (*val)
- {
- case EM_QUIET: /* be silent about it */
- case EM_MAIL: /* mail back */
- case EM_BERKNET: /* do berknet error processing */
- case EM_WRITE: /* write back (or mail) */
- case EM_PRINT: /* print errors normally (default) */
- e->e_errormode = *val;
- break;
- }
- break;
-
- case 'F': /* file mode */
- FileMode = atooct(val) & 0777;
- break;
-
- case 'f': /* save Unix-style From lines on front */
- SaveFrom = atobool(val);
- break;
-
- case 'G': /* match recipients against GECOS field */
- MatchGecos = atobool(val);
- break;
-
- case 'g': /* default gid */
- g_opt:
- if (isascii(*val) && isdigit(*val))
- DefGid = atoi(val);
- else
- {
- register struct group *gr;
-
- DefGid = -1;
- gr = getgrnam(val);
- if (gr == NULL)
- syserr("readcf: option %c: unknown group %s",
- opt, val);
- else
- DefGid = gr->gr_gid;
- }
- break;
-
- case 'H': /* help file */
- if (val[0] == '\0')
- HelpFile = "sendmail.hf";
- else
- HelpFile = newstr(val);
- break;
-
- case 'h': /* maximum hop count */
- MaxHopCount = atoi(val);
- break;
-
- case 'I': /* use internet domain name server */
-#if NAMED_BIND
- for (p = val; *p != 0; )
- {
- bool clearmode;
- char *q;
- struct resolverflags *rfp;
-
- while (*p == ' ')
- p++;
- if (*p == '\0')
- break;
- clearmode = FALSE;
- if (*p == '-')
- clearmode = TRUE;
- else if (*p != '+')
- p--;
- p++;
- q = p;
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
- p++;
- if (*p != '\0')
- *p++ = '\0';
- if (strcasecmp(q, "HasWildcardMX") == 0)
- {
- HasWildcardMX = !clearmode;
- continue;
- }
- for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++)
- {
- if (strcasecmp(q, rfp->rf_name) == 0)
- break;
- }
- if (rfp->rf_name == NULL)
- syserr("readcf: I option value %s unrecognized", q);
- else if (clearmode)
- _res.options &= ~rfp->rf_bits;
- else
- _res.options |= rfp->rf_bits;
- }
- if (tTd(8, 2))
- printf("_res.options = %x, HasWildcardMX = %d\n",
- (u_int) _res.options, HasWildcardMX);
-#else
- usrerr("name server (I option) specified but BIND not compiled in");
-#endif
- break;
-
- case 'i': /* ignore dot lines in message */
- IgnrDot = atobool(val);
- break;
-
- case 'j': /* send errors in MIME (RFC 1341) format */
- SendMIMEErrors = atobool(val);
- break;
-
- case 'J': /* .forward search path */
- ForwardPath = newstr(val);
- break;
-
- case 'k': /* connection cache size */
- MaxMciCache = atoi(val);
- if (MaxMciCache < 0)
- MaxMciCache = 0;
- break;
-
- case 'K': /* connection cache timeout */
- MciCacheTimeout = convtime(val, 'm');
- break;
-
- case 'l': /* use Errors-To: header */
- UseErrorsTo = atobool(val);
- break;
-
- case 'L': /* log level */
- if (safe || LogLevel < atoi(val))
- LogLevel = atoi(val);
- break;
-
- case 'M': /* define macro */
- mid = macid(val, &ep);
- p = newstr(ep);
- if (!safe)
- cleanstrcpy(p, p, MAXNAME);
- define(mid, p, CurEnv);
- sticky = FALSE;
- break;
-
- case 'm': /* send to me too */
- MeToo = atobool(val);
- break;
-
- case 'n': /* validate RHS in newaliases */
- CheckAliases = atobool(val);
- break;
-
- /* 'N' available -- was "net name" */
-
- case 'O': /* daemon options */
-#if DAEMON
- setdaemonoptions(val);
-#else
- syserr("DaemonPortOptions (O option) set but DAEMON not compiled in");
-#endif
- break;
-
- case 'o': /* assume old style headers */
- if (atobool(val))
- CurEnv->e_flags |= EF_OLDSTYLE;
- else
- CurEnv->e_flags &= ~EF_OLDSTYLE;
- break;
-
- case 'p': /* select privacy level */
- p = val;
- for (;;)
- {
- register struct prival *pv;
- extern struct prival PrivacyValues[];
-
- while (isascii(*p) && (isspace(*p) || ispunct(*p)))
- p++;
- if (*p == '\0')
- break;
- val = p;
- while (isascii(*p) && isalnum(*p))
- p++;
- if (*p != '\0')
- *p++ = '\0';
-
- for (pv = PrivacyValues; pv->pv_name != NULL; pv++)
- {
- if (strcasecmp(val, pv->pv_name) == 0)
- break;
- }
- if (pv->pv_name == NULL)
- syserr("readcf: Op line: %s unrecognized", val);
- PrivacyFlags |= pv->pv_flag;
- }
- sticky = FALSE;
- break;
-
- case 'P': /* postmaster copy address for returned mail */
- PostMasterCopy = newstr(val);
- break;
-
- case 'q': /* slope of queue only function */
- QueueFactor = atoi(val);
- break;
-
- case 'Q': /* queue directory */
- if (val[0] == '\0')
- QueueDir = "mqueue";
- else
- QueueDir = newstr(val);
- if (RealUid != 0 && !safe)
- Warn_Q_option = TRUE;
- break;
-
- case 'R': /* don't prune routes */
- DontPruneRoutes = atobool(val);
- break;
-
- case 'r': /* read timeout */
- if (subopt == NULL)
- inittimeouts(val);
- else
- settimeout(subopt, val);
- break;
-
- case 'S': /* status file */
- if (val[0] == '\0')
- StatFile = "sendmail.st";
- else
- StatFile = newstr(val);
- break;
-
- case 's': /* be super safe, even if expensive */
- SuperSafe = atobool(val);
- break;
-
- case 'T': /* queue timeout */
- p = strchr(val, '/');
- if (p != NULL)
- {
- *p++ = '\0';
- settimeout("queuewarn", p);
- }
- settimeout("queuereturn", val);
- break;
-
- case 't': /* time zone name */
- TimeZoneSpec = newstr(val);
- break;
-
- case 'U': /* location of user database */
- UdbSpec = newstr(val);
- break;
-
- case 'u': /* set default uid */
- for (p = val; *p != '\0'; p++)
- {
- if (*p == '.' || *p == '/' || *p == ':')
- {
- *p++ = '\0';
- break;
- }
- }
- if (isascii(*val) && isdigit(*val))
- {
- DefUid = atoi(val);
- setdefuser();
- }
- else
- {
- register struct passwd *pw;
-
- DefUid = -1;
- pw = sm_getpwnam(val);
- if (pw == NULL)
- syserr("readcf: option u: unknown user %s", val);
- else
- {
- DefUid = pw->pw_uid;
- DefGid = pw->pw_gid;
- DefUser = newstr(pw->pw_name);
- }
- }
-
-#ifdef UID_MAX
- if (DefUid > UID_MAX)
- {
- syserr("readcf: option u: uid value (%ld) > UID_MAX (%ld); ignored",
- DefUid, UID_MAX);
- }
-#endif
-
- /* handle the group if it is there */
- if (*p == '\0')
- break;
- val = p;
- goto g_opt;
-
- case 'V': /* fallback MX host */
- if (val[0] != '\0')
- FallBackMX = newstr(val);
- break;
-
- case 'v': /* run in verbose mode */
- Verbose = atobool(val) ? 1 : 0;
- break;
-
- case 'w': /* if we are best MX, try host directly */
- TryNullMXList = atobool(val);
- break;
-
- /* 'W' available -- was wizard password */
-
- case 'x': /* load avg at which to auto-queue msgs */
- QueueLA = atoi(val);
- break;
-
- case 'X': /* load avg at which to auto-reject connections */
- RefuseLA = atoi(val);
- break;
-
- case 'y': /* work recipient factor */
- WkRecipFact = atoi(val);
- break;
-
- case 'Y': /* fork jobs during queue runs */
- ForkQueueRuns = atobool(val);
- break;
-
- case 'z': /* work message class factor */
- WkClassFact = atoi(val);
- break;
-
- case 'Z': /* work time factor */
- WkTimeFact = atoi(val);
- break;
-
- case O_QUEUESORTORD: /* queue sorting order */
- switch (*val)
- {
- case 'h': /* Host first */
- case 'H':
- QueueSortOrder = QS_BYHOST;
- break;
-
- case 'p': /* Priority order */
- case 'P':
- QueueSortOrder = QS_BYPRIORITY;
- break;
-
- case 't': /* Submission time */
- case 'T':
- QueueSortOrder = QS_BYTIME;
- break;
-
- default:
- syserr("Invalid queue sort order \"%s\"", val);
- }
- break;
-
- case O_HOSTSFILE: /* pathname of /etc/hosts file */
- HostsFile = newstr(val);
- break;
-
- case O_MQA: /* minimum queue age between deliveries */
- MinQueueAge = convtime(val, 'm');
- break;
-
- case O_DEFCHARSET: /* default character set for mimefying */
- DefaultCharSet = newstr(denlstring(val, TRUE, TRUE));
- break;
-
- case O_SSFILE: /* service switch file */
- ServiceSwitchFile = newstr(val);
- break;
-
- case O_DIALDELAY: /* delay for dial-on-demand operation */
- DialDelay = convtime(val, 's');
- break;
-
- case O_NORCPTACTION: /* what to do if no recipient */
- if (strcasecmp(val, "none") == 0)
- NoRecipientAction = NRA_NO_ACTION;
- else if (strcasecmp(val, "add-to") == 0)
- NoRecipientAction = NRA_ADD_TO;
- else if (strcasecmp(val, "add-apparently-to") == 0)
- NoRecipientAction = NRA_ADD_APPARENTLY_TO;
- else if (strcasecmp(val, "add-bcc") == 0)
- NoRecipientAction = NRA_ADD_BCC;
- else if (strcasecmp(val, "add-to-undisclosed") == 0)
- NoRecipientAction = NRA_ADD_TO_UNDISCLOSED;
- else
- syserr("Invalid NoRecipientAction: %s", val);
- break;
-
- case O_SAFEFILEENV: /* chroot() environ for writing to files */
- SafeFileEnv = newstr(val);
- break;
-
- case O_MAXMSGSIZE: /* maximum message size */
- MaxMessageSize = atol(val);
- break;
-
- case O_COLONOKINADDR: /* old style handling of colon addresses */
- ColonOkInAddr = atobool(val);
- break;
-
- case O_MAXQUEUERUN: /* max # of jobs in a single queue run */
- MaxQueueRun = atol(val);
- break;
-
- case O_MAXCHILDREN: /* max # of children of daemon */
- MaxChildren = atoi(val);
- break;
-
- case O_KEEPCNAMES: /* don't expand CNAME records */
- DontExpandCnames = atobool(val);
- break;
-
- case O_MUSTQUOTE: /* must quote these characters in phrases */
- strcpy(buf, "@,;:\\()[]");
- if (strlen(val) < (SIZE_T) sizeof buf - 10)
- strcat(buf, val);
- MustQuoteChars = newstr(buf);
- break;
-
- case O_SMTPGREETING: /* SMTP greeting message (old $e macro) */
- SmtpGreeting = newstr(munchstring(val, NULL, '\0'));
- break;
-
- case O_UNIXFROM: /* UNIX From_ line (old $l macro) */
- UnixFromLine = newstr(munchstring(val, NULL, '\0'));
- break;
-
- case O_OPCHARS: /* operator characters (old $o macro) */
- OperatorChars = newstr(munchstring(val, NULL, '\0'));
- break;
-
- case O_DONTINITGRPS: /* don't call initgroups(3) */
- DontInitGroups = atobool(val);
- break;
-
- case O_SLFH: /* make sure from fits on one line */
- SingleLineFromHeader = atobool(val);
- break;
-
- case O_ABH: /* allow HELO commands with syntax errors */
- AllowBogusHELO = atobool(val);
- break;
-
- case O_CONNTHROT: /* connection rate throttle */
- ConnRateThrottle = atoi(val);
- break;
-
- case O_UGW: /* group writable files are unsafe */
- if (!atobool(val))
- DontBlameSendmail |= DBS_GROUPWRITABLEFORWARDFILESAFE|DBS_GROUPWRITABLEINCLUDEFILESAFE;
- break;
-
- case O_DBLBOUNCE: /* address to which to send double bounces */
- if (val[0] != '\0')
- DoubleBounceAddr = newstr(val);
- else
- syserr("readcf: option DoubleBounceAddress: value required");
- break;
-
- case O_HSDIR: /* persistent host status directory */
- if (val[0] != '\0')
- HostStatDir = newstr(val);
- break;
-
- case O_SINGTHREAD: /* single thread deliveries (requires hsdir) */
- SingleThreadDelivery = atobool(val);
- break;
-
- case O_RUNASUSER: /* run bulk of code as this user */
- for (p = val; *p != '\0'; p++)
- {
- if (*p == '.' || *p == '/' || *p == ':')
- {
- *p++ = '\0';
- break;
- }
- }
- if (isascii(*val) && isdigit(*val))
- {
- if (can_setuid)
- RunAsUid = atoi(val);
- }
- else
- {
- register struct passwd *pw;
-
- pw = sm_getpwnam(val);
- if (pw == NULL)
- syserr("readcf: option RunAsUser: unknown user %s", val);
- else if (can_setuid)
- {
- if (*p == '\0')
- RunAsUserName = newstr(val);
- RunAsUid = pw->pw_uid;
- RunAsGid = pw->pw_gid;
- }
- }
-#ifdef UID_MAX
- if (RunAsUid > UID_MAX)
- {
- syserr("readcf: option RunAsUser: uid value (%ld) > UID_MAX (%ld); ignored",
- RunAsUid, UID_MAX);
- }
-#endif
- if (*p != '\0')
- {
- if (isascii(*p) && isdigit(*p))
- {
- if (can_setuid)
- RunAsGid = atoi(p);
- }
- else
- {
- register struct group *gr;
-
- gr = getgrnam(p);
- if (gr == NULL)
- syserr("readcf: option RunAsUser: unknown group %s",
- p);
- else if (can_setuid)
- RunAsGid = gr->gr_gid;
- }
- }
- if (tTd(47, 5))
- printf("readcf: RunAsUser = %d:%d\n", (int)RunAsUid, (int)RunAsGid);
- break;
-
-#if _FFR_DSN_RRT_OPTION
- case O_DSN_RRT:
- RrtImpliesDsn = atobool(val);
- break;
-#endif
-
-#if _FFR_PIDFILE_OPTION
- case O_PIDFILE:
- free(PidFile);
- PidFile = newstr(val);
- break;
-#endif
-
- case O_DONTBLAMESENDMAIL:
- p = val;
- for (;;)
- {
- register struct dbsval *dbs;
- extern struct dbsval DontBlameSendmailValues[];
-
- while (isascii(*p) && (isspace(*p) || ispunct(*p)))
- p++;
- if (*p == '\0')
- break;
- val = p;
- while (isascii(*p) && isalnum(*p))
- p++;
- if (*p != '\0')
- *p++ = '\0';
-
- for (dbs = DontBlameSendmailValues;
- dbs->dbs_name != NULL; dbs++)
- {
- if (strcasecmp(val, dbs->dbs_name) == 0)
- break;
- }
- if (dbs->dbs_name == NULL)
- syserr("readcf: DontBlameSendmail option: %s unrecognized", val);
- else if (dbs->dbs_flag == DBS_SAFE)
- DontBlameSendmail = DBS_SAFE;
- else
- DontBlameSendmail |= dbs->dbs_flag;
- }
- sticky = FALSE;
- break;
-
- case O_DPI:
- DontProbeInterfaces = atobool(val);
- break;
-
- case O_MAXRCPT:
- MaxRcptPerMsg = atoi(val);
- break;
-
-#if _FFR_DEADLETTERDROP_OPTION
- case O_DEADLETTER:
- if (DeadLetterDrop != NULL)
- free(DeadLetterDrop);
- DeadLetterDrop = newstr(val);
- break;
-#endif
-
-#if _FFR_DONTLOCKFILESFORREAD_OPTION
- case O_DONTLOCK:
- DontLockReadFiles = atobool(val);
- break;
-#endif
-
-#if _FFR_MAXALIASRECURSION_OPTION
- case O_MAXALIASRCSN:
- MaxAliasRecursion = atoi(val);
- break;
-#endif
-
-#if _FFR_CONNECTONLYTO_OPTION
- case O_CNCTONLYTO:
- /* XXX should probably use gethostbyname */
- ConnectOnlyTo = inet_addr(val);
- break;
-#endif
-
-#if _FFR_TRUSTED_USER
- case O_TRUSTUSER:
- if (isascii(*val) && isdigit(*val))
- TrustedUid = atoi(val);
- else
- {
- register struct passwd *pw;
-
- TrustedUid = 0;
- pw = sm_getpwnam(val);
- if (pw == NULL)
- syserr("readcf: option TrustedUser: unknown user %s", val);
- else
- TrustedUid = pw->pw_uid;
- }
-
-#ifdef UID_MAX
- if (TrustedUid > UID_MAX)
- {
- syserr("readcf: option TrustedUser: uid value (%ld) > UID_MAX (%ld)",
- TrustedUid, UID_MAX);
- TrustedUid = 0;
- }
-#endif
- break;
-#endif
-
-#if _FFR_MAX_MIME_HEADER_LENGTH
- case O_MAXMIMEHDRLEN:
- p = strchr(val, '/');
- if (p != NULL)
- *p++ = '\0';
- MaxMimeHeaderLength = atoi(val);
- if (p != NULL && *p != '\0')
- MaxMimeFieldLength = atoi(p);
- else
- MaxMimeFieldLength = MaxMimeHeaderLength / 2;
-
- if (MaxMimeHeaderLength < 0)
- MaxMimeHeaderLength = 0;
- else if (MaxMimeHeaderLength < 128)
- printf("Warning: MaxMimeHeaderLength: header length limit set lower than 128\n");
-
- if (MaxMimeFieldLength < 0)
- MaxMimeFieldLength = 0;
- else if (MaxMimeFieldLength < 40)
- printf("Warning: MaxMimeHeaderLength: field length limit set lower than 40\n");
- break;
-#endif
-
-#if _FFR_CONTROL_SOCKET
- case O_CONTROLSOCKET:
- if (ControlSocketName != NULL)
- free(ControlSocketName);
- ControlSocketName = newstr(val);
- break;
-#endif
-
-#if _FFR_MAX_HEADERS_LENGTH
- case O_MAXHDRSLEN:
- MaxHeadersLength = atoi(val);
-
- if (MaxHeadersLength > 0 &&
- MaxHeadersLength < (MAXHDRSLEN / 2))
- printf("Warning: MaxHeadersLength: headers length limit set lower than %d\n", MAXHDRSLEN);
- break;
-#endif
-
- default:
- if (tTd(37, 1))
- {
- if (isascii(opt) && isprint(opt))
- printf("Warning: option %c unknown\n", opt);
- else
- printf("Warning: option 0x%x unknown\n", opt);
- }
- break;
- }
- if (sticky)
- setbitn(opt, StickyOpt);
-}
- /*
-** SETCLASS -- set a string into a class
-**
-** Parameters:
-** class -- the class to put the string in.
-** str -- the string to enter
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** puts the word into the symbol table.
-*/
-
-void
-setclass(class, str)
- int class;
- char *str;
-{
- register STAB *s;
-
- if (tTd(37, 8))
- printf("setclass(%s, %s)\n", macname(class), str);
- s = stab(str, ST_CLASS, ST_ENTER);
- setbitn(class, s->s_class);
-}
- /*
-** MAKEMAPENTRY -- create a map entry
-**
-** Parameters:
-** line -- the config file line
-**
-** Returns:
-** A pointer to the map that has been created.
-** NULL if there was a syntax error.
-**
-** Side Effects:
-** Enters the map into the dictionary.
-*/
-
-MAP *
-makemapentry(line)
- char *line;
-{
- register char *p;
- char *mapname;
- char *classname;
- register STAB *s;
- STAB *class;
-
- for (p = line; isascii(*p) && isspace(*p); p++)
- continue;
- if (!(isascii(*p) && isalnum(*p)))
- {
- syserr("readcf: config K line: no map name");
- return NULL;
- }
-
- mapname = p;
- while ((isascii(*++p) && isalnum(*p)) || *p == '_' || *p == '.')
- continue;
- if (*p != '\0')
- *p++ = '\0';
- while (isascii(*p) && isspace(*p))
- p++;
- if (!(isascii(*p) && isalnum(*p)))
- {
- syserr("readcf: config K line, map %s: no map class", mapname);
- return NULL;
- }
- classname = p;
- while (isascii(*++p) && isalnum(*p))
- continue;
- if (*p != '\0')
- *p++ = '\0';
- while (isascii(*p) && isspace(*p))
- p++;
-
- /* look up the class */
- class = stab(classname, ST_MAPCLASS, ST_FIND);
- if (class == NULL)
- {
- syserr("readcf: map %s: class %s not available", mapname, classname);
- return NULL;
- }
-
- /* enter the map */
- s = stab(mapname, ST_MAP, ST_ENTER);
- s->s_map.map_class = &class->s_mapclass;
- s->s_map.map_mname = newstr(mapname);
-
- if (class->s_mapclass.map_parse(&s->s_map, p))
- s->s_map.map_mflags |= MF_VALID;
-
- if (tTd(37, 5))
- {
- printf("map %s, class %s, flags %lx, file %s,\n",
- s->s_map.map_mname, s->s_map.map_class->map_cname,
- s->s_map.map_mflags,
- s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file);
- printf("\tapp %s, domain %s, rebuild %s\n",
- s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app,
- s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain,
- s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild);
- }
-
- return &s->s_map;
-}
- /*
-** STRTORWSET -- convert string to rewriting set number
-**
-** Parameters:
-** p -- the pointer to the string to decode.
-** endp -- if set, store the trailing delimiter here.
-** stabmode -- ST_ENTER to create this entry, ST_FIND if
-** it must already exist.
-**
-** Returns:
-** The appropriate ruleset number.
-** -1 if it is not valid (error already printed)
-*/
-
-int
-strtorwset(p, endp, stabmode)
- char *p;
- char **endp;
- int stabmode;
-{
- int ruleset;
- static int nextruleset = MAXRWSETS;
-
- while (isascii(*p) && isspace(*p))
- p++;
- if (!isascii(*p))
- {
- syserr("invalid ruleset name: \"%.20s\"", p);
- return -1;
- }
- if (isdigit(*p))
- {
- ruleset = strtol(p, endp, 10);
- if (ruleset >= MAXRWSETS / 2 || ruleset < 0)
- {
- syserr("bad ruleset %d (%d max)",
- ruleset, MAXRWSETS / 2);
- ruleset = -1;
- }
- }
- else
- {
- STAB *s;
- char delim;
- char *q;
-
- q = p;
- while (*p != '\0' && isascii(*p) &&
- (isalnum(*p) || *p == '_'))
- p++;
- if (q == p || !(isascii(*q) && isalpha(*q)))
- {
- /* no valid characters */
- syserr("invalid ruleset name: \"%.20s\"", q);
- return -1;
- }
- while (isascii(*p) && isspace(*p))
- *p++ = '\0';
- delim = *p;
- if (delim != '\0')
- *p = '\0';
- s = stab(q, ST_RULESET, stabmode);
- if (delim != '\0')
- *p = delim;
-
- if (s == NULL)
- return -1;
-
- if (stabmode == ST_ENTER && delim == '=')
- {
- while (isascii(*++p) && isspace(*p))
- continue;
- if (!(isascii(*p) && isdigit(*p)))
- {
- syserr("bad ruleset definition \"%s\" (number required after `=')", q);
- ruleset = -1;
- }
- else
- {
- ruleset = strtol(p, endp, 10);
- if (ruleset >= MAXRWSETS / 2 || ruleset < 0)
- {
- syserr("bad ruleset number %d in \"%s\" (%d max)",
- ruleset, q, MAXRWSETS / 2);
- ruleset = -1;
- }
- }
- }
- else
- {
- if (endp != NULL)
- *endp = p;
- if (s->s_ruleset > 0)
- ruleset = s->s_ruleset;
- else if ((ruleset = --nextruleset) < MAXRWSETS / 2)
- {
- syserr("%s: too many named rulesets (%d max)",
- q, MAXRWSETS / 2);
- ruleset = -1;
- }
- }
- if (s->s_ruleset > 0 && ruleset >= 0 && ruleset != s->s_ruleset)
- {
- syserr("%s: ruleset changed value (old %d, new %d)",
- q, s->s_ruleset, ruleset);
- ruleset = s->s_ruleset;
- }
- else if (ruleset > 0)
- {
- s->s_ruleset = ruleset;
- }
- }
- return ruleset;
-}
- /*
-** INITTIMEOUTS -- parse and set timeout values
-**
-** Parameters:
-** val -- a pointer to the values. If NULL, do initial
-** settings.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Initializes the TimeOuts structure
-*/
-
-#define SECONDS
-#define MINUTES * 60
-#define HOUR * 3600
-
-void
-inittimeouts(val)
- register char *val;
-{
- register char *p;
- extern time_t convtime __P((char *, char));
-
- if (tTd(37, 2))
- printf("inittimeouts(%s)\n", val == NULL ? "<NULL>" : val);
- if (val == NULL)
- {
- TimeOuts.to_connect = (time_t) 0 SECONDS;
- TimeOuts.to_initial = (time_t) 5 MINUTES;
- TimeOuts.to_helo = (time_t) 5 MINUTES;
- TimeOuts.to_mail = (time_t) 10 MINUTES;
- TimeOuts.to_rcpt = (time_t) 1 HOUR;
- TimeOuts.to_datainit = (time_t) 5 MINUTES;
- TimeOuts.to_datablock = (time_t) 1 HOUR;
- TimeOuts.to_datafinal = (time_t) 1 HOUR;
- TimeOuts.to_rset = (time_t) 5 MINUTES;
- TimeOuts.to_quit = (time_t) 2 MINUTES;
- TimeOuts.to_nextcommand = (time_t) 1 HOUR;
- TimeOuts.to_miscshort = (time_t) 2 MINUTES;
-#if IDENTPROTO
- TimeOuts.to_ident = (time_t) 30 SECONDS;
-#else
- TimeOuts.to_ident = (time_t) 0 SECONDS;
-#endif
- TimeOuts.to_fileopen = (time_t) 60 SECONDS;
- if (tTd(37, 5))
- {
- printf("Timeouts:\n");
- printf(" connect = %ld\n", (long)TimeOuts.to_connect);
- printf(" initial = %ld\n", (long)TimeOuts.to_initial);
- printf(" helo = %ld\n", (long)TimeOuts.to_helo);
- printf(" mail = %ld\n", (long)TimeOuts.to_mail);
- printf(" rcpt = %ld\n", (long)TimeOuts.to_rcpt);
- printf(" datainit = %ld\n", (long)TimeOuts.to_datainit);
- printf(" datablock = %ld\n", (long)TimeOuts.to_datablock);
- printf(" datafinal = %ld\n", (long)TimeOuts.to_datafinal);
- printf(" rset = %ld\n", (long)TimeOuts.to_rset);
- printf(" quit = %ld\n", (long)TimeOuts.to_quit);
- printf(" nextcommand = %ld\n", (long)TimeOuts.to_nextcommand);
- printf(" miscshort = %ld\n", (long)TimeOuts.to_miscshort);
- printf(" ident = %ld\n", (long)TimeOuts.to_ident);
- printf(" fileopen = %ld\n", (long)TimeOuts.to_fileopen);
- }
- return;
- }
-
- for (;; val = p)
- {
- while (isascii(*val) && isspace(*val))
- val++;
- if (*val == '\0')
- break;
- for (p = val; *p != '\0' && *p != ','; p++)
- continue;
- if (*p != '\0')
- *p++ = '\0';
-
- if (isascii(*val) && isdigit(*val))
- {
- /* old syntax -- set everything */
- TimeOuts.to_mail = convtime(val, 'm');
- TimeOuts.to_rcpt = TimeOuts.to_mail;
- TimeOuts.to_datainit = TimeOuts.to_mail;
- TimeOuts.to_datablock = TimeOuts.to_mail;
- TimeOuts.to_datafinal = TimeOuts.to_mail;
- TimeOuts.to_nextcommand = TimeOuts.to_mail;
- continue;
- }
- else
- {
- register char *q = strchr(val, ':');
-
- if (q == NULL && (q = strchr(val, '=')) == NULL)
- {
- /* syntax error */
- continue;
- }
- *q++ = '\0';
- settimeout(val, q);
- }
- }
-}
- /*
-** SETTIMEOUT -- set an individual timeout
-**
-** Parameters:
-** name -- the name of the timeout.
-** val -- the value of the timeout.
-**
-** Returns:
-** none.
-*/
-
-void
-settimeout(name, val)
- char *name;
- char *val;
-{
- register char *p;
- time_t to;
- extern time_t convtime __P((char *, char));
-
- if (tTd(37, 2))
- printf("settimeout(%s = %s)\n", name, val);
-
- to = convtime(val, 'm');
- p = strchr(name, '.');
- if (p != NULL)
- *p++ = '\0';
-
- if (strcasecmp(name, "initial") == 0)
- TimeOuts.to_initial = to;
- else if (strcasecmp(name, "mail") == 0)
- TimeOuts.to_mail = to;
- else if (strcasecmp(name, "rcpt") == 0)
- TimeOuts.to_rcpt = to;
- else if (strcasecmp(name, "datainit") == 0)
- TimeOuts.to_datainit = to;
- else if (strcasecmp(name, "datablock") == 0)
- TimeOuts.to_datablock = to;
- else if (strcasecmp(name, "datafinal") == 0)
- TimeOuts.to_datafinal = to;
- else if (strcasecmp(name, "command") == 0)
- TimeOuts.to_nextcommand = to;
- else if (strcasecmp(name, "rset") == 0)
- TimeOuts.to_rset = to;
- else if (strcasecmp(name, "helo") == 0)
- TimeOuts.to_helo = to;
- else if (strcasecmp(name, "quit") == 0)
- TimeOuts.to_quit = to;
- else if (strcasecmp(name, "misc") == 0)
- TimeOuts.to_miscshort = to;
- else if (strcasecmp(name, "ident") == 0)
- TimeOuts.to_ident = to;
- else if (strcasecmp(name, "fileopen") == 0)
- TimeOuts.to_fileopen = to;
- else if (strcasecmp(name, "connect") == 0)
- TimeOuts.to_connect = to;
- else if (strcasecmp(name, "iconnect") == 0)
- TimeOuts.to_iconnect = to;
- else if (strcasecmp(name, "queuewarn") == 0)
- {
- to = convtime(val, 'h');
- if (p == NULL || strcmp(p, "*") == 0)
- {
- TimeOuts.to_q_warning[TOC_NORMAL] = to;
- TimeOuts.to_q_warning[TOC_URGENT] = to;
- TimeOuts.to_q_warning[TOC_NONURGENT] = to;
- }
- else if (strcasecmp(p, "normal") == 0)
- TimeOuts.to_q_warning[TOC_NORMAL] = to;
- else if (strcasecmp(p, "urgent") == 0)
- TimeOuts.to_q_warning[TOC_URGENT] = to;
- else if (strcasecmp(p, "non-urgent") == 0)
- TimeOuts.to_q_warning[TOC_NONURGENT] = to;
- else
- syserr("settimeout: invalid queuewarn subtimeout %s", p);
- }
- else if (strcasecmp(name, "queuereturn") == 0)
- {
- to = convtime(val, 'd');
- if (p == NULL || strcmp(p, "*") == 0)
- {
- TimeOuts.to_q_return[TOC_NORMAL] = to;
- TimeOuts.to_q_return[TOC_URGENT] = to;
- TimeOuts.to_q_return[TOC_NONURGENT] = to;
- }
- else if (strcasecmp(p, "normal") == 0)
- TimeOuts.to_q_return[TOC_NORMAL] = to;
- else if (strcasecmp(p, "urgent") == 0)
- TimeOuts.to_q_return[TOC_URGENT] = to;
- else if (strcasecmp(p, "non-urgent") == 0)
- TimeOuts.to_q_return[TOC_NONURGENT] = to;
- else
- syserr("settimeout: invalid queuereturn subtimeout %s", p);
- }
- else if (strcasecmp(name, "hoststatus") == 0)
- MciInfoTimeout = convtime(val, 'm');
- else
- syserr("settimeout: invalid timeout %s", name);
-}
diff --git a/src/recipient.c b/src/recipient.c
deleted file mode 100644
index f7e221f..0000000
--- a/src/recipient.c
+++ /dev/null
@@ -1,1456 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)recipient.c 8.163 (Berkeley) 1/23/1999";
-#endif /* not lint */
-
-# include "sendmail.h"
-# include <grp.h>
-
-/*
-** SENDTOLIST -- Designate a send list.
-**
-** The parameter is a comma-separated list of people to send to.
-** This routine arranges to send to all of them.
-**
-** Parameters:
-** list -- the send list.
-** ctladdr -- the address template for the person to
-** send to -- effective uid/gid are important.
-** This is typically the alias that caused this
-** expansion.
-** sendq -- a pointer to the head of a queue to put
-** these people into.
-** aliaslevel -- the current alias nesting depth -- to
-** diagnose loops.
-** e -- the envelope in which to add these recipients.
-**
-** Returns:
-** The number of addresses actually on the list.
-**
-** Side Effects:
-** none.
-*/
-
-/* q_flags bits inherited from ctladdr */
-#define QINHERITEDBITS (QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY|QHASNOTIFY)
-
-int
-sendtolist(list, ctladdr, sendq, aliaslevel, e)
- char *list;
- ADDRESS *ctladdr;
- ADDRESS **sendq;
- int aliaslevel;
- register ENVELOPE *e;
-{
- register char *p;
- register ADDRESS *al; /* list of addresses to send to */
- char delimiter; /* the address delimiter */
- int naddrs;
- int i;
- char *oldto = e->e_to;
- char *bufp;
- char buf[MAXNAME + 1];
-
- if (list == NULL)
- {
- syserr("sendtolist: null list");
- return 0;
- }
-
- if (tTd(25, 1))
- {
- printf("sendto: %s\n ctladdr=", list);
- printaddr(ctladdr, FALSE);
- }
-
- /* heuristic to determine old versus new style addresses */
- if (ctladdr == NULL &&
- (strchr(list, ',') != NULL || strchr(list, ';') != NULL ||
- strchr(list, '<') != NULL || strchr(list, '(') != NULL))
- e->e_flags &= ~EF_OLDSTYLE;
- delimiter = ' ';
- if (!bitset(EF_OLDSTYLE, e->e_flags) || ctladdr != NULL)
- delimiter = ',';
-
- al = NULL;
- naddrs = 0;
-
- /* make sure we have enough space to copy the string */
- i = strlen(list) + 1;
- if (i <= sizeof buf)
- bufp = buf;
- else
- bufp = xalloc(i);
- strcpy(bufp, denlstring(list, FALSE, TRUE));
-
- for (p = bufp; *p != '\0'; )
- {
- auto char *delimptr;
- register ADDRESS *a;
-
- /* parse the address */
- while ((isascii(*p) && isspace(*p)) || *p == ',')
- p++;
- a = parseaddr(p, NULLADDR, RF_COPYALL, delimiter, &delimptr, e);
- p = delimptr;
- if (a == NULL)
- continue;
- a->q_next = al;
- a->q_alias = ctladdr;
-
- /* arrange to inherit attributes from parent */
- if (ctladdr != NULL)
- {
- ADDRESS *b;
- extern ADDRESS *self_reference __P((ADDRESS *, ENVELOPE *));
-
- /* self reference test */
- if (sameaddr(ctladdr, a))
- {
- if (tTd(27, 5))
- {
- printf("sendtolist: QSELFREF ");
- printaddr(ctladdr, FALSE);
- }
- ctladdr->q_flags |= QSELFREF;
- }
-
- /* check for address loops */
- b = self_reference(a, e);
- if (b != NULL)
- {
- b->q_flags |= QSELFREF;
- if (tTd(27, 5))
- {
- printf("sendtolist: QSELFREF ");
- printaddr(b, FALSE);
- }
- if (a != b)
- {
- if (tTd(27, 5))
- {
- printf("sendtolist: QDONTSEND ");
- printaddr(a, FALSE);
- }
- a->q_flags |= QDONTSEND;
- b->q_flags |= a->q_flags & QNOTREMOTE;
- continue;
- }
- }
-
- /* full name */
- if (a->q_fullname == NULL)
- a->q_fullname = ctladdr->q_fullname;
-
- /* various flag bits */
- a->q_flags &= ~QINHERITEDBITS;
- a->q_flags |= ctladdr->q_flags & QINHERITEDBITS;
-
- /* original recipient information */
- a->q_orcpt = ctladdr->q_orcpt;
- }
-
- al = a;
- }
-
- /* arrange to send to everyone on the local send list */
- while (al != NULL)
- {
- register ADDRESS *a = al;
-
- al = a->q_next;
- a = recipient(a, sendq, aliaslevel, e);
- naddrs++;
- }
-
- e->e_to = oldto;
- if (bufp != buf)
- free(bufp);
- return (naddrs);
-}
- /*
-** RECIPIENT -- Designate a message recipient
-**
-** Saves the named person for future mailing.
-**
-** Parameters:
-** a -- the (preparsed) address header for the recipient.
-** sendq -- a pointer to the head of a queue to put the
-** recipient in. Duplicate supression is done
-** in this queue.
-** aliaslevel -- the current alias nesting depth.
-** e -- the current envelope.
-**
-** Returns:
-** The actual address in the queue. This will be "a" if
-** the address is not a duplicate, else the original address.
-**
-** Side Effects:
-** none.
-*/
-
-ADDRESS *
-recipient(a, sendq, aliaslevel, e)
- register ADDRESS *a;
- register ADDRESS **sendq;
- int aliaslevel;
- register ENVELOPE *e;
-{
- register ADDRESS *q;
- ADDRESS **pq;
- register struct mailer *m;
- register char *p;
- bool quoted = FALSE; /* set if the addr has a quote bit */
- int findusercount = 0;
- bool initialdontsend = bitset(QDONTSEND, a->q_flags);
- int i;
- char *buf;
- char buf0[MAXNAME + 1]; /* unquoted image of the user name */
- extern void alias __P((ADDRESS *, ADDRESS **, int, ENVELOPE *));
-
- e->e_to = a->q_paddr;
- m = a->q_mailer;
- errno = 0;
- if (aliaslevel == 0)
- a->q_flags |= QPRIMARY;
- if (tTd(26, 1))
- {
- printf("\nrecipient (%d): ", aliaslevel);
- printaddr(a, FALSE);
- }
-
- /* if this is primary, add it to the original recipient list */
- if (a->q_alias == NULL)
- {
- if (e->e_origrcpt == NULL)
- e->e_origrcpt = a->q_paddr;
- else if (e->e_origrcpt != a->q_paddr)
- e->e_origrcpt = "";
- }
-
- /* break aliasing loops */
- if (aliaslevel > MaxAliasRecursion)
- {
- a->q_flags |= QBADADDR;
- a->q_status = "5.4.6";
- usrerr("554 aliasing/forwarding loop broken (%d aliases deep; %d max)",
- aliaslevel, MaxAliasRecursion);
- return (a);
- }
-
- /*
- ** Finish setting up address structure.
- */
-
- /* get unquoted user for file, program or user.name check */
- i = strlen(a->q_user);
- if (i >= sizeof buf0)
- buf = xalloc(i + 1);
- else
- buf = buf0;
- (void) strcpy(buf, a->q_user);
- for (p = buf; *p != '\0' && !quoted; p++)
- {
- if (*p == '\\')
- quoted = TRUE;
- }
- stripquotes(buf);
-
- /* check for direct mailing to restricted mailers */
- if (m == ProgMailer)
- {
- if (a->q_alias == NULL)
- {
- a->q_flags |= QBADADDR;
- a->q_status = "5.7.1";
- usrerr("550 Cannot mail directly to programs");
- }
- else if (bitset(QBOGUSSHELL, a->q_alias->q_flags))
- {
- a->q_flags |= QBADADDR;
- a->q_status = "5.7.1";
- if (a->q_alias->q_ruser == NULL)
- usrerr("550 UID %d is an unknown user: cannot mail to programs",
- a->q_alias->q_uid);
- else
- usrerr("550 User %s@%s doesn't have a valid shell for mailing to programs",
- a->q_alias->q_ruser, MyHostName);
- }
- else if (bitset(QUNSAFEADDR, a->q_alias->q_flags))
- {
- a->q_flags |= QBADADDR;
- a->q_status = "5.7.1";
- a->q_rstatus = newstr("Unsafe for mailing to programs");
- usrerr("550 Address %s is unsafe for mailing to programs",
- a->q_alias->q_paddr);
- }
- }
-
- /*
- ** Look up this person in the recipient list.
- ** If they are there already, return, otherwise continue.
- ** If the list is empty, just add it. Notice the cute
- ** hack to make from addresses suppress things correctly:
- ** the QDONTSEND bit will be set in the send list.
- ** [Please note: the emphasis is on "hack."]
- */
-
- for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next)
- {
- if (sameaddr(q, a) &&
- (bitset(QRCPTOK, q->q_flags) ||
- !bitset(QPRIMARY, q->q_flags)))
- {
- if (tTd(26, 1))
- {
- printf("%s in sendq: ", a->q_paddr);
- printaddr(q, FALSE);
- }
- if (!bitset(QPRIMARY, q->q_flags))
- {
- if (!bitset(QDONTSEND, a->q_flags))
- message("duplicate suppressed");
- q->q_flags |= a->q_flags;
- }
- else if (bitset(QSELFREF, q->q_flags))
- q->q_flags |= a->q_flags & ~QDONTSEND;
- a = q;
- goto done;
- }
- }
-
- /* add address on list */
- if (pq != NULL)
- {
- *pq = a;
- a->q_next = NULL;
- }
-
- /*
- ** Alias the name and handle special mailer types.
- */
-
- trylocaluser:
- if (tTd(29, 7))
- {
- printf("at trylocaluser: ");
- printaddr(a, FALSE);
- }
-
- if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags))
- goto testselfdestruct;
-
- if (m == InclMailer)
- {
- a->q_flags |= QDONTSEND;
- if (a->q_alias == NULL)
- {
- a->q_flags |= QBADADDR;
- a->q_status = "5.7.1";
- usrerr("550 Cannot mail directly to :include:s");
- }
- else
- {
- int ret;
-
- message("including file %s", a->q_user);
- ret = include(a->q_user, FALSE, a, sendq, aliaslevel, e);
- if (transienterror(ret))
- {
- if (LogLevel > 2)
- sm_syslog(LOG_ERR, e->e_id,
- "include %s: transient error: %s",
- shortenstring(a->q_user, MAXSHORTSTR),
- errstring(ret));
- a->q_flags |= QQUEUEUP;
- a->q_flags &= ~QDONTSEND;
- usrerr("451 Cannot open %s: %s",
- shortenstring(a->q_user, MAXSHORTSTR),
- errstring(ret));
- }
- else if (ret != 0)
- {
- a->q_flags |= QBADADDR;
- a->q_status = "5.2.4";
- usrerr("550 Cannot open %s: %s",
- shortenstring(a->q_user, MAXSHORTSTR),
- errstring(ret));
- }
- }
- }
- else if (m == FileMailer)
- {
- extern bool writable __P((char *, ADDRESS *, int));
-
- /* check if writable or creatable */
- if (a->q_alias == NULL)
- {
- a->q_flags |= QBADADDR;
- a->q_status = "5.7.1";
- usrerr("550 Cannot mail directly to files");
- }
- else if (bitset(QBOGUSSHELL, a->q_alias->q_flags))
- {
- a->q_flags |= QBADADDR;
- a->q_status = "5.7.1";
- if (a->q_alias->q_ruser == NULL)
- usrerr("550 UID %d is an unknown user: cannot mail to files",
- a->q_alias->q_uid);
- else
- usrerr("550 User %s@%s doesn't have a valid shell for mailing to files",
- a->q_alias->q_ruser, MyHostName);
- }
- else if (bitset(QUNSAFEADDR, a->q_alias->q_flags))
- {
- a->q_flags |= QBADADDR;
- a->q_status = "5.7.1";
- a->q_rstatus = newstr("Unsafe for mailing to files");
- usrerr("550 Address %s is unsafe for mailing to files",
- a->q_alias->q_paddr);
- }
- else if (strcmp(buf, "/dev/null") == 0)
- {
- /* /dev/null is always accepted */
- }
- else if (!writable(buf, a->q_alias, SFF_CREAT))
- {
- a->q_flags |= QBADADDR;
- giveresponse(EX_CANTCREAT, m, NULL, a->q_alias,
- (time_t) 0, e);
- }
- }
-
- /* try aliasing */
- if (!quoted && !bitset(QDONTSEND, a->q_flags) &&
- bitnset(M_ALIASABLE, m->m_flags))
- alias(a, sendq, aliaslevel, e);
-
-# if USERDB
- /* if not aliased, look it up in the user database */
- if (!bitset(QDONTSEND|QNOTREMOTE|QVERIFIED, a->q_flags) &&
- bitnset(M_CHECKUDB, m->m_flags))
- {
- extern int udbexpand __P((ADDRESS *, ADDRESS **, int, ENVELOPE *));
-
- if (udbexpand(a, sendq, aliaslevel, e) == EX_TEMPFAIL)
- {
- a->q_flags |= QQUEUEUP;
- if (e->e_message == NULL)
- e->e_message = newstr("Deferred: user database error");
- if (LogLevel > 8)
- sm_syslog(LOG_INFO, e->e_id,
- "deferred: udbexpand: %s",
- errstring(errno));
- message("queued (user database error): %s",
- errstring(errno));
- e->e_nrcpts++;
- goto testselfdestruct;
- }
- }
-# endif
-
- /*
- ** If we have a level two config file, then pass the name through
- ** Ruleset 5 before sending it off. Ruleset 5 has the right
- ** to send rewrite it to another mailer. This gives us a hook
- ** after local aliasing has been done.
- */
-
- if (tTd(29, 5))
- {
- printf("recipient: testing local? cl=%d, rr5=%lx\n\t",
- ConfigLevel, (u_long) RewriteRules[5]);
- printaddr(a, FALSE);
- }
- if (!bitset(QNOTREMOTE|QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) &&
- ConfigLevel >= 2 && RewriteRules[5] != NULL &&
- bitnset(M_TRYRULESET5, m->m_flags))
- {
- extern void maplocaluser __P((ADDRESS *, ADDRESS **, int, ENVELOPE *));
-
- maplocaluser(a, sendq, aliaslevel + 1, e);
- }
-
- /*
- ** If it didn't get rewritten to another mailer, go ahead
- ** and deliver it.
- */
-
- if (!bitset(QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) &&
- bitnset(M_HASPWENT, m->m_flags))
- {
- auto bool fuzzy;
- register struct passwd *pw;
- extern void forward __P((ADDRESS *, ADDRESS **, int, ENVELOPE *));
-
- /* warning -- finduser may trash buf */
- pw = finduser(buf, &fuzzy);
- if (pw == NULL || strlen(pw->pw_name) > MAXNAME)
- {
- a->q_flags |= QBADADDR;
- a->q_status = "5.1.1";
- giveresponse(EX_NOUSER, m, NULL, a->q_alias,
- (time_t) 0, e);
- }
- else
- {
- char nbuf[MAXNAME + 1];
-
- if (fuzzy)
- {
- /* name was a fuzzy match */
- a->q_user = newstr(pw->pw_name);
- if (findusercount++ > 3)
- {
- a->q_flags |= QBADADDR;
- a->q_status = "5.4.6";
- usrerr("554 aliasing/forwarding loop for %s broken",
- pw->pw_name);
- goto done;
- }
-
- /* see if it aliases */
- (void) strcpy(buf, pw->pw_name);
- goto trylocaluser;
- }
- if (strcmp(pw->pw_dir, "/") == 0)
- a->q_home = "";
- else
- a->q_home = newstr(pw->pw_dir);
- a->q_uid = pw->pw_uid;
- a->q_gid = pw->pw_gid;
- a->q_ruser = newstr(pw->pw_name);
- a->q_flags |= QGOODUID;
- buildfname(pw->pw_gecos, pw->pw_name, nbuf, sizeof nbuf);
- if (nbuf[0] != '\0')
- a->q_fullname = newstr(nbuf);
- if (!usershellok(pw->pw_name, pw->pw_shell))
- {
- a->q_flags |= QBOGUSSHELL;
- }
- if (bitset(EF_VRFYONLY, e->e_flags))
- {
- /* don't do any more now */
- a->q_flags |= QVERIFIED;
- }
- else if (!quoted)
- forward(a, sendq, aliaslevel, e);
- }
- }
- if (!bitset(QDONTSEND, a->q_flags))
- e->e_nrcpts++;
-
- testselfdestruct:
- a->q_flags |= QTHISPASS;
- if (tTd(26, 8))
- {
- printf("testselfdestruct: ");
- printaddr(a, FALSE);
- if (tTd(26, 10))
- {
- printf("SENDQ:\n");
- printaddr(*sendq, TRUE);
- printf("----\n");
- }
- }
- if (a->q_alias == NULL && a != &e->e_from &&
- bitset(QDONTSEND, a->q_flags))
- {
- for (q = *sendq; q != NULL; q = q->q_next)
- {
- if (!bitset(QDONTSEND, q->q_flags))
- break;
- }
- if (q == NULL)
- {
- a->q_flags |= QBADADDR;
- a->q_status = "5.4.6";
- usrerr("554 aliasing/forwarding loop broken");
- }
- }
-
- done:
- a->q_flags |= QTHISPASS;
- if (buf != buf0)
- free(buf);
-
- /*
- ** If we are at the top level, check to see if this has
- ** expanded to exactly one address. If so, it can inherit
- ** the primaryness of the address.
- **
- ** While we're at it, clear the QTHISPASS bits.
- */
-
- if (aliaslevel == 0)
- {
- int nrcpts = 0;
- ADDRESS *only = NULL;
-
- for (q = *sendq; q != NULL; q = q->q_next)
- {
- if (bitset(QTHISPASS, q->q_flags) &&
- !bitset(QDONTSEND|QBADADDR, q->q_flags))
- {
- nrcpts++;
- only = q;
- }
- q->q_flags &= ~QTHISPASS;
- }
- if (nrcpts == 1)
- {
- /* check to see if this actually got a new owner */
- q = only;
- while ((q = q->q_alias) != NULL)
- {
- if (q->q_owner != NULL)
- break;
- }
- if (q == NULL)
- only->q_flags |= QPRIMARY;
- }
- else if (!initialdontsend && nrcpts > 0)
- {
- /* arrange for return receipt */
- e->e_flags |= EF_SENDRECEIPT;
- a->q_flags |= QEXPANDED;
- if (e->e_xfp != NULL && bitset(QPINGONSUCCESS, a->q_flags))
- fprintf(e->e_xfp,
- "%s... expanded to multiple addresses\n",
- a->q_paddr);
- }
- }
- a->q_flags |= QRCPTOK;
- return (a);
-}
- /*
-** FINDUSER -- find the password entry for a user.
-**
-** This looks a lot like getpwnam, except that it may want to
-** do some fancier pattern matching in /etc/passwd.
-**
-** This routine contains most of the time of many sendmail runs.
-** It deserves to be optimized.
-**
-** Parameters:
-** name -- the name to match against.
-** fuzzyp -- an outarg that is set to TRUE if this entry
-** was found using the fuzzy matching algorithm;
-** set to FALSE otherwise.
-**
-** Returns:
-** A pointer to a pw struct.
-** NULL if name is unknown or ambiguous.
-**
-** Side Effects:
-** may modify name.
-*/
-
-struct passwd *
-finduser(name, fuzzyp)
- char *name;
- bool *fuzzyp;
-{
- register struct passwd *pw;
- register char *p;
- bool tryagain;
-
- if (tTd(29, 4))
- printf("finduser(%s): ", name);
-
- *fuzzyp = FALSE;
-
-#ifdef HESIOD
- /* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */
- for (p = name; *p != '\0'; p++)
- if (!isascii(*p) || !isdigit(*p))
- break;
- if (*p == '\0')
- {
- if (tTd(29, 4))
- printf("failed (numeric input)\n");
- return NULL;
- }
-#endif
-
- /* look up this login name using fast path */
- if ((pw = sm_getpwnam(name)) != NULL)
- {
- if (tTd(29, 4))
- printf("found (non-fuzzy)\n");
- return (pw);
- }
-
- /* try mapping it to lower case */
- tryagain = FALSE;
- for (p = name; *p != '\0'; p++)
- {
- if (isascii(*p) && isupper(*p))
- {
- *p = tolower(*p);
- tryagain = TRUE;
- }
- }
- if (tryagain && (pw = sm_getpwnam(name)) != NULL)
- {
- if (tTd(29, 4))
- printf("found (lower case)\n");
- *fuzzyp = TRUE;
- return pw;
- }
-
-#if MATCHGECOS
- /* see if fuzzy matching allowed */
- if (!MatchGecos)
- {
- if (tTd(29, 4))
- printf("not found (fuzzy disabled)\n");
- return NULL;
- }
-
- /* search for a matching full name instead */
- for (p = name; *p != '\0'; p++)
- {
- if (*p == (SpaceSub & 0177) || *p == '_')
- *p = ' ';
- }
- (void) setpwent();
- while ((pw = getpwent()) != NULL)
- {
- char buf[MAXNAME + 1];
-
-# if 0
- if (strcasecmp(pw->pw_name, name) == 0)
- {
- if (tTd(29, 4))
- printf("found (case wrapped)\n");
- break;
- }
-# endif
-
- buildfname(pw->pw_gecos, pw->pw_name, buf, sizeof buf);
- if (strchr(buf, ' ') != NULL && !strcasecmp(buf, name))
- {
- if (tTd(29, 4))
- printf("fuzzy matches %s\n", pw->pw_name);
- message("sending to login name %s", pw->pw_name);
- break;
- }
- }
- if (pw != NULL)
- *fuzzyp = TRUE;
- else if (tTd(29, 4))
- printf("no fuzzy match found\n");
-# if DEC_OSF_BROKEN_GETPWENT /* DEC OSF/1 3.2 or earlier */
- endpwent();
-# endif
- return pw;
-#else
- if (tTd(29, 4))
- printf("not found (fuzzy disabled)\n");
- return NULL;
-#endif
-}
- /*
-** WRITABLE -- predicate returning if the file is writable.
-**
-** This routine must duplicate the algorithm in sys/fio.c.
-** Unfortunately, we cannot use the access call since we
-** won't necessarily be the real uid when we try to
-** actually open the file.
-**
-** Notice that ANY file with ANY execute bit is automatically
-** not writable. This is also enforced by mailfile.
-**
-** Parameters:
-** filename -- the file name to check.
-** ctladdr -- the controlling address for this file.
-** flags -- SFF_* flags to control the function.
-**
-** Returns:
-** TRUE -- if we will be able to write this file.
-** FALSE -- if we cannot write this file.
-**
-** Side Effects:
-** none.
-*/
-
-bool
-writable(filename, ctladdr, flags)
- char *filename;
- ADDRESS *ctladdr;
- int flags;
-{
- uid_t euid;
- gid_t egid;
- char *uname;
-
- if (tTd(44, 5))
- printf("writable(%s, 0x%x)\n", filename, flags);
-
- /*
- ** File does exist -- check that it is writable.
- */
-
- if (geteuid() != 0)
- {
- euid = geteuid();
- egid = getegid();
- uname = NULL;
- }
- else if (ctladdr != NULL)
- {
- euid = ctladdr->q_uid;
- egid = ctladdr->q_gid;
- uname = ctladdr->q_user;
- }
- else if (bitset(SFF_RUNASREALUID, flags))
- {
- euid = RealUid;
- egid = RealGid;
- uname = RealUserName;
- }
- else if (FileMailer != NULL && !bitset(SFF_ROOTOK, flags))
- {
- euid = FileMailer->m_uid;
- egid = FileMailer->m_gid;
- uname = NULL;
- }
- else
- {
- euid = egid = 0;
- uname = NULL;
- }
- if (!bitset(SFF_ROOTOK, flags))
- {
- if (euid == 0)
- {
- euid = DefUid;
- uname = DefUser;
- }
- if (egid == 0)
- egid = DefGid;
- }
- if (geteuid() == 0 &&
- (ctladdr == NULL || !bitset(QGOODUID, ctladdr->q_flags)))
- flags |= SFF_SETUIDOK;
-
- if (!bitset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail))
- flags |= SFF_NOSLINK;
- if (!bitset(DBS_FILEDELIVERYTOHARDLINK, DontBlameSendmail))
- flags |= SFF_NOHLINK;
-
- errno = safefile(filename, euid, egid, uname, flags, S_IWRITE, NULL);
- return errno == 0;
-}
- /*
-** INCLUDE -- handle :include: specification.
-**
-** Parameters:
-** fname -- filename to include.
-** forwarding -- if TRUE, we are reading a .forward file.
-** if FALSE, it's a :include: file.
-** ctladdr -- address template to use to fill in these
-** addresses -- effective user/group id are
-** the important things.
-** sendq -- a pointer to the head of the send queue
-** to put these addresses in.
-** aliaslevel -- the alias nesting depth.
-** e -- the current envelope.
-**
-** Returns:
-** open error status
-**
-** Side Effects:
-** reads the :include: file and sends to everyone
-** listed in that file.
-**
-** Security Note:
-** If you have restricted chown (that is, you can't
-** give a file away), it is reasonable to allow programs
-** and files called from this :include: file to be to be
-** run as the owner of the :include: file. This is bogus
-** if there is any chance of someone giving away a file.
-** We assume that pre-POSIX systems can give away files.
-**
-** There is an additional restriction that if you
-** forward to a :include: file, it will not take on
-** the ownership of the :include: file. This may not
-** be necessary, but shouldn't hurt.
-*/
-
-static jmp_buf CtxIncludeTimeout;
-static void includetimeout __P((void));
-
-int
-include(fname, forwarding, ctladdr, sendq, aliaslevel, e)
- char *fname;
- bool forwarding;
- ADDRESS *ctladdr;
- ADDRESS **sendq;
- int aliaslevel;
- ENVELOPE *e;
-{
- FILE *volatile fp = NULL;
- char *oldto = e->e_to;
- char *oldfilename = FileName;
- int oldlinenumber = LineNumber;
- register EVENT *ev = NULL;
- int nincludes;
- int mode;
- register ADDRESS *ca;
- volatile uid_t saveduid, uid;
- volatile gid_t savedgid, gid;
- char *volatile uname;
- int rval = 0;
- volatile int sfflags = SFF_REGONLY;
- register char *p;
- bool safechown = FALSE;
- volatile bool safedir = FALSE;
- struct stat st;
- char buf[MAXLINE];
- extern bool chownsafe __P((int, bool));
-
- if (tTd(27, 2))
- printf("include(%s)\n", fname);
- if (tTd(27, 4))
- printf(" ruid=%d euid=%d\n", (int) getuid(), (int) geteuid());
- if (tTd(27, 14))
- {
- printf("ctladdr ");
- printaddr(ctladdr, FALSE);
- }
-
- if (tTd(27, 9))
- printf("include: old uid = %d/%d\n",
- (int) getuid(), (int) geteuid());
-
- if (forwarding)
- sfflags |= SFF_MUSTOWN|SFF_ROOTOK|SFF_NOWLINK;
-
- ca = getctladdr(ctladdr);
- if (ca == NULL)
- {
- uid = DefUid;
- gid = DefGid;
- uname = DefUser;
- }
- else
- {
- uid = ca->q_uid;
- gid = ca->q_gid;
- uname = ca->q_user;
- }
-#if HASSETREUID || USESETEUID
- saveduid = geteuid();
- savedgid = getegid();
- if (saveduid == 0)
- {
- if (!DontInitGroups)
- {
- if (initgroups(uname, gid) == -1)
- syserr("include: initgroups(%s, %d) failed",
- uname, gid);
- }
- else
- {
- GIDSET_T gidset[1];
-
- gidset[0] = gid;
- if (setgroups(1, gidset) == -1)
- syserr("include: setgroups() failed");
- }
-
- if (gid != 0 && setgid(gid) < -1)
- syserr("setgid(%d) failure", gid);
- if (uid != 0)
- {
-# if USESETEUID
- if (seteuid(uid) < 0)
- syserr("seteuid(%d) failure (real=%d, eff=%d)",
- uid, getuid(), geteuid());
-# else
- if (setreuid(0, uid) < 0)
- syserr("setreuid(0, %d) failure (real=%d, eff=%d)",
- uid, getuid(), geteuid());
-# endif
- }
- }
-#endif
-
- if (tTd(27, 9))
- printf("include: new uid = %d/%d\n",
- (int) getuid(), (int) geteuid());
-
- /*
- ** If home directory is remote mounted but server is down,
- ** this can hang or give errors; use a timeout to avoid this
- */
-
- if (setjmp(CtxIncludeTimeout) != 0)
- {
- ctladdr->q_flags |= QQUEUEUP;
- errno = 0;
-
- /* return pseudo-error code */
- rval = E_SM_OPENTIMEOUT;
- goto resetuid;
- }
- if (TimeOuts.to_fileopen > 0)
- ev = setevent(TimeOuts.to_fileopen, includetimeout, 0);
- else
- ev = NULL;
-
- /* check for writable parent directory */
- p = strrchr(fname, '/');
- if (p != NULL)
- {
- int ret;
-
- *p = '\0';
- ret = safedirpath(fname, uid, gid, uname, sfflags|SFF_SAFEDIRPATH);
- if (ret == 0)
- {
- /* in safe directory: relax chown & link rules */
- safedir = TRUE;
- sfflags |= SFF_NOPATHCHECK;
- }
- else
- {
- if (bitset((forwarding ?
- DBS_FORWARDFILEINUNSAFEDIRPATH :
- DBS_INCLUDEFILEINUNSAFEDIRPATH),
- DontBlameSendmail))
- sfflags |= SFF_NOPATHCHECK;
- else if (bitset((forwarding ?
- DBS_FORWARDFILEINGROUPWRITABLEDIRPATH :
- DBS_INCLUDEFILEINGROUPWRITABLEDIRPATH),
- DontBlameSendmail) &&
- ret == E_SM_GWDIR)
- {
- DontBlameSendmail |= DBS_GROUPWRITABLEDIRPATHSAFE;
- ret = safedirpath(fname, uid,
- gid, uname,
- sfflags|SFF_SAFEDIRPATH);
- DontBlameSendmail &= ~DBS_GROUPWRITABLEDIRPATHSAFE;
- if (ret == 0)
- sfflags |= SFF_NOPATHCHECK;
- else
- sfflags |= SFF_SAFEDIRPATH;
- }
- else
- sfflags |= SFF_SAFEDIRPATH;
- if (ret > E_PSEUDOBASE &&
- !bitset((forwarding ?
- DBS_FORWARDFILEINUNSAFEDIRPATHSAFE :
- DBS_INCLUDEFILEINUNSAFEDIRPATHSAFE),
- DontBlameSendmail))
- {
- if (LogLevel >= 12)
- sm_syslog(LOG_INFO, e->e_id,
- "%s: unsafe directory path, marked unsafe",
- shortenstring(fname, MAXSHORTSTR));
- ctladdr->q_flags |= QUNSAFEADDR;
- }
- }
- *p = '/';
- }
-
- /* allow links only in unwritable directories */
- if (!safedir &&
- !bitset((forwarding ?
- DBS_LINKEDFORWARDFILEINWRITABLEDIR :
- DBS_LINKEDINCLUDEFILEINWRITABLEDIR),
- DontBlameSendmail))
- sfflags |= SFF_NOLINK;
-
- rval = safefile(fname, uid, gid, uname, sfflags, S_IREAD, &st);
- if (rval != 0)
- {
- /* don't use this :include: file */
- if (tTd(27, 4))
- printf("include: not safe (uid=%d): %s\n",
- (int) uid, errstring(rval));
- }
- else if ((fp = fopen(fname, "r")) == NULL)
- {
- rval = errno;
- if (tTd(27, 4))
- printf("include: open: %s\n", errstring(rval));
- }
- else if (filechanged(fname, fileno(fp), &st))
- {
- rval = E_SM_FILECHANGE;
- if (tTd(27, 4))
- printf("include: file changed after open\n");
- }
- if (ev != NULL)
- clrevent(ev);
-
-resetuid:
-
-#if HASSETREUID || USESETEUID
- if (saveduid == 0)
- {
- if (uid != 0)
- {
-# if USESETEUID
- if (seteuid(0) < 0)
- syserr("seteuid(0) failure (real=%d, eff=%d)",
- getuid(), geteuid());
-# else
- if (setreuid(-1, 0) < 0)
- syserr("setreuid(-1, 0) failure (real=%d, eff=%d)",
- getuid(), geteuid());
- if (setreuid(RealUid, 0) < 0)
- syserr("setreuid(%d, 0) failure (real=%d, eff=%d)",
- RealUid, getuid(), geteuid());
-# endif
- }
- setgid(savedgid);
- }
-#endif
-
- if (tTd(27, 9))
- printf("include: reset uid = %d/%d\n",
- (int) getuid(), (int) geteuid());
-
- if (rval == E_SM_OPENTIMEOUT)
- usrerr("451 open timeout on %s", fname);
-
- if (fp == NULL)
- return rval;
-
- if (fstat(fileno(fp), &st) < 0)
- {
- rval = errno;
- syserr("Cannot fstat %s!", fname);
- return rval;
- }
-
- /* if path was writable, check to avoid file giveaway tricks */
- safechown = chownsafe(fileno(fp), safedir);
- if (tTd(27, 6))
- printf("include: parent of %s is %s, chown is %ssafe\n",
- fname,
- safedir ? "safe" : "dangerous",
- safechown ? "" : "un");
-
- if (ca == NULL && safechown)
- {
- ctladdr->q_uid = st.st_uid;
- ctladdr->q_gid = st.st_gid;
- ctladdr->q_flags |= QGOODUID;
- }
- if (ca != NULL && ca->q_uid == st.st_uid)
- {
- /* optimization -- avoid getpwuid if we already have info */
- ctladdr->q_flags |= ca->q_flags & QBOGUSSHELL;
- ctladdr->q_ruser = ca->q_ruser;
- }
- else if (!forwarding)
- {
- register struct passwd *pw;
-
- pw = sm_getpwuid(st.st_uid);
- if (pw == NULL)
- ctladdr->q_flags |= QBOGUSSHELL;
- else
- {
- char *sh;
-
- ctladdr->q_ruser = newstr(pw->pw_name);
- if (safechown)
- sh = pw->pw_shell;
- else
- sh = "/SENDMAIL/ANY/SHELL/";
- if (!usershellok(pw->pw_name, sh))
- {
- if (LogLevel >= 12)
- sm_syslog(LOG_INFO, e->e_id,
- "%s: user %s has bad shell %s, marked %s",
- shortenstring(fname, MAXSHORTSTR),
- pw->pw_name, sh,
- safechown ? "bogus" : "unsafe");
- if (safechown)
- ctladdr->q_flags |= QBOGUSSHELL;
- else
- ctladdr->q_flags |= QUNSAFEADDR;
- }
- }
- }
-
- if (bitset(EF_VRFYONLY, e->e_flags))
- {
- /* don't do any more now */
- ctladdr->q_flags |= QVERIFIED;
- ctladdr->q_flags &= ~QDONTSEND;
- e->e_nrcpts++;
- xfclose(fp, "include", fname);
- return rval;
- }
-
- /*
- ** Check to see if some bad guy can write this file
- **
- ** Group write checking could be more clever, e.g.,
- ** guessing as to which groups are actually safe ("sys"
- ** may be; "user" probably is not).
- */
-
- mode = S_IWOTH;
- if (!bitset((forwarding ?
- DBS_GROUPWRITABLEFORWARDFILESAFE :
- DBS_GROUPWRITABLEINCLUDEFILESAFE),
- DontBlameSendmail))
- mode |= S_IWGRP;
-
- if (bitset(mode, st.st_mode))
- {
- if (tTd(27, 6))
- printf("include: %s is %s writable, marked unsafe\n",
- shortenstring(fname, MAXSHORTSTR),
- bitset(S_IWOTH, st.st_mode) ? "world" : "group");
- if (LogLevel >= 12)
- sm_syslog(LOG_INFO, e->e_id,
- "%s: %s writable %s file, marked unsafe",
- shortenstring(fname, MAXSHORTSTR),
- bitset(S_IWOTH, st.st_mode) ? "world" : "group",
- forwarding ? "forward" : ":include:");
- ctladdr->q_flags |= QUNSAFEADDR;
- }
-
- /* read the file -- each line is a comma-separated list. */
- FileName = fname;
- LineNumber = 0;
- ctladdr->q_flags &= ~QSELFREF;
- nincludes = 0;
- while (fgets(buf, sizeof buf, fp) != NULL)
- {
- register char *p = strchr(buf, '\n');
-
- LineNumber++;
- if (p != NULL)
- *p = '\0';
- if (buf[0] == '#' || buf[0] == '\0')
- continue;
-
- /* <sp>#@# introduces a comment anywhere */
- /* for Japanese character sets */
- for (p = buf; (p = strchr(++p, '#')) != NULL; )
- {
- if (p[1] == '@' && p[2] == '#' &&
- isascii(p[-1]) && isspace(p[-1]) &&
- (p[3] == '\0' || (isascii(p[3]) && isspace(p[3]))))
- {
- p[-1] = '\0';
- break;
- }
- }
- if (buf[0] == '\0')
- continue;
-
- e->e_to = NULL;
- message("%s to %s",
- forwarding ? "forwarding" : "sending", buf);
- if (forwarding && LogLevel > 9)
- sm_syslog(LOG_INFO, e->e_id,
- "forward %.200s => %s",
- oldto, shortenstring(buf, MAXSHORTSTR));
-
- nincludes += sendtolist(buf, ctladdr, sendq, aliaslevel + 1, e);
- }
-
- if (ferror(fp) && tTd(27, 3))
- printf("include: read error: %s\n", errstring(errno));
- if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags))
- {
- if (tTd(27, 5))
- {
- printf("include: QDONTSEND ");
- printaddr(ctladdr, FALSE);
- }
- ctladdr->q_flags |= QDONTSEND;
- }
-
- (void) xfclose(fp, "include", fname);
- FileName = oldfilename;
- LineNumber = oldlinenumber;
- e->e_to = oldto;
- return rval;
-}
-
-static void
-includetimeout()
-{
- longjmp(CtxIncludeTimeout, 1);
-}
- /*
-** SENDTOARGV -- send to an argument vector.
-**
-** Parameters:
-** argv -- argument vector to send to.
-** e -- the current envelope.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** puts all addresses on the argument vector onto the
-** send queue.
-*/
-
-void
-sendtoargv(argv, e)
- register char **argv;
- register ENVELOPE *e;
-{
- register char *p;
-
- while ((p = *argv++) != NULL)
- {
- (void) sendtolist(p, NULLADDR, &e->e_sendqueue, 0, e);
- }
-}
- /*
-** GETCTLADDR -- get controlling address from an address header.
-**
-** If none, get one corresponding to the effective userid.
-**
-** Parameters:
-** a -- the address to find the controller of.
-**
-** Returns:
-** the controlling address.
-**
-** Side Effects:
-** none.
-*/
-
-ADDRESS *
-getctladdr(a)
- register ADDRESS *a;
-{
- while (a != NULL && !bitset(QGOODUID, a->q_flags))
- a = a->q_alias;
- return (a);
-}
- /*
-** SELF_REFERENCE -- check to see if an address references itself
-**
-** The check is done through a chain of aliases. If it is part of
-** a loop, break the loop at the "best" address, that is, the one
-** that exists as a real user.
-**
-** This is to handle the case of:
-** awc: Andrew.Chang
-** Andrew.Chang: awc@mail.server
-** which is a problem only on mail.server.
-**
-** Parameters:
-** a -- the address to check.
-** e -- the current envelope.
-**
-** Returns:
-** The address that should be retained.
-*/
-
-ADDRESS *
-self_reference(a, e)
- ADDRESS *a;
- ENVELOPE *e;
-{
- ADDRESS *b; /* top entry in self ref loop */
- ADDRESS *c; /* entry that point to a real mail box */
-
- if (tTd(27, 1))
- printf("self_reference(%s)\n", a->q_paddr);
-
- for (b = a->q_alias; b != NULL; b = b->q_alias)
- {
- if (sameaddr(a, b))
- break;
- }
-
- if (b == NULL)
- {
- if (tTd(27, 1))
- printf("\t... no self ref\n");
- return NULL;
- }
-
- /*
- ** Pick the first address that resolved to a real mail box
- ** i.e has a pw entry. The returned value will be marked
- ** QSELFREF in recipient(), which in turn will disable alias()
- ** from marking it QDONTSEND, which mean it will be used
- ** as a deliverable address.
- **
- ** The 2 key thing to note here are:
- ** 1) we are in a recursive call sequence:
- ** alias->sentolist->recipient->alias
- ** 2) normally, when we return back to alias(), the address
- ** will be marked QDONTSEND, since alias() assumes the
- ** expanded form will be used instead of the current address.
- ** This behaviour is turned off if the address is marked
- ** QSELFREF We set QSELFREF when we return to recipient().
- */
-
- c = a;
- while (c != NULL)
- {
- if (tTd(27, 10))
- printf(" %s", c->q_user);
- if (bitnset(M_HASPWENT, c->q_mailer->m_flags))
- {
- if (tTd(27, 2))
- printf("\t... getpwnam(%s)... ", c->q_user);
- if (sm_getpwnam(c->q_user) != NULL)
- {
- if (tTd(27, 2))
- printf("found\n");
-
- /* ought to cache results here */
- if (sameaddr(b, c))
- return b;
- else
- return c;
- }
- if (tTd(27, 2))
- printf("failed\n");
- }
- else
- {
- /* if local delivery, compare usernames */
- if (bitnset(M_LOCALMAILER, c->q_mailer->m_flags) &&
- b->q_mailer == c->q_mailer)
- {
- if (tTd(27, 2))
- printf("\t... local match (%s)\n", c->q_user);
- if (sameaddr(b, c))
- return b;
- else
- return c;
- }
- }
- if (tTd(27, 10))
- printf("\n");
- c = c->q_alias;
- }
-
- if (tTd(27, 1))
- printf("\t... cannot break loop for \"%s\"\n", a->q_paddr);
-
- return NULL;
-}
diff --git a/src/safefile.c b/src/safefile.c
deleted file mode 100644
index ff94b3d..0000000
--- a/src/safefile.c
+++ /dev/null
@@ -1,751 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)safefile.c 8.43 (Berkeley) 10/13/1998";
-#endif /* not lint */
-
-# include "sendmail.h"
- /*
-** SAFEFILE -- return true if a file exists and is safe for a user.
-**
-** Parameters:
-** fn -- filename to check.
-** uid -- user id to compare against.
-** gid -- group id to compare against.
-** uname -- user name to compare against (used for group
-** sets).
-** flags -- modifiers:
-** SFF_MUSTOWN -- "uid" must own this file.
-** SFF_NOSLINK -- file cannot be a symbolic link.
-** mode -- mode bits that must match.
-** st -- if set, points to a stat structure that will
-** get the stat info for the file.
-**
-** Returns:
-** 0 if fn exists, is owned by uid, and matches mode.
-** An errno otherwise. The actual errno is cleared.
-**
-** Side Effects:
-** none.
-*/
-
-#include <grp.h>
-
-int
-safefile(fn, uid, gid, uname, flags, mode, st)
- char *fn;
- UID_T uid;
- GID_T gid;
- char *uname;
- int flags;
- int mode;
- struct stat *st;
-{
- register char *p;
- register struct group *gr = NULL;
- int file_errno = 0;
- bool checkpath;
- struct stat stbuf;
- struct stat fstbuf;
- char fbuf[MAXPATHLEN + 1];
-
- if (tTd(44, 4))
- printf("safefile(%s, uid=%d, gid=%d, flags=%x, mode=%o):\n",
- fn, (int) uid, (int) gid, flags, mode);
- errno = 0;
- if (st == NULL)
- st = &fstbuf;
- if (strlen(fn) > sizeof fbuf - 1)
- {
- if (tTd(44, 4))
- printf("\tpathname too long\n");
- return ENAMETOOLONG;
- }
- strcpy(fbuf, fn);
- fn = fbuf;
-
- /* ignore SFF_SAFEDIRPATH if we are debugging */
- if (RealUid != 0 && RunAsUid == RealUid)
- flags &= ~SFF_SAFEDIRPATH;
-
- /* first check to see if the file exists at all */
-#ifdef HASLSTAT
- if ((bitset(SFF_NOSLINK, flags) ? lstat(fn, st)
- : stat(fn, st)) < 0)
-#else
- if (stat(fn, st) < 0)
-#endif
- {
- file_errno = errno;
- }
- else if (bitset(SFF_SETUIDOK, flags) &&
- !bitset(S_IXUSR|S_IXGRP|S_IXOTH, st->st_mode) &&
- S_ISREG(st->st_mode))
- {
- /*
- ** If final file is setuid, run as the owner of that
- ** file. Gotta be careful not to reveal anything too
- ** soon here!
- */
-
-#ifdef SUID_ROOT_FILES_OK
- if (bitset(S_ISUID, st->st_mode))
-#else
- if (bitset(S_ISUID, st->st_mode) && st->st_uid != 0 &&
- st->st_uid != TrustedUid)
-#endif
- {
- uid = st->st_uid;
- uname = NULL;
- }
-#ifdef SUID_ROOT_FILES_OK
- if (bitset(S_ISGID, st->st_mode))
-#else
- if (bitset(S_ISGID, st->st_mode) && st->st_gid != 0)
-#endif
- gid = st->st_gid;
- }
-
- checkpath = !bitset(SFF_NOPATHCHECK, flags) ||
- (uid == 0 && !bitset(SFF_ROOTOK|SFF_OPENASROOT, flags));
- if (bitset(SFF_NOWLINK, flags) && !bitset(SFF_SAFEDIRPATH, flags))
- {
- int ret;
-
- /* check the directory */
- p = strrchr(fn, '/');
- if (p == NULL)
- {
- ret = safedirpath(".", uid, gid, uname, flags|SFF_SAFEDIRPATH);
- }
- else
- {
- *p = '\0';
- ret = safedirpath(fn, uid, gid, uname, flags|SFF_SAFEDIRPATH);
- *p = '/';
- }
- if (ret == 0)
- {
- /* directory is safe */
- checkpath = FALSE;
- }
- else
- {
-#ifdef HASLSTAT
- /* Need lstat() information if called stat() before */
- if (!bitset(SFF_NOSLINK, flags) && lstat(fn, st) < 0)
- {
- ret = errno;
- if (tTd(44, 4))
- printf("\t%s\n", errstring(ret));
- return ret;
- }
-#endif
- /* directory is writable: disallow links */
- flags |= SFF_NOLINK;
- }
- }
-
- if (checkpath)
- {
- int ret;
-
- p = strrchr(fn, '/');
- if (p == NULL)
- {
- ret = safedirpath(".", uid, gid, uname, flags);
- }
- else
- {
- *p = '\0';
- ret = safedirpath(fn, uid, gid, uname, flags);
- *p = '/';
- }
- if (ret != 0)
- return ret;
- }
-
- /*
- ** If the target file doesn't exist, check the directory to
- ** ensure that it is writable by this user.
- */
-
- if (file_errno != 0)
- {
- int ret = file_errno;
- char *dir = fn;
-
- if (tTd(44, 4))
- printf("\t%s\n", errstring(ret));
-
- errno = 0;
- if (!bitset(SFF_CREAT, flags) || file_errno != ENOENT)
- return ret;
-
- /* check to see if legal to create the file */
- p = strrchr(dir, '/');
- if (p == NULL)
- dir = ".";
- else if (p == dir)
- dir = "/";
- else
- *p = '\0';
- if (stat(dir, &stbuf) >= 0)
- {
- int md = S_IWRITE|S_IEXEC;
-
- if (stbuf.st_uid == uid)
- ;
- else if (uid == 0 && stbuf.st_uid == TrustedUid)
- ;
- else
- {
- md >>= 3;
- if (stbuf.st_gid == gid)
- ;
-#ifndef NO_GROUP_SET
- else if (uname != NULL && !DontInitGroups &&
- ((gr != NULL &&
- gr->gr_gid == stbuf.st_gid) ||
- (gr = getgrgid(stbuf.st_gid)) != NULL))
- {
- register char **gp;
-
- for (gp = gr->gr_mem; *gp != NULL; gp++)
- if (strcmp(*gp, uname) == 0)
- break;
- if (*gp == NULL)
- md >>= 3;
- }
-#endif
- else
- md >>= 3;
- }
- if ((stbuf.st_mode & md) != md)
- errno = EACCES;
- }
- ret = errno;
- if (tTd(44, 4))
- printf("\t[final dir %s uid %d mode %lo] %s\n",
- dir, (int) stbuf.st_uid, (u_long) stbuf.st_mode,
- errstring(ret));
- if (p != NULL)
- *p = '/';
- st->st_mode = ST_MODE_NOFILE;
- return ret;
- }
-
-#ifdef S_ISLNK
- if (bitset(SFF_NOSLINK, flags) && S_ISLNK(st->st_mode))
- {
- if (tTd(44, 4))
- printf("\t[slink mode %lo]\tE_SM_NOSLINK\n",
- (u_long) st->st_mode);
- return E_SM_NOSLINK;
- }
-#endif
- if (bitset(SFF_REGONLY, flags) && !S_ISREG(st->st_mode))
- {
- if (tTd(44, 4))
- printf("\t[non-reg mode %lo]\tE_SM_REGONLY\n",
- (u_long) st->st_mode);
- return E_SM_REGONLY;
- }
- if (bitset(SFF_NOGWFILES, flags) &&
- bitset(S_IWGRP, st->st_mode))
- {
- if (tTd(44, 4))
- printf("\t[write bits %lo]\tE_SM_GWFILE\n",
- (u_long) st->st_mode);
- return E_SM_GWFILE;
- }
- if (bitset(SFF_NOWWFILES, flags) &&
- bitset(S_IWOTH, st->st_mode))
- {
- if (tTd(44, 4))
- printf("\t[write bits %lo]\tE_SM_WWFILE\n",
- (u_long) st->st_mode);
- return E_SM_WWFILE;
- }
- if (bitset(S_IWUSR|S_IWGRP|S_IWOTH, mode) &&
- bitset(S_IXUSR|S_IXGRP|S_IXOTH, st->st_mode))
- {
- if (tTd(44, 4))
- printf("\t[exec bits %lo]\tE_SM_ISEXEC]\n",
- (u_long) st->st_mode);
- return E_SM_ISEXEC;
- }
- if (bitset(SFF_NOHLINK, flags) && st->st_nlink != 1)
- {
- if (tTd(44, 4))
- printf("\t[link count %d]\tE_SM_NOHLINK\n",
- (int) st->st_nlink);
- return E_SM_NOHLINK;
- }
-
- if (uid == 0 && bitset(SFF_OPENASROOT, flags))
- ;
- else if (uid == 0 && !bitset(SFF_ROOTOK, flags))
- mode >>= 6;
- else if (st->st_uid == uid)
- ;
- else if (uid == 0 && st->st_uid == TrustedUid)
- ;
- else
- {
- mode >>= 3;
- if (st->st_gid == gid)
- ;
-#ifndef NO_GROUP_SET
- else if (uname != NULL && !DontInitGroups &&
- ((gr != NULL && gr->gr_gid == st->st_gid) ||
- (gr = getgrgid(st->st_gid)) != NULL))
- {
- register char **gp;
-
- for (gp = gr->gr_mem; *gp != NULL; gp++)
- if (strcmp(*gp, uname) == 0)
- break;
- if (*gp == NULL)
- mode >>= 3;
- }
-#endif
- else
- mode >>= 3;
- }
- if (tTd(44, 4))
- printf("\t[uid %d, nlink %d, stat %lo, mode %lo] ",
- (int) st->st_uid, (int) st->st_nlink,
- (u_long) st->st_mode, (u_long) mode);
- if ((st->st_uid == uid || st->st_uid == 0 ||
- st->st_uid == TrustedUid ||
- !bitset(SFF_MUSTOWN, flags)) &&
- (st->st_mode & mode) == mode)
- {
- if (tTd(44, 4))
- printf("\tOK\n");
- return 0;
- }
- if (tTd(44, 4))
- printf("\tEACCES\n");
- return EACCES;
-}
- /*
-** SAFEDIRPATH -- check to make sure a path to a directory is safe
-**
-** Safe means not writable and owned by the right folks.
-**
-** Parameters:
-** fn -- filename to check.
-** uid -- user id to compare against.
-** gid -- group id to compare against.
-** uname -- user name to compare against (used for group
-** sets).
-** flags -- modifiers:
-** SFF_ROOTOK -- ok to use root permissions to open.
-** SFF_SAFEDIRPATH -- writable directories are considered
-** to be fatal errors.
-**
-** Returns:
-** 0 -- if the directory path is "safe".
-** else -- an error number associated with the path.
-*/
-
-int
-safedirpath(fn, uid, gid, uname, flags)
- char *fn;
- UID_T uid;
- GID_T gid;
- char *uname;
- int flags;
-{
- char *p;
- register struct group *gr = NULL;
- int ret = 0;
- int mode = S_IWOTH;
- struct stat stbuf;
-
- /* special case root directory */
- if (*fn == '\0')
- fn = "/";
-
- if (tTd(44, 4))
- printf("safedirpath(%s, uid=%ld, gid=%ld, flags=%x):\n",
- fn, (long) uid, (long) gid, flags);
-
- if (!bitset(DBS_GROUPWRITABLEDIRPATHSAFE, DontBlameSendmail))
- mode |= S_IWGRP;
-
- p = fn;
- do
- {
- if (*p == '\0')
- *p = '/';
- p = strchr(++p, '/');
- if (p != NULL)
- *p = '\0';
- if (stat(fn, &stbuf) < 0)
- {
- ret = errno;
- break;
- }
- if ((uid == 0 || bitset(SFF_SAFEDIRPATH, flags)) &&
- bitset(mode, stbuf.st_mode))
- {
- if (tTd(44, 4))
- printf("\t[dir %s] mode %lo\n",
- fn, (u_long) stbuf.st_mode);
- if (bitset(SFF_SAFEDIRPATH, flags))
- {
- if (bitset(S_IWOTH, stbuf.st_mode))
- ret = E_SM_WWDIR;
- else
- ret = E_SM_GWDIR;
- break;
- }
- if (Verbose > 1)
- message("051 WARNING: %s writable directory %s",
- bitset(S_IWOTH, stbuf.st_mode)
- ? "World"
- : "Group",
- fn);
- }
- if (uid == 0 && !bitset(SFF_ROOTOK|SFF_OPENASROOT, flags))
- {
- if (bitset(S_IXOTH, stbuf.st_mode))
- continue;
- ret = EACCES;
- break;
- }
-
- /*
- ** Let OS determine access to file if we are not
- ** running as a privileged user. This allows ACLs
- ** to work.
- */
- if (geteuid() != 0)
- continue;
-
- if (stbuf.st_uid == uid &&
- bitset(S_IXUSR, stbuf.st_mode))
- continue;
- if (stbuf.st_gid == gid &&
- bitset(S_IXGRP, stbuf.st_mode))
- continue;
-#ifndef NO_GROUP_SET
- if (uname != NULL && !DontInitGroups &&
- ((gr != NULL && gr->gr_gid == stbuf.st_gid) ||
- (gr = getgrgid(stbuf.st_gid)) != NULL))
- {
- register char **gp;
-
- for (gp = gr->gr_mem; gp != NULL && *gp != NULL; gp++)
- if (strcmp(*gp, uname) == 0)
- break;
- if (gp != NULL && *gp != NULL &&
- bitset(S_IXGRP, stbuf.st_mode))
- continue;
- }
-#endif
- if (!bitset(S_IXOTH, stbuf.st_mode))
- {
- ret = EACCES;
- break;
- }
- } while (p != NULL);
- if (ret != 0 && tTd(44, 4))
- printf("\t[dir %s] %s\n", fn, errstring(ret));
- if (p != NULL)
- *p = '/';
- return ret;
-}
- /*
-** SAFEOPEN -- do a file open with extra checking
-**
-** Parameters:
-** fn -- the file name to open.
-** omode -- the open-style mode flags.
-** cmode -- the create-style mode flags.
-** sff -- safefile flags.
-**
-** Returns:
-** Same as open.
-*/
-
-#ifndef O_ACCMODE
-# define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR)
-#endif
-
-int
-safeopen(fn, omode, cmode, sff)
- char *fn;
- int omode;
- int cmode;
- int sff;
-{
- int rval;
- int fd;
- int smode;
- struct stat stb;
-
- if (bitset(O_CREAT, omode))
- sff |= SFF_CREAT;
- omode &= ~O_CREAT;
- smode = 0;
- switch (omode & O_ACCMODE)
- {
- case O_RDONLY:
- smode = S_IREAD;
- break;
-
- case O_WRONLY:
- smode = S_IWRITE;
- break;
-
- case O_RDWR:
- smode = S_IREAD|S_IWRITE;
- break;
-
- default:
- smode = 0;
- break;
- }
- if (bitset(SFF_OPENASROOT, sff))
- rval = safefile(fn, RunAsUid, RunAsGid, RunAsUserName,
- sff, smode, &stb);
- else
- rval = safefile(fn, RealUid, RealGid, RealUserName,
- sff, smode, &stb);
- if (rval != 0)
- {
- errno = rval;
- return -1;
- }
- if (stb.st_mode == ST_MODE_NOFILE && bitset(SFF_CREAT, sff))
- omode |= O_EXCL|O_CREAT;
-
- fd = dfopen(fn, omode, cmode, sff);
- if (fd < 0)
- return fd;
- if (filechanged(fn, fd, &stb))
- {
- syserr("554 cannot open: file %s changed after open", fn);
- close(fd);
- errno = E_SM_FILECHANGE;
- return -1;
- }
- return fd;
-}
- /*
-** SAFEFOPEN -- do a file open with extra checking
-**
-** Parameters:
-** fn -- the file name to open.
-** omode -- the open-style mode flags.
-** cmode -- the create-style mode flags.
-** sff -- safefile flags.
-**
-** Returns:
-** Same as fopen.
-*/
-
-FILE *
-safefopen(fn, omode, cmode, sff)
- char *fn;
- int omode;
- int cmode;
- int sff;
-{
- int fd;
- FILE *fp;
- char *fmode;
-
- switch (omode & O_ACCMODE)
- {
- case O_RDONLY:
- fmode = "r";
- break;
-
- case O_WRONLY:
- if (bitset(O_APPEND, omode))
- fmode = "a";
- else
- fmode = "w";
- break;
-
- case O_RDWR:
- if (bitset(O_TRUNC, omode))
- fmode = "w+";
- else if (bitset(O_APPEND, omode))
- fmode = "a+";
- else
- fmode = "r+";
- break;
-
- default:
- syserr("safefopen: unknown omode %o", omode);
- fmode = "x";
- }
- fd = safeopen(fn, omode, cmode, sff);
- if (fd < 0)
- {
- if (tTd(44, 10))
- printf("safefopen: safeopen failed: %s\n",
- errstring(errno));
- return NULL;
- }
- fp = fdopen(fd, fmode);
- if (fp != NULL)
- return fp;
-
- if (tTd(44, 10))
- {
- printf("safefopen: fdopen(%s, %s) failed: omode=%x, sff=%x, err=%s\n",
- fn, fmode, omode, sff, errstring(errno));
-#ifndef NOT_SENDMAIL
- dumpfd(fd, TRUE, FALSE);
-#endif
- }
- (void) close(fd);
- return NULL;
-}
- /*
-** FILECHANGED -- check to see if file changed after being opened
-**
-** Parameters:
-** fn -- pathname of file to check.
-** fd -- file descriptor to check.
-** stb -- stat structure from before open.
-**
-** Returns:
-** TRUE -- if a problem was detected.
-** FALSE -- if this file is still the same.
-*/
-
-bool
-filechanged(fn, fd, stb)
- char *fn;
- int fd;
- struct stat *stb;
-{
- struct stat sta;
-
- if (stb->st_mode == ST_MODE_NOFILE)
- {
-#if HASLSTAT && BOGUS_O_EXCL
- /* only necessary if exclusive open follows symbolic links */
- if (lstat(fn, stb) < 0 || stb->st_nlink != 1)
- return TRUE;
-#else
- return FALSE;
-#endif
- }
- if (fstat(fd, &sta) < 0)
- return TRUE;
-
- if (sta.st_nlink != stb->st_nlink ||
- sta.st_dev != stb->st_dev ||
- sta.st_ino != stb->st_ino ||
-#if HAS_ST_GEN && 0 /* AFS returns garbage in st_gen */
- sta.st_gen != stb->st_gen ||
-#endif
- sta.st_uid != stb->st_uid ||
- sta.st_gid != stb->st_gid)
- {
- if (tTd(44, 8))
- {
- printf("File changed after opening:\n");
- printf(" nlink = %ld/%ld\n",
- (long) stb->st_nlink, (long) sta.st_nlink);
- printf(" dev = %ld/%ld\n",
- (long) stb->st_dev, (long) sta.st_dev);
- if (sizeof sta.st_ino > sizeof (long))
- {
- printf(" ino = %s/",
- quad_to_string(stb->st_ino));
- printf("%s\n",
- quad_to_string(sta.st_ino));
- }
- else
- printf(" ino = %lu/%lu\n",
- (unsigned long) stb->st_ino,
- (unsigned long) sta.st_ino);
-#if HAS_ST_GEN
- printf(" gen = %ld/%ld\n",
- (long) stb->st_gen, (long) sta.st_gen);
-#endif
- printf(" uid = %ld/%ld\n",
- (long) stb->st_uid, (long) sta.st_uid);
- printf(" gid = %ld/%ld\n",
- (long) stb->st_gid, (long) sta.st_gid);
- }
- return TRUE;
- }
-
- return FALSE;
-}
- /*
-** DFOPEN -- determined file open
-**
-** This routine has the semantics of open, except that it will
-** keep trying a few times to make this happen. The idea is that
-** on very loaded systems, we may run out of resources (inodes,
-** whatever), so this tries to get around it.
-*/
-
-int
-dfopen(filename, omode, cmode, sff)
- char *filename;
- int omode;
- int cmode;
- int sff;
-{
- register int tries;
- int fd;
- struct stat st;
-
- for (tries = 0; tries < 10; tries++)
- {
- sleep((unsigned) (10 * tries));
- errno = 0;
- fd = open(filename, omode, cmode);
- if (fd >= 0)
- break;
- switch (errno)
- {
- case ENFILE: /* system file table full */
- case EINTR: /* interrupted syscall */
-#ifdef ETXTBSY
- case ETXTBSY: /* Apollo: net file locked */
-#endif
- continue;
- }
- break;
- }
- if (!bitset(SFF_NOLOCK, sff) &&
- fd >= 0 &&
- fstat(fd, &st) >= 0 &&
- S_ISREG(st.st_mode))
- {
- int locktype;
-
- /* lock the file to avoid accidental conflicts */
- if ((omode & O_ACCMODE) != O_RDONLY)
- locktype = LOCK_EX;
- else
- locktype = LOCK_SH;
- (void) lockfile(fd, filename, NULL, locktype);
- errno = 0;
- }
- return fd;
-}
diff --git a/src/savemail.c b/src/savemail.c
deleted file mode 100644
index 6a18ee6..0000000
--- a/src/savemail.c
+++ /dev/null
@@ -1,1486 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)savemail.c 8.140 (Berkeley) 1/18/1999";
-#endif /* not lint */
-
-# include "sendmail.h"
-
-/*
-** SAVEMAIL -- Save mail on error
-**
-** If mailing back errors, mail it back to the originator
-** together with an error message; otherwise, just put it in
-** dead.letter in the user's home directory (if he exists on
-** this machine).
-**
-** Parameters:
-** e -- the envelope containing the message in error.
-** sendbody -- if TRUE, also send back the body of the
-** message; otherwise just send the header.
-**
-** Returns:
-** none
-**
-** Side Effects:
-** Saves the letter, by writing or mailing it back to the
-** sender, or by putting it in dead.letter in her home
-** directory.
-*/
-
-/* defines for state machine */
-# define ESM_REPORT 0 /* report to sender's terminal */
-# define ESM_MAIL 1 /* mail back to sender */
-# define ESM_QUIET 2 /* messages have already been returned */
-# define ESM_DEADLETTER 3 /* save in ~/dead.letter */
-# define ESM_POSTMASTER 4 /* return to postmaster */
-# define ESM_USRTMP 5 /* save in /usr/tmp/dead.letter */
-# define ESM_PANIC 6 /* leave the locked queue/transcript files */
-# define ESM_DONE 7 /* the message is successfully delivered */
-
-
-void
-savemail(e, sendbody)
- register ENVELOPE *e;
- bool sendbody;
-{
- register struct passwd *pw;
- register FILE *fp;
- int state;
- auto ADDRESS *q = NULL;
- register char *p;
- MCI mcibuf;
- int flags;
- char buf[MAXLINE+1];
- extern char *ttypath __P((void));
- extern bool writable __P((char *, ADDRESS *, int));
-
- if (tTd(6, 1))
- {
- printf("\nsavemail, errormode = %c, id = %s, ExitStat = %d\n e_from=",
- e->e_errormode, e->e_id == NULL ? "NONE" : e->e_id,
- ExitStat);
- printaddr(&e->e_from, FALSE);
- }
-
- if (e->e_id == NULL)
- {
- /* can't return a message with no id */
- return;
- }
-
- /*
- ** In the unhappy event we don't know who to return the mail
- ** to, make someone up.
- */
-
- if (e->e_from.q_paddr == NULL)
- {
- e->e_sender = "Postmaster";
- if (parseaddr(e->e_sender, &e->e_from,
- RF_COPYPARSE|RF_SENDERADDR, '\0', NULL, e) == NULL)
- {
- syserr("553 Cannot parse Postmaster!");
- finis(TRUE, EX_SOFTWARE);
- }
- }
- e->e_to = NULL;
-
- /*
- ** Basic state machine.
- **
- ** This machine runs through the following states:
- **
- ** ESM_QUIET Errors have already been printed iff the
- ** sender is local.
- ** ESM_REPORT Report directly to the sender's terminal.
- ** ESM_MAIL Mail response to the sender.
- ** ESM_DEADLETTER Save response in ~/dead.letter.
- ** ESM_POSTMASTER Mail response to the postmaster.
- ** ESM_PANIC Save response anywhere possible.
- */
-
- /* determine starting state */
- switch (e->e_errormode)
- {
- case EM_WRITE:
- state = ESM_REPORT;
- break;
-
- case EM_BERKNET:
- case EM_MAIL:
- state = ESM_MAIL;
- break;
-
- case EM_PRINT:
- case '\0':
- state = ESM_QUIET;
- break;
-
- case EM_QUIET:
- /* no need to return anything at all */
- return;
-
- default:
- syserr("554 savemail: bogus errormode x%x\n", e->e_errormode);
- state = ESM_MAIL;
- break;
- }
-
- /* if this is already an error response, send to postmaster */
- if (bitset(EF_RESPONSE, e->e_flags))
- {
- if (e->e_parent != NULL &&
- bitset(EF_RESPONSE, e->e_parent->e_flags))
- {
- /* got an error sending a response -- can it */
- return;
- }
- state = ESM_POSTMASTER;
- }
-
- while (state != ESM_DONE)
- {
- if (tTd(6, 5))
- printf(" state %d\n", state);
-
- switch (state)
- {
- case ESM_QUIET:
- if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags))
- state = ESM_DEADLETTER;
- else
- state = ESM_MAIL;
- break;
-
- case ESM_REPORT:
-
- /*
- ** If the user is still logged in on the same terminal,
- ** then write the error messages back to hir (sic).
- */
-
- p = ttypath();
- if (p == NULL || freopen(p, "w", stdout) == NULL)
- {
- state = ESM_MAIL;
- break;
- }
-
- expand("\201n", buf, sizeof buf, e);
- printf("\r\nMessage from %s...\r\n", buf);
- printf("Errors occurred while sending mail.\r\n");
- if (e->e_xfp != NULL)
- {
- (void) fflush(e->e_xfp);
- fp = fopen(queuename(e, 'x'), "r");
- }
- else
- fp = NULL;
- if (fp == NULL)
- {
- syserr("Cannot open %s", queuename(e, 'x'));
- printf("Transcript of session is unavailable.\r\n");
- }
- else
- {
- printf("Transcript follows:\r\n");
- while (fgets(buf, sizeof buf, fp) != NULL &&
- !ferror(stdout))
- fputs(buf, stdout);
- (void) xfclose(fp, "savemail transcript", e->e_id);
- }
- printf("Original message will be saved in dead.letter.\r\n");
- state = ESM_DEADLETTER;
- break;
-
- case ESM_MAIL:
- /*
- ** If mailing back, do it.
- ** Throw away all further output. Don't alias,
- ** since this could cause loops, e.g., if joe
- ** mails to joe@x, and for some reason the network
- ** for @x is down, then the response gets sent to
- ** joe@x, which gives a response, etc. Also force
- ** the mail to be delivered even if a version of
- ** it has already been sent to the sender.
- **
- ** If this is a configuration or local software
- ** error, send to the local postmaster as well,
- ** since the originator can't do anything
- ** about it anyway. Note that this is a full
- ** copy of the message (intentionally) so that
- ** the Postmaster can forward things along.
- */
-
- if (ExitStat == EX_CONFIG || ExitStat == EX_SOFTWARE)
- {
- (void) sendtolist("postmaster",
- NULLADDR, &e->e_errorqueue, 0, e);
- }
- if (!emptyaddr(&e->e_from))
- {
- char from[TOBUFSIZE];
- extern bool pruneroute __P((char *));
-
- if (strlen(e->e_from.q_paddr) + 1 > sizeof from)
- {
- state = ESM_POSTMASTER;
- break;
- }
- strcpy(from, e->e_from.q_paddr);
-
- if (!DontPruneRoutes && pruneroute(from))
- {
- ADDRESS *a;
-
- for (a = e->e_errorqueue; a != NULL;
- a = a->q_next)
- {
- if (sameaddr(a, &e->e_from))
- a->q_flags |= QDONTSEND;
- }
- }
- (void) sendtolist(from, NULLADDR,
- &e->e_errorqueue, 0, e);
- }
-
- /*
- ** Deliver a non-delivery report to the
- ** Postmaster-designate (not necessarily
- ** Postmaster). This does not include the
- ** body of the message, for privacy reasons.
- ** You really shouldn't need this.
- */
-
- e->e_flags |= EF_PM_NOTIFY;
-
- /* check to see if there are any good addresses */
- for (q = e->e_errorqueue; q != NULL; q = q->q_next)
- if (!bitset(QBADADDR|QDONTSEND, q->q_flags))
- break;
- if (q == NULL)
- {
- /* this is an error-error */
- state = ESM_POSTMASTER;
- break;
- }
- if (returntosender(e->e_message, e->e_errorqueue,
- sendbody ? RTSF_SEND_BODY
- : RTSF_NO_BODY,
- e) == 0)
- {
- state = ESM_DONE;
- break;
- }
-
- /* didn't work -- return to postmaster */
- state = ESM_POSTMASTER;
- break;
-
- case ESM_POSTMASTER:
- /*
- ** Similar to previous case, but to system postmaster.
- */
-
- q = NULL;
- if (sendtolist(DoubleBounceAddr,
- NULLADDR, &q, 0, e) <= 0)
- {
- syserr("553 cannot parse %s!", DoubleBounceAddr);
- ExitStat = EX_SOFTWARE;
- state = ESM_USRTMP;
- break;
- }
- flags = RTSF_PM_BOUNCE;
- if (sendbody)
- flags |= RTSF_SEND_BODY;
- if (returntosender(e->e_message, q, flags, e) == 0)
- {
- state = ESM_DONE;
- break;
- }
-
- /* didn't work -- last resort */
- state = ESM_USRTMP;
- break;
-
- case ESM_DEADLETTER:
- /*
- ** Save the message in dead.letter.
- ** If we weren't mailing back, and the user is
- ** local, we should save the message in
- ** ~/dead.letter so that the poor person doesn't
- ** have to type it over again -- and we all know
- ** what poor typists UNIX users are.
- */
-
- p = NULL;
- if (bitnset(M_HASPWENT, e->e_from.q_mailer->m_flags))
- {
- if (e->e_from.q_home != NULL)
- p = e->e_from.q_home;
- else if ((pw = sm_getpwnam(e->e_from.q_user)) != NULL)
- p = pw->pw_dir;
- }
- if (p == NULL || e->e_dfp == NULL)
- {
- /* no local directory or no data file */
- state = ESM_MAIL;
- break;
- }
-
- /* we have a home directory; write dead.letter */
- define('z', p, e);
- expand("\201z/dead.letter", buf, sizeof buf, e);
- flags = SFF_CREAT|SFF_REGONLY|SFF_RUNASREALUID;
- if (RealUid == 0)
- flags |= SFF_ROOTOK;
- e->e_to = buf;
- if (mailfile(buf, FileMailer, NULL, flags, e) == EX_OK)
- {
- int oldverb = Verbose;
-
- Verbose = 1;
- message("Saved message in %s", buf);
- Verbose = oldverb;
- state = ESM_DONE;
- break;
- }
- state = ESM_MAIL;
- break;
-
- case ESM_USRTMP:
- /*
- ** Log the mail in /usr/tmp/dead.letter.
- */
-
- if (e->e_class < 0)
- {
- state = ESM_DONE;
- break;
- }
-
- if ((SafeFileEnv != NULL && SafeFileEnv[0] != '\0') ||
- DeadLetterDrop == NULL || DeadLetterDrop[0] == '\0')
- {
- state = ESM_PANIC;
- break;
- }
-
- flags = SFF_CREAT|SFF_REGONLY|SFF_ROOTOK|SFF_OPENASROOT|SFF_MUSTOWN;
- if (!writable(DeadLetterDrop, NULL, flags) ||
- (fp = safefopen(DeadLetterDrop, O_WRONLY|O_APPEND,
- FileMode, flags)) == NULL)
- {
- state = ESM_PANIC;
- break;
- }
-
- bzero(&mcibuf, sizeof mcibuf);
- mcibuf.mci_out = fp;
- mcibuf.mci_mailer = FileMailer;
- if (bitnset(M_7BITS, FileMailer->m_flags))
- mcibuf.mci_flags |= MCIF_7BIT;
- mcibuf.mci_contentlen = 0;
-
- putfromline(&mcibuf, e);
- (*e->e_puthdr)(&mcibuf, e->e_header, e, M87F_OUTER);
- (*e->e_putbody)(&mcibuf, e, NULL);
- putline("\n", &mcibuf);
- (void) fflush(fp);
- if (ferror(fp))
- state = ESM_PANIC;
- else
- {
- int oldverb = Verbose;
-
- Verbose = 1;
- message("Saved message in %s", DeadLetterDrop);
- Verbose = oldverb;
- if (LogLevel > 3)
- sm_syslog(LOG_NOTICE, e->e_id,
- "Saved message in %s",
- DeadLetterDrop);
- state = ESM_DONE;
- }
- (void) xfclose(fp, "savemail", DeadLetterDrop);
- break;
-
- default:
- syserr("554 savemail: unknown state %d", state);
-
- /* fall through ... */
-
- case ESM_PANIC:
- /* leave the locked queue & transcript files around */
- loseqfile(e, "savemail panic");
- syserr("!554 savemail: cannot save rejected email anywhere");
- }
- }
-}
- /*
-** RETURNTOSENDER -- return a message to the sender with an error.
-**
-** Parameters:
-** msg -- the explanatory message.
-** returnq -- the queue of people to send the message to.
-** flags -- flags tweaking the operation:
-** RTSF_SENDBODY -- include body of message (otherwise
-** just send the header).
-** RTSF_PMBOUNCE -- this is a postmaster bounce.
-** e -- the current envelope.
-**
-** Returns:
-** zero -- if everything went ok.
-** else -- some error.
-**
-** Side Effects:
-** Returns the current message to the sender via
-** mail.
-*/
-
-#define MAXRETURNS 6 /* max depth of returning messages */
-#define ERRORFUDGE 100 /* nominal size of error message text */
-
-int
-returntosender(msg, returnq, flags, e)
- char *msg;
- ADDRESS *returnq;
- int flags;
- register ENVELOPE *e;
-{
- register ENVELOPE *ee;
- ENVELOPE *oldcur = CurEnv;
- ENVELOPE errenvelope;
- static int returndepth = 0;
- register ADDRESS *q;
- char *p;
- char buf[MAXNAME + 1];
- extern void errbody __P((MCI *, ENVELOPE *, char *));
-
- if (returnq == NULL)
- return (-1);
-
- if (msg == NULL)
- msg = "Unable to deliver mail";
-
- if (tTd(6, 1))
- {
- printf("\n*** Return To Sender: msg=\"%s\", depth=%d, e=%lx, returnq=",
- msg, returndepth, (u_long) e);
- printaddr(returnq, TRUE);
- if (tTd(6, 20))
- {
- printf("Sendq=");
- printaddr(e->e_sendqueue, TRUE);
- }
- }
-
- if (++returndepth >= MAXRETURNS)
- {
- if (returndepth != MAXRETURNS)
- syserr("554 returntosender: infinite recursion on %s", returnq->q_paddr);
- /* don't "unrecurse" and fake a clean exit */
- /* returndepth--; */
- return (0);
- }
-
- define('g', e->e_from.q_paddr, e);
- define('u', NULL, e);
-
- /* initialize error envelope */
- ee = newenvelope(&errenvelope, e);
- define('a', "\201b", ee);
- define('r', "internal", ee);
- define('s', "localhost", ee);
- define('_', "localhost", ee);
- ee->e_puthdr = putheader;
- ee->e_putbody = errbody;
- ee->e_flags |= EF_RESPONSE|EF_METOO;
- if (!bitset(EF_OLDSTYLE, e->e_flags))
- ee->e_flags &= ~EF_OLDSTYLE;
- ee->e_sendqueue = returnq;
- ee->e_msgsize = ERRORFUDGE;
- if (bitset(RTSF_SEND_BODY, flags))
- ee->e_msgsize += e->e_msgsize;
- else
- ee->e_flags |= EF_NO_BODY_RETN;
- initsys(ee);
- for (q = returnq; q != NULL; q = q->q_next)
- {
- if (bitset(QBADADDR, q->q_flags))
- continue;
-
- q->q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS);
- q->q_flags |= QPINGONFAILURE;
-
- if (!bitset(QDONTSEND, q->q_flags))
- ee->e_nrcpts++;
-
- if (q->q_alias == NULL)
- addheader("To", q->q_paddr, &ee->e_header);
- }
-
- if (LogLevel > 5)
- {
- if (bitset(EF_RESPONSE|EF_WARNING, e->e_flags))
- p = "return to sender";
- else if (bitset(RTSF_PM_BOUNCE, flags))
- p = "postmaster notify";
- else
- p = "DSN";
- sm_syslog(LOG_INFO, e->e_id,
- "%s: %s: %s",
- ee->e_id, p, shortenstring(msg, MAXSHORTSTR));
- }
-
- if (SendMIMEErrors)
- {
- addheader("MIME-Version", "1.0", &ee->e_header);
-
- (void) snprintf(buf, sizeof buf, "%s.%ld/%.100s",
- ee->e_id, curtime(), MyHostName);
- ee->e_msgboundary = newstr(buf);
- (void) snprintf(buf, sizeof buf,
-#if DSN
- "multipart/report; report-type=delivery-status;\n\tboundary=\"%s\"",
-#else
- "multipart/mixed; boundary=\"%s\"",
-#endif
- ee->e_msgboundary);
- addheader("Content-Type", buf, &ee->e_header);
-
- p = hvalue("Content-Transfer-Encoding", e->e_header);
- if (p != NULL && strcasecmp(p, "binary") != 0)
- p = NULL;
- if (p == NULL && bitset(EF_HAS8BIT, e->e_flags))
- p = "8bit";
- if (p != NULL)
- addheader("Content-Transfer-Encoding", p, &ee->e_header);
- }
- if (strncmp(msg, "Warning:", 8) == 0)
- {
- addheader("Subject", msg, &ee->e_header);
- p = "warning-timeout";
- }
- else if (strncmp(msg, "Postmaster warning:", 19) == 0)
- {
- addheader("Subject", msg, &ee->e_header);
- p = "postmaster-warning";
- }
- else if (strcmp(msg, "Return receipt") == 0)
- {
- addheader("Subject", msg, &ee->e_header);
- p = "return-receipt";
- }
- else if (bitset(RTSF_PM_BOUNCE, flags))
- {
- snprintf(buf, sizeof buf, "Postmaster notify: %.*s",
- sizeof buf - 20, msg);
- addheader("Subject", buf, &ee->e_header);
- p = "postmaster-notification";
- }
- else
- {
- snprintf(buf, sizeof buf, "Returned mail: %.*s",
- sizeof buf - 20, msg);
- addheader("Subject", buf, &ee->e_header);
- p = "failure";
- }
- (void) snprintf(buf, sizeof buf, "auto-generated (%s)", p);
- addheader("Auto-Submitted", buf, &ee->e_header);
-
- /* fake up an address header for the from person */
- expand("\201n", buf, sizeof buf, e);
- if (parseaddr(buf, &ee->e_from, RF_COPYALL|RF_SENDERADDR, '\0', NULL, e) == NULL)
- {
- syserr("553 Can't parse myself!");
- ExitStat = EX_SOFTWARE;
- returndepth--;
- return (-1);
- }
- ee->e_from.q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS);
- ee->e_from.q_flags |= QPINGONFAILURE;
- ee->e_sender = ee->e_from.q_paddr;
-
- /* push state into submessage */
- CurEnv = ee;
- define('f', "\201n", ee);
- define('x', "Mail Delivery Subsystem", ee);
- eatheader(ee, TRUE);
-
- /* mark statistics */
- markstats(ee, NULLADDR, FALSE);
-
- /* actually deliver the error message */
- sendall(ee, SM_DELIVER);
-
- /* restore state */
- dropenvelope(ee, TRUE);
- CurEnv = oldcur;
- returndepth--;
-
- /* check for delivery errors */
- if (ee->e_parent == NULL || !bitset(EF_RESPONSE, ee->e_parent->e_flags))
- return 0;
- for (q = ee->e_sendqueue; q != NULL; q = q->q_next)
- {
- if (bitset(QQUEUEUP|QSENT, q->q_flags))
- return 0;
- }
- return -1;
-}
- /*
-** ERRBODY -- output the body of an error message.
-**
-** Typically this is a copy of the transcript plus a copy of the
-** original offending message.
-**
-** Parameters:
-** mci -- the mailer connection information.
-** e -- the envelope we are working in.
-** separator -- any possible MIME separator.
-**
-** Returns:
-** none
-**
-** Side Effects:
-** Outputs the body of an error message.
-*/
-
-void
-errbody(mci, e, separator)
- register MCI *mci;
- register ENVELOPE *e;
- char *separator;
-{
- register FILE *xfile;
- char *p;
- register ADDRESS *q = NULL;
- bool printheader;
- bool sendbody;
- bool pm_notify;
- char buf[MAXLINE];
-
- if (bitset(MCIF_INHEADER, mci->mci_flags))
- {
- putline("", mci);
- mci->mci_flags &= ~MCIF_INHEADER;
- }
- if (e->e_parent == NULL)
- {
- syserr("errbody: null parent");
- putline(" ----- Original message lost -----\n", mci);
- return;
- }
-
- /*
- ** Output MIME header.
- */
-
- if (e->e_msgboundary != NULL)
- {
- putline("This is a MIME-encapsulated message", mci);
- putline("", mci);
- (void) snprintf(buf, sizeof buf, "--%s", e->e_msgboundary);
- putline(buf, mci);
- putline("", mci);
- }
-
- /*
- ** Output introductory information.
- */
-
- pm_notify = FALSE;
- p = hvalue("subject", e->e_header);
- if (p != NULL && strncmp(p, "Postmaster ", 11) == 0)
- pm_notify = TRUE;
- else
- {
- for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
- if (bitset(QBADADDR, q->q_flags))
- break;
- }
- if (!pm_notify && q == NULL &&
- !bitset(EF_FATALERRS|EF_SENDRECEIPT, e->e_parent->e_flags))
- {
- putline(" **********************************************",
- mci);
- putline(" ** THIS IS A WARNING MESSAGE ONLY **",
- mci);
- putline(" ** YOU DO NOT NEED TO RESEND YOUR MESSAGE **",
- mci);
- putline(" **********************************************",
- mci);
- putline("", mci);
- }
- snprintf(buf, sizeof buf, "The original message was received at %s",
- arpadate(ctime(&e->e_parent->e_ctime)));
- putline(buf, mci);
- expand("from \201_", buf, sizeof buf, e->e_parent);
- putline(buf, mci);
- putline("", mci);
-
- /*
- ** Output error message header (if specified and available).
- */
-
- if (ErrMsgFile != NULL && !bitset(EF_SENDRECEIPT, e->e_parent->e_flags))
- {
- if (*ErrMsgFile == '/')
- {
- int sff = SFF_ROOTOK|SFF_REGONLY;
-
- if (DontLockReadFiles)
- sff |= SFF_NOLOCK;
- if (!bitset(DBS_ERRORHEADERINUNSAFEDIRPATH, DontBlameSendmail))
- sff |= SFF_SAFEDIRPATH;
- xfile = safefopen(ErrMsgFile, O_RDONLY, 0444, sff);
- if (xfile != NULL)
- {
- while (fgets(buf, sizeof buf, xfile) != NULL)
- {
- extern void translate_dollars __P((char *));
-
- translate_dollars(buf);
- expand(buf, buf, sizeof buf, e);
- putline(buf, mci);
- }
- (void) fclose(xfile);
- putline("\n", mci);
- }
- }
- else
- {
- expand(ErrMsgFile, buf, sizeof buf, e);
- putline(buf, mci);
- putline("", mci);
- }
- }
-
- /*
- ** Output message introduction
- */
-
- printheader = TRUE;
- for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
- {
- if (!bitset(QBADADDR, q->q_flags) ||
- !bitset(QPINGONFAILURE, q->q_flags))
- continue;
-
- if (printheader)
- {
- putline(" ----- The following addresses had permanent fatal errors -----",
- mci);
- printheader = FALSE;
- }
-
- snprintf(buf, sizeof buf, "%s",
- shortenstring(q->q_paddr, MAXSHORTSTR));
- putline(buf, mci);
- if (q->q_alias != NULL)
- {
- snprintf(buf, sizeof buf, " (expanded from: %s)",
- shortenstring(q->q_alias->q_paddr, MAXSHORTSTR));
- putline(buf, mci);
- }
- }
- if (!printheader)
- putline("", mci);
-
- printheader = TRUE;
- for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
- {
- if (bitset(QBADADDR, q->q_flags) ||
- !bitset(QPRIMARY, q->q_flags) ||
- !bitset(QDELAYED, q->q_flags))
- continue;
-
- if (printheader)
- {
- putline(" ----- The following addresses had transient non-fatal errors -----",
- mci);
- printheader = FALSE;
- }
-
- snprintf(buf, sizeof buf, "%s",
- shortenstring(q->q_paddr, MAXSHORTSTR));
- putline(buf, mci);
- if (q->q_alias != NULL)
- {
- snprintf(buf, sizeof buf, " (expanded from: %s)",
- shortenstring(q->q_alias->q_paddr, MAXSHORTSTR));
- putline(buf, mci);
- }
- }
- if (!printheader)
- putline("", mci);
-
- printheader = TRUE;
- for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
- {
- if (bitset(QBADADDR, q->q_flags) ||
- !bitset(QPRIMARY, q->q_flags) ||
- bitset(QDELAYED, q->q_flags))
- continue;
- else if (!bitset(QPINGONSUCCESS, q->q_flags))
- continue;
- else if (bitset(QRELAYED, q->q_flags))
- p = "relayed to non-DSN-aware mailer";
- else if (bitset(QDELIVERED, q->q_flags))
- {
- if (bitset(QEXPANDED, q->q_flags))
- p = "successfully delivered to mailing list";
- else
- p = "successfully delivered to mailbox";
- }
- else if (bitset(QEXPANDED, q->q_flags))
- p = "expanded by alias";
- else
- continue;
-
- if (printheader)
- {
- putline(" ----- The following addresses had successful delivery notifications -----",
- mci);
- printheader = FALSE;
- }
-
- snprintf(buf, sizeof buf, "%s (%s)",
- shortenstring(q->q_paddr, MAXSHORTSTR), p);
- putline(buf, mci);
- if (q->q_alias != NULL)
- {
- snprintf(buf, sizeof buf, " (expanded from: %s)",
- shortenstring(q->q_alias->q_paddr, MAXSHORTSTR));
- putline(buf, mci);
- }
- }
- if (!printheader)
- putline("", mci);
-
- /*
- ** Output transcript of errors
- */
-
- (void) fflush(stdout);
- p = queuename(e->e_parent, 'x');
- if ((xfile = fopen(p, "r")) == NULL)
- {
- syserr("Cannot open %s", p);
- putline(" ----- Transcript of session is unavailable -----\n", mci);
- }
- else
- {
- printheader = TRUE;
- if (e->e_xfp != NULL)
- (void) fflush(e->e_xfp);
- while (fgets(buf, sizeof buf, xfile) != NULL)
- {
- if (printheader)
- putline(" ----- Transcript of session follows -----\n", mci);
- printheader = FALSE;
- putline(buf, mci);
- }
- (void) xfclose(xfile, "errbody xscript", p);
- }
- errno = 0;
-
-#if DSN
- /*
- ** Output machine-readable version.
- */
-
- if (e->e_msgboundary != NULL)
- {
- putline("", mci);
- (void) snprintf(buf, sizeof buf, "--%s", e->e_msgboundary);
- putline(buf, mci);
- putline("Content-Type: message/delivery-status", mci);
- putline("", mci);
-
- /*
- ** Output per-message information.
- */
-
- /* original envelope id from MAIL FROM: line */
- if (e->e_parent->e_envid != NULL)
- {
- (void) snprintf(buf, sizeof buf, "Original-Envelope-Id: %.800s",
- xuntextify(e->e_parent->e_envid));
- putline(buf, mci);
- }
-
- /* Reporting-MTA: is us (required) */
- (void) snprintf(buf, sizeof buf, "Reporting-MTA: dns; %.800s", MyHostName);
- putline(buf, mci);
-
- /* DSN-Gateway: not relevant since we are not translating */
-
- /* Received-From-MTA: shows where we got this message from */
- if (RealHostName != NULL)
- {
- /* XXX use $s for type? */
- if (e->e_parent->e_from.q_mailer == NULL ||
- (p = e->e_parent->e_from.q_mailer->m_mtatype) == NULL)
- p = "dns";
- (void) snprintf(buf, sizeof buf, "Received-From-MTA: %s; %.800s",
- p, RealHostName);
- putline(buf, mci);
- }
-
- /* Arrival-Date: -- when it arrived here */
- (void) snprintf(buf, sizeof buf, "Arrival-Date: %s",
- arpadate(ctime(&e->e_parent->e_ctime)));
- putline(buf, mci);
-
- /*
- ** Output per-address information.
- */
-
- for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
- {
- register ADDRESS *r;
- char *action;
-
- if (bitset(QBADADDR, q->q_flags))
- action = "failed";
- else if (!bitset(QPRIMARY, q->q_flags))
- continue;
- else if (bitset(QDELIVERED, q->q_flags))
- {
- if (bitset(QEXPANDED, q->q_flags))
- action = "delivered (to mailing list)";
- else
- action = "delivered (to mailbox)";
- }
- else if (bitset(QRELAYED, q->q_flags))
- action = "relayed (to non-DSN-aware mailer)";
- else if (bitset(QEXPANDED, q->q_flags))
- action = "expanded (to multi-recipient alias)";
- else if (bitset(QDELAYED, q->q_flags))
- action = "delayed";
- else
- continue;
-
- putline("", mci);
-
- /* Original-Recipient: -- passed from on high */
- if (q->q_orcpt != NULL)
- {
- (void) snprintf(buf, sizeof buf, "Original-Recipient: %.800s",
- q->q_orcpt);
- putline(buf, mci);
- }
-
- /* Final-Recipient: -- the name from the RCPT command */
- p = e->e_parent->e_from.q_mailer->m_addrtype;
- if (p == NULL)
- p = "rfc822";
- for (r = q; r->q_alias != NULL; r = r->q_alias)
- continue;
- if (strchr(r->q_user, '@') != NULL)
- {
- (void) snprintf(buf, sizeof buf,
- "Final-Recipient: %s; %.800s",
- p, r->q_user);
- }
- else if (strchr(r->q_paddr, '@') != NULL)
- {
- (void) snprintf(buf, sizeof buf,
- "Final-Recipient: %s; %.800s",
- p, r->q_paddr);
- }
- else
- {
- (void) snprintf(buf, sizeof buf,
- "Final-Recipient: %s; %.700s@%.100s",
- p, r->q_user, MyHostName);
- }
- putline(buf, mci);
-
- /* X-Actual-Recipient: -- the real problem address */
- if (r != q && q->q_user[0] != '\0')
- {
- if (strchr(q->q_user, '@') == NULL)
- {
- (void) snprintf(buf, sizeof buf,
- "X-Actual-Recipient: %s; %.700s@%.100s",
- p, q->q_user, MyHostName);
- }
- else
- {
- (void) snprintf(buf, sizeof buf,
- "X-Actual-Recipient: %s; %.800s",
- p, q->q_user);
- }
- putline(buf, mci);
- }
-
- /* Action: -- what happened? */
- snprintf(buf, sizeof buf, "Action: %s", action);
- putline(buf, mci);
-
- /* Status: -- what _really_ happened? */
- if (q->q_status != NULL)
- p = q->q_status;
- else if (bitset(QBADADDR, q->q_flags))
- p = "5.0.0";
- else if (bitset(QQUEUEUP, q->q_flags))
- p = "4.0.0";
- else
- p = "2.0.0";
- snprintf(buf, sizeof buf, "Status: %s", p);
- putline(buf, mci);
-
- /* Remote-MTA: -- who was I talking to? */
- if (q->q_statmta != NULL)
- {
- if (q->q_mailer == NULL ||
- (p = q->q_mailer->m_mtatype) == NULL)
- p = "dns";
- (void) snprintf(buf, sizeof buf,
- "Remote-MTA: %s; %.800s",
- p, q->q_statmta);
- p = &buf[strlen(buf) - 1];
- if (*p == '.')
- *p = '\0';
- putline(buf, mci);
- }
-
- /* Diagnostic-Code: -- actual result from other end */
- if (q->q_rstatus != NULL)
- {
- p = q->q_mailer->m_diagtype;
- if (p == NULL)
- p = "smtp";
- (void) snprintf(buf, sizeof buf,
- "Diagnostic-Code: %s; %.800s",
- p, q->q_rstatus);
- putline(buf, mci);
- }
-
- /* Last-Attempt-Date: -- fine granularity */
- if (q->q_statdate == (time_t) 0L)
- q->q_statdate = curtime();
- (void) snprintf(buf, sizeof buf,
- "Last-Attempt-Date: %s",
- arpadate(ctime(&q->q_statdate)));
- putline(buf, mci);
-
- /* Will-Retry-Until: -- for delayed messages only */
- if (bitset(QQUEUEUP, q->q_flags) &&
- !bitset(QBADADDR, q->q_flags))
- {
- time_t xdate;
-
- xdate = e->e_parent->e_ctime +
- TimeOuts.to_q_return[e->e_parent->e_timeoutclass];
- snprintf(buf, sizeof buf,
- "Will-Retry-Until: %s",
- arpadate(ctime(&xdate)));
- putline(buf, mci);
- }
- }
- }
-#endif
-
- /*
- ** Output text of original message
- */
-
- putline("", mci);
- if (bitset(EF_HAS_DF, e->e_parent->e_flags))
- {
- sendbody = !bitset(EF_NO_BODY_RETN, e->e_parent->e_flags) &&
- !bitset(EF_NO_BODY_RETN, e->e_flags);
-
- if (e->e_msgboundary == NULL)
- {
- if (sendbody)
- putline(" ----- Original message follows -----\n", mci);
- else
- putline(" ----- Message header follows -----\n", mci);
- (void) fflush(mci->mci_out);
- }
- else
- {
- (void) snprintf(buf, sizeof buf, "--%s",
- e->e_msgboundary);
-
- putline(buf, mci);
- (void) snprintf(buf, sizeof buf, "Content-Type: %s",
- sendbody ? "message/rfc822"
- : "text/rfc822-headers");
- putline(buf, mci);
-
- p = hvalue("Content-Transfer-Encoding", e->e_parent->e_header);
- if (p != NULL && strcasecmp(p, "binary") != 0)
- p = NULL;
- if (p == NULL && bitset(EF_HAS8BIT, e->e_parent->e_flags))
- p = "8bit";
- if (p != NULL)
- {
- (void) snprintf(buf, sizeof buf, "Content-Transfer-Encoding: %s",
- p);
- putline(buf, mci);
- }
- }
- putline("", mci);
- putheader(mci, e->e_parent->e_header, e->e_parent, M87F_OUTER);
- if (sendbody)
- putbody(mci, e->e_parent, e->e_msgboundary);
- else if (e->e_msgboundary == NULL)
- {
- putline("", mci);
- putline(" ----- Message body suppressed -----", mci);
- }
- }
- else if (e->e_msgboundary == NULL)
- {
- putline(" ----- No message was collected -----\n", mci);
- }
-
- if (e->e_msgboundary != NULL)
- {
- putline("", mci);
- (void) snprintf(buf, sizeof buf, "--%s--", e->e_msgboundary);
- putline(buf, mci);
- }
- putline("", mci);
-
- /*
- ** Cleanup and exit
- */
-
- if (errno != 0)
- syserr("errbody: I/O error");
-}
- /*
-** SMTPTODSN -- convert SMTP to DSN status code
-**
-** Parameters:
-** smtpstat -- the smtp status code (e.g., 550).
-**
-** Returns:
-** The DSN version of the status code.
-*/
-
-char *
-smtptodsn(smtpstat)
- int smtpstat;
-{
- if (smtpstat < 0)
- return "4.4.2";
-
- switch (smtpstat)
- {
- case 450: /* Req mail action not taken: mailbox unavailable */
- return "4.2.0";
-
- case 451: /* Req action aborted: local error in processing */
- return "4.3.0";
-
- case 452: /* Req action not taken: insufficient sys storage */
- return "4.3.1";
-
- case 500: /* Syntax error, command unrecognized */
- return "5.5.2";
-
- case 501: /* Syntax error in parameters or arguments */
- return "5.5.4";
-
- case 502: /* Command not implemented */
- return "5.5.1";
-
- case 503: /* Bad sequence of commands */
- return "5.5.1";
-
- case 504: /* Command parameter not implemented */
- return "5.5.4";
-
- case 550: /* Req mail action not taken: mailbox unavailable */
- return "5.2.0";
-
- case 551: /* User not local; please try <...> */
- return "5.1.6";
-
- case 552: /* Req mail action aborted: exceeded storage alloc */
- return "5.2.2";
-
- case 553: /* Req action not taken: mailbox name not allowed */
- return "5.1.0";
-
- case 554: /* Transaction failed */
- return "5.0.0";
- }
-
- if ((smtpstat / 100) == 2)
- return "2.0.0";
- if ((smtpstat / 100) == 4)
- return "4.0.0";
- return "5.0.0";
-}
- /*
-** XTEXTIFY -- take regular text and turn it into DSN-style xtext
-**
-** Parameters:
-** t -- the text to convert.
-** taboo -- additional characters that must be encoded.
-**
-** Returns:
-** The xtext-ified version of the same string.
-*/
-
-char *
-xtextify(t, taboo)
- register char *t;
- char *taboo;
-{
- register char *p;
- int l;
- int nbogus;
- static char *bp = NULL;
- static int bplen = 0;
-
- if (taboo == NULL)
- taboo = "";
-
- /* figure out how long this xtext will have to be */
- nbogus = l = 0;
- for (p = t; *p != '\0'; p++)
- {
- register int c = (*p & 0xff);
-
- /* ASCII dependence here -- this is the way the spec words it */
- if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(' ||
- strchr(taboo, c) != NULL)
- nbogus++;
- l++;
- }
- if (nbogus == 0)
- return t;
- l += nbogus * 2 + 1;
-
- /* now allocate space if necessary for the new string */
- if (l > bplen)
- {
- if (bp != NULL)
- free(bp);
- bp = xalloc(l);
- bplen = l;
- }
-
- /* ok, copy the text with byte expansion */
- for (p = bp; *t != '\0'; )
- {
- register int c = (*t++ & 0xff);
-
- /* ASCII dependence here -- this is the way the spec words it */
- if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(' ||
- strchr(taboo, c) != NULL)
- {
- *p++ = '+';
- *p++ = "0123456789abcdef"[c >> 4];
- *p++ = "0123456789abcdef"[c & 0xf];
- }
- else
- *p++ = c;
- }
- *p = '\0';
- return bp;
-}
- /*
-** XUNTEXTIFY -- take xtext and turn it into plain text
-**
-** Parameters:
-** t -- the xtextified text.
-**
-** Returns:
-** The decoded text. No attempt is made to deal with
-** null strings in the resulting text.
-*/
-
-char *
-xuntextify(t)
- register char *t;
-{
- register char *p;
- int l;
- static char *bp = NULL;
- static int bplen = 0;
-
- /* heuristic -- if no plus sign, just return the input */
- if (strchr(t, '+') == NULL)
- return t;
-
- /* xtext is always longer than decoded text */
- l = strlen(t);
- if (l > bplen)
- {
- if (bp != NULL)
- free(bp);
- bp = xalloc(l);
- bplen = l;
- }
-
- /* ok, copy the text with byte compression */
- for (p = bp; *t != '\0'; t++)
- {
- register int c = *t & 0xff;
-
- if (c != '+')
- {
- *p++ = c;
- continue;
- }
-
- c = *++t & 0xff;
- if (!isascii(c) || !isxdigit(c))
- {
- /* error -- first digit is not hex */
- usrerr("bogus xtext: +%c", c);
- t--;
- continue;
- }
- if (isdigit(c))
- c -= '0';
- else if (isupper(c))
- c -= 'A' - 10;
- else
- c -= 'a' - 10;
- *p = c << 4;
-
- c = *++t & 0xff;
- if (!isascii(c) || !isxdigit(c))
- {
- /* error -- second digit is not hex */
- usrerr("bogus xtext: +%x%c", *p >> 4, c);
- t--;
- continue;
- }
- if (isdigit(c))
- c -= '0';
- else if (isupper(c))
- c -= 'A' - 10;
- else
- c -= 'a' - 10;
- *p++ |= c;
- }
- *p = '\0';
- return bp;
-}
- /*
-** XTEXTOK -- check if a string is legal xtext
-**
-** Xtext is used in Delivery Status Notifications. The spec was
-** taken from RFC 1891, ``SMTP Service Extension for Delivery
-** Status Notifications''.
-**
-** Parameters:
-** s -- the string to check.
-**
-** Returns:
-** TRUE -- if 's' is legal xtext.
-** FALSE -- if it has any illegal characters in it.
-*/
-
-bool
-xtextok(s)
- char *s;
-{
- int c;
-
- while ((c = *s++) != '\0')
- {
- if (c == '+')
- {
- c = *s++;
- if (!isascii(c) || !isxdigit(c))
- return FALSE;
- c = *s++;
- if (!isascii(c) || !isxdigit(c))
- return FALSE;
- }
- else if (c < '!' || c > '~' || c == '=')
- return FALSE;
- }
- return TRUE;
-}
- /*
-** PRUNEROUTE -- prune an RFC-822 source route
-**
-** Trims down a source route to the last internet-registered hop.
-** This is encouraged by RFC 1123 section 5.3.3.
-**
-** Parameters:
-** addr -- the address
-**
-** Returns:
-** TRUE -- address was modified
-** FALSE -- address could not be pruned
-**
-** Side Effects:
-** modifies addr in-place
-*/
-
-bool
-pruneroute(addr)
- char *addr;
-{
-#if NAMED_BIND
- char *start, *at, *comma;
- char c;
- int rcode;
- int i;
- char hostbuf[BUFSIZ];
- char *mxhosts[MAXMXHOSTS + 1];
-
- /* check to see if this is really a route-addr */
- if (*addr != '<' || addr[1] != '@' || addr[strlen(addr) - 1] != '>')
- return FALSE;
- start = strchr(addr, ':');
- at = strrchr(addr, '@');
- if (start == NULL || at == NULL || at < start)
- return FALSE;
-
- /* slice off the angle brackets */
- i = strlen(at + 1);
- if (i >= (SIZE_T) sizeof hostbuf)
- return FALSE;
- strcpy(hostbuf, at + 1);
- hostbuf[i - 1] = '\0';
-
- while (start)
- {
- if (getmxrr(hostbuf, mxhosts, FALSE, &rcode) > 0)
- {
- strcpy(addr + 1, start + 1);
- return TRUE;
- }
- c = *start;
- *start = '\0';
- comma = strrchr(addr, ',');
- if (comma != NULL && comma[1] == '@' &&
- strlen(comma + 2) < (SIZE_T) sizeof hostbuf)
- strcpy(hostbuf, comma + 2);
- else
- comma = NULL;
- *start = c;
- start = comma;
- }
-#endif
- return FALSE;
-}
diff --git a/src/sendmail.0 b/src/sendmail.0
deleted file mode 100644
index 0046bd3..0000000
--- a/src/sendmail.0
+++ /dev/null
@@ -1,356 +0,0 @@
-SENDMAIL(8) BSD System Manager's Manual SENDMAIL(8)
-
-NNAAMMEE
- sseennddmmaaiill - an electronic mail transport agent
-
-SSYYNNOOPPSSIISS
- sseennddmmaaiill [_f_l_a_g_s] [_a_d_d_r_e_s_s _._._.]
- nneewwaalliiaasseess
- mmaaiillqq [--vv]
-
-DDEESSCCRRIIPPTTIIOONN
- SSeennddmmaaiill sends a message to one or more _r_e_c_i_p_i_e_n_t_s, routing the message
- over whatever networks are necessary. SSeennddmmaaiill does internetwork for-
- warding as necessary to deliver the message to the correct place.
-
- SSeennddmmaaiill is not intended as a user interface routine; other programs pro-
- vide user-friendly front ends; sseennddmmaaiill is used only to deliver pre-for-
- matted messages.
-
- With no flags, sseennddmmaaiill reads its standard input up to an end-of-file or
- a line consisting only of a single dot and sends a copy of the message
- found there to all of the addresses listed. It determines the network(s)
- to use based on the syntax and contents of the addresses.
-
- Local addresses are looked up in a file and aliased appropriately.
- Aliasing can be prevented by preceding the address with a backslash.
- Normally the sender is not included in any alias expansions, e.g., if
- `john' sends to `group', and `group' includes `john' in the expansion,
- then the letter will not be delivered to `john'.
-
- PPaarraammeetteerrss
-
- --BB_t_y_p_e Set the body type to _t_y_p_e. Current legal values 7BIT or
- 8BITMIME.
-
- --bbaa Go into ARPANET mode. All input lines must end with a CR-LF,
- and all messages will be generated with a CR-LF at the end.
- Also, the ``From:'' and ``Sender:'' fields are examined for
- the name of the sender.
-
- --bbdd Run as a daemon. This requires Berkeley IPC. SSeennddmmaaiill will
- fork and run in background listening on socket 25 for incom-
- ing SMTP connections. This is normally run from _/_e_t_c_/_r_c.
-
- --bbDD Same as --bbdd except runs in foreground.
-
- --bbhh Print the persistent host status database.
-
- --bbHH Purge the persistent host status database.
-
- --bbii Initialize the alias database.
-
- --bbmm Deliver mail in the usual way (default).
-
- --bbpp Print a listing of the queue.
-
- --bbss Use the SMTP protocol as described in RFC821 on standard in-
- put and output. This flag implies all the operations of the
- --bbaa flag that are compatible with SMTP.
-
- --bbtt Run in address test mode. This mode reads addresses and
- shows the steps in parsing; it is used for debugging configu-
- ration tables.
-
- --bbvv Verify names only - do not try to collect or deliver a mes-
- sage. Verify mode is normally used for validating users or
- mailing lists.
-
- --CC_f_i_l_e Use alternate configuration file. SSeennddmmaaiill refuses to run as
- root if an alternate configuration file is specified.
-
- --dd_X Set debugging value to _X.
-
- --FF_f_u_l_l_n_a_m_e Set the full name of the sender.
-
- --ff_n_a_m_e Sets the name of the ``from'' person (i.e., the sender of the
- mail). --ff can only be used by ``trusted'' users (normally
- _r_o_o_t, _d_a_e_m_o_n, and _n_e_t_w_o_r_k) or if the person you are trying to
- become is the same as the person you are.
-
- --hh_N Set the hop count to _N. The hop count is incremented every
- time the mail is processed. When it reaches a limit, the
- mail is returned with an error message, the victim of an
- aliasing loop. If not specified, ``Received:'' lines in the
- message are counted.
-
- --ii Ignore dots alone on lines by themselves in incoming mes-
- sages. This should be set if you are reading data from a
- file.
-
- --NN _d_s_n Set delivery status notification conditions to _d_s_n_, which can
- be `never' for no notifications or a comma separated list of
- the values `failure' to be notified if delivery failed,
- `delay' to be notified if delivery is delayed, and `success'
- to be notified when the message is successfully delivered.
-
- --nn Don't do aliasing.
-
- --OO _o_p_t_i_o_n=_v_a_l_u_e
- Set option _o_p_t_i_o_n to the specified _v_a_l_u_e. This form uses long
- names. See below for more details.
-
- --oo_x _v_a_l_u_e Set option _x to the specified _v_a_l_u_e. This form uses single
- character names only. The short names are not described in
- this manual page; see the _S_e_n_d_m_a_i_l _I_n_s_t_a_l_l_a_t_i_o_n _a_n_d _O_p_e_r_a_t_i_o_n
- _G_u_i_d_e for details.
-
- --pp_p_r_o_t_o_c_o_l Set the name of the protocol used to receive the message.
- This can be a simple protocol name such as ``UUCP'' or a pro-
- tocol and hostname, such as ``UUCP:ucbvax''.
-
- --qq[_t_i_m_e] Processed saved messages in the queue at given intervals. If
- _t_i_m_e is omitted, process the queue once. Time is given as a
- tagged number, with `s' being seconds, `m' being minutes, `h'
- being hours, `d' being days, and `w' being weeks. For exam-
- ple, `-q1h30m' or `-q90m' would both set the timeout to one
- hour thirty minutes. If _t_i_m_e is specified, sseennddmmaaiill will run
- in background. This option can be used safely with --bbdd.
-
- --qqII_s_u_b_s_t_r Limit processed jobs to those containing _s_u_b_s_t_r as a sub-
- string of the queue id.
-
- --qqRR_s_u_b_s_t_r Limit processed jobs to those containing _s_u_b_s_t_r as a sub-
- string of one of the recipients.
-
- --qqSS_s_u_b_s_t_r Limit processed jobs to those containing _s_u_b_s_t_r as a sub-
- string of the sender.
-
- --RR _r_e_t_u_r_n Set the amount of the message to be returned if the message
- bounces. The _r_e_t_u_r_n parameter can be `full' to return the
-
- entire message or `hdrs' to return only the headers.
-
- --rr_n_a_m_e An alternate and obsolete form of the --ff flag.
-
- --tt Read message for recipients. To:, Cc:, and Bcc: lines will
- be scanned for recipient addresses. The Bcc: line will be
- deleted before transmission.
-
- --UU Initial (user) submission. This should _a_l_w_a_y_s be set when
- called from a user agent such as MMaaiill or eexxmmhh and _n_e_v_e_r be
- set when called by a network delivery agent such as rrmmaaiill.
-
- --VV _e_n_v_i_d Set the original envelope id. This is propagated across SMTP
- to servers that support DSNs and is returned in DSN-compliant
- error messages.
-
- --vv Go into verbose mode. Alias expansions will be announced,
- etc.
-
- --XX _l_o_g_f_i_l_e Log all traffic in and out of mailers in the indicated log
- file. This should only be used as a last resort for debug-
- ging mailer bugs. It will log a lot of data very quickly.
-
- ---- Stop processing command flags and use the rest of the argu-
- ments as addresses.
-
- OOppttiioonnss
- There are also a number of processing options that may be set. Normally
- these will only be used by a system administrator. Options may be set
- either on the command line using the --oo flag (for short names), the --OO
- flag (for long names), or in the configuration file. This is a partial
- list limited to those options that are likely to be useful on the command
- line and only shows the long names; for a complete list (and details),
- consult the _S_e_n_d_m_a_i_l _I_n_s_t_a_l_l_a_t_i_o_n _a_n_d _O_p_e_r_a_t_i_o_n _G_u_i_d_e. The options are:
-
- AliasFile=_f_i_l_e
- Use alternate alias file.
-
- HoldExpensive
- On mailers that are considered ``expensive'' to connect to,
- don't initiate immediate connection. This requires queueing.
-
- CheckpointInterval=_N
- Checkpoint the queue file after every _N successful deliveries
- (default 10). This avoids excessive duplicate deliveries
- when sending to long mailing lists interrupted by system
- crashes.
-
- DeliveryMode=_x
- Set the delivery mode to _x. Delivery modes are `i' for inter-
- active (synchronous) delivery, `b' for background (asyn-
- chronous) delivery, `q' for queue only - i.e., actual deliv-
- ery is done the next time the queue is run, and `d' for de-
- ferred - the same as `q' except that database lookups (no-
- tably DNS and NIS lookups) are avoided.
-
- ErrorMode=_x
- Set error processing to mode _x. Valid modes are `m' to mail
- back the error message, `w' to ``write'' back the error mes-
- sage (or mail it back if the sender is not logged in), `p' to
- print the errors on the terminal (default), `q' to throw away
- error messages (only exit status is returned), and `e' to do
- special processing for the BerkNet. If the text of the mes-
- sage is not mailed back by modes `m' or `w' and if the sender
- is local to this machine, a copy of the message is appended
-
- to the file _d_e_a_d_._l_e_t_t_e_r in the sender's home directory.
-
- SaveFromLine
- Save UNIX-style From lines at the front of messages.
-
- MaxHopCount= _N
- The maximum number of times a message is allowed to ``hop''
- before we decide it is in a loop.
-
- IgnoreDots Do not take dots on a line by themselves as a message termi-
- nator.
-
- SendMimeErrors
- Send error messages in MIME format. If not set, the DSN (De-
- livery Status Notification) SMTP extension is disabled.
-
- ConnectionCacheTimeout=_t_i_m_e_o_u_t
- Set connection cache timeout.
-
- ConnectionCacheSize=_N
- Set connection cache size.
-
- LogLevel=_n The log level.
-
- MeToo Send to ``me'' (the sender) also if I am in an alias expan-
- sion.
-
- CheckAliases
- Validate the right hand side of aliases during a newalias-
- es(1) command.
-
- OldStyleHeaders
- If set, this message may have old style headers. If not set,
- this message is guaranteed to have new style headers (i.e.,
- commas instead of spaces between addresses). If set, an
- adaptive algorithm is used that will correctly determine the
- header format in most cases.
-
- QueueDirectory=_q_u_e_u_e_d_i_r
- Select the directory in which to queue messages.
-
- StatusFile=_f_i_l_e
- Save statistics in the named file.
-
- Timeout.queuereturn=_t_i_m_e
- Set the timeout on undelivered messages in the queue to the
- specified time. After delivery has failed (e.g., because of
- a host being down) for this amount of time, failed messages
- will be returned to the sender. The default is five days.
-
- UserDatabaseSpec=_u_s_e_r_d_a_t_a_b_a_s_e
- If set, a user database is consulted to get forwarding infor-
- mation. You can consider this an adjunct to the aliasing
- mechanism, except that the database is intended to be dis-
- tributed; aliases are local to a particular host. This may
- not be available if your sendmail does not have the USERDB
- option compiled in.
-
- ForkEachJob
- Fork each job during queue runs. May be convenient on memo-
- ry-poor machines.
-
- SevenBitInput
- Strip incoming messages to seven bits.
-
- EightBitMode=_m_o_d_e
- Set the handling of eight bit input to seven bit destinations
- to _m_o_d_e: m (mimefy) will convert to seven-bit MIME format, p
- (pass) will pass it as eight bits (but violates protocols),
- and s (strict) will bounce the message.
-
- MinQueueAge=_t_i_m_e_o_u_t
- Sets how long a job must ferment in the queue between at-
- tempts to send it.
-
- DefaultCharSet=_c_h_a_r_s_e_t
- Sets the default character set used to label 8-bit data that
- is not otherwise labelled.
-
- DialDelay=_s_l_e_e_p_t_i_m_e
- If opening a connection fails, sleep for _s_l_e_e_p_t_i_m_e seconds
- and try again. Useful on dial-on-demand sites.
-
- NoRecipientAction=_a_c_t_i_o_n
- Set the behaviour when there are no recipient headers (To:,
- Cc: or Bcc:) in the message to _a_c_t_i_o_n: none leaves the mes-
- sage unchanged, add-to adds a To: header with the envelope
- recipients, add-apparently-to adds an Apparently-To: header
- with the envelope recipients, add-bcc adds an empty Bcc:
- header, and add-to-undisclosed adds a header reading `To:
- undisclosed-recipients:;'.
-
- MaxDaemonChildren=_N
- Sets the maximum number of children that an incoming SMTP
- daemon will allow to spawn at any time to _N.
-
- ConnectionRateThrottle=_N
- Sets the maximum number of connections per second to the SMTP
- port to _N.
-
- In aliases, the first character of a name may be a vertical bar to cause
- interpretation of the rest of the name as a command to pipe the mail to.
- It may be necessary to quote the name to keep sseennddmmaaiill from suppressing
- the blanks from between arguments. For example, a common alias is:
-
- msgs: "|/usr/bin/msgs -s"
-
- Aliases may also have the syntax ``:include:_f_i_l_e_n_a_m_e'' to ask sendmail to
- read the named file for a list of recipients. For example, an alias such
- as:
-
- poets: ":include:/usr/local/lib/poets.list"
-
- would read _/_u_s_r_/_l_o_c_a_l_/_l_i_b_/_p_o_e_t_s_._l_i_s_t for the list of addresses making up
- the group.
-
- SSeennddmmaaiill returns an exit status describing what it did. The codes are
- defined in <_s_y_s_e_x_i_t_s_._h>:
- EX_OK Successful completion on all addresses.
- EX_NOUSER User name not recognized.
- EX_UNAVAILABLE Catchall meaning necessary resources were not
- available.
- EX_SYNTAX Syntax error in address.
- EX_SOFTWARE Internal software error, including bad arguments.
- EX_OSERR Temporary operating system error, such as ``cannot
- fork''.
- EX_NOHOST Host name not recognized.
- EX_TEMPFAIL Message could not be sent immediately, but was
- queued.
-
- If invoked as nneewwaalliiaasseess, sseennddmmaaiill will rebuild the alias database. If
- invoked as mmaaiillqq, sseennddmmaaiill will print the contents of the mail queue.
-
-FFIILLEESS
- Except for the file _/_e_t_c_/_s_e_n_d_m_a_i_l_._c_f itself and the daemon process ID
- file, the following pathnames are all specified in _/_e_t_c_/_s_e_n_d_m_a_i_l_._c_f_.
- Thus, these values are only approximations.
-
- /etc/aliases raw data for alias names
- /etc/aliases.db data base of alias names
- /etc/sendmail.cf configuration file
- /etc/sendmail.hf help file
- /var/log/sendmail.st collected statistics
- /var/spool/mqueue/* temp files
-
-SSEEEE AALLSSOO
- binmail(1), mail(1), rmail(1), syslog(3), aliases(5), mailaddr(7),
- rc(8);
-
- DARPA Internet Request For Comments _R_F_C_8_1_9, _R_F_C_8_2_1, _R_F_C_8_2_2.
-
- _S_e_n_d_m_a_i_l _- _A_n _I_n_t_e_r_n_e_t_w_o_r_k _M_a_i_l _R_o_u_t_e_r, No. 9, SMM.
-
- _S_e_n_d_m_a_i_l _I_n_s_t_a_l_l_a_t_i_o_n _a_n_d _O_p_e_r_a_t_i_o_n _G_u_i_d_e, No. 8, SMM.
-
-HHIISSTTOORRYY
- The sseennddmmaaiill command appeared in 4.2BSD.
-
-4th Berkeley Distribution August 2, 1998 6
diff --git a/src/sendmail.8 b/src/sendmail.8
deleted file mode 100644
index 093b6e6..0000000
--- a/src/sendmail.8
+++ /dev/null
@@ -1,580 +0,0 @@
-.\" Copyright (c) 1998 Sendmail, Inc. All rights reserved.
-.\" Copyright (c) 1983, 1997 Eric P. Allman. All rights reserved.
-.\" Copyright (c) 1988, 1991, 1993
-.\" The Regents of the University of California. All rights reserved.
-.\"
-.\" By using this file, you agree to the terms and conditions set
-.\" forth in the LICENSE file which can be found at the top level of
-.\" the sendmail distribution.
-.\"
-.\"
-.\" @(#)sendmail.8 8.20 (Berkeley) 8/2/1998
-.\"
-.Dd August 2, 1998
-.Dt SENDMAIL 8
-.Os BSD 4
-.Sh NAME
-.Nm sendmail
-.Nd an electronic mail transport agent
-.Sh SYNOPSIS
-.Nm sendmail
-.Op Ar flags
-.Op Ar address ...
-.Nm newaliases
-.Nm mailq
-.Op Fl v
-.Sh DESCRIPTION
-.Nm Sendmail
-sends a message to one or more
-.Em recipients ,
-routing the message over whatever networks
-are necessary.
-.Nm Sendmail
-does internetwork forwarding as necessary
-to deliver the message to the correct place.
-.Pp
-.Nm Sendmail
-is not intended as a user interface routine;
-other programs provide user-friendly
-front ends;
-.Nm sendmail
-is used only to deliver pre-formatted messages.
-.Pp
-With no flags,
-.Nm sendmail
-reads its standard input
-up to an end-of-file
-or a line consisting only of a single dot
-and sends a copy of the message found there
-to all of the addresses listed.
-It determines the network(s) to use
-based on the syntax and contents of the addresses.
-.Pp
-Local addresses are looked up in a file
-and aliased appropriately.
-Aliasing can be prevented by preceding the address
-with a backslash.
-Normally the sender is not included in any alias
-expansions, e.g.,
-if `john' sends to `group',
-and `group' includes `john' in the expansion,
-then the letter will not be delivered to `john'.
-.Ss Parameters
-.Bl -tag -width Fl
-.It Fl B Ns Ar type
-Set the body type to
-.Ar type .
-Current legal values
-.Li 7BIT
-or
-.Li 8BITMIME .
-.It Fl ba
-Go into
-.Tn ARPANET
-mode.
-All input lines must end with a CR-LF,
-and all messages will be generated with a CR-LF at the end.
-Also,
-the ``From:'' and ``Sender:''
-fields are examined for the name of the sender.
-.It Fl bd
-Run as a daemon. This requires Berkeley
-.Tn IPC .
-.Nm Sendmail
-will fork and run in background
-listening on socket 25 for incoming
-.Tn SMTP
-connections.
-This is normally run from
-.Pa /etc/rc .
-.It Fl bD
-Same as
-.Fl bd
-except runs in foreground.
-.It Fl bh
-Print the persistent host status database.
-.It Fl bH
-Purge the persistent host status database.
-.It Fl bi
-Initialize the alias database.
-.It Fl bm
-Deliver mail in the usual way (default).
-.It Fl bp
-Print a listing of the queue.
-.It Fl bs
-Use the
-.Tn SMTP
-protocol as described in
-.Tn RFC821
-on standard input and output.
-This flag implies all the operations of the
-.Fl ba
-flag that are compatible with
-.Tn SMTP .
-.It Fl bt
-Run in address test mode.
-This mode reads addresses and shows the steps in parsing;
-it is used for debugging configuration tables.
-.It Fl bv
-Verify names only \- do not try to collect or deliver a message.
-Verify mode is normally used for validating
-users or mailing lists.
-.It Fl C Ns Ar file
-Use alternate configuration file.
-.Nm Sendmail
-refuses to run as root if an alternate configuration file is specified.
-.It Fl d Ns Ar X
-Set debugging value to
-.Ar X .
-.ne 1i
-.It Fl F Ns Ar fullname
-Set the full name of the sender.
-.It Fl f Ns Ar name
-Sets the name of the ``from'' person
-(i.e., the sender of the mail).
-.Fl f
-can only be used
-by ``trusted'' users
-(normally
-.Em root ,
-.Em daemon ,
-and
-.Em network )
-or if the person you are trying to become
-is the same as the person you are.
-.It Fl h Ns Ar N
-Set the hop count to
-.Ar N .
-The hop count is incremented every time the mail is
-processed.
-When it reaches a limit,
-the mail is returned with an error message,
-the victim of an aliasing loop.
-If not specified,
-``Received:'' lines in the message are counted.
-.It Fl i
-Ignore dots alone on lines by themselves in incoming messages.
-This should be set if you are reading data from a file.
-.It Fl N Ar dsn
-Set delivery status notification conditions to
-.Ar dsn,
-which can be
-.Ql never
-for no notifications
-or a comma separated list of the values
-.Ql failure
-to be notified if delivery failed,
-.Ql delay
-to be notified if delivery is delayed, and
-.Ql success
-to be notified when the message is successfully delivered.
-.It Fl n
-Don't do aliasing.
-.It Fl O Ar option Ns = Ns Em value
-Set option
-.Ar option
-to the specified
-.Em value .
-This form uses long names.
-See below for more details.
-.It Fl o Ns Ar x Em value
-Set option
-.Ar x
-to the specified
-.Em value .
-This form uses single character names only.
-The short names are not described in this manual page;
-see the
-.%T "Sendmail Installation and Operation Guide"
-for details.
-.It Fl p Ns Ar protocol
-Set the name of the protocol used to receive the message.
-This can be a simple protocol name such as ``UUCP''
-or a protocol and hostname, such as ``UUCP:ucbvax''.
-.It Fl q Ns Bq Ar time
-Processed saved messages in the queue at given intervals.
-If
-.Ar time
-is omitted,
-process the queue once.
-.Xr Time
-is given as a tagged number,
-with
-.Ql s
-being seconds,
-.Ql m
-being minutes,
-.Ql h
-being hours,
-.Ql d
-being days,
-and
-.Ql w
-being weeks.
-For example,
-.Ql \-q1h30m
-or
-.Ql \-q90m
-would both set the timeout to one hour thirty minutes.
-If
-.Ar time
-is specified,
-.Nm sendmail
-will run in background.
-This option can be used safely with
-.Fl bd .
-.It Fl qI Ns Ar substr
-Limit processed jobs to those containing
-.Ar substr
-as a substring of the queue id.
-.It Fl qR Ns Ar substr
-Limit processed jobs to those containing
-.Ar substr
-as a substring of one of the recipients.
-.It Fl qS Ns Ar substr
-Limit processed jobs to those containing
-.Ar substr
-as a substring of the sender.
-.It Fl R Ar return
-Set the amount of the message to be returned
-if the message bounces.
-The
-.Ar return
-parameter can be
-.Ql full
-to return the entire message or
-.Ql hdrs
-to return only the headers.
-.It Fl r Ns Ar name
-An alternate and obsolete form of the
-.Fl f
-flag.
-.It Fl t
-Read message for recipients.
-To:, Cc:, and Bcc: lines will be scanned for recipient addresses.
-The Bcc: line will be deleted before transmission.
-.It Fl U
-Initial (user) submission.
-This should
-.Em always
-be set when called from a user agent such as
-.Nm Mail
-or
-.Nm exmh
-and
-.Em never
-be set when called by a network delivery agent such as
-.Nm rmail .
-.It Fl V Ar envid
-Set the original envelope id.
-This is propagated across SMTP to servers that support DSNs
-and is returned in DSN-compliant error messages.
-.It Fl v
-Go into verbose mode.
-Alias expansions will be announced, etc.
-.It Fl X Ar logfile
-Log all traffic in and out of mailers in the indicated log file.
-This should only be used as a last resort
-for debugging mailer bugs.
-It will log a lot of data very quickly.
-.It Fl -
-Stop processing command flags and use the rest of the arguments
-as addresses.
-.El
-.Ss Options
-There are also a number of processing options that may be set.
-Normally these will only be used by a system administrator.
-Options may be set either on the command line
-using the
-.Fl o
-flag (for short names),
-the
-.Fl O
-flag (for long names),
-or in the configuration file.
-This is a partial list limited to those options that are likely to be useful
-on the command line
-and only shows the long names;
-for a complete list (and details), consult the
-.%T "Sendmail Installation and Operation Guide" .
-The options are:
-.Bl -tag -width Fl
-.It Li AliasFile= Ns Ar file
-Use alternate alias file.
-.It Li HoldExpensive
-On mailers that are considered ``expensive'' to connect to,
-don't initiate immediate connection.
-This requires queueing.
-.It Li CheckpointInterval= Ns Ar N
-Checkpoint the queue file after every
-.Ar N
-successful deliveries (default 10).
-This avoids excessive duplicate deliveries
-when sending to long mailing lists
-interrupted by system crashes.
-.ne 1i
-.It Li DeliveryMode= Ns Ar x
-Set the delivery mode to
-.Ar x .
-Delivery modes are
-.Ql i
-for interactive (synchronous) delivery,
-.Ql b
-for background (asynchronous) delivery,
-.Ql q
-for queue only \- i.e.,
-actual delivery is done the next time the queue is run, and
-.Ql d
-for deferred \- the same as
-.Ql q
-except that database lookups (notably DNS and NIS lookups) are avoided.
-.It Li ErrorMode= Ns Ar x
-Set error processing to mode
-.Ar x .
-Valid modes are
-.Ql m
-to mail back the error message,
-.Ql w
-to ``write'' back the error message
-(or mail it back if the sender is not logged in),
-.Ql p
-to print the errors on the terminal
-(default),
-.Ql q
-to throw away error messages
-(only exit status is returned),
-and
-.Ql e
-to do special processing for the BerkNet.
-If the text of the message is not mailed back
-by
-modes
-.Ql m
-or
-.Ql w
-and if the sender is local to this machine,
-a copy of the message is appended to the file
-.Pa dead.letter
-in the sender's home directory.
-.It Li SaveFromLine
-Save
-.Tn UNIX Ns \-style
-From lines at the front of messages.
-.It Li MaxHopCount= Ar N
-The maximum number of times a message is allowed to ``hop''
-before we decide it is in a loop.
-.It Li IgnoreDots
-Do not take dots on a line by themselves
-as a message terminator.
-.It Li SendMimeErrors
-Send error messages in MIME format.
-If not set, the DSN (Delivery Status Notification) SMTP extension
-is disabled.
-.It Li ConnectionCacheTimeout= Ns Ar timeout
-Set connection cache timeout.
-.It Li ConnectionCacheSize= Ns Ar N
-Set connection cache size.
-.It Li LogLevel= Ns Ar n
-The log level.
-.It Li MeToo
-Send to ``me'' (the sender) also if I am in an alias expansion.
-.It Li CheckAliases
-Validate the right hand side of aliases during a
-.Xr newaliases 1
-command.
-.It Li OldStyleHeaders
-If set, this message may have
-old style headers.
-If not set,
-this message is guaranteed to have new style headers
-(i.e., commas instead of spaces between addresses).
-If set, an adaptive algorithm is used that will correctly
-determine the header format in most cases.
-.It Li QueueDirectory= Ns Ar queuedir
-Select the directory in which to queue messages.
-.It Li StatusFile= Ns Ar file
-Save statistics in the named file.
-.It Li Timeout.queuereturn= Ns Ar time
-Set the timeout on undelivered messages in the queue to the specified time.
-After delivery has failed
-(e.g., because of a host being down)
-for this amount of time,
-failed messages will be returned to the sender.
-The default is five days.
-.It Li UserDatabaseSpec= Ns Ar userdatabase
-If set, a user database is consulted to get forwarding information.
-You can consider this an adjunct to the aliasing mechanism,
-except that the database is intended to be distributed;
-aliases are local to a particular host.
-This may not be available if your sendmail does not have the
-.Dv USERDB
-option compiled in.
-.It Li ForkEachJob
-Fork each job during queue runs.
-May be convenient on memory-poor machines.
-.It Li SevenBitInput
-Strip incoming messages to seven bits.
-.It Li EightBitMode= Ns Ar mode
-Set the handling of eight bit input to seven bit destinations to
-.Ar mode :
-.Li m
-(mimefy) will convert to seven-bit MIME format,
-.Li p
-(pass) will pass it as eight bits (but violates protocols),
-and
-.Li s
-(strict) will bounce the message.
-.It Li MinQueueAge= Ns Ar timeout
-Sets how long a job must ferment in the queue between attempts to send it.
-.It Li DefaultCharSet= Ns Ar charset
-Sets the default character set used to label 8-bit data
-that is not otherwise labelled.
-.It Li DialDelay= Ns Ar sleeptime
-If opening a connection fails,
-sleep for
-.Ar sleeptime
-seconds and try again.
-Useful on dial-on-demand sites.
-.It Li NoRecipientAction= Ns Ar action
-Set the behaviour when there are no recipient headers (To:, Cc: or Bcc:)
-in the message to
-.Ar action :
-.Li none
-leaves the message unchanged,
-.Li add-to
-adds a To: header with the envelope recipients,
-.Li add-apparently-to
-adds an Apparently-To: header with the envelope recipients,
-.Li add-bcc
-adds an empty Bcc: header, and
-.Li add-to-undisclosed
-adds a header reading
-.Ql "To: undisclosed-recipients:;" .
-.It Li MaxDaemonChildren= Ns Ar N
-Sets the maximum number of children that an incoming SMTP daemon
-will allow to spawn at any time to
-.Ar N .
-.It Li ConnectionRateThrottle= Ns Ar N
-Sets the maximum number of connections per second to the SMTP port to
-.Ar N .
-.El
-.Pp
-In aliases,
-the first character of a name may be
-a vertical bar to cause interpretation of
-the rest of the name as a command
-to pipe the mail to.
-It may be necessary to quote the name
-to keep
-.Nm sendmail
-from suppressing the blanks from between arguments.
-For example, a common alias is:
-.Pp
-.Bd -literal -offset indent -compact
-msgs: "|/usr/bin/msgs -s"
-.Ed
-.Pp
-Aliases may also have the syntax
-.Dq :include: Ns Ar filename
-to ask
-.Xr sendmail
-to read the named file for a list of recipients.
-For example, an alias such as:
-.Pp
-.Bd -literal -offset indent -compact
-poets: ":include:/usr/local/lib/poets.list"
-.Ed
-.Pp
-would read
-.Pa /usr/local/lib/poets.list
-for the list of addresses making up the group.
-.Pp
-.Nm Sendmail
-returns an exit status
-describing what it did.
-The codes are defined in
-.Aq Pa sysexits.h :
-.Bl -tag -width EX_UNAVAILABLE -compact -offset indent
-.It Dv EX_OK
-Successful completion on all addresses.
-.It Dv EX_NOUSER
-User name not recognized.
-.It Dv EX_UNAVAILABLE
-Catchall meaning necessary resources
-were not available.
-.It Dv EX_SYNTAX
-Syntax error in address.
-.It Dv EX_SOFTWARE
-Internal software error,
-including bad arguments.
-.It Dv EX_OSERR
-Temporary operating system error,
-such as
-.Dq cannot fork .
-.It Dv EX_NOHOST
-Host name not recognized.
-.It Dv EX_TEMPFAIL
-Message could not be sent immediately,
-but was queued.
-.El
-.Pp
-If invoked as
-.Nm newaliases ,
-.Nm sendmail
-will rebuild the alias database.
-If invoked as
-.Nm mailq ,
-.Nm sendmail
-will print the contents of the mail queue.
-.Sh FILES
-Except for the file
-.Pa /etc/sendmail.cf
-itself and the daemon process ID file,
-the following pathnames are all specified in
-.Pa /etc/sendmail.cf.
-Thus,
-these values are only approximations.
-.Pp
-.Bl -tag -width /usr/lib/sendmail.fc -compact
-.It Pa /etc/aliases
-raw data for alias names
-.It Pa /etc/aliases.db
-data base of alias names
-.It Pa /etc/sendmail.cf
-configuration file
-.It Pa /etc/sendmail.hf
-help file
-.It Pa /var/log/sendmail.st
-collected statistics
-.It Pa /var/spool/mqueue/*
-temp files
-.El
-.Sh SEE ALSO
-.Xr binmail 1 ,
-.Xr mail 1 ,
-.Xr rmail 1 ,
-.Xr syslog 3 ,
-.Xr aliases 5 ,
-.Xr mailaddr 7 ,
-.Xr rc 8 ;
-.Pp
-DARPA
-Internet Request For Comments
-.%T RFC819 ,
-.%T RFC821 ,
-.%T RFC822 .
-.Rs
-.%T "Sendmail \- An Internetwork Mail Router"
-.%V SMM
-.%N \&No. 9
-.Re
-.Rs
-.%T "Sendmail Installation and Operation Guide"
-.%V SMM
-.%N \&No. 8
-.Re
-.Sh HISTORY
-The
-.Nm
-command appeared in
-.Bx 4.2 .
diff --git a/src/sendmail.h b/src/sendmail.h
deleted file mode 100644
index ff2697e..0000000
--- a/src/sendmail.h
+++ /dev/null
@@ -1,1514 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- *
- * @(#)sendmail.h 8.295 (Berkeley) 1/26/1999
- */
-
-/*
-** SENDMAIL.H -- Global definitions for sendmail.
-*/
-
-# ifdef _DEFINE
-# define EXTERN
-# ifndef lint
-static char SmailSccsId[] = "@(#)sendmail.h 8.295 1/26/1999";
-# endif
-# else /* _DEFINE */
-# define EXTERN extern
-# endif /* _DEFINE */
-
-# include <unistd.h>
-# include <stddef.h>
-# include <stdlib.h>
-# include <stdio.h>
-# include <ctype.h>
-# include <setjmp.h>
-# include <string.h>
-# include <time.h>
-# include <errno.h>
-# ifdef EX_OK
-# undef EX_OK /* for SVr4.2 SMP */
-# endif
-# include <sysexits.h>
-
-# include "conf.h"
-# include "useful.h"
-
-# ifdef LOG
-# include <syslog.h>
-# endif /* LOG */
-
-# if NETINET || NETUNIX || NETISO || NETNS || NETX25
-# include <sys/socket.h>
-# endif
-# if NETUNIX
-# include <sys/un.h>
-# endif
-# if NETINET
-# include <netinet/in.h>
-# endif
-# if NETISO
-# include <netiso/iso.h>
-# endif
-# if NETNS
-# include <netns/ns.h>
-# endif
-# if NETX25
-# include <netccitt/x25.h>
-# endif
-
-#if NAMED_BIND
-# include <arpa/nameser.h>
-# ifdef NOERROR
-# undef NOERROR /* avoid <sys/streams.h> conflict */
-# endif
-#endif
-
-#ifdef HESIOD
-# include <hesiod.h>
-# if !defined(HES_ER_OK) || defined(HESIOD_INTERFACES)
-# define HESIOD_INIT /* support for the new interface */
-EXTERN void *HesiodContext;
-# endif
-#endif
-
-/*
-** Following are "sort of" configuration constants, but they should
-** be pretty solid on most architectures today. They have to be
-** defined after <arpa/nameser.h> because some versions of that
-** file also define them. In all cases, we can't use sizeof because
-** some systems (e.g., Crays) always treat everything as being at
-** least 64 bits.
-*/
-
-#ifndef INADDRSZ
-# define INADDRSZ 4 /* size of an IPv4 address in bytes */
-#endif
-#ifndef INT16SZ
-# define INT16SZ 2 /* size of a 16 bit integer in bytes */
-#endif
-#ifndef INT32SZ
-# define INT32SZ 4 /* size of a 32 bit integer in bytes */
-#endif
-
-
-
-/* forward references for prototypes */
-typedef struct envelope ENVELOPE;
-typedef struct mailer MAILER;
-
-
-/*
-** Data structure for bit maps.
-**
-** Each bit in this map can be referenced by an ascii character.
-** This is 256 possible bits, or 32 8-bit bytes.
-*/
-
-#define BITMAPBYTES 32 /* number of bytes in a bit map */
-#define BYTEBITS 8 /* number of bits in a byte */
-
-/* internal macros */
-#define _BITWORD(bit) ((bit) / (BYTEBITS * sizeof (int)))
-#define _BITBIT(bit) (1 << ((bit) % (BYTEBITS * sizeof (int))))
-
-typedef int BITMAP[BITMAPBYTES / sizeof (int)];
-
-/* test bit number N */
-#define bitnset(bit, map) ((map)[_BITWORD(bit)] & _BITBIT(bit))
-
-/* set bit number N */
-#define setbitn(bit, map) (map)[_BITWORD(bit)] |= _BITBIT(bit)
-
-/* clear bit number N */
-#define clrbitn(bit, map) (map)[_BITWORD(bit)] &= ~_BITBIT(bit)
-
-/* clear an entire bit map */
-#define clrbitmap(map) bzero((char *) map, BITMAPBYTES)
-
-
-/*
-** Utility macros
-*/
-
-/* return number of bytes left in a buffer */
-#define SPACELEFT(buf, ptr) (sizeof buf - ((ptr) - buf))
- /*
-** Address structure.
-** Addresses are stored internally in this structure.
-*/
-
-struct address
-{
- char *q_paddr; /* the printname for the address */
- char *q_user; /* user name */
- char *q_ruser; /* real user name, or NULL if q_user */
- char *q_host; /* host name */
- struct mailer *q_mailer; /* mailer to use */
- u_long q_flags; /* status flags, see below */
- uid_t q_uid; /* user-id of receiver (if known) */
- gid_t q_gid; /* group-id of receiver (if known) */
- char *q_home; /* home dir (local mailer only) */
- char *q_fullname; /* full name if known */
- struct address *q_next; /* chain */
- struct address *q_alias; /* address this results from */
- char *q_owner; /* owner of q_alias */
- struct address *q_tchain; /* temporary use chain */
- char *q_orcpt; /* ORCPT parameter from RCPT TO: line */
- char *q_status; /* status code for DSNs */
- char *q_rstatus; /* remote status message for DSNs */
- time_t q_statdate; /* date of status messages */
- char *q_statmta; /* MTA generating q_rstatus */
- short q_specificity; /* how "specific" this address is */
-};
-
-typedef struct address ADDRESS;
-
-# define QDONTSEND 0x00000001 /* don't send to this address */
-# define QBADADDR 0x00000002 /* this address is verified bad */
-# define QGOODUID 0x00000004 /* the q_uid q_gid fields are good */
-# define QPRIMARY 0x00000008 /* set from RCPT or argv */
-# define QQUEUEUP 0x00000010 /* queue for later transmission */
-# define QSENT 0x00000020 /* has been successfully delivered */
-# define QNOTREMOTE 0x00000040 /* address not for remote forwarding */
-# define QSELFREF 0x00000080 /* this address references itself */
-# define QVERIFIED 0x00000100 /* verified, but not expanded */
-# define QBOGUSSHELL 0x00000400 /* user has no valid shell listed */
-# define QUNSAFEADDR 0x00000800 /* address aquired via unsafe path */
-# define QPINGONSUCCESS 0x00001000 /* give return on successful delivery */
-# define QPINGONFAILURE 0x00002000 /* give return on failure */
-# define QPINGONDELAY 0x00004000 /* give return on message delay */
-# define QHASNOTIFY 0x00008000 /* propogate notify parameter */
-# define QRELAYED 0x00010000 /* DSN: relayed to non-DSN aware sys */
-# define QEXPANDED 0x00020000 /* DSN: undergone list expansion */
-# define QDELIVERED 0x00040000 /* DSN: successful final delivery */
-# define QDELAYED 0x00080000 /* DSN: message delayed */
-# define QTHISPASS 0x40000000 /* temp: address set this pass */
-# define QRCPTOK 0x80000000 /* recipient() processed address */
-
-# define Q_PINGFLAGS (QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY)
-
-# define NULLADDR ((ADDRESS *) NULL)
-
-/* functions */
-extern ADDRESS *parseaddr __P((char *, ADDRESS *, int, int, char **, ENVELOPE *));
-extern ADDRESS *buildaddr __P((char **, ADDRESS *, int, ENVELOPE *));
-extern ADDRESS *recipient __P((ADDRESS *, ADDRESS **, int, ENVELOPE *));
-extern char **prescan __P((char *, int, char[], int, char **, u_char *));
-extern int rewrite __P((char **, int, int, ENVELOPE *));
-extern char *remotename __P((char *, MAILER *, int, int *, ENVELOPE *));
-extern ADDRESS *getctladdr __P((ADDRESS *));
-extern bool sameaddr __P((ADDRESS *, ADDRESS *));
-extern bool emptyaddr __P((ADDRESS *));
-extern void printaddr __P((ADDRESS *, bool));
-extern void cataddr __P((char **, char **, char *, int, int));
-extern int sendtolist __P((char *, ADDRESS *, ADDRESS **, int, ENVELOPE *));
- /*
-** Mailer definition structure.
-** Every mailer known to the system is declared in this
-** structure. It defines the pathname of the mailer, some
-** flags associated with it, and the argument vector to
-** pass to it. The flags are defined in conf.c
-**
-** The argument vector is expanded before actual use. All
-** words except the first are passed through the macro
-** processor.
-*/
-
-struct mailer
-{
- char *m_name; /* symbolic name of this mailer */
- char *m_mailer; /* pathname of the mailer to use */
- char *m_mtatype; /* type of this MTA */
- char *m_addrtype; /* type for addresses */
- char *m_diagtype; /* type for diagnostics */
- BITMAP m_flags; /* status flags, see below */
- short m_mno; /* mailer number internally */
- short m_nice; /* niceness to run at (mostly for prog) */
- char **m_argv; /* template argument vector */
- short m_sh_rwset; /* rewrite set: sender header addresses */
- short m_se_rwset; /* rewrite set: sender envelope addresses */
- short m_rh_rwset; /* rewrite set: recipient header addresses */
- short m_re_rwset; /* rewrite set: recipient envelope addresses */
- char *m_eol; /* end of line string */
- long m_maxsize; /* size limit on message to this mailer */
- int m_linelimit; /* max # characters per line */
- char *m_execdir; /* directory to chdir to before execv */
- uid_t m_uid; /* UID to run as */
- gid_t m_gid; /* GID to run as */
- char *m_defcharset; /* default character set */
-};
-
-/* bits for m_flags */
-# define M_ESMTP 'a' /* run Extended SMTP protocol */
-# define M_ALIASABLE 'A' /* user can be LHS of an alias */
-# define M_BLANKEND 'b' /* ensure blank line at end of message */
-# define M_NOCOMMENT 'c' /* don't include comment part of address */
-# define M_CANONICAL 'C' /* make addresses canonical "u@dom" */
-# define M_NOBRACKET 'd' /* never angle bracket envelope route-addrs */
- /* 'D' CF: include Date: */
-# define M_EXPENSIVE 'e' /* it costs to use this mailer.... */
-# define M_ESCFROM 'E' /* escape From lines to >From */
-# define M_FOPT 'f' /* mailer takes picky -f flag */
- /* 'F' CF: include From: or Resent-From: */
-# define M_NO_NULL_FROM 'g' /* sender of errors should be $g */
-# define M_HST_UPPER 'h' /* preserve host case distinction */
-# define M_PREHEAD 'H' /* MAIL11V3: preview headers */
-# define M_UDBENVELOPE 'i' /* do udbsender rewriting on envelope */
-# define M_INTERNAL 'I' /* SMTP to another sendmail site */
-# define M_UDBRECIPIENT 'j' /* do udbsender rewriting on recipient lines */
-# define M_NOLOOPCHECK 'k' /* don't check for loops in HELO command */
-# define M_CHUNKING 'K' /* CHUNKING: reserved for future use */
-# define M_LOCALMAILER 'l' /* delivery is to this host */
-# define M_LIMITS 'L' /* must enforce SMTP line limits */
-# define M_MUSER 'm' /* can handle multiple users at once */
- /* 'M' CF: include Message-Id: */
-# define M_NHDR 'n' /* don't insert From line */
-# define M_MANYSTATUS 'N' /* MAIL11V3: DATA returns multi-status */
-# define M_RUNASRCPT 'o' /* always run mailer as recipient */
-# define M_FROMPATH 'p' /* use reverse-path in MAIL FROM: */
- /* 'P' CF: include Return-Path: */
-# define M_VRFY250 'q' /* VRFY command returns 250 instead of 252 */
-# define M_ROPT 'r' /* mailer takes picky -r flag */
-# define M_SECURE_PORT 'R' /* try to send on a reserved TCP port */
-# define M_STRIPQ 's' /* strip quote chars from user/host */
-# define M_SPECIFIC_UID 'S' /* run as specific uid/gid */
-# define M_USR_UPPER 'u' /* preserve user case distinction */
-# define M_UGLYUUCP 'U' /* this wants an ugly UUCP from line */
-# define M_CONTENT_LEN 'v' /* add Content-Length: header (SVr4) */
- /* 'V' UIUC: !-relativize all addresses */
-# define M_HASPWENT 'w' /* check for /etc/passwd entry */
- /* 'x' CF: include Full-Name: */
-# define M_XDOT 'X' /* use hidden-dot algorithm */
-# define M_LMTP 'z' /* run Local Mail Transport Protocol */
-# define M_NOMX '0' /* turn off MX lookups */
-# define M_NONULLS '1' /* don't send null bytes */
-# define M_EBCDIC '3' /* extend Q-P encoding for EBCDIC */
-# define M_TRYRULESET5 '5' /* use ruleset 5 after local aliasing */
-# define M_7BITHDRS '6' /* strip headers to 7 bits even in 8 bit path */
-# define M_7BITS '7' /* use 7-bit path */
-# define M_8BITS '8' /* force "just send 8" behaviour */
-# define M_MAKE8BIT '9' /* convert 7 -> 8 bit if appropriate */
-# define M_CHECKINCLUDE ':' /* check for :include: files */
-# define M_CHECKPROG '|' /* check for |program addresses */
-# define M_CHECKFILE '/' /* check for /file addresses */
-# define M_CHECKUDB '@' /* user can be user database key */
-# define M_CHECKHDIR '~' /* SGI: check for valid home directory */
-
-EXTERN MAILER *Mailer[MAXMAILERS+1];
-
-EXTERN MAILER *LocalMailer; /* ptr to local mailer */
-EXTERN MAILER *ProgMailer; /* ptr to program mailer */
-EXTERN MAILER *FileMailer; /* ptr to *file* mailer */
-EXTERN MAILER *InclMailer; /* ptr to *include* mailer */
- /*
-** Information about currently open connections to mailers, or to
-** hosts that we have looked up recently.
-*/
-
-# define MCI struct mailer_con_info
-
-MCI
-{
- short mci_flags; /* flag bits, see below */
- short mci_errno; /* error number on last connection */
- short mci_herrno; /* h_errno from last DNS lookup */
- short mci_exitstat; /* exit status from last connection */
- short mci_state; /* SMTP state */
- off_t mci_contentlen; /* body length for Content-Length: */
- long mci_maxsize; /* max size this server will accept */
- FILE *mci_in; /* input side of connection */
- FILE *mci_out; /* output side of connection */
- pid_t mci_pid; /* process id of subordinate proc */
- char *mci_phase; /* SMTP phase string */
- struct mailer *mci_mailer; /* ptr to the mailer for this conn */
- char *mci_host; /* host name */
- char *mci_status; /* DSN status to be copied to addrs */
- char *mci_rstatus; /* SMTP status to be copied to addrs */
- time_t mci_lastuse; /* last usage time */
- FILE *mci_statfile; /* long term status file */
-};
-
-
-/* flag bits */
-#define MCIF_VALID 0x0001 /* this entry is valid */
-#define MCIF_TEMP 0x0002 /* don't cache this connection */
-#define MCIF_CACHED 0x0004 /* currently in open cache */
-#define MCIF_ESMTP 0x0008 /* this host speaks ESMTP */
-#define MCIF_EXPN 0x0010 /* EXPN command supported */
-#define MCIF_SIZE 0x0020 /* SIZE option supported */
-#define MCIF_8BITMIME 0x0040 /* BODY=8BITMIME supported */
-#define MCIF_7BIT 0x0080 /* strip this message to 7 bits */
-#define MCIF_MULTSTAT 0x0100 /* MAIL11V3: handles MULT status */
-#define MCIF_INHEADER 0x0200 /* currently outputing header */
-#define MCIF_CVT8TO7 0x0400 /* convert from 8 to 7 bits */
-#define MCIF_DSN 0x0800 /* DSN extension supported */
-#define MCIF_8BITOK 0x1000 /* OK to send 8 bit characters */
-#define MCIF_CVT7TO8 0x2000 /* convert from 7 to 8 bits */
-#define MCIF_INMIME 0x4000 /* currently reading MIME header */
-
-/* states */
-#define MCIS_CLOSED 0 /* no traffic on this connection */
-#define MCIS_OPENING 1 /* sending initial protocol */
-#define MCIS_OPEN 2 /* open, initial protocol sent */
-#define MCIS_ACTIVE 3 /* message being sent */
-#define MCIS_QUITING 4 /* running quit protocol */
-#define MCIS_SSD 5 /* service shutting down */
-#define MCIS_ERROR 6 /* I/O error on connection */
-
-/* functions */
-extern MCI *mci_get __P((char *, MAILER *));
-extern void mci_cache __P((MCI *));
-extern void mci_flush __P((bool, MCI *));
-extern void mci_dump __P((MCI *, bool));
-extern void mci_dump_all __P((bool));
-extern MCI **mci_scan __P((MCI *));
-extern int mci_traverse_persistent __P((int (*)(), char *));
-extern int mci_print_persistent __P((char *, char *));
-extern int mci_purge_persistent __P((char *, char *));
-extern int mci_lock_host __P((MCI *));
-extern void mci_unlock_host __P((MCI *));
-extern int mci_lock_host_statfile __P((MCI *));
-extern void mci_store_persistent __P((MCI *));
-extern int mci_read_persistent __P((FILE *, MCI *));
- /*
-** Header structure.
-** This structure is used internally to store header items.
-*/
-
-struct header
-{
- char *h_field; /* the name of the field */
- char *h_value; /* the value of that field */
- struct header *h_link; /* the next header */
- u_short h_flags; /* status bits, see below */
- BITMAP h_mflags; /* m_flags bits needed */
-};
-
-typedef struct header HDR;
-
-/*
-** Header information structure.
-** Defined in conf.c, this struct declares the header fields
-** that have some magic meaning.
-*/
-
-struct hdrinfo
-{
- char *hi_field; /* the name of the field */
- u_short hi_flags; /* status bits, see below */
- char *hi_ruleset; /* validity check ruleset */
-};
-
-extern struct hdrinfo HdrInfo[];
-
-/* bits for h_flags and hi_flags */
-# define H_EOH 0x0001 /* this field terminates header */
-# define H_RCPT 0x0002 /* contains recipient addresses */
-# define H_DEFAULT 0x0004 /* if another value is found, drop this */
-# define H_RESENT 0x0008 /* this address is a "Resent-..." address */
-# define H_CHECK 0x0010 /* check h_mflags against m_flags */
-# define H_ACHECK 0x0020 /* ditto, but always (not just default) */
-# define H_FORCE 0x0040 /* force this field, even if default */
-# define H_TRACE 0x0080 /* this field contains trace information */
-# define H_FROM 0x0100 /* this is a from-type field */
-# define H_VALID 0x0200 /* this field has a validated value */
-# define H_RECEIPTTO 0x0400 /* this field has return receipt info */
-# define H_ERRORSTO 0x0800 /* this field has error address info */
-# define H_CTE 0x1000 /* this field is a content-transfer-encoding */
-# define H_CTYPE 0x2000 /* this is a content-type field */
-# define H_BCC 0x4000 /* Bcc: header: strip value or delete */
-# define H_ENCODABLE 0x8000 /* field can be RFC 1522 encoded */
-
-/* functions */
-extern void addheader __P((char *, char *, HDR **));
-extern char *hvalue __P((char *, HDR *));
-extern void commaize __P((HDR *, char *, bool, MCI *, ENVELOPE *));
-extern void put_vanilla_header __P((HDR *, char *, MCI *));
-extern void eatheader __P((ENVELOPE *, bool));
-extern int chompheader __P((char *, bool, HDR **, ENVELOPE *));
- /*
-** Envelope structure.
-** This structure defines the message itself. There is usually
-** only one of these -- for the message that we originally read
-** and which is our primary interest -- but other envelopes can
-** be generated during processing. For example, error messages
-** will have their own envelope.
-*/
-
-struct envelope
-{
- HDR *e_header; /* head of header list */
- long e_msgpriority; /* adjusted priority of this message */
- time_t e_ctime; /* time message appeared in the queue */
- char *e_to; /* the target person */
- ADDRESS e_from; /* the person it is from */
- char *e_sender; /* e_from.q_paddr w comments stripped */
- char **e_fromdomain; /* the domain part of the sender */
- ADDRESS *e_sendqueue; /* list of message recipients */
- ADDRESS *e_errorqueue; /* the queue for error responses */
- long e_msgsize; /* size of the message in bytes */
- long e_flags; /* flags, see below */
- int e_nrcpts; /* number of recipients */
- short e_class; /* msg class (priority, junk, etc.) */
- short e_hopcount; /* number of times processed */
- short e_nsent; /* number of sends since checkpoint */
- short e_sendmode; /* message send mode */
- short e_errormode; /* error return mode */
- short e_timeoutclass; /* message timeout class */
- void (*e_puthdr)__P((MCI *, HDR *, ENVELOPE *, int));
- /* function to put header of message */
- void (*e_putbody)__P((MCI *, ENVELOPE *, char *));
- /* function to put body of message */
- struct envelope *e_parent; /* the message this one encloses */
- struct envelope *e_sibling; /* the next envelope of interest */
- char *e_bodytype; /* type of message body */
- FILE *e_dfp; /* temporary file */
- char *e_id; /* code for this entry in queue */
- FILE *e_xfp; /* transcript file */
- FILE *e_lockfp; /* the lock file for this message */
- char *e_message; /* error message */
- char *e_statmsg; /* stat msg (changes per delivery) */
- char *e_msgboundary; /* MIME-style message part boundary */
- char *e_origrcpt; /* original recipient (one only) */
- char *e_envid; /* envelope id from MAIL FROM: line */
- char *e_status; /* DSN status for this message */
- time_t e_dtime; /* time of last delivery attempt */
- int e_ntries; /* number of delivery attempts */
- dev_t e_dfdev; /* df file's device, for crash recov */
- ino_t e_dfino; /* df file's ino, for crash recovery */
- char *e_macro[256]; /* macro definitions */
-};
-
-/* values for e_flags */
-#define EF_OLDSTYLE 0x0000001 /* use spaces (not commas) in hdrs */
-#define EF_INQUEUE 0x0000002 /* this message is fully queued */
-#define EF_NO_BODY_RETN 0x0000004 /* omit message body on error */
-#define EF_CLRQUEUE 0x0000008 /* disk copy is no longer needed */
-#define EF_SENDRECEIPT 0x0000010 /* send a return receipt */
-#define EF_FATALERRS 0x0000020 /* fatal errors occured */
-#define EF_DELETE_BCC 0x0000040 /* delete Bcc: headers entirely */
-#define EF_RESPONSE 0x0000080 /* this is an error or return receipt */
-#define EF_RESENT 0x0000100 /* this message is being forwarded */
-#define EF_VRFYONLY 0x0000200 /* verify only (don't expand aliases) */
-#define EF_WARNING 0x0000400 /* warning message has been sent */
-#define EF_QUEUERUN 0x0000800 /* this envelope is from queue */
-#define EF_GLOBALERRS 0x0001000 /* treat errors as global */
-#define EF_PM_NOTIFY 0x0002000 /* send return mail to postmaster */
-#define EF_METOO 0x0004000 /* send to me too */
-#define EF_LOGSENDER 0x0008000 /* need to log the sender */
-#define EF_NORECEIPT 0x0010000 /* suppress all return-receipts */
-#define EF_HAS8BIT 0x0020000 /* at least one 8-bit char in body */
-#define EF_NL_NOT_EOL 0x0040000 /* don't accept raw NL as EOLine */
-#define EF_CRLF_NOT_EOL 0x0080000 /* don't accept CR-LF as EOLine */
-#define EF_RET_PARAM 0x0100000 /* RCPT command had RET argument */
-#define EF_HAS_DF 0x0200000 /* set when df file is instantiated */
-#define EF_IS_MIME 0x0400000 /* really is a MIME message */
-#define EF_DONT_MIME 0x0800000 /* never MIME this message */
-#define EF_DISCARD 0x1000000 /* discard the message */
-
-EXTERN ENVELOPE *CurEnv; /* envelope currently being processed */
-
-/* functions */
-extern ENVELOPE *newenvelope __P((ENVELOPE *, ENVELOPE *));
-extern void dropenvelope __P((ENVELOPE *, bool));
-extern void clearenvelope __P((ENVELOPE *, bool));
-
-extern void putheader __P((MCI *, HDR *, ENVELOPE *, int));
-extern void putbody __P((MCI *, ENVELOPE *, char *));
- /*
-** Message priority classes.
-**
-** The message class is read directly from the Priority: header
-** field in the message.
-**
-** CurEnv->e_msgpriority is the number of bytes in the message plus
-** the creation time (so that jobs ``tend'' to be ordered correctly),
-** adjusted by the message class, the number of recipients, and the
-** amount of time the message has been sitting around. This number
-** is used to order the queue. Higher values mean LOWER priority.
-**
-** Each priority class point is worth WkClassFact priority points;
-** each recipient is worth WkRecipFact priority points. Each time
-** we reprocess a message the priority is adjusted by WkTimeFact.
-** WkTimeFact should normally decrease the priority so that jobs
-** that have historically failed will be run later; thanks go to
-** Jay Lepreau at Utah for pointing out the error in my thinking.
-**
-** The "class" is this number, unadjusted by the age or size of
-** this message. Classes with negative representations will have
-** error messages thrown away if they are not local.
-*/
-
-struct priority
-{
- char *pri_name; /* external name of priority */
- int pri_val; /* internal value for same */
-};
-
-EXTERN struct priority Priorities[MAXPRIORITIES];
-EXTERN int NumPriorities; /* pointer into Priorities */
- /*
-** Rewrite rules.
-*/
-
-struct rewrite
-{
- char **r_lhs; /* pattern match */
- char **r_rhs; /* substitution value */
- struct rewrite *r_next;/* next in chain */
-};
-
-EXTERN struct rewrite *RewriteRules[MAXRWSETS];
-
-/*
-** Special characters in rewriting rules.
-** These are used internally only.
-** The COND* rules are actually used in macros rather than in
-** rewriting rules, but are given here because they
-** cannot conflict.
-*/
-
-/* left hand side items */
-# define MATCHZANY ((u_char)0220) /* match zero or more tokens */
-# define MATCHANY ((u_char)0221) /* match one or more tokens */
-# define MATCHONE ((u_char)0222) /* match exactly one token */
-# define MATCHCLASS ((u_char)0223) /* match one token in a class */
-# define MATCHNCLASS ((u_char)0224) /* match anything not in class */
-# define MATCHREPL ((u_char)0225) /* replacement on RHS for above */
-
-/* right hand side items */
-# define CANONNET ((u_char)0226) /* canonical net, next token */
-# define CANONHOST ((u_char)0227) /* canonical host, next token */
-# define CANONUSER ((u_char)0230) /* canonical user, next N tokens */
-# define CALLSUBR ((u_char)0231) /* call another rewriting set */
-
-/* conditionals in macros */
-# define CONDIF ((u_char)0232) /* conditional if-then */
-# define CONDELSE ((u_char)0233) /* conditional else */
-# define CONDFI ((u_char)0234) /* conditional fi */
-
-/* bracket characters for host name lookup */
-# define HOSTBEGIN ((u_char)0235) /* hostname lookup begin */
-# define HOSTEND ((u_char)0236) /* hostname lookup end */
-
-/* bracket characters for generalized lookup */
-# define LOOKUPBEGIN ((u_char)0205) /* generalized lookup begin */
-# define LOOKUPEND ((u_char)0206) /* generalized lookup end */
-
-/* macro substitution character */
-# define MACROEXPAND ((u_char)0201) /* macro expansion */
-# define MACRODEXPAND ((u_char)0202) /* deferred macro expansion */
-
-/* to make the code clearer */
-# define MATCHZERO CANONHOST
-
-/* external <==> internal mapping table */
-struct metamac
-{
- char metaname; /* external code (after $) */
- u_char metaval; /* internal code (as above) */
-};
-
-/* values for macros with external names only */
-# define MID_OPMODE 0202 /* operation mode */
-
-/* functions */
-extern void expand __P((char *, char *, size_t, ENVELOPE *));
-extern void define __P((int, char *, ENVELOPE *));
-extern char *macvalue __P((int, ENVELOPE *));
-extern char *macname __P((int));
-extern int macid __P((char *, char **));
- /*
-** Name canonification short circuit.
-**
-** If the name server for a host is down, the process of trying to
-** canonify the name can hang. This is similar to (but alas, not
-** identical to) looking up the name for delivery. This stab type
-** caches the result of the name server lookup so we don't hang
-** multiple times.
-*/
-
-#define NAMECANON struct _namecanon
-
-NAMECANON
-{
- short nc_errno; /* cached errno */
- short nc_herrno; /* cached h_errno */
- short nc_stat; /* cached exit status code */
- short nc_flags; /* flag bits */
- char *nc_cname; /* the canonical name */
-};
-
-/* values for nc_flags */
-#define NCF_VALID 0x0001 /* entry valid */
- /*
-** Mapping functions
-**
-** These allow arbitrary mappings in the config file. The idea
-** (albeit not the implementation) comes from IDA sendmail.
-*/
-
-# define MAPCLASS struct _mapclass
-# define MAP struct _map
-# define MAXMAPACTIONS 3 /* size of map_actions array */
-
-
-/*
-** An actual map.
-*/
-
-MAP
-{
- MAPCLASS *map_class; /* the class of this map */
- char *map_mname; /* name of this map */
- long map_mflags; /* flags, see below */
- char *map_file; /* the (nominal) filename */
- ARBPTR_T map_db1; /* the open database ptr */
- ARBPTR_T map_db2; /* an "extra" database pointer */
- char *map_keycolnm; /* key column name */
- char *map_valcolnm; /* value column name */
- u_char map_keycolno; /* key column number */
- u_char map_valcolno; /* value column number */
- char map_coldelim; /* column delimiter */
- char *map_app; /* to append to successful matches */
- char *map_tapp; /* to append to "tempfail" matches */
- char *map_domain; /* the (nominal) NIS domain */
- char *map_rebuild; /* program to run to do auto-rebuild */
- time_t map_mtime; /* last database modification time */
- pid_t map_pid; /* PID of process which opened map */
- int map_lockfd; /* auxiliary lock file descriptor */
- short map_specificity; /* specificity of aliases */
- MAP *map_stack[MAXMAPSTACK]; /* list for stacked maps */
- short map_return[MAXMAPACTIONS]; /* return bitmaps for stacked maps */
-};
-
-/* bit values for map_mflags */
-# define MF_VALID 0x00000001 /* this entry is valid */
-# define MF_INCLNULL 0x00000002 /* include null byte in key */
-# define MF_OPTIONAL 0x00000004 /* don't complain if map not found */
-# define MF_NOFOLDCASE 0x00000008 /* don't fold case in keys */
-# define MF_MATCHONLY 0x00000010 /* don't use the map value */
-# define MF_OPEN 0x00000020 /* this entry is open */
-# define MF_WRITABLE 0x00000040 /* open for writing */
-# define MF_ALIAS 0x00000080 /* this is an alias file */
-# define MF_TRY0NULL 0x00000100 /* try with no null byte */
-# define MF_TRY1NULL 0x00000200 /* try with the null byte */
-# define MF_LOCKED 0x00000400 /* this map is currently locked */
-# define MF_ALIASWAIT 0x00000800 /* alias map in aliaswait state */
-# define MF_IMPL_HASH 0x00001000 /* implicit: underlying hash database */
-# define MF_IMPL_NDBM 0x00002000 /* implicit: underlying NDBM database */
-# define MF_UNSAFEDB 0x00004000 /* this map is world writable */
-# define MF_APPEND 0x00008000 /* append new entry on rebuiled */
-# define MF_KEEPQUOTES 0x00010000 /* don't dequote key before lookup */
-# define MF_NODEFER 0x00020000 /* don't defer if map lookup fails */
-# define MF_REGEX_NOT 0x00040000 /* regular expression negation */
-
-/* indices for map_actions */
-# define MA_NOTFOUND 0 /* member map returned "not found" */
-# define MA_UNAVAIL 1 /* member map is not available */
-# define MA_TRYAGAIN 2 /* member map returns temp failure */
-
-/*
-** The class of a map -- essentially the functions to call
-*/
-
-MAPCLASS
-{
- char *map_cname; /* name of this map class */
- char *map_ext; /* extension for database file */
- short map_cflags; /* flag bits, see below */
- bool (*map_parse)__P((MAP *, char *));
- /* argument parsing function */
- char *(*map_lookup)__P((MAP *, char *, char **, int *));
- /* lookup function */
- void (*map_store)__P((MAP *, char *, char *));
- /* store function */
- bool (*map_open)__P((MAP *, int));
- /* open function */
- void (*map_close)__P((MAP *));
- /* close function */
-};
-
-/* bit values for map_cflags */
-#define MCF_ALIASOK 0x0001 /* can be used for aliases */
-#define MCF_ALIASONLY 0x0002 /* usable only for aliases */
-#define MCF_REBUILDABLE 0x0004 /* can rebuild alias files */
-#define MCF_OPTFILE 0x0008 /* file name is optional */
-
-/* functions */
-extern char *map_rewrite __P((MAP *, const char *, size_t, char **));
-extern MAP *makemapentry __P((char *));
-extern void initmaps __P((bool, ENVELOPE *));
- /*
-** Symbol table definitions
-*/
-
-struct symtab
-{
- char *s_name; /* name to be entered */
- short s_type; /* general type (see below) */
- short s_len; /* length of this entry */
- struct symtab *s_next; /* pointer to next in chain */
- union
- {
- BITMAP sv_class; /* bit-map of word classes */
- ADDRESS *sv_addr; /* pointer to address header */
- MAILER *sv_mailer; /* pointer to mailer */
- char *sv_alias; /* alias */
- MAPCLASS sv_mapclass; /* mapping function class */
- MAP sv_map; /* mapping function */
- char *sv_hostsig; /* host signature */
- MCI sv_mci; /* mailer connection info */
- NAMECANON sv_namecanon; /* canonical name cache */
- int sv_macro; /* macro name => id mapping */
- int sv_ruleset; /* ruleset index */
- struct hdrinfo sv_header; /* header metainfo */
- char *sv_service[MAXMAPSTACK]; /* service switch */
- } s_value;
-};
-
-typedef struct symtab STAB;
-
-/* symbol types */
-# define ST_UNDEF 0 /* undefined type */
-# define ST_CLASS 1 /* class map */
-# define ST_ADDRESS 2 /* an address in parsed format */
-# define ST_MAILER 3 /* a mailer header */
-# define ST_ALIAS 4 /* an alias */
-# define ST_MAPCLASS 5 /* mapping function class */
-# define ST_MAP 6 /* mapping function */
-# define ST_HOSTSIG 7 /* host signature */
-# define ST_NAMECANON 8 /* cached canonical name */
-# define ST_MACRO 9 /* macro name to id mapping */
-# define ST_RULESET 10 /* ruleset index */
-# define ST_SERVICE 11 /* service switch entry */
-# define ST_HEADER 12 /* special header flags */
-# define ST_MCI 16 /* mailer connection info (offset) */
-
-# define s_class s_value.sv_class
-# define s_address s_value.sv_addr
-# define s_mailer s_value.sv_mailer
-# define s_alias s_value.sv_alias
-# define s_mci s_value.sv_mci
-# define s_mapclass s_value.sv_mapclass
-# define s_hostsig s_value.sv_hostsig
-# define s_map s_value.sv_map
-# define s_namecanon s_value.sv_namecanon
-# define s_macro s_value.sv_macro
-# define s_ruleset s_value.sv_ruleset
-# define s_service s_value.sv_service
-# define s_header s_value.sv_header
-
-extern STAB *stab __P((char *, int, int));
-extern void stabapply __P((void (*)(STAB *, int), int));
-
-/* opcodes to stab */
-# define ST_FIND 0 /* find entry */
-# define ST_ENTER 1 /* enter if not there */
- /*
-** STRUCT EVENT -- event queue.
-**
-** Maintained in sorted order.
-**
-** We store the pid of the process that set this event to insure
-** that when we fork we will not take events intended for the parent.
-*/
-
-struct event
-{
- time_t ev_time; /* time of the function call */
- void (*ev_func)__P((int));
- /* function to call */
- int ev_arg; /* argument to ev_func */
- int ev_pid; /* pid that set this event */
- struct event *ev_link; /* link to next item */
-};
-
-typedef struct event EVENT;
-
-EXTERN EVENT *EventQueue; /* head of event queue */
-
-/* functions */
-extern EVENT *setevent __P((time_t, void(*)(), int));
-extern void clrevent __P((EVENT *));
- /*
-** Operation, send, error, and MIME modes
-**
-** The operation mode describes the basic operation of sendmail.
-** This can be set from the command line, and is "send mail" by
-** default.
-**
-** The send mode tells how to send mail. It can be set in the
-** configuration file. It's setting determines how quickly the
-** mail will be delivered versus the load on your system. If the
-** -v (verbose) flag is given, it will be forced to SM_DELIVER
-** mode.
-**
-** The error mode tells how to return errors.
-*/
-
-EXTERN char OpMode; /* operation mode, see below */
-
-#define MD_DELIVER 'm' /* be a mail sender */
-#define MD_SMTP 's' /* run SMTP on standard input */
-#define MD_ARPAFTP 'a' /* obsolete ARPANET mode (Grey Book) */
-#define MD_DAEMON 'd' /* run as a daemon */
-#define MD_FGDAEMON 'D' /* run daemon in foreground */
-#define MD_VERIFY 'v' /* verify: don't collect or deliver */
-#define MD_TEST 't' /* test mode: resolve addrs only */
-#define MD_INITALIAS 'i' /* initialize alias database */
-#define MD_PRINT 'p' /* print the queue */
-#define MD_FREEZE 'z' /* freeze the configuration file */
-#define MD_HOSTSTAT 'h' /* print persistent host stat info */
-#define MD_PURGESTAT 'H' /* purge persistent host stat info */
-
-/* values for e_sendmode -- send modes */
-#define SM_DELIVER 'i' /* interactive delivery */
-#define SM_FORK 'b' /* deliver in background */
-#define SM_QUEUE 'q' /* queue, don't deliver */
-#define SM_DEFER 'd' /* defer map lookups as well as queue */
-#define SM_VERIFY 'v' /* verify only (used internally) */
-
-/* used only as a parameter to sendall */
-#define SM_DEFAULT '\0' /* unspecified, use SendMode */
-
-
-/* values for e_errormode -- error handling modes */
-#define EM_PRINT 'p' /* print errors */
-#define EM_MAIL 'm' /* mail back errors */
-#define EM_WRITE 'w' /* write back errors */
-#define EM_BERKNET 'e' /* special berknet processing */
-#define EM_QUIET 'q' /* don't print messages (stat only) */
-
-
-/* MIME processing mode */
-EXTERN int MimeMode;
-
-/* bit values for MimeMode */
-#define MM_CVTMIME 0x0001 /* convert 8 to 7 bit MIME */
-#define MM_PASS8BIT 0x0002 /* just send 8 bit data blind */
-#define MM_MIME8BIT 0x0004 /* convert 8-bit data to MIME */
-
-/* queue sorting order algorithm */
-EXTERN int QueueSortOrder;
-
-#define QS_BYPRIORITY 0 /* sort by message priority */
-#define QS_BYHOST 1 /* sort by first host name */
-#define QS_BYTIME 2 /* sort by submission time */
-
-
-/* how to handle messages without any recipient addresses */
-EXTERN int NoRecipientAction;
-
-#define NRA_NO_ACTION 0 /* just leave it as is */
-#define NRA_ADD_TO 1 /* add To: header */
-#define NRA_ADD_APPARENTLY_TO 2 /* add Apparently-To: header */
-#define NRA_ADD_BCC 3 /* add empty Bcc: header */
-#define NRA_ADD_TO_UNDISCLOSED 4 /* add To: undisclosed:; header */
-
-
-/* flags to putxline */
-#define PXLF_NOTHINGSPECIAL 0 /* no special mapping */
-#define PXLF_MAPFROM 0x0001 /* map From_ to >From_ */
-#define PXLF_STRIP8BIT 0x0002 /* strip 8th bit */
-#define PXLF_HEADER 0x0004 /* map newlines in headers */
- /*
-** Additional definitions
-*/
-
-
-/*
-** Privacy flags
-** These are bit values for the PrivacyFlags word.
-*/
-
-#define PRIV_PUBLIC 0 /* what have I got to hide? */
-#define PRIV_NEEDMAILHELO 0x0001 /* insist on HELO for MAIL, at least */
-#define PRIV_NEEDEXPNHELO 0x0002 /* insist on HELO for EXPN */
-#define PRIV_NEEDVRFYHELO 0x0004 /* insist on HELO for VRFY */
-#define PRIV_NOEXPN 0x0008 /* disallow EXPN command entirely */
-#define PRIV_NOVRFY 0x0010 /* disallow VRFY command entirely */
-#define PRIV_AUTHWARNINGS 0x0020 /* flag possible authorization probs */
-#define PRIV_NORECEIPTS 0x0040 /* disallow return receipts */
-#define PRIV_NOETRN 0x0080 /* disallow ETRN command entirely */
-#define PRIV_NOVERB 0x0100 /* disallow VERB command entirely */
-#define PRIV_RESTRICTMAILQ 0x1000 /* restrict mailq command */
-#define PRIV_RESTRICTQRUN 0x2000 /* restrict queue run */
-#define PRIV_GOAWAY 0x0fff /* don't give no info, anyway, anyhow */
-
-/* struct defining such things */
-struct prival
-{
- char *pv_name; /* name of privacy flag */
- int pv_flag; /* numeric level */
-};
-
-
-/*
-** Flags passed to remotename, parseaddr, allocaddr, and buildaddr.
-*/
-
-#define RF_SENDERADDR 0x001 /* this is a sender address */
-#define RF_HEADERADDR 0x002 /* this is a header address */
-#define RF_CANONICAL 0x004 /* strip comment information */
-#define RF_ADDDOMAIN 0x008 /* OK to do domain extension */
-#define RF_COPYPARSE 0x010 /* copy parsed user & host */
-#define RF_COPYPADDR 0x020 /* copy print address */
-#define RF_COPYALL (RF_COPYPARSE|RF_COPYPADDR)
-#define RF_COPYNONE 0
-
-
-/*
-** Flags passed to safefile/safedirpath.
-*/
-
-#define SFF_ANYFILE 0 /* no special restrictions */
-#define SFF_MUSTOWN 0x0001 /* user must own this file */
-#define SFF_NOSLINK 0x0002 /* file cannot be a symbolic link */
-#define SFF_ROOTOK 0x0004 /* ok for root to own this file */
-#define SFF_RUNASREALUID 0x0008 /* if no ctladdr, run as real uid */
-#define SFF_NOPATHCHECK 0x0010 /* don't bother checking dir path */
-#define SFF_SETUIDOK 0x0020 /* setuid files are ok */
-#define SFF_CREAT 0x0040 /* ok to create file if necessary */
-#define SFF_REGONLY 0x0080 /* regular files only */
-#define SFF_SAFEDIRPATH 0x0100 /* no writable directories allowed */
-#define SFF_NOHLINK 0x0200 /* file cannot have hard links */
-#define SFF_NOWLINK 0x0400 /* links only in non-writable dirs */
-#define SFF_NOGWFILES 0x0800 /* disallow world writable files */
-#define SFF_NOWWFILES 0x1000 /* disallow group writable files */
-
-/* flags that are actually specific to safeopen/safefopen/dfopen */
-#define SFF_OPENASROOT 0x2000 /* open as root instead of real user */
-#define SFF_NOLOCK 0x4000 /* don't lock the file */
-
-/* pseudo-flags */
-#define SFF_NOLINK (SFF_NOHLINK|SFF_NOSLINK)
-
-/* functions */
-extern int safefile __P((char *, UID_T, GID_T, char *, int, int, struct stat *));
-extern int safedirpath __P((char *, UID_T, GID_T, char *, int));
-extern int safeopen __P((char *, int, int, int));
-extern FILE *safefopen __P((char *, int, int, int));
-extern int dfopen __P((char *, int, int, int));
-extern bool filechanged __P((char *, int, struct stat *));
-
-
-/*
-** Flags passed to mime8to7.
-*/
-
-#define M87F_OUTER 0 /* outer context */
-#define M87F_NO8BIT 0x0001 /* can't have 8-bit in this section */
-#define M87F_DIGEST 0x0002 /* processing multipart/digest */
-#define M87F_NO8TO7 0x0004 /* don't do 8->7 bit conversions */
-
-
-/*
-** Flags passed to returntosender.
-*/
-
-#define RTSF_NO_BODY 0 /* send headers only */
-#define RTSF_SEND_BODY 0x0001 /* include body of message in return */
-#define RTSF_PM_BOUNCE 0x0002 /* this is a postmaster bounce */
-
-
-/*
-** Regular UNIX sockaddrs are too small to handle ISO addresses, so
-** we are forced to declare a supertype here.
-*/
-
-# if NETINET || NETUNIX || NETISO || NETNS || NETX25
-union bigsockaddr
-{
- struct sockaddr sa; /* general version */
-#if NETUNIX
- struct sockaddr_un sunix; /* UNIX family */
-#endif
-#if NETINET
- struct sockaddr_in sin; /* INET family */
-#endif
-#if NETISO
- struct sockaddr_iso siso; /* ISO family */
-#endif
-#if NETNS
- struct sockaddr_ns sns; /* XNS family */
-#endif
-#if NETX25
- struct sockaddr_x25 sx25; /* X.25 family */
-#endif
-};
-
-#define SOCKADDR union bigsockaddr
-
-EXTERN SOCKADDR RealHostAddr; /* address of host we are talking to */
-
-extern char *hostnamebyanyaddr __P((SOCKADDR *));
-extern char *anynet_ntoa __P((SOCKADDR *));
-# if DAEMON
-extern char *validate_connection __P((SOCKADDR *, char *, ENVELOPE *));
-# endif
-
-#endif
-
-
-/*
-** Vendor codes
-**
-** Vendors can customize sendmail to add special behaviour,
-** generally for back compatibility. Ideally, this should
-** be set up in the .cf file using the "V" command. However,
-** it's quite reasonable for some vendors to want the default
-** be their old version; this can be set using
-** -DVENDOR_DEFAULT=VENDOR_xxx
-** in the Makefile.
-**
-** Vendors should apply to sendmail@CS.Berkeley.EDU for
-** unique vendor codes.
-*/
-
-#define VENDOR_BERKELEY 1 /* Berkeley-native configuration file */
-#define VENDOR_SUN 2 /* Sun-native configuration file */
-#define VENDOR_HP 3 /* Hewlett-Packard specific config syntax */
-#define VENDOR_IBM 4 /* IBM specific config syntax */
-#define VENDOR_SENDMAIL 5 /* Sendmail, Inc. specific config syntax */
-
-EXTERN int VendorCode; /* vendor-specific operation enhancements */
-
-/* prototypes for vendor-specific hook routines */
-extern void vendor_set_uid __P((UID_T));
-extern void vendor_daemon_setup __P((ENVELOPE *));
-
-/*
-** DontBlameSendmail options
-**
-** Hopefully nobody uses these.
-*/
-#define DBS_SAFE 0
-#define DBS_ASSUMESAFECHOWN 0x00000001
-#define DBS_GROUPWRITABLEDIRPATHSAFE 0x00000002
-#define DBS_GROUPWRITABLEFORWARDFILESAFE 0x00000004
-#define DBS_GROUPWRITABLEINCLUDEFILESAFE 0x00000008
-#define DBS_GROUPWRITABLEALIASFILE 0x00000010
-#define DBS_WORLDWRITABLEALIASFILE 0x00000020
-#define DBS_FORWARDFILEINUNSAFEDIRPATH 0x00000040
-#define DBS_MAPINUNSAFEDIRPATH 0x00000080
-#define DBS_LINKEDALIASFILEINWRITABLEDIR 0x00000100
-#define DBS_LINKEDCLASSFILEINWRITABLEDIR 0x00000200
-#define DBS_LINKEDFORWARDFILEINWRITABLEDIR 0x00000400
-#define DBS_LINKEDINCLUDEFILEINWRITABLEDIR 0x00000800
-#define DBS_LINKEDMAPINWRITABLEDIR 0x00001000
-#define DBS_LINKEDSERVICESWITCHFILEINWRITABLEDIR 0x00002000
-#define DBS_FILEDELIVERYTOHARDLINK 0x00004000
-#define DBS_FILEDELIVERYTOSYMLINK 0x00008000
-#define DBS_WRITEMAPTOHARDLINK 0x00010000
-#define DBS_WRITEMAPTOSYMLINK 0x00020000
-#define DBS_WRITESTATSTOHARDLINK 0x00040000
-#define DBS_WRITESTATSTOSYMLINK 0x00080000
-#define DBS_FORWARDFILEINGROUPWRITABLEDIRPATH 0x00100000
-#define DBS_INCLUDEFILEINGROUPWRITABLEDIRPATH 0x00200000
-#define DBS_CLASSFILEINUNSAFEDIRPATH 0x00400000
-#define DBS_ERRORHEADERINUNSAFEDIRPATH 0x00800000
-#define DBS_HELPFILEINUNSAFEDIRPATH 0x01000000
-#define DBS_FORWARDFILEINUNSAFEDIRPATHSAFE 0x02000000
-#define DBS_INCLUDEFILEINUNSAFEDIRPATHSAFE 0x04000000
-#define DBS_RUNPROGRAMINUNSAFEDIRPATH 0x08000000
-#define DBS_RUNWRITABLEPROGRAM 0x10000000
-#define DBS_INCLUDEFILEINUNSAFEDIRPATH 0x20000000
-
-/* struct defining such things */
-struct dbsval
-{
- char *dbs_name; /* name of DontBlameSendmail flag */
- long dbs_flag; /* numeric level */
-};
-
-EXTERN long DontBlameSendmail; /* DontBlameSendmail option bits */
-
-/*
-** Terminal escape codes.
-**
-** To make debugging output clearer.
-*/
-
-struct termescape
-{
- char *te_rv_on; /* turn reverse-video on */
- char *te_rv_off; /* turn reverse-video off */
-};
-
-EXTERN struct termescape TermEscape;
-
-
-/*
-** Error return from inet_addr(3), in case not defined in /usr/include.
-*/
-
-#ifndef INADDR_NONE
-# define INADDR_NONE 0xffffffff
-#endif
- /*
-** Global variables.
-*/
-
-EXTERN bool FromFlag; /* if set, "From" person is explicit */
-EXTERN bool MeToo; /* send to the sender also */
-EXTERN bool IgnrDot; /* don't let dot end messages */
-EXTERN bool SaveFrom; /* save leading "From" lines */
-EXTERN bool GrabTo; /* if set, get recipients from msg */
-EXTERN bool SuprErrs; /* set if we are suppressing errors */
-EXTERN bool HoldErrs; /* only output errors to transcript */
-EXTERN bool NoConnect; /* don't connect to non-local mailers */
-EXTERN bool SuperSafe; /* be extra careful, even if expensive */
-EXTERN bool ForkQueueRuns; /* fork for each job when running the queue */
-EXTERN bool AutoRebuild; /* auto-rebuild the alias database as needed */
-EXTERN bool CheckAliases; /* parse addresses during newaliases */
-EXTERN bool NoAlias; /* suppress aliasing */
-EXTERN bool UseNameServer; /* using DNS -- interpret h_errno & MX RRs */
-EXTERN bool UseHesiod; /* using Hesiod -- interpret Hesiod errors */
-EXTERN bool SevenBitInput; /* force 7-bit data on input */
-EXTERN bool HasEightBits; /* has at least one eight bit input byte */
-EXTERN bool ConfigFileRead; /* configuration file has been read */
-EXTERN time_t SafeAlias; /* interval to wait until @:@ in alias file */
-EXTERN FILE *InChannel; /* input connection */
-EXTERN FILE *OutChannel; /* output connection */
-EXTERN char *RealUserName; /* real user name of caller */
-EXTERN uid_t RealUid; /* real uid of caller */
-EXTERN gid_t RealGid; /* real gid of caller */
-EXTERN uid_t DefUid; /* default uid to run as */
-EXTERN gid_t DefGid; /* default gid to run as */
-EXTERN char *DefUser; /* default user to run as (from DefUid) */
-EXTERN uid_t TrustedUid; /* uid of trusted user for files and startup */
-EXTERN MODE_T OldUmask; /* umask when sendmail starts up */
-EXTERN int Verbose; /* set if blow-by-blow desired */
-EXTERN int Errors; /* set if errors (local to single pass) */
-EXTERN int ExitStat; /* exit status code */
-EXTERN int LineNumber; /* line number in current input */
-EXTERN int LogLevel; /* level of logging to perform */
-EXTERN int FileMode; /* mode on files */
-EXTERN int QueueLA; /* load average starting forced queueing */
-EXTERN int RefuseLA; /* load average refusing connections are */
-EXTERN int CurrentLA; /* current load average */
-EXTERN long QueueFactor; /* slope of queue function */
-EXTERN time_t QueueIntvl; /* intervals between running the queue */
-EXTERN char *HelpFile; /* location of SMTP help file */
-EXTERN char *ErrMsgFile; /* file to prepend to all error messages */
-EXTERN char *StatFile; /* location of statistics summary */
-EXTERN char *QueueDir; /* location of queue directory */
-EXTERN char *FileName; /* name to print on error messages */
-EXTERN char *SmtpPhase; /* current phase in SMTP processing */
-EXTERN char *MyHostName; /* name of this host for SMTP messages */
-EXTERN char *RealHostName; /* name of host we are talking to */
-EXTERN char *CurHostName; /* current host we are dealing with */
-EXTERN jmp_buf TopFrame; /* branch-to-top-of-loop-on-error frame */
-EXTERN bool QuickAbort; /* .... but only if we want a quick abort */
-EXTERN bool OnlyOneError; /* .... or only want to give one SMTP reply */
-EXTERN bool LogUsrErrs; /* syslog user errors (e.g., SMTP RCPT cmd) */
-EXTERN bool SendMIMEErrors; /* send error messages in MIME format */
-EXTERN bool MatchGecos; /* look for user names in gecos field */
-EXTERN bool UseErrorsTo; /* use Errors-To: header (back compat) */
-EXTERN bool TryNullMXList; /* if we are the best MX, try host directly */
-EXTERN bool InChild; /* true if running in an SMTP subprocess */
-EXTERN bool DisConnected; /* running with OutChannel redirected to xf */
-EXTERN bool ColonOkInAddr; /* single colon legal in address */
-EXTERN bool HasWildcardMX; /* don't use MX records when canonifying */
-EXTERN char SpaceSub; /* substitution for <lwsp> */
-EXTERN int PrivacyFlags; /* privacy flags */
-EXTERN char *ConfFile; /* location of configuration file [conf.c] */
-EXTERN char *PidFile; /* location of proc id file [conf.c] */
-EXTERN char *ControlSocketName; /* control socket filename [control.c] */
-extern ADDRESS NullAddress; /* a null (template) address [main.c] */
-EXTERN long WkClassFact; /* multiplier for message class -> priority */
-EXTERN long WkRecipFact; /* multiplier for # of recipients -> priority */
-EXTERN long WkTimeFact; /* priority offset each time this job is run */
-EXTERN char *UdbSpec; /* user database source spec */
-EXTERN int MaxHopCount; /* max # of hops until bounce */
-EXTERN int ConfigLevel; /* config file level */
-EXTERN char *TimeZoneSpec; /* override time zone specification */
-EXTERN char *ForwardPath; /* path to search for .forward files */
-EXTERN long MinBlocksFree; /* min # of blocks free on queue fs */
-EXTERN char *FallBackMX; /* fall back MX host */
-EXTERN long MaxMessageSize; /* advertised max size we will accept */
-EXTERN time_t MinQueueAge; /* min delivery interval */
-EXTERN time_t DialDelay; /* delay between dial-on-demand tries */
-EXTERN char *SafeFileEnv; /* chroot location for file delivery */
-EXTERN char *HostsFile; /* path to /etc/hosts file */
-EXTERN char *HostStatDir; /* location of host status information */
-EXTERN int MaxQueueRun; /* maximum number of jobs in one queue run */
-EXTERN int MaxChildren; /* maximum number of daemonic children */
-EXTERN int CurChildren; /* current number of daemonic children */
-EXTERN char *SmtpGreeting; /* SMTP greeting message (old $e macro) */
-EXTERN char *UnixFromLine; /* UNIX From_ line (old $l macro) */
-EXTERN char *OperatorChars; /* operators (old $o macro) */
-EXTERN bool DontInitGroups; /* avoid initgroups() because of NIS cost */
-EXTERN int DefaultNotify; /* default DSN notification flags */
-EXTERN bool AllowBogusHELO; /* allow syntax errors on HELO command */
-EXTERN bool UserSubmission; /* initial (user) mail submission */
-EXTERN char *RunAsUserName; /* user to become for bulk of run */
-EXTERN uid_t RunAsUid; /* UID to become for bulk of run */
-EXTERN gid_t RunAsGid; /* GID to become for bulk of run */
-EXTERN int MaxRcptPerMsg; /* max recipients per SMTP message */
-EXTERN bool DoQueueRun; /* non-interrupt time queue run needed */
-EXTERN u_long ConnectOnlyTo; /* override connection address (for testing) */
-EXTERN int MaxHeadersLength; /* max length of headers */
-#if _FFR_DSN_RRT_OPTION
-EXTERN bool RrtImpliesDsn; /* turn Return-Receipt-To: into DSN */
-#endif
-EXTERN char *DeadLetterDrop; /* path to dead letter office */
-EXTERN bool DontProbeInterfaces; /* don't probe interfaces for names */
-EXTERN bool ChownAlwaysSafe; /* treat chown(2) as safe */
-EXTERN bool IgnoreHostStatus; /* ignore long term host status files */
-EXTERN bool SingleThreadDelivery; /* single thread hosts on delivery */
-EXTERN bool SingleLineFromHeader; /* force From: header to be one line */
-EXTERN bool DontLockReadFiles; /* don't read lock support files */
-EXTERN int ConnRateThrottle; /* throttle for SMTP connection rate */
-EXTERN int MaxAliasRecursion; /* maximum depth of alias recursion */
-EXTERN int MaxMacroRecursion; /* maximum depth of macro recursion */
-EXTERN int MaxRuleRecursion; /* maximum depth of ruleset recursion */
-EXTERN char *MustQuoteChars; /* quote these characters in phrases */
-EXTERN char *ServiceSwitchFile; /* backup service switch */
-EXTERN char *DefaultCharSet; /* default character set for MIME */
-EXTERN char *PostMasterCopy; /* address to get errs cc's */
-EXTERN int CheckpointInterval; /* queue file checkpoint interval */
-EXTERN bool DontPruneRoutes; /* don't prune source routes */
-EXTERN bool DontExpandCnames; /* do not $[...$] expand CNAMEs */
-EXTERN int MaxMciCache; /* maximum entries in MCI cache */
-EXTERN time_t ServiceCacheTime; /* time service switch was cached */
-EXTERN time_t ServiceCacheMaxAge; /* refresh interval for cache */
-EXTERN time_t MciCacheTimeout; /* maximum idle time on connections */
-EXTERN time_t MciInfoTimeout; /* how long 'til we retry down hosts */
-EXTERN FILE *TrafficLogFile; /* file in which to log all traffic */
-EXTERN char *DoubleBounceAddr; /* where to send double bounces */
-EXTERN char **ExternalEnviron; /* input environment */
-EXTERN char *UserEnviron[MAXUSERENVIRON + 1];
- /* saved user environment */
-EXTERN int MaxMimeHeaderLength; /* maximum MIME header length */
-EXTERN int MaxMimeFieldLength; /* maximum MIME field length */
-
-extern int errno;
-
-/*
-** Queue Run Limitations
-*/
-struct queue_char
-{
- char *queue_match; /* string to match */
- struct queue_char *queue_next;
-};
-
-typedef struct queue_char QUEUE_CHAR;
-
-EXTERN QUEUE_CHAR *QueueLimitRecipient; /* limit queue runs to this recipient */
-EXTERN QUEUE_CHAR *QueueLimitSender; /* limit queue runs to this sender */
-EXTERN QUEUE_CHAR *QueueLimitId; /* limit queue runs to this id */
-
-/*
-** Timeouts
-**
-** Indicated values are the MINIMUM per RFC 1123 section 5.3.2.
-*/
-
-EXTERN struct
-{
- /* RFC 1123-specified timeouts [minimum value] */
- time_t to_initial; /* initial greeting timeout [5m] */
- time_t to_mail; /* MAIL command [5m] */
- time_t to_rcpt; /* RCPT command [5m] */
- time_t to_datainit; /* DATA initiation [2m] */
- time_t to_datablock; /* DATA block [3m] */
- time_t to_datafinal; /* DATA completion [10m] */
- time_t to_nextcommand; /* next command [5m] */
- /* following timeouts are not mentioned in RFC 1123 */
- time_t to_iconnect; /* initial connection timeout (first try) */
- time_t to_connect; /* initial connection timeout (later tries) */
- time_t to_rset; /* RSET command */
- time_t to_helo; /* HELO command */
- time_t to_quit; /* QUIT command */
- time_t to_miscshort; /* misc short commands (NOOP, VERB, etc) */
- time_t to_ident; /* IDENT protocol requests */
- time_t to_fileopen; /* opening :include: and .forward files */
- /* following are per message */
- time_t to_q_return[MAXTOCLASS]; /* queue return timeouts */
- time_t to_q_warning[MAXTOCLASS]; /* queue warning timeouts */
-} TimeOuts;
-
-/* timeout classes for return and warning timeouts */
-# define TOC_NORMAL 0 /* normal delivery */
-# define TOC_URGENT 1 /* urgent delivery */
-# define TOC_NONURGENT 2 /* non-urgent delivery */
-
-
-/*
-** Trace information
-*/
-
-/* trace vector and macros for debugging flags */
-EXTERN u_char tTdvect[100];
-# define tTd(flag, level) (tTdvect[flag] >= level)
-# define tTdlevel(flag) (tTdvect[flag])
- /*
-** Miscellaneous information.
-*/
-
-
-/*
-** The "no queue id" queue id for sm_syslog
-*/
-
-#define NOQID "*~*"
-
-
-/*
-** Some in-line functions
-*/
-
-/* set exit status */
-#define setstat(s) { \
- if (ExitStat == EX_OK || ExitStat == EX_TEMPFAIL) \
- ExitStat = s; \
- }
-
-/* make a copy of a string */
-#define newstr(s) strcpy(xalloc(strlen(s) + 1), s)
-
-#define STRUCTCOPY(s, d) d = s
-
-
-
-/*
-** Declarations of useful functions
-*/
-
-extern char *xalloc __P((int));
-extern char *sfgets __P((char *, int, FILE *, time_t, char *));
-extern char *queuename __P((ENVELOPE *, int));
-extern time_t curtime __P((void));
-extern bool transienterror __P((int));
-extern char *fgetfolded __P((char *, int, FILE *));
-extern char *username __P((void));
-extern char *pintvl __P((time_t, bool));
-extern bool shouldqueue __P((long, time_t));
-extern bool lockfile __P((int, char *, char *, int));
-extern char *hostsignature __P((MAILER *, char *, ENVELOPE *));
-extern void openxscript __P((ENVELOPE *));
-extern void closexscript __P((ENVELOPE *));
-extern char *shortenstring __P((const char *, int));
-extern bool usershellok __P((char *, char *));
-extern char *defcharset __P((ENVELOPE *));
-extern bool wordinclass __P((char *, int));
-extern char *denlstring __P((char *, bool, bool));
-extern void makelower __P((char *));
-extern bool rebuildaliases __P((MAP *, bool));
-extern void readaliases __P((MAP *, FILE *, bool, bool));
-extern void finis __P((bool, volatile int));
-extern void setsender __P((char *, ENVELOPE *, char **, int, bool));
-extern void xputs __P((const char *));
-extern void logsender __P((ENVELOPE *, char *));
-extern void smtprset __P((MAILER *, MCI *, ENVELOPE *));
-extern void smtpquit __P((MAILER *, MCI *, ENVELOPE *));
-extern void setuserenv __P((const char *, const char *));
-extern char *getextenv __P((const char *));
-extern void disconnect __P((int, ENVELOPE *));
-extern void putxline __P((char *, size_t, MCI *, int));
-extern void dumpfd __P((int, bool, bool));
-extern void makemailer __P((char *));
-extern void putfromline __P((MCI *, ENVELOPE *));
-extern void setoption __P((int, char *, bool, bool, ENVELOPE *));
-extern void setclass __P((int, char *));
-extern void inittimeouts __P((char *));
-extern void logdelivery __P((MAILER *, MCI *, const char *, ADDRESS *, time_t, ENVELOPE *));
-extern void giveresponse __P((int, MAILER *, MCI *, ADDRESS *, time_t, ENVELOPE *));
-extern void buildfname __P((char *, char *, char *, int));
-extern void mci_setstat __P((MCI *, int, char *, char *));
-extern char *smtptodsn __P((int));
-extern int rscheck __P((char *, char *, char *, ENVELOPE *e));
-extern void mime7to8 __P((MCI *, HDR *, ENVELOPE *));
-extern int mime8to7 __P((MCI *, HDR *, ENVELOPE *, char **, int));
-extern void xfclose __P((FILE *, char *, char *));
-extern int switch_map_find __P((char *, char *[], short []));
-extern void shorten_hostname __P((char []));
-extern int waitfor __P((pid_t));
-extern void proc_list_add __P((pid_t, char *));
-extern void proc_list_set __P((pid_t, char *));
-extern void proc_list_drop __P((pid_t));
-extern void proc_list_clear __P((void));
-extern void proc_list_display __P((FILE *));
-extern void proc_list_probe __P((void));
-extern void buffer_errors __P((void));
-extern void flush_errors __P((bool));
-extern void putline __P((char *, MCI *));
-extern bool xtextok __P((char *));
-extern char *xtextify __P((char *, char *));
-extern char *xuntextify __P((char *));
-extern void cleanstrcpy __P((char *, char *, int));
-extern int getmxrr __P((char *, char **, bool, int *));
-extern int strtorwset __P((char *, char **, int));
-extern void printav __P((char **));
-extern void printopenfds __P((bool));
-extern int endmailer __P((MCI *, ENVELOPE *, char **));
-extern void fixcrlf __P((char *, bool));
-extern int dofork __P((void));
-extern void initsys __P((ENVELOPE *));
-extern void collect __P((FILE *, bool, HDR **, ENVELOPE *));
-extern void stripquotes __P((char *));
-extern int include __P((char *, bool, ADDRESS *, ADDRESS **, int, ENVELOPE *));
-extern void unlockqueue __P((ENVELOPE *));
-extern void xunlink __P((char *));
-extern bool runqueue __P((bool, bool));
-extern int getla __P((void));
-extern void sendall __P((ENVELOPE *, int));
-extern void queueup __P((ENVELOPE *, bool));
-extern void checkfds __P((char *));
-extern int returntosender __P((char *, ADDRESS *, int, ENVELOPE *));
-extern void markstats __P((ENVELOPE *, ADDRESS *, bool));
-extern void poststats __P((char *));
-extern char *arpadate __P((char *));
-extern int mailfile __P((char *volatile, MAILER *volatile, ADDRESS *, volatile int, ENVELOPE *));
-extern void loseqfile __P((ENVELOPE *, char *));
-extern int prog_open __P((char **, int *, ENVELOPE *));
-extern bool getcanonname __P((char *, int, bool));
-extern bool path_is_dir __P((char *, bool));
-extern pid_t dowork __P((char *, bool, bool, ENVELOPE *));
-extern int drop_privileges __P((bool));
-extern void fill_fd __P((int, char *));
-extern void closecontrolsocket __P((bool));
-extern void clrcontrol __P((void));
-
-extern const char *errstring __P((int));
-extern sigfunc_t setsignal __P((int, sigfunc_t));
-extern int blocksignal __P((int));
-extern int releasesignal __P((int));
-extern struct hostent *sm_gethostbyname __P((char *));
-extern struct hostent *sm_gethostbyaddr __P((char *, int, int));
-extern struct passwd *sm_getpwnam __P((char *));
-extern struct passwd *sm_getpwuid __P((UID_T));
-extern struct passwd *finduser __P((char *, bool *));
-
-#ifdef XDEBUG
-extern void checkfdopen __P((int, char *));
-extern void checkfd012 __P((char *));
-#endif
-
-/* ellipsis is a different case though */
-extern void auth_warning __P((ENVELOPE *, const char *, ...));
-extern void syserr __P((const char *, ...));
-extern void usrerr __P((const char *, ...));
-extern void message __P((const char *, ...));
-extern void nmessage __P((const char *, ...));
-extern void setproctitle __P((const char *, ...));
-extern void sm_setproctitle __P((bool, const char *, ...));
-extern void sm_syslog __P((int, const char *, const char *, ...));
-
-#if !HASSNPRINTF
-extern int snprintf __P((char *, size_t, const char *, ...));
-extern int vsnprintf __P((char *, size_t, const char *, va_list));
-#endif
-extern char *quad_to_string __P((QUAD_T));
diff --git a/src/sendmail.hf b/src/sendmail.hf
deleted file mode 100644
index 0952963..0000000
--- a/src/sendmail.hf
+++ /dev/null
@@ -1,124 +0,0 @@
-cpyr
-cpyr Copyright (c) 1998 Sendmail, Inc. All rights reserved.
-cpyr Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
-cpyr Copyright (c) 1988, 1993
-cpyr The Regents of the University of California. All rights reserved.
-cpyr
-cpyr
-cpyr By using this file, you agree to the terms and conditions set
-cpyr forth in the LICENSE file which can be found at the top level of
-cpyr the sendmail distribution.
-cpyr
-cpyr @(#)sendmail.hf 8.18 (Berkeley) 11/19/1998
-cpyr
-smtp Topics:
-smtp HELO EHLO MAIL RCPT DATA
-smtp RSET NOOP QUIT HELP VRFY
-smtp EXPN VERB ETRN DSN
-smtp For more info use "HELP <topic>".
-smtp To report bugs in the implementation send email to
-smtp sendmail-bugs@sendmail.org.
-smtp For local information send email to Postmaster at your site.
-help HELP [ <topic> ]
-help The HELP command gives help info.
-helo HELO <hostname>
-helo Introduce yourself.
-ehlo EHLO <hostname>
-ehlo Introduce yourself, and request extended SMTP mode.
-ehlo Possible replies include:
-ehlo SEND Send as mail [RFC821]
-ehlo SOML Send as mail or terminal [RFC821]
-ehlo SAML Send as mail and terminal [RFC821]
-ehlo EXPN Expand the mailing list [RFC821]
-ehlo HELP Supply helpful information [RFC821]
-ehlo TURN Turn the operation around [RFC821]
-ehlo 8BITMIME Use 8-bit data [RFC1652]
-ehlo SIZE Message size declaration [RFC1870]
-ehlo VERB Verbose [Allman]
-ehlo ONEX One message transaction only [Allman]
-ehlo CHUNKING Chunking [RFC1830]
-ehlo BINARYMIME Binary MIME [RFC1830]
-ehlo PIPELINING Command Pipelining [RFC1854]
-ehlo DSN Delivery Status Notification [RFC1891]
-ehlo ETRN Remote Message Queue Starting [RFC1985]
-ehlo XUSR Initial (user) submission [Allman]
-mail MAIL FROM: <sender> [ <parameters> ]
-mail Specifies the sender. Parameters are ESMTP extensions.
-mail See "HELP DSN" for details.
-rcpt RCPT TO: <recipient> [ <parameters> ]
-rcpt Specifies the recipient. Can be used any number of times.
-rcpt Parameters are ESMTP extensions. See "HELP DSN" for details.
-data DATA
-data Following text is collected as the message.
-data End with a single dot.
-rset RSET
-rset Resets the system.
-quit QUIT
-quit Exit sendmail (SMTP).
-verb VERB
-verb Go into verbose mode. This sends 0xy responses that are
-verb not RFC821 standard (but should be) They are recognized
-verb by humans and other sendmail implementations.
-vrfy VRFY <recipient>
-vrfy Verify an address. If you want to see what it aliases
-vrfy to, use EXPN instead.
-expn EXPN <recipient>
-expn Expand an address. If the address indicates a mailing
-expn list, return the contents of that list.
-noop NOOP
-noop Do nothing.
-send SEND FROM: <sender>
-send replaces the MAIL command, and can be used to send
-send directly to a users terminal. Not supported in this
-send implementation.
-soml SOML FROM: <sender>
-soml Send or mail. If the user is logged in, send directly,
-soml otherwise mail. Not supported in this implementation.
-saml SAML FROM: <sender>
-saml Send and mail. Send directly to the user's terminal,
-saml and also mail a letter. Not supported in this
-saml implementation.
-turn TURN
-turn Reverses the direction of the connection. Not currently
-turn implemented.
-etrn ETRN [ <hostname> | @<domain> | #<queuename> ]
-etrn Run the queue for the specified <hostname>, or
-etrn all hosts within a given <domain>, or a specially-named
-etrn <queuename> (implementation-specific).
-dsn MAIL FROM: <sender> [ RET={ FULL | HDRS} ] [ ENVID=<envid> ]
-dsn RCPT TO: <recipient> [ NOTIFY={NEVER,SUCCESS,FAILURE,DELAY} ]
-dsn [ ORCPT=<recipient> ]
-dsn SMTP Delivery Status Notifications.
-dsn Descriptions:
-dsn RET Return either the full message or only headers.
-dsn ENVID Sender's "envelope identifier" for tracking.
-dsn NOTIFY When to send a DSN. Multiple options are OK, comma-
-dsn delimited. NEVER must appear by itself.
-dsn ORCPT Original recipient.
--bt Help for test mode:
--bt ? :this help message.
--bt .Dmvalue :define macro `m' to `value'.
--bt .Ccvalue :add `value' to class `c'.
--bt =Sruleset :dump the contents of the indicated ruleset.
--bt =M :display the known mailers.
--bt -ddebug-spec :equivalent to the command-line -d debug flag.
--bt $m :print the value of macro $m.
--bt $=c :print the contents of class $=c.
--bt /mx host :returns the MX records for `host'.
--bt /parse address :parse address, returning the value of crackaddr, and
--bt the parsed address (same as -bv).
--bt /try mailer addr :rewrite address into the form it will have when
--bt presented to the indicated mailer.
--bt /tryflags flags :set flags used by parsing. The flags can be `H' for
--bt Header or `E' for Envelope, and `S' for Sender or `R'
--bt for Recipient. These can be combined, `HR' sets
--bt flags for header recipients.
--bt /canon hostname :try to canonify hostname.
--bt /map mapname key :look up `key' in the indicated `mapname'.
--bt rules addr :run the indicated address through the named rules.
--bt Rules can be a comma separated list of rules.
-control Help for smcontrol:
-control help This message.
-control restart Restart sendmail.
-control shutdown Shutdown sendmail.
-control status Show sendmail status.
diff --git a/src/snprintf.c b/src/snprintf.c
deleted file mode 100644
index 3e07e1b..0000000
--- a/src/snprintf.c
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)snprintf.c 8.12 (Berkeley) 10/13/1998";
-#endif /* not lint */
-
-#include "sendmail.h"
-
- /*
-** SNPRINTF, VSNPRINT -- counted versions of printf
-**
-** These versions have been grabbed off the net. They have been
-** cleaned up to compile properly and support for .precision and
-** %lx has been added.
-*/
-
-/**************************************************************
- * Original:
- * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
- * A bombproof version of doprnt (sm_dopr) included.
- * Sigh. This sort of thing is always nasty do deal with. Note that
- * the version here does not include floating point...
- *
- * snprintf() is used instead of sprintf() as it does limit checks
- * for string length. This covers a nasty loophole.
- *
- * The other functions are there to prevent NULL pointers from
- * causing nast effects.
- **************************************************************/
-
-/*static char _id[] = "$Id: snprintf.c,v 1.2 1995/10/09 11:19:47 roberto Exp $";*/
-void sm_dopr();
-char *DoprEnd;
-int SnprfOverflow;
-
-#if !HASSNPRINTF
-
-/* VARARGS3 */
-int
-# ifdef __STDC__
-snprintf(char *str, size_t count, const char *fmt, ...)
-# else
-snprintf(str, count, fmt, va_alist)
- char *str;
- size_t count;
- const char *fmt;
- va_dcl
-#endif
-{
- int len;
- VA_LOCAL_DECL
-
- VA_START(fmt);
- len = vsnprintf(str, count, fmt, ap);
- VA_END;
- return len;
-}
-
-
-# ifndef luna2
-int
-vsnprintf(str, count, fmt, args)
- char *str;
- size_t count;
- const char *fmt;
- va_list args;
-{
- str[0] = 0;
- DoprEnd = str + count - 1;
- SnprfOverflow = 0;
- sm_dopr( str, fmt, args );
- if (count > 0)
- DoprEnd[0] = 0;
- if (SnprfOverflow && tTd(57, 2))
- printf("\nvsnprintf overflow, len = %ld, str = %s",
- (long) count, shortenstring(str, MAXSHORTSTR));
- return strlen(str);
-}
-
-# endif /* !luna2 */
-#endif /* !HASSNPRINTF */
-
-/*
- * sm_dopr(): poor man's version of doprintf
- */
-
-void fmtstr __P((char *value, int ljust, int len, int zpad, int maxwidth));
-void fmtnum __P((long value, int base, int dosign, int ljust, int len, int zpad));
-void dostr __P(( char * , int ));
-char *output;
-void dopr_outch __P(( int c ));
-int SyslogErrno;
-
-void
-sm_dopr( buffer, format, args )
- char *buffer;
- const char *format;
- va_list args;
-{
- int ch;
- long value;
- int longflag = 0;
- int pointflag = 0;
- int maxwidth = 0;
- char *strvalue;
- int ljust;
- int len;
- int zpad;
-# if !HASSTRERROR && !defined(ERRLIST_PREDEFINED)
- extern char *sys_errlist[];
- extern int sys_nerr;
-# endif
-
-
- output = buffer;
- while( (ch = *format++) != '\0' ){
- switch( ch ){
- case '%':
- ljust = len = zpad = maxwidth = 0;
- longflag = pointflag = 0;
- nextch:
- ch = *format++;
- switch( ch ){
- case 0:
- dostr( "**end of format**" , 0);
- return;
- case '-': ljust = 1; goto nextch;
- case '0': /* set zero padding if len not set */
- if(len==0 && !pointflag) zpad = '0';
- case '1': case '2': case '3':
- case '4': case '5': case '6':
- case '7': case '8': case '9':
- if (pointflag)
- maxwidth = maxwidth*10 + ch - '0';
- else
- len = len*10 + ch - '0';
- goto nextch;
- case '*':
- if (pointflag)
- maxwidth = va_arg( args, int );
- else
- len = va_arg( args, int );
- goto nextch;
- case '.': pointflag = 1; goto nextch;
- case 'l': longflag = 1; goto nextch;
- case 'u': case 'U':
- /*fmtnum(value,base,dosign,ljust,len,zpad) */
- if( longflag ){
- value = va_arg( args, long );
- } else {
- value = va_arg( args, int );
- }
- fmtnum( value, 10,0, ljust, len, zpad ); break;
- case 'o': case 'O':
- /*fmtnum(value,base,dosign,ljust,len,zpad) */
- if( longflag ){
- value = va_arg( args, long );
- } else {
- value = va_arg( args, int );
- }
- fmtnum( value, 8,0, ljust, len, zpad ); break;
- case 'd': case 'D':
- if( longflag ){
- value = va_arg( args, long );
- } else {
- value = va_arg( args, int );
- }
- fmtnum( value, 10,1, ljust, len, zpad ); break;
- case 'x':
- if( longflag ){
- value = va_arg( args, long );
- } else {
- value = va_arg( args, int );
- }
- fmtnum( value, 16,0, ljust, len, zpad ); break;
- case 'X':
- if( longflag ){
- value = va_arg( args, long );
- } else {
- value = va_arg( args, int );
- }
- fmtnum( value,-16,0, ljust, len, zpad ); break;
- case 's':
- strvalue = va_arg( args, char *);
- if (maxwidth > 0 || !pointflag) {
- if (pointflag && len > maxwidth)
- len = maxwidth; /* Adjust padding */
- fmtstr( strvalue,ljust,len,zpad, maxwidth);
- }
- break;
- case 'c':
- ch = va_arg( args, int );
- dopr_outch( ch ); break;
- case 'm':
-#if HASSTRERROR
- dostr(strerror(SyslogErrno), 0);
-#else
- if (SyslogErrno < 0 || SyslogErrno >= sys_nerr)
- {
- dostr("Error ", 0);
- fmtnum(SyslogErrno, 10, 0, 0, 0, 0);
- }
- else
- dostr((char *)sys_errlist[SyslogErrno], 0);
-#endif
- break;
-
- case '%': dopr_outch( ch ); continue;
- default:
- dostr( "???????" , 0);
- }
- break;
- default:
- dopr_outch( ch );
- break;
- }
- }
- *output = 0;
-}
-
-void
-fmtstr( value, ljust, len, zpad, maxwidth )
- char *value;
- int ljust, len, zpad, maxwidth;
-{
- int padlen, strlen; /* amount to pad */
-
- if( value == 0 ){
- value = "<NULL>";
- }
- for( strlen = 0; value[strlen]; ++ strlen ); /* strlen */
- if (strlen > maxwidth && maxwidth)
- strlen = maxwidth;
- padlen = len - strlen;
- if( padlen < 0 ) padlen = 0;
- if( ljust ) padlen = -padlen;
- while( padlen > 0 ) {
- dopr_outch( ' ' );
- --padlen;
- }
- dostr( value, maxwidth );
- while( padlen < 0 ) {
- dopr_outch( ' ' );
- ++padlen;
- }
-}
-
-void
-fmtnum( value, base, dosign, ljust, len, zpad )
- long value;
- int base, dosign, ljust, len, zpad;
-{
- int signvalue = 0;
- unsigned long uvalue;
- char convert[20];
- int place = 0;
- int padlen = 0; /* amount to pad */
- int caps = 0;
-
- /* DEBUGP(("value 0x%x, base %d, dosign %d, ljust %d, len %d, zpad %d\n",
- value, base, dosign, ljust, len, zpad )); */
- uvalue = value;
- if( dosign ){
- if( value < 0 ) {
- signvalue = '-';
- uvalue = -value;
- }
- }
- if( base < 0 ){
- caps = 1;
- base = -base;
- }
- do{
- convert[place++] =
- (caps? "0123456789ABCDEF":"0123456789abcdef")
- [uvalue % (unsigned)base ];
- uvalue = (uvalue / (unsigned)base );
- }while(uvalue);
- convert[place] = 0;
- padlen = len - place;
- if( padlen < 0 ) padlen = 0;
- if( ljust ) padlen = -padlen;
- /* DEBUGP(( "str '%s', place %d, sign %c, padlen %d\n",
- convert,place,signvalue,padlen)); */
- if( zpad && padlen > 0 ){
- if( signvalue ){
- dopr_outch( signvalue );
- --padlen;
- signvalue = 0;
- }
- while( padlen > 0 ){
- dopr_outch( zpad );
- --padlen;
- }
- }
- while( padlen > 0 ) {
- dopr_outch( ' ' );
- --padlen;
- }
- if( signvalue ) dopr_outch( signvalue );
- while( place > 0 ) dopr_outch( convert[--place] );
- while( padlen < 0 ){
- dopr_outch( ' ' );
- ++padlen;
- }
-}
-
-void
-dostr( str , cut)
- char *str;
- int cut;
-{
- if (cut) {
- while(*str && cut-- > 0) dopr_outch(*str++);
- } else {
- while(*str) dopr_outch(*str++);
- }
-}
-
-void
-dopr_outch( c )
- int c;
-{
-#if 0
- if( iscntrl(c) && c != '\n' && c != '\t' ){
- c = '@' + (c & 0x1F);
- if( DoprEnd == 0 || output < DoprEnd )
- *output++ = '^';
- }
-#endif
- if( DoprEnd == 0 || output < DoprEnd )
- *output++ = c;
- else
- SnprfOverflow++;
-}
-
- /*
-** QUAD_TO_STRING -- Convert a quad type to a string.
-**
-** Convert a quad type to a string. This must be done
-** separately as %lld/%qd are not supported by snprint()
-** and adding support would slow down systems which only
-** emulate the data type.
-**
-** Parameters:
-** value -- number to convert to a string.
-**
-** Returns:
-** pointer to a string.
-*/
-
-char *
-quad_to_string(value)
- QUAD_T value;
-{
- char *fmtstr;
- static char buf[64];
-
- /*
- ** Use sprintf() instead of snprintf() since snprintf()
- ** does not support %qu or %llu. The buffer is large enough
- ** to hold the string so there is no danger of buffer
- ** overflow.
- */
-
-#if NEED_PERCENTQ
- fmtstr = "%qu";
-#else
- fmtstr = "%llu";
-#endif
- sprintf(buf, fmtstr, value);
- return buf;
-}
- /*
-** SHORTENSTRING -- return short version of a string
-**
-** If the string is already short, just return it. If it is too
-** long, return the head and tail of the string.
-**
-** Parameters:
-** s -- the string to shorten.
-** m -- the max length of the string.
-**
-** Returns:
-** Either s or a short version of s.
-*/
-
-char *
-shortenstring(s, m)
- register const char *s;
- int m;
-{
- int l;
- static char buf[MAXSHORTSTR + 1];
-
- l = strlen(s);
- if (l < m)
- return (char *) s;
- if (m > MAXSHORTSTR)
- m = MAXSHORTSTR;
- else if (m < 10)
- {
- if (m < 5)
- {
- strncpy(buf, s, m);
- buf[m] = '\0';
- return buf;
- }
- strncpy(buf, s, m - 3);
- strcpy(buf + m - 3, "...");
- return buf;
- }
- m = (m - 3) / 2;
- strncpy(buf, s, m);
- strcpy(buf + m, "...");
- strcpy(buf + m + 3, s + l - m);
- return buf;
-}
diff --git a/src/srvrsmtp.c b/src/srvrsmtp.c
deleted file mode 100644
index f4ffe8c..0000000
--- a/src/srvrsmtp.c
+++ /dev/null
@@ -1,1532 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-# include "sendmail.h"
-
-#ifndef lint
-#if SMTP
-static char sccsid[] = "@(#)srvrsmtp.c 8.187 (Berkeley) 10/23/1998 (with SMTP)";
-#else
-static char sccsid[] = "@(#)srvrsmtp.c 8.187 (Berkeley) 10/23/1998 (without SMTP)";
-#endif
-#endif /* not lint */
-
-# include <errno.h>
-
-# if SMTP
-
-/*
-** SMTP -- run the SMTP protocol.
-**
-** Parameters:
-** nullserver -- if non-NULL, rejection message for
-** all SMTP commands.
-** e -- the envelope.
-**
-** Returns:
-** never.
-**
-** Side Effects:
-** Reads commands from the input channel and processes
-** them.
-*/
-
-struct cmd
-{
- char *cmdname; /* command name */
- int cmdcode; /* internal code, see below */
-};
-
-/* values for cmdcode */
-# define CMDERROR 0 /* bad command */
-# define CMDMAIL 1 /* mail -- designate sender */
-# define CMDRCPT 2 /* rcpt -- designate recipient */
-# define CMDDATA 3 /* data -- send message text */
-# define CMDRSET 4 /* rset -- reset state */
-# define CMDVRFY 5 /* vrfy -- verify address */
-# define CMDEXPN 6 /* expn -- expand address */
-# define CMDNOOP 7 /* noop -- do nothing */
-# define CMDQUIT 8 /* quit -- close connection and die */
-# define CMDHELO 9 /* helo -- be polite */
-# define CMDHELP 10 /* help -- give usage info */
-# define CMDEHLO 11 /* ehlo -- extended helo (RFC 1425) */
-# define CMDETRN 12 /* etrn -- flush queue */
-/* non-standard commands */
-# define CMDONEX 16 /* onex -- sending one transaction only */
-# define CMDVERB 17 /* verb -- go into verbose mode */
-# define CMDXUSR 18 /* xusr -- initial (user) submission */
-/* use this to catch and log "door handle" attempts on your system */
-# define CMDLOGBOGUS 23 /* bogus command that should be logged */
-/* debugging-only commands, only enabled if SMTPDEBUG is defined */
-# define CMDDBGQSHOW 24 /* showq -- show send queue */
-# define CMDDBGDEBUG 25 /* debug -- set debug mode */
-
-static struct cmd CmdTab[] =
-{
- { "mail", CMDMAIL },
- { "rcpt", CMDRCPT },
- { "data", CMDDATA },
- { "rset", CMDRSET },
- { "vrfy", CMDVRFY },
- { "expn", CMDEXPN },
- { "help", CMDHELP },
- { "noop", CMDNOOP },
- { "quit", CMDQUIT },
- { "helo", CMDHELO },
- { "ehlo", CMDEHLO },
- { "etrn", CMDETRN },
- { "verb", CMDVERB },
- { "onex", CMDONEX },
- { "xusr", CMDXUSR },
- /* remaining commands are here only to trap and log attempts to use them */
- { "showq", CMDDBGQSHOW },
- { "debug", CMDDBGDEBUG },
- { "wiz", CMDLOGBOGUS },
-
- { NULL, CMDERROR }
-};
-
-bool OneXact = FALSE; /* one xaction only this run */
-char *CurSmtpClient; /* who's at the other end of channel */
-
-static char *skipword __P((char *volatile, char *));
-
-
-#define MAXBADCOMMANDS 25 /* maximum number of bad commands */
-#define MAXNOOPCOMMANDS 20 /* max "noise" commands before slowdown */
-#define MAXHELOCOMMANDS 3 /* max HELO/EHLO commands before slowdown */
-#define MAXVRFYCOMMANDS 6 /* max VRFY/EXPN commands before slowdown */
-#define MAXETRNCOMMANDS 8 /* max ETRN commands before slowdown */
-
-void
-smtp(nullserver, e)
- char *nullserver;
- register ENVELOPE *volatile e;
-{
- register char *volatile p;
- register struct cmd *c;
- char *cmd;
- auto ADDRESS *vrfyqueue;
- ADDRESS *a;
- volatile bool gotmail; /* mail command received */
- volatile bool gothello; /* helo command received */
- bool vrfy; /* set if this is a vrfy command */
- char *volatile protocol; /* sending protocol */
- char *volatile sendinghost; /* sending hostname */
- char *volatile peerhostname; /* name of SMTP peer or "localhost" */
- auto char *delimptr;
- char *id;
- volatile int nrcpts = 0; /* number of RCPT commands */
- bool doublequeue;
- volatile bool discard;
- volatile int badcommands = 0; /* count of bad commands */
- volatile int nverifies = 0; /* count of VRFY/EXPN commands */
- volatile int n_etrn = 0; /* count of ETRN commands */
- volatile int n_noop = 0; /* count of NOOP/VERB/ONEX etc cmds */
- volatile int n_helo = 0; /* count of HELO/EHLO commands */
- bool ok;
- volatile int lognullconnection = TRUE;
- register char *q;
- QUEUE_CHAR *new;
- char inp[MAXLINE];
- char cmdbuf[MAXLINE];
- extern ENVELOPE BlankEnvelope;
- extern void help __P((char *));
- extern void settime __P((ENVELOPE *));
- extern bool enoughdiskspace __P((long));
- extern int runinchild __P((char *, ENVELOPE *));
- extern void checksmtpattack __P((volatile int *, int, char *, ENVELOPE *));
-
- if (fileno(OutChannel) != fileno(stdout))
- {
- /* arrange for debugging output to go to remote host */
- (void) dup2(fileno(OutChannel), fileno(stdout));
- }
- settime(e);
- peerhostname = RealHostName;
- if (peerhostname == NULL)
- peerhostname = "localhost";
- CurHostName = peerhostname;
- CurSmtpClient = macvalue('_', e);
- if (CurSmtpClient == NULL)
- CurSmtpClient = CurHostName;
-
- /* check_relay may have set discard bit, save for later */
- discard = bitset(EF_DISCARD, e->e_flags);
-
- sm_setproctitle(TRUE, "server %s startup", CurSmtpClient);
-#if DAEMON
- if (LogLevel > 11)
- {
- /* log connection information */
- sm_syslog(LOG_INFO, NOQID,
- "SMTP connect from %.100s (%.100s)",
- CurSmtpClient, anynet_ntoa(&RealHostAddr));
- }
-#endif
-
- /* output the first line, inserting "ESMTP" as second word */
- expand(SmtpGreeting, inp, sizeof inp, e);
- p = strchr(inp, '\n');
- if (p != NULL)
- *p++ = '\0';
- id = strchr(inp, ' ');
- if (id == NULL)
- id = &inp[strlen(inp)];
- cmd = p == NULL ? "220 %.*s ESMTP%s" : "220-%.*s ESMTP%s";
- message(cmd, id - inp, inp, id);
-
- /* output remaining lines */
- while ((id = p) != NULL && (p = strchr(id, '\n')) != NULL)
- {
- *p++ = '\0';
- if (isascii(*id) && isspace(*id))
- id++;
- message("220-%s", id);
- }
- if (id != NULL)
- {
- if (isascii(*id) && isspace(*id))
- id++;
- message("220 %s", id);
- }
-
- protocol = NULL;
- sendinghost = macvalue('s', e);
- gothello = FALSE;
- gotmail = FALSE;
- for (;;)
- {
- /* arrange for backout */
- (void) setjmp(TopFrame);
- QuickAbort = FALSE;
- HoldErrs = FALSE;
- SuprErrs = FALSE;
- LogUsrErrs = FALSE;
- OnlyOneError = TRUE;
- e->e_flags &= ~(EF_VRFYONLY|EF_GLOBALERRS);
-
- /* setup for the read */
- e->e_to = NULL;
- Errors = 0;
- (void) fflush(stdout);
-
- /* read the input line */
- SmtpPhase = "server cmd read";
- sm_setproctitle(TRUE, "server %s cmd read", CurSmtpClient);
- p = sfgets(inp, sizeof inp, InChannel, TimeOuts.to_nextcommand,
- SmtpPhase);
-
- /* handle errors */
- if (p == NULL)
- {
- /* end of file, just die */
- disconnect(1, e);
- message("421 %s Lost input channel from %s",
- MyHostName, CurSmtpClient);
- if (LogLevel > (gotmail ? 1 : 19))
- sm_syslog(LOG_NOTICE, e->e_id,
- "lost input channel from %.100s",
- CurSmtpClient);
- if (lognullconnection && LogLevel > 5)
- sm_syslog(LOG_INFO, NULL,
- "Null connection from %.100s",
- CurSmtpClient);
-
- /*
- ** If have not accepted mail (DATA), do not bounce
- ** bad addresses back to sender.
- */
- if (bitset(EF_CLRQUEUE, e->e_flags))
- e->e_sendqueue = NULL;
-
- if (InChild)
- ExitStat = EX_QUIT;
- finis(TRUE, ExitStat);
- }
-
- /* clean up end of line */
- fixcrlf(inp, TRUE);
-
- /* echo command to transcript */
- if (e->e_xfp != NULL)
- fprintf(e->e_xfp, "<<< %s\n", inp);
-
- if (LogLevel >= 15)
- sm_syslog(LOG_INFO, e->e_id,
- "<-- %s",
- inp);
-
- if (e->e_id == NULL)
- sm_setproctitle(TRUE, "%s: %.80s", CurSmtpClient, inp);
- else
- sm_setproctitle(TRUE, "%s %s: %.80s", e->e_id, CurSmtpClient, inp);
-
- /* break off command */
- for (p = inp; isascii(*p) && isspace(*p); p++)
- continue;
- cmd = cmdbuf;
- while (*p != '\0' &&
- !(isascii(*p) && isspace(*p)) &&
- cmd < &cmdbuf[sizeof cmdbuf - 2])
- *cmd++ = *p++;
- *cmd = '\0';
-
- /* throw away leading whitespace */
- while (isascii(*p) && isspace(*p))
- p++;
-
- /* decode command */
- for (c = CmdTab; c->cmdname != NULL; c++)
- {
- if (!strcasecmp(c->cmdname, cmdbuf))
- break;
- }
-
- /* reset errors */
- errno = 0;
-
- /*
- ** Process command.
- **
- ** If we are running as a null server, return 550
- ** to everything.
- */
-
- if (nullserver != NULL)
- {
- switch (c->cmdcode)
- {
- case CMDQUIT:
- case CMDHELO:
- case CMDEHLO:
- case CMDNOOP:
- /* process normally */
- break;
-
- default:
- if (++badcommands > MAXBADCOMMANDS)
- sleep(1);
- usrerr("550 %s", nullserver);
- continue;
- }
- }
-
- /* non-null server */
- switch (c->cmdcode)
- {
- case CMDMAIL:
- case CMDEXPN:
- case CMDVRFY:
- case CMDETRN:
- lognullconnection = FALSE;
- }
-
- switch (c->cmdcode)
- {
- case CMDHELO: /* hello -- introduce yourself */
- case CMDEHLO: /* extended hello */
- if (c->cmdcode == CMDEHLO)
- {
- protocol = "ESMTP";
- SmtpPhase = "server EHLO";
- }
- else
- {
- protocol = "SMTP";
- SmtpPhase = "server HELO";
- }
-
- /* avoid denial-of-service */
- checksmtpattack(&n_helo, MAXHELOCOMMANDS, "HELO/EHLO", e);
-
- /* check for duplicate HELO/EHLO per RFC 1651 4.2 */
- if (gothello)
- {
- usrerr("503 %s Duplicate HELO/EHLO",
- MyHostName);
- break;
- }
-
- /* check for valid domain name (re 1123 5.2.5) */
- if (*p == '\0' && !AllowBogusHELO)
- {
- usrerr("501 %s requires domain address",
- cmdbuf);
- break;
- }
-
- /* check for long domain name (hides Received: info) */
- if (strlen(p) > MAXNAME)
- {
- usrerr("501 Invalid domain name");
- break;
- }
-
- for (q = p; *q != '\0'; q++)
- {
- if (!isascii(*q))
- break;
- if (isalnum(*q))
- continue;
- if (isspace(*q))
- {
- *q = '\0';
- break;
- }
- if (strchr("[].-_#", *q) == NULL)
- break;
- }
- if (*q == '\0')
- {
- q = "pleased to meet you";
- sendinghost = newstr(p);
- }
- else if (!AllowBogusHELO)
- {
- usrerr("501 Invalid domain name");
- break;
- }
- else
- {
- q = "accepting invalid domain name";
- }
-
- gothello = TRUE;
-
- /* print HELO response message */
- if (c->cmdcode != CMDEHLO || nullserver != NULL)
- {
- message("250 %s Hello %s, %s",
- MyHostName, CurSmtpClient, q);
- break;
- }
-
- message("250-%s Hello %s, %s",
- MyHostName, CurSmtpClient, q);
-
- /* print EHLO features list */
- if (!bitset(PRIV_NOEXPN, PrivacyFlags))
- {
- message("250-EXPN");
- if (!bitset(PRIV_NOVERB, PrivacyFlags))
- message("250-VERB");
- }
-#if MIME8TO7
- message("250-8BITMIME");
-#endif
- if (MaxMessageSize > 0)
- message("250-SIZE %ld", MaxMessageSize);
- else
- message("250-SIZE");
-#if DSN
- if (SendMIMEErrors)
- message("250-DSN");
-#endif
- message("250-ONEX");
- if (!bitset(PRIV_NOETRN, PrivacyFlags))
- message("250-ETRN");
- message("250-XUSR");
- message("250 HELP");
- break;
-
- case CMDMAIL: /* mail -- designate sender */
- SmtpPhase = "server MAIL";
-
- /* check for validity of this command */
- if (!gothello && bitset(PRIV_NEEDMAILHELO, PrivacyFlags))
- {
- usrerr("503 Polite people say HELO first");
- break;
- }
- if (gotmail)
- {
- usrerr("503 Sender already specified");
- break;
- }
- if (InChild)
- {
- errno = 0;
- syserr("503 Nested MAIL command: MAIL %s", p);
- finis(TRUE, ExitStat);
- }
-
- /* make sure we know who the sending host is */
- if (sendinghost == NULL)
- sendinghost = peerhostname;
-
- p = skipword(p, "from");
- if (p == NULL)
- break;
-
- /* fork a subprocess to process this command */
- if (runinchild("SMTP-MAIL", e) > 0)
- break;
- if (Errors > 0)
- goto undo_subproc_no_pm;
- if (!gothello)
- {
- auth_warning(e,
- "%s didn't use HELO protocol",
- CurSmtpClient);
- }
-#ifdef PICKY_HELO_CHECK
- if (strcasecmp(sendinghost, peerhostname) != 0 &&
- (strcasecmp(peerhostname, "localhost") != 0 ||
- strcasecmp(sendinghost, MyHostName) != 0))
- {
- auth_warning(e, "Host %s claimed to be %s",
- CurSmtpClient, sendinghost);
- }
-#endif
-
- if (protocol == NULL)
- protocol = "SMTP";
- define('r', protocol, e);
- define('s', sendinghost, e);
- initsys(e);
- if (Errors > 0)
- goto undo_subproc_no_pm;
- nrcpts = 0;
- e->e_flags |= EF_LOGSENDER|EF_CLRQUEUE;
- sm_setproctitle(TRUE, "%s %s: %.80s", e->e_id, CurSmtpClient, inp);
-
- /* child -- go do the processing */
- if (setjmp(TopFrame) > 0)
- {
- /* this failed -- undo work */
- undo_subproc_no_pm:
- e->e_flags &= ~EF_PM_NOTIFY;
- undo_subproc:
- if (InChild)
- {
- QuickAbort = FALSE;
- SuprErrs = TRUE;
- e->e_flags &= ~EF_FATALERRS;
- finis(TRUE, ExitStat);
- }
- break;
- }
- QuickAbort = TRUE;
-
- /* must parse sender first */
- delimptr = NULL;
- setsender(p, e, &delimptr, ' ', FALSE);
- if (delimptr != NULL && *delimptr != '\0')
- *delimptr++ = '\0';
- if (Errors > 0)
- goto undo_subproc_no_pm;
-
- /* do config file checking of the sender */
- if (rscheck("check_mail", p, NULL, e) != EX_OK ||
- Errors > 0)
- goto undo_subproc_no_pm;
-
- /* check for possible spoofing */
- if (RealUid != 0 && OpMode == MD_SMTP &&
- !wordinclass(RealUserName, 't') &&
- !bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) &&
- strcmp(e->e_from.q_user, RealUserName) != 0)
- {
- auth_warning(e, "%s owned process doing -bs",
- RealUserName);
- }
-
- /* now parse ESMTP arguments */
- e->e_msgsize = 0;
- p = delimptr;
- while (p != NULL && *p != '\0')
- {
- char *kp;
- char *vp = NULL;
- extern void mail_esmtp_args __P((char *, char *, ENVELOPE *));
-
- /* locate the beginning of the keyword */
- while (isascii(*p) && isspace(*p))
- p++;
- if (*p == '\0')
- break;
- kp = p;
-
- /* skip to the value portion */
- while ((isascii(*p) && isalnum(*p)) || *p == '-')
- p++;
- if (*p == '=')
- {
- *p++ = '\0';
- vp = p;
-
- /* skip to the end of the value */
- while (*p != '\0' && *p != ' ' &&
- !(isascii(*p) && iscntrl(*p)) &&
- *p != '=')
- p++;
- }
-
- if (*p != '\0')
- *p++ = '\0';
-
- if (tTd(19, 1))
- printf("MAIL: got arg %s=\"%s\"\n", kp,
- vp == NULL ? "<null>" : vp);
-
- mail_esmtp_args(kp, vp, e);
- if (Errors > 0)
- goto undo_subproc_no_pm;
- }
- if (Errors > 0)
- goto undo_subproc_no_pm;
-
- if (MaxMessageSize > 0 && e->e_msgsize > MaxMessageSize)
- {
- usrerr("552 Message size exceeds fixed maximum message size (%ld)",
- MaxMessageSize);
- goto undo_subproc_no_pm;
- }
-
- if (!enoughdiskspace(e->e_msgsize))
- {
- usrerr("452 Insufficient disk space; try again later");
- goto undo_subproc_no_pm;
- }
- if (Errors > 0)
- goto undo_subproc_no_pm;
- message("250 Sender ok");
- gotmail = TRUE;
- break;
-
- case CMDRCPT: /* rcpt -- designate recipient */
- if (!gotmail)
- {
- usrerr("503 Need MAIL before RCPT");
- break;
- }
- SmtpPhase = "server RCPT";
- if (setjmp(TopFrame) > 0)
- {
- e->e_flags &= ~EF_FATALERRS;
- break;
- }
- QuickAbort = TRUE;
- LogUsrErrs = TRUE;
-
- /* limit flooding of our machine */
- if (MaxRcptPerMsg > 0 && nrcpts >= MaxRcptPerMsg)
- {
- usrerr("452 Too many recipients");
- break;
- }
-
- if (e->e_sendmode != SM_DELIVER)
- e->e_flags |= EF_VRFYONLY;
-
- p = skipword(p, "to");
- if (p == NULL)
- break;
- a = parseaddr(p, NULLADDR, RF_COPYALL, ' ', &delimptr, e);
- if (Errors > 0)
- break;
- if (a == NULL)
- {
- usrerr("501 Missing recipient");
- break;
- }
-
- if (delimptr != NULL && *delimptr != '\0')
- *delimptr++ = '\0';
-
- /* do config file checking of the recipient */
- if (rscheck("check_rcpt", p, NULL, e) != EX_OK ||
- Errors > 0)
- break;
-
- /* now parse ESMTP arguments */
- p = delimptr;
- while (p != NULL && *p != '\0')
- {
- char *kp;
- char *vp = NULL;
- extern void rcpt_esmtp_args __P((ADDRESS *, char *, char *, ENVELOPE *));
-
- /* locate the beginning of the keyword */
- while (isascii(*p) && isspace(*p))
- p++;
- if (*p == '\0')
- break;
- kp = p;
-
- /* skip to the value portion */
- while ((isascii(*p) && isalnum(*p)) || *p == '-')
- p++;
- if (*p == '=')
- {
- *p++ = '\0';
- vp = p;
-
- /* skip to the end of the value */
- while (*p != '\0' && *p != ' ' &&
- !(isascii(*p) && iscntrl(*p)) &&
- *p != '=')
- p++;
- }
-
- if (*p != '\0')
- *p++ = '\0';
-
- if (tTd(19, 1))
- printf("RCPT: got arg %s=\"%s\"\n", kp,
- vp == NULL ? "<null>" : vp);
-
- rcpt_esmtp_args(a, kp, vp, e);
- if (Errors > 0)
- break;
- }
- if (Errors > 0)
- break;
-
- /* save in recipient list after ESMTP mods */
- a = recipient(a, &e->e_sendqueue, 0, e);
- if (Errors > 0)
- break;
-
- /* no errors during parsing, but might be a duplicate */
- e->e_to = a->q_paddr;
- if (!bitset(QBADADDR, a->q_flags))
- {
- message("250 Recipient ok%s",
- bitset(QQUEUEUP, a->q_flags) ?
- " (will queue)" : "");
- nrcpts++;
- }
- else
- {
- /* punt -- should keep message in ADDRESS.... */
- usrerr("550 Addressee unknown");
- }
- break;
-
- case CMDDATA: /* data -- text of mail */
- SmtpPhase = "server DATA";
- if (!gotmail)
- {
- usrerr("503 Need MAIL command");
- break;
- }
- else if (nrcpts <= 0)
- {
- usrerr("503 Need RCPT (recipient)");
- break;
- }
-
- /* put back discard bit */
- if (discard)
- e->e_flags |= EF_DISCARD;
-
- /* check to see if we need to re-expand aliases */
- /* also reset QBADADDR on already-diagnosted addrs */
- doublequeue = FALSE;
- for (a = e->e_sendqueue; a != NULL; a = a->q_next)
- {
- if (bitset(QVERIFIED, a->q_flags) &&
- !bitset(EF_DISCARD, e->e_flags))
- {
- /* need to re-expand aliases */
- doublequeue = TRUE;
- }
- if (bitset(QBADADDR, a->q_flags))
- {
- /* make this "go away" */
- a->q_flags |= QDONTSEND;
- a->q_flags &= ~QBADADDR;
- }
- }
-
- /* collect the text of the message */
- SmtpPhase = "collect";
- buffer_errors();
- collect(InChannel, TRUE, NULL, e);
- if (Errors > 0)
- {
- flush_errors(TRUE);
- buffer_errors();
- goto abortmessage;
- }
-
- /* make sure we actually do delivery */
- e->e_flags &= ~EF_CLRQUEUE;
-
- /* from now on, we have to operate silently */
- buffer_errors();
- e->e_errormode = EM_MAIL;
-
- /*
- ** Arrange to send to everyone.
- ** If sending to multiple people, mail back
- ** errors rather than reporting directly.
- ** In any case, don't mail back errors for
- ** anything that has happened up to
- ** now (the other end will do this).
- ** Truncate our transcript -- the mail has gotten
- ** to us successfully, and if we have
- ** to mail this back, it will be easier
- ** on the reader.
- ** Then send to everyone.
- ** Finally give a reply code. If an error has
- ** already been given, don't mail a
- ** message back.
- ** We goose error returns by clearing error bit.
- */
-
- SmtpPhase = "delivery";
- e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp);
- id = e->e_id;
-
- if (doublequeue)
- {
- /* make sure it is in the queue */
- queueup(e, FALSE);
- }
- else
- {
- /* send to all recipients */
- sendall(e, SM_DEFAULT);
- }
- e->e_to = NULL;
-
- /* issue success message */
- message("250 %s Message accepted for delivery", id);
-
- /* if we just queued, poke it */
- if (doublequeue &&
- e->e_sendmode != SM_QUEUE &&
- e->e_sendmode != SM_DEFER)
- {
- CurrentLA = getla();
-
- if (!shouldqueue(e->e_msgpriority, e->e_ctime))
- {
- unlockqueue(e);
- (void) dowork(id, TRUE, TRUE, e);
- }
- }
-
- abortmessage:
- /* if in a child, pop back to our parent */
- if (InChild)
- finis(TRUE, ExitStat);
-
- /* clean up a bit */
- gotmail = FALSE;
- dropenvelope(e, TRUE);
- CurEnv = e = newenvelope(e, CurEnv);
- e->e_flags = BlankEnvelope.e_flags;
- break;
-
- case CMDRSET: /* rset -- reset state */
- if (tTd(94, 100))
- message("451 Test failure");
- else
- message("250 Reset state");
-
- /* arrange to ignore any current send list */
- e->e_sendqueue = NULL;
- e->e_flags |= EF_CLRQUEUE;
- if (InChild)
- finis(TRUE, ExitStat);
-
- /* clean up a bit */
- gotmail = FALSE;
- SuprErrs = TRUE;
- dropenvelope(e, TRUE);
- CurEnv = e = newenvelope(e, CurEnv);
- break;
-
- case CMDVRFY: /* vrfy -- verify address */
- case CMDEXPN: /* expn -- expand address */
- checksmtpattack(&nverifies, MAXVRFYCOMMANDS,
- c->cmdcode == CMDVRFY ? "VRFY" : "EXPN", e);
- vrfy = c->cmdcode == CMDVRFY;
- if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN,
- PrivacyFlags))
- {
- if (vrfy)
- message("252 Cannot VRFY user; try RCPT to attempt delivery (or try finger)");
- else
- message("502 Sorry, we do not allow this operation");
- if (LogLevel > 5)
- sm_syslog(LOG_INFO, e->e_id,
- "%.100s: %s [rejected]",
- CurSmtpClient,
- shortenstring(inp, MAXSHORTSTR));
- break;
- }
- else if (!gothello &&
- bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO,
- PrivacyFlags))
- {
- usrerr("503 I demand that you introduce yourself first");
- break;
- }
- if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0)
- break;
- if (Errors > 0)
- goto undo_subproc;
- if (LogLevel > 5)
- sm_syslog(LOG_INFO, e->e_id,
- "%.100s: %s",
- CurSmtpClient,
- shortenstring(inp, MAXSHORTSTR));
- if (setjmp(TopFrame) > 0)
- goto undo_subproc;
- QuickAbort = TRUE;
- vrfyqueue = NULL;
- if (vrfy)
- e->e_flags |= EF_VRFYONLY;
- while (*p != '\0' && isascii(*p) && isspace(*p))
- p++;
- if (*p == '\0')
- {
- usrerr("501 Argument required");
- }
- else
- {
- (void) sendtolist(p, NULLADDR, &vrfyqueue, 0, e);
- }
- if (Errors > 0)
- goto undo_subproc;
- if (vrfyqueue == NULL)
- {
- usrerr("554 Nothing to %s", vrfy ? "VRFY" : "EXPN");
- }
- while (vrfyqueue != NULL)
- {
- extern void printvrfyaddr __P((ADDRESS *, bool, bool));
-
- a = vrfyqueue;
- while ((a = a->q_next) != NULL &&
- bitset(QDONTSEND|QBADADDR, a->q_flags))
- continue;
- if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags))
- printvrfyaddr(vrfyqueue, a == NULL, vrfy);
- vrfyqueue = vrfyqueue->q_next;
- }
- if (InChild)
- finis(TRUE, ExitStat);
- break;
-
- case CMDETRN: /* etrn -- force queue flush */
- if (bitset(PRIV_NOETRN, PrivacyFlags))
- {
- message("502 Sorry, we do not allow this operation");
- if (LogLevel > 5)
- sm_syslog(LOG_INFO, e->e_id,
- "%.100s: %s [rejected]",
- CurSmtpClient,
- shortenstring(inp, MAXSHORTSTR));
- break;
- }
-
- if (strlen(p) <= 0)
- {
- usrerr("500 Parameter required");
- break;
- }
-
- /* crude way to avoid denial-of-service attacks */
- checksmtpattack(&n_etrn, MAXETRNCOMMANDS, "ETRN", e);
-
- if (LogLevel > 5)
- sm_syslog(LOG_INFO, e->e_id,
- "%.100s: ETRN %s",
- CurSmtpClient,
- shortenstring(p, MAXSHORTSTR));
-
- id = p;
- if (*id == '@')
- id++;
- else
- *--id = '@';
-
- if ((new = (QUEUE_CHAR *)malloc(sizeof(QUEUE_CHAR))) == NULL)
- {
- syserr("500 ETRN out of memory");
- break;
- }
- new->queue_match = id;
- new->queue_next = NULL;
- QueueLimitRecipient = new;
- ok = runqueue(TRUE, TRUE);
- free(QueueLimitRecipient);
- QueueLimitRecipient = NULL;
- if (ok && Errors == 0)
- message("250 Queuing for node %s started", p);
- break;
-
- case CMDHELP: /* help -- give user info */
- help(p);
- break;
-
- case CMDNOOP: /* noop -- do nothing */
- checksmtpattack(&n_noop, MAXNOOPCOMMANDS, "NOOP", e);
- message("250 OK");
- break;
-
- case CMDQUIT: /* quit -- leave mail */
- message("221 %s closing connection", MyHostName);
-
-doquit:
- /* arrange to ignore any current send list */
- e->e_sendqueue = NULL;
-
- /* avoid future 050 messages */
- disconnect(1, e);
-
- if (InChild)
- ExitStat = EX_QUIT;
- if (lognullconnection && LogLevel > 5)
- sm_syslog(LOG_INFO, NULL,
- "Null connection from %.100s",
- CurSmtpClient);
- finis(TRUE, ExitStat);
-
- case CMDVERB: /* set verbose mode */
- if (bitset(PRIV_NOEXPN, PrivacyFlags) ||
- bitset(PRIV_NOVERB, PrivacyFlags))
- {
- /* this would give out the same info */
- message("502 Verbose unavailable");
- break;
- }
- checksmtpattack(&n_noop, MAXNOOPCOMMANDS, "VERB", e);
- Verbose = 1;
- e->e_sendmode = SM_DELIVER;
- message("250 Verbose mode");
- break;
-
- case CMDONEX: /* doing one transaction only */
- checksmtpattack(&n_noop, MAXNOOPCOMMANDS, "ONEX", e);
- OneXact = TRUE;
- message("250 Only one transaction");
- break;
-
- case CMDXUSR: /* initial (user) submission */
- checksmtpattack(&n_noop, MAXNOOPCOMMANDS, "XUSR", e);
- UserSubmission = TRUE;
- message("250 Initial submission");
- break;
-
-# if SMTPDEBUG
- case CMDDBGQSHOW: /* show queues */
- printf("Send Queue=");
- printaddr(e->e_sendqueue, TRUE);
- break;
-
- case CMDDBGDEBUG: /* set debug mode */
- tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
- tTflag(p);
- message("200 Debug set");
- break;
-
-# else /* not SMTPDEBUG */
- case CMDDBGQSHOW: /* show queues */
- case CMDDBGDEBUG: /* set debug mode */
-# endif /* SMTPDEBUG */
- case CMDLOGBOGUS: /* bogus command */
- if (LogLevel > 0)
- sm_syslog(LOG_CRIT, e->e_id,
- "\"%s\" command from %.100s (%.100s)",
- c->cmdname, CurSmtpClient,
- anynet_ntoa(&RealHostAddr));
- /* FALL THROUGH */
-
- case CMDERROR: /* unknown command */
- if (++badcommands > MAXBADCOMMANDS)
- {
- message("421 %s Too many bad commands; closing connection",
- MyHostName);
- goto doquit;
- }
-
- usrerr("500 Command unrecognized: \"%s\"",
- shortenstring(inp, MAXSHORTSTR));
- break;
-
- default:
- errno = 0;
- syserr("500 smtp: unknown code %d", c->cmdcode);
- break;
- }
- }
-}
- /*
-** CHECKSMTPATTACK -- check for denial-of-service attack by repetition
-**
-** Parameters:
-** pcounter -- pointer to a counter for this command.
-** maxcount -- maximum value for this counter before we
-** slow down.
-** cname -- command name for logging.
-** e -- the current envelope.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Slows down if we seem to be under attack.
-*/
-
-void
-checksmtpattack(pcounter, maxcount, cname, e)
- volatile int *pcounter;
- int maxcount;
- char *cname;
- ENVELOPE *e;
-{
- if (++(*pcounter) >= maxcount)
- {
- if (*pcounter == maxcount && LogLevel > 5)
- {
- sm_syslog(LOG_INFO, e->e_id,
- "%.100s: %.40s attack?",
- CurSmtpClient, cname);
- }
- sleep(*pcounter / maxcount);
- }
-}
- /*
-** SKIPWORD -- skip a fixed word.
-**
-** Parameters:
-** p -- place to start looking.
-** w -- word to skip.
-**
-** Returns:
-** p following w.
-** NULL on error.
-**
-** Side Effects:
-** clobbers the p data area.
-*/
-
-static char *
-skipword(p, w)
- register char *volatile p;
- char *w;
-{
- register char *q;
- char *firstp = p;
-
- /* find beginning of word */
- while (isascii(*p) && isspace(*p))
- p++;
- q = p;
-
- /* find end of word */
- while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p)))
- p++;
- while (isascii(*p) && isspace(*p))
- *p++ = '\0';
- if (*p != ':')
- {
- syntax:
- usrerr("501 Syntax error in parameters scanning \"%s\"",
- shortenstring(firstp, MAXSHORTSTR));
- return (NULL);
- }
- *p++ = '\0';
- while (isascii(*p) && isspace(*p))
- p++;
-
- if (*p == '\0')
- goto syntax;
-
- /* see if the input word matches desired word */
- if (strcasecmp(q, w))
- goto syntax;
-
- return (p);
-}
- /*
-** MAIL_ESMTP_ARGS -- process ESMTP arguments from MAIL line
-**
-** Parameters:
-** kp -- the parameter key.
-** vp -- the value of that parameter.
-** e -- the envelope.
-**
-** Returns:
-** none.
-*/
-
-void
-mail_esmtp_args(kp, vp, e)
- char *kp;
- char *vp;
- ENVELOPE *e;
-{
- if (strcasecmp(kp, "size") == 0)
- {
- if (vp == NULL)
- {
- usrerr("501 SIZE requires a value");
- /* NOTREACHED */
- }
-# if defined(__STDC__) && !defined(BROKEN_ANSI_LIBRARY)
- e->e_msgsize = strtoul(vp, (char **) NULL, 10);
-# else
- e->e_msgsize = strtol(vp, (char **) NULL, 10);
-# endif
- }
- else if (strcasecmp(kp, "body") == 0)
- {
- if (vp == NULL)
- {
- usrerr("501 BODY requires a value");
- /* NOTREACHED */
- }
- else if (strcasecmp(vp, "8bitmime") == 0)
- {
- SevenBitInput = FALSE;
- }
- else if (strcasecmp(vp, "7bit") == 0)
- {
- SevenBitInput = TRUE;
- }
- else
- {
- usrerr("501 Unknown BODY type %s",
- vp);
- /* NOTREACHED */
- }
- e->e_bodytype = newstr(vp);
- }
- else if (strcasecmp(kp, "envid") == 0)
- {
- if (vp == NULL)
- {
- usrerr("501 ENVID requires a value");
- /* NOTREACHED */
- }
- if (!xtextok(vp))
- {
- usrerr("501 Syntax error in ENVID parameter value");
- /* NOTREACHED */
- }
- if (e->e_envid != NULL)
- {
- usrerr("501 Duplicate ENVID parameter");
- /* NOTREACHED */
- }
- e->e_envid = newstr(vp);
- }
- else if (strcasecmp(kp, "ret") == 0)
- {
- if (vp == NULL)
- {
- usrerr("501 RET requires a value");
- /* NOTREACHED */
- }
- if (bitset(EF_RET_PARAM, e->e_flags))
- {
- usrerr("501 Duplicate RET parameter");
- /* NOTREACHED */
- }
- e->e_flags |= EF_RET_PARAM;
- if (strcasecmp(vp, "hdrs") == 0)
- e->e_flags |= EF_NO_BODY_RETN;
- else if (strcasecmp(vp, "full") != 0)
- {
- usrerr("501 Bad argument \"%s\" to RET", vp);
- /* NOTREACHED */
- }
- }
- else
- {
- usrerr("501 %s parameter unrecognized", kp);
- /* NOTREACHED */
- }
-}
- /*
-** RCPT_ESMTP_ARGS -- process ESMTP arguments from RCPT line
-**
-** Parameters:
-** a -- the address corresponding to the To: parameter.
-** kp -- the parameter key.
-** vp -- the value of that parameter.
-** e -- the envelope.
-**
-** Returns:
-** none.
-*/
-
-void
-rcpt_esmtp_args(a, kp, vp, e)
- ADDRESS *a;
- char *kp;
- char *vp;
- ENVELOPE *e;
-{
- if (strcasecmp(kp, "notify") == 0)
- {
- char *p;
-
- if (vp == NULL)
- {
- usrerr("501 NOTIFY requires a value");
- /* NOTREACHED */
- }
- a->q_flags &= ~(QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY);
- a->q_flags |= QHASNOTIFY;
- if (strcasecmp(vp, "never") == 0)
- return;
- for (p = vp; p != NULL; vp = p)
- {
- p = strchr(p, ',');
- if (p != NULL)
- *p++ = '\0';
- if (strcasecmp(vp, "success") == 0)
- a->q_flags |= QPINGONSUCCESS;
- else if (strcasecmp(vp, "failure") == 0)
- a->q_flags |= QPINGONFAILURE;
- else if (strcasecmp(vp, "delay") == 0)
- a->q_flags |= QPINGONDELAY;
- else
- {
- usrerr("501 Bad argument \"%s\" to NOTIFY",
- vp);
- /* NOTREACHED */
- }
- }
- }
- else if (strcasecmp(kp, "orcpt") == 0)
- {
- if (vp == NULL)
- {
- usrerr("501 ORCPT requires a value");
- /* NOTREACHED */
- }
- if (strchr(vp, ';') == NULL || !xtextok(vp))
- {
- usrerr("501 Syntax error in ORCPT parameter value");
- /* NOTREACHED */
- }
- if (a->q_orcpt != NULL)
- {
- usrerr("501 Duplicate ORCPT parameter");
- /* NOTREACHED */
- }
- a->q_orcpt = newstr(vp);
- }
- else
- {
- usrerr("501 %s parameter unrecognized", kp);
- /* NOTREACHED */
- }
-}
- /*
-** PRINTVRFYADDR -- print an entry in the verify queue
-**
-** Parameters:
-** a -- the address to print
-** last -- set if this is the last one.
-** vrfy -- set if this is a VRFY command.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** Prints the appropriate 250 codes.
-*/
-
-void
-printvrfyaddr(a, last, vrfy)
- register ADDRESS *a;
- bool last;
- bool vrfy;
-{
- char fmtbuf[20];
-
- if (vrfy && a->q_mailer != NULL &&
- !bitnset(M_VRFY250, a->q_mailer->m_flags))
- strcpy(fmtbuf, "252");
- else
- strcpy(fmtbuf, "250");
- fmtbuf[3] = last ? ' ' : '-';
-
- if (a->q_fullname == NULL)
- {
- if (strchr(a->q_user, '@') == NULL)
- strcpy(&fmtbuf[4], "<%s@%s>");
- else
- strcpy(&fmtbuf[4], "<%s>");
- message(fmtbuf, a->q_user, MyHostName);
- }
- else
- {
- if (strchr(a->q_user, '@') == NULL)
- strcpy(&fmtbuf[4], "%s <%s@%s>");
- else
- strcpy(&fmtbuf[4], "%s <%s>");
- message(fmtbuf, a->q_fullname, a->q_user, MyHostName);
- }
-}
- /*
-** RUNINCHILD -- return twice -- once in the child, then in the parent again
-**
-** Parameters:
-** label -- a string used in error messages
-**
-** Returns:
-** zero in the child
-** one in the parent
-**
-** Side Effects:
-** none.
-*/
-
-int
-runinchild(label, e)
- char *label;
- register ENVELOPE *e;
-{
- pid_t childpid;
-
- if (!OneXact)
- {
- /*
- ** Disable child process reaping, in case ETRN has preceeded
- ** MAIL command, and then fork.
- */
-
- (void) blocksignal(SIGCHLD);
-
- childpid = dofork();
- if (childpid < 0)
- {
- syserr("451 %s: cannot fork", label);
- (void) releasesignal(SIGCHLD);
- return (1);
- }
- if (childpid > 0)
- {
- auto int st;
-
- /* parent -- wait for child to complete */
- sm_setproctitle(TRUE, "server %s child wait", CurSmtpClient);
- st = waitfor(childpid);
- if (st == -1)
- syserr("451 %s: lost child", label);
- else if (!WIFEXITED(st))
- syserr("451 %s: died on signal %d",
- label, st & 0177);
-
- /* if we exited on a QUIT command, complete the process */
- if (WEXITSTATUS(st) == EX_QUIT)
- {
- disconnect(1, e);
- finis(TRUE, ExitStat);
- }
-
- /* restore the child signal */
- (void) releasesignal(SIGCHLD);
-
- return (1);
- }
- else
- {
- /* child */
- InChild = TRUE;
- QuickAbort = FALSE;
- clearenvelope(e, FALSE);
- (void) setsignal(SIGCHLD, SIG_DFL);
- (void) releasesignal(SIGCHLD);
- }
- }
- return (0);
-}
-
-# endif /* SMTP */
- /*
-** HELP -- implement the HELP command.
-**
-** Parameters:
-** topic -- the topic we want help for.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** outputs the help file to message output.
-*/
-
-void
-help(topic)
- char *topic;
-{
- register FILE *hf;
- int len;
- bool noinfo;
- int sff = SFF_OPENASROOT|SFF_REGONLY;
- char buf[MAXLINE];
- extern char Version[];
-
- if (DontLockReadFiles)
- sff |= SFF_NOLOCK;
- if (!bitset(DBS_HELPFILEINUNSAFEDIRPATH, DontBlameSendmail))
- sff |= SFF_SAFEDIRPATH;
-
- if (HelpFile == NULL ||
- (hf = safefopen(HelpFile, O_RDONLY, 0444, sff)) == NULL)
- {
- /* no help */
- errno = 0;
- message("502 Sendmail %s -- HELP not implemented", Version);
- return;
- }
-
- if (topic == NULL || *topic == '\0')
- {
- topic = "smtp";
- message("214-This is Sendmail version %s", Version);
- noinfo = FALSE;
- }
- else
- {
- makelower(topic);
- noinfo = TRUE;
- }
-
- len = strlen(topic);
-
- while (fgets(buf, sizeof buf, hf) != NULL)
- {
- if (strncmp(buf, topic, len) == 0)
- {
- register char *p;
-
- p = strchr(buf, '\t');
- if (p == NULL)
- p = buf;
- else
- p++;
- fixcrlf(p, TRUE);
- message("214-%s", p);
- noinfo = FALSE;
- }
- }
-
- if (noinfo)
- message("504 HELP topic \"%.10s\" unknown", topic);
- else
- message("214 End of HELP info");
- (void) fclose(hf);
-}
diff --git a/src/stab.c b/src/stab.c
deleted file mode 100644
index 37b87a3..0000000
--- a/src/stab.c
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)stab.c 8.19 (Berkeley) 5/19/1998";
-#endif /* not lint */
-
-# include "sendmail.h"
-
-/*
-** STAB -- manage the symbol table
-**
-** Parameters:
-** name -- the name to be looked up or inserted.
-** type -- the type of symbol.
-** op -- what to do:
-** ST_ENTER -- enter the name if not
-** already present.
-** ST_FIND -- find it only.
-**
-** Returns:
-** pointer to a STAB entry for this name.
-** NULL if not found and not entered.
-**
-** Side Effects:
-** can update the symbol table.
-*/
-
-# define STABSIZE 2003
-
-static STAB *SymTab[STABSIZE];
-
-STAB *
-stab(name, type, op)
- char *name;
- int type;
- int op;
-{
- register STAB *s;
- register STAB **ps;
- register int hfunc;
- register char *p;
- int len;
- extern char lower __P((char));
-
- if (tTd(36, 5))
- printf("STAB: %s %d ", name, type);
-
- /*
- ** Compute the hashing function
- */
-
- hfunc = type;
- for (p = name; *p != '\0'; p++)
- hfunc = ((hfunc << 1) ^ (lower(*p) & 0377)) % STABSIZE;
-
- if (tTd(36, 9))
- printf("(hfunc=%d) ", hfunc);
-
- ps = &SymTab[hfunc];
- if (type == ST_MACRO || type == ST_RULESET)
- {
- while ((s = *ps) != NULL &&
- (s->s_type != type || strcmp(name, s->s_name)))
- ps = &s->s_next;
- }
- else
- {
- while ((s = *ps) != NULL &&
- (s->s_type != type || strcasecmp(name, s->s_name)))
- ps = &s->s_next;
- }
-
- /*
- ** Dispose of the entry.
- */
-
- if (s != NULL || op == ST_FIND)
- {
- if (tTd(36, 5))
- {
- if (s == NULL)
- printf("not found\n");
- else
- {
- long *lp = (long *) s->s_class;
-
- printf("type %d val %lx %lx %lx %lx\n",
- s->s_type, lp[0], lp[1], lp[2], lp[3]);
- }
- }
- return (s);
- }
-
- /*
- ** Make a new entry and link it in.
- */
-
- if (tTd(36, 5))
- printf("entered\n");
-
- /* determine size of new entry */
-#if _FFR_MEMORY_MISER
- switch (type)
- {
- case ST_CLASS:
- len = sizeof s->s_class;
- break;
-
- case ST_ADDRESS:
- len = sizeof s->s_address;
- break;
-
- case ST_MAILER:
- len = sizeof s->s_mailer;
-
- case ST_ALIAS:
- len = sizeof s->s_alias;
- break;
-
- case ST_MAPCLASS:
- len = sizeof s->s_mapclass;
- break;
-
- case ST_MAP:
- len = sizeof s->s_map;
- break;
-
- case ST_HOSTSIG:
- len = sizeof s->s_hostsig;
- break;
-
- case ST_NAMECANON:
- len = sizeof s->s_namecanon;
- break;
-
- case ST_MACRO:
- len = sizeof s->s_macro;
- break;
-
- case ST_RULESET:
- len = sizeof s->s_ruleset;
- break;
-
- case ST_SERVICE:
- len = sizeof s->s_service;
- break;
-
- case ST_HEADER:
- len = sizeof s->s_header;
- break;
-
- default:
- if (type >= ST_MCI)
- len = sizeof s->s_mci;
- else
- {
- syserr("stab: unknown symbol type %d", type);
- len = sizeof s->s_value;
- }
- break;
- }
- len += sizeof *s - sizeof s->s_value;
-#else
- len = sizeof *s;
-#endif
-
- /* make new entry */
- s = (STAB *) xalloc(len);
- bzero((char *) s, len);
- s->s_name = newstr(name);
- s->s_type = type;
- s->s_len = len;
-
- /* link it in */
- *ps = s;
-
- return (s);
-}
- /*
-** STABAPPLY -- apply function to all stab entries
-**
-** Parameters:
-** func -- the function to apply. It will be given one
-** parameter (the stab entry).
-** arg -- an arbitrary argument, passed to func.
-**
-** Returns:
-** none.
-*/
-
-void
-stabapply(func, arg)
- void (*func)__P((STAB *, int));
- int arg;
-{
- register STAB **shead;
- register STAB *s;
-
- for (shead = SymTab; shead < &SymTab[STABSIZE]; shead++)
- {
- for (s = *shead; s != NULL; s = s->s_next)
- {
- if (tTd(36, 90))
- printf("stabapply: trying %d/%s\n",
- s->s_type, s->s_name);
- func(s, arg);
- }
- }
-}
diff --git a/src/stats.c b/src/stats.c
deleted file mode 100644
index b1162ff..0000000
--- a/src/stats.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)stats.c 8.22 (Berkeley) 5/19/1998";
-#endif /* not lint */
-
-# include "sendmail.h"
-# include "mailstats.h"
-
-struct statistics Stat;
-
-bool GotStats = FALSE; /* set when we have stats to merge */
-
-#define ONE_K 1000 /* one thousand (twenty-four?) */
-#define KBYTES(x) (((x) + (ONE_K - 1)) / ONE_K)
- /*
-** MARKSTATS -- mark statistics
-*/
-
-void
-markstats(e, to, reject)
- register ENVELOPE *e;
- register ADDRESS *to;
- bool reject;
-{
- if (reject == TRUE)
- {
- if (e->e_from.q_mailer != NULL)
- {
- if (bitset(EF_DISCARD, e->e_flags))
- Stat.stat_nd[e->e_from.q_mailer->m_mno]++;
- else
- Stat.stat_nr[e->e_from.q_mailer->m_mno]++;
- }
- }
- else if (to == NULL)
- {
- if (e->e_from.q_mailer != NULL)
- {
- Stat.stat_nf[e->e_from.q_mailer->m_mno]++;
- Stat.stat_bf[e->e_from.q_mailer->m_mno] +=
- KBYTES(e->e_msgsize);
- }
- }
- else
- {
- Stat.stat_nt[to->q_mailer->m_mno]++;
- Stat.stat_bt[to->q_mailer->m_mno] += KBYTES(e->e_msgsize);
- }
- GotStats = TRUE;
-}
- /*
-** POSTSTATS -- post statistics in the statistics file
-**
-** Parameters:
-** sfile -- the name of the statistics file.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** merges the Stat structure with the sfile file.
-*/
-
-void
-poststats(sfile)
- char *sfile;
-{
- register int fd;
- int sff = SFF_REGONLY|SFF_OPENASROOT;
- struct statistics stat;
- extern off_t lseek();
-
- if (sfile == NULL || !GotStats)
- return;
-
- (void) time(&Stat.stat_itime);
- Stat.stat_size = sizeof Stat;
- Stat.stat_magic = STAT_MAGIC;
- Stat.stat_version = STAT_VERSION;
-
- if (!bitset(DBS_WRITESTATSTOSYMLINK, DontBlameSendmail))
- sff |= SFF_NOSLINK;
- if (!bitset(DBS_WRITESTATSTOHARDLINK, DontBlameSendmail))
- sff |= SFF_NOHLINK;
-
- fd = safeopen(sfile, O_RDWR, 0644, sff);
- if (fd < 0)
- {
- if (LogLevel > 12)
- sm_syslog(LOG_INFO, NOQID, "poststats: %s: %s",
- sfile, errstring(errno));
- errno = 0;
- return;
- }
- if (read(fd, (char *) &stat, sizeof stat) == sizeof stat &&
- stat.stat_size == sizeof stat &&
- stat.stat_magic == Stat.stat_magic &&
- stat.stat_version == Stat.stat_version)
- {
- /* merge current statistics into statfile */
- register int i;
-
- for (i = 0; i < MAXMAILERS; i++)
- {
- stat.stat_nf[i] += Stat.stat_nf[i];
- stat.stat_bf[i] += Stat.stat_bf[i];
- stat.stat_nt[i] += Stat.stat_nt[i];
- stat.stat_bt[i] += Stat.stat_bt[i];
- stat.stat_nr[i] += Stat.stat_nr[i];
- stat.stat_nd[i] += Stat.stat_nd[i];
- }
- }
- else
- bcopy((char *) &Stat, (char *) &stat, sizeof stat);
-
- /* write out results */
- (void) lseek(fd, (off_t) 0, 0);
- (void) write(fd, (char *) &stat, sizeof stat);
- (void) close(fd);
-
- /* clear the structure to avoid future disappointment */
- bzero(&Stat, sizeof stat);
- GotStats = FALSE;
-}
diff --git a/src/sysexits.c b/src/sysexits.c
deleted file mode 100644
index c7934c7..0000000
--- a/src/sysexits.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)sysexits.c 8.13 (Berkeley) 5/24/1998";
-#endif /* not lint */
-
-#include "sendmail.h"
-
-/*
-** SYSEXITS.C -- error messages corresponding to sysexits.h
-**
-** If the first character of the string is a colon, interpolate
-** the current errno after the rest of the string.
-*/
-
-char *SysExMsg[] =
-{
- /* 64 USAGE */ " 500 Bad usage",
- /* 65 DATAERR */ " 501 Data format error",
- /* 66 NOINPUT */ ":550 Cannot open input",
- /* 67 NOUSER */ " 550 User unknown",
- /* 68 NOHOST */ " 550 Host unknown",
- /* 69 UNAVAILABLE */ " 554 Service unavailable",
- /* 70 SOFTWARE */ ":554 Internal error",
- /* 71 OSERR */ ":451 Operating system error",
- /* 72 OSFILE */ ":554 System file missing",
- /* 73 CANTCREAT */ ":550 Can't create output",
- /* 74 IOERR */ ":451 I/O error",
- /* 75 TEMPFAIL */ " 250 Deferred",
- /* 76 PROTOCOL */ " 554 Remote protocol error",
- /* 77 NOPERM */ ":550 Insufficient permission",
- /* 78 CONFIG */ " 554 Local configuration error",
-};
-
-int N_SysEx = sizeof(SysExMsg) / sizeof(SysExMsg[0]);
- /*
-** DSNTOEXITSTAT -- convert DSN-style error code to EX_ style.
-**
-** Parameters:
-** dsncode -- the text of the DSN-style code.
-**
-** Returns:
-** The corresponding exit status.
-*/
-
-int
-dsntoexitstat(dsncode)
- char *dsncode;
-{
- int code2, code3;
-
- /* first the easy cases.... */
- if (*dsncode == '2')
- return EX_OK;
- if (*dsncode == '4')
- return EX_TEMPFAIL;
-
- /* now decode the other two field parts */
- if (*++dsncode == '.')
- dsncode++;
- code2 = atoi(dsncode);
- while (*dsncode != '\0' && *dsncode != '.')
- dsncode++;
- if (*dsncode != '\0')
- dsncode++;
- code3 = atoi(dsncode);
-
- /* and do a nested switch to work them out */
- switch (code2)
- {
- case 0: /* Other or Undefined status */
- return EX_UNAVAILABLE;
-
- case 1: /* Address Status */
- switch (code3)
- {
- case 0: /* Other Address Status */
- return EX_DATAERR;
-
- case 1: /* Bad destination mailbox address */
- case 6: /* Mailbox has moved, No forwarding address */
- return EX_NOUSER;
-
- case 2: /* Bad destination system address */
- case 8: /* Bad senders system address */
- return EX_NOHOST;
-
- case 3: /* Bad destination mailbox address syntax */
- case 7: /* Bad senders mailbox address syntax */
- return EX_USAGE;
-
- case 4: /* Destination mailbox address ambiguous */
- return EX_UNAVAILABLE;
-
- case 5: /* Destination address valid */
- return EX_OK;
- }
- break;
-
- case 2: /* Mailbox Status */
- switch (code3)
- {
- case 0: /* Other or Undefined mailbox status */
- case 1: /* Mailbox disabled, not acccepting messages */
- case 2: /* Mailbox full */
- case 4: /* Mailing list expansion problem */
- return EX_UNAVAILABLE;
-
- case 3: /* Message length exceeds administrative lim */
- return EX_DATAERR;
- }
- break;
-
- case 3: /* System Status */
- return EX_OSERR;
-
- case 4: /* Network and Routing Status */
- switch (code3)
- {
- case 0: /* Other or undefined network or routing stat */
- return EX_IOERR;
-
- case 1: /* No answer from host */
- case 3: /* Routing server failure */
- case 5: /* Network congestion */
- return EX_TEMPFAIL;
-
- case 2: /* Bad connection */
- return EX_IOERR;
-
- case 4: /* Unable to route */
- return EX_PROTOCOL;
-
- case 6: /* Routing loop detected */
- return EX_CONFIG;
-
- case 7: /* Delivery time expired */
- return EX_UNAVAILABLE;
- }
- break;
-
- case 5: /* Protocol Status */
- return EX_PROTOCOL;
-
- case 6: /* Message Content or Media Status */
- return EX_UNAVAILABLE;
-
- case 7: /* Security Status */
- return EX_DATAERR;
- }
- return EX_CONFIG;
-}
diff --git a/src/sysexits.h b/src/sysexits.h
deleted file mode 100644
index 464cb11..0000000
--- a/src/sysexits.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (c) 1987, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * 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 the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University 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 THE REGENTS 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 THE REGENTS 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.
- *
- * @(#)sysexits.h 8.1 (Berkeley) 6/2/93
- */
-
-#ifndef _SYSEXITS_H_
-#define _SYSEXITS_H_
-
-/*
- * SYSEXITS.H -- Exit status codes for system programs.
- *
- * This include file attempts to categorize possible error
- * exit statuses for system programs, notably delivermail
- * and the Berkeley network.
- *
- * Error numbers begin at EX__BASE to reduce the possibility of
- * clashing with other exit statuses that random programs may
- * already return. The meaning of the codes is approximately
- * as follows:
- *
- * EX_USAGE -- The command was used incorrectly, e.g., with
- * the wrong number of arguments, a bad flag, a bad
- * syntax in a parameter, or whatever.
- * EX_DATAERR -- The input data was incorrect in some way.
- * This should only be used for user's data & not
- * system files.
- * EX_NOINPUT -- An input file (not a system file) did not
- * exist or was not readable. This could also include
- * errors like "No message" to a mailer (if it cared
- * to catch it).
- * EX_NOUSER -- The user specified did not exist. This might
- * be used for mail addresses or remote logins.
- * EX_NOHOST -- The host specified did not exist. This is used
- * in mail addresses or network requests.
- * EX_UNAVAILABLE -- A service is unavailable. This can occur
- * if a support program or file does not exist. This
- * can also be used as a catchall message when something
- * you wanted to do doesn't work, but you don't know
- * why.
- * EX_SOFTWARE -- An internal software error has been detected.
- * This should be limited to non-operating system related
- * errors as possible.
- * EX_OSERR -- An operating system error has been detected.
- * This is intended to be used for such things as "cannot
- * fork", "cannot create pipe", or the like. It includes
- * things like getuid returning a user that does not
- * exist in the passwd file.
- * EX_OSFILE -- Some system file (e.g., /etc/passwd, /etc/utmp,
- * etc.) does not exist, cannot be opened, or has some
- * sort of error (e.g., syntax error).
- * EX_CANTCREAT -- A (user specified) output file cannot be
- * created.
- * EX_IOERR -- An error occurred while doing I/O on some file.
- * EX_TEMPFAIL -- temporary failure, indicating something that
- * is not really an error. In sendmail, this means
- * that a mailer (e.g.) could not create a connection,
- * and the request should be reattempted later.
- * EX_PROTOCOL -- the remote system returned something that
- * was "not possible" during a protocol exchange.
- * EX_NOPERM -- You did not have sufficient permission to
- * perform the operation. This is not intended for
- * file system problems, which should use NOINPUT or
- * CANTCREAT, but rather for higher level permissions.
- */
-
-#define EX_OK 0 /* successful termination */
-
-#define EX__BASE 64 /* base value for error messages */
-
-#define EX_USAGE 64 /* command line usage error */
-#define EX_DATAERR 65 /* data format error */
-#define EX_NOINPUT 66 /* cannot open input */
-#define EX_NOUSER 67 /* addressee unknown */
-#define EX_NOHOST 68 /* host name unknown */
-#define EX_UNAVAILABLE 69 /* service unavailable */
-#define EX_SOFTWARE 70 /* internal software error */
-#define EX_OSERR 71 /* system error (e.g., can't fork) */
-#define EX_OSFILE 72 /* critical OS file missing */
-#define EX_CANTCREAT 73 /* can't create (user) output file */
-#define EX_IOERR 74 /* input/output error */
-#define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */
-#define EX_PROTOCOL 76 /* remote error in protocol */
-#define EX_NOPERM 77 /* permission denied */
-#define EX_CONFIG 78 /* configuration error */
-
-#define EX__MAX 78 /* maximum listed value */
-
-#endif /* !_SYSEXITS_H_ */
diff --git a/src/trace.c b/src/trace.c
deleted file mode 100644
index 5ab6032..0000000
--- a/src/trace.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)trace.c 8.12 (Berkeley) 5/19/1998";
-#endif /* not lint */
-
-# include "sendmail.h"
-
-/*
-** TtSETUP -- set up for trace package.
-**
-** Parameters:
-** vect -- pointer to trace vector.
-** size -- number of flags in trace vector.
-** defflags -- flags to set if no value given.
-**
-** Returns:
-** none
-**
-** Side Effects:
-** environment is set up.
-*/
-
-u_char *tTvect;
-int tTsize;
-static char *DefFlags;
-
-void
-tTsetup(vect, size, defflags)
- u_char *vect;
- int size;
- char *defflags;
-{
- tTvect = vect;
- tTsize = size;
- DefFlags = defflags;
-}
- /*
-** TtFLAG -- process an external trace flag description.
-**
-** Parameters:
-** s -- the trace flag.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** sets/clears trace flags.
-*/
-
-void
-tTflag(s)
- register char *s;
-{
- unsigned int first, last;
- register unsigned int i;
-
- if (*s == '\0')
- s = DefFlags;
-
- for (;;)
- {
- /* find first flag to set */
- i = 0;
- while (isascii(*s) && isdigit(*s))
- i = i * 10 + (*s++ - '0');
- first = i;
-
- /* find last flag to set */
- if (*s == '-')
- {
- i = 0;
- while (isascii(*++s) && isdigit(*s))
- i = i * 10 + (*s - '0');
- }
- last = i;
-
- /* find the level to set it to */
- i = 1;
- if (*s == '.')
- {
- i = 0;
- while (isascii(*++s) && isdigit(*s))
- i = i * 10 + (*s - '0');
- }
-
- /* clean up args */
- if (first >= tTsize)
- first = tTsize - 1;
- if (last >= tTsize)
- last = tTsize - 1;
-
- /* set the flags */
- while (first <= last)
- tTvect[first++] = i;
-
- /* more arguments? */
- if (*s++ == '\0')
- return;
- }
-}
diff --git a/src/udb.c b/src/udb.c
deleted file mode 100644
index 96c6513..0000000
--- a/src/udb.c
+++ /dev/null
@@ -1,1335 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-#include "sendmail.h"
-
-#ifndef lint
-#if USERDB
-static char sccsid [] = "@(#)udb.c 8.71 (Berkeley) 1/17/1999 (with USERDB)";
-#else
-static char sccsid [] = "@(#)udb.c 8.71 (Berkeley) 1/17/1999 (without USERDB)";
-#endif
-#endif
-
-#if USERDB
-
-#include <errno.h>
-
-#ifdef NEWDB
-# include <db.h>
-# ifndef DB_VERSION_MAJOR
-# define DB_VERSION_MAJOR 1
-# endif
-#else
-# define DBT struct _data_base_thang_
-DBT
-{
- void *data; /* pointer to data */
- size_t size; /* length of data */
-};
-#endif
-
-/*
-** UDB.C -- interface between sendmail and Berkeley User Data Base.
-**
-** This depends on the 4.4BSD db package.
-*/
-
-
-struct udbent
-{
- char *udb_spec; /* string version of spec */
- int udb_type; /* type of entry */
- pid_t udb_pid; /* PID of process which opened db */
- char *udb_default; /* default host for outgoing mail */
- union
- {
- /* type UE_REMOTE -- do remote call for lookup */
- struct
- {
- struct sockaddr_in _udb_addr; /* address */
- int _udb_timeout; /* timeout */
- } udb_remote;
-#define udb_addr udb_u.udb_remote._udb_addr
-#define udb_timeout udb_u.udb_remote._udb_timeout
-
- /* type UE_FORWARD -- forward message to remote */
- struct
- {
- char *_udb_fwdhost; /* name of forward host */
- } udb_forward;
-#define udb_fwdhost udb_u.udb_forward._udb_fwdhost
-
-#ifdef NEWDB
- /* type UE_FETCH -- lookup in local database */
- struct
- {
- char *_udb_dbname; /* pathname of database */
- DB *_udb_dbp; /* open database ptr */
- } udb_lookup;
-#define udb_dbname udb_u.udb_lookup._udb_dbname
-#define udb_dbp udb_u.udb_lookup._udb_dbp
-#endif
- } udb_u;
-};
-
-#define UDB_EOLIST 0 /* end of list */
-#define UDB_SKIP 1 /* skip this entry */
-#define UDB_REMOTE 2 /* look up in remote database */
-#define UDB_DBFETCH 3 /* look up in local database */
-#define UDB_FORWARD 4 /* forward to remote host */
-#define UDB_HESIOD 5 /* look up via hesiod */
-
-#define MAXUDBENT 10 /* maximum number of UDB entries */
-
-
-struct udb_option
-{
- char *name;
- char *val;
-};
-
-#ifdef HESIOD
-extern int hes_udb_get __P((DBT *, DBT *));
-#endif
-extern int _udbx_init __P((ENVELOPE *));
- /*
-** UDBEXPAND -- look up user in database and expand
-**
-** Parameters:
-** a -- address to expand.
-** sendq -- pointer to head of sendq to put the expansions in.
-** aliaslevel -- the current alias nesting depth.
-** e -- the current envelope.
-**
-** Returns:
-** EX_TEMPFAIL -- if something "odd" happened -- probably due
-** to accessing a file on an NFS server that is down.
-** EX_OK -- otherwise.
-**
-** Side Effects:
-** Modifies sendq.
-*/
-
-int UdbPort = 1616;
-int UdbTimeout = 10;
-
-struct udbent UdbEnts[MAXUDBENT + 1];
-int UdbSock = -1;
-bool UdbInitialized = FALSE;
-
-int
-udbexpand(a, sendq, aliaslevel, e)
- register ADDRESS *a;
- ADDRESS **sendq;
- int aliaslevel;
- register ENVELOPE *e;
-{
- int i;
- DBT key;
- DBT info;
- bool breakout;
- register struct udbent *up;
- int keylen;
- int naddrs;
- char *user;
- char keybuf[MAXKEY];
-
- bzero(&key, sizeof key);
- bzero(&info, sizeof info);
-
- if (tTd(28, 1))
- printf("udbexpand(%s)\n", a->q_paddr);
-
- /* make certain we are supposed to send to this address */
- if (bitset(QDONTSEND|QVERIFIED, a->q_flags))
- return EX_OK;
- e->e_to = a->q_paddr;
-
- /* on first call, locate the database */
- if (!UdbInitialized)
- {
- if (_udbx_init(e) == EX_TEMPFAIL)
- return EX_TEMPFAIL;
- }
-
- /* short circuit the process if no chance of a match */
- if (UdbSpec == NULL || UdbSpec[0] == '\0')
- return EX_OK;
-
- /* extract user to do userdb matching on */
- user = a->q_user;
-
- /* short circuit name begins with '\\' since it can't possibly match */
- /* (might want to treat this as unquoted instead) */
- if (user[0] == '\\')
- return EX_OK;
-
- /* if name is too long, assume it won't match */
- if (strlen(user) > (SIZE_T) sizeof keybuf - 12)
- return EX_OK;
-
- /* if name begins with a colon, it indicates our metadata */
- if (user[0] == ':')
- return EX_OK;
-
- /* build actual database key */
- (void) strcpy(keybuf, user);
- (void) strcat(keybuf, ":maildrop");
- keylen = strlen(keybuf);
-
- breakout = FALSE;
- for (up = UdbEnts; !breakout; up++)
- {
- char *user;
- int usersize;
- int userleft;
- char userbuf[MEMCHUNKSIZE];
-#if defined(HESIOD) && defined(HES_GETMAILHOST)
- char pobuf[MAXNAME];
-#endif
-#if defined(NEWDB) && DB_VERSION_MAJOR > 1
- DBC *dbc = NULL;
-#endif
-
- user = userbuf;
- userbuf[0] = '\0';
- usersize = sizeof userbuf;
- userleft = sizeof userbuf - 1;
-
- /*
- ** Select action based on entry type.
- **
- ** On dropping out of this switch, "class" should
- ** explain the type of the data, and "user" should
- ** contain the user information.
- */
-
- switch (up->udb_type)
- {
-#ifdef NEWDB
- case UDB_DBFETCH:
- key.data = keybuf;
- key.size = keylen;
- if (tTd(28, 80))
- printf("udbexpand: trying %s (%d) via db\n",
- keybuf, keylen);
-#if DB_VERSION_MAJOR < 2
- i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR);
-#else
- i = 0;
- if (dbc == NULL &&
-# if DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >=6
- (errno = (*up->udb_dbp->cursor)(up->udb_dbp,
- NULL, &dbc, 0)) != 0)
-# else
- (errno = (*up->udb_dbp->cursor)(up->udb_dbp,
- NULL, &dbc)) != 0)
-# endif
- i = -1;
- if (i != 0 || dbc == NULL ||
- (errno = dbc->c_get(dbc, &key,
- &info, DB_SET)) != 0)
- i = 1;
-#endif
- if (i > 0 || info.size <= 0)
- {
- if (tTd(28, 2))
- printf("udbexpand: no match on %s (%d)\n",
- keybuf, keylen);
-#if DB_VERSION_MAJOR > 1
- if (dbc != NULL)
- {
- (void) dbc->c_close(dbc);
- dbc = NULL;
- }
-#endif
- break;
- }
- if (tTd(28, 80))
- printf("udbexpand: match %.*s: %.*s\n",
- (int) key.size, (char *) key.data,
- (int) info.size, (char *) info.data);
-
- a->q_flags &= ~QSELFREF;
- while (i == 0 && key.size == keylen &&
- bcmp(key.data, keybuf, keylen) == 0)
- {
- char *p;
-
- if (bitset(EF_VRFYONLY, e->e_flags))
- {
- a->q_flags |= QVERIFIED;
-#if DB_VERSION_MAJOR > 1
- if (dbc != NULL)
- {
- (void) dbc->c_close(dbc);
- dbc = NULL;
- }
-#endif
- return EX_OK;
- }
-
- breakout = TRUE;
- if (info.size >= userleft - 1)
- {
- char *nuser;
- int size = MEMCHUNKSIZE;
-
- if (info.size > MEMCHUNKSIZE)
- size = info.size;
- nuser = xalloc(usersize + size);
-
- bcopy(user, nuser, usersize);
- if (user != userbuf)
- free(user);
- user = nuser;
- usersize += size;
- userleft += size;
- }
- p = &user[strlen(user)];
- if (p != user)
- {
- *p++ = ',';
- userleft--;
- }
- bcopy(info.data, p, info.size);
- p[info.size] = '\0';
- userleft -= info.size;
-
- /* get the next record */
-#if DB_VERSION_MAJOR < 2
- i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT);
-#else
- i = 0;
- if ((errno = dbc->c_get(dbc, &key,
- &info, DB_NEXT)) != 0)
- i = 1;
-#endif
- }
-
-#if DB_VERSION_MAJOR > 1
- if (dbc != NULL)
- {
- (void) dbc->c_close(dbc);
- dbc = NULL;
- }
-#endif
-
- /* if nothing ever matched, try next database */
- if (!breakout)
- break;
-
- message("expanded to %s", user);
- if (LogLevel >= 10)
- sm_syslog(LOG_INFO, e->e_id,
- "expand %.100s => %s",
- e->e_to,
- shortenstring(user, MAXSHORTSTR));
- naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e);
- if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
- {
- if (tTd(28, 5))
- {
- printf("udbexpand: QDONTSEND ");
- printaddr(a, FALSE);
- }
- a->q_flags |= QDONTSEND;
- }
- if (i < 0)
- {
- syserr("udbexpand: db-get %.*s stat %d",
- (int) key.size, (char *) key.data, i);
- return EX_TEMPFAIL;
- }
-
- /*
- ** If this address has a -request address, reflect
- ** it into the envelope.
- */
-
- bzero(&key, sizeof key);
- bzero(&info, sizeof info);
- (void) strcpy(keybuf, a->q_user);
- (void) strcat(keybuf, ":mailsender");
- keylen = strlen(keybuf);
- key.data = keybuf;
- key.size = keylen;
-
-#if DB_VERSION_MAJOR < 2
- i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
-#else
- i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL,
- &key, &info, 0);
-#endif
- if (i != 0 || info.size <= 0)
- break;
- a->q_owner = xalloc(info.size + 1);
- bcopy(info.data, a->q_owner, info.size);
- a->q_owner[info.size] = '\0';
-
- /* announce delivery; NORECEIPT bit set later */
- if (e->e_xfp != NULL)
- {
- fprintf(e->e_xfp,
- "Message delivered to mailing list %s\n",
- a->q_paddr);
- }
- e->e_flags |= EF_SENDRECEIPT;
- a->q_flags |= QDELIVERED|QEXPANDED;
- break;
-#endif
-
-#ifdef HESIOD
- case UDB_HESIOD:
- key.data = keybuf;
- key.size = keylen;
- if (tTd(28, 80))
- printf("udbexpand: trying %s (%d) via hesiod\n",
- keybuf, keylen);
- /* look up the key via hesiod */
- i = hes_udb_get(&key, &info);
- if (i < 0)
- {
- syserr("udbexpand: hesiod-get %.*s stat %d",
- (int) key.size, (char *) key.data, i);
- return EX_TEMPFAIL;
- }
- else if (i > 0 || info.size <= 0)
- {
-#if HES_GETMAILHOST
- struct hes_postoffice *hp;
-#endif
-
- if (tTd(28, 2))
- printf("udbexpand: no match on %s (%d)\n",
- (char *) keybuf, (int) keylen);
-#if HES_GETMAILHOST
- if (tTd(28, 8))
- printf(" ... trying hes_getmailhost(%s)\n",
- a->q_user);
- hp = hes_getmailhost(a->q_user);
- if (hp == NULL)
- {
- if (hes_error() == HES_ER_NET)
- {
- syserr("udbexpand: hesiod-getmail %s stat %d",
- a->q_user, hes_error());
- return EX_TEMPFAIL;
- }
- if (tTd(28, 2))
- printf("hes_getmailhost(%s): %d\n",
- a->q_user, hes_error());
- break;
- }
- if (strlen(hp->po_name) + strlen(hp->po_host) >
- sizeof pobuf - 2)
- {
- if (tTd(28, 2))
- printf("hes_getmailhost(%s): expansion too long: %.30s@%.30s\n",
- a->q_user,
- hp->po_name,
- hp->po_host);
- break;
- }
- info.data = pobuf;
- snprintf(pobuf, sizeof pobuf, "%s@%s",
- hp->po_name, hp->po_host);
- info.size = strlen(info.data);
-#else
- break;
-#endif
- }
- if (tTd(28, 80))
- printf("udbexpand: match %.*s: %.*s\n",
- (int) key.size, (char *) key.data,
- (int) info.size, (char *) info.data);
- a->q_flags &= ~QSELFREF;
-
- if (bitset(EF_VRFYONLY, e->e_flags))
- {
- a->q_flags |= QVERIFIED;
- return EX_OK;
- }
-
- breakout = TRUE;
- if (info.size >= usersize)
- user = xalloc(info.size + 1);
- bcopy(info.data, user, info.size);
- user[info.size] = '\0';
-
- message("hesioded to %s", user);
- if (LogLevel >= 10)
- sm_syslog(LOG_INFO, e->e_id,
- "hesiod %.100s => %s",
- e->e_to,
- shortenstring(user, MAXSHORTSTR));
- naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e);
-
- if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
- {
- if (tTd(28, 5))
- {
- printf("udbexpand: QDONTSEND ");
- printaddr(a, FALSE);
- }
- a->q_flags |= QDONTSEND;
- }
-
- /*
- ** If this address has a -request address, reflect
- ** it into the envelope.
- */
-
- (void) strcpy(keybuf, a->q_user);
- (void) strcat(keybuf, ":mailsender");
- keylen = strlen(keybuf);
- key.data = keybuf;
- key.size = keylen;
- i = hes_udb_get(&key, &info);
- if (i != 0 || info.size <= 0)
- break;
- a->q_owner = xalloc(info.size + 1);
- bcopy(info.data, a->q_owner, info.size);
- a->q_owner[info.size] = '\0';
- break;
-#endif /* HESIOD */
-
- case UDB_REMOTE:
- /* not yet implemented */
- break;
-
- case UDB_FORWARD:
- if (bitset(EF_VRFYONLY, e->e_flags))
- return EX_OK;
- i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1;
- if (i >= usersize)
- {
- usersize = i + 1;
- user = xalloc(usersize);
- }
- (void) snprintf(user, usersize, "%s@%s",
- a->q_user, up->udb_fwdhost);
- message("expanded to %s", user);
- a->q_flags &= ~QSELFREF;
- naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e);
- if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
- {
- if (tTd(28, 5))
- {
- printf("udbexpand: QDONTSEND ");
- printaddr(a, FALSE);
- }
- a->q_flags |= QDONTSEND;
- }
- breakout = TRUE;
- break;
-
- case UDB_EOLIST:
- breakout = TRUE;
- break;
-
- default:
- /* unknown entry type */
- break;
- }
- if (user != userbuf)
- free(user);
- }
- return EX_OK;
-}
- /*
-** UDBSENDER -- return canonical external name of sender, given local name
-**
-** Parameters:
-** sender -- the name of the sender on the local machine.
-**
-** Returns:
-** The external name for this sender, if derivable from the
-** database.
-** NULL -- if nothing is changed from the database.
-**
-** Side Effects:
-** none.
-*/
-
-char *
-udbsender(sender)
- char *sender;
-{
- extern char *udbmatch __P((char *, char *));
-
- return udbmatch(sender, "mailname");
-}
-
-
-char *
-udbmatch(user, field)
- char *user;
- char *field;
-{
- register char *p;
- register struct udbent *up;
- int i;
- int keylen;
- DBT key, info;
- char keybuf[MAXKEY];
-
- if (tTd(28, 1))
- printf("udbmatch(%s, %s)\n", user, field);
-
- if (!UdbInitialized)
- {
- if (_udbx_init(CurEnv) == EX_TEMPFAIL)
- return NULL;
- }
-
- /* short circuit if no spec */
- if (UdbSpec == NULL || UdbSpec[0] == '\0')
- return NULL;
-
- /* short circuit name begins with '\\' since it can't possibly match */
- if (user[0] == '\\')
- return NULL;
-
- /* long names can never match and are a pain to deal with */
- i = strlen(field);
- if (i < sizeof "maildrop")
- i = sizeof "maildrop";
- if ((strlen(user) + i) > sizeof keybuf - 4)
- return NULL;
-
- /* names beginning with colons indicate metadata */
- if (user[0] == ':')
- return NULL;
-
- /* build database key */
- (void) strcpy(keybuf, user);
- (void) strcat(keybuf, ":");
- (void) strcat(keybuf, field);
- keylen = strlen(keybuf);
-
- for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
- {
- /*
- ** Select action based on entry type.
- */
-
- switch (up->udb_type)
- {
-#ifdef NEWDB
- case UDB_DBFETCH:
- bzero(&key, sizeof key);
- bzero(&info, sizeof info);
- key.data = keybuf;
- key.size = keylen;
-#if DB_VERSION_MAJOR < 2
- i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
-#else
- i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL,
- &key, &info, 0);
-#endif
- if (i != 0 || info.size <= 0)
- {
- if (tTd(28, 2))
- printf("udbmatch: no match on %s (%d) via db\n",
- keybuf, keylen);
- continue;
- }
-
- p = xalloc(info.size + 1);
- bcopy(info.data, p, info.size);
- p[info.size] = '\0';
- if (tTd(28, 1))
- printf("udbmatch ==> %s\n", p);
- return p;
-#endif
-
-#ifdef HESIOD
- case UDB_HESIOD:
- key.data = keybuf;
- key.size = keylen;
- i = hes_udb_get(&key, &info);
- if (i != 0 || info.size <= 0)
- {
- if (tTd(28, 2))
- printf("udbmatch: no match on %s (%d) via hesiod\n",
- keybuf, keylen);
- continue;
- }
-
- p = xalloc(info.size + 1);
- bcopy(info.data, p, info.size);
- p[info.size] = '\0';
- if (tTd(28, 1))
- printf("udbmatch ==> %s\n", p);
- return p;
-#endif /* HESIOD */
- }
- }
-
- if (strcmp(field, "mailname") != 0)
- return NULL;
-
- /*
- ** Nothing yet. Search again for a default case. But only
- ** use it if we also have a forward (:maildrop) pointer already
- ** in the database.
- */
-
- /* build database key */
- (void) strcpy(keybuf, user);
- (void) strcat(keybuf, ":maildrop");
- keylen = strlen(keybuf);
-
- for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
- {
- switch (up->udb_type)
- {
-#ifdef NEWDB
- case UDB_DBFETCH:
- /* get the default case for this database */
- if (up->udb_default == NULL)
- {
- bzero(&key, sizeof key);
- bzero(&info, sizeof info);
- key.data = ":default:mailname";
- key.size = strlen(key.data);
-#if DB_VERSION_MAJOR < 2
- i = (*up->udb_dbp->get)(up->udb_dbp,
- &key, &info, 0);
-#else
- i = errno = (*up->udb_dbp->get)(up->udb_dbp,
- NULL, &key,
- &info, 0);
-#endif
- if (i != 0 || info.size <= 0)
- {
- /* no default case */
- up->udb_default = "";
- continue;
- }
-
- /* save the default case */
- up->udb_default = xalloc(info.size + 1);
- bcopy(info.data, up->udb_default, info.size);
- up->udb_default[info.size] = '\0';
- }
- else if (up->udb_default[0] == '\0')
- continue;
-
- /* we have a default case -- verify user:maildrop */
- bzero(&key, sizeof key);
- bzero(&info, sizeof info);
- key.data = keybuf;
- key.size = keylen;
-#if DB_VERSION_MAJOR < 2
- i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
-#else
- i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL,
- &key, &info, 0);
-#endif
- if (i != 0 || info.size <= 0)
- {
- /* nope -- no aliasing for this user */
- continue;
- }
-
- /* they exist -- build the actual address */
- p = xalloc(strlen(user) + strlen(up->udb_default) + 2);
- (void) strcpy(p, user);
- (void) strcat(p, "@");
- (void) strcat(p, up->udb_default);
- if (tTd(28, 1))
- printf("udbmatch ==> %s\n", p);
- return p;
-#endif
-
-#ifdef HESIOD
- case UDB_HESIOD:
- /* get the default case for this database */
- if (up->udb_default == NULL)
- {
- key.data = ":default:mailname";
- key.size = strlen(key.data);
- i = hes_udb_get(&key, &info);
-
- if (i != 0 || info.size <= 0)
- {
- /* no default case */
- up->udb_default = "";
- continue;
- }
-
- /* save the default case */
- up->udb_default = xalloc(info.size + 1);
- bcopy(info.data, up->udb_default, info.size);
- up->udb_default[info.size] = '\0';
- }
- else if (up->udb_default[0] == '\0')
- continue;
-
- /* we have a default case -- verify user:maildrop */
- key.data = keybuf;
- key.size = keylen;
- i = hes_udb_get(&key, &info);
- if (i != 0 || info.size <= 0)
- {
- /* nope -- no aliasing for this user */
- continue;
- }
-
- /* they exist -- build the actual address */
- p = xalloc(strlen(user) + strlen(up->udb_default) + 2);
- (void) strcpy(p, user);
- (void) strcat(p, "@");
- (void) strcat(p, up->udb_default);
- if (tTd(28, 1))
- printf("udbmatch ==> %s\n", p);
- return p;
- break;
-#endif /* HESIOD */
- }
- }
-
- /* still nothing.... too bad */
- return NULL;
-}
- /*
-** UDB_MAP_LOOKUP -- look up arbitrary entry in user database map
-**
-** Parameters:
-** map -- the map being queried.
-** name -- the name to look up.
-** av -- arguments to the map lookup.
-** statp -- to get any error status.
-**
-** Returns:
-** NULL if name not found in map.
-** The rewritten name otherwise.
-*/
-
-/* ARGSUSED3 */
-char *
-udb_map_lookup(map, name, av, statp)
- MAP *map;
- char *name;
- char **av;
- int *statp;
-{
- char *val;
- char *key;
- char keybuf[MAXNAME + 1];
-
- if (tTd(28, 20) || tTd(38, 20))
- printf("udb_map_lookup(%s, %s)\n", map->map_mname, name);
-
- if (bitset(MF_NOFOLDCASE, map->map_mflags))
- {
- key = name;
- }
- else
- {
- int keysize = strlen(name);
-
- if (keysize > sizeof keybuf - 1)
- keysize = sizeof keybuf - 1;
- bcopy(name, keybuf, keysize);
- keybuf[keysize] = '\0';
- makelower(keybuf);
- key = keybuf;
- }
- val = udbmatch(key, map->map_file);
- if (val == NULL)
- return NULL;
- if (bitset(MF_MATCHONLY, map->map_mflags))
- return map_rewrite(map, name, strlen(name), NULL);
- else
- return map_rewrite(map, val, strlen(val), av);
-}
- /*
-** _UDBX_INIT -- parse the UDB specification, opening any valid entries.
-**
-** Parameters:
-** e -- the current envelope.
-**
-** Returns:
-** EX_TEMPFAIL -- if it appeared it couldn't get hold of a
-** database due to a host being down or some similar
-** (recoverable) situation.
-** EX_OK -- otherwise.
-**
-** Side Effects:
-** Fills in the UdbEnts structure from UdbSpec.
-*/
-
-#define MAXUDBOPTS 27
-
-int
-_udbx_init(e)
- ENVELOPE *e;
-{
- int ents = 0;
- register char *p;
- register struct udbent *up;
-
- if (UdbInitialized)
- return EX_OK;
-
-# ifdef UDB_DEFAULT_SPEC
- if (UdbSpec == NULL)
- UdbSpec = UDB_DEFAULT_SPEC;
-# endif
-
- p = UdbSpec;
- up = UdbEnts;
- while (p != NULL)
- {
- char *spec;
- int l;
-# if 0
- auto int rcode;
- int nmx;
- int i;
- register struct hostent *h;
- char *mxhosts[MAXMXHOSTS + 1];
-# endif
- struct udb_option opts[MAXUDBOPTS + 1];
- extern int _udb_parsespec __P((char *, struct udb_option [], int));
-
- while (*p == ' ' || *p == '\t' || *p == ',')
- p++;
- if (*p == '\0')
- break;
- spec = p;
- p = strchr(p, ',');
- if (p != NULL)
- *p++ = '\0';
-
- if (ents >= MAXUDBENT)
- {
- syserr("Maximum number of UDB entries exceeded");
- break;
- }
-
- /* extract options */
- (void) _udb_parsespec(spec, opts, MAXUDBOPTS);
-
- /*
- ** Decode database specification.
- **
- ** In the sendmail tradition, the leading character
- ** defines the semantics of the rest of the entry.
- **
- ** +hostname -- send a datagram to the udb server
- ** on host "hostname" asking for the
- ** home mail server for this user.
- ** *hostname -- similar to +hostname, except that the
- ** hostname is searched as an MX record;
- ** resulting hosts are searched as for
- ** +mxhostname. If no MX host is found,
- ** this is the same as +hostname.
- ** @hostname -- forward email to the indicated host.
- ** This should be the last in the list,
- ** since it always matches the input.
- ** /dbname -- search the named database on the local
- ** host using the Berkeley db package.
- ** Hesiod -- search the named database with BIND
- ** using the MIT Hesiod package.
- */
-
- switch (*spec)
- {
-#if 0
- case '+': /* search remote database */
- case '*': /* search remote database (expand MX) */
- if (*spec == '*')
- {
-#if NAMED_BIND
- nmx = getmxrr(spec + 1, mxhosts, FALSE, &rcode);
-#else
- mxhosts[0] = spec + 1;
- nmx = 1;
- rcode = 0;
-#endif
- if (tTd(28, 16))
- {
- int i;
-
- printf("getmxrr(%s): %d", spec + 1, nmx);
- for (i = 0; i <= nmx; i++)
- printf(" %s", mxhosts[i]);
- printf("\n");
- }
- }
- else
- {
- nmx = 1;
- mxhosts[0] = spec + 1;
- }
-
- for (i = 0; i < nmx; i++)
- {
- h = sm_gethostbyname(mxhosts[i]);
- if (h == NULL)
- continue;
- up->udb_type = UDB_REMOTE;
- up->udb_pid = getpid();
- up->udb_addr.sin_family = h->h_addrtype;
- bcopy(h->h_addr_list[0],
- (char *) &up->udb_addr.sin_addr,
- INADDRSZ);
- up->udb_addr.sin_port = UdbPort;
- up->udb_timeout = UdbTimeout;
- ents++;
- up++;
- }
-
- /* set up a datagram socket */
- if (UdbSock < 0)
- {
- UdbSock = socket(AF_INET, SOCK_DGRAM, 0);
- (void) fcntl(UdbSock, F_SETFD, 1);
- }
- break;
-#endif
-
- case '@': /* forward to remote host */
- up->udb_type = UDB_FORWARD;
- up->udb_pid = getpid();
- up->udb_fwdhost = spec + 1;
- ents++;
- up++;
- break;
-
-#ifdef HESIOD
- case 'h': /* use hesiod */
- case 'H':
- if (strcasecmp(spec, "hesiod") != 0)
- goto badspec;
- up->udb_type = UDB_HESIOD;
- up->udb_pid = getpid();
- ents++;
- up++;
- break;
-#endif /* HESIOD */
-
-#ifdef NEWDB
- case '/': /* look up remote name */
- l = strlen(spec);
- if (l > 3 && strcmp(&spec[l - 3], ".db") == 0)
- {
- up->udb_dbname = spec;
- }
- else
- {
- up->udb_dbname = xalloc(l + 4);
- strcpy(up->udb_dbname, spec);
- strcat(up->udb_dbname, ".db");
- }
- errno = 0;
-#if DB_VERSION_MAJOR < 2
- up->udb_dbp = dbopen(up->udb_dbname, O_RDONLY,
- 0644, DB_BTREE, NULL);
-#else
- up->udb_dbp = NULL;
- errno = db_open(up->udb_dbname, DB_BTREE, DB_RDONLY,
- 0644, NULL, NULL, &up->udb_dbp);
-#endif
- if (up->udb_dbp == NULL)
- {
- if (tTd(28, 1))
- {
- int saveerrno = errno;
-
-#if DB_VERSION_MAJOR < 2
- printf("dbopen(%s): %s\n",
-#else
- printf("db_open(%s): %s\n",
-#endif
- up->udb_dbname,
- errstring(errno));
- errno = saveerrno;
- }
- if (errno != ENOENT && errno != EACCES)
- {
- if (LogLevel > 2)
- sm_syslog(LOG_ERR, e->e_id,
-#if DB_VERSION_MAJOR < 2
- "dbopen(%s): %s",
-#else
- "db_open(%s): %s",
-#endif
- up->udb_dbname,
- errstring(errno));
- up->udb_type = UDB_EOLIST;
- if (up->udb_dbname != spec)
- free(up->udb_dbname);
- goto tempfail;
- }
- if (up->udb_dbname != spec)
- free(up->udb_dbname);
- break;
- }
- if (tTd(28, 1))
- {
-#if DB_VERSION_MAJOR < 2
- printf("_udbx_init: dbopen(%s)\n",
-#else
- printf("_udbx_init: db_open(%s)\n",
-#endif
- up->udb_dbname);
- }
- up->udb_type = UDB_DBFETCH;
- up->udb_pid = getpid();
- ents++;
- up++;
- break;
-#endif
-
- default:
-badspec:
- syserr("Unknown UDB spec %s", spec);
- break;
- }
- }
- up->udb_type = UDB_EOLIST;
-
- if (tTd(28, 4))
- {
- for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
- {
- switch (up->udb_type)
- {
-#if DAEMON
- case UDB_REMOTE:
- printf("REMOTE: addr %s, timeo %d\n",
- anynet_ntoa((SOCKADDR *) &up->udb_addr),
- up->udb_timeout);
- break;
-#endif
-
- case UDB_DBFETCH:
-#ifdef NEWDB
- printf("FETCH: file %s\n",
- up->udb_dbname);
-#else
- printf("FETCH\n");
-#endif
- break;
-
- case UDB_FORWARD:
- printf("FORWARD: host %s\n",
- up->udb_fwdhost);
- break;
-
- case UDB_HESIOD:
- printf("HESIOD\n");
- break;
-
- default:
- printf("UNKNOWN\n");
- break;
- }
- }
- }
-
- UdbInitialized = TRUE;
- errno = 0;
- return EX_OK;
-
- /*
- ** On temporary failure, back out anything we've already done
- */
-
- tempfail:
-#ifdef NEWDB
- for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
- {
- if (up->udb_type == UDB_DBFETCH)
- {
-#if DB_VERSION_MAJOR < 2
- (*up->udb_dbp->close)(up->udb_dbp);
-#else
- errno = (*up->udb_dbp->close)(up->udb_dbp, 0);
-#endif
- if (tTd(28, 1))
- {
- printf("_udbx_init: db->close(%s)\n",
- up->udb_dbname);
- }
- }
- }
-#endif
- return EX_TEMPFAIL;
-}
-
-int
-_udb_parsespec(udbspec, opt, maxopts)
- char *udbspec;
- struct udb_option opt[];
- int maxopts;
-{
- register char *spec;
- register char *spec_end;
- register int optnum;
-
- spec_end = strchr(udbspec, ':');
- for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++)
- {
- register char *p;
-
- while (isascii(*spec) && isspace(*spec))
- spec++;
- spec_end = strchr(spec, ':');
- if (spec_end != NULL)
- *spec_end++ = '\0';
-
- opt[optnum].name = spec;
- opt[optnum].val = NULL;
- p = strchr(spec, '=');
- if (p != NULL)
- opt[optnum].val = ++p;
- }
- return optnum;
-}
- /*
-** _UDBX_CLOSE -- close all file based UDB entries.
-**
-** Parameters:
-** none
-**
-** Returns:
-** none
-*/
-void
-_udbx_close()
-{
- pid_t pid;
- struct udbent *up;
-
- if (!UdbInitialized)
- return;
-
- pid = getpid();
-
- for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
- {
- if (up->udb_pid != pid)
- continue;
-
-#ifdef NEWDB
- if (up->udb_type == UDB_DBFETCH)
- {
-#if DB_VERSION_MAJOR < 2
- (*up->udb_dbp->close)(up->udb_dbp);
-#else
- errno = (*up->udb_dbp->close)(up->udb_dbp, 0);
-#endif
- }
- if (tTd(28, 1))
- {
- printf("_udbx_init: db->close(%s)\n",
- up->udb_dbname);
- }
-#endif
- }
-}
-
-#ifdef HESIOD
-
-int
-hes_udb_get(key, info)
- DBT *key;
- DBT *info;
-{
- char *name, *type;
- char **hp;
- char kbuf[MAXKEY + 1];
-
- if (strlen(key->data) >= (SIZE_T) sizeof kbuf)
- return 0;
- strcpy(kbuf, key->data);
- name = kbuf;
- type = strrchr(name, ':');
- if (type == NULL)
- return 1;
- *type++ = '\0';
- if (strchr(name, '@') != NULL)
- return 1;
-
- if (tTd(28, 1))
- printf("hes_udb_get(%s, %s)\n", name, type);
-
- /* make the hesiod query */
-#ifdef HESIOD_INIT
- if (HesiodContext == NULL && hesiod_init(&HesiodContext) != 0)
- return -1;
- hp = hesiod_resolve(HesiodContext, name, type);
-#else
- hp = hes_resolve(name, type);
-#endif /* HESIOD_INIT */
- *--type = ':';
-#ifdef HESIOD_INIT
- if (hp == NULL)
- return 1;
- if (*hp == NULL)
- {
- hesiod_free_list(HesiodContext, hp);
- if (errno == ECONNREFUSED || errno == EMSGSIZE)
- return -1;
- return 1;
- }
-#else
- if (hp == NULL || hp[0] == NULL)
- {
- /* network problem or timeout */
- if (hes_error() == HES_ER_NET)
- return -1;
-
- return 1;
- }
-#endif /* HESIOD_INIT */
- else
- {
- /*
- ** If there are multiple matches, just return the
- ** first one.
- **
- ** XXX These should really be returned; for example,
- ** XXX it is legal for :maildrop to be multi-valued.
- */
-
- info->data = hp[0];
- info->size = (size_t) strlen(info->data);
- }
-
- if (tTd(28, 80))
- printf("hes_udb_get => %s\n", *hp);
-
- return 0;
-}
-#endif /* HESIOD */
-
-#else /* not USERDB */
-
-int
-udbexpand(a, sendq, aliaslevel, e)
- ADDRESS *a;
- ADDRESS **sendq;
- int aliaslevel;
- ENVELOPE *e;
-{
- return EX_OK;
-}
-
-#endif /* USERDB */
diff --git a/src/useful.h b/src/useful.h
deleted file mode 100644
index a19dd9e..0000000
--- a/src/useful.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- *
- * @(#)useful.h 8.12 (Berkeley) 5/19/1998
- */
-
-# include <sys/types.h>
-
-/* support for bool type */
-typedef int bool;
-#ifndef TRUE
-# define TRUE 1
-# define FALSE 0
-#endif
-
-# ifndef NULL
-# define NULL 0
-# endif /* NULL */
-
-/* bit hacking */
-# define bitset(bit, word) (((word) & (bit)) != 0)
-
-/* some simple functions */
-# ifndef max
-# define max(a, b) ((a) > (b) ? (a) : (b))
-# define min(a, b) ((a) < (b) ? (a) : (b))
-# endif
-
-/* assertions */
-# ifndef NASSERT
-# define ASSERT(expr, msg, parm)\
- if (!(expr))\
- {\
- fprintf(stderr, "assertion botch: %s:%d: ", __FILE__, __LINE__);\
- fprintf(stderr, msg, parm);\
- }
-# else /* NASSERT */
-# define ASSERT(expr, msg, parm)
-# endif /* NASSERT */
-
-/* sccs id's */
-# ifndef lint
-# ifdef __STDC__
-# define SCCSID(arg) static char SccsId[] = #arg;
-# else
-# define SCCSID(arg) static char SccsId[] = "arg";
-# endif
-# else
-# define SCCSID(arg)
-# endif
diff --git a/src/usersmtp.c b/src/usersmtp.c
deleted file mode 100644
index c82942b..0000000
--- a/src/usersmtp.c
+++ /dev/null
@@ -1,1172 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-# include "sendmail.h"
-
-#ifndef lint
-#if SMTP
-static char sccsid[] = "@(#)usersmtp.c 8.111 (Berkeley) 2/3/1999 (with SMTP)";
-#else
-static char sccsid[] = "@(#)usersmtp.c 8.111 (Berkeley) 2/3/1999 (without SMTP)";
-#endif
-#endif /* not lint */
-
-# include <sysexits.h>
-# include <errno.h>
-
-# if SMTP
-
-/*
-** USERSMTP -- run SMTP protocol from the user end.
-**
-** This protocol is described in RFC821.
-*/
-
-#define REPLYTYPE(r) ((r) / 100) /* first digit of reply code */
-#define REPLYCLASS(r) (((r) / 10) % 10) /* second digit of reply code */
-#define SMTPCLOSING 421 /* "Service Shutting Down" */
-
-char SmtpMsgBuffer[MAXLINE]; /* buffer for commands */
-char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */
-char SmtpError[MAXLINE] = ""; /* save failure error messages */
-bool SmtpNeedIntro; /* need "while talking" in transcript */
-
-extern void smtpmessage __P((char *f, MAILER *m, MCI *mci, ...));
-extern int reply __P((MAILER *, MCI *, ENVELOPE *, time_t, void (*)()));
- /*
-** SMTPINIT -- initialize SMTP.
-**
-** Opens the connection and sends the initial protocol.
-**
-** Parameters:
-** m -- mailer to create connection to.
-** pvp -- pointer to parameter vector to pass to
-** the mailer.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** creates connection and sends initial protocol.
-*/
-
-void
-smtpinit(m, mci, e)
- MAILER *m;
- register MCI *mci;
- ENVELOPE *e;
-{
- register int r;
- register char *p;
- extern void esmtp_check __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
- extern void helo_options __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
-
- if (tTd(18, 1))
- {
- printf("smtpinit ");
- mci_dump(mci, FALSE);
- }
-
- /*
- ** Open the connection to the mailer.
- */
-
- SmtpError[0] = '\0';
- CurHostName = mci->mci_host; /* XXX UGLY XXX */
- if (CurHostName == NULL)
- CurHostName = MyHostName;
- SmtpNeedIntro = TRUE;
- switch (mci->mci_state)
- {
- case MCIS_ACTIVE:
- /* need to clear old information */
- smtprset(m, mci, e);
- /* fall through */
-
- case MCIS_OPEN:
- return;
-
- case MCIS_ERROR:
- case MCIS_SSD:
- /* shouldn't happen */
- smtpquit(m, mci, e);
- /* fall through */
-
- case MCIS_CLOSED:
- syserr("451 smtpinit: state CLOSED");
- return;
-
- case MCIS_OPENING:
- break;
- }
-
- mci->mci_state = MCIS_OPENING;
-
- /*
- ** Get the greeting message.
- ** This should appear spontaneously. Give it five minutes to
- ** happen.
- */
-
- SmtpPhase = mci->mci_phase = "client greeting";
- sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
- r = reply(m, mci, e, TimeOuts.to_initial, esmtp_check);
- if (r < 0)
- goto tempfail1;
- if (REPLYTYPE(r) == 4)
- goto tempfail2;
- if (REPLYTYPE(r) != 2)
- goto unavailable;
-
- /*
- ** Send the HELO command.
- ** My mother taught me to always introduce myself.
- */
-
- if (bitnset(M_ESMTP, m->m_flags) || bitnset(M_LMTP, m->m_flags))
- mci->mci_flags |= MCIF_ESMTP;
-
-tryhelo:
- if (bitnset(M_LMTP, m->m_flags))
- {
- smtpmessage("LHLO %s", m, mci, MyHostName);
- SmtpPhase = mci->mci_phase = "client LHLO";
- }
- else if (bitset(MCIF_ESMTP, mci->mci_flags))
- {
- smtpmessage("EHLO %s", m, mci, MyHostName);
- SmtpPhase = mci->mci_phase = "client EHLO";
- }
- else
- {
- smtpmessage("HELO %s", m, mci, MyHostName);
- SmtpPhase = mci->mci_phase = "client HELO";
- }
- sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
- r = reply(m, mci, e, TimeOuts.to_helo, helo_options);
- if (r < 0)
- goto tempfail1;
- else if (REPLYTYPE(r) == 5)
- {
- if (bitset(MCIF_ESMTP, mci->mci_flags) &&
- !bitnset(M_LMTP, m->m_flags))
- {
- /* try old SMTP instead */
- mci->mci_flags &= ~MCIF_ESMTP;
- goto tryhelo;
- }
- goto unavailable;
- }
- else if (REPLYTYPE(r) != 2)
- goto tempfail2;
-
- /*
- ** Check to see if we actually ended up talking to ourself.
- ** This means we didn't know about an alias or MX, or we managed
- ** to connect to an echo server.
- */
-
- p = strchr(&SmtpReplyBuffer[4], ' ');
- if (p != NULL)
- *p = '\0';
- if (!bitnset(M_NOLOOPCHECK, m->m_flags) &&
- !bitnset(M_LMTP, m->m_flags) &&
- strcasecmp(&SmtpReplyBuffer[4], MyHostName) == 0)
- {
- syserr("553 %s config error: mail loops back to me (MX problem?)",
- CurHostName);
- mci_setstat(mci, EX_CONFIG, NULL, NULL);
- mci->mci_errno = 0;
- smtpquit(m, mci, e);
- return;
- }
-
- /*
- ** If this is expected to be another sendmail, send some internal
- ** commands.
- */
-
- if (bitnset(M_INTERNAL, m->m_flags))
- {
- /* tell it to be verbose */
- smtpmessage("VERB", m, mci);
- r = reply(m, mci, e, TimeOuts.to_miscshort, NULL);
- if (r < 0)
- goto tempfail1;
- }
-
- if (mci->mci_state != MCIS_CLOSED)
- {
- mci->mci_state = MCIS_OPEN;
- return;
- }
-
- /* got a 421 error code during startup */
-
- tempfail1:
- if (mci->mci_errno == 0)
- mci->mci_errno = errno;
- mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL);
- if (mci->mci_state != MCIS_CLOSED)
- smtpquit(m, mci, e);
- return;
-
- tempfail2:
- if (mci->mci_errno == 0)
- mci->mci_errno = errno;
- /* XXX should use code from other end iff ENHANCEDSTATUSCODES */
- mci_setstat(mci, EX_TEMPFAIL, "4.5.0", SmtpReplyBuffer);
- if (mci->mci_state != MCIS_CLOSED)
- smtpquit(m, mci, e);
- return;
-
- unavailable:
- mci->mci_errno = errno;
- mci_setstat(mci, EX_UNAVAILABLE, "5.5.0", SmtpReplyBuffer);
- smtpquit(m, mci, e);
- return;
-}
- /*
-** ESMTP_CHECK -- check to see if this implementation likes ESMTP protocol
-**
-** Parameters:
-** line -- the response line.
-** firstline -- set if this is the first line of the reply.
-** m -- the mailer.
-** mci -- the mailer connection info.
-** e -- the envelope.
-**
-** Returns:
-** none.
-*/
-
-void
-esmtp_check(line, firstline, m, mci, e)
- char *line;
- bool firstline;
- MAILER *m;
- register MCI *mci;
- ENVELOPE *e;
-{
- if (strstr(line, "ESMTP") != NULL)
- mci->mci_flags |= MCIF_ESMTP;
- if (strstr(line, "8BIT-OK") != NULL)
- mci->mci_flags |= MCIF_8BITOK;
-}
- /*
-** HELO_OPTIONS -- process the options on a HELO line.
-**
-** Parameters:
-** line -- the response line.
-** firstline -- set if this is the first line of the reply.
-** m -- the mailer.
-** mci -- the mailer connection info.
-** e -- the envelope.
-**
-** Returns:
-** none.
-*/
-
-void
-helo_options(line, firstline, m, mci, e)
- char *line;
- bool firstline;
- MAILER *m;
- register MCI *mci;
- ENVELOPE *e;
-{
- register char *p;
-
- if (firstline)
- return;
-
- if (strlen(line) < (SIZE_T) 5)
- return;
- line += 4;
- p = strchr(line, ' ');
- if (p != NULL)
- *p++ = '\0';
- if (strcasecmp(line, "size") == 0)
- {
- mci->mci_flags |= MCIF_SIZE;
- if (p != NULL)
- mci->mci_maxsize = atol(p);
- }
- else if (strcasecmp(line, "8bitmime") == 0)
- {
- mci->mci_flags |= MCIF_8BITMIME;
- mci->mci_flags &= ~MCIF_7BIT;
- }
- else if (strcasecmp(line, "expn") == 0)
- mci->mci_flags |= MCIF_EXPN;
- else if (strcasecmp(line, "dsn") == 0)
- mci->mci_flags |= MCIF_DSN;
-}
- /*
-** SMTPMAILFROM -- send MAIL command
-**
-** Parameters:
-** m -- the mailer.
-** mci -- the mailer connection structure.
-** e -- the envelope (including the sender to specify).
-*/
-
-int
-smtpmailfrom(m, mci, e)
- MAILER *m;
- MCI *mci;
- ENVELOPE *e;
-{
- int r;
- char *bufp;
- char *bodytype;
- char buf[MAXNAME + 1];
- char optbuf[MAXLINE];
-
- if (tTd(18, 2))
- printf("smtpmailfrom: CurHost=%s\n", CurHostName);
-
- /* set up appropriate options to include */
- bufp = optbuf;
- if (bitset(MCIF_SIZE, mci->mci_flags) && e->e_msgsize > 0)
- snprintf(optbuf, sizeof optbuf, " SIZE=%ld", e->e_msgsize);
- else
- strcpy(optbuf, "");
- bufp = &optbuf[strlen(optbuf)];
-
- bodytype = e->e_bodytype;
- if (bitset(MCIF_8BITMIME, mci->mci_flags))
- {
- if (bodytype == NULL &&
- bitset(MM_MIME8BIT, MimeMode) &&
- bitset(EF_HAS8BIT, e->e_flags) &&
- !bitset(EF_DONT_MIME, e->e_flags) &&
- !bitnset(M_8BITS, m->m_flags))
- bodytype = "8BITMIME";
- if (bodytype != NULL &&
- SPACELEFT(optbuf, bufp) > strlen(bodytype) + 7)
- {
- snprintf(bufp, SPACELEFT(optbuf, bufp),
- " BODY=%s", bodytype);
- bufp += strlen(bufp);
- }
- }
- else if (bitnset(M_8BITS, m->m_flags) ||
- !bitset(EF_HAS8BIT, e->e_flags) ||
- bitset(MCIF_8BITOK, mci->mci_flags))
- {
- /* just pass it through */
- }
-#if MIME8TO7
- else if (bitset(MM_CVTMIME, MimeMode) &&
- !bitset(EF_DONT_MIME, e->e_flags) &&
- (!bitset(MM_PASS8BIT, MimeMode) ||
- bitset(EF_IS_MIME, e->e_flags)))
- {
- /* must convert from 8bit MIME format to 7bit encoded */
- mci->mci_flags |= MCIF_CVT8TO7;
- }
-#endif
- else if (!bitset(MM_PASS8BIT, MimeMode))
- {
- /* cannot just send a 8-bit version */
- extern char MsgBuf[];
-
- usrerr("%s does not support 8BITMIME", CurHostName);
- mci_setstat(mci, EX_NOTSTICKY, "5.6.3", MsgBuf);
- return EX_DATAERR;
- }
-
- if (bitset(MCIF_DSN, mci->mci_flags))
- {
- if (e->e_envid != NULL &&
- SPACELEFT(optbuf, bufp) > strlen(e->e_envid) + 7)
- {
- snprintf(bufp, SPACELEFT(optbuf, bufp),
- " ENVID=%s", e->e_envid);
- bufp += strlen(bufp);
- }
-
- /* RET= parameter */
- if (bitset(EF_RET_PARAM, e->e_flags) &&
- SPACELEFT(optbuf, bufp) > 9)
- {
- snprintf(bufp, SPACELEFT(optbuf, bufp),
- " RET=%s",
- bitset(EF_NO_BODY_RETN, e->e_flags) ?
- "HDRS" : "FULL");
- bufp += strlen(bufp);
- }
- }
-
- /*
- ** Send the MAIL command.
- ** Designates the sender.
- */
-
- mci->mci_state = MCIS_ACTIVE;
-
- if (bitset(EF_RESPONSE, e->e_flags) &&
- !bitnset(M_NO_NULL_FROM, m->m_flags))
- (void) strcpy(buf, "");
- else
- expand("\201g", buf, sizeof buf, e);
- if (buf[0] == '<')
- {
- /* strip off <angle brackets> (put back on below) */
- bufp = &buf[strlen(buf) - 1];
- if (*bufp == '>')
- *bufp = '\0';
- bufp = &buf[1];
- }
- else
- bufp = buf;
- if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) ||
- !bitnset(M_FROMPATH, m->m_flags))
- {
- smtpmessage("MAIL From:<%s>%s", m, mci, bufp, optbuf);
- }
- else
- {
- smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName,
- *bufp == '@' ? ',' : ':', bufp, optbuf);
- }
- SmtpPhase = mci->mci_phase = "client MAIL";
- sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
- r = reply(m, mci, e, TimeOuts.to_mail, NULL);
- if (r < 0)
- {
- /* communications failure */
- mci->mci_errno = errno;
- mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL);
- smtpquit(m, mci, e);
- return EX_TEMPFAIL;
- }
- else if (r == 421)
- {
- /* service shutting down */
- mci_setstat(mci, EX_TEMPFAIL, "4.5.0", SmtpReplyBuffer);
- smtpquit(m, mci, e);
- return EX_TEMPFAIL;
- }
- else if (REPLYTYPE(r) == 4)
- {
- mci_setstat(mci, EX_NOTSTICKY, smtptodsn(r), SmtpReplyBuffer);
- return EX_TEMPFAIL;
- }
- else if (REPLYTYPE(r) == 2)
- {
- return EX_OK;
- }
- else if (r == 501)
- {
- /* syntax error in arguments */
- mci_setstat(mci, EX_NOTSTICKY, "5.5.2", SmtpReplyBuffer);
- return EX_DATAERR;
- }
- else if (r == 553)
- {
- /* mailbox name not allowed */
- mci_setstat(mci, EX_NOTSTICKY, "5.1.3", SmtpReplyBuffer);
- return EX_DATAERR;
- }
- else if (r == 552)
- {
- /* exceeded storage allocation */
- mci_setstat(mci, EX_NOTSTICKY, "5.3.4", SmtpReplyBuffer);
- if (bitset(MCIF_SIZE, mci->mci_flags))
- e->e_flags |= EF_NO_BODY_RETN;
- return EX_UNAVAILABLE;
- }
- else if (REPLYTYPE(r) == 5)
- {
- /* unknown error */
- mci_setstat(mci, EX_NOTSTICKY, "5.0.0", SmtpReplyBuffer);
- return EX_UNAVAILABLE;
- }
-
- if (LogLevel > 1)
- {
- sm_syslog(LOG_CRIT, e->e_id,
- "%.100s: SMTP MAIL protocol error: %s",
- CurHostName,
- shortenstring(SmtpReplyBuffer, 403));
- }
-
- /* protocol error -- close up */
- mci_setstat(mci, EX_PROTOCOL, "5.5.1", SmtpReplyBuffer);
- smtpquit(m, mci, e);
- return EX_PROTOCOL;
-}
- /*
-** SMTPRCPT -- designate recipient.
-**
-** Parameters:
-** to -- address of recipient.
-** m -- the mailer we are sending to.
-** mci -- the connection info for this transaction.
-** e -- the envelope for this transaction.
-**
-** Returns:
-** exit status corresponding to recipient status.
-**
-** Side Effects:
-** Sends the mail via SMTP.
-*/
-
-int
-smtprcpt(to, m, mci, e)
- ADDRESS *to;
- register MAILER *m;
- MCI *mci;
- ENVELOPE *e;
-{
- register int r;
- char *bufp;
- char optbuf[MAXLINE];
-
- strcpy(optbuf, "");
- bufp = &optbuf[strlen(optbuf)];
- if (bitset(MCIF_DSN, mci->mci_flags))
- {
- /* NOTIFY= parameter */
- if (bitset(QHASNOTIFY, to->q_flags) &&
- bitset(QPRIMARY, to->q_flags) &&
- !bitnset(M_LOCALMAILER, m->m_flags))
- {
- bool firstone = TRUE;
-
- strcat(bufp, " NOTIFY=");
- if (bitset(QPINGONSUCCESS, to->q_flags))
- {
- strcat(bufp, "SUCCESS");
- firstone = FALSE;
- }
- if (bitset(QPINGONFAILURE, to->q_flags))
- {
- if (!firstone)
- strcat(bufp, ",");
- strcat(bufp, "FAILURE");
- firstone = FALSE;
- }
- if (bitset(QPINGONDELAY, to->q_flags))
- {
- if (!firstone)
- strcat(bufp, ",");
- strcat(bufp, "DELAY");
- firstone = FALSE;
- }
- if (firstone)
- strcat(bufp, "NEVER");
- bufp += strlen(bufp);
- }
-
- /* ORCPT= parameter */
- if (to->q_orcpt != NULL &&
- SPACELEFT(optbuf, bufp) > strlen(to->q_orcpt) + 7)
- {
- snprintf(bufp, SPACELEFT(optbuf, bufp),
- " ORCPT=%s", to->q_orcpt);
- bufp += strlen(bufp);
- }
- }
-
- smtpmessage("RCPT To:<%s>%s", m, mci, to->q_user, optbuf);
-
- SmtpPhase = mci->mci_phase = "client RCPT";
- sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
- r = reply(m, mci, e, TimeOuts.to_rcpt, NULL);
- to->q_rstatus = newstr(SmtpReplyBuffer);
- to->q_status = smtptodsn(r);
- to->q_statmta = mci->mci_host;
- if (r < 0 || REPLYTYPE(r) == 4)
- return EX_TEMPFAIL;
- else if (REPLYTYPE(r) == 2)
- return EX_OK;
- else if (r == 550)
- {
- to->q_status = "5.1.1";
- return EX_NOUSER;
- }
- else if (r == 551)
- {
- to->q_status = "5.1.6";
- return EX_NOUSER;
- }
- else if (r == 553)
- {
- to->q_status = "5.1.3";
- return EX_NOUSER;
- }
- else if (REPLYTYPE(r) == 5)
- {
- return EX_UNAVAILABLE;
- }
-
- if (LogLevel > 1)
- {
- sm_syslog(LOG_CRIT, e->e_id,
- "%.100s: SMTP RCPT protocol error: %s",
- CurHostName,
- shortenstring(SmtpReplyBuffer, 403));
- }
-
- mci_setstat(mci, EX_PROTOCOL, "5.5.1", SmtpReplyBuffer);
- return EX_PROTOCOL;
-}
- /*
-** SMTPDATA -- send the data and clean up the transaction.
-**
-** Parameters:
-** m -- mailer being sent to.
-** mci -- the mailer connection information.
-** e -- the envelope for this message.
-**
-** Returns:
-** exit status corresponding to DATA command.
-**
-** Side Effects:
-** none.
-*/
-
-static jmp_buf CtxDataTimeout;
-static void datatimeout __P((void));
-
-int
-smtpdata(m, mci, e)
- MAILER *m;
- register MCI *mci;
- register ENVELOPE *e;
-{
- register int r;
- register EVENT *ev;
- int rstat;
- int xstat;
- time_t timeout;
-
- /*
- ** Send the data.
- ** First send the command and check that it is ok.
- ** Then send the data.
- ** Follow it up with a dot to terminate.
- ** Finally get the results of the transaction.
- */
-
- /* send the command and check ok to proceed */
- smtpmessage("DATA", m, mci);
- SmtpPhase = mci->mci_phase = "client DATA 354";
- sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
- r = reply(m, mci, e, TimeOuts.to_datainit, NULL);
- if (r < 0 || REPLYTYPE(r) == 4)
- {
- smtpquit(m, mci, e);
- return EX_TEMPFAIL;
- }
- else if (REPLYTYPE(r) == 5)
- {
- smtprset(m, mci, e);
- return EX_UNAVAILABLE;
- }
- else if (REPLYTYPE(r) != 3)
- {
- if (LogLevel > 1)
- {
- sm_syslog(LOG_CRIT, e->e_id,
- "%.100s: SMTP DATA-1 protocol error: %s",
- CurHostName,
- shortenstring(SmtpReplyBuffer, 403));
- }
- smtprset(m, mci, e);
- mci_setstat(mci, EX_PROTOCOL, "5.5.1", SmtpReplyBuffer);
- return (EX_PROTOCOL);
- }
-
- /*
- ** Set timeout around data writes. Make it at least large
- ** enough for DNS timeouts on all recipients plus some fudge
- ** factor. The main thing is that it should not be infinite.
- */
-
- if (setjmp(CtxDataTimeout) != 0)
- {
- mci->mci_errno = errno;
- mci->mci_state = MCIS_ERROR;
- mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL);
- syserr("451 timeout writing message to %s", CurHostName);
- smtpquit(m, mci, e);
- return EX_TEMPFAIL;
- }
-
- timeout = e->e_msgsize / 16;
- if (timeout < (time_t) 600)
- timeout = (time_t) 600;
- timeout += e->e_nrcpts * 300;
- ev = setevent(timeout, datatimeout, 0);
-
- /*
- ** Output the actual message.
- */
-
- (*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER);
- (*e->e_putbody)(mci, e, NULL);
-
- /*
- ** Cleanup after sending message.
- */
-
- clrevent(ev);
-
- if (ferror(mci->mci_out))
- {
- /* error during processing -- don't send the dot */
- mci->mci_errno = EIO;
- mci->mci_state = MCIS_ERROR;
- mci_setstat(mci, EX_IOERR, "4.4.2", NULL);
- smtpquit(m, mci, e);
- return EX_IOERR;
- }
-
- /* terminate the message */
- fprintf(mci->mci_out, ".%s", m->m_eol);
- if (TrafficLogFile != NULL)
- fprintf(TrafficLogFile, "%05d >>> .\n", (int) getpid());
- if (Verbose)
- nmessage(">>> .");
-
- /* check for the results of the transaction */
- SmtpPhase = mci->mci_phase = "client DATA status";
- sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
- if (bitnset(M_LMTP, m->m_flags))
- return EX_OK;
- r = reply(m, mci, e, TimeOuts.to_datafinal, NULL);
- if (r < 0)
- {
- smtpquit(m, mci, e);
- return EX_TEMPFAIL;
- }
- mci->mci_state = MCIS_OPEN;
- xstat = EX_NOTSTICKY;
- if (r == 452)
- rstat = EX_TEMPFAIL;
- else if (REPLYTYPE(r) == 4)
- rstat = xstat = EX_TEMPFAIL;
- else if (REPLYCLASS(r) != 5)
- rstat = xstat = EX_PROTOCOL;
- else if (REPLYTYPE(r) == 2)
- rstat = xstat = EX_OK;
- else if (REPLYTYPE(r) == 5)
- rstat = EX_UNAVAILABLE;
- else
- rstat = EX_PROTOCOL;
- mci_setstat(mci, xstat, smtptodsn(r), SmtpReplyBuffer);
- if (e->e_statmsg != NULL)
- free(e->e_statmsg);
- e->e_statmsg = newstr(&SmtpReplyBuffer[4]);
- if (rstat != EX_PROTOCOL)
- return rstat;
- if (LogLevel > 1)
- {
- sm_syslog(LOG_CRIT, e->e_id,
- "%.100s: SMTP DATA-2 protocol error: %s",
- CurHostName,
- shortenstring(SmtpReplyBuffer, 403));
- }
- return rstat;
-}
-
-
-static void
-datatimeout()
-{
- longjmp(CtxDataTimeout, 1);
-}
- /*
-** SMTPGETSTAT -- get status code from DATA in LMTP
-**
-** Parameters:
-** m -- the mailer to which we are sending the message.
-** mci -- the mailer connection structure.
-** e -- the current envelope.
-**
-** Returns:
-** The exit status corresponding to the reply code.
-*/
-
-int
-smtpgetstat(m, mci, e)
- MAILER *m;
- MCI *mci;
- ENVELOPE *e;
-{
- int r;
- int stat;
-
- /* check for the results of the transaction */
- r = reply(m, mci, e, TimeOuts.to_datafinal, NULL);
- if (r < 0)
- {
- smtpquit(m, mci, e);
- return EX_TEMPFAIL;
- }
- if (e->e_statmsg != NULL)
- free(e->e_statmsg);
- e->e_statmsg = newstr(&SmtpReplyBuffer[4]);
- if (REPLYTYPE(r) == 4)
- stat = EX_TEMPFAIL;
- else if (REPLYCLASS(r) != 5)
- stat = EX_PROTOCOL;
- else if (REPLYTYPE(r) == 2)
- stat = EX_OK;
- else if (REPLYTYPE(r) == 5)
- stat = EX_UNAVAILABLE;
- else
- stat = EX_PROTOCOL;
- mci_setstat(mci, stat, smtptodsn(r), SmtpReplyBuffer);
- if (LogLevel > 1 && stat == EX_PROTOCOL)
- {
- sm_syslog(LOG_CRIT, e->e_id,
- "%.100s: SMTP DATA-3 protocol error: %s",
- CurHostName,
- shortenstring(SmtpReplyBuffer, 403));
- }
- return stat;
-}
- /*
-** SMTPQUIT -- close the SMTP connection.
-**
-** Parameters:
-** m -- a pointer to the mailer.
-** mci -- the mailer connection information.
-** e -- the current envelope.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** sends the final protocol and closes the connection.
-*/
-
-void
-smtpquit(m, mci, e)
- register MAILER *m;
- register MCI *mci;
- ENVELOPE *e;
-{
- bool oldSuprErrs = SuprErrs;
-
- /*
- ** Suppress errors here -- we may be processing a different
- ** job when we do the quit connection, and we don't want the
- ** new job to be penalized for something that isn't it's
- ** problem.
- */
-
- SuprErrs = TRUE;
-
- /* send the quit message if we haven't gotten I/O error */
- if (mci->mci_state != MCIS_ERROR)
- {
- SmtpPhase = "client QUIT";
- smtpmessage("QUIT", m, mci);
- (void) reply(m, mci, e, TimeOuts.to_quit, NULL);
- SuprErrs = oldSuprErrs;
- if (mci->mci_state == MCIS_CLOSED)
- return;
- }
-
- /* now actually close the connection and pick up the zombie */
- (void) endmailer(mci, e, NULL);
-
- SuprErrs = oldSuprErrs;
-}
- /*
-** SMTPRSET -- send a RSET (reset) command
-*/
-
-void
-smtprset(m, mci, e)
- register MAILER *m;
- register MCI *mci;
- ENVELOPE *e;
-{
- int r;
-
- SmtpPhase = "client RSET";
- smtpmessage("RSET", m, mci);
- r = reply(m, mci, e, TimeOuts.to_rset, NULL);
- if (r < 0)
- mci->mci_state = MCIS_ERROR;
- else if (REPLYTYPE(r) == 2)
- {
- mci->mci_state = MCIS_OPEN;
- return;
- }
- smtpquit(m, mci, e);
-}
- /*
-** SMTPPROBE -- check the connection state
-*/
-
-int
-smtpprobe(mci)
- register MCI *mci;
-{
- int r;
- MAILER *m = mci->mci_mailer;
- extern ENVELOPE BlankEnvelope;
- ENVELOPE *e = &BlankEnvelope;
-
- SmtpPhase = "client probe";
- smtpmessage("RSET", m, mci);
- r = reply(m, mci, e, TimeOuts.to_miscshort, NULL);
- if (r < 0 || REPLYTYPE(r) != 2)
- smtpquit(m, mci, e);
- return r;
-}
- /*
-** REPLY -- read arpanet reply
-**
-** Parameters:
-** m -- the mailer we are reading the reply from.
-** mci -- the mailer connection info structure.
-** e -- the current envelope.
-** timeout -- the timeout for reads.
-** pfunc -- processing function called on each line of response.
-** If null, no special processing is done.
-**
-** Returns:
-** reply code it reads.
-**
-** Side Effects:
-** flushes the mail file.
-*/
-
-int
-reply(m, mci, e, timeout, pfunc)
- MAILER *m;
- MCI *mci;
- ENVELOPE *e;
- time_t timeout;
- void (*pfunc)();
-{
- register char *bufp;
- register int r;
- bool firstline = TRUE;
- char junkbuf[MAXLINE];
-
- if (mci->mci_out != NULL)
- (void) fflush(mci->mci_out);
-
- if (tTd(18, 1))
- printf("reply\n");
-
- /*
- ** Read the input line, being careful not to hang.
- */
-
- bufp = SmtpReplyBuffer;
- for (;;)
- {
- register char *p;
-
- /* actually do the read */
- if (e->e_xfp != NULL)
- (void) fflush(e->e_xfp); /* for debugging */
-
- /* if we are in the process of closing just give the code */
- if (mci->mci_state == MCIS_CLOSED)
- return (SMTPCLOSING);
-
- if (mci->mci_out != NULL)
- fflush(mci->mci_out);
-
- /* get the line from the other side */
- p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase);
- mci->mci_lastuse = curtime();
-
- if (p == NULL)
- {
- bool oldholderrs;
- extern char MsgBuf[];
-
- /* if the remote end closed early, fake an error */
- if (errno == 0)
-# ifdef ECONNRESET
- errno = ECONNRESET;
-# else /* ECONNRESET */
- errno = EPIPE;
-# endif /* ECONNRESET */
-
- mci->mci_errno = errno;
- oldholderrs = HoldErrs;
- HoldErrs = TRUE;
- usrerr("451 reply: read error from %s", CurHostName);
-
- /* errors on QUIT should not be persistent */
- if (strncmp(SmtpMsgBuffer, "QUIT", 4) != 0)
- mci_setstat(mci, EX_TEMPFAIL, "4.4.2", MsgBuf);
-
- /* if debugging, pause so we can see state */
- if (tTd(18, 100))
- pause();
- mci->mci_state = MCIS_ERROR;
- smtpquit(m, mci, e);
-#if XDEBUG
- {
- char wbuf[MAXLINE];
- char *p = wbuf;
- int wbufleft = sizeof wbuf;
-
- if (e->e_to != NULL)
- {
- int plen;
-
- snprintf(p, wbufleft, "%s... ",
- shortenstring(e->e_to, MAXSHORTSTR));
- plen = strlen(p);
- p += plen;
- wbufleft -= plen;
- }
- snprintf(p, wbufleft, "reply(%.100s) during %s",
- CurHostName == NULL ? "NO_HOST" : CurHostName,
- SmtpPhase);
- checkfd012(wbuf);
- }
-#endif
- HoldErrs = oldholderrs;
- return (-1);
- }
- fixcrlf(bufp, TRUE);
-
- /* EHLO failure is not a real error */
- if (e->e_xfp != NULL && (bufp[0] == '4' ||
- (bufp[0] == '5' && strncmp(SmtpMsgBuffer, "EHLO", 4) != 0)))
- {
- /* serious error -- log the previous command */
- if (SmtpNeedIntro)
- {
- /* inform user who we are chatting with */
- fprintf(CurEnv->e_xfp,
- "... while talking to %s:\n",
- CurHostName);
- SmtpNeedIntro = FALSE;
- }
- if (SmtpMsgBuffer[0] != '\0')
- fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer);
- SmtpMsgBuffer[0] = '\0';
-
- /* now log the message as from the other side */
- fprintf(e->e_xfp, "<<< %s\n", bufp);
- }
-
- /* display the input for verbose mode */
- if (Verbose)
- nmessage("050 %s", bufp);
-
- /* ignore improperly formated input */
- if (!(isascii(bufp[0]) && isdigit(bufp[0])) ||
- !(isascii(bufp[1]) && isdigit(bufp[1])) ||
- !(isascii(bufp[2]) && isdigit(bufp[2])) ||
- !(bufp[3] == ' ' || bufp[3] == '-' || bufp[3] == '\0'))
- continue;
-
- /* process the line */
- if (pfunc != NULL)
- (*pfunc)(bufp, firstline, m, mci, e);
-
- firstline = FALSE;
-
- /* decode the reply code */
- r = atoi(bufp);
-
- /* extra semantics: 0xx codes are "informational" */
- if (r < 100)
- continue;
-
- /* if no continuation lines, return this line */
- if (bufp[3] != '-')
- break;
-
- /* first line of real reply -- ignore rest */
- bufp = junkbuf;
- }
-
- /*
- ** Now look at SmtpReplyBuffer -- only care about the first
- ** line of the response from here on out.
- */
-
- /* save temporary failure messages for posterity */
- if (SmtpReplyBuffer[0] == '4' &&
- (bitnset(M_LMTP, m->m_flags) || SmtpError[0] == '\0'))
- snprintf(SmtpError, sizeof SmtpError, "%s", SmtpReplyBuffer);
-
- /* reply code 421 is "Service Shutting Down" */
- if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD)
- {
- /* send the quit protocol */
- mci->mci_state = MCIS_SSD;
- smtpquit(m, mci, e);
- }
-
- return (r);
-}
- /*
-** SMTPMESSAGE -- send message to server
-**
-** Parameters:
-** f -- format
-** m -- the mailer to control formatting.
-** a, b, c -- parameters
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** writes message to mci->mci_out.
-*/
-
-/*VARARGS1*/
-void
-#ifdef __STDC__
-smtpmessage(char *f, MAILER *m, MCI *mci, ...)
-#else
-smtpmessage(f, m, mci, va_alist)
- char *f;
- MAILER *m;
- MCI *mci;
- va_dcl
-#endif
-{
- VA_LOCAL_DECL
-
- VA_START(mci);
- (void) vsnprintf(SmtpMsgBuffer, sizeof SmtpMsgBuffer, f, ap);
- VA_END;
-
- if (tTd(18, 1) || Verbose)
- nmessage(">>> %s", SmtpMsgBuffer);
- if (TrafficLogFile != NULL)
- fprintf(TrafficLogFile, "%05d >>> %s\n",
- (int) getpid(), SmtpMsgBuffer);
- if (mci->mci_out != NULL)
- {
- fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer,
- m == NULL ? "\r\n" : m->m_eol);
- }
- else if (tTd(18, 1))
- {
- printf("smtpmessage: NULL mci_out\n");
- }
-}
-
-# endif /* SMTP */
diff --git a/src/util.c b/src/util.c
deleted file mode 100644
index 0cb8992..0000000
--- a/src/util.c
+++ /dev/null
@@ -1,2365 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)util.c 8.168 (Berkeley) 1/21/1999";
-#endif /* not lint */
-
-# include "sendmail.h"
-# include <sysexits.h>
- /*
-** STRIPQUOTES -- Strip quotes & quote bits from a string.
-**
-** Runs through a string and strips off unquoted quote
-** characters and quote bits. This is done in place.
-**
-** Parameters:
-** s -- the string to strip.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** none.
-**
-** Called By:
-** deliver
-*/
-
-void
-stripquotes(s)
- char *s;
-{
- register char *p;
- register char *q;
- register char c;
-
- if (s == NULL)
- return;
-
- p = q = s;
- do
- {
- c = *p++;
- if (c == '\\')
- c = *p++;
- else if (c == '"')
- continue;
- *q++ = c;
- } while (c != '\0');
-}
- /*
-** ADDQUOTES -- Adds quotes & quote bits to a string.
-**
-** Runs through a string and adds characters and quote bits.
-**
-** Parameters:
-** s -- the string to modify.
-**
-** Returns:
-** pointer to quoted string.
-**
-** Side Effects:
-** none.
-**
-*/
-
-char *
-addquotes(s)
- char *s;
-{
- int len = 0;
- char c;
- char *p = s, *q, *r;
-
- if (s == NULL)
- return NULL;
-
- /* Find length of quoted string */
- while ((c = *p++) != '\0')
- {
- len++;
- if (c == '\\' || c == '"')
- len++;
- }
-
- q = r = xalloc(len + 3);
- p = s;
-
- /* add leading quote */
- *q++ = '"';
- while ((c = *p++) != '\0')
- {
- /* quote \ or " */
- if (c == '\\' || c == '"')
- *q++ = '\\';
- *q++ = c;
- }
- *q++ = '"';
- *q = '\0';
- return r;
-}
- /*
-** RFC822_STRING -- Checks string for proper RFC822 string quoting.
-**
-** Runs through a string and verifies RFC822 special characters
-** are only found inside comments, quoted strings, or backslash
-** escaped. Also verified balanced quotes and parenthesis.
-**
-** Parameters:
-** s -- the string to modify.
-**
-** Returns:
-** TRUE -- if the string is RFC822 compliant.
-** FALSE -- if the string is not RFC822 compliant.
-**
-** Side Effects:
-** none.
-**
-*/
-
-bool
-rfc822_string(s)
- char *s;
-{
- bool quoted = FALSE;
- int commentlev = 0;
- char *c = s;
-
- if (s == NULL)
- return FALSE;
-
- while (*c != '\0')
- {
- /* escaped character */
- if (*c == '\\')
- {
- c++;
- if (*c == '\0')
- return FALSE;
- }
- else if (commentlev == 0 && *c == '"')
- quoted = !quoted;
- else if (!quoted)
- {
- if (*c == ')')
- {
- /* unbalanced ')' */
- if (commentlev == 0)
- return FALSE;
- else
- commentlev--;
- }
- else if (*c == '(')
- commentlev++;
- else if (commentlev == 0 &&
- strchr(MustQuoteChars, *c) != NULL)
- return FALSE;
- }
- c++;
- }
- /* unbalanced '"' or '(' */
- if (quoted || commentlev != 0)
- return FALSE;
- else
- return TRUE;
-}
- /*
-** SHORTEN_RFC822_STRING -- Truncate and rebalance an RFC822 string
-**
-** Arbitratily shorten (in place) an RFC822 string and rebalance
-** comments and quotes.
-**
-** Parameters:
-** string -- the string to shorten
-** length -- the maximum size, 0 if no maximum
-**
-** Returns:
-** TRUE if string is changed, FALSE otherwise
-**
-** Side Effects:
-** Changes string in place, possibly resulting
-** in a shorter string.
-*/
-
-bool
-shorten_rfc822_string(string, length)
- char *string;
- size_t length;
-{
- bool backslash = FALSE;
- bool modified = FALSE;
- bool quoted = FALSE;
- size_t slen;
- int parencount = 0;
- char *ptr = string;
-
- /*
- ** If have to rebalance an already short enough string,
- ** need to do it within allocated space.
- */
- slen = strlen(string);
- if (length == 0 || slen < length)
- length = slen;
-
- while (*ptr != '\0')
- {
- if (backslash)
- {
- backslash = FALSE;
- goto increment;
- }
-
- if (*ptr == '\\')
- backslash = TRUE;
- else if (*ptr == '(')
- {
- if (!quoted)
- parencount++;
- }
- else if (*ptr == ')')
- {
- if (--parencount < 0)
- parencount = 0;
- }
-
- /* Inside a comment, quotes don't matter */
- if (parencount <= 0 && *ptr == '"')
- quoted = !quoted;
-
-increment:
- /* Check for sufficient space for next character */
- if (length - (ptr - string) <= ((backslash ? 1 : 0) +
- parencount +
- (quoted ? 1 : 0)))
- {
- /* Not enough, backtrack */
- if (*ptr == '\\')
- backslash = FALSE;
- else if (*ptr == '(' && !quoted)
- parencount--;
- else if (*ptr == '"' && parencount == 0)
- quoted = FALSE;
- break;
- }
- ptr++;
- }
-
- /* Rebalance */
- while (parencount-- > 0)
- {
- if (*ptr != ')')
- {
- modified = TRUE;
- *ptr = ')';
- }
- ptr++;
- }
- if (quoted)
- {
- if (*ptr != '"')
- {
- modified = TRUE;
- *ptr = '"';
- }
- ptr++;
- }
- if (*ptr != '\0')
- {
- modified = TRUE;
- *ptr = '\0';
- }
- return modified;
-}
- /*
-** FIND_CHARACTER -- find an unquoted character in an RFC822 string
-**
-** Find an unquoted, non-commented character in an RFC822
-** string and return a pointer to its location in the
-** string.
-**
-** Parameters:
-** string -- the string to search
-** character -- the character to find
-**
-** Returns:
-** pointer to the character, or
-** a pointer to the end of the line if character is not found
-*/
-
-char *
-find_character(string, character)
- char *string;
- char character;
-{
- bool backslash = FALSE;
- bool quoted = FALSE;
- int parencount = 0;
-
- while (string != NULL && *string != '\0')
- {
- if (backslash)
- {
- backslash = FALSE;
- if (!quoted && character == '\\' && *string == '\\')
- break;
- string++;
- continue;
- }
- switch (*string)
- {
- case '\\':
- backslash = TRUE;
- break;
-
- case '(':
- if (!quoted)
- parencount++;
- break;
-
- case ')':
- if (--parencount < 0)
- parencount = 0;
- break;
- }
-
- /* Inside a comment, nothing matters */
- if (parencount > 0)
- {
- string++;
- continue;
- }
-
- if (*string == '"')
- quoted = !quoted;
- else if (*string == character && !quoted)
- break;
- string++;
- }
-
- /* Return pointer to the character */
- return string;
-}
- /*
-** XALLOC -- Allocate memory and bitch wildly on failure.
-**
-** THIS IS A CLUDGE. This should be made to give a proper
-** error -- but after all, what can we do?
-**
-** Parameters:
-** sz -- size of area to allocate.
-**
-** Returns:
-** pointer to data region.
-**
-** Side Effects:
-** Memory is allocated.
-*/
-
-char *
-xalloc(sz)
- register int sz;
-{
- register char *p;
-
- /* some systems can't handle size zero mallocs */
- if (sz <= 0)
- sz = 1;
-
- p = malloc((unsigned) sz);
- if (p == NULL)
- {
- syserr("!Out of memory!!");
- /* exit(EX_UNAVAILABLE); */
- }
- return (p);
-}
- /*
-** COPYPLIST -- copy list of pointers.
-**
-** This routine is the equivalent of newstr for lists of
-** pointers.
-**
-** Parameters:
-** list -- list of pointers to copy.
-** Must be NULL terminated.
-** copycont -- if TRUE, copy the contents of the vector
-** (which must be a string) also.
-**
-** Returns:
-** a copy of 'list'.
-**
-** Side Effects:
-** none.
-*/
-
-char **
-copyplist(list, copycont)
- char **list;
- bool copycont;
-{
- register char **vp;
- register char **newvp;
-
- for (vp = list; *vp != NULL; vp++)
- continue;
-
- vp++;
-
- newvp = (char **) xalloc((int) (vp - list) * sizeof *vp);
- bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp);
-
- if (copycont)
- {
- for (vp = newvp; *vp != NULL; vp++)
- *vp = newstr(*vp);
- }
-
- return (newvp);
-}
- /*
-** COPYQUEUE -- copy address queue.
-**
-** This routine is the equivalent of newstr for address queues
-** addresses marked with QDONTSEND aren't copied
-**
-** Parameters:
-** addr -- list of address structures to copy.
-**
-** Returns:
-** a copy of 'addr'.
-**
-** Side Effects:
-** none.
-*/
-
-ADDRESS *
-copyqueue(addr)
- ADDRESS *addr;
-{
- register ADDRESS *newaddr;
- ADDRESS *ret;
- register ADDRESS **tail = &ret;
-
- while (addr != NULL)
- {
- if (!bitset(QDONTSEND, addr->q_flags))
- {
- newaddr = (ADDRESS *) xalloc(sizeof(ADDRESS));
- STRUCTCOPY(*addr, *newaddr);
- *tail = newaddr;
- tail = &newaddr->q_next;
- }
- addr = addr->q_next;
- }
- *tail = NULL;
-
- return ret;
-}
- /*
-** PRINTAV -- print argument vector.
-**
-** Parameters:
-** av -- argument vector.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** prints av.
-*/
-
-void
-printav(av)
- register char **av;
-{
- while (*av != NULL)
- {
- if (tTd(0, 44))
- printf("\n\t%08lx=", (u_long) *av);
- else
- (void) putchar(' ');
- xputs(*av++);
- }
- (void) putchar('\n');
-}
- /*
-** LOWER -- turn letter into lower case.
-**
-** Parameters:
-** c -- character to turn into lower case.
-**
-** Returns:
-** c, in lower case.
-**
-** Side Effects:
-** none.
-*/
-
-char
-lower(c)
- register char c;
-{
- return((isascii(c) && isupper(c)) ? tolower(c) : c);
-}
- /*
-** XPUTS -- put string doing control escapes.
-**
-** Parameters:
-** s -- string to put.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** output to stdout
-*/
-
-void
-xputs(s)
- register const char *s;
-{
- register int c;
- register struct metamac *mp;
- bool shiftout = FALSE;
- extern struct metamac MetaMacros[];
-
- if (s == NULL)
- {
- printf("%s<null>%s", TermEscape.te_rv_on, TermEscape.te_rv_off);
- return;
- }
- while ((c = (*s++ & 0377)) != '\0')
- {
- if (shiftout)
- {
- printf("%s", TermEscape.te_rv_off);
- shiftout = FALSE;
- }
- if (!isascii(c))
- {
- if (c == MATCHREPL)
- {
- printf("%s$", TermEscape.te_rv_on);
- shiftout = TRUE;
- if (*s == '\0')
- continue;
- c = *s++ & 0377;
- goto printchar;
- }
- if (c == MACROEXPAND || c == MACRODEXPAND)
- {
- printf("%s$", TermEscape.te_rv_on);
- if (c == MACRODEXPAND)
- putchar('&');
- shiftout = TRUE;
- if (*s == '\0')
- continue;
- if (strchr("=~&?", *s) != NULL)
- putchar(*s++);
- if (bitset(0200, *s))
- printf("{%s}", macname(*s++ & 0377));
- else
- printf("%c", *s++);
- continue;
- }
- for (mp = MetaMacros; mp->metaname != '\0'; mp++)
- {
- if ((mp->metaval & 0377) == c)
- {
- printf("%s$%c",
- TermEscape.te_rv_on,
- mp->metaname);
- shiftout = TRUE;
- break;
- }
- }
- if (c == MATCHCLASS || c == MATCHNCLASS)
- {
- if (bitset(0200, *s))
- printf("{%s}", macname(*s++ & 0377));
- else if (*s != '\0')
- printf("%c", *s++);
- }
- if (mp->metaname != '\0')
- continue;
-
- /* unrecognized meta character */
- printf("%sM-", TermEscape.te_rv_on);
- shiftout = TRUE;
- c &= 0177;
- }
- printchar:
- if (isprint(c))
- {
- putchar(c);
- continue;
- }
-
- /* wasn't a meta-macro -- find another way to print it */
- switch (c)
- {
- case '\n':
- c = 'n';
- break;
-
- case '\r':
- c = 'r';
- break;
-
- case '\t':
- c = 't';
- break;
- }
- if (!shiftout)
- {
- printf("%s", TermEscape.te_rv_on);
- shiftout = TRUE;
- }
- if (isprint(c))
- {
- (void) putchar('\\');
- (void) putchar(c);
- }
- else
- {
- (void) putchar('^');
- (void) putchar(c ^ 0100);
- }
- }
- if (shiftout)
- printf("%s", TermEscape.te_rv_off);
- (void) fflush(stdout);
-}
- /*
-** MAKELOWER -- Translate a line into lower case
-**
-** Parameters:
-** p -- the string to translate. If NULL, return is
-** immediate.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** String pointed to by p is translated to lower case.
-**
-** Called By:
-** parse
-*/
-
-void
-makelower(p)
- register char *p;
-{
- register char c;
-
- if (p == NULL)
- return;
- for (; (c = *p) != '\0'; p++)
- if (isascii(c) && isupper(c))
- *p = tolower(c);
-}
- /*
-** BUILDFNAME -- build full name from gecos style entry.
-**
-** This routine interprets the strange entry that would appear
-** in the GECOS field of the password file.
-**
-** Parameters:
-** p -- name to build.
-** login -- the login name of this user (for &).
-** buf -- place to put the result.
-** buflen -- length of buf.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** none.
-*/
-
-void
-buildfname(gecos, login, buf, buflen)
- register char *gecos;
- char *login;
- char *buf;
- int buflen;
-{
- register char *p;
- register char *bp = buf;
-
- if (*gecos == '*')
- gecos++;
-
- /* copy gecos, interpolating & to be full name */
- for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++)
- {
- if (bp >= &buf[buflen - 1])
- {
- /* buffer overflow -- just use login name */
- snprintf(buf, buflen, "%s", login);
- return;
- }
- if (*p == '&')
- {
- /* interpolate full name */
- snprintf(bp, buflen - (bp - buf), "%s", login);
- *bp = toupper(*bp);
- bp += strlen(bp);
- }
- else
- *bp++ = *p;
- }
- *bp = '\0';
-}
- /*
-** FIXCRLF -- fix <CR><LF> in line.
-**
-** Looks for the <CR><LF> combination and turns it into the
-** UNIX canonical <NL> character. It only takes one line,
-** i.e., it is assumed that the first <NL> found is the end
-** of the line.
-**
-** Parameters:
-** line -- the line to fix.
-** stripnl -- if true, strip the newline also.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** line is changed in place.
-*/
-
-void
-fixcrlf(line, stripnl)
- char *line;
- bool stripnl;
-{
- register char *p;
-
- p = strchr(line, '\n');
- if (p == NULL)
- return;
- if (p > line && p[-1] == '\r')
- p--;
- if (!stripnl)
- *p++ = '\n';
- *p = '\0';
-}
- /*
-** PUTLINE -- put a line like fputs obeying SMTP conventions
-**
-** This routine always guarantees outputing a newline (or CRLF,
-** as appropriate) at the end of the string.
-**
-** Parameters:
-** l -- line to put.
-** mci -- the mailer connection information.
-**
-** Returns:
-** none
-**
-** Side Effects:
-** output of l to fp.
-*/
-
-void
-putline(l, mci)
- register char *l;
- register MCI *mci;
-{
- putxline(l, strlen(l), mci, PXLF_MAPFROM);
-}
- /*
-** PUTXLINE -- putline with flags bits.
-**
-** This routine always guarantees outputing a newline (or CRLF,
-** as appropriate) at the end of the string.
-**
-** Parameters:
-** l -- line to put.
-** len -- the length of the line.
-** mci -- the mailer connection information.
-** pxflags -- flag bits:
-** PXLF_MAPFROM -- map From_ to >From_.
-** PXLF_STRIP8BIT -- strip 8th bit.
-** PXLF_HEADER -- map bare newline in header to newline space.
-**
-** Returns:
-** none
-**
-** Side Effects:
-** output of l to fp.
-*/
-
-void
-putxline(l, len, mci, pxflags)
- register char *l;
- size_t len;
- register MCI *mci;
- int pxflags;
-{
- register char *p, *end;
- int slop = 0;
- size_t eol_len = strlen(mci->mci_mailer->m_eol);
-
- /* strip out 0200 bits -- these can look like TELNET protocol */
- if (bitset(MCIF_7BIT, mci->mci_flags) ||
- bitset(PXLF_STRIP8BIT, pxflags))
- {
- register char svchar;
-
- for (p = l; (svchar = *p) != '\0'; ++p)
- if (bitset(0200, svchar))
- *p = svchar &~ 0200;
- }
-
- end = l + len;
- do
- {
- /* find the end of the line */
- p = memchr(l, '\n', end - l);
- if (p == NULL)
- p = end;
-
- if (TrafficLogFile != NULL)
- fprintf(TrafficLogFile, "%05d >>> ", (int) getpid());
-
- /* check for line overflow */
- while (mci->mci_mailer->m_linelimit > 0 &&
- (p - l + slop) > mci->mci_mailer->m_linelimit)
- {
- char *l_base = l;
- register char *q = &l[mci->mci_mailer->m_linelimit - slop - 1];
-
- if (l[0] == '.' && slop == 0 &&
- bitnset(M_XDOT, mci->mci_mailer->m_flags))
- {
- (void) putc('.', mci->mci_out);
- if (!bitset(MCIF_INHEADER, mci->mci_flags))
- mci->mci_contentlen++;
- if (TrafficLogFile != NULL)
- (void) putc('.', TrafficLogFile);
- }
- else if (l[0] == 'F' && slop == 0 &&
- bitset(PXLF_MAPFROM, pxflags) &&
- strncmp(l, "From ", 5) == 0 &&
- bitnset(M_ESCFROM, mci->mci_mailer->m_flags))
- {
- (void) putc('>', mci->mci_out);
- if (!bitset(MCIF_INHEADER, mci->mci_flags))
- mci->mci_contentlen++;
- if (TrafficLogFile != NULL)
- (void) putc('>', TrafficLogFile);
- }
- while (l < q)
- {
- (void) putc(*l++, mci->mci_out);
- if (!bitset(MCIF_INHEADER, mci->mci_flags))
- mci->mci_contentlen++;
- }
- (void) putc('!', mci->mci_out);
- if (!bitset(MCIF_INHEADER, mci->mci_flags))
- mci->mci_contentlen++;
- fputs(mci->mci_mailer->m_eol, mci->mci_out);
- if (!bitset(MCIF_INHEADER, mci->mci_flags))
- mci->mci_contentlen += eol_len;
- (void) putc(' ', mci->mci_out);
- if (!bitset(MCIF_INHEADER, mci->mci_flags))
- mci->mci_contentlen++;
- if (TrafficLogFile != NULL)
- {
- for (l = l_base; l < q; l++)
- (void) putc(*l, TrafficLogFile);
- fprintf(TrafficLogFile, "!\n%05d >>> ",
- (int) getpid());
- }
- slop = 1;
- }
-
- /* output last part */
- if (l[0] == '.' && slop == 0 &&
- bitnset(M_XDOT, mci->mci_mailer->m_flags))
- {
- (void) putc('.', mci->mci_out);
- if (!bitset(MCIF_INHEADER, mci->mci_flags))
- mci->mci_contentlen++;
- if (TrafficLogFile != NULL)
- (void) putc('.', TrafficLogFile);
- }
- else if (l[0] == 'F' && slop == 0 &&
- bitset(PXLF_MAPFROM, pxflags) &&
- strncmp(l, "From ", 5) == 0 &&
- bitnset(M_ESCFROM, mci->mci_mailer->m_flags))
- {
- (void) putc('>', mci->mci_out);
- if (!bitset(MCIF_INHEADER, mci->mci_flags))
- mci->mci_contentlen++;
- if (TrafficLogFile != NULL)
- (void) putc('>', TrafficLogFile);
- }
- for ( ; l < p; ++l)
- {
- if (TrafficLogFile != NULL)
- (void) putc(*l, TrafficLogFile);
- (void) putc(*l, mci->mci_out);
- if (!bitset(MCIF_INHEADER, mci->mci_flags))
- mci->mci_contentlen++;
- }
- if (TrafficLogFile != NULL)
- (void) putc('\n', TrafficLogFile);
- fputs(mci->mci_mailer->m_eol, mci->mci_out);
- if (!bitset(MCIF_INHEADER, mci->mci_flags))
- mci->mci_contentlen += eol_len;
- if (l < end && *l == '\n')
- {
- if (*++l != ' ' && *l != '\t' && *l != '\0' &&
- bitset(PXLF_HEADER, pxflags))
- {
- (void) putc(' ', mci->mci_out);
- if (!bitset(MCIF_INHEADER, mci->mci_flags))
- mci->mci_contentlen++;
- if (TrafficLogFile != NULL)
- (void) putc(' ', TrafficLogFile);
- }
- }
- } while (l < end);
-}
- /*
-** XUNLINK -- unlink a file, doing logging as appropriate.
-**
-** Parameters:
-** f -- name of file to unlink.
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** f is unlinked.
-*/
-
-void
-xunlink(f)
- char *f;
-{
- register int i;
-
- if (LogLevel > 98)
- sm_syslog(LOG_DEBUG, CurEnv->e_id,
- "unlink %s",
- f);
-
- i = unlink(f);
- if (i < 0 && LogLevel > 97)
- sm_syslog(LOG_DEBUG, CurEnv->e_id,
- "%s: unlink-fail %d",
- f, errno);
-}
- /*
-** XFCLOSE -- close a file, doing logging as appropriate.
-**
-** Parameters:
-** fp -- file pointer for the file to close
-** a, b -- miscellaneous crud to print for debugging
-**
-** Returns:
-** none.
-**
-** Side Effects:
-** fp is closed.
-*/
-
-void
-xfclose(fp, a, b)
- FILE *fp;
- char *a, *b;
-{
- if (tTd(53, 99))
- printf("xfclose(%lx) %s %s\n", (u_long) fp, a, b);
-#if XDEBUG
- if (fileno(fp) == 1)
- syserr("xfclose(%s %s): fd = 1", a, b);
-#endif
- if (fclose(fp) < 0 && tTd(53, 99))
- printf("xfclose FAILURE: %s\n", errstring(errno));
-}
- /*
-** SFGETS -- "safe" fgets -- times out and ignores random interrupts.
-**
-** Parameters:
-** buf -- place to put the input line.
-** siz -- size of buf.
-** fp -- file to read from.
-** timeout -- the timeout before error occurs.
-** during -- what we are trying to read (for error messages).
-**
-** Returns:
-** NULL on error (including timeout). This will also leave
-** buf containing a null string.
-** buf otherwise.
-**
-** Side Effects:
-** none.
-*/
-
-static jmp_buf CtxReadTimeout;
-static void readtimeout __P((time_t));
-
-char *
-sfgets(buf, siz, fp, timeout, during)
- char *buf;
- int siz;
- FILE *fp;
- time_t timeout;
- char *during;
-{
- register EVENT *ev = NULL;
- register char *p;
- int save_errno;
-
- if (fp == NULL)
- {
- buf[0] = '\0';
- return NULL;
- }
-
- /* set the timeout */
- if (timeout != 0)
- {
- if (setjmp(CtxReadTimeout) != 0)
- {
- if (LogLevel > 1)
- sm_syslog(LOG_NOTICE, CurEnv->e_id,
- "timeout waiting for input from %.100s during %s",
- CurHostName ? CurHostName : "local",
- during);
- buf[0] = '\0';
-#if XDEBUG
- checkfd012(during);
-#endif
- if (TrafficLogFile != NULL)
- fprintf(TrafficLogFile, "%05d <<< [TIMEOUT]\n",
- (int) getpid());
- errno = 0;
- return (NULL);
- }
- ev = setevent(timeout, readtimeout, 0);
- }
-
- /* try to read */
- p = NULL;
- errno = 0;
- while (!feof(fp) && !ferror(fp))
- {
- errno = 0;
- p = fgets(buf, siz, fp);
- if (p != NULL || errno != EINTR)
- break;
- clearerr(fp);
- }
- save_errno = errno;
-
- /* clear the event if it has not sprung */
- clrevent(ev);
-
- /* clean up the books and exit */
- LineNumber++;
- if (p == NULL)
- {
- buf[0] = '\0';
- if (TrafficLogFile != NULL)
- fprintf(TrafficLogFile, "%05d <<< [EOF]\n", (int) getpid());
- errno = save_errno;
- return (NULL);
- }
- if (TrafficLogFile != NULL)
- fprintf(TrafficLogFile, "%05d <<< %s", (int) getpid(), buf);
- if (SevenBitInput)
- {
- for (p = buf; *p != '\0'; p++)
- *p &= ~0200;
- }
- else if (!HasEightBits)
- {
- for (p = buf; *p != '\0'; p++)
- {
- if (bitset(0200, *p))
- {
- HasEightBits = TRUE;
- break;
- }
- }
- }
- return (buf);
-}
-
-/* ARGSUSED */
-static void
-readtimeout(timeout)
- time_t timeout;
-{
- longjmp(CtxReadTimeout, 1);
-}
- /*
-** FGETFOLDED -- like fgets, but know about folded lines.
-**
-** Parameters:
-** buf -- place to put result.
-** n -- bytes available.
-** f -- file to read from.
-**
-** Returns:
-** input line(s) on success, NULL on error or EOF.
-** This will normally be buf -- unless the line is too
-** long, when it will be xalloc()ed.
-**
-** Side Effects:
-** buf gets lines from f, with continuation lines (lines
-** with leading white space) appended. CRLF's are mapped
-** into single newlines. Any trailing NL is stripped.
-*/
-
-char *
-fgetfolded(buf, n, f)
- char *buf;
- register int n;
- FILE *f;
-{
- register char *p = buf;
- char *bp = buf;
- register int i;
-
- n--;
- while ((i = getc(f)) != EOF)
- {
- if (i == '\r')
- {
- i = getc(f);
- if (i != '\n')
- {
- if (i != EOF)
- (void) ungetc(i, f);
- i = '\r';
- }
- }
- if (--n <= 0)
- {
- /* allocate new space */
- char *nbp;
- int nn;
-
- nn = (p - bp);
- if (nn < MEMCHUNKSIZE)
- nn *= 2;
- else
- nn += MEMCHUNKSIZE;
- nbp = xalloc(nn);
- bcopy(bp, nbp, p - bp);
- p = &nbp[p - bp];
- if (bp != buf)
- free(bp);
- bp = nbp;
- n = nn - (p - bp);
- }
- *p++ = i;
- if (i == '\n')
- {
- LineNumber++;
- i = getc(f);
- if (i != EOF)
- (void) ungetc(i, f);
- if (i != ' ' && i != '\t')
- break;
- }
- }
- if (p == bp)
- return (NULL);
- if (p[-1] == '\n')
- p--;
- *p = '\0';
- return (bp);
-}
- /*
-** CURTIME -- return current time.
-**
-** Parameters:
-** none.
-**
-** Returns:
-** the current time.
-**
-** Side Effects:
-** none.
-*/
-
-time_t
-curtime()
-{
- auto time_t t;
-
- (void) time(&t);
- return (t);
-}
- /*
-** ATOBOOL -- convert a string representation to boolean.
-**
-** Defaults to "TRUE"
-**
-** Parameters:
-** s -- string to convert. Takes "tTyY" as true,
-** others as false.
-**
-** Returns:
-** A boolean representation of the string.
-**
-** Side Effects:
-** none.
-*/
-
-bool
-atobool(s)
- register char *s;
-{
- if (s == NULL || *s == '\0' || strchr("tTyY", *s) != NULL)
- return (TRUE);
- return (FALSE);
-}
- /*
-** ATOOCT -- convert a string representation to octal.
-**
-** Parameters:
-** s -- string to convert.
-**
-** Returns:
-** An integer representing the string interpreted as an
-** octal number.
-**
-** Side Effects:
-** none.
-*/
-
-int
-atooct(s)
- register char *s;
-{
- register int i = 0;
-
- while (*s >= '0' && *s <= '7')
- i = (i << 3) | (*s++ - '0');
- return (i);
-}
- /*
-** BITINTERSECT -- tell if two bitmaps intersect
-**
-** Parameters:
-** a, b -- the bitmaps in question
-**
-** Returns:
-** TRUE if they have a non-null intersection
-** FALSE otherwise
-**
-** Side Effects:
-** none.
-*/
-
-bool
-bitintersect(a, b)
- BITMAP a;
- BITMAP b;
-{
- int i;
-
- for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
- if ((a[i] & b[i]) != 0)
- return (TRUE);
- return (FALSE);
-}
- /*
-** BITZEROP -- tell if a bitmap is all zero
-**
-** Parameters:
-** map -- the bit map to check
-**
-** Returns:
-** TRUE if map is all zero.
-** FALSE if there are any bits set in map.
-**
-** Side Effects:
-** none.
-*/
-
-bool
-bitzerop(map)
- BITMAP map;
-{
- int i;
-
- for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
- if (map[i] != 0)
- return (FALSE);
- return (TRUE);
-}
- /*
-** STRCONTAINEDIN -- tell if one string is contained in another
-**
-** Parameters:
-** a -- possible substring.
-** b -- possible superstring.
-**
-** Returns:
-** TRUE if a is contained in b.
-** FALSE otherwise.
-*/
-
-bool
-strcontainedin(a, b)
- register char *a;
- register char *b;
-{
- int la;
- int lb;
- int c;
-
- la = strlen(a);
- lb = strlen(b);
- c = *a;
- if (isascii(c) && isupper(c))
- c = tolower(c);
- for (; lb-- >= la; b++)
- {
- if (*b != c && isascii(*b) && isupper(*b) && tolower(*b) != c)
- continue;
- if (strncasecmp(a, b, la) == 0)
- return TRUE;
- }
- return FALSE;
-}
- /*
-** CHECKFD012 -- check low numbered file descriptors
-**
-** File descriptors 0, 1, and 2 should be open at all times.
-** This routine verifies that, and fixes it if not true.
-**
-** Parameters:
-** where -- a tag printed if the assertion failed
-**
-** Returns:
-** none
-*/
-
-void
-checkfd012(where)
- char *where;
-{
-#if XDEBUG
- register int i;
-
- for (i = 0; i < 3; i++)
- fill_fd(i, where);
-#endif /* XDEBUG */
-}
- /*
-** CHECKFDOPEN -- make sure file descriptor is open -- for extended debugging
-**
-** Parameters:
-** fd -- file descriptor to check.
-** where -- tag to print on failure.
-**
-** Returns:
-** none.
-*/
-
-void
-checkfdopen(fd, where)
- int fd;
- char *where;
-{
-#if XDEBUG
- struct stat st;
-
- if (fstat(fd, &st) < 0 && errno == EBADF)
- {
- syserr("checkfdopen(%d): %s not open as expected!", fd, where);
- printopenfds(TRUE);
- }
-#endif
-}
- /*
-** CHECKFDS -- check for new or missing file descriptors
-**
-** Parameters:
-** where -- tag for printing. If null, take a base line.
-**
-** Returns:
-** none
-**
-** Side Effects:
-** If where is set, shows changes since the last call.
-*/
-
-void
-checkfds(where)
- char *where;
-{
- int maxfd;
- register int fd;
- bool printhdr = TRUE;
- int save_errno = errno;
- static BITMAP baseline;
- extern int DtableSize;
-
- if (DtableSize > 256)
- maxfd = 256;
- else
- maxfd = DtableSize;
- if (where == NULL)
- clrbitmap(baseline);
-
- for (fd = 0; fd < maxfd; fd++)
- {
- struct stat stbuf;
-
- if (fstat(fd, &stbuf) < 0 && errno != EOPNOTSUPP)
- {
- if (!bitnset(fd, baseline))
- continue;
- clrbitn(fd, baseline);
- }
- else if (!bitnset(fd, baseline))
- setbitn(fd, baseline);
- else
- continue;
-
- /* file state has changed */
- if (where == NULL)
- continue;
- if (printhdr)
- {
- sm_syslog(LOG_DEBUG, CurEnv->e_id,
- "%s: changed fds:",
- where);
- printhdr = FALSE;
- }
- dumpfd(fd, TRUE, TRUE);
- }
- errno = save_errno;
-}
- /*
-** PRINTOPENFDS -- print the open file descriptors (for debugging)
-**
-** Parameters:
-** logit -- if set, send output to syslog; otherwise
-** print for debugging.
-**
-** Returns:
-** none.
-*/
-
-#include <arpa/inet.h>
-
-void
-printopenfds(logit)
- bool logit;
-{
- register int fd;
- extern int DtableSize;
-
- for (fd = 0; fd < DtableSize; fd++)
- dumpfd(fd, FALSE, logit);
-}
- /*
-** DUMPFD -- dump a file descriptor
-**
-** Parameters:
-** fd -- the file descriptor to dump.
-** printclosed -- if set, print a notification even if
-** it is closed; otherwise print nothing.
-** logit -- if set, send output to syslog instead of stdout.
-*/
-
-void
-dumpfd(fd, printclosed, logit)
- int fd;
- bool printclosed;
- bool logit;
-{
- register char *p;
- char *hp;
-#ifdef S_IFSOCK
- SOCKADDR sa;
-#endif
- auto SOCKADDR_LEN_T slen;
- int i;
-#if STAT64 > 0
- struct stat64 st;
-#else
- struct stat st;
-#endif
- char buf[200];
-
- p = buf;
- snprintf(p, SPACELEFT(buf, p), "%3d: ", fd);
- p += strlen(p);
-
- if (
-#if STAT64 > 0
- fstat64(fd, &st)
-#else
- fstat(fd, &st)
-#endif
- < 0)
- {
- if (errno != EBADF)
- {
- snprintf(p, SPACELEFT(buf, p), "CANNOT STAT (%s)",
- errstring(errno));
- goto printit;
- }
- else if (printclosed)
- {
- snprintf(p, SPACELEFT(buf, p), "CLOSED");
- goto printit;
- }
- return;
- }
-
- i = fcntl(fd, F_GETFL, NULL);
- if (i != -1)
- {
- snprintf(p, SPACELEFT(buf, p), "fl=0x%x, ", i);
- p += strlen(p);
- }
-
- snprintf(p, SPACELEFT(buf, p), "mode=%o: ", st.st_mode);
- p += strlen(p);
- switch (st.st_mode & S_IFMT)
- {
-#ifdef S_IFSOCK
- case S_IFSOCK:
- snprintf(p, SPACELEFT(buf, p), "SOCK ");
- p += strlen(p);
- slen = sizeof sa;
- if (getsockname(fd, &sa.sa, &slen) < 0)
- snprintf(p, SPACELEFT(buf, p), "(%s)", errstring(errno));
- else
- {
- hp = hostnamebyanyaddr(&sa);
- if (sa.sa.sa_family == AF_INET)
- snprintf(p, SPACELEFT(buf, p), "%s/%d",
- hp, ntohs(sa.sin.sin_port));
- else
- snprintf(p, SPACELEFT(buf, p), "%s", hp);
- }
- p += strlen(p);
- snprintf(p, SPACELEFT(buf, p), "->");
- p += strlen(p);
- slen = sizeof sa;
- if (getpeername(fd, &sa.sa, &slen) < 0)
- snprintf(p, SPACELEFT(buf, p), "(%s)", errstring(errno));
- else
- {
- hp = hostnamebyanyaddr(&sa);
- if (sa.sa.sa_family == AF_INET)
- snprintf(p, SPACELEFT(buf, p), "%s/%d",
- hp, ntohs(sa.sin.sin_port));
- else
- snprintf(p, SPACELEFT(buf, p), "%s", hp);
- }
- break;
-#endif
-
- case S_IFCHR:
- snprintf(p, SPACELEFT(buf, p), "CHR: ");
- p += strlen(p);
- goto defprint;
-
- case S_IFBLK:
- snprintf(p, SPACELEFT(buf, p), "BLK: ");
- p += strlen(p);
- goto defprint;
-
-#if defined(S_IFIFO) && (!defined(S_IFSOCK) || S_IFIFO != S_IFSOCK)
- case S_IFIFO:
- snprintf(p, SPACELEFT(buf, p), "FIFO: ");
- p += strlen(p);
- goto defprint;
-#endif
-
-#ifdef S_IFDIR
- case S_IFDIR:
- snprintf(p, SPACELEFT(buf, p), "DIR: ");
- p += strlen(p);
- goto defprint;
-#endif
-
-#ifdef S_IFLNK
- case S_IFLNK:
- snprintf(p, SPACELEFT(buf, p), "LNK: ");
- p += strlen(p);
- goto defprint;
-#endif
-
- default:
-defprint:
- if (sizeof st.st_ino > sizeof (long))
- snprintf(p, SPACELEFT(buf, p),
- "dev=%d/%d, ino=%s, nlink=%d, u/gid=%d/%d, ",
- major(st.st_dev), minor(st.st_dev),
- quad_to_string(st.st_ino),
- st.st_nlink, st.st_uid, st.st_gid);
- else
- snprintf(p, SPACELEFT(buf, p),
- "dev=%d/%d, ino=%lu, nlink=%d, u/gid=%d/%d, ",
- major(st.st_dev), minor(st.st_dev),
- (unsigned long) st.st_ino,
- st.st_nlink, st.st_uid, st.st_gid);
- if (sizeof st.st_size > sizeof (long))
- snprintf(p, SPACELEFT(buf, p), "size=%s",
- quad_to_string(st.st_size));
- else
- snprintf(p, SPACELEFT(buf, p), "size=%lu",
- (unsigned long) st.st_size);
- break;
- }
-
-printit:
- if (logit)
- sm_syslog(LOG_DEBUG, CurEnv ? CurEnv->e_id : NULL,
- "%.800s", buf);
- else
- printf("%s\n", buf);
-}
- /*
-** SHORTEN_HOSTNAME -- strip local domain information off of hostname.
-**
-** Parameters:
-** host -- the host to shorten (stripped in place).
-**
-** Returns:
-** none.
-*/
-
-void
-shorten_hostname(host)
- char host[];
-{
- register char *p;
- char *mydom;
- int i;
- bool canon = FALSE;
-
- /* strip off final dot */
- p = &host[strlen(host) - 1];
- if (*p == '.')
- {
- *p = '\0';
- canon = TRUE;
- }
-
- /* see if there is any domain at all -- if not, we are done */
- p = strchr(host, '.');
- if (p == NULL)
- return;
-
- /* yes, we have a domain -- see if it looks like us */
- mydom = macvalue('m', CurEnv);
- if (mydom == NULL)
- mydom = "";
- i = strlen(++p);
- if ((canon ? strcasecmp(p, mydom) : strncasecmp(p, mydom, i)) == 0 &&
- (mydom[i] == '.' || mydom[i] == '\0'))
- *--p = '\0';
-}
- /*
-** PROG_OPEN -- open a program for reading
-**
-** Parameters:
-** argv -- the argument list.
-** pfd -- pointer to a place to store the file descriptor.
-** e -- the current envelope.
-**
-** Returns:
-** pid of the process -- -1 if it failed.
-*/
-
-int
-prog_open(argv, pfd, e)
- char **argv;
- int *pfd;
- ENVELOPE *e;
-{
- int pid;
- int i;
- int saveerrno;
- int fdv[2];
- char *p, *q;
- char buf[MAXLINE + 1];
- extern int DtableSize;
-
- if (pipe(fdv) < 0)
- {
- syserr("%s: cannot create pipe for stdout", argv[0]);
- return -1;
- }
- pid = fork();
- if (pid < 0)
- {
- syserr("%s: cannot fork", argv[0]);
- close(fdv[0]);
- close(fdv[1]);
- return -1;
- }
- if (pid > 0)
- {
- /* parent */
- close(fdv[1]);
- *pfd = fdv[0];
- return pid;
- }
-
- /* child -- close stdin */
- close(0);
-
- /* stdout goes back to parent */
- close(fdv[0]);
- if (dup2(fdv[1], 1) < 0)
- {
- syserr("%s: cannot dup2 for stdout", argv[0]);
- _exit(EX_OSERR);
- }
- close(fdv[1]);
-
- /* stderr goes to transcript if available */
- if (e->e_xfp != NULL)
- {
- if (dup2(fileno(e->e_xfp), 2) < 0)
- {
- syserr("%s: cannot dup2 for stderr", argv[0]);
- _exit(EX_OSERR);
- }
- }
-
- /* this process has no right to the queue file */
- if (e->e_lockfp != NULL)
- close(fileno(e->e_lockfp));
-
- /* run as default user */
- endpwent();
- if (setgid(DefGid) < 0 && geteuid() == 0)
- syserr("prog_open: setgid(%ld) failed", (long) DefGid);
- if (setuid(DefUid) < 0 && geteuid() == 0)
- syserr("prog_open: setuid(%ld) failed", (long) DefUid);
-
- /* run in some directory */
- if (ProgMailer != NULL)
- p = ProgMailer->m_execdir;
- else
- p = NULL;
- for (; p != NULL; p = q)
- {
- q = strchr(p, ':');
- if (q != NULL)
- *q = '\0';
- expand(p, buf, sizeof buf, e);
- if (q != NULL)
- *q++ = ':';
- if (buf[0] != '\0' && chdir(buf) >= 0)
- break;
- }
- if (p == NULL)
- {
- /* backup directories */
- if (chdir("/tmp") < 0)
- (void) chdir("/");
- }
-
- /* arrange for all the files to be closed */
- for (i = 3; i < DtableSize; i++)
- {
- register int j;
-
- if ((j = fcntl(i, F_GETFD, 0)) != -1)
- (void) fcntl(i, F_SETFD, j | 1);
- }
-
- /* now exec the process */
- execve(argv[0], (ARGV_T) argv, (ARGV_T) UserEnviron);
-
- /* woops! failed */
- saveerrno = errno;
- syserr("%s: cannot exec", argv[0]);
- if (transienterror(saveerrno))
- _exit(EX_OSERR);
- _exit(EX_CONFIG);
- return -1; /* avoid compiler warning on IRIX */
-}
- /*
-** GET_COLUMN -- look up a Column in a line buffer
-**
-** Parameters:
-** line -- the raw text line to search.
-** col -- the column number to fetch.
-** delim -- the delimiter between columns. If null,
-** use white space.
-** buf -- the output buffer.
-** buflen -- the length of buf.
-**
-** Returns:
-** buf if successful.
-** NULL otherwise.
-*/
-
-char *
-get_column(line, col, delim, buf, buflen)
- char line[];
- int col;
- char delim;
- char buf[];
- int buflen;
-{
- char *p;
- char *begin, *end;
- int i;
- char delimbuf[4];
-
- if (delim == '\0')
- strcpy(delimbuf, "\n\t ");
- else
- {
- delimbuf[0] = delim;
- delimbuf[1] = '\0';
- }
-
- p = line;
- if (*p == '\0')
- return NULL; /* line empty */
- if (*p == delim && col == 0)
- return NULL; /* first column empty */
-
- begin = line;
-
- if (col == 0 && delim == '\0')
- {
- while (*begin != '\0' && isascii(*begin) && isspace(*begin))
- begin++;
- }
-
- for (i = 0; i < col; i++)
- {
- if ((begin = strpbrk(begin, delimbuf)) == NULL)
- return NULL; /* no such column */
- begin++;
- if (delim == '\0')
- {
- while (*begin != '\0' && isascii(*begin) && isspace(*begin))
- begin++;
- }
- }
-
- end = strpbrk(begin, delimbuf);
- if (end == NULL)
- i = strlen(begin);
- else
- i = end - begin;
- if (i >= buflen)
- i = buflen - 1;
- strncpy(buf, begin, i);
- buf[i] = '\0';
- return buf;
-}
- /*
-** CLEANSTRCPY -- copy string keeping out bogus characters
-**
-** Parameters:
-** t -- "to" string.
-** f -- "from" string.
-** l -- length of space available in "to" string.
-**
-** Returns:
-** none.
-*/
-
-void
-cleanstrcpy(t, f, l)
- register char *t;
- register char *f;
- int l;
-{
- /* check for newlines and log if necessary */
- (void) denlstring(f, TRUE, TRUE);
-
- l--;
- while (l > 0 && *f != '\0')
- {
- if (isascii(*f) &&
- (isalnum(*f) || strchr("!#$%&'*+-./^_`{|}~", *f) != NULL))
- {
- l--;
- *t++ = *f;
- }
- f++;
- }
- *t = '\0';
-}
- /*
-** DENLSTRING -- convert newlines in a string to spaces
-**
-** Parameters:
-** s -- the input string
-** strict -- if set, don't permit continuation lines.
-** logattacks -- if set, log attempted attacks.
-**
-** Returns:
-** A pointer to a version of the string with newlines
-** mapped to spaces. This should be copied.
-*/
-
-char *
-denlstring(s, strict, logattacks)
- char *s;
- bool strict;
- bool logattacks;
-{
- register char *p;
- int l;
- static char *bp = NULL;
- static int bl = 0;
-
- p = s;
- while ((p = strchr(p, '\n')) != NULL)
- if (strict || (*++p != ' ' && *p != '\t'))
- break;
- if (p == NULL)
- return s;
-
- l = strlen(s) + 1;
- if (bl < l)
- {
- /* allocate more space */
- if (bp != NULL)
- free(bp);
- bp = xalloc(l);
- bl = l;
- }
- strcpy(bp, s);
- for (p = bp; (p = strchr(p, '\n')) != NULL; )
- *p++ = ' ';
-
- if (logattacks)
- {
- sm_syslog(LOG_NOTICE, CurEnv->e_id,
- "POSSIBLE ATTACK from %.100s: newline in string \"%s\"",
- RealHostName == NULL ? "[UNKNOWN]" : RealHostName,
- shortenstring(bp, MAXSHORTSTR));
- }
-
- return bp;
-}
- /*
-** PATH_IS_DIR -- check to see if file exists and is a directory.
-**
-** There are some additional checks for security violations in
-** here. This routine is intended to be used for the host status
-** support.
-**
-** Parameters:
-** pathname -- pathname to check for directory-ness.
-** createflag -- if set, create directory if needed.
-**
-** Returns:
-** TRUE -- if the indicated pathname is a directory
-** FALSE -- otherwise
-*/
-
-int
-path_is_dir(pathname, createflag)
- char *pathname;
- bool createflag;
-{
- struct stat statbuf;
-
-#if HASLSTAT
- if (lstat(pathname, &statbuf) < 0)
-#else
- if (stat(pathname, &statbuf) < 0)
-#endif
- {
- if (errno != ENOENT || !createflag)
- return FALSE;
- if (mkdir(pathname, 0755) < 0)
- return FALSE;
- return TRUE;
- }
- if (!S_ISDIR(statbuf.st_mode))
- {
- errno = ENOTDIR;
- return FALSE;
- }
-
- /* security: don't allow writable directories */
- if (bitset(S_IWGRP|S_IWOTH, statbuf.st_mode))
- {
- errno = EACCES;
- return FALSE;
- }
-
- return TRUE;
-}
- /*
-** PROC_LIST_ADD -- add process id to list of our children
-**
-** Parameters:
-** pid -- pid to add to list.
-**
-** Returns:
-** none
-*/
-
-struct procs
-{
- pid_t proc_pid;
- char *proc_task;
-};
-
-static struct procs *ProcListVec = NULL;
-static int ProcListSize = 0;
-
-#define NO_PID ((pid_t) 0)
-#ifndef PROC_LIST_SEG
-# define PROC_LIST_SEG 32 /* number of pids to alloc at a time */
-#endif
-
-void
-proc_list_add(pid, task)
- pid_t pid;
- char *task;
-{
- int i;
-
- for (i = 0; i < ProcListSize; i++)
- {
- if (ProcListVec[i].proc_pid == NO_PID)
- break;
- }
- if (i >= ProcListSize)
- {
- /* probe the existing vector to avoid growing infinitely */
- proc_list_probe();
-
- /* now scan again */
- for (i = 0; i < ProcListSize; i++)
- {
- if (ProcListVec[i].proc_pid == NO_PID)
- break;
- }
- }
- if (i >= ProcListSize)
- {
- /* grow process list */
- struct procs *npv;
-
- npv = (struct procs *) xalloc(sizeof (struct procs) * (ProcListSize + PROC_LIST_SEG));
- if (ProcListSize > 0)
- {
- bcopy(ProcListVec, npv, ProcListSize *
- sizeof (struct procs));
- free(ProcListVec);
- }
- for (i = ProcListSize; i < ProcListSize + PROC_LIST_SEG; i++)
- {
- npv[i].proc_pid = NO_PID;
- npv[i].proc_task = NULL;
- }
- i = ProcListSize;
- ProcListSize += PROC_LIST_SEG;
- ProcListVec = npv;
- }
- ProcListVec[i].proc_pid = pid;
- ProcListVec[i].proc_task = newstr(task);
-
- /* if process adding itself, it's not a child */
- if (pid != getpid())
- CurChildren++;
-}
- /*
-** PROC_LIST_SET -- set pid task in process list
-**
-** Parameters:
-** pid -- pid to set
-** task -- task of pid
-**
-** Returns:
-** none.
-*/
-
-void
-proc_list_set(pid, task)
- pid_t pid;
- char *task;
-{
- int i;
-
- for (i = 0; i < ProcListSize; i++)
- {
- if (ProcListVec[i].proc_pid == pid)
- {
- if (ProcListVec[i].proc_task != NULL)
- free(ProcListVec[i].proc_task);
- ProcListVec[i].proc_task = newstr(task);
- break;
- }
- }
-}
- /*
-** PROC_LIST_DROP -- drop pid from process list
-**
-** Parameters:
-** pid -- pid to drop
-**
-** Returns:
-** none.
-*/
-
-void
-proc_list_drop(pid)
- pid_t pid;
-{
- int i;
-
- for (i = 0; i < ProcListSize; i++)
- {
- if (ProcListVec[i].proc_pid == pid)
- {
- ProcListVec[i].proc_pid = NO_PID;
- if (ProcListVec[i].proc_task != NULL)
- {
- free(ProcListVec[i].proc_task);
- ProcListVec[i].proc_task = NULL;
- }
- break;
- }
- }
- if (CurChildren > 0)
- CurChildren--;
-}
- /*
-** PROC_LIST_CLEAR -- clear the process list
-**
-** Parameters:
-** none.
-**
-** Returns:
-** none.
-*/
-
-void
-proc_list_clear()
-{
- int i;
-
- /* start from 1 since 0 is the daemon itself */
- for (i = 1; i < ProcListSize; i++)
- {
- ProcListVec[i].proc_pid = NO_PID;
- if (ProcListVec[i].proc_task != NULL)
- {
- free(ProcListVec[i].proc_task);
- ProcListVec[i].proc_task = NULL;
- }
- }
- CurChildren = 0;
-}
- /*
-** PROC_LIST_PROBE -- probe processes in the list to see if they still exist
-**
-** Parameters:
-** none
-**
-** Returns:
-** none
-*/
-
-void
-proc_list_probe()
-{
- int i;
-
- /* start from 1 since 0 is the daemon itself */
- for (i = 1; i < ProcListSize; i++)
- {
- if (ProcListVec[i].proc_pid == NO_PID)
- continue;
- if (kill(ProcListVec[i].proc_pid, 0) < 0)
- {
- if (LogLevel > 3)
- sm_syslog(LOG_DEBUG, CurEnv->e_id,
- "proc_list_probe: lost pid %d",
- (int) ProcListVec[i].proc_pid);
- ProcListVec[i].proc_pid = NO_PID;
- if (ProcListVec[i].proc_task != NULL)
- {
- free(ProcListVec[i].proc_task);
- ProcListVec[i].proc_task = NULL;
- }
- CurChildren--;
- }
- }
- if (CurChildren < 0)
- CurChildren = 0;
-}
- /*
-** PROC_LIST_DISPLAY -- display the process list
-**
-** Parameters:
-** out -- output file pointer
-**
-** Returns:
-** none.
-*/
-
-void
-proc_list_display(out)
- FILE *out;
-{
- int i;
-
- for (i = 0; i < ProcListSize; i++)
- {
- if (ProcListVec[i].proc_pid == NO_PID)
- continue;
-
- fprintf(out, "%d %s%s\n", (int) ProcListVec[i].proc_pid,
- ProcListVec[i].proc_task != NULL ?
- ProcListVec[i].proc_task : "(unknown)",
- (OpMode == MD_SMTP ||
- OpMode == MD_DAEMON ||
- OpMode == MD_ARPAFTP) ? "\r" : "");
- }
-}
- /*
-** SM_STRCASECMP -- 8-bit clean version of strcasecmp
-**
-** Thank you, vendors, for making this all necessary.
-*/
-
-/*
- * Copyright (c) 1987, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * 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 the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University 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 THE REGENTS 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 THE REGENTS 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.
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)strcasecmp.c 8.1 (Berkeley) 6/4/93";
-#endif /* LIBC_SCCS and not lint */
-
-/*
- * This array is designed for mapping upper and lower case letter
- * together for a case independent comparison. The mappings are
- * based upon ascii character sequences.
- */
-static const u_char charmap[] = {
- 0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007,
- 0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017,
- 0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027,
- 0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037,
- 0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047,
- 0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057,
- 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
- 0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077,
- 0100, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
- 0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
- 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
- 0170, 0171, 0172, 0133, 0134, 0135, 0136, 0137,
- 0140, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
- 0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
- 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
- 0170, 0171, 0172, 0173, 0174, 0175, 0176, 0177,
- 0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
- 0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
- 0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
- 0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
- 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
- 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
- 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
- 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
- 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
- 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
- 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
- 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
- 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
- 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
- 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
- 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377,
-};
-
-int
-sm_strcasecmp(s1, s2)
- const char *s1, *s2;
-{
- register const u_char *cm = charmap,
- *us1 = (const u_char *)s1,
- *us2 = (const u_char *)s2;
-
- while (cm[*us1] == cm[*us2++])
- if (*us1++ == '\0')
- return (0);
- return (cm[*us1] - cm[*--us2]);
-}
-
-int
-sm_strncasecmp(s1, s2, n)
- const char *s1, *s2;
- register size_t n;
-{
- if (n != 0) {
- register const u_char *cm = charmap,
- *us1 = (const u_char *)s1,
- *us2 = (const u_char *)s2;
-
- do {
- if (cm[*us1] != cm[*us2++])
- return (cm[*us1] - cm[*--us2]);
- if (*us1++ == '\0')
- break;
- } while (--n != 0);
- }
- return (0);
-}
diff --git a/src/version.c b/src/version.c
deleted file mode 100644
index 6f9d05e..0000000
--- a/src/version.c
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
- * Copyright (c) 1983 Eric P. Allman. All rights reserved.
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)version.c 8.9.3.1 (Berkeley) 2/4/1999";
-#endif /* not lint */
-
-char Version[] = "8.9.3";