aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore7
-rw-r--r--Dockerfile66
-rw-r--r--INSTALL237
-rw-r--r--LICENSE342
-rw-r--r--Makefile.am3
-rw-r--r--README.md (renamed from README)56
-rwxr-xr-xbootstrap151
-rw-r--r--configure.ac2067
-rw-r--r--contrib/CVS/Entries4
-rw-r--r--contrib/CVS/Repository1
-rw-r--r--contrib/CVS/Root1
-rw-r--r--contrib/Makefile.am1
-rw-r--r--contrib/libexec/CVS/Entries3
-rw-r--r--contrib/libexec/CVS/Repository1
-rw-r--r--contrib/libexec/CVS/Root1
-rw-r--r--contrib/libexec/Makefile.am1
-rw-r--r--contrib/libexec/encrypt/Makefile.am13
-rw-r--r--contrib/libexec/encrypt/encrypt.c102
-rw-r--r--contrib/libexec/mail.local/CVS/Entries7
-rw-r--r--contrib/libexec/mail.local/CVS/Repository1
-rw-r--r--contrib/libexec/mail.local/CVS/Root1
-rw-r--r--contrib/libexec/mail.local/Makefile.am22
-rw-r--r--contrib/libexec/mail.local/locking.c179
-rw-r--r--contrib/libexec/mail.local/mail.local.8183
-rw-r--r--contrib/libexec/mail.local/mail.local.c327
-rw-r--r--contrib/libexec/mail.local/mail.local.h42
-rw-r--r--contrib/libexec/mail.local/pathnames.h38
-rw-r--r--docker-compose.test.yml6
-rw-r--r--m4/aclocal-openssh.m4179
-rw-r--r--mk/Makefile.am3
-rw-r--r--mk/mail/Makefile.am5
-rw-r--r--mk/mail/mail.lmtp/Makefile.am22
-rw-r--r--mk/mail/mail.maildir/Makefile.am22
-rw-r--r--mk/mail/mail.mboxfile/Makefile.am22
-rw-r--r--mk/mail/mail.mda/Makefile.am22
-rw-r--r--mk/mdoc2man.awk391
-rw-r--r--mk/pathnames11
-rw-r--r--mk/smtpctl/Makefile.am96
-rw-r--r--mk/smtpd/Makefile.am188
-rw-r--r--openbsd-compat/Makefile.am112
-rw-r--r--openbsd-compat/NOTES37
-rw-r--r--openbsd-compat/arc4random.c294
-rw-r--r--openbsd-compat/base64.c315
-rw-r--r--openbsd-compat/base64.h65
-rw-r--r--openbsd-compat/basename.c67
-rw-r--r--openbsd-compat/bsd-closefrom.c109
-rw-r--r--openbsd-compat/bsd-err.c102
-rw-r--r--openbsd-compat/bsd-err.h29
-rw-r--r--openbsd-compat/bsd-getpeereid.c73
-rw-r--r--openbsd-compat/bsd-misc.c278
-rw-r--r--openbsd-compat/bsd-misc.h117
-rw-r--r--openbsd-compat/bsd-vis.h95
-rw-r--r--openbsd-compat/bsd-waitpid.c53
-rw-r--r--openbsd-compat/bsd-waitpid.h51
-rw-r--r--openbsd-compat/chacha_private.h224
-rw-r--r--openbsd-compat/clock_gettime.c59
-rw-r--r--openbsd-compat/crypt_checkpass.c33
-rw-r--r--openbsd-compat/daemon.c82
-rw-r--r--openbsd-compat/defines.h506
-rw-r--r--openbsd-compat/dirname.c72
-rw-r--r--openbsd-compat/entropy.c69
-rw-r--r--openbsd-compat/entropy.h37
-rw-r--r--openbsd-compat/err_h/err.h14
-rw-r--r--openbsd-compat/errc.c50
-rw-r--r--openbsd-compat/event_asr_run.c88
-rw-r--r--openbsd-compat/explicit_bzero.c17
-rw-r--r--openbsd-compat/fgetln.c60
-rw-r--r--openbsd-compat/fmt_scaled.c274
-rw-r--r--openbsd-compat/fparseln.c217
-rw-r--r--openbsd-compat/freezero.c34
-rw-r--r--openbsd-compat/getopt.c123
-rw-r--r--openbsd-compat/imsg-buffer.c310
-rw-r--r--openbsd-compat/imsg.c330
-rw-r--r--openbsd-compat/imsg.h115
-rw-r--r--openbsd-compat/includes.h71
-rw-r--r--openbsd-compat/inet_net_pton.c236
-rw-r--r--openbsd-compat/libressl.c131
-rw-r--r--openbsd-compat/openbsd-compat.h276
-rw-r--r--openbsd-compat/paths_h/paths.h8
-rw-r--r--openbsd-compat/pidfile.c112
-rw-r--r--openbsd-compat/pw_dup.c96
-rw-r--r--openbsd-compat/reallocarray.c43
-rw-r--r--openbsd-compat/recallocarray.c84
-rw-r--r--openbsd-compat/setproctitle.c174
-rw-r--r--openbsd-compat/setresguid.c67
-rw-r--r--openbsd-compat/strlcat.c62
-rw-r--r--openbsd-compat/strlcpy.c58
-rw-r--r--openbsd-compat/strmode.c148
-rw-r--r--openbsd-compat/strndup.c39
-rw-r--r--openbsd-compat/strnlen.c32
-rw-r--r--openbsd-compat/strsep.c79
-rw-r--r--openbsd-compat/strtonum.c72
-rw-r--r--openbsd-compat/sys/queue.h653
-rw-r--r--openbsd-compat/sys/tree.h755
-rw-r--r--openbsd-compat/vis.c224
-rw-r--r--openbsd-compat/xmalloc.c129
-rw-r--r--openbsd-compat/xmalloc.h35
-rw-r--r--smtpd/aliases.c7
-rw-r--r--smtpd/bounce.c2
-rw-r--r--smtpd/ca.c3
-rw-r--r--smtpd/cert.c2
-rw-r--r--smtpd/compress_backend.c2
-rw-r--r--smtpd/compress_gzip.c2
-rw-r--r--smtpd/config.c9
-rw-r--r--smtpd/control.c7
-rw-r--r--smtpd/crypto.c2
-rw-r--r--smtpd/dict.c2
-rw-r--r--smtpd/dns.c14
-rw-r--r--smtpd/enqueue.c6
-rw-r--r--smtpd/envelope.c6
-rw-r--r--smtpd/esc.c6
-rw-r--r--smtpd/expand.c8
-rw-r--r--smtpd/filter.c868
-rw-r--r--smtpd/forward.c7
-rw-r--r--smtpd/iobuf.c2
-rw-r--r--smtpd/ioev.c6
-rw-r--r--smtpd/libressl.c213
-rw-r--r--smtpd/limit.c2
-rw-r--r--smtpd/lka.c4
-rw-r--r--smtpd/lka_filter.c2
-rw-r--r--smtpd/lka_proc.c2
-rw-r--r--smtpd/lka_report.c2
-rw-r--r--smtpd/lka_session.c4
-rw-r--r--smtpd/log.c2
-rw-r--r--smtpd/log.h6
-rw-r--r--smtpd/mail.lmtp.c2
-rw-r--r--smtpd/mail.maildir.c2
-rw-r--r--smtpd/mail.mboxfile.c9
-rw-r--r--smtpd/mail.mda.c2
-rw-r--r--smtpd/mailaddr.c2
-rw-r--r--smtpd/makemap.c18
-rw-r--r--smtpd/mda.c9
-rw-r--r--smtpd/mda_unpriv.c2
-rw-r--r--smtpd/mda_variables.c2
-rw-r--r--smtpd/mproc.c9
-rw-r--r--smtpd/mta.c23
-rw-r--r--smtpd/mta_session.c4
-rw-r--r--smtpd/parse.y44
-rw-r--r--smtpd/parser.c8
-rw-r--r--smtpd/pony.c2
-rw-r--r--smtpd/queue.c4
-rw-r--r--smtpd/queue_backend.c2
-rw-r--r--smtpd/queue_fs.c17
-rw-r--r--smtpd/queue_null.c2
-rw-r--r--smtpd/queue_proc.c2
-rw-r--r--smtpd/queue_ram.c2
-rw-r--r--smtpd/report_smtp.c6
-rw-r--r--smtpd/resolver.c8
-rw-r--r--smtpd/rfc5322.c2
-rw-r--r--smtpd/ruleset.c2
-rw-r--r--smtpd/runq.c2
-rw-r--r--smtpd/scheduler.c3
-rw-r--r--smtpd/scheduler_backend.c2
-rw-r--r--smtpd/scheduler_null.c2
-rw-r--r--smtpd/scheduler_proc.c2
-rw-r--r--smtpd/scheduler_ramqueue.c2
-rw-r--r--smtpd/smtp.c23
-rw-r--r--smtpd/smtp_session.c6
-rw-r--r--smtpd/smtpctl.c23
-rw-r--r--smtpd/smtpd-defines.h10
-rw-r--r--smtpd/smtpd.c196
-rw-r--r--smtpd/smtpd.conf19
-rw-r--r--smtpd/smtpd.h38
-rw-r--r--smtpd/spfwalk.c6
-rw-r--r--smtpd/ssl.c4
-rw-r--r--smtpd/ssl.h1
-rw-r--r--smtpd/ssl_smtpd.c2
-rw-r--r--smtpd/stat_backend.c2
-rw-r--r--smtpd/stat_ramstat.c1
-rw-r--r--smtpd/table.c14
-rw-r--r--smtpd/table_db.c9
-rw-r--r--smtpd/table_getpwnam.c2
-rw-r--r--smtpd/table_proc.c4
-rw-r--r--smtpd/table_static.c2
-rw-r--r--smtpd/to.c61
-rw-r--r--smtpd/tree.c2
-rw-r--r--smtpd/unpack_dns.c5
-rw-r--r--smtpd/util.c13
-rw-r--r--smtpd/waitq.c2
-rw-r--r--tests/certificate_test/smtpd.conf13
-rwxr-xr-xtests/certificate_test/test.sh20
-rwxr-xr-xtests/test_all.sh6
-rw-r--r--tests/test_email.txt13
183 files changed, 14736 insertions, 76 deletions
diff --git a/.gitignore b/.gitignore
index 7644dffc..be0da24a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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
diff --git a/README b/README.md
index 0e223143..b234f983 100644
--- a/README
+++ b/README.md
@@ -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>
diff --git a/smtpd/ca.c b/smtpd/ca.c
index 4c3bdded..2fdb302f 100644
--- a/smtpd/ca.c
+++ b/smtpd/ca.c
@@ -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>
diff --git a/smtpd/to.c b/smtpd/to.c
index 6f8592dc..48ce949c 100644
--- a/smtpd/to.c
+++ b/smtpd/to.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>
@@ -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