diff options
author | peter <peter@FreeBSD.org> | 1995-12-02 17:30:23 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 1995-12-02 17:30:23 +0000 |
commit | 91b3d1fef5f70cc06d726f635e7a187744eb869d (patch) | |
tree | 221eab8d922761351b23e802dbb321351f81605a /usr.sbin/sendmail/src | |
parent | cd51f07d81cc51a9aeaf07e6df1d41f265dda20d (diff) | |
parent | 88797ecc8d2743a86e4e574fadaac061649931a1 (diff) | |
download | FreeBSD-src-91b3d1fef5f70cc06d726f635e7a187744eb869d.zip FreeBSD-src-91b3d1fef5f70cc06d726f635e7a187744eb869d.tar.gz |
This commit was generated by cvs2svn to compensate for changes in r12571,
which included commits to RCS files with non-trunk default branches.
Diffstat (limited to 'usr.sbin/sendmail/src')
-rw-r--r-- | usr.sbin/sendmail/src/READ_ME | 512 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/TRACEFLAGS | 9 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/alias.c | 195 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/arpadate.c | 60 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/clock.c | 20 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/convtime.c | 10 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/envelope.c | 313 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/err.c | 228 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/macro.c | 190 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/makesendmail | 259 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/map.c | 2385 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/mci.c | 41 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/mime.c | 866 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/pathnames.h | 12 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/queue.c | 754 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/sendmail.hf | 28 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/stab.c | 27 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/stats.c | 6 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/sysexits.c | 123 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/sysexits.h | 118 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/trace.c | 6 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/useful.h | 5 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/version.c | 4 |
23 files changed, 5436 insertions, 735 deletions
diff --git a/usr.sbin/sendmail/src/READ_ME b/usr.sbin/sendmail/src/READ_ME index ace0d3a..82889ff 100644 --- a/usr.sbin/sendmail/src/READ_ME +++ b/usr.sbin/sendmail/src/READ_ME @@ -1,4 +1,4 @@ -# Copyright (c) 1983 Eric P. Allman +# Copyright (c) 1983, 1995 Eric P. Allman # Copyright (c) 1988 The Regents of the University of California. # All rights reserved. # @@ -30,32 +30,30 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -# @(#)READ_ME 8.61.1.1 (Berkeley) 3/5/95 +# @(#)READ_ME 8.112 (Berkeley) 11/18/95 # This directory contains the source files for sendmail. -For detailed instructions, please read the document ../doc/op.me: - - eqn ../doc/op.me | pic | ditroff -me +********************* +!! DO NOT USE MAKE !! to compile sendmail -- instead, use the +********************* "makesendmail" script located in the src +directory. It will find an appropriate Makefile, and create an +appropriate obj.* subdirectory so that multiplatform support +works easily. The Makefile is for the new (4.4BSD) Berkeley make and uses syntax that is not recognized by older makes. It also has assumptions about the 4.4 file system layout built in. See below for details about other Makefiles. -There is also a Makefile.dist which is much less clever, but works on -the old traditional make. You can use this using: +If you are porting to a new architecture for which there is no existing +Makefile, you might start with Makefile.dist. This works on the old +traditional make, but isn't customized for any particular architecture. - make -f Makefile.dist - -************************************************** -** Read below for more details of Makefiles. ** -************************************************** - -There is also a shell script (makesendmail) that tries to be clever -about using object subdirectories. It's pretty straightforward, and -may help if you share a source tree among different architectures. + ************************************************** + ** Read below for more details of Makefiles. ** + ************************************************** ************************************************************************** ** IMPORTANT: DO NOT USE OPTIMIZATION (``-O'') IF YOU ARE RUNNING ** @@ -67,16 +65,34 @@ 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. + ************************************************************************** ** IMPORTANT: Read the appropriate paragraphs in the section on ** ** ``Operating System and Compile Quirks''. ** ************************************************************************** +For detailed instructions, please read the document ../doc/op.me: + + eqn ../doc/op.me | pic | ditroff -me + +-----------+ | MAKEFILES | +-----------+ +By far, the easiest way to compile sendmail is to use the "makesendmail" +script: + + sh makesendmail + +This uses the "uname" command to figure out what architecture you are +on and selects 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. However, if for some +reason this doesn't work (e.g., NeXT systems don't have the "uname" +command) you may have to set up your compile environment by hand. + The "Makefile"s in these directories are from 4.4 BSD, and hence really only work properly if you are on a 4.4 system. In particular, they use new syntax that will not be recognized on old make programs, @@ -88,17 +104,15 @@ outside of the sendmail tree. Instead, you should use one of the other Makefiles, such as Makefile.SunOS for a SunOS system, and so forth. These should work with the version of make that is appropriate for that -system. - -There are a bunch of other Makefiles for other systems with names -like Makefile.HPUX for an HP-UX system. They use the version of -make that is native for that system. These are the Makefiles that -I use, and they have "Berkeley quirks" in them. I can't guarantee -that they will work unmodified in your environment. Many of them -include -I/usr/sww/include/db and -L/usr/sww/lib -- this is Berkeley's -location (the ``Software Warehouse'') for the new database libraries, -described below. You don't have to remove these definitions if you -don't have these directories. +system. All other Makefiles are in the "src/Makefiles" subdirectory. +They use the version of make that is native for that system. These +are the Makefiles that I use, and they have "Berkeley quirks" in them. +I can't guarantee that they will work unmodified in your environment. +In particular, Many of them include -I/usr/sww/include/db and +-L/usr/sww/lib -- these are Berkeley's locations in the ``Software +Warehouse'' for the new database libraries, described below. You don't +have to remove these definitions if you don't have these directories, +but you may have to remove -DNEWDB from the DBMDEF definition. Please look for an appropriate Makefile before you start trying to compile with Makefile or Makefile.dist. @@ -107,9 +121,10 @@ If you want to port the new Berkeley make, you can get it from ftp.uu.net in the directory /systems/unix/bsd-sources/usr.bin/make. Diffs and instructions for building this version of make under SunOS 4.1.x are available on ftp.css.itd.umich.edu in -/pub/systems/sun/Net2-make.sun4.diff.Z. Diffs and instructions +/pub/systems/sun/Net2-make-sun4.diff.Z. Diffs and instructions for building this version of make under IBM AIX 3.2.4 are available on ftp.uni-stuttgart.de in /sw/src/patches/bsd-make-rus-patches. +For Ultrix, try ftp.vix.com:~ftp/pub/patches/pmake-for-ultrix.Z. Paul Southworth <pauls@umich.edu> published a description of porting this make in comp.unix.bsd. @@ -133,10 +148,11 @@ The three options are NEWDB (the new Berkeley DB package), NDBM (the older DBM implementation -- the very old V7 implementation is no longer supported), and NIS (Network Information Services). Used alone these just include the support they indicate. [If you are using NEWDB, -get the latest version from FTP.CS.Berkeley.EDU in /ucb/4bsd. DO NOT -use the version from the Net2 distribution! However, if you are on -BSD/386 or 386BSD-based systems, use the one that already exists -on your system. You may need to #define OLD_NEWDB 1 to do this.] +get the latest version from FTP.CS.Berkeley.EDU in /ucb/4bsd/db.tar.Z +(or db.tar.gz). DO NOT use the version from the Net2 distribution! +However, if you are on BSD/386 or 386BSD-based systems, use the one +that already exists on your system. You may need to #define OLD_NEWDB +1 to do this.] [NOTE WELL: it is CRITICAL that you remove ndbm.o from libdb.a and ndbm.h from the appropriate include directories if you want to get @@ -152,19 +168,28 @@ the NEWDB library also catches and maps NDBM calls; you will have to back out this feature to get this to work. See ``Quirks'' section below for details.] -If all three are defined, sendmail operates as described above, and also -looks for the file /var/yp/Makefile. If it exists, newaliases will -build BOTH the NEWDB and NDBM format alias files. However, it will -only use the NEWDB file; the NDBM format file is used only by the -NIS subsystem. +If all three are 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. -If NDBM and NIS are defined (regardless of the definition of NEWDB -or the existance of /var/yp/Makefile), sendmail adds the special +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 -DNEWDB, -DNDBM, and -DNIS are normally defined in the DBMDEF -line in the Makefile. +There is also preliminary support for NIS+ (-DNISPLUS), Hesiod +(-DHESIOD), and NetInfo (-DNETINFO). These have not been well +tested. + +All of -DNEWDB, -DNDBM, -DNIS, -DNISPLUS, -DHESIOD, and -DNETINFO 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. +---------------+ @@ -174,25 +199,14 @@ line in the Makefile. Whereever 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 availble, requiring the following compilation flags in the -Makefile: - -SOLARIS Define this if you are running Solaris 2.0 or higher. -SOLARIS_2_3 Define this if you are running Solaris 2.3 or higher. -SUNOS403 Define this if you are running SunOS 4.0.3. -NeXT Define this if you are on a NeXT box. (This one may - be pre-defined for you.) There are other hacks you - have to make -- see below. -_AIX3 Define this if you are IBM AIX 3.x. -RISCOS Define this if you are running RISC/os from MIPS. -IRIX Define this if you are running IRIX from SGI. -_SCO_unix_ Define this if you are on SCO UNIX. -_SCO_unix_4_2 Define this if you are on SCO Open Server 3.2v4. - -If you are a system that sendmail has already been ported to, you -probably won't have to touch these. 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: +symbols available, requiring that a compilation flag be defined in +the Makefile; see the Makefiles 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 @@ -201,12 +215,18 @@ SYS5SIGNALS Use System V signal semantics -- the signal handler 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. - For this reason, this should not be set unless you - don't have an alternative. + 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" @@ -234,11 +254,28 @@ HASSETREUID Define this if you have setreuid(2) ***AND*** root can 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 seteuid(2) if you have a seteuid + 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. 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 @@ -261,6 +298,12 @@ HASGETUSERSHELL Define this to 1 if you have getusershell(3) in your 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 @@ -276,35 +319,71 @@ ARBPTR_T The type of an arbitrary pointer -- defaults to "void *". this to be "char *". 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 + LA_ZERO (1) -- it always returns the load average as "zero" (and does so on all architectures). - LA_SUBR (4) if you have the getloadavg(3) routine, - LA_MACH (5) to use MACH-style load averages (calls + 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 + LA_PROCSTR (7) to read /proc/loadavg and interpret it as a string representing a floating-point - number (Linux-style), - LA_FLOAT (3) if you read kmem and interpret the value - as a floating point number, - LA_INT (2) to interpret as a long integer, - LA_SHORT (6) to interpret as a short integer. - These last three 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. + 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_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. 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>), - and SFS_VFS (3), SFS_MOUNT (4), SFS_STATFS (5) or - SFS_STATVFS (6) if you have the two-argument statfs(2) - system call, with includes in <sys/vfs.h>, <sys/mount.h>, - <sys/statfs.h>, or <sys/statvfs.h> respectively. The - default if nothing is defined is SFS_NONE. + 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 hou 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_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 @@ -329,6 +408,12 @@ BROKEN_RES_SEARCH -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. + +-----------------------+ @@ -351,24 +436,50 @@ OLD_NEWDB If non-zero, the version of NEWDB you have is the old use -DOLD_NEWDB=0 it forces you to use the new interface. NIS Define this to get NIS (YP) support for aliases and maps. Normally defined in the Makefile. -USERDB Include support for the User Information Database. Implied - by NEWDB in conf.h. +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. -MIME Include support for MIME-encapsulated error messages. + 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 AIX 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 Define this to get DNS (name daemon) support, including - MX support. The specs you must use this if you run - SMTP. Defined by default in conf.h. +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. @@ -379,9 +490,16 @@ 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. -SETPROCTITLE Try to set the string printed by "ps" to something - informative about what sendmail is doing. 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. Not yet + implemented. +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. +---------------------+ @@ -405,6 +523,13 @@ 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 | @@ -431,7 +556,7 @@ GCC 2.5.x problems *** IMPORTANT *** *************** find_reloads_toplev (x, opnum, type, ind *** 3888,3894 **** force a reload in that case. So we should not do anything here. */ - + else if (regno >= FIRST_PSEUDO_REGISTER ! #if defined(BYTE_LOADS_ZERO_EXTEND) || defined(BYTE_LOADS_SIGN_EXTEND) && (GET_MODE_SIZE (GET_MODE (x)) @@ -439,13 +564,18 @@ GCC 2.5.x problems *** IMPORTANT *** #endif --- 3888,3894 ---- force a reload in that case. So we should not do anything here. */ - + else if (regno >= FIRST_PSEUDO_REGISTER ! #ifdef LOAD_EXTEND_OP && (GET_MODE_SIZE (GET_MODE (x)) <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))) #endif +GCC 2.7.x problems + 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. + SunOS 4.x (Solaris 1.x) You may have to use -lresolv on SunOS. However, beware that @@ -469,6 +599,40 @@ SunOS 4.x (Solaris 1.x) 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 the + Makefile.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_U1 + Sendmail causes crashes on SunOS 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. + + This is fixed in patch 101790-01 (SunOS 4.1.3_U1: TCP socket and + reset problems). + Solaris 2.x (SunOS 5.x) To compile for Solaris, be sure you use -DSOLARIS. @@ -478,7 +642,7 @@ Solaris 2.x (SunOS 5.x) From a correspondent: - For solaris 2.2, I have + For solaris 2.2, I have hosts: files dns @@ -522,8 +686,54 @@ Solaris 2.x (SunOS 5.x) 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. + +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. + OSF/1 - If you are compiling on OSF/1 (DEC Alpha), you must use + 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. @@ -542,9 +752,17 @@ IRIX when compiling map.c; this is not important because the function being prototyped is not used in that file. -NeXT - If you are compiling on NeXT, you will have to create an empty - file "unistd.h" and create a file "dirent.h" containing: + In order to compile sendmail you will have had to install + the developers' option in order to get the necessary include + files. + +NeXT or NEXTSTEP + NEXTSTEP 3.3 and earlier ship with the old DBM library. You will + need to acquire the new Berkeley DB from ftp.cs.berkeley.edu. + Install it in /usr/local/{lib,include}. + + 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 @@ -626,10 +844,29 @@ A/UX (not easy at least); the gnu-dbm package "configured" and compiled easily. +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 - + DG/UX - Apparently, /bin/mail doesn't work properly for delivery on - DG/UX -- the person who has this working, Douglas Anderson - <dlander@afterlife.ncsc.mil>, used procmail instead. + 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 @@ -677,10 +914,22 @@ Linux 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). + AIX 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/. + RISC/os RISC/os from MIPS is a merged AT&T/Berkeley system. When you compile on that platform you will get duplicate definitions @@ -727,7 +976,7 @@ DELL SVR4 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. + 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 @@ -738,11 +987,32 @@ DELL SVR4 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 2.0 + 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. + +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>. Non-DNS based sites This version of sendmail always tries to connect to the Domain @@ -769,9 +1039,10 @@ GNU getopt 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 the conf/Info.Ultrix - carefully -- there is information in there that you need to know - in order to avoid errors of the form: + 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 @@ -780,6 +1051,35 @@ BIND 4.9.2 and Ultrix 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. :) + + +--------------+ | MANUAL PAGES | @@ -880,4 +1180,4 @@ version.c The version number and information about this Eric Allman -(Version 8.61.1.1, last update 3/5/95 12:52:16) +(Version 8.112, last update 11/18/95 08:44:31) diff --git a/usr.sbin/sendmail/src/TRACEFLAGS b/usr.sbin/sendmail/src/TRACEFLAGS index f05c219..f2499aa 100644 --- a/usr.sbin/sendmail/src/TRACEFLAGS +++ b/usr.sbin/sendmail/src/TRACEFLAGS @@ -4,7 +4,7 @@ 0, 44 util.c printav print address of each string 1 main.c main print from person 2 main.c finis -3 conf.c getla +3 conf.c getla, shouldqueue 4 conf.c enoughspace 5 clock.c setevent, clrevent, tick 6 savemail.c savemail, returntosender @@ -50,6 +50,9 @@ 40 queue.c queueup, orderq, dowork 41 queue.c orderq 42 mci.c mci_get +43 mime.c mime8to7 +44 recipient.c writeable +44 util.c safefile 45 envelope.c setsender 46 envelope.c openxscript 49 conf.c checkcompat @@ -61,4 +64,8 @@ 55 conf.c lockfile 59 Extended Load Average implementation from Christophe Wolfhugel 60 map.c +61 conf.c sm_gethostbyname +80 content length +81 sun remote mode 91 mci.c syslogging of MCI cache information +99 main.c avoid backgrounding (no printed output) diff --git a/usr.sbin/sendmail/src/alias.c b/usr.sbin/sendmail/src/alias.c index 9952db5..2bc4487 100644 --- a/usr.sbin/sendmail/src/alias.c +++ b/usr.sbin/sendmail/src/alias.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983 Eric P. Allman + * Copyright (c) 1983, 1995 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,15 +33,14 @@ */ # include "sendmail.h" -# include <pwd.h> #ifndef lint -static char sccsid[] = "@(#)alias.c 8.25 (Berkeley) 4/14/94"; +static char sccsid[] = "@(#)alias.c 8.52 (Berkeley) 10/28/95"; #endif /* not lint */ -MAP *AliasDB[MAXALIASDB + 1]; /* actual database list */ -int NAliasDBs; /* number of alias databases */ +MAP *AliasFileMap = NULL; /* the actual aliases.files map */ +int NAliasFileMaps; /* the number of entries in AliasFileMap */ /* ** ALIAS -- Compute aliases. ** @@ -53,6 +52,7 @@ int NAliasDBs; /* number of alias databases */ ** 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: @@ -66,19 +66,22 @@ int NAliasDBs; /* number of alias databases */ ** nothing. */ -alias(a, sendq, e) +void +alias(a, sendq, aliaslevel, e) register ADDRESS *a; ADDRESS **sendq; + int aliaslevel; register ENVELOPE *e; { register char *p; int naliases; char *owner; + auto int stat = EX_OK; char obuf[MAXNAME + 6]; extern char *aliaslookup(); if (tTd(27, 1)) - printf("alias(%s)\n", a->q_paddr); + printf("alias(%s)\n", a->q_user); /* don't realias already aliased names */ if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags)) @@ -90,10 +93,21 @@ alias(a, sendq, e) e->e_to = a->q_paddr; /* - ** Look up this name + ** 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, e); + 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 = "alias database unavailable"; + return; + } if (p == NULL) return; @@ -108,29 +122,25 @@ alias(a, sendq, e) if (bitset(EF_VRFYONLY, e->e_flags)) { a->q_flags |= QVERIFIED; - e->e_nrcpts++; return; } - message("aliased to %s", p); + message("aliased to %s", shortenstring(p, 203)); #ifdef LOG if (LogLevel > 9) - syslog(LOG_INFO, "%s: alias %s => %s", + syslog(LOG_INFO, "%s: alias %.100s => %s", e->e_id == NULL ? "NOQUEUE" : e->e_id, - a->q_paddr, p); + a->q_paddr, shortenstring(p, 203)); #endif a->q_flags &= ~QSELFREF; - AliasLevel++; - naliases = sendtolist(p, a, sendq, e); - AliasLevel--; - if (!bitset(QSELFREF, a->q_flags)) + if (tTd(27, 5)) { - if (tTd(27, 5)) - { - printf("alias: QDONTSEND "); - printaddr(a, FALSE); - } - a->q_flags |= QDONTSEND; + printf("alias: QDONTSEND "); + printaddr(a, FALSE); } + a->q_flags |= QDONTSEND; + naliases = sendtolist(p, a, sendq, aliaslevel + 1, e); + if (bitset(QSELFREF, a->q_flags)) + a->q_flags &= ~QDONTSEND; /* ** Look for owner of alias @@ -143,7 +153,7 @@ alias(a, sendq, e) (void) strcat(obuf, a->q_user); if (!bitnset(M_USR_UPPER, a->q_mailer->m_flags)) makelower(obuf); - owner = aliaslookup(obuf, e); + owner = aliaslookup(obuf, &stat, e); if (owner == NULL) return; @@ -154,17 +164,18 @@ alias(a, sendq, e) /* 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; - } + 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. @@ -178,26 +189,24 @@ alias(a, sendq, e) */ char * -aliaslookup(name, e) +aliaslookup(name, pstat, e) char *name; + int *pstat; ENVELOPE *e; { - register int dbno; - register MAP *map; - register char *p; + static MAP *map = NULL; - for (dbno = 0; dbno < NAliasDBs; dbno++) + if (map == NULL) { - auto int stat; + STAB *s = stab("aliases", ST_MAP, ST_FIND); - map = AliasDB[dbno]; - if (!bitset(MF_OPEN, map->map_mflags)) - continue; - p = (*map->map_class->map_lookup)(map, name, NULL, &stat); - if (p != NULL) - return p; + if (s == NULL) + return NULL; + map = &s->s_map; } - return NULL; + if (!bitset(MF_OPEN, map->map_mflags)) + return NULL; + return (*map->map_class->map_lookup)(map, name, NULL, pstat); } /* ** SETALIAS -- set up an alias map @@ -211,6 +220,7 @@ aliaslookup(name, e) ** none. */ +void setalias(spec) char *spec; { @@ -224,7 +234,7 @@ setalias(spec) for (p = spec; p != NULL; ) { - char aname[50]; + char buf[50]; while (isspace(*p)) p++; @@ -232,16 +242,27 @@ setalias(spec) break; spec = p; - if (NAliasDBs >= MAXALIASDB) + if (NAliasFileMaps >= MAXMAPSTACK) { - syserr("Too many alias databases defined, %d max", MAXALIASDB); + syserr("Too many alias databases defined, %d max", + MAXMAPSTACK); return; } - (void) sprintf(aname, "Alias%d", NAliasDBs); - s = stab(aname, ST_MAP, ST_ENTER); + if (AliasFileMap == NULL) + { + strcpy(buf, "aliases.files sequence"); + AliasFileMap = makemapentry(buf); + if (AliasFileMap == NULL) + { + syserr("setalias: cannot create aliases.files map"); + return; + } + } + (void) sprintf(buf, "Alias%d", NAliasFileMaps); + s = stab(buf, ST_MAP, ST_ENTER); map = &s->s_map; - AliasDB[NAliasDBs] = map; bzero(map, sizeof *map); + map->map_mname = s->s_name; p = strpbrk(p, " ,/:"); if (p != NULL && *p == ':') @@ -263,6 +284,9 @@ setalias(spec) 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) @@ -281,7 +305,7 @@ setalias(spec) if (map->map_class->map_parse(map, spec)) { map->map_mflags |= MF_VALID|MF_ALIAS; - NAliasDBs++; + AliasFileMap->map_stack[NAliasFileMaps++] = map; } } } @@ -313,7 +337,7 @@ aliaswait(map, ext, isopen) bool attimeout = FALSE; time_t mtime; struct stat stb; - char buf[MAXNAME]; + char buf[MAXNAME + 1]; if (tTd(27, 3)) printf("aliaswait(%s:%s)\n", @@ -348,6 +372,7 @@ aliaswait(map, ext, isopen) sleeptime); map->map_class->map_close(map); + map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); sleep(sleeptime); sleeptime *= 2; if (sleeptime > 60) @@ -380,11 +405,19 @@ aliaswait(map, ext, isopen) /* database is out of date */ if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid()) { + 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); + } rebuildaliases(map, TRUE); isopen = map->map_class->map_open(map, O_RDONLY); + SuprErrs = oldSuprErrs; } else { @@ -414,13 +447,17 @@ aliaswait(map, ext, isopen) ** DBM or DB version. */ +void rebuildaliases(map, automatic) register MAP *map; bool automatic; { FILE *af; bool nolock = FALSE; - sigfunc_t oldsigint; + sigfunc_t oldsigint, oldsigquit; +#ifdef SIGTSTP + sigfunc_t oldsigtstp; +#endif if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) return; @@ -428,6 +465,8 @@ rebuildaliases(map, automatic) /* try to lock the source file */ if ((af = fopen(map->map_file, "r+")) == NULL) { + struct stat stb; + if ((errno != EACCES && errno != EROFS) || automatic || (af = fopen(map->map_file, "r")) == NULL) { @@ -436,15 +475,18 @@ rebuildaliases(map, automatic) if (tTd(27, 1)) printf("Can't open %s: %s\n", map->map_file, errstring(saveerr)); - if (!automatic) + if (!automatic && !bitset(MF_OPTIONAL, map->map_mflags)) message("newaliases: cannot open %s: %s", map->map_file, errstring(saveerr)); errno = 0; return; } nolock = TRUE; - message("warning: cannot lock %s: %s", - map->map_file, errstring(errno)); + 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 */ @@ -465,7 +507,13 @@ rebuildaliases(map, automatic) return; } + /* avoid denial-of-service attacks */ + resetlimits(); 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)) { @@ -478,7 +526,7 @@ rebuildaliases(map, automatic) } #endif /* LOG */ map->map_mflags |= MF_OPEN|MF_WRITABLE; - readaliases(map, af, automatic); + readaliases(map, af, !automatic, TRUE); } else { @@ -495,10 +543,17 @@ rebuildaliases(map, automatic) /* 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 signal */ + /* restore the old signals */ (void) setsignal(SIGINT, oldsigint); + (void) setsignal(SIGQUIT, oldsigquit); +#ifdef SIGTSTP + (void) setsignal(SIGTSTP, oldsigtstp); +#endif } /* ** READALIASES -- read and process the alias file. @@ -509,7 +564,9 @@ rebuildaliases(map, automatic) ** Parameters: ** map -- the alias database descriptor. ** af -- file to read the aliases from. -** automatic -- set if this was an automatic rebuild. +** announcestats -- anounce statistics regarding number of +** aliases, longest alias, etc. +** logstats -- lot the same info. ** ** Returns: ** none. @@ -519,10 +576,12 @@ rebuildaliases(map, automatic) ** Optionally, builds the .dir & .pag files. */ -readaliases(map, af, automatic) +void +readaliases(map, af, announcestats, logstats) register MAP *map; FILE *af; - int automatic; + bool announcestats; + bool logstats; { register char *p; char *rhs; @@ -627,7 +686,7 @@ readaliases(map, af, automatic) } /* see if there should be a continuation line */ - c = fgetc(af); + c = getc(af); if (!feof(af)) (void) ungetc(c, af); if (c != ' ' && c != '\t') @@ -645,7 +704,7 @@ readaliases(map, af, automatic) break; } } - if (al.q_mailer != LocalMailer) + if (!bitnset(M_ALIASABLE, al.q_mailer->m_flags)) { syserr("554 %s... cannot alias non-local names", al.q_paddr); @@ -679,11 +738,11 @@ readaliases(map, af, automatic) CurEnv->e_to = NULL; FileName = NULL; - if (Verbose || !automatic) + if (Verbose || announcestats) message("%s: %d aliases, longest %d bytes, %d bytes total", map->map_file, naliases, longest, bytes); # ifdef LOG - if (LogLevel > 7) + if (LogLevel > 7 && logstats) syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total", map->map_file, naliases, longest, bytes); # endif /* LOG */ @@ -700,6 +759,8 @@ readaliases(map, af, automatic) ** 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. @@ -708,9 +769,11 @@ readaliases(map, af, automatic) ** New names are added to send queues. */ -forward(user, sendq, e) +void +forward(user, sendq, aliaslevel, e) ADDRESS *user; ADDRESS **sendq; + int aliaslevel; register ENVELOPE *e; { char *pp; @@ -719,7 +782,8 @@ forward(user, sendq, e) if (tTd(27, 1)) printf("forward(%s)\n", user->q_paddr); - if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags)) + if (!bitnset(M_HASPWENT, user->q_mailer->m_flags) || + bitset(QBADADDR, user->q_flags)) return; if (user->q_home == NULL) { @@ -738,17 +802,18 @@ forward(user, sendq, e) { int err; char buf[MAXPATHLEN+1]; + extern int include(); ep = strchr(pp, ':'); if (ep != NULL) *ep = '\0'; - expand(pp, buf, &buf[sizeof buf - 1], e); + expand(pp, buf, sizeof buf, e); if (ep != NULL) *ep++ = ':'; if (tTd(27, 3)) printf("forward: trying %s\n", buf); - err = include(buf, TRUE, user, sendq, e); + err = include(buf, TRUE, user, sendq, aliaslevel, e); if (err == 0) break; else if (transienterror(err)) diff --git a/usr.sbin/sendmail/src/arpadate.c b/usr.sbin/sendmail/src/arpadate.c index d3f9ac5..f676470 100644 --- a/usr.sbin/sendmail/src/arpadate.c +++ b/usr.sbin/sendmail/src/arpadate.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983 Eric P. Allman + * Copyright (c) 1983, 1995 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)arpadate.c 8.1 (Berkeley) 6/7/93"; +static char sccsid[] = "@(#)arpadate.c 8.4 (Berkeley) 4/21/95"; #endif /* not lint */ # include "sendmail.h" @@ -64,6 +64,17 @@ static char sccsid[] = "@(#)arpadate.c 8.1 (Berkeley) 6/7/93"; ** 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; @@ -75,7 +86,8 @@ arpadate(ud) register struct tm *lt; time_t t; struct tm gmt; - static char b[40]; + char *tz; + static char b[43 + TZNAME_MAX]; /* ** Get current time. @@ -147,15 +159,41 @@ arpadate(ud) off += 24 * 60; *q++ = ' '; - if (off == 0) { + if (off == 0) + { *q++ = 'G'; *q++ = 'M'; *q++ = 'T'; - } else { - if (off < 0) { + } + 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[]; + + tz = tzname[lt->tm_isdst]; + } +#endif +#if TZ_TYPE == TZ_TIMEZONE + { + extern char *timezone(); + + tz = timezone(off, lt->tm_isdst); + } +#endif + if (off < 0) + { off = -off; *q++ = '-'; - } else + } + else *q++ = '+'; if (off >= 24*60) /* should be impossible */ @@ -166,6 +204,14 @@ arpadate(ud) off %= 60; *q++ = (off / 10) + '0'; *q++ = (off % 10) + '0'; + if (tz != NULL && *tz != '\0') + { + *q++ = ' '; + *q++ = '('; + while (*tz != '\0') + *q++ = *tz++; + *q++ = ')'; + } } *q = '\0'; diff --git a/usr.sbin/sendmail/src/clock.c b/usr.sbin/sendmail/src/clock.c index 45ef1c2..1490137 100644 --- a/usr.sbin/sendmail/src/clock.c +++ b/usr.sbin/sendmail/src/clock.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983 Eric P. Allman + * Copyright (c) 1983, 1995 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)clock.c 8.8 (Berkeley) 1/12/94"; +static char sccsid[] = "@(#)clock.c 8.12 (Berkeley) 5/23/95"; #endif /* not lint */ # include "sendmail.h" @@ -65,7 +65,7 @@ static void tick __P((int)); EVENT * setevent(intvl, func, arg) time_t intvl; - int (*func)(); + void (*func)(); int arg; { register EVENT **evp; @@ -117,6 +117,7 @@ setevent(intvl, func, arg) ** arranges for event ev to not happen. */ +void clrevent(ev) register EVENT *ev; { @@ -182,7 +183,7 @@ tick(arg) while ((ev = EventQueue) != NULL && (ev->ev_time <= now || ev->ev_pid != mypid)) { - int (*f)(); + void (*f)(); int arg; int pid; @@ -216,10 +217,10 @@ tick(arg) sigaddset(&ss, SIGALRM); sigprocmask(SIG_UNBLOCK, &ss, NULL); #else -#ifdef SIGVTALRM +#if HASSIGSETMASK /* reset 4.2bsd signal mask to allow future alarms */ (void) sigsetmask(sigblock(0) & ~sigmask(SIGALRM)); -#endif /* SIGVTALRM */ +#endif /* HASSIGSETMASK */ #endif /* SIG_UNBLOCK */ /* call ev_func */ @@ -251,7 +252,7 @@ tick(arg) */ static bool SleepDone; -static int endsleep(); +static void endsleep(); #ifndef SLEEP_T # define SLEEP_T unsigned int @@ -262,14 +263,15 @@ sleep(intvl) unsigned int intvl; { if (intvl == 0) - return; + return (SLEEP_T) 0; SleepDone = FALSE; (void) setevent((time_t) intvl, endsleep, 0); while (!SleepDone) pause(); + return (SLEEP_T) 0; } -static +static void endsleep() { SleepDone = TRUE; diff --git a/usr.sbin/sendmail/src/convtime.c b/usr.sbin/sendmail/src/convtime.c index 5cb5e49..f978e92 100644 --- a/usr.sbin/sendmail/src/convtime.c +++ b/usr.sbin/sendmail/src/convtime.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983 Eric P. Allman + * Copyright (c) 1983, 1995 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,10 +33,11 @@ */ #ifndef lint -static char sccsid[] = "@(#)convtime.c 8.1 (Berkeley) 6/7/93"; +static char sccsid[] = "@(#)convtime.c 8.4 (Berkeley) 5/19/95"; #endif /* not lint */ # include <ctype.h> +# include <string.h> # include "useful.h" /* @@ -81,6 +82,11 @@ convtime(p, units) c = units; p--; } + else if (strchr("wdhms", c) == NULL) + { + usrerr("Invalid time unit `%c'", c); + c = units; + } switch (c) { case 'w': /* weeks */ diff --git a/usr.sbin/sendmail/src/envelope.c b/usr.sbin/sendmail/src/envelope.c index e8bb1e4..4bf7ac2 100644 --- a/usr.sbin/sendmail/src/envelope.c +++ b/usr.sbin/sendmail/src/envelope.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983 Eric P. Allman + * Copyright (c) 1983, 1995 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,11 +33,10 @@ */ #ifndef lint -static char sccsid[] = "@(#)envelope.c 8.34.1.1 (Berkeley) 2/28/95"; +static char sccsid[] = "@(#)envelope.c 8.76 (Berkeley) 11/11/95"; #endif /* not lint */ #include "sendmail.h" -#include <pwd.h> /* ** NEWENVELOPE -- allocate a new envelope @@ -60,9 +59,6 @@ newenvelope(e, parent) register ENVELOPE *e; register ENVELOPE *parent; { - extern putheader(), putbody(); - extern ENVELOPE BlankEnvelope; - if (e == parent && e->e_parent != NULL) parent = e->e_parent; clearenvelope(e, TRUE); @@ -100,16 +96,20 @@ dropenvelope(e) register ENVELOPE *e; { bool queueit = FALSE; - bool saveit = bitset(EF_FATALERRS, e->e_flags); + bool failure_return = FALSE; + bool success_return = FALSE; register ADDRESS *q; char *id = e->e_id; char buf[MAXLINE]; if (tTd(50, 1)) { + extern void printenvflags(); + printf("dropenvelope %x: id=", e); xputs(e->e_id); - printf(", flags=0x%x\n", e->e_flags); + printf(", flags="); + printenvflags(e); if (tTd(50, 10)) { printf("sendq="); @@ -117,17 +117,23 @@ dropenvelope(e) } } +#ifdef LOG + if (LogLevel > 84) + syslog(LOG_DEBUG, "%s: dropenvelope, e_flags=0x%x, OpMode=%c, pid=%d", + id == NULL ? "[NOQUEUE]" : id, + e->e_flags, OpMode, getpid()); +#endif + /* we must have an id to remove disk files */ if (id == NULL) return; -#ifdef LOG + /* 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); - if (LogLevel > 84) - syslog(LOG_DEBUG, "dropenvelope, id=%s, flags=0x%x, pid=%d", - id, e->e_flags, getpid()); -#endif /* LOG */ e->e_flags &= ~EF_LOGSENDER; /* post statistics */ @@ -140,69 +146,116 @@ dropenvelope(e) e->e_flags &= ~EF_QUEUERUN; for (q = e->e_sendqueue; q != NULL; q = q->q_next) { - if (bitset(QQUEUEUP, q->q_flags)) + if (!bitset(QBADADDR|QDONTSEND|QSENT, q->q_flags) || + bitset(QQUEUEUP, q->q_flags)) queueit = TRUE; - if (!bitset(QDONTSEND, q->q_flags) && - bitset(QBADADDR, q->q_flags)) + + /* see if a notification is needed */ + if (bitset(QBADADDR, q->q_flags) && + bitset(QPINGONFAILURE, q->q_flags)) { - if (q->q_owner == NULL && - strcmp(e->e_from.q_paddr, "<>") != 0) + failure_return = TRUE; + if (q->q_owner == NULL && !emptyaddr(&e->e_from)) (void) sendtolist(e->e_from.q_paddr, NULL, - &e->e_errorqueue, e); + &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 (curtime() > e->e_ctime + TimeOuts.to_q_return) + else if (curtime() > e->e_ctime + TimeOuts.to_q_return[e->e_timeoutclass]) { (void) sprintf(buf, "Cannot send message for %s", - pintvl(TimeOuts.to_q_return, FALSE)); + 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; - saveit = TRUE; + failure_return = TRUE; fprintf(e->e_xfp, "Message could not be delivered for %s\n", - pintvl(TimeOuts.to_q_return, FALSE)); + 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(QQUEUEUP, q->q_flags)) + if (bitset(QQUEUEUP, q->q_flags) || + !bitset(QBADADDR|QDONTSEND|QSENT, q->q_flags)) + { q->q_flags |= QBADADDR; + q->q_status = "4.4.7"; + } } } - else if (TimeOuts.to_q_warning > 0 && - curtime() > e->e_ctime + TimeOuts.to_q_warning) + 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) && + bool delay_return = FALSE; + + 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 && + !bitset(EF_WARNING|EF_RESPONSE, e->e_flags) && e->e_class >= 0 && - strcmp(e->e_from.q_paddr, "<>") != 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)) { (void) sprintf(buf, - "warning: cannot send message for %s", - pintvl(TimeOuts.to_q_warning, FALSE)); + "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; - saveit = TRUE; + failure_return = TRUE; } fprintf(e->e_xfp, "Warning: message still undelivered after %s\n", - pintvl(TimeOuts.to_q_warning, FALSE)); + 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, FALSE)); + pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE)); + } + + if (tTd(50, 2)) + printf("failure_return=%d success_return=%d queueit=%d\n", + failure_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) + { + failure_return = TRUE; for (q = e->e_sendqueue; q != NULL; q = q->q_next) { - if (bitset(QQUEUEUP, q->q_flags)) - q->q_flags |= QREPORT; + if (!bitset(QDONTSEND, q->q_flags)) + q->q_flags |= QBADADDR; } } @@ -210,33 +263,42 @@ dropenvelope(e) ** Send back return receipts as requested. */ +/* if (e->e_receiptto != NULL && bitset(EF_SENDRECEIPT, e->e_flags) && !bitset(PRIV_NORECEIPTS, PrivacyFlags)) +*/ + if (e->e_receiptto == NULL) + e->e_receiptto = e->e_from.q_paddr; + if (success_return && !failure_return && + !bitset(PRIV_NORECEIPTS, PrivacyFlags) && + strcmp(e->e_receiptto, "<>") != 0) { auto ADDRESS *rlist = NULL; - (void) sendtolist(e->e_receiptto, NULLADDR, &rlist, e); + e->e_flags |= EF_SENDRECEIPT; + (void) sendtolist(e->e_receiptto, NULLADDR, &rlist, 0, e); (void) returntosender("Return receipt", rlist, FALSE, e); - e->e_flags &= ~EF_SENDRECEIPT; } + e->e_flags &= ~EF_SENDRECEIPT; /* ** Arrange to send error messages if there are fatal errors. */ - if (saveit && e->e_errormode != EM_QUIET) - savemail(e); + if (failure_return && e->e_errormode != EM_QUIET) + savemail(e, !bitset(EF_NO_BODY_RETN, e->e_flags)); /* ** Arrange to send warning messages to postmaster as requested. */ - if (bitset(EF_PM_NOTIFY, e->e_flags) && PostMasterCopy != NULL && + 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; - (void) sendtolist(PostMasterCopy, NULLADDR, &rlist, e); + (void) sendtolist(PostMasterCopy, NULLADDR, &rlist, 0, e); (void) returntosender(e->e_message, rlist, FALSE, e); } @@ -244,13 +306,18 @@ dropenvelope(e) ** Instantiate or deinstantiate the queue. */ - if ((!queueit && !bitset(EF_KEEPQUEUE, e->e_flags)) || - bitset(EF_CLRQUEUE, e->e_flags)) +simpledrop: + if (!queueit || bitset(EF_CLRQUEUE, e->e_flags)) { if (tTd(50, 1)) - printf("\n===== Dropping [dq]f%s =====\n\n", e->e_id); - if (e->e_df != NULL) - xunlink(e->e_df); + { + extern void printenvflags(); + + printf("\n===== Dropping [dq]f%s... queueit=%d, e_flags=", + e->e_id, queueit); + printenvflags(e); + } + xunlink(queuename(e, 'd')); xunlink(queuename(e, 'q')); #ifdef LOG @@ -261,7 +328,7 @@ dropenvelope(e) else if (queueit || !bitset(EF_INQUEUE, e->e_flags)) { #ifdef QUEUE - queueup(e, bitset(EF_KEEPQUEUE, e->e_flags), FALSE); + queueup(e, FALSE); #else /* QUEUE */ syserr("554 dropenvelope: queueup"); #endif /* QUEUE */ @@ -273,9 +340,10 @@ dropenvelope(e) /* make sure that this envelope is marked unused */ if (e->e_dfp != NULL) - (void) xfclose(e->e_dfp, "dropenvelope", e->e_df); + (void) xfclose(e->e_dfp, "dropenvelope df", e->e_id); e->e_dfp = NULL; - e->e_id = e->e_df = NULL; + e->e_id = NULL; + e->e_flags &= ~EF_HAS_DF; } /* ** CLEARENVELOPE -- clear an envelope without unlocking @@ -312,7 +380,7 @@ clearenvelope(e, fullclear) 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_df); + (void) xfclose(e->e_dfp, "clearenvelope dfp", e->e_id); e->e_xfp = e->e_dfp = NULL; } @@ -359,7 +427,6 @@ initsys(e) #endif /* TTYNAME */ extern char *ttyname(); extern void settime(); - extern char Version[]; /* ** Give this envelope a reality. @@ -491,9 +558,12 @@ openxscript(e) } 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); @@ -573,7 +643,6 @@ setsender(from, e, delimptr, internal) char *bp; char buf[MAXNAME + 2]; char pvpbuf[PSBUFSIZE]; - extern struct passwd *getpwnam(); extern char *FullName; if (tTd(45, 1)) @@ -614,9 +683,12 @@ setsender(from, e, delimptr, internal) if (p == NULL) { char *host = RealHostName; + if (host == NULL) host = MyHostName; - (void) sprintf(ebuf, "%s@%s", realname, host); + (void) sprintf(ebuf, "%.*s@%.*s", + MAXNAME, realname, + MAXNAME, host); p = ebuf; } syslog(LOG_NOTICE, @@ -629,6 +701,7 @@ setsender(from, e, delimptr, internal) 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; @@ -640,7 +713,7 @@ setsender(from, e, delimptr, internal) char nbuf[100]; SuprErrs = TRUE; - expand("\201n", nbuf, &nbuf[sizeof nbuf], e); + 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, @@ -658,37 +731,30 @@ setsender(from, e, delimptr, internal) } SuprErrs = FALSE; - pvp = NULL; - if (e->e_from.q_mailer == LocalMailer) +# if USERDB + if (bitnset(M_CHECKUDB, e->e_from.q_mailer->m_flags)) { -# ifdef USERDB register char *p; extern char *udbsender(); -# endif + 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 has given fullname already, don't redefine */ + /* if the user already given fullname don't redefine */ if (FullName == NULL) FullName = macvalue('x', e); if (FullName != NULL && FullName[0] == '\0') FullName = NULL; - -# ifdef USERDB - p = udbsender(e->e_from.q_user); - - if (p != NULL) - { - /* - ** We have an alternate address for the sender - */ - - pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL); - } -# endif /* USERDB */ } - if ((pw = getpwnam(e->e_from.q_user)) != NULL) + if ((pw = sm_getpwnam(e->e_from.q_user)) != NULL) { /* ** Process passwd file entry. @@ -738,14 +804,14 @@ setsender(from, e, delimptr, internal) ** links in the net. */ - if (pvp == NULL) - pvp = prescan(from, delimchar, pvpbuf, sizeof pvpbuf, NULL); + pvp = prescan(from, delimchar, pvpbuf, sizeof pvpbuf, NULL, NULL); if (pvp == NULL) { /* don't need to give error -- prescan did that already */ # ifdef LOG if (LogLevel > 2) - syslog(LOG_NOTICE, "cannot prescan from (%s)", from); + syslog(LOG_NOTICE, "cannot prescan from (%s)", + shortenstring(from, 203)); # endif finis(); } @@ -754,7 +820,7 @@ setsender(from, e, delimptr, internal) (void) rewrite(pvp, 4, 0, e); bp = buf + 1; cataddr(pvp, NULL, bp, sizeof buf - 2, '\0'); - if (*bp == '@') + if (*bp == '@' && !bitnset(M_NOBRACKET, e->e_from.q_mailer->m_flags)) { /* heuristic: route-addr: add angle brackets */ strcat(bp, ">"); @@ -767,11 +833,92 @@ setsender(from, e, delimptr, internal) if (e->e_from.q_mailer != NULL && bitnset(M_CANONICAL, e->e_from.q_mailer->m_flags)) { + char **lastat; extern char **copyplist(); - while (*pvp != NULL && strcmp(*pvp, "@") != 0) - pvp++; - if (*pvp != NULL) - e->e_fromdomain = copyplist(pvp, TRUE); + /* 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/usr.sbin/sendmail/src/err.c b/usr.sbin/sendmail/src/err.c index c6a87e9..6acb8fb 100644 --- a/usr.sbin/sendmail/src/err.c +++ b/usr.sbin/sendmail/src/err.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983 Eric P. Allman + * Copyright (c) 1983, 1995 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,13 +33,11 @@ */ #ifndef lint -static char sccsid[] = "@(#)err.c 8.27 (Berkeley) 4/18/94"; +static char sccsid[] = "@(#)err.c 8.41 (Berkeley) 10/8/95"; #endif /* not lint */ # include "sendmail.h" # include <errno.h> -# include <netdb.h> -# include <pwd.h> /* ** SYSERR -- Print error message. @@ -53,8 +51,11 @@ static char sccsid[] = "@(#)err.c 8.27 (Berkeley) 4/18/94"; ** be used lightly. ** ** Parameters: -** f -- the format string -** a, b, c, d, e -- 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 @@ -65,9 +66,12 @@ static char sccsid[] = "@(#)err.c 8.27 (Berkeley) 4/18/94"; ** sets ExitStat. */ -char MsgBuf[BUFSIZ*2]; /* text of most recent message */ +char MsgBuf[BUFSIZ*2]; /* text of most recent message */ +char HeldMessageBuf[sizeof MsgBuf]; /* for held messages */ -static void fmtmsg(); +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 @@ -107,6 +111,14 @@ syserr(fmt, va_alist) VA_END; puterrmsg(MsgBuf); + /* save this message for mailq printing */ + if (!panic) + { + 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) { @@ -119,7 +131,7 @@ syserr(fmt, va_alist) } # ifdef LOG - pw = getpwuid(getuid()); + pw = sm_getpwuid(getuid()); if (pw != NULL) uname = pw->pw_name; else @@ -129,7 +141,7 @@ syserr(fmt, va_alist) } if (LogLevel > 0) - syslog(panic ? LOG_ALERT : LOG_CRIT, "%s: SYSERR(%s): %s", + syslog(panic ? LOG_ALERT : LOG_CRIT, "%s: SYSERR(%s): %.900s", CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, uname, &MsgBuf[4]); # endif /* LOG */ @@ -143,6 +155,8 @@ syserr(fmt, va_alist) #ifdef XLA xla_all_end(); #endif + if (tTd(0, 1)) + abort(); exit(EX_OSERR); } errno = 0; @@ -155,7 +169,9 @@ syserr(fmt, va_alist) ** This is much like syserr except it is for user errors. ** ** Parameters: -** fmt, a, b, c, d -- printf strings +** fmt -- the format string. If it does not begin with +** a three-digit SMTP reply code, 501 is assumed. +** (others) -- printf strings ** ** Returns: ** none @@ -183,11 +199,41 @@ usrerr(fmt, va_alist) 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]; + + sprintf(buf, "Postmaster warning: %.*s", + sizeof buf - 22, MsgBuf + 4); + CurEnv->e_message = newstr(buf); + } + else + { + CurEnv->e_message = newstr(MsgBuf + 4); + } + break; + } + puterrmsg(MsgBuf); # ifdef LOG if (LogLevel > 3 && LogUsrErrs) - syslog(LOG_NOTICE, "%s: %s", + syslog(LOG_NOTICE, "%s: %.900s", CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, &MsgBuf[4]); # endif /* LOG */ @@ -201,7 +247,7 @@ usrerr(fmt, va_alist) ** Parameters: ** msg -- the message (printf fmt) -- it can begin with ** an SMTP reply code. If not, 050 is assumed. -** a, b, c, d, e -- printf arguments +** (others) -- printf arguments ** ** Returns: ** none @@ -226,7 +272,23 @@ message(msg, va_alist) VA_START(msg); fmtmsg(MsgBuf, CurEnv->e_to, "050", 0, msg, ap); VA_END; - putoutmsg(MsgBuf, FALSE); + 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) @@ -234,10 +296,10 @@ message(msg, va_alist) ** Just like "message" except it never puts the to... tag on. ** ** Parameters: -** num -- the default ARPANET error number (in ascii) ** msg -- the message (printf fmt) -- if it begins -** with three digits, this number overrides num. -** a, b, c, d, e -- printf arguments +** with a three digit SMTP reply code, that is used, +** otherwise 050 is assumed. +** (others) -- printf arguments ** ** Returns: ** none @@ -262,7 +324,23 @@ nmessage(msg, va_alist) VA_START(msg); fmtmsg(MsgBuf, (char *) NULL, "050", 0, msg, ap); VA_END; - putoutmsg(MsgBuf, FALSE); + 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 @@ -271,6 +349,8 @@ nmessage(msg, va_alist) ** 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. @@ -281,25 +361,42 @@ nmessage(msg, va_alist) ** Deletes SMTP reply code number as appropriate. */ -putoutmsg(msg, holdmsg) +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\n", msg, holdmsg ? " (held)" : ""); + 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 (CurEnv->e_xfp != NULL && strchr("456", msg[0]) != NULL) + if (!heldmsg && CurEnv->e_xfp != NULL && strchr("45", msg[0]) != NULL) fprintf(CurEnv->e_xfp, "%s\n", msg); + if (msgcode == '8') + msg[0] == '0'; + /* output to channel if appropriate */ - if (holdmsg || (!Verbose && msg[0] == '0')) + if (!Verbose && msg[0] == '0') return; - - /* map warnings to something SMTP can handle */ - if (msg[0] == '6') - msg[0] = '5'; + if (holdmsg) + { + /* save for possible future display */ + msg[0] = msgcode; + strcpy(HeldMessageBuf, msg); + return; + } (void) fflush(stdout); @@ -334,7 +431,7 @@ putoutmsg(msg, holdmsg) "%s: SYSERR: putoutmsg (%s): error on output channel sending \"%s\": %s", CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, CurHostName == NULL ? "NO-HOST" : CurHostName, - msg, errstring(errno)); + shortenstring(msg, 203), errstring(errno)); #endif } /* @@ -350,13 +447,14 @@ putoutmsg(msg, holdmsg) ** 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); + putoutmsg(msg, HoldErrs, FALSE); /* signal the error */ Errors++; @@ -392,14 +490,16 @@ puterrmsg(msg) static void fmtmsg(eb, to, num, eno, fmt, ap) register char *eb; - char *to; - char *num; + const char *to; + const char *num; int eno; - char *fmt; + const char *fmt; va_list ap; { char del; char *meb; + int l; + int spaceleft = sizeof MsgBuf; /* output the reply code */ if (isdigit(fmt[0]) && isdigit(fmt[1]) && isdigit(fmt[2])) @@ -413,18 +513,23 @@ fmtmsg(eb, to, num, eno, fmt, ap) del = ' '; (void) sprintf(eb, "%3.3s%c", num, del); eb += 4; + spaceleft -= 4; /* output the file name and line number */ if (FileName != NULL) { - (void) sprintf(eb, "%s: line %d: ", FileName, LineNumber); - eb += strlen(eb); + (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') { - (void) sprintf(eb, "%s... ", shortenstring(to, 203)); + (void) snprintf(eb, spaceleft, "%s... ", + shortenstring(to, 203)); + spaceleft -= strlen(eb); while (*eb != '\0') *eb++ &= 0177; } @@ -432,23 +537,50 @@ fmtmsg(eb, to, num, eno, fmt, ap) meb = eb; /* output the message */ - (void) vsprintf(eb, fmt, ap); + (void) vsnprintf(eb, spaceleft, fmt, ap); + spaceleft -= strlen(eb); while (*eb != '\0') *eb++ &= 0177; /* output the error code, if any */ if (eno != 0) - { - (void) sprintf(eb, ": %s", errstring(eno)); - eb += strlen(eb); - } + (void) snprintf(eb, spaceleft, ": %s", errstring(eno)); +} +/* +** BUFFER_ERRORS -- arrange to buffer future error messages +** +** Parameters: +** none +** +** Returns: +** none. +*/ - if (num[0] == '5' || (CurEnv->e_message == NULL && num[0] == '4')) - { - if (CurEnv->e_message != NULL) - free(CurEnv->e_message); - CurEnv->e_message = newstr(meb); - } +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 @@ -505,13 +637,15 @@ errstring(errnum) case EHOSTDOWN: if (CurHostName == NULL) break; - (void) sprintf(buf, "Host %s is down", CurHostName); + (void) sprintf(buf, "Host %s is down", + shortenstring(CurHostName, 203)); return (buf); case ECONNREFUSED: if (CurHostName == NULL) break; - (void) sprintf(buf, "Connection refused by %s", CurHostName); + (void) sprintf(buf, "Connection refused by %s", + shortenstring(CurHostName, 203)); return (buf); # endif diff --git a/usr.sbin/sendmail/src/macro.c b/usr.sbin/sendmail/src/macro.c index 8a8a90b..94ef834 100644 --- a/usr.sbin/sendmail/src/macro.c +++ b/usr.sbin/sendmail/src/macro.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983 Eric P. Allman + * Copyright (c) 1983, 1995 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,19 +33,22 @@ */ #ifndef lint -static char sccsid[] = "@(#)macro.c 8.3 (Berkeley) 2/7/94"; +static char sccsid[] = "@(#)macro.c 8.13 (Berkeley) 7/10/95"; #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. -** buflim -- the buffer limit, i.e., the address -** of the last usable position in buf. +** bufsize -- the size of the buffer. ** e -- envelope in which to work. ** ** Returns: @@ -56,10 +59,10 @@ static char sccsid[] = "@(#)macro.c 8.3 (Berkeley) 2/7/94"; */ void -expand(s, buf, buflim, e) +expand(s, buf, bufsize, e) register char *s; register char *buf; - char *buflim; + size_t bufsize; register ENVELOPE *e; { register char *xp; @@ -115,7 +118,7 @@ expand(s, buf, buflim, e) continue; case MACROEXPAND: /* macro interpolation */ - c = *++s & 0177; + c = *++s & 0377; if (c != '\0') q = macvalue(c, e); else @@ -160,14 +163,14 @@ expand(s, buf, buflim, e) /* recurse as appropriate */ if (recurse) { - expand(xbuf, buf, buflim, e); + expand(xbuf, buf, bufsize, e); return; } /* copy results out */ - i = buflim - buf - 1; - if (i > xp - xbuf) - i = xp - xbuf; + i = xp - xbuf; + if (i >= bufsize) + i = bufsize - 1; bcopy(xbuf, buf, i); buf[i] = '\0'; } @@ -242,11 +245,12 @@ define(n, v, e) { if (tTd(35, 9)) { - printf("define(%c as ", n); + printf("%sdefine(%s as ", + (e->e_macro[n & 0377] == NULL) ? "" : "re", macname(n)); xputs(v); printf(")\n"); } - e->e_macro[n & 0177] = v; + e->e_macro[n & 0377] = v; } /* ** MACVALUE -- return uninterpreted value of a macro. @@ -266,7 +270,7 @@ macvalue(n, e) int n; register ENVELOPE *e; { - n &= 0177; + n &= 0377; while (e != NULL) { register char *p = e->e_macro[n]; @@ -277,3 +281,161 @@ macvalue(n, e) } 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[21]; + + 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]) + { + 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/usr.sbin/sendmail/src/makesendmail b/usr.sbin/sendmail/src/makesendmail index 7c13db9..df202e9 100644 --- a/usr.sbin/sendmail/src/makesendmail +++ b/usr.sbin/sendmail/src/makesendmail @@ -32,7 +32,7 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -# @(#)makesendmail 8.5 (Berkeley) 2/27/94 +# @(#)makesendmail 8.29 (Berkeley) 8/1/95 # # @@ -40,8 +40,65 @@ # multiple architectures and Makefiles. # -# determine machine architecture -arch=`uname -m` +if [ "x${1-""}" = "x-m" ] +then + # show Makefile name only + mflag=1 +else + mflag="" +fi + +# +# Do heuristic guesses !ONLY! for machines that do not have uname +# +if [ -d /LocalApps -a ! -f /bin/uname -a ! -f /usr/bin/uname ] +then + # probably a NeXT box + arch=NeXT + os=Mach + rel=`strings /mach | grep 'Mach.*:' | sed -e 's/.* Mach //' -e 's/:.*//'` +elif [ -f /usr/sony/bin/machine -a -f /etc/osversion ] +then + # probably a Sony NEWS 4.x + os=NEWS-OS + rel=`awk '{ print $3}' /etc/osversion` + arch=`/usr/sony/bin/machine` +elif [ -d /usr/omron -a -f /bin/luna ] +then + # probably a Omron LUNA + os=LUNA + if [ -f /bin/luna1 ] && /bin/luna1 + then + rel=unios-b + arch=luna1 + elif [ -f /bin/luna2 ] && /bin/luna2 + then + rel=Mach + arch=luna2 + elif [ -f /bin/luna88k ] && /bin/luna88k + then + rel=Mach + arch=luna88k + fi +fi + +if [ ! "$arch" -a ! "$os" -a ! "$rel" ] +then + arch=`uname -m | sed -e 's/ //g'` + os=`uname -s | sed 's/\//-/g'` + rel=`uname -r` +fi + +# +# Tweak the values we have already got. PLEASE LIMIT THESE to +# tweaks that are absolutely necessary because your system uname +# routine doesn't return something sufficiently unique. Don't do +# it just because you don't like the name that is returned. You +# can combine the architecture name with the os name to create a +# unique Makefile name. +# + +# tweak machine architecture case $arch in sun4*) arch=sun4;; @@ -49,65 +106,177 @@ in 9000/*) arch=`echo $arch | sed -e 's/9000.//' -e 's/..$/xx/'`;; esac -# determine operating system type -os=`uname -s` +# tweak operating system type and release +case $os +in + DYNIX-ptx) os=PTX;; + Paragon*) os=Paragon;; + HP-UX) rel=`echo $rel | sed -e 's/^[^.]*\.0*//'`;; + AIX) rel=`uname -v`;; + BSD-386) os=BSD-OS;; +esac + +# get "base part" of operating system release +rbase=`echo $rel | sed -e 's/\..*//'` -# determine operating system release -rel=`uname -r` -rbase=`echo $rel | sed 's/\..*//''` +# heuristic tweaks to clean up names -- PLEASE LIMIT THESE! +if [ "$os" = "unix" ] +then + # might be Altos System V + case $rel + in + 5.3*) os=Altos;; + esac +elif [ -r /unix -a -r /usr/lib/libseq.a -a -r /lib/cpp ] +then + # might be a DYNIX/ptx 2.x system, which has a broken uname + if strings /lib/cpp | grep _SEQUENT_ > /dev/null + then + os=PTX + fi +elif [ -d /usr/nec ] +then + # NEC machine -- what is it running? + if [ "$os" = "UNIX_System_V" ] + then + os=EWS-UX_V + elif [ "$os" = "UNIX_SV" ] + then + os=UX4800 + fi +elif [ "$arch" = "mips" ] +then + case $rel + in + 4_*) + if [ `uname -v` = "UMIPS" ] + then + os=RISCos + fi;; + esac +fi + +# see if there is a "user suffix" specified +if [ "${SENDMAIL_SUFFIX-}x" = "x" ] +then + sfx="" +else + sfx=".${SENDMAIL_SUFFIX}" +fi + +echo "Configuration: os=$os, rel=$rel, rbase=$rbase, arch=$arch, sfx=$sfx" # now try to find a reasonable object directory -if [ -r obj.$os.$arch.$rel ]; then - obj=obj.$os.$arch.$rel -elif [ -r obj.$os.$arch.$rbase.x ]; then - obj=obj.$os.$arch.$rbase.x -elif [ -r obj.$os.$rel ]; then - obj=obj.$os.$rel -elif [ -r obj.$os.$rbase.x ]; then - obj=obj.$os.$rbase.x -elif [ -r obj.$os.$arch ]; then - obj=obj.$os.$arch -elif [ -r obj.$arch.$rel ]; then - obj=obj.$arch.$rel -elif [ -r obj.$arch.$rbase.x ]; then - obj=obj.$arch.$rbase.x -elif [ -r obj.$os ]; then - obj=obj.$os -elif [ -r obj.$arch ]; then - obj=obj.$arch -elif [ -r obj.$rel ]; then - obj=obj.$rel +if [ -r obj.$os.$rel.$arch$sfx ]; then + obj=obj.$os.$rel.$arch$sfx +elif [ -r obj.$os.$rbase.x.$arch$sfx ]; then + obj=obj.$os.$rbase.x.$arch$sfx +elif [ -r obj.$os.$rel$sfx ]; then + obj=obj.$os.$rel$sfx +elif [ -r obj.$os.$rbase.x$sfx ]; then + obj=obj.$os.$rbase.x$sfx +elif [ -r obj.$os.$arch$sfx ]; then + obj=obj.$os.$arch$sfx +elif [ -r obj.$rel.$arch$sfx ]; then + obj=obj.$rel.$arch$sfx +elif [ -r obj.$rbase.x.$arch$sfx ]; then + obj=obj.$rbase.x.$arch$sfx +elif [ -r obj.$os$sfx ]; then + obj=obj.$os$sfx +elif [ -r obj.$arch$sfx ]; then + obj=obj.$arch$sfx +elif [ -r obj.$rel$sfx ]; then + obj=obj.$rel$sfx +elif [ -r obj$sfx ]; then + obj=obj$sfx else # no existing obj directory -- try to create one if Makefile found - obj=obj.$os.$arch.$rel - if [ -r Makefile.$os.$arch.$rel ]; then - makefile=Makefile.$os.$arch.$rel - elif [ -r Makefile.$os.$arch.$rbase.x ]; then - makefile=Makefile.$os.$arch.$rbase.x - elif [ -r Makefile.$os.$rel ]; then + obj=obj.$os.$rel.$arch$sfx + if [ -r Makefiles/Makefile.$os.$rel.$arch$sfx ]; then + makefile=Makefile.$os.$rel.$arch$sfx + elif [ -r Makefiles/Makefile.$os.$rel.$arch ]; then + makefile=Makefile.$os.$rel.$arch + elif [ -r Makefiles/Makefile.$os.$rbase.x.$arch$sfx ]; then + makefile=Makefile.$os.$rbase.x.$arch$sfx + elif [ -r Makefiles/Makefile.$os.$rbase.x.$arch ]; then + makefile=Makefile.$os.$rbase.x.$arch + elif [ -r Makefiles/Makefile.$os.$rel$sfx ]; then + makefile=Makefile.$os.$rel$sfx + elif [ -r Makefiles/Makefile.$os.$rel ]; then makefile=Makefile.$os.$rel - elif [ -r Makefile.$os.$rbase.x ]; then + elif [ -r Makefiles/Makefile.$os.$rbase.x$sfx ]; then + makefile=Makefile.$os.$rbase.x$sfx + elif [ -r Makefiles/Makefile.$os.$rbase.x ]; then makefile=Makefile.$os.$rbase.x - elif [ -r Makefile.$os.$arch ]; then + elif [ -r Makefiles/Makefile.$os.$arch$sfx ]; then + makefile=Makefile.$os.$arch$sfx + elif [ -r Makefiles/Makefile.$os.$arch ]; then makefile=Makefile.$os.$arch - elif [ -r Makefile.$arch.$rel ]; then - makefile=Makefile.$arch.$rel - elif [ -r Makefile.$arch.$rbase.x ]; then - makefile=Makefile.$arch.$rbase.x - elif [ -r Makefile.$os ]; then + elif [ -r Makefiles/Makefile.$rel.$arch$sfx ]; then + makefile=Makefile.$rel.$arch$sfx + elif [ -r Makefiles/Makefile.$rel.$arch ]; then + makefile=Makefile.$rel.$arch + elif [ -r Makefiles/Makefile.$rbase.x.$arch$sfx ]; then + makefile=Makefile.$rbase.x.$arch$sfx + elif [ -r Makefiles/Makefile.$rbase.x.$arch ]; then + makefile=Makefile.$rbase.x.$arch + elif [ -r Makefiles/Makefile.$os$sfx ]; then + makefile=Makefile.$os$sfx + elif [ -r Makefiles/Makefile.$os ]; then makefile=Makefile.$os - elif [ -r Makefile.$arch ]; then + elif [ -r Makefiles/Makefile.$arch$sfx ]; then + makefile=Makefile.$arch$sfx + elif [ -r Makefiles/Makefile.$arch ]; then makefile=Makefile.$arch - elif [ -r Makefile.$rel ]; then + elif [ -r Makefiles/Makefile.$rel$sfx ]; then + makefile=Makefile.$rel$sfx + elif [ -r Makefiles/Makefile.$rel ]; then makefile=Makefile.$rel + elif [ -r Makefiles/Makefile.$rel$sfx ]; then + makefile=Makefile.$rel$sfx else echo "Cannot determine how to support $arch.$os.$rel" exit 1 fi + if [ "$mflag" ] + then + echo "Will run in virgin $obj using $makefile" + exit 0 + fi echo "Creating $obj using $makefile" mkdir $obj - (cd $obj; ln -s ../*.[ch158] ../sendmail.hf .; ln -s ../$makefile Makefile) + (cd $obj; ln -s ../*.[ch158] ../sendmail.hf .; ln -s ../Makefiles/$makefile Makefile) + echo "Making dependencies in $obj" + (cd $obj; ${MAKE-make} depend) fi + +if [ "$mflag" ] +then + makefile=`ls -l $obj/Makefile | sed 's/.* //'` + if [ -z "$makefile" ] + then + echo "ERROR: $obj exists but has no Makefile" + exit 1 + fi + case $makefile + in + ../Makefiles/*) + makefile=`echo $makefile | sed 's/...Makefiles.//'` + echo "Will run in existing $obj using $makefile" + ;; + + *) + echo "Will run in existing $obj using custom $makefile" + ;; + esac + exit 0 +fi + echo "Making in $obj" cd $obj -exec make -f Makefile $* +if [ $# = 0 ] +then + exec ${MAKE-make} +else + exec ${MAKE-make} "$@" +fi diff --git a/usr.sbin/sendmail/src/map.c b/usr.sbin/sendmail/src/map.c index a2b3337..b8ea903 100644 --- a/usr.sbin/sendmail/src/map.c +++ b/usr.sbin/sendmail/src/map.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1992 Eric P. Allman. + * Copyright (c) 1992, 1995 Eric P. Allman. * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,19 +33,25 @@ */ #ifndef lint -static char sccsid[] = "@(#)map.c 8.25.1.1 (Berkeley) 2/10/95"; +static char sccsid[] = "@(#)map.c 8.107 (Berkeley) 11/20/95"; #endif /* not lint */ #include "sendmail.h" #ifdef NDBM -#include <ndbm.h> +# include <ndbm.h> #endif #ifdef NEWDB -#include <db.h> +# ifdef R_FIRST + ERROR README: You are running the Berkeley DB version of ndbm.h. See + ERROR README: the READ_ME file about tweaking Berkeley DB so it can + ERROR README: coexist with NDBM, or delete -DNDBM from the Makefile. +# endif +# include <db.h> #endif #ifdef NIS -#include <rpcsvc/ypclnt.h> + struct dom_binding; /* forward reference needed on IRIX */ +# include <rpcsvc/ypclnt.h> #endif /* @@ -82,11 +88,24 @@ static char sccsid[] = "@(#)map.c 8.25.1.1 (Berkeley) 2/10/95"; ** ** 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 +#define EX_NOTFOUND EX_NOHOST + extern bool aliaswait __P((MAP *, char *, int)); +extern bool extract_canonname __P((char *, char *, char[])); + +#if defined(O_EXLOCK) && HASFLOCK +# 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 /* ** MAP_PARSEARGS -- parse config line arguments for database lookup ** @@ -141,9 +160,59 @@ map_parseargs(map, ap) 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 '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; +#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++; @@ -152,6 +221,10 @@ map_parseargs(map, ap) } if (map->map_app != NULL) map->map_app = newstr(map->map_app); + 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') { @@ -168,7 +241,8 @@ map_parseargs(map, ap) if (*p != '\0') map->map_rebuild = newstr(p); - if (map->map_file == NULL) + 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); @@ -316,13 +390,14 @@ map_rewrite(map, s, slen, av) ** if ~NDBM: reads the aliases into the symbol table. */ +void initmaps(rebuild, e) bool rebuild; register ENVELOPE *e; { extern void map_init(); -#ifdef XDEBUG +#if XDEBUG checkfd012("entering initmaps"); #endif CurEnv = e; @@ -335,7 +410,7 @@ initmaps(rebuild, e) { stabapply(map_init, 0); } -#ifdef XDEBUG +#if XDEBUG checkfd012("exiting initmaps"); #endif } @@ -356,9 +431,10 @@ map_init(s, rebuild) return; if (tTd(38, 2)) - printf("map_init(%s:%s, %d)\n", + 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, rebuild); @@ -386,23 +462,241 @@ map_init(s, rebuild) if (map->map_class->map_open(map, O_RDONLY)) { if (tTd(38, 4)) - printf("\t%s:%s: valid\n", + 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; } - else if (tTd(38, 4)) - printf("\t%s:%s: invalid: %s\n", - map->map_class->map_cname == NULL ? "NULL" : - map->map_class->map_cname, - map->map_file == NULL ? "NULL" : - map->map_file, - errstring(errno)); + 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; + } + } } } /* +** 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 (stat == EX_NOHOST && !got_tempfail) + h_errno = HOST_NOT_FOUND; + else + h_errno = TRY_AGAIN; +#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. +** +** Returns: +** TRUE -- if the line matched the desired name. +** FALSE -- otherwise. +*/ + +bool +extract_canonname(name, line, cbuf) + char *name; + char *line; + char cbuf[]; +{ + int i; + char *p; + bool found = FALSE; + extern char *get_column(); + + cbuf[0] = '\0'; + if (line[0] == '#') + return FALSE; + + for (i = 1; ; i++) + { + char nbuf[MAXNAME + 1]; + + p = get_column(line, i, '\0', nbuf); + if (p == NULL) + break; + if (cbuf[0] == '\0' || + (strchr(cbuf, '.') == NULL && strchr(p, '.') != NULL)) + strcpy(cbuf, 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 < MAXNAME) + { + p = &cbuf[strlen(cbuf)]; + *p++ = '.'; + strcpy(p, domain); + } + } + return found; +} +/* ** NDBM modules */ @@ -419,40 +713,99 @@ ndbm_map_open(map, mode) { register DBM *dbm; struct stat st; + int fd; if (tTd(38, 2)) - printf("ndbm_map_open(%s, %d)\n", map->map_file, mode); + printf("ndbm_map_open(%s, %s, %d)\n", + map->map_mname, map->map_file, mode); +#if LOCK_ON_OPEN + if (mode == O_RDONLY) + mode |= O_SHLOCK; + else + mode |= O_CREAT|O_TRUNC|O_EXLOCK; +#else if (mode == O_RDWR) + { +# ifdef NOFTRUNCATE + /* + ** Warning: race condition. Try to lock the file as + ** quickly as possible after opening it. + */ + mode |= O_CREAT|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; + char dirfile[MAXNAME + 1]; + char pagfile[MAXNAME + 1]; + + sprintf(dirfile, "%s.dir", map->map_file); + sprintf(pagfile, "%s.pag", map->map_file); + dirfd = open(dirfile, mode|O_CREAT, DBMMODE); + pagfd = open(pagfile, mode|O_CREAT, DBMMODE); + + if (dirfd < 0 || pagfd < 0) + { + syserr("ndbm_map_open: cannot create database %s", + map->map_file); + close(dirfd); + close(pagfd); + return FALSE; + } + if (!lockfile(dirfd, map->map_file, ".dir", LOCK_EX)) + syserr("ndbm_map_open: cannot lock %s.dir", + map->map_file); + if (ftruncate(dirfd, 0) < 0) + syserr("ndbm_map_open: cannot truncate %s.dir", + map->map_file); + if (ftruncate(pagfd, 0) < 0) + syserr("ndbm_map_open: cannot truncate %s.pag", + map->map_file); + + /* we can safely unlock because others will wait for @:@ */ + close(dirfd); + close(pagfd); +# endif + } +#endif /* open the database */ dbm = dbm_open(map->map_file, mode, DBMMODE); if (dbm == NULL) { -#ifdef MAYBENEXTRELEASE - if (aliaswait(map, ".pag", FALSE)) + if (bitset(MF_ALIAS, map->map_mflags) && + aliaswait(map, ".pag", FALSE)) return TRUE; -#endif if (!bitset(MF_OPTIONAL, map->map_mflags)) syserr("Cannot open DBM database %s", map->map_file); return FALSE; } map->map_db1 = (void *) dbm; + fd = dbm_dirfno((DBM *) map->map_db1); if (mode == O_RDONLY) { +#if LOCK_ON_OPEN + if (fd >= 0) + (void) lockfile(fd, map->map_file, ".pag", LOCK_UN); +#endif if (bitset(MF_ALIAS, map->map_mflags) && !aliaswait(map, ".pag", TRUE)) return FALSE; } else { - int fd; - /* exclusive lock for duration of rebuild */ - fd = dbm_dirfno((DBM *) map->map_db1); +#if !LOCK_ON_OPEN if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags) && lockfile(fd, map->map_file, ".dir", LOCK_EX)) +#endif map->map_mflags |= MF_LOCKED; } if (fstat(dbm_dirfno((DBM *) map->map_db1), &st) >= 0) @@ -477,7 +830,8 @@ ndbm_map_lookup(map, name, av, statp) char keybuf[MAXNAME + 1]; if (tTd(38, 20)) - printf("ndbm_map_lookup(%s)\n", name); + printf("ndbm_map_lookup(%s, %s)\n", + map->map_mname, name); key.dptr = name; key.dsize = strlen(name); @@ -532,7 +886,8 @@ ndbm_map_store(map, lhs, rhs) int stat; if (tTd(38, 12)) - printf("ndbm_map_store(%s, %s)\n", lhs, rhs); + printf("ndbm_map_store(%s, %s, %s)\n", + map->map_mname, lhs, rhs); key.dsize = strlen(lhs); key.dptr = lhs; @@ -549,7 +904,33 @@ ndbm_map_store(map, lhs, rhs) stat = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT); if (stat > 0) { - usrerr("050 Warning: duplicate alias name %s", lhs); + if (!bitset(MF_APPEND, map->map_mflags)) + usrerr("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, NULL, &xstat); + if (old.dptr != NULL && *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); + } + sprintf(buf, "%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) @@ -566,7 +947,8 @@ ndbm_map_close(map) register MAP *map; { if (tTd(38, 9)) - printf("ndbm_map_close(%s, %x)\n", map->map_file, map->map_mflags); + printf("ndbm_map_close(%s, %s, %x)\n", + map->map_mname, map->map_file, map->map_mflags); if (bitset(MF_WRITABLE, map->map_mflags)) { @@ -577,11 +959,14 @@ ndbm_map_close(map) inclnull = bitset(MF_INCLNULL, map->map_mflags); map->map_mflags &= ~MF_INCLNULL; - (void) sprintf(buf, "%010ld", curtime()); - ndbm_map_store(map, "YP_LAST_MODIFIED", buf); + if (strstr(map->map_file, "/yp/") != NULL) + { + (void) sprintf(buf, "%010ld", curtime()); + ndbm_map_store(map, "YP_LAST_MODIFIED", buf); - (void) gethostname(buf, sizeof buf); - ndbm_map_store(map, "YP_MASTER_NAME", buf); + (void) gethostname(buf, sizeof buf); + ndbm_map_store(map, "YP_MASTER_NAME", buf); + } if (inclnull) map->map_mflags |= MF_INCLNULL; @@ -617,143 +1002,111 @@ bt_map_open(map, mode) MAP *map; int mode; { - DB *db; - int i; - int omode; - int fd; - struct stat st; - char buf[MAXNAME]; - if (tTd(38, 2)) - printf("bt_map_open(%s, %d)\n", map->map_file, mode); - - omode = mode; - if (omode == O_RDWR) - { - omode |= O_CREAT|O_TRUNC; -#if defined(O_EXLOCK) && HASFLOCK - omode |= O_EXLOCK; -# if !OLD_NEWDB - } - else - { - omode |= O_SHLOCK; -# endif -#endif - } - - (void) strcpy(buf, map->map_file); - i = strlen(buf); - if (i < 3 || strcmp(&buf[i - 3], ".db") != 0) - (void) strcat(buf, ".db"); - db = dbopen(buf, omode, DBMMODE, DB_BTREE, NULL); - if (db == NULL) - { -#ifdef MAYBENEXTRELEASE - if (aliaswait(map, ".db", FALSE)) - return TRUE; -#endif - if (!bitset(MF_OPTIONAL, map->map_mflags)) - syserr("Cannot open BTREE database %s", map->map_file); - return FALSE; - } -#if !OLD_NEWDB && HASFLOCK - fd = db->fd(db); -# if !defined(O_EXLOCK) - if (mode == O_RDWR && fd >= 0) - { - if (lockfile(fd, map->map_file, ".db", LOCK_EX)) - map->map_mflags |= MF_LOCKED; - } -# else - if (mode == O_RDONLY && fd >= 0) - (void) lockfile(fd, map->map_file, ".db", LOCK_UN); - else - map->map_mflags |= MF_LOCKED; -# endif -#endif - - /* try to make sure that at least the database header is on disk */ - if (mode == O_RDWR) -#if OLD_NEWDB - (void) db->sync(db); -#else - (void) db->sync(db, 0); - - if (fd >= 0 && fstat(fd, &st) >= 0) - map->map_mtime = st.st_mtime; -#endif - - map->map_db2 = (void *) db; - if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags)) - if (!aliaswait(map, ".db", TRUE)) - return FALSE; - return TRUE; + printf("bt_map_open(%s, %s, %d)\n", + map->map_mname, map->map_file, mode); + return db_map_open(map, mode, DB_BTREE); } - -/* -** HASH_MAP_INIT -- HASH-style map initialization -*/ - bool hash_map_open(map, mode) MAP *map; int mode; { + if (tTd(38, 2)) + printf("hash_map_open(%s, %s, %d)\n", + map->map_mname, map->map_file, mode); + return db_map_open(map, mode, DB_HASH); +} + +bool +db_map_open(map, mode, dbtype) + MAP *map; + int mode; + DBTYPE dbtype; +{ DB *db; int i; int omode; int fd; + int saveerrno; struct stat st; - char buf[MAXNAME]; + char buf[MAXNAME + 1]; - if (tTd(38, 2)) - printf("hash_map_open(%s, %d)\n", map->map_file, mode); + (void) strcpy(buf, map->map_file); + i = strlen(buf); + if (i < 3 || strcmp(&buf[i - 3], ".db") != 0) + (void) strcat(buf, ".db"); omode = mode; - if (omode == O_RDWR) - { - omode |= O_CREAT|O_TRUNC; -#if defined(O_EXLOCK) && HASFLOCK - omode |= O_EXLOCK; + +#if LOCK_ON_OPEN + if (mode == O_RDWR) + omode |= O_CREAT|O_TRUNC|O_EXLOCK; # if !OLD_NEWDB - } else - { omode |= O_SHLOCK; # endif -#endif +#else + if (mode == O_RDWR) + omode |= O_CREAT; + + /* + ** 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) + { + syserr("db_map_open: cannot pre-open database %s", + buf); + close(fd); + return FALSE; } + if (!lockfile(fd, map->map_file, ".db", + mode == O_RDONLY ? LOCK_SH : LOCK_EX)) + syserr("db_map_open: cannot lock %s", buf); + if (mode == O_RDWR) + omode |= O_TRUNC; +#endif + + db = dbopen(buf, omode, DBMMODE, dbtype, NULL); + saveerrno = errno; + +#if !LOCK_ON_OPEN + /* we can safely unlock now because others will wait for @:@ */ + close(fd); +#endif - (void) strcpy(buf, map->map_file); - i = strlen(buf); - if (i < 3 || strcmp(&buf[i - 3], ".db") != 0) - (void) strcat(buf, ".db"); - db = dbopen(buf, omode, DBMMODE, DB_HASH, NULL); if (db == NULL) { -#ifdef MAYBENEXTRELEASE - if (aliaswait(map, ".db", FALSE)) + if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) && + aliaswait(map, ".db", FALSE)) return TRUE; -#endif + errno = saveerrno; if (!bitset(MF_OPTIONAL, map->map_mflags)) - syserr("Cannot open HASH database %s", map->map_file); + syserr("Cannot open DB database %s", map->map_file); return FALSE; } -#if !OLD_NEWDB && HASFLOCK +#if !OLD_NEWDB fd = db->fd(db); -# if !defined(O_EXLOCK) +# if LOCK_ON_OPEN + if (fd >= 0) + { + if (mode == O_RDONLY) + (void) lockfile(fd, map->map_file, ".db", LOCK_UN); + else + map->map_mflags |= MF_LOCKED; + } +# else if (mode == O_RDWR && fd >= 0) { if (lockfile(fd, map->map_file, ".db", LOCK_EX)) map->map_mflags |= MF_LOCKED; } -# else - if (mode == O_RDONLY && fd >= 0) - (void) lockfile(fd, map->map_file, ".db", LOCK_UN); - else - map->map_mflags |= MF_LOCKED; # endif #endif @@ -769,9 +1122,9 @@ hash_map_open(map, mode) #endif map->map_db2 = (void *) db; - if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags)) - if (!aliaswait(map, ".db", TRUE)) - return FALSE; + if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) && + !aliaswait(map, ".db", TRUE)) + return FALSE; return TRUE; } @@ -795,7 +1148,8 @@ db_map_lookup(map, name, av, statp) char keybuf[MAXNAME + 1]; if (tTd(38, 20)) - printf("db_map_lookup(%s)\n", name); + printf("db_map_lookup(%s, %s)\n", + map->map_mname, name); key.size = strlen(name); if (key.size > sizeof keybuf - 1) @@ -857,8 +1211,9 @@ db_map_store(map, lhs, rhs) DBT data; register DB *db = map->map_db2; - if (tTd(38, 20)) - printf("db_map_store(%s, %s)\n", lhs, rhs); + if (tTd(38, 12)) + printf("db_map_store(%s, %s, %s)\n", + map->map_mname, lhs, rhs); key.size = strlen(lhs); key.data = lhs; @@ -875,7 +1230,32 @@ db_map_store(map, lhs, rhs) stat = db->put(db, &key, &data, R_NOOVERWRITE); if (stat > 0) { - usrerr("050 Warning: duplicate alias name %s", lhs); + if (!bitset(MF_APPEND, map->map_mflags)) + usrerr("050 Warning: duplicate alias name %s", lhs); + else + { + static char *buf = NULL; + static int bufsiz = 0; + DBT old; + + old.data = db_map_lookup(map, key.data, 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); + } + sprintf(buf, "%s,%s", data.data, old.data); + data.size = data.size + old.size + 1; + data.data = buf; + if (tTd(38, 9)) + printf("db_map_store append=%s\n", data.data); + } + } stat = db->put(db, &key, &data, 0); } if (stat != 0) @@ -894,7 +1274,8 @@ db_map_close(map) register DB *db = map->map_db2; if (tTd(38, 9)) - printf("db_map_close(%s, %x)\n", map->map_file, map->map_mflags); + printf("db_map_close(%s, %s, %x)\n", + map->map_mname, map->map_file, map->map_mflags); if (bitset(MF_WRITABLE, map->map_mflags)) { @@ -930,10 +1311,10 @@ nis_map_open(map, mode) register char *p; auto char *vp; auto int vsize; - char *master; if (tTd(38, 2)) - printf("nis_map_open(%s)\n", map->map_file); + printf("nis_map_open(%s, %s, %d)\n", + map->map_mname, map->map_file, mode); if (mode != O_RDONLY) { @@ -967,7 +1348,7 @@ nis_map_open(map, mode) if (yperr != 0) { if (!bitset(MF_OPTIONAL, map->map_mflags)) - syserr("NIS map %s specified, but NIS not running\n", + syserr("421 NIS map %s specified, but NIS not running\n", map->map_file); return FALSE; } @@ -977,14 +1358,29 @@ nis_map_open(map, mode) 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", + 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) - return TRUE; + { + /* + ** 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("Cannot bind to domain %s: %s", map->map_domain, - yperr_string(yperr)); + { + syserr("421 Cannot bind to map %s in domain %s: %s", + map->map_file, map->map_domain, yperr_string(yperr)); + } return FALSE; } @@ -1008,7 +1404,8 @@ nis_map_lookup(map, name, av, statp) char keybuf[MAXNAME + 1]; if (tTd(38, 20)) - printf("nis_map_lookup(%s)\n", name); + printf("nis_map_lookup(%s, %s)\n", + map->map_mname, name); buflen = strlen(name); if (buflen > sizeof keybuf - 1) @@ -1046,31 +1443,1131 @@ nis_map_lookup(map, name, av, statp) /* -** NIS_MAP_STORE +** NIS_GETCANONNAME -- look up canonical name in NIS */ -void -nis_map_store(map, lhs, rhs) +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; + } + 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)) + { + /* 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 */ +#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; - char *lhs; - char *rhs; + int mode; { - /* nothing */ + register char *p; + char qbuf[MAXLINE + NIS_MAXNAMELEN]; + nis_result *res = NULL; + u_int objs_len; + nis_object *obj_ptr; + int retry_cnt, max_col, i; + + if (tTd(38, 2)) + printf("nisplus_map_open(%s, %s, %d)\n", + map->map_mname, map->map_file, mode); + + if (mode != O_RDONLY) + { + errno = ENODEV; + 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(); + + 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(""); + + /* check to see if this map actually exists */ + if (PARTIAL_NAME(map->map_file)) + sprintf(qbuf, "%s.%s", map->map_file, map->map_domain); + else + strcpy(qbuf, map->map_file); + + 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 = EBADR; + 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 = EBADR; + 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 = EBADR; + 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 = EBADR; + 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 = EBADR; + return FALSE; } /* -** NIS_MAP_CLOSE +** NISPLUS_MAP_LOOKUP -- look up a datum in a NISPLUS table */ -void -nis_map_close(map) +char * +nisplus_map_lookup(map, name, av, statp) + MAP *map; + char *name; + char **av; + int *statp; +{ + char *vp; + auto int vsize; + int buflen; + char search_key[MAXNAME + 1]; + 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; + else + { + *statp = EX_UNAVAILABLE; + return NULL; + } + } + + buflen = strlen(name); + if (buflen > sizeof search_key - 1) + buflen = sizeof search_key - 1; + bcopy(name, search_key, buflen + 1); + if (!bitset(MF_NOFOLDCASE, map->map_mflags)) + makelower(search_key); + + /* construct the query */ + if (PARTIAL_NAME(map->map_file)) + sprintf(qbuf, "[%s=%s],%s.%s", map->map_keycolnm, + search_key, map->map_file, map->map_domain); + else + sprintf(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) + syslog(LOG_WARNING, + "%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); + } + + vp = ((NIS_RES_OBJECT(result))->EN_col(map->map_valcolno)); + /* set the length of the result */ + if (vp == NULL) + vp = ""; + vsize = strlen(vp); + if (tTd(38, 20)) + printf("nisplus_map_lookup(%s), found %s\n", + name, vp); + if (bitset(MF_MATCHONLY, map->map_mflags)) + str = map_rewrite(map, name, strlen(name), NULL); + else + str = map_rewrite(map, vp, 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 */ + sprintf(qbuf, "[name=%s],hosts.org_dir", nbuf); + } + else if (p[1] != '\0') + { + /* multi token -- take only first token in nbuf */ + *p = '\0'; + sprintf(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 *str; + char *domain; + + if ((count = NIS_RES_NUMOBJ(result)) != 1) + { +#ifdef LOG + if (LogLevel > 10) + syslog(LOG_WARNING, + "nisplus_getcanonname: lookup error, expected 1 entry, got %d", + count); +#endif + + /* ignore second entry */ + if (tTd(38, 20)) + printf("nisplus_getcanoname(%s), got %d entries, addtional entries ignores\n", name); + } + + 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 + sprintf(name, "%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(); + strcpy(default_domain, p); + return default_domain; +} + +#endif /* NISPLUS */ +/* +** HESIOD Modules +*/ + +#ifdef HESIOD + +#include <hesiod.h> + +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; + } + + 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; +} + +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); + hp = hes_resolve(np, map->map_file); + if (np != nbuf) + free(np); + } + else + { + hp = hes_resolve(name, map->map_file); + } + 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; + } + + 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; +{ + char *p; + + if (tTd(38, 20)) + printf("ni_map_open(%s, %s, %d)\n", + map->map_mname, map->map_file, mode); + + 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; { - /* nothing */ + 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; } -#endif /* NIS */ + +bool +ni_getcanonname(name, hbsize, statp) + char *name; + int hbsize; + int *statp; +{ + char *vptr; + 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", '\0'); + + if (vptr == NULL) + { + *statp = EX_NOHOST; + return FALSE; + } + + 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 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; ++i) + { + if (i == 0) + { + nis = ni_open(NULL, LOCAL_NETINFO_DOMAIN, &ni); + } + else + { + if (lastni != NULL) + ni_free(lastni); + lastni = ni; + nis = ni_open(lastni, PARENT_NETINFO_DOMAIN, &ni); + } + + /* + ** 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; + + /* + ** 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); + + return propval; +} + +#endif +/* +** TEXT (unindexed text file) Modules +** +** This code donated by Sun Microsystems. +*/ + + +/* +** TEXT_MAP_OPEN -- open text table +*/ + +bool +text_map_open(map, mode) + MAP *map; + int mode; +{ + struct stat sbuf; + + if (tTd(38, 2)) + printf("text_map_open(%s, %s, %d)\n", + map->map_mname, map->map_file, mode); + + if (mode != O_RDONLY) + { + errno = ENODEV; + return FALSE; + } + + if (*map->map_file == '\0') + { + if (tTd(38, 2)) + printf("text_map_open(%s): file name required\n", + map->map_mname); + return FALSE; + } + + if (map->map_file[0] != '/') + { + if (tTd(38, 2)) + printf("text_map_open(%s, %s): file name must be fully qualified\n", + map->map_mname, map->map_file); + return FALSE; + } + /* check to see if this map actually accessable */ + if (access(map->map_file, R_OK) <0) + return FALSE; + + /* check to see if this map actually exist */ + if (stat(map->map_file, &sbuf) <0) + { + if (tTd(38, 2)) + printf("text_map_open(%s, %s): cannot stat\n", + map->map_mname, map->map_file); + return FALSE; + } + + if (!S_ISREG(sbuf.st_mode)) + { + if (tTd(38, 2)) + printf("text_map_open(%s): %s is not a regular file\n", + map->map_mname, map->map_file); + return FALSE; + } + + if (map->map_keycolnm == NULL) + map->map_keycolno = 0; + else + { + if (!isdigit(*map->map_keycolnm)) + { + if (tTd(38, 2)) + printf("text_map_open(%s, %s): -k should specify a number, not %s\n", + 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 (!isdigit(*map->map_valcolnm)) + { + if (tTd(38, 2)) + printf("text_map_open(%s, %s): -v should specify a number, not %s\n", + 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); + } + + 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; + char search_key[MAXNAME + 1]; + char linebuf[MAXLINE]; + FILE *f; + char buf[MAXNAME + 1]; + char delim; + int key_idx; + bool found_it; + extern char *get_column(); + + + 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 + 1); + if (!bitset(MF_NOFOLDCASE, map->map_mflags)) + makelower(search_key); + + f = fopen(map->map_file, "r"); + 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); + 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); + 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; +{ + int key_idx; + bool found; + FILE *f; + char linebuf[MAXLINE]; + char cbuf[MAXNAME + 1]; + char fbuf[MAXNAME + 1]; + char nbuf[MAXNAME + 1]; + extern char *get_column(); + + if (tTd(38, 20)) + printf("text_getcanonname(%s)\n", name); + + if (strlen(name) >= 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); + } + fclose(f); + if (!found) + { + *statp = EX_NOHOST; + return FALSE; + } + + if (hbsize >= strlen(cbuf)) + { + strcpy(name, cbuf); + *statp = EX_OK; + return TRUE; + } + *statp = EX_UNAVAILABLE; + return FALSE; +} /* ** STAB (Symbol Table) Modules */ @@ -1090,7 +2587,8 @@ stab_map_lookup(map, name, av, pstat) register STAB *s; if (tTd(38, 20)) - printf("stab_lookup(%s)\n", name); + printf("stab_lookup(%s, %s)\n", + map->map_mname, name); s = stab(name, ST_ALIAS, ST_FIND); if (s != NULL) @@ -1134,7 +2632,8 @@ stab_map_open(map, mode) struct stat st; if (tTd(38, 2)) - printf("stab_map_open(%s)\n", map->map_file); + printf("stab_map_open(%s, %s, %d)\n", + map->map_mname, map->map_file, mode); if (mode != O_RDONLY) { @@ -1145,7 +2644,7 @@ stab_map_open(map, mode) af = fopen(map->map_file, "r"); if (af == NULL) return FALSE; - readaliases(map, af, TRUE); + readaliases(map, af, FALSE, FALSE); if (fstat(fileno(af), &st) >= 0) map->map_mtime = st.st_mtime; @@ -1153,20 +2652,6 @@ stab_map_open(map, mode) return TRUE; } - - -/* -** STAB_MAP_CLOSE -- close symbol table. -** -** Since this is in memory, there is nothing to do. -*/ - -void -stab_map_close(map) - MAP *map; -{ - /* ignore it */ -} /* ** Implicit Modules ** @@ -1186,7 +2671,8 @@ impl_map_lookup(map, name, av, pstat) int *pstat; { if (tTd(38, 20)) - printf("impl_map_lookup(%s)\n", name); + printf("impl_map_lookup(%s, %s)\n", + map->map_mname, name); #ifdef NEWDB if (bitset(MF_IMPL_HASH, map->map_mflags)) @@ -1209,6 +2695,9 @@ impl_map_store(map, lhs, rhs) 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); @@ -1229,25 +2718,16 @@ impl_map_open(map, mode) MAP *map; int mode; { - struct stat stb; - if (tTd(38, 2)) - printf("impl_map_open(%s, %d)\n", map->map_file, mode); - - if (stat(map->map_file, &stb) < 0) - { - /* no alias file at all */ - if (tTd(38, 3)) - printf("no map file\n"); - return FALSE; - } + printf("impl_map_open(%s, %s, %d)\n", + map->map_mname, map->map_file, mode); #ifdef NEWDB map->map_mflags |= MF_IMPL_HASH; if (hash_map_open(map, mode)) { #if defined(NDBM) && defined(NIS) - if (mode == O_RDONLY || access("/var/yp/Makefile", R_OK) != 0) + if (mode == O_RDONLY || strstr(map->map_file, "/yp/") == NULL) #endif return TRUE; } @@ -1284,6 +2764,9 @@ void impl_map_close(map) MAP *map; { + if (tTd(38, 9)) + printf("impl_map_close(%s, %s, %x)\n", + map->map_mname, map->map_file, map->map_mflags); #ifdef NEWDB if (bitset(MF_IMPL_HASH, map->map_mflags)) { @@ -1301,6 +2784,490 @@ impl_map_close(map) #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); + + 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. +*/ + +char * +user_map_lookup(map, key, av, statp) + MAP *map; + char *key; + char **av; + int *statp; +{ + struct passwd *pw; + + if (tTd(38, 20)) + printf("user_map_lookup(%s, %s)\n", + map->map_mname, key); + + pw = sm_getpwnam(key); + 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: + sprintf(buf, "%d", pw->pw_uid); + rwval = buf; + break; + + case 4: + sprintf(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) + { + strcpy(buf, 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"); + } + 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 && tTd(38, 20)) + { + printf("prog_map_lookup(%s): empty answer\n", + map->map_mname); + rval = NULL; + } + if (i > 0) + { + 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); + + 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); + + 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) sprintf(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 */ @@ -1319,6 +3286,17 @@ null_map_close(map) return; } +char * +null_map_lookup(map, key, args, pstat) + MAP *map; + char *key; + char **args; + int *pstat; +{ + *pstat = EX_NOTFOUND; + return NULL; +} + void null_map_store(map, key, val) MAP *map; @@ -1327,3 +3305,26 @@ null_map_store(map, key, 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, +}; diff --git a/usr.sbin/sendmail/src/mci.c b/usr.sbin/sendmail/src/mci.c index 8211a62..ee0da2d 100644 --- a/usr.sbin/sendmail/src/mci.c +++ b/usr.sbin/sendmail/src/mci.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983 Eric P. Allman + * Copyright (c) 1995 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)mci.c 8.14 (Berkeley) 5/15/94"; +static char sccsid[] = "@(#)mci.c 8.22 (Berkeley) 11/18/95"; #endif /* not lint */ #include "sendmail.h" @@ -65,6 +65,8 @@ static char sccsid[] = "@(#)mci.c 8.14 (Berkeley) 5/15/94"; */ MCI **MciCache; /* the open connection cache */ + +extern void mci_uncache __P((MCI **, bool)); /* ** MCI_CACHE -- enter a connection structure into the open connection cache ** @@ -77,6 +79,7 @@ MCI **MciCache; /* the open connection cache */ ** none. */ +void mci_cache(mci) register MCI *mci; { @@ -108,7 +111,7 @@ mci_cache(mci) mci, mci->mci_host, mcislot - MciCache); #ifdef LOG if (tTd(91, 100)) - syslog(LOG_DEBUG, "%s: mci_cache: caching %x (%s) in slot %d", + syslog(LOG_DEBUG, "%s: mci_cache: caching %x (%.100s) in slot %d", CurEnv->e_id ? CurEnv->e_id : "NOQUEUE", mci, mci->mci_host, mcislot - MciCache); #endif @@ -188,6 +191,7 @@ mci_scan(savemci) ** none. */ +void mci_uncache(mcislot, doquit) register MCI **mcislot; bool doquit; @@ -205,11 +209,12 @@ mci_uncache(mcislot, doquit) mci, mci->mci_host, mcislot - MciCache, doquit); #ifdef LOG if (tTd(91, 100)) - syslog(LOG_DEBUG, "%s: mci_uncache: uncaching %x (%s) from slot %d (%d)", + syslog(LOG_DEBUG, "%s: mci_uncache: uncaching %x (%.100s) from slot %d (%d)", CurEnv->e_id ? CurEnv->e_id : "NOQUEUE", mci, mci->mci_host, mcislot - MciCache, doquit); #endif +#ifdef SMTP if (doquit) { message("Closing connection to %s", mci->mci_host); @@ -224,6 +229,7 @@ mci_uncache(mcislot, doquit) #endif } else +#endif { if (mci->mci_in != NULL) xfclose(mci->mci_in, "mci_uncache", "mci_in"); @@ -248,6 +254,7 @@ mci_uncache(mcislot, doquit) ** none. */ +void mci_flush(doquit, allbut) bool doquit; MCI *allbut; @@ -297,6 +304,7 @@ mci_get(host, m) mci->mci_exitstat, mci->mci_errno); } +#ifdef SMTP if (mci->mci_state == MCIS_OPEN) { /* poke the connection to see if it's still alive */ @@ -309,6 +317,7 @@ mci_get(host, m) mci->mci_exitstat = EX_OK; mci->mci_state = MCIS_CLOSED; } +# ifdef DAEMON else { /* get peer host address for logging reasons only */ @@ -318,13 +327,23 @@ mci_get(host, m) (void) getpeername(fileno(mci->mci_in), (struct sockaddr *) &CurHostAddr, &socksize); } +# endif } +#endif +#ifdef MAYBE_NEXT_RELEASE if (mci->mci_state == MCIS_CLOSED) { - /* copy out any mailer flags needed in connection state */ - if (bitnset(M_7BITS, m->m_flags)) - mci->mci_flags |= MCIF_7BIT; + 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; + } } +#endif return mci; } @@ -341,13 +360,14 @@ mci_get(host, m) ** none. */ +void mci_dump(mci, logit) register MCI *mci; bool logit; { register char *p; char *sep; - char buf[1000]; + char buf[4000]; extern char *ctime(); sep = logit ? " " : "\n\t"; @@ -359,7 +379,7 @@ mci_dump(mci, logit) sprintf(p, "NULL"); goto printit; } - sprintf(p, "flags=%o, errno=%d, herrno=%d, exitstat=%d, state=%d, pid=%d,%s", + sprintf(p, "flags=%x, errno=%d, herrno=%d, exitstat=%d, state=%d, pid=%d,%s", mci->mci_flags, mci->mci_errno, mci->mci_herrno, mci->mci_exitstat, mci->mci_state, mci->mci_pid, sep); p += strlen(p); @@ -375,7 +395,7 @@ mci_dump(mci, logit) printit: #ifdef LOG if (logit) - syslog(LOG_DEBUG, "%s", buf); + syslog(LOG_DEBUG, "%.1000s", buf); else #endif printf("%s\n", buf); @@ -391,6 +411,7 @@ printit: ** none. */ +void mci_dump_all(logit) bool logit; { diff --git a/usr.sbin/sendmail/src/mime.c b/usr.sbin/sendmail/src/mime.c new file mode 100644 index 0000000..acbc04c --- /dev/null +++ b/usr.sbin/sendmail/src/mime.c @@ -0,0 +1,866 @@ +/* + * Copyright (c) 1994 Eric P. Allman + * Copyright (c) 1994 + * 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. + */ + +# include "sendmail.h" +# include <string.h> + +#ifndef lint +static char sccsid[] = "@(#)mime.c 8.30 (Berkeley) 10/31/95"; +#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" +}; +/* +** 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; + struct args argv[MAXMIMEARGS]; + char bbuf[128]; + char buf[MAXLINE]; + char pvpbuf[MAXLINE]; + extern u_char MimeTokenTab[256]; + + 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"); + } + 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. + */ + + sprintf(buf, "%.100s/%.100s", type, subtype); + if (wordinclass(buf, 'n') || (cte != NULL && !wordinclass(cte, 'e'))) + flags |= M87F_NO8BIT; + + /* + ** Multipart requires special processing. + ** + ** Do a recursive descent into the message. + */ + + if (strcasecmp(type, "multipart") == 0 && !bitset(M87F_NO8BIT, 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) + { + syserr("mime8to7: Content-Type: %s missing boundary", p); + p = "---"; + } + 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; + } + 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"); + else + { + boundaries[i] = bbuf; + boundaries[i + 1] = NULL; + } + mci->mci_flags |= MCIF_INMIME; + + /* skip the early "comment" prologue */ + putline("", mci); + while (fgets(buf, sizeof buf, e->e_dfp) != NULL) + { + bt = mimeboundary(buf, boundaries); + if (bt != MBT_NOTSEP) + break; + putxline(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; + + sprintf(buf, "--%s", bbuf); + putline(buf, mci); + if (tTd(43, 35)) + printf(" ...%s\n", buf); + collect(e->e_dfp, FALSE, FALSE, &hdr, e); + if (tTd(43, 101)) + putline("+++after collect", mci); + putheader(mci, hdr, e); + if (tTd(43, 101)) + putline("+++after putheader", mci); + bt = mime8to7(mci, hdr, e, boundaries, flags); + } + sprintf(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, 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/* 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, FALSE, &hdr, e); + if (tTd(43, 101)) + putline("+++after collect", mci); + putheader(mci, hdr, e); + 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, 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\n", + sectionhighbits, sectionsize, + cte == NULL ? "[none]" : cte); + } + if (cte != NULL && strcasecmp(cte, "binary") == 0) + sectionsize = sectionhighbits; + linelen = 0; + bp = buf; + if (sectionhighbits == 0) + { + /* no encoding necessary */ + if (cte != NULL) + { + sprintf(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 (sectionsize / 8 < sectionhighbits) + { + /* use base64 encoding */ + int c1, c2; + + putline("Content-Transfer-Encoding: base64", mci); + if (tTd(43, 36)) + printf(" ...Content-Transfer-Encoding: base64\n"); + 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); + + putline("Content-Transfer-Encoding: quoted-printable", mci); + if (tTd(43, 36)) + printf(" ...Content-Transfer-Encoding: quoted-printable\n"); + 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 */ + + if (buflen > 0) + { + buflen--; + return *bp++; + } + bp = buf; + buflen = 0; + c = getc(fp); + 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; + } + } + 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(&buf[1], 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') + { + 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; + + 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 /* MIME */ diff --git a/usr.sbin/sendmail/src/pathnames.h b/usr.sbin/sendmail/src/pathnames.h index a611c0b..a364fba 100644 --- a/usr.sbin/sendmail/src/pathnames.h +++ b/usr.sbin/sendmail/src/pathnames.h @@ -30,11 +30,15 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)pathnames.h 8.2 (Berkeley) 8/20/93 + * @(#)pathnames.h 8.4 (Berkeley) 6/19/95 */ #ifndef _PATH_SENDMAILCF -# define _PATH_SENDMAILCF "/etc/sendmail.cf" +# 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 @@ -44,3 +48,7 @@ # define _PATH_SENDMAILPID "/etc/sendmail.pid" # endif #endif + +#ifndef _PATH_HOSTS +# define _PATH_HOSTS "/etc/hosts" +#endif diff --git a/usr.sbin/sendmail/src/queue.c b/usr.sbin/sendmail/src/queue.c index 1dc56a6..97bf36c 100644 --- a/usr.sbin/sendmail/src/queue.c +++ b/usr.sbin/sendmail/src/queue.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983 Eric P. Allman + * Copyright (c) 1983, 1995 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -36,14 +36,13 @@ #ifndef lint #ifdef QUEUE -static char sccsid[] = "@(#)queue.c 8.41.1.3 (Berkeley) 3/5/95 (with queueing)"; +static char sccsid[] = "@(#)queue.c 8.98 (Berkeley) 11/11/95 (with queueing)"; #else -static char sccsid[] = "@(#)queue.c 8.41.1.3 (Berkeley) 3/5/95 (without queueing)"; +static char sccsid[] = "@(#)queue.c 8.98 (Berkeley) 11/11/95 (without queueing)"; #endif #endif /* not lint */ # include <errno.h> -# include <pwd.h> # include <dirent.h> # ifdef QUEUE @@ -55,6 +54,9 @@ static char sccsid[] = "@(#)queue.c 8.41.1.3 (Berkeley) 3/5/95 (without queueing 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 */ @@ -63,13 +65,17 @@ struct work typedef struct work WORK; WORK *WorkQ; /* queue of things to be done */ + +#define QF_VERSION 1 /* version number of this queue format */ + +#if !defined(NGROUPS_MAX) && defined(NGROUPS) +# define NGROUPS_MAX NGROUPS /* POSIX naming convention */ +#endif /* ** QUEUEUP -- queue a message up for future transmission. ** ** Parameters: ** e -- the envelope to queue up. -** queueall -- if TRUE, queue all addresses, rather than -** just those with the QQUEUEUP flag set. ** announce -- if TRUE, tell when you are queueing up. ** ** Returns: @@ -80,9 +86,9 @@ WORK *WorkQ; /* queue of things to be done */ ** The queue file is left locked. */ -queueup(e, queueall, announce) +void +queueup(e, announce) register ENVELOPE *e; - bool queueall; bool announce; { char *qf; @@ -96,6 +102,7 @@ queueup(e, queueall, announce) MAILER nullmailer; MCI mcibuf; char buf[MAXLINE], tf[MAXLINE]; + extern void printctladdr __P((ADDRESS *, FILE *)); /* ** Create control file. @@ -157,6 +164,18 @@ queueup(e, queueall, announce) if (tTd(40, 1)) printf("\n>>>>> queueing %s%s >>>>>\n", e->e_id, newid ? " (new id)" : ""); + if (tTd(40, 3)) + { + extern void printenvflags(); + + printf(" e_flags="); + printenvflags(e); + } + if (tTd(40, 32)) + { + printf(" sendq="); + printaddr(e->e_sendqueue, TRUE); + } if (tTd(40, 9)) { printf(" tfp="); @@ -172,17 +191,25 @@ queueup(e, queueall, announce) ** If there is no data file yet, create one. */ - if (e->e_df == NULL) + if (!bitset(EF_HAS_DF, e->e_flags)) { register FILE *dfp; - extern putbody(); + char dfname[20]; + struct stat stbuf; - e->e_df = queuename(e, 'd'); - e->e_df = newstr(e->e_df); - fd = open(e->e_df, O_WRONLY|O_CREAT|O_TRUNC, FileMode); + 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", - e->e_df, geteuid()); + 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; @@ -197,16 +224,30 @@ queueup(e, queueall, announce) ** they are required by orderq. */ - /* output message priority */ - fprintf(tfp, "P%ld\n", e->e_msgpriority); + /* output queue version number (must be first!) */ + fprintf(tfp, "V%d\n", QF_VERSION); /* output creation time */ fprintf(tfp, "T%ld\n", e->e_ctime); - /* output type and name of data file */ + /* output last delivery time */ + fprintf(tfp, "K%ld\n", 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) + fprintf(tfp, "I%d/%d/%ld\n", + major(e->e_dfdev), minor(e->e_dfdev), e->e_dfino); + + /* output body type */ if (e->e_bodytype != NULL) fprintf(tfp, "B%s\n", e->e_bodytype); - fprintf(tfp, "D%s\n", e->e_df); /* message from envelope, if it exists */ if (e->e_message != NULL) @@ -218,6 +259,8 @@ queueup(e, queueall, announce) *p++ = 'w'; if (bitset(EF_RESPONSE, e->e_flags)) *p++ = 'r'; + if (bitset(EF_HAS8BIT, e->e_flags)) + *p++ = '8'; *p++ = '\0'; if (buf[0] != '\0') fprintf(tfp, "F%s\n", buf); @@ -231,33 +274,45 @@ queueup(e, queueall, announce) fprintf(tfp, "$_%s\n", denlstring(p, TRUE, FALSE)); /* output name of sender */ - fprintf(tfp, "S%s\n", denlstring(e->e_from.q_paddr, TRUE, FALSE)); + 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 list of error recipients */ - printctladdr(NULL, NULL); - for (q = e->e_errorqueue; q != NULL; q = q->q_next) - { - if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) - { - printctladdr(q, tfp); - fprintf(tfp, "E%s\n", denlstring(q->q_paddr, 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(QQUEUEUP, q->q_flags) || - (queueall && !bitset(QDONTSEND|QBADADDR|QSENT, q->q_flags))) + !bitset(QDONTSEND|QBADADDR|QSENT, q->q_flags)) { printctladdr(q, tfp); - fprintf(tfp, "R%s\n", denlstring(q->q_paddr, TRUE, FALSE)); + 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(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(NULL, NULL, "queued", NULL, e); + logdelivery(q->q_mailer, NULL, "queued", + NULL, (time_t) 0, e); e->e_to = NULL; } if (tTd(40, 1)) @@ -302,7 +357,7 @@ queueup(e, queueall, announce) /* expand macros; if null, don't output header at all */ if (bitset(H_DEFAULT, h->h_flags)) { - (void) expand(h->h_value, buf, &buf[sizeof buf], e); + (void) expand(h->h_value, buf, sizeof buf, e); if (buf[0] == '\0') continue; } @@ -347,8 +402,13 @@ queueup(e, queueall, announce) /* ** Clean up. + ** + ** Write a terminator record -- this is to prevent + ** scurrilous crackers from appending any data. */ + fprintf(tfp, ".\n"); + if (fflush(tfp) < 0 || fsync(fileno(tfp)) < 0 || ferror(tfp)) { if (newid) @@ -362,8 +422,8 @@ queueup(e, queueall, announce) /* rename (locked) tf to be (locked) qf */ qf = queuename(e, 'q'); if (rename(tf, qf) < 0) - syserr("cannot rename(%s, %s), df=%s, uid=%d", - tf, qf, e->e_df, geteuid()); + syserr("cannot rename(%s, %s), uid=%d", + tf, qf, geteuid()); /* close and unlock old (locked) qf */ if (e->e_lockfp != NULL) @@ -378,7 +438,7 @@ queueup(e, queueall, announce) # ifdef LOG /* save log info */ if (LogLevel > 79) - syslog(LOG_DEBUG, "%s: queueup, qf=%s, df=%s\n", e->e_id, qf, e->e_df); + syslog(LOG_DEBUG, "%s: queueup, qf=%s", e->e_id, qf); # endif /* LOG */ if (tTd(40, 1)) @@ -386,6 +446,7 @@ queueup(e, queueall, announce) return; } +void printctladdr(a, tfp) register ADDRESS *a; FILE *tfp; @@ -422,14 +483,13 @@ printctladdr(a, tfp) lastuid = uid; lastctladdr = a; - if (uid == 0 || (pw = getpwuid(uid)) == NULL) + if (uid == 0 || (pw = sm_getpwuid(uid)) == NULL) uname = ""; else uname = pw->pw_name; fprintf(tfp, "C%s:%s\n", uname, denlstring(a->q_paddr, TRUE, FALSE)); } - /* ** RUNQUEUE -- run the jobs in the queue. ** @@ -450,10 +510,13 @@ printctladdr(a, tfp) ENVELOPE QueueEnvelope; /* the queue run envelope */ +void runqueue(forkflag) bool forkflag; { register ENVELOPE *e; + int njobs; + int sequenceno = 0; extern ENVELOPE BlankEnvelope; /* @@ -465,8 +528,14 @@ runqueue(forkflag) if (shouldqueue(0L, curtime())) { + char *msg = "Skipping queue run -- load average too high"; + if (Verbose) - printf("Skipping queue run -- load average too high\n"); + printf("%s\n", msg); +#ifdef LOG + if (LogLevel > 8) + syslog(LOG_INFO, "runqueue: %s", msg); +#endif if (forkflag && QueueIntvl != 0) (void) setevent(QueueIntvl, runqueue, TRUE); return; @@ -479,6 +548,7 @@ runqueue(forkflag) if (forkflag) { int pid; + extern void intsig(); #ifdef SIGCHLD extern void reapchild(); @@ -491,18 +561,21 @@ runqueue(forkflag) /* parent -- pick up intermediate zombie */ #ifndef SIGCHLD (void) waitfor(pid); +#else + CurChildren++; #endif /* SIGCHLD */ if (QueueIntvl != 0) (void) setevent(QueueIntvl, runqueue, TRUE); return; } - /* child -- double fork */ + /* child -- double fork and clean up signals */ #ifndef SIGCHLD if (fork() != 0) exit(EX_OK); #else /* SIGCHLD */ (void) setsignal(SIGCHLD, SIG_DFL); #endif /* SIGCHLD */ + (void) setsignal(SIGHUP, intsig); } setproctitle("running queue: %s", QueueDir); @@ -546,7 +619,7 @@ runqueue(forkflag) */ /* order the existing work requests */ - (void) orderq(FALSE); + njobs = orderq(FALSE); /* process them once at a time */ while (WorkQ != NULL) @@ -559,22 +632,29 @@ runqueue(forkflag) ** Ignore jobs that are too expensive for the moment. */ + sequenceno++; if (shouldqueue(w->w_pri, w->w_ctime)) { if (Verbose) - printf("\nSkipping %s\n", w->w_name + 2); + printf("\nSkipping %s (sequence %d of %d)\n", + w->w_name + 2, sequenceno, njobs); } else { pid_t pid; extern pid_t dowork(); + if (Verbose) + printf("\nRunning %s (sequence %d of %d)\n", + 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); } @@ -604,6 +684,10 @@ runqueue(forkflag) # define NEED_R 004 # define NEED_S 010 +static WORK *WorkList = NULL; +static int WorkListSize = 0; + +int orderq(doall) bool doall; { @@ -611,9 +695,8 @@ orderq(doall) register WORK *w; DIR *f; register int i; - WORK wlist[QUEUESIZE+1]; int wn = -1; - extern workcmpf(); + int wc; if (tTd(41, 1)) { @@ -633,6 +716,8 @@ orderq(doall) WorkQ = nw; free(w->w_name); + if (w->w_host) + free(w->w_host); free((char *) w); w = nw; } @@ -653,9 +738,12 @@ orderq(doall) { FILE *cf; register char *p; - char lbuf[MAXNAME]; + char lbuf[MAXNAME + 1]; extern bool strcontainedin(); + 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; @@ -664,6 +752,7 @@ orderq(doall) !strcontainedin(QueueLimitId, d->d_name)) continue; +#ifdef PICKY_QF_NAME_CHECK /* ** Check queue name for plausibility. This handles ** both old and new type ids. @@ -682,22 +771,38 @@ orderq(doall) { if (Verbose) printf("orderq: bogus qf name %s\n", d->d_name); -#ifdef LOG - if (LogLevel > 3) - syslog(LOG_CRIT, "orderq: bogus qf name %s", +# ifdef LOG + if (LogLevel > 0) + syslog(LOG_ALERT, "orderq: bogus qf name %s", d->d_name); -#endif - if (strlen(d->d_name) >= MAXNAME) - d->d_name[MAXNAME - 1] = '\0'; +# endif + 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 - /* yes -- open control file (if not too many files) */ - if (++wn >= QUEUESIZE) + /* open control file (if not too many files) */ + if (++wn >= MaxQueueRun && MaxQueueRun > 0) + { +# ifdef LOG + if (wn == MaxQueueRun && LogLevel > 0) + syslog(LOG_ALERT, "WorkList for %s maxed out at %d", + QueueDir, MaxQueueRun); +# endif 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) @@ -705,14 +810,17 @@ orderq(doall) /* this may be some random person sending hir msgs */ /* syserr("orderq: cannot open %s", cbuf); */ if (tTd(41, 2)) - printf("orderq: cannot open %s (%d)\n", - d->d_name, errno); + printf("orderq: cannot open %s: %s\n", + d->d_name, errstring(errno)); errno = 0; wn--; continue; } - w = &wlist[wn]; + 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; @@ -722,11 +830,10 @@ orderq(doall) i = NEED_P | NEED_T; if (QueueLimitSender != NULL) i |= NEED_S; - if (QueueLimitRecipient != NULL) + if (QueueSortOrder == QS_BYHOST || QueueLimitRecipient != NULL) i |= NEED_R; while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL) { - extern long atol(); extern bool strcontainedin(); switch (lbuf[0]) @@ -742,7 +849,10 @@ orderq(doall) break; case 'R': - if (QueueLimitRecipient != NULL && + if (w->w_host == NULL && + (p = strrchr(&lbuf[1], '@')) != NULL) + w->w_host = newstr(&p[1]); + if (QueueLimitRecipient == NULL || strcontainedin(QueueLimitRecipient, &lbuf[1])) i &= ~NEED_R; break; @@ -752,6 +862,16 @@ orderq(doall) strcontainedin(QueueLimitSender, &lbuf[1])) i &= ~NEED_S; break; + + case 'K': + if ((curtime() - (time_t) atol(&lbuf[1])) < MinQueueAge) + w->w_tooyoung = TRUE; + break; + + case 'N': + if (atol(&lbuf[1]) == 0) + w->w_tooyoung = FALSE; + break; } } (void) fclose(cf); @@ -760,17 +880,78 @@ orderq(doall) 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++; - /* - ** Sort the work directory. - */ + wc = min(wn, WorkListSize); + if (wc > MaxQueueRun && MaxQueueRun > 0) + wc = MaxQueueRun; + + if (QueueSortOrder == QS_BYHOST) + { + extern workcmpf1(); + extern 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) + { + 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 && + strcmp(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 + { + extern workcmpf0(); + + /* + ** Simple sort based on queue priority only. + */ - qsort((char *) wlist, min(wn, QUEUESIZE), sizeof *wlist, workcmpf); + qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf0); + } /* ** Convert the work list into canonical form. @@ -778,15 +959,21 @@ orderq(doall) */ WorkQ = NULL; - for (i = min(wn, QUEUESIZE); --i >= 0; ) + for (i = wc; --i >= 0; ) { w = (WORK *) xalloc(sizeof *w); - w->w_name = wlist[i].w_name; - w->w_pri = wlist[i].w_pri; - w->w_ctime = wlist[i].w_ctime; + 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; if (tTd(40, 1)) { @@ -797,7 +984,59 @@ orderq(doall) return (wn); } /* -** WORKCMPF -- compare function for ordering work. +** 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; +# ifdef LOG + if (LogLevel > 1) + { + syslog(LOG_NOTICE, "grew WorkList for %s to %d", + QueueDir, WorkListSize); + } + } + else if (LogLevel > 0) + { + syslog(LOG_ALERT, "FAILED to grow WorkList for %s to %d", + QueueDir, newsize); +# endif + } + } + if (tTd(41, 1)) + printf("grow_wlist: WorkListSize now %d\n", WorkListSize); +} +/* +** WORKCMPF0 -- simple priority-only compare function. ** ** Parameters: ** a -- the first argument. @@ -812,7 +1051,8 @@ orderq(doall) ** none. */ -workcmpf(a, b) +int +workcmpf0(a, b) register WORK *a; register WORK *b; { @@ -820,11 +1060,93 @@ workcmpf(a, b) long pb = b->w_pri; if (pa == pb) - return (0); + return 0; else if (pa > pb) - return (1); + return 1; else - return (-1); + 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; + + /* 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 = strcmp(a->w_host, b->w_host))) + 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; + + /* 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 = strcmp(a->w_host, b->w_host))) + return i; + + /* job priority */ + return a->w_pri - b->w_pri; } /* ** DOWORK -- do a work request. @@ -895,6 +1217,7 @@ dowork(id, forkflag, requeueflag, e) (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; @@ -928,7 +1251,7 @@ dowork(id, forkflag, requeueflag, e) eatheader(e, requeueflag); if (requeueflag) - queueup(e, TRUE, FALSE); + queueup(e, FALSE); /* do the delivery */ sendall(e, SM_DELIVER); @@ -964,10 +1287,14 @@ readqf(e) ADDRESS *ctladdr; struct stat st; char *bp; + int qfver = 0; + register char *p; + char *orcpt = NULL; + bool nomore = FALSE; char qf[20]; char buf[MAXLINE]; - extern long atol(); extern ADDRESS *setctluser(); + extern void loseqfile(); /* ** Read and process the file. @@ -988,9 +1315,7 @@ readqf(e) if (!lockfile(fileno(qfp), qf, NULL, LOCK_EX|LOCK_NB)) { /* being processed by another queuer */ - if (tTd(40, 8)) - printf("readqf(%s): locked\n", qf); - if (Verbose) + if (Verbose || tTd(40, 8)) printf("%s: locked\n", e->e_id); # ifdef LOG if (LogLevel > 19) @@ -1014,7 +1339,7 @@ readqf(e) return FALSE; } - if (st.st_uid != geteuid()) + if (st.st_uid != geteuid() || bitset(S_IWOTH|S_IWGRP, st.st_mode)) { # ifdef LOG if (LogLevel > 0) @@ -1025,7 +1350,7 @@ readqf(e) # endif /* LOG */ if (tTd(40, 8)) printf("readqf(%s): bogus file\n", qf); - rename(qf, queuename(e, 'Q')); + loseqfile(e, "bogus file uid in mqueue"); fclose(qfp); return FALSE; } @@ -1059,32 +1384,91 @@ readqf(e) LineNumber = 0; e->e_flags |= EF_GLOBALERRS; OpMode = MD_DELIVER; - if (Verbose) - printf("\nRunning %s\n", e->e_id); ctladdr = NULL; + e->e_dfino = -1; + e->e_msgsize = -1; while ((bp = fgetfolded(buf, sizeof buf, qfp)) != NULL) { register char *p; - struct stat st; + u_long qflags; + ADDRESS *q; 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) + { + syserr("Version number in qf (%d) greater than max (%d)", + qfver, QF_VERSION); + } + break; + case 'C': /* specify controlling user */ ctladdr = setctluser(&bp[1]); break; + case 'Q': /* original recipient */ + orcpt = newstr(&bp[1]); + break; + case 'R': /* specify recipient */ - (void) sendtolist(&bp[1], ctladdr, &e->e_sendqueue, e); + p = bp; + qflags = 0; + if (qfver >= 1) + { + /* get flag bits */ + while (*++p != '\0' && *p != ':') + { + switch (*p) + { + 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; + q->q_flags |= qflags; + q->q_orcpt = orcpt; + (void) recipient(q, &e->e_sendqueue, 0, e); + } + orcpt = NULL; break; case 'E': /* specify error recipient */ - (void) sendtolist(&bp[1], ctladdr, &e->e_errorqueue, e); + /* no longer used */ break; case 'H': /* header */ - (void) chompheader(&bp[1], FALSE, e); + (void) chompheader(&bp[1], FALSE, NULL, e); break; case 'M': /* message */ @@ -1100,26 +1484,39 @@ readqf(e) break; case 'D': /* data file name */ - e->e_df = newstr(&bp[1]); - e->e_dfp = fopen(e->e_df, "r"); - if (e->e_dfp == NULL) - { - syserr("readqf: cannot open %s", e->e_df); - e->e_msgsize = -1; - } - else if (fstat(fileno(e->e_dfp), &st) >= 0) - e->e_msgsize = st.st_size; + /* obsolete -- ignore */ break; case 'T': /* init time */ e->e_ctime = atol(&bp[1]); break; + case 'I': /* data file's inode number */ + if (e->e_dfino == -1) + e->e_dfino = atol(&buf[1]); + 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]); + 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) @@ -1131,22 +1528,31 @@ readqf(e) case 'r': /* response */ e->e_flags |= EF_RESPONSE; break; + + case '8': /* has 8 bit data */ + e->e_flags |= EF_HAS8BIT; + break; } } break; + case 'Z': /* original envelope id from ESMTP */ + e->e_envid = newstr(&bp[1]); + break; + case '$': /* define macro */ define(bp[1], newstr(&bp[2]), e); break; - case '\0': /* blank line; ignore */ + case '.': /* terminate file */ + nomore = TRUE; break; default: syserr("readqf: %s: line %d: bad line \"%s\"", qf, LineNumber, bp); fclose(qfp); - rename(qf, queuename(e, 'Q')); + loseqfile(e, "unrecognized line"); return FALSE; } @@ -1163,7 +1569,49 @@ readqf(e) { errno = 0; e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE; + return TRUE; + } + + /* if this has been tried recently, let it be */ + if (e->e_ntries > 0 && (curtime() - e->e_dtime) < MinQueueAge) + { + char *howlong = pintvl(curtime() - e->e_dtime, TRUE); + extern void unlockqueue(); + + if (Verbose || tTd(40, 8)) + printf("%s: too young (%s)\n", + e->e_id, howlong); +#ifdef LOG + if (LogLevel > 19) + syslog(LOG_DEBUG, "%s: too young (%s)", + e->e_id, howlong); +#endif + e->e_id = NULL; + unlockqueue(e); + return FALSE; + } + + /* + ** 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; + e->e_dfdev = st.st_dev; + e->e_dfino = st.st_ino; + } } + return TRUE; } /* @@ -1179,6 +1627,7 @@ readqf(e) ** Prints a listing of the mail queue on the standard output. */ +void printqueue() { register WORK *w; @@ -1193,9 +1642,9 @@ printqueue() if (bitset(PRIV_RESTRICTMAILQ, PrivacyFlags) && RealUid != 0) { struct stat st; -# ifdef NGROUPS +# ifdef NGROUPS_MAX int n; - GIDSET_T gidset[NGROUPS]; + GIDSET_T gidset[NGROUPS_MAX]; # endif if (stat(QueueDir, &st) < 0) @@ -1203,14 +1652,14 @@ printqueue() syserr("Cannot stat %s", QueueDir); return; } -# ifdef NGROUPS - n = getgroups(NGROUPS, gidset); +# ifdef NGROUPS_MAX + n = getgroups(NGROUPS_MAX, gidset); while (--n >= 0) { if (gidset[n] == st.st_gid) break; } - if (n < 0) + if (n < 0 && RealGid != st.st_gid) # else if (RealGid != st.st_gid) # endif @@ -1241,8 +1690,8 @@ printqueue() CurrentLA = getla(); /* get load average */ printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s"); - if (nrequests > QUEUESIZE) - printf(", only %d printed", QUEUESIZE); + if (nrequests > WorkListSize) + printf(", only %d printed", WorkListSize); if (Verbose) printf(")\n--Q-ID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n"); else @@ -1251,10 +1700,11 @@ printqueue() { struct stat st; auto time_t submittime = 0; - long dfsize = -1; + long dfsize; int flags = 0; - char message[MAXLINE]; - char bodytype[MAXNAME]; + int qfver; + char statmsg[MAXLINE]; + char bodytype[MAXNAME + 1]; printf("%8s", w->w_name + 2); f = fopen(w->w_name, "r"); @@ -1264,15 +1714,23 @@ printqueue() errno = 0; continue; } - if (!lockfile(fileno(f), w->w_name, NULL, LOCK_SH|LOCK_NB)) + 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; - message[0] = bodytype[0] = '\0'; + statmsg[0] = bodytype[0] = '\0'; + qfver = 0; while (fgets(buf, sizeof buf, f) != NULL) { register int i; @@ -1281,11 +1739,15 @@ printqueue() 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 message) - i = sizeof message - 1; - bcopy(&buf[1], message, i); - message[i] = '\0'; + if ((i = strlen(&buf[1])) >= sizeof statmsg) + i = sizeof statmsg - 1; + bcopy(&buf[1], statmsg, i); + statmsg[i] = '\0'; break; case 'B': /* body type */ @@ -1306,11 +1768,11 @@ printqueue() else printf("%8ld %.16s %.45s", dfsize, ctime(&submittime), &buf[1]); - if (message[0] != '\0' || bodytype[0] != '\0') + if (statmsg[0] != '\0' || bodytype[0] != '\0') { printf("\n %10.10s", bodytype); - if (message[0] != '\0') - printf(" (%.60s)", message); + if (statmsg[0] != '\0') + printf(" (%.60s)", statmsg); } break; @@ -1321,21 +1783,24 @@ printqueue() 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 %.38s", &buf[1]); + printf("\n\t\t\t\t\t %.38s", p); else - printf("\n\t\t\t\t %.45s", &buf[1]); + printf("\n\t\t\t\t %.45s", p); break; case 'T': /* creation time */ submittime = atol(&buf[1]); break; - case 'D': /* data file name */ - if (stat(&buf[1], &st) >= 0) - dfsize = st.st_size; - break; - case 'F': /* flag bits */ for (p = &buf[1]; *p != '\0'; p++) { @@ -1388,7 +1853,7 @@ queuename(e, type) static char c2; time_t now; struct tm *tm; - static char buf[MAXNAME]; + static char buf[MAXNAME + 1]; if (e->e_id == NULL) { @@ -1480,6 +1945,7 @@ queuename(e, type) ** unlocks the queue for `e'. */ +void unlockqueue(e) ENVELOPE *e; { @@ -1545,7 +2011,7 @@ setctluser(user) p = strchr(user, ':'); if (p != NULL) *p++ = '\0'; - if (*user != '\0' && (pw = getpwnam(user)) != NULL) + if (*user != '\0' && (pw = sm_getpwnam(user)) != NULL) { if (strcmp(pw->pw_dir, "/") == 0) a->q_home = ""; @@ -1553,13 +2019,15 @@ setctluser(user) a->q_home = newstr(pw->pw_dir); a->q_uid = pw->pw_uid; a->q_gid = pw->pw_gid; - a->q_user = newstr(user); a->q_flags |= QGOODUID; } + + if (*user != '\0') + a->q_user = newstr(user); + else if (p != NULL) + a->q_user = newstr(p); else - { a->q_user = newstr(DefUser); - } a->q_flags |= QPRIMARY; /* flag as a "ctladdr" */ a->q_mailer = LocalMailer; @@ -1569,3 +2037,35 @@ setctluser(user) 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[40]; + + if (e == NULL || e->e_id == NULL) + return; + if (strlen(e->e_id) > sizeof buf - 4) + return; + strcpy(buf, queuename(e, 'q')); + p = queuename(e, 'Q'); + if (rename(buf, p) < 0) + syserr("cannot rename(%s, %s), uid=%d", buf, p, geteuid()); +#ifdef LOG + else if (LogLevel > 0) + syslog(LOG_ALERT, "Losing %s: %s", buf, why); +#endif +} diff --git a/usr.sbin/sendmail/src/sendmail.hf b/usr.sbin/sendmail/src/sendmail.hf index 142a7f5..14db22c 100644 --- a/usr.sbin/sendmail/src/sendmail.hf +++ b/usr.sbin/sendmail/src/sendmail.hf @@ -1,9 +1,9 @@ cpyr -cpyr Copyright (c) 1983 Eric P. Allman +cpyr Copyright (c) 1983, 1995 Eric P. Allman cpyr Copyright (c) 1988, 1993 cpyr The Regents of the University of California. All rights reserved. cpyr -cpyr @(#)sendmail.hf 8.2 (Berkeley) 7/16/93 +cpyr @(#)sendmail.hf 8.7 (Berkeley) 10/1/95 cpyr smtp Commands: smtp HELO EHLO MAIL RCPT DATA @@ -11,7 +11,7 @@ smtp RSET NOOP QUIT HELP VRFY smtp EXPN VERB smtp For more info use "HELP <topic>". smtp To report bugs in the implementation send email to -smtp sendmail@CS.Berkeley.EDU. +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. @@ -32,7 +32,7 @@ quit QUIT quit Exit sendmail (SMTP). verb VERB verb Go into verbose mode. This sends 0xy responses that are -verb are not RFC821 standard (but should be) They are recognized +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 @@ -56,3 +56,23 @@ saml implementation. turn TURN turn Reverses the direction of the connection. Not currently turn implemented. +-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'. diff --git a/usr.sbin/sendmail/src/stab.c b/usr.sbin/sendmail/src/stab.c index 07893e5..cfb02c6 100644 --- a/usr.sbin/sendmail/src/stab.c +++ b/usr.sbin/sendmail/src/stab.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983 Eric P. Allman + * Copyright (c) 1983, 1995 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)stab.c 8.1 (Berkeley) 6/7/93"; +static char sccsid[] = "@(#)stab.c 8.6 (Berkeley) 8/31/95"; #endif /* not lint */ # include "sendmail.h" @@ -57,7 +57,7 @@ static char sccsid[] = "@(#)stab.c 8.1 (Berkeley) 6/7/93"; ** can update the symbol table. */ -# define STABSIZE 400 +# define STABSIZE 2003 static STAB *SymTab[STABSIZE]; @@ -78,20 +78,28 @@ stab(name, type, op) /* ** Compute the hashing function - ** - ** We could probably do better.... */ hfunc = type; for (p = name; *p != '\0'; p++) - hfunc = (((hfunc << 7) | lower(*p)) & 077777) % STABSIZE; + hfunc = ((hfunc << 1) ^ (lower(*p) & 0377)) % STABSIZE; if (tTd(36, 9)) printf("(hfunc=%d) ", hfunc); ps = &SymTab[hfunc]; - while ((s = *ps) != NULL && (strcasecmp(name, s->s_name) || s->s_type != type)) - ps = &s->s_next; + 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. @@ -125,7 +133,6 @@ stab(name, type, op) s = (STAB *) xalloc(sizeof *s); bzero((char *) s, sizeof *s); s->s_name = newstr(name); - makelower(s->s_name); s->s_type = type; /* link it in */ @@ -157,7 +164,7 @@ stabapply(func, arg) { for (s = *shead; s != NULL; s = s->s_next) { - if (tTd(38, 90)) + if (tTd(36, 90)) printf("stabapply: trying %d/%s\n", s->s_type, s->s_name); func(s, arg); diff --git a/usr.sbin/sendmail/src/stats.c b/usr.sbin/sendmail/src/stats.c index 2dc6827..f59885a 100644 --- a/usr.sbin/sendmail/src/stats.c +++ b/usr.sbin/sendmail/src/stats.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983 Eric P. Allman + * Copyright (c) 1983, 1995 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)stats.c 8.3 (Berkeley) 8/28/93"; +static char sccsid[] = "@(#)stats.c 8.5 (Berkeley) 5/28/95"; #endif /* not lint */ # include "sendmail.h" @@ -49,6 +49,7 @@ bool GotStats = FALSE; /* set when we have stats to merge */ ** MARKSTATS -- mark statistics */ +void markstats(e, to) register ENVELOPE *e; register ADDRESS *to; @@ -82,6 +83,7 @@ markstats(e, to) ** merges the Stat structure with the sfile file. */ +void poststats(sfile) char *sfile; { diff --git a/usr.sbin/sendmail/src/sysexits.c b/usr.sbin/sendmail/src/sysexits.c index fff3783..ad4f1e1 100644 --- a/usr.sbin/sendmail/src/sysexits.c +++ b/usr.sbin/sendmail/src/sysexits.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983 Eric P. Allman + * Copyright (c) 1983, 1995 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,10 +33,10 @@ */ #ifndef lint -static char sccsid[] = "@(#)sysexits.c 8.1 (Berkeley) 6/7/93"; +static char sccsid[] = "@(#)sysexits.c 8.5 (Berkeley) 5/24/95"; #endif /* not lint */ -#include <sysexits.h> +#include <sendmail.h> /* ** SYSEXITS.C -- error messages corresponding to sysexits.h @@ -65,3 +65,120 @@ char *SysExMsg[] = }; 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/usr.sbin/sendmail/src/sysexits.h b/usr.sbin/sendmail/src/sysexits.h new file mode 100644 index 0000000..464cb11 --- /dev/null +++ b/usr.sbin/sendmail/src/sysexits.h @@ -0,0 +1,118 @@ +/* + * 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/usr.sbin/sendmail/src/trace.c b/usr.sbin/sendmail/src/trace.c index 29421ee..9762cab 100644 --- a/usr.sbin/sendmail/src/trace.c +++ b/usr.sbin/sendmail/src/trace.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983 Eric P. Allman + * Copyright (c) 1983, 1995 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)trace.c 8.2 (Berkeley) 3/14/94"; +static char sccsid[] = "@(#)trace.c 8.4 (Berkeley) 5/28/95"; #endif /* not lint */ # include "sendmail.h" @@ -57,6 +57,7 @@ u_char *tTvect; int tTsize; static char *DefFlags; +void tTsetup(vect, size, defflags) u_char *vect; int size; @@ -79,6 +80,7 @@ tTsetup(vect, size, defflags) ** sets/clears trace flags. */ +void tTflag(s) register char *s; { diff --git a/usr.sbin/sendmail/src/useful.h b/usr.sbin/sendmail/src/useful.h index ba33a79..8f9009e 100644 --- a/usr.sbin/sendmail/src/useful.h +++ b/usr.sbin/sendmail/src/useful.h @@ -1,4 +1,5 @@ /* + * Copyright (c) 1995 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -30,13 +31,13 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)useful.h 8.2 (Berkeley) 9/24/93 + * @(#)useful.h 8.4 (Berkeley) 4/21/95 */ # include <sys/types.h> /* support for bool type */ -typedef char bool; +typedef int bool; # define TRUE 1 # define FALSE 0 diff --git a/usr.sbin/sendmail/src/version.c b/usr.sbin/sendmail/src/version.c index ad4dd52..2d51c38 100644 --- a/usr.sbin/sendmail/src/version.c +++ b/usr.sbin/sendmail/src/version.c @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)version.c 8.6.12.1 (Berkeley) 3/28/95"; +static char sccsid[] = "@(#)version.c 8.7.2.2 (Berkeley) 11/20/95"; #endif /* not lint */ -char Version[] = "8.6.12"; +char Version[] = "8.7.2"; |