diff options
Diffstat (limited to 'src')
l--------- | src/Build | 1 | ||||
-rw-r--r-- | src/Makefile.m4 | 152 | ||||
-rw-r--r-- | src/README | 1464 | ||||
-rw-r--r-- | src/TRACEFLAGS | 79 | ||||
-rw-r--r-- | src/alias.c | 895 | ||||
-rw-r--r-- | src/aliases | 53 | ||||
-rw-r--r-- | src/aliases.0 | 48 | ||||
-rw-r--r-- | src/aliases.5 | 85 | ||||
-rw-r--r-- | src/arpadate.c | 202 | ||||
-rw-r--r-- | src/cdefs.h | 123 | ||||
-rw-r--r-- | src/clock.c | 267 | ||||
-rw-r--r-- | src/collect.c | 772 | ||||
-rw-r--r-- | src/conf.c | 4938 | ||||
-rw-r--r-- | src/conf.h | 2522 | ||||
-rw-r--r-- | src/control.c | 356 | ||||
-rw-r--r-- | src/convtime.c | 183 | ||||
-rw-r--r-- | src/daemon.c | 2154 | ||||
-rw-r--r-- | src/deliver.c | 3758 | ||||
-rw-r--r-- | src/domain.c | 912 | ||||
-rw-r--r-- | src/envelope.c | 938 | ||||
-rw-r--r-- | src/err.c | 767 | ||||
-rw-r--r-- | src/headers.c | 1710 | ||||
-rw-r--r-- | src/ldap_map.h | 91 | ||||
-rw-r--r-- | src/macro.c | 437 | ||||
-rw-r--r-- | src/mailq.0 | 41 | ||||
-rw-r--r-- | src/mailq.1 | 67 | ||||
-rw-r--r-- | src/mailstats.h | 34 | ||||
-rw-r--r-- | src/main.c | 2748 | ||||
l--------- | src/makesendmail | 1 | ||||
-rw-r--r-- | src/map.c | 5209 | ||||
-rw-r--r-- | src/mci.c | 1293 | ||||
-rw-r--r-- | src/mime.c | 1190 | ||||
-rw-r--r-- | src/newaliases.0 | 27 | ||||
-rw-r--r-- | src/newaliases.1 | 47 | ||||
-rw-r--r-- | src/parseaddr.c | 2555 | ||||
-rw-r--r-- | src/pathnames.h | 32 | ||||
-rw-r--r-- | src/queue.c | 2422 | ||||
-rw-r--r-- | src/readcf.c | 2920 | ||||
-rw-r--r-- | src/recipient.c | 1456 | ||||
-rw-r--r-- | src/safefile.c | 751 | ||||
-rw-r--r-- | src/savemail.c | 1486 | ||||
-rw-r--r-- | src/sendmail.0 | 356 | ||||
-rw-r--r-- | src/sendmail.8 | 580 | ||||
-rw-r--r-- | src/sendmail.h | 1514 | ||||
-rw-r--r-- | src/sendmail.hf | 124 | ||||
-rw-r--r-- | src/snprintf.c | 428 | ||||
-rw-r--r-- | src/srvrsmtp.c | 1532 | ||||
-rw-r--r-- | src/stab.c | 219 | ||||
-rw-r--r-- | src/stats.c | 135 | ||||
-rw-r--r-- | src/sysexits.c | 162 | ||||
-rw-r--r-- | src/sysexits.h | 118 | ||||
-rw-r--r-- | src/trace.c | 111 | ||||
-rw-r--r-- | src/udb.c | 1335 | ||||
-rw-r--r-- | src/useful.h | 58 | ||||
-rw-r--r-- | src/usersmtp.c | 1172 | ||||
-rw-r--r-- | src/util.c | 2365 | ||||
-rw-r--r-- | src/version.c | 17 |
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"; |