diff options
183 files changed, 14736 insertions, 76 deletions
@@ -4,7 +4,6 @@ *.in *.out *.log -*~ .#* .deps m4 @@ -26,6 +25,8 @@ stamp-h1 ylwrap tags obj + +#Other VCS files CVS/ smtpd/CVS smtpd/smtpctl/CVS @@ -34,3 +35,7 @@ smtpd/mail/CVS smtpd/mail/CVS smtpd/mail/*/CVS smtpd/smtpctl/CVS/* + +#Editor temporary files +*~ +.idea diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..a2467dba --- /dev/null +++ b/Dockerfile @@ -0,0 +1,66 @@ +FROM alpine:3.9 as build + +WORKDIR /opensmtpd + +# libressl is used for testing only +RUN apk add --no-cache \ + ca-certificates \ + automake \ + autoconf \ + libtool \ + gcc \ + make \ + musl-dev \ + bison \ + libevent-dev \ + libtool \ + libasr-dev \ + fts-dev \ + zlib-dev \ + libressl-dev \ + libressl + +#For testing +RUN mkdir -p /var/lib/opensmtpd/empty/ && \ + adduser _smtpd -h /var/lib/opensmtpd/empty/ -D -H -s /bin/false && \ + adduser _smtpq -h /var/lib/opensmtpd/empty/ -D -H -s /bin/false && \ + mkdir -p /var/spool/smtpd && \ + chmod 711 /var/spool/smtpd + +COPY . /opensmtpd + +#build opensmtpd +RUN rm -r /usr/local/ +RUN ./bootstrap && \ + ./configure --with-gnu-ld --sysconfdir=/etc/mail --with-path-empty=/var/lib/opensmtpd/empty/ && \ + make && \ + make install + +FROM alpine:3.9 +LABEL maintainer="Arthur Moore <Arthur.Moore.git@cd-net.net>" + +EXPOSE 25 +EXPOSE 465 +EXPOSE 587 + +VOLUME /etc/mail +VOLUME /var/spool/smtpd +WORKDIR /var/spool/smtpd + +ENTRYPOINT ["smtpd", "-d"] +CMD ["-P", "mda"] + +RUN apk add --no-cache libressl libevent libasr fts zlib ca-certificates && \ + mkdir -p /var/lib/opensmtpd/empty/ && \ + adduser _smtpd -h /var/lib/opensmtpd/empty/ -D -H -s /bin/false && \ + adduser _smtpq -h /var/lib/opensmtpd/empty/ -D -H -s /bin/false && \ + mkdir -p /etc/mail/ && \ + mkdir -p /var/spool/smtpd && \ + chmod 711 /var/spool/smtpd + +COPY --from=build /usr/local/ /usr/local/ + +COPY smtpd/smtpd.conf /etc/mail + +#OpenSMTPD needs root permissions to open port 25. +#It immediately changes to running as _smtpd after that. diff --git a/INSTALL b/INSTALL new file mode 100644 index 00000000..d3c5b40a --- /dev/null +++ b/INSTALL @@ -0,0 +1,237 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, +2006, 2007 Free Software Foundation, Inc. + +This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + +Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. + + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + 6. Often, you can also type `make uninstall' to remove the installed + files again. + +Compilers and Options +===================== + +Some systems require unusual options for compilation or linking that the +`configure' script does not know about. Run `./configure --help' for +details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + +You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + +Installation Names +================== + +By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + +Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + +There may be some features `configure' cannot figure out automatically, +but needs to determine by the type of machine the package will run on. +Usually, assuming the package is built to be run on the _same_ +architectures, `configure' can figure that out, but if it prints a +message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + +If you want to set default values for `configure' scripts to share, you +can create a site shell script called `config.site' that gives default +values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + +Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf bug. Until the bug is fixed you can use this workaround: + + CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + +`configure' recognizes the following options to control how it operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..f1cea087 --- /dev/null +++ b/LICENSE @@ -0,0 +1,342 @@ +This file is part of the OpenSMTPD software. + +The licences which components of this software fall under are as +follows. First, we will summarize and say that all components +are under a BSD licence, or a licence more free than that. + +OpenSMTPD contains no GPL code. + +Portable OpenSMTPD is divided in 4 parts: +- Original OpenSMTPD +- mail.local +- openbsd-compat +- smtpctl encrypt sub command + + + +OpenSMTPD +========= + + +1) Almost all code is licensed under an ISC-style license, to the following + copyright holders: + + Gilles Chehade + Eric Faurot + Jacek Masiulaniec + Pierre-Yves Ritschard + Henning Brauer + Esben Norby + Markus Friedl + Daniel Hartmeier + Theo de Raadt + Claudio Jeker + Reyk Floeter + Janne Johansson + Alexander Schrijver + Marc Balmer + Ashish Shukla + Ryan Kavanagh + Charles Longeau + + +2) ssl_privsep.c + + /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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 cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + + /* + * SSL operations needed when running in a privilege separated environment. + * Adapted from openssl's ssl_rsa.c by Pierre-Yves Ritschard . + */ + + + +mail.local +========== + + +1) mail.local is covered by a 3-clause BSD license, to the following + copyright holders: + + The Regents of the University of California. + David Mazieres + Theo de Raadt + + * 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. 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. + + + +openbsd-compat +============== + + +Most of the OpenBSD compatibility layer is based on the work by Damien Miller for +Portable OpenSSH. + +1) Almost all code is licensed under an ISC-style license, to the following + copyright holders: + + Internet Software Consortium. + David Mazieres + Damien Miller + Markus Friedl + Todd C. Miller + Henning Brauer + Pierre-Yves Ritschard + Reyk Floeter + Theo de Raadt + Ted Unangst + Charles Longeau + + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +2) base64.{c,h} in addition to beeing covered by an ISC-style licence, is also + covered by this one: + + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + + +3) Portable OpenSMTPD includes code under the 2-clause BSD license, from the + following copyright holders: + + Ben Lindstrom + Damien Miller + Marc Espie + Tim Rice + The NetBSD Foundation, Inc. + Jason R. Thorpe? + Niels Provos + + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + + +4) Some code is under a 3-clause BSD license, from the + following copyright holders: + + The Regents of the University of California. + Ian F. Darwin + Damien Miller + Eric P. Allman + + * 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. 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. + + +5) Some code is under a 4-clause BSD license, from the + following copyright holder: + + Christos Zoulas + + * 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 Christos Zoulas. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + + +6) includes.h, log.h, setresguid.c, xmalloc.c, xmalloc.c + + * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + * All rights reserved + * + * As far as I am concerned, the code I have written for this software + * can be used freely for any purpose. Any derived versions of this + * software must be clearly marked as such, and if the derived work is + * incompatible with the protocol description in the RFC file, it must be + * called by a name other than "ssh" or "Secure Shell". + + +7) chacha_private.h + +D. J. Bernstein +Public domain. + + +8) bootstrap (only there in the git repository) + + # Copyright (c) 2002-2011 Sam Hocevar <sam@hocevar.net> + # + # This program is free software. It comes without any warranty, to + # the extent permitted by applicable law. You can redistribute it + # and/or modify it under the terms of the Do What The Fuck You Want + # To Public License, Version 2, as published by Sam Hocevar. See + # http://sam.zoy.org/wtfpl/COPYING for more details. + + + +smtpctl encrypt sub command +=========================== + + +smtpctl encrypt sub command is licensed under an ISC-style license, to the +following copyright holders: + + Sunil Nimmagadda + Gilles Chehade diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 00000000..7d95a5b8 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = openbsd-compat mk contrib + +ACLOCAL_AMFLAGS = -I m4 @@ -42,7 +42,7 @@ Portable OpenSMTPD relies on: or byacc (http://invisible-island.net/byacc/byacc.html) * libevent (http://libevent.org/) * libtool (http://www.gnu.org/software/libtool/) - * openssl (http://www.openssl.org/) + * libressl (https://www.libressl.org/) * libasr (https://opensmtpd.org/archives/libasr-1.0.2.tar.gz) @@ -81,11 +81,46 @@ Install sudo make install +Setup historical interface +------- + +OpenSMTPD provides a single utility `smtpctl` to control the daemon and +the local submission subsystem. + +To accomodate systems that require historical interfaces such as `sendmail`, +`newaliases` or `makemap`, the `smtpctl` utility can operate in compatibility +mode if called with the historical name. + +On mailwrapper-enabled systems, this is achieved by editing /etc/mailer.conf +and adding the following lines: + + sendmail /usr/sbin/smtpctl + send-mail /usr/sbin/smtpctl + mailq /usr/sbin/smtpctl + makemap /usr/sbin/smtpctl + newaliases /usr/sbin/smtpctl + + +Whereas on systems that don't provide mailwrapper, it can be achieved by +setting the appropriate symbolic links: + + ln -s /usr/sbin/smtpctl sendmail + ln -s /usr/sbin/smtpctl send-mail + ln -s /usr/sbin/smtpctl mailq + ln -s /usr/sbin/smtpctl makemap + ln -s /usr/sbin/smtpctl newaliases + + +The OpenSMTPD project leaves it up to the package maintainers to setup the +links in their packages as it is very hard for us to accomodate all systems +with the prefered method in a clean way. + + Configure /etc/smtpd.conf ------------------------- Please have a look at the complete format description of smtpd.conf -configuration file (http://opensmtpd.org/smtpd.conf.5.html) +configuration file (https://man.openbsd.org/smtpd.conf) Add OpenSMTPD users @@ -160,3 +195,20 @@ Then: or in debug and verbose mode smtpd -dv + +# Docker version + +OpenSMTPD provides a convenient docker file for getting started quickly. However, there are a few minor quirks to know about. + +For ease of use, all configuration files live in '/etc/mail'. This means the two files to modify are: + + /etc/mail/smtpd.conf + /etc/mail/mailname + +Also, local deliveries are disabled by default. The nature of Docker makes interacting with local users a bit tricky, and requires a user to know the ins and outs of Docker. + + +To run the Docker version, create a '/etc/mail' directory, and add your own smtpd.conf file there. Next, run: +``` +docker run --name smtpd_server -p 25:25 -v /etc/mail:/etc/mail emperorarthur/opensmtpd +``` diff --git a/bootstrap b/bootstrap new file mode 100755 index 00000000..24e29440 --- /dev/null +++ b/bootstrap @@ -0,0 +1,151 @@ +#! /bin/sh + +# bootstrap: generic bootstrap/autogen.sh script for autotools projects +# +# Copyright (c) 2002-2011 Sam Hocevar <sam@hocevar.net> +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. +# +# The latest version of this script can be found at the following place: +# http://caca.zoy.org/wiki/build + +# Die if an error occurs +set -e + +# Guess whether we are using configure.ac or configure.in +if test -f configure.ac; then + conffile="configure.ac" +elif test -f configure.in; then + conffile="configure.in" +else + echo "$0: could not find configure.ac or configure.in" + exit 1 +fi + +# Check for needed features +auxdir="`sed -ne 's/^[ \t]*A._CONFIG_AUX_DIR *([[ ]*\([^] )]*\).*/\1/p' $conffile`" +pkgconfig="`grep '^[ \t]*PKG_PROG_PKG_CONFIG' $conffile >/dev/null 2>&1 && echo yes || echo no`" +libtool="`grep '^[ \t]*A._PROG_LIBTOOL' $conffile >/dev/null 2>&1 && echo yes || echo no`" +header="`grep '^[ \t]*A._CONFIG_HEADER' $conffile >/dev/null 2>&1 && echo yes || echo no`" +makefile="`[ -f Makefile.am ] && echo yes || echo no`" +aclocalflags="`sed -ne 's/^[ \t]*ACLOCAL_AMFLAGS[ \t]*=//p' Makefile.am 2>/dev/null || :`" + +# Check for automake +amvers="no" +for v in 16.1 16 15 14 13; do + if automake-1.${v} --version >/dev/null 2>&1; then + amvers="-1.${v}" + break + elif automake1.${v} --version >/dev/null 2>&1; then + amvers="1.${v}" + break + fi +done + +if test "${amvers}" = "no" && automake --version > /dev/null 2>&1; then + amvers="`automake --version | sed -e '1s/[^0-9]*//' -e q`" + if `echo "$amvers\n1.14" | sort -V | head -n 1 | grep -q "$amvers"`; then + amvers="no" + else + amvers="" + fi +fi + +if test "$amvers" = "no"; then + echo "$0: you need automake version 1.14 or later" + exit 1 +fi + +# Check for autoconf +acvers="no" +for v in "" "269" "-2.69"; do + if autoconf${v} --version >/dev/null 2>&1; then + acvers="${v}" + break + fi +done + +if test "$acvers" = "no"; then + echo "$0: you need autoconf" + exit 1 +fi + +# Check for libtool +if test "$libtool" = "yes"; then + libtoolize="no" + if glibtoolize --version >/dev/null 2>&1; then + libtoolize="glibtoolize" + else + for v in "16" "15" "" "14"; do + if libtoolize${v} --version >/dev/null 2>&1; then + libtoolize="libtoolize${v}" + break + fi + done + fi + + if test "$libtoolize" = "no"; then + echo "$0: you need libtool" + exit 1 + fi +fi + +# Check for pkg-config +if test "$pkgconfig" = "yes"; then + if ! pkg-config --version >/dev/null 2>&1; then + echo "$0: you need pkg-config" + exit 1 + fi +fi + +# Remove old cruft +for x in aclocal.m4 configure config.guess config.log config.sub config.cache config.h.in config.h compile libtool.m4 ltoptions.m4 ltsugar.m4 ltversion.m4 ltmain.sh libtool ltconfig missing mkinstalldirs depcomp install-sh; do rm -f $x autotools/$x; if test -n "$auxdir"; then rm -f "$auxdir/$x"; fi; done +rm -Rf autom4te.cache +if test -n "$auxdir"; then + if test ! -d "$auxdir"; then + mkdir "$auxdir" + fi + aclocalflags="${aclocalflags} -I $auxdir -I ." +fi + +# Honour M4PATH because sometimes M4 doesn't +save_IFS=$IFS +IFS=: +tmp="$M4PATH" +for x in $tmp; do + if test -n "$x"; then + aclocalflags="${aclocalflags} -I $x" + fi +done +IFS=$save_IFS + +# Explain what we are doing from now +set -x + +# Bootstrap package +if test "$libtool" = "yes"; then + ${libtoolize} --copy --force + if test -n "$auxdir" -a ! "$auxdir" = "." -a -f "ltmain.sh"; then + echo "$0: working around a minor libtool issue" + mv ltmain.sh "$auxdir/" + fi +fi + +aclocal${amvers} ${aclocalflags} +autoconf${acvers} +if test "$header" = "yes"; then + autoheader${acvers} +fi +if test "$makefile" = "yes"; then + #add --include-deps if you want to bootstrap with any other compiler than gcc + #automake${amvers} --add-missing --copy --include-deps + automake${amvers} --foreign --add-missing --copy +fi + +# Remove cruft that we no longer want +rm -Rf autom4te.cache + diff --git a/configure.ac b/configure.ac new file mode 100644 index 00000000..7856318d --- /dev/null +++ b/configure.ac @@ -0,0 +1,2067 @@ +# $Id: configure.ac,v 1.519 2013/03/22 01:49:15 dtucker Exp $ +# +# Copyright (c) 2016 Gilles Chehade <gilles@poolp.org> +# Copyright (c) 1999-2004 Damien Miller +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +# +# WE NEED TO CLEANUP CONFIGURE.AC AND MAKE IT FOLLOW THE +# STANDARD LAYOUT ... +# +# 3.1.3 Standard configure.ac Layout +# +# https://www.gnu.org/software/autoconf/manual/autoconf-2.69/html_node/Autoconf-Input-Layout.html +# + + +# +# AUTOCONF REQUIREMENTS +# +AC_PREREQ(2.69) + + +# +# AC_INIT +# +AC_INIT([OpenSMTPD], + [portable], + [bugs@opensmtpd.org], + [opensmtpd], + [https://www.OpenSMTPD.org]) + +AM_INIT_AUTOMAKE([subdir-objects no-dependencies]) +LT_INIT + +# here we should test for variables set by libtool detection +if test "x$with_pic" != "xno"; then + CFLAGS="$CFLAGS ${pic_flag}" +fi + + +# +# PACKAGE INFORMATION +# +AC_LANG([C]) +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_HEADER([config.h]) +AC_PROG_CC +AC_CANONICAL_HOST +AC_C_BIGENDIAN + + +# +# CHECKS FOR PROGRAMS +# +AC_PROG_CPP +AC_PROG_INSTALL +AC_PROG_LIBTOOL +AC_PATH_PROG([AR], [ar]) +AC_PATH_PROG([CAT], [cat]) +AC_PATH_PROG([CHMOD], [chmod]) +AC_PATH_PROG([CHOWN], [chown]) +AC_PATH_PROG([ZCAT], [zcat]) +AC_PATH_PROG([SED], [sed]) +AC_PATH_PROG([TEST_MINUS_S_SH], [bash]) +AC_PATH_PROG([TEST_MINUS_S_SH], [ksh]) +AC_PATH_PROG([TEST_MINUS_S_SH], [sh]) +AC_PATH_PROG([SH], [sh]) +AC_PATH_PROG([GROFF], [groff]) +AC_PATH_PROG([NROFF], [nroff]) +AC_PATH_PROG([MANDOC], [mandoc]) +AC_PROG_YACC + +AC_SUBST([ZCAT]) + + +if test -z "$AR"; then + AC_MSG_ERROR([*** 'ar' missing, please install or fix your \$PATH ***]) +fi + +if test -z "$LD"; then + LD=$CC +fi +AC_SUBST([LD]) + +dnl select manpage formatter +if test -n "$MANDOC"; then + MANFMT="$MANDOC" +elif test -n "$NROFF"; then + MANFMT="$NROFF -mandoc" +elif test -n "$GROFF"; then + MANFMT="$GROFF -mandoc -Tascii" +else + AC_MSG_WARN([no manpage formatted found]) + MANFMT="false" +fi +AC_SUBST([MANFMT]) + + +# +# CHECKS FOR LIBRARIES +# + + +# +# CHECKS FOR HEADERS +# +AC_CHECK_HEADERS([ \ + arpa/nameser_compat.h \ + crypt.h \ + dirent.h \ + err.h \ + fcntl.h \ + getopt.h \ + grp.h \ + libgen.h \ + limits.h \ + maillock.h \ + mach/mach_time.h \ + ndir.h \ + netdb.h \ + pam/pam_appl.h \ + paths.h \ + security/pam_appl.h \ + shadow.h \ + sys/cdefs.h \ + sys/dir.h \ + sys/file.h \ + sys/mount.h \ + sys/ndir.h \ + sys/pstat.h \ + sys/statfs.h \ + sys/time.h \ + sys/un.h \ + time.h \ + ucred.h \ + util.h \ + utime.h \ + vis.h +]) + +AM_CONDITIONAL([SUPPORT_ERR_H], [test x$HAVE_ERR_H = x1]) +AM_CONDITIONAL([SUPPORT_PATHS_H], [test x$HAVE_PATHS_H = x1]) + +# NetBSD requires sys/types.h before login_cap.h +AC_CHECK_HEADERS([login_cap.h], [], [], [ +#include <sys/types.h> +]) + +# older BSDs need sys/param.h before sys/mount.h +AC_CHECK_HEADERS([sys/mount.h], [], [], [ +#include <sys/param.h> +]) + +AC_CHECK_HEADERS([bsd/libutil.h libutil.h]) + +AC_CHECK_HEADER([fts.h], + [], + [AC_MSG_ERROR([*** fts.h missing - please install fts library ***])], + [ +#include <sys/types.h> +#include <sys/stat.h> +]) + + + + +# +# CHECKS FOR TYPES +# +AC_CHECK_TYPES([long long, unsigned long long, long double, u_int, u_char]) +AC_CHECK_SIZEOF([short int], [2]) +AC_CHECK_SIZEOF([int], [4]) +AC_CHECK_SIZEOF([long int], [4]) +AC_CHECK_SIZEOF([long long int], [8]) + +AC_TYPE_INT8_T +AC_TYPE_INT16_T +AC_TYPE_INT32_T +AC_TYPE_INT64_T +AC_TYPE_UINT8_T +AC_TYPE_UINT16_T +AC_TYPE_UINT32_T +AC_TYPE_UINT64_T +AC_TYPE_INTPTR_T +AC_TYPE_INTMAX_T +AC_TYPE_UINTPTR_T +AC_TYPE_UINTMAX_T +AC_TYPE_SIZE_T +AC_TYPE_SSIZE_T +AC_TYPE_OFF_T +AC_TYPE_MODE_T +AC_TYPE_PID_T +AC_TYPE_UID_T + +TYPE_SOCKLEN_T + +AC_CHECK_TYPES([sig_atomic_t], [], [], [ +#include <signal.h> +]) +AC_CHECK_TYPES([fsblkcnt_t, fsfilcnt_t], [], [], [ +#include <sys/types.h> +#ifdef HAVE_SYS_BITYPES_H +#include <sys/bitypes.h> +#endif +#ifdef HAVE_SYS_STATFS_H +#include <sys/statfs.h> +#endif +#ifdef HAVE_SYS_STATVFS_H +#include <sys/statvfs.h> +#endif +]) + +AC_CHECK_TYPES([in_addr_t, in_port_t], [], [], [ +#include <sys/types.h> +#include <netinet/in.h> +]) + +AC_CHECK_TYPES([sa_family_t], [], [], [ +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +]) + +AC_CHECK_TYPES([struct timespec]) +AC_CHECK_TYPES([struct ifgroupreq]) +AC_CHECK_TYPES([struct sockaddr_storage], [], [], [ +#include <sys/types.h> +#include <sys/socket.h> +]) +AC_CHECK_TYPES([struct sockaddr_in6], [], [], [ +#include <sys/types.h> +#include <netinet/in.h> +]) +AC_CHECK_TYPES([struct in6_addr], [], [], [ +#include <sys/types.h> +#include <netinet/in.h> +]) +AC_CHECK_TYPES([struct addrinfo], [], [], [ +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> +]) +AC_CHECK_TYPES([struct timeval], [], [], [ +#include <sys/time.h> +]) + + +# +# CHECKS FOR STRUCTURES +# +AC_CHECK_MEMBERS([struct sockaddr_in6.sin6_scope_id], [], [], [ +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#include <netinet/in.h> +]) + +AC_CHECK_MEMBERS([struct passwd.pw_gecos, struct passwd.pw_class, +struct passwd.pw_change, struct passwd.pw_expire], +[], [], [ +#include <sys/types.h> +#include <pwd.h> +]) + +AC_CHECK_MEMBERS([struct stat.st_flags], , , + [ #include <sys/types.h> + #include <sys/stat.h> ] +) + +AC_CHECK_MEMBERS([struct stat.st_mtim], , , + [ #include <sys/types.h> + #include <sys/stat.h> ] +) + +AC_CHECK_MEMBERS([struct stat.st_mtimespec], , , + [ #include <sys/types.h> + #include <sys/stat.h> ] +) + +AC_CHECK_MEMBERS([struct sockaddr.sa_len], , , + [ #include <netdb.h> + #include <netinet/in.h> + #include <sys/socket.h> ] +) + +AC_CHECK_MEMBERS([struct sockaddr_storage.ss_len], , , + [ #include <netdb.h> + #include <netinet/in.h> + #include <sys/socket.h> ] +) + +AC_CHECK_MEMBERS([struct sockaddr_in.sin_len], , , + [ #include <netdb.h> + #include <netinet/in.h> + #include <sys/socket.h> ] +) + +AC_CHECK_MEMBERS([struct sockaddr_in6.sin6_len], , , + [ #include <netdb.h> + #include <netinet/in.h> + #include <sys/socket.h> ] +) + +AC_CHECK_MEMBERS([struct statfs.f_favail], , , + [ #include <sys/vfs.h> + #include <sys/statfs.h> ] +) + +AC_CHECK_MEMBERS([struct sockaddr_storage.ss_family], [], [], [ +#include <sys/types.h> +#include <sys/socket.h> +]) + +AC_CHECK_MEMBERS([struct sockaddr_storage.__ss_family], [], [], [ +#include <sys/types.h> +#include <sys/socket.h> +]) + +AC_CHECK_MEMBERS([struct tm.tm_gmtoff, struct tm.tm_zone], [], + [ + AC_CHECK_DECLS([timezone, altzone, tzname], + [], + [ AC_MSG_ERROR([cannot find timezone])], + [ #include <time.h> ] + ) + ], + [ #include <time.h> ] +) + +AC_CHECK_MEMBERS([struct DIR.d_type], [], [], [ +#include <sys/types.h> +#include <dirent.h> +]) + +# +# CHECKS FOR DECLARATIONS +# +AC_CHECK_DECLS([O_NONBLOCK], [], [], [ +#include <sys/types.h> +#ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif +#ifdef HAVE_FCNTL_H +# include <fcntl.h> +#endif +]) + +AC_CHECK_DECLS([AF_LOCAL, PF_LOCAL], [], [], [ +#include <sys/socket.h> +]) + +AC_CHECK_DECLS([WAIT_MYPGRP], [], [], [ +#include <sys/wait.h> +]) + +AC_CHECK_DECLS([writev], [], [], [ +#include <sys/types.h> +#include <sys/uio.h> +#include <unistd.h> +]) + +AC_CHECK_DECLS([LOG_PERROR], [], [], [ +#include <syslog.h> +]) + + +# +# CHECKS FOR COMPILER CHARACTERISTICS +# +AC_C_INLINE + + +AC_ARG_WITH([libs], + [ --with-libs Specify additional libraries to link with], + [ + if test -n "$withval" -a "$withval" != "no" -a "${withval}" != "yes"; then + LIBS="$LIBS $withval" + fi + ] +) +# +# CHECKS FOR LIBRARY FUNCTIONS +# +BASENAME_SUPPORT=no +AC_SEARCH_LIBS([basename], + [gen], + [ + AC_DEFINE([HAVE_BASENAME], [1], + [Define if you have the basename() function.]) + BASENAME_SUPPORT=yes + ]) +AM_CONDITIONAL([SUPPORT_BASENAME], [test $BASENAME_SUPPORT = yes]) + + +CLOSEFROM_SUPPORT=no +AC_SEARCH_LIBS([closefrom], + [gen], + [ + AC_DEFINE([HAVE_CLOSEFROM], [1], + [Define if you have the closefrom() function.]) + CLOSEFROM_SUPPORT=yes + AC_COMPILE_IFELSE( + [ + AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT], [[int res = closefrom(0);]]) + ], + AC_DEFINE(HAVE_CLOSEFROM_INT, 1, [closefrom return int]) + ) + ]) +AM_CONDITIONAL([SUPPORT_CLOSEFROM], [test $CLOSEFROM_SUPPORT = yes]) + +UTIMES_SUPPORT=no +AC_SEARCH_LIBS([utimes], + [c89], + [ + AC_DEFINE([HAVE_UTIMES], + [1], [Define if you have the utimes() function.]) + UTIMES_SUPPORT=yes + ]) +AM_CONDITIONAL([SUPPORT_UTIMES], [test $UTIMES_SUPPORT = yes]) + +FMT_SCALED_SUPPORT=no +AC_SEARCH_LIBS([fmt_scaled], + [util bsd], + [ + AC_DEFINE([HAVE_FMT_SCALED], [1], + [Define if you have the fmt_scaled() function.]) + FMT_SCALED_SUPPORT=yes + ]) +AM_CONDITIONAL([SUPPORT_FMT_SCALED], [test $FMT_SCALED_SUPPORT = yes]) + +DIRNAME_SUPPORT=no +AC_SEARCH_LIBS([dirname], + [gen], + [ + AC_DEFINE([HAVE_DIRNAME], [1], + [Define if you have the dirname() function.]) + DIRNAME_SUPPORT=yes + ]) +AM_CONDITIONAL([SUPPORT_DIRNAME], [test $DIRNAME_SUPPORT = yes]) + +ERRC_SUPPORT=no +AC_CHECK_FUNC([errc], + [ + AC_DEFINE([HAVE_ERRC], [1], + [Define if you have the errc() function.]) + ERRC_SUPPORT=yes + ]) +AM_CONDITIONAL([SUPPORT_ERRC], [test $ERRC_SUPPORT = yes]) + +INET_NET_PTON_SUPPORT=no +AC_SEARCH_LIBS([inet_net_pton], + [resolv], + [ + AC_DEFINE([HAVE_INET_NET_PTON], [1], + [Define if you have the inet_net_pton() function.]) + INET_NET_PTON_SUPPORT=yes + ]) +AM_CONDITIONAL([SUPPORT_INET_NET_PTON], [test $INET_NET_PTON_SUPPORT = yes]) + +CLOCK_GETTIME_SUPPORT=no +AC_SEARCH_LIBS([clock_gettime], + [rt], + [ + AC_DEFINE([HAVE_CLOCK_GETTIME], [1], + [Define if you have the clock_gettime() function.]) + CLOCK_GETTIME_SUPPORT=yes + ]) +AM_CONDITIONAL([SUPPORT_CLOCK_GETTIME], [test $CLOCK_GETTIME_SUPPORT = yes]) + +FTS_OPEN_SUPPORT=no +AC_SEARCH_LIBS([fts_open], + [fts], + [ + AC_DEFINE([HAVE_FTS_OPEN], [1], + [Define if you have the fts_open() function.]) + FTS_OPEN_SUPPORT=yes + ]) +AM_CONDITIONAL([SUPPORT_FTS_OPEN], [test $FTS_OPEN_SUPPORT = yes]) + +FLOCK_SUPPORT=no +AC_SEARCH_LIBS([flock], + [], + [ + AC_DEFINE([HAVE_FLOCK], [1], + [Define if you have the flock() function.]) + FLOCK_SUPPORT=yes + ]) +AM_CONDITIONAL([SUPPORT_FLOCK], [test $FLOCK_SUPPORT = yes]) + +DAEMON_SUPPORT=no +AC_SEARCH_LIBS([daemon], + [bsd], + [ + AC_DEFINE([HAVE_DAEMON], [1], + [Define if you have the daemon() function.]) + DAEMON_SUPPORT=yes + ]) +AM_CONDITIONAL([SUPPORT_DAEMON], [test $DAEMON_SUPPORT = yes]) + +FPARSELN_SUPPORT=no +AC_SEARCH_LIBS([fparseln], + [util], + [ + AC_DEFINE([HAVE_FPARSELN], [1], + [Define if you have the fparseln() function.]) + FPARSELN_SUPPORT=yes + ]) +AM_CONDITIONAL([SUPPORT_FPARSELN], [test $FPARSELN_SUPPORT = yes]) + +RES_9_B64_NTOP_SUPPORT=no +AC_SEARCH_LIBS([res_9_b64_ntop], + [resolv], + [ + AC_DEFINE([HAVE_RES_9_B64_NTOP], [1], + [Define if you have the res_9_b64_ntop() function.]) + RES_9_B64_NTOP_SUPPORT=yes + ]) +AM_CONDITIONAL([SUPPORT_RES_9_B64_NTOP], [test $RES_9_B64_NTOP_SUPPORT = yes]) + +SETSOCKOPT_SUPPORT=no +AC_SEARCH_LIBS([setsockopt], + [socket], + [ + AC_DEFINE([HAVE_SETSOCKOPT], [1], + [Define if you have the setsockopt() function.]) + SETSOCKOPT_SUPPORT=yes + ]) +AM_CONDITIONAL([SUPPORT_SETSOCKOPT], [test $SETSOCKOPT_SUPPORT = yes]) + +CRYPT_SUPPORT=no +AC_SEARCH_LIBS([crypt], + [crypt], + [ + AC_DEFINE([HAVE_CRYPT], [1], + [Define if you have the crypt() function.]) + CRYPT_SUPPORT=yes + ]) +AM_CONDITIONAL([SUPPORT_CRYPT], [test $CRYPT_SUPPORT = yes]) + +GETLINE_SUPPORT=no +AC_CHECK_FUNC([getline], + [ + AC_DEFINE([HAVE_GETLINE], [1], + [Define if you have the getline() function.]) + GETLINE_SUPPORT=yes + ]) +AM_CONDITIONAL([SUPPORT_GETLINE], [test $GETLINE_SUPPORT = yes]) + +EXPLICIT_BZERO_SUPPORT=no +AC_CHECK_FUNC([explicit_bzero], + [ + AC_DEFINE([HAVE_EXPLICIT_BZERO], [1], + [Define if you have the explicit_bzero() function.]) + EXPLICIT_BZERO_SUPPORT=yes + ]) +AM_CONDITIONAL([SUPPORT_EXPLICIT_BZERO], [test $EXPLICIT_BZERO_SUPPORT = yes]) + +CRYPT_CHECKPASS_SUPPORT=no +AC_CHECK_FUNC([crypt_checkpass], + [ + AC_DEFINE([HAVE_CRYPT_CHECKPASS], [1], + [Define if you have the crypt_checkpass() function.]) + CRYPT_CHECKPASS_SUPPORT=yes + ]) +AM_CONDITIONAL([SUPPORT_CRYPT_CHECKPASS], [test $CRYPT_CHECKPASS_SUPPORT = yes]) + +STRNDUP_SUPPORT=no +AC_CHECK_FUNC([strndup], + [ + AC_DEFINE([HAVE_STRNDUP], [1], + [Define if you have the strndup() function.]) + STRNDUP_SUPPORT=yes + ]) +AM_CONDITIONAL([SUPPORT_STRNDUP], [test $STRNDUP_SUPPORT = yes]) + +STRNLEN_SUPPORT=no +AC_CHECK_FUNC([strnlen], + [ + AC_DEFINE([HAVE_STRNLEN], [1], + [Define if you have the strnlen() function.]) + STRNLEN_SUPPORT=yes + ]) +AM_CONDITIONAL([SUPPORT_STRNLEN], [test $STRNLEN_SUPPORT = yes]) + +AC_CHECK_FUNCS([ \ + asprintf \ + b64_ntop \ + __b64_ntop \ + b64_pton \ + __b64_pton \ + bcopy \ + chflags \ + crypt_checkpass \ + dirfd \ + endgrent \ + explicit_bzero \ + fchflags \ + fgetln \ + freeaddrinfo \ + freezero \ + getaddrinfo \ + getnameinfo \ + gettimeofday \ + getopt \ + getpeereid \ + getpeerucred \ + getspnam \ + inet_aton \ + inet_ntoa \ + inet_ntop \ + isblank \ + memmove \ + nsleep \ + pidfile \ + pledge \ + pw_dup \ + reallocarray \ + recallocarray \ + res_hnok \ + setenv \ + setlinebuf \ + setproctitle \ + setregid \ + setreuid \ + setresuid \ + setresgid \ + setsid \ + sigaction \ + snprintf \ + socketpair \ + strdup \ + strerror \ + strlcat \ + strlcpy \ + strmode \ + strnvis \ + strtonum \ + sysconf \ + tcgetpgrp \ + time \ + truncate \ + vasprintf \ + vsnprintf \ + waitpid \ +]) + +AC_CHECK_DECL([strsep], + [AC_CHECK_FUNCS([strsep])], + [], + [ +#ifdef HAVE_STRING_H +# include <string.h> +#endif + ]) + + + +# These functions might be found in libressl +AC_CHECK_DECLS([strlcat, strlcpy], + [], + [], + []) + +# +# CHECKS FOR SYSTEM SERVICES +# +AC_MSG_CHECKING([for /proc/pid/fd directory]) +if test -d "/proc/$$/fd"; then + AC_DEFINE([HAVE_PROC_PID], [1], [Define if you have /proc/$pid/fd]) + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi + + +# +# AC_CONFIG_FILES +# + +# +# AC_OUTPUT +# + + +### +### EVERYTHING BELOW MUST BE CLEANED AND MOVED ABOVE +### + + +AC_CHECK_DECL([LLONG_MAX], [have_llong_max=1], , [#include <limits.h>]) +#l108 + +#l150 (without _FORTIFY_SOURCE=2) +if test "$GCC" = "yes" -o "$GCC" = "egcs"; then + OSSH_CHECK_CFLAG_COMPILE([-Qunused-arguments]) + OSSH_CHECK_CFLAG_COMPILE([-Wunknown-warning-option]) + OSSH_CHECK_CFLAG_COMPILE([-Wall]) + OSSH_CHECK_CFLAG_COMPILE([-Wpointer-arith]) + OSSH_CHECK_CFLAG_COMPILE([-Wuninitialized]) + OSSH_CHECK_CFLAG_COMPILE([-Wsign-compare]) + OSSH_CHECK_CFLAG_COMPILE([-Wformat-security]) + OSSH_CHECK_CFLAG_COMPILE([-Wsizeof-pointer-memaccess]) + OSSH_CHECK_CFLAG_COMPILE([-Wpointer-sign], [-Wno-pointer-sign]) + OSSH_CHECK_CFLAG_COMPILE([-Wunused-result], [-Wno-unused-result]) + OSSH_CHECK_CFLAG_COMPILE([-fno-strict-aliasing]) +# OSSH_CHECK_CFLAG_COMPILE([-D_FORTIFY_SOURCE=2]) + if test "x$use_toolchain_hardening" = "x1"; then + OSSH_CHECK_LDFLAG_LINK([-Wl,-z,relro]) + OSSH_CHECK_LDFLAG_LINK([-Wl,-z,now]) + OSSH_CHECK_LDFLAG_LINK([-Wl,-z,noexecstack]) + # NB. -ftrapv expects certain support functions to be present in + # the compiler library (libgcc or similar) to detect integer operations + # that can overflow. We must check that the result of enabling it + # actually links. The test program compiled/linked includes a number + # of integer operations that should exercise this. + OSSH_CHECK_CFLAG_LINK([-ftrapv]) + fi + AC_MSG_CHECKING([gcc version]) + GCC_VER=`$CC -v 2>&1 | $AWK '/gcc version /{print $3}'` + case $GCC_VER in + 1.*) no_attrib_nonnull=1 ;; + 2.8* | 2.9*) + no_attrib_nonnull=1 + ;; + 2.*) no_attrib_nonnull=1 ;; + *) ;; + esac + AC_MSG_RESULT([$GCC_VER]) + + AC_MSG_CHECKING([if $CC accepts -fno-builtin-memset]) + saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fno-builtin-memset" + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include <string.h> ]], + [[ char b[10]; memset(b, 0, sizeof(b)); ]])], + [ AC_MSG_RESULT([yes]) ], + [ AC_MSG_RESULT([no]) + CFLAGS="$saved_CFLAGS" ] + ) + + # -fstack-protector-all doesn't always work for some GCC versions + # and/or platforms, so we test if we can. If it's not supported + # on a given platform gcc will emit a warning so we use -Werror. + if test "x$use_stack_protector" = "x1"; then + for t in -fstack-protector-strong -fstack-protector-all \ + -fstack-protector; do + AC_MSG_CHECKING([if $CC supports $t]) + saved_CFLAGS="$CFLAGS" + saved_LDFLAGS="$LDFLAGS" + CFLAGS="$CFLAGS $t -Werror" + LDFLAGS="$LDFLAGS $t -Werror" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[ #include <stdio.h> ]], + [[ + char x[256]; + snprintf(x, sizeof(x), "XXX"); + ]])], + [ AC_MSG_RESULT([yes]) + CFLAGS="$saved_CFLAGS $t" + LDFLAGS="$saved_LDFLAGS $t" + AC_MSG_CHECKING([if $t works]) + AC_RUN_IFELSE( + [AC_LANG_PROGRAM([[ #include <stdio.h> ]], + [[ + char x[256]; + snprintf(x, sizeof(x), "XXX"); + ]])], + [ AC_MSG_RESULT([yes]) + break ], + [ AC_MSG_RESULT([no]) ], + [ AC_MSG_WARN([cross compiling: cannot test]) + break ] + ) + ], + [ AC_MSG_RESULT([no]) ] + ) + CFLAGS="$saved_CFLAGS" + LDFLAGS="$saved_LDFLAGS" + done + fi + + if test -z "$have_llong_max"; then + # retry LLONG_MAX with -std=gnu99, needed on some Linuxes + unset ac_cv_have_decl_LLONG_MAX + saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -std=gnu99" + AC_CHECK_DECL([LLONG_MAX], + [have_llong_max=1], + [CFLAGS="$saved_CFLAGS"], + [#include <limits.h>] + ) + fi +fi + +AC_MSG_CHECKING([if compiler allows __attribute__ on return types]) +AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[ +#include <stdlib.h> +__attribute__((__unused__)) static void foo(void){return;}]], + [[ exit(0); ]])], + [ AC_MSG_RESULT([yes]) ], + [ AC_MSG_RESULT([no]) + AC_DEFINE(NO_ATTRIBUTE_ON_RETURN_TYPE, 1, + [compiler does not accept __attribute__ on return types]) ] +) + +if test "x$no_attrib_nonnull" != "x1"; then + AC_DEFINE([HAVE_ATTRIBUTE__NONNULL__], [1], [Have attribute nonnull]) +fi + +AC_ARG_WITH([rpath], + [ --without-rpath Disable auto-added -R linker paths], + [ + if test "x$withval" = "xno"; then + need_dash_r="" + fi + if test "x$withval" = "xyes"; then + need_dash_r=1 + fi + ] +) + + +AC_ARG_WITH([cflags], + [ --with-cflags Specify additional flags to pass to compiler], + [ + if test -n "$withval" -a "$withval" != "no" -a "${withval}" != "yes"; then + CFLAGS="$CFLAGS $withval" + fi + ] +) +AC_ARG_WITH([cppflags], + [ --with-cppflags Specify additional flags to pass to preprocessor] , + [ + if test -n "$withval" -a "$withval" != "no" -a "${withval}" != "yes"; then + CPPFLAGS="$CPPFLAGS $withval" + fi + ] +) +AC_ARG_WITH([ldflags], + [ --with-ldflags Specify additional flags to pass to linker], + [ + if test -n "$withval" -a "$withval" != "xno" -a "${withval}" != "yes"; then + LDFLAGS="$LDFLAGS $withval" + fi + ] +) +AC_ARG_WITH([Werror], + [ --with-Werror Build main code with -Werror], + [ + if test -n "$withval" -a "$withval" != "no"; then + werror_flags="-Werror" + if test "${withval}" != "yes"; then + werror_flags="$withval" + fi + fi + ] +) + + + +AC_ARG_WITH([pie], + [ --with-pie Build Position Independent Executables if possible], [ + if test "x$withval" = "xno"; then + use_pie=no + fi + if test "x$withval" = "xyes"; then + use_pie=yes + fi + ] +) +if test -z "$use_pie"; then + use_pie=no +fi +if test "x$use_toolchain_hardening" != "x1" -a "x$use_pie" = "xauto"; then + # Turn off automatic PIE when toolchain hardening is off. + use_pie=no +fi +if test "x$use_pie" = "xauto"; then + # Automatic PIE requires gcc >= 4.x + AC_MSG_CHECKING([for gcc >= 4.x]) + AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ +#if !defined(__GNUC__) || __GNUC__ < 4 +#error gcc is too old +#endif +]])], + [ AC_MSG_RESULT([yes]) ], + [ AC_MSG_RESULT([no]) + use_pie=no ] +) +fi +if test "x$use_pie" != "xno"; then + SAVED_CFLAGS="$CFLAGS" + SAVED_LDFLAGS="$LDFLAGS" + OSSH_CHECK_CFLAG_COMPILE([-fPIE]) + OSSH_CHECK_LDFLAG_LINK([-pie]) + # We use both -fPIE and -pie or neither. + AC_MSG_CHECKING([whether both -fPIE and -pie are supported]) + if echo "x $CFLAGS" | grep ' -fPIE' >/dev/null 2>&1 && \ + echo "x $LDFLAGS" | grep ' -pie' >/dev/null 2>&1 ; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + CFLAGS="$SAVED_CFLAGS" + LDFLAGS="$SAVED_LDFLAGS" + fi +fi + + + + + + +#l432 (customized) +# Check for some target-specific stuff +ASR_LIB=-lasr + +case "$host" in +*-*-darwin*) + use_pie=auto + AC_MSG_CHECKING([if we have working getaddrinfo]) + AC_RUN_IFELSE([AC_LANG_SOURCE([[ +#include <stdlib.h> +#include <mach-o/dyld.h> +main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) + exit(0); + else + exit(1); +} + ]])], + [AC_MSG_RESULT([working])], + [AC_MSG_RESULT([buggy]) + AC_DEFINE([BROKEN_GETADDRINFO], [1], + [getaddrinfo is broken (if present)]) + ], + [AC_MSG_RESULT([assume it is working])]) + AC_DEFINE([SETEUID_BREAKS_SETUID], [1], [define if seteuid breaks setuid]) + AC_DEFINE([BROKEN_SETREUID], [1], [define if setreuid is broken]) + AC_DEFINE([BROKEN_SETREGID], [1], [define if setregid is broken]) + AC_DEFINE([BROKEN_GLOB], [1], [OS X glob does not do what we expect]) + AC_DEFINE([SPT_TYPE], [SPT_REUSEARGV], + [Define to a Set Process Title type if your system is + supported by bsd-setproctitle.c]) + AC_DEFINE([BROKEN_STRNVIS], [1], + [OSX strnvis argument order is swapped compared to OpenBSD]) + ;; +*-*-dragonfly*) + ;; +*-*-linux* | *-gnu* | *-k*bsd*-gnu* ) + use_pie=auto + CFLAGS="$CFLAGS -D_BSD_SOURCE -D_DEFAULT_SOURCE" + AC_DEFINE([SPT_TYPE], [SPT_REUSEARGV]) + ;; +*-*-netbsd*) + if test "x$withval" != "xno"; then + need_dash_r=1 + fi + AC_DEFINE([BROKEN_STRNVIS], [1], + [NetBSD strnvis argument order is swapped compared to OpenBSD]) + ;; +*-*-freebsd*) + AC_DEFINE([BROKEN_GLOB], [1], [FreeBSD glob does not do what we need]) + AC_DEFINE([BROKEN_STRNVIS], [1], + [FreeBSD strnvis argument order is swapped compared to OpenBSD]) + ;; +*-*-openbsd*) + use_pie=auto + AC_DEFINE([HAVE_ATTRIBUTE__SENTINEL__], [1], [OpenBSD's gcc has sentinel]) + AC_DEFINE([HAVE_ATTRIBUTE__BOUNDED__], [1], [OpenBSD's gcc has bounded]) + + AC_DEFINE([BROKEN_STRNVIS], [0], + [FreeBSD strnvis argument order is swapped compared to OpenBSD]) + YACC='yacc' + ASR_LIB= + AC_DEFINE([NOOP_ASR_FREEADDRINFO], [0], [OpenBSD doesn't need ASR_FREEADDRINFO]) + ;; +*-sun-solaris*) + AC_DEFINE([HAVE_M_DATA], [1], [M_DATA is defined in sys/stream.h included by netinet/in.h]) + ;; +esac +AC_SUBST([ASR_LIB]) + + +AC_MSG_CHECKING([compiler and flags for sanity]) +AC_RUN_IFELSE([AC_LANG_PROGRAM([[ +#include <stdio.h> +#include <stdlib.h> ]], [[ exit(0); ]])], + [ AC_MSG_RESULT([yes]) ], + [ + AC_MSG_RESULT([no]) + AC_MSG_ERROR([*** compiler cannot create working executables, check config.log ***]) + ], + [ AC_MSG_WARN([cross compiling: not checking compiler sanity]) ] +) + + + +#l1747 + + + + +# Check for missing getpeereid (or equiv) support +NO_PEERCHECK="" +if test "x$ac_cv_func_getpeereid" != "xyes" -a "x$ac_cv_func_getpeerucred" != "xyes"; then + AC_MSG_CHECKING([whether system supports SO_PEERCRED getsockopt]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include <sys/types.h> +#include <sys/socket.h>]], [[int i = SO_PEERCRED;]])], + [ AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_SO_PEERCRED], [1], [Have PEERCRED socket option]) + ], [AC_MSG_RESULT([no]) + NO_PEERCHECK=1 + ]) +fi + +#l4176 (customized s/ssh.1/smtpd/smtpd.8/) +# Options from here on. Some of these are preset by platform above +AC_ARG_WITH([mantype], + [ --with-mantype=man|cat|doc Set man page type], + [ + case "$withval" in + man|cat|doc) + MANTYPE=$withval + ;; + *) + AC_MSG_ERROR([invalid man type: $withval]) + ;; + esac + ] +) +if test -z "$MANTYPE"; then + TestPath="/usr/bin${PATH_SEPARATOR}/usr/ucb" + AC_PATH_PROGS([NROFF], [nroff awf], [/bin/false], [$TestPath]) + if ${NROFF} -mdoc ${srcdir}/smtpd/smtpd.8 >/dev/null 2>&1; then + MANTYPE=doc + elif ${NROFF} -man ${srcdir}/smtpd/smtpd.8 >/dev/null 2>&1; then + MANTYPE=man + else + MANTYPE=cat + fi +fi +AC_SUBST([MANTYPE]) +if test "$MANTYPE" = "doc"; then + mansubdir=man; +else + mansubdir=$MANTYPE; +fi +AC_SUBST([mansubdir]) +#l4207 + + +#l4432 (customized s/pid/sock/) +# Whether to enable BSD auth support +BSD_AUTH_MSG=no +AC_ARG_WITH([auth-bsdauth], + [ --with-auth-bsdauth Enable bsd_auth(3) authentication support], + [ + if test "x$withval" != "xno"; then + AC_DEFINE([BSD_AUTH], [1], + [Define if you have BSD auth support]) + BSD_AUTH_MSG=yes + fi + ] +) + + +#l2757 +# Check for PAM libs +PAM_MSG="no" +USE_PAM_SERVICE=smtpd +AC_ARG_WITH([auth-pam], + [ --with-auth-pam=SERVICE Enable PAM authentication support (default=smtpd)], + [ + if test "x$withval" != "xno"; then + if test -n "$withval" -a "x${withval}" != "xyes"; then + USE_PAM_SERVICE=$withval + fi + + if test "x$ac_cv_header_security_pam_appl_h" != "xyes" -a \ + test "x$ac_cv_header_pam_pam_appl_h" != "xyes"; then + AC_MSG_ERROR([PAM headers not found]) + fi + + saved_LIBS="$LIBS" + AC_CHECK_LIB([dl], [dlopen], , ) + AC_CHECK_LIB([pam], [pam_set_item], , [AC_MSG_ERROR([*** libpam missing])]) + AC_CHECK_FUNCS([pam_getenvlist]) + AC_CHECK_FUNCS([pam_putenv]) + LIBS="$saved_LIBS" + + PAM_MSG="yes" + + SMTPDLIBS="$SMTPDLIBS -lpam" + AC_DEFINE([USE_PAM], [1], + [Define if you want to enable PAM support]) + + if test "x$ac_cv_lib_dl_dlopen" = "xyes"; then + case "$LIBS" in + *-ldl*) + # libdl already in LIBS + ;; + *) + SMTPDLIBS="$SMTPDLIBS -ldl" + ;; + esac + fi + fi + ] +) +AC_DEFINE_UNQUOTED([USE_PAM_SERVICE], ["$USE_PAM_SERVICE"], [pam service]) +AC_SUBST([USE_PAM_SERVICE]) + +AC_CHECK_FUNCS([arc4random arc4random_buf arc4random_stir arc4random_uniform]) + +# Check for older PAM +if test "x$PAM_MSG" = "xyes"; then + # Check PAM strerror arguments (old PAM) + AC_MSG_CHECKING([whether pam_strerror takes only one argument]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include <stdlib.h> +#if defined(HAVE_SECURITY_PAM_APPL_H) +#include <security/pam_appl.h> +#elif defined (HAVE_PAM_PAM_APPL_H) +#include <pam/pam_appl.h> +#endif + ]], [[ +(void)pam_strerror((pam_handle_t *)NULL, -1); + ]])], [AC_MSG_RESULT([no])], [ + AC_DEFINE([HAVE_OLD_PAM], [1], + [Define if you have an old version of PAM + which takes only one argument to pam_strerror]) + AC_MSG_RESULT([yes]) + PAM_MSG="yes (old library)" + + ]) +fi +#l2816 + + +##gilles + +SMTPD_USER=_smtpd +AC_ARG_WITH([user-smtpd], + [ --with-user-smtpd=user Specify non-privileged user for smtpd (default=_smtpd)], + [ + if test -n "$withval" -a "$withval" != "no" -a "${withval}" != "yes"; then + SMTPD_USER=$withval + fi + ] +) +AC_DEFINE_UNQUOTED([SMTPD_USER], ["$SMTPD_USER"], + [non-privileged user for privilege separation]) +AC_SUBST([SMTPD_USER]) + +SMTPD_QUEUE_USER=_smtpq +AC_ARG_WITH([user-queue], + [ --with-user-queue=user Specify non-privileged user for queue process (default=_smtpq)], + [ + if test -n "$withval" -a "$withval" != "no" -a "${withval}" != "yes"; then + SMTPD_QUEUE_USER=$withval + fi + ] +) +AC_DEFINE_UNQUOTED([SMTPD_QUEUE_USER], ["$SMTPD_QUEUE_USER"], + [non-privileged user for queue process]) +AC_SUBST([SMTPD_QUEUE_USER]) + +SMTPD_QUEUE_GROUP=_smtpq +AC_ARG_WITH([group-queue], + [ --with-group-queue=group Specify non-privileged group for offline queue (default=_smtpq)], + [ + if test -n "$withval" -a "$withval" != "no" -a "${withval}" != "yes"; then + SMTPD_QUEUE_GROUP=$withval + fi + ] +) +AC_DEFINE_UNQUOTED([SMTPD_QUEUE_GROUP], ["$SMTPD_QUEUE_GROUP"], + [non-privileged group for queue process]) +AC_SUBST([SMTPD_QUEUE_GROUP]) + +# Where to place spooler +spooldir=/var/spool/smtpd +AC_ARG_WITH([path-queue], + [ --with-path-queue=PATH Specify path to queue directory (default=/var/spool/smtpd)], + [ + if test -n "$withval" -a "$withval" != "no" -a "${withval}" != "yes"; then + spooldir=$withval + if test ! -d $spooldir; then + AC_MSG_WARN([** no $spooldir directory on this system **]) + fi + fi + ] +) + +AC_DEFINE_UNQUOTED([PATH_SPOOL], ["$spooldir"], + [Specify location of spooler]) +AC_SUBST([spooldir]) + + +PRIVSEP_PATH=/var/empty +AC_ARG_WITH([path-empty], + [ --with-path-empty=PATH Specify path to empty directory (default=/var/empty)], + [ + if test -n "$withval" -a "$withval" != "no" -a "${withval}" != "yes"; then + PRIVSEP_PATH=$withval + fi + ] +) +AC_SUBST([PRIVSEP_PATH]) +#l4022 + +#l4066 +dnl # --with-maildir=/path/to/mail gets top priority. +dnl # if maildir is set in the platform case statement above we use that. +dnl # Otherwise we run a program to get the dir from system headers. +dnl # We first look for _PATH_MAILDIR then MAILDIR then _PATH_MAIL +dnl # If we find _PATH_MAILDIR we do nothing because that is what +dnl # session.c expects anyway. Otherwise we set to the value found +dnl # stripping any trailing slash. If for some strage reason our program +dnl # does not find what it needs, we default to /var/spool/mail. +# Check for mail directory +AC_ARG_WITH([path-mbox], + [ --with-path-mbox=PATH Specify path to mbox directory (default=/var/spool/mail)], + [ + if test -n "$withval" -a "$withval" != "no" -a "${withval}" != "yes"; then + AC_DEFINE_UNQUOTED([MAIL_DIRECTORY], ["$withval"], + [Set this to your mail directory if you do not have _PATH_MAILDIR]) + fi + ],[ + if test -n "$maildir"; then + AC_DEFINE_UNQUOTED([MAIL_DIRECTORY], ["$maildir"]) + else + AC_MSG_CHECKING([system mail directory]) + AC_RUN_IFELSE( + [AC_LANG_PROGRAM([[ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#ifdef HAVE_PATHS_H +#include <paths.h> +#endif +#ifdef HAVE_MAILLOCK_H +#include <maillock.h> +#endif +#define DATA "conftest.maildir" + ]], [[ + FILE *fd; + int rc; + + fd = fopen(DATA,"w"); + if(fd == NULL) + exit(1); + +#if defined (_PATH_MAILDIR) + if ((rc = fprintf(fd ,"_PATH_MAILDIR:%s\n", _PATH_MAILDIR)) <0) + exit(1); +#elif defined (MAILDIR) + if ((rc = fprintf(fd ,"MAILDIR:%s\n", MAILDIR)) <0) + exit(1); +#elif defined (_PATH_MAIL) + if ((rc = fprintf(fd ,"_PATH_MAIL:%s\n", _PATH_MAIL)) <0) + exit(1); +#else + exit (2); +#endif + + exit(0); + ]])], + [ + maildir_what=`awk -F: '{print $1}' conftest.maildir` + maildir=`awk -F: '{print $2}' conftest.maildir \ + | sed 's|/$||'` + AC_MSG_RESULT([$maildir from $maildir_what]) + if test "x$maildir_what" != "x_PATH_MAILDIR"; then + AC_DEFINE_UNQUOTED([MAIL_DIRECTORY], ["$maildir"]) + fi + ], + [ + if test "X$ac_status" = "X2"; then +# our test program didn't find it. Default to /var/spool/mail + AC_MSG_RESULT([/var/spool/mail]) + AC_DEFINE_UNQUOTED([MAIL_DIRECTORY], ["/var/spool/mail"]) + else + AC_MSG_RESULT([*** not found ***]) + fi + ], + [ + AC_MSG_WARN([cross compiling: use --with-maildir=/path/to/mail]) + ] + ) + fi + ] +) # maildir +#l4146 + +# Where to place smtpd.sock +sockdir=/var/run +# make sure the directory exists +if test ! -d $sockdir; then + sockdir=`eval echo ${sysconfdir}` + case $sockdir in + NONE/*) sockdir=`echo $sockdir | sed "s~NONE~$ac_default_prefix~"` ;; + esac +fi + +AC_ARG_WITH([path-socket], + [ --with-path-socket=PATH Specify path to smtpd.sock directory (default=/var/run)], + [ + if test -n "$withval" -a "$withval" != "no" -a "${withval}" != "yes"; then + sockdir=$withval + if test ! -d $sockdir; then + AC_MSG_WARN([** no $sockdir directory on this system **]) + fi + fi + ] +) + +AC_DEFINE_UNQUOTED([SMTPD_SOCKDIR], ["$sockdir"], + [Specify location of smtpd.sock]) +AC_SUBST([sockdir]) +#l4470 + +# Where to place smtpd.pid +piddir=/var/run +AC_MSG_CHECKING([system pid directory]) +AC_RUN_IFELSE( + [ + AC_LANG_PROGRAM([[ +#include <stdio.h> +#include <stdlib.h> +#ifdef HAVE_PATHS_H +#include <paths.h> +#endif +#define DATA "conftest.piddir" + ]], + [[ +#ifdef _PATH_VARRUN +FILE *fd; +int rc; + +if ((fd = fopen(DATA,"w")) == NULL) { exit(1); } +if ((rc = fprintf(fd ,"%s\n", _PATH_VARRUN)) < 0) { exit(2); } +exit(0); +#else +exit(-1); +#endif + ]]) + ], [ + piddir=`cat conftest.piddir` + AC_MSG_RESULT([$piddir from paths.h]) + ], + [ + AC_MSG_RESULT([$piddir from default value]) + ], + [ + AC_MSG_RESULT([$piddir from default value]) + ] +) + +AC_ARG_WITH([path-pidfile], + [ --with-path-pidfile=PATH Specify path to smtpd.pid directory (default=/var/run)], + [ + if test -n "$withval" -a "$withval" != "no" -a "${withval}" != "yes"; then + piddir=$withval + fi + ] +) + +AC_DEFINE_UNQUOTED([SMTPD_PIDDIR], ["$piddir"], [Specify location of smtpd.pid]) +AC_SUBST([piddir]) + +CA_FILE=/etc/ssl/cert.pem +AC_ARG_WITH([path-CAfile], + [ --with-path-CAfile=FILE Specify path to CA certificate (default=/etc/ssl/cert.pem)], + [ + if test -n "$withval" -a "$withval" != "no" -a "${withval}" != "yes"; then + CA_FILE=$withval + fi + ] +) +AC_SUBST([CA_FILE]) + + + + + + +# compute LLONG_MIN and LLONG_MAX if we don't know them. +if test -z "$have_llong_max"; then + AC_MSG_CHECKING([for max value of long long]) + AC_RUN_IFELSE( + [AC_LANG_PROGRAM([[ +#include <stdio.h> +#include <stdlib.h> +/* Why is this so damn hard? */ +#ifdef __GNUC__ +# undef __GNUC__ +#endif +#define __USE_ISOC99 +#include <limits.h> +#define DATA "conftest.llminmax" +#define my_abs(a) ((a) < 0 ? ((a) * -1) : (a)) + +/* + * printf in libc on some platforms (eg old Tru64) does not understand %lld so + * we do this the hard way. + */ +static int +fprint_ll(FILE *f, long long n) +{ + unsigned int i; + int l[sizeof(long long) * 8]; + + if (n < 0) + if (fprintf(f, "-") < 0) + return -1; + for (i = 0; n != 0; i++) { + l[i] = my_abs(n % 10); + n /= 10; + } + do { + if (fprintf(f, "%d", l[--i]) < 0) + return -1; + } while (i != 0); + if (fprintf(f, " ") < 0) + return -1; + return 0; +} + ]], [[ + FILE *f; + long long i, llmin, llmax = 0; + + if((f = fopen(DATA,"w")) == NULL) + exit(1); + +#if defined(LLONG_MIN) && defined(LLONG_MAX) + fprintf(stderr, "Using system header for LLONG_MIN and LLONG_MAX\n"); + llmin = LLONG_MIN; + llmax = LLONG_MAX; +#else + fprintf(stderr, "Calculating LLONG_MIN and LLONG_MAX\n"); + /* This will work on one's complement and two's complement */ + for (i = 1; i > llmax; i <<= 1, i++) + llmax = i; + llmin = llmax + 1LL; /* wrap */ +#endif + + /* Sanity check */ + if (llmin + 1 < llmin || llmin - 1 < llmin || llmax + 1 > llmax + || llmax - 1 > llmax || llmin == llmax || llmin == 0 + || llmax == 0 || llmax < LONG_MAX || llmin > LONG_MIN) { + fprintf(f, "unknown unknown\n"); + exit(2); + } + + if (fprint_ll(f, llmin) < 0) + exit(3); + if (fprint_ll(f, llmax) < 0) + exit(4); + if (fclose(f) < 0) + exit(5); + exit(0); + ]])], + [ + llong_min=`$AWK '{print $1}' conftest.llminmax` + llong_max=`$AWK '{print $2}' conftest.llminmax` + + AC_MSG_RESULT([$llong_max]) + AC_DEFINE_UNQUOTED([LLONG_MAX], [${llong_max}LL], + [max value of long long calculated by configure]) + AC_MSG_CHECKING([for min value of long long]) + AC_MSG_RESULT([$llong_min]) + AC_DEFINE_UNQUOTED([LLONG_MIN], [${llong_min}LL], + [min value of long long calculated by configure]) + ], + [ + AC_MSG_RESULT([not found]) + ], + [ + AC_MSG_WARN([cross compiling: not checking]) + ] + ) +fi + + + + + +#l3561 + + +dnl make sure we're using the real structure members and not defines +AC_CACHE_CHECK([for msg_accrights field in struct msghdr], + ac_cv_have_accrights_in_msghdr, [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <stdlib.h> + ]], [[ +#ifdef msg_accrights +#error "msg_accrights is a macro" +exit(1); +#endif +struct msghdr m; +m.msg_accrights = 0; +exit(0); + ]])], + [ ac_cv_have_accrights_in_msghdr="yes" ], + [ ac_cv_have_accrights_in_msghdr="no" ] + ) +]) +if test "x$ac_cv_have_accrights_in_msghdr" = "xyes"; then + AC_DEFINE([HAVE_ACCRIGHTS_IN_MSGHDR], [1], + [Define if your system uses access rights style + file descriptor passing]) +fi + + +AC_CACHE_CHECK([for msg_control field in struct msghdr], + ac_cv_have_control_in_msghdr, [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <stdlib.h> + ]], [[ +#ifdef msg_control +#error "msg_control is a macro" +exit(1); +#endif +struct msghdr m; +m.msg_control = 0; +exit(0); + ]])], + [ ac_cv_have_control_in_msghdr="yes" ], + [ ac_cv_have_control_in_msghdr="no" ] + ) +]) +if test "x$ac_cv_have_control_in_msghdr" = "xyes"; then + AC_DEFINE([HAVE_CONTROL_IN_MSGHDR], [1], + [Define if your system uses ancillary data style + file descriptor passing]) +fi + +AC_CACHE_CHECK([if libc defines __progname], ac_cv_libc_defines___progname, [ + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include <stdio.h> ]], + [[ extern char *__progname; printf("%s", __progname); ]])], + [ ac_cv_libc_defines___progname="yes" ], + [ ac_cv_libc_defines___progname="no" + ]) +]) +if test "x$ac_cv_libc_defines___progname" = "xyes"; then + AC_DEFINE([HAVE___PROGNAME], [1], [Define if libc defines __progname]) +fi + +AC_CACHE_CHECK([whether $CC implements __FUNCTION__], ac_cv_cc_implements___FUNCTION__, [ + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include <stdio.h> ]], + [[ printf("%s", __FUNCTION__); ]])], + [ ac_cv_cc_implements___FUNCTION__="yes" ], + [ ac_cv_cc_implements___FUNCTION__="no" + ]) +]) +if test "x$ac_cv_cc_implements___FUNCTION__" = "xyes"; then + AC_DEFINE([HAVE___FUNCTION__], [1], + [Define if compiler implements __FUNCTION__]) +fi + +AC_CACHE_CHECK([whether $CC implements __func__], ac_cv_cc_implements___func__, [ + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include <stdio.h> ]], + [[ printf("%s", __func__); ]])], + [ ac_cv_cc_implements___func__="yes" ], + [ ac_cv_cc_implements___func__="no" + ]) +]) +if test "x$ac_cv_cc_implements___func__" = "xyes"; then + AC_DEFINE([HAVE___func__], [1], [Define if compiler implements __func__]) +fi + +AC_CACHE_CHECK([whether va_copy exists], ac_cv_have_va_copy, [ + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#include <stdarg.h> +va_list x,y; + ]], [[ va_copy(x,y); ]])], + [ ac_cv_have_va_copy="yes" ], + [ ac_cv_have_va_copy="no" + ]) +]) +if test "x$ac_cv_have_va_copy" = "xyes"; then + AC_DEFINE([HAVE_VA_COPY], [1], [Define if va_copy exists]) +fi + +AC_CACHE_CHECK([whether __va_copy exists], ac_cv_have___va_copy, [ + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#include <stdarg.h> +va_list x,y; + ]], [[ __va_copy(x,y); ]])], + [ ac_cv_have___va_copy="yes" ], [ ac_cv_have___va_copy="no" + ]) +]) +if test "x$ac_cv_have___va_copy" = "xyes"; then + AC_DEFINE([HAVE___VA_COPY], [1], [Define if __va_copy exists]) +fi + +AC_CACHE_CHECK([whether getopt has optreset support], + ac_cv_have_getopt_optreset, [ + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include <getopt.h> ]], + [[ extern int optreset; optreset = 0; ]])], + [ ac_cv_have_getopt_optreset="yes" ], + [ ac_cv_have_getopt_optreset="no" + ]) +]) +if test "x$ac_cv_have_getopt_optreset" = "xyes"; then + AC_DEFINE([HAVE_GETOPT_OPTRESET], [1], + [Define if your getopt(3) defines and uses optreset]) +fi +#l3765 + + + + +#l4045 +STRIP_OPT=-s +AC_ARG_ENABLE([strip], + [ --disable-strip Disable calling strip(1) on install], + [ + if test "x$enableval" = "xno"; then + STRIP_OPT= + fi + ] +) +AC_SUBST([STRIP_OPT]) +#l4054 + + + +case "$host" in +*-*-openbsd*) + pkglibexecdir="$libexecdir/smtpd" + ;; +*) + pkglibexecdir="$libexecdir/opensmtpd" + ;; +esac +AC_SUBST([pkglibexecdir]) + + + + + + + + + +#l4742 +dnl Adding -Werror to CFLAGS early prevents configure tests from running. +dnl Add now. +CFLAGS="$CFLAGS $werror_flags" + +AC_SUBST([TEST_MALLOC_OPTIONS], [$TEST_MALLOC_OPTIONS]) + + +AC_EXEEXT +#l4757 + + +# Search for asr (based on zlib checks) +dnl asr is required +AC_ARG_WITH([libasr], + [ --with-libasr=PATH Specify path to libasr installation], + [ if test "x$withval" = "xno"; then + AC_MSG_ERROR([*** asr is required ***]) + elif test "x$withval" != "xyes"; then + if test -d "$withval/lib"; then + if test -n "${need_dash_r}"; then + LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}" + else + LDFLAGS="-L${withval}/lib ${LDFLAGS}" + fi + else + if test -n "${need_dash_r}"; then + LDFLAGS="-L${withval} -R${withval} ${LDFLAGS}" + else + LDFLAGS="-L${withval} ${LDFLAGS}" + fi + fi + if test -d "$withval/include"; then + CPPFLAGS="-I${withval}/include ${CPPFLAGS}" + else + CPPFLAGS="-I${withval} ${CPPFLAGS}" + fi + fi ] +) + +AC_CHECK_HEADER([asr.h], ,[AC_MSG_ERROR([*** asr.h missing - please install first or check config.log ***])], +[#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h>]) +AC_CHECK_LIB([asr], [asr_run], , + [ + saved_CPPFLAGS="$CPPFLAGS" + saved_LDFLAGS="$LDFLAGS" + save_LIBS="$LIBS" + dnl Check default asr install dir + if test -n "${need_dash_r}"; then + LDFLAGS="-L/usr/local/lib -R/usr/local/lib ${saved_LDFLAGS}" + else + LDFLAGS="-L/usr/local/lib ${saved_LDFLAGS}" + fi + CPPFLAGS="-I/usr/local/include ${saved_CPPFLAGS}" +# don't add -lasr to LIBS, it's only added when needed +# LIBS="$LIBS -lasr" + AC_TRY_LINK_FUNC([asr_run], , + [ + AC_MSG_ERROR([*** libasr missing - please install first or check config.log ***]) + ] + ) + ] +) + + +# Search for fts +AC_ARG_WITH([libfts], + [ --with-libfts=PATH Specify path to libfts installation (default: none, part of libc)], + [ if test "x$withval" = "xno"; then + AC_MSG_ERROR([*** fts is required ***]) + elif test "x$withval" != "xyes"; then + if test -d "$withval/lib"; then + if test -n "${need_dash_r}"; then + LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}" + else + LDFLAGS="-L${withval}/lib ${LDFLAGS}" + fi + else + if test -n "${need_dash_r}"; then + LDFLAGS="-L${withval} -R${withval} ${LDFLAGS}" + else + LDFLAGS="-L${withval} ${LDFLAGS}" + fi + fi + if test -d "$withval/include"; then + CPPFLAGS="-I${withval}/include ${CPPFLAGS}" + else + CPPFLAGS="-I${withval} ${CPPFLAGS}" + fi + LIBS="-lfts $LIBS" + fi + ] +) + + + +##chl (based on OpenSSL checks, see above) +# Search for libevent +saved_CPPFLAGS="$CPPFLAGS" +saved_LDFLAGS="$LDFLAGS" +AC_ARG_WITH([libevent], + [ --with-libevent=PATH Specify path to libevent installation ], + [ + if test "x$withval" != "xno"; then + case "$withval" in + # Relative paths + ./*|../*) withval="`pwd`/$withval" + esac + if test -d "$withval/lib"; then + if test -n "${need_dash_r}"; then + LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}" + else + LDFLAGS="-L${withval}/lib ${LDFLAGS}" + fi + elif test -d "$withval/lib64"; then + if test -n "${need_dash_r}"; then + LDFLAGS="-L${withval}/lib64 -R${withval}/lib64 ${LDFLAGS}" + else + LDFLAGS="-L${withval}/lib64 ${LDFLAGS}" + fi + else + if test -n "${need_dash_r}"; then + LDFLAGS="-L${withval} -R${withval} ${LDFLAGS}" + else + LDFLAGS="-L${withval} ${LDFLAGS}" + fi + fi + if test -d "$withval/include"; then + CPPFLAGS="-I${withval}/include ${CPPFLAGS}" + else + CPPFLAGS="-I${withval} ${CPPFLAGS}" + fi + need_libevent_autodetect=no + fi + ] +) + +if test "x${need_libevent_autodetect}" != "xno"; then + for path in /usr/local /usr; do + if test -f "${path}/include/event.h"; then + CPPFLAGS="-I${path}/include ${CPPFLAGS}" + LDFLAGS="-L${path}/lib ${LDFLAGS}" + fi + done +fi + +LIBS="-levent $LIBS" + +AC_MSG_CHECKING([if programs using libevent functions will link]) +AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[ + #include <event.h> + ]], [[ + event_base_new(); + ]])], + [ + AC_MSG_RESULT([yes]) + ], + [ + AC_MSG_RESULT([no]) + ] +) + + +#l2174 (customized, bu adding -lssl to LIBS) +# Search for OpenSSL +saved_CPPFLAGS="$CPPFLAGS" +saved_LDFLAGS="$LDFLAGS" +AC_ARG_WITH([libssl], + [ --with-libssl=PATH Specify path to libssl installation ], + [ + if test "x$withval" != "xno"; then + case "$withval" in + # Relative paths + ./*|../*) withval="`pwd`/$withval" + esac + if test -d "$withval/lib"; then + if test -n "${need_dash_r}"; then + LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}" + else + LDFLAGS="-L${withval}/lib ${LDFLAGS}" + fi + elif test -d "$withval/lib64"; then + if test -n "${need_dash_r}"; then + LDFLAGS="-L${withval}/lib64 -R${withval}/lib64 ${LDFLAGS}" + else + LDFLAGS="-L${withval}/lib64 ${LDFLAGS}" + fi + else + if test -n "${need_dash_r}"; then + LDFLAGS="-L${withval} -R${withval} ${LDFLAGS}" + else + LDFLAGS="-L${withval} ${LDFLAGS}" + fi + fi + if test -d "$withval/include"; then + CPPFLAGS="-I${withval}/include ${CPPFLAGS}" + else + CPPFLAGS="-I${withval} ${CPPFLAGS}" + fi + fi + ] +) +## XXX chl -lssl manually added +LIBS="-lcrypto -lssl $LIBS" +AC_TRY_LINK_FUNC([RAND_add], [AC_DEFINE([HAVE_OPENSSL], [1], + [Define if your ssl headers are included + with #include <openssl/header.h>])], + [ + dnl Check default openssl install dir + if test -n "${need_dash_r}"; then + LDFLAGS="-L/usr/local/ssl/lib -R/usr/local/ssl/lib ${saved_LDFLAGS}" + else + LDFLAGS="-L/usr/local/ssl/lib ${saved_LDFLAGS}" + fi + CPPFLAGS="-I/usr/local/ssl/include ${saved_CPPFLAGS}" + AC_CHECK_HEADER([openssl/opensslv.h], , + [AC_MSG_ERROR([*** LibreSSL headers missing - please install first or check config.log ***])]) + AC_TRY_LINK_FUNC([RAND_add], [AC_DEFINE([HAVE_OPENSSL])], + [ + AC_MSG_ERROR([*** Can't find recent LibreSSL libcrypto (see config.log for details) ***]) + ] + ) + ] +) + + +# Sanity check OpenSSL headers +AC_MSG_CHECKING([whether LibreSSL's headers match the library]) +AC_RUN_IFELSE( + [AC_LANG_PROGRAM([[ +#include <stdlib.h> +#include <string.h> +#include <openssl/opensslv.h> +#include <openssl/crypto.h> + ]], [[ + exit(SSLeay() == OPENSSL_VERSION_NUMBER ? 0 : 1); + ]])], + [ + AC_MSG_RESULT([yes]) + ], + [ + AC_MSG_RESULT([no]) + AC_MSG_ERROR([Your LibreSSL headers do not match your library.]) + ], + [ + AC_MSG_WARN([cross compiling: not checking]) + ] +) + +AC_MSG_CHECKING([if programs using LibreSSL functions will link]) +AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[ #include <openssl/evp.h> ]], + [[ SSLeay_add_all_algorithms(); ]])], + [ + AC_MSG_RESULT([yes]) + ], + [ + AC_MSG_RESULT([no]) + saved_LIBS="$LIBS" + LIBS="$LIBS -ldl" + AC_MSG_CHECKING([if programs using LibreSSL need -ldl]) + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[ #include <openssl/evp.h> ]], + [[ SSLeay_add_all_algorithms(); ]])], + [ + AC_MSG_RESULT([yes]) + ], + [ + AC_MSG_RESULT([no]) + LIBS="$saved_LIBS" + ] + ) + ] +) +#l2371 + + +dnl zlib is required +AC_ARG_WITH([libz], + [ --with-libz=PATH Specify path to libz installation], + [ if test "x$withval" = "xno"; then + AC_MSG_ERROR([*** zlib is required ***]) + elif test "x$withval" != "xyes"; then + if test -d "$withval/lib"; then + if test -n "${need_dash_r}"; then + LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}" + else + LDFLAGS="-L${withval}/lib ${LDFLAGS}" + fi + else + if test -n "${need_dash_r}"; then + LDFLAGS="-L${withval} -R${withval} ${LDFLAGS}" + else + LDFLAGS="-L${withval} ${LDFLAGS}" + fi + fi + if test -d "$withval/include"; then + CPPFLAGS="-I${withval}/include ${CPPFLAGS}" + else + CPPFLAGS="-I${withval} ${CPPFLAGS}" + fi + fi ] +) + +AC_CHECK_HEADER([zlib.h], ,[AC_MSG_ERROR([*** zlib.h missing - please install first or check config.log ***])]) +AC_CHECK_LIB([z], [deflate], , + [ + saved_CPPFLAGS="$CPPFLAGS" + saved_LDFLAGS="$LDFLAGS" + save_LIBS="$LIBS" + dnl Check default zlib install dir + if test -n "${need_dash_r}"; then + LDFLAGS="-L/usr/local/lib -R/usr/local/lib ${saved_LDFLAGS}" + else + LDFLAGS="-L/usr/local/lib ${saved_LDFLAGS}" + fi + CPPFLAGS="-I/usr/local/include ${saved_CPPFLAGS}" + LIBS="$LIBS -lz" + AC_TRY_LINK_FUNC([deflate], [AC_DEFINE([HAVE_LIBZ])], + [ + AC_MSG_ERROR([*** zlib missing - please install first or check config.log ***]) + ] + ) + ] +) + + + + + +AC_ARG_WITH([table-db], + [ --with-table-db Enable building of table-db backend (default=no)], + [ + if test "x$withval" = "xyes"; then + use_db_api=1 + else + use_db_api=0 + fi + ] +) + +if test "x$use_db_api" = "x1"; then +# Search for libdb +AC_CHECK_HEADER(db_185.h, [AC_DEFINE([HAVE_DB_185_H], [], [if you have the <db_185.h> header file]) ] , [ +AC_CHECK_HEADER(db.h, [AC_DEFINE([HAVE_DB_H], [], [if you have the <db.h> header file]) ] , [ +AC_CHECK_HEADER(db1/db.h, [AC_DEFINE([HAVE_DB1_DB_H], [], [if you have the <db1/db.h> header file]) ] , [ + AC_MSG_ERROR([*** Can't find Berkeley DB headers (see config.log for details) ***]) +])])]) +fi + +save_LIBS="$LIBS" + +if test "x$use_db_api" = "x1"; then +DB_LIB= + +for libdb in db db1 c; do + AC_CHECK_LIB($libdb, dbopen, [ DB_LIB="$libdb"; break; ], + AC_CHECK_LIB($libdb, __db185_open, [ DB_LIB="$libdb"; break; ])) +done + +if test -z "$DB_LIB"; then + AC_MSG_ERROR([Berkeley DB not found or not built with --enable-185]) +fi + +DB_LIB="-l$DB_LIB" +AC_SUBST([DB_LIB]) +fi + +LIBS="$save_LIBS" + + +AM_CONDITIONAL([HAVE_DB_API], [test "x$use_db_api" = "x1"]) +AM_COND_IF([HAVE_DB_API], [AC_DEFINE([HAVE_DB_API], [1], [Define to 1 if HAVE_DB_API])]) + + + + +LIBS="$LIBS ${SMTPDLIBS}" +##end of chl + +AC_CONFIG_FILES([Makefile + openbsd-compat/Makefile + mk/Makefile + mk/mail/Makefile + mk/mail/mail.lmtp/Makefile + mk/mail/mail.maildir/Makefile + mk/mail/mail.mboxfile/Makefile + mk/mail/mail.mda/Makefile + mk/smtpd/Makefile + mk/smtpctl/Makefile + contrib/Makefile + contrib/libexec/Makefile + contrib/libexec/mail.local/Makefile + contrib/libexec/encrypt/Makefile + ]) + +#l4761 +AC_OUTPUT diff --git a/contrib/CVS/Entries b/contrib/CVS/Entries new file mode 100644 index 00000000..82a9d101 --- /dev/null +++ b/contrib/CVS/Entries @@ -0,0 +1,4 @@ +D/lib//// +D/libexec//// +/Makefile/-1.50/Mon Mar 5 11:15:41 2012// +/Makefile.inc/-1.2/Sun Jan 28 19:34:26 2001// diff --git a/contrib/CVS/Repository b/contrib/CVS/Repository new file mode 100644 index 00000000..31ac4266 --- /dev/null +++ b/contrib/CVS/Repository @@ -0,0 +1 @@ +src/libexec diff --git a/contrib/CVS/Root b/contrib/CVS/Root new file mode 100644 index 00000000..7040dfb5 --- /dev/null +++ b/contrib/CVS/Root @@ -0,0 +1 @@ +anoncvs@anoncvs.spacehopper.org:/cvs diff --git a/contrib/Makefile.am b/contrib/Makefile.am new file mode 100644 index 00000000..37a8e73a --- /dev/null +++ b/contrib/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = libexec diff --git a/contrib/libexec/CVS/Entries b/contrib/libexec/CVS/Entries new file mode 100644 index 00000000..cc09ac02 --- /dev/null +++ b/contrib/libexec/CVS/Entries @@ -0,0 +1,3 @@ +D/mail.local//// +/Makefile/1.50/Mon Jul 9 11:41:26 2012// +/Makefile.inc/1.2/Mon Jul 9 11:41:26 2012// diff --git a/contrib/libexec/CVS/Repository b/contrib/libexec/CVS/Repository new file mode 100644 index 00000000..31ac4266 --- /dev/null +++ b/contrib/libexec/CVS/Repository @@ -0,0 +1 @@ +src/libexec diff --git a/contrib/libexec/CVS/Root b/contrib/libexec/CVS/Root new file mode 100644 index 00000000..7040dfb5 --- /dev/null +++ b/contrib/libexec/CVS/Root @@ -0,0 +1 @@ +anoncvs@anoncvs.spacehopper.org:/cvs diff --git a/contrib/libexec/Makefile.am b/contrib/libexec/Makefile.am new file mode 100644 index 00000000..6079ae6a --- /dev/null +++ b/contrib/libexec/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = mail.local encrypt diff --git a/contrib/libexec/encrypt/Makefile.am b/contrib/libexec/encrypt/Makefile.am new file mode 100644 index 00000000..c1d8e1cb --- /dev/null +++ b/contrib/libexec/encrypt/Makefile.am @@ -0,0 +1,13 @@ +pkglibexec_PROGRAMS = encrypt + +encrypt_SOURCES = encrypt.c +encrypt_SOURCES += $(top_srcdir)/smtpd/log.c + +AM_CPPFLAGS = -I$(top_srcdir)/openbsd-compat + +LIBCOMPAT = $(top_builddir)/openbsd-compat/libopenbsd-compat.a + +LDADD = $(LIBCOMPAT) + +uninstall-hook: + rmdir $(DESTDIR)$(pkglibexecdir) 2> /dev/null || /bin/true diff --git a/contrib/libexec/encrypt/encrypt.c b/contrib/libexec/encrypt/encrypt.c new file mode 100644 index 00000000..80275921 --- /dev/null +++ b/contrib/libexec/encrypt/encrypt.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2013 Sunil Nimmagadda <sunil@sunilnimmagadda.com> + * Copyright (c) 2013 Gilles Chehade <gilles@poolp.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +#ifdef HAVE_CRYPT_H +#include <crypt.h> /* needed for crypt() */ +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#define PASSWORD_LEN 128 +#define SALT_LEN 16 + +static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +static void to64(char *, long int, int); +static void print_passwd(const char *); + +int +main(int argc, char *argv[]) +{ + char *line; + size_t linesz; + ssize_t linelen; + + if (argc > 2) { + fprintf(stderr, "usage: encrypt <string>\n"); + return (1); + } + + if (argc == 2) { + print_passwd(argv[1]); + return (0); + } + + line = NULL; + linesz = 0; + while ((linelen = getline(&line, &linesz, stdin)) != -1) { + if (line[linelen - 1] == '\n') + line[linelen - 1] = '\0'; + print_passwd(line); + } + free(line); + + return (0); +} + +void +print_passwd(const char *string) +{ + const char *ids[] = { "2a", "6", "5", "3", "2", "1", NULL }; + const char *id; + char salt[SALT_LEN+1]; + char buffer[PASSWORD_LEN]; + int n; + const char *p; + + for (n = 0; n < SALT_LEN; ++n) + to64(&salt[n], arc4random_uniform(0xff), 1); + salt[SALT_LEN] = '\0'; + + for (n = 0; ids[n]; n++) { + id = ids[n]; + (void)snprintf(buffer, sizeof buffer, "$%s$%s$", id, salt); + if ((p = crypt(string, buffer)) == NULL) + continue; + if (strncmp(p, buffer, strlen(buffer)) != 0) + continue; + printf("%s\n", p); + return; + } + + salt[2] = 0; + printf("%s\n", crypt(string, salt)); +} + +void +to64(char *s, long int v, int n) +{ + while (--n >= 0) { + *s++ = itoa64[v & 0x3f]; + v >>= 6; + } +} diff --git a/contrib/libexec/mail.local/CVS/Entries b/contrib/libexec/mail.local/CVS/Entries new file mode 100644 index 00000000..e02ca255 --- /dev/null +++ b/contrib/libexec/mail.local/CVS/Entries @@ -0,0 +1,7 @@ +/locking.c/1.10/Mon Jan 10 21:00:50 2011// +/mail.local.c/1.32/Tue Oct 27 23:59:31 2009// +/Makefile/1.3/Mon Jul 9 11:41:26 2012// +/mail.local.8/1.29/Mon Jul 9 11:36:35 2012// +/mail.local.h/1.5/Mon Jul 9 11:36:35 2012// +/pathnames.h/1.5/Mon Jul 9 11:36:35 2012// +D diff --git a/contrib/libexec/mail.local/CVS/Repository b/contrib/libexec/mail.local/CVS/Repository new file mode 100644 index 00000000..ca372a1e --- /dev/null +++ b/contrib/libexec/mail.local/CVS/Repository @@ -0,0 +1 @@ +src/libexec/mail.local diff --git a/contrib/libexec/mail.local/CVS/Root b/contrib/libexec/mail.local/CVS/Root new file mode 100644 index 00000000..7040dfb5 --- /dev/null +++ b/contrib/libexec/mail.local/CVS/Root @@ -0,0 +1 @@ +anoncvs@anoncvs.spacehopper.org:/cvs diff --git a/contrib/libexec/mail.local/Makefile.am b/contrib/libexec/mail.local/Makefile.am new file mode 100644 index 00000000..d15f59ec --- /dev/null +++ b/contrib/libexec/mail.local/Makefile.am @@ -0,0 +1,22 @@ +pkglibexec_PROGRAMS = mail.local + +mail_local_SOURCES = mail.local.c +mail_local_SOURCES += locking.c +mail_local_SOURCES += $(top_srcdir)/smtpd/log.c + +EXTRA_DIST = mail.local.h pathnames.h + +AM_CPPFLAGS = -I$(top_srcdir)/openbsd-compat + +LIBCOMPAT = $(top_builddir)/openbsd-compat/libopenbsd-compat.a + +LDADD = $(LIBCOMPAT) + +# need to define _GNU_SOURCE to get: +# EAI_NODATA defined +# {v,}asprintf +# setres{g,u}id +#CFLAGS += -D_GNU_SOURCE + +uninstall-hook: + rmdir $(DESTDIR)$(pkglibexecdir) 2> /dev/null || /bin/true diff --git a/contrib/libexec/mail.local/locking.c b/contrib/libexec/mail.local/locking.c new file mode 100644 index 00000000..ab6eb1a8 --- /dev/null +++ b/contrib/libexec/mail.local/locking.c @@ -0,0 +1,179 @@ +/* $OpenBSD: locking.c,v 1.10 2011/01/10 21:00:50 millert Exp $ */ + +/* + * Copyright (c) 1996-1998 Theo de Raadt <deraadt@theos.com> + * Copyright (c) 1996-1998 David Mazieres <dm@lcs.mit.edu> + * 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. The name of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``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 AUTHORS 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 "includes.h" + +#include <sys/param.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <pwd.h> +#include <syslog.h> +#include <time.h> +#include <unistd.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include "pathnames.h" +#include "mail.local.h" + +static char lpath[MAXPATHLEN]; + +void +rellock(void) +{ + + if (lpath[0]) + unlink(lpath); +} + +int +getlock(char *name, struct passwd *pw) +{ + struct stat sb, fsb; + int lfd=-1; + char buf[8*1024]; + int tries = 0; + + (void)snprintf(lpath, sizeof lpath, "%s/%s.lock", + _PATH_MAILDIR, name); + + if (stat(_PATH_MAILDIR, &sb) == -1) + merr(FATAL, "%s: %s", _PATH_MAILDIR, strerror(errno)); + if ((sb.st_mode & S_IWOTH) == S_IWOTH) { + /* + * We have a writeable spool, deal with it as + * securely as possible. + */ + time_t ctim = -1; + + seteuid(pw->pw_uid); + if (lstat(lpath, &sb) != -1) + ctim = sb.st_ctime; + while (1) { + /* + * Deal with existing user.lock files + * or directories or symbolic links that + * should not be here. + */ + if (readlink(lpath, buf, sizeof buf-1) != -1) { + if (lstat(lpath, &sb) != -1 && + S_ISLNK(sb.st_mode)) { + seteuid(sb.st_uid); + unlink(lpath); + seteuid(pw->pw_uid); + } + goto again; + } +#ifndef O_EXLOCK +#define O_EXLOCK 0 +#endif + if ((lfd = open(lpath, O_CREAT|O_WRONLY|O_EXCL|O_EXLOCK, + S_IRUSR|S_IWUSR)) != -1) + break; +#ifndef O_EXLOCK + /* XXX : do something! */ +#endif +again: + if (tries > 10) { + merr(NOTFATAL, "%s: %s", lpath, + strerror(errno)); + seteuid(0); + return(-1); + } + if (tries > 9 && + (lfd = open(lpath, O_WRONLY|O_EXLOCK, 0)) != -1) { + if (fstat(lfd, &fsb) != -1 && + lstat(lpath, &sb) != -1) { + if (fsb.st_dev == sb.st_dev && + fsb.st_ino == sb.st_ino && + ctim == fsb.st_ctime ) { + seteuid(fsb.st_uid); + baditem(lpath); + seteuid(pw->pw_uid); + } + } + } + sleep(1U << tries); + tries++; + continue; + } + seteuid(0); + } else { + /* + * Only root can write the spool directory. + */ + while (1) { + if ((lfd = open(lpath, O_CREAT|O_WRONLY|O_EXCL, + S_IRUSR|S_IWUSR)) != -1) + break; + if (tries > 9) { + merr(NOTFATAL, "%s: %s", lpath, strerror(errno)); + return(-1); + } + sleep(1U << tries); + tries++; + } + } + return(lfd); +} + +void +baditem(char *path) +{ + char npath[MAXPATHLEN]; + int fd; + + if (unlink(path) == 0) + return; + snprintf(npath, sizeof npath, "%s/mailXXXXXXXXXX", _PATH_MAILDIR); + if ((fd = mkstemp(npath)) == -1) + return; + close(fd); + if (rename(path, npath) == -1) + unlink(npath); + else + merr(NOTFATAL, "nasty spool item %s renamed to %s", + path, npath); + /* XXX if we fail to rename, another attempt will happen later */ +} + +void +merr(int isfatal, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vsyslog(LOG_ERR, fmt, ap); + va_end(ap); + if (isfatal) + exit(1); +} diff --git a/contrib/libexec/mail.local/mail.local.8 b/contrib/libexec/mail.local/mail.local.8 new file mode 100644 index 00000000..f77fa6da --- /dev/null +++ b/contrib/libexec/mail.local/mail.local.8 @@ -0,0 +1,183 @@ +.\" $OpenBSD: mail.local.8,v 1.29 2010/09/03 11:35:08 jmc Exp $ +.\" Copyright (c) 1990 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. 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. +.\" +.\" from: @(#)mail.local.8 6.8 (Berkeley) 4/27/91 +.\" +.Dd $Mdocdate: September 3 2010 $ +.Dt MAIL.LOCAL 8 +.Os +.Sh NAME +.Nm mail.local +.Nd store mail in a mailbox +.Sh SYNOPSIS +.Nm mail.local +.Op Fl Ll +.Op Fl f Ar from +.Ar user ... +.Sh DESCRIPTION +.Nm +reads the standard input up to an end-of-file and appends it to each +.Ar user Ns 's +.Pa mail +file. +The +.Ar user +must be a valid user name. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl f Ar from +Specify the sender's name. +.It Fl L +Don't create a +.Pa username.lock +file while locking the spool. +.It Fl l +For compatibility, request that files named +.Pa username.lock +be used for locking. +(This is the default behavior.) +.El +.Pp +Individual mail messages in the mailbox are delimited by an empty +line followed by a line beginning with the string +.Dq "From\&\ " . +A line containing the string +.Dq "From\&\ " , +the sender's name and a timestamp is prepended to each delivered mail message. +A blank line is appended to each message. +A greater-than character +.Pq Ql > +is prepended to any line in the message which could be mistaken for a +.Dq "From\&\ " +delimiter line. +.Pp +Significant efforts have been made to ensure that +.Nm +acts as securely as possible if the spool directory is mode 1777 or 755. +The default of mode 755 is more secure, but it prevents mail clients from using +.Pa username.lock +style locking. +The use of 1777 is more flexible in an NFS shared-spool environment, +so many sites use it. +However, it does carry some risks, such as attackers filling the spool disk. +Some of these problems may be alleviated +by making the spool a separate filesystem, and placing quotas on it. +The use of any mode other than 1777 and 755 for the spool directory is +recommended against but may work properly. +.Pp +The mailbox is always locked using +.Xr flock 2 +while mail is appended. +Unless the +.Fl L +flag is specified, a +.Pa username.lock +file is also used. +.Pp +If the +.Xr biff 1 +service is returned by +.Xr getservbyname 3 , +the biff server is notified of delivered mail. +.Sh ENVIRONMENT +.Bl -tag -width indent +.It Ev TZ +Used to set the appropriate time zone on the timestamp. +.El +.Sh FILES +.Bl -tag -width /tmp/local.XXXXXXXXXX -compact +.It Pa /tmp/local.XXXXXXXXXX +temporary files +.It Pa /var/mail/user +user's mailbox directory +.El +.Sh EXIT STATUS +.Ex -std mail.local +.Sh SEE ALSO +.Xr biff 1 , +.Xr mail 1 , +.Xr flock 2 , +.Xr getservbyname 3 , +.Xr comsat 8 , +.Xr sendmail 8 +.Sh HISTORY +A superset of +.Nm +(handling mailbox reading as well as mail delivery) appeared in +.At v7 +as the program +.Xr mail 1 . +.Sh BUGS +Since +.Xr sendmail 8 +bases its idea of whether a message has been delivered or not +on the return value from +.Nm mail.local , +using quotas in +.Pa /var/mail +can be problematic. +By default, +.Xr sendmail 8 +will ask +.Nm +to deliver a message to multiple recipients if possible. +This causes problems in a quota environment since a message may be +delivered to some users but not others due to disk quotas. +Even though the message was delivered to some of the recipients, +.Nm +will exit with an exit code > 0, causing +.Xr sendmail 8 +to attempt redelivery later. +That means that some users will keep getting the same message every time +.Xr sendmail 8 +runs its queue. +.Pp +If you are running with disk quotas on +.Pa /var/mail +it is imperative that you unset the +.Dq m +mailer flag for the +.Sq local +mailer. +To do this, locate the line beginning with +.Dq Mlocal +in +.Pa /etc/mail/sendmail.cf +and remove the +.Dq m +from the flags section, denoted by +.Dq F= . +Alternately, you can override the default mailer flags by adding the line: +.Pp +.Dl define(`LOCAL_MAILER_FLAGS', `rn9S')dnl +.Pp +to your +.Dq \.mc +file (this is the source file that is used to generate +.Pa /etc/mail/sendmail.cf ) . diff --git a/contrib/libexec/mail.local/mail.local.c b/contrib/libexec/mail.local/mail.local.c new file mode 100644 index 00000000..d1f7d2f2 --- /dev/null +++ b/contrib/libexec/mail.local/mail.local.c @@ -0,0 +1,327 @@ +/* $OpenBSD: mail.local.c,v 1.32 2009/10/27 23:59:31 deraadt Exp $ */ + +/*- + * Copyright (c) 1996-1998 Theo de Raadt <deraadt@theos.com> + * Copyright (c) 1996-1998 David Mazieres <dm@lcs.mit.edu> + * Copyright (c) 1990 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. 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 "includes.h" + +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <syslog.h> +#include <fcntl.h> +#include <netdb.h> +#include <pwd.h> +#include <time.h> +#include <unistd.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "pathnames.h" +#include "mail.local.h" + +int +main(int argc, char *argv[]) +{ + struct passwd *pw; + int ch, fd, eval, lockfile=1, holdme=0; + uid_t uid; + char *from; + + openlog("mail.local", LOG_PERROR, LOG_MAIL); + + from = NULL; + while ((ch = getopt(argc, argv, "lLdf:r:H")) != -1) + switch (ch) { + case 'd': /* backward compatible */ + break; + case 'f': + case 'r': /* backward compatible */ + if (from) + merr(FATAL, "multiple -f options"); + from = optarg; + break; + case 'l': + lockfile=1; + break; + case 'L': + lockfile=0; + break; + case 'H': + holdme=1; + break; + default: + usage(); + } + argc -= optind; + argv += optind; + + /* Support -H flag for backwards compat */ + if (holdme) { + execl(_PATH_LOCKSPOOL, "lockspool", (char *)NULL); + merr(FATAL, "execl: lockspool: %s", strerror(errno)); + } else { + if (!*argv) + usage(); + if (geteuid() != 0) + merr(FATAL, "may only be run by the superuser"); + } + + /* + * If from not specified, use the name from getlogin() if the + * uid matches, otherwise, use the name from the password file + * corresponding to the uid. + */ + uid = getuid(); + if (!from && (!(from = getlogin()) || + !(pw = getpwnam(from)) || pw->pw_uid != uid)) + from = (pw = getpwuid(uid)) ? pw->pw_name : "???"; + + fd = storemail(from); + for (eval = 0; *argv; ++argv) + eval |= deliver(fd, *argv, lockfile); + exit(eval); +} + +int +storemail(char *from) +{ + FILE *fp = NULL; + time_t tval; + int fd, eline; + ssize_t len; + size_t linesz; + char *line, *tbuf; + + if ((tbuf = strdup(_PATH_LOCTMP)) == NULL) + merr(FATAL, "unable to allocate memory"); + if ((fd = mkstemp(tbuf)) == -1 || !(fp = fdopen(fd, "w+"))) + merr(FATAL, "unable to open temporary file"); + (void)unlink(tbuf); + free(tbuf); + + (void)time(&tval); + (void)fprintf(fp, "From %s %s", from, ctime(&tval)); + + for (eline = 1, line = NULL, linesz = 0; + (len = getline(&line, &linesz, stdin)) != -1;) { + if (line[len - 1] == '\n') + line[--len] = '\0'; + if (line[0] == '\0') + eline = 1; + else { + if (eline && line[0] == 'F' && len > 5 && + !memcmp(line, "From ", 5)) + (void)putc('>', fp); + eline = 0; + } + (void)fprintf(fp, "%s\n", line); + if (ferror(fp)) + break; + } + free(line); + + /* Output a newline; note, empty messages are allowed. */ + (void)putc('\n', fp); + (void)fflush(fp); + if (ferror(fp)) + merr(FATAL, "temporary file write error"); + return(fd); +} + +int +deliver(int fd, char *name, int lockfile) +{ + struct stat sb, fsb; + struct passwd *pw; + int mbfd=-1, rval=1, lfd=-1; + char biffmsg[100], buf[8*1024], path[MAXPATHLEN]; + off_t curoff; + size_t off; + ssize_t nr, nw; + + /* + * Disallow delivery to unknown names -- special mailboxes can be + * handled in the sendmail aliases file. + */ + if (!(pw = getpwnam(name))) { + merr(NOTFATAL, "unknown name: %s", name); + return(1); + } + + (void)snprintf(path, sizeof path, "%s/%s", _PATH_MAILDIR, name); + + if (lockfile) { + lfd = getlock(name, pw); + if (lfd == -1) + return (1); + } + + /* after this point, always exit via bad to remove lockfile */ +retry: + if (lstat(path, &sb)) { + if (errno != ENOENT) { + merr(NOTFATAL, "%s: %s", path, strerror(errno)); + goto bad; + } +#ifndef O_EXLOCK +#define O_EXLOCK 0 +#endif + if ((mbfd = open(path, O_APPEND|O_CREAT|O_EXCL|O_WRONLY|O_EXLOCK, + S_IRUSR|S_IWUSR)) < 0) { +#ifndef HAVE_O_EXLOCK + /* XXX : do something! */ +#endif + if (errno == EEXIST) { + /* file appeared since lstat */ + goto retry; + } else { + merr(NOTFATAL, "%s: %s", path, strerror(errno)); + goto bad; + } + } + /* + * Set the owner and group. Historically, binmail repeated + * this at each mail delivery. We no longer do this, assuming + * that if the ownership or permissions were changed there + * was a reason for doing so. + */ + if (fchown(mbfd, pw->pw_uid, pw->pw_gid) < 0) { + merr(NOTFATAL, "chown %u:%u: %s", + pw->pw_uid, pw->pw_gid, name); + goto bad; + } + } else { + if (sb.st_nlink != 1 || !S_ISREG(sb.st_mode)) { + merr(NOTFATAL, "%s: linked or special file", path); + goto bad; + } + if ((mbfd = open(path, O_APPEND|O_WRONLY|O_EXLOCK, + S_IRUSR|S_IWUSR)) < 0) { + merr(NOTFATAL, "%s: %s", path, strerror(errno)); + goto bad; + } + if (fstat(mbfd, &fsb)) { + /* relating error to path may be bad style */ + merr(NOTFATAL, "%s: %s", path, strerror(errno)); + goto bad; + } + if (sb.st_dev != fsb.st_dev || sb.st_ino != fsb.st_ino) { + merr(NOTFATAL, "%s: changed after open", path); + goto bad; + } + /* paranoia? */ + if (fsb.st_nlink != 1 || !S_ISREG(fsb.st_mode)) { + merr(NOTFATAL, "%s: linked or special file", path); + goto bad; + } + } + + curoff = lseek(mbfd, 0, SEEK_END); + (void)snprintf(biffmsg, sizeof biffmsg, "%s@%qd\n", name, + (long long int) curoff); + if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { + merr(NOTFATAL, "temporary file: %s", strerror(errno)); + goto bad; + } + + while ((nr = read(fd, buf, sizeof(buf))) > 0) + for (off = 0; off < (size_t)nr; off += nw) + if ((nw = write(mbfd, buf + off, nr - off)) < 0) { + merr(NOTFATAL, "%s: %s", path, strerror(errno)); + (void)ftruncate(mbfd, curoff); + goto bad; + } + + if (nr == 0) { + rval = 0; + } else { + (void)ftruncate(mbfd, curoff); + merr(FATAL, "temporary file: %s", strerror(errno)); + } + +bad: + if (lfd != -1) { + rellock(); + close(lfd); + } + + if (mbfd != -1) { + (void)fsync(mbfd); /* Don't wait for update. */ + (void)close(mbfd); /* Implicit unlock. */ + } + + if (!rval) + notifybiff(biffmsg); + return(rval); +} + +void +notifybiff(char *msg) +{ + static struct sockaddr_in addr; + static int f = -1; + struct hostent *hp; + struct servent *sp; + size_t len; + + if (!addr.sin_family) { + /* Be silent if biff service not available. */ + if (!(sp = getservbyname("biff", "udp"))) + return; + if (!(hp = gethostbyname("localhost"))) { + merr(NOTFATAL, "localhost: %s", strerror(errno)); + return; + } +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN + addr.sin_len = sizeof(struct sockaddr_in); +#endif + addr.sin_family = hp->h_addrtype; + addr.sin_port = sp->s_port; + bcopy(hp->h_addr, &addr.sin_addr, (size_t)hp->h_length); + } + if (f < 0 && (f = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + merr(NOTFATAL, "socket: %s", strerror(errno)); + return; + } + len = strlen(msg) + 1; + if (sendto(f, msg, len, 0, (struct sockaddr *)&addr, sizeof(addr)) + != (ssize_t)len) + merr(NOTFATAL, "sendto biff: %s", strerror(errno)); +} + +void +usage(void) +{ + merr(FATAL, "usage: mail.local [-Ll] [-f from] user ..."); +} diff --git a/contrib/libexec/mail.local/mail.local.h b/contrib/libexec/mail.local/mail.local.h new file mode 100644 index 00000000..0377aa20 --- /dev/null +++ b/contrib/libexec/mail.local/mail.local.h @@ -0,0 +1,42 @@ +/* $OpenBSD: mail.local.h,v 1.5 2006/04/01 22:48:57 deraadt Exp $ */ + +/*- + * Copyright (c) 1990 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. 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. + */ + +#define FATAL 1 +#define NOTFATAL 0 + +void baditem(char *); +int deliver(int, char *, int); +void merr(int, const char *, ...); +int getlock(char *, struct passwd *); +void notifybiff(char *); +void rellock(void); +int storemail(char *); +void usage(void); diff --git a/contrib/libexec/mail.local/pathnames.h b/contrib/libexec/mail.local/pathnames.h new file mode 100644 index 00000000..a39a6c90 --- /dev/null +++ b/contrib/libexec/mail.local/pathnames.h @@ -0,0 +1,38 @@ +/* $OpenBSD: pathnames.h,v 1.5 2003/06/02 19:38:24 millert Exp $*/ + +/*- + * Copyright (c) 1990 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. 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. + * + * from: @(#)pathnames.h 5.3 (Berkeley) 1/17/91 + */ +#ifdef HAVE_PATHS_H +#include <paths.h> +#endif + +#define _PATH_LOCTMP "/tmp/local.XXXXXXXXXX" +#define _PATH_LOCKSPOOL "/usr/libexec/lockspool" diff --git a/docker-compose.test.yml b/docker-compose.test.yml new file mode 100644 index 00000000..b86b38a5 --- /dev/null +++ b/docker-compose.test.yml @@ -0,0 +1,6 @@ +sut: + build: . + #This means we are using the build container, not the final container + target: build + entrypoint: /bin/sh + command: /opensmtpd/tests/test_all.sh diff --git a/m4/aclocal-openssh.m4 b/m4/aclocal-openssh.m4 new file mode 100644 index 00000000..2944bb99 --- /dev/null +++ b/m4/aclocal-openssh.m4 @@ -0,0 +1,179 @@ +dnl $Id: aclocal.m4,v 1.13 2014/01/22 10:30:12 djm Exp $ +dnl +dnl OpenSSH-specific autoconf macros +dnl + +dnl OSSH_CHECK_CFLAG_COMPILE(check_flag[, define_flag]) +dnl Check that $CC accepts a flag 'check_flag'. If it is supported append +dnl 'define_flag' to $CFLAGS. If 'define_flag' is not specified, then append +dnl 'check_flag'. +AC_DEFUN([OSSH_CHECK_CFLAG_COMPILE], [{ + AC_MSG_CHECKING([if $CC supports compile flag $1]) + saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $WERROR $1" + _define_flag="$2" + test "x$_define_flag" = "x" && _define_flag="$1" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ +#include <stdlib.h> +#include <stdio.h> +int main(int argc, char **argv) { + /* Some math to catch -ftrapv problems in the toolchain */ + int i = 123 * argc, j = 456 + argc, k = 789 - argc; + float l = i * 2.1; + double m = l / 0.5; + long long int n = argc * 12345LL, o = 12345LL * (long long int)argc; + printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o); + exit(0); +} + ]])], + [ +if `grep -i "unrecognized option" conftest.err >/dev/null` +then + AC_MSG_RESULT([no]) + CFLAGS="$saved_CFLAGS" +else + AC_MSG_RESULT([yes]) + CFLAGS="$saved_CFLAGS $_define_flag" +fi], + [ AC_MSG_RESULT([no]) + CFLAGS="$saved_CFLAGS" ] + ) +}]) + +dnl OSSH_CHECK_CFLAG_LINK(check_flag[, define_flag]) +dnl Check that $CC accepts a flag 'check_flag'. If it is supported append +dnl 'define_flag' to $CFLAGS. If 'define_flag' is not specified, then append +dnl 'check_flag'. +AC_DEFUN([OSSH_CHECK_CFLAG_LINK], [{ + AC_MSG_CHECKING([if $CC supports compile flag $1 and linking succeeds]) + saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $WERROR $1" + _define_flag="$2" + test "x$_define_flag" = "x" && _define_flag="$1" + AC_LINK_IFELSE([AC_LANG_SOURCE([[ +#include <stdlib.h> +#include <stdio.h> +int main(int argc, char **argv) { + /* Some math to catch -ftrapv problems in the toolchain */ + int i = 123 * argc, j = 456 + argc, k = 789 - argc; + float l = i * 2.1; + double m = l / 0.5; + long long int n = argc * 12345LL, o = 12345LL * (long long int)argc; + printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o); + exit(0); +} + ]])], + [ +if `grep -i "unrecognized option" conftest.err >/dev/null` +then + AC_MSG_RESULT([no]) + CFLAGS="$saved_CFLAGS" +else + AC_MSG_RESULT([yes]) + CFLAGS="$saved_CFLAGS $_define_flag" +fi], + [ AC_MSG_RESULT([no]) + CFLAGS="$saved_CFLAGS" ] + ) +}]) + +dnl OSSH_CHECK_LDFLAG_LINK(check_flag[, define_flag]) +dnl Check that $LD accepts a flag 'check_flag'. If it is supported append +dnl 'define_flag' to $LDFLAGS. If 'define_flag' is not specified, then append +dnl 'check_flag'. +AC_DEFUN([OSSH_CHECK_LDFLAG_LINK], [{ + AC_MSG_CHECKING([if $LD supports link flag $1]) + saved_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $WERROR $1" + _define_flag="$2" + test "x$_define_flag" = "x" && _define_flag="$1" + AC_LINK_IFELSE([AC_LANG_SOURCE([[ +#include <stdlib.h> +#include <stdio.h> +int main(int argc, char **argv) { + /* Some math to catch -ftrapv problems in the toolchain */ + int i = 123 * argc, j = 456 + argc, k = 789 - argc; + float l = i * 2.1; + double m = l / 0.5; + long long int n = argc * 12345LL, o = 12345LL * (long long int)argc; + printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o); + exit(0); +} + ]])], + [ AC_MSG_RESULT([yes]) + LDFLAGS="$saved_LDFLAGS $_define_flag"], + [ AC_MSG_RESULT([no]) + LDFLAGS="$saved_LDFLAGS" ] + ) +}]) + +dnl OSSH_CHECK_HEADER_FOR_FIELD(field, header, symbol) +dnl Does AC_EGREP_HEADER on 'header' for the string 'field' +dnl If found, set 'symbol' to be defined. Cache the result. +dnl TODO: This is not foolproof, better to compile and read from there +AC_DEFUN([OSSH_CHECK_HEADER_FOR_FIELD], [ +# look for field '$1' in header '$2' + dnl This strips characters illegal to m4 from the header filename + ossh_safe=`echo "$2" | sed 'y%./+-%__p_%'` + dnl + ossh_varname="ossh_cv_$ossh_safe""_has_"$1 + AC_MSG_CHECKING(for $1 field in $2) + AC_CACHE_VAL($ossh_varname, [ + AC_EGREP_HEADER($1, $2, [ dnl + eval "$ossh_varname=yes" dnl + ], [ dnl + eval "$ossh_varname=no" dnl + ]) dnl + ]) + ossh_result=`eval 'echo $'"$ossh_varname"` + if test -n "`echo $ossh_varname`"; then + AC_MSG_RESULT($ossh_result) + if test "x$ossh_result" = "xyes"; then + AC_DEFINE($3, 1, [Define if you have $1 in $2]) + fi + else + AC_MSG_RESULT(no) + fi +]) + +dnl Check for socklen_t: historically on BSD it is an int, and in +dnl POSIX 1g it is a type of its own, but some platforms use different +dnl types for the argument to getsockopt, getpeername, etc. So we +dnl have to test to find something that will work. +AC_DEFUN([TYPE_SOCKLEN_T], +[ + AC_CHECK_TYPE([socklen_t], ,[ + AC_MSG_CHECKING([for socklen_t equivalent]) + AC_CACHE_VAL([curl_cv_socklen_t_equiv], + [ + # Systems have either "struct sockaddr *" or + # "void *" as the second argument to getpeername + curl_cv_socklen_t_equiv= + for arg2 in "struct sockaddr" void; do + for t in int size_t unsigned long "unsigned long"; do + AC_TRY_COMPILE([ + #include <sys/types.h> + #include <sys/socket.h> + + int getpeername (int, $arg2 *, $t *); + ],[ + $t len; + getpeername(0,0,&len); + ],[ + curl_cv_socklen_t_equiv="$t" + break + ]) + done + done + + if test "x$curl_cv_socklen_t_equiv" = x; then + AC_MSG_ERROR([Cannot find a type to use in place of socklen_t]) + fi + ]) + AC_MSG_RESULT($curl_cv_socklen_t_equiv) + AC_DEFINE_UNQUOTED(socklen_t, $curl_cv_socklen_t_equiv, + [type to use in place of socklen_t if not defined])], + [#include <sys/types.h> +#include <sys/socket.h>]) +]) + diff --git a/mk/Makefile.am b/mk/Makefile.am new file mode 100644 index 00000000..15261a41 --- /dev/null +++ b/mk/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = smtpd +SUBDIRS += smtpctl +SUBDIRS += mail diff --git a/mk/mail/Makefile.am b/mk/mail/Makefile.am new file mode 100644 index 00000000..cc6d96cb --- /dev/null +++ b/mk/mail/Makefile.am @@ -0,0 +1,5 @@ +SUBDIRS = mail.lmtp +SUBDIRS += mail.maildir +SUBDIRS += mail.mboxfile +SUBDIRS += mail.mda + diff --git a/mk/mail/mail.lmtp/Makefile.am b/mk/mail/mail.lmtp/Makefile.am new file mode 100644 index 00000000..181d2d0b --- /dev/null +++ b/mk/mail/mail.lmtp/Makefile.am @@ -0,0 +1,22 @@ +include $(top_srcdir)/mk/pathnames + +pkglibexec_PROGRAMS = mail.lmtp + +mail_lmtp_SOURCES = $(smtpd_srcdir)/mail.lmtp.c +mail_lmtp_SOURCES+= $(smtpd_srcdir)/log.c + +AM_CPPFLAGS= -I$(top_srcdir)/smtpd \ + -I$(top_srcdir)/openbsd-compat +if !SUPPORT_ERR_H +AM_CPPFLAGS += -I$(top_srcdir)/openbsd-compat/err_h +endif + +LIBCOMPAT = $(top_builddir)/openbsd-compat/libopenbsd-compat.a + +LDADD = $(LIBCOMPAT) + + + + +uninstall-hook: + rmdir $(DESTDIR)$(pkglibexecdir) 2> /dev/null || /bin/true diff --git a/mk/mail/mail.maildir/Makefile.am b/mk/mail/mail.maildir/Makefile.am new file mode 100644 index 00000000..923ff83b --- /dev/null +++ b/mk/mail/mail.maildir/Makefile.am @@ -0,0 +1,22 @@ +include $(top_srcdir)/mk/pathnames + +pkglibexec_PROGRAMS = mail.maildir + +mail_maildir_SOURCES = $(smtpd_srcdir)/mail.maildir.c +mail_maildir_SOURCES+= $(smtpd_srcdir)/log.c + +AM_CPPFLAGS= -I$(top_srcdir)/smtpd \ + -I$(top_srcdir)/openbsd-compat +if !SUPPORT_ERR_H +AM_CPPFLAGS += -I$(top_srcdir)/openbsd-compat/err_h +endif + +LIBCOMPAT = $(top_builddir)/openbsd-compat/libopenbsd-compat.a + +LDADD = $(LIBCOMPAT) + + + + +uninstall-hook: + rmdir $(DESTDIR)$(pkglibexecdir) 2> /dev/null || /bin/true diff --git a/mk/mail/mail.mboxfile/Makefile.am b/mk/mail/mail.mboxfile/Makefile.am new file mode 100644 index 00000000..b7675101 --- /dev/null +++ b/mk/mail/mail.mboxfile/Makefile.am @@ -0,0 +1,22 @@ +include $(top_srcdir)/mk/pathnames + +pkglibexec_PROGRAMS = mail.mboxfile + +mail_mboxfile_SOURCES = $(smtpd_srcdir)/mail.mboxfile.c +mail_mboxfile_SOURCES+= $(smtpd_srcdir)/log.c + +AM_CPPFLAGS= -I$(top_srcdir)/smtpd \ + -I$(top_srcdir)/openbsd-compat +if !SUPPORT_ERR_H +AM_CPPFLAGS += -I$(top_srcdir)/openbsd-compat/err_h +endif + +LIBCOMPAT = $(top_builddir)/openbsd-compat/libopenbsd-compat.a + +LDADD = $(LIBCOMPAT) + + + + +uninstall-hook: + rmdir $(DESTDIR)$(pkglibexecdir) 2> /dev/null || /bin/true diff --git a/mk/mail/mail.mda/Makefile.am b/mk/mail/mail.mda/Makefile.am new file mode 100644 index 00000000..29e2ec2c --- /dev/null +++ b/mk/mail/mail.mda/Makefile.am @@ -0,0 +1,22 @@ +include $(top_srcdir)/mk/pathnames + +pkglibexec_PROGRAMS = mail.mda + +mail_mda_SOURCES = $(smtpd_srcdir)/mail.mda.c +mail_mda_SOURCES+= $(smtpd_srcdir)/log.c + +AM_CPPFLAGS= -I$(top_srcdir)/smtpd \ + -I$(top_srcdir)/openbsd-compat +if !SUPPORT_ERR_H +AM_CPPFLAGS += -I$(top_srcdir)/openbsd-compat/err_h +endif + +LIBCOMPAT = $(top_builddir)/openbsd-compat/libopenbsd-compat.a + +LDADD = $(LIBCOMPAT) + + + + +uninstall-hook: + rmdir $(DESTDIR)$(pkglibexecdir) 2> /dev/null || /bin/true diff --git a/mk/mdoc2man.awk b/mk/mdoc2man.awk new file mode 100644 index 00000000..726f628c --- /dev/null +++ b/mk/mdoc2man.awk @@ -0,0 +1,391 @@ +#!/usr/bin/awk +# +# Copyright (c) 2003 Peter Stuge <stuge-mdoc2man@cdy.org> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +# Dramatically overhauled by Tim Kientzle. This version almost +# handles library-style pages with Fn, Ft, etc commands. Still +# a lot of problems... + +BEGIN { + displaylines = 0 + trailer = "" + out = "" + sep = "" + nextsep = " " +} + +# Add a word with appropriate preceding whitespace +# Maintain a short queue of the expected upcoming word separators. +function add(str) { + out=out sep str + sep = nextsep + nextsep = " " +} + +# Add a word with no following whitespace +# Use for opening punctuation such as '(' +function addopen(str) { + add(str) + sep = "" +} + +# Add a word with no preceding whitespace +# Use for closing punctuation such as ')' or '.' +function addclose(str) { + sep = "" + add(str) +} + +# Add a word with no space before or after +# Use for separating punctuation such as '=' +function addpunct(str) { + sep = "" + add(str) + sep = "" +} + +# Emit the current line so far +function endline() { + addclose(trailer) + trailer = "" + if(length(out) > 0) { + print out + out="" + } + if(displaylines > 0) { + displaylines = displaylines - 1 + if (displaylines == 0) + dispend() + } + # First word on next line has no preceding whitespace + sep = "" +} + +function linecmd(cmd) { + endline() + add(cmd) + endline() +} + +function breakline() { + linecmd(".br") +} + +# Start an indented display +function dispstart() { + linecmd(".RS 4") +} + +# End an indented display +function dispend() { + linecmd(".RE") +} + +# Collect rest of input line +function wtail() { + retval="" + while(w<nwords) { + if(length(retval)) + retval=retval " " + retval=retval words[++w] + } + return retval +} + +function splitwords(l, dest, n, o, w) { + n = 1 + delete dest + while (length(l) > 0) { + sub("^[ \t]*", "", l) + if (match(l, "^\"")) { + l = substr(l, 2) + o = index(l, "\"") + if (o > 0) { + w = substr(l, 1, o-1) + l = substr(l, o+1) + dest[n++] = w + } else { + dest[n++] = l + l = "" + } + } else { + o = match(l, "[ \t]") + if (o > 0) { + w = substr(l, 1, o-1) + l = substr(l, o+1) + dest[n++] = w + } else { + dest[n++] = l + l = "" + } + } + } + return n-1 +} + +! /^\./ { + out = $0 + endline() + next +} + +/^\.\\"/ { next } + +{ + sub("^\\.","") + nwords=splitwords($0, words) + # TODO: Instead of iterating 'w' over the array, have a separate + # function that returns 'next word' and use that. This will allow + # proper handling of double-quoted arguments as well. + for(w=1;w<=nwords;w++) { + if(match(words[w],"^Li$")) { # Literal; rest of line is unformatted + dispstart() + displaylines = 1 + } else if(match(words[w],"^Dl$")) { # Display literal + dispstart() + displaylines = 1 + } else if(match(words[w],"^Bd$")) { # Begin display + if(match(words[w+1],"-literal")) { + dispstart() + linecmd(".nf") + displaylines=10000 + w=nwords + } + } else if(match(words[w],"^Ed$")) { # End display + displaylines = 0 + dispend() + } else if(match(words[w],"^Ns$")) { # Suppress space after next word + nextsep = "" + } else if(match(words[w],"^No$")) { # Normal text + add(words[++w]) + } else if(match(words[w],"^Dq$")) { # Quote + addopen("``") + add(words[++w]) + while(w<nwords&&!match(words[w+1],"^[\\.,]")) + add(words[++w]) + addclose("''") + } else if(match(words[w],"^Do$")) { + addopen("``") + } else if(match(words[w],"^Dc$")) { + addclose("''") + } else if(match(words[w],"^Oo$")) { + addopen("[") + } else if(match(words[w],"^Oc$")) { + addclose("]") + } else if(match(words[w],"^Ao$")) { + addopen("<") + } else if(match(words[w],"^Ac$")) { + addclose(">") + } else if(match(words[w],"^Dd$")) { + date=wtail() + next + } else if(match(words[w],"^Dt$")) { + id=wtail() + next + } else if(match(words[w],"^Ox$")) { + add("OpenBSD") + } else if(match(words[w],"^Fx$")) { + add("FreeBSD") + } else if(match(words[w],"^Nx$")) { + add("NetBSD") + } else if(match(words[w],"^St$")) { + if (match(words[w+1], "^-p1003.1$")) { + w++ + add("IEEE Std 1003.1 (``POSIX.1'')") + } else if(match(words[w+1], "^-p1003.1-96$")) { + w++ + add("ISO/IEC 9945-1:1996 (``POSIX.1'')") + } else if(match(words[w+1], "^-p1003.1-88$")) { + w++ + add("IEEE Std 1003.1-1988 (``POSIX.1'')") + } else if(match(words[w+1], "^-p1003.1-2001$")) { + w++ + add("IEEE Std 1003.1-2001 (``POSIX.1'')") + } else if(match(words[w+1], "^-susv2$")) { + w++ + add("Version 2 of the Single UNIX Specification (``SUSv2'')") + } + } else if(match(words[w],"^Ex$")) { + if (match(words[w+1], "^-std$")) { + w++ + add("The \\fB" name "\\fP utility exits 0 on success, and >0 if an error occurs.") + } + } else if(match(words[w],"^Os$")) { + add(".TH " id " \"" date "\" \"" wtail() "\"") + } else if(match(words[w],"^Sh$")) { + section=wtail() + add(".SH " section) + linecmd(".ad l") + } else if(match(words[w],"^Xr$")) { + add("\\fB" words[++w] "\\fP(" words[++w] ")" words[++w]) + } else if(match(words[w],"^Nm$")) { + if(match(section,"SYNOPSIS")) + breakline() + if(w >= nwords) + n=name + else if (match(words[w+1], "^[A-Z][a-z]$")) + n=name + else if (match(words[w+1], "^[.,;:]$")) + n=name + else { + n=words[++w] + if(!length(name)) + name=n + } + if(!length(n)) + n=name + add("\\fB\\%" n "\\fP") + } else if(match(words[w],"^Nd$")) { + add("\\- " wtail()) + } else if(match(words[w],"^Fl$")) { + add("\\fB\\-" words[++w] "\\fP") + } else if(match(words[w],"^Ar$")) { + addopen("\\fI") + if(w==nwords) + add("file ...\\fP") + else + add(words[++w] "\\fP") + } else if(match(words[w],"^Cm$")) { + add("\\fB" words[++w] "\\fP") + } else if(match(words[w],"^Op$")) { + addopen("[") + option=1 + trailer="]" trailer + } else if(match(words[w],"^Pp$")) { + linecmd(".PP") + } else if(match(words[w],"^An$")) { + endline() + } else if(match(words[w],"^Ss$")) { + add(".SS") + } else if(match(words[w],"^Ft$")) { + if (match(section, "SYNOPSIS")) { + breakline() + } + add("\\fI" wtail() "\\fP") + if (match(section, "SYNOPSIS")) { + breakline() + } + } else if(match(words[w],"^Fn$")) { + ++w + F = "\\fB\\%" words[w] "\\fP(" + Fsep = "" + while(w<nwords) { + ++w + if (match(words[w], "^[.,:]$")) { + --w + break + } + gsub(" ", "\\ ", words[w]) + F = F Fsep "\\fI\\%" words[w] "\\fP" + Fsep = ", " + } + add(F ")") + if (match(section, "SYNOPSIS")) { + addclose(";") + } + } else if(match(words[w],"^Fo$")) { + w++ + F = "\\fB\\%" words[w] "\\fP(" + Fsep = "" + } else if(match(words[w],"^Fa$")) { + w++ + gsub(" ", "\\ ", words[w]) + F = F Fsep "\\fI\\%" words[w] "\\fP" + Fsep = ", " + } else if(match(words[w],"^Fc$")) { + add(F ")") + if (match(section, "SYNOPSIS")) { + addclose(";") + } + } else if(match(words[w],"^Va$")) { + w++ + add("\\fI" words[w] "\\fP") + } else if(match(words[w],"^In$")) { + w++ + add("\\fB#include <" words[w] ">\\fP") + } else if(match(words[w],"^Pa$")) { + addopen("\\fI") + w++ + if(match(words[w],"^\\.")) + add("\\&") + add(words[w] "\\fP") + } else if(match(words[w],"^Dv$")) { + add(".BR") + } else if(match(words[w],"^Em|Ev$")) { + add(".IR") + } else if(match(words[w],"^Pq$")) { + addopen("(") + trailer=")" trailer + } else if(match(words[w],"^Aq$")) { + addopen("\\%<") + trailer=">" trailer + } else if(match(words[w],"^Brq$")) { + addopen("{") + trailer="}" trailer + } else if(match(words[w],"^S[xy]$")) { + add(".B " wtail()) + } else if(match(words[w],"^Ic$")) { + add("\\fB") + trailer="\\fP" trailer + } else if(match(words[w],"^Bl$")) { + oldoptlist=optlist + linecmd(".RS 5") + if(match(words[w+1],"-bullet")) + optlist=1 + else if(match(words[w+1],"-enum")) { + optlist=2 + enum=0 + } else if(match(words[w+1],"-tag")) + optlist=3 + else if(match(words[w+1],"-item")) + optlist=4 + else if(match(words[w+1],"-bullet")) + optlist=1 + w=nwords + } else if(match(words[w],"^El$")) { + linecmd(".RE") + optlist=oldoptlist + } else if(match(words[w],"^It$")&&optlist) { + if(optlist==1) + add(".IP \\(bu") + else if(optlist==2) + add(".IP " ++enum ".") + else if(optlist==3) { + add(".TP") + endline() + if(match(words[w+1],"^Pa$|^Ev$")) { + add(".B") + w++ + } + } else if(optlist==4) + add(".IP") + } else if(match(words[w],"^Xo$")) { + # TODO: Figure out how to handle this + } else if(match(words[w],"^Xc$")) { + # TODO: Figure out how to handle this + } else if(match(words[w],"^[=]$")) { + addpunct(words[w]) + } else if(match(words[w],"^[[{(]$")) { + addopen(words[w]) + } else if(match(words[w],"^[\\])}.,;:]$")) { + addclose(words[w]) + } else { + add(words[w]) + } + } + if(match(out,"^\\.[^a-zA-Z]")) + sub("^\\.","",out) + endline() +} diff --git a/mk/pathnames b/mk/pathnames new file mode 100644 index 00000000..38582bcc --- /dev/null +++ b/mk/pathnames @@ -0,0 +1,11 @@ +smtpd_srcdir = $(top_srcdir)/smtpd +compat_srcdir = $(top_srcdir)/openbsd-compat +regress_srcdir = $(top_srcdir)/regress/bin + +PATHS= -DSMTPD_CONFDIR=\"$(sysconfdir)\" \ + -DPATH_CHROOT=\"$(PRIVSEP_PATH)\" \ + -DPATH_SMTPCTL=\"$(sbindir)/smtpctl\" \ + -DPATH_MAILLOCAL=\"$(pkglibexecdir)/mail.local\" \ + -DPATH_LIBEXEC=\"$(pkglibexecdir)\" + + diff --git a/mk/smtpctl/Makefile.am b/mk/smtpctl/Makefile.am new file mode 100644 index 00000000..8335ef52 --- /dev/null +++ b/mk/smtpctl/Makefile.am @@ -0,0 +1,96 @@ +include $(top_srcdir)/mk/pathnames + +sbin_PROGRAMS= smtpctl + +smtpctl_SOURCES= $(smtpd_srcdir)/enqueue.c +smtpctl_SOURCES+= $(smtpd_srcdir)/parser.c +smtpctl_SOURCES+= $(smtpd_srcdir)/log.c +smtpctl_SOURCES+= $(smtpd_srcdir)/envelope.c +smtpctl_SOURCES+= $(smtpd_srcdir)/queue_backend.c +smtpctl_SOURCES+= $(smtpd_srcdir)/queue_fs.c +smtpctl_SOURCES+= $(smtpd_srcdir)/smtpctl.c +smtpctl_SOURCES+= $(smtpd_srcdir)/spfwalk.c +smtpctl_SOURCES+= $(smtpd_srcdir)/util.c +smtpctl_SOURCES+= $(smtpd_srcdir)/unpack_dns.c +smtpctl_SOURCES+= $(smtpd_srcdir)/compress_backend.c +smtpctl_SOURCES+= $(smtpd_srcdir)/compress_gzip.c +smtpctl_SOURCES+= $(smtpd_srcdir)/to.c +smtpctl_SOURCES+= $(smtpd_srcdir)/expand.c +smtpctl_SOURCES+= $(smtpd_srcdir)/tree.c +smtpctl_SOURCES+= $(smtpd_srcdir)/dict.c + +if HAVE_DB_API +smtpctl_SOURCES+= $(smtpd_srcdir)/config.c +smtpctl_SOURCES+= $(smtpd_srcdir)/parse.y +smtpctl_SOURCES+= $(smtpd_srcdir)/limit.c +smtpctl_SOURCES+= $(smtpd_srcdir)/table.c +smtpctl_SOURCES+= $(smtpd_srcdir)/table_static.c +smtpctl_SOURCES+= $(smtpd_srcdir)/table_db.c +smtpctl_SOURCES+= $(smtpd_srcdir)/table_getpwnam.c +smtpctl_SOURCES+= $(smtpd_srcdir)/table_proc.c +smtpctl_SOURCES+= $(smtpd_srcdir)/mailaddr.c +smtpctl_SOURCES+= $(smtpd_srcdir)/makemap.c +endif + +smtpctl_SOURCES+= $(smtpd_srcdir)/crypto.c + +smtpctl_CFLAGS= -DNO_IO -DCONFIG_MINIMUM +smtpctl_CFLAGS+= -DPATH_GZCAT=\"$(ZCAT)\" \ + -DPATH_ENCRYPT=\"$(pkglibexecdir)/encrypt\" + +AM_CPPFLAGS= -I$(top_srcdir)/smtpd \ + -I$(top_srcdir)/openbsd-compat +if !SUPPORT_ERR_H +AM_CPPFLAGS += -I$(top_srcdir)/openbsd-compat/err_h +endif + +LIBCOMPAT= $(top_builddir)/openbsd-compat/libopenbsd-compat.a + +LDADD= $(LIBCOMPAT) +if HAVE_DB_API +LDADD+= $(DB_LIB) +endif + +# need to define _GNU_SOURCE to get: +# EAI_NODATA defined +# {v,}asprintf +# setres{g,u}id +CFLAGS+= -D_GNU_SOURCE +CPPFLAGS= -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@ + +MANPAGES= smtpctl.8.out sendmail.8.out makemap.8.out newaliases.8.out +MANPAGES_IN= $(smtpd_srcdir)/smtpctl.8 $(smtpd_srcdir)/sendmail.8 $(smtpd_srcdir)/makemap.8 $(smtpd_srcdir)/newaliases.8 + +EXTRA_DIST= $(MANPAGES_IN) + +PATHSUBS= -e 's|/var/run/smtpd.sock|$(sockdir)/smtpd.sock|g' \ + -e 's|/usr/libexec|$(libexecdir)|g' \ + -e 's|/etc/mail/|$(sysconfdir)/|g' + +FIXPATHSCMD= $(SED) $(PATHSUBS) + + +$(MANPAGES): $(MANPAGES_IN) + manpage=$(smtpd_srcdir)/`echo $@ | sed 's/\.out$$//'`; \ + if test "$(MANTYPE)" = "man"; then \ + $(FIXPATHSCMD) $${manpage} | $(AWK) -f $(srcdir)/../mdoc2man.awk > $@; \ + else \ + $(FIXPATHSCMD) $${manpage} > $@; \ + fi + +install-exec-hook: $(CONFIGFILES) $(MANPAGES) + $(MKDIR_P) $(DESTDIR)$(mandir)/$(mansubdir)8 + chgrp $(SMTPD_QUEUE_USER) $(DESTDIR)$(sbindir)/smtpctl || true + chmod 2555 $(DESTDIR)$(sbindir)/smtpctl || true + $(INSTALL) -m 644 smtpctl.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/smtpctl.8 + $(INSTALL) -m 644 sendmail.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sendmail.8 + $(INSTALL) -m 644 makemap.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/makemap.8 + $(INSTALL) -m 644 newaliases.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/newaliases.8 + rm smtpctl.8.out sendmail.8.out makemap.8.out newaliases.8.out + +uninstall-hook: + rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/smtpctl.8 + rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/sendmail.8 + rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/makemap.8 + rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/newaliases.8 + rmdir $(DESTDIR)$(mandir)/$(mansubdir)8 2> /dev/null || /bin/true diff --git a/mk/smtpd/Makefile.am b/mk/smtpd/Makefile.am new file mode 100644 index 00000000..2bd2c71f --- /dev/null +++ b/mk/smtpd/Makefile.am @@ -0,0 +1,188 @@ +# In OpenBSD, smtpd's files are installed this way: +# +# /etc/mail/smtpd.conf +# /usr/sbin/smtpd +# +# +# For OpenSMTPD portable, here's where files are installed: +# (assuming PREFIX=/usr/local) +# +# /usr/local/etc/smtpd.conf +# /usr/local/sbin/smtpd + +include $(top_srcdir)/mk/pathnames + +sbin_PROGRAMS= smtpd + +smtpd_SOURCES= $(smtpd_srcdir)/aliases.c +smtpd_SOURCES+= $(smtpd_srcdir)/bounce.c +smtpd_SOURCES+= $(smtpd_srcdir)/ca.c +smtpd_SOURCES+= $(smtpd_srcdir)/cert.c +smtpd_SOURCES+= $(smtpd_srcdir)/compress_backend.c +smtpd_SOURCES+= $(smtpd_srcdir)/config.c +smtpd_SOURCES+= $(smtpd_srcdir)/control.c +smtpd_SOURCES+= $(smtpd_srcdir)/dict.c +smtpd_SOURCES+= $(smtpd_srcdir)/dns.c +smtpd_SOURCES+= $(smtpd_srcdir)/esc.c +smtpd_SOURCES+= $(smtpd_srcdir)/envelope.c +smtpd_SOURCES+= $(smtpd_srcdir)/expand.c +smtpd_SOURCES+= $(smtpd_srcdir)/forward.c +smtpd_SOURCES+= $(smtpd_srcdir)/iobuf.c +smtpd_SOURCES+= $(smtpd_srcdir)/ioev.c +smtpd_SOURCES+= $(smtpd_srcdir)/limit.c +smtpd_SOURCES+= $(smtpd_srcdir)/lka.c +smtpd_SOURCES+= $(smtpd_srcdir)/lka_filter.c +smtpd_SOURCES+= $(smtpd_srcdir)/lka_proc.c +smtpd_SOURCES+= $(smtpd_srcdir)/lka_report.c +smtpd_SOURCES+= $(smtpd_srcdir)/lka_session.c +smtpd_SOURCES+= $(smtpd_srcdir)/log.c +smtpd_SOURCES+= $(smtpd_srcdir)/mda.c +smtpd_SOURCES+= $(smtpd_srcdir)/mda_unpriv.c +smtpd_SOURCES+= $(smtpd_srcdir)/mda_variables.c +smtpd_SOURCES+= $(smtpd_srcdir)/mproc.c +smtpd_SOURCES+= $(smtpd_srcdir)/mailaddr.c +smtpd_SOURCES+= $(smtpd_srcdir)/mta.c +smtpd_SOURCES+= $(smtpd_srcdir)/mta_session.c +smtpd_SOURCES+= $(smtpd_srcdir)/parse.y +smtpd_SOURCES+= $(smtpd_srcdir)/pony.c +smtpd_SOURCES+= $(smtpd_srcdir)/queue.c +smtpd_SOURCES+= $(smtpd_srcdir)/queue_backend.c +smtpd_SOURCES+= $(smtpd_srcdir)/report_smtp.c +smtpd_SOURCES+= $(smtpd_srcdir)/resolver.c +smtpd_SOURCES+= $(smtpd_srcdir)/rfc5322.c +smtpd_SOURCES+= $(smtpd_srcdir)/ruleset.c +smtpd_SOURCES+= $(smtpd_srcdir)/runq.c +smtpd_SOURCES+= $(smtpd_srcdir)/scheduler.c +smtpd_SOURCES+= $(smtpd_srcdir)/scheduler_backend.c +smtpd_SOURCES+= $(smtpd_srcdir)/smtp.c +smtpd_SOURCES+= $(smtpd_srcdir)/smtp_session.c +smtpd_SOURCES+= $(smtpd_srcdir)/smtpd.c +smtpd_SOURCES+= $(smtpd_srcdir)/ssl.c +smtpd_SOURCES+= $(smtpd_srcdir)/ssl_smtpd.c +smtpd_SOURCES+= $(smtpd_srcdir)/stat_backend.c +smtpd_SOURCES+= $(smtpd_srcdir)/table.c +smtpd_SOURCES+= $(smtpd_srcdir)/to.c +smtpd_SOURCES+= $(smtpd_srcdir)/tree.c +smtpd_SOURCES+= $(smtpd_srcdir)/unpack_dns.c +smtpd_SOURCES+= $(smtpd_srcdir)/util.c +smtpd_SOURCES+= $(smtpd_srcdir)/waitq.c + +# backends +smtpd_SOURCES+= $(smtpd_srcdir)/crypto.c +smtpd_SOURCES+= $(smtpd_srcdir)/compress_gzip.c +if HAVE_DB_API +smtpd_SOURCES+= $(smtpd_srcdir)/table_db.c +endif +smtpd_SOURCES+= $(smtpd_srcdir)/table_getpwnam.c +smtpd_SOURCES+= $(smtpd_srcdir)/table_proc.c +smtpd_SOURCES+= $(smtpd_srcdir)/table_static.c +smtpd_SOURCES+= $(smtpd_srcdir)/queue_fs.c +smtpd_SOURCES+= $(smtpd_srcdir)/queue_null.c +smtpd_SOURCES+= $(smtpd_srcdir)/queue_proc.c +smtpd_SOURCES+= $(smtpd_srcdir)/queue_ram.c +smtpd_SOURCES+= $(smtpd_srcdir)/scheduler_null.c +smtpd_SOURCES+= $(smtpd_srcdir)/scheduler_proc.c +smtpd_SOURCES+= $(smtpd_srcdir)/scheduler_ramqueue.c +smtpd_SOURCES+= $(smtpd_srcdir)/stat_ramstat.c + + +smtpd_CFLAGS= -DIO_SSL +smtpd_CFLAGS+= -DCA_FILE=\"$(CA_FILE)\" + +AM_CPPFLAGS= -I$(smtpd_srcdir) \ + -I$(compat_srcdir) +if !SUPPORT_ERR_H +AM_CPPFLAGS += -I$(top_srcdir)/openbsd-compat/err_h +endif +if !SUPPORT_PATHS_H +AM_CPPFLAGS += -I$(top_srcdir)/openbsd-compat/paths_h +endif + +LIBCOMPAT= $(top_builddir)/openbsd-compat/libopenbsd-compat.a + +LDADD= $(LIBCOMPAT) $(DB_LIB) $(ASR_LIB) + +# need to define _GNU_SOURCE to get: +# EAI_NODATA defined +# {v,}asprintf +# setres{g,u}id +CFLAGS+= -D_GNU_SOURCE -DNEED_EVENT_ASR_RUN +CPPFLAGS= -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@ + +MANPAGES= aliases.5.out forward.5.out smtpd.8.out \ + smtpd.conf.5.out table.5.out + +MANPAGES_IN= $(smtpd_srcdir)/aliases.5 +MANPAGES_IN+= $(smtpd_srcdir)/forward.5 +MANPAGES_IN+= $(smtpd_srcdir)/smtpd.8 +MANPAGES_IN+= $(smtpd_srcdir)/smtpd.conf.5 +MANPAGES_IN+= $(smtpd_srcdir)/table.5 + +CONFIGFILES= smtpd.conf.out +CONFIGFILES_IN= $(smtpd_srcdir)/smtpd.conf + +EXTRA_DIST= $(CONFIGFILES_IN) $(MANPAGES_IN) + + +EXTRA_DIST+= $(smtpd_srcdir)/smtpd.h +EXTRA_DIST+= $(smtpd_srcdir)/smtpd-api.h +EXTRA_DIST+= $(smtpd_srcdir)/smtpd-defines.h +EXTRA_DIST+= $(smtpd_srcdir)/ioev.h +EXTRA_DIST+= $(smtpd_srcdir)/iobuf.h +EXTRA_DIST+= $(smtpd_srcdir)/log.h +EXTRA_DIST+= $(smtpd_srcdir)/ssl.h +EXTRA_DIST+= $(smtpd_srcdir)/parser.h + +EXTRA_DIST+= $(backends_srcdir)/queue_utils.h +EXTRA_DIST+= $(filters_srcdir)/asr_event.h + +PATHSUBS= -e 's|/etc/mail/|$(sysconfdir)/|g' \ + -e 's|/var/run/smtpd.sock|$(sockdir)/smtpd.sock|g' + +FIXPATHSCMD= $(SED) $(PATHSUBS) + +$(MANPAGES): $(MANPAGES_IN) + manpage=$(smtpd_srcdir)/`echo $@ | sed 's/\.out$$//'`; \ + if test "$(MANTYPE)" = "man"; then \ + $(FIXPATHSCMD) $${manpage} | $(AWK) -f $(srcdir)/../mdoc2man.awk > $@; \ + else \ + $(FIXPATHSCMD) $${manpage} > $@; \ + fi + +$(CONFIGFILES): $(CONFIGFILES_IN) + conffile=$(smtpd_srcdir)/`echo $@ | sed 's/.out$$//'`; \ + $(CAT) $(srcdir)/$${conffile} > $@ + + +# smtpd.conf +# newaliases makemap +install-exec-hook: $(CONFIGFILES) $(MANPAGES) + $(MKDIR_P) $(DESTDIR)$(sysconfdir) + $(MKDIR_P) $(DESTDIR)$(bindir) + $(MKDIR_P) $(DESTDIR)$(mandir)/$(mansubdir)5 + $(MKDIR_P) $(DESTDIR)$(mandir)/$(mansubdir)8 + + @if [ ! -f $(DESTDIR)$(sysconfdir)/smtpd.conf ]; then \ + $(INSTALL) -m 644 smtpd.conf.out $(DESTDIR)$(sysconfdir)/smtpd.conf; \ + else \ + echo "$(DESTDIR)$(sysconfdir)/smtpd.conf already exists, install will not overwrite"; \ + fi + + $(INSTALL) -m 644 aliases.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/aliases.5 + $(INSTALL) -m 644 forward.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/forward.5 + $(INSTALL) -m 644 table.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/table.5 + $(INSTALL) -m 644 smtpd.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/smtpd.8 + $(INSTALL) -m 644 smtpd.conf.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/smtpd.conf.5 + rm aliases.5.out forward.5.out table.5.out \ + smtpd.8.out smtpd.conf.5.out smtpd.conf.out + +uninstall-hook: +# XXX to make "make distcheck" happy we need to rm smtpd.conf +# rm $(DESTDIR)$(sysconfdir)/smtpd.conf + rm -f $(DESTDIR)$(mandir)/$(mansubdir)5/aliases.5 \ + $(DESTDIR)$(mandir)/$(mansubdir)5/forward.5 \ + $(DESTDIR)$(mandir)/$(mansubdir)5/table.5 \ + $(DESTDIR)$(mandir)/$(mansubdir)5/smtpd.conf.5 \ + $(DESTDIR)$(mandir)/$(mansubdir)8/smtpd.8 + rmdir $(DESTDIR)$(mandir)/$(mansubdir)5 \ + $(DESTDIR)$(mandir)/$(mansubdir)8 2> /dev/null || /bin/true diff --git a/openbsd-compat/Makefile.am b/openbsd-compat/Makefile.am new file mode 100644 index 00000000..7252d91d --- /dev/null +++ b/openbsd-compat/Makefile.am @@ -0,0 +1,112 @@ +noinst_LIBRARIES = libopenbsd-compat.a + +#libopenbsd_compat_a_SOURCES = arc4random.c +libopenbsd_compat_a_SOURCES = base64.c +libopenbsd_compat_a_SOURCES += bsd-getpeereid.c +libopenbsd_compat_a_SOURCES += bsd-misc.c +libopenbsd_compat_a_SOURCES += bsd-waitpid.c +libopenbsd_compat_a_SOURCES += entropy.c +libopenbsd_compat_a_SOURCES += event_asr_run.c +libopenbsd_compat_a_SOURCES += fgetln.c +libopenbsd_compat_a_SOURCES += freezero.c +libopenbsd_compat_a_SOURCES += getopt.c +libopenbsd_compat_a_SOURCES += imsg.c +libopenbsd_compat_a_SOURCES += imsg-buffer.c +#libopenbsd_compat_a_SOURCES += libressl.c +libopenbsd_compat_a_SOURCES += pidfile.c +libopenbsd_compat_a_SOURCES += pw_dup.c +libopenbsd_compat_a_SOURCES += reallocarray.c +libopenbsd_compat_a_SOURCES += recallocarray.c +libopenbsd_compat_a_SOURCES += setproctitle.c +libopenbsd_compat_a_SOURCES += setresguid.c +libopenbsd_compat_a_SOURCES += strlcat.c +libopenbsd_compat_a_SOURCES += strlcpy.c +libopenbsd_compat_a_SOURCES += strmode.c +libopenbsd_compat_a_SOURCES += strtonum.c +libopenbsd_compat_a_SOURCES += strsep.c +libopenbsd_compat_a_SOURCES += vis.c +libopenbsd_compat_a_SOURCES += xmalloc.c + +if !SUPPORT_BASENAME +libopenbsd_compat_a_SOURCES += basename.c +endif + +if !SUPPORT_CRYPT_CHECKPASS +libopenbsd_compat_a_SOURCES += crypt_checkpass.c +endif + +if !SUPPORT_CLOCK_GETTIME +libopenbsd_compat_a_SOURCES += clock_gettime.c +endif + +if !SUPPORT_CLOSEFROM +libopenbsd_compat_a_SOURCES += bsd-closefrom.c +endif + +if !SUPPORT_DAEMON +libopenbsd_compat_a_SOURCES += daemon.c +endif + +if !SUPPORT_DIRNAME +libopenbsd_compat_a_SOURCES += dirname.c +endif + +if !SUPPORT_ERR_H +libopenbsd_compat_a_SOURCES += bsd-err.c +endif + +if !SUPPORT_ERRC +libopenbsd_compat_a_SOURCES += errc.c +endif + +if !SUPPORT_EXPLICIT_BZERO +libopenbsd_compat_a_SOURCES += explicit_bzero.c +endif + +if !SUPPORT_FMT_SCALED +libopenbsd_compat_a_SOURCES += fmt_scaled.c +endif + +if !SUPPORT_FLOCK +libopenbsd_compat_a_SOURCES += flock.c +endif + +if !SUPPORT_FPARSELN +libopenbsd_compat_a_SOURCES += fparseln.c +endif + +if !SUPPORT_GETLINE +libopenbsd_compat_a_SOURCES += getline.c +endif + +if !SUPPORT_INET_NET_PTON +libopenbsd_compat_a_SOURCES += inet_net_pton.c +endif + +if !SUPPORT_STRNDUP +libopenbsd_compat_a_SOURCES += strndup.c +endif + +if !SUPPORT_STRNLEN +libopenbsd_compat_a_SOURCES += strnlen.c +endif + +EXTRA_DIST = base64.h +EXTRA_DIST += bsd-misc.h +EXTRA_DIST += bsd-waitpid.h +EXTRA_DIST += chacha_private.h +EXTRA_DIST += defines.h +EXTRA_DIST += entropy.h +EXTRA_DIST += imsg.h +EXTRA_DIST += includes.h +EXTRA_DIST += log.h +EXTRA_DIST += openbsd-compat.h +EXTRA_DIST += sys/queue.h +EXTRA_DIST += sys/tree.h +EXTRA_DIST += bsd-vis.h +EXTRA_DIST += xmalloc.h + +AM_CPPFLAGS = -I$(top_srcdir)/smtpd -I$(top_srcdir)/openbsd-compat +if !SUPPORT_ERR_H +AM_CPPFLAGS += -I$(top_srcdir)/openbsd-compat/err_h +endif diff --git a/openbsd-compat/NOTES b/openbsd-compat/NOTES new file mode 100644 index 00000000..42aefc7d --- /dev/null +++ b/openbsd-compat/NOTES @@ -0,0 +1,37 @@ +List of files and where they come from + +arc4random.c portable openssh +base64.{c,h} portable openssh +basename.c portable openssh +bsd-closefrom.c portable openssh +bsd-getpeereid.c portable openssh +bsd-waitpid.{c,h} portable openssh +clock_gettime.c handmade +daemon.c portable openssh +defines.h portable openssh +dirname.c portable openssh +entropy.{c,h} portable openssh +event_asr_run.c end of /usr/src/lib/libevent/event.c +fgetln.c part of /usr/src/usr.bin/make/util.c +fmt_scaled.c portable openssh +fparseln.c part of /usr/src/lib/libutil/fparseln.c +getopt.c portable openssh +imsg-buffer.c part of /usr/src/libutil/imsg-buffer.c +imsg.{c,h} part of /usr/src/libutil/imsg.c +includes.h portable openssh +log.h portable openssh +mktemp.c portable openssh +openbsd-compat.h portable openssh +pidfile.c /usr/src/lib/libutil/pidfile.c +pw_dup.c /usr/src/lib/libc/gen/pw_dup.c +reallocarray.c /usr/src/lib/libc/stdlib/reallocarray.c +setproctitle.c portable openssh +strlcat.c portable openssh +strlcpy.c portable openssh +strmode.c portable openssh +strsep.c portable openssh +strtonum.c portable openssh +sys/queue.h portable openssh +sys/tree.h portable openssh +vis.{c,h} portable openssh +xmalloc.{c,h} portable openssh diff --git a/openbsd-compat/arc4random.c b/openbsd-compat/arc4random.c new file mode 100644 index 00000000..1598ebeb --- /dev/null +++ b/openbsd-compat/arc4random.c @@ -0,0 +1,294 @@ +/* OPENBSD ORIGINAL: lib/libc/crypto/arc4random.c */ + +/* $OpenBSD: arc4random.c,v 1.25 2013/10/01 18:34:57 markus Exp $ */ + +/* + * Copyright (c) 1996, David Mazieres <dm@uun.org> + * Copyright (c) 2008, Damien Miller <djm@openbsd.org> + * Copyright (c) 2013, Markus Friedl <markus@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * ChaCha based random number generator for OpenBSD. + */ + +#include "includes.h" + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> + +#ifndef HAVE_ARC4RANDOM + +#include <openssl/rand.h> +#include <openssl/err.h> + +#include "log.h" + +#define KEYSTREAM_ONLY +#include "chacha_private.h" + +#ifdef __GNUC__ +#define inline __inline +#else /* !__GNUC__ */ +#define inline +#endif /* !__GNUC__ */ + +/* OpenSSH isn't multithreaded */ +#define _ARC4_LOCK() +#define _ARC4_UNLOCK() + +#define KEYSZ 32 +#define IVSZ 8 +#define BLOCKSZ 64 +#define RSBUFSZ (16*BLOCKSZ) +static int rs_initialized; +static pid_t rs_stir_pid; +static chacha_ctx rs; /* chacha context for random keystream */ +static u_char rs_buf[RSBUFSZ]; /* keystream blocks */ +static size_t rs_have; /* valid bytes at end of rs_buf */ +static size_t rs_count; /* bytes till reseed */ + +static inline void _rs_rekey(u_char *dat, size_t datlen); + +static inline void +_rs_init(u_char *buf, size_t n) +{ + if (n < KEYSZ + IVSZ) + return; + chacha_keysetup(&rs, buf, KEYSZ * 8, 0); + chacha_ivsetup(&rs, buf + KEYSZ); +} + +static void +_rs_stir(void) +{ + u_char rnd[KEYSZ + IVSZ]; + + if (RAND_bytes(rnd, sizeof(rnd)) <= 0) + fatal("Couldn't obtain random bytes (error %ld)", + ERR_get_error()); + + if (!rs_initialized) { + rs_initialized = 1; + _rs_init(rnd, sizeof(rnd)); + } else + _rs_rekey(rnd, sizeof(rnd)); + memset(rnd, 0, sizeof(rnd)); + + /* invalidate rs_buf */ + rs_have = 0; + memset(rs_buf, 0, RSBUFSZ); + + rs_count = 1600000; +} + +static inline void +_rs_stir_if_needed(size_t len) +{ + pid_t pid = getpid(); + + if (rs_count <= len || !rs_initialized || rs_stir_pid != pid) { + rs_stir_pid = pid; + _rs_stir(); + } else + rs_count -= len; +} + +static inline void +_rs_rekey(u_char *dat, size_t datlen) +{ +#ifndef KEYSTREAM_ONLY + memset(rs_buf, 0,RSBUFSZ); +#endif + /* fill rs_buf with the keystream */ + chacha_encrypt_bytes(&rs, rs_buf, rs_buf, RSBUFSZ); + /* mix in optional user provided data */ + if (dat) { + size_t i, m; + + m = MIN(datlen, KEYSZ + IVSZ); + for (i = 0; i < m; i++) + rs_buf[i] ^= dat[i]; + } + /* immediately reinit for backtracking resistance */ + _rs_init(rs_buf, KEYSZ + IVSZ); + memset(rs_buf, 0, KEYSZ + IVSZ); + rs_have = RSBUFSZ - KEYSZ - IVSZ; +} + +static inline void +_rs_random_buf(void *_buf, size_t n) +{ + u_char *buf = (u_char *)_buf; + size_t m; + + _rs_stir_if_needed(n); + while (n > 0) { + if (rs_have > 0) { + m = MIN(n, rs_have); + memcpy(buf, rs_buf + RSBUFSZ - rs_have, m); + memset(rs_buf + RSBUFSZ - rs_have, 0, m); + buf += m; + n -= m; + rs_have -= m; + } + if (rs_have == 0) + _rs_rekey(NULL, 0); + } +} + +static inline void +_rs_random_u32(uint32_t *val) +{ + _rs_stir_if_needed(sizeof(*val)); + if (rs_have < sizeof(*val)) + _rs_rekey(NULL, 0); + memcpy(val, rs_buf + RSBUFSZ - rs_have, sizeof(*val)); + memset(rs_buf + RSBUFSZ - rs_have, 0, sizeof(*val)); + rs_have -= sizeof(*val); + return; +} + +void +arc4random_stir(void) +{ + _ARC4_LOCK(); + _rs_stir(); + _ARC4_UNLOCK(); +} + +void +arc4random_addrandom(u_char *dat, int datlen) +{ + int m; + + _ARC4_LOCK(); + if (!rs_initialized) + _rs_stir(); + while (datlen > 0) { + m = MIN(datlen, KEYSZ + IVSZ); + _rs_rekey(dat, m); + dat += m; + datlen -= m; + } + _ARC4_UNLOCK(); +} + +uint32_t +arc4random(void) +{ + uint32_t val; + + _ARC4_LOCK(); + _rs_random_u32(&val); + _ARC4_UNLOCK(); + return val; +} + +/* + * If we are providing arc4random, then we can provide a more efficient + * arc4random_buf(). + */ +# ifndef HAVE_ARC4RANDOM_BUF +void +arc4random_buf(void *buf, size_t n) +{ + _ARC4_LOCK(); + _rs_random_buf(buf, n); + _ARC4_UNLOCK(); +} +# endif /* !HAVE_ARC4RANDOM_BUF */ +#endif /* !HAVE_ARC4RANDOM */ + +/* arc4random_buf() that uses platform arc4random() */ +#if !defined(HAVE_ARC4RANDOM_BUF) && defined(HAVE_ARC4RANDOM) +void +arc4random_buf(void *_buf, size_t n) +{ + size_t i; + uint32_t r = 0; + char *buf = (char *)_buf; + + for (i = 0; i < n; i++) { + if (i % 4 == 0) + r = arc4random(); + buf[i] = r & 0xff; + r >>= 8; + } + explicit_bzero(&r, sizeof(r)); +} +#endif /* !defined(HAVE_ARC4RANDOM_BUF) && defined(HAVE_ARC4RANDOM) */ + +#ifndef HAVE_ARC4RANDOM_UNIFORM +/* + * Calculate a uniformly distributed random number less than upper_bound + * avoiding "modulo bias". + * + * Uniformity is achieved by generating new random numbers until the one + * returned is outside the range [0, 2**32 % upper_bound). This + * guarantees the selected random number will be inside + * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound) + * after reduction modulo upper_bound. + */ +uint32_t +arc4random_uniform(uint32_t upper_bound) +{ + uint32_t r, min; + + if (upper_bound < 2) + return 0; + + /* 2**32 % x == (2**32 - x) % x */ + min = -upper_bound % upper_bound; + + /* + * This could theoretically loop forever but each retry has + * p > 0.5 (worst case, usually far better) of selecting a + * number inside the range we need, so it should rarely need + * to re-roll. + */ + for (;;) { + r = arc4random(); + if (r >= min) + break; + } + + return r % upper_bound; +} +#endif /* !HAVE_ARC4RANDOM_UNIFORM */ + +#if 0 +/*-------- Test code for i386 --------*/ +#include <stdio.h> +#include <machine/pctr.h> +int +main(int argc, char **argv) +{ + const int iter = 1000000; + int i; + pctrval v; + + v = rdtsc(); + for (i = 0; i < iter; i++) + arc4random(); + v = rdtsc() - v; + v /= iter; + + printf("%qd cycles\n", v); + exit(0); +} +#endif diff --git a/openbsd-compat/base64.c b/openbsd-compat/base64.c new file mode 100644 index 00000000..9e746671 --- /dev/null +++ b/openbsd-compat/base64.c @@ -0,0 +1,315 @@ +/* $OpenBSD: base64.c,v 1.5 2006/10/21 09:55:03 otto Exp $ */ + +/* + * Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +/* OPENBSD ORIGINAL: lib/libc/net/base64.c */ + +#include "includes.h" + +#if (!defined(HAVE_B64_NTOP) && !defined(HAVE___B64_NTOP)) || (!defined(HAVE_B64_PTON) && !defined(HAVE___B64_PTON)) + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <ctype.h> +#include <stdio.h> + +#include <stdlib.h> +#include <string.h> + +#include "base64.h" + +static const char Base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char Pad64 = '='; + +/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) + The following encoding technique is taken from RFC 1521 by Borenstein + and Freed. It is reproduced here in a slightly edited form for + convenience. + + A 65-character subset of US-ASCII is used, enabling 6 bits to be + represented per printable character. (The extra 65th character, "=", + is used to signify a special processing function.) + + The encoding process represents 24-bit groups of input bits as output + strings of 4 encoded characters. Proceeding from left to right, a + 24-bit input group is formed by concatenating 3 8-bit input groups. + These 24 bits are then treated as 4 concatenated 6-bit groups, each + of which is translated into a single digit in the base64 alphabet. + + Each 6-bit group is used as an index into an array of 64 printable + characters. The character referenced by the index is placed in the + output string. + + Table 1: The Base64 Alphabet + + Value Encoding Value Encoding Value Encoding Value Encoding + 0 A 17 R 34 i 51 z + 1 B 18 S 35 j 52 0 + 2 C 19 T 36 k 53 1 + 3 D 20 U 37 l 54 2 + 4 E 21 V 38 m 55 3 + 5 F 22 W 39 n 56 4 + 6 G 23 X 40 o 57 5 + 7 H 24 Y 41 p 58 6 + 8 I 25 Z 42 q 59 7 + 9 J 26 a 43 r 60 8 + 10 K 27 b 44 s 61 9 + 11 L 28 c 45 t 62 + + 12 M 29 d 46 u 63 / + 13 N 30 e 47 v + 14 O 31 f 48 w (pad) = + 15 P 32 g 49 x + 16 Q 33 h 50 y + + Special processing is performed if fewer than 24 bits are available + at the end of the data being encoded. A full encoding quantum is + always completed at the end of a quantity. When fewer than 24 input + bits are available in an input group, zero bits are added (on the + right) to form an integral number of 6-bit groups. Padding at the + end of the data is performed using the '=' character. + + Since all base64 input is an integral number of octets, only the + ------------------------------------------------- + following cases can arise: + + (1) the final quantum of encoding input is an integral + multiple of 24 bits; here, the final unit of encoded + output will be an integral multiple of 4 characters + with no "=" padding, + (2) the final quantum of encoding input is exactly 8 bits; + here, the final unit of encoded output will be two + characters followed by two "=" padding characters, or + (3) the final quantum of encoding input is exactly 16 bits; + here, the final unit of encoded output will be three + characters followed by one "=" padding character. + */ + +#if !defined(HAVE_B64_NTOP) && !defined(HAVE___B64_NTOP) +int +b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) +{ + size_t datalength = 0; + u_char input[3]; + u_char output[4]; + u_int i; + + while (2 < srclength) { + input[0] = *src++; + input[1] = *src++; + input[2] = *src++; + srclength -= 3; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + output[3] = input[2] & 0x3f; + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + target[datalength++] = Base64[output[2]]; + target[datalength++] = Base64[output[3]]; + } + + /* Now we worry about padding. */ + if (0 != srclength) { + /* Get what's left. */ + input[0] = input[1] = input[2] = '\0'; + for (i = 0; i < srclength; i++) + input[i] = *src++; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + if (srclength == 1) + target[datalength++] = Pad64; + else + target[datalength++] = Base64[output[2]]; + target[datalength++] = Pad64; + } + if (datalength >= targsize) + return (-1); + target[datalength] = '\0'; /* Returned value doesn't count \0. */ + return (datalength); +} +#endif /* !defined(HAVE_B64_NTOP) && !defined(HAVE___B64_NTOP) */ + +#if !defined(HAVE_B64_PTON) && !defined(HAVE___B64_PTON) + +/* skips all whitespace anywhere. + converts characters, four at a time, starting at (or after) + src from base - 64 numbers into three 8 bit bytes in the target area. + it returns the number of data bytes stored at the target, or -1 on error. + */ + +int +b64_pton(char const *src, u_char *target, size_t targsize) +{ + u_int tarindex, state; + int ch; + char *pos; + + state = 0; + tarindex = 0; + + while ((ch = *src++) != '\0') { + if (isspace(ch)) /* Skip whitespace anywhere. */ + continue; + + if (ch == Pad64) + break; + + pos = strchr(Base64, ch); + if (pos == 0) /* A non-base64 character. */ + return (-1); + + switch (state) { + case 0: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] = (pos - Base64) << 2; + } + state = 1; + break; + case 1: + if (target) { + if (tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 4; + target[tarindex+1] = ((pos - Base64) & 0x0f) + << 4 ; + } + tarindex++; + state = 2; + break; + case 2: + if (target) { + if (tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 2; + target[tarindex+1] = ((pos - Base64) & 0x03) + << 6; + } + tarindex++; + state = 3; + break; + case 3: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] |= (pos - Base64); + } + tarindex++; + state = 0; + break; + } + } + + /* + * We are done decoding Base-64 chars. Let's see if we ended + * on a byte boundary, and/or with erroneous trailing characters. + */ + + if (ch == Pad64) { /* We got a pad char. */ + ch = *src++; /* Skip it, get next. */ + switch (state) { + case 0: /* Invalid = in first position */ + case 1: /* Invalid = in second position */ + return (-1); + + case 2: /* Valid, means one byte of info */ + /* Skip any number of spaces. */ + for (; ch != '\0'; ch = *src++) + if (!isspace(ch)) + break; + /* Make sure there is another trailing = sign. */ + if (ch != Pad64) + return (-1); + ch = *src++; /* Skip the = */ + /* Fall through to "single trailing =" case. */ + /* FALLTHROUGH */ + + case 3: /* Valid, means two bytes of info */ + /* + * We know this char is an =. Is there anything but + * whitespace after it? + */ + for (; ch != '\0'; ch = *src++) + if (!isspace(ch)) + return (-1); + + /* + * Now make sure for cases 2 and 3 that the "extra" + * bits that slopped past the last full byte were + * zeros. If we don't check them, they become a + * subliminal channel. + */ + if (target && target[tarindex] != 0) + return (-1); + } + } else { + /* + * We ended by seeing the end of the string. Make sure we + * have no partial bytes lying around. + */ + if (state != 0) + return (-1); + } + + return (tarindex); +} + +#endif /* !defined(HAVE_B64_PTON) && !defined(HAVE___B64_PTON) */ +#endif diff --git a/openbsd-compat/base64.h b/openbsd-compat/base64.h new file mode 100644 index 00000000..732c6b3f --- /dev/null +++ b/openbsd-compat/base64.h @@ -0,0 +1,65 @@ +/* $Id: base64.h,v 1.6 2003/08/29 16:59:52 mouring Exp $ */ + +/* + * Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef _BSD_BASE64_H +#define _BSD_BASE64_H + +#include "includes.h" + +#ifndef HAVE___B64_NTOP +# ifndef HAVE_B64_NTOP +int b64_ntop(u_char const *src, size_t srclength, char *target, + size_t targsize); +# endif /* !HAVE_B64_NTOP */ +# define __b64_ntop(a,b,c,d) b64_ntop(a,b,c,d) +#endif /* HAVE___B64_NTOP */ + +#ifndef HAVE___B64_PTON +# ifndef HAVE_B64_PTON +int b64_pton(char const *src, u_char *target, size_t targsize); +# endif /* !HAVE_B64_PTON */ +# define __b64_pton(a,b,c) b64_pton(a,b,c) +#endif /* HAVE___B64_PTON */ + +#endif /* _BSD_BASE64_H */ diff --git a/openbsd-compat/basename.c b/openbsd-compat/basename.c new file mode 100644 index 00000000..ffa5c898 --- /dev/null +++ b/openbsd-compat/basename.c @@ -0,0 +1,67 @@ +/* $OpenBSD: basename.c,v 1.14 2005/08/08 08:05:33 espie Exp $ */ + +/* + * Copyright (c) 1997, 2004 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* OPENBSD ORIGINAL: lib/libc/gen/basename.c */ + +#include "includes.h" +#ifndef HAVE_BASENAME +#include <errno.h> +#include <string.h> + +char * +basename(const char *path) +{ + static char bname[MAXPATHLEN]; + size_t len; + const char *endp, *startp; + + /* Empty or NULL string gets treated as "." */ + if (path == NULL || *path == '\0') { + bname[0] = '.'; + bname[1] = '\0'; + return (bname); + } + + /* Strip any trailing slashes */ + endp = path + strlen(path) - 1; + while (endp > path && *endp == '/') + endp--; + + /* All slashes becomes "/" */ + if (endp == path && *endp == '/') { + bname[0] = '/'; + bname[1] = '\0'; + return (bname); + } + + /* Find the start of the base */ + startp = endp; + while (startp > path && *(startp - 1) != '/') + startp--; + + len = endp - startp + 1; + if (len >= sizeof(bname)) { + errno = ENAMETOOLONG; + return (NULL); + } + memcpy(bname, startp, len); + bname[len] = '\0'; + return (bname); +} + +#endif /* !defined(HAVE_BASENAME) */ diff --git a/openbsd-compat/bsd-closefrom.c b/openbsd-compat/bsd-closefrom.c new file mode 100644 index 00000000..9380b33a --- /dev/null +++ b/openbsd-compat/bsd-closefrom.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2004-2005 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +#ifndef HAVE_CLOSEFROM + +#include <sys/types.h> +#include <sys/param.h> +#include <unistd.h> +#include <stdio.h> +#ifdef HAVE_FCNTL_H +# include <fcntl.h> +#endif +#include <limits.h> +#include <stdlib.h> +#include <stddef.h> +#include <string.h> +#include <unistd.h> +#ifdef HAVE_DIRENT_H +# include <dirent.h> +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# ifdef HAVE_SYS_NDIR_H +# include <sys/ndir.h> +# endif +# ifdef HAVE_SYS_DIR_H +# include <sys/dir.h> +# endif +# ifdef HAVE_NDIR_H +# include <ndir.h> +# endif +#endif + +#ifndef OPEN_MAX +# define OPEN_MAX 256 +#endif + +#if 0 +__unused static const char rcsid[] = "$Sudo: closefrom.c,v 1.11 2006/08/17 15:26:54 millert Exp $"; +#endif /* lint */ + +/* + * Close all file descriptors greater than or equal to lowfd. + */ +#ifdef HAVE_FCNTL_CLOSEM +void +closefrom(int lowfd) +{ + (void) fcntl(lowfd, F_CLOSEM, 0); +} +#else +void +closefrom(int lowfd) +{ + long fd, maxfd; +#if defined(HAVE_DIRFD) && defined(HAVE_PROC_PID) + char fdpath[PATH_MAX], *endp; + struct dirent *dent; + DIR *dirp; + int len; + + /* Check for a /proc/$$/fd directory. */ + len = snprintf(fdpath, sizeof(fdpath), "/proc/%ld/fd", (long)getpid()); + if (len > 0 && (size_t)len <= sizeof(fdpath) && (dirp = opendir(fdpath))) { + while ((dent = readdir(dirp)) != NULL) { + fd = strtol(dent->d_name, &endp, 10); + if (dent->d_name != endp && *endp == '\0' && + fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp)) + (void) close((int) fd); + } + (void) closedir(dirp); + } else +#endif + { + /* + * Fall back on sysconf() or getdtablesize(). We avoid checking + * resource limits since it is possible to open a file descriptor + * and then drop the rlimit such that it is below the open fd. + */ +#ifdef HAVE_SYSCONF + maxfd = sysconf(_SC_OPEN_MAX); +#else + maxfd = getdtablesize(); +#endif /* HAVE_SYSCONF */ + if (maxfd < 0) + maxfd = OPEN_MAX; + + for (fd = lowfd; fd < maxfd; fd++) + (void) close((int) fd); + } +} +#endif /* !HAVE_FCNTL_CLOSEM */ +#endif /* HAVE_CLOSEFROM */ diff --git a/openbsd-compat/bsd-err.c b/openbsd-compat/bsd-err.c new file mode 100644 index 00000000..a73267f9 --- /dev/null +++ b/openbsd-compat/bsd-err.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2015 Tim Rice <tim@multitalents.net> + * + * 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 "includes.h" + +#include <errno.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +extern char *__progname; + +#ifndef HAVE_ERR +void +err(int r, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + fprintf(stderr, "%s: ", __progname); + fprintf(stderr, "%s", strerror(errno)); + if (fmt != NULL) + vfprintf(stderr, fmt, args); + fputc('\n', stderr); + va_end(args); + exit(r); +} +#endif + +#ifndef HAVE_ERRX +void +errx(int r, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + fprintf(stderr, "%s: ", __progname); + if (fmt != NULL) + vfprintf(stderr, fmt, args); + fputc('\n', stderr); + va_end(args); + exit(r); +} +#endif + +#ifndef HAVE_WARN +void +warn(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + fprintf(stderr, "%s: ", __progname); + if (fmt != NULL) { + vfprintf(stderr, fmt, args); + fprintf(stderr, ": "); + } + fprintf(stderr, "%s", strerror(errno)); + fputc('\n', stderr); + va_end(args); +} +#endif + +#ifndef HAVE_WARNX +void +warnx(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + fprintf(stderr, "%s: ", __progname); + if (fmt != NULL) + vfprintf(stderr, fmt, args); + fputc('\n', stderr); + va_end(args); +} +#endif diff --git a/openbsd-compat/bsd-err.h b/openbsd-compat/bsd-err.h new file mode 100644 index 00000000..f75d0eb4 --- /dev/null +++ b/openbsd-compat/bsd-err.h @@ -0,0 +1,29 @@ +/* + * Public domain + * err.h compatibility shim + */ + +#ifndef HAVE_ERR_H + +#ifndef LIBCRYPTOCOMPAT_ERR_H +#define LIBCRYPTOCOMPAT_ERR_H + +#include <errno.h> +#include <stdio.h> +#include <string.h> + +#define err(exitcode, format, args...) \ + errx(exitcode, format ": %s", ## args, strerror(errno)) + +#define errx(exitcode, format, args...) \ + do { warnx(format, ## args); exit(exitcode); } while (0) + +#define warn(format, args...) \ + warnx(format ": %s", ## args, strerror(errno)) + +#define warnx(format, args...) \ + fprintf(stderr, format "\n", ## args) + +#endif + +#endif diff --git a/openbsd-compat/bsd-getpeereid.c b/openbsd-compat/bsd-getpeereid.c new file mode 100644 index 00000000..5f7e677e --- /dev/null +++ b/openbsd-compat/bsd-getpeereid.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2002,2004 Damien Miller <djm@mindrot.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +#if !defined(HAVE_GETPEEREID) + +#include <sys/types.h> +#include <sys/socket.h> + +#include <unistd.h> + +#if defined(SO_PEERCRED) +int +getpeereid(int s, uid_t *euid, gid_t *gid) +{ + struct ucred cred; + socklen_t len = sizeof(cred); + + if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cred, &len) < 0) + return (-1); + *euid = cred.uid; + *gid = cred.gid; + + return (0); +} +#elif defined(HAVE_GETPEERUCRED) + +#ifdef HAVE_UCRED_H +# include <ucred.h> +#endif + +int +getpeereid(int s, uid_t *euid, gid_t *gid) +{ + ucred_t *ucred = NULL; + + if (getpeerucred(s, &ucred) == -1) + return (-1); + if ((*euid = ucred_geteuid(ucred)) == -1) + return (-1); + if ((*gid = ucred_getrgid(ucred)) == -1) + return (-1); + + ucred_free(ucred); + + return (0); +} +#else +int +getpeereid(int s, uid_t *euid, gid_t *gid) +{ + *euid = geteuid(); + *gid = getgid(); + + return (0); +} +#endif /* defined(SO_PEERCRED) */ + +#endif /* !defined(HAVE_GETPEEREID) */ diff --git a/openbsd-compat/bsd-misc.c b/openbsd-compat/bsd-misc.c new file mode 100644 index 00000000..fa0bb26c --- /dev/null +++ b/openbsd-compat/bsd-misc.c @@ -0,0 +1,278 @@ + +/* + * Copyright (c) 1999-2004 Damien Miller <djm@mindrot.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +#include <sys/types.h> +#ifdef HAVE_SYS_SELECT_H +# include <sys/select.h> +#endif +#ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +#endif + +#include <string.h> +#include <signal.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> + +#include "xmalloc.h" + +#ifndef HAVE___PROGNAME +char *__progname; +#endif + +/* + * NB. duplicate __progname in case it is an alias for argv[0] + * Otherwise it may get clobbered by setproctitle() + */ +char *ssh_get_progname(char *argv0) +{ +#ifdef HAVE___PROGNAME + extern char *__progname; + + return __xstrdup(__progname); +#else + char *p; + + if (argv0 == NULL) + return ("unknown"); /* XXX */ + p = strrchr(argv0, '/'); + if (p == NULL) + p = argv0; + else + p++; + + return __xstrdup(p); +#endif +} + +#ifndef HAVE_SETLOGIN +int setlogin(const char *name) +{ + return (0); +} +#endif /* !HAVE_SETLOGIN */ + +#ifndef HAVE_INNETGR +int innetgr(const char *netgroup, const char *host, + const char *user, const char *domain) +{ + return (0); +} +#endif /* HAVE_INNETGR */ + +#if !defined(HAVE_SETEUID) && defined(HAVE_SETREUID) +int seteuid(uid_t euid) +{ + return (setreuid(-1, euid)); +} +#endif /* !defined(HAVE_SETEUID) && defined(HAVE_SETREUID) */ + +#if !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID) +int setegid(uid_t egid) +{ + return(setresgid(-1, egid, -1)); +} +#endif /* !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID) */ + +#if !defined(HAVE_STRERROR) && defined(HAVE_SYS_ERRLIST) && defined(HAVE_SYS_NERR) +const char *strerror(int e) +{ + extern int sys_nerr; + extern char *sys_errlist[]; + + if ((e >= 0) && (e < sys_nerr)) + return (sys_errlist[e]); + + return ("unlisted error"); +} +#endif + +#ifndef HAVE_UTIMES +int utimes(char *filename, struct timeval *tvp) +{ + struct utimbuf ub; + + ub.actime = tvp[0].tv_sec; + ub.modtime = tvp[1].tv_sec; + + return (utime(filename, &ub)); +} +#endif + +#ifndef HAVE_TRUNCATE +int truncate(const char *path, off_t length) +{ + int fd, ret, saverrno; + + fd = open(path, O_WRONLY); + if (fd < 0) + return (-1); + + ret = ftruncate(fd, length); + saverrno = errno; + close(fd); + if (ret == -1) + errno = saverrno; + + return(ret); +} +#endif /* HAVE_TRUNCATE */ + +#if !defined(HAVE_NANOSLEEP) && !defined(HAVE_NSLEEP) +int nanosleep(const struct timespec *req, struct timespec *rem) +{ + int rc, saverrno; + extern int errno; + struct timeval tstart, tstop, tremain, time2wait; + + TIMESPEC_TO_TIMEVAL(&time2wait, req); + (void) gettimeofday(&tstart, NULL); + rc = select(0, NULL, NULL, NULL, &time2wait); + if (rc == -1) { + saverrno = errno; + (void) gettimeofday (&tstop, NULL); + errno = saverrno; + tremain.tv_sec = time2wait.tv_sec - + (tstop.tv_sec - tstart.tv_sec); + tremain.tv_usec = time2wait.tv_usec - + (tstop.tv_usec - tstart.tv_usec); + tremain.tv_sec += tremain.tv_usec / 1000000L; + tremain.tv_usec %= 1000000L; + } else { + tremain.tv_sec = 0; + tremain.tv_usec = 0; + } + if (rem != NULL) + TIMEVAL_TO_TIMESPEC(&tremain, rem); + + return(rc); +} +#endif + +#if !defined(HAVE_USLEEP) +int usleep(unsigned int useconds) +{ + struct timespec ts; + + ts.tv_sec = useconds / 1000000; + ts.tv_nsec = (useconds % 1000000) * 1000; + return nanosleep(&ts, NULL); +} +#endif + +#ifndef HAVE_TCGETPGRP +pid_t +tcgetpgrp(int fd) +{ + int ctty_pgrp; + + if (ioctl(fd, TIOCGPGRP, &ctty_pgrp) == -1) + return(-1); + else + return(ctty_pgrp); +} +#endif /* HAVE_TCGETPGRP */ + +#ifndef HAVE_TCSENDBREAK +int +tcsendbreak(int fd, int duration) +{ +# if defined(TIOCSBRK) && defined(TIOCCBRK) + struct timeval sleepytime; + + sleepytime.tv_sec = 0; + sleepytime.tv_usec = 400000; + if (ioctl(fd, TIOCSBRK, 0) == -1) + return (-1); + (void)select(0, 0, 0, 0, &sleepytime); + if (ioctl(fd, TIOCCBRK, 0) == -1) + return (-1); + return (0); +# else + return -1; +# endif +} +#endif /* HAVE_TCSENDBREAK */ + +mysig_t +mysignal(int sig, mysig_t act) +{ +#ifdef HAVE_SIGACTION + struct sigaction sa, osa; + + if (sigaction(sig, NULL, &osa) == -1) + return (mysig_t) -1; + if (osa.sa_handler != act) { + memset(&sa, 0, sizeof(sa)); + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; +#ifdef SA_INTERRUPT + if (sig == SIGALRM) + sa.sa_flags |= SA_INTERRUPT; +#endif + sa.sa_handler = act; + if (sigaction(sig, &sa, NULL) == -1) + return (mysig_t) -1; + } + return (osa.sa_handler); +#else + #undef signal + return (signal(sig, act)); +#endif +} + +#ifndef HAVE_STRDUP +char * +strdup(const char *str) +{ + size_t len; + char *cp; + + len = strlen(str) + 1; + cp = malloc(len); + if (cp != NULL) + return(memcpy(cp, str, len)); + return NULL; +} +#endif + +#ifndef HAVE_ISBLANK +int +isblank(int c) +{ + return (c == ' ' || c == '\t'); +} +#endif + +#ifndef HAVE_GETPGID +pid_t +getpgid(pid_t pid) +{ +#if defined(HAVE_GETPGRP) && !defined(GETPGRP_VOID) + return getpgrp(pid); +#elif defined(HAVE_GETPGRP) + if (pid == 0) + return getpgrp(); +#endif + + errno = ESRCH; + return -1; +} +#endif diff --git a/openbsd-compat/bsd-misc.h b/openbsd-compat/bsd-misc.h new file mode 100644 index 00000000..4e517a93 --- /dev/null +++ b/openbsd-compat/bsd-misc.h @@ -0,0 +1,117 @@ +/* $Id: bsd-misc.h,v 1.25 2013/08/04 11:48:41 dtucker Exp $ */ + +/* + * Copyright (c) 1999-2004 Damien Miller <djm@mindrot.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _BSD_MISC_H +#define _BSD_MISC_H + +#include "includes.h" + +char *ssh_get_progname(char *); + +#ifndef HAVE_SETSID +#define setsid() setpgrp(0, getpid()) +#endif /* !HAVE_SETSID */ + +#ifndef HAVE_SETENV +int setenv(const char *, const char *, int); +#endif /* !HAVE_SETENV */ + +#ifndef HAVE_SETLOGIN +int setlogin(const char *); +#endif /* !HAVE_SETLOGIN */ + +#ifndef HAVE_INNETGR +int innetgr(const char *, const char *, const char *, const char *); +#endif /* HAVE_INNETGR */ + +#if !defined(HAVE_SETEUID) && defined(HAVE_SETREUID) +int seteuid(uid_t); +#endif /* !defined(HAVE_SETEUID) && defined(HAVE_SETREUID) */ + +#if !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID) +int setegid(uid_t); +#endif /* !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID) */ + +#if !defined(HAVE_STRERROR) && defined(HAVE_SYS_ERRLIST) && defined(HAVE_SYS_NERR) +const char *strerror(int); +#endif + +#if !defined(HAVE_SETLINEBUF) +#define setlinebuf(a) (setvbuf((a), NULL, _IOLBF, 0)) +#endif + +#ifndef HAVE_UTIMES +#ifndef HAVE_STRUCT_TIMEVAL +struct timeval { + long tv_sec; + long tv_usec; +} +#endif /* HAVE_STRUCT_TIMEVAL */ + +int utimes(char *, struct timeval *); +#endif /* HAVE_UTIMES */ + +#ifndef HAVE_TRUNCATE +int truncate (const char *, off_t); +#endif /* HAVE_TRUNCATE */ + +#if !defined(HAVE_NANOSLEEP) && !defined(HAVE_NSLEEP) +#ifndef HAVE_STRUCT_TIMESPEC +struct timespec { + time_t tv_sec; + long tv_nsec; +}; +#endif +int nanosleep(const struct timespec *, struct timespec *); +#endif + +#ifndef HAVE_USLEEP +int usleep(unsigned int useconds); +#endif + +#ifndef HAVE_TCGETPGRP +pid_t tcgetpgrp(int); +#endif + +#ifndef HAVE_TCSENDBREAK +int tcsendbreak(int, int); +#endif + +#ifndef HAVE_UNSETENV +int unsetenv(const char *); +#endif + +/* wrapper for signal interface */ +typedef void (*mysig_t)(int); +mysig_t mysignal(int sig, mysig_t act); + +#define signal(a,b) mysignal(a,b) + +#ifndef HAVE_ISBLANK +int isblank(int); +#endif + +#ifndef HAVE_GETPGID +pid_t getpgid(pid_t); +#endif + +#ifndef HAVE_ENDGRENT +# define endgrent() {} +#endif + +#endif /* _BSD_MISC_H */ diff --git a/openbsd-compat/bsd-vis.h b/openbsd-compat/bsd-vis.h new file mode 100644 index 00000000..d1286c99 --- /dev/null +++ b/openbsd-compat/bsd-vis.h @@ -0,0 +1,95 @@ +/* $OpenBSD: vis.h,v 1.11 2005/08/09 19:38:31 millert Exp $ */ +/* $NetBSD: vis.h,v 1.4 1994/10/26 00:56:41 cgd Exp $ */ + +/*- + * Copyright (c) 1990 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. 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. + * + * @(#)vis.h 5.9 (Berkeley) 4/3/91 + */ + +/* OPENBSD ORIGINAL: include/vis.h */ + +#include "includes.h" +#if !defined(HAVE_STRNVIS) || defined(BROKEN_STRNVIS) + +#ifndef _VIS_H_ +#define _VIS_H_ + +#include <sys/types.h> +#include <limits.h> + +/* + * to select alternate encoding format + */ +#define VIS_OCTAL 0x01 /* use octal \ddd format */ +#define VIS_CSTYLE 0x02 /* use \[nrft0..] where appropriate */ + +/* + * to alter set of characters encoded (default is to encode all + * non-graphic except space, tab, and newline). + */ +#define VIS_SP 0x04 /* also encode space */ +#define VIS_TAB 0x08 /* also encode tab */ +#define VIS_NL 0x10 /* also encode newline */ +#define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL) +#define VIS_SAFE 0x20 /* only encode "unsafe" characters */ + +/* + * other + */ +#define VIS_NOSLASH 0x40 /* inhibit printing '\' */ +#define VIS_GLOB 0x100 /* encode glob(3) magics and '#' */ + +/* + * unvis return codes + */ +#define UNVIS_VALID 1 /* character valid */ +#define UNVIS_VALIDPUSH 2 /* character valid, push back passed char */ +#define UNVIS_NOCHAR 3 /* valid sequence, no character produced */ +#define UNVIS_SYNBAD -1 /* unrecognized escape sequence */ +#define UNVIS_ERROR -2 /* decoder in unknown state (unrecoverable) */ + +/* + * unvis flags + */ +#define UNVIS_END 1 /* no more characters */ + +char *vis(char *, int, int, int); +int strvis(char *, const char *, int); +int strnvis(char *, const char *, size_t, int) + __attribute__ ((__bounded__(__string__,1,3))); +int strvisx(char *, const char *, size_t, int) + __attribute__ ((__bounded__(__string__,1,3))); +int strunvis(char *, const char *); +int unvis(char *, char, int *, int); +ssize_t strnunvis(char *, const char *, size_t) + __attribute__ ((__bounded__(__string__,1,3))); + +#endif /* !_VIS_H_ */ + +#endif /* !HAVE_STRNVIS || BROKEN_STRNVIS */ diff --git a/openbsd-compat/bsd-waitpid.c b/openbsd-compat/bsd-waitpid.c new file mode 100644 index 00000000..40e6ffaa --- /dev/null +++ b/openbsd-compat/bsd-waitpid.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2000 Ben Lindstrom. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 "includes.h" + +#ifndef HAVE_WAITPID +#include <errno.h> +#include <sys/wait.h> +#include "bsd-waitpid.h" + +pid_t +waitpid(int pid, int *stat_loc, int options) +{ + union wait statusp; + pid_t wait_pid; + + if (pid <= 0) { + if (pid != -1) { + errno = EINVAL; + return (-1); + } + /* wait4() wants pid=0 for indiscriminate wait. */ + pid = 0; + } + wait_pid = wait4(pid, &statusp, options, NULL); + if (stat_loc) + *stat_loc = (int) statusp.w_status; + + return (wait_pid); +} + +#endif /* !HAVE_WAITPID */ diff --git a/openbsd-compat/bsd-waitpid.h b/openbsd-compat/bsd-waitpid.h new file mode 100644 index 00000000..2d853db6 --- /dev/null +++ b/openbsd-compat/bsd-waitpid.h @@ -0,0 +1,51 @@ +/* $Id: bsd-waitpid.h,v 1.5 2003/08/29 16:59:52 mouring Exp $ */ + +/* + * Copyright (c) 2000 Ben Lindstrom. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + */ + +#ifndef _BSD_WAITPID_H +#define _BSD_WAITPID_H + +#ifndef HAVE_WAITPID +/* Clean out any potental issues */ +#undef WIFEXITED +#undef WIFSTOPPED +#undef WIFSIGNALED + +/* Define required functions to mimic a POSIX look and feel */ +#define _W_INT(w) (*(int*)&(w)) /* convert union wait to int */ +#define WIFEXITED(w) (!((_W_INT(w)) & 0377)) +#define WIFSTOPPED(w) ((_W_INT(w)) & 0100) +#define WIFSIGNALED(w) (!WIFEXITED(w) && !WIFSTOPPED(w)) +#define WEXITSTATUS(w) (int)(WIFEXITED(w) ? ((_W_INT(w) >> 8) & 0377) : -1) +#define WTERMSIG(w) (int)(WIFSIGNALED(w) ? (_W_INT(w) & 0177) : -1) +#define WCOREFLAG 0x80 +#define WCOREDUMP(w) ((_W_INT(w)) & WCOREFLAG) + +/* Prototype */ +pid_t waitpid(int, int *, int); + +#endif /* !HAVE_WAITPID */ +#endif /* _BSD_WAITPID_H */ diff --git a/openbsd-compat/chacha_private.h b/openbsd-compat/chacha_private.h new file mode 100644 index 00000000..46613646 --- /dev/null +++ b/openbsd-compat/chacha_private.h @@ -0,0 +1,224 @@ +/* +chacha-merged.c version 20080118 +D. J. Bernstein +Public domain. +*/ + +/* $OpenBSD: chacha_private.h,v 1.2 2013/10/04 07:02:27 djm Exp $ */ + +#include <sys/types.h> + +typedef unsigned char u8; +typedef unsigned int u32; + +typedef struct +{ + u32 input[16]; /* could be compressed */ +} chacha_ctx; + +#define U8C(v) (v##U) +#define U32C(v) (v##U) + +#define U8V(v) ((u8)(v) & U8C(0xFF)) +#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) + +#define ROTL32(v, n) \ + (U32V((v) << (n)) | ((v) >> (32 - (n)))) + +#define U8TO32_LITTLE(p) \ + (((u32)((p)[0]) ) | \ + ((u32)((p)[1]) << 8) | \ + ((u32)((p)[2]) << 16) | \ + ((u32)((p)[3]) << 24)) + +#define U32TO8_LITTLE(p, v) \ + do { \ + (p)[0] = U8V((v) ); \ + (p)[1] = U8V((v) >> 8); \ + (p)[2] = U8V((v) >> 16); \ + (p)[3] = U8V((v) >> 24); \ + } while (0) + +#define ROTATE(v,c) (ROTL32(v,c)) +#define XOR(v,w) ((v) ^ (w)) +#define PLUS(v,w) (U32V((v) + (w))) +#define PLUSONE(v) (PLUS((v),1)) + +#define QUARTERROUND(a,b,c,d) \ + a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ + a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); + +static const char sigma[16] = "expand 32-byte k"; +static const char tau[16] = "expand 16-byte k"; + +static void +chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits,u32 ivbits) +{ + const char *constants; + + x->input[4] = U8TO32_LITTLE(k + 0); + x->input[5] = U8TO32_LITTLE(k + 4); + x->input[6] = U8TO32_LITTLE(k + 8); + x->input[7] = U8TO32_LITTLE(k + 12); + if (kbits == 256) { /* recommended */ + k += 16; + constants = sigma; + } else { /* kbits == 128 */ + constants = tau; + } + x->input[8] = U8TO32_LITTLE(k + 0); + x->input[9] = U8TO32_LITTLE(k + 4); + x->input[10] = U8TO32_LITTLE(k + 8); + x->input[11] = U8TO32_LITTLE(k + 12); + x->input[0] = U8TO32_LITTLE(constants + 0); + x->input[1] = U8TO32_LITTLE(constants + 4); + x->input[2] = U8TO32_LITTLE(constants + 8); + x->input[3] = U8TO32_LITTLE(constants + 12); +} + +static void +chacha_ivsetup(chacha_ctx *x,const u8 *iv) +{ + x->input[12] = 0; + x->input[13] = 0; + x->input[14] = U8TO32_LITTLE(iv + 0); + x->input[15] = U8TO32_LITTLE(iv + 4); +} + +static void +chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes) +{ + u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; + u8 *ctarget = NULL; + u8 tmp[64]; + u_int i; + + if (!bytes) return; + + j0 = x->input[0]; + j1 = x->input[1]; + j2 = x->input[2]; + j3 = x->input[3]; + j4 = x->input[4]; + j5 = x->input[5]; + j6 = x->input[6]; + j7 = x->input[7]; + j8 = x->input[8]; + j9 = x->input[9]; + j10 = x->input[10]; + j11 = x->input[11]; + j12 = x->input[12]; + j13 = x->input[13]; + j14 = x->input[14]; + j15 = x->input[15]; + + for (;;) { + if (bytes < 64) { + for (i = 0;i < bytes;++i) tmp[i] = m[i]; + m = tmp; + ctarget = c; + c = tmp; + } + x0 = j0; + x1 = j1; + x2 = j2; + x3 = j3; + x4 = j4; + x5 = j5; + x6 = j6; + x7 = j7; + x8 = j8; + x9 = j9; + x10 = j10; + x11 = j11; + x12 = j12; + x13 = j13; + x14 = j14; + x15 = j15; + for (i = 20;i > 0;i -= 2) { + QUARTERROUND( x0, x4, x8,x12) + QUARTERROUND( x1, x5, x9,x13) + QUARTERROUND( x2, x6,x10,x14) + QUARTERROUND( x3, x7,x11,x15) + QUARTERROUND( x0, x5,x10,x15) + QUARTERROUND( x1, x6,x11,x12) + QUARTERROUND( x2, x7, x8,x13) + QUARTERROUND( x3, x4, x9,x14) + } + x0 = PLUS(x0,j0); + x1 = PLUS(x1,j1); + x2 = PLUS(x2,j2); + x3 = PLUS(x3,j3); + x4 = PLUS(x4,j4); + x5 = PLUS(x5,j5); + x6 = PLUS(x6,j6); + x7 = PLUS(x7,j7); + x8 = PLUS(x8,j8); + x9 = PLUS(x9,j9); + x10 = PLUS(x10,j10); + x11 = PLUS(x11,j11); + x12 = PLUS(x12,j12); + x13 = PLUS(x13,j13); + x14 = PLUS(x14,j14); + x15 = PLUS(x15,j15); + +#ifndef KEYSTREAM_ONLY + x0 = XOR(x0,U8TO32_LITTLE(m + 0)); + x1 = XOR(x1,U8TO32_LITTLE(m + 4)); + x2 = XOR(x2,U8TO32_LITTLE(m + 8)); + x3 = XOR(x3,U8TO32_LITTLE(m + 12)); + x4 = XOR(x4,U8TO32_LITTLE(m + 16)); + x5 = XOR(x5,U8TO32_LITTLE(m + 20)); + x6 = XOR(x6,U8TO32_LITTLE(m + 24)); + x7 = XOR(x7,U8TO32_LITTLE(m + 28)); + x8 = XOR(x8,U8TO32_LITTLE(m + 32)); + x9 = XOR(x9,U8TO32_LITTLE(m + 36)); + x10 = XOR(x10,U8TO32_LITTLE(m + 40)); + x11 = XOR(x11,U8TO32_LITTLE(m + 44)); + x12 = XOR(x12,U8TO32_LITTLE(m + 48)); + x13 = XOR(x13,U8TO32_LITTLE(m + 52)); + x14 = XOR(x14,U8TO32_LITTLE(m + 56)); + x15 = XOR(x15,U8TO32_LITTLE(m + 60)); +#endif + + j12 = PLUSONE(j12); + if (!j12) { + j13 = PLUSONE(j13); + /* stopping at 2^70 bytes per nonce is user's responsibility */ + } + + U32TO8_LITTLE(c + 0,x0); + U32TO8_LITTLE(c + 4,x1); + U32TO8_LITTLE(c + 8,x2); + U32TO8_LITTLE(c + 12,x3); + U32TO8_LITTLE(c + 16,x4); + U32TO8_LITTLE(c + 20,x5); + U32TO8_LITTLE(c + 24,x6); + U32TO8_LITTLE(c + 28,x7); + U32TO8_LITTLE(c + 32,x8); + U32TO8_LITTLE(c + 36,x9); + U32TO8_LITTLE(c + 40,x10); + U32TO8_LITTLE(c + 44,x11); + U32TO8_LITTLE(c + 48,x12); + U32TO8_LITTLE(c + 52,x13); + U32TO8_LITTLE(c + 56,x14); + U32TO8_LITTLE(c + 60,x15); + + if (bytes <= 64) { + if (bytes < 64) { + for (i = 0;i < bytes;++i) ctarget[i] = c[i]; + } + x->input[12] = j12; + x->input[13] = j13; + return; + } + bytes -= 64; + c += 64; +#ifndef KEYSTREAM_ONLY + m += 64; +#endif + } +} diff --git a/openbsd-compat/clock_gettime.c b/openbsd-compat/clock_gettime.c new file mode 100644 index 00000000..6c1ef0d4 --- /dev/null +++ b/openbsd-compat/clock_gettime.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2012 Charles Longeau <chl@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +#ifdef HAVE_MACH_MACH_TIME_H +#include <mach/mach_time.h> +#endif +#include <sys/time.h> +#include <time.h> + +#if !defined(HAVE_CLOCK_GETTIME) +int +clock_gettime(int clock_id, struct timespec *tp) +{ + int ret = 0; + uint64_t time; + mach_timebase_info_data_t info; + static double scaling_factor = 0; + +#if 0 + struct timeval tv; + + ret = gettimeofday(&tv, NULL); + TIMEVAL_TO_TIMESPEC(&tv, tp); +#endif + +/* based on http://code-factor.blogspot.fr/2009/11/monotonic-timers.html */ + + time = mach_absolute_time(); + + if (scaling_factor == 0) { + ret = (int) mach_timebase_info(&info); + if (ret != 0) + fatal("mach_timebase_info failed"); + scaling_factor = info.numer/info.denom; + } + + time *= scaling_factor; + + tp->tv_sec = time / 1000000000; + tp->tv_nsec = time % 1000000000; + + return (ret); +} +#endif diff --git a/openbsd-compat/crypt_checkpass.c b/openbsd-compat/crypt_checkpass.c new file mode 100644 index 00000000..d10b3a57 --- /dev/null +++ b/openbsd-compat/crypt_checkpass.c @@ -0,0 +1,33 @@ +/* OPENBSD ORIGINAL: lib/libc/crypt/cryptutil.c */ + +#include "includes.h" +#include <errno.h> +#ifdef HAVE_CRYPT_H +#include <crypt.h> +#endif +#include <string.h> +#include <unistd.h> + +int +crypt_checkpass(const char *pass, const char *goodhash) +{ + char *c; + + if (goodhash == NULL) + goto fail; + + /* empty password */ + if (strlen(goodhash) == 0 && strlen(pass) == 0) + return 0; + + c = crypt(pass, goodhash); + if (c == NULL) + goto fail; + + if (strcmp(c, goodhash) == 0) + return 0; + +fail: + errno = EACCES; + return -1; +} diff --git a/openbsd-compat/daemon.c b/openbsd-compat/daemon.c new file mode 100644 index 00000000..3efe14c6 --- /dev/null +++ b/openbsd-compat/daemon.c @@ -0,0 +1,82 @@ +/* $OpenBSD: daemon.c,v 1.6 2005/08/08 08:05:33 espie Exp $ */ +/*- + * Copyright (c) 1990, 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. 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. + */ + +/* OPENBSD ORIGINAL: lib/libc/gen/daemon.c */ + +#include "includes.h" + +#ifndef HAVE_DAEMON + +#include <sys/types.h> + +#ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif + +#ifdef HAVE_FCNTL_H +# include <fcntl.h> +#endif + +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +int +daemon(int nochdir, int noclose) +{ + int fd; + + switch (fork()) { + case -1: + return (-1); + case 0: + break; + default: + _exit(0); + } + + if (setsid() == -1) + return (-1); + + if (!nochdir) + (void)chdir("/"); + + if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { + (void)dup2(fd, STDIN_FILENO); + (void)dup2(fd, STDOUT_FILENO); + (void)dup2(fd, STDERR_FILENO); + if (fd > 2) + (void)close (fd); + } + return (0); +} + +#endif /* !HAVE_DAEMON */ + diff --git a/openbsd-compat/defines.h b/openbsd-compat/defines.h new file mode 100644 index 00000000..d987f858 --- /dev/null +++ b/openbsd-compat/defines.h @@ -0,0 +1,506 @@ +/* + * Copyright (c) 2016 Gilles Chehade <gilles@poolp.org>. All rights reserved. + * Copyright (c) 1999-2003 Damien Miller. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#ifndef _DEFINES_H +#define _DEFINES_H + +/* $Id: defines.h,v 1.181 2014/06/11 19:22:50 dtucker Exp $ */ + + +/* Constants */ + +#ifndef HOST_NAME_MAX +# ifdef _POSIX_HOST_NAME_MAX +# define HOST_NAME_MAX _POSIX_HOST_NAME_MAX +# endif +#endif + +#ifndef PATH_MAX +# ifdef _POSIX_PATH_MAX +# define PATH_MAX _POSIX_PATH_MAX +# endif +#endif + +#ifndef MAXPATHLEN +# ifdef PATH_MAX +# define MAXPATHLEN PATH_MAX +# else /* PATH_MAX */ +# define MAXPATHLEN 64 +# define PATH_MAX 64 +/* realpath uses a fixed buffer of size MAXPATHLEN, so force use of ours */ +# ifndef BROKEN_REALPATH +# define BROKEN_REALPATH 1 +# endif /* BROKEN_REALPATH */ +# endif /* PATH_MAX */ +#endif /* MAXPATHLEN */ + +#ifndef MAXHOSTNAMELEN +# define MAXHOSTNAMELEN 64 +#endif + +#ifndef LOGIN_NAME_MAX +# define LOGIN_NAME_MAX 9 +#endif + +#ifndef MAXLOGNAME +#define MAXLOGNAME LOGIN_NAME_MAX +#endif + +#ifndef UID_MAX +#define UID_MAX UINT_MAX +#endif +#ifndef GID_MAX +#define GID_MAX UINT_MAX +#endif + +#ifndef STDIN_FILENO +# define STDIN_FILENO 0 +#endif +#ifndef STDOUT_FILENO +# define STDOUT_FILENO 1 +#endif +#ifndef STDERR_FILENO +# define STDERR_FILENO 2 +#endif + +#if !HAVE_DECL_O_NONBLOCK +# define O_NONBLOCK 00004 /* Non Blocking Open */ +#endif + +#ifndef S_ISDIR +# define S_ISDIR(mode) (((mode) & (_S_IFMT)) == (_S_IFDIR)) +#endif /* S_ISDIR */ + +#ifndef S_ISREG +# define S_ISREG(mode) (((mode) & (_S_IFMT)) == (_S_IFREG)) +#endif /* S_ISREG */ + +#ifndef S_ISLNK +# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) +#endif /* S_ISLNK */ + +#ifndef S_IXUSR +# define S_ISUID 0004000 /* set-uid */ +# define S_ISGID 0002000 /* set-gid */ +# define S_ISVTX 0001000 /* sticky */ +# define S_IXUSR 0000100 /* execute/search permission, */ +# define S_IXGRP 0000010 /* execute/search permission, */ +# define S_IXOTH 0000001 /* execute/search permission, */ +# define _S_IWUSR 0000200 /* write permission, */ +# define S_IWUSR _S_IWUSR /* write permission, owner */ +# define S_IWGRP 0000020 /* write permission, group */ +# define S_IWOTH 0000002 /* write permission, other */ +# define S_IRUSR 0000400 /* read permission, owner */ +# define S_IRGRP 0000040 /* read permission, group */ +# define S_IROTH 0000004 /* read permission, other */ +# define S_IRWXU 0000700 /* read, write, execute */ +# define S_IRWXG 0000070 /* read, write, execute */ +# define S_IRWXO 0000007 /* read, write, execute */ +#endif /* S_IXUSR */ + +#if !defined(MAP_ANON) && defined(MAP_ANONYMOUS) +#define MAP_ANON MAP_ANONYMOUS +#endif + +#ifndef MAP_FAILED +# define MAP_FAILED ((void *)-1) +#endif + +/* +SCO Open Server 3 has INADDR_LOOPBACK defined in rpc/rpc.h but +including rpc/rpc.h breaks Solaris 6 +*/ +#ifndef INADDR_LOOPBACK +#define INADDR_LOOPBACK ((u_long)0x7f000001) +#endif + + +/* Types */ +#ifndef HAVE_U_CHAR +typedef unsigned char u_char; +# define HAVE_U_CHAR +#endif /* HAVE_U_CHAR */ + +#ifndef HAVE_U_INT +typedef unsigned int u_int; +# define HAVE_U_INT +#endif + +#ifndef HAVE_INTMAX_T +typedef long long intmax_t; +# define HAVE_INTMAX_T +#endif + +#ifndef HAVE_UINTMAX_T +typedef unsigned long long uintmax_t; +# define HAVE_UINTMAX_T +#endif + +#ifndef HAVE_SA_FAMILY_T +typedef int sa_family_t; +# define HAVE_SA_FAMILY_T +#endif /* HAVE_SA_FAMILY_T */ + +#ifndef HAVE_SIG_ATOMIC_T +typedef int sig_atomic_t; +# define HAVE_SIG_ATOMIC_T +#endif /* HAVE_SIG_ATOMIC_T */ + + +#ifndef ULLONG_MAX +# define ULLONG_MAX ((unsigned long long)-1) +#endif + +#ifndef SIZE_T_MAX +#define SIZE_T_MAX ULONG_MAX +#endif /* SIZE_T_MAX */ + +#ifndef SIZE_MAX +#define SIZE_MAX SIZE_T_MAX +#endif + + + +#if !defined(HAVE_SS_FAMILY_IN_SS) && defined(HAVE___SS_FAMILY_IN_SS) +# define ss_family __ss_family +#endif /* !defined(HAVE_SS_FAMILY_IN_SS) && defined(HAVE_SA_FAMILY_IN_SS) */ + +#ifndef HAVE_SYS_UN_H +struct sockaddr_un { + short sun_family; /* AF_UNIX */ + char sun_path[108]; /* path name (gag) */ +}; +#endif /* HAVE_SYS_UN_H */ + +#ifndef HAVE_IN_ADDR_T +typedef uint32_t in_addr_t; +#endif + +#ifndef HAVE_IN_PORT_T +typedef uint16_t in_port_t; +#endif + + +/* Paths */ + +/* needed by compat/daemon.c */ +#ifndef _PATH_DEVNULL +# define _PATH_DEVNULL "/dev/null" +#endif + +/* user may have set a different path */ +#if defined(_PATH_MAILDIR) && defined(MAIL_DIRECTORY) +# undef _PATH_MAILDIR +#endif /* defined(_PATH_MAILDIR) && defined(MAIL_DIRECTORY) */ + +#ifdef MAIL_DIRECTORY +# define _PATH_MAILDIR MAIL_DIRECTORY +#endif + +#ifdef MAILDIR +# undef MAILDIR +#endif + + + +/* Macros */ + +/* needed by compat */ +#ifndef MAX +# define MAX(a,b) (((a)>(b))?(a):(b)) +#endif +#ifndef MIN +# define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +/* needed by smtpd */ +#ifndef timespeccmp +#define timespeccmp(a, b, cmp) \ + (((a)->tv_sec == (b)->tv_sec) ? \ + ((a)->tv_nsec cmp (b)->tv_nsec) : \ + ((a)->tv_sec cmp (b)->tv_sec)) +#endif + +/* needed by smtpd */ +#ifndef timespecsub +#define timespecsub(a, b, result) \ + do { \ + (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ + (result)->tv_nsec = (a)->tv_nsec - (b)->tv_nsec; \ + if ((result)->tv_nsec < 0) { \ + --(result)->tv_sec; \ + (result)->tv_nsec += 1000000000L; \ + } \ + } while (0) +#endif + +/* needed by smtpd */ +#ifndef TIMEVAL_TO_TIMESPEC +#define TIMEVAL_TO_TIMESPEC(tv, ts) { \ + (ts)->tv_sec = (tv)->tv_sec; \ + (ts)->tv_nsec = (tv)->tv_usec * 1000; \ +} +#endif + +/* needed by compat */ +#ifndef TIMESPEC_TO_TIMEVAL +#define TIMESPEC_TO_TIMEVAL(tv, ts) { \ + (tv)->tv_sec = (ts)->tv_sec; \ + (tv)->tv_usec = (ts)->tv_nsec / 1000; \ +} +#endif + +#ifndef __P +# define __P(x) x +#endif + +#if !defined(IN6_IS_ADDR_V4MAPPED) +# define IN6_IS_ADDR_V4MAPPED(a) \ + ((((uint32_t *) (a))[0] == 0) && (((uint32_t *) (a))[1] == 0) && \ + (((uint32_t *) (a))[2] == htonl (0xffff))) +#endif /* !defined(IN6_IS_ADDR_V4MAPPED) */ + +#if !defined(__GNUC__) || (__GNUC__ < 2) +# define __attribute__(x) +#endif /* !defined(__GNUC__) || (__GNUC__ < 2) */ + +#ifndef __dead +# define __dead __attribute__((noreturn)) +#endif + +#if !defined(HAVE_ATTRIBUTE__SENTINEL__) && !defined(__sentinel__) +# define __sentinel__ +#endif + +#if !defined(HAVE_ATTRIBUTE__BOUNDED__) && !defined(__bounded__) +# define __bounded__(x, y, z) +#endif + +#if !defined(HAVE_ATTRIBUTE__NONNULL__) && !defined(__nonnull__) +# define __nonnull__(x) +#endif + +#ifndef OSSH_ALIGNBYTES +#define OSSH_ALIGNBYTES (sizeof(int) - 1) +#endif +#ifndef __CMSG_ALIGN +#define __CMSG_ALIGN(p) (((u_int)(p) + OSSH_ALIGNBYTES) &~ OSSH_ALIGNBYTES) +#endif + +/* Length of the contents of a control message of length len */ +#ifndef CMSG_LEN +#define CMSG_LEN(len) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + (len)) +#endif + +/* Length of the space taken up by a padded control message of length len */ +#ifndef CMSG_SPACE +#define CMSG_SPACE(len) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + __CMSG_ALIGN(len)) +#endif + +/* given pointer to struct cmsghdr, return pointer to data */ +#ifndef CMSG_DATA +#define CMSG_DATA(cmsg) ((u_char *)(cmsg) + __CMSG_ALIGN(sizeof(struct cmsghdr))) +#endif /* CMSG_DATA */ + +/* + * RFC 2292 requires to check msg_controllen, in case that the kernel returns + * an empty list for some reasons. + */ +#ifndef CMSG_FIRSTHDR +#define CMSG_FIRSTHDR(mhdr) \ + ((mhdr)->msg_controllen >= sizeof(struct cmsghdr) ? \ + (struct cmsghdr *)(mhdr)->msg_control : \ + (struct cmsghdr *)NULL) +#endif /* CMSG_FIRSTHDR */ + + +/* Set up BSD-style BYTE_ORDER definition if it isn't there already */ +/* XXX: doesn't try to cope with strange byte orders (PDP_ENDIAN) */ +#ifndef BYTE_ORDER +# ifndef LITTLE_ENDIAN +# define LITTLE_ENDIAN 1234 +# endif /* LITTLE_ENDIAN */ +# ifndef BIG_ENDIAN +# define BIG_ENDIAN 4321 +# endif /* BIG_ENDIAN */ +# ifdef WORDS_BIGENDIAN +# define BYTE_ORDER BIG_ENDIAN +# else /* WORDS_BIGENDIAN */ +# define BYTE_ORDER LITTLE_ENDIAN +# endif /* WORDS_BIGENDIAN */ +#endif /* BYTE_ORDER */ + +/* Function replacement / compatibility hacks */ + +#ifndef HAVE_GETOPT_OPTRESET +# undef getopt +# undef opterr +# undef optind +# undef optopt +# undef optreset +# undef optarg +# define getopt(ac, av, o) BSDgetopt(ac, av, o) +# define opterr BSDopterr +# define optind BSDoptind +# define optopt BSDoptopt +# define optreset BSDoptreset +# define optarg BSDoptarg +#endif + +#if defined(BROKEN_GETADDRINFO) && defined(HAVE_GETADDRINFO) +# undef HAVE_GETADDRINFO +#endif +#if defined(BROKEN_GETADDRINFO) && defined(HAVE_FREEADDRINFO) +# undef HAVE_FREEADDRINFO +#endif +#if defined(BROKEN_GETADDRINFO) && defined(HAVE_GAI_STRERROR) +# undef HAVE_GAI_STRERROR +#endif + +#if !defined(HAVE_MEMMOVE) && defined(HAVE_BCOPY) +# define memmove(s1, s2, n) bcopy((s2), (s1), (n)) +#endif /* !defined(HAVE_MEMMOVE) && defined(HAVE_BCOPY) */ + +#if !defined(HAVE___func__) && defined(HAVE___FUNCTION__) +# define __func__ __FUNCTION__ +#elif !defined(HAVE___func__) +# define __func__ "" +#endif + + +/* Maximum number of file descriptors available */ +/* needed by compat/bsd-closefrom.c */ +#ifndef OPEN_MAX +# ifdef HAVE_SYSCONF +# define OPEN_MAX sysconf(_SC_OPEN_MAX) +# else +# define OPEN_MAX 256 +# endif +#endif + + + +/** end of login recorder definitions */ + +#ifndef IOV_MAX +# if defined(_XOPEN_IOV_MAX) +# define IOV_MAX _XOPEN_IOV_MAX +# elif defined(DEF_IOV_MAX) +# define IOV_MAX DEF_IOV_MAX +# else +# define IOV_MAX 16 +# endif +#endif + +#ifndef EWOULDBLOCK +# define EWOULDBLOCK EAGAIN +#endif + +#ifndef INET6_ADDRSTRLEN /* for non IPv6 machines */ +#define INET6_ADDRSTRLEN 46 +#endif + +#ifndef HAVE_VA_COPY +# ifdef HAVE___VA_COPY +# define va_copy(dest, src) __va_copy(dest, src) +# else +# define va_copy(dest, src) (dest) = (src) +# endif +#endif + +/* OpenSMTPD-portable specific entries */ + +/* From OpenNTPD portable */ +#if !defined(SA_LEN) +# if defined(HAVE_STRUCT_SOCKADDR_SA_LEN) +# define SA_LEN(x) ((x)->sa_len) +# else +# define SA_LEN(x) ((x)->sa_family == AF_INET6 ? \ + sizeof(struct sockaddr_in6) : \ + sizeof(struct sockaddr_in)) +# endif +#endif + +/* From OpenBGPD portable */ +#if !defined(SS_LEN) +# if defined(HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN) +# define SS_LEN(x) ((x)->ss_len) +# else +# define SS_LEN(x) SA_LEN((struct sockaddr *)(x)) +# endif +#endif + +#ifdef HAVE_SS_LEN +# define STORAGE_LEN(X) ((X).ss_len) +# define SET_STORAGE_LEN(X, Y) do { STORAGE_LEN(X) = (Y); } while(0) +#elif defined(HAVE___SS_LEN) +# define STORAGE_LEN(X) ((X).__ss_len) +# define SET_STORAGE_LEN(X, Y) do { STORAGE_LEN(X) = (Y); } while(0) +#else +# define STORAGE_LEN(X) (STORAGE_FAMILY(X) == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)) +# define SET_STORAGE_LEN(X, Y) (void) 0 +#endif + +/* chl parts */ +#ifndef EAI_NODATA +# ifdef EAI_NONAME +# define EAI_NODATA EAI_NONAME +# else +# error "Neither EAI_NODATA and EAI_NONAME are defined! :(" +# endif +#endif +/* end of chl */ + +#ifndef HAVE_FPARSELN +/* + * fparseln() specific operation flags. + */ +#define FPARSELN_UNESCESC 0x01 +#define FPARSELN_UNESCCONT 0x02 +#define FPARSELN_UNESCCOMM 0x04 +#define FPARSELN_UNESCREST 0x08 +#define FPARSELN_UNESCALL 0x0f +#endif + +#ifdef HAVE_M_DATA +#undef M_DATA +#endif + +#ifndef SCOPE_DELIMITER +#define SCOPE_DELIMITER '%' +#endif + +#ifndef HAVE_FLOCK +#define LOCK_SH 0x01 /* shared file lock */ +#define LOCK_EX 0x02 /* exclusive file lock */ +#define LOCK_NB 0x04 /* don't block when locking */ +#define LOCK_UN 0x08 /* unlock file */ +#endif + +#if !HAVE_DECL_LOG_PERROR +#define LOG_PERROR 0 +#endif + +#endif /* _DEFINES_H */ diff --git a/openbsd-compat/dirname.c b/openbsd-compat/dirname.c new file mode 100644 index 00000000..30fcb496 --- /dev/null +++ b/openbsd-compat/dirname.c @@ -0,0 +1,72 @@ +/* $OpenBSD: dirname.c,v 1.13 2005/08/08 08:05:33 espie Exp $ */ + +/* + * Copyright (c) 1997, 2004 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* OPENBSD ORIGINAL: lib/libc/gen/dirname.c */ + +#include "includes.h" +#ifndef HAVE_DIRNAME + +#include <errno.h> +#include <string.h> +#include <sys/param.h> + +char * +dirname(const char *path) +{ + static char dname[MAXPATHLEN]; + size_t len; + const char *endp; + + /* Empty or NULL string gets treated as "." */ + if (path == NULL || *path == '\0') { + dname[0] = '.'; + dname[1] = '\0'; + return (dname); + } + + /* Strip any trailing slashes */ + endp = path + strlen(path) - 1; + while (endp > path && *endp == '/') + endp--; + + /* Find the start of the dir */ + while (endp > path && *endp != '/') + endp--; + + /* Either the dir is "/" or there are no slashes */ + if (endp == path) { + dname[0] = *endp == '/' ? '/' : '.'; + dname[1] = '\0'; + return (dname); + } else { + /* Move forward past the separating slashes */ + do { + endp--; + } while (endp > path && *endp == '/'); + } + + len = endp - path + 1; + if (len >= sizeof(dname)) { + errno = ENAMETOOLONG; + return (NULL); + } + memcpy(dname, path, len); + dname[len] = '\0'; + return (dname); +} +#endif diff --git a/openbsd-compat/entropy.c b/openbsd-compat/entropy.c new file mode 100644 index 00000000..367d7135 --- /dev/null +++ b/openbsd-compat/entropy.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2001 Damien Miller. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 "includes.h" + +#include <sys/types.h> +#include <sys/socket.h> +#ifdef HAVE_SYS_UN_H +# include <sys/un.h> +#endif + +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <errno.h> +#include <signal.h> +#include <string.h> +#include <unistd.h> + +#include <openssl/rand.h> +#include <openssl/crypto.h> +#include <openssl/err.h> + +#include "smtpd/log.h" + +void +seed_rng(void) +{ +#ifndef LIBRESSL_VERSION + u_long mask; + + /* + * OpenSSL version numbers: MNNFFPPS: major minor fix patch status + * We match major, minor, fix and status (not patch) for <1.0.0. + * After that, we acceptable compatible fix versions (so we + * allow 1.0.1 to work with 1.0.0). Going backwards is only allowed + * within a patch series. + */ + mask = SSLeay() >= 0x1000000f ? 0xfff00000L : 0xfffff00fL; + if ((SSLeay() & mask) < (OPENSSL_VERSION_NUMBER & mask)) { + fatalx("OpenSSL version mismatch. Built against %lx, you have %lx\n", + (u_long)OPENSSL_VERSION_NUMBER, SSLeay()); + } +#endif + + if (RAND_status() != 1) + fatal("PRNG is not seeded"); +} diff --git a/openbsd-compat/entropy.h b/openbsd-compat/entropy.h new file mode 100644 index 00000000..496bed66 --- /dev/null +++ b/openbsd-compat/entropy.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 1999-2000 Damien Miller. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +/* $Id: entropy.h,v 1.6 2011/09/09 01:29:41 dtucker Exp $ */ + +#ifndef _RANDOMS_H +#define _RANDOMS_H + +/* #include "buffer.h" */ + +void seed_rng(void); + +/* void rexec_send_rng_seed(Buffer *); */ +/* void rexec_recv_rng_seed(Buffer *); */ + +#endif /* _RANDOMS_H */ diff --git a/openbsd-compat/err_h/err.h b/openbsd-compat/err_h/err.h new file mode 100644 index 00000000..806ba14a --- /dev/null +++ b/openbsd-compat/err_h/err.h @@ -0,0 +1,14 @@ +#ifndef ERR_H +#define ERR_H + +#ifndef LIBCRYPTOCOMPAT_ERR_H +#define LIBCRYPTOCOMPAT_ERR_H + +void err(int, const char *, ...); +void errx(int, const char *, ...); +void warn(const char *, ...); +void warnx(const char *, ...); + +#endif + +#endif diff --git a/openbsd-compat/errc.c b/openbsd-compat/errc.c new file mode 100644 index 00000000..985101dc --- /dev/null +++ b/openbsd-compat/errc.c @@ -0,0 +1,50 @@ +/* $OpenBSD: basename.c,v 1.14 2005/08/08 08:05:33 espie Exp $ */ + +/* + * Copyright (c) 1997, 2004 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* OPENBSD ORIGINAL: lib/libc/gen/errc.c */ + +#include "includes.h" +#include <errno.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +extern char *__progname; + +void +_verrc(int eval, int code, const char *fmt, va_list ap) +{ + (void)fprintf(stderr, "%s: ", __progname); + if (fmt != NULL) { + (void)vfprintf(stderr, fmt, ap); + (void)fprintf(stderr, ": "); + } + (void)fprintf(stderr, "%s\n", strerror(code)); + exit(eval); +} + +void +errc(int eval, int code, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + _verrc(eval, code, fmt, ap); + va_end(ap); +} diff --git a/openbsd-compat/event_asr_run.c b/openbsd-compat/event_asr_run.c new file mode 100644 index 00000000..aef86154 --- /dev/null +++ b/openbsd-compat/event_asr_run.c @@ -0,0 +1,88 @@ +/* $OpenBSD$ */ +/* + * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> + +#include <asr.h> +#include <event.h> +#include <stdlib.h> + +struct event_asr { + struct event ev; + struct asr_query *async; + void (*cb)(struct asr_result *, void *); + void *arg; +}; + +struct event_asr * event_asr_run(struct asr_query *, + void (*)(struct asr_result *, void *), void *); +void event_asr_abort(struct event_asr *); + +static void +event_asr_dispatch(int fd __attribute__((__unused__)), + short ev __attribute__((__unused__)), void *arg) +{ + struct event_asr *eva = arg; + struct asr_result ar; + struct timeval tv; + + event_del(&eva->ev); + + if (asr_run(eva->async, &ar)) { + eva->cb(&ar, eva->arg); + free(eva); + } else { + event_set(&eva->ev, ar.ar_fd, + ar.ar_cond == ASR_WANT_READ ? EV_READ : EV_WRITE, + event_asr_dispatch, eva); + tv.tv_sec = ar.ar_timeout / 1000; + tv.tv_usec = (ar.ar_timeout % 1000) * 1000; + event_add(&eva->ev, &tv); + } +} + +struct event_asr * +event_asr_run(struct asr_query *async, void (*cb)(struct asr_result *, void *), + void *arg) +{ + struct event_asr *eva; + struct timeval tv; + + eva = calloc(1, sizeof *eva); + if (eva == NULL) + return (NULL); + eva->async = async; + eva->cb = cb; + eva->arg = arg; + tv.tv_sec = 0; + tv.tv_usec = 0; + evtimer_set(&eva->ev, event_asr_dispatch, eva); + evtimer_add(&eva->ev, &tv); + return (eva); +} + +void +event_asr_abort(struct event_asr *eva) +{ + asr_abort(eva->async); + event_del(&eva->ev); + free(eva); +} diff --git a/openbsd-compat/explicit_bzero.c b/openbsd-compat/explicit_bzero.c new file mode 100644 index 00000000..58c81d68 --- /dev/null +++ b/openbsd-compat/explicit_bzero.c @@ -0,0 +1,17 @@ +/* $OpenBSD: explicit_bzero.c,v 1.4 2015/08/31 02:53:57 guenther Exp $ */ +/* + * Public domain. + * Written by Matthew Dempsky. + */ + +#include "includes.h" +#ifndef HAVE_EXPLICIT_BZERO + +#include <string.h> + +void +explicit_bzero(void *buf, size_t len) +{ + memset(buf, 0, len); +} +#endif diff --git a/openbsd-compat/fgetln.c b/openbsd-compat/fgetln.c new file mode 100644 index 00000000..78099515 --- /dev/null +++ b/openbsd-compat/fgetln.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2015 Joerg Jung <jung@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * portable fgetln() version, NOT reentrant + */ + +#ifndef HAVE_FGETLN +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + +void *reallocarray(void *, size_t, size_t); + +char * +fgetln(FILE *fp, size_t *len) +{ + static char *buf = NULL; + static size_t bufsz = 0; + size_t r = 0; + char *p; + int c, e; + + if (buf == NULL) { + if ((buf = calloc(1, BUFSIZ)) == NULL) + return NULL; + bufsz = BUFSIZ; + } + + while ((c = getc(fp)) != EOF) { + buf[r++] = c; + if (r == bufsz) { + if (!(p = reallocarray(buf, 2, bufsz))) { + e = errno; + free(buf); + errno = e; + buf = NULL, bufsz = 0; + return NULL; + } + buf = p, bufsz = 2 * bufsz; + } + if (c == '\n') + break; + } + return (*len = r) ? buf : NULL; +} +#endif diff --git a/openbsd-compat/fmt_scaled.c b/openbsd-compat/fmt_scaled.c new file mode 100644 index 00000000..edd682a4 --- /dev/null +++ b/openbsd-compat/fmt_scaled.c @@ -0,0 +1,274 @@ +/* $OpenBSD: fmt_scaled.c,v 1.9 2007/03/20 03:42:52 tedu Exp $ */ + +/* + * Copyright (c) 2001, 2002, 2003 Ian F. Darwin. 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +/* OPENBSD ORIGINAL: lib/libutil/fmt_scaled.c */ + +/* + * fmt_scaled: Format numbers scaled for human comprehension + * scan_scaled: Scan numbers in this format. + * + * "Human-readable" output uses 4 digits max, and puts a unit suffix at + * the end. Makes output compact and easy-to-read esp. on huge disks. + * Formatting code was originally in OpenBSD "df", converted to library routine. + * Scanning code written for OpenBSD libutil. + */ + +#include "includes.h" + +#ifndef HAVE_FMT_SCALED + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <ctype.h> +#include <limits.h> + +typedef enum { + NONE = 0, KILO = 1, MEGA = 2, GIGA = 3, TERA = 4, PETA = 5, EXA = 6 +} unit_type; + +/* These three arrays MUST be in sync! XXX make a struct */ +static unit_type units[] = { NONE, KILO, MEGA, GIGA, TERA, PETA, EXA }; +static char scale_chars[] = "BKMGTPE"; +static long long scale_factors[] = { + 1LL, + 1024LL, + 1024LL*1024, + 1024LL*1024*1024, + 1024LL*1024*1024*1024, + 1024LL*1024*1024*1024*1024, + 1024LL*1024*1024*1024*1024*1024, +}; +#define SCALE_LENGTH (sizeof(units)/sizeof(units[0])) + +#define MAX_DIGITS (SCALE_LENGTH * 3) /* XXX strlen(sprintf("%lld", -1)? */ + +/** Convert the given input string "scaled" into numeric in "result". + * Return 0 on success, -1 and errno set on error. + */ +int +scan_scaled(char *scaled, long long *result) +{ + char *p = scaled; + int sign = 0; + unsigned int i, ndigits = 0, fract_digits = 0; + long long scale_fact = 1, whole = 0, fpart = 0; + + /* Skip leading whitespace */ + while (isascii(*p) && isspace(*p)) + ++p; + + /* Then at most one leading + or - */ + while (*p == '-' || *p == '+') { + if (*p == '-') { + if (sign) { + errno = EINVAL; + return -1; + } + sign = -1; + ++p; + } else if (*p == '+') { + if (sign) { + errno = EINVAL; + return -1; + } + sign = +1; + ++p; + } + } + + /* Main loop: Scan digits, find decimal point, if present. + * We don't allow exponentials, so no scientific notation + * (but note that E for Exa might look like e to some!). + * Advance 'p' to end, to get scale factor. + */ + for (; isascii(*p) && (isdigit(*p) || *p=='.'); ++p) { + if (*p == '.') { + if (fract_digits > 0) { /* oops, more than one '.' */ + errno = EINVAL; + return -1; + } + fract_digits = 1; + continue; + } + + i = (*p) - '0'; /* whew! finally a digit we can use */ + if (fract_digits > 0) { + if (fract_digits >= MAX_DIGITS-1) + /* ignore extra fractional digits */ + continue; + fract_digits++; /* for later scaling */ + fpart *= 10; + fpart += i; + } else { /* normal digit */ + if (++ndigits >= MAX_DIGITS) { + errno = ERANGE; + return -1; + } + whole *= 10; + whole += i; + } + } + + if (sign) { + whole *= sign; + fpart *= sign; + } + + /* If no scale factor given, we're done. fraction is discarded. */ + if (!*p) { + *result = whole; + return 0; + } + + /* Validate scale factor, and scale whole and fraction by it. */ + for (i = 0; i < SCALE_LENGTH; i++) { + + /** Are we there yet? */ + if (*p == scale_chars[i] || + *p == tolower(scale_chars[i])) { + + /* If it ends with alphanumerics after the scale char, bad. */ + if (isalnum(*(p+1))) { + errno = EINVAL; + return -1; + } + scale_fact = scale_factors[i]; + + /* scale whole part */ + whole *= scale_fact; + + /* truncate fpart so it does't overflow. + * then scale fractional part. + */ + while (fpart >= LLONG_MAX / scale_fact) { + fpart /= 10; + fract_digits--; + } + fpart *= scale_fact; + if (fract_digits > 0) { + for (i = 0; i < fract_digits -1; i++) + fpart /= 10; + } + whole += fpart; + *result = whole; + return 0; + } + } + errno = ERANGE; + return -1; +} + +/* Format the given "number" into human-readable form in "result". + * Result must point to an allocated buffer of length FMT_SCALED_STRSIZE. + * Return 0 on success, -1 and errno set if error. + */ +int +fmt_scaled(long long number, char *result) +{ + long long abval, fract = 0; + unsigned int i; + unit_type unit = NONE; + + abval = (number < 0LL) ? -number : number; /* no long long_abs yet */ + + /* Not every negative long long has a positive representation. + * Also check for numbers that are just too darned big to format + */ + if (abval < 0 || abval / 1024 >= scale_factors[SCALE_LENGTH-1]) { + errno = ERANGE; + return -1; + } + + /* scale whole part; get unscaled fraction */ + for (i = 0; i < SCALE_LENGTH; i++) { + if (abval/1024 < scale_factors[i]) { + unit = units[i]; + fract = (i == 0) ? 0 : abval % scale_factors[i]; + number /= scale_factors[i]; + if (i > 0) + fract /= scale_factors[i - 1]; + break; + } + } + + fract = (10 * fract + 512) / 1024; + /* if the result would be >= 10, round main number */ + if (fract == 10) { + if (number >= 0) + number++; + else + number--; + fract = 0; + } + + if (number == 0) + strlcpy(result, "0B", FMT_SCALED_STRSIZE); + else if (unit == NONE || number >= 100 || number <= -100) { + if (fract >= 5) { + if (number >= 0) + number++; + else + number--; + } + (void)snprintf(result, FMT_SCALED_STRSIZE, "%lld%c", + number, scale_chars[unit]); + } else + (void)snprintf(result, FMT_SCALED_STRSIZE, "%lld.%1lld%c", + number, fract, scale_chars[unit]); + + return 0; +} + +#ifdef MAIN +/* + * This is the original version of the program in the man page. + * Copy-and-paste whatever you need from it. + */ +int +main(int argc, char **argv) +{ + char *cinput = "1.5K", buf[FMT_SCALED_STRSIZE]; + long long ninput = 10483892, result; + + if (scan_scaled(cinput, &result) == 0) + printf("\"%s\" -> %lld\n", cinput, result); + else + perror(cinput); + + if (fmt_scaled(ninput, buf) == 0) + printf("%lld -> \"%s\"\n", ninput, buf); + else + fprintf(stderr, "%lld invalid (%s)\n", ninput, strerror(errno)); + + return 0; +} +#endif + +#endif /* HAVE_FMT_SCALED */ diff --git a/openbsd-compat/fparseln.c b/openbsd-compat/fparseln.c new file mode 100644 index 00000000..36fbb78a --- /dev/null +++ b/openbsd-compat/fparseln.c @@ -0,0 +1,217 @@ +/* $OpenBSD: fparseln.c,v 1.6 2005/08/02 21:46:23 espie Exp $ */ +/* $NetBSD: fparseln.c,v 1.7 1999/07/02 15:49:12 simonb Exp $ */ + +/* + * Copyright (c) 1997 Christos Zoulas. 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 Christos Zoulas. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +/* OPENBSD ORIGINAL: lib/libutil/fparseln.c */ + +#include "includes.h" + +#ifdef HAVE_SYS_CDEFS +#include <sys/cdefs.h> +#endif + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#ifndef HAVE_FPARSELN + +static int isescaped(const char *, const char *, int); + +/* isescaped(): + * Return true if the character in *p that belongs to a string + * that starts in *sp, is escaped by the escape character esc. + */ +static int +isescaped(const char *sp, const char *p, int esc) +{ + const char *cp; + size_t ne; + + /* No escape character */ + if (esc == '\0') + return 1; + + /* Count the number of escape characters that precede ours */ + for (ne = 0, cp = p; --cp >= sp && *cp == esc; ne++) + continue; + + /* Return true if odd number of escape characters */ + return (ne & 1) != 0; +} + + +/* fparseln(): + * Read a line from a file parsing continuations ending in \ + * and eliminating trailing newlines, or comments starting with + * the comment char. + */ +char * +fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], + int flags) +{ + static const char dstr[3] = { '\\', '\\', '#' }; + char *buf = NULL, *ptr, *cp, esc, con, nl, com; + size_t s, len = 0; + int cnt = 1; + + if (str == NULL) + str = dstr; + + esc = str[0]; + con = str[1]; + com = str[2]; + + /* + * XXX: it would be cool to be able to specify the newline character, + * but unfortunately, fgetln does not let us + */ + nl = '\n'; + + while (cnt) { + cnt = 0; + + if (lineno) + (*lineno)++; + + if ((ptr = fgetln(fp, &s)) == NULL) + break; + + if (s && com) { /* Check and eliminate comments */ + for (cp = ptr; cp < ptr + s; cp++) + if (*cp == com && !isescaped(ptr, cp, esc)) { + s = cp - ptr; + cnt = s == 0 && buf == NULL; + break; + } + } + + if (s && nl) { /* Check and eliminate newlines */ + cp = &ptr[s - 1]; + + if (*cp == nl) + s--; /* forget newline */ + } + + if (s && con) { /* Check and eliminate continuations */ + cp = &ptr[s - 1]; + + if (*cp == con && !isescaped(ptr, cp, esc)) { + s--; /* forget escape */ + cnt = 1; + } + } + + if (s == 0 && buf != NULL) + continue; + + if ((cp = realloc(buf, len + s + 1)) == NULL) { + free(buf); + return NULL; + } + buf = cp; + + (void) memcpy(buf + len, ptr, s); + len += s; + buf[len] = '\0'; + } + + if ((flags & FPARSELN_UNESCALL) != 0 && esc && buf != NULL && + strchr(buf, esc) != NULL) { + ptr = cp = buf; + while (cp[0] != '\0') { + int skipesc; + + while (cp[0] != '\0' && cp[0] != esc) + *ptr++ = *cp++; + if (cp[0] == '\0' || cp[1] == '\0') + break; + + skipesc = 0; + if (cp[1] == com) + skipesc += (flags & FPARSELN_UNESCCOMM); + if (cp[1] == con) + skipesc += (flags & FPARSELN_UNESCCONT); + if (cp[1] == esc) + skipesc += (flags & FPARSELN_UNESCESC); + if (cp[1] != com && cp[1] != con && cp[1] != esc) + skipesc = (flags & FPARSELN_UNESCREST); + + if (skipesc) + cp++; + else + *ptr++ = *cp++; + *ptr++ = *cp++; + } + *ptr = '\0'; + len = strlen(buf); + } + + if (size) + *size = len; + return buf; +} +#endif + +#ifdef TEST + +int main(int, char **); + +int +main(argc, argv) + int argc; + char **argv; +{ + char *ptr; + size_t size, line; + + line = 0; + while ((ptr = fparseln(stdin, &size, &line, NULL, + FPARSELN_UNESCALL)) != NULL) + printf("line %d (%d) |%s|\n", line, size, ptr); + return 0; +} + +/* + +# This is a test +line 1 +line 2 \ +line 3 # Comment +line 4 \# Not comment \\\\ + +# And a comment \ +line 5 \\\ +line 6 + +*/ + +#endif /* TEST */ diff --git a/openbsd-compat/freezero.c b/openbsd-compat/freezero.c new file mode 100644 index 00000000..172226b2 --- /dev/null +++ b/openbsd-compat/freezero.c @@ -0,0 +1,34 @@ +/* $OpenBSD: strtonum.c,v 1.6 2004/08/03 19:38:01 millert Exp $ */ + +/* + * Copyright (c) 2004 Ted Unangst and Todd Miller + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* OPENBSD ORIGINAL: lib/libc/stdlib/malloc.c */ + +#include "includes.h" + +#ifndef HAVE_FREEZERO +#include <stdlib.h> + +void +freezero(void *ptr, size_t sz) +{ + explicit_bzero(ptr, sz); + free(ptr); +} + +#endif /* HAVE_FREEZERO */ diff --git a/openbsd-compat/getopt.c b/openbsd-compat/getopt.c new file mode 100644 index 00000000..5450e43d --- /dev/null +++ b/openbsd-compat/getopt.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 1987, 1993, 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. 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. + */ + +/* OPENBSD ORIGINAL: lib/libc/stdlib/getopt.c */ + +#include "includes.h" +#if !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_OPTRESET) + +#if defined(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: getopt.c,v 1.5 2003/06/02 20:18:37 millert Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +int BSDopterr = 1, /* if error message should be printed */ + BSDoptind = 1, /* index into parent argv vector */ + BSDoptopt, /* character checked for validity */ + BSDoptreset; /* reset getopt */ +char *BSDoptarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int +BSDgetopt(nargc, nargv, ostr) + int nargc; + char * const *nargv; + const char *ostr; +{ + extern char *__progname; + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + if (ostr == NULL) + return (-1); + + if (BSDoptreset || !*place) { /* update scanning pointer */ + BSDoptreset = 0; + if (BSDoptind >= nargc || *(place = nargv[BSDoptind]) != '-') { + place = EMSG; + return (-1); + } + if (place[1] && *++place == '-') { /* found "--" */ + ++BSDoptind; + place = EMSG; + return (-1); + } + } /* option letter okay? */ + if ((BSDoptopt = (int)*place++) == (int)':' || + !(oli = strchr(ostr, BSDoptopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (BSDoptopt == (int)'-') + return (-1); + if (!*place) + ++BSDoptind; + if (BSDopterr && *ostr != ':') + (void)fprintf(stderr, + "%s: illegal option -- %c\n", __progname, BSDoptopt); + return (BADCH); + } + if (*++oli != ':') { /* don't need argument */ + BSDoptarg = NULL; + if (!*place) + ++BSDoptind; + } + else { /* need an argument */ + if (*place) /* no white space */ + BSDoptarg = place; + else if (nargc <= ++BSDoptind) { /* no arg */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (BSDopterr) + (void)fprintf(stderr, + "%s: option requires an argument -- %c\n", + __progname, BSDoptopt); + return (BADCH); + } + else /* white space */ + BSDoptarg = nargv[BSDoptind]; + place = EMSG; + ++BSDoptind; + } + return (BSDoptopt); /* dump back option letter */ +} + +#endif /* !defined(HAVE_GETOPT) || !defined(HAVE_OPTRESET) */ diff --git a/openbsd-compat/imsg-buffer.c b/openbsd-compat/imsg-buffer.c new file mode 100644 index 00000000..e3762092 --- /dev/null +++ b/openbsd-compat/imsg-buffer.c @@ -0,0 +1,310 @@ +/* $OpenBSD: imsg-buffer.c,v 1.3 2013/11/13 20:40:24 benno Exp $ */ + +/* + * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/socket.h> +#include <sys/uio.h> + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#ifndef HAVE_EXPLICIT_BZERO +#include <strings.h> +#endif +#include <unistd.h> + +#include "imsg.h" + +int ibuf_realloc(struct ibuf *, size_t); +void ibuf_enqueue(struct msgbuf *, struct ibuf *); +void ibuf_dequeue(struct msgbuf *, struct ibuf *); + +struct ibuf * +ibuf_open(size_t len) +{ + struct ibuf *buf; + + if ((buf = calloc(1, sizeof(struct ibuf))) == NULL) + return (NULL); + if ((buf->buf = malloc(len)) == NULL) { + free(buf); + return (NULL); + } + buf->size = buf->max = len; + buf->fd = -1; + + return (buf); +} + +struct ibuf * +ibuf_dynamic(size_t len, size_t max) +{ + struct ibuf *buf; + + if (max < len) + return (NULL); + + if ((buf = ibuf_open(len)) == NULL) + return (NULL); + + if (max > 0) + buf->max = max; + + return (buf); +} + +int +ibuf_realloc(struct ibuf *buf, size_t len) +{ + u_char *b; + + /* on static buffers max is eq size and so the following fails */ + if (buf->wpos + len > buf->max) { + errno = ENOMEM; + return (-1); + } + + b = realloc(buf->buf, buf->wpos + len); + if (b == NULL) + return (-1); + buf->buf = b; + buf->size = buf->wpos + len; + + return (0); +} + +int +ibuf_add(struct ibuf *buf, const void *data, size_t len) +{ + if (buf->wpos + len > buf->size) + if (ibuf_realloc(buf, len) == -1) + return (-1); + + memcpy(buf->buf + buf->wpos, data, len); + buf->wpos += len; + return (0); +} + +void * +ibuf_reserve(struct ibuf *buf, size_t len) +{ + void *b; + + if (buf->wpos + len > buf->size) + if (ibuf_realloc(buf, len) == -1) + return (NULL); + + b = buf->buf + buf->wpos; + buf->wpos += len; + return (b); +} + +void * +ibuf_seek(struct ibuf *buf, size_t pos, size_t len) +{ + /* only allowed to seek in already written parts */ + if (pos + len > buf->wpos) + return (NULL); + + return (buf->buf + pos); +} + +size_t +ibuf_size(struct ibuf *buf) +{ + return (buf->wpos); +} + +size_t +ibuf_left(struct ibuf *buf) +{ + return (buf->max - buf->wpos); +} + +void +ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf) +{ + ibuf_enqueue(msgbuf, buf); +} + +int +ibuf_write(struct msgbuf *msgbuf) +{ + struct iovec iov[IOV_MAX]; + struct ibuf *buf; + unsigned int i = 0; + ssize_t n; + + bzero(&iov, sizeof(iov)); + TAILQ_FOREACH(buf, &msgbuf->bufs, entry) { + if (i >= IOV_MAX) + break; + iov[i].iov_base = buf->buf + buf->rpos; + iov[i].iov_len = buf->wpos - buf->rpos; + i++; + } + +again: + if ((n = writev(msgbuf->fd, iov, i)) == -1) { + if (errno == EINTR) + goto again; + if (errno == ENOBUFS) + errno = EAGAIN; + return (-1); + } + + if (n == 0) { /* connection closed */ + errno = 0; + return (0); + } + + msgbuf_drain(msgbuf, n); + + return (1); +} + +void +ibuf_free(struct ibuf *buf) +{ + free(buf->buf); + free(buf); +} + +void +msgbuf_init(struct msgbuf *msgbuf) +{ + msgbuf->queued = 0; + msgbuf->fd = -1; + TAILQ_INIT(&msgbuf->bufs); +} + +void +msgbuf_drain(struct msgbuf *msgbuf, size_t n) +{ + struct ibuf *buf, *next; + + for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0; + buf = next) { + next = TAILQ_NEXT(buf, entry); + if (buf->rpos + n >= buf->wpos) { + n -= buf->wpos - buf->rpos; + ibuf_dequeue(msgbuf, buf); + } else { + buf->rpos += n; + n = 0; + } + } +} + +void +msgbuf_clear(struct msgbuf *msgbuf) +{ + struct ibuf *buf; + + while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL) + ibuf_dequeue(msgbuf, buf); +} + +int +msgbuf_write(struct msgbuf *msgbuf) +{ + struct iovec iov[IOV_MAX]; + struct ibuf *buf; + unsigned int i = 0; + ssize_t n; + struct msghdr msg; + struct cmsghdr *cmsg; + union { + struct cmsghdr hdr; + char buf[CMSG_SPACE(sizeof(int))]; + } cmsgbuf; + + bzero(&iov, sizeof(iov)); + bzero(&msg, sizeof(msg)); + TAILQ_FOREACH(buf, &msgbuf->bufs, entry) { + if (i >= IOV_MAX) + break; + iov[i].iov_base = buf->buf + buf->rpos; + iov[i].iov_len = buf->wpos - buf->rpos; + i++; + if (buf->fd != -1) + break; + } + + msg.msg_iov = iov; + msg.msg_iovlen = i; + + if (buf != NULL && buf->fd != -1) { + msg.msg_control = (caddr_t)&cmsgbuf.buf; + msg.msg_controllen = sizeof(cmsgbuf.buf); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + *(int *)CMSG_DATA(cmsg) = buf->fd; + } + +again: + if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) { + if (errno == EINTR) + goto again; + if (errno == ENOBUFS) + errno = EAGAIN; + return (-1); + } + + if (n == 0) { /* connection closed */ + errno = 0; + return (0); + } + + /* + * assumption: fd got sent if sendmsg sent anything + * this works because fds are passed one at a time + */ + if (buf != NULL && buf->fd != -1) { + close(buf->fd); + buf->fd = -1; + } + + msgbuf_drain(msgbuf, n); + + return (1); +} + +void +ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf) +{ + TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry); + msgbuf->queued++; +} + +void +ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf) +{ + TAILQ_REMOVE(&msgbuf->bufs, buf, entry); + + if (buf->fd != -1) + close(buf->fd); + + msgbuf->queued--; + ibuf_free(buf); +} diff --git a/openbsd-compat/imsg.c b/openbsd-compat/imsg.c new file mode 100644 index 00000000..a5900a05 --- /dev/null +++ b/openbsd-compat/imsg.c @@ -0,0 +1,330 @@ +/* $OpenBSD: imsg.c,v 1.5 2013/12/26 17:32:33 eric Exp $ */ + +/* + * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/socket.h> +#include <sys/uio.h> + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#ifndef HAVE_EXPLICIT_BZERO +#include <strings.h> +#endif +#include <unistd.h> + +#include "imsg.h" + +int imsg_fd_overhead = 0; + +int imsg_get_fd(struct imsgbuf *); + +int +available_fds(unsigned int n) +{ + unsigned int i; + int ret, fds[256]; + + if (n > (sizeof(fds)/sizeof(fds[0]))) + return (1); + + ret = 0; + for (i = 0; i < n; i++) { + fds[i] = -1; + if ((fds[i] = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + ret = 1; + break; + } + } + + for (i = 0; i < n && fds[i] >= 0; i++) + close(fds[i]); + + return (ret); +} + +void +imsg_init(struct imsgbuf *ibuf, int fd) +{ + msgbuf_init(&ibuf->w); + bzero(&ibuf->r, sizeof(ibuf->r)); + ibuf->fd = fd; + ibuf->w.fd = fd; + ibuf->pid = getpid(); + TAILQ_INIT(&ibuf->fds); +} + +ssize_t +imsg_read(struct imsgbuf *ibuf) +{ + struct msghdr msg; + struct cmsghdr *cmsg; + union { + struct cmsghdr hdr; + char buf[CMSG_SPACE(sizeof(int) * 1)]; + } cmsgbuf; + struct iovec iov; + ssize_t n = -1; + int fd; + struct imsg_fd *ifd; + + bzero(&msg, sizeof(msg)); + + iov.iov_base = ibuf->r.buf + ibuf->r.wpos; + iov.iov_len = sizeof(ibuf->r.buf) - ibuf->r.wpos; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = &cmsgbuf.buf; + msg.msg_controllen = sizeof(cmsgbuf.buf); + + if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL) + return (-1); + +again: + if (available_fds(imsg_fd_overhead + + (CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int))) { + errno = EAGAIN; + free(ifd); + return (-1); + } + + if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) { + if (errno == EMSGSIZE) + goto fail; + if (errno != EINTR && errno != EAGAIN) + goto fail; + goto again; + } + + ibuf->r.wpos += n; + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; + cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS) { + int i; + int j; + + /* + * We only accept one file descriptor. Due to C + * padding rules, our control buffer might contain + * more than one fd, and we must close them. + */ + j = ((char *)cmsg + cmsg->cmsg_len - + (char *)CMSG_DATA(cmsg)) / sizeof(int); + for (i = 0; i < j; i++) { + fd = ((int *)CMSG_DATA(cmsg))[i]; + if (ifd != NULL) { + ifd->fd = fd; + TAILQ_INSERT_TAIL(&ibuf->fds, ifd, + entry); + ifd = NULL; + } else + close(fd); + } + } + /* we do not handle other ctl data level */ + } + +fail: + if (ifd) + free(ifd); + return (n); +} + +ssize_t +imsg_get(struct imsgbuf *ibuf, struct imsg *imsg) +{ + size_t av, left, datalen; + + av = ibuf->r.wpos; + + if (IMSG_HEADER_SIZE > av) + return (0); + + memcpy(&imsg->hdr, ibuf->r.buf, sizeof(imsg->hdr)); + if (imsg->hdr.len < IMSG_HEADER_SIZE || + imsg->hdr.len > MAX_IMSGSIZE) { + errno = ERANGE; + return (-1); + } + if (imsg->hdr.len > av) + return (0); + datalen = imsg->hdr.len - IMSG_HEADER_SIZE; + ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE; + if ((imsg->data = malloc(datalen)) == NULL) + return (-1); + + if (imsg->hdr.flags & IMSGF_HASFD) + imsg->fd = imsg_get_fd(ibuf); + else + imsg->fd = -1; + + memcpy(imsg->data, ibuf->r.rptr, datalen); + + if (imsg->hdr.len < av) { + left = av - imsg->hdr.len; + memmove(&ibuf->r.buf, ibuf->r.buf + imsg->hdr.len, left); + ibuf->r.wpos = left; + } else + ibuf->r.wpos = 0; + + return (datalen + IMSG_HEADER_SIZE); +} + +int +imsg_compose(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, + pid_t pid, int fd, const void *data, uint16_t datalen) +{ + struct ibuf *wbuf; + + if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL) + return (-1); + + if (imsg_add(wbuf, data, datalen) == -1) + return (-1); + + wbuf->fd = fd; + + imsg_close(ibuf, wbuf); + + return (1); +} + +int +imsg_composev(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, + pid_t pid, int fd, const struct iovec *iov, int iovcnt) +{ + struct ibuf *wbuf; + int i, datalen = 0; + + for (i = 0; i < iovcnt; i++) + datalen += iov[i].iov_len; + + if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL) + return (-1); + + for (i = 0; i < iovcnt; i++) + if (imsg_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1) + return (-1); + + wbuf->fd = fd; + + imsg_close(ibuf, wbuf); + + return (1); +} + +/* ARGSUSED */ +struct ibuf * +imsg_create(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, + pid_t pid, uint16_t datalen) +{ + struct ibuf *wbuf; + struct imsg_hdr hdr; + + datalen += IMSG_HEADER_SIZE; + if (datalen > MAX_IMSGSIZE) { + errno = ERANGE; + return (NULL); + } + + hdr.type = type; + hdr.flags = 0; + hdr.peerid = peerid; + if ((hdr.pid = pid) == 0) + hdr.pid = ibuf->pid; + if ((wbuf = ibuf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) { + return (NULL); + } + if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1) + return (NULL); + + return (wbuf); +} + +int +imsg_add(struct ibuf *msg, const void *data, uint16_t datalen) +{ + if (datalen) + if (ibuf_add(msg, data, datalen) == -1) { + ibuf_free(msg); + return (-1); + } + return (datalen); +} + +void +imsg_close(struct imsgbuf *ibuf, struct ibuf *msg) +{ + struct imsg_hdr *hdr; + + hdr = (struct imsg_hdr *)msg->buf; + + hdr->flags &= ~IMSGF_HASFD; + if (msg->fd != -1) + hdr->flags |= IMSGF_HASFD; + + hdr->len = (uint16_t)msg->wpos; + + ibuf_close(&ibuf->w, msg); +} + +void +imsg_free(struct imsg *imsg) +{ + free(imsg->data); +} + +int +imsg_get_fd(struct imsgbuf *ibuf) +{ + int fd; + struct imsg_fd *ifd; + + if ((ifd = TAILQ_FIRST(&ibuf->fds)) == NULL) + return (-1); + + fd = ifd->fd; + TAILQ_REMOVE(&ibuf->fds, ifd, entry); + free(ifd); + + return (fd); +} + +int +imsg_flush(struct imsgbuf *ibuf) +{ + while (ibuf->w.queued) + if (msgbuf_write(&ibuf->w) <= 0) + return (-1); + return (0); +} + +void +imsg_clear(struct imsgbuf *ibuf) +{ + int fd; + + msgbuf_clear(&ibuf->w); + while ((fd = imsg_get_fd(ibuf)) != -1) + close(fd); +} diff --git a/openbsd-compat/imsg.h b/openbsd-compat/imsg.h new file mode 100644 index 00000000..3757c8b9 --- /dev/null +++ b/openbsd-compat/imsg.h @@ -0,0 +1,115 @@ +/* $OpenBSD: imsg.h,v 1.3 2013/12/26 17:32:33 eric Exp $ */ + +/* + * Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org> + * Copyright (c) 2006, 2007, 2008 Reyk Floeter <reyk@openbsd.org> + * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _IMSG_H_ +#define _IMSG_H_ + +#define IBUF_READ_SIZE 65535 +#define IMSG_HEADER_SIZE sizeof(struct imsg_hdr) +#define MAX_IMSGSIZE 16384 + +#include "defines.h" + +struct ibuf { + TAILQ_ENTRY(ibuf) entry; + u_char *buf; + size_t size; + size_t max; + size_t wpos; + size_t rpos; + int fd; +}; + +struct msgbuf { + TAILQ_HEAD(, ibuf) bufs; + uint32_t queued; + int fd; +}; + +struct ibuf_read { + u_char buf[IBUF_READ_SIZE]; + u_char *rptr; + size_t wpos; +}; + +struct imsg_fd { + TAILQ_ENTRY(imsg_fd) entry; + int fd; +}; + +struct imsgbuf { + TAILQ_HEAD(, imsg_fd) fds; + struct ibuf_read r; + struct msgbuf w; + int fd; + pid_t pid; +}; + +#define IMSGF_HASFD 1 + +struct imsg_hdr { + uint32_t type; + uint16_t len; + uint16_t flags; + uint32_t peerid; + uint32_t pid; +}; + +struct imsg { + struct imsg_hdr hdr; + int fd; + void *data; +}; + + +/* buffer.c */ +struct ibuf *ibuf_open(size_t); +struct ibuf *ibuf_dynamic(size_t, size_t); +int ibuf_add(struct ibuf *, const void *, size_t); +void *ibuf_reserve(struct ibuf *, size_t); +void *ibuf_seek(struct ibuf *, size_t, size_t); +size_t ibuf_size(struct ibuf *); +size_t ibuf_left(struct ibuf *); +void ibuf_close(struct msgbuf *, struct ibuf *); +int ibuf_write(struct msgbuf *); +void ibuf_free(struct ibuf *); +void msgbuf_init(struct msgbuf *); +void msgbuf_clear(struct msgbuf *); +int msgbuf_write(struct msgbuf *); +void msgbuf_drain(struct msgbuf *, size_t); + +/* imsg.c */ +int available_fds(unsigned int); +void imsg_init(struct imsgbuf *, int); +ssize_t imsg_read(struct imsgbuf *); +ssize_t imsg_get(struct imsgbuf *, struct imsg *); +int imsg_compose(struct imsgbuf *, uint32_t, uint32_t, pid_t, + int, const void *, uint16_t); +int imsg_composev(struct imsgbuf *, uint32_t, uint32_t, pid_t, + int, const struct iovec *, int); +struct ibuf *imsg_create(struct imsgbuf *, uint32_t, uint32_t, pid_t, + uint16_t); +int imsg_add(struct ibuf *, const void *, uint16_t); +void imsg_close(struct imsgbuf *, struct ibuf *); +void imsg_free(struct imsg *); +int imsg_flush(struct imsgbuf *); +void imsg_clear(struct imsgbuf *); + +#endif diff --git a/openbsd-compat/includes.h b/openbsd-compat/includes.h new file mode 100644 index 00000000..8d636e16 --- /dev/null +++ b/openbsd-compat/includes.h @@ -0,0 +1,71 @@ +/* $OpenBSD: includes.h,v 1.54 2006/07/22 20:48:23 stevesk Exp $ */ + +/* + * Author: Tatu Ylonen <ylo@cs.hut.fi> + * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + * All rights reserved + * This file includes most of the needed system headers. + * + * As far as I am concerned, the code I have written for this software + * can be used freely for any purpose. Any derived versions of this + * software must be clearly marked as such, and if the derived work is + * incompatible with the protocol description in the RFC file, it must be + * called by a name other than "ssh" or "Secure Shell". + */ + +#ifndef INCLUDES_H +#define INCLUDES_H + +#include "config.h" + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE /* activate extra prototypes for glibc */ +#endif + +#include <sys/types.h> +#include <sys/socket.h> /* For CMSG_* */ + +#ifdef HAVE_LIMITS_H +# include <limits.h> /* For PATH_MAX */ +#endif +#ifdef HAVE_BSTRING_H +# include <bstring.h> +#endif + +#ifdef HAVE_ENDIAN_H +# include <endian.h> +#endif +#ifdef HAVE_MAILLOCK_H +# include <maillock.h> /* For _PATH_MAILDIR */ +#endif +#ifdef HAVE_PATHS_H +# include <paths.h> +#endif + +#ifdef HAVE_RPC_TYPES_H +# include <rpc/types.h> /* For INADDR_LOOPBACK */ +#endif +#ifdef USE_PAM +#if defined(HAVE_SECURITY_PAM_APPL_H) +# include <security/pam_appl.h> +#elif defined (HAVE_PAM_PAM_APPL_H) +# include <pam/pam_appl.h> +#endif +#endif +#include <errno.h> + +/* chl */ +#ifdef HAVE_NETDB_H +# include <netdb.h> +#endif +/* end of chl*/ + +#include <openssl/opensslv.h> /* For OPENSSL_VERSION_NUMBER */ + +#include "defines.h" + +#include "openbsd-compat.h" + +#include "entropy.h" + +#endif /* INCLUDES_H */ diff --git a/openbsd-compat/inet_net_pton.c b/openbsd-compat/inet_net_pton.c new file mode 100644 index 00000000..b65cb76f --- /dev/null +++ b/openbsd-compat/inet_net_pton.c @@ -0,0 +1,236 @@ +/* $OpenBSD: inet_net_pton.c,v 1.8 2013/11/25 18:23:51 deraadt Exp $ */ + +/* + * Copyright (c) 2012 by Gilles Chehade <gilles@openbsd.org> + * Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#include "includes.h" +#ifndef HAVE_INET_NET_PTON + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <assert.h> +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +static int inet_net_pton_ipv4(const char *, u_char *, size_t); +static int inet_net_pton_ipv6(const char *, u_char *, size_t); + +/* + * static int + * inet_net_pton(af, src, dst, size) + * convert network number from presentation to network format. + * accepts hex octets, hex strings, decimal octets, and /CIDR. + * "size" is in bytes and describes "dst". + * return: + * number of bits, either imputed classfully or specified with /CIDR, + * or -1 if some failure occurred (check errno). ENOENT means it was + * not a valid network specification. + * author: + * Paul Vixie (ISC), June 1996 + */ +int +inet_net_pton(int af, const char *src, void *dst, size_t size) +{ + switch (af) { + case AF_INET: + return (inet_net_pton_ipv4(src, dst, size)); + case AF_INET6: + return (inet_net_pton_ipv6(src, dst, size)); + default: + errno = EAFNOSUPPORT; + return (-1); + } +} + +/* + * static int + * inet_net_pton_ipv4(src, dst, size) + * convert IPv4 network number from presentation to network format. + * accepts hex octets, hex strings, decimal octets, and /CIDR. + * "size" is in bytes and describes "dst". + * return: + * number of bits, either imputed classfully or specified with /CIDR, + * or -1 if some failure occurred (check errno). ENOENT means it was + * not an IPv4 network specification. + * note: + * network byte order assumed. this means 192.5.5.240/28 has + * 0x11110000 in its fourth octet. + * author: + * Paul Vixie (ISC), June 1996 + */ +static int +inet_net_pton_ipv4(const char *src, u_char *dst, size_t size) +{ + static const char + xdigits[] = "0123456789abcdef", + digits[] = "0123456789"; + int n, ch, tmp, dirty, bits; + const u_char *odst = dst; + + ch = (unsigned char)*src++; + if (ch == '0' && (src[0] == 'x' || src[0] == 'X') + && isascii((unsigned char)src[1]) && isxdigit((unsigned char)src[1])) { + /* Hexadecimal: Eat nybble string. */ + if (size <= 0) + goto emsgsize; + *dst = 0, dirty = 0; + src++; /* skip x or X. */ + while ((ch = (unsigned char)*src++) != '\0' && + isascii(ch) && isxdigit(ch)) { + if (isupper(ch)) + ch = tolower(ch); + n = strchr(xdigits, ch) - xdigits; + assert(n >= 0 && n <= 15); + *dst |= n; + if (!dirty++) + *dst <<= 4; + else if (size-- > 0) + *++dst = 0, dirty = 0; + else + goto emsgsize; + } + if (dirty) + size--; + } else if (isascii(ch) && isdigit(ch)) { + /* Decimal: eat dotted digit string. */ + for (;;) { + tmp = 0; + do { + n = strchr(digits, ch) - digits; + assert(n >= 0 && n <= 9); + tmp *= 10; + tmp += n; + if (tmp > 255) + goto enoent; + } while ((ch = (unsigned char)*src++) != '\0' && + isascii(ch) && isdigit(ch)); + if (size-- <= 0) + goto emsgsize; + *dst++ = (u_char) tmp; + if (ch == '\0' || ch == '/') + break; + if (ch != '.') + goto enoent; + ch = (unsigned char)*src++; + if (!isascii(ch) || !isdigit(ch)) + goto enoent; + } + } else + goto enoent; + + bits = -1; + if (ch == '/' && isascii((unsigned char)src[0]) && + isdigit((unsigned char)src[0]) && dst > odst) { + /* CIDR width specifier. Nothing can follow it. */ + ch = (unsigned char)*src++; /* Skip over the /. */ + bits = 0; + do { + n = strchr(digits, ch) - digits; + assert(n >= 0 && n <= 9); + bits *= 10; + bits += n; + if (bits > 32) + goto emsgsize; + } while ((ch = (unsigned char)*src++) != '\0' && + isascii(ch) && isdigit(ch)); + if (ch != '\0') + goto enoent; + } + + /* Firey death and destruction unless we prefetched EOS. */ + if (ch != '\0') + goto enoent; + + /* If nothing was written to the destination, we found no address. */ + if (dst == odst) + goto enoent; + /* If no CIDR spec was given, infer width from net class. */ + if (bits == -1) { + if (*odst >= 240) /* Class E */ + bits = 32; + else if (*odst >= 224) /* Class D */ + bits = 4; + else if (*odst >= 192) /* Class C */ + bits = 24; + else if (*odst >= 128) /* Class B */ + bits = 16; + else /* Class A */ + bits = 8; + /* If imputed mask is narrower than specified octets, widen. */ + if (bits < ((dst - odst) * 8)) + bits = (dst - odst) * 8; + } + /* Extend network to cover the actual mask. */ + while (bits > ((dst - odst) * 8)) { + if (size-- <= 0) + goto emsgsize; + *dst++ = '\0'; + } + return (bits); + + enoent: + errno = ENOENT; + return (-1); + + emsgsize: + errno = EMSGSIZE; + return (-1); +} + + +static int +inet_net_pton_ipv6(const char *src, u_char *dst, size_t size) +{ + int ret; + int bits; + char buf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255:255:255:255/128")]; + char *sep; + const char *errstr; + + if (strlcpy(buf, src, sizeof buf) >= sizeof buf) { + errno = EMSGSIZE; + return (-1); + } + + sep = strchr(buf, '/'); + if (sep != NULL) + *sep++ = '\0'; + + ret = inet_pton(AF_INET6, buf, dst); + if (ret != 1) + return (-1); + + if (sep == NULL) + return 128; + + bits = strtonum(sep, 0, 128, &errstr); + if (errstr) { + errno = EINVAL; + return (-1); + } + + return bits; +} + +#endif diff --git a/openbsd-compat/libressl.c b/openbsd-compat/libressl.c new file mode 100644 index 00000000..f4f2b52e --- /dev/null +++ b/openbsd-compat/libressl.c @@ -0,0 +1,131 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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 cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#include <sys/types.h> + +#include <unistd.h> +#include <stdio.h> + +#include <openssl/err.h> +#include <openssl/bio.h> +#include <openssl/objects.h> +#include <openssl/evp.h> +#include <openssl/x509.h> +#include <openssl/pem.h> +#include <openssl/ssl.h> + +int +SSL_CTX_use_certificate_chain(SSL_CTX *ctx, char *buf, off_t len) +{ + int ret; + BIO*in; + X509*x; + X509*ca; + unsigned long err; + + ret = 0; + x = ca = NULL; + + if ((in = BIO_new_mem_buf(buf, len)) == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_BUF_LIB); + goto end; + } + + if ((x = PEM_read_bio_X509(in, NULL, + ctx->default_passwd_callback, + ctx->default_passwd_callback_userdata)) == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_PEM_LIB); + goto end; + } + + if (!SSL_CTX_use_certificate(ctx, x) || ERR_peek_error() != 0) + goto end; + + /* If we could set up our certificate, now proceed to + * the CA certificates. + */ + + if (ctx->extra_certs != NULL) { + sk_X509_pop_free(ctx->extra_certs, X509_free); + ctx->extra_certs = NULL; + } + + while ((ca = PEM_read_bio_X509(in, NULL, + ctx->default_passwd_callback, + ctx->default_passwd_callback_userdata)) != NULL) { + + if (!SSL_CTX_add_extra_chain_cert(ctx, ca)) + goto end; + } + + err = ERR_peek_last_error(); + if (ERR_GET_LIB(err) == ERR_LIB_PEM && + ERR_GET_REASON(err) == PEM_R_NO_START_LINE) + ERR_clear_error(); + else + goto end; + + ret = 1; +end: + if (ca != NULL) + X509_free(ca); + if (x != NULL) + X509_free(x); + if (in != NULL) + BIO_free(in); + return (ret); +} diff --git a/openbsd-compat/openbsd-compat.h b/openbsd-compat/openbsd-compat.h new file mode 100644 index 00000000..7dde2fe1 --- /dev/null +++ b/openbsd-compat/openbsd-compat.h @@ -0,0 +1,276 @@ +/* $Id: openbsd-compat.h,v 1.51 2010/10/07 10:25:29 djm Exp $ */ + +/* + * Copyright (c) 1999-2003 Damien Miller. All rights reserved. + * Copyright (c) 2003 Ben Lindstrom. All rights reserved. + * Copyright (c) 2002 Tim Rice. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#ifndef _OPENBSD_COMPAT_H +#define _OPENBSD_COMPAT_H + +#include "includes.h" + +#include <sys/types.h> + +#include <sys/socket.h> +#include <netinet/in.h> + +/* OpenBSD function replacements */ +#include "base64.h" + +#include <sys/queue.h> +#include <sys/tree.h> +#include "bsd-vis.h" +#include "xmalloc.h" + +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif + +#ifndef HAVE_BASENAME +char *basename(const char *path); +#endif + +#ifndef HAVE_CLOSEFROM +void closefrom(int); +#endif + +#if !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH) +char *realpath(const char *path, char *resolved); +#endif + +#if !HAVE_DECL_STRLCPY +size_t strlcpy(char *dst, const char *src, size_t size); +#endif + +#if !HAVE_DECL_STRLCAT +size_t strlcat(char *dst, const char *src, size_t size); +#endif + +#ifndef HAVE_STRMODE +void strmode(int mode, char *p); +#endif + +#ifndef HAVE_DAEMON +int daemon(int nochdir, int noclose); +#endif + +#ifndef HAVE_DIRNAME +char *dirname(const char *path); +#endif + +#ifndef HAVE_FMT_SCALED +#define FMT_SCALED_STRSIZE 7 +int fmt_scaled(long long number, char *result); +#endif + +#ifndef HAVE_SCAN_SCALED +int scan_scaled(char *, long long *); +#endif + +#ifndef HAVE_INET_NTOP +const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); +#endif + +#ifndef HAVE_STRSEP +char *strsep(char **stringp, const char *delim); +#endif + +#ifndef HAVE_SETPROCTITLE +void setproctitle(const char *fmt, ...); +void compat_init_setproctitle(int argc, char *argv[]); +#endif + +#if !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_OPTRESET) +int BSDgetopt(int argc, char * const *argv, const char *opts); +char *BSDoptarg; /* argument associated with option */ +int BSDoptind; /* index into parent argv vector */ +#endif + +/* Home grown routines */ +#include "bsd-misc.h" +/* #include "bsd-setres_id.h" */ +/* #include "bsd-statvfs.h" */ +#include "bsd-waitpid.h" +/* #include "bsd-poll.h" */ + +#ifndef HAVE_GETPEEREID +int getpeereid(int , uid_t *, gid_t *); +#endif + +#if !defined(HAVE_ARC4RANDOM) || defined(LIBRESSL_VERSION_NUMBER) +unsigned int arc4random(void); +#endif + +#if defined(HAVE_ARC4RANDOM_STIR) +void arc4random_stir(void); +#elif defined(HAVE_ARC4RANDOM) || defined(LIBRESSL_VERSION_NUMBER) +/* Recent system/libressl implementation; no need for explicit stir */ +# define arc4random_stir() +#else +/* openbsd-compat/arc4random.c provides arc4random_stir() */ +void arc4random_stir(void); +#endif + +#if !defined(HAVE_ARC4RANDOM_BUF) || defined(LIBRESSL_VERSION_NUMBER) +void arc4random_buf(void *, size_t); +#endif + +#if !defined(HAVE_ARC4RANDOM_UNIFORM) || defined(LIBRESSL_VERSION_NUMBER) +uint32_t arc4random_uniform(uint32_t); +#endif + +#ifndef HAVE_ASPRINTF +int asprintf(char **, const char *, ...); +#endif + +/* #include <sys/types.h> XXX needed? For size_t */ + +#ifndef HAVE_SNPRINTF +int snprintf(char *, size_t, const char *, ...); +#endif + +#ifndef HAVE_STRTOLL +long long strtoll(const char *, char **, int); +#endif + +#ifndef HAVE_STRTOUL +unsigned long strtoul(const char *, char **, int); +#endif + +#ifndef HAVE_STRTOULL +unsigned long long strtoull(const char *, char **, int); +#endif + +#ifndef HAVE_STRTONUM +long long strtonum(const char *nptr, long long minval, long long maxval, const char **errstr); +#endif + +#if !defined(HAVE_VASPRINTF) || !defined(HAVE_VSNPRINTF) +# include <stdarg.h> +#endif + +#ifndef HAVE_VASPRINTF +int vasprintf(char **, const char *, va_list); +#endif + +#ifndef HAVE_VSNPRINTF +int vsnprintf(char *, size_t, const char *, va_list); +#endif + +#if !defined(HAVE_EXPLICIT_BZERO) || defined(LIBRESSL_VERSION_NUMBER) +void explicit_bzero(void *p, size_t n); +#endif + +/* OpenSMTPD-portable specific entries */ + +#ifndef HAVE_FGETLN +#include <stdio.h> +#include <string.h> +char * fgetln(FILE *stream, size_t *len); +#endif + +#ifndef HAVE_FPARSELN +#include <stdio.h> +#include <string.h> +char * fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags); +#endif + +#ifndef HAVE_FREEZERO +void freezero(void *, size_t); +#endif + +#ifndef HAVE_PIDFILE +int pidfile(const char *basename); +#endif + +#ifndef HAVE_PW_DUP +struct passwd *pw_dup(const struct passwd *); +#endif + +#if !defined(HAVE_REALLOCARRAY) || defined(LIBRESSL_VERSION_NUMBER) +void *reallocarray(void *, size_t, size_t); +#endif + +#if !defined(HAVE_RECALLOCARRAY) || defined(LIBRESSL_VERSION_NUMBER) +void *recallocarray(void *, size_t, size_t, size_t); +#endif + +#ifndef HAVE_ERRC +void errc(int, int, const char *, ...); +#endif + +#ifndef HAVE_INET_NET_PTON +int inet_net_pton(int, const char *, void *, size_t); +#endif + +#ifndef HAVE_PLEDGE +#define pledge(promises, paths) 0 +#endif + +#ifndef HAVE_RES_HNOK +int res_hnok(const char *); +#endif + +#if !HAVE_DECL_AF_LOCAL +#define AF_LOCAL AF_UNIX +#endif + +#if !HAVE_DECL_PF_LOCAL +#define PF_LOCAL PF_UNIX +#endif + +#if !HAVE_DECL_WAIT_MYPGRP +#define WAIT_MYPGRP 0 +#endif + +#ifndef HAVE_FLOCK +int flock(int, int); +#endif + +#ifndef HAVE_SETRESGID +int setresgid(uid_t, uid_t, uid_t); +#endif + +#ifndef HAVE_SETRESUID +int setresuid(uid_t, uid_t, uid_t); +#endif + +#ifndef HAVE_GETLINE +ssize_t getline(char **, size_t *, FILE *); +#endif + +#ifndef HAVE_CRYPT_CHECKPASS +int crypt_checkpass(const char *, const char *); +#endif + +#ifndef HAVE_STRNDUP +char * strndup(const char *, size_t); +#endif + +#ifndef HAVE_STRNLEN +char * strnlen(const char *, size_t); +#endif + +#endif /* _OPENBSD_COMPAT_H */ diff --git a/openbsd-compat/paths_h/paths.h b/openbsd-compat/paths_h/paths.h new file mode 100644 index 00000000..6b66a9c1 --- /dev/null +++ b/openbsd-compat/paths_h/paths.h @@ -0,0 +1,8 @@ +#ifndef PATHS_H +#define PATHS_H + +#ifndef _PATH_DEFPATH +#define _PATH_DEFPATH "/bin:/usr/bin" +#endif + +#endif diff --git a/openbsd-compat/pidfile.c b/openbsd-compat/pidfile.c new file mode 100644 index 00000000..d6f83880 --- /dev/null +++ b/openbsd-compat/pidfile.c @@ -0,0 +1,112 @@ +/* $OpenBSD: pidfile.c,v 1.8 2008/06/26 05:42:05 ray Exp $ */ +/* $NetBSD: pidfile.c,v 1.4 2001/02/19 22:43:42 cgd Exp $ */ + +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/* OPENBSD ORIGINAL: lib/libutil/pidfile.c */ + +#include "includes.h" +#ifndef HAVE_PIDFILE + +#include <sys/param.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +static char *pidfile_path; +static pid_t pidfile_pid; + +static void pidfile_cleanup(void); + +extern char *__progname; + +int +pidfile(const char *basename) +{ + int save_errno; + pid_t pid; + FILE *f; + + if (basename == NULL) + basename = __progname; + + if (pidfile_path != NULL) { + free(pidfile_path); + pidfile_path = NULL; + } + + (void) asprintf(&pidfile_path, "%s/%s.pid", SMTPD_PIDDIR, basename); + if (pidfile_path == NULL) + return (-1); + + if ((f = fopen(pidfile_path, "w")) == NULL) { + save_errno = errno; + free(pidfile_path); + pidfile_path = NULL; + errno = save_errno; + return (-1); + } + + pid = getpid(); + if (fprintf(f, "%ld\n", (long)pid) <= 0) { + fclose(f); + save_errno = errno; + (void) unlink(pidfile_path); + free(pidfile_path); + pidfile_path = NULL; + errno = save_errno; + return (-1); + } + + fclose(f); + pidfile_pid = pid; + if (atexit(pidfile_cleanup) < 0) { + save_errno = errno; + (void) unlink(pidfile_path); + free(pidfile_path); + pidfile_path = NULL; + pidfile_pid = 0; + errno = save_errno; + return (-1); + } + + return (0); +} + +static void +pidfile_cleanup(void) +{ + + if (pidfile_path != NULL && pidfile_pid == getpid()) + (void) unlink(pidfile_path); +} + +#endif diff --git a/openbsd-compat/pw_dup.c b/openbsd-compat/pw_dup.c new file mode 100644 index 00000000..e16680c4 --- /dev/null +++ b/openbsd-compat/pw_dup.c @@ -0,0 +1,96 @@ +/* $OpenBSD: pw_dup.c,v 1.7 2005/08/08 08:05:34 espie Exp $ */ + +/* + * Copyright (c) 2000, 2002 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + */ + +/* OPENBSD ORIGINAL: lib/libc/gen/pw_dup.c */ + +#include "includes.h" + +#include <sys/types.h> + +#include <pwd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#ifndef HAVE_PW_DUP + +#define PW_SIZE(name, size) \ +do { \ + if (pw->name) { \ + size = strlen(pw->name) + 1; \ + total += size; \ + } \ +} while (0) + +#define PW_COPY(name, size) \ +do { \ + if (pw->name) { \ + (void)memcpy(cp, pw->name, size); \ + newpw->name = cp; \ + cp += size; \ + } \ +} while (0) + +struct passwd * +pw_dup(const struct passwd *pw) +{ + char *cp; + size_t nsize, psize, gsize, dsize, ssize, total; +#if HAVE_STRUCT_PASSWD_PW_CLASS + size_t csize; +#endif + struct passwd *newpw; + + /* Allocate in one big chunk for easy freeing */ + total = sizeof(struct passwd); + PW_SIZE(pw_name, nsize); + PW_SIZE(pw_passwd, psize); +#if HAVE_STRUCT_PASSWD_PW_CLASS + PW_SIZE(pw_class, csize); +#endif + PW_SIZE(pw_gecos, gsize); + PW_SIZE(pw_dir, dsize); + PW_SIZE(pw_shell, ssize); + + if ((cp = malloc(total)) == NULL) + return (NULL); + newpw = (struct passwd *)cp; + + /* + * Copy in passwd contents and make strings relative to space + * at the end of the buffer. + */ + (void)memcpy(newpw, pw, sizeof(struct passwd)); + cp += sizeof(struct passwd); + + PW_COPY(pw_name, nsize); + PW_COPY(pw_passwd, psize); +#if HAVE_STRUCT_PASSWD_PW_CLASS + PW_COPY(pw_class, csize); +#endif + PW_COPY(pw_gecos, gsize); + PW_COPY(pw_dir, dsize); + PW_COPY(pw_shell, ssize); + + return (newpw); +} +#endif diff --git a/openbsd-compat/reallocarray.c b/openbsd-compat/reallocarray.c new file mode 100644 index 00000000..ddd7f3a2 --- /dev/null +++ b/openbsd-compat/reallocarray.c @@ -0,0 +1,43 @@ +/* $OpenBSD: reallocarray.c,v 1.1 2014/05/08 21:43:49 deraadt Exp $ */ +/* + * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* OPENBSD ORIGINAL: lib/libc/stdlib/reallocarray.c */ + +#include "includes.h" +#ifndef HAVE_REALLOCARRAY +#include <sys/types.h> +#include <errno.h> +#include <stdint.h> +#include <stdlib.h> + +/* + * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX + * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW + */ +#define MUL_NO_OVERFLOW (1UL << (sizeof(size_t) * 4)) + +void * +reallocarray(void *optr, size_t nmemb, size_t size) +{ + if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && + nmemb > 0 && SIZE_MAX / nmemb < size) { + errno = ENOMEM; + return NULL; + } + return realloc(optr, size * nmemb); +} +#endif diff --git a/openbsd-compat/recallocarray.c b/openbsd-compat/recallocarray.c new file mode 100644 index 00000000..fc0b5a8a --- /dev/null +++ b/openbsd-compat/recallocarray.c @@ -0,0 +1,84 @@ +/* $OpenBSD: recallocarray.c,v 1.1 2017/03/06 18:44:21 otto Exp $ */ +/* + * Copyright (c) 2008, 2017 Otto Moerbeek <otto@drijf.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* OPENBSD ORIGINAL: lib/libc/stdlib/recallocarray.c */ + +#include "includes.h" + +#include <errno.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> + +/* + * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX + * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW + */ +#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) + +void * +recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size) +{ + size_t oldsize, newsize; + void *newptr; + + if (ptr == NULL) + return calloc(newnmemb, size); + + if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && + newnmemb > 0 && SIZE_MAX / newnmemb < size) { + errno = ENOMEM; + return NULL; + } + newsize = newnmemb * size; + + if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && + oldnmemb > 0 && SIZE_MAX / oldnmemb < size) { + errno = EINVAL; + return NULL; + } + oldsize = oldnmemb * size; + + /* + * Don't bother too much if we're shrinking just a bit, + * we do not shrink for series of small steps, oh well. + */ + if (newsize <= oldsize) { + size_t d = oldsize - newsize; + + if (d < oldsize / 2 && d < (size_t)getpagesize()) { + memset((char *)ptr + newsize, 0, d); + return ptr; + } + } + + newptr = malloc(newsize); + if (newptr == NULL) + return NULL; + + if (newsize > oldsize) { + memcpy(newptr, ptr, oldsize); + memset((char *)newptr + oldsize, 0, newsize - oldsize); + } else + memcpy(newptr, ptr, newsize); + + explicit_bzero(ptr, oldsize); + free(ptr); + + return newptr; +} diff --git a/openbsd-compat/setproctitle.c b/openbsd-compat/setproctitle.c new file mode 100644 index 00000000..0e433425 --- /dev/null +++ b/openbsd-compat/setproctitle.c @@ -0,0 +1,174 @@ +/* Based on conf.c from UCB sendmail 8.8.8 */ + +/* + * Copyright 2003 Damien Miller + * Copyright (c) 1983, 1995-1997 Eric P. Allman + * Copyright (c) 1988, 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. 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 "includes.h" + +#ifndef HAVE_SETPROCTITLE + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#ifdef HAVE_SYS_PSTAT_H +#include <sys/pstat.h> +#endif +#include <string.h> + +#if defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS) +#include <vis.h> +#else +#include "bsd-vis.h" +#endif + +#define SPT_NONE 0 /* don't use it at all */ +#define SPT_PSTAT 1 /* use pstat(PSTAT_SETCMD, ...) */ +#define SPT_REUSEARGV 2 /* cover argv with title information */ + +#ifndef SPT_TYPE +# define SPT_TYPE SPT_NONE +#endif + +#ifndef SPT_PADCHAR +# define SPT_PADCHAR '\0' +#endif + +#if SPT_TYPE == SPT_REUSEARGV +static char *argv_start = NULL; +static size_t argv_env_len = 0; +#endif + +#endif /* HAVE_SETPROCTITLE */ + +void +compat_init_setproctitle(int argc, char *argv[]) +{ +#if !defined(HAVE_SETPROCTITLE) && \ + defined(SPT_TYPE) && SPT_TYPE == SPT_REUSEARGV + extern char **environ; + char *lastargv = NULL; + char **envp = environ; + int i; + + /* + * NB: This assumes that argv has already been copied out of the + * way. This is true for sshd, but may not be true for other + * programs. Beware. + */ + + if (argc == 0 || argv[0] == NULL) + return; + + /* Fail if we can't allocate room for the new environment */ + for (i = 0; envp[i] != NULL; i++) + ; + if ((environ = calloc(i + 1, sizeof(*environ))) == NULL) { + environ = envp; /* put it back */ + return; + } + + /* + * Find the last argv string or environment variable within + * our process memory area. + */ + for (i = 0; i < argc; i++) { + if (lastargv == NULL || lastargv + 1 == argv[i]) + lastargv = argv[i] + strlen(argv[i]); + } + for (i = 0; envp[i] != NULL; i++) { + if (lastargv + 1 == envp[i]) + lastargv = envp[i] + strlen(envp[i]); + } + + argv[1] = NULL; + argv_start = argv[0]; + argv_env_len = lastargv - argv[0] - 1; + + /* + * Copy environment + * XXX - will truncate env on strdup fail + */ + for (i = 0; envp[i] != NULL; i++) + environ[i] = strdup(envp[i]); + environ[i] = NULL; +#endif /* SPT_REUSEARGV */ +} + +#ifndef HAVE_SETPROCTITLE +void +setproctitle(const char *fmt, ...) +{ +#if SPT_TYPE != SPT_NONE + va_list ap; + char buf[1024], ptitle[1024]; + size_t len; + int r; + extern char *__progname; +#if SPT_TYPE == SPT_PSTAT + union pstun pst; +#endif + +#if SPT_TYPE == SPT_REUSEARGV + if (argv_env_len <= 0) + return; +#endif + + strlcpy(buf, __progname, sizeof(buf)); + + r = -1; + va_start(ap, fmt); + if (fmt != NULL) { + len = strlcat(buf, ": ", sizeof(buf)); + if (len < sizeof(buf)) + r = vsnprintf(buf + len, sizeof(buf) - len , fmt, ap); + } + va_end(ap); + if (r == -1 || (size_t)r >= sizeof(buf) - len) + return; + strnvis(ptitle, buf, sizeof(ptitle), + VIS_CSTYLE|VIS_NL|VIS_TAB|VIS_OCTAL); + +#if SPT_TYPE == SPT_PSTAT + pst.pst_command = ptitle; + pstat(PSTAT_SETCMD, pst, strlen(ptitle), 0, 0); +#elif SPT_TYPE == SPT_REUSEARGV +/* debug("setproctitle: copy \"%s\" into len %d", + buf, argv_env_len); */ + len = strlcpy(argv_start, ptitle, argv_env_len); + for(; len < argv_env_len; len++) + argv_start[len] = SPT_PADCHAR; +#endif + +#endif /* SPT_NONE */ +} + +#endif /* HAVE_SETPROCTITLE */ diff --git a/openbsd-compat/setresguid.c b/openbsd-compat/setresguid.c new file mode 100644 index 00000000..78e7f196 --- /dev/null +++ b/openbsd-compat/setresguid.c @@ -0,0 +1,67 @@ +/* Subset of uidswap.c from portable OpenSSH */ + +/* $OpenBSD: uidswap.c,v 1.35 2006/08/03 03:34:42 deraadt Exp $ */ +/* + * Author: Tatu Ylonen <ylo@cs.hut.fi> + * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + * All rights reserved + * Code for uid-swapping. + * + * As far as I am concerned, the code I have written for this software + * can be used freely for any purpose. Any derived versions of this + * software must be clearly marked as such, and if the derived work is + * incompatible with the protocol description in the RFC file, it must be + * called by a name other than "ssh" or "Secure Shell". + */ + +#include "includes.h" + +#include <stdarg.h> +#include <string.h> +#include <unistd.h> + +#include "log.h" + +#ifndef HAVE_SETRESGID +int setresgid(uid_t rgid, uid_t egid, uid_t sgid) +{ + +#if defined(HAVE_SETRESGID) && !defined(BROKEN_SETRESGID) + if (setresgid(rgid, egid, sgid) < 0) + fatal("setresgid %u: %.100s", (u_int)rgid, strerror(errno)); +#elif defined(HAVE_SETREGID) && !defined(BROKEN_SETREGID) + if (setregid(rgid, egid) < 0) + fatal("setregid %u: %.100s", (u_int)rgid, strerror(errno)); +#else + if (setegid(egid) < 0) + fatal("setegid %u: %.100s", (u_int)egid, strerror(errno)); + if (setgid(rgid) < 0) + fatal("setgid %u: %.100s", (u_int)rgid, strerror(errno)); +#endif + return (0); +} +#endif /* HAVE_SETRESGID */ + + + +#ifndef HAVE_SETRESUID +int setresuid(uid_t ruid, uid_t euid, uid_t suid) +{ + +#if defined(HAVE_SETRESUID) && !defined(BROKEN_SETRESUID) + if (setresuid(ruid, euid, suid) < 0) + fatal("setresuid %u: %.100s", (u_int)ruid, strerror(errno)); +#elif defined(HAVE_SETREUID) && !defined(BROKEN_SETREUID) + if (setreuid(ruid, euid) < 0) + fatal("setreuid %u: %.100s", (u_int)ruid, strerror(errno)); +#else +# ifndef SETEUID_BREAKS_SETUID + if (seteuid(euid) < 0) + fatal("seteuid %u: %.100s", (u_int)euid, strerror(errno)); +# endif + if (setuid(ruid) < 0) + fatal("setuid %u: %.100s", (u_int)ruid, strerror(errno)); +#endif + return (0); +} +#endif /* HAVE_SETRESUID */ diff --git a/openbsd-compat/strlcat.c b/openbsd-compat/strlcat.c new file mode 100644 index 00000000..bcc1b61a --- /dev/null +++ b/openbsd-compat/strlcat.c @@ -0,0 +1,62 @@ +/* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* OPENBSD ORIGINAL: lib/libc/string/strlcat.c */ + +#include "includes.h" +#ifndef HAVE_STRLCAT + +#include <sys/types.h> +#include <string.h> + +/* + * Appends src to string dst of size siz (unlike strncat, siz is the + * full size of dst, not space left). At most siz-1 characters + * will be copied. Always NUL terminates (unless siz <= strlen(dst)). + * Returns strlen(src) + MIN(siz, strlen(initial dst)). + * If retval >= siz, truncation occurred. + */ +size_t +strlcat(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0 && *d != '\0') + d++; + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return(dlen + strlen(s)); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return(dlen + (s - src)); /* count does not include NUL */ +} + +#endif /* !HAVE_STRLCAT */ diff --git a/openbsd-compat/strlcpy.c b/openbsd-compat/strlcpy.c new file mode 100644 index 00000000..b4b1b601 --- /dev/null +++ b/openbsd-compat/strlcpy.c @@ -0,0 +1,58 @@ +/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* OPENBSD ORIGINAL: lib/libc/string/strlcpy.c */ + +#include "includes.h" +#ifndef HAVE_STRLCPY + +#include <sys/types.h> +#include <string.h> + +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t +strlcpy(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0) { + while (--n != 0) { + if ((*d++ = *s++) == '\0') + break; + } + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} + +#endif /* !HAVE_STRLCPY */ diff --git a/openbsd-compat/strmode.c b/openbsd-compat/strmode.c new file mode 100644 index 00000000..4a816142 --- /dev/null +++ b/openbsd-compat/strmode.c @@ -0,0 +1,148 @@ +/* $OpenBSD: strmode.c,v 1.7 2005/08/08 08:05:37 espie Exp $ */ +/*- + * Copyright (c) 1990 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. 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. + */ + +/* OPENBSD ORIGINAL: lib/libc/string/strmode.c */ + +#include "includes.h" +#ifndef HAVE_STRMODE + +#include <sys/types.h> +#include <sys/stat.h> +#include <string.h> + +/* XXX mode should be mode_t */ + +void +strmode(int mode, char *p) +{ + /* print type */ + switch (mode & S_IFMT) { + case S_IFDIR: /* directory */ + *p++ = 'd'; + break; + case S_IFCHR: /* character special */ + *p++ = 'c'; + break; + case S_IFBLK: /* block special */ + *p++ = 'b'; + break; + case S_IFREG: /* regular */ + *p++ = '-'; + break; + case S_IFLNK: /* symbolic link */ + *p++ = 'l'; + break; +#ifdef S_IFSOCK + case S_IFSOCK: /* socket */ + *p++ = 's'; + break; +#endif +#ifdef S_IFIFO + case S_IFIFO: /* fifo */ + *p++ = 'p'; + break; +#endif + default: /* unknown */ + *p++ = '?'; + break; + } + /* usr */ + if (mode & S_IRUSR) + *p++ = 'r'; + else + *p++ = '-'; + if (mode & S_IWUSR) + *p++ = 'w'; + else + *p++ = '-'; + switch (mode & (S_IXUSR | S_ISUID)) { + case 0: + *p++ = '-'; + break; + case S_IXUSR: + *p++ = 'x'; + break; + case S_ISUID: + *p++ = 'S'; + break; + case S_IXUSR | S_ISUID: + *p++ = 's'; + break; + } + /* group */ + if (mode & S_IRGRP) + *p++ = 'r'; + else + *p++ = '-'; + if (mode & S_IWGRP) + *p++ = 'w'; + else + *p++ = '-'; + switch (mode & (S_IXGRP | S_ISGID)) { + case 0: + *p++ = '-'; + break; + case S_IXGRP: + *p++ = 'x'; + break; + case S_ISGID: + *p++ = 'S'; + break; + case S_IXGRP | S_ISGID: + *p++ = 's'; + break; + } + /* other */ + if (mode & S_IROTH) + *p++ = 'r'; + else + *p++ = '-'; + if (mode & S_IWOTH) + *p++ = 'w'; + else + *p++ = '-'; + switch (mode & (S_IXOTH | S_ISVTX)) { + case 0: + *p++ = '-'; + break; + case S_IXOTH: + *p++ = 'x'; + break; + case S_ISVTX: + *p++ = 'T'; + break; + case S_IXOTH | S_ISVTX: + *p++ = 't'; + break; + } + *p++ = ' '; /* will be a '+' if ACL's implemented */ + *p = '\0'; +} +#endif diff --git a/openbsd-compat/strndup.c b/openbsd-compat/strndup.c new file mode 100644 index 00000000..f43ba659 --- /dev/null +++ b/openbsd-compat/strndup.c @@ -0,0 +1,39 @@ +/* $OpenBSD: strndup.c,v 1.2 2015/08/31 02:53:57 guenther Exp $ */ + +/* + * Copyright (c) 2010 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> + +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +char * +strndup(const char *str, size_t maxlen) +{ + char *copy; + size_t len; + + len = strnlen(str, maxlen); + copy = malloc(len + 1); + if (copy != NULL) { + (void)memcpy(copy, str, len); + copy[len] = '\0'; + } + + return copy; +} diff --git a/openbsd-compat/strnlen.c b/openbsd-compat/strnlen.c new file mode 100644 index 00000000..a2017e19 --- /dev/null +++ b/openbsd-compat/strnlen.c @@ -0,0 +1,32 @@ +/* $OpenBSD: strnlen.c,v 1.8 2016/10/16 17:37:39 dtucker Exp $ */ + +/* + * Copyright (c) 2010 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> + +#include <string.h> + +size_t +strnlen(const char *str, size_t maxlen) +{ + const char *cp; + + for (cp = str; maxlen != 0 && *cp != '\0'; cp++, maxlen--) + ; + + return (size_t)(cp - str); +} diff --git a/openbsd-compat/strsep.c b/openbsd-compat/strsep.c new file mode 100644 index 00000000..b36eb8fd --- /dev/null +++ b/openbsd-compat/strsep.c @@ -0,0 +1,79 @@ +/* $OpenBSD: strsep.c,v 1.6 2005/08/08 08:05:37 espie Exp $ */ + +/*- + * Copyright (c) 1990, 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. 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. + */ + +/* OPENBSD ORIGINAL: lib/libc/string/strsep.c */ + +#include "includes.h" + +#if !defined(HAVE_STRSEP) + +#include <string.h> +#include <stdio.h> + +/* + * Get next token from string *stringp, where tokens are possibly-empty + * strings separated by characters from delim. + * + * Writes NULs into the string at *stringp to end tokens. + * delim need not remain constant from call to call. + * On return, *stringp points past the last NUL written (if there might + * be further tokens), or is NULL (if there are definitely no more tokens). + * + * If *stringp is NULL, strsep returns NULL. + */ +char * +strsep(char **stringp, const char *delim) +{ + char *s; + const char *spanp; + int c, sc; + char *tok; + + if ((s = *stringp) == NULL) + return (NULL); + for (tok = s;;) { + c = *s++; + spanp = delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = 0; + *stringp = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} + +#endif /* !defined(HAVE_STRSEP) */ diff --git a/openbsd-compat/strtonum.c b/openbsd-compat/strtonum.c new file mode 100644 index 00000000..87f2f24b --- /dev/null +++ b/openbsd-compat/strtonum.c @@ -0,0 +1,72 @@ +/* $OpenBSD: strtonum.c,v 1.6 2004/08/03 19:38:01 millert Exp $ */ + +/* + * Copyright (c) 2004 Ted Unangst and Todd Miller + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* OPENBSD ORIGINAL: lib/libc/stdlib/strtonum.c */ + +#include "includes.h" + +#ifndef HAVE_STRTONUM +#include <stdlib.h> +#include <limits.h> +#include <errno.h> + +#define INVALID 1 +#define TOOSMALL 2 +#define TOOLARGE 3 + +long long +strtonum(const char *numstr, long long minval, long long maxval, + const char **errstrp) +{ + long long ll = 0; + char *ep; + int error = 0; + struct errval { + const char *errstr; + int err; + } ev[4] = { + { NULL, 0 }, + { "invalid", EINVAL }, + { "too small", ERANGE }, + { "too large", ERANGE }, + }; + + ev[0].err = errno; + errno = 0; + if (minval > maxval) + error = INVALID; + else { + ll = strtoll(numstr, &ep, 10); + if (numstr == ep || *ep != '\0') + error = INVALID; + else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) + error = TOOSMALL; + else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) + error = TOOLARGE; + } + if (errstrp != NULL) + *errstrp = ev[error].errstr; + errno = ev[error].err; + if (error) + ll = 0; + + return (ll); +} + +#endif /* HAVE_STRTONUM */ diff --git a/openbsd-compat/sys/queue.h b/openbsd-compat/sys/queue.h new file mode 100644 index 00000000..28aaaa37 --- /dev/null +++ b/openbsd-compat/sys/queue.h @@ -0,0 +1,653 @@ +/* $OpenBSD: queue.h,v 1.36 2012/04/11 13:29:14 naddy Exp $ */ +/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ + +/* + * Copyright (c) 1991, 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. 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. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +/* OPENBSD ORIGINAL: sys/sys/queue.h */ + +#ifndef _FAKE_QUEUE_H_ +#define _FAKE_QUEUE_H_ + +/* + * Require for OS/X and other platforms that have old/broken/incomplete + * <sys/queue.h>. + */ +#undef SLIST_HEAD +#undef SLIST_HEAD_INITIALIZER +#undef SLIST_ENTRY +#undef SLIST_FOREACH_PREVPTR +#undef SLIST_FIRST +#undef SLIST_END +#undef SLIST_EMPTY +#undef SLIST_NEXT +#undef SLIST_FOREACH +#undef SLIST_INIT +#undef SLIST_INSERT_AFTER +#undef SLIST_INSERT_HEAD +#undef SLIST_REMOVE_HEAD +#undef SLIST_REMOVE +#undef SLIST_REMOVE_NEXT +#undef LIST_HEAD +#undef LIST_HEAD_INITIALIZER +#undef LIST_ENTRY +#undef LIST_FIRST +#undef LIST_END +#undef LIST_EMPTY +#undef LIST_NEXT +#undef LIST_FOREACH +#undef LIST_INIT +#undef LIST_INSERT_AFTER +#undef LIST_INSERT_BEFORE +#undef LIST_INSERT_HEAD +#undef LIST_REMOVE +#undef LIST_REPLACE +#undef SIMPLEQ_HEAD +#undef SIMPLEQ_HEAD_INITIALIZER +#undef SIMPLEQ_ENTRY +#undef SIMPLEQ_FIRST +#undef SIMPLEQ_END +#undef SIMPLEQ_EMPTY +#undef SIMPLEQ_NEXT +#undef SIMPLEQ_FOREACH +#undef SIMPLEQ_INIT +#undef SIMPLEQ_INSERT_HEAD +#undef SIMPLEQ_INSERT_TAIL +#undef SIMPLEQ_INSERT_AFTER +#undef SIMPLEQ_REMOVE_HEAD +#undef TAILQ_HEAD +#undef TAILQ_HEAD_INITIALIZER +#undef TAILQ_ENTRY +#undef TAILQ_FIRST +#undef TAILQ_END +#undef TAILQ_NEXT +#undef TAILQ_LAST +#undef TAILQ_PREV +#undef TAILQ_EMPTY +#undef TAILQ_FOREACH +#undef TAILQ_FOREACH_REVERSE +#undef TAILQ_INIT +#undef TAILQ_INSERT_HEAD +#undef TAILQ_INSERT_TAIL +#undef TAILQ_INSERT_AFTER +#undef TAILQ_INSERT_BEFORE +#undef TAILQ_REMOVE +#undef TAILQ_REPLACE +#undef CIRCLEQ_HEAD +#undef CIRCLEQ_HEAD_INITIALIZER +#undef CIRCLEQ_ENTRY +#undef CIRCLEQ_FIRST +#undef CIRCLEQ_LAST +#undef CIRCLEQ_END +#undef CIRCLEQ_NEXT +#undef CIRCLEQ_PREV +#undef CIRCLEQ_EMPTY +#undef CIRCLEQ_FOREACH +#undef CIRCLEQ_FOREACH_REVERSE +#undef CIRCLEQ_INIT +#undef CIRCLEQ_INSERT_AFTER +#undef CIRCLEQ_INSERT_BEFORE +#undef CIRCLEQ_INSERT_HEAD +#undef CIRCLEQ_INSERT_TAIL +#undef CIRCLEQ_REMOVE +#undef CIRCLEQ_REPLACE + +/* + * This file defines five types of data structures: singly-linked lists, + * lists, simple queues, tail queues, and circular queues. + * + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC)) +#define _Q_INVALIDATE(a) (a) = ((void *)-1) +#else +#define _Q_INVALIDATE(a) +#endif + +/* + * Singly-linked List definitions. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List access methods. + */ +#define SLIST_FIRST(head) ((head)->slh_first) +#define SLIST_END(head) NULL +#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_FOREACH(var, head, field) \ + for((var) = SLIST_FIRST(head); \ + (var) != SLIST_END(head); \ + (var) = SLIST_NEXT(var, field)) + +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SLIST_FIRST(head); \ + (var) && ((tvar) = SLIST_NEXT(var, field), 1); \ + (var) = (tvar)) + +/* + * Singly-linked List functions. + */ +#define SLIST_INIT(head) { \ + SLIST_FIRST(head) = SLIST_END(head); \ +} + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} while (0) + +#define SLIST_REMOVE_AFTER(elm, field) do { \ + (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} while (0) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if ((head)->slh_first == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->slh_first; \ + \ + while (curelm->field.sle_next != (elm)) \ + curelm = curelm->field.sle_next; \ + curelm->field.sle_next = \ + curelm->field.sle_next->field.sle_next; \ + _Q_INVALIDATE((elm)->field.sle_next); \ + } \ +} while (0) + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List access methods + */ +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_END(head) NULL +#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_FOREACH(var, head, field) \ + for((var) = LIST_FIRST(head); \ + (var)!= LIST_END(head); \ + (var) = LIST_NEXT(var, field)) + +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST(head); \ + (var) && ((tvar) = LIST_NEXT(var, field), 1); \ + (var) = (tvar)) + +/* + * List functions. + */ +#define LIST_INIT(head) do { \ + LIST_FIRST(head) = LIST_END(head); \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (0) + +#define LIST_REMOVE(elm, field) do { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ + _Q_INVALIDATE((elm)->field.le_prev); \ + _Q_INVALIDATE((elm)->field.le_next); \ +} while (0) + +#define LIST_REPLACE(elm, elm2, field) do { \ + if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ + (elm2)->field.le_next->field.le_prev = \ + &(elm2)->field.le_next; \ + (elm2)->field.le_prev = (elm)->field.le_prev; \ + *(elm2)->field.le_prev = (elm2); \ + _Q_INVALIDATE((elm)->field.le_prev); \ + _Q_INVALIDATE((elm)->field.le_next); \ +} while (0) + +/* + * Simple queue definitions. + */ +#define SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define SIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue access methods. + */ +#define SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define SIMPLEQ_END(head) NULL +#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) +#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + +#define SIMPLEQ_FOREACH(var, head, field) \ + for((var) = SIMPLEQ_FIRST(head); \ + (var) != SIMPLEQ_END(head); \ + (var) = SIMPLEQ_NEXT(var, field)) + +#define SIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SIMPLEQ_FIRST(head); \ + (var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1); \ + (var) = (tvar)) + +/* + * Simple queue functions. + */ +#define SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (0) + +#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (0) + +#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (0) + +#define SIMPLEQ_REMOVE_HEAD(head, field) do { \ + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \ + if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \ + == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (0) + +/* + * Tail queue definitions. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * tail queue access methods + */ +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_END(head) NULL +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +/* XXX */ +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) +#define TAILQ_EMPTY(head) \ + (TAILQ_FIRST(head) == TAILQ_END(head)) + +#define TAILQ_FOREACH(var, head, field) \ + for((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_NEXT(var, field)) + +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head) && \ + ((tvar) = TAILQ_NEXT(var, field), 1); \ + (var) = (tvar)) + + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for((var) = TAILQ_LAST(head, headname); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_PREV(var, headname, field)) + +#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = TAILQ_LAST(head, headname); \ + (var) != TAILQ_END(head) && \ + ((tvar) = TAILQ_PREV(var, headname, field), 1); \ + (var) = (tvar)) + +/* + * Tail queue functions. + */ +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ + _Q_INVALIDATE((elm)->field.tqe_prev); \ + _Q_INVALIDATE((elm)->field.tqe_next); \ +} while (0) + +#define TAILQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ + (elm2)->field.tqe_next->field.tqe_prev = \ + &(elm2)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm2)->field.tqe_next; \ + (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ + *(elm2)->field.tqe_prev = (elm2); \ + _Q_INVALIDATE((elm)->field.tqe_prev); \ + _Q_INVALIDATE((elm)->field.tqe_next); \ +} while (0) + +/* + * Circular queue definitions. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(head) \ + { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue access methods + */ +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define CIRCLEQ_LAST(head) ((head)->cqh_last) +#define CIRCLEQ_END(head) ((void *)(head)) +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) +#define CIRCLEQ_EMPTY(head) \ + (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) + +#define CIRCLEQ_FOREACH(var, head, field) \ + for((var) = CIRCLEQ_FIRST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_NEXT(var, field)) + +#define CIRCLEQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = CIRCLEQ_FIRST(head); \ + (var) != CIRCLEQ_END(head) && \ + ((tvar) = CIRCLEQ_NEXT(var, field), 1); \ + (var) = (tvar)) + +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for((var) = CIRCLEQ_LAST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_PREV(var, field)) + +#define CIRCLEQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = CIRCLEQ_LAST(head, headname); \ + (var) != CIRCLEQ_END(head) && \ + ((tvar) = CIRCLEQ_PREV(var, headname, field), 1); \ + (var) = (tvar)) + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = CIRCLEQ_END(head); \ + (head)->cqh_last = CIRCLEQ_END(head); \ +} while (0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = CIRCLEQ_END(head); \ + if ((head)->cqh_last == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.cqe_next = CIRCLEQ_END(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (0) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ + _Q_INVALIDATE((elm)->field.cqe_prev); \ + _Q_INVALIDATE((elm)->field.cqe_next); \ +} while (0) + +#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ + CIRCLEQ_END(head)) \ + (head).cqh_last = (elm2); \ + else \ + (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ + if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ + CIRCLEQ_END(head)) \ + (head).cqh_first = (elm2); \ + else \ + (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ + _Q_INVALIDATE((elm)->field.cqe_prev); \ + _Q_INVALIDATE((elm)->field.cqe_next); \ +} while (0) + +#endif /* !_FAKE_QUEUE_H_ */ diff --git a/openbsd-compat/sys/tree.h b/openbsd-compat/sys/tree.h new file mode 100644 index 00000000..7f7546ec --- /dev/null +++ b/openbsd-compat/sys/tree.h @@ -0,0 +1,755 @@ +/* $OpenBSD: tree.h,v 1.13 2011/07/09 00:19:45 pirofti Exp $ */ +/* + * Copyright 2002 Niels Provos <provos@citi.umich.edu> + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +/* OPENBSD ORIGINAL: sys/sys/tree.h */ + +#include "config.h" +#ifdef NO_ATTRIBUTE_ON_RETURN_TYPE +# define __attribute__(x) +#endif + +#ifndef _SYS_TREE_H_ +#define _SYS_TREE_H_ + +/* + * This file defines data structures for different types of trees: + * splay trees and red-black trees. + * + * A splay tree is a self-organizing data structure. Every operation + * on the tree causes a splay to happen. The splay moves the requested + * node to the root of the tree and partly rebalances it. + * + * This has the benefit that request locality causes faster lookups as + * the requested nodes move to the top of the tree. On the other hand, + * every lookup causes memory writes. + * + * The Balance Theorem bounds the total access time for m operations + * and n inserts on an initially empty tree as O((m + n)lg n). The + * amortized cost for a sequence of m accesses to a splay tree is O(lg n); + * + * A red-black tree is a binary search tree with the node color as an + * extra attribute. It fulfills a set of conditions: + * - every search path from the root to a leaf consists of the + * same number of black nodes, + * - each red node (except for the root) has a black parent, + * - each leaf node is black. + * + * Every operation on a red-black tree is bounded as O(lg n). + * The maximum height of a red-black tree is 2lg (n+1). + */ + +#define SPLAY_HEAD(name, type) \ +struct name { \ + struct type *sph_root; /* root of the tree */ \ +} + +#define SPLAY_INITIALIZER(root) \ + { NULL } + +#define SPLAY_INIT(root) do { \ + (root)->sph_root = NULL; \ +} while (0) + +#define SPLAY_ENTRY(type) \ +struct { \ + struct type *spe_left; /* left element */ \ + struct type *spe_right; /* right element */ \ +} + +#define SPLAY_LEFT(elm, field) (elm)->field.spe_left +#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right +#define SPLAY_ROOT(head) (head)->sph_root +#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) + +/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ +#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (0) + +#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (0) + +#define SPLAY_LINKLEFT(head, tmp, field) do { \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ +} while (0) + +#define SPLAY_LINKRIGHT(head, tmp, field) do { \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ +} while (0) + +#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ + SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ + SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ +} while (0) + +/* Generates prototypes and inline functions */ + +#define SPLAY_PROTOTYPE(name, type, field, cmp) \ +void name##_SPLAY(struct name *, struct type *); \ +void name##_SPLAY_MINMAX(struct name *, int); \ +struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ +struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ + \ +/* Finds the node with the same key as elm */ \ +static __inline struct type * \ +name##_SPLAY_FIND(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) \ + return(NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) \ + return (head->sph_root); \ + return (NULL); \ +} \ + \ +static __inline struct type * \ +name##_SPLAY_NEXT(struct name *head, struct type *elm) \ +{ \ + name##_SPLAY(head, elm); \ + if (SPLAY_RIGHT(elm, field) != NULL) { \ + elm = SPLAY_RIGHT(elm, field); \ + while (SPLAY_LEFT(elm, field) != NULL) { \ + elm = SPLAY_LEFT(elm, field); \ + } \ + } else \ + elm = NULL; \ + return (elm); \ +} \ + \ +static __inline struct type * \ +name##_SPLAY_MIN_MAX(struct name *head, int val) \ +{ \ + name##_SPLAY_MINMAX(head, val); \ + return (SPLAY_ROOT(head)); \ +} + +/* Main splay operation. + * Moves node close to the key of elm to top + */ +#define SPLAY_GENERATE(name, type, field, cmp) \ +struct type * \ +name##_SPLAY_INSERT(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) { \ + SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ + } else { \ + int __comp; \ + name##_SPLAY(head, elm); \ + __comp = (cmp)(elm, (head)->sph_root); \ + if(__comp < 0) { \ + SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ + SPLAY_RIGHT(elm, field) = (head)->sph_root; \ + SPLAY_LEFT((head)->sph_root, field) = NULL; \ + } else if (__comp > 0) { \ + SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ + SPLAY_LEFT(elm, field) = (head)->sph_root; \ + SPLAY_RIGHT((head)->sph_root, field) = NULL; \ + } else \ + return ((head)->sph_root); \ + } \ + (head)->sph_root = (elm); \ + return (NULL); \ +} \ + \ +struct type * \ +name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *__tmp; \ + if (SPLAY_EMPTY(head)) \ + return (NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) { \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ + } else { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ + name##_SPLAY(head, elm); \ + SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ + } \ + return (elm); \ + } \ + return (NULL); \ +} \ + \ +void \ +name##_SPLAY(struct name *head, struct type *elm) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ + int __comp; \ +\ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ + __left = __right = &__node; \ +\ + while ((__comp = (cmp)(elm, (head)->sph_root))) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) > 0){ \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} \ + \ +/* Splay with either the minimum or the maximum element \ + * Used to find minimum or maximum element in tree. \ + */ \ +void name##_SPLAY_MINMAX(struct name *head, int __comp) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ +\ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ + __left = __right = &__node; \ +\ + while (1) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp > 0) { \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} + +#define SPLAY_NEGINF -1 +#define SPLAY_INF 1 + +#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) +#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) +#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) +#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) +#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) +#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) + +#define SPLAY_FOREACH(x, name, head) \ + for ((x) = SPLAY_MIN(name, head); \ + (x) != NULL; \ + (x) = SPLAY_NEXT(name, head, x)) + +/* Macros that define a red-black tree */ +#define RB_HEAD(name, type) \ +struct name { \ + struct type *rbh_root; /* root of the tree */ \ +} + +#define RB_INITIALIZER(root) \ + { NULL } + +#define RB_INIT(root) do { \ + (root)->rbh_root = NULL; \ +} while (0) + +#define RB_BLACK 0 +#define RB_RED 1 +#define RB_ENTRY(type) \ +struct { \ + struct type *rbe_left; /* left element */ \ + struct type *rbe_right; /* right element */ \ + struct type *rbe_parent; /* parent element */ \ + int rbe_color; /* node color */ \ +} + +#define RB_LEFT(elm, field) (elm)->field.rbe_left +#define RB_RIGHT(elm, field) (elm)->field.rbe_right +#define RB_PARENT(elm, field) (elm)->field.rbe_parent +#define RB_COLOR(elm, field) (elm)->field.rbe_color +#define RB_ROOT(head) (head)->rbh_root +#define RB_EMPTY(head) (RB_ROOT(head) == NULL) + +#define RB_SET(elm, parent, field) do { \ + RB_PARENT(elm, field) = parent; \ + RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ + RB_COLOR(elm, field) = RB_RED; \ +} while (0) + +#define RB_SET_BLACKRED(black, red, field) do { \ + RB_COLOR(black, field) = RB_BLACK; \ + RB_COLOR(red, field) = RB_RED; \ +} while (0) + +#ifndef RB_AUGMENT +#define RB_AUGMENT(x) do {} while (0) +#endif + +#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ + (tmp) = RB_RIGHT(elm, field); \ + if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \ + RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_LEFT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (0) + +#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ + (tmp) = RB_LEFT(elm, field); \ + if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \ + RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_RIGHT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (0) + +/* Generates prototypes and inline functions */ +#define RB_PROTOTYPE(name, type, field, cmp) \ + RB_PROTOTYPE_INTERNAL(name, type, field, cmp,) +#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \ + RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static) +#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \ +attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \ +attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ +attr struct type *name##_RB_REMOVE(struct name *, struct type *); \ +attr struct type *name##_RB_INSERT(struct name *, struct type *); \ +attr struct type *name##_RB_FIND(struct name *, struct type *); \ +attr struct type *name##_RB_NFIND(struct name *, struct type *); \ +attr struct type *name##_RB_NEXT(struct type *); \ +attr struct type *name##_RB_PREV(struct type *); \ +attr struct type *name##_RB_MINMAX(struct name *, int); \ + \ + +/* Main rb operation. + * Moves node close to the key of elm to top + */ +#define RB_GENERATE(name, type, field, cmp) \ + RB_GENERATE_INTERNAL(name, type, field, cmp,) +#define RB_GENERATE_STATIC(name, type, field, cmp) \ + RB_GENERATE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static) +#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \ +attr void \ +name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ +{ \ + struct type *parent, *gparent, *tmp; \ + while ((parent = RB_PARENT(elm, field)) && \ + RB_COLOR(parent, field) == RB_RED) { \ + gparent = RB_PARENT(parent, field); \ + if (parent == RB_LEFT(gparent, field)) { \ + tmp = RB_RIGHT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field);\ + elm = gparent; \ + continue; \ + } \ + if (RB_RIGHT(parent, field) == elm) { \ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_RIGHT(head, gparent, tmp, field); \ + } else { \ + tmp = RB_LEFT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field);\ + elm = gparent; \ + continue; \ + } \ + if (RB_LEFT(parent, field) == elm) { \ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_LEFT(head, gparent, tmp, field); \ + } \ + } \ + RB_COLOR(head->rbh_root, field) = RB_BLACK; \ +} \ + \ +attr void \ +name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ +{ \ + struct type *tmp; \ + while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ + elm != RB_ROOT(head)) { \ + if (RB_LEFT(parent, field) == elm) { \ + tmp = RB_RIGHT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + tmp = RB_RIGHT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ + struct type *oleft; \ + if ((oleft = RB_LEFT(tmp, field)))\ + RB_COLOR(oleft, field) = RB_BLACK;\ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_RIGHT(head, tmp, oleft, field);\ + tmp = RB_RIGHT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_RIGHT(tmp, field)) \ + RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + elm = RB_ROOT(head); \ + break; \ + } \ + } else { \ + tmp = RB_LEFT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + tmp = RB_LEFT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ + struct type *oright; \ + if ((oright = RB_RIGHT(tmp, field)))\ + RB_COLOR(oright, field) = RB_BLACK;\ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_LEFT(head, tmp, oright, field);\ + tmp = RB_LEFT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_LEFT(tmp, field)) \ + RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + elm = RB_ROOT(head); \ + break; \ + } \ + } \ + } \ + if (elm) \ + RB_COLOR(elm, field) = RB_BLACK; \ +} \ + \ +attr struct type * \ +name##_RB_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *child, *parent, *old = elm; \ + int color; \ + if (RB_LEFT(elm, field) == NULL) \ + child = RB_RIGHT(elm, field); \ + else if (RB_RIGHT(elm, field) == NULL) \ + child = RB_LEFT(elm, field); \ + else { \ + struct type *left; \ + elm = RB_RIGHT(elm, field); \ + while ((left = RB_LEFT(elm, field))) \ + elm = left; \ + child = RB_RIGHT(elm, field); \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ + if (RB_PARENT(elm, field) == old) \ + parent = elm; \ + (elm)->field = (old)->field; \ + if (RB_PARENT(old, field)) { \ + if (RB_LEFT(RB_PARENT(old, field), field) == old)\ + RB_LEFT(RB_PARENT(old, field), field) = elm;\ + else \ + RB_RIGHT(RB_PARENT(old, field), field) = elm;\ + RB_AUGMENT(RB_PARENT(old, field)); \ + } else \ + RB_ROOT(head) = elm; \ + RB_PARENT(RB_LEFT(old, field), field) = elm; \ + if (RB_RIGHT(old, field)) \ + RB_PARENT(RB_RIGHT(old, field), field) = elm; \ + if (parent) { \ + left = parent; \ + do { \ + RB_AUGMENT(left); \ + } while ((left = RB_PARENT(left, field))); \ + } \ + goto color; \ + } \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ +color: \ + if (color == RB_BLACK) \ + name##_RB_REMOVE_COLOR(head, parent, child); \ + return (old); \ +} \ + \ +/* Inserts a node into the RB tree */ \ +attr struct type * \ +name##_RB_INSERT(struct name *head, struct type *elm) \ +{ \ + struct type *tmp; \ + struct type *parent = NULL; \ + int comp = 0; \ + tmp = RB_ROOT(head); \ + while (tmp) { \ + parent = tmp; \ + comp = (cmp)(elm, parent); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + RB_SET(elm, parent, field); \ + if (parent != NULL) { \ + if (comp < 0) \ + RB_LEFT(parent, field) = elm; \ + else \ + RB_RIGHT(parent, field) = elm; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = elm; \ + name##_RB_INSERT_COLOR(head, elm); \ + return (NULL); \ +} \ + \ +/* Finds the node with the same key as elm */ \ +attr struct type * \ +name##_RB_FIND(struct name *head, struct type *elm) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + int comp; \ + while (tmp) { \ + comp = cmp(elm, tmp); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (NULL); \ +} \ + \ +/* Finds the first node greater than or equal to the search key */ \ +attr struct type * \ +name##_RB_NFIND(struct name *head, struct type *elm) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + struct type *res = NULL; \ + int comp; \ + while (tmp) { \ + comp = cmp(elm, tmp); \ + if (comp < 0) { \ + res = tmp; \ + tmp = RB_LEFT(tmp, field); \ + } \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (res); \ +} \ + \ +/* ARGSUSED */ \ +attr struct type * \ +name##_RB_NEXT(struct type *elm) \ +{ \ + if (RB_RIGHT(elm, field)) { \ + elm = RB_RIGHT(elm, field); \ + while (RB_LEFT(elm, field)) \ + elm = RB_LEFT(elm, field); \ + } else { \ + if (RB_PARENT(elm, field) && \ + (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else { \ + while (RB_PARENT(elm, field) && \ + (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ +} \ + \ +/* ARGSUSED */ \ +attr struct type * \ +name##_RB_PREV(struct type *elm) \ +{ \ + if (RB_LEFT(elm, field)) { \ + elm = RB_LEFT(elm, field); \ + while (RB_RIGHT(elm, field)) \ + elm = RB_RIGHT(elm, field); \ + } else { \ + if (RB_PARENT(elm, field) && \ + (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else { \ + while (RB_PARENT(elm, field) && \ + (elm == RB_LEFT(RB_PARENT(elm, field), field)))\ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ +} \ + \ +attr struct type * \ +name##_RB_MINMAX(struct name *head, int val) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + struct type *parent = NULL; \ + while (tmp) { \ + parent = tmp; \ + if (val < 0) \ + tmp = RB_LEFT(tmp, field); \ + else \ + tmp = RB_RIGHT(tmp, field); \ + } \ + return (parent); \ +} + +#define RB_NEGINF -1 +#define RB_INF 1 + +#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) +#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) +#define RB_FIND(name, x, y) name##_RB_FIND(x, y) +#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y) +#define RB_NEXT(name, x, y) name##_RB_NEXT(y) +#define RB_PREV(name, x, y) name##_RB_PREV(y) +#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) +#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) + +#define RB_FOREACH(x, name, head) \ + for ((x) = RB_MIN(name, head); \ + (x) != NULL; \ + (x) = name##_RB_NEXT(x)) + +#define RB_FOREACH_SAFE(x, name, head, y) \ + for ((x) = RB_MIN(name, head); \ + ((x) != NULL) && ((y) = name##_RB_NEXT(x), 1); \ + (x) = (y)) + +#define RB_FOREACH_REVERSE(x, name, head) \ + for ((x) = RB_MAX(name, head); \ + (x) != NULL; \ + (x) = name##_RB_PREV(x)) + +#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \ + for ((x) = RB_MAX(name, head); \ + ((x) != NULL) && ((y) = name##_RB_PREV(x), 1); \ + (x) = (y)) + +#endif /* _SYS_TREE_H_ */ diff --git a/openbsd-compat/vis.c b/openbsd-compat/vis.c new file mode 100644 index 00000000..71101c1a --- /dev/null +++ b/openbsd-compat/vis.c @@ -0,0 +1,224 @@ +/* $OpenBSD: vis.c,v 1.19 2005/09/01 17:15:49 millert Exp $ */ +/*- + * Copyright (c) 1989, 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. 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. + */ + +/* OPENBSD ORIGINAL: lib/libc/gen/vis.c */ + +#include "includes.h" +#if !defined(HAVE_STRNVIS) || defined(BROKEN_STRNVIS) +#include <ctype.h> +#include <string.h> + +#include "bsd-vis.h" + +#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') +#define isvisible(c) \ + (((u_int)(c) <= UCHAR_MAX && isascii((u_char)(c)) && \ + (((c) != '*' && (c) != '?' && (c) != '[' && (c) != '#') || \ + (flag & VIS_GLOB) == 0) && isgraph((u_char)(c))) || \ + ((flag & VIS_SP) == 0 && (c) == ' ') || \ + ((flag & VIS_TAB) == 0 && (c) == '\t') || \ + ((flag & VIS_NL) == 0 && (c) == '\n') || \ + ((flag & VIS_SAFE) && ((c) == '\b' || \ + (c) == '\007' || (c) == '\r' || \ + isgraph((u_char)(c))))) + +/* + * vis - visually encode characters + */ +char * +vis(char *dst, int c, int flag, int nextc) +{ + if (isvisible(c)) { + *dst++ = c; + if (c == '\\' && (flag & VIS_NOSLASH) == 0) + *dst++ = '\\'; + *dst = '\0'; + return (dst); + } + + if (flag & VIS_CSTYLE) { + switch(c) { + case '\n': + *dst++ = '\\'; + *dst++ = 'n'; + goto done; + case '\r': + *dst++ = '\\'; + *dst++ = 'r'; + goto done; + case '\b': + *dst++ = '\\'; + *dst++ = 'b'; + goto done; + case '\a': + *dst++ = '\\'; + *dst++ = 'a'; + goto done; + case '\v': + *dst++ = '\\'; + *dst++ = 'v'; + goto done; + case '\t': + *dst++ = '\\'; + *dst++ = 't'; + goto done; + case '\f': + *dst++ = '\\'; + *dst++ = 'f'; + goto done; + case ' ': + *dst++ = '\\'; + *dst++ = 's'; + goto done; + case '\0': + *dst++ = '\\'; + *dst++ = '0'; + if (isoctal(nextc)) { + *dst++ = '0'; + *dst++ = '0'; + } + goto done; + } + } + if (((c & 0177) == ' ') || (flag & VIS_OCTAL) || + ((flag & VIS_GLOB) && (c == '*' || c == '?' || c == '[' || c == '#'))) { + *dst++ = '\\'; + *dst++ = ((u_char)c >> 6 & 07) + '0'; + *dst++ = ((u_char)c >> 3 & 07) + '0'; + *dst++ = ((u_char)c & 07) + '0'; + goto done; + } + if ((flag & VIS_NOSLASH) == 0) + *dst++ = '\\'; + if (c & 0200) { + c &= 0177; + *dst++ = 'M'; + } + if (iscntrl((u_char)c)) { + *dst++ = '^'; + if (c == 0177) + *dst++ = '?'; + else + *dst++ = c + '@'; + } else { + *dst++ = '-'; + *dst++ = c; + } +done: + *dst = '\0'; + return (dst); +} + +/* + * strvis, strnvis, strvisx - visually encode characters from src into dst + * + * Dst must be 4 times the size of src to account for possible + * expansion. The length of dst, not including the trailing NULL, + * is returned. + * + * Strnvis will write no more than siz-1 bytes (and will NULL terminate). + * The number of bytes needed to fully encode the string is returned. + * + * Strvisx encodes exactly len bytes from src into dst. + * This is useful for encoding a block of data. + */ +int +strvis(char *dst, const char *src, int flag) +{ + char c; + char *start; + + for (start = dst; (c = *src);) + dst = vis(dst, c, flag, *++src); + *dst = '\0'; + return (dst - start); +} + +int +strnvis(char *dst, const char *src, size_t siz, int flag) +{ + char *start, *end; + char tbuf[5]; + int c, i; + + i = 0; + for (start = dst, end = start + siz - 1; (c = *src) && dst < end; ) { + if (isvisible(c)) { + i = 1; + *dst++ = c; + if (c == '\\' && (flag & VIS_NOSLASH) == 0) { + /* need space for the extra '\\' */ + if (dst < end) + *dst++ = '\\'; + else { + dst--; + i = 2; + break; + } + } + src++; + } else { + i = vis(tbuf, c, flag, *++src) - tbuf; + if (dst + i <= end) { + memcpy(dst, tbuf, i); + dst += i; + } else { + src--; + break; + } + } + } + if (siz > 0) + *dst = '\0'; + if (dst + i > end) { + /* adjust return value for truncation */ + while ((c = *src)) + dst += vis(tbuf, c, flag, *++src) - tbuf; + } + return (dst - start); +} + +int +strvisx(char *dst, const char *src, size_t len, int flag) +{ + char c; + char *start; + + for (start = dst; len > 1; len--) { + c = *src; + dst = vis(dst, c, flag, *++src); + } + if (len) + dst = vis(dst, *src, flag, '\0'); + *dst = '\0'; + return (dst - start); +} + +#endif diff --git a/openbsd-compat/xmalloc.c b/openbsd-compat/xmalloc.c new file mode 100644 index 00000000..0f2da917 --- /dev/null +++ b/openbsd-compat/xmalloc.c @@ -0,0 +1,129 @@ +/* $OpenBSD: xmalloc.c,v 1.8 2007/02/22 06:42:10 otto Exp $ */ +/* + * Author: Tatu Ylonen <ylo@cs.hut.fi> + * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + * All rights reserved + * Versions of malloc and friends that check their results, and never return + * failure (they call fatal if they encounter an error). + * + * As far as I am concerned, the code I have written for this software + * can be used freely for any purpose. Any derived versions of this + * software must be clearly marked as such, and if the derived work is + * incompatible with the protocol description in the RFC file, it must be + * called by a name other than "ssh" or "Secure Shell". + */ + +#include "includes.h" + +#include <err.h> +#include <limits.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "log.h" +#include "xmalloc.h" + +void * +__xmalloc(size_t size) +{ + void *ptr; + + if (size == 0) + fatal("xmalloc: zero size"); + ptr = malloc(size); + if (ptr == NULL) + err(255, "fatal: xmalloc: out of memory (allocating %lu bytes)", (u_long) size); + return ptr; +} + +void * +__xcalloc(size_t nmemb, size_t size) +{ + void *ptr; + + if (size == 0 || nmemb == 0) + fatal("xcalloc: zero size"); + if (SIZE_T_MAX / nmemb < size) + fatal("xcalloc: nmemb * size > SIZE_T_MAX"); + ptr = calloc(nmemb, size); + if (ptr == NULL) + err(255, "fatal: xcalloc: out of memory (allocating %lu bytes)", + (u_long)(size * nmemb)); + return ptr; +} + +void * +__xrealloc(void *ptr, size_t nmemb, size_t size) +{ + void *new_ptr; + size_t new_size = nmemb * size; + + if (new_size == 0) + fatal("xrealloc: zero size"); + if (SIZE_T_MAX / nmemb < size) + fatal("xrealloc: nmemb * size > SIZE_T_MAX"); + if (ptr == NULL) + new_ptr = malloc(new_size); + else + new_ptr = realloc(ptr, new_size); + if (new_ptr == NULL) + err(255, "fatal: xrealloc: out of memory (new_size %lu bytes)", + (u_long) new_size); + return new_ptr; +} + +void +__xfree(void *ptr) +{ + if (ptr == NULL) + fatal("xfree: NULL pointer given as argument"); + free(ptr); +} + +char * +__xstrdup(const char *str) +{ + size_t len; + char *cp; + + len = strlen(str) + 1; + cp = __xmalloc(len); + strlcpy(cp, str, len); + return cp; +} + +/* +int +xasprintf(char **ret, const char *fmt, ...) +{ + va_list ap; + int i; + + va_start(ap, fmt); + i = vasprintf(ret, fmt, ap); + va_end(ap); + + if (i < 0 || *ret == NULL) + fatal("xasprintf: could not allocate memory"); + + return (i); +} +*/ + +int +xsnprintf(char *str, size_t size, const char *fmt, ...) +{ + va_list ap; + int i; + + va_start(ap, fmt); + i = vsnprintf(str, size, fmt, ap); + va_end(ap); + + if (i == -1 || i >= (int)size) + fatal("xsnprintf: overflow"); + + return (i); +} diff --git a/openbsd-compat/xmalloc.h b/openbsd-compat/xmalloc.h new file mode 100644 index 00000000..043a9645 --- /dev/null +++ b/openbsd-compat/xmalloc.h @@ -0,0 +1,35 @@ +/* $OpenBSD: xmalloc.h,v 1.3 2007/01/29 16:22:29 xsa Exp $ */ + +/* + * Author: Tatu Ylonen <ylo@cs.hut.fi> + * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + * All rights reserved + * Created: Mon Mar 20 22:09:17 1995 ylo + * + * Versions of malloc and friends that check their results, and never return + * failure (they call fatal if they encounter an error). + * + * As far as I am concerned, the code I have written for this software + * can be used freely for any purpose. Any derived versions of this + * software must be clearly marked as such, and if the derived work is + * incompatible with the protocol description in the RFC file, it must be + * called by a name other than "ssh" or "Secure Shell". + */ + +#ifndef XMALLOC_H +#define XMALLOC_H + +void *__xmalloc(size_t); +void *__xcalloc(size_t, size_t); +void *__xrealloc(void *, size_t, size_t); +void __xfree(void *); +char *__xstrdup(const char *); +//int xasprintf(char **, const char *, ...) +// __attribute__((__format__ (printf, 2, 3))) +// __attribute__((__nonnull__ (2))); +int xsnprintf(char *, size_t, const char *, ...) + __attribute__((__format__ (printf, 3, 4))) + __attribute__((__nonnull__ (3))); +// __attribute__((__bounded__ (__string__,1,2))); + +#endif /* XMALLOC_H */ diff --git a/smtpd/aliases.c b/smtpd/aliases.c index 884f6963..cd47d684 100644 --- a/smtpd/aliases.c +++ b/smtpd/aliases.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -29,7 +31,12 @@ #include <stdlib.h> #include <string.h> #include <limits.h> +#ifdef HAVE_UTIL_H #include <util.h> +#endif +#ifdef HAVE_LIBUTIL_H +#include <libutil.h> +#endif #include "smtpd.h" #include "log.h" diff --git a/smtpd/bounce.c b/smtpd/bounce.c index 02239988..41526d8d 100644 --- a/smtpd/bounce.c +++ b/smtpd/bounce.c @@ -18,6 +18,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -17,11 +17,14 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/socket.h> #include <sys/tree.h> +#include <grp.h> /* needed for setgroups */ #include <err.h> #include <imsg.h> #include <limits.h> diff --git a/smtpd/cert.c b/smtpd/cert.c index 05aff418..79b1df91 100644 --- a/smtpd/cert.c +++ b/smtpd/cert.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/socket.h> #include <sys/tree.h> diff --git a/smtpd/compress_backend.c b/smtpd/compress_backend.c index 516dd1ee..1b974662 100644 --- a/smtpd/compress_backend.c +++ b/smtpd/compress_backend.c @@ -17,6 +17,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/compress_gzip.c b/smtpd/compress_gzip.c index e7421cec..dd60aeec 100644 --- a/smtpd/compress_gzip.c +++ b/smtpd/compress_gzip.c @@ -17,6 +17,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/config.c b/smtpd/config.c index 8b8b8570..0d80f2e3 100644 --- a/smtpd/config.c +++ b/smtpd/config.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -202,7 +204,9 @@ set_localaddrs(struct smtpd *conf, struct table *localnames) case AF_INET: sain = (struct sockaddr_in *)&ss; *sain = *(struct sockaddr_in *)p->ifa_addr; +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sain->sin_len = sizeof(struct sockaddr_in); +#endif table_add(t, ss_to_text(&ss), NULL); table_add(localnames, ss_to_text(&ss), NULL); (void)snprintf(buf, sizeof buf, "[%s]", ss_to_text(&ss)); @@ -212,7 +216,9 @@ set_localaddrs(struct smtpd *conf, struct table *localnames) case AF_INET6: sin6 = (struct sockaddr_in6 *)&ss; *sin6 = *(struct sockaddr_in6 *)p->ifa_addr; +#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN sin6->sin6_len = sizeof(struct sockaddr_in6); +#endif table_add(t, ss_to_text(&ss), NULL); table_add(localnames, ss_to_text(&ss), NULL); (void)snprintf(buf, sizeof buf, "[%s]", ss_to_text(&ss)); @@ -303,7 +309,8 @@ config_process(enum smtp_proc_type proc) fatal("fdlimit: getrlimit"); rl.rlim_cur = rl.rlim_max; if (setrlimit(RLIMIT_NOFILE, &rl) == -1) - fatal("fdlimit: setrlimit"); + if (errno != EINVAL) + fatal("fdlimit: setrlimit"); } void diff --git a/smtpd/control.c b/smtpd/control.c index 6f9c9aca..d85bf578 100644 --- a/smtpd/control.c +++ b/smtpd/control.c @@ -18,6 +18,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -29,6 +31,7 @@ #include <errno.h> #include <event.h> #include <fcntl.h> +#include <grp.h> /* needed for setgroups */ #include <imsg.h> #include <pwd.h> #include <signal.h> @@ -292,7 +295,7 @@ control_accept(int listenfd, short event, void *arg) uid_t euid; gid_t egid; - if (getdtablesize() - getdtablecount() < CONTROL_FD_RESERVE) + if (available_fds(CONTROL_FD_RESERVE)) goto pause; len = sizeof(s_un); @@ -366,7 +369,7 @@ control_close(struct ctl_conn *c) stat_backend->decrement("control.session", 1); - if (getdtablesize() - getdtablecount() < CONTROL_FD_RESERVE) + if (available_fds(CONTROL_FD_RESERVE)) return; if (!event_pending(&control_state.ev, EV_READ, NULL)) { diff --git a/smtpd/crypto.c b/smtpd/crypto.c index 1cc1af7c..76f98807 100644 --- a/smtpd/crypto.c +++ b/smtpd/crypto.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/stat.h> diff --git a/smtpd/dict.c b/smtpd/dict.c index 91156d5a..e660f0a5 100644 --- a/smtpd/dict.c +++ b/smtpd/dict.c @@ -17,6 +17,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/tree.h> diff --git a/smtpd/dns.c b/smtpd/dns.c index 4d369e24..74499e09 100644 --- a/smtpd/dns.c +++ b/smtpd/dns.c @@ -18,6 +18,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/socket.h> #include <sys/tree.h> @@ -27,10 +29,15 @@ #include <netinet/in.h> #include <arpa/inet.h> #include <arpa/nameser.h> +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +#include <arpa/nameser_compat.h> +#endif #include <netdb.h> #include <asr.h> #include <event.h> +#include <netdb.h> +#include <resolv.h> #include <imsg.h> #include <stdio.h> #include <stdlib.h> @@ -41,6 +48,11 @@ #include "log.h" #include "unpack_dns.h" +/* On OpenBSD, this function is not needed because we don't free addrinfo */ +#if defined(NOOP_ASR_FREEADDRINFO) +#define asr_freeaddrinfo(x) do { } while(0); +#endif + struct dns_lookup { struct dns_session *session; int preference; @@ -214,7 +226,7 @@ dns_dispatch_host(struct asr_result *ar, void *arg) } free(lookup); if (ar->ar_addrinfo) - freeaddrinfo(ar->ar_addrinfo); + asr_freeaddrinfo(ar->ar_addrinfo); if (ar->ar_gai_errno) s->error = ar->ar_gai_errno; diff --git a/smtpd/enqueue.c b/smtpd/enqueue.c index bc59989a..dcb40cd3 100644 --- a/smtpd/enqueue.c +++ b/smtpd/enqueue.c @@ -18,6 +18,8 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/socket.h> @@ -561,12 +563,12 @@ build_from(char *fake_from, struct passwd *pw) apos, pw->pw_gecos, pw->pw_name, len - apos - 1, p + 1) == -1) - err(1, NULL); + err(1, "asprintf"); msg.fromname[apos] = toupper((unsigned char)msg.fromname[apos]); } else { if (asprintf(&msg.fromname, "%.*s", len, pw->pw_gecos) == -1) - err(1, NULL); + err(1, "asprintf"); } } } diff --git a/smtpd/envelope.c b/smtpd/envelope.c index cd247a82..596b701d 100644 --- a/smtpd/envelope.c +++ b/smtpd/envelope.c @@ -17,6 +17,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -301,14 +303,18 @@ ascii_load_sockaddr(struct sockaddr_storage *ss, char *buf) return 0; ssin6.sin6_family = AF_INET6; memcpy(ss, &ssin6, sizeof(ssin6)); +#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN ss->ss_len = sizeof(struct sockaddr_in6); +#endif } else { if (inet_pton(AF_INET, buf, &ssin.sin_addr) != 1) return 0; ssin.sin_family = AF_INET; memcpy(ss, &ssin, sizeof(ssin)); +#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN ss->ss_len = sizeof(struct sockaddr_in); +#endif } return 1; } diff --git a/smtpd/esc.c b/smtpd/esc.c index a07320ce..64a44c79 100644 --- a/smtpd/esc.c +++ b/smtpd/esc.c @@ -16,12 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/queue.h> -#include <sys/tree.h> -#include <sys/socket.h> +#include "includes.h" -#include <netinet/in.h> -#include <netdb.h> #include <stdio.h> #include <limits.h> diff --git a/smtpd/expand.c b/smtpd/expand.c index 99b25d51..a4306fc0 100644 --- a/smtpd/expand.c +++ b/smtpd/expand.c @@ -17,6 +17,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -29,6 +31,12 @@ #include <limits.h> #include <stdlib.h> #include <string.h> +#ifdef HAVE_UTIL_H +#include <util.h> +#endif +#ifdef HAVE_LIBUTIL_H +#include <libutil.h> +#endif #include "smtpd.h" #include "log.h" diff --git a/smtpd/filter.c b/smtpd/filter.c new file mode 100644 index 00000000..614486b7 --- /dev/null +++ b/smtpd/filter.c @@ -0,0 +1,868 @@ +/* $OpenBSD: filter.c,v 1.25 2017/01/09 09:53:23 reyk Exp $ */ + +/* + * Copyright (c) 2011 Gilles Chehade <gilles@poolp.org> + * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/tree.h> +#include <sys/socket.h> +#include <sys/wait.h> + +#include <netinet/in.h> + +#include <ctype.h> +#include <errno.h> +#include <event.h> +#include <imsg.h> +#include <inttypes.h> +#include <limits.h> +#include <resolv.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "smtpd.h" +#include "log.h" + +enum { + QUERY_READY, + QUERY_RUNNING, + QUERY_DONE +}; + + +struct filter_proc { + TAILQ_ENTRY(filter_proc) entry; + struct mproc mproc; + int hooks; + int flags; + int ready; +}; + +struct filter { + TAILQ_ENTRY(filter) entry; + struct filter_proc *proc; +}; +TAILQ_HEAD(filter_lst, filter); + +TAILQ_HEAD(filter_query_lst, filter_query); +struct filter_session { + uint64_t id; + int terminate; + struct filter_lst *filters; + struct filter *fcurr; + + int error; + struct io *iev; + size_t idatalen; + FILE *ofile; + + struct filter_query *eom; +}; + +struct filter_query { + uint64_t qid; + int type; + struct filter_session *session; + + int state; + struct filter *current; + + /* current data */ + union { + struct { + struct sockaddr_storage local; + struct sockaddr_storage remote; + char hostname[HOST_NAME_MAX+1]; + } connect; + char line[LINE_MAX]; + struct mailaddr maddr; + size_t datalen; + } u; + + /* current response */ + struct { + int status; + int code; + char *response; + } smtp; +}; + +static void filter_imsg(struct mproc *, struct imsg *); +static void filter_post_event(uint64_t, int, struct filter *, struct filter *); +static struct filter_query *filter_query(struct filter_session *, int); +static void filter_drain_query(struct filter_query *); +static void filter_run_query(struct filter *, struct filter_query *); +static void filter_end_query(struct filter_query *); +static void filter_set_sink(struct filter_session *, int); +static int filter_tx(struct filter_session *, int); +static void filter_tx_io(struct io *, int, void *); + +static TAILQ_HEAD(, filter_proc) procs; +struct dict chains; + +static const char * filter_session_to_text(struct filter_session *); +static const char * filter_query_to_text(struct filter_query *); +static const char * filter_to_text(struct filter *); +static const char * filter_proc_to_text(struct filter_proc *); +static const char * query_to_str(int); +static const char * event_to_str(int); +static const char * status_to_str(int); +static const char * filterimsg_to_str(int); + +struct tree sessions; +struct tree queries; + +static void +filter_add_arg(struct filter_conf *filter, char *arg) +{ + if (filter->argc == MAX_FILTER_ARGS) { + log_warnx("warn: filter \"%s\" is full", filter->name); + fatalx("exiting"); + } + filter->argv[filter->argc++] = arg; +} + +static void +filter_extend_chain(struct filter_lst *chain, const char *name) +{ + struct filter *n; + struct filter_lst *fchain; + struct filter_conf *fconf; + int i; + + fconf = dict_xget(&env->sc_filters, name); + if (fconf->chain) { + log_debug("filter: extending with \"%s\"", name); + for (i = 0; i < fconf->argc; i++) + filter_extend_chain(chain, fconf->argv[i]); + } + else { + log_debug("filter: adding filter \"%s\"", name); + n = xcalloc(1, sizeof(*n), "filter_extend_chain"); + fchain = dict_get(&chains, name); + n->proc = TAILQ_FIRST(fchain)->proc; + TAILQ_INSERT_TAIL(chain, n, entry); + } +} + +void +filter_postfork(void) +{ + static int prepare = 0; + struct filter_conf *filter; + void *iter; + struct filter_proc *proc; + struct filter_lst *fchain; + struct filter *f; + struct mproc *p; + int done, i; + + if (prepare) + return; + prepare = 1; + + TAILQ_INIT(&procs); + dict_init(&chains); + + log_debug("filter: building simple chains..."); + + /* create all filter proc and associated chains */ + iter = NULL; + while (dict_iter(&env->sc_filters, &iter, NULL, (void **)&filter)) { + if (filter->chain) + continue; + + log_debug("filter: building simple chain \"%s\"", filter->name); + proc = xcalloc(1, sizeof(*proc), "filter_postfork"); + p = &proc->mproc; + p->handler = filter_imsg; + p->proc = PROC_FILTER; + p->name = xstrdup(filter->name, "filter_postfork"); + p->data = proc; + if (tracing & TRACE_DEBUG) + filter_add_arg(filter, "-v"); + if (foreground_log) + filter_add_arg(filter, "-d"); + if (mproc_fork(p, filter->path, filter->argv) < 0) + fatalx("filter_postfork"); + + log_debug("filter: registering proc \"%s\"", filter->name); + f = xcalloc(1, sizeof(*f), "filter_postfork"); + f->proc = proc; + + TAILQ_INSERT_TAIL(&procs, proc, entry); + fchain = xcalloc(1, sizeof(*fchain), "filter_postfork"); + TAILQ_INIT(fchain); + TAILQ_INSERT_TAIL(fchain, f, entry); + dict_xset(&chains, filter->name, fchain); + filter->done = 1; + } + + log_debug("filter: building complex chains..."); + + /* resolve all chains */ + done = 0; + while (!done) { + done = 1; + iter = NULL; + while (dict_iter(&env->sc_filters, &iter, NULL, + (void **)&filter)) { + if (filter->done) + continue; + done = 0; + filter->done = 1; + for (i = 0; i < filter->argc; i++) { + if (!dict_get(&chains, filter->argv[i])) { + filter->done = 0; + break; + } + } + if (filter->done == 0) + continue; + fchain = xcalloc(1, sizeof(*fchain), "filter_postfork"); + TAILQ_INIT(fchain); + log_debug("filter: building chain \"%s\"...", + filter->name); + for (i = 0; i < filter->argc; i++) + filter_extend_chain(fchain, filter->argv[i]); + log_debug("filter: done building chain \"%s\"", + filter->name); + dict_xset(&chains, filter->name, fchain); + } + } + log_debug("filter: done building complex chains"); + + fchain = xcalloc(1, sizeof(*fchain), "filter_postfork"); + TAILQ_INIT(fchain); + dict_xset(&chains, "<no-filter>", fchain); +} + +void +filter_configure(void) +{ + static int init = 0; + struct filter_proc *p; + + if (init) + return; + init = 1; + + tree_init(&sessions); + tree_init(&queries); + + TAILQ_FOREACH(p, &procs, entry) { + m_create(&p->mproc, IMSG_FILTER_REGISTER, 0, 0, -1); + m_add_u32(&p->mproc, FILTER_API_VERSION); + m_add_string(&p->mproc, p->mproc.name); + m_close(&p->mproc); + mproc_enable(&p->mproc); + } + + if (TAILQ_FIRST(&procs) == NULL) + smtp_configure(); +} + +void +filter_event(uint64_t id, int event) +{ + struct filter_session *s; + + if (event == EVENT_DISCONNECT) + /* On disconnect, the session is virtualy dead */ + s = tree_xpop(&sessions, id); + else + s = tree_xget(&sessions, id); + + filter_post_event(id, event, TAILQ_FIRST(s->filters), NULL); + + if (event == EVENT_DISCONNECT) { + if (s->iev) + io_free(s->iev); + if (s->ofile) + fclose(s->ofile); + free(s); + } +} + +void +filter_connect(uint64_t id, const struct sockaddr *local, + const struct sockaddr *remote, const char *host, const char *filter) +{ + struct filter_session *s; + struct filter_query *q; + + s = xcalloc(1, sizeof(*s), "filter_event"); + s->id = id; + if (filter == NULL) + filter = "<no-filter>"; + s->filters = dict_xget(&chains, filter); + tree_xset(&sessions, s->id, s); + + filter_event(id, EVENT_CONNECT); + q = filter_query(s, QUERY_CONNECT); + + memmove(&q->u.connect.local, local, SA_LEN(local)); + memmove(&q->u.connect.remote, remote, SA_LEN(remote)); + strlcpy(q->u.connect.hostname, host, sizeof(q->u.connect.hostname)); + + q->smtp.status = FILTER_OK; + q->smtp.code = 0; + q->smtp.response = NULL; + + filter_drain_query(q); +} + +void +filter_mailaddr(uint64_t id, int type, const struct mailaddr *maddr) +{ + struct filter_session *s; + struct filter_query *q; + + s = tree_xget(&sessions, id); + q = filter_query(s, type); + + strlcpy(q->u.maddr.user, maddr->user, sizeof(q->u.maddr.user)); + strlcpy(q->u.maddr.domain, maddr->domain, sizeof(q->u.maddr.domain)); + + filter_drain_query(q); +} + +void +filter_line(uint64_t id, int type, const char *line) +{ + struct filter_session *s; + struct filter_query *q; + + s = tree_xget(&sessions, id); + q = filter_query(s, type); + + if (line) + strlcpy(q->u.line, line, sizeof(q->u.line)); + + filter_drain_query(q); +} + +void +filter_eom(uint64_t id, int type, size_t datalen) +{ + struct filter_session *s; + struct filter_query *q; + + s = tree_xget(&sessions, id); + q = filter_query(s, type); + q->u.datalen = datalen; + + filter_drain_query(q); +} + +static void +filter_set_sink(struct filter_session *s, int sink) +{ + struct mproc *p; + + while (s->fcurr) { + if (s->fcurr->proc->hooks & HOOK_DATALINE) { + log_trace(TRACE_FILTERS, "filter: sending fd %d to %s", + sink, filter_to_text(s->fcurr)); + p = &s->fcurr->proc->mproc; + m_create(p, IMSG_FILTER_PIPE, 0, 0, sink); + m_add_id(p, s->id); + m_close(p); + return; + } + s->fcurr = TAILQ_PREV(s->fcurr, filter_lst, entry); + } + + log_trace(TRACE_FILTERS, "filter: chain input is %d", sink); + smtp_filter_fd(s->id, sink); +} + +void +filter_build_fd_chain(uint64_t id, int sink) +{ + struct filter_session *s; + int fd; + + s = tree_xget(&sessions, id); + s->fcurr = TAILQ_LAST(s->filters, filter_lst); + + fd = filter_tx(s, sink); + filter_set_sink(s, fd); +} + +void +filter_post_event(uint64_t id, int event, struct filter *f, struct filter *end) +{ + for(; f && f != end; f = TAILQ_NEXT(f, entry)) { + log_trace(TRACE_FILTERS, "filter: post-event event=%s filter=%s", + event_to_str(event), f->proc->mproc.name); + + m_create(&f->proc->mproc, IMSG_FILTER_EVENT, 0, 0, -1); + m_add_id(&f->proc->mproc, id); + m_add_int(&f->proc->mproc, event); + m_close(&f->proc->mproc); + } +} + +static struct filter_query * +filter_query(struct filter_session *s, int type) +{ + struct filter_query *q; + + q = xcalloc(1, sizeof(*q), "filter_query"); + q->qid = generate_uid(); + q->session = s; + q->type = type; + + q->state = QUERY_READY; + q->current = TAILQ_FIRST(s->filters); + + log_trace(TRACE_FILTERS, "filter: new query %s", query_to_str(type)); + + return (q); +} + +static void +filter_drain_query(struct filter_query *q) +{ + log_trace(TRACE_FILTERS, "filter: filter_drain_query %s", + filter_query_to_text(q)); + + /* + * The query must be passed through all filters that registered + * a hook, until one rejects it. + */ + while (q->state != QUERY_DONE) { + /* Walk over all filters */ + while (q->current) { + filter_run_query(q->current, q); + if (q->state == QUERY_RUNNING) { + log_trace(TRACE_FILTERS, + "filter: waiting for running query %s", + filter_query_to_text(q)); + return; + } + } + q->state = QUERY_DONE; + } + + /* Defer the response if the file is not closed yet. */ + if (q->type == QUERY_EOM && q->session->ofile && q->smtp.status == FILTER_OK) { + log_debug("filter: deferring eom query..."); + q->session->eom = q; + return; + } + + filter_end_query(q); +} + +static void +filter_run_query(struct filter *f, struct filter_query *q) +{ + log_trace(TRACE_FILTERS, + "filter: running filter %s for query %s", + filter_to_text(f), filter_query_to_text(q)); + + m_create(&f->proc->mproc, IMSG_FILTER_QUERY, 0, 0, -1); + m_add_id(&f->proc->mproc, q->session->id); + m_add_id(&f->proc->mproc, q->qid); + m_add_int(&f->proc->mproc, q->type); + + switch (q->type) { + case QUERY_CONNECT: + m_add_sockaddr(&f->proc->mproc, + (struct sockaddr *)&q->u.connect.local); + m_add_sockaddr(&f->proc->mproc, + (struct sockaddr *)&q->u.connect.remote); + m_add_string(&f->proc->mproc, q->u.connect.hostname); + break; + case QUERY_HELO: + m_add_string(&f->proc->mproc, q->u.line); + break; + case QUERY_MAIL: + case QUERY_RCPT: + m_add_mailaddr(&f->proc->mproc, &q->u.maddr); + break; + case QUERY_EOM: + m_add_u32(&f->proc->mproc, q->u.datalen); + break; + default: + break; + } + m_close(&f->proc->mproc); + + tree_xset(&queries, q->qid, q); + q->state = QUERY_RUNNING; +} + +static void +filter_end_query(struct filter_query *q) +{ + struct filter_session *s = q->session; + const char *response = q->smtp.response; + + log_trace(TRACE_FILTERS, "filter: filter_end_query %s", + filter_query_to_text(q)); + + if (q->type == QUERY_EOM && q->smtp.status == FILTER_OK) { + if (s->error || q->u.datalen != s->idatalen) { + response = "Internal error"; + q->smtp.code = 451; + q->smtp.status = FILTER_FAIL; + if (!s->error) + log_warnx("filter: datalen mismatch on session %" PRIx64 + ": %zu/%zu", s->id, s->idatalen, q->u.datalen); + } + } + + log_trace(TRACE_FILTERS, + "filter: query %016"PRIx64" done: " + "status=%s code=%d response=\"%s\"", + q->qid, + status_to_str(q->smtp.status), + q->smtp.code, + response); + + smtp_filter_response(s->id, q->type, q->smtp.status, q->smtp.code, + response); + free(q->smtp.response); + free(q); +} + +static void +filter_imsg(struct mproc *p, struct imsg *imsg) +{ + struct filter_proc *proc = p->data; + struct filter_session *s; + struct filter_query *q; + struct msg m; + const char *line; + uint64_t qid; + uint32_t datalen; + int type, status, code; + + if (imsg == NULL) { + log_warnx("warn: filter \"%s\" closed unexpectedly", p->name); + fatalx("exiting"); + } + + log_trace(TRACE_FILTERS, "filter: imsg %s from procfilter %s", + filterimsg_to_str(imsg->hdr.type), + filter_proc_to_text(proc)); + + switch (imsg->hdr.type) { + + case IMSG_FILTER_REGISTER: + if (proc->ready) { + log_warnx("warn: filter \"%s\" already registered", + proc->mproc.name); + exit(1); + } + + m_msg(&m, imsg); + m_get_int(&m, &proc->hooks); + m_get_int(&m, &proc->flags); + m_end(&m); + proc->ready = 1; + + log_debug("debug: filter \"%s\": hooks 0x%08x flags 0x%04x", + proc->mproc.name, proc->hooks, proc->flags); + + TAILQ_FOREACH(proc, &procs, entry) + if (!proc->ready) + return; + + smtp_configure(); + break; + + case IMSG_FILTER_RESPONSE: + m_msg(&m, imsg); + m_get_id(&m, &qid); + m_get_int(&m, &type); + if (type == QUERY_EOM) + m_get_u32(&m, &datalen); + m_get_int(&m, &status); + m_get_int(&m, &code); + if (m_is_eom(&m)) + line = NULL; + else + m_get_string(&m, &line); + m_end(&m); + + q = tree_xpop(&queries, qid); + if (q->type != type) { + log_warnx("warn: filter: type mismatch %d != %d", + q->type, type); + fatalx("exiting"); + } + q->smtp.status = status; + if (code) + q->smtp.code = code; + if (line) { + free(q->smtp.response); + q->smtp.response = xstrdup(line, "filter_imsg"); + } + q->state = (status == FILTER_OK) ? QUERY_READY : QUERY_DONE; + if (type == QUERY_EOM) + q->u.datalen = datalen; + + q->current = TAILQ_NEXT(q->current, entry); + filter_drain_query(q); + break; + + case IMSG_FILTER_PIPE: + m_msg(&m, imsg); + m_get_id(&m, &qid); + m_end(&m); + + s = tree_xget(&sessions, qid); + s->fcurr = TAILQ_PREV(s->fcurr, filter_lst, entry); + filter_set_sink(s, imsg->fd); + break; + + default: + log_warnx("warn: bad imsg from filter %s", p->name); + exit(1); + } +} + +static int +filter_tx(struct filter_session *s, int sink) +{ + int sp[2]; + + s->idatalen = 0; + s->eom = NULL; + s->error = 0; + + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sp) == -1) { + log_warn("warn: filter: socketpair"); + return (-1); + } + + if ((s->ofile = fdopen(sink, "w")) == NULL) { + log_warn("warn: filter: fdopen"); + close(sp[0]); + close(sp[1]); + return (-1); + } + + io_set_nonblocking(sp[0]); + io_set_nonblocking(sp[1]); + + s->iev = io_new(); + io_set_callback(s->iev, filter_tx_io, s); + io_set_fd(s->iev, sp[0]); + io_set_read(s->iev); + + return (sp[1]); +} + +static void +filter_tx_io(struct io *io, int evt, void *arg) +{ + struct filter_session *s = arg; + size_t len, n; + char *data; + + log_trace(TRACE_FILTERS, "filter: filter_tx_io(%p, %s)", + s, io_strevent(evt)); + + switch (evt) { + case IO_DATAIN: + data = io_data(s->iev); + len = io_datalen(s->iev); + + log_trace(TRACE_FILTERS, + "filter: filter_tx_io: datain (%zu) for req %016"PRIx64"", + len, s->id); + + n = fwrite(data, 1, len, s->ofile); + if (n != len) { + log_warnx("warn: filter_tx_io: fwrite %zu/%zu", n, len); + s->error = 1; + break; + } + s->idatalen += n; + io_drop(s->iev, n); + return; + + case IO_DISCONNECTED: + log_trace(TRACE_FILTERS, + "debug: filter: tx done (%zu) for req %016"PRIx64, + s->idatalen, s->id); + break; + + default: + log_warn("warn: filter_tx_io: bad evt (%d) for req %016"PRIx64, + evt, s->id); + s->error = 1; + break; + } + + io_free(s->iev); + s->iev = NULL; + fclose(s->ofile); + s->ofile = NULL; + + /* deferred eom request */ + if (s->eom) { + log_debug("filter: running eom query..."); + filter_end_query(s->eom); + } else { + log_debug("filter: eom not received yet"); + } +} + +static const char * +filter_query_to_text(struct filter_query *q) +{ + static char buf[1024]; + char tmp[1024]; + + tmp[0] = '\0'; + + switch (q->type) { + case QUERY_CONNECT: + strlcat(tmp, "=", sizeof tmp); + strlcat(tmp, ss_to_text(&q->u.connect.local), + sizeof tmp); + strlcat(tmp, " <-> ", sizeof tmp); + strlcat(tmp, ss_to_text(&q->u.connect.remote), + sizeof tmp); + strlcat(tmp, "(", sizeof tmp); + strlcat(tmp, q->u.connect.hostname, sizeof tmp); + strlcat(tmp, ")", sizeof tmp); + break; + case QUERY_MAIL: + case QUERY_RCPT: + snprintf(tmp, sizeof tmp, "=%s@%s", + q->u.maddr.user, q->u.maddr.domain); + break; + case QUERY_HELO: + snprintf(tmp, sizeof tmp, "=%s", q->u.line); + break; + default: + break; + } + snprintf(buf, sizeof buf, "%016"PRIx64"[%s%s,%s]", + q->qid, query_to_str(q->type), tmp, + filter_session_to_text(q->session)); + + return (buf); +} + +static const char * +filter_session_to_text(struct filter_session *s) +{ + static char buf[1024]; + + if (s == NULL) + return "filter_session@NULL"; + + snprintf(buf, sizeof(buf), + "filter_session@%p[datalen=%zu,eom=%p,ofile=%p]", + s, s->idatalen, s->eom, s->ofile); + + return buf; +} + +static const char * +filter_to_text(struct filter *f) +{ + static char buf[1024]; + + snprintf(buf, sizeof buf, "filter:%s", filter_proc_to_text(f->proc)); + + return (buf); +} + +static const char * +filter_proc_to_text(struct filter_proc *proc) +{ + static char buf[1024]; + + snprintf(buf, sizeof buf, "%s[hooks=0x%08x,flags=0x%04x]", + proc->mproc.name, proc->hooks, proc->flags); + + return (buf); +} + +#define CASE(x) case x : return #x + +static const char * +filterimsg_to_str(int imsg) +{ + switch (imsg) { + CASE(IMSG_FILTER_REGISTER); + CASE(IMSG_FILTER_EVENT); + CASE(IMSG_FILTER_QUERY); + CASE(IMSG_FILTER_PIPE); + CASE(IMSG_FILTER_RESPONSE); + default: + return "IMSG_FILTER_???"; + } +} + +static const char * +query_to_str(int query) +{ + switch (query) { + CASE(QUERY_CONNECT); + CASE(QUERY_HELO); + CASE(QUERY_MAIL); + CASE(QUERY_RCPT); + CASE(QUERY_DATA); + CASE(QUERY_EOM); + CASE(QUERY_DATALINE); + default: + return "QUERY_???"; + } +} + +static const char * +event_to_str(int event) +{ + switch (event) { + CASE(EVENT_CONNECT); + CASE(EVENT_RESET); + CASE(EVENT_DISCONNECT); + CASE(EVENT_TX_BEGIN); + CASE(EVENT_TX_COMMIT); + CASE(EVENT_TX_ROLLBACK); + default: + return "EVENT_???"; + } +} + +static const char * +status_to_str(int status) +{ + switch (status) { + CASE(FILTER_OK); + CASE(FILTER_FAIL); + CASE(FILTER_CLOSE); + default: + return "FILTER_???"; + } +} diff --git a/smtpd/forward.c b/smtpd/forward.c index d30d55e9..7494c6ce 100644 --- a/smtpd/forward.c +++ b/smtpd/forward.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -28,7 +30,12 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#ifdef HAVE_UTIL_H #include <util.h> +#endif +#ifdef HAVE_LIBUTIL_H +#include <libutil.h> +#endif #include <unistd.h> #include <limits.h> diff --git a/smtpd/iobuf.c b/smtpd/iobuf.c index 27c404a0..46d8ef04 100644 --- a/smtpd/iobuf.c +++ b/smtpd/iobuf.c @@ -15,6 +15,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/socket.h> #include <sys/uio.h> diff --git a/smtpd/ioev.c b/smtpd/ioev.c index 44690766..28de5c7b 100644 --- a/smtpd/ioev.c +++ b/smtpd/ioev.c @@ -15,6 +15,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/socket.h> @@ -749,10 +751,10 @@ io_connect(struct io *io, const struct sockaddr *sa, const struct sockaddr *bsa) io_set_nonblocking(sock); io_set_nolinger(sock); - if (bsa && bind(sock, bsa, bsa->sa_len) == -1) + if (bsa && bind(sock, bsa, SA_LEN(bsa)) == -1) goto fail; - if (connect(sock, sa, sa->sa_len) == -1) + if (connect(sock, sa, SA_LEN(sa)) == -1) if (errno != EINPROGRESS) goto fail; diff --git a/smtpd/libressl.c b/smtpd/libressl.c new file mode 100644 index 00000000..57d74389 --- /dev/null +++ b/smtpd/libressl.c @@ -0,0 +1,213 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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 cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +/* + * SSL operations needed when running in a privilege separated environment. + * Adapted from openssl's ssl_rsa.c by Pierre-Yves Ritschard . + */ + +#include "includes.h" + +#include <sys/types.h> + +#include <limits.h> +#include <unistd.h> +#include <stdio.h> + +#include <openssl/err.h> +#include <openssl/bio.h> +#include <openssl/objects.h> +#include <openssl/evp.h> +#include <openssl/x509.h> +#include <openssl/pem.h> +#include <openssl/ssl.h> + +#include "log.h" +#include "ssl.h" + +#define SSL_ECDH_CURVE "prime256v1" + +/* + * Read a bio that contains our certificate in "PEM" format, + * possibly followed by a sequence of CA certificates that should be + * sent to the peer in the Certificate message. + */ +static int +ssl_ctx_use_certificate_chain_bio(SSL_CTX *ctx, BIO *in) +{ + int ret = 0; + X509 *x = NULL; + + ERR_clear_error(); /* clear error stack for SSL_CTX_use_certificate() */ + + x = PEM_read_bio_X509_AUX(in, NULL, ctx->default_passwd_callback, + ctx->default_passwd_callback_userdata); + if (x == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_PEM_LIB); + goto end; + } + + ret = SSL_CTX_use_certificate(ctx, x); + + if (ERR_peek_error() != 0) + ret = 0; + /* Key/certificate mismatch doesn't imply ret==0 ... */ + if (ret) { + /* + * If we could set up our certificate, now proceed to + * the CA certificates. + */ + X509 *ca; + int r; + unsigned long err; + + if (ctx->extra_certs != NULL) { + sk_X509_pop_free(ctx->extra_certs, X509_free); + ctx->extra_certs = NULL; + } + + while ((ca = PEM_read_bio_X509(in, NULL, + ctx->default_passwd_callback, + ctx->default_passwd_callback_userdata)) != NULL) { + r = SSL_CTX_add_extra_chain_cert(ctx, ca); + if (!r) { + X509_free(ca); + ret = 0; + goto end; + } + /* + * Note that we must not free r if it was successfully + * added to the chain (while we must free the main + * certificate, since its reference count is increased + * by SSL_CTX_use_certificate). + */ + } + + /* When the while loop ends, it's usually just EOF. */ + err = ERR_peek_last_error(); + if (ERR_GET_LIB(err) == ERR_LIB_PEM && + ERR_GET_REASON(err) == PEM_R_NO_START_LINE) + ERR_clear_error(); + else + ret = 0; /* some real error */ + } + +end: + if (x != NULL) + X509_free(x); + return (ret); +} + +int +SSL_CTX_use_certificate_chain_mem(SSL_CTX *ctx, void *buf, int len) +{ + BIO *in; + int ret = 0; + + in = BIO_new_mem_buf(buf, len); + if (in == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_BUF_LIB); + goto end; + } + + ret = ssl_ctx_use_certificate_chain_bio(ctx, in); + +end: + BIO_free(in); + return (ret); +} + +#ifndef HAVE_SSL_CTX_SET_ECDH_AUTO +void +SSL_CTX_set_ecdh_auto(SSL_CTX *ctx, int enable) +{ + int nid; + EC_KEY *ecdh; + + if (!enable) + return; + + if ((nid = OBJ_sn2nid(SSL_ECDH_CURVE)) == 0) { + ssl_error("ssl_set_ecdh_auto"); + fatal("ssl_set_ecdh_auto: unknown curve name " + SSL_ECDH_CURVE); + } + + if ((ecdh = EC_KEY_new_by_curve_name(nid)) == NULL) { + ssl_error("ssl_set_ecdh_auto"); + fatal("ssl_set_ecdh_auto: unable to create curve " + SSL_ECDH_CURVE); + } + + SSL_CTX_set_tmp_ecdh(ctx, ecdh); + SSL_CTX_set_options(ctx, SSL_OP_SINGLE_ECDH_USE); + EC_KEY_free(ecdh); +} +#endif + +#ifndef HAVE_SSL_CTX_SET_DH_AUTO +void +SSL_CTX_set_dh_auto(SSL_CTX *ctx, int enable) +{ + if (!enable) + return; + + /* stub until OpenSSL catches up with this ... */ + log_warnx("OpenSSL does not support SSL_CTX_set_dh_auto (yet ?)"); + return; +} +#endif diff --git a/smtpd/limit.c b/smtpd/limit.c index e7d0cb17..25e7a026 100644 --- a/smtpd/limit.c +++ b/smtpd/limit.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/lka.c b/smtpd/lka.c index fcb4ad6b..eff9cf71 100644 --- a/smtpd/lka.c +++ b/smtpd/lka.c @@ -18,6 +18,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -31,6 +33,8 @@ #include <err.h> #include <errno.h> #include <event.h> +#include <netdb.h> +#include <grp.h> /* needed for setgroups */ #include <imsg.h> #include <openssl/err.h> #include <openssl/ssl.h> diff --git a/smtpd/lka_filter.c b/smtpd/lka_filter.c index a10d9cbe..6ac692fc 100644 --- a/smtpd/lka_filter.c +++ b/smtpd/lka_filter.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/lka_proc.c b/smtpd/lka_proc.c index fb3a4137..eafebbec 100644 --- a/smtpd/lka_proc.c +++ b/smtpd/lka_proc.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/lka_report.c b/smtpd/lka_report.c index aff14ad3..cf43d51a 100644 --- a/smtpd/lka_report.c +++ b/smtpd/lka_report.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/lka_session.c b/smtpd/lka_session.c index ed17adcb..bbb06de7 100644 --- a/smtpd/lka_session.c +++ b/smtpd/lka_session.c @@ -17,6 +17,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -520,7 +522,7 @@ lka_submit(struct lka_session *lks, struct rule *rule, struct expandnode *xn) "run with %s privileges", SMTPD_USER); if (xn->type == EXPAND_FILENAME) - format = "/usr/libexec/mail.mboxfile -f %%{mbox.from} %s"; + format = PATH_LIBEXEC"/mail.mboxfile -f %%{mbox.from} %s"; else if (xn->type == EXPAND_FILTER) format = "%s"; (void)snprintf(ep->mda_exec, sizeof(ep->mda_exec), diff --git a/smtpd/log.c b/smtpd/log.c index 7ec8ca42..14f681e3 100644 --- a/smtpd/log.c +++ b/smtpd/log.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <stdio.h> #include <stdlib.h> #include <stdarg.h> diff --git a/smtpd/log.h b/smtpd/log.h index 22bb4164..81d0973c 100644 --- a/smtpd/log.h +++ b/smtpd/log.h @@ -19,8 +19,14 @@ #ifndef LOG_H #define LOG_H +#include "openbsd-compat.h" + +#include <syslog.h> + #include <stdarg.h> +#ifdef HAVE_SYS_CDEFS_H #include <sys/cdefs.h> +#endif void log_init(int, int); void log_procinit(const char *); diff --git a/smtpd/mail.lmtp.c b/smtpd/mail.lmtp.c index 6f35f7f0..e6e4fa14 100644 --- a/smtpd/mail.lmtp.c +++ b/smtpd/mail.lmtp.c @@ -14,6 +14,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> diff --git a/smtpd/mail.maildir.c b/smtpd/mail.maildir.c index e1796e0e..637d3f72 100644 --- a/smtpd/mail.maildir.c +++ b/smtpd/mail.maildir.c @@ -14,6 +14,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif diff --git a/smtpd/mail.mboxfile.c b/smtpd/mail.mboxfile.c index 6dbcc058..bf6951d8 100644 --- a/smtpd/mail.mboxfile.c +++ b/smtpd/mail.mboxfile.c @@ -14,6 +14,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/stat.h> @@ -26,6 +28,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <time.h> #include <unistd.h> static void mboxfile_engine(const char *sender, const char *filename); @@ -71,7 +74,13 @@ mboxfile_engine(const char *sender, const char *filename) time(&now); +#ifndef O_EXLOCK +#define O_EXLOCK 0 +#endif fd = open(filename, O_CREAT | O_APPEND | O_WRONLY | O_EXLOCK, 0600); +#ifndef HAVE_O_EXLOCK + /* XXX : do something! */ +#endif if (fd < 0) err(1, NULL); diff --git a/smtpd/mail.mda.c b/smtpd/mail.mda.c index f9fb3236..23958071 100644 --- a/smtpd/mail.mda.c +++ b/smtpd/mail.mda.c @@ -14,6 +14,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/stat.h> #include <sys/wait.h> diff --git a/smtpd/mailaddr.c b/smtpd/mailaddr.c index a15470d7..4346e3dc 100644 --- a/smtpd/mailaddr.c +++ b/smtpd/mailaddr.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/makemap.c b/smtpd/makemap.c index dd8bc8d3..274833e9 100644 --- a/smtpd/makemap.c +++ b/smtpd/makemap.c @@ -17,6 +17,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + +#ifdef HAVE_SYS_FILE_H +#include <sys/file.h> /* Needed for flock */ +#endif #include <sys/types.h> #include <sys/stat.h> #include <sys/tree.h> @@ -24,7 +29,13 @@ #include <sys/socket.h> #include <ctype.h> +#ifdef HAVE_DB_H #include <db.h> +#elif defined(HAVE_DB1_DB_H) +#include <db1/db.h> +#elif defined(HAVE_DB_185_H) +#include <db_185.h> +#endif #include <err.h> #include <errno.h> #include <event.h> @@ -36,12 +47,17 @@ #include <syslog.h> #include <unistd.h> #include <limits.h> +#ifdef HAVE_UTIL_H #include <util.h> +#endif +#ifdef HAVE_LIBUTIL_H +#include <libutil.h> +#endif #include "smtpd.h" #include "log.h" -#define PATH_ALIASES "/etc/mail/aliases" +#define PATH_ALIASES SMTPD_CONFDIR "/aliases" static void usage(void); static int parse_map(DB *, int *, char *); diff --git a/smtpd/mda.c b/smtpd/mda.c index 348192fc..97b60631 100644 --- a/smtpd/mda.c +++ b/smtpd/mda.c @@ -19,6 +19,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -28,6 +30,7 @@ #include <err.h> #include <errno.h> #include <event.h> +#include <grp.h> /* needed for setgroups */ #include <imsg.h> #include <inttypes.h> #include <pwd.h> @@ -39,7 +42,11 @@ #include <time.h> #include <unistd.h> #include <limits.h> +#if defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS) #include <vis.h> +#else +#include "bsd-vis.h" +#endif #include "smtpd.h" #include "log.h" @@ -520,7 +527,7 @@ mda_getlastline(int fd, char *dst, size_t dstsz) size_t sz = 0; ssize_t len; int out = 0; - + if (lseek(fd, 0, SEEK_SET) < 0) { log_warn("warn: mda: lseek"); close(fd); diff --git a/smtpd/mda_unpriv.c b/smtpd/mda_unpriv.c index 23754070..ee54e101 100644 --- a/smtpd/mda_unpriv.c +++ b/smtpd/mda_unpriv.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/mda_variables.c b/smtpd/mda_variables.c index 03052e21..df453477 100644 --- a/smtpd/mda_variables.c +++ b/smtpd/mda_variables.c @@ -17,6 +17,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/mproc.c b/smtpd/mproc.c index d5a934d4..e1bf324f 100644 --- a/smtpd/mproc.c +++ b/smtpd/mproc.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/socket.h> #include <sys/tree.h> @@ -60,8 +62,7 @@ mproc_fork(struct mproc *p, const char *path, char *argv[]) if (p->pid == 0) { /* child process */ dup2(sp[0], STDIN_FILENO); - if (closefrom(STDERR_FILENO + 1) < 0) - exit(1); + closefrom(STDERR_FILENO + 1); execv(path, argv); err(1, "execv: %s", path); @@ -484,8 +485,8 @@ m_add_msgid(struct mproc *m, uint32_t v) void m_add_sockaddr(struct mproc *m, const struct sockaddr *sa) { - m_add_size(m, sa->sa_len); - m_add(m, sa, sa->sa_len); + m_add_size(m, SA_LEN(sa)); + m_add(m, sa, SA_LEN(sa)); } void diff --git a/smtpd/mta.c b/smtpd/mta.c index 6958384a..ec1be548 100644 --- a/smtpd/mta.c +++ b/smtpd/mta.c @@ -19,6 +19,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -31,6 +33,7 @@ #include <imsg.h> #include <inttypes.h> #include <netdb.h> +#include <grp.h> /* needed for setgroups */ #include <limits.h> #include <pwd.h> #include <signal.h> @@ -2085,13 +2088,13 @@ mta_host(const struct sockaddr *sa) struct mta_host key, *h; struct sockaddr_storage ss; - memmove(&ss, sa, sa->sa_len); + memmove(&ss, sa, SA_LEN(sa)); key.sa = (struct sockaddr*)&ss; h = SPLAY_FIND(mta_host_tree, &hosts, &key); if (h == NULL) { h = xcalloc(1, sizeof(*h)); - h->sa = xmemdup(sa, sa->sa_len); + h->sa = xmemdup(sa, SA_LEN(sa)); SPLAY_INSERT(mta_host_tree, &hosts, h); stat_increment("mta.host", 1); } @@ -2136,11 +2139,11 @@ mta_host_to_text(struct mta_host *h) static int mta_host_cmp(const struct mta_host *a, const struct mta_host *b) { - if (a->sa->sa_len < b->sa->sa_len) + if (SA_LEN(a->sa) < SA_LEN(b->sa)) return (-1); - if (a->sa->sa_len > b->sa->sa_len) + if (SA_LEN(a->sa) > SA_LEN(b->sa)) return (1); - return (memcmp(a->sa, b->sa, a->sa->sa_len)); + return (memcmp(a->sa, b->sa, SA_LEN(a->sa))); } SPLAY_GENERATE(mta_host_tree, mta_host, entry, mta_host_cmp); @@ -2214,7 +2217,7 @@ mta_source(const struct sockaddr *sa) struct sockaddr_storage ss; if (sa) { - memmove(&ss, sa, sa->sa_len); + memmove(&ss, sa, SA_LEN(sa)); key.sa = (struct sockaddr*)&ss; } else key.sa = NULL; @@ -2223,7 +2226,7 @@ mta_source(const struct sockaddr *sa) if (s == NULL) { s = xcalloc(1, sizeof(*s)); if (sa) - s->sa = xmemdup(sa, sa->sa_len); + s->sa = xmemdup(sa, SA_LEN(sa)); SPLAY_INSERT(mta_source_tree, &sources, s); stat_increment("mta.source", 1); } @@ -2268,11 +2271,11 @@ mta_source_cmp(const struct mta_source *a, const struct mta_source *b) return ((b->sa == NULL) ? 0 : -1); if (b->sa == NULL) return (1); - if (a->sa->sa_len < b->sa->sa_len) + if (SA_LEN(a->sa) < SA_LEN(b->sa)) return (-1); - if (a->sa->sa_len > b->sa->sa_len) + if (SA_LEN(a->sa) > SA_LEN(b->sa)) return (1); - return (memcmp(a->sa, b->sa, a->sa->sa_len)); + return (memcmp(a->sa, b->sa, SA_LEN(a->sa))); } SPLAY_GENERATE(mta_source_tree, mta_source, entry, mta_source_cmp); diff --git a/smtpd/mta_session.c b/smtpd/mta_session.c index 959b45e8..628b0ed1 100644 --- a/smtpd/mta_session.c +++ b/smtpd/mta_session.c @@ -19,6 +19,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -473,7 +475,7 @@ mta_connect(struct mta_session *s) if (s->relay->port) portno = s->relay->port; - memmove(&ss, s->route->dst->sa, s->route->dst->sa->sa_len); + memmove(&ss, s->route->dst->sa, SA_LEN(s->route->dst->sa)); sa = (struct sockaddr *)&ss; if (sa->sa_family == AF_INET) diff --git a/smtpd/parse.y b/smtpd/parse.y index 88f2c0b5..8f331315 100644 --- a/smtpd/parse.y +++ b/smtpd/parse.y @@ -22,7 +22,10 @@ */ %{ +#include "includes.h" + #include <sys/types.h> +#include <sys/time.h> #include <sys/queue.h> #include <sys/tree.h> #include <sys/socket.h> @@ -43,13 +46,16 @@ #include <limits.h> #include <netdb.h> #include <pwd.h> +#include <stdarg.h> #include <resolv.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <syslog.h> #include <unistd.h> +#ifdef HAVE_UTIL_H #include <util.h> +#endif #include <openssl/ssl.h> @@ -638,41 +644,41 @@ dispatcher_local: MBOX { dispatcher->u.local.requires_root = 1; dispatcher->u.local.user = xstrdup("root"); - asprintf(&dispatcher->u.local.command, "/usr/libexec/mail.local -f %%{mbox.from} %%{user.username}"); + asprintf(&dispatcher->u.local.command, PATH_LIBEXEC"/mail.local -f %%{mbox.from} %%{user.username}"); } dispatcher_local_options | MAILDIR { - asprintf(&dispatcher->u.local.command, "/usr/libexec/mail.maildir"); + asprintf(&dispatcher->u.local.command, PATH_LIBEXEC"/mail.maildir"); } dispatcher_local_options | MAILDIR JUNK { - asprintf(&dispatcher->u.local.command, "/usr/libexec/mail.maildir -j"); + asprintf(&dispatcher->u.local.command, PATH_LIBEXEC"/mail.maildir -j"); } dispatcher_local_options | MAILDIR STRING { if (strncmp($2, "~/", 2) == 0) asprintf(&dispatcher->u.local.command, - "/usr/libexec/mail.maildir \"%%{user.directory}/%s\"", $2+2); + PATH_LIBEXEC"/mail.maildir \"%%{user.directory}/%s\"", $2+2); else asprintf(&dispatcher->u.local.command, - "/usr/libexec/mail.maildir \"%s\"", $2); + PATH_LIBEXEC"/mail.maildir \"%s\"", $2); } dispatcher_local_options | MAILDIR STRING JUNK { if (strncmp($2, "~/", 2) == 0) asprintf(&dispatcher->u.local.command, - "/usr/libexec/mail.maildir -j \"%%{user.directory}/%s\"", $2+2); + PATH_LIBEXEC"/mail.maildir -j \"%%{user.directory}/%s\"", $2+2); else asprintf(&dispatcher->u.local.command, - "/usr/libexec/mail.maildir -j \"%s\"", $2); + PATH_LIBEXEC"/mail.maildir -j \"%s\"", $2); } dispatcher_local_options | LMTP STRING { asprintf(&dispatcher->u.local.command, - "/usr/libexec/mail.lmtp -f %%{mbox.from} -d %s %%{user.username}", $2); + PATH_LIBEXEC"/mail.lmtp -f %%{mbox.from} -d %s %%{user.username}", $2); } dispatcher_local_options | LMTP STRING RCPT_TO { asprintf(&dispatcher->u.local.command, - "/usr/libexec/mail.lmtp -f %%{mbox.from} -d %s %%{dest}", $2); + PATH_LIBEXEC"/mail.lmtp -f %%{mbox.from} -d %s %%{dest}", $2); } dispatcher_local_options | MDA STRING { asprintf(&dispatcher->u.local.command, - "/usr/libexec/mail.mda \"%s\"", $2); + PATH_LIBEXEC"/mail.mda \"%s\"", $2); } dispatcher_local_options | FORWARD_ONLY { dispatcher->u.local.forward_only = 1; @@ -2822,7 +2828,9 @@ create_sock_listener(struct listen_opts *lo) lo->tag = "local"; lo->hostname = conf->sc_hostname; l->ss.ss_family = AF_LOCAL; +#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN l->ss.ss_len = sizeof(struct sockaddr *); +#endif l->local = 1; conf->sc_sock_listener = l; config_listener(l, lo); @@ -2954,7 +2962,9 @@ host_v4(struct listen_opts *lo) h = xcalloc(1, sizeof(*h)); sain = (struct sockaddr_in *)&h->ss; +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sain->sin_len = sizeof(struct sockaddr_in); +#endif sain->sin_family = AF_INET; sain->sin_addr.s_addr = ina.s_addr; sain->sin_port = lo->port; @@ -2982,7 +2992,9 @@ host_v6(struct listen_opts *lo) h = xcalloc(1, sizeof(*h)); sin6 = (struct sockaddr_in6 *)&h->ss; +#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN sin6->sin6_len = sizeof(struct sockaddr_in6); +#endif sin6->sin6_family = AF_INET6; sin6->sin6_port = lo->port; memcpy(&sin6->sin6_addr, &ina6, sizeof(ina6)); @@ -3025,7 +3037,9 @@ host_dns(struct listen_opts *lo) h->ss.ss_family = res->ai_family; if (res->ai_family == AF_INET) { sain = (struct sockaddr_in *)&h->ss; +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sain->sin_len = sizeof(struct sockaddr_in); +#endif sain->sin_addr.s_addr = ((struct sockaddr_in *) res->ai_addr)->sin_addr.s_addr; sain->sin_port = lo->port; @@ -3033,7 +3047,9 @@ host_dns(struct listen_opts *lo) h->local = 1; } else { sin6 = (struct sockaddr_in6 *)&h->ss; +#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN sin6->sin6_len = sizeof(struct sockaddr_in6); +#endif memcpy(&sin6->sin6_addr, &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr, sizeof(struct in6_addr)); sin6->sin6_port = lo->port; @@ -3077,7 +3093,9 @@ interface(struct listen_opts *lo) case AF_INET: sain = (struct sockaddr_in *)&h->ss; *sain = *(struct sockaddr_in *)p->ifa_addr; +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sain->sin_len = sizeof(struct sockaddr_in); +#endif sain->sin_port = lo->port; if (sain->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) h->local = 1; @@ -3086,7 +3104,9 @@ interface(struct listen_opts *lo) case AF_INET6: sin6 = (struct sockaddr_in6 *)&h->ss; *sin6 = *(struct sockaddr_in6 *)p->ifa_addr; +#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN sin6->sin6_len = sizeof(struct sockaddr_in6); +#endif sin6->sin6_port = lo->port; if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) h->local = 1; @@ -3155,6 +3175,7 @@ bad: int is_if_in_group(const char *ifname, const char *groupname) { +#ifdef HAVE_STRUCT_IFGROUPREQ unsigned int len; struct ifgroupreq ifgr; struct ifg_req *ifg; @@ -3193,6 +3214,9 @@ is_if_in_group(const char *ifname, const char *groupname) end: close(s); return ret; +#else + return (0); +#endif } static int diff --git a/smtpd/parser.c b/smtpd/parser.c index df90e508..997e3405 100644 --- a/smtpd/parser.c +++ b/smtpd/parser.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/socket.h> @@ -281,7 +283,9 @@ text_to_sockaddr(struct sockaddr *sa, int family, const char *str) in = (struct sockaddr_in *)sa; memset(in, 0, sizeof *in); +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN in->sin_len = sizeof(struct sockaddr_in); +#endif in->sin_family = PF_INET; in->sin_addr.s_addr = ina.s_addr; return (0); @@ -304,7 +308,9 @@ text_to_sockaddr(struct sockaddr *sa, int family, const char *str) in6 = (struct sockaddr_in6 *)sa; memset(in6, 0, sizeof *in6); +#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN in6->sin6_len = sizeof(struct sockaddr_in6); +#endif in6->sin6_family = PF_INET6; in6->sin6_addr = in6a; @@ -313,7 +319,7 @@ text_to_sockaddr(struct sockaddr *sa, int family, const char *str) if (IN6_IS_ADDR_LINKLOCAL(&in6a) || IN6_IS_ADDR_MC_LINKLOCAL(&in6a) || - IN6_IS_ADDR_MC_INTFACELOCAL(&in6a)) + IN6_IS_ADDR_MC_NODELOCAL(&in6a)) if ((in6->sin6_scope_id = if_nametoindex(cp))) return (0); diff --git a/smtpd/pony.c b/smtpd/pony.c index aeb7a522..238f0244 100644 --- a/smtpd/pony.c +++ b/smtpd/pony.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/queue.c b/smtpd/queue.c index 8380c7b5..e372d748 100644 --- a/smtpd/queue.c +++ b/smtpd/queue.c @@ -18,6 +18,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -26,6 +28,8 @@ #include <err.h> #include <event.h> +#include <fcntl.h> +#include <grp.h> /* needed for setgroups */ #include <imsg.h> #include <inttypes.h> #include <pwd.h> diff --git a/smtpd/queue_backend.c b/smtpd/queue_backend.c index 5e7c38fa..6fc720da 100644 --- a/smtpd/queue_backend.c +++ b/smtpd/queue_backend.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/queue_fs.c b/smtpd/queue_fs.c index ecbc53a8..88dde90b 100644 --- a/smtpd/queue_fs.c +++ b/smtpd/queue_fs.c @@ -16,12 +16,19 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> +#if HAVE_SYS_MOUNT_H #include <sys/mount.h> +#endif #include <sys/queue.h> #include <sys/tree.h> #include <sys/socket.h> #include <sys/stat.h> +#ifdef HAVE_SYS_STATFS_H +#include <sys/statfs.h> +#endif #include <ctype.h> #include <dirent.h> @@ -340,8 +347,10 @@ queue_fs_message_walk(uint64_t *evpid, char *buf, size_t len, (void)snprintf(msgid_str, sizeof msgid_str, "%08" PRIx32, msgid); while ((dp = readdir(dir)) != NULL) { +#if defined(HAVE_STRUCT_DIR_D_TYPE) if (dp->d_type != DT_REG) continue; +#endif /* ignore files other than envelopes */ if (strlen(dp->d_name) != 16 || @@ -410,6 +419,7 @@ queue_fs_envelope_walk(uint64_t *evpid, char *buf, size_t len) static int fsqueue_check_space(void) { +#ifdef __OpenBSD__ struct statfs buf; uint64_t used; uint64_t total; @@ -453,7 +463,7 @@ fsqueue_check_space(void) log_warnx("warn: temporarily rejecting messages"); return 0; } - +#endif return 1; } @@ -616,7 +626,12 @@ fsqueue_qwalk(void *hdl, uint64_t *evpid) break; if (e->fts_namelen != 16) break; +#if HAVE_STRUCT_STAT_ST_MTIM if (timespeccmp(&e->fts_statp->st_mtim, &startup, >)) +#endif +#if HAVE_STRUCT_STAT_ST_MTIMSPEC + if (timespeccmp(&e->fts_statp->st_mtimspec, &startup, >)) +#endif break; tmp = NULL; *evpid = strtoull(e->fts_name, &tmp, 16); diff --git a/smtpd/queue_null.c b/smtpd/queue_null.c index d92f98a7..1e608be8 100644 --- a/smtpd/queue_null.c +++ b/smtpd/queue_null.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/queue_proc.c b/smtpd/queue_proc.c index 753271c1..d6e0f409 100644 --- a/smtpd/queue_proc.c +++ b/smtpd/queue_proc.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/queue_ram.c b/smtpd/queue_ram.c index 56b9fa5b..50ce17e1 100644 --- a/smtpd/queue_ram.c +++ b/smtpd/queue_ram.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/report_smtp.c b/smtpd/report_smtp.c index a4268909..81e9584c 100644 --- a/smtpd/report_smtp.c +++ b/smtpd/report_smtp.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -36,7 +38,11 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#if defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS) #include <vis.h> +#else +#include "bsd-vis.h" +#endif #include "smtpd.h" #include "log.h" diff --git a/smtpd/resolver.c b/smtpd/resolver.c index 54221416..aeb4e6bb 100644 --- a/smtpd/resolver.c +++ b/smtpd/resolver.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/socket.h> #include <sys/tree.h> @@ -186,7 +188,7 @@ resolver_dispatch_request(struct mproc *proc, struct imsg *imsg) if ((s = calloc(1, sizeof(*s))) && (s->host = malloc(NI_MAXHOST)) && (s->serv = malloc(NI_MAXSERV)) && - (q = getnameinfo_async(sa, sa->sa_len, s->host, NI_MAXHOST, + (q = getnameinfo_async(sa, SA_LEN(sa), s->host, NI_MAXHOST, s->serv, NI_MAXSERV, flags, NULL)) && (event_asr_run(q, resolver_getnameinfo_cb, s))) { s->reqid = reqid; @@ -249,14 +251,14 @@ resolver_dispatch_result(struct mproc *proc, struct imsg *imsg) m_get_string(&m, &cname); m_end(&m); - ai->ai_addr = malloc(ss.ss_len); + ai->ai_addr = malloc(SS_LEN(&ss)); if (ai->ai_addr == NULL) { log_warn("%s: malloc", __func__); free(ai); break; } - memmove(ai->ai_addr, &ss, ss.ss_len); + memmove(ai->ai_addr, &ss, SS_LEN(&ss)); if (cname) { ai->ai_canonname = strdup(cname); diff --git a/smtpd/rfc5322.c b/smtpd/rfc5322.c index 02ea7976..0af66772 100644 --- a/smtpd/rfc5322.c +++ b/smtpd/rfc5322.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <ctype.h> #include <errno.h> #include <limits.h> diff --git a/smtpd/ruleset.c b/smtpd/ruleset.c index 237feae1..09259c2a 100644 --- a/smtpd/ruleset.c +++ b/smtpd/ruleset.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/runq.c b/smtpd/runq.c index ce8c67ef..29b909ae 100644 --- a/smtpd/runq.c +++ b/smtpd/runq.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/socket.h> #include <sys/queue.h> diff --git a/smtpd/scheduler.c b/smtpd/scheduler.c index b3bda175..bf81aa46 100644 --- a/smtpd/scheduler.c +++ b/smtpd/scheduler.c @@ -19,6 +19,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -30,6 +32,7 @@ #include <err.h> #include <errno.h> #include <event.h> +#include <grp.h> /* needed for setgroups */ #include <imsg.h> #include <inttypes.h> #include <pwd.h> diff --git a/smtpd/scheduler_backend.c b/smtpd/scheduler_backend.c index 061f1129..ad2b4cab 100644 --- a/smtpd/scheduler_backend.c +++ b/smtpd/scheduler_backend.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/scheduler_null.c b/smtpd/scheduler_null.c index a8c43331..40db6205 100644 --- a/smtpd/scheduler_null.c +++ b/smtpd/scheduler_null.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/scheduler_proc.c b/smtpd/scheduler_proc.c index 0f8c44b9..5f4e8b70 100644 --- a/smtpd/scheduler_proc.c +++ b/smtpd/scheduler_proc.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/scheduler_ramqueue.c b/smtpd/scheduler_ramqueue.c index 8d5efc10..0c04fc0b 100644 --- a/smtpd/scheduler_ramqueue.c +++ b/smtpd/scheduler_ramqueue.c @@ -17,6 +17,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/smtp.c b/smtpd/smtp.c index 921d9f8a..a0ab898b 100644 --- a/smtpd/smtp.c +++ b/smtpd/smtp.c @@ -18,6 +18,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -26,6 +28,7 @@ #include <err.h> #include <errno.h> #include <event.h> +#include <grp.h> /* needed for setgroups */ #include <imsg.h> #include <netdb.h> #include <pwd.h> @@ -55,6 +58,8 @@ static void smtp_accepted(struct listener *, int, const struct sockaddr_storage #define SMTP_FD_RESERVE 5 +#define getdtablecount() 0 + static size_t sessions; static size_t maxsessions; @@ -137,10 +142,26 @@ smtp_setup_listeners(void) fatal("smtpd: socket"); } opt = 1; +#ifdef SO_REUSEADDR if (setsockopt(l->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) fatal("smtpd: setsockopt"); - if (bind(l->fd, (struct sockaddr *)&l->ss, l->ss.ss_len) == -1) +#else + if (setsockopt(l->fd, SOL_SOCKET, SO_REUSEPORT, &opt, + sizeof(opt)) < 0) + fatal("smtpd: setsockopt"); +#endif +#ifdef IPV6_V6ONLY + /* + * If using IPv6, bind only to IPv6 if possible. + * This avoids ambiguities with IPv4-mapped IPv6 addresses. + */ + if (l->ss.ss_family == AF_INET6) + if (setsockopt(l->fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, + sizeof(opt)) < 0) + fatal("smtpd: setsockopt"); +#endif + if (bind(l->fd, (struct sockaddr *)&l->ss, SS_LEN(&l->ss)) == -1) fatal("smtpd: bind"); } } diff --git a/smtpd/smtp_session.c b/smtpd/smtp_session.c index 1fc67d77..5fc2c796 100644 --- a/smtpd/smtp_session.c +++ b/smtpd/smtp_session.c @@ -19,6 +19,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -39,7 +41,11 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#if defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS) #include <vis.h> +#else +#include "bsd-vis.h" +#endif #include "smtpd.h" #include "log.h" diff --git a/smtpd/smtpctl.c b/smtpd/smtpctl.c index 4b44d9dd..42c018b9 100644 --- a/smtpd/smtpctl.c +++ b/smtpd/smtpctl.c @@ -21,6 +21,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/socket.h> #include <sys/queue.h> @@ -29,6 +31,12 @@ #include <sys/wait.h> #include <sys/stat.h> +#include <net/if.h> +/* #include <net/if_media.h> */ +/* #include <net/if_types.h> */ +#include <netinet/in.h> +#include <arpa/inet.h> + #include <err.h> #include <errno.h> #include <event.h> @@ -42,17 +50,30 @@ #include <syslog.h> #include <time.h> #include <unistd.h> +#if defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS) #include <vis.h> +#else +#include "bsd-vis.h" +#endif #include <limits.h> #include "smtpd.h" #include "parser.h" #include "log.h" +#ifndef PATH_GZCAT #define PATH_GZCAT "/usr/bin/gzcat" +#endif #define PATH_CAT "/bin/cat" #define PATH_QUEUE "/queue" +#ifndef PATH_ENCRYPT #define PATH_ENCRYPT "/usr/bin/encrypt" +#endif + +#ifndef HAVE_DB_API +#define makemap(x, y, z) 1 +#endif + int srv_connect(void); int srv_connected(void); @@ -1043,6 +1064,8 @@ main(int argc, char **argv) int privileged; char *argv_mailq[] = { "show", "queue", NULL }; + __progname = ssh_get_progname(argv[0]); + sendmail_compat(argc, argv); privileged = geteuid() == 0; diff --git a/smtpd/smtpd-defines.h b/smtpd/smtpd-defines.h index 3b9038cd..c5202e34 100644 --- a/smtpd/smtpd-defines.h +++ b/smtpd/smtpd-defines.h @@ -32,11 +32,21 @@ #define SMTPD_VUSERNAME_SIZE (255 + 1) #define SMTPD_SUBADDRESS_SIZE (255 + 1) +#ifndef SMTPD_USER #define SMTPD_USER "_smtpd" +#endif +#ifndef PATH_CHROOT #define PATH_CHROOT "/var/empty" +#endif +#ifndef SMTPD_QUEUE_USER #define SMTPD_QUEUE_USER "_smtpq" +#endif +#ifndef SMTPD_QUEUE_GROUP #define SMTPD_QUEUE_GROUP "_smtpq" +#endif +#ifndef PATH_SPOOL #define PATH_SPOOL "/var/spool/smtpd" +#endif #define SUBADDRESSING_DELIMITER "+" diff --git a/smtpd/smtpd.c b/smtpd/smtpd.c index 66022264..1052ca52 100644 --- a/smtpd/smtpd.c +++ b/smtpd/smtpd.c @@ -18,6 +18,9 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + +#include <sys/file.h> /* Needed for flock */ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -27,21 +30,44 @@ #include <sys/uio.h> #include <sys/mman.h> +#ifdef BSD_AUTH #include <bsd_auth.h> +#endif + +#ifdef USE_PAM +#if defined(HAVE_SECURITY_PAM_APPL_H) +#include <security/pam_appl.h> +#elif defined (HAVE_PAM_PAM_APPL_H) +#include <pam/pam_appl.h> +#endif +#endif + +#ifdef HAVE_CRYPT_H +#include <crypt.h> /* needed for crypt() */ +#endif #include <dirent.h> #include <err.h> #include <errno.h> #include <event.h> #include <fcntl.h> +#include <grp.h> /* needed for setgroups */ #include <fts.h> #include <grp.h> #include <imsg.h> #include <inttypes.h> +#include <libgen.h> +#ifdef HAVE_LOGIN_CAP_H #include <login_cap.h> +#endif +#ifdef HAVE_PATHS_H #include <paths.h> +#endif #include <poll.h> #include <pwd.h> #include <signal.h> +#ifdef HAVE_SHADOW_H +#include <shadow.h> /* needed for getspnam() */ +#endif #include <stdio.h> #include <syslog.h> #include <limits.h> @@ -50,6 +76,9 @@ #include <sysexits.h> #include <time.h> #include <unistd.h> +#ifdef HAVE_UTIL_H +#include <util.h> +#endif #include <openssl/ssl.h> #include <openssl/evp.h> @@ -58,6 +87,8 @@ #include "log.h" #include "ssl.h" +extern char *__progname; + #define SMTPD_MAXARG 32 static void parent_imsg(struct mproc *, struct imsg *); @@ -152,6 +183,10 @@ int control_socket = -1; struct tree children; +/* Saved arguments to main(). */ +char **saved_argv; +int saved_argc; + static void parent_imsg(struct mproc *p, struct imsg *imsg) { @@ -470,6 +505,25 @@ main(int argc, char *argv[]) char *rexec = NULL; struct smtpd *conf; + __progname = ssh_get_progname(argv[0]); + + /* Save argv. Duplicate so setproctitle emulation doesn't clobber it */ + saved_argc = argc; + saved_argv = __xcalloc(argc + 1, sizeof(*saved_argv)); + for (i = 0; i < argc; i++) + saved_argv[i] = __xstrdup(argv[i]); + saved_argv[i] = NULL; + +#ifndef HAVE_SETPROCTITLE + /* Prepare for later setproctitle emulation */ + compat_init_setproctitle(argc, argv); + argv = saved_argv; +#endif + + /* this is to work around GNU getopt + portable setproctitle() fuckery */ + save_argc = saved_argc; + save_argv = saved_argv; + if ((conf = config_default()) == NULL) err(1, NULL); @@ -600,6 +654,8 @@ main(int argc, char *argv[]) if (parse_config(conf, conffile, opts)) exit(1); + seed_rng(); + if (strlcpy(env->sc_conffile, conffile, PATH_MAX) >= PATH_MAX) errx(1, "config file exceeds PATH_MAX"); @@ -830,8 +886,7 @@ start_child(int save_argc, char **save_argv, char *rexec) if (dup2(sp[0], 3) == -1) fatal("%s: dup2", rexec); - if (closefrom(4) == -1) - fatal("%s: closefrom", rexec); + xclosefrom(4); for (argc = 0; argc < save_argc; argc++) argv[argc] = save_argv[argc]; @@ -1064,6 +1119,9 @@ smtpd(void) { offline_timeout.tv_usec = 0; evtimer_add(&offline_ev, &offline_timeout); + if (pidfile(NULL) < 0) + err(1, "pidfile"); + fork_processors(); purge_task(); @@ -1164,8 +1222,7 @@ fork_proc_backend(const char *key, const char *conf, const char *procname) if (pid == 0) { /* child process */ dup2(sp[0], STDIN_FILENO); - if (closefrom(STDERR_FILENO + 1) < 0) - exit(1); + closefrom(STDERR_FILENO + 1); if (procname == NULL) procname = name; @@ -1305,8 +1362,8 @@ fork_processor(const char *name, const char *command, const char *user, const ch setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) err(1, "fork_processor: cannot drop privileges"); - if (closefrom(STDERR_FILENO + 1) < 0) - err(1, "closefrom"); + xclosefrom(STDERR_FILENO + 1); + if (setsid() < 0) err(1, "setsid"); if (signal(SIGPIPE, SIG_DFL) == SIG_ERR || @@ -1451,8 +1508,7 @@ forkmda(struct mproc *p, uint64_t id, struct deliver *deliver) dup2(allout, STDOUT_FILENO) < 0 || dup2(allout, STDERR_FILENO) < 0) err(1, "forkmda: dup2"); - if (closefrom(STDERR_FILENO + 1) < 0) - err(1, "closefrom"); + closefrom(STDERR_FILENO + 1); if (setsid() < 0) err(1, "setsid"); if (signal(SIGPIPE, SIG_DFL) == SIG_ERR || @@ -1563,8 +1619,7 @@ offline_enqueue(char *name) ssize_t len; arglist args; - if (closefrom(STDERR_FILENO + 1) == -1) - _exit(1); + closefrom(STDERR_FILENO + 1); memset(&args, 0, sizeof(args)); @@ -2027,8 +2082,9 @@ imsg_to_str(int type) } } +#ifdef BSD_AUTH int -parent_auth_user(const char *username, const char *password) +parent_auth_bsd(const char *username, const char *password) { char user[LOGIN_NAME_MAX]; char pass[LINE_MAX]; @@ -2042,3 +2098,121 @@ parent_auth_user(const char *username, const char *password) return LKA_OK; return LKA_PERMFAIL; } +#endif + +#ifdef USE_PAM +int +pam_conv_password(int num_msg, const struct pam_message **msg, + struct pam_response **respp, const char *password) +{ + struct pam_response *response; + + if (num_msg != 1) + return PAM_CONV_ERR; + + response = calloc(1, sizeof(struct pam_response)); + if (response == NULL || (response->resp = strdup(password)) == NULL) { + free(response); + return PAM_BUF_ERR; + } + + *respp = response; + return PAM_SUCCESS; +} +int +parent_auth_pam(const char *username, const char *password) +{ + int rc; + pam_handle_t *pamh = NULL; + struct pam_conv conv = { pam_conv_password, password }; + + if ((rc = pam_start(USE_PAM_SERVICE, username, &conv, &pamh)) != PAM_SUCCESS) + goto end; + if ((rc = pam_authenticate(pamh, 0)) != PAM_SUCCESS) + goto end; + if ((rc = pam_acct_mgmt(pamh, 0)) != PAM_SUCCESS) + goto end; + +end: + pam_end(pamh, rc); + + switch (rc) { + case PAM_SUCCESS: + return LKA_OK; + case PAM_SYSTEM_ERR: + case PAM_ABORT: + case PAM_AUTHINFO_UNAVAIL: + return LKA_TEMPFAIL; + default: + return LKA_PERMFAIL; + } +} +#endif + +#ifdef HAVE_GETSPNAM +int +parent_auth_getspnam(const char *username, const char *password) +{ + struct spwd *pw; + char *ep; + + errno = 0; + do { + pw = getspnam(username); + } while (pw == NULL && errno == EINTR); + + if (pw == NULL) { + if (errno) + return LKA_TEMPFAIL; + return LKA_PERMFAIL; + } + + if ((ep = crypt(password, pw->sp_pwdp)) == NULL) + return LKA_PERMFAIL; + + if (strcmp(pw->sp_pwdp, ep) == 0) + return LKA_OK; + + return LKA_PERMFAIL; +} +#endif + +int +parent_auth_pwd(const char *username, const char *password) +{ + struct passwd *pw; + char *ep; + + errno = 0; + do { + pw = getpwnam(username); + } while (pw == NULL && errno == EINTR); + + if (pw == NULL) { + if (errno) + return LKA_TEMPFAIL; + return LKA_PERMFAIL; + } + + if ((ep = crypt(password, pw->pw_passwd)) == NULL) + return LKA_PERMFAIL; + + if (strcmp(pw->pw_passwd, ep) == 0) + return LKA_OK; + + return LKA_PERMFAIL; +} + +int +parent_auth_user(const char *username, const char *password) +{ +#if defined(BSD_AUTH) + return (parent_auth_bsd(username, password)); +#elif defined(USE_PAM) + return (parent_auth_pam(username, password)); +#elif defined(HAVE_GETSPNAM) + return (parent_auth_getspnam(username, password)); +#else + return (parent_auth_pwd(username, password)); +#endif +} diff --git a/smtpd/smtpd.conf b/smtpd/smtpd.conf new file mode 100644 index 00000000..efecf2a6 --- /dev/null +++ b/smtpd/smtpd.conf @@ -0,0 +1,19 @@ +# $OpenBSD: smtpd.conf,v 1.10 2018/05/24 11:40:17 gilles Exp $ + +# This is the smtpd server system-wide configuration file. +# See smtpd.conf(5) for more information. + +table aliases file:/etc/mail/aliases + +# To accept external mail, replace with: listen on all +# +listen on localhost + +action "local" mbox alias <aliases> +action "relay" relay + +# Uncomment the following to accept external mail for domain "example.org" +# +# match from any for domain "example.org" action "local" +match for local action "local" +match from local for any action "relay" diff --git a/smtpd/smtpd.h b/smtpd/smtpd.h index 10420526..986bfeea 100644 --- a/smtpd/smtpd.h +++ b/smtpd/smtpd.h @@ -18,6 +18,12 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <event.h> + +#include <imsg.h> + +#include "openbsd-compat.h" + #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif @@ -37,9 +43,14 @@ (expected_sz), (imsg)->hdr.len - IMSG_HEADER_SIZE); \ } while (0) -#define CONF_FILE "/etc/mail/smtpd.conf" -#define MAILNAME_FILE "/etc/mail/mailname" -#define CA_FILE "/etc/ssl/cert.pem" +#ifndef SMTPD_CONFDIR +#define SMTPD_CONFDIR "/etc" +#endif +#define CONF_FILE SMTPD_CONFDIR "/smtpd.conf" +#define MAILNAME_FILE SMTPD_CONFDIR "/mailname" +#ifndef CA_FILE +#define CA_FILE "/etc/ssl/cert.pem" +#endif #define PROC_COUNT 7 @@ -49,19 +60,34 @@ #define EXPAND_BUFFER 1024 #define SMTPD_QUEUE_EXPIRY (4 * 24 * 60 * 60) -#define SMTPD_SOCKET "/var/run/smtpd.sock" +#ifndef SMTPD_USER +#define SMTPD_USER "_smtpd" +#endif +#ifndef SMTPD_QUEUE_USER +#define SMTPD_QUEUE_USER "_smtpq" +#endif +#ifndef SMTPD_SOCKDIR +#define SMTPD_SOCKDIR "/var/run" +#endif +#define SMTPD_SOCKET SMTPD_SOCKDIR "/smtpd.sock" +#ifndef SMTPD_NAME #define SMTPD_NAME "OpenSMTPD" -#define SMTPD_VERSION "6.4.0" +#endif +#define SMTPD_VERSION "6.4.0-portable" #define SMTPD_SESSION_TIMEOUT 300 #define SMTPD_BACKLOG 5 +#ifndef PATH_SMTPCTL #define PATH_SMTPCTL "/usr/sbin/smtpctl" +#endif #define PATH_OFFLINE "/offline" #define PATH_PURGE "/purge" #define PATH_TEMPORARY "/temporary" +#ifndef PATH_LIBEXEC #define PATH_LIBEXEC "/usr/local/libexec/smtpd" +#endif /* @@ -1688,7 +1714,7 @@ int session_socket_error(int); int getmailname(char *, size_t); int base64_encode(unsigned char const *, size_t, char *, size_t); int base64_decode(char const *, unsigned char *, size_t); - +void xclosefrom(int); void log_trace_verbose(int); void log_trace(int, const char *, ...) __attribute__((format (printf, 2, 3))); diff --git a/smtpd/spfwalk.c b/smtpd/spfwalk.c index 22b05796..8188c620 100644 --- a/smtpd/spfwalk.c +++ b/smtpd/spfwalk.c @@ -14,10 +14,15 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/socket.h> #include <sys/tree.h> +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +#include <arpa/nameser_compat.h> +#endif #include <arpa/inet.h> #include <arpa/nameser.h> #include <netinet/in.h> @@ -34,7 +39,6 @@ #include <strings.h> #include <unistd.h> -#define LINE_MAX 1024 #include "smtpd-defines.h" #include "smtpd-api.h" #include "unpack_dns.h" diff --git a/smtpd/ssl.c b/smtpd/ssl.c index 7cbee563..74932247 100644 --- a/smtpd/ssl.c +++ b/smtpd/ssl.c @@ -18,6 +18,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -85,7 +87,7 @@ ssl_setup(SSL_CTX **ctxp, struct pki *pki, if (sni_cb) SSL_CTX_set_tlsext_servername_callback(ctx, sni_cb); - SSL_CTX_set_dh_auto(ctx, pki->pki_dhe); + SSL_CTX_set_dh_auto(ctx, 0); SSL_CTX_set_ecdh_auto(ctx, 1); diff --git a/smtpd/ssl.h b/smtpd/ssl.h index dfa6994c..b7c8351f 100644 --- a/smtpd/ssl.h +++ b/smtpd/ssl.h @@ -65,3 +65,4 @@ int ssl_ctx_fake_private_key(SSL_CTX *, const void *, size_t, /* ssl_privsep.c */ int ssl_by_mem_ctrl(X509_LOOKUP *, int, const char *, long, char **); +int SSL_CTX_use_certificate_chain_mem(SSL_CTX *, void *, int); diff --git a/smtpd/ssl_smtpd.c b/smtpd/ssl_smtpd.c index 1f1e62d2..4e5b7e75 100644 --- a/smtpd/ssl_smtpd.c +++ b/smtpd/ssl_smtpd.c @@ -18,6 +18,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/stat_backend.c b/smtpd/stat_backend.c index 027f37a5..30cb299b 100644 --- a/smtpd/stat_backend.c +++ b/smtpd/stat_backend.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/socket.h> #include <sys/queue.h> diff --git a/smtpd/stat_ramstat.c b/smtpd/stat_ramstat.c index ede2e130..bbf1541a 100644 --- a/smtpd/stat_ramstat.c +++ b/smtpd/stat_ramstat.c @@ -15,6 +15,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" #include <sys/types.h> #include <sys/socket.h> diff --git a/smtpd/table.c b/smtpd/table.c index b79451ca..469eeee1 100644 --- a/smtpd/table.c +++ b/smtpd/table.c @@ -17,6 +17,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -43,7 +45,9 @@ struct table_backend *table_backend_lookup(const char *); extern struct table_backend table_backend_static; +#ifdef HAVE_DB_API extern struct table_backend table_backend_db; +#endif extern struct table_backend table_backend_getpwnam; extern struct table_backend table_backend_proc; @@ -56,7 +60,9 @@ static unsigned int last_table_id = 0; static struct table_backend *backends[] = { &table_backend_static, +#ifdef HAVE_DB_API &table_backend_db, +#endif &table_backend_getpwnam, &table_backend_proc, NULL @@ -395,7 +401,7 @@ table_netaddr_match(const char *s1, const char *s2) return 0; if (n1.ss.ss_family != n2.ss.ss_family) return 0; - if (n1.ss.ss_len != n2.ss.ss_len) + if (SS_LEN(&n1.ss) != SS_LEN(&n2.ss)) return 0; return table_match_mask(&n1.ss, &n2); } @@ -648,7 +654,9 @@ parse_sockaddr(struct sockaddr *sa, int family, const char *str) sin = (struct sockaddr_in *)sa; memset(sin, 0, sizeof *sin); +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sin->sin_len = sizeof(struct sockaddr_in); +#endif sin->sin_family = PF_INET; sin->sin_addr.s_addr = ina.s_addr; return (0); @@ -673,7 +681,9 @@ parse_sockaddr(struct sockaddr *sa, int family, const char *str) sin6 = (struct sockaddr_in6 *)sa; memset(sin6, 0, sizeof *sin6); +#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN sin6->sin6_len = sizeof(struct sockaddr_in6); +#endif sin6->sin6_family = PF_INET6; sin6->sin6_addr = in6a; @@ -682,7 +692,7 @@ parse_sockaddr(struct sockaddr *sa, int family, const char *str) if (IN6_IS_ADDR_LINKLOCAL(&in6a) || IN6_IS_ADDR_MC_LINKLOCAL(&in6a) || - IN6_IS_ADDR_MC_INTFACELOCAL(&in6a)) + IN6_IS_ADDR_MC_NODELOCAL(&in6a)) if ((sin6->sin6_scope_id = if_nametoindex(cp))) return (0); diff --git a/smtpd/table_db.c b/smtpd/table_db.c index 426d0f7c..d4e39e08 100644 --- a/smtpd/table_db.c +++ b/smtpd/table_db.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/stat.h> #include <sys/queue.h> @@ -24,8 +26,13 @@ #include <netinet/in.h> #include <arpa/inet.h> - +#ifdef HAVE_DB_H #include <db.h> +#elif defined(HAVE_DB1_DB_H) +#include <db1/db.h> +#elif defined(HAVE_DB_185_H) +#include <db_185.h> +#endif #include <ctype.h> #include <err.h> #include <event.h> diff --git a/smtpd/table_getpwnam.c b/smtpd/table_getpwnam.c index 78e6edc2..ccf889be 100644 --- a/smtpd/table_getpwnam.c +++ b/smtpd/table_getpwnam.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/table_proc.c b/smtpd/table_proc.c index 50592a74..3581cbd9 100644 --- a/smtpd/table_proc.c +++ b/smtpd/table_proc.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -26,7 +28,9 @@ #include <event.h> #include <fcntl.h> #include <imsg.h> +#ifdef HAVE_PATHS_H #include <paths.h> +#endif #include <stdio.h> #include <stdlib.h> #include <string.h> diff --git a/smtpd/table_static.c b/smtpd/table_static.c index f9519cb4..8f78ae11 100644 --- a/smtpd/table_static.c +++ b/smtpd/table_static.c @@ -17,6 +17,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -18,6 +18,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -56,12 +58,14 @@ static int alias_is_filename(struct expandnode *, const char *, size_t); static int alias_is_include(struct expandnode *, const char *, size_t); static int alias_is_error(struct expandnode *, const char *, size_t); +static int broken_inet_net_pton_ipv6(const char *, void *, size_t); + const char * sockaddr_to_text(struct sockaddr *sa) { static char buf[NI_MAXHOST]; - if (getnameinfo(sa, sa->sa_len, buf, sizeof(buf), NULL, 0, + if (getnameinfo(sa, SA_LEN(sa), buf, sizeof(buf), NULL, 0, NI_NUMERICHOST)) return ("(unknown)"); else @@ -75,7 +79,9 @@ in6addr_to_text(const struct in6_addr *addr) uint16_t tmp16; memset(&sa_in6, 0, sizeof(sa_in6)); +#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN sa_in6.sin6_len = sizeof(sa_in6); +#endif sa_in6.sin6_family = AF_INET6; memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr)); @@ -192,15 +198,20 @@ time_to_text(time_t when) char *day[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; char *month[] = {"Jan","Feb","Mar","Apr","May","Jun", "Jul","Aug","Sep","Oct","Nov","Dec"}; - char *tz; + const char *tz; long offset; lt = localtime(&when); if (lt == NULL || when == 0) fatalx("time_to_text: localtime"); +#if HAVE_STRUCT_TM_TM_GMTOFF offset = lt->tm_gmtoff; tz = lt->tm_zone; +#elif defined HAVE_DECL_ALTZONE && defined HAVE_DECL_TIMEZONE + offset = lt->tm_isdst > 0 ? altzone : timezone; + tz = lt->tm_isdst > 0 ? tzname[1] : tzname[0]; +#endif /* We do not use strftime because it is subject to locale substitution*/ if (!bsnprintf(buf, sizeof(buf), @@ -282,15 +293,25 @@ text_to_netaddr(struct netaddr *netaddr, const char *s) if (bits != -1) { ssin.sin_family = AF_INET; memcpy(&ss, &ssin, sizeof(ssin)); +#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN ss.ss_len = sizeof(struct sockaddr_in); +#endif } else { bits = inet_net_pton(AF_INET6, s, &ssin6.sin6_addr, sizeof(struct in6_addr)); - if (bits == -1) - return 0; + if (bits == -1) { + if (errno != EAFNOSUPPORT) + return 0; + bits = broken_inet_net_pton_ipv6(s, &ssin6.sin6_addr, + sizeof(struct in6_addr)); + if (bits == -1) + return 0; + } ssin6.sin6_family = AF_INET6; memcpy(&ss, &ssin6, sizeof(ssin6)); +#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN ss.ss_len = sizeof(struct sockaddr_in6); +#endif } netaddr->ss = ss; @@ -809,3 +830,35 @@ alias_is_error(struct expandnode *alias, const char *line, size_t len) alias->type = EXPAND_ERROR; return 1; } + +static int +broken_inet_net_pton_ipv6(const char *src, void *dst, size_t size) +{ + int ret; + int bits; + char buf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255:255:255:255/128")]; + char *sep; + const char *errstr; + + if (strlcpy(buf, src, sizeof buf) >= sizeof buf) { + errno = EMSGSIZE; + return (-1); + } + + sep = strchr(buf, '/'); + if (sep != NULL) + *sep++ = '\0'; + + ret = inet_pton(AF_INET6, buf, dst); + if (ret != 1) + return (-1); + + if (sep == NULL) + return 128; + + bits = strtonum(sep, 0, 128, &errstr); + if (errstr) + return (-1); + + return bits; +} diff --git a/smtpd/tree.c b/smtpd/tree.c index 70aef047..1d720a59 100644 --- a/smtpd/tree.c +++ b/smtpd/tree.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/tree.h> diff --git a/smtpd/unpack_dns.c b/smtpd/unpack_dns.c index fe50b026..974d5727 100644 --- a/smtpd/unpack_dns.c +++ b/smtpd/unpack_dns.c @@ -16,6 +16,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +#include <arpa/nameser_compat.h> +#endif #include <arpa/inet.h> #include <string.h> diff --git a/smtpd/util.c b/smtpd/util.c index 2d962848..fd80b69a 100644 --- a/smtpd/util.c +++ b/smtpd/util.c @@ -19,6 +19,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -832,3 +834,14 @@ log_trace_verbose(int v) /* Set debug logging in log.c */ log_setverbose(v & TRACE_DEBUG ? 2 : foreground_log); } + +void +xclosefrom(int lowfd) +{ +#if defined HAVE_CLOSEFROM_INT + if (closefrom(lowfd) == -1) + err(1, "closefrom"); +#else + closefrom(lowfd); +#endif +} diff --git a/smtpd/waitq.c b/smtpd/waitq.c index dc459372..082a1e51 100644 --- a/smtpd/waitq.c +++ b/smtpd/waitq.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/socket.h> #include <sys/queue.h> diff --git a/tests/certificate_test/smtpd.conf b/tests/certificate_test/smtpd.conf new file mode 100644 index 00000000..34887103 --- /dev/null +++ b/tests/certificate_test/smtpd.conf @@ -0,0 +1,13 @@ +pki_domain = "localhost" +pki $pki_domain cert "/etc/ssl/private/sites/fullchain.cer" +pki $pki_domain key "/etc/ssl/private/sites/site.key" + +#Encrypted password is "password" +table passwords {"user"="$6$tf940h4BpywpeKID$pWYiqoWywVPybeHaEcqHSRBD/7UxBmYhx7iHvxj/B3LBxCWwnFx7.3JwMISsN9EpPMwEZELvbNehVLl0IvvZo/"} + +listen on localhost tls hostname $pki_domain pki $pki_domain auth-optional <passwords> +listen on localhost port 465 smtps hostname $pki_domain pki $pki_domain auth-optional <passwords> +listen on localhost port 587 tls-require hostname $pki_domain pki $pki_domain auth <passwords> + +action "local" maildir "/tmp/" +match auth from any for any action "local" diff --git a/tests/certificate_test/test.sh b/tests/certificate_test/test.sh new file mode 100755 index 00000000..1eb50b40 --- /dev/null +++ b/tests/certificate_test/test.sh @@ -0,0 +1,20 @@ +#!/bin/sh +set -euxo pipefail +BASEDIR=$(dirname $0) + +# Setup TLS +mkdir -p /etc/ssl/private/sites/ +openssl genrsa -out /etc/ssl/private/sites/site.key 4096 +openssl req -new -x509 -key /etc/ssl/private/sites/site.key -out /etc/ssl/private/sites/fullchain.cer -subj "/CN='localhost'" +chmod 600 /etc/ssl/private/sites/site.key +chmod 644 /etc/ssl/private/sites/fullchain.cer + +smtpd -dv -f "$BASEDIR/smtpd.conf" & + +#Wait for smtpd to be ready to receive connections +sleep 3 + +#OpenSSL is crazy and will treat a capital "R" or "Q" as a command without the -quiet flag +#OpenSMTPD doesn't support pipelining, so wait 0.1 seconds between lines +awk '{print $0; system("sleep .1");}' "$BASEDIR/../test_email.txt" | \ + openssl s_client -quiet -connect localhost:25 -starttls smtp diff --git a/tests/test_all.sh b/tests/test_all.sh new file mode 100755 index 00000000..ca619479 --- /dev/null +++ b/tests/test_all.sh @@ -0,0 +1,6 @@ +#!/bin/sh +set -euxo pipefail +BASEDIR=$(dirname $0) + +echo "Testing TLS" +"$BASEDIR/certificate_test/test.sh" diff --git a/tests/test_email.txt b/tests/test_email.txt new file mode 100644 index 00000000..4fd3acfd --- /dev/null +++ b/tests/test_email.txt @@ -0,0 +1,13 @@ +HELO localhost +AUTH LOGIN +dXNlcg== +cGFzc3dvcmQ= +MAIL FROM:<_smtpd@localhost> +RCPT TO:<_smtpd@localhost> +DATA +Subject: Test Email + +It works + +. +QUIT |