aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--INSTALL237
-rw-r--r--LICENSE384
-rw-r--r--Makefile.am3
-rw-r--r--README.md16
-rw-r--r--THANKS27
-rwxr-xr-xbootstrap151
-rw-r--r--configure.ac3012
-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/lib/CVS/Entries7
-rw-r--r--contrib/lib/CVS/Repository1
-rw-r--r--contrib/lib/CVS/Root1
-rw-r--r--contrib/lib/Makefile.am1
-rw-r--r--contrib/lib/libc/CVS/Entries30
-rw-r--r--contrib/lib/libc/CVS/Repository1
-rw-r--r--contrib/lib/libc/CVS/Root1
-rw-r--r--contrib/lib/libc/Makefile.am1
-rw-r--r--contrib/lib/libc/asr/CVS/Entries26
-rw-r--r--contrib/lib/libc/asr/CVS/Repository1
-rw-r--r--contrib/lib/libc/asr/CVS/Root1
-rw-r--r--contrib/lib/libc/asr/asr.c956
-rw-r--r--contrib/lib/libc/asr/asr.h96
-rw-r--r--contrib/lib/libc/asr/asr_debug.c363
-rw-r--r--contrib/lib/libc/asr/asr_private.h367
-rw-r--r--contrib/lib/libc/asr/asr_utils.c551
-rw-r--r--contrib/lib/libc/asr/event_asr_run.c85
-rw-r--r--contrib/lib/libc/asr/getaddrinfo.c52
-rw-r--r--contrib/lib/libc/asr/getaddrinfo_async.c887
-rw-r--r--contrib/lib/libc/asr/gethostnamadr.c196
-rw-r--r--contrib/lib/libc/asr/gethostnamadr_async.c731
-rw-r--r--contrib/lib/libc/asr/getnameinfo.c51
-rw-r--r--contrib/lib/libc/asr/getnameinfo_async.c299
-rw-r--r--contrib/lib/libc/asr/getnetnamadr.c132
-rw-r--r--contrib/lib/libc/asr/getnetnamadr_async.c450
-rw-r--r--contrib/lib/libc/asr/getrrsetbyname.c81
-rw-r--r--contrib/lib/libc/asr/getrrsetbyname_async.c589
-rw-r--r--contrib/lib/libc/asr/res_debug.c2
-rw-r--r--contrib/lib/libc/asr/res_init.c86
-rw-r--r--contrib/lib/libc/asr/res_mkquery.c108
-rw-r--r--contrib/lib/libc/asr/res_query.c110
-rw-r--r--contrib/lib/libc/asr/res_search_async.c319
-rw-r--r--contrib/lib/libc/asr/res_send.c60
-rw-r--r--contrib/lib/libc/asr/res_send_async.c770
-rw-r--r--contrib/lib/libc/asr/sethostent.c41
-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.c109
-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.c178
-rw-r--r--contrib/libexec/mail.local/mail.local.8183
-rw-r--r--contrib/libexec/mail.local/mail.local.c335
-rw-r--r--contrib/libexec/mail.local/mail.local.h42
-rw-r--r--contrib/libexec/mail.local/pathnames.h36
-rw-r--r--m4/aclocal-openssh.m4101
-rw-r--r--mk/Makefile.am1
-rw-r--r--mk/backends/Makefile.am33
-rw-r--r--mk/backends/queue-null/Makefile.am7
-rw-r--r--mk/backends/queue-ram/Makefile.am7
-rw-r--r--mk/backends/queue-stub/Makefile.am7
-rw-r--r--mk/backends/scheduler-ram/Makefile.am7
-rw-r--r--mk/backends/scheduler-stub/Makefile.am7
-rw-r--r--mk/backends/table-ldap/Makefile.am9
-rw-r--r--mk/backends/table-mysql/Makefile.am9
-rw-r--r--mk/backends/table-passwd/Makefile.am7
-rw-r--r--mk/backends/table-postgres/Makefile.am10
-rw-r--r--mk/backends/table-redis/Makefile.am10
-rw-r--r--mk/backends/table-socketmap/Makefile.am7
-rw-r--r--mk/backends/table-sqlite/Makefile.am9
-rw-r--r--mk/backends/table-stub/Makefile.am7
-rw-r--r--mk/filter.mk17
-rw-r--r--mk/filters/Makefile.am1
-rw-r--r--mk/filters/dnsbl/Makefile.am19
-rw-r--r--mk/filters/monkey/Makefile.am7
-rw-r--r--mk/filters/stub/Makefile.am7
-rw-r--r--mk/filters/trace/Makefile.am7
-rw-r--r--mk/makemap/Makefile.am81
-rw-r--r--mk/mdoc2man.awk391
-rw-r--r--mk/pathnames15
-rw-r--r--mk/queue.mk11
-rw-r--r--mk/scheduler.mk9
-rw-r--r--mk/smtpctl/Makefile.am83
-rw-r--r--mk/smtpd/Makefile.am193
-rw-r--r--mk/table.mk10
-rw-r--r--openbsd-compat/Makefile.am15
-rw-r--r--openbsd-compat/NOTES35
-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-getpeereid.c73
-rw-r--r--openbsd-compat/bsd-misc.c278
-rw-r--r--openbsd-compat/bsd-misc.h117
-rw-r--r--openbsd-compat/bsd-waitpid.c53
-rw-r--r--openbsd-compat/bsd-waitpid.h51
-rw-r--r--openbsd-compat/chacha_private.h222
-rw-r--r--openbsd-compat/clock_gettime.c59
-rw-r--r--openbsd-compat/daemon.c82
-rw-r--r--openbsd-compat/defines.h799
-rw-r--r--openbsd-compat/dirname.c72
-rw-r--r--openbsd-compat/entropy.c239
-rw-r--r--openbsd-compat/entropy.h37
-rw-r--r--openbsd-compat/explicit_bzero.c20
-rw-r--r--openbsd-compat/fgetln.c62
-rw-r--r--openbsd-compat/fmt_scaled.c274
-rw-r--r--openbsd-compat/fparseln.c224
-rw-r--r--openbsd-compat/getopt.c123
-rw-r--r--openbsd-compat/imsg-buffer.c307
-rw-r--r--openbsd-compat/imsg.c327
-rw-r--r--openbsd-compat/imsg.h113
-rw-r--r--openbsd-compat/includes.h81
-rw-r--r--openbsd-compat/log.h65
-rw-r--r--openbsd-compat/mktemp.c141
-rw-r--r--openbsd-compat/openbsd-compat.h204
-rw-r--r--openbsd-compat/pidfile.c114
-rw-r--r--openbsd-compat/pw_dup.c96
-rw-r--r--openbsd-compat/setproctitle.c168
-rw-r--r--openbsd-compat/setresguid.c62
-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/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.c225
-rw-r--r--openbsd-compat/vis.h95
-rw-r--r--openbsd-compat/xmalloc.c127
-rw-r--r--openbsd-compat/xmalloc.h35
-rw-r--r--regress/config/test0.conf2
-rw-r--r--regress/config/test1.conf2
-rw-r--r--regress/config/test10.conf2
-rw-r--r--regress/config/test11.conf2
-rw-r--r--regress/config/test2.conf2
-rw-r--r--regress/config/test3.conf2
-rw-r--r--regress/config/test4.conf4
-rw-r--r--regress/config/test5.conf4
-rw-r--r--regress/config/test6.conf2
-rw-r--r--regress/config/test7.conf2
-rw-r--r--regress/config/test8.conf2
-rw-r--r--regress/config/test9.conf2
-rw-r--r--smtpd/aldap.c2
-rw-r--r--smtpd/aliases.c7
-rw-r--r--smtpd/backends/queue_null.c2
-rw-r--r--smtpd/backends/queue_ram.c2
-rw-r--r--smtpd/backends/queue_stub.c2
-rw-r--r--smtpd/backends/queue_utils.c2
-rw-r--r--smtpd/backends/scheduler_ram.c2
-rw-r--r--smtpd/backends/scheduler_stub.c2
-rw-r--r--smtpd/ber.c2
-rw-r--r--smtpd/bounce.c2
-rw-r--r--smtpd/ca.c4
-rw-r--r--smtpd/compress_backend.c2
-rw-r--r--smtpd/compress_gzip.c2
-rw-r--r--smtpd/config.c2
-rw-r--r--smtpd/control.c7
-rw-r--r--smtpd/crypto.c2
-rw-r--r--smtpd/delivery.c2
-rw-r--r--smtpd/delivery_filename.c9
-rw-r--r--smtpd/delivery_lmtp.c2
-rw-r--r--smtpd/delivery_maildir.c2
-rw-r--r--smtpd/delivery_mbox.c4
-rw-r--r--smtpd/delivery_mda.c2
-rw-r--r--smtpd/dict.c2
-rw-r--r--smtpd/dns.c8
-rw-r--r--smtpd/enqueue.c2
-rw-r--r--smtpd/envelope.c6
-rw-r--r--smtpd/esc.c2
-rw-r--r--smtpd/expand.c8
-rw-r--r--smtpd/filter.c6
-rw-r--r--smtpd/filter_api.c4
-rw-r--r--smtpd/filters/filter_dnsbl.c2
-rw-r--r--smtpd/filters/filter_monkey.c2
-rw-r--r--smtpd/filters/filter_stub.c2
-rw-r--r--smtpd/filters/filter_trace.c2
-rw-r--r--smtpd/forward.c7
-rw-r--r--smtpd/iobuf.c2
-rw-r--r--smtpd/ioev.c6
-rw-r--r--smtpd/limit.c2
-rw-r--r--smtpd/lka.c4
-rw-r--r--smtpd/lka_session.c2
-rw-r--r--smtpd/log.c2
-rw-r--r--smtpd/log.h2
-rw-r--r--smtpd/makemap.c29
-rw-r--r--smtpd/mda.c5
-rw-r--r--smtpd/mfa.c429
-rw-r--r--smtpd/mproc.c7
-rw-r--r--smtpd/mta.c23
-rw-r--r--smtpd/mta_session.c4
-rw-r--r--smtpd/parse.y26
-rw-r--r--smtpd/parser.c8
-rw-r--r--smtpd/pony.c1
-rw-r--r--smtpd/queue.c6
-rw-r--r--smtpd/queue_api.c3
-rw-r--r--smtpd/queue_backend.c14
-rw-r--r--smtpd/queue_fs.c16
-rw-r--r--smtpd/queue_null.c2
-rw-r--r--smtpd/queue_proc.c5
-rw-r--r--smtpd/queue_ram.c2
-rw-r--r--smtpd/ruleset.c2
-rw-r--r--smtpd/runq.c2
-rw-r--r--smtpd/scheduler.c3
-rw-r--r--smtpd/scheduler_api.c3
-rw-r--r--smtpd/scheduler_backend.c2
-rw-r--r--smtpd/scheduler_null.c2
-rw-r--r--smtpd/scheduler_proc.c5
-rw-r--r--smtpd/scheduler_ramqueue.c2
-rw-r--r--smtpd/smtp.c21
-rw-r--r--smtpd/smtp_session.c12
-rw-r--r--smtpd/smtpctl.c19
-rw-r--r--smtpd/smtpd-defines.h11
-rw-r--r--smtpd/smtpd.c172
-rw-r--r--smtpd/smtpd.conf14
-rw-r--r--smtpd/smtpd.conf.54
-rw-r--r--smtpd/smtpd.h38
-rw-r--r--smtpd/ssl.c11
-rw-r--r--smtpd/ssl_privsep.c2
-rw-r--r--smtpd/ssl_smtpd.c4
-rw-r--r--smtpd/stat_backend.c2
-rw-r--r--smtpd/stat_ramstat.c1
-rw-r--r--smtpd/table.c10
-rw-r--r--smtpd/table_api.c3
-rw-r--r--smtpd/table_db.c9
-rw-r--r--smtpd/table_getpwnam.c2
-rw-r--r--smtpd/table_ldap.c2
-rw-r--r--smtpd/table_mysql.c2
-rw-r--r--smtpd/table_passwd.c2
-rw-r--r--smtpd/table_postgres.c2
-rw-r--r--smtpd/table_proc.c5
-rw-r--r--smtpd/table_redis.c2
-rw-r--r--smtpd/table_sqlite.c2
-rw-r--r--smtpd/table_static.c2
-rw-r--r--smtpd/table_stub.c2
-rw-r--r--smtpd/to.c60
-rw-r--r--smtpd/tree.c2
-rw-r--r--smtpd/util.c2
-rw-r--r--smtpd/waitq.c2
245 files changed, 22087 insertions, 86 deletions
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..fa4ce636
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,384 @@
+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 5 parts:
+- Original OpenSMTPD
+- asr
+- 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 .
+ */
+
+
+
+asr
+===
+
+
+1) Almost all code is licensed under an ISC-style license, to the following
+ copyright holders:
+
+ Eric Faurot
+ Internet Software Consortium
+
+
+2) last part of getrrsetbyname_async.c is covered by 2-clause BSD license
+
+/*
+ * Copyright (c) 2001 Jakob Schlyter. 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.
+ */
+
+
+
+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.md b/README.md
index 9f06282f..7c65459e 100644
--- a/README.md
+++ b/README.md
@@ -35,7 +35,7 @@ Dependencies
Portable OpenSMTPD relies on:
* [autoconf](http://www.gnu.org/software/autoconf/)
* [automake](http://www.gnu.org/software/automake/)
-* [Berkeley DB](http://www.oracle.com/technetwork/products/berkeleydb/overview/index.html)
+* [Berkeley DB](http://www.oracle.com/technetwork/products/berkeleydb/overview/index.html) to be built with --enable-compat185 configure flag
* [bison](http://www.gnu.org/software/bison/) (or [byacc](http://invisible-island.net/byacc/byacc.html))
* [libevent](http://libevent.org/)
* [libtool](http://www.gnu.org/software/libtool/)
@@ -57,7 +57,7 @@ Build
-----
cd opensmtpd*
- ./bootstrap
+ ./bootstrap # Only if you build from git sources
./configure
make
sudo make install
@@ -96,11 +96,15 @@ Add OpenSMTPD users
-------------------
To operate, OpenSMTPD requires at least one user, by default _smtpd; and
-preferably three users, by default _smtpd, _smtpq and _smtpf.
+preferably two users, by default _smtpd and _smtpq.
+
+Using two users instead of one will increase security by a large factor so...
+unless you want to voluntarily reduce security or you have absolute more faith in our code than we do, by all means use two.
+
The instructions below assume the default users however, the configure
script allows overriding these using the options:
---with-privsep-user, --with-queue-user and --with-filter-user.
+--with-privsep-user, --with-queue-user.
### NetBSD, Linux (Debian, ArchLinux, ...)
@@ -108,13 +112,11 @@ script allows overriding these using the options:
mkdir /var/empty
useradd -c "SMTP Daemon" -d /var/empty -s /sbin/nologin _smtpd
useradd -c "SMTP queue user" -d /var/empty -s /sbin/nologin _smtpq
- useradd -c "SMTP filter user" -d /var/empty -s /sbin/nologin _smtpf
### DragonFlyBSD, FreeBSD
pw useradd _smtpd -c "SMTP Daemon" -d /var/empty -s /sbin/nologin
pw useradd _smtpq -c "SMTP queue user" -d /var/empty -s /sbin/nologin
- pw useradd _smtpf -c "SMTP filter user" -d /var/empty -s /sbin/nologin
### Mac OS X
@@ -143,7 +145,7 @@ Add a user - here we have picked 444:
/usr/bin/sudo /usr/bin/dscl . -create /Users/_smtpd NFSHomeDirectory /var/empty
/usr/bin/sudo /usr/bin/dscl . -create /Users/_smtpd UserShell /usr/bin/false
-repeat for the _smtpq and _smtpf users.
+repeat for the _smtpq user.
Launch smtpd
diff --git a/THANKS b/THANKS
index ecf12d74..20f8fe99 100644
--- a/THANKS
+++ b/THANKS
@@ -1,16 +1,19 @@
-Jason McIntyre Documentation tweaks
-Freddy Dissaux IPv6 fix on FreeBSD
-Alexandre Lissy Mandriva fix
-Brad Arrington ArchLinux package
-Todd T. Fries Nokia N900 debian/armel
-Francois Tigeot DragonFlyBSD fixes / pkgsrc
-Ashish Shukla FreeBSD port, LMTP support
-Jean-Loup Colautti Debian package
-Rune Lynge MacOS X port
-Jason A. Donenfeld Gentoo ebuild, PAM support
-Gleb Kozyrev LMTP delivery improvements
+Jason McIntyre
+Freddy Dissaux
+Alexandre Lissy
+Brad Arrington
+Todd T. Fries
+Francois Tigeot
+Ashish Shukla
+Jean-Loup Colautti
+Rune Lynge
+Jason A. Donenfeld
+Gleb Kozyrev
+Colin Didier
+Ryan Kavanagh
+Sunil Nimmagadda
-Miod Vallat Hosting hackathons with ducks and cheese and beer
+Miod Vallat
And of course Gilles Chehade and Eric Faurot for their work and continuous help.
diff --git a/bootstrap b/bootstrap
new file mode 100755
index 00000000..b8d8fe5b
--- /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 15 14 13 12 11 10 9 8 7 6 5; 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 expr "$amvers" "<" "1.5" > /dev/null 2>&1; then
+ amvers="no"
+ else
+ amvers=""
+ fi
+fi
+
+if test "$amvers" = "no"; then
+ echo "$0: you need automake version 1.5 or later"
+ exit 1
+fi
+
+# Check for autoconf
+acvers="no"
+for v in "" "269" "-2.69" "259" "-2.59" "253" "-2.53"; 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..81a08a75
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,3012 @@
+# $Id: configure.ac,v 1.519 2013/03/22 01:49:15 dtucker Exp $
+#
+# 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.
+
+dnl AC_INIT([OpenSMTPD-portable],[4.9.0],[Charles Longeau <chl@openbsd.org>])
+dnl AC_INIT([OpenSMTPD-portable], m4_esyscmd(date +%Y%m%d%H%M%S | sed -e 's/^\(.*\)$/5.2-\1/' | tr -d '\n'),[Charles Longeau <chl@openbsd.org>])
+AC_INIT([opensmtpd], [portable], [bugs@opensmtpd.org])
+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([ZCAT], [zcat])
+AC_SUBST([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
+
+AM_INIT_AUTOMAKE
+
+LT_INIT
+
+#here we should test for variables set by libtool detection
+if test "x$with_pic" != "xno" ; then
+ CFLAGS="$CFLAGS ${pic_flag}"
+fi
+
+
+#from here everything comes from portable openssh configure.ac script
+
+#l50
+dnl select manpage formatter
+if test "x$MANDOC" != "x" ; then
+ MANFMT="$MANDOC"
+elif test "x$NROFF" != "x" ; then
+ MANFMT="$NROFF -mandoc"
+elif test "x$GROFF" != "x" ; then
+ MANFMT="$GROFF -mandoc -Tascii"
+else
+ AC_MSG_WARN([no manpage formatted found])
+ MANFMT="false"
+fi
+AC_SUBST([MANFMT])
+#l61
+
+#l78
+if test -z "$AR" ; then
+ AC_MSG_ERROR([*** 'ar' missing, please install or fix your \$PATH ***])
+fi
+#l80
+
+#l101
+if test -z "$LD" ; then
+ LD=$CC
+fi
+AC_SUBST([LD])
+
+AC_C_INLINE
+
+AC_CHECK_DECL([LLONG_MAX], [have_llong_max=1], , [#include <limits.h>])
+#l108
+
+#l131
+if test "$GCC" = "yes" || test "$GCC" = "egcs"; then
+ OSSH_CHECK_CFLAG_COMPILE([-Qunused-arguments -Werror],
+ [-Qunused-arguments])
+ OSSH_CHECK_CFLAG_COMPILE([-Wunknown-warning-option -Werror],
+ [-Wno-unknown-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])
+ 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-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
+ ]
+)
+
+# Allow user to specify flags
+AC_ARG_WITH([cflags],
+ [ --with-cflags Specify additional flags to pass to compiler],
+ [
+ if test -n "$withval" && test "x$withval" != "xno" && \
+ test "x${withval}" != "xyes"; then
+ CFLAGS="$CFLAGS $withval"
+ fi
+ ]
+)
+AC_ARG_WITH([cppflags],
+ [ --with-cppflags Specify additional flags to pass to preprocessor] ,
+ [
+ if test -n "$withval" && test "x$withval" != "xno" && \
+ test "x${withval}" != "xyes"; then
+ CPPFLAGS="$CPPFLAGS $withval"
+ fi
+ ]
+)
+AC_ARG_WITH([ldflags],
+ [ --with-ldflags Specify additional flags to pass to linker],
+ [
+ if test -n "$withval" && test "x$withval" != "xno" && \
+ test "x${withval}" != "xyes"; then
+ LDFLAGS="$LDFLAGS $withval"
+ fi
+ ]
+)
+AC_ARG_WITH([libs],
+ [ --with-libs Specify additional libraries to link with],
+ [
+ if test -n "$withval" && test "x$withval" != "xno" && \
+ test "x${withval}" != "xyes"; then
+ LIBS="$LIBS $withval"
+ fi
+ ]
+)
+AC_ARG_WITH([Werror],
+ [ --with-Werror Build main code with -Werror],
+ [
+ if test -n "$withval" && test "x$withval" != "xno"; then
+ werror_flags="-Werror"
+ if test "x${withval}" != "xyes"; then
+ werror_flags="$withval"
+ fi
+ fi
+ ]
+)
+#l296
+
+AC_CHECK_HEADERS([ \
+ crypt.h \
+ dirent.h \
+ fcntl.h \
+ getopt.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/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
+])
+
+#l379
+# login_cap.h requires sys/types.h on NetBSD
+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>
+])
+#l387
+
+#l400 (customized)
+# Check for some target-specific stuff
+case "$host" in
+*-*-aix*)
+ check_for_aix_broken_getaddrinfo=1
+ AC_DEFINE([BROKEN_REALPATH], [1], [Define if you have a broken realpath.])
+ AC_DEFINE([SETEUID_BREAKS_SETUID], [1],
+ [Define if your platform breaks doing a seteuid before a setuid])
+ AC_DEFINE([BROKEN_SETREUID], [1], [Define if your setreuid() is broken])
+ AC_DEFINE([BROKEN_SETREGID], [1], [Define if your setregid() is broken])
+ AC_DEFINE([SPT_TYPE], [SPT_REUSEARGV],
+ [Define to a Set Process Title type if your system is
+ supported by bsd-setproctitle.c])
+ ;;
+*-*-darwin*)
+ AC_MSG_CHECKING([if we have working getaddrinfo])
+ AC_RUN_IFELSE([AC_LANG_SOURCE([[ #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])
+ AC_DEFINE([BROKEN_SETREUID])
+ AC_DEFINE([BROKEN_SETREGID])
+ AC_DEFINE([BROKEN_GLOB], [1], [OS X glob does not do what we expect])
+ AC_DEFINE_UNQUOTED([BIND_8_COMPAT], [1],
+ [Define if your resolver libs need this for getrrsetbyname])
+ AC_DEFINE([SPT_TYPE], [SPT_REUSEARGV],
+ [Define to a Set Process Title type if your system is
+ supported by bsd-setproctitle.c])
+ ;;
+*-*-dragonfly*)
+ SMTPDLIBS="$SMTPDLIBS -lcrypt"
+ ;;
+*-*-hpux*)
+ # first we define all of the options common to all HP-UX releases
+ CPPFLAGS="$CPPFLAGS -D_HPUX_SOURCE -D_XOPEN_SOURCE -D_XOPEN_SOURCE_EXTENDED=1"
+ AC_DEFINE([SPT_TYPE], [SPT_PSTAT])
+ maildir="/var/mail"
+ LIBS="$LIBS -lsec"
+
+ # next, we define all of the options specific to major releases
+ case "$host" in
+ *-*-hpux10*)
+ if test -z "$GCC"; then
+ CFLAGS="$CFLAGS -Ae"
+ fi
+ ;;
+ *-*-hpux11*)
+ AC_DEFINE([PAM_SUN_CODEBASE], [1],
+ [Define if you are using Solaris-derived PAM which
+ passes pam_messages to the conversation function
+ with an extra level of indirection])
+ ;;
+ esac
+ ;;
+*-*-linux* | *-gnu* | *-k*bsd*-gnu* )
+ check_for_libcrypt_later=1
+ AC_DEFINE([SPT_TYPE], [SPT_REUSEARGV])
+ case `uname -r` in
+ 1.*|2.0.*)
+ AC_DEFINE(BROKEN_CMSG_TYPE, 1,
+ [Define if cmsg_type is not passed correctly])
+ ;;
+ esac
+ ;;
+*-*-netbsd*)
+ check_for_libcrypt_before=1
+ if test "x$withval" != "xno" ; then
+ need_dash_r=1
+ fi
+ #not in portable OpenSSH, maybe because they don't use portable OpenSSH?
+ AC_DEFINE([BROKEN_STRNVIS], [1], [NetBSD strnvis does not do what we need])
+ ;;
+*-*-freebsd*)
+ check_for_libcrypt_later=1
+ AC_DEFINE([BROKEN_GLOB], [1], [FreeBSD glob does not do what we need])
+ AC_DEFINE([BROKEN_STRNVIS], [1], [FreeBSD strnvis does not do what we need])
+ ;;
+*-*-openbsd*)
+ AC_DEFINE([HAVE_ATTRIBUTE__SENTINEL__], [1], [OpenBSD's gcc has sentinel])
+ AC_DEFINE([HAVE_ATTRIBUTE__BOUNDED__], [1], [OpenBSD's gcc has bounded])
+ echo "Please use -current or a native version at http://www.opensmtpd.org/archives/"
+ ;;
+*-*-solaris*)
+ if test "x$withval" != "xno" ; then
+ need_dash_r=1
+ fi
+ AC_DEFINE([PAM_SUN_CODEBASE])
+ AC_DEFINE([SSHPAM_CHAUTHTOK_NEEDS_RUID], [1],
+ [Define if pam_chauthtok wants real uid set
+ to the unpriv'ed user])
+ ;;
+*-*-sunos4*)
+ CPPFLAGS="$CPPFLAGS -DSUNOS4"
+ AC_DEFINE([PAM_SUN_CODEBASE])
+ ;;
+esac
+
+AC_MSG_CHECKING([compiler and flags for sanity])
+AC_RUN_IFELSE([AC_LANG_PROGRAM([[ #include <stdio.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]) ]
+)
+
+dnl Checks for header files.
+# Checks for libraries.
+AC_CHECK_FUNC([setsockopt], , [AC_CHECK_LIB([socket], [setsockopt])])
+
+dnl IRIX and Solaris 2.5.1 have dirname() in libgen
+AC_CHECK_FUNCS([dirname], [AC_CHECK_HEADERS([libgen.h])] , [
+ AC_CHECK_LIB([gen], [dirname], [
+ AC_CACHE_CHECK([for broken dirname],
+ ac_cv_have_broken_dirname, [
+ save_LIBS="$LIBS"
+ LIBS="$LIBS -lgen"
+ AC_RUN_IFELSE(
+ [AC_LANG_SOURCE([[
+#include <libgen.h>
+#include <string.h>
+
+int main(int argc, char **argv) {
+ char *s, buf[32];
+
+ strncpy(buf,"/etc", 32);
+ s = dirname(buf);
+ if (!s || strncmp(s, "/", 32) != 0) {
+ exit(1);
+ } else {
+ exit(0);
+ }
+}
+ ]])],
+ [ ac_cv_have_broken_dirname="no" ],
+ [ ac_cv_have_broken_dirname="yes" ],
+ [ ac_cv_have_broken_dirname="no" ],
+ )
+ LIBS="$save_LIBS"
+ ])
+ if test "x$ac_cv_have_broken_dirname" = "xno" ; then
+ LIBS="$LIBS -lgen"
+ AC_DEFINE([HAVE_DIRNAME])
+ AC_CHECK_HEADERS([libgen.h])
+ fi
+ ])
+])
+#l1069
+
+#l1073
+AC_SEARCH_LIBS([basename], [gen], [AC_DEFINE([HAVE_BASENAME], [1],
+ [Define if you have the basename function.])])
+
+dnl zlib is required
+AC_ARG_WITH([zlib],
+ [ --with-zlib=PATH Use zlib in PATH],
+ [ 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([zlib-version-check],
+ [ --without-zlib-version-check Disable zlib version check],
+ [ if test "x$withval" = "xno" ; then
+ zlib_check_nonfatal=1
+ fi
+ ]
+)
+
+AC_MSG_CHECKING([for possibly buggy zlib])
+AC_RUN_IFELSE([AC_LANG_PROGRAM([[
+#include <stdio.h>
+#include <stdlib.h>
+#include <zlib.h>
+ ]],
+ [[
+ int a=0, b=0, c=0, d=0, n, v;
+ n = sscanf(ZLIB_VERSION, "%d.%d.%d.%d", &a, &b, &c, &d);
+ if (n != 3 && n != 4)
+ exit(1);
+ v = a*1000000 + b*10000 + c*100 + d;
+ fprintf(stderr, "found zlib version %s (%d)\n", ZLIB_VERSION, v);
+
+ /* 1.1.4 is OK */
+ if (a == 1 && b == 1 && c >= 4)
+ exit(0);
+
+ /* 1.2.3 and up are OK */
+ if (v >= 1020300)
+ exit(0);
+
+ exit(2);
+ ]])],
+ AC_MSG_RESULT([no]),
+ [ AC_MSG_RESULT([yes])
+ if test -z "$zlib_check_nonfatal" ; then
+ AC_MSG_ERROR([*** zlib too old - check config.log ***
+Your reported zlib version has known security problems. It's possible your
+vendor has fixed these problems without changing the version number. If you
+are sure this is the case, you can disable the check by running
+"./configure --without-zlib-version-check".
+If you are in doubt, upgrade zlib to version 1.2.3 or greater.
+See http://www.gzip.org/zlib/ for details.])
+ else
+ AC_MSG_WARN([zlib version may have security problems])
+ fi
+ ],
+ [ AC_MSG_WARN([cross compiling: not checking zlib version]) ]
+)
+
+dnl UnixWare 2.x
+AC_CHECK_FUNC([strcasecmp],
+ [], [ AC_CHECK_LIB([resolv], [strcasecmp], [LIBS="$LIBS -lresolv"]) ]
+)
+AC_CHECK_FUNCS([utimes],
+ [], [ AC_CHECK_LIB([c89], [utimes], [AC_DEFINE([HAVE_UTIMES])
+ LIBS="$LIBS -lc89"]) ]
+)
+
+dnl Checks for libutil functions
+AC_CHECK_HEADERS([bsd/libutil.h libutil.h])
+AC_SEARCH_LIBS([fmt_scaled], [util bsd])
+AC_SEARCH_LIBS([scan_scaled], [util bsd])
+AC_CHECK_FUNCS([fmt_scaled scan_scaled])
+#l1192
+
+#l1250
+AC_MSG_CHECKING([whether struct dirent allocates space for d_name])
+AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <dirent.h>]],
+ [[
+ struct dirent d;
+ exit(sizeof(d.d_name)<=sizeof(char));
+ ]])],
+ [AC_MSG_RESULT([yes])],
+ [
+ AC_MSG_RESULT([no])
+ AC_DEFINE([BROKEN_ONE_BYTE_DIRENT_D_NAME], [1],
+ [Define if your struct dirent expects you to
+ allocate extra space for d_name])
+ ],
+ [
+ AC_MSG_WARN([cross compiling: assuming BROKEN_ONE_BYTE_DIRENT_D_NAME])
+ AC_DEFINE([BROKEN_ONE_BYTE_DIRENT_D_NAME])
+ ]
+)
+
+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
+#l1278
+
+#l1527 (customized)
+dnl Checks for library functions. Please keep in alphabetical order
+AC_CHECK_FUNCS([ \
+ arc4random \
+ arc4random_buf \
+ arc4random_uniform \
+ asprintf \
+ b64_ntop \
+ __b64_ntop \
+ b64_pton \
+ __b64_pton \
+ bcopy \
+ chflags \
+ closefrom \
+ dirfd \
+ dirname \
+ endgrent \
+ explicit_bzero \
+ fgetln \
+ freeaddrinfo \
+ getaddrinfo \
+ getnameinfo \
+ getopt \
+ getpeereid \
+ getspnam \
+ inet_aton \
+ inet_ntoa \
+ inet_ntop \
+ isblank \
+ memmove \
+ nsleep \
+ pidfile \
+ pw_dup \
+ setenv \
+ setlinebuf \
+ setproctitle \
+ setregid \
+ setreuid \
+ setsid \
+ sigaction \
+ socketpair \
+ strdup \
+ strerror \
+ strlcat \
+ strlcpy \
+ strnvis \
+ strmode \
+ strtonum \
+ sysconf \
+ tcgetpgrp \
+ truncate \
+ vasprintf \
+ vsnprintf \
+ waitpid \
+])
+#l1631
+
+#l1645
+# IRIX has a const char return value for gai_strerror()
+AC_CHECK_FUNCS([gai_strerror], [
+ AC_DEFINE([HAVE_GAI_STRERROR])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+const char *gai_strerror(int);
+ ]], [[
+ char *str;
+ str = gai_strerror(0);
+ ]])], [
+ AC_DEFINE([HAVE_CONST_GAI_STRERROR_PROTO], [1],
+ [Define if gai_strerror() returns const char *])], [])])
+#l1659
+
+#l1661
+AC_SEARCH_LIBS([nanosleep], [rt posix4], [AC_DEFINE([HAVE_NANOSLEEP], [1],
+ [Some systems put nanosleep outside of libc])])
+
+AC_SEARCH_LIBS([clock_gettime], [rt],
+ [AC_DEFINE([HAVE_CLOCK_GETTIME], [1], [Have clock_gettime])])
+#l1665
+
+#l1669
+AC_CHECK_DECL([strsep],
+ [AC_CHECK_FUNCS([strsep])],
+ [],
+ [
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+ ])
+#l1676
+
+#l1693
+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([writev], , , [
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+ ])
+
+AC_CHECK_DECLS([MAXSYMLINKS], , , [
+#include <sys/param.h>
+ ])
+
+AC_CHECK_DECLS([offsetof], , , [
+#include <stddef.h>
+ ])
+
+# extra bits for select(2)
+AC_CHECK_DECLS([howmany, NFDBITS], [], [], [[
+#include <sys/param.h>
+#include <sys/types.h>
+#ifdef HAVE_SYS_SYSMACROS_H
+#include <sys/sysmacros.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+ ]])
+AC_CHECK_TYPES([fd_mask], [], [], [[
+#include <sys/param.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
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+ ]])
+
+AC_CHECK_FUNCS([setresuid], [
+ dnl Some platorms have setresuid that isn't implemented, test for this
+ AC_MSG_CHECKING([if setresuid seems to work])
+ AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([[
+#include <stdlib.h>
+#include <errno.h>
+ ]], [[
+ errno=0;
+ setresuid(0,0,0);
+ if (errno==ENOSYS)
+ exit(1);
+ else
+ exit(0);
+ ]])],
+ [AC_MSG_RESULT([yes])],
+ [AC_DEFINE([BROKEN_SETRESUID], [1],
+ [Define if your setresuid() is broken])
+ AC_MSG_RESULT([not implemented])],
+ [AC_MSG_WARN([cross compiling: not checking setresuid])]
+ )
+])
+
+AC_CHECK_FUNCS([setresgid], [
+ dnl Some platorms have setresgid that isn't implemented, test for this
+ AC_MSG_CHECKING([if setresgid seems to work])
+ AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([[
+#include <stdlib.h>
+#include <errno.h>
+ ]], [[
+ errno=0;
+ setresgid(0,0,0);
+ if (errno==ENOSYS)
+ exit(1);
+ else
+ exit(0);
+ ]])],
+ [AC_MSG_RESULT([yes])],
+ [AC_DEFINE([BROKEN_SETRESGID], [1],
+ [Define if your setresgid() is broken])
+ AC_MSG_RESULT([not implemented])],
+ [AC_MSG_WARN([cross compiling: not checking setresuid])]
+ )
+])
+
+dnl Checks for time functions
+AC_CHECK_FUNCS([gettimeofday time])
+#l1796
+
+#l1806
+AC_CHECK_FUNC([daemon],
+ [AC_DEFINE([HAVE_DAEMON], [1], [Define if your libraries define daemon()])],
+ [AC_CHECK_LIB([bsd], [daemon],
+ [LIBS="$LIBS -lbsd"; AC_DEFINE([HAVE_DAEMON])])]
+)
+#l1810
+
+##chl
+AC_CHECK_FUNC([fparseln],
+ [AC_DEFINE([HAVE_FPARSELN], [1], [Define if your libraries define fparseln()])],
+ [AC_CHECK_LIB([util], [fparseln],
+ [LIBS="$LIBS -lutil"; AC_DEFINE([HAVE_FPARSELN])])]
+)
+
+AC_SEARCH_LIBS(res_9_b64_ntop, resolv)
+##chl
+
+#l1819
+# Check for broken snprintf
+if test "x$ac_cv_func_snprintf" = "xyes" ; then
+ AC_MSG_CHECKING([whether snprintf correctly terminates long strings])
+ AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([[ #include <stdio.h> ]],
+ [[
+ char b[5];
+ snprintf(b,5,"123456789");
+ exit(b[4]!='\0');
+ ]])],
+ [AC_MSG_RESULT([yes])],
+ [
+ AC_MSG_RESULT([no])
+ AC_DEFINE([BROKEN_SNPRINTF], [1],
+ [Define if your snprintf is busted])
+ AC_MSG_WARN([****** Your snprintf() function is broken, complain to your vendor])
+ ],
+ [ AC_MSG_WARN([cross compiling: Assuming working snprintf()]) ]
+ )
+fi
+
+# If we don't have a working asprintf, then we strongly depend on vsnprintf
+# returning the right thing on overflow: the number of characters it tried to
+# create (as per SUSv3)
+if test "x$ac_cv_func_asprintf" != "xyes" && \
+ test "x$ac_cv_func_vsnprintf" = "xyes" ; then
+ AC_MSG_CHECKING([whether vsnprintf returns correct values on overflow])
+ AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+int x_snprintf(char *str,size_t count,const char *fmt,...)
+{
+ size_t ret; va_list ap;
+ va_start(ap, fmt); ret = vsnprintf(str, count, fmt, ap); va_end(ap);
+ return ret;
+}
+ ]], [[
+ char x[1];
+ exit(x_snprintf(x, 1, "%s %d", "hello", 12345) == 11 ? 0 : 1);
+ ]])],
+ [AC_MSG_RESULT([yes])],
+ [
+ AC_MSG_RESULT([no])
+ AC_DEFINE([BROKEN_SNPRINTF], [1],
+ [Define if your snprintf is busted])
+ AC_MSG_WARN([****** Your vsnprintf() function is broken, complain to your vendor])
+ ],
+ [ AC_MSG_WARN([cross compiling: Assuming working vsnprintf()]) ]
+ )
+fi
+
+# On systems where [v]snprintf is broken, but is declared in stdio,
+# check that the fmt argument is const char * or just char *.
+# This is only useful for when BROKEN_SNPRINTF
+AC_MSG_CHECKING([whether snprintf can declare const char *fmt])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <stdio.h>
+int snprintf(char *a, size_t b, const char *c, ...) { return 0; }
+ ]], [[
+ snprintf(0, 0, 0);
+ ]])],
+ [AC_MSG_RESULT([yes])
+ AC_DEFINE([SNPRINTF_CONST], [const],
+ [Define as const if snprintf() can declare const char *fmt])],
+ [AC_MSG_RESULT([no])
+ AC_DEFINE([SNPRINTF_CONST], [/* not const */])])
+
+# 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
+
+dnl see whether mkstemp() requires XXXXXX
+if test "x$ac_cv_func_mkdtemp" = "xyes" ; then
+AC_MSG_CHECKING([for (overly) strict mkstemp])
+AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([[
+#include <stdlib.h>
+ ]], [[
+ char template[]="conftest.mkstemp-test";
+ if (mkstemp(template) == -1)
+ exit(1);
+ unlink(template);
+ exit(0);
+ ]])],
+ [
+ AC_MSG_RESULT([no])
+ ],
+ [
+ AC_MSG_RESULT([yes])
+ AC_DEFINE([HAVE_STRICT_MKSTEMP], [1], [Silly mkstemp()])
+ ],
+ [
+ AC_MSG_RESULT([yes])
+ AC_DEFINE([HAVE_STRICT_MKSTEMP])
+ ]
+)
+fi
+#l1928
+
+#l1976
+if test "x$ac_cv_func_getaddrinfo" = "xyes" && \
+ test "x$check_for_hpux_broken_getaddrinfo" = "x1"; then
+ AC_MSG_CHECKING([if getaddrinfo seems to work])
+ AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([[
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <errno.h>
+#include <netinet/in.h>
+
+#define TEST_PORT "2222"
+ ]], [[
+ int err, sock;
+ struct addrinfo *gai_ai, *ai, hints;
+ char ntop[NI_MAXHOST], strport[NI_MAXSERV], *name = NULL;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE;
+
+ err = getaddrinfo(name, TEST_PORT, &hints, &gai_ai);
+ if (err != 0) {
+ fprintf(stderr, "getaddrinfo failed (%s)", gai_strerror(err));
+ exit(1);
+ }
+
+ for (ai = gai_ai; ai != NULL; ai = ai->ai_next) {
+ if (ai->ai_family != AF_INET6)
+ continue;
+
+ err = getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop,
+ sizeof(ntop), strport, sizeof(strport),
+ NI_NUMERICHOST|NI_NUMERICSERV);
+
+ if (err != 0) {
+ if (err == EAI_SYSTEM)
+ perror("getnameinfo EAI_SYSTEM");
+ else
+ fprintf(stderr, "getnameinfo failed: %s\n",
+ gai_strerror(err));
+ exit(2);
+ }
+
+ sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (sock < 0)
+ perror("socket");
+ if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
+ if (errno == EBADF)
+ exit(3);
+ }
+ }
+ exit(0);
+ ]])],
+ [
+ AC_MSG_RESULT([yes])
+ ],
+ [
+ AC_MSG_RESULT([no])
+ AC_DEFINE([BROKEN_GETADDRINFO])
+ ],
+ [
+ AC_MSG_RESULT([cross-compiling, assuming yes])
+ ]
+ )
+fi
+
+if test "x$ac_cv_func_getaddrinfo" = "xyes" && \
+ test "x$check_for_aix_broken_getaddrinfo" = "x1"; then
+ AC_MSG_CHECKING([if getaddrinfo seems to work])
+ AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([[
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <errno.h>
+#include <netinet/in.h>
+
+#define TEST_PORT "2222"
+ ]], [[
+ int err, sock;
+ struct addrinfo *gai_ai, *ai, hints;
+ char ntop[NI_MAXHOST], strport[NI_MAXSERV], *name = NULL;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE;
+
+ err = getaddrinfo(name, TEST_PORT, &hints, &gai_ai);
+ if (err != 0) {
+ fprintf(stderr, "getaddrinfo failed (%s)", gai_strerror(err));
+ exit(1);
+ }
+
+ for (ai = gai_ai; ai != NULL; ai = ai->ai_next) {
+ if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
+ continue;
+
+ err = getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop,
+ sizeof(ntop), strport, sizeof(strport),
+ NI_NUMERICHOST|NI_NUMERICSERV);
+
+ if (ai->ai_family == AF_INET && err != 0) {
+ perror("getnameinfo");
+ exit(2);
+ }
+ }
+ exit(0);
+ ]])],
+ [
+ AC_MSG_RESULT([yes])
+ AC_DEFINE([AIX_GETNAMEINFO_HACK], [1],
+ [Define if you have a getaddrinfo that fails
+ for the all-zeros IPv6 address])
+ ],
+ [
+ AC_MSG_RESULT([no])
+ AC_DEFINE([BROKEN_GETADDRINFO])
+ ],
+ [
+ AC_MSG_RESULT([cross-compiling, assuming no])
+ ]
+ )
+fi
+#l2101
+
+#l2120
+# Search for OpenSSL
+saved_CPPFLAGS="$CPPFLAGS"
+saved_LDFLAGS="$LDFLAGS"
+AC_ARG_WITH([ssl-dir],
+ [ --with-ssl-dir=PATH Specify path to OpenSSL 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([*** OpenSSL 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 OpenSSL libcrypto (see config.log for details) ***])
+ ]
+ )
+ ]
+)
+
+# Determine OpenSSL header version
+AC_MSG_CHECKING([OpenSSL header version])
+AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([[
+#include <stdio.h>
+#include <string.h>
+#include <openssl/opensslv.h>
+#define DATA "conftest.sslincver"
+ ]], [[
+ FILE *fd;
+ int rc;
+
+ fd = fopen(DATA,"w");
+ if(fd == NULL)
+ exit(1);
+
+ if ((rc = fprintf(fd ,"%x (%s)\n", OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT)) <0)
+ exit(1);
+
+ exit(0);
+ ]])],
+ [
+ ssl_header_ver=`cat conftest.sslincver`
+ AC_MSG_RESULT([$ssl_header_ver])
+ ],
+ [
+ AC_MSG_RESULT([not found])
+ AC_MSG_ERROR([OpenSSL version header not found.])
+ ],
+ [
+ AC_MSG_WARN([cross compiling: not checking])
+ ]
+)
+
+# Determine OpenSSL library version
+AC_MSG_CHECKING([OpenSSL library version])
+AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([[
+#include <stdio.h>
+#include <string.h>
+#include <openssl/opensslv.h>
+#include <openssl/crypto.h>
+#define DATA "conftest.ssllibver"
+ ]], [[
+ FILE *fd;
+ int rc;
+
+ fd = fopen(DATA,"w");
+ if(fd == NULL)
+ exit(1);
+
+ if ((rc = fprintf(fd ,"%x (%s)\n", SSLeay(), SSLeay_version(SSLEAY_VERSION))) <0)
+ exit(1);
+
+ exit(0);
+ ]])],
+ [
+ ssl_library_ver=`cat conftest.ssllibver`
+ AC_MSG_RESULT([$ssl_library_ver])
+ ],
+ [
+ AC_MSG_RESULT([not found])
+ AC_MSG_ERROR([OpenSSL library not found.])
+ ],
+ [
+ AC_MSG_WARN([cross compiling: not checking])
+ ]
+)
+
+AC_ARG_WITH([openssl-header-check],
+ [ --without-openssl-header-check Disable OpenSSL version consistency check],
+ [ if test "x$withval" = "xno" ; then
+ openssl_check_nonfatal=1
+ fi
+ ]
+)
+
+# Sanity check OpenSSL headers
+AC_MSG_CHECKING([whether OpenSSL's headers match the library])
+AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([[
+#include <string.h>
+#include <openssl/opensslv.h>
+ ]], [[
+ exit(SSLeay() == OPENSSL_VERSION_NUMBER ? 0 : 1);
+ ]])],
+ [
+ AC_MSG_RESULT([yes])
+ ],
+ [
+ AC_MSG_RESULT([no])
+ if test "x$openssl_check_nonfatal" = "x"; then
+ AC_MSG_ERROR([Your OpenSSL headers do not match your
+library. Check config.log for details.
+If you are sure your installation is consistent, you can disable the check
+by running "./configure --without-openssl-header-check".
+Also see contrib/findssl.sh for help identifying header/library mismatches.
+])
+ else
+ AC_MSG_WARN([Your OpenSSL headers do not match your
+library. Check config.log for details.
+Also see contrib/findssl.sh for help identifying header/library mismatches.])
+ fi
+ ],
+ [
+ AC_MSG_WARN([cross compiling: not checking])
+ ]
+)
+
+AC_MSG_CHECKING([if programs using OpenSSL 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 OpenSSL 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"
+ ]
+ )
+ ]
+)
+#l2313
+
+##chl
+EXPERIMENTAL_GCM_CRYPTO=no
+AC_MSG_CHECKING([if programs using OpenSSL EVP_aes_256_gcm() will link])
+AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM([[ #include <openssl/evp.h> ]],
+ [[ EVP_aes_256_gcm(); ]])],
+ [
+ AC_MSG_RESULT([yes])
+ AC_DEFINE([HAVE_GCM_CRYPTO], [1],
+ [Define if you want to use GCM crypto support])
+ EXPERIMENTAL_GCM_CRYPTO=yes
+ ],
+ [
+ AC_MSG_RESULT([no])
+ ]
+)
+AM_CONDITIONAL([HAVE_GCM_CRYPTO], [test $EXPERIMENTAL_GCM_CRYPTO = yes])
+##chl
+
+##gilles
+OPENSSL_SUPPORTS_SNI=no
+AC_MSG_CHECKING([if programs using TLSEXT_NAMETYPE_host_name will link])
+AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM([[ #include <openssl/ssl.h> ]],
+ [[ SSL_CTX_set_tlsext_servername_callback(NULL, NULL); ]])],
+ [
+ AC_MSG_RESULT([yes])
+ AC_DEFINE([HAVE_TLSEXT_SERVERNAME], [1],
+ [Define if you want to enable TLS extension SERVERNAME])
+ OPENSSL_SUPPORTS_SNI=yes
+ ],
+ [
+ AC_MSG_RESULT([no])
+ ]
+)
+AM_CONDITIONAL([HAVE_TLSEXT_SERVERNAME], [test $OPENSSL_SUPPORTS_SNI = yes])
+##gilles
+
+##gilles
+AC_MSG_CHECKING([if SSL_OP_NO_TICKET is supported])
+AC_EGREP_CPP(HAVE_SSL_OP_NO_TICKET, [
+#include <openssl/ssl.h>
+#ifdef SSL_OP_NO_TICKET
+HAVE_SSL_OP_NO_TICKET
+#endif
+], [
+ AC_MSG_RESULT([yes])
+], [
+ AC_MSG_RESULT([no])
+ AC_DEFINE([SSL_OP_NO_TICKET], [0], [Defined to 0 if SSL_OP_NO_TICKET isn't supported by OpenSSL.])
+])
+##gilles
+
+#l2425
+# Some systems want crypt() from libcrypt, *not* the version in OpenSSL,
+# because the system crypt() is more featureful.
+if test "x$check_for_libcrypt_before" = "x1"; then
+ AC_CHECK_LIB([crypt], [crypt])
+fi
+
+# Some Linux systems (Slackware) need crypt() from libcrypt, *not* the
+# version in OpenSSL.
+if test "x$check_for_libcrypt_later" = "x1"; then
+ AC_CHECK_LIB([crypt], [crypt], [LIBS="$LIBS -lcrypt"])
+fi
+#l2435
+
+#l2499 (customized s/SSH/SMTP/)
+### Configure cryptographic random number support
+
+# Check wheter OpenSSL seeds itself
+AC_MSG_CHECKING([whether OpenSSL's PRNG is internally seeded])
+AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([[
+#include <string.h>
+#include <openssl/rand.h>
+ ]], [[
+ exit(RAND_status() == 1 ? 0 : 1);
+ ]])],
+ [
+ OPENSSL_SEEDS_ITSELF=yes
+ AC_MSG_RESULT([yes])
+ ],
+ [
+ AC_MSG_RESULT([no])
+ ],
+ [
+ AC_MSG_WARN([cross compiling: assuming yes])
+ # This is safe, since we will fatal() at runtime if
+ # OpenSSL is not seeded correctly.
+ OPENSSL_SEEDS_ITSELF=yes
+ ]
+)
+
+# PRNGD TCP socket
+AC_ARG_WITH([prngd-port],
+ [ --with-prngd-port=PORT read entropy from PRNGD/EGD TCP localhost:PORT],
+ [
+ case "$withval" in
+ no)
+ withval=""
+ ;;
+ [[0-9]]*)
+ ;;
+ *)
+ AC_MSG_ERROR([You must specify a numeric port number for --with-prngd-port])
+ ;;
+ esac
+ if test ! -z "$withval" ; then
+ PRNGD_PORT="$withval"
+ AC_DEFINE_UNQUOTED([PRNGD_PORT], [$PRNGD_PORT],
+ [Port number of PRNGD/EGD random number socket])
+ fi
+ ]
+)
+
+# PRNGD Unix domain socket
+AC_ARG_WITH([prngd-socket],
+ [ --with-prngd-socket=FILE read entropy from PRNGD/EGD socket FILE (default=/var/run/egd-pool)],
+ [
+ case "$withval" in
+ yes)
+ withval="/var/run/egd-pool"
+ ;;
+ no)
+ withval=""
+ ;;
+ /*)
+ ;;
+ *)
+ AC_MSG_ERROR([You must specify an absolute path to the entropy socket])
+ ;;
+ esac
+
+ if test ! -z "$withval" ; then
+ if test ! -z "$PRNGD_PORT" ; then
+ AC_MSG_ERROR([You may not specify both a PRNGD/EGD port and socket])
+ fi
+ if test ! -r "$withval" ; then
+ AC_MSG_WARN([Entropy socket is not readable])
+ fi
+ PRNGD_SOCKET="$withval"
+ AC_DEFINE_UNQUOTED([PRNGD_SOCKET], ["$PRNGD_SOCKET"],
+ [Location of PRNGD/EGD random number socket])
+ fi
+ ],
+ [
+ # Check for existing socket only if we don't have a random device already
+ if test "x$OPENSSL_SEEDS_ITSELF" != "xyes" ; then
+ AC_MSG_CHECKING([for PRNGD/EGD socket])
+ # Insert other locations here
+ for sock in /var/run/egd-pool /dev/egd-pool /etc/entropy; do
+ if test -r $sock && $TEST_MINUS_S_SH -c "test -S $sock -o -p $sock" ; then
+ PRNGD_SOCKET="$sock"
+ AC_DEFINE_UNQUOTED([PRNGD_SOCKET], ["$PRNGD_SOCKET"])
+ break;
+ fi
+ done
+ if test ! -z "$PRNGD_SOCKET" ; then
+ AC_MSG_RESULT([$PRNGD_SOCKET])
+ else
+ AC_MSG_RESULT([not found])
+ fi
+ fi
+ ]
+)
+
+# Which randomness source do we use?
+if test ! -z "$PRNGD_PORT" ; then
+ RAND_MSG="PRNGd port $PRNGD_PORT"
+elif test ! -z "$PRNGD_SOCKET" ; then
+ RAND_MSG="PRNGd socket $PRNGD_SOCKET"
+elif test ! -z "$OPENSSL_SEEDS_ITSELF" ; then
+ AC_DEFINE([OPENSSL_PRNG_ONLY], [1],
+ [Define if you want OpenSSL's internally seeded PRNG only])
+ RAND_MSG="OpenSSL internal ONLY"
+else
+ AC_MSG_ERROR([OpenSMTPD has no source of random numbers. Please configure OpenSSL with an entropy source or re-run configure using one of the --with-prngd-port or --with-prngd-socket options])
+fi
+
+# Check for PAM libs
+PAM_MSG="no"
+AC_ARG_WITH([pam],
+ [ --with-pam Enable PAM support ],
+ [
+ if test "x$withval" != "xno" ; then
+ if test "x$ac_cv_header_security_pam_appl_h" != "xyes" && \
+ 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 $ac_cv_lib_dl_dlopen = yes; then
+ case "$LIBS" in
+ *-ldl*)
+ # libdl already in LIBS
+ ;;
+ *)
+ SMTPDLIBS="$SMTPDLIBS -ldl"
+ ;;
+ esac
+ fi
+ fi
+ ]
+)
+
+# 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
+
+
+USE_PAM_SERVICE=smtpd
+AC_ARG_WITH([pam-service],
+ [ --with-pam-service=service Specify PAM service],
+ [
+ if test -n "$withval" && test "x$withval" != "xno" && \
+ test "x${withval}" != "xyes"; then
+ USE_PAM_SERVICE=$withval
+ fi
+ ]
+)
+AC_DEFINE_UNQUOTED([USE_PAM_SERVICE], ["$USE_PAM_SERVICE"], [pam service])
+AC_SUBST([USE_PAM_SERVICE])
+
+
+SMTPD_USER=_smtpd
+AC_ARG_WITH([privsep-user],
+ [ --with-privsep-user=user Specify non-privileged user for privilege separation],
+ [
+ if test -n "$withval" && test "x$withval" != "xno" && \
+ test "x${withval}" != "xyes"; then
+ SMTPD_USER=$withval
+ fi
+ ]
+)
+AC_DEFINE_UNQUOTED([SMTPD_USER], ["$SMTPD_USER"],
+ [non-privileged user for privilege separation])
+AC_SUBST([SMTPD_USER])
+#l2684
+
+SMTPD_QUEUE_USER=_smtpq
+AC_ARG_WITH([queue-user],
+ [ --with-queue-user=user Specify non-privileged user for queue process],
+ [
+ if test -n "$withval" && test "x$withval" != "xno" && \
+ test "x${withval}" != "xyes"; 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])
+
+#l2869 (customized)
+# Check for long long datatypes
+AC_CHECK_TYPES([long long, unsigned long long, long double])
+
+# Check datatype sizes
+AC_CHECK_SIZEOF([short int], [2])
+AC_CHECK_SIZEOF([int], [4])
+AC_CHECK_SIZEOF([long int], [4])
+AC_CHECK_SIZEOF([long long int], [8])
+
+# Sanity check long long for some platforms (AIX)
+if test "x$ac_cv_sizeof_long_long_int" = "x4" ; then
+ ac_cv_sizeof_long_long_int=0
+fi
+
+# 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>
+/* 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
+
+
+# More checks for data types
+AC_CACHE_CHECK([for u_int type], ac_cv_have_u_int, [
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <sys/types.h> ]],
+ [[ u_int a; a = 1;]])],
+ [ ac_cv_have_u_int="yes" ], [ ac_cv_have_u_int="no"
+ ])
+])
+if test "x$ac_cv_have_u_int" = "xyes" ; then
+ AC_DEFINE([HAVE_U_INT], [1], [define if you have u_int data type])
+ have_u_int=1
+fi
+
+AC_CACHE_CHECK([for intXX_t types], ac_cv_have_intxx_t, [
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <sys/types.h> ]],
+ [[ int8_t a; int16_t b; int32_t c; a = b = c = 1;]])],
+ [ ac_cv_have_intxx_t="yes" ], [ ac_cv_have_intxx_t="no"
+ ])
+])
+if test "x$ac_cv_have_intxx_t" = "xyes" ; then
+ AC_DEFINE([HAVE_INTXX_T], [1], [define if you have intxx_t data type])
+ have_intxx_t=1
+fi
+
+if (test -z "$have_intxx_t" && \
+ test "x$ac_cv_header_stdint_h" = "xyes")
+then
+ AC_MSG_CHECKING([for intXX_t types in stdint.h])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <stdint.h> ]],
+ [[ int8_t a; int16_t b; int32_t c; a = b = c = 1;]])],
+ [
+ AC_DEFINE([HAVE_INTXX_T])
+ AC_MSG_RESULT([yes])
+ ], [ AC_MSG_RESULT([no])
+ ])
+fi
+
+AC_CACHE_CHECK([for int64_t type], ac_cv_have_int64_t, [
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#include <sys/socket.h>
+#ifdef HAVE_SYS_BITYPES_H
+# include <sys/bitypes.h>
+#endif
+ ]], [[
+int64_t a; a = 1;
+ ]])],
+ [ ac_cv_have_int64_t="yes" ], [ ac_cv_have_int64_t="no"
+ ])
+])
+if test "x$ac_cv_have_int64_t" = "xyes" ; then
+ AC_DEFINE([HAVE_INT64_T], [1], [define if you have int64_t data type])
+fi
+
+AC_CACHE_CHECK([for u_intXX_t types], ac_cv_have_u_intxx_t, [
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <sys/types.h> ]],
+ [[ u_int8_t a; u_int16_t b; u_int32_t c; a = b = c = 1;]])],
+ [ ac_cv_have_u_intxx_t="yes" ], [ ac_cv_have_u_intxx_t="no"
+ ])
+])
+if test "x$ac_cv_have_u_intxx_t" = "xyes" ; then
+ AC_DEFINE([HAVE_U_INTXX_T], [1], [define if you have u_intxx_t data type])
+ have_u_intxx_t=1
+fi
+
+if test -z "$have_u_intxx_t" ; then
+ AC_MSG_CHECKING([for u_intXX_t types in sys/socket.h])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <sys/socket.h> ]],
+ [[ u_int8_t a; u_int16_t b; u_int32_t c; a = b = c = 1;]])],
+ [
+ AC_DEFINE([HAVE_U_INTXX_T])
+ AC_MSG_RESULT([yes])
+ ], [ AC_MSG_RESULT([no])
+ ])
+fi
+
+AC_CACHE_CHECK([for u_int64_t types], ac_cv_have_u_int64_t, [
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <sys/types.h> ]],
+ [[ u_int64_t a; a = 1;]])],
+ [ ac_cv_have_u_int64_t="yes" ], [ ac_cv_have_u_int64_t="no"
+ ])
+])
+if test "x$ac_cv_have_u_int64_t" = "xyes" ; then
+ AC_DEFINE([HAVE_U_INT64_T], [1], [define if you have u_int64_t data type])
+ have_u_int64_t=1
+fi
+
+if test -z "$have_u_int64_t" ; then
+ AC_MSG_CHECKING([for u_int64_t type in sys/bitypes.h])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <sys/bitypes.h> ]],
+ [[ u_int64_t a; a = 1]])],
+ [
+ AC_DEFINE([HAVE_U_INT64_T])
+ AC_MSG_RESULT([yes])
+ ], [ AC_MSG_RESULT([no])
+ ])
+fi
+
+if test -z "$have_u_intxx_t" ; then
+ AC_CACHE_CHECK([for uintXX_t types], ac_cv_have_uintxx_t, [
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+ ]], [[
+ uint8_t a;
+ uint16_t b;
+ uint32_t c;
+ a = b = c = 1;
+ ]])],
+ [ ac_cv_have_uintxx_t="yes" ], [ ac_cv_have_uintxx_t="no"
+ ])
+ ])
+ if test "x$ac_cv_have_uintxx_t" = "xyes" ; then
+ AC_DEFINE([HAVE_UINTXX_T], [1],
+ [define if you have uintxx_t data type])
+ fi
+fi
+
+if test -z "$have_uintxx_t" ; then
+ AC_MSG_CHECKING([for uintXX_t types in stdint.h])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <stdint.h> ]],
+ [[ uint8_t a; uint16_t b; uint32_t c; a = b = c = 1;]])],
+ [
+ AC_DEFINE([HAVE_UINTXX_T])
+ AC_MSG_RESULT([yes])
+ ], [ AC_MSG_RESULT([no])
+ ])
+fi
+
+if (test -z "$have_u_intxx_t" || test -z "$have_intxx_t" && \
+ test "x$ac_cv_header_sys_bitypes_h" = "xyes")
+then
+ AC_MSG_CHECKING([for intXX_t and u_intXX_t types in sys/bitypes.h])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/bitypes.h>
+ ]], [[
+ int8_t a; int16_t b; int32_t c;
+ u_int8_t e; u_int16_t f; u_int32_t g;
+ a = b = c = e = f = g = 1;
+ ]])],
+ [
+ AC_DEFINE([HAVE_U_INTXX_T])
+ AC_DEFINE([HAVE_INTXX_T])
+ AC_MSG_RESULT([yes])
+ ], [AC_MSG_RESULT([no])
+ ])
+fi
+
+
+AC_CACHE_CHECK([for u_char], ac_cv_have_u_char, [
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <sys/types.h> ]],
+ [[ u_char foo; foo = 125; ]])],
+ [ ac_cv_have_u_char="yes" ], [ ac_cv_have_u_char="no"
+ ])
+])
+if test "x$ac_cv_have_u_char" = "xyes" ; then
+ AC_DEFINE([HAVE_U_CHAR], [1], [define if you have u_char data type])
+fi
+
+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_CACHE_CHECK([for size_t], ac_cv_have_size_t, [
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <sys/types.h> ]],
+ [[ size_t foo; foo = 1235; ]])],
+ [ ac_cv_have_size_t="yes" ], [ ac_cv_have_size_t="no"
+ ])
+])
+if test "x$ac_cv_have_size_t" = "xyes" ; then
+ AC_DEFINE([HAVE_SIZE_T], [1], [define if you have size_t data type])
+fi
+
+AC_CACHE_CHECK([for ssize_t], ac_cv_have_ssize_t, [
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <sys/types.h> ]],
+ [[ ssize_t foo; foo = 1235; ]])],
+ [ ac_cv_have_ssize_t="yes" ], [ ac_cv_have_ssize_t="no"
+ ])
+])
+if test "x$ac_cv_have_ssize_t" = "xyes" ; then
+ AC_DEFINE([HAVE_SSIZE_T], [1], [define if you have ssize_t data type])
+fi
+
+AC_CACHE_CHECK([for clock_t], ac_cv_have_clock_t, [
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <time.h> ]],
+ [[ clock_t foo; foo = 1235; ]])],
+ [ ac_cv_have_clock_t="yes" ], [ ac_cv_have_clock_t="no"
+ ])
+])
+if test "x$ac_cv_have_clock_t" = "xyes" ; then
+ AC_DEFINE([HAVE_CLOCK_T], [1], [define if you have clock_t data type])
+fi
+
+AC_CACHE_CHECK([for sa_family_t], ac_cv_have_sa_family_t, [
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <sys/socket.h>
+ ]], [[ sa_family_t foo; foo = 1235; ]])],
+ [ ac_cv_have_sa_family_t="yes" ],
+ [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+ ]], [[ sa_family_t foo; foo = 1235; ]])],
+ [ ac_cv_have_sa_family_t="yes" ],
+ [ ac_cv_have_sa_family_t="no" ]
+ )
+ ])
+])
+if test "x$ac_cv_have_sa_family_t" = "xyes" ; then
+ AC_DEFINE([HAVE_SA_FAMILY_T], [1],
+ [define if you have sa_family_t data type])
+fi
+
+AC_CACHE_CHECK([for pid_t], ac_cv_have_pid_t, [
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <sys/types.h> ]],
+ [[ pid_t foo; foo = 1235; ]])],
+ [ ac_cv_have_pid_t="yes" ], [ ac_cv_have_pid_t="no"
+ ])
+])
+if test "x$ac_cv_have_pid_t" = "xyes" ; then
+ AC_DEFINE([HAVE_PID_T], [1], [define if you have pid_t data type])
+fi
+
+AC_CACHE_CHECK([for mode_t], ac_cv_have_mode_t, [
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <sys/types.h> ]],
+ [[ mode_t foo; foo = 1235; ]])],
+ [ ac_cv_have_mode_t="yes" ], [ ac_cv_have_mode_t="no"
+ ])
+])
+if test "x$ac_cv_have_mode_t" = "xyes" ; then
+ AC_DEFINE([HAVE_MODE_T], [1], [define if you have mode_t data type])
+fi
+
+
+AC_CACHE_CHECK([for struct sockaddr_storage], ac_cv_have_struct_sockaddr_storage, [
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <sys/socket.h>
+ ]], [[ struct sockaddr_storage s; ]])],
+ [ ac_cv_have_struct_sockaddr_storage="yes" ],
+ [ ac_cv_have_struct_sockaddr_storage="no"
+ ])
+])
+if test "x$ac_cv_have_struct_sockaddr_storage" = "xyes" ; then
+ AC_DEFINE([HAVE_STRUCT_SOCKADDR_STORAGE], [1],
+ [define if you have struct sockaddr_storage data type])
+fi
+
+AC_CACHE_CHECK([for struct sockaddr_in6], ac_cv_have_struct_sockaddr_in6, [
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <netinet/in.h>
+ ]], [[ struct sockaddr_in6 s; s.sin6_family = 0; ]])],
+ [ ac_cv_have_struct_sockaddr_in6="yes" ],
+ [ ac_cv_have_struct_sockaddr_in6="no"
+ ])
+])
+if test "x$ac_cv_have_struct_sockaddr_in6" = "xyes" ; then
+ AC_DEFINE([HAVE_STRUCT_SOCKADDR_IN6], [1],
+ [define if you have struct sockaddr_in6 data type])
+fi
+
+AC_CACHE_CHECK([for struct in6_addr], ac_cv_have_struct_in6_addr, [
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <netinet/in.h>
+ ]], [[ struct in6_addr s; s.s6_addr[0] = 0; ]])],
+ [ ac_cv_have_struct_in6_addr="yes" ],
+ [ ac_cv_have_struct_in6_addr="no"
+ ])
+])
+if test "x$ac_cv_have_struct_in6_addr" = "xyes" ; then
+ AC_DEFINE([HAVE_STRUCT_IN6_ADDR], [1],
+ [define if you have struct in6_addr data type])
+
+dnl Now check for sin6_scope_id
+ AC_CHECK_MEMBERS([struct sockaddr_in6.sin6_scope_id], , ,
+ [
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#include <netinet/in.h>
+ ])
+fi
+
+AC_CACHE_CHECK([for struct addrinfo], ac_cv_have_struct_addrinfo, [
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+ ]], [[ struct addrinfo s; s.ai_flags = AI_PASSIVE; ]])],
+ [ ac_cv_have_struct_addrinfo="yes" ],
+ [ ac_cv_have_struct_addrinfo="no"
+ ])
+])
+if test "x$ac_cv_have_struct_addrinfo" = "xyes" ; then
+ AC_DEFINE([HAVE_STRUCT_ADDRINFO], [1],
+ [define if you have struct addrinfo data type])
+fi
+
+AC_CACHE_CHECK([for struct timeval], ac_cv_have_struct_timeval, [
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <sys/time.h> ]],
+ [[ struct timeval tv; tv.tv_sec = 1;]])],
+ [ ac_cv_have_struct_timeval="yes" ],
+ [ ac_cv_have_struct_timeval="no"
+ ])
+])
+if test "x$ac_cv_have_struct_timeval" = "xyes" ; then
+ AC_DEFINE([HAVE_STRUCT_TIMEVAL], [1], [define if you have struct timeval])
+ have_struct_timeval=1
+fi
+
+AC_CHECK_TYPES([struct timespec])
+
+# We need int64_t or else certian parts of the compile will fail.
+if test "x$ac_cv_have_int64_t" = "xno" && \
+ test "x$ac_cv_sizeof_long_int" != "x8" && \
+ test "x$ac_cv_sizeof_long_long_int" = "x0" ; then
+ echo "OpenSMTPD requires int64_t support. Contact your vendor or install"
+ echo "an alternative compiler (I.E., GCC) before continuing."
+ echo ""
+ exit 1;
+else
+dnl test snprintf (broken on SCO w/gcc)
+ AC_RUN_IFELSE(
+ [AC_LANG_SOURCE([[
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_SNPRINTF
+main()
+{
+ char buf[50];
+ char expected_out[50];
+ int mazsize = 50 ;
+#if (SIZEOF_LONG_INT == 8)
+ long int num = 0x7fffffffffffffff;
+#else
+ long long num = 0x7fffffffffffffffll;
+#endif
+ strcpy(expected_out, "9223372036854775807");
+ snprintf(buf, mazsize, "%lld", num);
+ if(strcmp(buf, expected_out) != 0)
+ exit(1);
+ exit(0);
+}
+#else
+main() { exit(0); }
+#endif
+ ]])], [ true ], [ AC_DEFINE([BROKEN_SNPRINTF]) ],
+ AC_MSG_WARN([cross compiling: Assuming working snprintf()])
+ )
+fi
+#l3349
+
+#l3371
+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_MEMBER([struct __res_state.retrans], [], [AC_DEFINE([__res_state], [state],
+ [Define if we don't have struct __res_state in resolv.h])],
+[[
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+]])
+
+AC_CACHE_CHECK([for ss_family field in struct sockaddr_storage],
+ ac_cv_have_ss_family_in_struct_ss, [
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <sys/socket.h>
+ ]], [[ struct sockaddr_storage s; s.ss_family = 1; ]])],
+ [ ac_cv_have_ss_family_in_struct_ss="yes" ],
+ [ ac_cv_have_ss_family_in_struct_ss="no" ])
+])
+if test "x$ac_cv_have_ss_family_in_struct_ss" = "xyes" ; then
+ AC_DEFINE([HAVE_SS_FAMILY_IN_SS], [1], [Fields in struct sockaddr_storage])
+fi
+
+AC_CACHE_CHECK([for __ss_family field in struct sockaddr_storage],
+ ac_cv_have___ss_family_in_struct_ss, [
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <sys/socket.h>
+ ]], [[ struct sockaddr_storage s; s.__ss_family = 1; ]])],
+ [ ac_cv_have___ss_family_in_struct_ss="yes" ],
+ [ ac_cv_have___ss_family_in_struct_ss="no"
+ ])
+])
+if test "x$ac_cv_have___ss_family_in_struct_ss" = "xyes" ; then
+ AC_DEFINE([HAVE___SS_FAMILY_IN_SS], [1],
+ [Fields in struct sockaddr_storage])
+fi
+
+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>
+ ]], [[
+#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_MSG_CHECKING([if struct statvfs.f_fsid is integral type])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/param.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+#ifdef HAVE_SYS_STATVFS_H
+#include <sys/statvfs.h>
+#endif
+ ]], [[ struct statvfs s; s.f_fsid = 0; ]])],
+ [ AC_MSG_RESULT([yes]) ],
+ [ AC_MSG_RESULT([no])
+
+ AC_MSG_CHECKING([if fsid_t has member val])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <sys/statvfs.h>
+ ]], [[ fsid_t t; t.val[0] = 0; ]])],
+ [ AC_MSG_RESULT([yes])
+ AC_DEFINE([FSID_HAS_VAL], [1], [fsid_t has member val]) ],
+ [ AC_MSG_RESULT([no]) ])
+
+ AC_MSG_CHECKING([if f_fsid has member __val])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <sys/statvfs.h>
+ ]], [[ fsid_t t; t.__val[0] = 0; ]])],
+ [ AC_MSG_RESULT([yes])
+ AC_DEFINE([FSID_HAS___VAL], [1], [fsid_t has member __val]) ],
+ [ AC_MSG_RESULT([no]) ])
+])
+
+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>
+ ]], [[
+#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([[]],
+ [[ 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
+#l3575
+
+##chl part
+AC_CHECK_TYPES([struct ifgroupreq])
+
+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> ]
+)
+##chl part
+
+
+#l3820
+# Looking for programs, paths and files
+
+PRIVSEP_PATH=/var/empty
+AC_ARG_WITH([privsep-path],
+ [ --with-privsep-path=xxx Path for privilege separation chroot (default=/var/empty)],
+ [
+ if test -n "$withval" && test "x$withval" != "xno" && \
+ test "x${withval}" != "xyes"; then
+ PRIVSEP_PATH=$withval
+ fi
+ ]
+)
+AC_SUBST([PRIVSEP_PATH])
+#l3832
+
+#l3855
+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])
+#l3864
+
+#l3876
+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([maildir],
+ [ --with-maildir=/path/to/mail Specify your system mail directory],
+ [
+ if test "X$withval" != X && test "x$withval" != xno && \
+ test "x${withval}" != xyes; then
+ AC_DEFINE_UNQUOTED([MAIL_DIRECTORY], ["$withval"],
+ [Set this to your mail directory if you do not have _PATH_MAILDIR])
+ fi
+ ],[
+ if test "X$maildir" != "X"; then
+ AC_DEFINE_UNQUOTED([MAIL_DIRECTORY], ["$maildir"])
+ else
+ AC_MSG_CHECKING([Discovering system mail directory])
+ AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([[
+#include <stdio.h>
+#include <string.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([Using: $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([Using: default value of /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
+#l3956
+
+#l3986
+# 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])
+#l4017
+
+#l4242
+# Whether to enable BSD auth support
+BSD_AUTH_MSG=no
+AC_ARG_WITH([bsd-auth],
+ [ --with-bsd-auth Enable BSD auth support],
+ [
+ if test "x$withval" != "xno" ; then
+ AC_DEFINE([BSD_AUTH], [1],
+ [Define if you have BSD auth support])
+ BSD_AUTH_MSG=yes
+ fi
+ ]
+)
+
+# 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([sock-dir],
+ [ --with-sock-dir=PATH Specify location of smtpd.sock file],
+ [
+ if test -n "$withval" && test "x$withval" != "xno" && \
+ test "x${withval}" != "xyes"; 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])
+#l4280
+
+
+CA_FILE=/etc/ssl/cert.pem
+AC_ARG_WITH([ca-file],
+ [ --with-ca-file=FILE Path for certificate file (default=/etc/ssl/cert.pem)],
+ [
+ if test -n "$withval" && test "x$withval" != "xno" && \
+ test "x${withval}" != "xyes"; then
+ CA_FILE=$withval
+ fi
+ ]
+)
+AC_SUBST([CA_FILE])
+
+
+# Where to place spooler
+spooldir=/var/spool/smtpd
+AC_ARG_WITH([spooldir],
+ [ --with-spooldir=PATH Specify location of spooler directory],
+ [
+ if test -n "$withval" && test "x$withval" != "xno" && \
+ test "x${withval}" != "xyes"; 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])
+
+
+
+
+# Whether to enable *experimental* LDAP support
+EXPERIMENTAL_LDAP=no
+AC_ARG_WITH([experimental-ldap],
+ [ --with-experimental-ldap Enable experimental LDAP support],
+ [
+ if test "x$withval" != "xno" ; then
+ AC_DEFINE([HAVE_LDAP], [1],
+ [Define if you have experimental LDAP support])
+ EXPERIMENTAL_LDAP=yes
+ fi
+ ]
+)
+AM_CONDITIONAL([HAVE_LDAP], [test $EXPERIMENTAL_LDAP = yes])
+
+# Whether to enable *experimental* MySQL support
+EXPERIMENTAL_MYSQL=no
+AC_ARG_WITH([experimental-mysql],
+ [ --with-experimental-mysql Enable experimental MySQL support],
+ [
+ if test "x$withval" != "xno" ; then
+ AC_DEFINE([HAVE_MYSQL], [1],
+ [Define if you have experimental MySQL support])
+ EXPERIMENTAL_MYSQL=yes
+ fi
+ ]
+)
+AM_CONDITIONAL([HAVE_MYSQL], [test $EXPERIMENTAL_MYSQL = yes])
+
+# Whether to enable *experimental* PostgreSQL support
+EXPERIMENTAL_POSTGRES=no
+AC_ARG_WITH([experimental-postgres],
+ [ --with-experimental-postgres Enable experimental PostgreSQL support],
+ [
+ if test "x$withval" != "xno" ; then
+ AC_DEFINE([HAVE_POSTGRES], [1],
+ [Define if you have experimental PostgreSQL support])
+ EXPERIMENTAL_POSTGRES=yes
+ fi
+ ]
+)
+AM_CONDITIONAL([HAVE_POSTGRES], [test $EXPERIMENTAL_POSTGRES = yes])
+
+# Whether to enable *experimental* SQLite support
+EXPERIMENTAL_SQLITE=no
+AC_ARG_WITH([experimental-sqlite],
+ [ --with-experimental-sqlite Enable experimental SQLite support],
+ [
+ if test "x$withval" != "xno" ; then
+ AC_DEFINE([HAVE_SQLITE], [1],
+ [Define if you have experimental SQLite support])
+ AC_CHECK_HEADER([sqlite3.h],
+ [AC_DEFINE([HAVE_SQLITE3_H], [], [if you have the <sqlite3.h> header file]) ],
+ [AC_MSG_ERROR([*** sqlite3.h missing - please install first or check config.log ***])]
+ )
+
+ save_LIBS="$LIBS"
+ saved_CPPFLAGS="$CPPFLAGS"
+ saved_LDFLAGS="$LDFLAGS"
+ AC_CHECK_LIB([sqlite3], [sqlite3_open], ,
+ [
+ dnl Check default sqlite 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 -lsqlite3"
+ AC_TRY_LINK_FUNC([sqlite3_open], [AC_DEFINE([HAVE_LIBSQLITE3])],
+ [
+ AC_MSG_ERROR([*** sqlite3 missing - please install first or check config.log ***])
+ ]
+ )
+ ]
+ )
+ CPPFLAGS="$saved_CPPFLAGS"
+ LDFLAGS="$saved_LDFLAGS"
+ LIBS="$save_LIBS"
+ EXPERIMENTAL_SQLITE=yes
+ fi
+ ]
+)
+AM_CONDITIONAL([HAVE_SQLITE], [test $EXPERIMENTAL_SQLITE = yes])
+
+# Whether to enable *experimental* Redis support
+EXPERIMENTAL_REDIS=no
+AC_ARG_WITH([experimental-redis],
+ [ --with-experimental-redis Enable experimental Redis support],
+ [
+ if test "x$withval" != "xno" ; then
+ AC_DEFINE([HAVE_REDIS], [1],
+ [Define if you have experimental Redis support])
+ EXPERIMENTAL_REDIS=yes
+ fi
+ ]
+)
+AM_CONDITIONAL([HAVE_REDIS], [test $EXPERIMENTAL_REDIS = yes])
+
+# Whether to enable *experimental* Redis support
+EXPERIMENTAL_SOCKETMAP=no
+AC_ARG_WITH([experimental-socketmap],
+ [ --with-experimental-socketmap Enable experimental socketmap support],
+ [
+ if test "x$withval" != "xno" ; then
+ AC_DEFINE([HAVE_SOCKETMAP], [1],
+ [Define if you have experimental socketmap support])
+ EXPERIMENTAL_SOCKETMAP=yes
+ fi
+ ]
+)
+AM_CONDITIONAL([HAVE_SOCKETMAP], [test $EXPERIMENTAL_SOCKETMAP = yes])
+
+
+dnl AC_DEFINE([_GNU_SOURCE], [], [Enable GNU Extensions])
+
+
+#l4553
+dnl Adding -Werror to CFLAGS early prevents configure tests from running.
+dnl Add now.
+CFLAGS="$CFLAGS $werror_flags"
+
+if test "x$ac_cv_func_getaddrinfo" != "xyes" ; then
+ TEST_SSH_IPV6=no
+else
+ TEST_SSH_IPV6=yes
+fi
+AC_CHECK_DECL([BROKEN_GETADDRINFO], [TEST_SSH_IPV6=no])
+AC_SUBST([TEST_SSH_IPV6], [$TEST_SSH_IPV6])
+AC_SUBST([UNSUPPORTED_ALGORITHMS], [$unsupported_algorithms])
+
+AC_EXEEXT
+#l4566
+
+##chl (still based on portable OpenSSH's configure.ac)
+AC_MSG_CHECKING([if inet_net_pton will link])
+AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <netdb.h>
+#include <resolv.h>
+ ]], [[
+ inet_net_pton (0, 0, 0, 0, 0);
+ ]])],
+ AC_MSG_RESULT([yes]),
+ [AC_MSG_RESULT([no])
+ saved_LIBS="$LIBS"
+ LIBS="$LIBS -lresolv"
+ AC_MSG_CHECKING([for inet_net_pton in -lresolv])
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <netdb.h>
+#include <resolv.h>
+ ]], [[
+ inet_net_pton (0, 0, 0, 0, 0);
+ ]])],
+ [AC_MSG_RESULT([yes])],
+ [LIBS="$saved_LIBS"
+ AC_MSG_RESULT([no])])
+ ])
+##end of chl
+
+##chl (based on OpenSSL checks, see above)
+# Search for libevent
+saved_CPPFLAGS="$CPPFLAGS"
+saved_LDFLAGS="$LDFLAGS"
+AC_ARG_WITH([libevent-dir],
+ [ --with-libevent-dir=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
+ fi
+ ]
+)
+
+LIBS="-levent $LIBS"
+
+# Determine libevent header version
+AC_MSG_CHECKING([libevent header version])
+AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([[
+#include <stdio.h>
+#include <string.h>
+#include <event.h>
+#define DATA "conftest.libeventincver"
+ ]], [[
+ FILE *fd;
+ int rc;
+
+ fd = fopen(DATA,"w");
+ if(fd == NULL)
+ exit(1);
+
+ if ((rc = fprintf(fd ,"%s\n", _EVENT_VERSION)) <0)
+ exit(1);
+
+ exit(0);
+ ]])],
+ [
+ libevent_header_ver=`cat conftest.libeventincver`
+ AC_MSG_RESULT([$libevent_header_ver])
+ ],
+ [
+ AC_MSG_RESULT([not found])
+ AC_MSG_ERROR([libevent version header not found.])
+ ],
+ [
+ AC_MSG_WARN([cross compiling: not checking])
+ ]
+)
+
+# Determine libevent library version
+AC_MSG_CHECKING([libevent library version])
+AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([[
+#include <stdio.h>
+#include <string.h>
+#include <event.h>
+#define DATA "conftest.libeventlibver"
+ ]], [[
+ FILE *fd;
+ int rc;
+
+ fd = fopen(DATA,"w");
+ if(fd == NULL)
+ exit(1);
+
+ if ((rc = fprintf(fd ,"%s\n", event_get_version())) <0)
+ exit(1);
+
+ exit(0);
+ ]])],
+ [
+ libevent_library_ver=`cat conftest.libeventlibver`
+ AC_MSG_RESULT([$libevent_library_ver])
+ ],
+ [
+ AC_MSG_RESULT([not found])
+ AC_MSG_ERROR([libevent library not found.])
+ ],
+ [
+ AC_MSG_WARN([cross compiling: not checking])
+ ]
+)
+
+libevent_major_version=`cat conftest.libeventlibver|head -c1 || echo 1`
+
+AC_DEFINE_UNQUOTED([LIBEVENT_MAJOR_VERSION], [$libevent_major_version], [Define libevent major version])
+
+AC_ARG_WITH([libevent-header-check],
+ [ --without-libevent-header-check Disable libevent version consistency check],
+ [ if test "x$withval" = "xno" ; then
+ libevent_check_nonfatal=1
+ fi
+ ]
+)
+
+# Sanity check libevent headers
+AC_MSG_CHECKING([whether libevent's headers match the library])
+AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([[
+#if LIBEVENT_MAJOR_VERSION < 2
+#include <event.h>
+#else
+#include <event2/event.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+ ]], [[
+ exit(strcmp(event_get_version(), _EVENT_VERSION) == 0 ? 0 : 1);
+ ]])],
+ [
+ AC_MSG_RESULT([yes])
+ ],
+ [
+ AC_MSG_RESULT([no])
+ if test "x$libevent_check_nonfatal" = "x"; then
+ AC_MSG_ERROR([Your libevent headers do not match your
+library. Check config.log for details.
+If you are sure your installation is consistent, you can disable the check
+by running "./configure --without-libevent-header-check".])
+ else
+ AC_MSG_WARN([Your libevent headers do not match your
+library. Check config.log for details.])
+ fi
+ ],
+ [
+ AC_MSG_WARN([cross compiling: not checking])
+ ]
+)
+
+AC_MSG_CHECKING([if programs using libevent functions will link])
+AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM([[
+#if LIBEVENT_MAJOR_VERSION < 2
+#include <event.h>
+#else
+#include <event2/event.h>
+#endif
+ ]], [[
+ event_base_new();
+ ]])],
+ [
+ AC_MSG_RESULT([yes])
+ ],
+ [
+ AC_MSG_RESULT([no])
+ ]
+)
+
+# 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) ***])
+])])])
+
+
+save_LIBS="$LIBS"
+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
+
+LIBS="$LIBS -l$DB_LIB"
+
+LIBS="$LIBS ${SMTPDLIBS}"
+##end of chl
+
+AC_MSG_CHECKING([if RES_USE_EDNS0 is defined in resolv.h])
+AC_EGREP_CPP(HAVE_RES_USE_EDNS0, [
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#ifdef RES_USE_EDNS0
+HAVE_RES_USE_EDNS0
+#endif
+], [
+ AC_MSG_RESULT([yes])
+], [
+ AC_MSG_RESULT([no])
+ AC_DEFINE([RES_USE_EDNS0], [0], [Defined to 0 if RES_USE_EDNS0 isn't a supported resolver flag.])
+])
+
+
+AC_MSG_CHECKING([if RES_USE_DNSSEC is defined in resolv.h])
+AC_EGREP_CPP(HAVE_RES_USE_DNSSEC, [
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#ifdef RES_USE_DNSSEC
+HAVE_RES_USE_DNSSEC
+#endif
+], [
+ AC_MSG_RESULT([yes])
+], [
+ AC_MSG_RESULT([no])
+ AC_DEFINE([RES_USE_DNSSEC], [0], [Defined to 0 if RES_USE_DNSSEC isn't a supported resolver flag.])
+])
+
+
+use_mailwrapper=0
+AC_ARG_WITH([mailwrapper],
+ [ --with-mailwrapper Install smtpctl and makemap utilities in libexec],
+ [ if test "x$withval" = "xyes"; then
+ use_mailwrapper=1
+ fi
+ ]
+)
+AM_CONDITIONAL([HAVE_MAILWRAPPER], [test $use_mailwrapper = 1])
+
+AC_CONFIG_FILES([Makefile
+ openbsd-compat/Makefile
+ mk/Makefile
+ mk/smtpd/Makefile
+ mk/smtpctl/Makefile
+ mk/makemap/Makefile
+ mk/backends/Makefile
+ mk/backends/queue-null/Makefile
+ mk/backends/queue-ram/Makefile
+ mk/backends/queue-stub/Makefile
+ mk/backends/scheduler-ram/Makefile
+ mk/backends/scheduler-stub/Makefile
+ mk/backends/table-ldap/Makefile
+ mk/backends/table-mysql/Makefile
+ mk/backends/table-passwd/Makefile
+ mk/backends/table-postgres/Makefile
+ mk/backends/table-sqlite/Makefile
+ mk/backends/table-stub/Makefile
+ mk/backends/table-redis/Makefile
+ mk/filters/Makefile
+ mk/filters/dnsbl/Makefile
+ mk/filters/stub/Makefile
+ mk/filters/trace/Makefile
+ mk/filters/monkey/Makefile
+ contrib/Makefile
+ contrib/libexec/Makefile
+ contrib/libexec/mail.local/Makefile
+ contrib/libexec/encrypt/Makefile
+ ])
+
+#l4570
+AC_OUTPUT
+
+# Print summary of options
+
+# Someone please show me a better way :)
+A=`eval echo ${prefix}` ; A=`eval echo ${A}`
+B=`eval echo ${bindir}` ; B=`eval echo ${B}`
+C=`eval echo ${sbindir}` ; C=`eval echo ${C}`
+D=`eval echo ${sysconfdir}` ; D=`eval echo ${D}`
+E=`eval echo ${libexecdir}/${PACKAGE}/mail.local` ; E=`eval echo ${E}`
+F=`eval echo ${libexecdir}/${PACKAGE}/encrypt` ; F=`eval echo ${F}`
+G=`eval echo ${mandir}/${mansubdir}X` ; G=`eval echo ${G}`
+H=`eval echo ${sockdir}` ; H=`eval echo ${H}`
+I=`eval echo ${PRIVSEP_PATH}` ; I=`eval echo ${I}`
+J=`eval echo ${user_path}` ; J=`eval echo ${J}`
+K=`eval echo ${superuser_path}` ; K=`eval echo ${K}`
+
+echo ""
+echo "OpenSMTPD has been configured with the following options:"
+echo " User binaries: $B"
+echo " System binaries: $C"
+echo " Configuration files: $D"
+echo " mail.local program: $E"
+echo " encrypt program: $F"
+echo " Manual pages: $G"
+echo " smtpd.sock dir: $H"
+echo " Privilege separation chroot path: $I"
+echo " Manpage format: $MANTYPE"
+echo " PAM support: $PAM_MSG"
+echo " BSD Auth support: $BSD_AUTH_MSG"
+echo " Random number source: $RAND_MSG"
+
+echo ""
+
+echo " Host: ${host}"
+echo " Compiler: ${CC}"
+echo " Compiler flags: ${CFLAGS}"
+echo "Preprocessor flags: ${CPPFLAGS}"
+echo " Linker flags: ${LDFLAGS}"
+echo " Libraries: ${LIBS}"
+echo ""
+
+if test "x$MAKE_PACKAGE_SUPPORTED" = "xyes" ; then
+ echo "SVR4 style packages are supported with \"make package\""
+ echo ""
+fi
+
+if test "x$PAM_MSG" = "xyes" ; then
+ echo "PAM is enabled. You may need to install a PAM control file "
+ echo "for smtpd, otherwise password authentication may fail. "
+# echo "Example PAM control files can be found in the contrib/ "
+# echo "subdirectory"
+ echo ""
+fi
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/lib/CVS/Entries b/contrib/lib/CVS/Entries
new file mode 100644
index 00000000..8c4d7449
--- /dev/null
+++ b/contrib/lib/CVS/Entries
@@ -0,0 +1,7 @@
+D/csu////
+D/i18n_module////
+D/libaltq////
+D/libarch////
+D/libasn1////
+D/libc////
+/Makefile/-1.59/dummy timestamp//
diff --git a/contrib/lib/CVS/Repository b/contrib/lib/CVS/Repository
new file mode 100644
index 00000000..fc1ff103
--- /dev/null
+++ b/contrib/lib/CVS/Repository
@@ -0,0 +1 @@
+src/lib
diff --git a/contrib/lib/CVS/Root b/contrib/lib/CVS/Root
new file mode 100644
index 00000000..7040dfb5
--- /dev/null
+++ b/contrib/lib/CVS/Root
@@ -0,0 +1 @@
+anoncvs@anoncvs.spacehopper.org:/cvs
diff --git a/contrib/lib/Makefile.am b/contrib/lib/Makefile.am
new file mode 100644
index 00000000..1a5e92aa
--- /dev/null
+++ b/contrib/lib/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = libc \ No newline at end of file
diff --git a/contrib/lib/libc/CVS/Entries b/contrib/lib/libc/CVS/Entries
new file mode 100644
index 00000000..65f3ec6b
--- /dev/null
+++ b/contrib/lib/libc/CVS/Entries
@@ -0,0 +1,30 @@
+D/arch////
+D/asr////
+D/citrus////
+D/compat-43////
+D/crypt////
+D/db////
+D/dlfcn////
+D/gdtoa////
+D/gen////
+D/gmon////
+D/hash////
+D/iconv////
+D/include////
+D/locale////
+D/md////
+D/net////
+D/nls////
+D/ohash////
+D/posix1e////
+D/quad////
+D/regex////
+D/rpc////
+D/softfloat////
+D/stdio////
+D/stdlib////
+D/string////
+D/sys////
+/Makefile/-1.29/dummy timestamp//
+/Makefile.inc/-1.17/dummy timestamp//
+/shlib_version/-1.144/dummy timestamp//
diff --git a/contrib/lib/libc/CVS/Repository b/contrib/lib/libc/CVS/Repository
new file mode 100644
index 00000000..3b52c161
--- /dev/null
+++ b/contrib/lib/libc/CVS/Repository
@@ -0,0 +1 @@
+src/lib/libc
diff --git a/contrib/lib/libc/CVS/Root b/contrib/lib/libc/CVS/Root
new file mode 100644
index 00000000..7040dfb5
--- /dev/null
+++ b/contrib/lib/libc/CVS/Root
@@ -0,0 +1 @@
+anoncvs@anoncvs.spacehopper.org:/cvs
diff --git a/contrib/lib/libc/Makefile.am b/contrib/lib/libc/Makefile.am
new file mode 100644
index 00000000..1591fc85
--- /dev/null
+++ b/contrib/lib/libc/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = asr \ No newline at end of file
diff --git a/contrib/lib/libc/asr/CVS/Entries b/contrib/lib/libc/asr/CVS/Entries
new file mode 100644
index 00000000..9d659658
--- /dev/null
+++ b/contrib/lib/libc/asr/CVS/Entries
@@ -0,0 +1,26 @@
+/asr.c/1.31/Result of merge//
+/asr.h/1.7/Result of merge//
+/asr_debug.c/1.14/Result of merge//
+/getaddrinfo_async.c/1.19/Result of merge//
+/getnameinfo_async.c/1.7/Result of merge//
+/getnetnamadr_async.c/1.10/Result of merge//
+/getrrsetbyname_async.c/1.5/Result of merge//
+/res_search_async.c/1.10/Result of merge//
+/res_send_async.c/1.19/Result of merge//
+/Makefile.inc/1.6/Sat Sep 28 15:48:04 2013//
+/asr_resolver.3/1.1/Thu Aug 8 06:55:42 2013//
+/asr_private.h/1.23/Mon Nov 25 20:11:46 2013//
+/asr_utils.c/1.9/Result of merge//
+/getaddrinfo.c/1.3/Mon Nov 25 20:11:46 2013//
+/gethostnamadr.c/1.9/Mon Nov 25 20:11:46 2013//
+/gethostnamadr_async.c/1.23/Result of merge//
+/getnameinfo.c/1.3/Mon Nov 25 20:11:46 2013//
+/getnetnamadr.c/1.6/Mon Nov 25 20:11:46 2013//
+/getrrsetbyname.c/1.3/Mon Nov 25 20:11:46 2013//
+/res_debug.c/1.1/Mon Nov 25 20:11:46 2013//
+/res_init.c/1.2/Mon Nov 25 20:11:46 2013//
+/res_mkquery.c/1.6/Mon Nov 25 20:11:46 2013//
+/res_query.c/1.6/Mon Nov 25 20:11:46 2013//
+/res_send.c/1.6/Mon Nov 25 20:11:46 2013//
+/sethostent.c/1.1/Mon Nov 25 20:11:46 2013//
+D
diff --git a/contrib/lib/libc/asr/CVS/Repository b/contrib/lib/libc/asr/CVS/Repository
new file mode 100644
index 00000000..c5429dbf
--- /dev/null
+++ b/contrib/lib/libc/asr/CVS/Repository
@@ -0,0 +1 @@
+src/lib/libc/asr
diff --git a/contrib/lib/libc/asr/CVS/Root b/contrib/lib/libc/asr/CVS/Root
new file mode 100644
index 00000000..7040dfb5
--- /dev/null
+++ b/contrib/lib/libc/asr/CVS/Root
@@ -0,0 +1 @@
+anoncvs@anoncvs.spacehopper.org:/cvs
diff --git a/contrib/lib/libc/asr/asr.c b/contrib/lib/libc/asr/asr.c
new file mode 100644
index 00000000..13b6097e
--- /dev/null
+++ b/contrib/lib/libc/asr/asr.c
@@ -0,0 +1,956 @@
+/* $OpenBSD: asr.c,v 1.32 2014/03/25 19:48:11 eric Exp $ */
+/*
+ * Copyright (c) 2010-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/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <sys/time.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "asr.h"
+#include "asr_private.h"
+
+#ifndef ASR_OPT_THREADSAFE
+#define ASR_OPT_THREADSAFE 1
+#endif
+#ifndef ASR_OPT_HOSTALIASES
+#define ASR_OPT_HOSTALIASES 1
+#endif
+#ifndef ASR_OPT_ENVOPTS
+#define ASR_OPT_ENVOPTS 1
+#endif
+#ifndef ASR_OPT_RELOADCONF
+#define ASR_OPT_RELOADCONF 1
+#endif
+#ifndef ASR_OPT_ALTCONF
+#define ASR_OPT_ALTCONF 1
+#endif
+
+#if ASR_OPT_THREADSAFE
+#include "thread_private.h"
+#endif
+
+#define DEFAULT_CONFFILE "/etc/resolv.conf"
+#define DEFAULT_HOSTFILE "/etc/hosts"
+#define DEFAULT_CONF "lookup file\n"
+#define DEFAULT_LOOKUP "lookup bind file"
+
+#define RELOAD_DELAY 15 /* seconds */
+
+static void asr_check_reload(struct asr *);
+static struct asr_ctx *asr_ctx_create(void);
+static void asr_ctx_ref(struct asr_ctx *);
+static void asr_ctx_free(struct asr_ctx *);
+static int asr_ctx_add_searchdomain(struct asr_ctx *, const char *);
+static int asr_ctx_from_file(struct asr_ctx *, const char *);
+static int asr_ctx_from_string(struct asr_ctx *, const char *);
+static int asr_ctx_parse(struct asr_ctx *, const char *);
+static int asr_parse_nameserver(struct sockaddr *, const char *);
+static int asr_ndots(const char *);
+static void pass0(char **, int, struct asr_ctx *);
+static int strsplit(char *, char **, int);
+#if ASR_OPT_ENVOPTS
+static void asr_ctx_envopts(struct asr_ctx *);
+#endif
+#if ASR_OPT_THREADSAFE
+static void *__THREAD_NAME(_asr);
+#else
+# define _THREAD_PRIVATE(a, b, c) (c)
+#endif
+
+static struct asr *_asr = NULL;
+
+#define issetugid() ((getuid() != geteuid()))
+
+/* Allocate and configure an async "resolver". */
+void *
+asr_resolver(const char *conf)
+{
+ static int init = 0;
+ struct asr *asr;
+
+ if (init == 0) {
+#ifdef DEBUG
+ if (getenv("ASR_DEBUG"))
+ asr_debug = stderr;
+#endif
+ init = 1;
+ }
+
+ if ((asr = calloc(1, sizeof(*asr))) == NULL)
+ goto fail;
+
+#if ASR_OPT_ALTCONF
+ /* If not setuid/setgid, allow to use an alternate config. */
+ if (conf == NULL && !issetugid())
+ conf = getenv("ASR_CONFIG");
+#endif
+
+ if (conf == NULL)
+ conf = DEFAULT_CONFFILE;
+
+ if (conf[0] == '!') {
+ /* Use the rest of the string as config file */
+ if ((asr->a_ctx = asr_ctx_create()) == NULL)
+ goto fail;
+ if (asr_ctx_from_string(asr->a_ctx, conf + 1) == -1)
+ goto fail;
+ } else {
+ /* Use the given config file */
+ asr->a_path = strdup(conf);
+ if (asr->a_path == NULL)
+ goto fail;
+ asr_check_reload(asr);
+ if (asr->a_ctx == NULL) {
+ if ((asr->a_ctx = asr_ctx_create()) == NULL)
+ goto fail;
+ if (asr_ctx_from_string(asr->a_ctx, DEFAULT_CONF) == -1)
+ goto fail;
+#if ASR_OPT_ENVOPTS
+ asr_ctx_envopts(asr->a_ctx);
+#endif
+ }
+ }
+
+#ifdef DEBUG
+ asr_dump_config(asr_debug, asr);
+#endif
+ return (asr);
+
+ fail:
+ if (asr) {
+ if (asr->a_ctx)
+ asr_ctx_free(asr->a_ctx);
+ free(asr->a_path);
+ free(asr);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Free the "asr" async resolver (or the thread-local resolver if NULL).
+ * Drop the reference to the current context.
+ */
+void
+asr_resolver_done(void *arg)
+{
+ struct asr *asr = arg;
+ struct asr **priv;
+
+ if (asr == NULL) {
+ priv = _THREAD_PRIVATE(_asr, _asr, &_asr);
+ if (*priv == NULL)
+ return;
+ asr = *priv;
+ *priv = NULL;
+ }
+
+ asr_ctx_unref(asr->a_ctx);
+ free(asr->a_path);
+ free(asr);
+}
+
+/*
+ * Cancel an async query.
+ */
+void
+asr_abort(struct asr_query *as)
+{
+ asr_async_free(as);
+}
+
+/*
+ * Resume the "as" async query resolution. Return one of ASYNC_COND,
+ * or ASYNC_DONE and put query-specific return values in the user-allocated
+ * memory at "ar".
+ */
+int
+asr_run(struct asr_query *as, struct asr_result *ar)
+{
+ int r, saved_errno = errno;
+
+ DPRINT("asr: asr_run(%p, %p) %s ctx=[%p]\n", as, ar,
+ asr_querystr(as->as_type), as->as_ctx);
+ r = as->as_run(as, ar);
+
+ DPRINT("asr: asr_run(%p, %p) -> %s", as, ar, asr_transitionstr(r));
+#ifdef DEBUG
+ if (r == ASYNC_COND)
+#endif
+ DPRINT(" fd=%i timeout=%i", ar->ar_fd, ar->ar_timeout);
+ DPRINT("\n");
+ if (r == ASYNC_DONE)
+ asr_async_free(as);
+
+ errno = saved_errno;
+
+ return (r);
+}
+
+/*
+ * Same as above, but run in a loop that handles the fd conditions result.
+ */
+int
+asr_run_sync(struct asr_query *as, struct asr_result *ar)
+{
+ struct pollfd fds[1];
+ int r, saved_errno = errno;
+
+ while ((r = asr_run(as, ar)) == ASYNC_COND) {
+ fds[0].fd = ar->ar_fd;
+ fds[0].events = (ar->ar_cond == ASR_WANT_READ) ? POLLIN:POLLOUT;
+ again:
+ r = poll(fds, 1, ar->ar_timeout);
+ if (r == -1 && errno == EINTR)
+ goto again;
+ /*
+ * Otherwise, just ignore the error and let asr_run()
+ * catch the failure.
+ */
+ }
+
+ errno = saved_errno;
+
+ return (r);
+}
+
+/*
+ * Create a new async request of the given "type" on the async context "ac".
+ * Take a reference on it so it does not gets deleted while the async query
+ * is running.
+ */
+struct asr_query *
+asr_async_new(struct asr_ctx *ac, int type)
+{
+ struct asr_query *as;
+
+ DPRINT("asr: asr_async_new(ctx=%p) type=%i refcount=%i\n", ac, type,
+ ac ? ac->ac_refcount : 0);
+ if (ac == NULL || (as = calloc(1, sizeof(*as))) == NULL)
+ return (NULL);
+
+ ac->ac_refcount += 1;
+ as->as_ctx = ac;
+ as->as_fd = -1;
+ as->as_type = type;
+ as->as_state = ASR_STATE_INIT;
+
+ return (as);
+}
+
+/*
+ * Free an async query and unref the associated context.
+ */
+void
+asr_async_free(struct asr_query *as)
+{
+ DPRINT("asr: asr_async_free(%p)\n", as);
+ switch (as->as_type) {
+ case ASR_SEND:
+ if (as->as_fd != -1)
+ close(as->as_fd);
+ if (as->as.dns.obuf && !(as->as.dns.flags & ASYNC_EXTOBUF))
+ free(as->as.dns.obuf);
+ if (as->as.dns.ibuf)
+ free(as->as.dns.ibuf);
+ if (as->as.dns.dname)
+ free(as->as.dns.dname);
+ break;
+
+ case ASR_SEARCH:
+ if (as->as.search.subq)
+ asr_async_free(as->as.search.subq);
+ if (as->as.search.name)
+ free(as->as.search.name);
+ break;
+
+ case ASR_GETRRSETBYNAME:
+ if (as->as.rrset.subq)
+ asr_async_free(as->as.rrset.subq);
+ if (as->as.rrset.name)
+ free(as->as.rrset.name);
+ break;
+
+ case ASR_GETHOSTBYNAME:
+ case ASR_GETHOSTBYADDR:
+ if (as->as.hostnamadr.subq)
+ asr_async_free(as->as.hostnamadr.subq);
+ if (as->as.hostnamadr.name)
+ free(as->as.hostnamadr.name);
+ break;
+
+ case ASR_GETNETBYNAME:
+ case ASR_GETNETBYADDR:
+ if (as->as.netnamadr.subq)
+ asr_async_free(as->as.netnamadr.subq);
+ if (as->as.netnamadr.name)
+ free(as->as.netnamadr.name);
+ break;
+
+ case ASR_GETADDRINFO:
+ if (as->as.ai.subq)
+ asr_async_free(as->as.ai.subq);
+ if (as->as.ai.aifirst)
+ freeaddrinfo(as->as.ai.aifirst);
+ if (as->as.ai.hostname)
+ free(as->as.ai.hostname);
+ if (as->as.ai.servname)
+ free(as->as.ai.servname);
+ if (as->as.ai.fqdn)
+ free(as->as.ai.fqdn);
+ break;
+
+ case ASR_GETNAMEINFO:
+ if (as->as.ni.subq)
+ asr_async_free(as->as.ni.subq);
+ break;
+ }
+
+ asr_ctx_unref(as->as_ctx);
+ free(as);
+}
+
+/*
+ * Get a context from the given resolver. This takes a new reference to
+ * the returned context, which *must* be explicitely dropped when done
+ * using this context.
+ */
+struct asr_ctx *
+asr_use_resolver(void *arg)
+{
+ struct asr *asr = arg;
+ struct asr **priv;
+
+ if (asr == NULL) {
+ DPRINT("using thread-local resolver\n");
+ priv = _THREAD_PRIVATE(_asr, _asr, &_asr);
+ if (*priv == NULL) {
+ DPRINT("setting up thread-local resolver\n");
+ *priv = asr_resolver(NULL);
+ }
+ asr = *priv;
+ }
+ if (asr != NULL) {
+ asr_check_reload(asr);
+ asr_ctx_ref(asr->a_ctx);
+ return (asr->a_ctx);
+ }
+ return (NULL);
+}
+
+static void
+asr_ctx_ref(struct asr_ctx *ac)
+{
+ DPRINT("asr: asr_ctx_ref(ctx=%p) refcount=%i\n", ac, ac->ac_refcount);
+ ac->ac_refcount += 1;
+}
+
+/*
+ * Drop a reference to an async context, freeing it if the reference
+ * count drops to 0.
+ */
+void
+asr_ctx_unref(struct asr_ctx *ac)
+{
+ DPRINT("asr: asr_ctx_unref(ctx=%p) refcount=%i\n", ac,
+ ac ? ac->ac_refcount : 0);
+ if (ac == NULL)
+ return;
+ if (--ac->ac_refcount)
+ return;
+
+ asr_ctx_free(ac);
+}
+
+static void
+asr_ctx_free(struct asr_ctx *ac)
+{
+ int i;
+
+ if (ac->ac_domain)
+ free(ac->ac_domain);
+ for (i = 0; i < ASR_MAXNS; i++)
+ free(ac->ac_ns[i]);
+ for (i = 0; i < ASR_MAXDOM; i++)
+ free(ac->ac_dom[i]);
+
+ free(ac);
+}
+
+/*
+ * Reload the configuration file if it has changed on disk.
+ */
+static void
+asr_check_reload(struct asr *asr)
+{
+ struct asr_ctx *ac;
+#if ASR_OPT_RELOADCONF
+ struct stat st;
+ struct timespec ts;
+#endif
+
+ if (asr->a_path == NULL)
+ return;
+
+#if ASR_OPT_RELOADCONF
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
+ return;
+
+ if ((ts.tv_sec - asr->a_rtime) < RELOAD_DELAY && asr->a_rtime != 0)
+ return;
+ asr->a_rtime = ts.tv_sec;
+
+ DPRINT("asr: checking for update of \"%s\"\n", asr->a_path);
+ if (stat(asr->a_path, &st) == -1 ||
+ asr->a_mtime == st.st_mtime ||
+ (ac = asr_ctx_create()) == NULL)
+ return;
+ asr->a_mtime = st.st_mtime;
+#else
+ if ((ac = asr_ctx_create()) == NULL)
+ return;
+#endif
+
+ DPRINT("asr: reloading config file\n");
+ if (asr_ctx_from_file(ac, asr->a_path) == -1) {
+ asr_ctx_free(ac);
+ return;
+ }
+
+#if ASR_OPT_ENVOPTS
+ asr_ctx_envopts(ac);
+#endif
+ if (asr->a_ctx)
+ asr_ctx_unref(asr->a_ctx);
+ asr->a_ctx = ac;
+}
+
+/*
+ * Construct a fully-qualified domain name for the given name and domain.
+ * If "name" ends with a '.' it is considered as a FQDN by itself.
+ * Otherwise, the domain, which must be a FQDN, is appended to "name" (it
+ * may have a leading dot which would be ignored). If the domain is null,
+ * then "." is used. Return the length of the constructed FQDN or (0) on
+ * error.
+ */
+size_t
+asr_make_fqdn(const char *name, const char *domain, char *buf, size_t buflen)
+{
+ size_t len;
+
+ if (domain == NULL)
+ domain = ".";
+ else if ((len = strlen(domain)) == 0)
+ return (0);
+ else if (domain[len -1] != '.')
+ return (0);
+
+ len = strlen(name);
+ if (len == 0) {
+ if (strlcpy(buf, domain, buflen) >= buflen)
+ return (0);
+ } else if (name[len - 1] != '.') {
+ if (domain[0] == '.')
+ domain += 1;
+ if (strlcpy(buf, name, buflen) >= buflen ||
+ strlcat(buf, ".", buflen) >= buflen ||
+ strlcat(buf, domain, buflen) >= buflen)
+ return (0);
+ } else {
+ if (strlcpy(buf, name, buflen) >= buflen)
+ return (0);
+ }
+
+ return (strlen(buf));
+}
+
+/*
+ * Count the dots in a string.
+ */
+static int
+asr_ndots(const char *s)
+{
+ int n;
+
+ for (n = 0; *s; s++)
+ if (*s == '.')
+ n += 1;
+
+ return (n);
+}
+
+/*
+ * Allocate a new empty context.
+ */
+static struct asr_ctx *
+asr_ctx_create(void)
+{
+ struct asr_ctx *ac;
+
+ if ((ac = calloc(1, sizeof(*ac))) == NULL)
+ return (NULL);
+
+ ac->ac_options = RES_RECURSE | RES_DEFNAMES | RES_DNSRCH;
+ ac->ac_refcount = 1;
+ ac->ac_ndots = 1;
+#ifndef ASR_IPV4_BEFORE_IPV6
+ ac->ac_family[0] = AF_INET6;
+ ac->ac_family[1] = AF_INET;
+#else
+ ac->ac_family[0] = AF_INET;
+ ac->ac_family[1] = AF_INET6;
+#endif
+ ac->ac_family[2] = -1;
+
+ ac->ac_hostfile = DEFAULT_HOSTFILE;
+
+ ac->ac_nscount = 0;
+ ac->ac_nstimeout = 5;
+ ac->ac_nsretries = 4;
+
+ return (ac);
+}
+
+/*
+ * Add a search domain to the async context.
+ */
+static int
+asr_ctx_add_searchdomain(struct asr_ctx *ac, const char *domain)
+{
+ char buf[MAXDNAME];
+
+ if (ac->ac_domcount == ASR_MAXDOM)
+ return (-1);
+
+ if (asr_make_fqdn(domain, NULL, buf, sizeof(buf)) == 0)
+ return (-1);
+
+ if ((ac->ac_dom[ac->ac_domcount] = strdup(buf)) == NULL)
+ return (0);
+
+ ac->ac_domcount += 1;
+
+ return (1);
+}
+
+static int
+strsplit(char *line, char **tokens, int ntokens)
+{
+ int ntok;
+ char *cp, **tp;
+
+ for (cp = line, tp = tokens, ntok = 0;
+ ntok < ntokens && (*tp = strsep(&cp, " \t")) != NULL; )
+ if (**tp != '\0') {
+ tp++;
+ ntok++;
+ }
+
+ return (ntok);
+}
+
+/*
+ * Pass on a split config line.
+ */
+static void
+pass0(char **tok, int n, struct asr_ctx *ac)
+{
+ int i, j, d;
+ const char *e;
+ struct sockaddr_storage ss;
+
+ if (!strcmp(tok[0], "nameserver")) {
+ if (ac->ac_nscount == ASR_MAXNS)
+ return;
+ if (n != 2)
+ return;
+ if (asr_parse_nameserver((struct sockaddr *)&ss, tok[1]))
+ return;
+ if ((ac->ac_ns[ac->ac_nscount] = calloc(1, SS_LEN(&ss))) == NULL)
+ return;
+ memmove(ac->ac_ns[ac->ac_nscount], &ss, SS_LEN(&ss));
+ ac->ac_nscount += 1;
+
+ } else if (!strcmp(tok[0], "domain")) {
+ if (n != 2)
+ return;
+ if (ac->ac_domain)
+ return;
+ ac->ac_domain = strdup(tok[1]);
+
+ } else if (!strcmp(tok[0], "lookup")) {
+ /* ensure that each lookup is only given once */
+ for (i = 1; i < n; i++)
+ for (j = i + 1; j < n; j++)
+ if (!strcmp(tok[i], tok[j]))
+ return;
+ ac->ac_dbcount = 0;
+ for (i = 1; i < n && ac->ac_dbcount < ASR_MAXDB; i++) {
+ if (!strcmp(tok[i], "yp"))
+ ac->ac_db[ac->ac_dbcount++] = ASR_DB_YP;
+ else if (!strcmp(tok[i], "bind"))
+ ac->ac_db[ac->ac_dbcount++] = ASR_DB_DNS;
+ else if (!strcmp(tok[i], "file"))
+ ac->ac_db[ac->ac_dbcount++] = ASR_DB_FILE;
+ }
+ } else if (!strcmp(tok[0], "search")) {
+ /* resolv.conf says the last line wins */
+ for (i = 0; i < ASR_MAXDOM; i++)
+ free(ac->ac_dom[i]);
+ ac->ac_domcount = 0;
+ for (i = 1; i < n; i++)
+ asr_ctx_add_searchdomain(ac, tok[i]);
+
+ } else if (!strcmp(tok[0], "family")) {
+ if (n == 1 || n > 3)
+ return;
+ for (i = 1; i < n; i++)
+ if (strcmp(tok[i], "inet4") && strcmp(tok[i], "inet6"))
+ return;
+ for (i = 1; i < n; i++)
+ ac->ac_family[i - 1] = strcmp(tok[i], "inet4") ? \
+ AF_INET6 : AF_INET;
+ ac->ac_family[i - 1] = -1;
+
+ } else if (!strcmp(tok[0], "options")) {
+ for (i = 1; i < n; i++) {
+ if (!strcmp(tok[i], "tcp"))
+ ac->ac_options |= RES_USEVC;
+ else if ((!strncmp(tok[i], "ndots:", 6))) {
+ e = NULL;
+ d = strtonum(tok[i] + 6, 1, 16, &e);
+ if (e == NULL)
+ ac->ac_ndots = d;
+ }
+ }
+ }
+}
+
+/*
+ * Setup an async context with the config specified in the string "str".
+ */
+static int
+asr_ctx_from_string(struct asr_ctx *ac, const char *str)
+{
+ char buf[512], *ch;
+
+ asr_ctx_parse(ac, str);
+
+ if (ac->ac_dbcount == 0) {
+ /* No lookup directive */
+ asr_ctx_parse(ac, DEFAULT_LOOKUP);
+ }
+
+ if (ac->ac_nscount == 0)
+ asr_ctx_parse(ac, "nameserver 127.0.0.1");
+
+ if (ac->ac_domain == NULL)
+ if (gethostname(buf, sizeof buf) == 0) {
+ ch = strchr(buf, '.');
+ if (ch)
+ ac->ac_domain = strdup(ch + 1);
+ else /* Assume root. see resolv.conf(5) */
+ ac->ac_domain = strdup("");
+ }
+
+ /* If no search domain was specified, use the local subdomains */
+ if (ac->ac_domcount == 0)
+ for (ch = ac->ac_domain; ch; ) {
+ asr_ctx_add_searchdomain(ac, ch);
+ ch = strchr(ch, '.');
+ if (ch && asr_ndots(++ch) == 0)
+ break;
+ }
+
+ return (0);
+}
+
+/*
+ * Setup the "ac" async context from the file at location "path".
+ */
+static int
+asr_ctx_from_file(struct asr_ctx *ac, const char *path)
+{
+ FILE *cf;
+ char buf[4096];
+ ssize_t r;
+
+ cf = fopen(path, "r");
+ if (cf == NULL)
+ return (-1);
+
+ r = fread(buf, 1, sizeof buf - 1, cf);
+ if (feof(cf) == 0) {
+ DPRINT("asr: config file too long: \"%s\"\n", path);
+ r = -1;
+ }
+ fclose(cf);
+ if (r == -1)
+ return (-1);
+ buf[r] = '\0';
+
+ return asr_ctx_from_string(ac, buf);
+}
+
+/*
+ * Parse lines in the configuration string. For each one, split it into
+ * tokens and pass them to "pass0" for processing.
+ */
+static int
+asr_ctx_parse(struct asr_ctx *ac, const char *str)
+{
+ size_t len;
+ const char *line;
+ char buf[1024];
+ char *tok[10];
+ int ntok;
+
+ line = str;
+ while (*line) {
+ len = strcspn(line, "\n\0");
+ if (len < sizeof buf) {
+ memmove(buf, line, len);
+ buf[len] = '\0';
+ } else
+ buf[0] = '\0';
+ line += len;
+ if (*line == '\n')
+ line++;
+ buf[strcspn(buf, ";#")] = '\0';
+ if ((ntok = strsplit(buf, tok, 10)) == 0)
+ continue;
+
+ pass0(tok, ntok, ac);
+ }
+
+ return (0);
+}
+
+#if ASR_OPT_ENVOPTS
+/*
+ * Check for environment variables altering the configuration as described
+ * in resolv.conf(5). Altough not documented there, this feature is disabled
+ * for setuid/setgid programs.
+ */
+static void
+asr_ctx_envopts(struct asr_ctx *ac)
+{
+ char buf[4096], *e;
+ size_t s;
+
+ if (issetugid()) {
+ ac->ac_options |= RES_NOALIASES;
+ return;
+ }
+
+ if ((e = getenv("RES_OPTIONS")) != NULL) {
+ strlcpy(buf, "options ", sizeof buf);
+ strlcat(buf, e, sizeof buf);
+ s = strlcat(buf, "\n", sizeof buf);
+ s = strlcat(buf, "\n", sizeof buf);
+ if (s < sizeof buf)
+ asr_ctx_parse(ac, buf);
+ }
+
+ if ((e = getenv("LOCALDOMAIN")) != NULL) {
+ strlcpy(buf, "search ", sizeof buf);
+ strlcat(buf, e, sizeof buf);
+ s = strlcat(buf, "\n", sizeof buf);
+ if (s < sizeof buf)
+ asr_ctx_parse(ac, buf);
+ }
+}
+#endif
+
+/*
+ * Parse a resolv.conf(5) nameserver string into a sockaddr.
+ */
+static int
+asr_parse_nameserver(struct sockaddr *sa, const char *s)
+{
+ const char *estr;
+ char buf[256];
+ char *port = NULL;
+ in_port_t portno = 53;
+
+ if (*s == '[') {
+ strlcpy(buf, s + 1, sizeof buf);
+ s = buf;
+ port = strchr(buf, ']');
+ if (port == NULL)
+ return (-1);
+ *port++ = '\0';
+ if (*port != ':')
+ return (-1);
+ port++;
+ }
+
+ if (port) {
+ portno = strtonum(port, 1, USHRT_MAX, &estr);
+ if (estr)
+ return (-1);
+ }
+
+ if (asr_sockaddr_from_str(sa, PF_UNSPEC, s) == -1)
+ return (-1);
+
+ if (sa->sa_family == PF_INET)
+ ((struct sockaddr_in *)sa)->sin_port = htons(portno);
+ else if (sa->sa_family == PF_INET6)
+ ((struct sockaddr_in6 *)sa)->sin6_port = htons(portno);
+
+ return (0);
+}
+
+/*
+ * Turn a (uncompressed) DNS domain name into a regular nul-terminated string
+ * where labels are separated by dots. The result is put into the "buf" buffer,
+ * truncated if it exceeds "max" chars. The function returns "buf".
+ */
+char *
+asr_strdname(const char *_dname, char *buf, size_t max)
+{
+ const unsigned char *dname = _dname;
+ char *res;
+ size_t left, n, count;
+
+ if (_dname[0] == 0) {
+ strlcpy(buf, ".", max);
+ return buf;
+ }
+
+ res = buf;
+ left = max - 1;
+ for (n = 0; dname[0] && left; n += dname[0]) {
+ count = (dname[0] < (left - 1)) ? dname[0] : (left - 1);
+ memmove(buf, dname + 1, count);
+ dname += dname[0] + 1;
+ left -= count;
+ buf += count;
+ if (left) {
+ left -= 1;
+ *buf++ = '.';
+ }
+ }
+ buf[0] = 0;
+
+ return (res);
+}
+
+/*
+ * Read and split the next line from the given namedb file.
+ * Return -1 on error, or put the result in the "tokens" array of
+ * size "ntoken" and returns the number of token on the line.
+ */
+int
+asr_parse_namedb_line(FILE *file, char **tokens, int ntoken)
+{
+ size_t len;
+ char *buf;
+ int ntok;
+
+ again:
+ if ((buf = fgetln(file, &len)) == NULL)
+ return (-1);
+
+ if (buf[len - 1] == '\n')
+ len--;
+
+ buf[len] = '\0';
+ buf[strcspn(buf, "#")] = '\0';
+ if ((ntok = strsplit(buf, tokens, ntoken)) == 0)
+ goto again;
+
+ return (ntok);
+}
+
+/*
+ * Update the async context so that it uses the next configured DB.
+ * Return 0 on success, or -1 if no more DBs is available.
+ */
+int
+asr_iter_db(struct asr_query *as)
+{
+ if (as->as_db_idx >= as->as_ctx->ac_dbcount) {
+ DPRINT("asr_iter_db: done\n");
+ return (-1);
+ }
+
+ as->as_db_idx += 1;
+ DPRINT("asr_iter_db: %i\n", as->as_db_idx);
+
+ return (0);
+}
+
+/*
+ * Check if the hostname "name" is a user-defined alias as per hostname(7).
+ * If so, copies the result in the buffer "abuf" of size "abufsz" and
+ * return "abuf". Otherwise return NULL.
+ */
+char *
+asr_hostalias(struct asr_ctx *ac, const char *name, char *abuf, size_t abufsz)
+{
+#if ASR_OPT_HOSTALIASES
+ FILE *fp;
+ size_t len;
+ char *file, *buf, *tokens[2];
+ int ntok;
+
+ if (ac->ac_options & RES_NOALIASES ||
+ asr_ndots(name) != 0 ||
+ issetugid() ||
+ (file = getenv("HOSTALIASES")) == NULL ||
+ (fp = fopen(file, "r")) == NULL)
+ return (NULL);
+
+ DPRINT("asr: looking up aliases in \"%s\"\n", file);
+
+ while ((buf = fgetln(fp, &len)) != NULL) {
+ if (buf[len - 1] == '\n')
+ len--;
+ buf[len] = '\0';
+ if ((ntok = strsplit(buf, tokens, 2)) != 2)
+ continue;
+ if (!strcasecmp(tokens[0], name)) {
+ if (strlcpy(abuf, tokens[1], abufsz) > abufsz)
+ continue;
+ DPRINT("asr: found alias \"%s\"\n", abuf);
+ fclose(fp);
+ return (abuf);
+ }
+ }
+
+ fclose(fp);
+#endif
+ return (NULL);
+}
diff --git a/contrib/lib/libc/asr/asr.h b/contrib/lib/libc/asr/asr.h
new file mode 100644
index 00000000..76ca11ce
--- /dev/null
+++ b/contrib/lib/libc/asr/asr.h
@@ -0,0 +1,96 @@
+/* $OpenBSD: asr.h,v 1.8 2014/03/25 19:48:11 eric Exp $ */
+/*
+ * Copyright (c) 2012-2014 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 <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+/*
+ * Expected fd conditions
+ */
+#define ASR_WANT_READ 1
+#define ASR_WANT_WRITE 2
+
+/*
+ * Structure through which asynchronous query results are returned when
+ * calling asr_run().
+ */
+struct asr_result {
+ /* Fields set if the query is not done yet (asr_run returns 0) */
+ int ar_cond; /* ASR_WANT_READ or ASR_WANT_WRITE */
+ int ar_fd; /* the fd waiting for io condition */
+ int ar_timeout; /* time to wait for in milliseconds */
+
+ /* Error fields. Depends on the query type. */
+ int ar_errno;
+ int ar_h_errno;
+ int ar_gai_errno;
+ int ar_rrset_errno;
+
+ /* Result for res_*_async() calls */
+ int ar_count; /* number of answers in the dns reply */
+ int ar_rcode; /* response code in the dns reply */
+ void *ar_data; /* raw reply packet (must be freed) */
+ int ar_datalen; /* reply packet length */
+ struct sockaddr_storage ar_ns; /* nameserver that responded */
+
+ /* Result for other calls. Must be freed properly. */
+ struct addrinfo *ar_addrinfo;
+ struct rrsetinfo *ar_rrsetinfo;
+ struct hostent *ar_hostent;
+ struct netent *ar_netent;
+};
+
+/*
+ * Asynchronous query management.
+ */
+
+/* Forward declaration. The API uses opaque pointers as query handles. */
+struct asr_query;
+
+int asr_run(struct asr_query *, struct asr_result *);
+int asr_run_sync(struct asr_query *, struct asr_result *);
+void asr_abort(struct asr_query *);
+
+/*
+ * Asynchronous version of the resolver functions. Similar prototypes, with
+ * an extra context parameter at the end which must currently be set to NULL.
+ * All functions return a handle suitable for use with the management functions
+ * above.
+ */
+struct asr_query *res_send_async(const unsigned char *, int, void *);
+struct asr_query *res_query_async(const char *, int, int, void *);
+struct asr_query *res_search_async(const char *, int, int, void *);
+
+struct asr_query *getrrsetbyname_async(const char *, unsigned int, unsigned int,
+ unsigned int, void *);
+
+struct asr_query *gethostbyname_async(const char *, void *);
+struct asr_query *gethostbyname2_async(const char *, int, void *);
+struct asr_query *gethostbyaddr_async(const void *, socklen_t, int, void *);
+
+struct asr_query *getnetbyname_async(const char *, void *);
+struct asr_query *getnetbyaddr_async(in_addr_t, int, void *);
+
+struct asr_query *getaddrinfo_async(const char *, const char *,
+ const struct addrinfo *, void *);
+struct asr_query *getnameinfo_async(const struct sockaddr *, socklen_t, char *,
+ size_t, char *, size_t, int, void *);
+
+/* from in event.h */
+struct event_asr * event_asr_run(struct asr_query *,
+ void (*)(struct asr_result *, void *), void *);
diff --git a/contrib/lib/libc/asr/asr_debug.c b/contrib/lib/libc/asr/asr_debug.c
new file mode 100644
index 00000000..3dc6fe51
--- /dev/null
+++ b/contrib/lib/libc/asr/asr_debug.c
@@ -0,0 +1,363 @@
+/* $OpenBSD: asr_debug.c,v 1.16 2014/03/25 19:48:11 eric Exp $ */
+/*
+ * 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 <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <resolv.h>
+
+#include "asr.h"
+#include "asr_private.h"
+
+static const char *rcodetostr(uint16_t);
+static const char *print_dname(const char *, char *, size_t);
+static const char *print_header(const struct asr_dns_header *, char *, size_t);
+static const char *print_query(const struct asr_dns_query *, char *, size_t);
+static const char *print_rr(const struct asr_dns_rr *, char *, size_t);
+
+FILE *asr_debug = NULL;
+
+#define OPCODE_SHIFT 11
+#define Z_SHIFT 4
+
+static const char *
+rcodetostr(uint16_t v)
+{
+ switch (v) {
+ case NOERROR: return "NOERROR";
+ case FORMERR: return "FORMERR";
+ case SERVFAIL: return "SERVFAIL";
+ case NXDOMAIN: return "NXDOMAIN";
+ case NOTIMP: return "NOTIMP";
+ case REFUSED: return "REFUSED";
+ default: return "?";
+ }
+}
+
+static const char *
+print_dname(const char *_dname, char *buf, size_t max)
+{
+ return (asr_strdname(_dname, buf, max));
+}
+
+static const char *
+print_rr(const struct asr_dns_rr *rr, char *buf, size_t max)
+{
+ char *res;
+ char tmp[256];
+ char tmp2[256];
+ int r;
+
+ res = buf;
+
+ r = snprintf(buf, max, "%s %u %s %s ",
+ print_dname(rr->rr_dname, tmp, sizeof tmp),
+ rr->rr_ttl,
+ __p_class(rr->rr_class),
+ __p_type(rr->rr_type));
+ if (r == -1) {
+ buf[0] = '\0';
+ return (buf);
+ }
+
+ if ((size_t)r >= max)
+ return (buf);
+
+ max -= r;
+ buf += r;
+
+ switch (rr->rr_type) {
+ case T_CNAME:
+ print_dname(rr->rr.cname.cname, buf, max);
+ break;
+ case T_MX:
+ snprintf(buf, max, "%lu %s",
+ (unsigned long)rr->rr.mx.preference,
+ print_dname(rr->rr.mx.exchange, tmp, sizeof tmp));
+ break;
+ case T_NS:
+ print_dname(rr->rr.ns.nsname, buf, max);
+ break;
+ case T_PTR:
+ print_dname(rr->rr.ptr.ptrname, buf, max);
+ break;
+ case T_SOA:
+ snprintf(buf, max, "%s %s %lu %lu %lu %lu %lu",
+ print_dname(rr->rr.soa.rname, tmp, sizeof tmp),
+ print_dname(rr->rr.soa.mname, tmp2, sizeof tmp2),
+ (unsigned long)rr->rr.soa.serial,
+ (unsigned long)rr->rr.soa.refresh,
+ (unsigned long)rr->rr.soa.retry,
+ (unsigned long)rr->rr.soa.expire,
+ (unsigned long)rr->rr.soa.minimum);
+ break;
+ case T_A:
+ if (rr->rr_class != C_IN)
+ goto other;
+ snprintf(buf, max, "%s", inet_ntop(AF_INET,
+ &rr->rr.in_a.addr, tmp, sizeof tmp));
+ break;
+ case T_AAAA:
+ if (rr->rr_class != C_IN)
+ goto other;
+ snprintf(buf, max, "%s", inet_ntop(AF_INET6,
+ &rr->rr.in_aaaa.addr6, tmp, sizeof tmp));
+ break;
+ default:
+ other:
+ snprintf(buf, max, "(rdlen=%i)", (int)rr->rr.other.rdlen);
+ break;
+ }
+
+ return (res);
+}
+
+static const char *
+print_query(const struct asr_dns_query *q, char *buf, size_t max)
+{
+ char b[256];
+
+ snprintf(buf, max, "%s %s %s",
+ print_dname(q->q_dname, b, sizeof b),
+ __p_class(q->q_class), __p_type(q->q_type));
+
+ return (buf);
+}
+
+static const char *
+print_header(const struct asr_dns_header *h, char *buf, size_t max)
+{
+ snprintf(buf, max,
+ "id:0x%04x %s op:%i %s %s %s %s z:%i r:%s qd:%i an:%i ns:%i ar:%i",
+ ((int)h->id),
+ (h->flags & QR_MASK) ? "QR":" ",
+ (int)(OPCODE(h->flags) >> OPCODE_SHIFT),
+ (h->flags & AA_MASK) ? "AA":" ",
+ (h->flags & TC_MASK) ? "TC":" ",
+ (h->flags & RD_MASK) ? "RD":" ",
+ (h->flags & RA_MASK) ? "RA":" ",
+ ((h->flags & Z_MASK) >> Z_SHIFT),
+ rcodetostr(RCODE(h->flags)),
+ h->qdcount, h->ancount, h->nscount, h->arcount);
+
+ return (buf);
+}
+
+void
+asr_dump_packet(FILE *f, const void *data, size_t len)
+{
+ char buf[1024];
+ struct asr_unpack p;
+ struct asr_dns_header h;
+ struct asr_dns_query q;
+ struct asr_dns_rr rr;
+ int i, an, ns, ar, n;
+
+ if (f == NULL)
+ return;
+
+ asr_unpack_init(&p, data, len);
+
+ if (asr_unpack_header(&p, &h) == -1) {
+ fprintf(f, ";; BAD PACKET: %s\n", p.err);
+ return;
+ }
+
+ fprintf(f, ";; HEADER %s\n", print_header(&h, buf, sizeof buf));
+
+ if (h.qdcount)
+ fprintf(f, ";; QUERY SECTION:\n");
+ for (i = 0; i < h.qdcount; i++) {
+ if (asr_unpack_query(&p, &q) == -1)
+ goto error;
+ fprintf(f, "%s\n", print_query(&q, buf, sizeof buf));
+ }
+
+ an = 0;
+ ns = an + h.ancount;
+ ar = ns + h.nscount;
+ n = ar + h.arcount;
+
+ for (i = 0; i < n; i++) {
+ if (i == an)
+ fprintf(f, "\n;; ANSWER SECTION:\n");
+ if (i == ns)
+ fprintf(f, "\n;; AUTHORITY SECTION:\n");
+ if (i == ar)
+ fprintf(f, "\n;; ADDITIONAL SECTION:\n");
+
+ if (asr_unpack_rr(&p, &rr) == -1)
+ goto error;
+ fprintf(f, "%s\n", print_rr(&rr, buf, sizeof buf));
+ }
+
+ if (p.offset != len)
+ fprintf(f, ";; REMAINING GARBAGE %zu\n", len - p.offset);
+
+ error:
+ if (p.err)
+ fprintf(f, ";; ERROR AT OFFSET %zu/%zu: %s\n", p.offset, p.len,
+ p.err);
+}
+
+const char *
+print_sockaddr(const struct sockaddr *sa, char *buf, size_t len)
+{
+ char h[256];
+ int portno;
+ union {
+ const struct sockaddr *sa;
+ const struct sockaddr_in *sin;
+ const struct sockaddr_in6 *sin6;
+ } s;
+
+ s.sa = sa;
+
+ switch (sa->sa_family) {
+ case AF_INET:
+ inet_ntop(AF_INET, &s.sin->sin_addr, h, sizeof h);
+ portno = ntohs(s.sin->sin_port);
+ break;
+ case AF_INET6:
+ inet_ntop(AF_INET6, &s.sin6->sin6_addr, h, sizeof h);
+ portno = ntohs(s.sin6->sin6_port);
+ break;
+ default:
+ snprintf(buf, len, "?");
+ return (buf);
+ }
+
+ snprintf(buf, len, "%s:%i", h, portno);
+ return (buf);
+}
+
+void
+asr_dump_config(FILE *f, struct asr *a)
+{
+ char buf[256];
+ int i;
+ struct asr_ctx *ac;
+ unsigned int o;
+
+ if (f == NULL)
+ return;
+
+ ac = a->a_ctx;
+
+ fprintf(f, "--------- ASR CONFIG ---------------\n");
+ if (a->a_path)
+ fprintf(f, "CONF FILE \"%s\"\n", a->a_path);
+ else
+ fprintf(f, "STATIC CONF\n");
+ fprintf(f, "DOMAIN \"%s\"\n", ac->ac_domain);
+ fprintf(f, "SEARCH\n");
+ for (i = 0; i < ac->ac_domcount; i++)
+ fprintf(f, " \"%s\"\n", ac->ac_dom[i]);
+ fprintf(f, "OPTIONS\n");
+ fprintf(f, " options:");
+ o = ac->ac_options;
+
+#define PRINTOPT(flag, n) if (o & (flag)) { fprintf(f, " " n); o &= ~(flag); }
+ PRINTOPT(RES_INIT, "INIT");
+ PRINTOPT(RES_DEBUG, "DEBUG");
+ PRINTOPT(RES_USEVC, "USEVC");
+ PRINTOPT(RES_IGNTC, "IGNTC");
+ PRINTOPT(RES_RECURSE, "RECURSE");
+ PRINTOPT(RES_DEFNAMES, "DEFNAMES");
+ PRINTOPT(RES_STAYOPEN, "STAYOPEN");
+ PRINTOPT(RES_DNSRCH, "DNSRCH");
+ PRINTOPT(RES_NOALIASES, "NOALIASES");
+ PRINTOPT(RES_USE_EDNS0, "USE_EDNS0");
+ PRINTOPT(RES_USE_DNSSEC, "USE_DNSSEC");
+ if (o)
+ fprintf(f, " 0x%08x", o);
+ fprintf(f, "\n");
+
+ fprintf(f, " ndots: %i\n", ac->ac_ndots);
+ fprintf(f, " family:");
+ for (i = 0; ac->ac_family[i] != -1; i++)
+ fprintf(f, " %s", (ac->ac_family[i] == AF_INET)?"inet4":"inet6");
+ fprintf(f, "\n");
+ fprintf(f, "NAMESERVERS timeout=%i retry=%i\n",
+ ac->ac_nstimeout,
+ ac->ac_nsretries);
+ for (i = 0; i < ac->ac_nscount; i++)
+ fprintf(f, " %s\n", print_sockaddr(ac->ac_ns[i], buf,
+ sizeof buf));
+ fprintf(f, "HOSTFILE %s\n", ac->ac_hostfile);
+ fprintf(f, "LOOKUP %s", ac->ac_db);
+ fprintf(f, "\n------------------------------------\n");
+}
+
+#define CASE(n) case n: return #n
+
+const char *
+asr_statestr(int state)
+{
+ switch (state) {
+ CASE(ASR_STATE_INIT);
+ CASE(ASR_STATE_NEXT_DOMAIN);
+ CASE(ASR_STATE_NEXT_DB);
+ CASE(ASR_STATE_SAME_DB);
+ CASE(ASR_STATE_NEXT_FAMILY);
+ CASE(ASR_STATE_NEXT_NS);
+ CASE(ASR_STATE_UDP_SEND);
+ CASE(ASR_STATE_UDP_RECV);
+ CASE(ASR_STATE_TCP_WRITE);
+ CASE(ASR_STATE_TCP_READ);
+ CASE(ASR_STATE_PACKET);
+ CASE(ASR_STATE_SUBQUERY);
+ CASE(ASR_STATE_NOT_FOUND);
+ CASE(ASR_STATE_HALT);
+ default:
+ return "?";
+ }
+};
+
+const char *
+asr_querystr(int type)
+{
+ switch (type) {
+ CASE(ASR_SEND);
+ CASE(ASR_SEARCH);
+ CASE(ASR_GETRRSETBYNAME);
+ CASE(ASR_GETHOSTBYNAME);
+ CASE(ASR_GETHOSTBYADDR);
+ CASE(ASR_GETNETBYNAME);
+ CASE(ASR_GETNETBYADDR);
+ CASE(ASR_GETADDRINFO);
+ CASE(ASR_GETNAMEINFO);
+ default:
+ return "?";
+ }
+}
+
+const char *
+asr_transitionstr(int type)
+{
+ switch (type) {
+ CASE(ASYNC_COND);
+ CASE(ASYNC_DONE);
+ default:
+ return "?";
+ }
+}
diff --git a/contrib/lib/libc/asr/asr_private.h b/contrib/lib/libc/asr/asr_private.h
new file mode 100644
index 00000000..d03e6863
--- /dev/null
+++ b/contrib/lib/libc/asr/asr_private.h
@@ -0,0 +1,367 @@
+/* $OpenBSD: asr_private.h,v 1.25 2014/03/25 19:48:11 eric Exp $ */
+/*
+ * 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 <stdio.h>
+
+#ifndef ASRNODEBUG
+#define DEBUG
+#endif
+
+#define QR_MASK (0x1 << 15)
+#define OPCODE_MASK (0xf << 11)
+#define AA_MASK (0x1 << 10)
+#define TC_MASK (0x1 << 9)
+#define RD_MASK (0x1 << 8)
+#define RA_MASK (0x1 << 7)
+#define Z_MASK (0x7 << 4)
+#define RCODE_MASK (0xf)
+
+#define OPCODE(v) ((v) & OPCODE_MASK)
+#define RCODE(v) ((v) & RCODE_MASK)
+
+
+struct asr_pack {
+ char *buf;
+ size_t len;
+ size_t offset;
+ const char *err;
+};
+
+struct asr_unpack {
+ const char *buf;
+ size_t len;
+ size_t offset;
+ const char *err;
+};
+
+struct asr_dns_header {
+ uint16_t id;
+ uint16_t flags;
+ uint16_t qdcount;
+ uint16_t ancount;
+ uint16_t nscount;
+ uint16_t arcount;
+};
+
+struct asr_dns_query {
+ char q_dname[MAXDNAME];
+ uint16_t q_type;
+ uint16_t q_class;
+};
+
+struct asr_dns_rr {
+ char rr_dname[MAXDNAME];
+ uint16_t rr_type;
+ uint16_t rr_class;
+ uint32_t rr_ttl;
+ union {
+ struct {
+ char cname[MAXDNAME];
+ } cname;
+ struct {
+ uint16_t preference;
+ char exchange[MAXDNAME];
+ } mx;
+ struct {
+ char nsname[MAXDNAME];
+ } ns;
+ struct {
+ char ptrname[MAXDNAME];
+ } ptr;
+ struct {
+ char mname[MAXDNAME];
+ char rname[MAXDNAME];
+ uint32_t serial;
+ uint32_t refresh;
+ uint32_t retry;
+ uint32_t expire;
+ uint32_t minimum;
+ } soa;
+ struct {
+ struct in_addr addr;
+ } in_a;
+ struct {
+ struct in6_addr addr6;
+ } in_aaaa;
+ struct {
+ uint16_t rdlen;
+ const void *rdata;
+ } other;
+ } rr;
+};
+
+
+#define ASR_MAXNS 5
+#define ASR_MAXDB 3
+#define ASR_MAXDOM 10
+
+enum async_type {
+ ASR_SEND,
+ ASR_SEARCH,
+ ASR_GETRRSETBYNAME,
+ ASR_GETHOSTBYNAME,
+ ASR_GETHOSTBYADDR,
+ ASR_GETNETBYNAME,
+ ASR_GETNETBYADDR,
+ ASR_GETADDRINFO,
+ ASR_GETNAMEINFO,
+};
+
+#define ASR_DB_FILE 'f'
+#define ASR_DB_DNS 'b'
+#define ASR_DB_YP 'y'
+
+struct asr_ctx {
+ int ac_refcount;
+ int ac_options;
+ int ac_ndots;
+ char *ac_domain;
+ int ac_domcount;
+ char *ac_dom[ASR_MAXDOM];
+ int ac_dbcount;
+ char ac_db[ASR_MAXDB + 1];
+ int ac_family[3];
+
+ char *ac_hostfile;
+
+ int ac_nscount;
+ int ac_nstimeout;
+ int ac_nsretries;
+ struct sockaddr *ac_ns[ASR_MAXNS];
+
+};
+
+struct asr {
+ char *a_path;
+ time_t a_mtime;
+ time_t a_rtime;
+ struct asr_ctx *a_ctx;
+};
+
+#define ASYNC_COND 0
+#define ASYNC_DONE 1
+
+#define ASYNC_DOM_FQDN 0x00000001
+#define ASYNC_DOM_NDOTS 0x00000002
+#define ASYNC_DOM_DOMAIN 0x00000004
+#define ASYNC_DOM_ASIS 0x00000008
+
+#define ASYNC_NODATA 0x00000100
+#define ASYNC_AGAIN 0x00000200
+
+#define ASYNC_EXTOBUF 0x00002000
+
+
+struct asr_query {
+ int (*as_run)(struct asr_query *, struct asr_result *);
+ struct asr_ctx *as_ctx;
+ int as_type;
+ int as_state;
+
+ /* cond */
+ int as_timeout;
+ int as_fd;
+
+ /* loop indices in ctx */
+ int as_dom_step;
+ int as_dom_idx;
+ int as_dom_flags;
+ int as_family_idx;
+ int as_db_idx;
+
+ int as_count;
+
+ union {
+ struct {
+ int flags;
+ uint16_t reqid;
+ int class;
+ int type;
+ char *dname; /* not fqdn! */
+ int rcode; /* response code */
+ int ancount; /* answer count */
+
+ int nsidx;
+ int nsloop;
+
+ /* io buffers for query/response */
+ unsigned char *obuf;
+ size_t obuflen;
+ size_t obufsize;
+ unsigned char *ibuf;
+ size_t ibuflen;
+ size_t ibufsize;
+ size_t datalen; /* for tcp io */
+ uint16_t pktlen;
+ } dns;
+
+ struct {
+ int flags;
+ int class;
+ int type;
+ char *name;
+ struct asr_query *subq;
+ int saved_h_errno;
+ } search;
+
+ struct {
+ int flags;
+ int class;
+ int type;
+ char *name;
+ struct asr_query *subq;
+ } rrset;
+
+ struct {
+ char *name;
+ int family;
+ struct asr_query *subq;
+ char addr[16];
+ int addrlen;
+ int subq_h_errno;
+ } hostnamadr;
+
+ struct {
+ char *name;
+ int family;
+ struct asr_query *subq;
+ in_addr_t addr;
+ } netnamadr;
+
+ struct {
+ char *hostname;
+ char *servname;
+ int port_tcp;
+ int port_udp;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sain;
+ struct sockaddr_in6 sain6;
+ } sa;
+
+ struct addrinfo hints;
+ char *fqdn;
+ struct addrinfo *aifirst;
+ struct addrinfo *ailast;
+ struct asr_query *subq;
+ int flags;
+ } ai;
+
+ struct {
+ char *hostname;
+ char *servname;
+ size_t hostnamelen;
+ size_t servnamelen;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sain;
+ struct sockaddr_in6 sain6;
+ } sa;
+ int flags;
+ struct asr_query *subq;
+ } ni;
+#define MAXTOKEN 10
+ } as;
+
+};
+
+#define AS_DB(p) ((p)->as_ctx->ac_db[(p)->as_db_idx - 1])
+#define AS_FAMILY(p) ((p)->as_ctx->ac_family[(p)->as_family_idx])
+
+enum asr_state {
+ ASR_STATE_INIT,
+ ASR_STATE_NEXT_DOMAIN,
+ ASR_STATE_NEXT_DB,
+ ASR_STATE_SAME_DB,
+ ASR_STATE_NEXT_FAMILY,
+ ASR_STATE_NEXT_NS,
+ ASR_STATE_UDP_SEND,
+ ASR_STATE_UDP_RECV,
+ ASR_STATE_TCP_WRITE,
+ ASR_STATE_TCP_READ,
+ ASR_STATE_PACKET,
+ ASR_STATE_SUBQUERY,
+ ASR_STATE_NOT_FOUND,
+ ASR_STATE_HALT,
+};
+
+
+/* asr_utils.c */
+void asr_pack_init(struct asr_pack *, char *, size_t);
+int asr_pack_header(struct asr_pack *, const struct asr_dns_header *);
+int asr_pack_query(struct asr_pack *, uint16_t, uint16_t, const char *);
+void asr_unpack_init(struct asr_unpack *, const char *, size_t);
+int asr_unpack_header(struct asr_unpack *, struct asr_dns_header *);
+int asr_unpack_query(struct asr_unpack *, struct asr_dns_query *);
+int asr_unpack_rr(struct asr_unpack *, struct asr_dns_rr *);
+int asr_sockaddr_from_str(struct sockaddr *, int, const char *);
+ssize_t asr_dname_from_fqdn(const char *, char *, size_t);
+ssize_t asr_addr_as_fqdn(const char *, int, char *, size_t);
+
+/* asr.c */
+void *asr_resolver(const char *);
+void asr_resolver_done(void *);
+struct asr_ctx *asr_use_resolver(void *);
+void asr_ctx_unref(struct asr_ctx *);
+struct asr_query *asr_async_new(struct asr_ctx *, int);
+void asr_async_free(struct asr_query *);
+size_t asr_make_fqdn(const char *, const char *, char *, size_t);
+char *asr_strdname(const char *, char *, size_t);
+int asr_iter_db(struct asr_query *);
+int asr_parse_namedb_line(FILE *, char **, int);
+char *asr_hostalias(struct asr_ctx *, const char *, char *, size_t);
+
+/* *_async.c */
+struct asr_query *res_query_async_ctx(const char *, int, int, struct asr_ctx *);
+struct asr_query *res_search_async_ctx(const char *, int, int, struct asr_ctx *);
+struct asr_query *gethostbyaddr_async_ctx(const void *, socklen_t, int,
+ struct asr_ctx *);
+
+#ifdef DEBUG
+
+#define DPRINT(...) do { if(asr_debug) { \
+ fprintf(asr_debug, __VA_ARGS__); \
+ } } while (0)
+#define DPRINT_PACKET(n, p, s) do { if(asr_debug) { \
+ fprintf(asr_debug, "----- %s -----\n", n); \
+ asr_dump_packet(asr_debug, (p), (s)); \
+ fprintf(asr_debug, "--------------\n"); \
+ } } while (0)
+
+const char *asr_querystr(int);
+const char *asr_statestr(int);
+const char *asr_transitionstr(int);
+const char *print_sockaddr(const struct sockaddr *, char *, size_t);
+void asr_dump_config(FILE *, struct asr *);
+void asr_dump_packet(FILE *, const void *, size_t);
+
+extern FILE * asr_debug;
+
+#else /* DEBUG */
+
+#define DPRINT(...)
+#define DPRINT_PACKET(...)
+
+#endif /* DEBUG */
+
+#define async_set_state(a, s) do { \
+ DPRINT("asr: [%s@%p] %s -> %s\n", \
+ asr_querystr((a)->as_type), \
+ as, \
+ asr_statestr((a)->as_state), \
+ asr_statestr((s))); \
+ (a)->as_state = (s); } while (0)
diff --git a/contrib/lib/libc/asr/asr_utils.c b/contrib/lib/libc/asr/asr_utils.c
new file mode 100644
index 00000000..7d83ecdf
--- /dev/null
+++ b/contrib/lib/libc/asr/asr_utils.c
@@ -0,0 +1,551 @@
+/* $OpenBSD: asr_utils.c,v 1.11 2014/03/14 11:07:33 eric Exp $ */
+/*
+ * Copyright (c) 2009-2012 Eric Faurot <eric@faurot.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.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "asr.h"
+#include "asr_private.h"
+
+static int dname_check_label(const char *, size_t);
+static ssize_t dname_expand(const unsigned char *, size_t, size_t, size_t *,
+ char *, size_t);
+
+static int unpack_data(struct asr_unpack *, void *, size_t);
+static int unpack_u16(struct asr_unpack *, uint16_t *);
+static int unpack_u32(struct asr_unpack *, uint32_t *);
+static int unpack_inaddr(struct asr_unpack *, struct in_addr *);
+static int unpack_in6addr(struct asr_unpack *, struct in6_addr *);
+static int unpack_dname(struct asr_unpack *, char *, size_t);
+
+static int pack_data(struct asr_pack *, const void *, size_t);
+static int pack_u16(struct asr_pack *, uint16_t);
+static int pack_dname(struct asr_pack *, const char *);
+
+static int
+dname_check_label(const char *s, size_t l)
+{
+ if (l == 0 || l > 63)
+ return (-1);
+
+ return (0);
+}
+
+ssize_t
+asr_dname_from_fqdn(const char *str, char *dst, size_t max)
+{
+ ssize_t res;
+ size_t l, n;
+ char *d;
+
+ res = 0;
+
+ /* special case: the root domain */
+ if (str[0] == '.') {
+ if (str[1] != '\0')
+ return (-1);
+ if (dst && max >= 1)
+ *dst = '\0';
+ return (1);
+ }
+
+ for (; *str; str = d + 1) {
+
+ d = strchr(str, '.');
+ if (d == NULL || d == str)
+ return (-1);
+
+ l = (d - str);
+
+ if (dname_check_label(str, l) == -1)
+ return (-1);
+
+ res += l + 1;
+
+ if (dst) {
+ *dst++ = l;
+ max -= 1;
+ n = (l > max) ? max : l;
+ memmove(dst, str, n);
+ max -= n;
+ if (max == 0)
+ dst = NULL;
+ else
+ dst += n;
+ }
+ }
+
+ if (dst)
+ *dst++ = '\0';
+
+ return (res + 1);
+}
+
+static ssize_t
+dname_expand(const unsigned char *data, size_t len, size_t offset,
+ size_t *newoffset, char *dst, size_t max)
+{
+ size_t n, count, end, ptr, start;
+ ssize_t res;
+
+ if (offset >= len)
+ return (-1);
+
+ res = 0;
+ end = start = offset;
+
+ for (; (n = data[offset]); ) {
+ if ((n & 0xc0) == 0xc0) {
+ if (offset + 2 > len)
+ return (-1);
+ ptr = 256 * (n & ~0xc0) + data[offset + 1];
+ if (ptr >= start)
+ return (-1);
+ if (end < offset + 2)
+ end = offset + 2;
+ offset = start = ptr;
+ continue;
+ }
+ if (offset + n + 1 > len)
+ return (-1);
+
+ if (dname_check_label(data + offset + 1, n) == -1)
+ return (-1);
+
+ /* copy n + at offset+1 */
+ if (dst != NULL && max != 0) {
+ count = (max < n + 1) ? (max) : (n + 1);
+ memmove(dst, data + offset, count);
+ dst += count;
+ max -= count;
+ }
+ res += n + 1;
+ offset += n + 1;
+ if (end < offset)
+ end = offset;
+ }
+ if (end < offset + 1)
+ end = offset + 1;
+
+ if (dst != NULL && max != 0)
+ dst[0] = 0;
+ if (newoffset)
+ *newoffset = end;
+ return (res + 1);
+}
+
+void
+asr_pack_init(struct asr_pack *pack, char *buf, size_t len)
+{
+ pack->buf = buf;
+ pack->len = len;
+ pack->offset = 0;
+ pack->err = NULL;
+}
+
+void
+asr_unpack_init(struct asr_unpack *unpack, const char *buf, size_t len)
+{
+ unpack->buf = buf;
+ unpack->len = len;
+ unpack->offset = 0;
+ unpack->err = NULL;
+}
+
+static int
+unpack_data(struct asr_unpack *p, void *data, size_t len)
+{
+ if (p->err)
+ return (-1);
+
+ if (p->len - p->offset < len) {
+ p->err = "too short";
+ return (-1);
+ }
+
+ memmove(data, p->buf + p->offset, len);
+ p->offset += len;
+
+ return (0);
+}
+
+static int
+unpack_u16(struct asr_unpack *p, uint16_t *u16)
+{
+ if (unpack_data(p, u16, 2) == -1)
+ return (-1);
+
+ *u16 = ntohs(*u16);
+
+ return (0);
+}
+
+static int
+unpack_u32(struct asr_unpack *p, uint32_t *u32)
+{
+ if (unpack_data(p, u32, 4) == -1)
+ return (-1);
+
+ *u32 = ntohl(*u32);
+
+ return (0);
+}
+
+static int
+unpack_inaddr(struct asr_unpack *p, struct in_addr *a)
+{
+ return (unpack_data(p, a, 4));
+}
+
+static int
+unpack_in6addr(struct asr_unpack *p, struct in6_addr *a6)
+{
+ return (unpack_data(p, a6, 16));
+}
+
+static int
+unpack_dname(struct asr_unpack *p, char *dst, size_t max)
+{
+ ssize_t e;
+
+ if (p->err)
+ return (-1);
+
+ e = dname_expand(p->buf, p->len, p->offset, &p->offset, dst, max);
+ if (e == -1) {
+ p->err = "bad domain name";
+ return (-1);
+ }
+ if (e < 0 || e > MAXDNAME) {
+ p->err = "domain name too long";
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+asr_unpack_header(struct asr_unpack *p, struct asr_dns_header *h)
+{
+ if (unpack_data(p, h, HFIXEDSZ) == -1)
+ return (-1);
+
+ h->flags = ntohs(h->flags);
+ h->qdcount = ntohs(h->qdcount);
+ h->ancount = ntohs(h->ancount);
+ h->nscount = ntohs(h->nscount);
+ h->arcount = ntohs(h->arcount);
+
+ return (0);
+}
+
+int
+asr_unpack_query(struct asr_unpack *p, struct asr_dns_query *q)
+{
+ unpack_dname(p, q->q_dname, sizeof(q->q_dname));
+ unpack_u16(p, &q->q_type);
+ unpack_u16(p, &q->q_class);
+
+ return (p->err) ? (-1) : (0);
+}
+
+int
+asr_unpack_rr(struct asr_unpack *p, struct asr_dns_rr *rr)
+{
+ uint16_t rdlen;
+ size_t save_offset;
+
+ unpack_dname(p, rr->rr_dname, sizeof(rr->rr_dname));
+ unpack_u16(p, &rr->rr_type);
+ unpack_u16(p, &rr->rr_class);
+ unpack_u32(p, &rr->rr_ttl);
+ unpack_u16(p, &rdlen);
+
+ if (p->err)
+ return (-1);
+
+ if (p->len - p->offset < rdlen) {
+ p->err = "too short";
+ return (-1);
+ }
+
+ save_offset = p->offset;
+
+ switch (rr->rr_type) {
+
+ case T_CNAME:
+ unpack_dname(p, rr->rr.cname.cname, sizeof(rr->rr.cname.cname));
+ break;
+
+ case T_MX:
+ unpack_u16(p, &rr->rr.mx.preference);
+ unpack_dname(p, rr->rr.mx.exchange, sizeof(rr->rr.mx.exchange));
+ break;
+
+ case T_NS:
+ unpack_dname(p, rr->rr.ns.nsname, sizeof(rr->rr.ns.nsname));
+ break;
+
+ case T_PTR:
+ unpack_dname(p, rr->rr.ptr.ptrname, sizeof(rr->rr.ptr.ptrname));
+ break;
+
+ case T_SOA:
+ unpack_dname(p, rr->rr.soa.mname, sizeof(rr->rr.soa.mname));
+ unpack_dname(p, rr->rr.soa.rname, sizeof(rr->rr.soa.rname));
+ unpack_u32(p, &rr->rr.soa.serial);
+ unpack_u32(p, &rr->rr.soa.refresh);
+ unpack_u32(p, &rr->rr.soa.retry);
+ unpack_u32(p, &rr->rr.soa.expire);
+ unpack_u32(p, &rr->rr.soa.minimum);
+ break;
+
+ case T_A:
+ if (rr->rr_class != C_IN)
+ goto other;
+ unpack_inaddr(p, &rr->rr.in_a.addr);
+ break;
+
+ case T_AAAA:
+ if (rr->rr_class != C_IN)
+ goto other;
+ unpack_in6addr(p, &rr->rr.in_aaaa.addr6);
+ break;
+ default:
+ other:
+ rr->rr.other.rdata = p->buf + p->offset;
+ rr->rr.other.rdlen = rdlen;
+ p->offset += rdlen;
+ }
+
+ if (p->err)
+ return (-1);
+
+ /* make sure that the advertised rdlen is really ok */
+ if (p->offset - save_offset != rdlen)
+ p->err = "bad dlen";
+
+ return (p->err) ? (-1) : (0);
+}
+
+static int
+pack_data(struct asr_pack *p, const void *data, size_t len)
+{
+ if (p->err)
+ return (-1);
+
+ if (p->len < p->offset + len) {
+ p->err = "no space";
+ return (-1);
+ }
+
+ memmove(p->buf + p->offset, data, len);
+ p->offset += len;
+
+ return (0);
+}
+
+static int
+pack_u16(struct asr_pack *p, uint16_t v)
+{
+ v = htons(v);
+
+ return (pack_data(p, &v, 2));
+}
+
+static int
+pack_dname(struct asr_pack *p, const char *dname)
+{
+ /* dname compression would be nice to have here.
+ * need additionnal context.
+ */
+ return (pack_data(p, dname, strlen(dname) + 1));
+}
+
+int
+asr_pack_header(struct asr_pack *p, const struct asr_dns_header *h)
+{
+ struct asr_dns_header c;
+
+ c.id = h->id;
+ c.flags = htons(h->flags);
+ c.qdcount = htons(h->qdcount);
+ c.ancount = htons(h->ancount);
+ c.nscount = htons(h->nscount);
+ c.arcount = htons(h->arcount);
+
+ return (pack_data(p, &c, HFIXEDSZ));
+}
+
+int
+asr_pack_query(struct asr_pack *p, uint16_t type, uint16_t class, const char *dname)
+{
+ pack_dname(p, dname);
+ pack_u16(p, type);
+ pack_u16(p, class);
+
+ return (p->err) ? (-1) : (0);
+}
+
+int
+asr_sockaddr_from_str(struct sockaddr *sa, int family, const char *str)
+{
+ struct in_addr ina;
+ struct in6_addr in6a;
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+ char *cp, *str2;
+ const char *errstr;
+
+ switch (family) {
+ case PF_UNSPEC:
+ if (asr_sockaddr_from_str(sa, PF_INET, str) == 0)
+ return (0);
+ return asr_sockaddr_from_str(sa, PF_INET6, str);
+
+ case PF_INET:
+ if (inet_pton(PF_INET, str, &ina) != 1)
+ return (-1);
+
+ 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);
+
+ case PF_INET6:
+ cp = strchr(str, SCOPE_DELIMITER);
+ if (cp) {
+ str2 = strdup(str);
+ if (str2 == NULL)
+ return (-1);
+ str2[cp - str] = '\0';
+ if (inet_pton(PF_INET6, str2, &in6a) != 1) {
+ free(str2);
+ return (-1);
+ }
+ cp++;
+ free(str2);
+ } else if (inet_pton(PF_INET6, str, &in6a) != 1)
+ return (-1);
+
+ 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;
+
+ if (cp == NULL)
+ return (0);
+
+ if (IN6_IS_ADDR_LINKLOCAL(&in6a) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(&in6a) ||
+ IN6_IS_ADDR_MC_NODELOCAL(&in6a))
+ if ((sin6->sin6_scope_id = if_nametoindex(cp)))
+ return (0);
+
+ sin6->sin6_scope_id = strtonum(cp, 0, UINT32_MAX, &errstr);
+ if (errstr)
+ return (-1);
+ return (0);
+
+ default:
+ break;
+ }
+
+ return (-1);
+}
+
+ssize_t
+asr_addr_as_fqdn(const char *addr, int family, char *dst, size_t max)
+{
+ const struct in6_addr *in6_addr;
+ in_addr_t in_addr;
+
+ switch (family) {
+ case AF_INET:
+ in_addr = ntohl(*((const in_addr_t *)addr));
+ snprintf(dst, max,
+ "%d.%d.%d.%d.in-addr.arpa.",
+ in_addr & 0xff,
+ (in_addr >> 8) & 0xff,
+ (in_addr >> 16) & 0xff,
+ (in_addr >> 24) & 0xff);
+ break;
+ case AF_INET6:
+ in6_addr = (const struct in6_addr *)addr;
+ snprintf(dst, max,
+ "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
+ "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
+ "ip6.arpa.",
+ in6_addr->s6_addr[15] & 0xf,
+ (in6_addr->s6_addr[15] >> 4) & 0xf,
+ in6_addr->s6_addr[14] & 0xf,
+ (in6_addr->s6_addr[14] >> 4) & 0xf,
+ in6_addr->s6_addr[13] & 0xf,
+ (in6_addr->s6_addr[13] >> 4) & 0xf,
+ in6_addr->s6_addr[12] & 0xf,
+ (in6_addr->s6_addr[12] >> 4) & 0xf,
+ in6_addr->s6_addr[11] & 0xf,
+ (in6_addr->s6_addr[11] >> 4) & 0xf,
+ in6_addr->s6_addr[10] & 0xf,
+ (in6_addr->s6_addr[10] >> 4) & 0xf,
+ in6_addr->s6_addr[9] & 0xf,
+ (in6_addr->s6_addr[9] >> 4) & 0xf,
+ in6_addr->s6_addr[8] & 0xf,
+ (in6_addr->s6_addr[8] >> 4) & 0xf,
+ in6_addr->s6_addr[7] & 0xf,
+ (in6_addr->s6_addr[7] >> 4) & 0xf,
+ in6_addr->s6_addr[6] & 0xf,
+ (in6_addr->s6_addr[6] >> 4) & 0xf,
+ in6_addr->s6_addr[5] & 0xf,
+ (in6_addr->s6_addr[5] >> 4) & 0xf,
+ in6_addr->s6_addr[4] & 0xf,
+ (in6_addr->s6_addr[4] >> 4) & 0xf,
+ in6_addr->s6_addr[3] & 0xf,
+ (in6_addr->s6_addr[3] >> 4) & 0xf,
+ in6_addr->s6_addr[2] & 0xf,
+ (in6_addr->s6_addr[2] >> 4) & 0xf,
+ in6_addr->s6_addr[1] & 0xf,
+ (in6_addr->s6_addr[1] >> 4) & 0xf,
+ in6_addr->s6_addr[0] & 0xf,
+ (in6_addr->s6_addr[0] >> 4) & 0xf);
+ break;
+ default:
+ return (-1);
+ }
+ return (0);
+}
diff --git a/contrib/lib/libc/asr/event_asr_run.c b/contrib/lib/libc/asr/event_asr_run.c
new file mode 100644
index 00000000..4306e8a3
--- /dev/null
+++ b/contrib/lib/libc/asr/event_asr_run.c
@@ -0,0 +1,85 @@
+/* $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 <sys/types.h>
+#include <sys/socket.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/contrib/lib/libc/asr/getaddrinfo.c b/contrib/lib/libc/asr/getaddrinfo.c
new file mode 100644
index 00000000..074a824c
--- /dev/null
+++ b/contrib/lib/libc/asr/getaddrinfo.c
@@ -0,0 +1,52 @@
+/* $OpenBSD: getaddrinfo.c,v 1.4 2014/03/25 19:48:11 eric Exp $ */
+/*
+ * 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 <sys/types.h>
+#include <netinet/in.h>
+
+#include <errno.h>
+#include <resolv.h>
+
+#include "asr.h"
+
+int
+getaddrinfo(const char *hostname, const char *servname,
+ const struct addrinfo *hints, struct addrinfo **res)
+{
+ struct asr_query *as;
+ struct asr_result ar;
+ int saved_errno = errno;
+
+ res_init();
+
+ as = getaddrinfo_async(hostname, servname, hints, NULL);
+ if (as == NULL) {
+ if (errno == ENOMEM) {
+ errno = saved_errno;
+ return (EAI_MEMORY);
+ }
+ return (EAI_SYSTEM);
+ }
+
+ asr_run_sync(as, &ar);
+
+ *res = ar.ar_addrinfo;
+ if (ar.ar_gai_errno == EAI_SYSTEM)
+ errno = ar.ar_errno;
+
+ return (ar.ar_gai_errno);
+}
diff --git a/contrib/lib/libc/asr/getaddrinfo_async.c b/contrib/lib/libc/asr/getaddrinfo_async.c
new file mode 100644
index 00000000..6a0c4cde
--- /dev/null
+++ b/contrib/lib/libc/asr/getaddrinfo_async.c
@@ -0,0 +1,887 @@
+/* $OpenBSD: getaddrinfo_async.c,v 1.25 2014/03/25 19:48:11 eric Exp $ */
+/*
+ * 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/uio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#ifdef YP
+#include <rpc/rpc.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+#include "ypinternal.h"
+#endif
+
+#include <err.h>
+#include <errno.h>
+#include <resolv.h> /* for res_hnok */
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "asr.h"
+#include "asr_private.h"
+
+struct match {
+ int family;
+ int socktype;
+ int protocol;
+};
+
+static int getaddrinfo_async_run(struct asr_query *, struct asr_result *);
+static int get_port(const char *, const char *, int);
+static int iter_family(struct asr_query *, int);
+static int iter_domain(struct asr_query *, const char *, char *, size_t);
+static int addrinfo_add(struct asr_query *, const struct sockaddr *, const char *);
+static int addrinfo_from_file(struct asr_query *, int, FILE *);
+static int addrinfo_from_pkt(struct asr_query *, char *, size_t);
+#ifdef YP
+static int addrinfo_from_yp(struct asr_query *, int, char *);
+#endif
+
+static const struct match matches[] = {
+ { PF_INET, SOCK_DGRAM, IPPROTO_UDP },
+ { PF_INET, SOCK_STREAM, IPPROTO_TCP },
+ { PF_INET, SOCK_RAW, 0 },
+ { PF_INET6, SOCK_DGRAM, IPPROTO_UDP },
+ { PF_INET6, SOCK_STREAM, IPPROTO_TCP },
+ { PF_INET6, SOCK_RAW, 0 },
+ { -1, 0, 0, },
+};
+
+#define MATCH_FAMILY(a, b) ((a) == matches[(b)].family || (a) == PF_UNSPEC)
+#define MATCH_PROTO(a, b) ((a) == matches[(b)].protocol || (a) == 0 || matches[(b)].protocol == 0)
+/* Do not match SOCK_RAW unless explicitely specified */
+#define MATCH_SOCKTYPE(a, b) ((a) == matches[(b)].socktype || ((a) == 0 && \
+ matches[(b)].socktype != SOCK_RAW))
+
+enum {
+ DOM_INIT,
+ DOM_DOMAIN,
+ DOM_DONE
+};
+
+struct asr_query *
+getaddrinfo_async(const char *hostname, const char *servname,
+ const struct addrinfo *hints, void *asr)
+{
+ struct asr_ctx *ac;
+ struct asr_query *as;
+ char alias[MAXDNAME];
+
+ ac = asr_use_resolver(asr);
+ if ((as = asr_async_new(ac, ASR_GETADDRINFO)) == NULL)
+ goto abort; /* errno set */
+ as->as_run = getaddrinfo_async_run;
+
+ if (hostname) {
+ if (asr_hostalias(ac, hostname, alias, sizeof(alias)))
+ hostname = alias;
+ if ((as->as.ai.hostname = strdup(hostname)) == NULL)
+ goto abort; /* errno set */
+ }
+ if (servname && (as->as.ai.servname = strdup(servname)) == NULL)
+ goto abort; /* errno set */
+ if (hints)
+ memmove(&as->as.ai.hints, hints, sizeof *hints);
+ else {
+ memset(&as->as.ai.hints, 0, sizeof as->as.ai.hints);
+ as->as.ai.hints.ai_family = PF_UNSPEC;
+ }
+
+ asr_ctx_unref(ac);
+ return (as);
+ abort:
+ if (as)
+ asr_async_free(as);
+ asr_ctx_unref(ac);
+ return (NULL);
+}
+
+static int
+getaddrinfo_async_run(struct asr_query *as, struct asr_result *ar)
+{
+#ifdef YP
+ static char *domain = NULL;
+ char *res;
+ int len;
+ char *name;
+#endif
+ char fqdn[MAXDNAME];
+ const char *str;
+ struct addrinfo *ai;
+ int i, family, r;
+ FILE *f;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sain;
+ struct sockaddr_in6 sain6;
+ } sa;
+
+ next:
+ switch (as->as_state) {
+
+ case ASR_STATE_INIT:
+
+ /*
+ * First, make sure the parameters are valid.
+ */
+
+ as->as_count = 0;
+
+ if (as->as.ai.hostname == NULL &&
+ as->as.ai.servname == NULL) {
+ ar->ar_gai_errno = EAI_NONAME;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ ai = &as->as.ai.hints;
+
+#ifdef EAI_BADHINTS
+ if (ai->ai_addrlen ||
+ ai->ai_canonname ||
+ ai->ai_addr ||
+ ai->ai_next) {
+ ar->ar_gai_errno = EAI_BADHINTS;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+#endif
+
+ if (ai->ai_flags & ~AI_MASK ||
+ (ai->ai_flags & AI_CANONNAME && ai->ai_flags & AI_FQDN)) {
+ ar->ar_gai_errno = EAI_BADFLAGS;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ if (ai->ai_family != PF_UNSPEC &&
+ ai->ai_family != PF_INET &&
+ ai->ai_family != PF_INET6) {
+ ar->ar_gai_errno = EAI_FAMILY;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ if (ai->ai_socktype &&
+ ai->ai_socktype != SOCK_DGRAM &&
+ ai->ai_socktype != SOCK_STREAM &&
+ ai->ai_socktype != SOCK_RAW) {
+ ar->ar_gai_errno = EAI_SOCKTYPE;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ if (ai->ai_socktype == SOCK_RAW &&
+ get_port(as->as.ai.servname, NULL, 1) != 0) {
+ ar->ar_gai_errno = EAI_SERVICE;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ /* Make sure there is at least a valid combination */
+ for (i = 0; matches[i].family != -1; i++)
+ if (MATCH_FAMILY(ai->ai_family, i) &&
+ MATCH_SOCKTYPE(ai->ai_socktype, i) &&
+ MATCH_PROTO(ai->ai_protocol, i))
+ break;
+ if (matches[i].family == -1) {
+#ifdef EAI_BADHINTS
+ ar->ar_gai_errno = EAI_BADHINTS;
+#else
+ ar->ar_gai_errno = EAI_FAIL;
+#endif
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ if (ai->ai_protocol == 0 || ai->ai_protocol == IPPROTO_UDP)
+ as->as.ai.port_udp = get_port(as->as.ai.servname, "udp",
+ as->as.ai.hints.ai_flags & AI_NUMERICSERV);
+ if (ai->ai_protocol == 0 || ai->ai_protocol == IPPROTO_TCP)
+ as->as.ai.port_tcp = get_port(as->as.ai.servname, "tcp",
+ as->as.ai.hints.ai_flags & AI_NUMERICSERV);
+ if (as->as.ai.port_tcp == -2 || as->as.ai.port_udp == -2 ||
+ (as->as.ai.port_tcp == -1 && as->as.ai.port_udp == -1) ||
+ (ai->ai_protocol && (as->as.ai.port_udp == -1 ||
+ as->as.ai.port_tcp == -1))) {
+ ar->ar_gai_errno = EAI_SERVICE;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ ar->ar_gai_errno = 0;
+
+ /* If hostname is NULL, use local address */
+ if (as->as.ai.hostname == NULL) {
+ for (family = iter_family(as, 1);
+ family != -1;
+ family = iter_family(as, 0)) {
+ /*
+ * We could use statically built sockaddrs for
+ * those, rather than parsing over and over.
+ */
+ if (family == PF_INET)
+ str = (ai->ai_flags & AI_PASSIVE) ? \
+ "0.0.0.0" : "127.0.0.1";
+ else /* PF_INET6 */
+ str = (ai->ai_flags & AI_PASSIVE) ? \
+ "::" : "::1";
+ /* This can't fail */
+ asr_sockaddr_from_str(&sa.sa, family, str);
+ if ((r = addrinfo_add(as, &sa.sa, NULL))) {
+ ar->ar_gai_errno = r;
+ break;
+ }
+ }
+ if (ar->ar_gai_errno == 0 && as->as_count == 0) {
+ ar->ar_gai_errno = EAI_NODATA;
+ }
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ /* Try numeric addresses first */
+ for (family = iter_family(as, 1);
+ family != -1;
+ family = iter_family(as, 0)) {
+
+ if (asr_sockaddr_from_str(&sa.sa, family,
+ as->as.ai.hostname) == -1)
+ continue;
+
+ if ((r = addrinfo_add(as, &sa.sa, NULL)))
+ ar->ar_gai_errno = r;
+ break;
+ }
+ if (ar->ar_gai_errno || as->as_count) {
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ if (ai->ai_flags & AI_NUMERICHOST) {
+ ar->ar_gai_errno = EAI_NONAME;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ async_set_state(as, ASR_STATE_NEXT_DB);
+ break;
+
+ case ASR_STATE_NEXT_DB:
+ if (asr_iter_db(as) == -1) {
+ async_set_state(as, ASR_STATE_NOT_FOUND);
+ break;
+ }
+ as->as_family_idx = 0;
+ async_set_state(as, ASR_STATE_SAME_DB);
+ break;
+
+ case ASR_STATE_NEXT_FAMILY:
+ as->as_family_idx += 1;
+ if (as->as.ai.hints.ai_family != AF_UNSPEC ||
+ AS_FAMILY(as) == -1) {
+ /* The family was specified, or we have tried all
+ * families with this DB.
+ */
+ if (as->as_count) {
+ ar->ar_gai_errno = 0;
+ async_set_state(as, ASR_STATE_HALT);
+ } else
+ async_set_state(as, ASR_STATE_NEXT_DOMAIN);
+ break;
+ }
+ async_set_state(as, ASR_STATE_SAME_DB);
+ break;
+
+ case ASR_STATE_NEXT_DOMAIN:
+ /* domain search is only for dns */
+ if (AS_DB(as) != ASR_DB_DNS) {
+ async_set_state(as, ASR_STATE_NEXT_DB);
+ break;
+ }
+ as->as_family_idx = 0;
+
+ free(as->as.ai.fqdn);
+ as->as.ai.fqdn = NULL;
+ r = iter_domain(as, as->as.ai.hostname, fqdn, sizeof(fqdn));
+ if (r == -1) {
+ async_set_state(as, ASR_STATE_NEXT_DB);
+ break;
+ }
+ if (r == 0) {
+ ar->ar_gai_errno = EAI_FAIL;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+ as->as.ai.fqdn = strdup(fqdn);
+ if (as->as.ai.fqdn == NULL) {
+ ar->ar_gai_errno = EAI_MEMORY;
+ async_set_state(as, ASR_STATE_HALT);
+ }
+
+ async_set_state(as, ASR_STATE_SAME_DB);
+ break;
+
+ case ASR_STATE_SAME_DB:
+ /* query the current DB again */
+ switch (AS_DB(as)) {
+ case ASR_DB_DNS:
+ if (as->as.ai.fqdn == NULL) {
+ /* First try, initialize domain iteration */
+ as->as_dom_flags = 0;
+ as->as_dom_step = DOM_INIT;
+ async_set_state(as, ASR_STATE_NEXT_DOMAIN);
+ break;
+ }
+
+ family = (as->as.ai.hints.ai_family == AF_UNSPEC) ?
+ AS_FAMILY(as) : as->as.ai.hints.ai_family;
+
+ as->as.ai.subq = res_query_async_ctx(as->as.ai.fqdn,
+ C_IN, (family == AF_INET6) ? T_AAAA : T_A,
+ as->as_ctx);
+
+ if (as->as.ai.subq == NULL) {
+ if (errno == ENOMEM)
+ ar->ar_gai_errno = EAI_MEMORY;
+ else
+ ar->ar_gai_errno = EAI_FAIL;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+ async_set_state(as, ASR_STATE_SUBQUERY);
+ break;
+
+ case ASR_DB_FILE:
+ f = fopen(as->as_ctx->ac_hostfile, "r");
+ if (f == NULL) {
+ async_set_state(as, ASR_STATE_NEXT_DB);
+ break;
+ }
+ family = (as->as.ai.hints.ai_family == AF_UNSPEC) ?
+ AS_FAMILY(as) : as->as.ai.hints.ai_family;
+
+ r = addrinfo_from_file(as, family, f);
+ if (r == -1) {
+ if (errno == ENOMEM)
+ ar->ar_gai_errno = EAI_MEMORY;
+ else
+ ar->ar_gai_errno = EAI_FAIL;
+ async_set_state(as, ASR_STATE_HALT);
+ } else
+ async_set_state(as, ASR_STATE_NEXT_FAMILY);
+ fclose(f);
+ break;
+
+#ifdef YP
+ case ASR_DB_YP:
+ if (!domain && _yp_check(&domain) == 0) {
+ async_set_state(as, ASR_STATE_NEXT_DB);
+ break;
+ }
+ family = (as->as.ai.hints.ai_family == AF_UNSPEC) ?
+ AS_FAMILY(as) : as->as.ai.hints.ai_family;
+
+ name = as->as.ai.hostname;
+
+ /* XXX
+ * ipnodes.byname could also contain IPv4 address
+ */
+ r = yp_match(domain, (family == AF_INET6) ?
+ "ipnodes.byname" : "hosts.byname",
+ name, strlen(name), &res, &len);
+ if (r == 0) {
+ r = addrinfo_from_yp(as, family, res);
+ free(res);
+ if (r == -1) {
+ if (errno == ENOMEM)
+ ar->ar_gai_errno = EAI_MEMORY;
+ else
+ ar->ar_gai_errno = EAI_FAIL;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+ }
+ async_set_state(as, ASR_STATE_NEXT_FAMILY);
+ break;
+#endif
+ default:
+ async_set_state(as, ASR_STATE_NEXT_DB);
+ }
+ break;
+
+ case ASR_STATE_SUBQUERY:
+ if ((r = asr_run(as->as.ai.subq, ar)) == ASYNC_COND)
+ return (ASYNC_COND);
+
+ as->as.ai.subq = NULL;
+
+ if (ar->ar_datalen == -1) {
+ async_set_state(as, ASR_STATE_NEXT_FAMILY);
+ break;
+ }
+
+ r = addrinfo_from_pkt(as, ar->ar_data, ar->ar_datalen);
+ if (r == -1) {
+ if (errno == ENOMEM)
+ ar->ar_gai_errno = EAI_MEMORY;
+ else
+ ar->ar_gai_errno = EAI_FAIL;
+ async_set_state(as, ASR_STATE_HALT);
+ } else
+ async_set_state(as, ASR_STATE_NEXT_FAMILY);
+ free(ar->ar_data);
+ break;
+
+ case ASR_STATE_NOT_FOUND:
+ /* No result found. Maybe we can try again. */
+ if (as->as.ai.flags & ASYNC_AGAIN)
+ ar->ar_gai_errno = EAI_AGAIN;
+ else
+ ar->ar_gai_errno = EAI_NODATA;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+
+ case ASR_STATE_HALT:
+ if (ar->ar_gai_errno == 0) {
+ ar->ar_count = as->as_count;
+ ar->ar_addrinfo = as->as.ai.aifirst;
+ as->as.ai.aifirst = NULL;
+ } else {
+ ar->ar_count = 0;
+ ar->ar_addrinfo = NULL;
+ }
+ return (ASYNC_DONE);
+
+ default:
+ ar->ar_errno = EOPNOTSUPP;
+ ar->ar_gai_errno = EAI_SYSTEM;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+ goto next;
+}
+
+/*
+ * Retreive the port number for the service name "servname" and
+ * the protocol "proto".
+ */
+static int
+get_port(const char *servname, const char *proto, int numonly)
+{
+ struct servent se;
+#ifdef HAVE_STRUCT_SERVENT_DATA
+ struct servent_data sed;
+#endif
+ int port, r;
+ const char *e;
+
+ if (servname == NULL)
+ return (0);
+
+ e = NULL;
+ port = strtonum(servname, 0, USHRT_MAX, &e);
+ if (e == NULL)
+ return (port);
+ if (errno == ERANGE)
+ return (-2); /* invalid */
+ if (numonly)
+ return (-2);
+
+#ifdef HAVE_STRUCT_SERVENT_DATA
+ memset(&sed, 0, sizeof(sed));
+#endif
+#ifdef HAVE_GETSERVBYNAME_R_4_ARGS
+ r = getservbyname_r(servname, proto, &se, &sed);
+#else
+ r = -1;
+#endif
+ port = ntohs(se.s_port);
+#ifdef HAVE_ENDSERVENT_R
+ endservent_r(&sed);
+#endif
+
+ if (r == -1)
+ return (-1); /* not found */
+
+ return (port);
+}
+
+/*
+ * Iterate over the address families that are to be queried. Use the
+ * list on the async context, unless a specific family was given in hints.
+ */
+static int
+iter_family(struct asr_query *as, int first)
+{
+ if (first) {
+ as->as_family_idx = 0;
+ if (as->as.ai.hints.ai_family != PF_UNSPEC)
+ return as->as.ai.hints.ai_family;
+ return AS_FAMILY(as);
+ }
+
+ if (as->as.ai.hints.ai_family != PF_UNSPEC)
+ return (-1);
+
+ as->as_family_idx++;
+
+ return AS_FAMILY(as);
+}
+
+/*
+ * Concatenate a name and a domain name. The result has no trailing dot.
+ * Return the resulting string length, or 0 in case of error.
+ */
+static size_t
+domcat(const char *name, const char *domain, char *buf, size_t buflen)
+{
+ size_t r;
+
+ r = asr_make_fqdn(name, domain, buf, buflen);
+ if (r == 0)
+ return (0);
+ buf[r - 1] = '\0';
+
+ return (r - 1);
+}
+
+/*
+ * Implement the search domain strategy.
+ *
+ * XXX duplicate from res_search_async
+ *
+ * This function works as a generator that constructs complete domains in
+ * buffer "buf" of size "len" for the given host name "name", according to the
+ * search rules defined by the resolving context. It is supposed to be called
+ * multiple times (with the same name) to generate the next possible domain
+ * name, if any.
+ *
+ * It returns -1 if all possibilities have been exhausted, 0 if there was an
+ * error generating the next name, or the resulting name length.
+ */
+static int
+iter_domain(struct asr_query *as, const char *name, char * buf, size_t len)
+{
+ const char *c;
+ int dots;
+
+ switch (as->as_dom_step) {
+
+ case DOM_INIT:
+ /* First call */
+
+ /*
+ * If "name" is an FQDN, that's the only result and we
+ * don't try anything else.
+ */
+ if (strlen(name) && name[strlen(name) - 1] == '.') {
+ DPRINT("asr: iter_domain(\"%s\") fqdn\n", name);
+ as->as_dom_flags |= ASYNC_DOM_FQDN;
+ as->as_dom_step = DOM_DONE;
+ return (domcat(name, NULL, buf, len));
+ }
+
+ /*
+ * Otherwise, we iterate through the specified search domains.
+ */
+ as->as_dom_step = DOM_DOMAIN;
+ as->as_dom_idx = 0;
+
+ /*
+ * If "name" as enough dots, use it as-is first, as indicated
+ * in resolv.conf(5).
+ */
+ dots = 0;
+ for (c = name; *c; c++)
+ dots += (*c == '.');
+ if (dots >= as->as_ctx->ac_ndots) {
+ DPRINT("asr: iter_domain(\"%s\") ndots\n", name);
+ as->as_dom_flags |= ASYNC_DOM_NDOTS;
+ if (strlcpy(buf, name, len) >= len)
+ return (0);
+ return (strlen(buf));
+ }
+ /* Otherwise, starts using the search domains */
+ /* FALLTHROUGH */
+
+ case DOM_DOMAIN:
+ if (as->as_dom_idx < as->as_ctx->ac_domcount) {
+ DPRINT("asr: iter_domain(\"%s\") domain \"%s\"\n",
+ name, as->as_ctx->ac_dom[as->as_dom_idx]);
+ as->as_dom_flags |= ASYNC_DOM_DOMAIN;
+ return (domcat(name,
+ as->as_ctx->ac_dom[as->as_dom_idx++], buf, len));
+ }
+
+ /* No more domain to try. */
+
+ as->as_dom_step = DOM_DONE;
+
+ /*
+ * If the name was not tried as an absolute name before,
+ * do it now.
+ */
+ if (!(as->as_dom_flags & ASYNC_DOM_NDOTS)) {
+ DPRINT("asr: iter_domain(\"%s\") as is\n", name);
+ as->as_dom_flags |= ASYNC_DOM_ASIS;
+ if (strlcpy(buf, name, len) >= len)
+ return (0);
+ return (strlen(buf));
+ }
+ /* Otherwise, we are done. */
+
+ case DOM_DONE:
+ default:
+ DPRINT("asr: iter_domain(\"%s\") done\n", name);
+ return (-1);
+ }
+}
+
+/*
+ * Use the sockaddr at "sa" to extend the result list on the "as" context,
+ * with the specified canonical name "cname". This function adds one
+ * entry per protocol/socktype match.
+ */
+static int
+addrinfo_add(struct asr_query *as, const struct sockaddr *sa, const char *cname)
+{
+ struct addrinfo *ai;
+ int i, port, proto;
+
+ for (i = 0; matches[i].family != -1; i++) {
+ if (matches[i].family != sa->sa_family ||
+ !MATCH_SOCKTYPE(as->as.ai.hints.ai_socktype, i) ||
+ !MATCH_PROTO(as->as.ai.hints.ai_protocol, i))
+ continue;
+
+ proto = as->as.ai.hints.ai_protocol;
+ if (!proto)
+ proto = matches[i].protocol;
+
+ if (proto == IPPROTO_TCP)
+ port = as->as.ai.port_tcp;
+ else if (proto == IPPROTO_UDP)
+ port = as->as.ai.port_udp;
+ else
+ port = 0;
+
+ /* servname specified, but not defined for this protocol */
+ if (port == -1)
+ continue;
+
+ ai = calloc(1, sizeof(*ai) + SA_LEN(sa));
+ if (ai == NULL)
+ return (EAI_MEMORY);
+ ai->ai_family = sa->sa_family;
+ ai->ai_socktype = matches[i].socktype;
+ ai->ai_protocol = proto;
+ ai->ai_flags = as->as.ai.hints.ai_flags;
+ ai->ai_addrlen = SA_LEN(sa);
+ ai->ai_addr = (void *)(ai + 1);
+ if (cname &&
+ as->as.ai.hints.ai_flags & (AI_CANONNAME | AI_FQDN)) {
+ if ((ai->ai_canonname = strdup(cname)) == NULL) {
+ free(ai);
+ return (EAI_MEMORY);
+ }
+ }
+ memmove(ai->ai_addr, sa, SA_LEN(sa));
+ if (sa->sa_family == PF_INET)
+ ((struct sockaddr_in *)ai->ai_addr)->sin_port =
+ htons(port);
+ else if (sa->sa_family == PF_INET6)
+ ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port =
+ htons(port);
+
+ if (as->as.ai.aifirst == NULL)
+ as->as.ai.aifirst = ai;
+ if (as->as.ai.ailast)
+ as->as.ai.ailast->ai_next = ai;
+ as->as.ai.ailast = ai;
+ as->as_count += 1;
+ }
+
+ return (0);
+}
+
+void
+asr_freeaddrinfo(struct addrinfo *ai)
+{
+ struct addrinfo *ai_next;
+
+ while (ai) {
+ ai_next = ai->ai_next;
+ if (ai->ai_canonname)
+ free(ai->ai_canonname);
+ free(ai);
+ ai = ai_next;
+ }
+}
+
+static int
+addrinfo_from_file(struct asr_query *as, int family, FILE *f)
+{
+ char *tokens[MAXTOKEN], *c;
+ int n, i;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sain;
+ struct sockaddr_in6 sain6;
+ } u;
+
+ for (;;) {
+ n = asr_parse_namedb_line(f, tokens, MAXTOKEN);
+ if (n == -1)
+ break; /* ignore errors reading the file */
+
+ for (i = 1; i < n; i++) {
+ if (strcasecmp(as->as.ai.hostname, tokens[i]))
+ continue;
+ if (asr_sockaddr_from_str(&u.sa, family, tokens[0]) == -1)
+ continue;
+ break;
+ }
+ if (i == n)
+ continue;
+
+ if (as->as.ai.hints.ai_flags & (AI_CANONNAME | AI_FQDN))
+ c = tokens[1];
+ else
+ c = NULL;
+
+ if (addrinfo_add(as, &u.sa, c))
+ return (-1); /* errno set */
+ }
+ return (0);
+}
+
+static int
+addrinfo_from_pkt(struct asr_query *as, char *pkt, size_t pktlen)
+{
+ struct asr_unpack p;
+ struct asr_dns_header h;
+ struct asr_dns_query q;
+ struct asr_dns_rr rr;
+ int i;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sain;
+ struct sockaddr_in6 sain6;
+ } u;
+ char buf[MAXDNAME], *c;
+
+ asr_unpack_init(&p, pkt, pktlen);
+ asr_unpack_header(&p, &h);
+ for (; h.qdcount; h.qdcount--)
+ asr_unpack_query(&p, &q);
+
+ for (i = 0; i < h.ancount; i++) {
+ asr_unpack_rr(&p, &rr);
+ if (rr.rr_type != q.q_type ||
+ rr.rr_class != q.q_class)
+ continue;
+
+ memset(&u, 0, sizeof u);
+ if (rr.rr_type == T_A) {
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+ u.sain.sin_len = sizeof u.sain;
+#endif
+ u.sain.sin_family = AF_INET;
+ u.sain.sin_addr = rr.rr.in_a.addr;
+ u.sain.sin_port = 0;
+ } else if (rr.rr_type == T_AAAA) {
+#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
+ u.sain6.sin6_len = sizeof u.sain6;
+#endif
+ u.sain6.sin6_family = AF_INET6;
+ u.sain6.sin6_addr = rr.rr.in_aaaa.addr6;
+ u.sain6.sin6_port = 0;
+ } else
+ continue;
+
+ if (as->as.ai.hints.ai_flags & AI_CANONNAME) {
+ asr_strdname(rr.rr_dname, buf, sizeof buf);
+ buf[strlen(buf) - 1] = '\0';
+ c = res_hnok(buf) ? buf : NULL;
+ } else if (as->as.ai.hints.ai_flags & AI_FQDN)
+ c = as->as.ai.fqdn;
+ else
+ c = NULL;
+
+ if (addrinfo_add(as, &u.sa, c))
+ return (-1); /* errno set */
+ }
+ return (0);
+}
+
+#ifdef YP
+static int
+strsplit(char *line, char **tokens, int ntokens)
+{
+ int ntok;
+ char *cp, **tp;
+
+ for (cp = line, tp = tokens, ntok = 0;
+ ntok < ntokens && (*tp = strsep(&cp, " \t")) != NULL; )
+ if (**tp != '\0') {
+ tp++;
+ ntok++;
+ }
+
+ return (ntok);
+}
+
+static int
+addrinfo_from_yp(struct asr_query *as, int family, char *line)
+{
+ char *next, *tokens[MAXTOKEN], *c;
+ int ntok;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sain;
+ struct sockaddr_in6 sain6;
+ } u;
+
+ for (next = line; line; line = next) {
+ if ((next = strchr(line, '\n'))) {
+ *next = '\0';
+ next += 1;
+ }
+ ntok = strsplit(line, tokens, MAXTOKEN);
+ if (ntok < 2)
+ continue;
+
+ if (asr_sockaddr_from_str(&u.sa, family, tokens[0]) == -1)
+ continue;
+
+ if (as->as.ai.hints.ai_flags & (AI_CANONNAME | AI_FQDN))
+ c = tokens[1];
+ else
+ c = NULL;
+
+ if (addrinfo_add(as, &u.sa, c))
+ return (-1); /* errno set */
+ }
+ return (0);
+}
+#endif
diff --git a/contrib/lib/libc/asr/gethostnamadr.c b/contrib/lib/libc/asr/gethostnamadr.c
new file mode 100644
index 00000000..a7561f13
--- /dev/null
+++ b/contrib/lib/libc/asr/gethostnamadr.c
@@ -0,0 +1,196 @@
+/* $OpenBSD: gethostnamadr.c,v 1.10 2014/03/25 19:48:11 eric Exp $ */
+/*
+ * Copyright (c) 2012,2013 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 <sys/types.h>
+#include <netinet/in.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "asr.h"
+
+static int _gethostbyname(const char *, int, struct hostent *, char *, size_t,
+ int *);
+static int _fillhostent(const struct hostent *, struct hostent *, char *,
+ size_t);
+
+static struct hostent _hostent;
+static char _entbuf[4096];
+
+static char *_empty[] = { NULL, };
+
+static int
+_fillhostent(const struct hostent *h, struct hostent *r, char *buf, size_t len)
+{
+ char **ptr, *end, *pos;
+ size_t n, i;
+ int naliases, naddrs;
+
+ bzero(buf, len);
+ bzero(r, sizeof(*r));
+ r->h_aliases = _empty;
+ r->h_addr_list = _empty;
+
+ end = buf + len;
+ ptr = (char **)ALIGN(buf);
+
+ if ((char *)ptr >= end)
+ return (ERANGE);
+
+ for (naliases = 0; h->h_aliases[naliases]; naliases++)
+ ;
+ for (naddrs = 0; h->h_addr_list[naddrs]; naddrs++)
+ ;
+
+ pos = (char *)(ptr + (naliases + 1) + (naddrs + 1));
+ if (pos >= end)
+ return (ERANGE);
+
+ r->h_name = NULL;
+ r->h_addrtype = h->h_addrtype;
+ r->h_length = h->h_length;
+ r->h_aliases = ptr;
+ r->h_addr_list = ptr + naliases + 1;
+
+ n = strlcpy(pos, h->h_name, end - pos);
+ if (n >= end - pos)
+ return (ERANGE);
+ r->h_name = pos;
+ pos += n + 1;
+
+ for (i = 0; i < naliases; i++) {
+ n = strlcpy(pos, h->h_aliases[i], end - pos);
+ if (n >= end - pos)
+ return (ERANGE);
+ r->h_aliases[i] = pos;
+ pos += n + 1;
+ }
+
+ pos = (char *)ALIGN(pos);
+ if (pos >= end)
+ return (ERANGE);
+
+ for (i = 0; i < naddrs; i++) {
+ if (r->h_length > end - pos)
+ return (ERANGE);
+ memmove(pos, h->h_addr_list[i], r->h_length);
+ r->h_addr_list[i] = pos;
+ pos += r->h_length;
+ }
+
+ return (0);
+}
+
+static int
+_gethostbyname(const char *name, int af, struct hostent *ret, char *buf,
+ size_t buflen, int *h_errnop)
+{
+ struct asr_query *as;
+ struct asr_result ar;
+ int r;
+
+ if (af == -1)
+ as = gethostbyname_async(name, NULL);
+ else
+ as = gethostbyname2_async(name, af, NULL);
+
+ if (as == NULL)
+ return (errno);
+
+ asr_run_sync(as, &ar);
+
+ errno = ar.ar_errno;
+ *h_errnop = ar.ar_h_errno;
+ if (ar.ar_hostent == NULL)
+ return (0);
+
+ r = _fillhostent(ar.ar_hostent, ret, buf, buflen);
+ free(ar.ar_hostent);
+
+ return (r);
+}
+
+struct hostent *
+gethostbyname(const char *name)
+{
+ struct hostent *h;
+
+ res_init();
+
+ if (_res.options & RES_USE_INET6 &&
+ (h = gethostbyname2(name, AF_INET6)))
+ return (h);
+
+ return gethostbyname2(name, AF_INET);
+}
+
+struct hostent *
+gethostbyname2(const char *name, int af)
+{
+ int r;
+
+ res_init();
+
+ r = _gethostbyname(name, af, &_hostent, _entbuf, sizeof(_entbuf),
+ &h_errno);
+ if (r) {
+ h_errno = NETDB_INTERNAL;
+ errno = r;
+ }
+
+ if (h_errno)
+ return (NULL);
+
+ return (&_hostent);
+}
+
+struct hostent *
+gethostbyaddr(const void *addr, socklen_t len, int af)
+{
+ struct asr_query *as;
+ struct asr_result ar;
+ int r;
+
+ res_init();
+
+ as = gethostbyaddr_async(addr, len, af, NULL);
+ if (as == NULL) {
+ h_errno = NETDB_INTERNAL;
+ return (NULL);
+ }
+
+ asr_run_sync(as, &ar);
+
+ errno = ar.ar_errno;
+ h_errno = ar.ar_h_errno;
+ if (ar.ar_hostent == NULL)
+ return (NULL);
+
+ r = _fillhostent(ar.ar_hostent, &_hostent, _entbuf, sizeof(_entbuf));
+ free(ar.ar_hostent);
+
+ if (r) {
+ h_errno = NETDB_INTERNAL;
+ errno = r;
+ return (NULL);
+ }
+
+ return (&_hostent);
+}
diff --git a/contrib/lib/libc/asr/gethostnamadr_async.c b/contrib/lib/libc/asr/gethostnamadr_async.c
new file mode 100644
index 00000000..9723db05
--- /dev/null
+++ b/contrib/lib/libc/asr/gethostnamadr_async.c
@@ -0,0 +1,731 @@
+/* $OpenBSD: gethostnamadr_async.c,v 1.27 2014/03/25 19:48:11 eric Exp $ */
+/*
+ * 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 <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#ifdef YP
+#include <rpc/rpc.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+#include "ypinternal.h"
+#endif
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <resolv.h> /* for res_hnok */
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "asr.h"
+#include "asr_private.h"
+
+#define MAXALIASES 16
+#define MAXADDRS 16
+
+struct hostent_ext {
+ struct hostent h;
+ char *aliases[MAXALIASES + 1];
+ char *addrs[MAXADDRS + 1];
+ char *end;
+ char *pos;
+};
+
+static int gethostnamadr_async_run(struct asr_query *, struct asr_result *);
+static struct hostent_ext *hostent_alloc(int);
+static int hostent_set_cname(struct hostent_ext *, const char *, int);
+static int hostent_add_alias(struct hostent_ext *, const char *, int);
+static int hostent_add_addr(struct hostent_ext *, const void *, size_t);
+static struct hostent_ext *hostent_from_addr(int, const char *, const char *);
+static struct hostent_ext *hostent_file_match(FILE *, int, int, const char *,
+ int);
+static struct hostent_ext *hostent_from_packet(int, int, char *, size_t);
+#ifdef YP
+static struct hostent_ext *_yp_gethostnamadr(int, const void *);
+static struct hostent_ext *hostent_from_yp(int, char *);
+#endif
+
+struct asr_query *
+gethostbyname_async(const char *name, void *asr)
+{
+ return gethostbyname2_async(name, AF_INET, asr);
+}
+
+struct asr_query *
+gethostbyname2_async(const char *name, int af, void *asr)
+{
+ struct asr_ctx *ac;
+ struct asr_query *as;
+
+ /* the original segfaults */
+ if (name == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ ac = asr_use_resolver(asr);
+ if ((as = asr_async_new(ac, ASR_GETHOSTBYNAME)) == NULL)
+ goto abort; /* errno set */
+ as->as_run = gethostnamadr_async_run;
+
+ as->as.hostnamadr.family = af;
+ if (af == AF_INET)
+ as->as.hostnamadr.addrlen = INADDRSZ;
+ else if (af == AF_INET6)
+ as->as.hostnamadr.addrlen = IN6ADDRSZ;
+ as->as.hostnamadr.name = strdup(name);
+ if (as->as.hostnamadr.name == NULL)
+ goto abort; /* errno set */
+
+ asr_ctx_unref(ac);
+ return (as);
+
+ abort:
+ if (as)
+ asr_async_free(as);
+ asr_ctx_unref(ac);
+ return (NULL);
+}
+
+struct asr_query *
+gethostbyaddr_async(const void *addr, socklen_t len, int af, void *asr)
+{
+ struct asr_ctx *ac;
+ struct asr_query *as;
+
+ ac = asr_use_resolver(asr);
+ as = gethostbyaddr_async_ctx(addr, len, af, ac);
+ asr_ctx_unref(ac);
+
+ return (as);
+}
+
+struct asr_query *
+gethostbyaddr_async_ctx(const void *addr, socklen_t len, int af,
+ struct asr_ctx *ac)
+{
+ struct asr_query *as;
+
+ if ((as = asr_async_new(ac, ASR_GETHOSTBYADDR)) == NULL)
+ goto abort; /* errno set */
+ as->as_run = gethostnamadr_async_run;
+
+ as->as.hostnamadr.family = af;
+ as->as.hostnamadr.addrlen = len;
+ if (len > 0)
+ memmove(as->as.hostnamadr.addr, addr, (len > 16) ? 16 : len);
+
+ return (as);
+
+ abort:
+ if (as)
+ asr_async_free(as);
+ return (NULL);
+}
+
+static int
+gethostnamadr_async_run(struct asr_query *as, struct asr_result *ar)
+{
+ struct hostent_ext *h;
+ int r, type, saved_errno;
+ FILE *f;
+ char name[MAXDNAME], *data, addr[16], *c;
+
+ next:
+ switch (as->as_state) {
+
+ case ASR_STATE_INIT:
+
+ if (as->as.hostnamadr.family != AF_INET &&
+ as->as.hostnamadr.family != AF_INET6) {
+ ar->ar_h_errno = NETDB_INTERNAL;
+ ar->ar_errno = EAFNOSUPPORT;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ if ((as->as.hostnamadr.family == AF_INET &&
+ as->as.hostnamadr.addrlen != INADDRSZ) ||
+ (as->as.hostnamadr.family == AF_INET6 &&
+ as->as.hostnamadr.addrlen != IN6ADDRSZ)) {
+ ar->ar_h_errno = NETDB_INTERNAL;
+ ar->ar_errno = EINVAL;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ /* Name might be an IP address string */
+ if (as->as_type == ASR_GETHOSTBYNAME) {
+ for (c = as->as.hostnamadr.name; *c; c++)
+ if (!isdigit((unsigned char)*c) &&
+ *c != '.' && *c != ':')
+ break;
+ if (*c == 0 &&
+ inet_pton(as->as.hostnamadr.family,
+ as->as.hostnamadr.name, addr) == 1) {
+ h = hostent_from_addr(as->as.hostnamadr.family,
+ as->as.hostnamadr.name, addr);
+ if (h == NULL) {
+ ar->ar_errno = errno;
+ ar->ar_h_errno = NETDB_INTERNAL;
+ }
+ else {
+ ar->ar_hostent = &h->h;
+ ar->ar_h_errno = NETDB_SUCCESS;
+ }
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+ }
+ async_set_state(as, ASR_STATE_NEXT_DB);
+ break;
+
+ case ASR_STATE_NEXT_DB:
+
+ if (asr_iter_db(as) == -1) {
+ async_set_state(as, ASR_STATE_NOT_FOUND);
+ break;
+ }
+
+ switch (AS_DB(as)) {
+
+ case ASR_DB_DNS:
+
+ /* Create a subquery to do the DNS lookup */
+
+ if (as->as_type == ASR_GETHOSTBYNAME) {
+ type = (as->as.hostnamadr.family == AF_INET) ?
+ T_A : T_AAAA;
+ as->as.hostnamadr.subq = res_search_async_ctx(
+ as->as.hostnamadr.name,
+ C_IN, type, as->as_ctx);
+ } else {
+ asr_addr_as_fqdn(as->as.hostnamadr.addr,
+ as->as.hostnamadr.family,
+ name, sizeof(name));
+ as->as.hostnamadr.subq = res_query_async_ctx(
+ name, C_IN, T_PTR, as->as_ctx);
+ }
+
+ if (as->as.hostnamadr.subq == NULL) {
+ ar->ar_errno = errno;
+ ar->ar_h_errno = NETDB_INTERNAL;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ async_set_state(as, ASR_STATE_SUBQUERY);
+ break;
+
+ case ASR_DB_FILE:
+
+ /* Try to find a match in the host file */
+
+ if ((f = fopen(as->as_ctx->ac_hostfile, "r")) == NULL)
+ break;
+
+ if (as->as_type == ASR_GETHOSTBYNAME) {
+ data = asr_hostalias(as->as_ctx,
+ as->as.hostnamadr.name, name, sizeof(name));
+ if (data == NULL)
+ data = as->as.hostnamadr.name;
+ }
+ else
+ data = as->as.hostnamadr.addr;
+
+ h = hostent_file_match(f, as->as_type,
+ as->as.hostnamadr.family, data,
+ as->as.hostnamadr.addrlen);
+ saved_errno = errno;
+ fclose(f);
+ errno = saved_errno;
+
+ if (h == NULL) {
+ if (errno) {
+ ar->ar_errno = errno;
+ ar->ar_h_errno = NETDB_INTERNAL;
+ async_set_state(as, ASR_STATE_HALT);
+ }
+ /* otherwise not found */
+ break;
+ }
+ ar->ar_hostent = &h->h;
+ ar->ar_h_errno = NETDB_SUCCESS;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+#ifdef YP
+ case ASR_DB_YP:
+ /* IPv4 only */
+ if (as->as.hostnamadr.family != AF_INET)
+ break;
+ if (as->as_type == ASR_GETHOSTBYNAME) {
+ data = asr_hostalias(as->as_ctx,
+ as->as.hostnamadr.name, name, sizeof(name));
+ if (data == NULL)
+ data = as->as.hostnamadr.name;
+ }
+ else
+ data = as->as.hostnamadr.addr;
+ h = _yp_gethostnamadr(as->as_type, data);
+ if (h == NULL) {
+ if (errno) {
+ ar->ar_errno = errno;
+ ar->ar_h_errno = NETDB_INTERNAL;
+ async_set_state(as, ASR_STATE_HALT);
+ }
+ /* otherwise not found */
+ break;
+ }
+ ar->ar_hostent = &h->h;
+ ar->ar_h_errno = NETDB_SUCCESS;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+#endif
+ }
+ break;
+
+ case ASR_STATE_SUBQUERY:
+
+ /* Run the DNS subquery. */
+
+ if ((r = asr_run(as->as.hostnamadr.subq, ar)) == ASYNC_COND)
+ return (ASYNC_COND);
+
+ /* Done. */
+ as->as.hostnamadr.subq = NULL;
+
+ if (ar->ar_datalen == -1) {
+ async_set_state(as, ASR_STATE_NEXT_DB);
+ break;
+ }
+
+ /* If we got a packet but no anwser, use the next DB. */
+ if (ar->ar_count == 0) {
+ free(ar->ar_data);
+ as->as.hostnamadr.subq_h_errno = ar->ar_h_errno;
+ async_set_state(as, ASR_STATE_NEXT_DB);
+ break;
+ }
+
+ /* Read the hostent from the packet. */
+
+ h = hostent_from_packet(as->as_type,
+ as->as.hostnamadr.family, ar->ar_data, ar->ar_datalen);
+ free(ar->ar_data);
+ if (h == NULL) {
+ ar->ar_errno = errno;
+ ar->ar_h_errno = NETDB_INTERNAL;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ if (as->as_type == ASR_GETHOSTBYADDR) {
+ if (hostent_add_addr(h, as->as.hostnamadr.addr,
+ as->as.hostnamadr.addrlen) == -1) {
+ free(h);
+ ar->ar_errno = errno;
+ ar->ar_h_errno = NETDB_INTERNAL;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+ }
+
+ /*
+ * No address found in the dns packet. The blocking version
+ * reports this as an error.
+ */
+ if ((as->as_type == ASR_GETHOSTBYNAME &&
+ h->h.h_addr_list[0] == NULL) ||
+ (as->as_type == ASR_GETHOSTBYADDR &&
+ h->h.h_name == NULL)) {
+ free(h);
+ async_set_state(as, ASR_STATE_NEXT_DB);
+ break;
+ }
+
+ ar->ar_hostent = &h->h;
+ ar->ar_h_errno = NETDB_SUCCESS;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+
+ case ASR_STATE_NOT_FOUND:
+ ar->ar_errno = 0;
+ if (as->as.hostnamadr.subq_h_errno)
+ ar->ar_h_errno = as->as.hostnamadr.subq_h_errno;
+ else
+ ar->ar_h_errno = HOST_NOT_FOUND;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+
+ case ASR_STATE_HALT:
+ if (ar->ar_h_errno)
+ ar->ar_hostent = NULL;
+ else
+ ar->ar_errno = 0;
+ return (ASYNC_DONE);
+
+ default:
+ ar->ar_errno = EOPNOTSUPP;
+ ar->ar_h_errno = NETDB_INTERNAL;
+ ar->ar_gai_errno = EAI_SYSTEM;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+ goto next;
+}
+
+/*
+ * Create a hostent from a numeric address string.
+ */
+static struct hostent_ext *
+hostent_from_addr(int family, const char *name, const char *addr)
+{
+ struct hostent_ext *h;
+
+ if ((h = hostent_alloc(family)) == NULL)
+ return (NULL);
+ if (hostent_set_cname(h, name, 0) == -1)
+ goto fail;
+ if (hostent_add_addr(h, addr, h->h.h_length) == -1)
+ goto fail;
+ return (h);
+fail:
+ free(h);
+ return (NULL);
+}
+
+/*
+ * Lookup the first matching entry in the hostfile, either by address or by
+ * name depending on reqtype, and build a hostent from the line.
+ */
+static struct hostent_ext *
+hostent_file_match(FILE *f, int reqtype, int family, const char *data,
+ int datalen)
+{
+ char *tokens[MAXTOKEN], addr[16];
+ struct hostent_ext *h;
+ int n, i;
+
+ for (;;) {
+ n = asr_parse_namedb_line(f, tokens, MAXTOKEN);
+ if (n == -1) {
+ errno = 0; /* ignore errors reading the file */
+ return (NULL);
+ }
+
+ if (reqtype == ASR_GETHOSTBYNAME) {
+ for (i = 1; i < n; i++) {
+ if (strcasecmp(data, tokens[i]))
+ continue;
+ if (inet_pton(family, tokens[0], addr) == 1)
+ goto found;
+ }
+ } else {
+ if (inet_pton(family, tokens[0], addr) == 1 &&
+ memcmp(addr, data, datalen) == 0)
+ goto found;
+ }
+ }
+
+found:
+ if ((h = hostent_alloc(family)) == NULL)
+ return (NULL);
+ if (hostent_set_cname(h, tokens[1], 0) == -1)
+ goto fail;
+ for (i = 2; i < n; i ++)
+ if (hostent_add_alias(h, tokens[i], 0) == -1)
+ goto fail;
+ if (hostent_add_addr(h, addr, h->h.h_length) == -1)
+ goto fail;
+ return (h);
+fail:
+ free(h);
+ return (NULL);
+}
+
+/*
+ * Fill the hostent from the given DNS packet.
+ */
+static struct hostent_ext *
+hostent_from_packet(int reqtype, int family, char *pkt, size_t pktlen)
+{
+ struct hostent_ext *h;
+ struct asr_unpack p;
+ struct asr_dns_header hdr;
+ struct asr_dns_query q;
+ struct asr_dns_rr rr;
+ char dname[MAXDNAME];
+
+ if ((h = hostent_alloc(family)) == NULL)
+ return (NULL);
+
+ asr_unpack_init(&p, pkt, pktlen);
+ asr_unpack_header(&p, &hdr);
+ for (; hdr.qdcount; hdr.qdcount--)
+ asr_unpack_query(&p, &q);
+ strlcpy(dname, q.q_dname, sizeof(dname));
+
+ for (; hdr.ancount; hdr.ancount--) {
+ asr_unpack_rr(&p, &rr);
+ if (rr.rr_class != C_IN)
+ continue;
+ switch (rr.rr_type) {
+
+ case T_CNAME:
+ if (reqtype == ASR_GETHOSTBYNAME) {
+ if (hostent_add_alias(h, rr.rr_dname, 1) == -1)
+ goto fail;
+ } else {
+ if (strcasecmp(rr.rr_dname, dname) == 0)
+ strlcpy(dname, rr.rr.cname.cname,
+ sizeof(dname));
+ }
+ break;
+
+ case T_PTR:
+ if (reqtype != ASR_GETHOSTBYADDR)
+ break;
+ if (strcasecmp(rr.rr_dname, dname) != 0)
+ continue;
+ if (hostent_set_cname(h, rr.rr.ptr.ptrname, 1) == -1)
+ hostent_add_alias(h, rr.rr.ptr.ptrname, 1);
+ break;
+
+ case T_A:
+ if (reqtype != ASR_GETHOSTBYNAME)
+ break;
+ if (family != AF_INET)
+ break;
+ if (hostent_set_cname(h, rr.rr_dname, 1) == -1)
+ ;
+ if (hostent_add_addr(h, &rr.rr.in_a.addr, 4) == -1)
+ goto fail;
+ break;
+
+ case T_AAAA:
+ if (reqtype != ASR_GETHOSTBYNAME)
+ break;
+ if (family != AF_INET6)
+ break;
+ if (hostent_set_cname(h, rr.rr_dname, 1) == -1)
+ ;
+ if (hostent_add_addr(h, &rr.rr.in_aaaa.addr6, 16) == -1)
+ goto fail;
+ break;
+ }
+ }
+
+ return (h);
+fail:
+ free(h);
+ return (NULL);
+}
+
+static struct hostent_ext *
+hostent_alloc(int family)
+{
+ struct hostent_ext *h;
+ size_t alloc;
+
+ alloc = sizeof(*h) + 1024;
+ if ((h = calloc(1, alloc)) == NULL)
+ return (NULL);
+
+ h->h.h_addrtype = family;
+ h->h.h_length = (family == AF_INET) ? 4 : 16;
+ h->h.h_aliases = h->aliases;
+ h->h.h_addr_list = h->addrs;
+ h->pos = (char *)(h) + sizeof(*h);
+ h->end = h->pos + 1024;
+
+ return (h);
+}
+
+static int
+hostent_set_cname(struct hostent_ext *h, const char *name, int isdname)
+{
+ char buf[MAXDNAME];
+ size_t n;
+
+ if (h->h.h_name)
+ return (-1);
+
+ if (isdname) {
+ asr_strdname(name, buf, sizeof buf);
+ buf[strlen(buf) - 1] = '\0';
+ if (!res_hnok(buf))
+ return (-1);
+ name = buf;
+ }
+
+ n = strlen(name) + 1;
+ if (h->pos + n >= h->end)
+ return (-1);
+
+ h->h.h_name = h->pos;
+ memmove(h->pos, name, n);
+ h->pos += n;
+ return (0);
+}
+
+static int
+hostent_add_alias(struct hostent_ext *h, const char *name, int isdname)
+{
+ char buf[MAXDNAME];
+ size_t i, n;
+
+ for (i = 0; i < MAXALIASES; i++)
+ if (h->aliases[i] == NULL)
+ break;
+ if (i == MAXALIASES)
+ return (-1);
+
+ if (isdname) {
+ asr_strdname(name, buf, sizeof buf);
+ buf[strlen(buf)-1] = '\0';
+ if (!res_hnok(buf))
+ return (-1);
+ name = buf;
+ }
+
+ n = strlen(name) + 1;
+ if (h->pos + n >= h->end)
+ return (-1);
+
+ h->aliases[i] = h->pos;
+ memmove(h->pos, name, n);
+ h->pos += n;
+ return (0);
+}
+
+static int
+hostent_add_addr(struct hostent_ext *h, const void *addr, size_t size)
+{
+ int i;
+
+ for (i = 0; i < MAXADDRS; i++)
+ if (h->addrs[i] == NULL)
+ break;
+ if (i == MAXADDRS)
+ return (-1);
+
+ if (h->pos + size >= h->end)
+ return (-1);
+
+ h->addrs[i] = h->pos;
+ memmove(h->pos, addr, size);
+ h->pos += size;
+ return (0);
+}
+
+#ifdef YP
+static struct hostent_ext *
+_yp_gethostnamadr(int type, const void *data)
+{
+ static char *domain = NULL;
+ struct hostent_ext *h = NULL;
+ const char *name;
+ char buf[MAXHOSTNAMELEN];
+ char *res = NULL;
+ int r, len;
+
+ if (!domain && _yp_check(&domain) == 0) {
+ errno = 0; /* ignore yp_bind errors */
+ return (NULL);
+ }
+
+ if (type == ASR_GETHOSTBYNAME) {
+ name = data;
+ len = strlen(name);
+ r = yp_match(domain, "hosts.byname", name, len, &res, &len);
+ }
+ else {
+ if (inet_ntop(AF_INET, data, buf, sizeof buf) == NULL)
+ return (NULL);
+ len = strlen(buf);
+ r = yp_match(domain, "hosts.byaddr", buf, len, &res, &len);
+ }
+ if (r == 0) {
+ h = hostent_from_yp(AF_INET, res);
+ } else {
+ errno = 0; /* ignore error if not found */
+ }
+ if (res)
+ free(res);
+ return (h);
+}
+
+static int
+strsplit(char *line, char **tokens, int ntokens)
+{
+ int ntok;
+ char *cp, **tp;
+
+ for (cp = line, tp = tokens, ntok = 0;
+ ntok < ntokens && (*tp = strsep(&cp, " \t")) != NULL; )
+ if (**tp != '\0') {
+ tp++;
+ ntok++;
+ }
+
+ return (ntok);
+}
+
+static struct hostent_ext *
+hostent_from_yp(int family, char *line)
+{
+ struct hostent_ext *h;
+ char *next, *tokens[10], addr[IN6ADDRSZ];
+ int i, ntok;
+
+ if ((h = hostent_alloc(family)) == NULL)
+ return (NULL);
+
+ for (next = line; line; line = next) {
+ if ((next = strchr(line, '\n'))) {
+ *next = '\0';
+ next += 1;
+ }
+ ntok = strsplit(line, tokens, 10);
+ if (ntok < 2)
+ continue;
+ if (inet_pton(family, tokens[0], addr) == 1)
+ hostent_add_addr(h, addr, family == AF_INET ?
+ INADDRSZ : IN6ADDRSZ);
+ i = 2;
+ if (h->h.h_name == NULL)
+ hostent_set_cname(h, tokens[1], 0);
+ else if (strcmp(h->h.h_name, tokens[1]))
+ i = 1;
+ for (; i < ntok; i++)
+ hostent_add_alias(h, tokens[i], 0);
+ }
+
+ if (h->h.h_name == NULL) {
+ free(h);
+ return (NULL);
+ }
+
+ return (h);
+}
+#endif
diff --git a/contrib/lib/libc/asr/getnameinfo.c b/contrib/lib/libc/asr/getnameinfo.c
new file mode 100644
index 00000000..4ca82dae
--- /dev/null
+++ b/contrib/lib/libc/asr/getnameinfo.c
@@ -0,0 +1,51 @@
+/* $OpenBSD: getnameinfo.c,v 1.4 2014/03/25 19:48:11 eric Exp $ */
+/*
+ * 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 <sys/types.h>
+#include <netinet/in.h>
+
+#include <errno.h>
+#include <resolv.h>
+
+#include "asr.h"
+
+int
+getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host,
+ size_t hostlen, char *serv, size_t servlen, int flags)
+{
+ struct asr_query *as;
+ struct asr_result ar;
+ int saved_errno = errno;
+
+ res_init();
+
+ as = getnameinfo_async(sa, salen, host, hostlen, serv, servlen, flags,
+ NULL);
+ if (as == NULL) {
+ if (errno == ENOMEM) {
+ errno = saved_errno;
+ return (EAI_MEMORY);
+ }
+ return (EAI_SYSTEM);
+ }
+
+ asr_run_sync(as, &ar);
+ if (ar.ar_gai_errno == EAI_SYSTEM)
+ errno = ar.ar_errno;
+
+ return (ar.ar_gai_errno);
+}
diff --git a/contrib/lib/libc/asr/getnameinfo_async.c b/contrib/lib/libc/asr/getnameinfo_async.c
new file mode 100644
index 00000000..c727f2b8
--- /dev/null
+++ b/contrib/lib/libc/asr/getnameinfo_async.c
@@ -0,0 +1,299 @@
+/* $OpenBSD: getnameinfo_async.c,v 1.8 2014/03/25 19:48:11 eric Exp $ */
+/*
+ * 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 <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "asr.h"
+#include "asr_private.h"
+
+static int getnameinfo_async_run(struct asr_query *, struct asr_result *);
+static int _servname(struct asr_query *);
+static int _numerichost(struct asr_query *);
+
+struct asr_query *
+getnameinfo_async(const struct sockaddr *sa, socklen_t slen, char *host,
+ size_t hostlen, char *serv, size_t servlen, int flags, void *asr)
+{
+ struct asr_ctx *ac;
+ struct asr_query *as;
+
+ ac = asr_use_resolver(asr);
+ if ((as = asr_async_new(ac, ASR_GETNAMEINFO)) == NULL)
+ goto abort; /* errno set */
+ as->as_run = getnameinfo_async_run;
+
+ if (sa->sa_family == AF_INET)
+ memmove(&as->as.ni.sa.sa, sa, sizeof (as->as.ni.sa.sain));
+ else if (sa->sa_family == AF_INET6)
+ memmove(&as->as.ni.sa.sa, sa, sizeof (as->as.ni.sa.sain6));
+
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ as->as.ni.sa.sa.sa_len = slen;
+#endif
+ as->as.ni.hostname = host;
+ as->as.ni.hostnamelen = hostlen;
+ as->as.ni.servname = serv;
+ as->as.ni.servnamelen = servlen;
+ as->as.ni.flags = flags;
+
+ asr_ctx_unref(ac);
+ return (as);
+
+ abort:
+ if (as)
+ asr_async_free(as);
+ asr_ctx_unref(ac);
+ return (NULL);
+}
+
+static int
+getnameinfo_async_run(struct asr_query *as, struct asr_result *ar)
+{
+ void *addr;
+ socklen_t addrlen;
+ int r;
+
+ next:
+ switch (as->as_state) {
+
+ case ASR_STATE_INIT:
+
+ /* Make sure the parameters are all valid. */
+
+ if (as->as.ni.sa.sa.sa_family != AF_INET &&
+ as->as.ni.sa.sa.sa_family != AF_INET6) {
+ ar->ar_gai_errno = EAI_FAMILY;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ if ((as->as.ni.sa.sa.sa_family == AF_INET &&
+ (SA_LEN(&as->as.ni.sa.sa) != sizeof (as->as.ni.sa.sain))) ||
+ (as->as.ni.sa.sa.sa_family == AF_INET6 &&
+ (SA_LEN(&as->as.ni.sa.sa) != sizeof (as->as.ni.sa.sain6)))) {
+ ar->ar_gai_errno = EAI_FAIL;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ /* Set the service name first, if needed. */
+ if (_servname(as) == -1) {
+ ar->ar_gai_errno = EAI_OVERFLOW;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ if (as->as.ni.hostname == NULL || as->as.ni.hostnamelen == 0) {
+ ar->ar_gai_errno = 0;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ if (as->as.ni.flags & NI_NUMERICHOST) {
+ if (_numerichost(as) == -1) {
+ if (errno == ENOMEM)
+ ar->ar_gai_errno = EAI_MEMORY;
+ else if (errno == ENOSPC)
+ ar->ar_gai_errno = EAI_OVERFLOW;
+ else {
+ ar->ar_errno = errno;
+ ar->ar_gai_errno = EAI_SYSTEM;
+ }
+ } else
+ ar->ar_gai_errno = 0;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ if (as->as.ni.sa.sa.sa_family == AF_INET) {
+ addrlen = sizeof(as->as.ni.sa.sain.sin_addr);
+ addr = &as->as.ni.sa.sain.sin_addr;
+ } else {
+ addrlen = sizeof(as->as.ni.sa.sain6.sin6_addr);
+ addr = &as->as.ni.sa.sain6.sin6_addr;
+ }
+
+ /*
+ * Create a subquery to lookup the address.
+ */
+ as->as.ni.subq = gethostbyaddr_async_ctx(addr, addrlen,
+ as->as.ni.sa.sa.sa_family,
+ as->as_ctx);
+ if (as->as.ni.subq == NULL) {
+ ar->ar_gai_errno = EAI_MEMORY;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ async_set_state(as, ASR_STATE_SUBQUERY);
+ break;
+
+ case ASR_STATE_SUBQUERY:
+
+ if ((r = asr_run(as->as.ni.subq, ar)) == ASYNC_COND)
+ return (ASYNC_COND);
+
+ /*
+ * Request done.
+ */
+ as->as.ni.subq = NULL;
+
+ if (ar->ar_hostent == NULL) {
+ if (as->as.ni.flags & NI_NAMEREQD) {
+ ar->ar_gai_errno = EAI_NONAME;
+ } else if (_numerichost(as) == -1) {
+ if (errno == ENOMEM)
+ ar->ar_gai_errno = EAI_MEMORY;
+ else if (errno == ENOSPC)
+ ar->ar_gai_errno = EAI_OVERFLOW;
+ else {
+ ar->ar_errno = errno;
+ ar->ar_gai_errno = EAI_SYSTEM;
+ }
+ } else
+ ar->ar_gai_errno = 0;
+ } else {
+ if (strlcpy(as->as.ni.hostname,
+ ar->ar_hostent->h_name,
+ as->as.ni.hostnamelen) >= as->as.ni.hostnamelen)
+ ar->ar_gai_errno = EAI_OVERFLOW;
+ else
+ ar->ar_gai_errno = 0;
+ free(ar->ar_hostent);
+ }
+
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+
+ case ASR_STATE_HALT:
+ return (ASYNC_DONE);
+
+ default:
+ ar->ar_errno = EOPNOTSUPP;
+ ar->ar_gai_errno = EAI_SYSTEM;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+ goto next;
+}
+
+
+/*
+ * Set the service name on the result buffer is not NULL.
+ * return (-1) if the buffer is too small.
+ */
+static int
+_servname(struct asr_query *as)
+{
+ struct servent s;
+#ifdef HAVE_STRUCT_SERVENT_DATA
+ struct servent_data sd;
+#endif
+ int port, r;
+ char *buf = as->as.ni.servname;
+ size_t buflen = as->as.ni.servnamelen;
+
+ if (as->as.ni.servname == NULL || as->as.ni.servnamelen == 0)
+ return (0);
+
+ if (as->as.ni.sa.sa.sa_family == AF_INET)
+ port = as->as.ni.sa.sain.sin_port;
+ else
+ port = as->as.ni.sa.sain6.sin6_port;
+
+ if (!(as->as.ni.flags & NI_NUMERICSERV)) {
+#ifdef HAVE_STRUCT_SERVENT_DATA
+ memset(&sd, 0, sizeof (sd));
+#endif
+#ifdef HAVE_GETSERVBYPORT_R_4_ARGS
+ r = getservbyport_r(port,
+ (as->as.ni.flags & NI_DGRAM) ? "udp" : "tcp",
+ &s, &sd);
+#else
+ r = -1;
+#endif
+ if (r != -1) {
+ r = strlcpy(buf, s.s_name, buflen) >= buflen;
+#ifdef HAVE_ENDSERVENT_R
+ endservent_r(&sd);
+#endif
+ return (r ? -1 : 0);
+ }
+ }
+
+ r = snprintf(buf, buflen, "%u", ntohs(port));
+ if (r == -1 || r >= (int)buflen)
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * Write the numeric address
+ */
+static int
+_numerichost(struct asr_query *as)
+{
+ unsigned int ifidx;
+ char scope[IF_NAMESIZE + 1], *ifname;
+ void *addr;
+ char *buf = as->as.ni.hostname;
+ size_t buflen = as->as.ni.hostnamelen;
+
+ if (as->as.ni.sa.sa.sa_family == AF_INET)
+ addr = &as->as.ni.sa.sain.sin_addr;
+ else
+ addr = &as->as.ni.sa.sain6.sin6_addr;
+
+ if (inet_ntop(as->as.ni.sa.sa.sa_family, addr, buf, buflen) == NULL)
+ return (-1); /* errno set */
+
+ if (as->as.ni.sa.sa.sa_family == AF_INET6 &&
+ as->as.ni.sa.sain6.sin6_scope_id) {
+
+ scope[0] = SCOPE_DELIMITER;
+ scope[1] = '\0';
+
+ ifidx = as->as.ni.sa.sain6.sin6_scope_id;
+ ifname = NULL;
+
+ if (IN6_IS_ADDR_LINKLOCAL(&as->as.ni.sa.sain6.sin6_addr) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(&as->as.ni.sa.sain6.sin6_addr) ||
+ IN6_IS_ADDR_MC_NODELOCAL(&as->as.ni.sa.sain6.sin6_addr))
+ ifname = if_indextoname(ifidx, scope + 1);
+
+ if (ifname == NULL)
+ snprintf(scope + 1, sizeof(scope) - 1, "%u", ifidx);
+
+ strlcat(buf, scope, buflen);
+ }
+
+ return (0);
+}
diff --git a/contrib/lib/libc/asr/getnetnamadr.c b/contrib/lib/libc/asr/getnetnamadr.c
new file mode 100644
index 00000000..07ed822d
--- /dev/null
+++ b/contrib/lib/libc/asr/getnetnamadr.c
@@ -0,0 +1,132 @@
+/* $OpenBSD: getnetnamadr.c,v 1.7 2014/03/25 19:48:11 eric Exp $ */
+/*
+ * 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 <sys/types.h>
+#include <netinet/in.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "asr.h"
+
+static void _fillnetent(const struct netent *, struct netent *, char *buf,
+ size_t);
+
+static struct netent _netent;
+static char _entbuf[4096];
+
+static char *_empty[] = { NULL, };
+
+static void
+_fillnetent(const struct netent *e, struct netent *r, char *buf, size_t len)
+{
+ char **ptr, *end, *pos;
+ size_t n, i;
+ int naliases;
+
+ bzero(buf, len);
+ bzero(r, sizeof(*r));
+ r->n_aliases = _empty;
+
+ end = buf + len;
+ ptr = (char **)ALIGN(buf);
+
+ if ((char *)ptr >= end)
+ return;
+
+ for (naliases = 0; e->n_aliases[naliases]; naliases++)
+ ;
+
+ r->n_name = NULL;
+ r->n_addrtype = e->n_addrtype;
+ r->n_net = e->n_net;
+ r->n_aliases = ptr;
+
+ pos = (char *)(ptr + (naliases + 1));
+ if (pos > end)
+ r->n_aliases = _empty;
+
+ n = strlcpy(pos, e->n_name, end - pos);
+ if (n >= end - pos)
+ return;
+ r->n_name = pos;
+ pos += n + 1;
+
+ for (i = 0; i < naliases; i++) {
+ n = strlcpy(pos, e->n_aliases[i], end - pos);
+ if (n >= end - pos)
+ return;
+ r->n_aliases[i] = pos;
+ pos += n + 1;
+ }
+}
+
+struct netent *
+getnetbyname(const char *name)
+{
+ struct asr_query *as;
+ struct asr_result ar;
+
+ res_init();
+
+ as = getnetbyname_async(name, NULL);
+ if (as == NULL) {
+ h_errno = NETDB_INTERNAL;
+ return (NULL);
+ }
+
+ asr_run_sync(as, &ar);
+
+ errno = ar.ar_errno;
+ h_errno = ar.ar_h_errno;
+ if (ar.ar_netent == NULL)
+ return (NULL);
+
+ _fillnetent(ar.ar_netent, &_netent, _entbuf, sizeof(_entbuf));
+ free(ar.ar_netent);
+
+ return (&_netent);
+}
+
+struct netent *
+getnetbyaddr(in_addr_t net, int type)
+{
+ struct asr_query *as;
+ struct asr_result ar;
+
+ res_init();
+
+ as = getnetbyaddr_async(net, type, NULL);
+ if (as == NULL) {
+ h_errno = NETDB_INTERNAL;
+ return (NULL);
+ }
+
+ asr_run_sync(as, &ar);
+
+ errno = ar.ar_errno;
+ h_errno = ar.ar_h_errno;
+ if (ar.ar_netent == NULL)
+ return (NULL);
+
+ _fillnetent(ar.ar_netent, &_netent, _entbuf, sizeof(_entbuf));
+ free(ar.ar_netent);
+
+ return (&_netent);
+}
diff --git a/contrib/lib/libc/asr/getnetnamadr_async.c b/contrib/lib/libc/asr/getnetnamadr_async.c
new file mode 100644
index 00000000..d024d97e
--- /dev/null
+++ b/contrib/lib/libc/asr/getnetnamadr_async.c
@@ -0,0 +1,450 @@
+/* $OpenBSD: getnetnamadr_async.c,v 1.13 2014/03/25 19:48:11 eric Exp $ */
+/*
+ * 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 <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <err.h>
+#include <errno.h>
+#include <resolv.h> /* for res_hnok */
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "asr.h"
+#include "asr_private.h"
+
+#define MAXALIASES 16
+
+struct netent_ext {
+ struct netent n;
+ char *aliases[MAXALIASES + 1];
+ char *end;
+ char *pos;
+};
+
+static int getnetnamadr_async_run(struct asr_query *, struct asr_result *);
+static struct netent_ext *netent_alloc(int);
+static int netent_set_cname(struct netent_ext *, const char *, int);
+static int netent_add_alias(struct netent_ext *, const char *, int);
+static struct netent_ext *netent_file_match(FILE *, int, const char *);
+static struct netent_ext *netent_from_packet(int, char *, size_t);
+
+struct asr_query *
+getnetbyname_async(const char *name, void *asr)
+{
+ struct asr_ctx *ac;
+ struct asr_query *as;
+
+ /* The current resolver segfaults. */
+ if (name == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ ac = asr_use_resolver(asr);
+ if ((as = asr_async_new(ac, ASR_GETNETBYNAME)) == NULL)
+ goto abort; /* errno set */
+ as->as_run = getnetnamadr_async_run;
+
+ as->as.netnamadr.family = AF_INET;
+ as->as.netnamadr.name = strdup(name);
+ if (as->as.netnamadr.name == NULL)
+ goto abort; /* errno set */
+
+ asr_ctx_unref(ac);
+ return (as);
+
+ abort:
+ if (as)
+ asr_async_free(as);
+ asr_ctx_unref(ac);
+ return (NULL);
+}
+
+struct asr_query *
+getnetbyaddr_async(in_addr_t net, int family, void *asr)
+{
+ struct asr_ctx *ac;
+ struct asr_query *as;
+
+ ac = asr_use_resolver(asr);
+ if ((as = asr_async_new(ac, ASR_GETNETBYADDR)) == NULL)
+ goto abort; /* errno set */
+ as->as_run = getnetnamadr_async_run;
+
+ as->as.netnamadr.family = family;
+ as->as.netnamadr.addr = net;
+
+ asr_ctx_unref(ac);
+ return (as);
+
+ abort:
+ if (as)
+ asr_async_free(as);
+ asr_ctx_unref(ac);
+ return (NULL);
+}
+
+static int
+getnetnamadr_async_run(struct asr_query *as, struct asr_result *ar)
+{
+ struct netent_ext *n;
+ int r, type, saved_errno;
+ FILE *f;
+ char dname[MAXDNAME], *name, *data;
+ in_addr_t in;
+
+ next:
+ switch (as->as_state) {
+
+ case ASR_STATE_INIT:
+
+ if (as->as.netnamadr.family != AF_INET) {
+ ar->ar_h_errno = NETDB_INTERNAL;
+ ar->ar_errno = EAFNOSUPPORT;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ async_set_state(as, ASR_STATE_NEXT_DB);
+ break;
+
+ case ASR_STATE_NEXT_DB:
+
+ if (asr_iter_db(as) == -1) {
+ async_set_state(as, ASR_STATE_NOT_FOUND);
+ break;
+ }
+
+ switch (AS_DB(as)) {
+ case ASR_DB_DNS:
+
+ if (as->as_type == ASR_GETNETBYNAME) {
+ type = T_A;
+ /*
+ * I think we want to do the former, but our
+ * resolver is doing the following, so let's
+ * preserve bugward-compatibility there.
+ */
+ type = T_PTR;
+ name = as->as.netnamadr.name;
+ as->as.netnamadr.subq = res_search_async_ctx(
+ name, C_IN, type, as->as_ctx);
+ } else {
+ type = T_PTR;
+ name = dname;
+
+ in = htonl(as->as.netnamadr.addr);
+ asr_addr_as_fqdn((char *)&in,
+ as->as.netnamadr.family,
+ dname, sizeof(dname));
+ as->as.netnamadr.subq = res_query_async_ctx(
+ name, C_IN, type, as->as_ctx);
+ }
+
+ if (as->as.netnamadr.subq == NULL) {
+ ar->ar_errno = errno;
+ ar->ar_h_errno = NETDB_INTERNAL;
+ async_set_state(as, ASR_STATE_HALT);
+ }
+ async_set_state(as, ASR_STATE_SUBQUERY);
+ break;
+
+ case ASR_DB_FILE:
+
+ if ((f = fopen("/etc/networks", "r")) == NULL)
+ break;
+
+ if (as->as_type == ASR_GETNETBYNAME)
+ data = as->as.netnamadr.name;
+ else
+ data = (void *)&as->as.netnamadr.addr;
+
+ n = netent_file_match(f, as->as_type, data);
+ saved_errno = errno;
+ fclose(f);
+ errno = saved_errno;
+ if (n == NULL) {
+ if (errno) {
+ ar->ar_errno = errno;
+ ar->ar_h_errno = NETDB_INTERNAL;
+ async_set_state(as, ASR_STATE_HALT);
+ }
+ /* otherwise not found */
+ break;
+ }
+
+ ar->ar_netent = &n->n;
+ ar->ar_h_errno = NETDB_SUCCESS;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+ break;
+
+ case ASR_STATE_SUBQUERY:
+
+ if ((r = asr_run(as->as.netnamadr.subq, ar)) == ASYNC_COND)
+ return (ASYNC_COND);
+ as->as.netnamadr.subq = NULL;
+
+ if (ar->ar_datalen == -1) {
+ async_set_state(as, ASR_STATE_NEXT_DB);
+ break;
+ }
+
+ /* Got packet, but no answer */
+ if (ar->ar_count == 0) {
+ free(ar->ar_data);
+ async_set_state(as, ASR_STATE_NEXT_DB);
+ break;
+ }
+
+ n = netent_from_packet(as->as_type, ar->ar_data,
+ ar->ar_datalen);
+ free(ar->ar_data);
+ if (n == NULL) {
+ ar->ar_errno = errno;
+ ar->ar_h_errno = NETDB_INTERNAL;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ if (as->as_type == ASR_GETNETBYADDR)
+ n->n.n_net = as->as.netnamadr.addr;
+
+ /*
+ * No address found in the dns packet. The blocking version
+ * reports this as an error.
+ */
+ if (as->as_type == ASR_GETNETBYNAME && n->n.n_net == 0) {
+ /* XXX wrong */
+ free(n);
+ async_set_state(as, ASR_STATE_NEXT_DB);
+ break;
+ }
+
+ ar->ar_netent = &n->n;
+ ar->ar_h_errno = NETDB_SUCCESS;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+
+ case ASR_STATE_NOT_FOUND:
+
+ ar->ar_errno = 0;
+ ar->ar_h_errno = HOST_NOT_FOUND;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+
+ case ASR_STATE_HALT:
+
+ if (ar->ar_h_errno)
+ ar->ar_netent = NULL;
+ else
+ ar->ar_errno = 0;
+ return (ASYNC_DONE);
+
+ default:
+ ar->ar_errno = EOPNOTSUPP;
+ ar->ar_h_errno = NETDB_INTERNAL;
+ ar->ar_gai_errno = EAI_SYSTEM;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+ goto next;
+}
+
+static struct netent_ext *
+netent_file_match(FILE *f, int reqtype, const char *data)
+{
+ struct netent_ext *e;
+ char *tokens[MAXTOKEN];
+ int n, i;
+ in_addr_t net;
+
+ for (;;) {
+ n = asr_parse_namedb_line(f, tokens, MAXTOKEN);
+ if (n == -1) {
+ errno = 0; /* ignore errors reading the file */
+ return (NULL);
+ }
+
+ if (reqtype == ASR_GETNETBYADDR) {
+ net = inet_network(tokens[1]);
+ if (memcmp(&net, data, sizeof net) == 0)
+ goto found;
+ } else {
+ for (i = 0; i < n; i++) {
+ if (i == 1)
+ continue;
+ if (strcasecmp(data, tokens[i]))
+ continue;
+ goto found;
+ }
+ }
+ }
+
+found:
+ if ((e = netent_alloc(AF_INET)) == NULL)
+ return (NULL);
+ if (netent_set_cname(e, tokens[0], 0) == -1)
+ goto fail;
+ for (i = 2; i < n; i ++)
+ if (netent_add_alias(e, tokens[i], 0) == -1)
+ goto fail;
+ e->n.n_net = inet_network(tokens[1]);
+ return (e);
+fail:
+ free(e);
+ return (NULL);
+}
+
+static struct netent_ext *
+netent_from_packet(int reqtype, char *pkt, size_t pktlen)
+{
+ struct netent_ext *n;
+ struct asr_unpack p;
+ struct asr_dns_header hdr;
+ struct asr_dns_query q;
+ struct asr_dns_rr rr;
+
+ if ((n = netent_alloc(AF_INET)) == NULL)
+ return (NULL);
+
+ asr_unpack_init(&p, pkt, pktlen);
+ asr_unpack_header(&p, &hdr);
+ for (; hdr.qdcount; hdr.qdcount--)
+ asr_unpack_query(&p, &q);
+ for (; hdr.ancount; hdr.ancount--) {
+ asr_unpack_rr(&p, &rr);
+ if (rr.rr_class != C_IN)
+ continue;
+ switch (rr.rr_type) {
+ case T_CNAME:
+ if (reqtype == ASR_GETNETBYNAME) {
+ if (netent_add_alias(n, rr.rr_dname, 1) == -1)
+ goto fail;
+ } else {
+ if (netent_set_cname(n, rr.rr_dname, 1) == -1)
+ goto fail;
+ }
+ break;
+
+ case T_PTR:
+ if (reqtype != ASR_GETNETBYADDR)
+ continue;
+ if (netent_set_cname(n, rr.rr.ptr.ptrname, 1) == -1)
+ goto fail;
+ /* XXX See if we need to have MULTI_PTRS_ARE_ALIASES */
+ break;
+
+ case T_A:
+ if (n->n.n_addrtype != AF_INET)
+ break;
+ if (netent_set_cname(n, rr.rr_dname, 1) == -1)
+ goto fail;
+ n->n.n_net = ntohl(rr.rr.in_a.addr.s_addr);
+ break;
+ }
+ }
+
+ return (n);
+fail:
+ free(n);
+ return (NULL);
+}
+
+static struct netent_ext *
+netent_alloc(int family)
+{
+ struct netent_ext *n;
+ size_t alloc;
+
+ alloc = sizeof(*n) + 1024;
+ if ((n = calloc(1, alloc)) == NULL)
+ return (NULL);
+
+ n->n.n_addrtype = family;
+ n->n.n_aliases = n->aliases;
+ n->pos = (char *)(n) + sizeof(*n);
+ n->end = n->pos + 1024;
+
+ return (n);
+}
+
+static int
+netent_set_cname(struct netent_ext *n, const char *name, int isdname)
+{
+ char buf[MAXDNAME];
+ size_t l;
+
+ if (n->n.n_name)
+ return (-1);
+
+ if (isdname) {
+ asr_strdname(name, buf, sizeof buf);
+ buf[strlen(buf) - 1] = '\0';
+ if (!res_hnok(buf))
+ return (-1);
+ name = buf;
+ }
+
+ l = strlen(name) + 1;
+ if (n->pos + l >= n->end)
+ return (-1);
+
+ n->n.n_name = n->pos;
+ memmove(n->pos, name, l);
+ n->pos += l;
+
+ return (0);
+}
+
+static int
+netent_add_alias(struct netent_ext *n, const char *name, int isdname)
+{
+ char buf[MAXDNAME];
+ size_t i, l;
+
+ for (i = 0; i < MAXALIASES; i++)
+ if (n->aliases[i] == NULL)
+ break;
+ if (i == MAXALIASES)
+ return (-1);
+
+ if (isdname) {
+ asr_strdname(name, buf, sizeof buf);
+ buf[strlen(buf)-1] = '\0';
+ if (!res_hnok(buf))
+ return (-1);
+ name = buf;
+ }
+
+ l = strlen(name) + 1;
+ if (n->pos + l >= n->end)
+ return (-1);
+
+ n->aliases[i] = n->pos;
+ memmove(n->pos, name, l);
+ n->pos += l;
+ return (0);
+}
diff --git a/contrib/lib/libc/asr/getrrsetbyname.c b/contrib/lib/libc/asr/getrrsetbyname.c
new file mode 100644
index 00000000..359f1dd4
--- /dev/null
+++ b/contrib/lib/libc/asr/getrrsetbyname.c
@@ -0,0 +1,81 @@
+/* $OpenBSD: getrrsetbyname.c,v 1.4 2014/03/25 19:48:11 eric Exp $ */
+/*
+ * 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 <sys/types.h>
+#include <netinet/in.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <stdlib.h>
+
+#include "asr.h"
+
+int
+getrrsetbyname(const char *name, unsigned int class, unsigned int type,
+ unsigned int flags, struct rrsetinfo **res)
+{
+ struct asr_query *as;
+ struct asr_result ar;
+ int r, saved_errno = errno;
+
+ res_init();
+
+ as = getrrsetbyname_async(name, class, type, flags, NULL);
+ if (as == NULL) {
+ r = (errno == ENOMEM) ? ERRSET_NOMEMORY : ERRSET_FAIL;
+ errno = saved_errno;
+ return (r);
+ }
+
+ asr_run_sync(as, &ar);
+
+ *res = ar.ar_rrsetinfo;
+
+ return (ar.ar_rrset_errno);
+}
+
+/* from net/getrrsetbyname.c */
+void
+freerrset(struct rrsetinfo *rrset)
+{
+ u_int16_t i;
+
+ if (rrset == NULL)
+ return;
+
+ if (rrset->rri_rdatas) {
+ for (i = 0; i < rrset->rri_nrdatas; i++) {
+ if (rrset->rri_rdatas[i].rdi_data == NULL)
+ break;
+ free(rrset->rri_rdatas[i].rdi_data);
+ }
+ free(rrset->rri_rdatas);
+ }
+
+ if (rrset->rri_sigs) {
+ for (i = 0; i < rrset->rri_nsigs; i++) {
+ if (rrset->rri_sigs[i].rdi_data == NULL)
+ break;
+ free(rrset->rri_sigs[i].rdi_data);
+ }
+ free(rrset->rri_sigs);
+ }
+
+ if (rrset->rri_name)
+ free(rrset->rri_name);
+ free(rrset);
+}
diff --git a/contrib/lib/libc/asr/getrrsetbyname_async.c b/contrib/lib/libc/asr/getrrsetbyname_async.c
new file mode 100644
index 00000000..eb5db42d
--- /dev/null
+++ b/contrib/lib/libc/asr/getrrsetbyname_async.c
@@ -0,0 +1,589 @@
+/* $OpenBSD: getrrsetbyname_async.c,v 1.6 2014/03/25 19:48:11 eric Exp $ */
+/*
+ * 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/uio.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "asr.h"
+#include "asr_private.h"
+
+static int getrrsetbyname_async_run(struct asr_query *, struct asr_result *);
+static void get_response(struct asr_result *, const char *, int);
+
+struct asr_query *
+getrrsetbyname_async(const char *hostname, unsigned int rdclass,
+ unsigned int rdtype, unsigned int flags, void *asr)
+{
+ struct asr_ctx *ac;
+ struct asr_query *as;
+
+ ac = asr_use_resolver(asr);
+ if ((as = asr_async_new(ac, ASR_GETRRSETBYNAME)) == NULL)
+ goto abort; /* errno set */
+ as->as_run = getrrsetbyname_async_run;
+
+ as->as.rrset.flags = flags;
+ as->as.rrset.class = rdclass;
+ as->as.rrset.type = rdtype;
+ as->as.rrset.name = strdup(hostname);
+ if (as->as.rrset.name == NULL)
+ goto abort; /* errno set */
+
+ asr_ctx_unref(ac);
+ return (as);
+ abort:
+ if (as)
+ asr_async_free(as);
+
+ asr_ctx_unref(ac);
+ return (NULL);
+}
+
+static int
+getrrsetbyname_async_run(struct asr_query *as, struct asr_result *ar)
+{
+ next:
+ switch (as->as_state) {
+
+ case ASR_STATE_INIT:
+
+ /* Check for invalid class and type. */
+ if (as->as.rrset.class > 0xffff || as->as.rrset.type > 0xffff) {
+ ar->ar_rrset_errno = ERRSET_INVAL;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ /* Do not allow queries of class or type ANY. */
+ if (as->as.rrset.class == 0xff || as->as.rrset.type == 0xff) {
+ ar->ar_rrset_errno = ERRSET_INVAL;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ /* Do not allow flags yet, unimplemented. */
+ if (as->as.rrset.flags) {
+ ar->ar_rrset_errno = ERRSET_INVAL;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ /* Create a delegate the lookup to a subquery. */
+ as->as.rrset.subq = res_query_async_ctx(
+ as->as.rrset.name,
+ as->as.rrset.class,
+ as->as.rrset.type,
+ as->as_ctx);
+ if (as->as.rrset.subq == NULL) {
+ ar->ar_rrset_errno = ERRSET_FAIL;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ async_set_state(as, ASR_STATE_SUBQUERY);
+ break;
+
+ case ASR_STATE_SUBQUERY:
+
+ if ((asr_run(as->as.rrset.subq, ar)) == ASYNC_COND)
+ return (ASYNC_COND);
+
+ as->as.rrset.subq = NULL;
+
+ /* No packet received.*/
+ if (ar->ar_datalen == -1) {
+ switch (ar->ar_h_errno) {
+ case HOST_NOT_FOUND:
+ ar->ar_rrset_errno = ERRSET_NONAME;
+ break;
+ case NO_DATA:
+ ar->ar_rrset_errno = ERRSET_NODATA;
+ break;
+ default:
+ ar->ar_rrset_errno = ERRSET_FAIL;
+ break;
+ }
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ /* Got a packet but no answer. */
+ if (ar->ar_count == 0) {
+ free(ar->ar_data);
+ switch (ar->ar_rcode) {
+ case NXDOMAIN:
+ ar->ar_rrset_errno = ERRSET_NONAME;
+ break;
+ case NOERROR:
+ ar->ar_rrset_errno = ERRSET_NODATA;
+ break;
+ default:
+ ar->ar_rrset_errno = ERRSET_FAIL;
+ break;
+ }
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ get_response(ar, ar->ar_data, ar->ar_datalen);
+ free(ar->ar_data);
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+
+ case ASR_STATE_HALT:
+ if (ar->ar_rrset_errno)
+ ar->ar_rrsetinfo = NULL;
+ return (ASYNC_DONE);
+
+ default:
+ ar->ar_rrset_errno = ERRSET_FAIL;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+ goto next;
+}
+
+/* The rest of this file is taken from the orignal implementation. */
+
+/* $OpenBSD: getrrsetbyname_async.c,v 1.6 2014/03/25 19:48:11 eric Exp $ */
+
+/*
+ * Copyright (c) 2001 Jakob Schlyter. 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.
+ */
+
+/*
+ * Portions Copyright (c) 1999-2001 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.
+ */
+
+#define MAXPACKET 1024*64
+
+struct dns_query {
+ char *name;
+ u_int16_t type;
+ u_int16_t class;
+ struct dns_query *next;
+};
+
+struct dns_rr {
+ char *name;
+ u_int16_t type;
+ u_int16_t class;
+ u_int16_t ttl;
+ u_int16_t size;
+ void *rdata;
+ struct dns_rr *next;
+};
+
+struct dns_response {
+ HEADER header;
+ struct dns_query *query;
+ struct dns_rr *answer;
+ struct dns_rr *authority;
+ struct dns_rr *additional;
+};
+
+static struct dns_response *parse_dns_response(const u_char *, int);
+static struct dns_query *parse_dns_qsection(const u_char *, int,
+ const u_char **, int);
+static struct dns_rr *parse_dns_rrsection(const u_char *, int, const u_char **,
+ int);
+
+static void free_dns_query(struct dns_query *);
+static void free_dns_rr(struct dns_rr *);
+static void free_dns_response(struct dns_response *);
+
+static int count_dns_rr(struct dns_rr *, u_int16_t, u_int16_t);
+
+static void
+get_response(struct asr_result *ar, const char *pkt, int pktlen)
+{
+ struct rrsetinfo *rrset = NULL;
+ struct dns_response *response = NULL;
+ struct dns_rr *rr;
+ struct rdatainfo *rdata;
+ unsigned int index_ans, index_sig;
+
+ /* parse result */
+ response = parse_dns_response(pkt, pktlen);
+ if (response == NULL) {
+ ar->ar_rrset_errno = ERRSET_FAIL;
+ goto fail;
+ }
+
+ if (response->header.qdcount != 1) {
+ ar->ar_rrset_errno = ERRSET_FAIL;
+ goto fail;
+ }
+
+ /* initialize rrset */
+ rrset = calloc(1, sizeof(struct rrsetinfo));
+ if (rrset == NULL) {
+ ar->ar_rrset_errno = ERRSET_NOMEMORY;
+ goto fail;
+ }
+ rrset->rri_rdclass = response->query->class;
+ rrset->rri_rdtype = response->query->type;
+ rrset->rri_ttl = response->answer->ttl;
+ rrset->rri_nrdatas = response->header.ancount;
+
+ /* check for authenticated data */
+ if (response->header.ad == 1)
+ rrset->rri_flags |= RRSET_VALIDATED;
+
+ /* copy name from answer section */
+ rrset->rri_name = strdup(response->answer->name);
+ if (rrset->rri_name == NULL) {
+ ar->ar_rrset_errno = ERRSET_NOMEMORY;
+ goto fail;
+ }
+
+ /* count answers */
+ rrset->rri_nrdatas = count_dns_rr(response->answer, rrset->rri_rdclass,
+ rrset->rri_rdtype);
+ rrset->rri_nsigs = count_dns_rr(response->answer, rrset->rri_rdclass,
+ T_RRSIG);
+
+ /* allocate memory for answers */
+ rrset->rri_rdatas = calloc(rrset->rri_nrdatas,
+ sizeof(struct rdatainfo));
+ if (rrset->rri_rdatas == NULL) {
+ ar->ar_rrset_errno = ERRSET_NOMEMORY;
+ goto fail;
+ }
+
+ /* allocate memory for signatures */
+ rrset->rri_sigs = calloc(rrset->rri_nsigs, sizeof(struct rdatainfo));
+ if (rrset->rri_sigs == NULL) {
+ ar->ar_rrset_errno = ERRSET_NOMEMORY;
+ goto fail;
+ }
+
+ /* copy answers & signatures */
+ for (rr = response->answer, index_ans = 0, index_sig = 0;
+ rr; rr = rr->next) {
+
+ rdata = NULL;
+
+ if (rr->class == rrset->rri_rdclass &&
+ rr->type == rrset->rri_rdtype)
+ rdata = &rrset->rri_rdatas[index_ans++];
+
+ if (rr->class == rrset->rri_rdclass &&
+ rr->type == T_RRSIG)
+ rdata = &rrset->rri_sigs[index_sig++];
+
+ if (rdata) {
+ rdata->rdi_length = rr->size;
+ rdata->rdi_data = malloc(rr->size);
+
+ if (rdata->rdi_data == NULL) {
+ ar->ar_rrset_errno = ERRSET_NOMEMORY;
+ goto fail;
+ }
+ memcpy(rdata->rdi_data, rr->rdata, rr->size);
+ }
+ }
+ free_dns_response(response);
+
+ ar->ar_rrsetinfo = rrset;
+ ar->ar_rrset_errno = ERRSET_SUCCESS;
+ return;
+
+fail:
+ if (rrset != NULL)
+ freerrset(rrset);
+ if (response != NULL)
+ free_dns_response(response);
+}
+
+/*
+ * DNS response parsing routines
+ */
+static struct dns_response *
+parse_dns_response(const u_char *answer, int size)
+{
+ struct dns_response *resp;
+ const u_char *cp;
+
+ /* allocate memory for the response */
+ resp = calloc(1, sizeof(*resp));
+ if (resp == NULL)
+ return (NULL);
+
+ /* initialize current pointer */
+ cp = answer;
+
+ /* copy header */
+ memcpy(&resp->header, cp, HFIXEDSZ);
+ cp += HFIXEDSZ;
+
+ /* fix header byte order */
+ resp->header.qdcount = ntohs(resp->header.qdcount);
+ resp->header.ancount = ntohs(resp->header.ancount);
+ resp->header.nscount = ntohs(resp->header.nscount);
+ resp->header.arcount = ntohs(resp->header.arcount);
+
+ /* there must be at least one query */
+ if (resp->header.qdcount < 1) {
+ free_dns_response(resp);
+ return (NULL);
+ }
+
+ /* parse query section */
+ resp->query = parse_dns_qsection(answer, size, &cp,
+ resp->header.qdcount);
+ if (resp->header.qdcount && resp->query == NULL) {
+ free_dns_response(resp);
+ return (NULL);
+ }
+
+ /* parse answer section */
+ resp->answer = parse_dns_rrsection(answer, size, &cp,
+ resp->header.ancount);
+ if (resp->header.ancount && resp->answer == NULL) {
+ free_dns_response(resp);
+ return (NULL);
+ }
+
+ /* parse authority section */
+ resp->authority = parse_dns_rrsection(answer, size, &cp,
+ resp->header.nscount);
+ if (resp->header.nscount && resp->authority == NULL) {
+ free_dns_response(resp);
+ return (NULL);
+ }
+
+ /* parse additional section */
+ resp->additional = parse_dns_rrsection(answer, size, &cp,
+ resp->header.arcount);
+ if (resp->header.arcount && resp->additional == NULL) {
+ free_dns_response(resp);
+ return (NULL);
+ }
+
+ return (resp);
+}
+
+static struct dns_query *
+parse_dns_qsection(const u_char *answer, int size, const u_char **cp, int count)
+{
+ struct dns_query *head, *curr, *prev;
+ int i, length;
+ char name[MAXDNAME];
+
+ for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) {
+
+ /* allocate and initialize struct */
+ curr = calloc(1, sizeof(struct dns_query));
+ if (curr == NULL) {
+ free_dns_query(head);
+ return (NULL);
+ }
+ if (head == NULL)
+ head = curr;
+ if (prev != NULL)
+ prev->next = curr;
+
+ /* name */
+ length = dn_expand(answer, answer + size, *cp, name,
+ sizeof(name));
+ if (length < 0) {
+ free_dns_query(head);
+ return (NULL);
+ }
+ curr->name = strdup(name);
+ if (curr->name == NULL) {
+ free_dns_query(head);
+ return (NULL);
+ }
+ *cp += length;
+
+ /* type */
+ curr->type = _getshort(*cp);
+ *cp += INT16SZ;
+
+ /* class */
+ curr->class = _getshort(*cp);
+ *cp += INT16SZ;
+ }
+
+ return (head);
+}
+
+static struct dns_rr *
+parse_dns_rrsection(const u_char *answer, int size, const u_char **cp,
+ int count)
+{
+ struct dns_rr *head, *curr, *prev;
+ int i, length;
+ char name[MAXDNAME];
+
+ for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) {
+
+ /* allocate and initialize struct */
+ curr = calloc(1, sizeof(struct dns_rr));
+ if (curr == NULL) {
+ free_dns_rr(head);
+ return (NULL);
+ }
+ if (head == NULL)
+ head = curr;
+ if (prev != NULL)
+ prev->next = curr;
+
+ /* name */
+ length = dn_expand(answer, answer + size, *cp, name,
+ sizeof(name));
+ if (length < 0) {
+ free_dns_rr(head);
+ return (NULL);
+ }
+ curr->name = strdup(name);
+ if (curr->name == NULL) {
+ free_dns_rr(head);
+ return (NULL);
+ }
+ *cp += length;
+
+ /* type */
+ curr->type = _getshort(*cp);
+ *cp += INT16SZ;
+
+ /* class */
+ curr->class = _getshort(*cp);
+ *cp += INT16SZ;
+
+ /* ttl */
+ curr->ttl = _getlong(*cp);
+ *cp += INT32SZ;
+
+ /* rdata size */
+ curr->size = _getshort(*cp);
+ *cp += INT16SZ;
+
+ /* rdata itself */
+ curr->rdata = malloc(curr->size);
+ if (curr->rdata == NULL) {
+ free_dns_rr(head);
+ return (NULL);
+ }
+ memcpy(curr->rdata, *cp, curr->size);
+ *cp += curr->size;
+ }
+
+ return (head);
+}
+
+static void
+free_dns_query(struct dns_query *p)
+{
+ if (p == NULL)
+ return;
+
+ if (p->name)
+ free(p->name);
+ free_dns_query(p->next);
+ free(p);
+}
+
+static void
+free_dns_rr(struct dns_rr *p)
+{
+ if (p == NULL)
+ return;
+
+ if (p->name)
+ free(p->name);
+ if (p->rdata)
+ free(p->rdata);
+ free_dns_rr(p->next);
+ free(p);
+}
+
+static void
+free_dns_response(struct dns_response *p)
+{
+ if (p == NULL)
+ return;
+
+ free_dns_query(p->query);
+ free_dns_rr(p->answer);
+ free_dns_rr(p->authority);
+ free_dns_rr(p->additional);
+ free(p);
+}
+
+static int
+count_dns_rr(struct dns_rr *p, u_int16_t class, u_int16_t type)
+{
+ int n = 0;
+
+ while (p) {
+ if (p->class == class && p->type == type)
+ n++;
+ p = p->next;
+ }
+
+ return (n);
+}
diff --git a/contrib/lib/libc/asr/res_debug.c b/contrib/lib/libc/asr/res_debug.c
new file mode 100644
index 00000000..ca9c5ee0
--- /dev/null
+++ b/contrib/lib/libc/asr/res_debug.c
@@ -0,0 +1,2 @@
+/* $OpenBSD: res_debug.c,v 1.1 2012/09/08 11:08:21 eric Exp $ */
+/* NOTHING */
diff --git a/contrib/lib/libc/asr/res_init.c b/contrib/lib/libc/asr/res_init.c
new file mode 100644
index 00000000..86065046
--- /dev/null
+++ b/contrib/lib/libc/asr/res_init.c
@@ -0,0 +1,86 @@
+/* $OpenBSD: res_init.c,v 1.3 2014/01/15 02:25:34 sthen Exp $ */
+/*
+ * 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 <sys/types.h>
+#include <arpa/nameser.h>
+#include <netinet/in.h>
+
+#include <resolv.h>
+#include <string.h>
+
+#include "asr.h"
+#include "asr_private.h"
+#include "thread_private.h"
+
+
+struct __res_state _res;
+struct __res_state_ext _res_ext;
+
+int h_errno;
+
+int
+res_init(void)
+{
+ _THREAD_PRIVATE_MUTEX(init);
+ struct asr_ctx *ac;
+ int i;
+
+ ac = asr_use_resolver(NULL);
+
+ /*
+ * The first thread to call res_init() will setup the global _res
+ * structure from the async context, not overriding fields set early
+ * by the user.
+ */
+ _THREAD_PRIVATE_MUTEX_LOCK(init);
+ if (!(_res.options & RES_INIT)) {
+ if (_res.retry == 0)
+ _res.retry = ac->ac_nsretries;
+ if (_res.options == 0)
+ _res.options = ac->ac_options;
+ if (_res.lookups[0] == '\0')
+ strlcpy(_res.lookups, ac->ac_db, sizeof(_res.lookups));
+
+ _res.nscount = ac->ac_nscount;
+ for (i = 0; i < ac->ac_nscount; i++) {
+ memcpy(&_res.nsaddr_list[i], ac->ac_ns[i],
+ SA_LEN(ac->ac_ns[i]));
+ }
+ _res.options |= RES_INIT;
+ }
+ _THREAD_PRIVATE_MUTEX_UNLOCK(init);
+
+ /*
+ * If the program is not threaded, we want to reflect (some) changes
+ * made by the user to the global _res structure.
+ * This is a bit of a hack: if there is already an async query on
+ * this context, it might change things in its back. It is ok
+ * as long as the user only uses the blocking resolver API.
+ * If needed we could consider cloning the context if there is
+ * a running query.
+ */
+ if (!__isthreaded) {
+ ac->ac_nsretries = _res.retry;
+ ac->ac_options = _res.options;
+ strlcpy(ac->ac_db, _res.lookups, sizeof(ac->ac_db));
+ ac->ac_dbcount = strlen(ac->ac_db);
+ }
+
+ asr_ctx_unref(ac);
+
+ return (0);
+}
diff --git a/contrib/lib/libc/asr/res_mkquery.c b/contrib/lib/libc/asr/res_mkquery.c
new file mode 100644
index 00000000..9f2aa0de
--- /dev/null
+++ b/contrib/lib/libc/asr/res_mkquery.c
@@ -0,0 +1,108 @@
+/* $OpenBSD: res_mkquery.c,v 1.7 2014/03/14 11:07:33 eric Exp $ */
+/*
+ * 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 <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h> /* for MAXDNAME */
+
+#include <errno.h>
+#include <resolv.h>
+#include <string.h>
+
+#include "asr.h"
+#include "asr_private.h"
+
+/* This function is apparently needed by some ports. */
+int
+res_mkquery(int op, const char *dname, int class, int type,
+ const unsigned char *data, int datalen, const unsigned char *newrr,
+ unsigned char *buf, int buflen)
+{
+ struct asr_ctx *ac;
+ struct asr_pack p;
+ struct asr_dns_header h;
+ char fqdn[MAXDNAME];
+ char dn[MAXDNAME];
+
+ /* we currently only support QUERY */
+ if (op != QUERY || data)
+ return (-1);
+
+ if (dname[0] == '\0' || dname[strlen(dname) - 1] != '.') {
+ if (strlcpy(fqdn, dname, sizeof(fqdn)) >= sizeof(fqdn) ||
+ strlcat(fqdn, ".", sizeof(fqdn)) >= sizeof(fqdn))
+ return (-1);
+ dname = fqdn;
+ }
+
+ if (asr_dname_from_fqdn(dname, dn, sizeof(dn)) == -1)
+ return (-1);
+
+ ac = asr_use_resolver(NULL);
+
+ memset(&h, 0, sizeof h);
+ h.id = res_randomid();
+ if (ac->ac_options & RES_RECURSE)
+ h.flags |= RD_MASK;
+ h.qdcount = 1;
+
+ asr_pack_init(&p, buf, buflen);
+ asr_pack_header(&p, &h);
+ asr_pack_query(&p, type, class, dn);
+
+ asr_ctx_unref(ac);
+
+ if (p.err)
+ return (-1);
+
+ return (p.offset);
+}
+
+/*
+ * This function is not documented, but used by sendmail.
+ * Put here because it uses asr_private.h too.
+ */
+int
+res_querydomain(const char *name,
+ const char *domain,
+ int class,
+ int type,
+ u_char *answer,
+ int anslen)
+{
+ char fqdn[MAXDNAME], ndom[MAXDNAME];
+ size_t n;
+
+ /* we really want domain to end with a dot for now */
+ if (domain && ((n = strlen(domain)) == 0 || domain[n - 1 ] != '.')) {
+ if (strlcpy(ndom, domain, sizeof(ndom)) >= sizeof(ndom) ||
+ strlcat(ndom, ".", sizeof(ndom)) >= sizeof(ndom)) {
+ h_errno = NETDB_INTERNAL;
+ errno = EINVAL;
+ return (-1);
+ }
+ domain = ndom;
+ }
+
+ if (asr_make_fqdn(name, domain, fqdn, sizeof fqdn) == 0) {
+ h_errno = NETDB_INTERNAL;
+ errno = EINVAL;
+ return (-1);
+ }
+
+ return (res_query(fqdn, class, type, answer, anslen));
+}
diff --git a/contrib/lib/libc/asr/res_query.c b/contrib/lib/libc/asr/res_query.c
new file mode 100644
index 00000000..2c6b198e
--- /dev/null
+++ b/contrib/lib/libc/asr/res_query.c
@@ -0,0 +1,110 @@
+/* $OpenBSD: res_query.c,v 1.7 2014/03/25 19:48:11 eric Exp $ */
+/*
+ * 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 <sys/types.h>
+#include <netinet/in.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "asr.h"
+
+int
+res_query(const char *name, int class, int type, u_char *ans, int anslen)
+{
+ struct asr_query *as;
+ struct asr_result ar;
+ size_t len;
+
+ res_init();
+
+ if (ans == NULL || anslen <= 0) {
+ h_errno = NO_RECOVERY;
+ errno = EINVAL;
+ return (-1);
+ }
+
+ as = res_query_async(name, class, type, NULL);
+ if (as == NULL) {
+ if (errno == EINVAL)
+ h_errno = NO_RECOVERY;
+ else
+ h_errno = NETDB_INTERNAL;
+ return (-1); /* errno set */
+ }
+
+ asr_run_sync(as, &ar);
+
+ if (ar.ar_errno)
+ errno = ar.ar_errno;
+ h_errno = ar.ar_h_errno;
+
+ if (ar.ar_h_errno != NETDB_SUCCESS)
+ return (-1);
+
+ len = anslen;
+ if (ar.ar_datalen < len)
+ len = ar.ar_datalen;
+ memmove(ans, ar.ar_data, len);
+ free(ar.ar_data);
+
+ return (ar.ar_datalen);
+}
+
+int
+res_search(const char *name, int class, int type, u_char *ans, int anslen)
+{
+ struct asr_query *as;
+ struct asr_result ar;
+ size_t len;
+
+ res_init();
+
+ if (ans == NULL || anslen <= 0) {
+ h_errno = NO_RECOVERY;
+ errno = EINVAL;
+ return (-1);
+ }
+
+ as = res_search_async(name, class, type, NULL);
+ if (as == NULL) {
+ if (errno == EINVAL)
+ h_errno = NO_RECOVERY;
+ else
+ h_errno = NETDB_INTERNAL;
+ return (-1); /* errno set */
+ }
+
+ asr_run_sync(as, &ar);
+
+ if (ar.ar_errno)
+ errno = ar.ar_errno;
+ h_errno = ar.ar_h_errno;
+
+ if (ar.ar_h_errno != NETDB_SUCCESS)
+ return (-1);
+
+ len = anslen;
+ if (ar.ar_datalen < len)
+ len = ar.ar_datalen;
+ memmove(ans, ar.ar_data, len);
+ free(ar.ar_data);
+
+ return (ar.ar_datalen);
+}
diff --git a/contrib/lib/libc/asr/res_search_async.c b/contrib/lib/libc/asr/res_search_async.c
new file mode 100644
index 00000000..6a23a962
--- /dev/null
+++ b/contrib/lib/libc/asr/res_search_async.c
@@ -0,0 +1,319 @@
+/* $OpenBSD: res_search_async.c,v 1.12 2014/03/25 19:48:11 eric Exp $ */
+/*
+ * 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/uio.h>
+#include <arpa/nameser.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "asr.h"
+#include "asr_private.h"
+
+static int res_search_async_run(struct asr_query *, struct asr_result *);
+static size_t domcat(const char *, const char *, char *, size_t);
+static int iter_domain(struct asr_query *, const char *, char *, size_t);
+
+/*
+ * Unlike res_query_async(), this function returns a valid packet only if
+ * h_errno is NETDB_SUCCESS.
+ */
+struct asr_query *
+res_search_async(const char *name, int class, int type, void *asr)
+{
+ struct asr_ctx *ac;
+ struct asr_query *as;
+
+ DPRINT("asr: res_search_async(\"%s\", %i, %i)\n", name, class, type);
+
+ ac = asr_use_resolver(asr);
+ as = res_search_async_ctx(name, class, type, ac);
+ asr_ctx_unref(ac);
+
+ return (as);
+}
+
+struct asr_query *
+res_search_async_ctx(const char *name, int class, int type, struct asr_ctx *ac)
+{
+ struct asr_query *as;
+ char alias[MAXDNAME];
+
+ DPRINT("asr: res_search_async_ctx(\"%s\", %i, %i)\n", name, class,
+ type);
+
+ if (asr_hostalias(ac, name, alias, sizeof(alias)))
+ return res_query_async_ctx(alias, class, type, ac);
+
+ if ((as = asr_async_new(ac, ASR_SEARCH)) == NULL)
+ goto err; /* errno set */
+ as->as_run = res_search_async_run;
+ if ((as->as.search.name = strdup(name)) == NULL)
+ goto err; /* errno set */
+
+ as->as.search.class = class;
+ as->as.search.type = type;
+
+ return (as);
+ err:
+ if (as)
+ asr_async_free(as);
+ return (NULL);
+}
+
+#define HERRNO_UNSET -2
+
+static int
+res_search_async_run(struct asr_query *as, struct asr_result *ar)
+{
+ int r;
+ char fqdn[MAXDNAME];
+
+ next:
+ switch (as->as_state) {
+
+ case ASR_STATE_INIT:
+
+ as->as.search.saved_h_errno = HERRNO_UNSET;
+ async_set_state(as, ASR_STATE_NEXT_DOMAIN);
+ break;
+
+ case ASR_STATE_NEXT_DOMAIN:
+ /*
+ * Reset flags to be able to identify the case in
+ * STATE_SUBQUERY.
+ */
+ as->as_dom_flags = 0;
+
+ r = iter_domain(as, as->as.search.name, fqdn, sizeof(fqdn));
+ if (r == -1) {
+ async_set_state(as, ASR_STATE_NOT_FOUND);
+ break;
+ }
+ if (r == 0) {
+ ar->ar_errno = EINVAL;
+ ar->ar_h_errno = NO_RECOVERY;
+ ar->ar_datalen = -1;
+ ar->ar_data = NULL;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+ as->as.search.subq = res_query_async_ctx(fqdn,
+ as->as.search.class, as->as.search.type, as->as_ctx);
+ if (as->as.search.subq == NULL) {
+ ar->ar_errno = errno;
+ if (errno == EINVAL)
+ ar->ar_h_errno = NO_RECOVERY;
+ else
+ ar->ar_h_errno = NETDB_INTERNAL;
+ ar->ar_datalen = -1;
+ ar->ar_data = NULL;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+ async_set_state(as, ASR_STATE_SUBQUERY);
+ break;
+
+ case ASR_STATE_SUBQUERY:
+
+ if ((r = asr_run(as->as.search.subq, ar)) == ASYNC_COND)
+ return (ASYNC_COND);
+ as->as.search.subq = NULL;
+
+ if (ar->ar_h_errno == NETDB_SUCCESS) {
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ /*
+ * The original res_search() does this in the domain search
+ * loop, but only for ECONNREFUSED. I think we can do better
+ * because technically if we get an errno, it means
+ * we couldn't reach any nameserver, so there is no point
+ * in trying further.
+ */
+ if (ar->ar_errno) {
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ free(ar->ar_data);
+
+ /*
+ * The original resolver does something like this.
+ */
+ if (as->as_dom_flags & ASYNC_DOM_NDOTS)
+ as->as.search.saved_h_errno = ar->ar_h_errno;
+
+ if (as->as_dom_flags & ASYNC_DOM_DOMAIN) {
+ if (ar->ar_h_errno == NO_DATA)
+ as->as.search.flags |= ASYNC_NODATA;
+ else if (ar->ar_h_errno == TRY_AGAIN)
+ as->as.search.flags |= ASYNC_AGAIN;
+ }
+
+ async_set_state(as, ASR_STATE_NEXT_DOMAIN);
+ break;
+
+ case ASR_STATE_NOT_FOUND:
+
+ if (as->as.search.saved_h_errno != HERRNO_UNSET)
+ ar->ar_h_errno = as->as.search.saved_h_errno;
+ else if (as->as.search.flags & ASYNC_NODATA)
+ ar->ar_h_errno = NO_DATA;
+ else if (as->as.search.flags & ASYNC_AGAIN)
+ ar->ar_h_errno = TRY_AGAIN;
+ /*
+ * Else, we got the ar_h_errno value set by res_query_async()
+ * for the last domain.
+ */
+ ar->ar_datalen = -1;
+ ar->ar_data = NULL;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+
+ case ASR_STATE_HALT:
+
+ return (ASYNC_DONE);
+
+ default:
+ ar->ar_errno = EOPNOTSUPP;
+ ar->ar_h_errno = NETDB_INTERNAL;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+ goto next;
+}
+
+/*
+ * Concatenate a name and a domain name. The result has no trailing dot.
+ * Return the resulting string length, or 0 in case of error.
+ */
+static size_t
+domcat(const char *name, const char *domain, char *buf, size_t buflen)
+{
+ size_t r;
+
+ r = asr_make_fqdn(name, domain, buf, buflen);
+ if (r == 0)
+ return (0);
+ buf[r - 1] = '\0';
+
+ return (r - 1);
+}
+
+enum {
+ DOM_INIT,
+ DOM_DOMAIN,
+ DOM_DONE
+};
+
+/*
+ * Implement the search domain strategy.
+ *
+ * This function works as a generator that constructs complete domains in
+ * buffer "buf" of size "len" for the given host name "name", according to the
+ * search rules defined by the resolving context. It is supposed to be called
+ * multiple times (with the same name) to generate the next possible domain
+ * name, if any.
+ *
+ * It returns -1 if all possibilities have been exhausted, 0 if there was an
+ * error generating the next name, or the resulting name length.
+ */
+int
+iter_domain(struct asr_query *as, const char *name, char * buf, size_t len)
+{
+ const char *c;
+ int dots;
+
+ switch (as->as_dom_step) {
+
+ case DOM_INIT:
+ /* First call */
+
+ /*
+ * If "name" is an FQDN, that's the only result and we
+ * don't try anything else.
+ */
+ if (strlen(name) && name[strlen(name) - 1] == '.') {
+ DPRINT("asr: iter_domain(\"%s\") fqdn\n", name);
+ as->as_dom_flags |= ASYNC_DOM_FQDN;
+ as->as_dom_step = DOM_DONE;
+ return (domcat(name, NULL, buf, len));
+ }
+
+ /*
+ * Otherwise, we iterate through the specified search domains.
+ */
+ as->as_dom_step = DOM_DOMAIN;
+ as->as_dom_idx = 0;
+
+ /*
+ * If "name" as enough dots, use it as-is first, as indicated
+ * in resolv.conf(5).
+ */
+ dots = 0;
+ for (c = name; *c; c++)
+ dots += (*c == '.');
+ if (dots >= as->as_ctx->ac_ndots) {
+ DPRINT("asr: iter_domain(\"%s\") ndots\n", name);
+ as->as_dom_flags |= ASYNC_DOM_NDOTS;
+ if (strlcpy(buf, name, len) >= len)
+ return (0);
+ return (strlen(buf));
+ }
+ /* Otherwise, starts using the search domains */
+ /* FALLTHROUGH */
+
+ case DOM_DOMAIN:
+ if (as->as_dom_idx < as->as_ctx->ac_domcount) {
+ DPRINT("asr: iter_domain(\"%s\") domain \"%s\"\n",
+ name, as->as_ctx->ac_dom[as->as_dom_idx]);
+ as->as_dom_flags |= ASYNC_DOM_DOMAIN;
+ return (domcat(name,
+ as->as_ctx->ac_dom[as->as_dom_idx++], buf, len));
+ }
+
+ /* No more domain to try. */
+
+ as->as_dom_step = DOM_DONE;
+
+ /*
+ * If the name was not tried as an absolute name before,
+ * do it now.
+ */
+ if (!(as->as_dom_flags & ASYNC_DOM_NDOTS)) {
+ DPRINT("asr: iter_domain(\"%s\") as is\n", name);
+ as->as_dom_flags |= ASYNC_DOM_ASIS;
+ if (strlcpy(buf, name, len) >= len)
+ return (0);
+ return (strlen(buf));
+ }
+ /* Otherwise, we are done. */
+
+ case DOM_DONE:
+ default:
+ DPRINT("asr: iter_domain(\"%s\") done\n", name);
+ return (-1);
+ }
+}
diff --git a/contrib/lib/libc/asr/res_send.c b/contrib/lib/libc/asr/res_send.c
new file mode 100644
index 00000000..b00510c4
--- /dev/null
+++ b/contrib/lib/libc/asr/res_send.c
@@ -0,0 +1,60 @@
+/* $OpenBSD: res_send.c,v 1.7 2014/03/25 19:48:11 eric Exp $ */
+/*
+ * 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 <sys/types.h>
+#include <netinet/in.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "asr.h"
+
+int
+res_send(const u_char *buf, int buflen, u_char *ans, int anslen)
+{
+ struct asr_query *as;
+ struct asr_result ar;
+ size_t len;
+
+ res_init();
+
+ if (ans == NULL || anslen <= 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ as = res_send_async(buf, buflen, NULL);
+ if (as == NULL)
+ return (-1); /* errno set */
+
+ asr_run_sync(as, &ar);
+
+ if (ar.ar_errno) {
+ errno = ar.ar_errno;
+ return (-1);
+ }
+
+ len = anslen;
+ if (ar.ar_datalen < len)
+ len = ar.ar_datalen;
+ memmove(ans, ar.ar_data, len);
+ free(ar.ar_data);
+
+ return (ar.ar_datalen);
+}
diff --git a/contrib/lib/libc/asr/res_send_async.c b/contrib/lib/libc/asr/res_send_async.c
new file mode 100644
index 00000000..d8eee859
--- /dev/null
+++ b/contrib/lib/libc/asr/res_send_async.c
@@ -0,0 +1,770 @@
+/* $OpenBSD: res_send_async.c,v 1.21 2014/03/25 19:48:11 eric Exp $ */
+/*
+ * 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/uio.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <resolv.h> /* for res_random */
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "asr.h"
+#include "asr_private.h"
+
+#define OP_QUERY (0)
+
+static int res_send_async_run(struct asr_query *, struct asr_result *);
+static int sockaddr_connect(const struct sockaddr *, int);
+static int udp_send(struct asr_query *);
+static int udp_recv(struct asr_query *);
+static int tcp_write(struct asr_query *);
+static int tcp_read(struct asr_query *);
+static int validate_packet(struct asr_query *);
+static int setup_query(struct asr_query *, const char *, const char *, int, int);
+static int ensure_ibuf(struct asr_query *, size_t);
+static int iter_ns(struct asr_query *);
+
+#define AS_NS_SA(p) ((p)->as_ctx->ac_ns[(p)->as.dns.nsidx - 1])
+
+
+struct asr_query *
+res_send_async(const unsigned char *buf, int buflen, void *asr)
+{
+ struct asr_ctx *ac;
+ struct asr_query *as;
+ struct asr_unpack p;
+ struct asr_dns_header h;
+ struct asr_dns_query q;
+
+ DPRINT_PACKET("asr: res_send_async()", buf, buflen);
+
+ ac = asr_use_resolver(asr);
+ if ((as = asr_async_new(ac, ASR_SEND)) == NULL) {
+ asr_ctx_unref(ac);
+ return (NULL); /* errno set */
+ }
+ as->as_run = res_send_async_run;
+
+ as->as.dns.flags |= ASYNC_EXTOBUF;
+ as->as.dns.obuf = (unsigned char *)buf;
+ as->as.dns.obuflen = buflen;
+ as->as.dns.obufsize = buflen;
+
+ asr_unpack_init(&p, buf, buflen);
+ asr_unpack_header(&p, &h);
+ asr_unpack_query(&p, &q);
+ if (p.err) {
+ errno = EINVAL;
+ goto err;
+ }
+ as->as.dns.reqid = h.id;
+ as->as.dns.type = q.q_type;
+ as->as.dns.class = q.q_class;
+ as->as.dns.dname = strdup(q.q_dname);
+ if (as->as.dns.dname == NULL)
+ goto err; /* errno set */
+
+ asr_ctx_unref(ac);
+ return (as);
+ err:
+ if (as)
+ asr_async_free(as);
+ asr_ctx_unref(ac);
+ return (NULL);
+}
+
+/*
+ * Unlike res_query(), this version will actually return the packet
+ * if it has received a valid one (errno == 0) even if h_errno is
+ * not NETDB_SUCCESS. So the packet *must* be freed if necessary.
+ */
+struct asr_query *
+res_query_async(const char *name, int class, int type, void *asr)
+{
+ struct asr_ctx *ac;
+ struct asr_query *as;
+
+ DPRINT("asr: res_query_async(\"%s\", %i, %i)\n", name, class, type);
+
+ ac = asr_use_resolver(asr);
+ as = res_query_async_ctx(name, class, type, ac);
+ asr_ctx_unref(ac);
+
+ return (as);
+}
+
+struct asr_query *
+res_query_async_ctx(const char *name, int class, int type, struct asr_ctx *a_ctx)
+{
+ struct asr_query *as;
+
+ DPRINT("asr: res_query_async_ctx(\"%s\", %i, %i)\n", name, class, type);
+
+ if ((as = asr_async_new(a_ctx, ASR_SEND)) == NULL)
+ return (NULL); /* errno set */
+ as->as_run = res_send_async_run;
+
+ /* This adds a "." to name if it doesn't already has one.
+ * That's how res_query() behaves (through res_mkquery").
+ */
+ if (setup_query(as, name, NULL, class, type) == -1)
+ goto err; /* errno set */
+
+ return (as);
+
+ err:
+ if (as)
+ asr_async_free(as);
+
+ return (NULL);
+}
+
+static int
+res_send_async_run(struct asr_query *as, struct asr_result *ar)
+{
+ next:
+ switch (as->as_state) {
+
+ case ASR_STATE_INIT:
+
+ if (as->as_ctx->ac_nscount == 0) {
+ ar->ar_errno = ECONNREFUSED;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ async_set_state(as, ASR_STATE_NEXT_NS);
+ break;
+
+ case ASR_STATE_NEXT_NS:
+
+ if (iter_ns(as) == -1) {
+ ar->ar_errno = ETIMEDOUT;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ if (as->as_ctx->ac_options & RES_USEVC ||
+ as->as.dns.obuflen > PACKETSZ)
+ async_set_state(as, ASR_STATE_TCP_WRITE);
+ else
+ async_set_state(as, ASR_STATE_UDP_SEND);
+ break;
+
+ case ASR_STATE_UDP_SEND:
+
+ if (udp_send(as) == -1) {
+ async_set_state(as, ASR_STATE_NEXT_NS);
+ break;
+ }
+ async_set_state(as, ASR_STATE_UDP_RECV);
+ ar->ar_cond = ASR_WANT_READ;
+ ar->ar_fd = as->as_fd;
+ ar->ar_timeout = as->as_timeout;
+ return (ASYNC_COND);
+ break;
+
+ case ASR_STATE_UDP_RECV:
+
+ if (udp_recv(as) == -1) {
+ if (errno == ENOMEM) {
+ ar->ar_errno = errno;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+ if (errno != EOVERFLOW) {
+ /* Fail or timeout */
+ async_set_state(as, ASR_STATE_NEXT_NS);
+ break;
+ }
+ if (as->as_ctx->ac_options & RES_IGNTC)
+ async_set_state(as, ASR_STATE_PACKET);
+ else
+ async_set_state(as, ASR_STATE_TCP_WRITE);
+ } else
+ async_set_state(as, ASR_STATE_PACKET);
+ break;
+
+ case ASR_STATE_TCP_WRITE:
+
+ switch (tcp_write(as)) {
+ case -1: /* fail or timeout */
+ async_set_state(as, ASR_STATE_NEXT_NS);
+ break;
+ case 0:
+ async_set_state(as, ASR_STATE_TCP_READ);
+ ar->ar_cond = ASR_WANT_READ;
+ ar->ar_fd = as->as_fd;
+ ar->ar_timeout = as->as_timeout;
+ return (ASYNC_COND);
+ case 1:
+ ar->ar_cond = ASR_WANT_WRITE;
+ ar->ar_fd = as->as_fd;
+ ar->ar_timeout = as->as_timeout;
+ return (ASYNC_COND);
+ }
+ break;
+
+ case ASR_STATE_TCP_READ:
+
+ switch (tcp_read(as)) {
+ case -1: /* Fail or timeout */
+ if (errno == ENOMEM) {
+ ar->ar_errno = errno;
+ async_set_state(as, ASR_STATE_HALT);
+ } else
+ async_set_state(as, ASR_STATE_NEXT_NS);
+ break;
+ case 0:
+ async_set_state(as, ASR_STATE_PACKET);
+ break;
+ case 1:
+ ar->ar_cond = ASR_WANT_READ;
+ ar->ar_fd = as->as_fd;
+ ar->ar_timeout = as->as_timeout;
+ return (ASYNC_COND);
+ }
+ break;
+
+ case ASR_STATE_PACKET:
+
+ memmove(&ar->ar_ns, AS_NS_SA(as), SA_LEN(AS_NS_SA(as)));
+ ar->ar_datalen = as->as.dns.ibuflen;
+ ar->ar_data = as->as.dns.ibuf;
+ as->as.dns.ibuf = NULL;
+ ar->ar_errno = 0;
+ ar->ar_rcode = as->as.dns.rcode;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+
+ case ASR_STATE_HALT:
+
+ if (ar->ar_errno) {
+ ar->ar_h_errno = TRY_AGAIN;
+ ar->ar_count = 0;
+ ar->ar_datalen = -1;
+ ar->ar_data = NULL;
+ } else if (as->as.dns.ancount) {
+ ar->ar_h_errno = NETDB_SUCCESS;
+ ar->ar_count = as->as.dns.ancount;
+ } else {
+ ar->ar_count = 0;
+ switch (as->as.dns.rcode) {
+ case NXDOMAIN:
+ ar->ar_h_errno = HOST_NOT_FOUND;
+ break;
+ case SERVFAIL:
+ ar->ar_h_errno = TRY_AGAIN;
+ break;
+ case NOERROR:
+ ar->ar_h_errno = NO_DATA;
+ break;
+ default:
+ ar->ar_h_errno = NO_RECOVERY;
+ }
+ }
+ return (ASYNC_DONE);
+
+ default:
+
+ ar->ar_errno = EOPNOTSUPP;
+ ar->ar_h_errno = NETDB_INTERNAL;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+ goto next;
+}
+
+static int
+sockaddr_connect(const struct sockaddr *sa, int socktype)
+{
+ int errno_save, flags, sock;
+
+ if ((sock = socket(sa->sa_family, socktype, 0)) == -1)
+ goto fail;
+
+ if ((flags = fcntl(sock, F_GETFL, 0)) == -1)
+ goto fail;
+
+ flags |= O_NONBLOCK;
+
+ if ((flags = fcntl(sock, F_SETFL, flags)) == -1)
+ goto fail;
+
+ if (connect(sock, sa, SA_LEN(sa)) == -1) {
+ /*
+ * In the TCP case, the caller will be asked to poll for
+ * POLLOUT so that we start writing the packet in tcp_write()
+ * when the connection is established, or fail there on error.
+ */
+ if (errno == EINPROGRESS)
+ return (sock);
+ goto fail;
+ }
+
+ return (sock);
+
+ fail:
+
+ if (sock != -1) {
+ errno_save = errno;
+ close(sock);
+ errno = errno_save;
+ }
+
+ return (-1);
+}
+
+/*
+ * Prepare the DNS packet for the query type "type", class "class" and domain
+ * name created by the concatenation on "name" and "dom".
+ * Return 0 on success, set errno and return -1 on error.
+ */
+static int
+setup_query(struct asr_query *as, const char *name, const char *dom,
+ int class, int type)
+{
+ struct asr_pack p;
+ struct asr_dns_header h;
+ char fqdn[MAXDNAME];
+ char dname[MAXDNAME];
+
+ if (as->as.dns.flags & ASYNC_EXTOBUF) {
+ errno = EINVAL;
+ DPRINT("attempting to write in user packet");
+ return (-1);
+ }
+
+ if (asr_make_fqdn(name, dom, fqdn, sizeof(fqdn)) > sizeof(fqdn)) {
+ errno = EINVAL;
+ DPRINT("asr_make_fqdn: name too long\n");
+ return (-1);
+ }
+
+ if (asr_dname_from_fqdn(fqdn, dname, sizeof(dname)) == -1) {
+ errno = EINVAL;
+ DPRINT("asr_dname_from_fqdn: invalid\n");
+ return (-1);
+ }
+
+ if (as->as.dns.obuf == NULL) {
+ as->as.dns.obufsize = PACKETSZ;
+ as->as.dns.obuf = malloc(as->as.dns.obufsize);
+ if (as->as.dns.obuf == NULL)
+ return (-1); /* errno set */
+ }
+ as->as.dns.obuflen = 0;
+
+ memset(&h, 0, sizeof h);
+ h.id = res_randomid();
+ if (as->as_ctx->ac_options & RES_RECURSE)
+ h.flags |= RD_MASK;
+ h.qdcount = 1;
+
+ asr_pack_init(&p, as->as.dns.obuf, as->as.dns.obufsize);
+ asr_pack_header(&p, &h);
+ asr_pack_query(&p, type, class, dname);
+ if (p.err) {
+ DPRINT("error packing query");
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /* Remember the parameters. */
+ as->as.dns.reqid = h.id;
+ as->as.dns.type = type;
+ as->as.dns.class = class;
+ if (as->as.dns.dname)
+ free(as->as.dns.dname);
+ as->as.dns.dname = strdup(dname);
+ if (as->as.dns.dname == NULL) {
+ DPRINT("strdup");
+ return (-1); /* errno set */
+ }
+ as->as.dns.obuflen = p.offset;
+
+ DPRINT_PACKET("asr_setup_query", as->as.dns.obuf, as->as.dns.obuflen);
+
+ return (0);
+}
+
+/*
+ * Create a connect UDP socket and send the output packet.
+ *
+ * Return 0 on success, or -1 on error (errno set).
+ */
+static int
+udp_send(struct asr_query *as)
+{
+ ssize_t n;
+ int save_errno;
+#ifdef DEBUG
+ char buf[256];
+#endif
+
+ DPRINT("asr: [%p] connecting to %s UDP\n", as,
+ print_sockaddr(AS_NS_SA(as), buf, sizeof buf));
+
+ as->as_fd = sockaddr_connect(AS_NS_SA(as), SOCK_DGRAM);
+ if (as->as_fd == -1)
+ return (-1); /* errno set */
+
+ n = send(as->as_fd, as->as.dns.obuf, as->as.dns.obuflen, 0);
+ if (n == -1) {
+ save_errno = errno;
+ close(as->as_fd);
+ errno = save_errno;
+ as->as_fd = -1;
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Try to receive a valid packet from the current UDP socket.
+ *
+ * Return 0 if a full packet could be read, or -1 on error (errno set).
+ */
+static int
+udp_recv(struct asr_query *as)
+{
+ ssize_t n;
+ int save_errno;
+
+ if (ensure_ibuf(as, PACKETSZ) == -1) {
+ save_errno = errno;
+ close(as->as_fd);
+ errno = save_errno;
+ as->as_fd = -1;
+ return (-1);
+ }
+
+ n = recv(as->as_fd, as->as.dns.ibuf, as->as.dns.ibufsize, 0);
+ save_errno = errno;
+ close(as->as_fd);
+ errno = save_errno;
+ as->as_fd = -1;
+ if (n == -1)
+ return (-1);
+
+ as->as.dns.ibuflen = n;
+
+ DPRINT_PACKET("asr_udp_recv()", as->as.dns.ibuf, as->as.dns.ibuflen);
+
+ if (validate_packet(as) == -1)
+ return (-1); /* errno set */
+
+ return (0);
+}
+
+/*
+ * Write the output packet to the TCP socket.
+ *
+ * Return 0 when all bytes have been sent, 1 there is no buffer space on the
+ * socket or it is not connected yet, or -1 on error (errno set).
+ */
+static int
+tcp_write(struct asr_query *as)
+{
+ struct msghdr msg;
+ struct iovec iov[2];
+ uint16_t len;
+ ssize_t n;
+ size_t offset;
+ int i;
+#ifdef DEBUG
+ char buf[256];
+#endif
+
+ /* First try to connect if not already */
+ if (as->as_fd == -1) {
+ DPRINT("asr: [%p] connecting to %s TCP\n", as,
+ print_sockaddr(AS_NS_SA(as), buf, sizeof buf));
+ as->as_fd = sockaddr_connect(AS_NS_SA(as), SOCK_STREAM);
+ if (as->as_fd == -1)
+ return (-1); /* errno set */
+ as->as.dns.datalen = 0; /* bytes sent */
+ return (1);
+ }
+
+ i = 0;
+
+ /* Prepend de packet length if not sent already. */
+ if (as->as.dns.datalen < sizeof(len)) {
+ offset = 0;
+ len = htons(as->as.dns.obuflen);
+ iov[i].iov_base = (char *)(&len) + as->as.dns.datalen;
+ iov[i].iov_len = sizeof(len) - as->as.dns.datalen;
+ i++;
+ } else
+ offset = as->as.dns.datalen - sizeof(len);
+
+ iov[i].iov_base = as->as.dns.obuf + offset;
+ iov[i].iov_len = as->as.dns.obuflen - offset;
+ i++;
+
+ memset(&msg, 0, sizeof msg);
+ msg.msg_iov = iov;
+ msg.msg_iovlen = i;
+
+ send_again:
+/* Mac OS X doesn't have MSG_NOSIGNAL flag. */
+#ifndef MSG_NOSIGNAL
+#define MSG_NOSIGNAL SO_NOSIGPIPE
+#endif
+ n = sendmsg(as->as_fd, &msg, MSG_NOSIGNAL);
+ if (n == -1) {
+ if (errno == EINTR)
+ goto send_again;
+ goto close; /* errno set */
+ }
+
+ as->as.dns.datalen += n;
+
+ if (as->as.dns.datalen == as->as.dns.obuflen + sizeof(len)) {
+ /* All sent. Prepare for TCP read */
+ as->as.dns.datalen = 0;
+ return (0);
+ }
+
+ /* More data to write */
+ return (1);
+
+close:
+ close(as->as_fd);
+ as->as_fd = -1;
+ return (-1);
+}
+
+/*
+ * Try to read a valid packet from the current TCP socket.
+ *
+ * Return 0 if a full packet could be read, 1 if more data is needed and the
+ * socket must be read again, or -1 on error (errno set).
+ */
+static int
+tcp_read(struct asr_query *as)
+{
+ ssize_t n;
+ size_t offset, len;
+ char *pos;
+ int save_errno, nfds;
+ struct pollfd pfd;
+
+ /* We must read the packet len first */
+ if (as->as.dns.datalen < sizeof(as->as.dns.pktlen)) {
+
+ pos = (char *)(&as->as.dns.pktlen) + as->as.dns.datalen;
+ len = sizeof(as->as.dns.pktlen) - as->as.dns.datalen;
+
+ n = read(as->as_fd, pos, len);
+ if (n == -1)
+ goto close; /* errno set */
+
+ as->as.dns.datalen += n;
+ if (as->as.dns.datalen < sizeof(as->as.dns.pktlen))
+ return (1); /* need more data */
+
+ as->as.dns.ibuflen = ntohs(as->as.dns.pktlen);
+ if (ensure_ibuf(as, as->as.dns.ibuflen) == -1)
+ goto close; /* errno set */
+
+ pfd.fd = as->as_fd;
+ pfd.events = POLLIN;
+ poll_again:
+ nfds = poll(&pfd, 1, 0);
+ if (nfds == -1) {
+ if (errno == EINTR)
+ goto poll_again;
+ goto close; /* errno set */
+ }
+ if (nfds == 0)
+ return (1); /* no more data available */
+ }
+
+ offset = as->as.dns.datalen - sizeof(as->as.dns.pktlen);
+ pos = as->as.dns.ibuf + offset;
+ len = as->as.dns.ibuflen - offset;
+
+ read_again:
+ n = read(as->as_fd, pos, len);
+ if (n == -1) {
+ if (errno == EINTR)
+ goto read_again;
+ goto close; /* errno set */
+ }
+ if (n == 0) {
+ errno = ECONNRESET;
+ goto close;
+ }
+ as->as.dns.datalen += n;
+
+ /* See if we got all the advertised bytes. */
+ if (as->as.dns.datalen != as->as.dns.ibuflen + sizeof(as->as.dns.pktlen))
+ return (1);
+
+ DPRINT_PACKET("asr_tcp_read()", as->as.dns.ibuf, as->as.dns.ibuflen);
+
+ if (validate_packet(as) == -1)
+ goto close; /* errno set */
+
+ errno = 0;
+close:
+ save_errno = errno;
+ close(as->as_fd);
+ errno = save_errno;
+ as->as_fd = -1;
+ return (errno ? -1 : 0);
+}
+
+/*
+ * Make sure the input buffer is at least "n" bytes long, and allocate or
+ * extend it if necessary. Return 0 on success, or set errno and return -1.
+ */
+static int
+ensure_ibuf(struct asr_query *as, size_t n)
+{
+ char *t;
+
+ if (as->as.dns.ibuf == NULL) {
+ as->as.dns.ibuf = malloc(n);
+ if (as->as.dns.ibuf == NULL)
+ return (-1); /* errno set */
+ as->as.dns.ibufsize = n;
+ return (0);
+ }
+
+ if (as->as.dns.ibufsize >= n)
+ return (0);
+
+ t = realloc(as->as.dns.ibuf, n);
+ if (t == NULL)
+ return (-1); /* errno set */
+ as->as.dns.ibuf = t;
+ as->as.dns.ibufsize = n;
+
+ return (0);
+}
+
+/*
+ * Check if the received packet is valid.
+ * Return 0 on success, or set errno and return -1.
+ */
+static int
+validate_packet(struct asr_query *as)
+{
+ struct asr_unpack p;
+ struct asr_dns_header h;
+ struct asr_dns_query q;
+ struct asr_dns_rr rr;
+ int r;
+
+ asr_unpack_init(&p, as->as.dns.ibuf, as->as.dns.ibuflen);
+
+ asr_unpack_header(&p, &h);
+ if (p.err)
+ goto inval;
+
+ if (h.id != as->as.dns.reqid) {
+ DPRINT("incorrect reqid\n");
+ goto inval;
+ }
+ if (h.qdcount != 1)
+ goto inval;
+ /* Should be zero, we could allow this */
+ if ((h.flags & Z_MASK) != 0)
+ goto inval;
+ /* Actually, it depends on the request but we only use OP_QUERY */
+ if (OPCODE(h.flags) != OP_QUERY)
+ goto inval;
+ /* Must be a response */
+ if ((h.flags & QR_MASK) == 0)
+ goto inval;
+
+ as->as.dns.rcode = RCODE(h.flags);
+ as->as.dns.ancount = h.ancount;
+
+ asr_unpack_query(&p, &q);
+ if (p.err)
+ goto inval;
+
+ if (q.q_type != as->as.dns.type ||
+ q.q_class != as->as.dns.class ||
+ strcasecmp(q.q_dname, as->as.dns.dname)) {
+ DPRINT("incorrect type/class/dname '%s' != '%s'\n",
+ q.q_dname, as->as.dns.dname);
+ goto inval;
+ }
+
+ /* Check for truncation */
+ if (h.flags & TC_MASK) {
+ errno = EOVERFLOW;
+ return (-1);
+ }
+
+ /* Validate the rest of the packet */
+ for (r = h.ancount + h.nscount + h.arcount; r; r--)
+ asr_unpack_rr(&p, &rr);
+
+ if (p.err || (p.offset != as->as.dns.ibuflen))
+ goto inval;
+
+ return (0);
+
+ inval:
+ errno = EINVAL;
+ return (-1);
+}
+
+/*
+ * Set the async context nameserver index to the next nameserver, cycling
+ * over the list until the maximum retry counter is reached. Return 0 on
+ * success, or -1 if all nameservers were used.
+ */
+static int
+iter_ns(struct asr_query *as)
+{
+ for (;;) {
+ if (as->as.dns.nsloop >= as->as_ctx->ac_nsretries)
+ return (-1);
+
+ as->as.dns.nsidx += 1;
+ if (as->as.dns.nsidx <= as->as_ctx->ac_nscount)
+ break;
+ as->as.dns.nsidx = 0;
+ as->as.dns.nsloop++;
+ DPRINT("asr: iter_ns(): cycle %i\n", as->as.dns.nsloop);
+ }
+
+ as->as_timeout = 1000 * (as->as_ctx->ac_nstimeout << as->as.dns.nsloop);
+ if (as->as.dns.nsloop > 0)
+ as->as_timeout /= as->as_ctx->ac_nscount;
+ if (as->as_timeout < 1000)
+ as->as_timeout = 1000;
+
+ return (0);
+}
diff --git a/contrib/lib/libc/asr/sethostent.c b/contrib/lib/libc/asr/sethostent.c
new file mode 100644
index 00000000..833df8e5
--- /dev/null
+++ b/contrib/lib/libc/asr/sethostent.c
@@ -0,0 +1,41 @@
+/* $OpenBSD: sethostent.c,v 1.1 2012/09/08 11:08:21 eric Exp $ */
+/*
+ * 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 <sys/types.h>
+#include <netinet/in.h>
+
+#include <netdb.h>
+#include <resolv.h>
+
+/* XXX these functions do nothing for now */
+
+void
+sethostent(int stayopen)
+{
+}
+
+void
+endhostent(void)
+{
+}
+
+struct hostent *
+gethostent(void)
+{
+ h_errno = NETDB_INTERNAL;
+ return (NULL);
+}
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..c2639914
--- /dev/null
+++ b/contrib/libexec/encrypt/encrypt.c
@@ -0,0 +1,109 @@
+/*
+ * 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 *buf, *lbuf;
+ size_t len;
+
+ if (argc > 2) {
+ fprintf(stderr, "usage: encrypt <string>\n");
+ return (1);
+ }
+
+ if (argc == 2) {
+ print_passwd(argv[1]);
+ return (0);
+ }
+
+ lbuf = NULL;
+ while ((buf = fgetln(stdin, &len))) {
+ if (buf[len - 1] == '\n')
+ buf[len - 1] = '\0';
+ else {
+ if ((lbuf = malloc(len + 1)) == NULL) {
+ fprintf(stderr, "memory exhausted");
+ return (1);
+ }
+ memcpy(lbuf, buf, len);
+ lbuf[len] = '\0';
+ buf = lbuf;
+ }
+ print_passwd(buf);
+ }
+ free(lbuf);
+
+ 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..e16a61ad
--- /dev/null
+++ b/contrib/libexec/mail.local/locking.c
@@ -0,0 +1,178 @@
+/* $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 &&
+ (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..209803c4
--- /dev/null
+++ b/contrib/libexec/mail.local/mail.local.c
@@ -0,0 +1,335 @@
+/* $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;
+ size_t len;
+ 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, tbuf = NULL; (line = fgetln(stdin, &len));) {
+ /* We have to NUL-terminate the line since fgetln does not */
+ if (line[len - 1] == '\n')
+ line[len - 1] = '\0';
+ else {
+ /* No trailing newline, so alloc space and copy */
+ if ((tbuf = malloc(len + 1)) == NULL)
+ merr(FATAL, "unable to allocate memory");
+ memcpy(tbuf, line, len);
+ tbuf[len] = '\0';
+ line = tbuf;
+ }
+ 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;
+ }
+ if (tbuf)
+ free(tbuf);
+
+ /* 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..b405a048
--- /dev/null
+++ b/contrib/libexec/mail.local/pathnames.h
@@ -0,0 +1,36 @@
+/* $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
+ */
+#include <paths.h>
+
+#define _PATH_LOCTMP "/tmp/local.XXXXXXXXXX"
+#define _PATH_LOCKSPOOL "/usr/libexec/lockspool"
diff --git a/m4/aclocal-openssh.m4 b/m4/aclocal-openssh.m4
new file mode 100644
index 00000000..7a81faa1
--- /dev/null
+++ b/m4/aclocal-openssh.m4
@@ -0,0 +1,101 @@
+dnl $Id: aclocal.m4,v 1.9 2013/06/02 21:31:27 tim 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 $1])
+ saved_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $1"
+ _define_flag="$2"
+ test "x$_define_flag" = "x" && _define_flag="$1"
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int main(void) { return 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_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..537d7ac1
--- /dev/null
+++ b/mk/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = smtpd smtpctl makemap backends filters
diff --git a/mk/backends/Makefile.am b/mk/backends/Makefile.am
new file mode 100644
index 00000000..6bd1ef94
--- /dev/null
+++ b/mk/backends/Makefile.am
@@ -0,0 +1,33 @@
+SUBDIRS = queue-stub
+SUBDIRS+= queue-null
+SUBDIRS+= queue-ram
+
+SUBDIRS+= scheduler-stub
+SUBDIRS+= scheduler-ram
+
+SUBDIRS+= table-stub
+SUBDIRS+= table-passwd
+
+if HAVE_MYSQL
+SUBDIRS+= table-mysql
+endif
+
+if HAVE_POSTGRES
+SUBDIRS+= table-postgres
+endif
+
+if HAVE_LDAP
+SUBDIRS+= table-ldap
+endif
+
+if HAVE_SQLITE
+SUBDIRS+= table-sqlite
+endif
+
+if HAVE_REDIS
+SUBDIRS+= table-redis
+endif
+
+if HAVE_SOCKETMAP
+SUBDIRS+= table-socketmap
+endif
diff --git a/mk/backends/queue-null/Makefile.am b/mk/backends/queue-null/Makefile.am
new file mode 100644
index 00000000..597b3145
--- /dev/null
+++ b/mk/backends/queue-null/Makefile.am
@@ -0,0 +1,7 @@
+include $(top_srcdir)/mk/pathnames
+include $(top_srcdir)/mk/queue.mk
+
+pkglibexec_PROGRAMS = queue-null
+
+queue_null_SOURCES = $(SRCS)
+queue_null_SOURCES += $(backends_srcdir)/queue_null.c
diff --git a/mk/backends/queue-ram/Makefile.am b/mk/backends/queue-ram/Makefile.am
new file mode 100644
index 00000000..0f2ec229
--- /dev/null
+++ b/mk/backends/queue-ram/Makefile.am
@@ -0,0 +1,7 @@
+include $(top_srcdir)/mk/pathnames
+include $(top_srcdir)/mk/queue.mk
+
+pkglibexec_PROGRAMS = queue-ram
+
+queue_ram_SOURCES = $(SRCS)
+queue_ram_SOURCES += $(backends_srcdir)/queue_ram.c
diff --git a/mk/backends/queue-stub/Makefile.am b/mk/backends/queue-stub/Makefile.am
new file mode 100644
index 00000000..08dcf9c3
--- /dev/null
+++ b/mk/backends/queue-stub/Makefile.am
@@ -0,0 +1,7 @@
+include $(top_srcdir)/mk/pathnames
+include $(top_srcdir)/mk/queue.mk
+
+pkglibexec_PROGRAMS = queue-stub
+
+queue_stub_SOURCES = $(SRCS)
+queue_stub_SOURCES += $(backends_srcdir)/queue_stub.c
diff --git a/mk/backends/scheduler-ram/Makefile.am b/mk/backends/scheduler-ram/Makefile.am
new file mode 100644
index 00000000..dfbff090
--- /dev/null
+++ b/mk/backends/scheduler-ram/Makefile.am
@@ -0,0 +1,7 @@
+include $(top_srcdir)/mk/pathnames
+include $(top_srcdir)/mk/scheduler.mk
+
+pkglibexec_PROGRAMS = scheduler-ram
+
+scheduler_ram_SOURCES = $(SRCS)
+scheduler_ram_SOURCES += $(backends_srcdir)/scheduler_ram.c
diff --git a/mk/backends/scheduler-stub/Makefile.am b/mk/backends/scheduler-stub/Makefile.am
new file mode 100644
index 00000000..a4a7d11f
--- /dev/null
+++ b/mk/backends/scheduler-stub/Makefile.am
@@ -0,0 +1,7 @@
+include $(top_srcdir)/mk/pathnames
+include $(top_srcdir)/mk/scheduler.mk
+
+pkglibexec_PROGRAMS = scheduler-stub
+
+scheduler_stub_SOURCES = $(SRCS)
+scheduler_stub_SOURCES += $(backends_srcdir)/scheduler_stub.c
diff --git a/mk/backends/table-ldap/Makefile.am b/mk/backends/table-ldap/Makefile.am
new file mode 100644
index 00000000..24a2ec52
--- /dev/null
+++ b/mk/backends/table-ldap/Makefile.am
@@ -0,0 +1,9 @@
+include $(top_srcdir)/mk/pathnames
+include $(top_srcdir)/mk/table.mk
+
+pkglibexec_PROGRAMS = table-ldap
+
+table_ldap_SOURCES = $(SRCS)
+table_ldap_SOURCES += $(smtpd_srcdir)/table_ldap.c
+table_ldap_SOURCES += $(smtpd_srcdir)/aldap.c
+table_ldap_SOURCES += $(smtpd_srcdir)/ber.c
diff --git a/mk/backends/table-mysql/Makefile.am b/mk/backends/table-mysql/Makefile.am
new file mode 100644
index 00000000..0372bb38
--- /dev/null
+++ b/mk/backends/table-mysql/Makefile.am
@@ -0,0 +1,9 @@
+include $(top_srcdir)/mk/pathnames
+include $(top_srcdir)/mk/table.mk
+
+pkglibexec_PROGRAMS = table-mysql
+
+table_mysql_SOURCES = $(SRCS)
+table_mysql_SOURCES += $(smtpd_srcdir)/table_mysql.c
+
+LDADD += -lmysqlclient
diff --git a/mk/backends/table-passwd/Makefile.am b/mk/backends/table-passwd/Makefile.am
new file mode 100644
index 00000000..068c604e
--- /dev/null
+++ b/mk/backends/table-passwd/Makefile.am
@@ -0,0 +1,7 @@
+include $(top_srcdir)/mk/pathnames
+include $(top_srcdir)/mk/table.mk
+
+pkglibexec_PROGRAMS = table-passwd
+
+table_passwd_SOURCES = $(SRCS)
+table_passwd_SOURCES += $(smtpd_srcdir)/table_passwd.c
diff --git a/mk/backends/table-postgres/Makefile.am b/mk/backends/table-postgres/Makefile.am
new file mode 100644
index 00000000..94122ec3
--- /dev/null
+++ b/mk/backends/table-postgres/Makefile.am
@@ -0,0 +1,10 @@
+include $(top_srcdir)/mk/pathnames
+include $(top_srcdir)/mk/table.mk
+
+pkglibexec_PROGRAMS = table-postgres
+
+table_postgres_SOURCES = $(SRCS)
+table_postgres_SOURCES += $(smtpd_srcdir)/table_postgres.c
+
+CFLAGS += -I/usr/include/postgresql
+LDADD += -lpq
diff --git a/mk/backends/table-redis/Makefile.am b/mk/backends/table-redis/Makefile.am
new file mode 100644
index 00000000..64148fa3
--- /dev/null
+++ b/mk/backends/table-redis/Makefile.am
@@ -0,0 +1,10 @@
+include $(top_srcdir)/mk/pathnames
+include $(top_srcdir)/mk/table.mk
+
+pkglibexec_PROGRAMS = table-redis
+
+table_redis_SOURCES = $(SRCS)
+table_redis_SOURCES += $(smtpd_srcdir)/table_redis.c
+
+CFLAGS += -I/usr/local/include/hiredis
+LDADD += -lhiredis
diff --git a/mk/backends/table-socketmap/Makefile.am b/mk/backends/table-socketmap/Makefile.am
new file mode 100644
index 00000000..33ead9e3
--- /dev/null
+++ b/mk/backends/table-socketmap/Makefile.am
@@ -0,0 +1,7 @@
+include $(top_srcdir)/mk/pathnames
+include $(top_srcdir)/mk/table.mk
+
+pkglibexec_PROGRAMS = table-socketmap
+
+table_sqlite_SOURCES = $(SRCS)
+table_sqlite_SOURCES += $(smtpd_srcdir)/table_socketmap.c
diff --git a/mk/backends/table-sqlite/Makefile.am b/mk/backends/table-sqlite/Makefile.am
new file mode 100644
index 00000000..3e1ae2ac
--- /dev/null
+++ b/mk/backends/table-sqlite/Makefile.am
@@ -0,0 +1,9 @@
+include $(top_srcdir)/mk/pathnames
+include $(top_srcdir)/mk/table.mk
+
+pkglibexec_PROGRAMS = table-sqlite
+
+table_sqlite_SOURCES = $(SRCS)
+table_sqlite_SOURCES += $(smtpd_srcdir)/table_sqlite.c
+
+LDADD += -lsqlite3
diff --git a/mk/backends/table-stub/Makefile.am b/mk/backends/table-stub/Makefile.am
new file mode 100644
index 00000000..9a0ed6be
--- /dev/null
+++ b/mk/backends/table-stub/Makefile.am
@@ -0,0 +1,7 @@
+include $(top_srcdir)/mk/pathnames
+include $(top_srcdir)/mk/table.mk
+
+pkglibexec_PROGRAMS = table-stub
+
+table_stub_SOURCES = $(SRCS)
+table_stub_SOURCES += $(smtpd_srcdir)/table_stub.c
diff --git a/mk/filter.mk b/mk/filter.mk
new file mode 100644
index 00000000..d86cfdc7
--- /dev/null
+++ b/mk/filter.mk
@@ -0,0 +1,17 @@
+AM_CPPFLAGS = -I$(smtpd_srcdir)
+AM_CPPFLAGS += -I$(compat_srcdir)
+AM_CPPFLAGS += -I$(asr_srcdir)
+
+SRCS = $(smtpd_srcdir)/filter_api.c
+SRCS += $(smtpd_srcdir)/mproc.c
+SRCS += $(smtpd_srcdir)/log.c
+SRCS += $(smtpd_srcdir)/tree.c
+SRCS += $(smtpd_srcdir)/util.c
+SRCS += $(smtpd_srcdir)/iobuf.c
+SRCS += $(smtpd_srcdir)/ioev.c
+
+LIBCOMPAT = $(top_builddir)/openbsd-compat/libopenbsd-compat.a
+LDADD = $(LIBCOMPAT)
+
+CFLAGS= -DNO_IO -DBUILD_FILTER
+
diff --git a/mk/filters/Makefile.am b/mk/filters/Makefile.am
new file mode 100644
index 00000000..7fdd76ee
--- /dev/null
+++ b/mk/filters/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = stub trace dnsbl monkey
diff --git a/mk/filters/dnsbl/Makefile.am b/mk/filters/dnsbl/Makefile.am
new file mode 100644
index 00000000..8d7f5935
--- /dev/null
+++ b/mk/filters/dnsbl/Makefile.am
@@ -0,0 +1,19 @@
+include $(top_srcdir)/mk/pathnames
+include $(top_srcdir)/mk/filter.mk
+
+pkglibexec_PROGRAMS = filter-dnsbl
+
+filter_dnsbl_SOURCES = $(SRCS)
+filter_dnsbl_SOURCES += $(filters_srcdir)/filter_dnsbl.c
+
+filter_dnsbl_SOURCES += $(asr_srcdir)/asr.c
+filter_dnsbl_SOURCES += $(asr_srcdir)/asr_debug.c
+filter_dnsbl_SOURCES += $(asr_srcdir)/asr_utils.c
+filter_dnsbl_SOURCES += $(asr_srcdir)/gethostnamadr_async.c
+filter_dnsbl_SOURCES += $(asr_srcdir)/res_send_async.c
+filter_dnsbl_SOURCES += $(asr_srcdir)/getaddrinfo_async.c
+filter_dnsbl_SOURCES += $(asr_srcdir)/getnameinfo_async.c
+filter_dnsbl_SOURCES += $(asr_srcdir)/res_search_async.c
+filter_dnsbl_SOURCES += $(asr_srcdir)/event_asr_run.c
+
+filter_dnsbl_CFLAGS = -DASR_OPT_THREADSAFE=0
diff --git a/mk/filters/monkey/Makefile.am b/mk/filters/monkey/Makefile.am
new file mode 100644
index 00000000..3a41afbb
--- /dev/null
+++ b/mk/filters/monkey/Makefile.am
@@ -0,0 +1,7 @@
+include $(top_srcdir)/mk/pathnames
+include $(top_srcdir)/mk/filter.mk
+
+pkglibexec_PROGRAMS = filter-monkey
+
+filter_monkey_SOURCES = $(SRCS)
+filter_monkey_SOURCES += $(filters_srcdir)/filter_monkey.c
diff --git a/mk/filters/stub/Makefile.am b/mk/filters/stub/Makefile.am
new file mode 100644
index 00000000..cedf3a21
--- /dev/null
+++ b/mk/filters/stub/Makefile.am
@@ -0,0 +1,7 @@
+include $(top_srcdir)/mk/pathnames
+include $(top_srcdir)/mk/filter.mk
+
+pkglibexec_PROGRAMS = filter-stub
+
+filter_stub_SOURCES = $(SRCS)
+filter_stub_SOURCES += $(filters_srcdir)/filter_stub.c
diff --git a/mk/filters/trace/Makefile.am b/mk/filters/trace/Makefile.am
new file mode 100644
index 00000000..d3710955
--- /dev/null
+++ b/mk/filters/trace/Makefile.am
@@ -0,0 +1,7 @@
+include $(top_srcdir)/mk/pathnames
+include $(top_srcdir)/mk/filter.mk
+
+pkglibexec_PROGRAMS = filter-trace
+
+filter_trace_SOURCES = $(SRCS)
+filter_trace_SOURCES += $(filters_srcdir)/filter_trace.c
diff --git a/mk/makemap/Makefile.am b/mk/makemap/Makefile.am
new file mode 100644
index 00000000..1d412ad3
--- /dev/null
+++ b/mk/makemap/Makefile.am
@@ -0,0 +1,81 @@
+include $(top_srcdir)/mk/pathnames
+
+if HAVE_MAILWRAPPER
+USE_MAILWRAPPER=1
+pkglibexec_PROGRAMS= makemap
+else
+USE_MAILWRAPPER=0
+sbin_PROGRAMS= makemap
+endif
+
+makemap_SOURCES= $(smtpd_srcdir)/parse.y
+makemap_SOURCES+= $(smtpd_srcdir)/makemap.c
+makemap_SOURCES+= $(smtpd_srcdir)/aliases.c
+makemap_SOURCES+= $(smtpd_srcdir)/expand.c
+makemap_SOURCES+= $(smtpd_srcdir)/limit.c
+makemap_SOURCES+= $(smtpd_srcdir)/log.c
+makemap_SOURCES+= $(smtpd_srcdir)/util.c
+makemap_SOURCES+= $(smtpd_srcdir)/table.c
+makemap_SOURCES+= $(smtpd_srcdir)/dict.c
+makemap_SOURCES+= $(smtpd_srcdir)/tree.c
+makemap_SOURCES+= $(smtpd_srcdir)/to.c
+makemap_SOURCES+= $(smtpd_srcdir)/table_static.c
+makemap_SOURCES+= $(smtpd_srcdir)/table_db.c
+makemap_SOURCES+= $(smtpd_srcdir)/table_getpwnam.c
+makemap_SOURCES+= $(smtpd_srcdir)/table_proc.c
+
+makemap_CFLAGS= -DNO_IO
+
+
+AM_CPPFLAGS= -I$(smtpd_srcdir) \
+ -I$(compat_srcdir) \
+ -I$(asr_srcdir)
+
+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
+CPPFLAGS= -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@
+
+MANPAGES= makemap.8.out newaliases.8.out
+MANPAGES_IN= $(smtpd_srcdir)/makemap.8
+MANPAGES_IN+= $(smtpd_srcdir)/newaliases.8
+
+EXTRA_DIST= $(MANPAGES_IN)
+
+PATHSUBS= -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
+
+# newaliases makemap
+install-exec-hook: $(MANPAGES)
+ $(MKDIR_P) $(DESTDIR)$(mandir)/$(mansubdir)8
+ if test "$(USE_MAILWRAPPER)" = "0"; then \
+ ln -s $(sbindir)/makemap $(DESTDIR)$(sbindir)/newaliases;\
+ fi
+
+ $(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 makemap.8.out newaliases.8.out
+
+uninstall-hook:
+ rm -f $(DESTDIR)$(sbindir)/newaliases$(EXEEXT) \
+ $(DESTDIR)$(sbindir)/makemap$(EXEEXT)
+ rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/makemap.8 \
+ $(DESTDIR)$(mandir)/$(mansubdir)8/newaliases.8
+ rmdir $(DESTDIR)$(pkglibexecdir) \
+ $(DESTDIR)$(mandir)/$(mansubdir)8 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..7aff7176
--- /dev/null
+++ b/mk/pathnames
@@ -0,0 +1,15 @@
+smtpd_srcdir = $(top_srcdir)/smtpd
+asr_srcdir = $(top_srcdir)/contrib/lib/libc/asr
+compat_srcdir = $(top_srcdir)/openbsd-compat
+regress_srcdir = $(top_srcdir)/regress/bin
+filters_srcdir = $(smtpd_srcdir)/filters
+backends_srcdir = $(smtpd_srcdir)/backends
+
+PATHS= -DSMTPD_CONFDIR=\"$(sysconfdir)\" \
+ -DPATH_CHROOT=\"$(PRIVSEP_PATH)\" \
+ -DPATH_SMTPCTL=\"$(sbindir)/smtpctl\" \
+ -DPATH_MAILLOCAL=\"$(pkglibexecdir)/mail.local\" \
+ -DPATH_FILTERS=\"$(pkglibexecdir)\" \
+ -DPATH_TABLES=\"$(pkglibexecdir)\"
+
+
diff --git a/mk/queue.mk b/mk/queue.mk
new file mode 100644
index 00000000..b79acbd6
--- /dev/null
+++ b/mk/queue.mk
@@ -0,0 +1,11 @@
+AM_CPPFLAGS = -I$(smtpd_srcdir)
+AM_CPPFLAGS += -I$(compat_srcdir)
+
+LIBCOMPAT = $(top_builddir)/openbsd-compat/libopenbsd-compat.a
+LDADD = $(LIBCOMPAT)
+
+SRCS = $(smtpd_srcdir)/log.c
+SRCS += $(backends_srcdir)/queue_utils.c
+SRCS += $(smtpd_srcdir)/queue_api.c
+SRCS += $(smtpd_srcdir)/tree.c
+SRCS += $(smtpd_srcdir)/dict.c
diff --git a/mk/scheduler.mk b/mk/scheduler.mk
new file mode 100644
index 00000000..43c5b53f
--- /dev/null
+++ b/mk/scheduler.mk
@@ -0,0 +1,9 @@
+AM_CPPFLAGS = -I$(smtpd_srcdir)
+AM_CPPFLAGS += -I$(compat_srcdir)
+
+LIBCOMPAT = $(top_builddir)/openbsd-compat/libopenbsd-compat.a
+LDADD = $(LIBCOMPAT)
+
+SRCS = $(smtpd_srcdir)/log.c
+SRCS += $(smtpd_srcdir)/scheduler_api.c
+SRCS += $(smtpd_srcdir)/tree.c
diff --git a/mk/smtpctl/Makefile.am b/mk/smtpctl/Makefile.am
new file mode 100644
index 00000000..8ac88eb7
--- /dev/null
+++ b/mk/smtpctl/Makefile.am
@@ -0,0 +1,83 @@
+include $(top_srcdir)/mk/pathnames
+
+sbin_PROGRAMS= smtpctl
+
+if HAVE_MAILWRAPPER
+USE_MAILWRAPPER=1
+else
+USE_MAILWRAPPER=0
+endif
+
+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)/util.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_GCM_CRYPTO
+smtpctl_SOURCES+= $(smtpd_srcdir)/crypto.c
+endif
+
+smtpctl_CFLAGS= -DNO_IO
+smtpctl_CFLAGS+= -DPATH_GZCAT=\"$(ZCAT)\" \
+ -DPATH_ENCRYPT=\"$(pkglibexecdir)/encrypt\"
+
+AM_CPPFLAGS= -I$(top_srcdir)/smtpd \
+ -I$(top_srcdir)/openbsd-compat \
+ -I$(top_srcdir)/contrib/lib/libc/asr
+
+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
+CPPFLAGS= -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@
+
+MANPAGES= smtpctl.8.out sendmail.8.out
+MANPAGES_IN= $(smtpd_srcdir)/smtpctl.8 $(smtpd_srcdir)/sendmail.8
+
+EXTRA_DIST= $(MANPAGES_IN)
+
+PATHSUBS= -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
+
+install-exec-hook: $(CONFIGFILES) $(MANPAGES)
+ $(MKDIR_P) $(DESTDIR)$(mandir)/$(mansubdir)8
+ if test "$(USE_MAILWRAPPER)" = "0"; then \
+ ln -s $(sbindir)/smtpctl $(DESTDIR)$(sbindir)/mailq;\
+ ln -s $(sbindir)/smtpctl $(DESTDIR)$(bindir)/sendmail;\
+ fi
+ $(INSTALL) -m 644 smtpctl.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/smtpctl.8
+ $(INSTALL) -m 644 sendmail.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sendmail.8
+ rm smtpctl.8.out sendmail.8.out
+
+uninstall-hook:
+ rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/smtpctl.8 \
+ rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/sendmail.8 \
+ rmdir $(DESTDIR)$(mandir)/$(mansubdir)8 2> /dev/null || /bin/true
+ if test "$(USE_MAILWRAPPER)" = "0"; then \
+ rm -f $(DESTDIR)$(sbindir)/mailq;\
+ rm -f $(DESTDIR)$(bindir)/sendmail;\
+ fi
diff --git a/mk/smtpd/Makefile.am b/mk/smtpd/Makefile.am
new file mode 100644
index 00000000..7035e81e
--- /dev/null
+++ b/mk/smtpd/Makefile.am
@@ -0,0 +1,193 @@
+# 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)/compress_backend.c
+smtpd_SOURCES+= $(smtpd_srcdir)/config.c
+smtpd_SOURCES+= $(smtpd_srcdir)/control.c
+smtpd_SOURCES+= $(smtpd_srcdir)/delivery.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)/filter.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_session.c
+smtpd_SOURCES+= $(smtpd_srcdir)/log.c
+smtpd_SOURCES+= $(smtpd_srcdir)/mda.c
+smtpd_SOURCES+= $(smtpd_srcdir)/mproc.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)/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_privsep.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)/util.c
+smtpd_SOURCES+= $(smtpd_srcdir)/waitq.c
+
+# backends
+if HAVE_GCM_CRYPTO
+smtpd_SOURCES+= $(smtpd_srcdir)/crypto.c
+endif
+smtpd_SOURCES+= $(smtpd_srcdir)/compress_gzip.c
+smtpd_SOURCES+= $(smtpd_srcdir)/delivery_filename.c
+smtpd_SOURCES+= $(smtpd_srcdir)/delivery_maildir.c
+smtpd_SOURCES+= $(smtpd_srcdir)/delivery_mbox.c
+smtpd_SOURCES+= $(smtpd_srcdir)/delivery_mda.c
+smtpd_SOURCES+= $(smtpd_srcdir)/delivery_lmtp.c
+smtpd_SOURCES+= $(smtpd_srcdir)/table_db.c
+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
+
+# resolver
+smtpd_SOURCES+= $(asr_srcdir)/asr.c \
+ $(asr_srcdir)/asr_debug.c \
+ $(asr_srcdir)/asr_utils.c \
+ $(asr_srcdir)/gethostnamadr_async.c \
+ $(asr_srcdir)/res_send_async.c \
+ $(asr_srcdir)/getaddrinfo_async.c \
+ $(asr_srcdir)/getnameinfo_async.c \
+ $(asr_srcdir)/res_search_async.c \
+ $(asr_srcdir)/event_asr_run.c
+
+smtpd_CFLAGS= -DIO_SSL -DASR_OPT_THREADSAFE=0
+smtpd_CFLAGS+= -DCA_FILE=\"$(CA_FILE)\"
+
+AM_CPPFLAGS= -I$(smtpd_srcdir) \
+ -I$(compat_srcdir) \
+ -I$(asr_srcdir)
+
+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 -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
+
+EXTRA_DIST+= $(asr_srcdir)/asr.h
+EXTRA_DIST+= $(asr_srcdir)/asr_private.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/mk/table.mk b/mk/table.mk
new file mode 100644
index 00000000..03003149
--- /dev/null
+++ b/mk/table.mk
@@ -0,0 +1,10 @@
+AM_CPPFLAGS = -I$(smtpd_srcdir)
+AM_CPPFLAGS += -I$(compat_srcdir)
+
+LIBCOMPAT = $(top_builddir)/openbsd-compat/libopenbsd-compat.a
+LDADD = $(LIBCOMPAT)
+
+SRCS = $(smtpd_srcdir)/log.c
+SRCS += $(smtpd_srcdir)/table_api.c
+SRCS += $(smtpd_srcdir)/tree.c
+SRCS += $(smtpd_srcdir)/dict.c
diff --git a/openbsd-compat/Makefile.am b/openbsd-compat/Makefile.am
new file mode 100644
index 00000000..46491704
--- /dev/null
+++ b/openbsd-compat/Makefile.am
@@ -0,0 +1,15 @@
+noinst_LIBRARIES = libopenbsd-compat.a
+
+libopenbsd_compat_a_SOURCES = \
+ arc4random.c base64.c basename.c bsd-closefrom.c \
+ bsd-getpeereid.c bsd-misc.c bsd-waitpid.c clock_gettime.c \
+ daemon.c dirname.c entropy.c fgetln.c getopt.c fmt_scaled.c \
+ fparseln.c imsg.c imsg-buffer.c mktemp.c pw_dup.c setresguid.c \
+ setproctitle.c strlcat.c strlcpy.c strmode.c strtonum.c \
+ strsep.c vis.c xmalloc.c pidfile.c explicit_bzero.c
+
+EXTRA_DIST = base64.h bsd-misc.h bsd-waitpid.h chacha_private.h defines.h \
+ entropy.h imsg.h includes.h log.h openbsd-compat.h sys/queue.h \
+ sys/tree.h vis.h xmalloc.h
+
+AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/openbsd-compat
diff --git a/openbsd-compat/NOTES b/openbsd-compat/NOTES
new file mode 100644
index 00000000..dabf2c34
--- /dev/null
+++ b/openbsd-compat/NOTES
@@ -0,0 +1,35 @@
+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
+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
+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..eac073cc
--- /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(u_int32_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();
+}
+
+u_int32_t
+arc4random(void)
+{
+ u_int32_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;
+ u_int32_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;
+ }
+ i = r = 0;
+}
+#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.
+ */
+u_int32_t
+arc4random_uniform(u_int32_t upper_bound)
+{
+ u_int32_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-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..93095eb1
--- /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-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..7c3680fa
--- /dev/null
+++ b/openbsd-compat/chacha_private.h
@@ -0,0 +1,222 @@
+/*
+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 $ */
+
+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/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..e8e72424
--- /dev/null
+++ b/openbsd-compat/defines.h
@@ -0,0 +1,799 @@
+/*
+ * 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.145 2007/09/26 21:03:20 dtucker Exp $ */
+
+
+/* Constants */
+
+#if defined(HAVE_DECL_SHUT_RD) && HAVE_DECL_SHUT_RD == 0
+enum
+{
+ SHUT_RD = 0, /* No more receptions. */
+ SHUT_WR, /* No more transmissions. */
+ SHUT_RDWR /* No more receptions or transmissions. */
+};
+# define SHUT_RD SHUT_RD
+# define SHUT_WR SHUT_WR
+# define SHUT_RDWR SHUT_RDWR
+#endif
+
+#ifndef IPTOS_LOWDELAY
+# define IPTOS_LOWDELAY 0x10
+# define IPTOS_THROUGHPUT 0x08
+# define IPTOS_RELIABILITY 0x04
+# define IPTOS_LOWCOST 0x02
+# define IPTOS_MINCOST IPTOS_LOWCOST
+#endif /* IPTOS_LOWDELAY */
+
+#ifndef MAXHOSTNAMELEN
+# define MAXHOSTNAMELEN 64
+#endif
+
+#ifndef LOGIN_NAME_MAX
+# define LOGIN_NAME_MAX 9
+#endif
+
+#ifndef PATH_MAX
+# ifdef _POSIX_PATH_MAX
+# define PATH_MAX _POSIX_PATH_MAX
+# else
+# define PATH_MAX 64
+# endif
+#endif
+
+/*
+ * Looks like ugly, but MAX_IMSGSIZE equals 16384,
+ * and if we don't care it will overflow for some struct
+ */
+#if PATH_MAX > 1024
+# undef PATH_MAX
+# define PATH_MAX 1024
+#endif
+
+#ifndef MAXPATHLEN
+# define MAXPATHLEN PATH_MAX
+#endif
+
+#if MAXPATHLEN > 1024
+# undef MAXPATHLEN
+# define MAXPATHLEN 1024
+#endif
+
+#if defined(HAVE_DECL_MAXSYMLINKS) && HAVE_DECL_MAXSYMLINKS == 0
+# define MAXSYMLINKS 5
+#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
+
+#ifndef NGROUPS_MAX /* Disable groupaccess if NGROUP_MAX is not set */
+#ifdef NGROUPS
+#define NGROUPS_MAX NGROUPS
+#else
+#define NGROUPS_MAX 0
+#endif
+#endif
+
+#if defined(HAVE_DECL_O_NONBLOCK) && HAVE_DECL_O_NONBLOCK == 0
+# 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_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
+
+/* *-*-nto-qnx doesn't define this constant in the system headers */
+#ifdef MISSING_NFDBITS
+# define NFDBITS (8 * sizeof(unsigned long))
+#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 */
+
+/* If sys/types.h does not supply intXX_t, supply them ourselves */
+/* (or die trying) */
+
+#ifndef HAVE_U_INT
+typedef unsigned int u_int;
+#endif
+
+#ifndef HAVE_INTXX_T
+# if (SIZEOF_CHAR == 1)
+typedef char int8_t;
+# else
+# error "8 bit int type not found."
+# endif
+# if (SIZEOF_SHORT_INT == 2)
+typedef short int int16_t;
+# else
+# ifdef _UNICOS
+# if (SIZEOF_SHORT_INT == 4)
+typedef short int16_t;
+# else
+typedef long int16_t;
+# endif
+# else
+# error "16 bit int type not found."
+# endif /* _UNICOS */
+# endif
+# if (SIZEOF_INT == 4)
+typedef int int32_t;
+# else
+# ifdef _UNICOS
+typedef long int32_t;
+# else
+# error "32 bit int type not found."
+# endif /* _UNICOS */
+# endif
+#endif
+
+/* If sys/types.h does not supply u_intXX_t, supply them ourselves */
+#ifndef HAVE_U_INTXX_T
+# ifdef HAVE_UINTXX_T
+typedef uint8_t u_int8_t;
+typedef uint16_t u_int16_t;
+typedef uint32_t u_int32_t;
+# define HAVE_U_INTXX_T 1
+# else
+# if (SIZEOF_CHAR == 1)
+typedef unsigned char u_int8_t;
+# else
+# error "8 bit int type not found."
+# endif
+# if (SIZEOF_SHORT_INT == 2)
+typedef unsigned short int u_int16_t;
+# else
+# ifdef _UNICOS
+# if (SIZEOF_SHORT_INT == 4)
+typedef unsigned short u_int16_t;
+# else
+typedef unsigned long u_int16_t;
+# endif
+# else
+# error "16 bit int type not found."
+# endif
+# endif
+# if (SIZEOF_INT == 4)
+typedef unsigned int u_int32_t;
+# else
+# ifdef _UNICOS
+typedef unsigned long u_int32_t;
+# else
+# error "32 bit int type not found."
+# endif
+# endif
+# endif
+#define __BIT_TYPES_DEFINED__
+#endif
+
+/* 64-bit types */
+#ifndef HAVE_INT64_T
+# if (SIZEOF_LONG_INT == 8)
+typedef long int int64_t;
+# else
+# if (SIZEOF_LONG_LONG_INT == 8)
+typedef long long int int64_t;
+# endif
+# endif
+#endif
+#ifndef HAVE_U_INT64_T
+# if (SIZEOF_LONG_INT == 8)
+typedef unsigned long int u_int64_t;
+# else
+# if (SIZEOF_LONG_LONG_INT == 8)
+typedef unsigned long long int u_int64_t;
+# endif
+# endif
+#endif
+
+#ifndef HAVE_U_CHAR
+typedef unsigned char u_char;
+# define HAVE_U_CHAR
+#endif /* HAVE_U_CHAR */
+
+#ifndef SIZE_T_MAX
+#define SIZE_T_MAX ULONG_MAX
+#endif /* SIZE_T_MAX */
+
+#ifndef HAVE_SIZE_T
+typedef unsigned int size_t;
+# define HAVE_SIZE_T
+# define SIZE_T_MAX UINT_MAX
+#endif /* HAVE_SIZE_T */
+
+#ifndef HAVE_SSIZE_T
+typedef int ssize_t;
+# define HAVE_SSIZE_T
+#endif /* HAVE_SSIZE_T */
+
+#ifndef HAVE_CLOCK_T
+typedef long clock_t;
+# define HAVE_CLOCK_T
+#endif /* HAVE_CLOCK_T */
+
+#ifndef HAVE_SA_FAMILY_T
+typedef int sa_family_t;
+# define HAVE_SA_FAMILY_T
+#endif /* HAVE_SA_FAMILY_T */
+
+#ifndef HAVE_PID_T
+typedef int pid_t;
+# define HAVE_PID_T
+#endif /* HAVE_PID_T */
+
+#ifndef HAVE_SIG_ATOMIC_T
+typedef int sig_atomic_t;
+# define HAVE_SIG_ATOMIC_T
+#endif /* HAVE_SIG_ATOMIC_T */
+
+#ifndef HAVE_MODE_T
+typedef int mode_t;
+# define HAVE_MODE_T
+#endif /* HAVE_MODE_T */
+
+#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 u_int32_t in_addr_t;
+#endif
+
+#ifndef HAVE_IN_PORT_T
+typedef u_int16_t in_port_t;
+#endif
+
+#if defined(BROKEN_SYS_TERMIO_H) && !defined(_STRUCT_WINSIZE)
+#define _STRUCT_WINSIZE
+struct winsize {
+ unsigned short ws_row; /* rows, in characters */
+ unsigned short ws_col; /* columns, in character */
+ unsigned short ws_xpixel; /* horizontal size, pixels */
+ unsigned short ws_ypixel; /* vertical size, pixels */
+};
+#endif
+
+/* *-*-nto-qnx does not define this type in the system headers */
+#ifdef MISSING_FD_MASK
+ typedef unsigned long int fd_mask;
+#endif
+
+/* Paths */
+
+#ifndef _PATH_BSHELL
+# define _PATH_BSHELL "/bin/sh"
+#endif
+
+#ifdef USER_PATH
+# ifdef _PATH_STDPATH
+# undef _PATH_STDPATH
+# endif
+# define _PATH_STDPATH USER_PATH
+#endif
+
+#ifndef _PATH_STDPATH
+# define _PATH_STDPATH "/usr/bin:/bin:/usr/sbin:/sbin"
+#endif
+
+#ifndef SUPERUSER_PATH
+# define SUPERUSER_PATH _PATH_STDPATH
+#endif
+
+#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 MAILDIR
+#endif /* defined(_PATH_MAILDIR) && defined(MAIL_DIRECTORY) */
+
+#ifdef MAIL_DIRECTORY
+# define _PATH_MAILDIR MAIL_DIRECTORY
+#endif
+
+#ifdef MAILDIR
+# undef MAILDIR
+#endif
+
+#ifndef _PATH_NOLOGIN
+# define _PATH_NOLOGIN "/etc/nologin"
+#endif
+
+/* Define this to be the path of the xauth program. */
+#ifdef XAUTH_PATH
+#define _PATH_XAUTH XAUTH_PATH
+#endif /* XAUTH_PATH */
+
+/* derived from XF4/xc/lib/dps/Xlibnet.h */
+#ifndef X_UNIX_PATH
+# ifdef __hpux
+# define X_UNIX_PATH "/var/spool/sockets/X11/%u"
+# else
+# define X_UNIX_PATH "/tmp/.X11-unix/X%u"
+# endif
+#endif /* X_UNIX_PATH */
+#define _PATH_UNIX_X X_UNIX_PATH
+
+#ifndef _PATH_TTY
+# define _PATH_TTY "/dev/tty"
+#endif
+
+/* Macros */
+
+#if defined(HAVE_LOGIN_GETCAPBOOL) && defined(HAVE_LOGIN_CAP_H)
+# define HAVE_LOGIN_CAP
+#endif
+
+#ifndef MAX
+# define MAX(a,b) (((a)>(b))?(a):(b))
+# define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+#ifndef roundup
+# define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
+#endif
+
+#ifndef timersub
+#define timersub(a, b, result) \
+ do { \
+ (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
+ (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
+ if ((result)->tv_usec < 0) { \
+ --(result)->tv_sec; \
+ (result)->tv_usec += 1000000; \
+ } \
+ } while (0)
+#endif
+
+#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
+
+#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
+
+#ifndef TIMEVAL_TO_TIMESPEC
+#define TIMEVAL_TO_TIMESPEC(tv, ts) { \
+ (ts)->tv_sec = (tv)->tv_sec; \
+ (ts)->tv_nsec = (tv)->tv_usec * 1000; \
+}
+#endif
+
+#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) \
+ ((((u_int32_t *) (a))[0] == 0) && (((u_int32_t *) (a))[1] == 0) && \
+ (((u_int32_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
+
+/* *-*-nto-qnx doesn't define this macro in the system headers */
+#ifdef MISSING_HOWMANY
+# define howmany(x,y) (((x)+((y)-1))/(y))
+#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 */
+
+#if defined(HAVE_DECL_OFFSETOF) && HAVE_DECL_OFFSETOF == 0
+# define offsetof(type, member) ((size_t) &((type *)0)->member)
+#endif
+
+/* 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 */
+
+#if !defined(HAVE_GETADDRINFO) && (defined(HAVE_OGETADDRINFO) || defined(HAVE_NGETADDRINFO))
+# define HAVE_GETADDRINFO
+#endif
+
+#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(BROKEN_UPDWTMPX) && defined(HAVE_UPDWTMPX)
+# undef HAVE_UPDWTMPX
+#endif
+
+#if defined(BROKEN_SHADOW_EXPIRE) && defined(HAS_SHADOW_EXPIRE)
+# undef HAS_SHADOW_EXPIRE
+#endif
+
+#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) && \
+ defined(SYSLOG_R_SAFE_IN_SIGHAND)
+# define DO_LOG_SAFE_IN_SIGHAND
+#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_VHANGUP) && !defined(HAVE_DEV_PTMX)
+# define USE_VHANGUP
+#endif /* defined(HAVE_VHANGUP) && !defined(HAVE_DEV_PTMX) */
+
+#ifdef USE_BSM_AUDIT
+# define SSH_AUDIT_EVENTS
+# define CUSTOM_SSH_AUDIT_EVENTS
+#endif
+
+/* OPENSSL_free() is Free() in versions before OpenSSL 0.9.6 */
+#if !defined(OPENSSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x0090600f)
+# define OPENSSL_free(x) Free(x)
+#endif
+
+#if !defined(HAVE___func__) && defined(HAVE___FUNCTION__)
+# define __func__ __FUNCTION__
+#elif !defined(HAVE___func__)
+# define __func__ ""
+#endif
+
+#if defined(KRB5) && !defined(HEIMDAL)
+# define krb5_get_err_text(context,code) error_message(code)
+#endif
+
+#if defined(SKEYCHALLENGE_4ARG)
+# define _compat_skeychallenge(a,b,c,d) skeychallenge(a,b,c,d)
+#else
+# define _compat_skeychallenge(a,b,c,d) skeychallenge(a,b,c)
+#endif
+
+/* Maximum number of file descriptors available */
+#ifndef OPEN_MAX
+# ifdef HAVE_SYSCONF
+# define OPEN_MAX sysconf(_SC_OPEN_MAX)
+# else
+# define OPEN_MAX 256
+# endif
+#endif
+
+#if defined(__Lynx__)
+ /*
+ * LynxOS defines these in param.h which we do not want to include since
+ * it will also pull in a bunch of kernel definitions.
+ */
+# define ALIGNBYTES (sizeof(int) - 1)
+# define ALIGN(p) (((unsigned)p + ALIGNBYTES) & ~ALIGNBYTES)
+ /* Missing prototypes on LynxOS */
+ int snprintf (char *, size_t, const char *, ...);
+ int mkstemp (char *);
+ char *crypt (const char *, const char *);
+ int seteuid (uid_t);
+ int setegid (gid_t);
+ char *mkdtemp (char *);
+ int rresvport_af (int *, sa_family_t);
+ int innetgr (const char *, const char *, const char *, const char *);
+#endif
+
+/*
+ * Define this to use pipes instead of socketpairs for communicating with the
+ * client program. Socketpairs do not seem to work on all systems.
+ *
+ * configure.ac sets this for a few OS's which are known to have problems
+ * but you may need to set it yourself
+ */
+/* #define USE_PIPES 1 */
+
+/**
+ ** login recorder definitions
+ **/
+
+/* FIXME: put default paths back in */
+#ifndef UTMP_FILE
+# ifdef _PATH_UTMP
+# define UTMP_FILE _PATH_UTMP
+# else
+# ifdef CONF_UTMP_FILE
+# define UTMP_FILE CONF_UTMP_FILE
+# endif
+# endif
+#endif
+#ifndef WTMP_FILE
+# ifdef _PATH_WTMP
+# define WTMP_FILE _PATH_WTMP
+# else
+# ifdef CONF_WTMP_FILE
+# define WTMP_FILE CONF_WTMP_FILE
+# endif
+# endif
+#endif
+/* pick up the user's location for lastlog if given */
+#ifndef LASTLOG_FILE
+# ifdef _PATH_LASTLOG
+# define LASTLOG_FILE _PATH_LASTLOG
+# else
+# ifdef CONF_LASTLOG_FILE
+# define LASTLOG_FILE CONF_LASTLOG_FILE
+# endif
+# endif
+#endif
+
+#if defined(HAVE_SHADOW_H) && !defined(DISABLE_SHADOW)
+# define USE_SHADOW
+#endif
+
+/* The login() library function in libutil is first choice */
+#if defined(HAVE_LOGIN) && !defined(DISABLE_LOGIN)
+# define USE_LOGIN
+
+#else
+/* Simply select your favourite login types. */
+/* Can't do if-else because some systems use several... <sigh> */
+# if defined(UTMPX_FILE) && !defined(DISABLE_UTMPX)
+# define USE_UTMPX
+# endif
+# if defined(UTMP_FILE) && !defined(DISABLE_UTMP)
+# define USE_UTMP
+# endif
+# if defined(WTMPX_FILE) && !defined(DISABLE_WTMPX)
+# define USE_WTMPX
+# endif
+# if defined(WTMP_FILE) && !defined(DISABLE_WTMP)
+# define USE_WTMP
+# endif
+
+#endif
+
+#ifndef UT_LINESIZE
+# define UT_LINESIZE 8
+#endif
+
+/* I hope that the presence of LASTLOG_FILE is enough to detect this */
+#if defined(LASTLOG_FILE) && !defined(DISABLE_LASTLOG)
+# define USE_LASTLOG
+#endif
+
+#ifdef HAVE_OSF_SIA
+# ifdef USE_SHADOW
+# undef USE_SHADOW
+# endif
+# define CUSTOM_SYS_AUTH_PASSWD 1
+#endif
+
+#if defined(HAVE_LIBIAF) && defined(HAVE_SET_ID)
+# define CUSTOM_SYS_AUTH_PASSWD 1
+#endif
+#if defined(HAVE_LIBIAF) && defined(HAVE_SET_ID) && !defined(BROKEN_LIBIAF)
+# define USE_LIBIAF
+#endif
+
+/* HP-UX 11.11 */
+#ifdef BTMP_FILE
+# define _PATH_BTMP BTMP_FILE
+#endif
+
+#if defined(USE_BTMP) && defined(_PATH_BTMP)
+# define CUSTOM_FAILED_LOGIN
+#endif
+
+/** end of login recorder definitions */
+
+#ifdef BROKEN_GETGROUPS
+# define getgroups(a,b) ((a)==0 && (b)==NULL ? NGROUPS_MAX : getgroups((a),(b)))
+#endif
+
+#if defined(HAVE_MMAP) && defined(BROKEN_MMAP)
+# undef HAVE_MMAP
+#endif
+
+#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
+
+/* 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
+
+#ifndef CLOCK_MONOTONIC
+#define CLOCK_MONOTONIC -1
+#endif
+/* end of chl */
+
+#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..ae3357da
--- /dev/null
+++ b/openbsd-compat/entropy.c
@@ -0,0 +1,239 @@
+/*
+ * 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 <stddef.h> /* for offsetof */
+
+#include <openssl/rand.h>
+#include <openssl/crypto.h>
+#include <openssl/err.h>
+
+//#include "ssh.h"
+//#include "misc.h"
+//#include "xmalloc.h"
+//#include "atomicio.h"
+//#include "pathnames.h"
+#include "log.h"
+//#include "buffer.h"
+
+/*
+ * Portable OpenSSH PRNG seeding:
+ * If OpenSSL has not "internally seeded" itself (e.g. pulled data from
+ * /dev/random), then collect RANDOM_SEED_SIZE bytes of randomness from
+ * PRNGd.
+ */
+#ifndef OPENSSL_PRNG_ONLY
+
+#define RANDOM_SEED_SIZE 48
+
+/*
+ * Collect 'len' bytes of entropy into 'buf' from PRNGD/EGD daemon
+ * listening either on 'tcp_port', or via Unix domain socket at *
+ * 'socket_path'.
+ * Either a non-zero tcp_port or a non-null socket_path must be
+ * supplied.
+ * Returns 0 on success, -1 on error
+ */
+int
+get_random_bytes_prngd(unsigned char *buf, int len,
+ unsigned short tcp_port, char *socket_path)
+{
+ int fd, addr_len, rval, errors;
+ u_char msg[2];
+ struct sockaddr_storage addr;
+ struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr;
+ struct sockaddr_un *addr_un = (struct sockaddr_un *)&addr;
+ mysig_t old_sigpipe;
+
+ /* Sanity checks */
+ if (socket_path == NULL && tcp_port == 0)
+ fatal("You must specify a port or a socket");
+ if (socket_path != NULL &&
+ strlen(socket_path) >= sizeof(addr_un->sun_path))
+ fatal("Random pool path is too long");
+ if (len <= 0 || len > 255)
+ fatal("Too many bytes (%d) to read from PRNGD", len);
+
+ memset(&addr, '\0', sizeof(addr));
+
+ if (tcp_port != 0) {
+ addr_in->sin_family = AF_INET;
+ addr_in->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ addr_in->sin_port = htons(tcp_port);
+ addr_len = sizeof(*addr_in);
+ } else {
+ addr_un->sun_family = AF_UNIX;
+ strlcpy(addr_un->sun_path, socket_path,
+ sizeof(addr_un->sun_path));
+ addr_len = offsetof(struct sockaddr_un, sun_path) +
+ strlen(socket_path) + 1;
+ }
+
+ old_sigpipe = mysignal(SIGPIPE, SIG_IGN);
+
+ errors = 0;
+ rval = -1;
+reopen:
+ fd = socket(addr.ss_family, SOCK_STREAM, 0);
+ if (fd == -1) {
+ error("Couldn't create socket: %s", strerror(errno));
+ goto done;
+ }
+
+ if (connect(fd, (struct sockaddr*)&addr, addr_len) == -1) {
+ if (tcp_port != 0) {
+ error("Couldn't connect to PRNGD port %d: %s",
+ tcp_port, strerror(errno));
+ } else {
+ error("Couldn't connect to PRNGD socket \"%s\": %s",
+ addr_un->sun_path, strerror(errno));
+ }
+ goto done;
+ }
+
+ /* Send blocking read request to PRNGD */
+ msg[0] = 0x02;
+ msg[1] = len;
+
+ if (atomicio(vwrite, fd, msg, sizeof(msg)) != sizeof(msg)) {
+ if (errno == EPIPE && errors < 10) {
+ close(fd);
+ errors++;
+ goto reopen;
+ }
+ error("Couldn't write to PRNGD socket: %s",
+ strerror(errno));
+ goto done;
+ }
+
+ if (atomicio(read, fd, buf, len) != (size_t)len) {
+ if (errno == EPIPE && errors < 10) {
+ close(fd);
+ errors++;
+ goto reopen;
+ }
+ error("Couldn't read from PRNGD socket: %s",
+ strerror(errno));
+ goto done;
+ }
+
+ rval = 0;
+done:
+ mysignal(SIGPIPE, old_sigpipe);
+ if (fd != -1)
+ close(fd);
+ return rval;
+}
+
+static int
+seed_from_prngd(unsigned char *buf, size_t bytes)
+{
+#ifdef PRNGD_PORT
+ debug("trying egd/prngd port %d", PRNGD_PORT);
+ if (get_random_bytes_prngd(buf, bytes, PRNGD_PORT, NULL) == 0)
+ return 0;
+#endif
+#ifdef PRNGD_SOCKET
+ debug("trying egd/prngd socket %s", PRNGD_SOCKET);
+ if (get_random_bytes_prngd(buf, bytes, 0, PRNGD_SOCKET) == 0)
+ return 0;
+#endif
+ return -1;
+}
+
+void
+rexec_send_rng_seed(Buffer *m)
+{
+ u_char buf[RANDOM_SEED_SIZE];
+
+ if (RAND_bytes(buf, sizeof(buf)) <= 0) {
+ error("Couldn't obtain random bytes (error %ld)",
+ ERR_get_error());
+ buffer_put_string(m, "", 0);
+ } else
+ buffer_put_string(m, buf, sizeof(buf));
+}
+
+void
+rexec_recv_rng_seed(Buffer *m)
+{
+ u_char *buf;
+ u_int len;
+
+ buf = buffer_get_string_ret(m, &len);
+ if (buf != NULL) {
+ debug3("rexec_recv_rng_seed: seeding rng with %u bytes", len);
+ RAND_add(buf, len, len);
+ }
+}
+#endif /* OPENSSL_PRNG_ONLY */
+
+void
+seed_rng(void)
+{
+#ifndef OPENSSL_PRNG_ONLY
+ unsigned char buf[RANDOM_SEED_SIZE];
+#endif
+ /*
+ * 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.
+ */
+ u_long version_mask = SSLeay() >= 0x1000000f ? ~0xffff0L : ~0xff0L;
+ if (((SSLeay() ^ OPENSSL_VERSION_NUMBER) & version_mask) ||
+ (SSLeay() >> 12) < (OPENSSL_VERSION_NUMBER >> 12))
+ fatal("OpenSSL version mismatch. Built against %lx, you "
+ "have %lx", (u_long)OPENSSL_VERSION_NUMBER, SSLeay());
+
+#ifndef OPENSSL_PRNG_ONLY
+ if (RAND_status() == 1) {
+ debug3("RNG is ready, skipping seeding");
+ return;
+ }
+
+ if (seed_from_prngd(buf, sizeof(buf)) == -1)
+ fatal("Could not obtain seed from PRNGd");
+ RAND_add(buf, sizeof(buf), sizeof(buf));
+ memset(buf, '\0', sizeof(buf));
+
+#endif /* OPENSSL_PRNG_ONLY */
+ 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/explicit_bzero.c b/openbsd-compat/explicit_bzero.c
new file mode 100644
index 00000000..67b0a2d6
--- /dev/null
+++ b/openbsd-compat/explicit_bzero.c
@@ -0,0 +1,20 @@
+/* OPENBSD ORIGINAL: lib/libc/string/explicit_bzero.c */
+/* $OpenBSD: explicit_bzero.c,v 1.1 2014/01/22 21:06:45 tedu Exp $ */
+/*
+ * Public domain.
+ * Written by Ted Unangst
+ */
+
+#include "includes.h"
+
+#ifndef HAVE_EXPLICIT_BZERO
+
+/*
+ * explicit_bzero - don't let the compiler optimize away bzero
+ */
+void
+explicit_bzero(void *p, size_t n)
+{
+ bzero(p, n);
+}
+#endif
diff --git a/openbsd-compat/fgetln.c b/openbsd-compat/fgetln.c
new file mode 100644
index 00000000..4a7d6461
--- /dev/null
+++ b/openbsd-compat/fgetln.c
@@ -0,0 +1,62 @@
+/* $OpenPackages$ */
+/* $OpenBSD: util.c,v 1.23 2007/09/17 09:28:36 espie Exp $ */
+/* $NetBSD: util.c,v 1.10 1996/12/31 17:56:04 christos Exp $ */
+
+/*
+ * Copyright (c) 2001 Marc Espie.
+ *
+ * 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 OPENBSD PROJECT 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 OPENBSD
+ * PROJECT 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: usr.bin/make/util.c */
+
+#include "includes.h"
+
+#ifndef HAVE_FGETLN
+
+#include "xmalloc.h"
+
+char *
+fgetln(stream, len)
+ FILE *stream;
+ size_t *len;
+{
+ static char *buffer = NULL;
+ static size_t buflen = 0;
+
+ if (buflen == 0) {
+ buflen = 512;
+ buffer = __xmalloc(buflen+1);
+ }
+ if (fgets(buffer, buflen+1, stream) == NULL)
+ return NULL;
+ *len = strlen(buffer);
+ while (*len == buflen && buffer[*len-1] != '\n') {
+ buffer = __xrealloc(buffer, 1, 2*buflen + 1);
+ if (fgets(buffer + buflen, buflen + 1, stream) == NULL)
+ return NULL;
+ *len += strlen(buffer + buflen);
+ buflen *= 2;
+ }
+ return buffer;
+}
+#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..7098de58
--- /dev/null
+++ b/openbsd-compat/fparseln.c
@@ -0,0 +1,224 @@
+/* $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"
+
+#include <sys/cdefs.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#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
+
+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/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..199afc4f
--- /dev/null
+++ b/openbsd-compat/imsg-buffer.c
@@ -0,0 +1,307 @@
+/* $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>
+#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..0cb96275
--- /dev/null
+++ b/openbsd-compat/imsg.c
@@ -0,0 +1,327 @@
+/* $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>
+#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, u_int32_t type, u_int32_t peerid,
+ pid_t pid, int fd, const void *data, u_int16_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, u_int32_t type, u_int32_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, u_int32_t type, u_int32_t peerid,
+ pid_t pid, u_int16_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, u_int16_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 = (u_int16_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..e87aa6c8
--- /dev/null
+++ b/openbsd-compat/imsg.h
@@ -0,0 +1,113 @@
+/* $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
+
+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;
+ u_int32_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 {
+ u_int32_t type;
+ u_int16_t len;
+ u_int16_t flags;
+ u_int32_t peerid;
+ u_int32_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 *, u_int32_t, u_int32_t, pid_t,
+ int, const void *, u_int16_t);
+int imsg_composev(struct imsgbuf *, u_int32_t, u_int32_t, pid_t,
+ int, const struct iovec *, int);
+struct ibuf *imsg_create(struct imsgbuf *, u_int32_t, u_int32_t, pid_t,
+ u_int16_t);
+int imsg_add(struct ibuf *, const void *, u_int16_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..b31496ff
--- /dev/null
+++ b/openbsd-compat/includes.h
@@ -0,0 +1,81 @@
+/* $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
+
+/*
+ *-*-nto-qnx needs these headers for strcasecmp and LASTLOG_FILE respectively
+ */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_LOGIN_H
+# include <login.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/log.h b/openbsd-compat/log.h
new file mode 100644
index 00000000..7a8c5707
--- /dev/null
+++ b/openbsd-compat/log.h
@@ -0,0 +1,65 @@
+/* $OpenBSD: log.h,v 1.15 2006/08/18 09:13:25 deraadt Exp $ */
+
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * 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".
+ */
+
+#ifndef SSH_LOG_H
+#define SSH_LOG_H
+
+/* Supported syslog facilities and levels. */
+typedef enum {
+ SYSLOG_FACILITY_DAEMON,
+ SYSLOG_FACILITY_USER,
+ SYSLOG_FACILITY_AUTH,
+#ifdef LOG_AUTHPRIV
+ SYSLOG_FACILITY_AUTHPRIV,
+#endif
+ SYSLOG_FACILITY_LOCAL0,
+ SYSLOG_FACILITY_LOCAL1,
+ SYSLOG_FACILITY_LOCAL2,
+ SYSLOG_FACILITY_LOCAL3,
+ SYSLOG_FACILITY_LOCAL4,
+ SYSLOG_FACILITY_LOCAL5,
+ SYSLOG_FACILITY_LOCAL6,
+ SYSLOG_FACILITY_LOCAL7,
+ SYSLOG_FACILITY_NOT_SET = -1
+} SyslogFacility;
+
+typedef enum {
+ SYSLOG_LEVEL_QUIET,
+ SYSLOG_LEVEL_FATAL,
+ SYSLOG_LEVEL_ERROR,
+ SYSLOG_LEVEL_INFO,
+ SYSLOG_LEVEL_VERBOSE,
+ SYSLOG_LEVEL_DEBUG1,
+ SYSLOG_LEVEL_DEBUG2,
+ SYSLOG_LEVEL_DEBUG3,
+ SYSLOG_LEVEL_NOT_SET = -1
+} LogLevel;
+
+void log_init(char *, LogLevel, SyslogFacility, int);
+
+SyslogFacility log_facility_number(char *);
+LogLevel log_level_number(char *);
+
+void fatal(const char *, ...) __dead __attribute__((format(printf, 1, 2)));
+void error(const char *, ...) __attribute__((format(printf, 1, 2)));
+void sigdie(const char *, ...) __attribute__((format(printf, 1, 2)));
+void logit(const char *, ...) __attribute__((format(printf, 1, 2)));
+void verbose(const char *, ...) __attribute__((format(printf, 1, 2)));
+void debug(const char *, ...) __attribute__((format(printf, 1, 2)));
+void debug2(const char *, ...) __attribute__((format(printf, 1, 2)));
+void debug3(const char *, ...) __attribute__((format(printf, 1, 2)));
+
+void do_log(LogLevel, const char *, va_list);
+void cleanup_exit(int) __dead;
+#endif
diff --git a/openbsd-compat/mktemp.c b/openbsd-compat/mktemp.c
new file mode 100644
index 00000000..4eb52f42
--- /dev/null
+++ b/openbsd-compat/mktemp.c
@@ -0,0 +1,141 @@
+/* THIS FILE HAS BEEN MODIFIED FROM THE ORIGINAL OPENBSD SOURCE */
+/* Changes: Removed mktemp */
+
+/* $OpenBSD: mktemp.c,v 1.30 2010/03/21 23:09:30 schwarze Exp $ */
+/*
+ * Copyright (c) 1996-1998, 2008 Theo de Raadt
+ * Copyright (c) 1997, 2008-2009 Todd C. 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.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/stdio/mktemp.c */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#if !defined(HAVE_MKDTEMP) || defined(HAVE_STRICT_MKSTEMP)
+
+#define MKTEMP_NAME 0
+#define MKTEMP_FILE 1
+#define MKTEMP_DIR 2
+
+#define TEMPCHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
+#define NUM_CHARS (sizeof(TEMPCHARS) - 1)
+
+static int
+mktemp_internal(char *path, int slen, int mode)
+{
+ char *start, *cp, *ep;
+ const char *tempchars = TEMPCHARS;
+ unsigned int r, tries;
+ struct stat sb;
+ size_t len;
+ int fd;
+
+ len = strlen(path);
+ if (len == 0 || slen < 0 || (size_t)slen >= len) {
+ errno = EINVAL;
+ return(-1);
+ }
+ ep = path + len - slen;
+
+ tries = 1;
+ for (start = ep; start > path && start[-1] == 'X'; start--) {
+ if (tries < INT_MAX / NUM_CHARS)
+ tries *= NUM_CHARS;
+ }
+ tries *= 2;
+
+ do {
+ for (cp = start; cp != ep; cp++) {
+ r = arc4random_uniform(NUM_CHARS);
+ *cp = tempchars[r];
+ }
+
+ switch (mode) {
+ case MKTEMP_NAME:
+ if (lstat(path, &sb) != 0)
+ return(errno == ENOENT ? 0 : -1);
+ break;
+ case MKTEMP_FILE:
+ fd = open(path, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR);
+ if (fd != -1 || errno != EEXIST)
+ return(fd);
+ break;
+ case MKTEMP_DIR:
+ if (mkdir(path, S_IRUSR|S_IWUSR|S_IXUSR) == 0)
+ return(0);
+ if (errno != EEXIST)
+ return(-1);
+ break;
+ }
+ } while (--tries);
+
+ errno = EEXIST;
+ return(-1);
+}
+
+#if 0
+char *_mktemp(char *);
+
+char *
+_mktemp(char *path)
+{
+ if (mktemp_internal(path, 0, MKTEMP_NAME) == -1)
+ return(NULL);
+ return(path);
+}
+
+__warn_references(mktemp,
+ "warning: mktemp() possibly used unsafely; consider using mkstemp()");
+
+char *
+mktemp(char *path)
+{
+ return(_mktemp(path));
+}
+#endif
+
+int
+mkstemp(char *path)
+{
+ return(mktemp_internal(path, 0, MKTEMP_FILE));
+}
+
+int
+mkstemps(char *path, int slen)
+{
+ return(mktemp_internal(path, slen, MKTEMP_FILE));
+}
+
+char *
+mkdtemp(char *path)
+{
+ int error;
+
+ error = mktemp_internal(path, 0, MKTEMP_DIR);
+ return(error ? NULL : path);
+}
+
+#endif /* !defined(HAVE_MKDTEMP) || defined(HAVE_STRICT_MKSTEMP) */
diff --git a/openbsd-compat/openbsd-compat.h b/openbsd-compat/openbsd-compat.h
new file mode 100644
index 00000000..2317f17e
--- /dev/null
+++ b/openbsd-compat/openbsd-compat.h
@@ -0,0 +1,204 @@
+/* $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"
+
+#ifndef AI_MASK
+/* valid flags for addrinfo */
+#define AI_MASK \
+ (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | AI_NUMERICSERV)
+#ifdef AI_FQDN
+#define AI_MASK (AI_MASK | AI_FQDN)
+#endif
+#endif
+
+#ifndef AI_FQDN
+#define AI_FQDN AI_CANONNAME
+#endif
+
+#include <sys/queue.h>
+#include <sys/tree.h>
+#include "vis.h"
+#include "xmalloc.h"
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifndef SIZE_MAX
+#include <stdint.h>
+#endif
+
+/* 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
+
+
+#ifndef HAVE_BASENAME
+char *basename(const char *path);
+#endif
+
+#ifndef HAVE_CLOSEFROM
+void closefrom(int);
+#endif
+
+#ifndef HAVE_STRLCPY
+size_t strlcpy(char *dst, const char *src, size_t size);
+#endif
+
+#ifndef HAVE_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_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
+
+#ifndef HAVE_ARC4RANDOM
+unsigned int arc4random(void);
+void arc4random_stir(void);
+#endif /* !HAVE_ARC4RANDOM */
+
+#ifndef HAVE_ARC4RANDOM_BUF
+void arc4random_buf(void *, size_t);
+#endif
+
+#ifndef HAVE_ARC4RANDOM_UNIFORM
+u_int32_t arc4random_uniform(u_int32_t);
+#endif
+
+#ifndef HAVE_STRTONUM
+long long strtonum(const char *nptr, long long minval, long long maxval, const char **errstr);
+#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
+char * fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags);
+#endif
+
+#ifndef HAVE_PIDFILE
+int pidfile(const char *basename);
+#endif
+
+#ifndef HAVE_PW_DUP
+struct passwd *pw_dup(const struct passwd *);
+#endif
+
+#ifndef HAVE_EXPLICIT_BZERO
+void explicit_bzero(void *b, size_t len);
+#endif
+
+#endif /* _OPENBSD_COMPAT_H */
diff --git a/openbsd-compat/pidfile.c b/openbsd-compat/pidfile.c
new file mode 100644
index 00000000..7af20fc6
--- /dev/null
+++ b/openbsd-compat/pidfile.c
@@ -0,0 +1,114 @@
+/* $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 <paths.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;
+ }
+
+ /* _PATH_VARRUN includes trailing / */
+ (void) asprintf(&pidfile_path, "%s%s.pid", _PATH_VARRUN, 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/setproctitle.c b/openbsd-compat/setproctitle.c
new file mode 100644
index 00000000..a69db22a
--- /dev/null
+++ b/openbsd-compat/setproctitle.c
@@ -0,0 +1,168 @@
+/* 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 <stdlib.h>
+#include <unistd.h>
+#ifdef HAVE_SYS_PSTAT_H
+#include <sys/pstat.h>
+#endif
+#include <string.h>
+
+#include <vis.h>
+
+#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(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..cdaa9e44
--- /dev/null
+++ b/openbsd-compat/setresguid.c
@@ -0,0 +1,62 @@
+/* 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"
+
+
+#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/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..f6f5665c
--- /dev/null
+++ b/openbsd-compat/vis.c
@@ -0,0 +1,225 @@
+/* $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 "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/vis.h b/openbsd-compat/vis.h
new file mode 100644
index 00000000..d1286c99
--- /dev/null
+++ b/openbsd-compat/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/xmalloc.c b/openbsd-compat/xmalloc.c
new file mode 100644
index 00000000..d4f18727
--- /dev/null
+++ b/openbsd-compat/xmalloc.c
@@ -0,0 +1,127 @@
+/* $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..da1c4cbb
--- /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/regress/config/test0.conf b/regress/config/test0.conf
index cbd2a2f1..2bad0cc2 100644
--- a/regress/config/test0.conf
+++ b/regress/config/test0.conf
@@ -1,3 +1,3 @@
-listen on lo0
+listen on localhost
accept for local deliver to mbox
diff --git a/regress/config/test1.conf b/regress/config/test1.conf
index 8983f6c8..70a658a9 100644
--- a/regress/config/test1.conf
+++ b/regress/config/test1.conf
@@ -1,4 +1,4 @@
-listen on lo0
+listen on localhost
include "include.conf"
diff --git a/regress/config/test10.conf b/regress/config/test10.conf
index b40480d6..37685b9f 100644
--- a/regress/config/test10.conf
+++ b/regress/config/test10.conf
@@ -1,4 +1,4 @@
-listen on lo0
+listen on localhost
accept from any for local deliver to mbox
accept from any for local deliver to maildir
diff --git a/regress/config/test11.conf b/regress/config/test11.conf
index 3b43f72d..5ffc385e 100644
--- a/regress/config/test11.conf
+++ b/regress/config/test11.conf
@@ -1,4 +1,4 @@
-listen on lo0
+listen on localhost
accept for any relay
accept for any relay as example
diff --git a/regress/config/test2.conf b/regress/config/test2.conf
index dc67a4e4..7c60d696 100644
--- a/regress/config/test2.conf
+++ b/regress/config/test2.conf
@@ -1,4 +1,4 @@
-listen on lo0
+listen on localhost
expire 4d
diff --git a/regress/config/test3.conf b/regress/config/test3.conf
index 8ca91bf4..6faffb18 100644
--- a/regress/config/test3.conf
+++ b/regress/config/test3.conf
@@ -1,4 +1,4 @@
-listen on lo0
+listen on localhost
hostname test.org
diff --git a/regress/config/test4.conf b/regress/config/test4.conf
index 6e5f4b04..942bb422 100644
--- a/regress/config/test4.conf
+++ b/regress/config/test4.conf
@@ -1,4 +1,4 @@
-listen on lo0 port 25
-listen on lo0 port smtp
+listen on localhost port 25
+listen on localhost port smtp
accept for local deliver to mbox
diff --git a/regress/config/test5.conf b/regress/config/test5.conf
index dc1c42ad..0e152e2b 100644
--- a/regress/config/test5.conf
+++ b/regress/config/test5.conf
@@ -1,5 +1,5 @@
-listen on lo0 port 25
-listen on lo0 port smtp
+listen on localhost port 25
+listen on localhost port smtp
table aliases_dynamic "/etc/mail/aliases"
table aliases_static { root => test }
diff --git a/regress/config/test6.conf b/regress/config/test6.conf
index a2a6ded2..05b0e00d 100644
--- a/regress/config/test6.conf
+++ b/regress/config/test6.conf
@@ -1,4 +1,4 @@
-listen on lo0
+listen on localhost
max-message-size 1G
diff --git a/regress/config/test7.conf b/regress/config/test7.conf
index 274273bd..00158b4a 100644
--- a/regress/config/test7.conf
+++ b/regress/config/test7.conf
@@ -1,4 +1,4 @@
-listen on lo0
+listen on localhost
table sources { 192.168.1.2 }
diff --git a/regress/config/test8.conf b/regress/config/test8.conf
index 9cf0c269..e91d9e93 100644
--- a/regress/config/test8.conf
+++ b/regress/config/test8.conf
@@ -1,4 +1,4 @@
-listen on lo0
+listen on localhost
table aliases "/etc/mail/aliases"
table domains { example.org, example.com }
diff --git a/regress/config/test9.conf b/regress/config/test9.conf
index 7bcb1fcb..8f2b1690 100644
--- a/regress/config/test9.conf
+++ b/regress/config/test9.conf
@@ -1,4 +1,4 @@
-listen on lo0
+listen on localhost
table vusers "/etc/mail/aliases"
table domains { example.org, example.com }
diff --git a/smtpd/aldap.c b/smtpd/aldap.c
index 3162e55c..77419d80 100644
--- a/smtpd/aldap.c
+++ b/smtpd/aldap.c
@@ -17,6 +17,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "includes.h"
+
#include <errno.h>
#include <inttypes.h>
#include <string.h>
diff --git a/smtpd/aliases.c b/smtpd/aliases.c
index b5a320e3..f3d7e13f 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>
@@ -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 "smtpd.h"
#include "log.h"
diff --git a/smtpd/backends/queue_null.c b/smtpd/backends/queue_null.c
index 3b983d13..1e507e0f 100644
--- a/smtpd/backends/queue_null.c
+++ b/smtpd/backends/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 <fcntl.h>
diff --git a/smtpd/backends/queue_ram.c b/smtpd/backends/queue_ram.c
index fa092961..2906839a 100644
--- a/smtpd/backends/queue_ram.c
+++ b/smtpd/backends/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/stat.h>
diff --git a/smtpd/backends/queue_stub.c b/smtpd/backends/queue_stub.c
index 73ad0b86..052d350f 100644
--- a/smtpd/backends/queue_stub.c
+++ b/smtpd/backends/queue_stub.c
@@ -16,6 +16,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "includes.h"
+
#include <sys/types.h>
#include <unistd.h>
diff --git a/smtpd/backends/queue_utils.c b/smtpd/backends/queue_utils.c
index 436a4903..0871e208 100644
--- a/smtpd/backends/queue_utils.c
+++ b/smtpd/backends/queue_utils.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/backends/scheduler_ram.c b/smtpd/backends/scheduler_ram.c
index 6a2094a5..b5369c81 100644
--- a/smtpd/backends/scheduler_ram.c
+++ b/smtpd/backends/scheduler_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 <err.h>
diff --git a/smtpd/backends/scheduler_stub.c b/smtpd/backends/scheduler_stub.c
index 4b23d4ee..f6aa9c2d 100644
--- a/smtpd/backends/scheduler_stub.c
+++ b/smtpd/backends/scheduler_stub.c
@@ -16,6 +16,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "includes.h"
+
#include <sys/types.h>
#include <stdlib.h>
diff --git a/smtpd/ber.c b/smtpd/ber.c
index 72722f54..60d6a01f 100644
--- a/smtpd/ber.c
+++ b/smtpd/ber.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/param.h>
diff --git a/smtpd/bounce.c b/smtpd/bounce.c
index 5850f619..fa4f9ede 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 8235e5ab..4061118b 100644
--- a/smtpd/ca.c
+++ b/smtpd/ca.c
@@ -17,10 +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 <grp.h> /* needed for setgroups */
+#include <signal.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
diff --git a/smtpd/compress_backend.c b/smtpd/compress_backend.c
index 963336cd..6eeada90 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 8f0157a4..70cfc374 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 4a25e7d1..fe671f94 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>
diff --git a/smtpd/control.c b/smtpd/control.c
index f7afeedf..3a60dc6a 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>
@@ -325,7 +328,7 @@ control_accept(int listenfd, short event, void *arg)
struct sockaddr_un sun;
struct ctl_conn *c;
- if (getdtablesize() - getdtablecount() < CONTROL_FD_RESERVE)
+ if (available_fds(CONTROL_FD_RESERVE))
goto pause;
len = sizeof(sun);
@@ -368,7 +371,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 3e820f43..60e51659 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/delivery.c b/smtpd/delivery.c
index ddaa4376..656c58bb 100644
--- a/smtpd/delivery.c
+++ b/smtpd/delivery.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/delivery_filename.c b/smtpd/delivery_filename.c
index 1ce62432..483936db 100644
--- a/smtpd/delivery_filename.c
+++ b/smtpd/delivery_filename.c
@@ -16,6 +16,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/queue.h>
#include <sys/tree.h>
@@ -69,7 +74,11 @@ delivery_filename_open(struct deliver *deliver)
error("open");
if (fstat(fd, &sb) < 0)
error("fstat");
+#ifndef HAVE_STAT_ST_FLAGS
if (S_ISREG(sb.st_mode) && flock(fd, LOCK_EX) < 0)
+#else
+ if (S_ISREG(sb.st_flags) && flock(fd, LOCK_EX) < 0)
+#endif
error("flock");
fp = fdopen(fd, "a");
if (fp == NULL)
diff --git a/smtpd/delivery_lmtp.c b/smtpd/delivery_lmtp.c
index 381d7328..f474b5d6 100644
--- a/smtpd/delivery_lmtp.c
+++ b/smtpd/delivery_lmtp.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/delivery_maildir.c b/smtpd/delivery_maildir.c
index bfeb7171..c2e4f3cf 100644
--- a/smtpd/delivery_maildir.c
+++ b/smtpd/delivery_maildir.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/delivery_mbox.c b/smtpd/delivery_mbox.c
index 19cc61e7..6e0d967d 100644
--- a/smtpd/delivery_mbox.c
+++ b/smtpd/delivery_mbox.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>
@@ -35,7 +37,9 @@
#include "smtpd.h"
#include "log.h"
+#ifndef PATH_MAILLOCAL
#define PATH_MAILLOCAL "/usr/libexec/mail.local"
+#endif
extern char **environ;
diff --git a/smtpd/delivery_mda.c b/smtpd/delivery_mda.c
index b9b02576..e8acf853 100644
--- a/smtpd/delivery_mda.c
+++ b/smtpd/delivery_mda.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/dict.c b/smtpd/dict.c
index d9182386..2d769517 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 d73acbec..fc8bce69 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>
@@ -31,6 +33,8 @@
#include <asr.h>
#include <event.h>
+#include <netdb.h>
+#include <resolv.h>
#include <imsg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -215,7 +219,7 @@ dns_imsg(struct mproc *p, struct imsg *imsg)
sa = (struct sockaddr *)&ss;
m_get_sockaddr(&m, sa);
m_end(&m);
- as = getnameinfo_async(sa, sa->sa_len, s->name, sizeof(s->name),
+ as = getnameinfo_async(sa, SA_LEN(sa), s->name, sizeof(s->name),
NULL, 0, 0, NULL);
event_asr_run(as, dns_dispatch_ptr, s);
return;
@@ -304,7 +308,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 4f436741..1f67383c 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>
diff --git a/smtpd/envelope.c b/smtpd/envelope.c
index 4bae589c..ca8739fb 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>
@@ -322,14 +324,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 32bcbfd5..bf1b8ce0 100644
--- a/smtpd/esc.c
+++ b/smtpd/esc.c
@@ -16,6 +16,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "includes.h"
+
#include <stdio.h>
#include "smtpd-defines.h"
diff --git a/smtpd/expand.c b/smtpd/expand.c
index ca8f4e2f..9479af75 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>
@@ -28,6 +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 "smtpd.h"
#include "log.h"
diff --git a/smtpd/filter.c b/smtpd/filter.c
index b68541f2..5c1b3dc1 100644
--- a/smtpd/filter.c
+++ b/smtpd/filter.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>
@@ -313,8 +315,8 @@ filter_connect(uint64_t id, const struct sockaddr *local,
q = filter_query(s, QK_QUERY, QUERY_CONNECT);
- memmove(&q->u.connect.local, local, local->sa_len);
- memmove(&q->u.connect.remote, remote, remote->sa_len);
+ 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;
diff --git a/smtpd/filter_api.c b/smtpd/filter_api.c
index 2f72c5d1..586b876d 100644
--- a/smtpd/filter_api.c
+++ b/smtpd/filter_api.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/uio.h>
@@ -977,7 +979,7 @@ filter_api_sockaddr_to_text(const 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
diff --git a/smtpd/filters/filter_dnsbl.c b/smtpd/filters/filter_dnsbl.c
index 3fb7c678..7e6ce067 100644
--- a/smtpd/filters/filter_dnsbl.c
+++ b/smtpd/filters/filter_dnsbl.c
@@ -15,6 +15,8 @@
* 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/filters/filter_monkey.c b/smtpd/filters/filter_monkey.c
index 2ead57b4..9a7fa2b4 100644
--- a/smtpd/filters/filter_monkey.c
+++ b/smtpd/filters/filter_monkey.c
@@ -16,6 +16,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "includes.h"
+
#include <sys/types.h>
#include <inttypes.h>
diff --git a/smtpd/filters/filter_stub.c b/smtpd/filters/filter_stub.c
index a089ad37..2b36aeeb 100644
--- a/smtpd/filters/filter_stub.c
+++ b/smtpd/filters/filter_stub.c
@@ -15,6 +15,8 @@
* 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>
diff --git a/smtpd/filters/filter_trace.c b/smtpd/filters/filter_trace.c
index 1ab88758..9c0dc25b 100644
--- a/smtpd/filters/filter_trace.c
+++ b/smtpd/filters/filter_trace.c
@@ -16,6 +16,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "includes.h"
+
#include <sys/types.h>
#include <inttypes.h>
diff --git a/smtpd/forward.c b/smtpd/forward.c
index 2a99ca59..c963dea6 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 "smtpd.h"
diff --git a/smtpd/iobuf.c b/smtpd/iobuf.c
index 7dcd45b9..d92f7722 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 c1d6736c..b39848b6 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>
@@ -599,10 +601,10 @@ io_connect(struct io *io, const struct sockaddr *sa, const struct sockaddr *bsa)
io_set_blocking(sock, 0);
io_set_linger(sock, 0);
- 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/limit.c b/smtpd/limit.c
index 1e80d81e..5461e699 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 72f99dc6..a8671a19 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_session.c b/smtpd/lka_session.c
index 659f106c..d4f259f9 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>
diff --git a/smtpd/log.c b/smtpd/log.c
index 3d5ebdf4..e1ca5e95 100644
--- a/smtpd/log.c
+++ b/smtpd/log.c
@@ -16,6 +16,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/tree.h>
diff --git a/smtpd/log.h b/smtpd/log.h
index 9581df62..ab71cf8c 100644
--- a/smtpd/log.h
+++ b/smtpd/log.h
@@ -16,6 +16,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "openbsd-compat.h"
+
void log_init(int);
void log_verbose(int);
void log_warn(const char *, ...)
diff --git a/smtpd/makemap.c b/smtpd/makemap.c
index b66355c2..18189033 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>
@@ -34,12 +45,17 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.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"
extern char *__progname;
@@ -183,7 +199,16 @@ main(int argc, char *argv[])
err(1, "mkstemp");
umask(omode);
- db = dbopen(dbname, O_EXLOCK|O_RDWR|O_SYNC, 0644, dbtype, NULL);
+/* XXX */
+#ifndef O_EXLOCK
+#define O_EXLOCK 0
+#endif
+ /* Depending on the Linux distrib, sometimes dbopen() flags
+ * O_SYNC must be avoid, and O_TRUNC have to be used
+ * XXX: it should be properly checked and handled in configure script */
+
+ /* db = dbopen(dbname, O_EXLOCK|O_RDWR|O_SYNC, 0644, dbtype, NULL); */
+ db = dbopen(dbname, O_EXLOCK|O_RDWR|O_TRUNC, 0644, dbtype, NULL);
if (db == NULL) {
warn("dbopen: %s", dbname);
goto bad;
diff --git a/smtpd/mda.c b/smtpd/mda.c
index 052a9b87..253c4f3b 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>
@@ -37,7 +40,9 @@
#include <string.h>
#include <time.h>
#include <unistd.h>
+#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H)
#include <vis.h>
+#endif
#include "smtpd.h"
#include "log.h"
diff --git a/smtpd/mfa.c b/smtpd/mfa.c
new file mode 100644
index 00000000..34654990
--- /dev/null
+++ b/smtpd/mfa.c
@@ -0,0 +1,429 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
+ * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@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/wait.h>
+#include <sys/queue.h>
+#include <sys/tree.h>
+#include <sys/socket.h>
+
+#include <err.h>
+#include <errno.h>
+#include <event.h>
+#include <grp.h> /* needed for setgroups */
+#include <imsg.h>
+#include <inttypes.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "smtpd.h"
+#include "log.h"
+
+struct mfa_tx {
+ uint64_t reqid;
+ struct io io;
+ struct iobuf iobuf;
+ FILE *ofile;
+ size_t datain;
+ size_t datalen;
+ int eom;
+ int error;
+};
+
+static void mfa_imsg(struct mproc *, struct imsg *);
+static void mfa_shutdown(void);
+static void mfa_sig_handler(int, short, void *);
+static void mfa_tx_io(struct io *, int);
+static int mfa_tx(uint64_t, int);
+static void mfa_tx_done(struct mfa_tx *);
+
+struct tree tx_tree;
+
+static void
+mfa_imsg(struct mproc *p, struct imsg *imsg)
+{
+ struct sockaddr_storage local, remote;
+ struct mailaddr maddr;
+ struct msg m;
+ const char *line, *hostname;
+ uint64_t reqid;
+ uint32_t datalen; /* XXX make it off_t? */
+ int v, success, fdout;
+
+ if (p->proc == PROC_PONY) {
+ switch (imsg->hdr.type) {
+ case IMSG_SMTP_REQ_CONNECT:
+ m_msg(&m, imsg);
+ m_get_id(&m, &reqid);
+ m_get_sockaddr(&m, (struct sockaddr *)&local);
+ m_get_sockaddr(&m, (struct sockaddr *)&remote);
+ m_get_string(&m, &hostname);
+ m_end(&m);
+ mfa_filter_event(reqid, EVENT_CONNECT);
+ mfa_filter_connect(reqid, (struct sockaddr *)&local,
+ (struct sockaddr *)&remote, hostname);
+ return;
+
+ case IMSG_SMTP_REQ_HELO:
+ m_msg(&m, imsg);
+ m_get_id(&m, &reqid);
+ m_get_string(&m, &line);
+ m_end(&m);
+ mfa_filter_line(reqid, QUERY_HELO, line);
+ return;
+
+ case IMSG_SMTP_REQ_MAIL:
+ m_msg(&m, imsg);
+ m_get_id(&m, &reqid);
+ m_get_mailaddr(&m, &maddr);
+ m_end(&m);
+ mfa_filter_mailaddr(reqid, QUERY_MAIL, &maddr);
+ return;
+
+ case IMSG_SMTP_REQ_RCPT:
+ m_msg(&m, imsg);
+ m_get_id(&m, &reqid);
+ m_get_mailaddr(&m, &maddr);
+ m_end(&m);
+ mfa_filter_mailaddr(reqid, QUERY_RCPT, &maddr);
+ return;
+
+ case IMSG_SMTP_REQ_DATA:
+ m_msg(&m, imsg);
+ m_get_id(&m, &reqid);
+ m_end(&m);
+ mfa_filter(reqid, QUERY_DATA);
+ return;
+
+ case IMSG_SMTP_REQ_EOM:
+ m_msg(&m, imsg);
+ m_get_id(&m, &reqid);
+ m_get_u32(&m, &datalen);
+ m_end(&m);
+ mfa_filter_eom(reqid, QUERY_EOM, datalen);
+ return;
+
+ case IMSG_SMTP_EVENT_RSET:
+ m_msg(&m, imsg);
+ m_get_id(&m, &reqid);
+ m_end(&m);
+ mfa_filter_event(reqid, EVENT_RESET);
+ return;
+
+ case IMSG_SMTP_EVENT_COMMIT:
+ m_msg(&m, imsg);
+ m_get_id(&m, &reqid);
+ m_end(&m);
+ mfa_filter_event(reqid, EVENT_COMMIT);
+ return;
+
+ case IMSG_SMTP_EVENT_ROLLBACK:
+ m_msg(&m, imsg);
+ m_get_id(&m, &reqid);
+ m_end(&m);
+ mfa_filter_event(reqid, EVENT_ROLLBACK);
+ return;
+
+ case IMSG_SMTP_EVENT_DISCONNECT:
+ m_msg(&m, imsg);
+ m_get_id(&m, &reqid);
+ m_end(&m);
+ mfa_filter_event(reqid, EVENT_DISCONNECT);
+ return;
+ }
+ }
+
+ if (p->proc == PROC_QUEUE) {
+ switch (imsg->hdr.type) {
+ case IMSG_QUEUE_MESSAGE_FILE:
+ m_msg(&m, imsg);
+ m_get_id(&m, &reqid);
+ m_get_int(&m, &success);
+ m_end(&m);
+
+ fdout = mfa_tx(reqid, imsg->fd);
+ mfa_build_fd_chain(reqid, fdout);
+ return;
+ }
+ }
+
+ if (p->proc == PROC_PARENT) {
+ switch (imsg->hdr.type) {
+ case IMSG_CONF_START:
+ return;
+
+ case IMSG_CONF_FILTER:
+ return;
+
+ case IMSG_CONF_END:
+ mfa_filter_init();
+ return;
+
+ case IMSG_CTL_VERBOSE:
+ m_msg(&m, imsg);
+ m_get_int(&m, &v);
+ m_end(&m);
+ log_verbose(v);
+ return;
+
+ case IMSG_CTL_PROFILE:
+ m_msg(&m, imsg);
+ m_get_int(&m, &v);
+ m_end(&m);
+ profiling = v;
+ return;
+ }
+ }
+
+ errx(1, "mfa_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type));
+}
+
+static void
+mfa_sig_handler(int sig, short event, void *p)
+{
+ switch (sig) {
+ case SIGINT:
+ case SIGTERM:
+ mfa_shutdown();
+ break;
+
+ case SIGCHLD:
+ fatalx("unexpected SIGCHLD");
+ break;
+
+ default:
+ fatalx("mfa_sig_handler: unexpected signal");
+ }
+}
+
+static void
+mfa_shutdown(void)
+{
+ pid_t pid;
+
+ do {
+ pid = waitpid(WAIT_MYPGRP, NULL, 0);
+ } while (pid != -1 || (pid == -1 && errno == EINTR));
+
+ log_info("info: mail filter exiting");
+ _exit(0);
+}
+
+pid_t
+mfa(void)
+{
+ pid_t pid;
+ struct passwd *pw;
+ struct event ev_sigint;
+ struct event ev_sigterm;
+ struct event ev_sigchld;
+
+ switch (pid = fork()) {
+ case -1:
+ fatal("filter: cannot fork");
+ case 0:
+ post_fork(PROC_MFA);
+ break;
+ default:
+ return (pid);
+ }
+
+ mfa_filter_prepare();
+
+ purge_config(PURGE_EVERYTHING);
+
+ if ((pw = getpwnam(SMTPD_USER)) == NULL)
+ fatalx("unknown user " SMTPD_USER);
+
+ config_process(PROC_MFA);
+
+ if (chroot(PATH_CHROOT) == -1)
+ fatal("scheduler: chroot");
+ if (chdir("/") == -1)
+ fatal("scheduler: chdir(\"/\")");
+
+ if (setgroups(1, &pw->pw_gid) ||
+ setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
+ setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
+ fatal("filter: cannot drop privileges");
+
+ imsg_callback = mfa_imsg;
+ event_init();
+
+ tree_init(&tx_tree);
+
+ signal_set(&ev_sigint, SIGINT, mfa_sig_handler, NULL);
+ signal_set(&ev_sigterm, SIGTERM, mfa_sig_handler, NULL);
+ signal_set(&ev_sigchld, SIGCHLD, mfa_sig_handler, NULL);
+ signal_add(&ev_sigint, NULL);
+ signal_add(&ev_sigterm, NULL);
+ signal_add(&ev_sigchld, NULL);
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+
+ config_peer(PROC_PARENT);
+ config_peer(PROC_QUEUE);
+ config_peer(PROC_CONTROL);
+ config_peer(PROC_PONY);
+ config_done();
+
+ mproc_disable(p_pony);
+
+ if (event_dispatch() < 0)
+ fatal("event_dispatch");
+ mfa_shutdown();
+
+ return (0);
+}
+
+void
+mfa_ready(void)
+{
+ log_debug("debug: mfa ready");
+ mproc_enable(p_pony);
+}
+
+static int
+mfa_tx(uint64_t reqid, int fdout)
+{
+ struct mfa_tx *tx;
+ int sp[2];
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sp) == -1) {
+ log_warn("warn: mfa: socketpair");
+ return (-1);
+ }
+
+ tx = xcalloc(1, sizeof(*tx), "mfa_tx");
+
+ if ((tx->ofile = fdopen(fdout, "w")) == NULL) {
+ log_warn("warn: mfa: fdopen");
+ free(tx);
+ close(sp[0]);
+ close(sp[1]);
+ return (-1);
+ }
+
+ iobuf_init(&tx->iobuf, 0, 0);
+ io_init(&tx->io, sp[0], tx, mfa_tx_io, &tx->iobuf);
+ io_set_read(&tx->io);
+ tx->reqid = reqid;
+ tree_xset(&tx_tree, reqid, tx);
+
+ return (sp[1]);
+}
+
+static void
+mfa_tx_io(struct io *io, int evt)
+{
+ struct mfa_tx *tx = io->arg;
+ size_t len, n;
+ char *data;
+
+ switch (evt) {
+ case IO_DATAIN:
+ data = iobuf_data(&tx->iobuf);
+ len = iobuf_len(&tx->iobuf);
+ log_debug("debug: mfa: tx data (%zu) for req %016"PRIx64,
+ len, tx->reqid);
+ n = fwrite(data, 1, len, tx->ofile);
+ if (n != len) {
+ tx->error = 1;
+ break;
+ }
+ tx->datain += n;
+ iobuf_drop(&tx->iobuf, n);
+ iobuf_normalize(&tx->iobuf);
+ return;
+
+ case IO_DISCONNECTED:
+ log_debug("debug: mfa: tx done for req %016"PRIx64,
+ tx->reqid);
+ break;
+
+ default:
+ log_debug("debug: mfa: tx error for req %016"PRIx64,
+ tx->reqid);
+ tx->error = 1;
+ break;
+ }
+
+ io_clear(&tx->io);
+ iobuf_clear(&tx->iobuf);
+ fclose(tx->ofile);
+ tx->ofile = NULL;
+ if (tx->eom)
+ mfa_tx_done(tx);
+}
+
+static void
+mfa_tx_done(struct mfa_tx *tx)
+{
+ log_debug("debug: mfa: tx done for %016"PRIx64, tx->reqid);
+
+ tree_xpop(&tx_tree, tx->reqid);
+
+ if (!tx->error && tx->datain != tx->datalen) {
+ log_debug("debug: mfa: tx datalen mismatch: %zu/%zu",
+ tx->datain, tx->datalen);
+ tx->error = 1;
+ }
+
+ if (tx->error) {
+ log_debug("debug: mfa: tx error");
+
+ m_create(p_pony, IMSG_MFA_SMTP_RESPONSE, 0, 0, -1);
+ m_add_id(p_pony, tx->reqid);
+ m_add_int(p_pony, MFA_FAIL);
+ m_add_u32(p_pony, 0);
+ m_add_string(p_pony, "Internal server error");
+ m_close(p_pony);
+ }
+ else {
+ /* XXX we could send the commit message here directly */
+ m_create(p_pony, IMSG_MFA_SMTP_RESPONSE, 0, 0, -1);
+ m_add_id(p_pony, tx->reqid);
+ m_add_int(p_pony, MFA_OK);
+ m_add_u32(p_pony, 300);
+ m_add_string(p_pony, "This is not to be sent to the client");
+ m_close(p_pony);
+ }
+
+ free(tx);
+}
+
+void
+mfa_report_eom(uint64_t reqid, size_t size)
+{
+ struct mfa_tx *tx;
+
+ tx = tree_xget(&tx_tree, reqid);
+
+ tx->datalen = size;
+ tx->eom = 1;
+
+ if (tx->ofile == NULL)
+ mfa_tx_done(tx);
+}
diff --git a/smtpd/mproc.c b/smtpd/mproc.c
index 29c01339..a2760093 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>
@@ -59,8 +61,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);
@@ -592,7 +593,7 @@ m_add_msgid(struct mproc *m, uint32_t v)
void
m_add_sockaddr(struct mproc *m, const struct sockaddr *sa)
{
- m_add_typed_sized(m, M_SOCKADDR, sa, sa->sa_len);
+ m_add_typed_sized(m, M_SOCKADDR, sa, SA_LEN(sa));
}
void
diff --git a/smtpd/mta.c b/smtpd/mta.c
index 55e9e46c..12f232c8 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 <pwd.h>
#include <signal.h>
#include <stdio.h>
@@ -1972,13 +1975,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), "mta_host");
- h->sa = xmemdup(sa, sa->sa_len, "mta_host");
+ h->sa = xmemdup(sa, SA_LEN(sa), "mta_host");
SPLAY_INSERT(mta_host_tree, &hosts, h);
stat_increment("mta.host", 1);
}
@@ -2023,11 +2026,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);
@@ -2101,7 +2104,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;
@@ -2110,7 +2113,7 @@ mta_source(const struct sockaddr *sa)
if (s == NULL) {
s = xcalloc(1, sizeof(*s), "mta_source");
if (sa)
- s->sa = xmemdup(sa, sa->sa_len, "mta_source");
+ s->sa = xmemdup(sa, SA_LEN(sa), "mta_source");
SPLAY_INSERT(mta_source_tree, &sources, s);
stat_increment("mta.source", 1);
}
@@ -2155,11 +2158,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 6bef456b..2b7b33f2 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>
@@ -541,7 +543,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 d47a840d..5ccb3ed2 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,12 +46,15 @@
#include <netdb.h>
#include <paths.h>
#include <pwd.h>
+#include <stdarg.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>
@@ -1828,7 +1834,9 @@ host_v4(const char *s, in_port_t port)
h = xcalloc(1, sizeof(*h), "host_v4");
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 = port;
@@ -1849,7 +1857,9 @@ host_v6(const char *s, in_port_t port)
h = xcalloc(1, sizeof(*h), "host_v6");
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 = port;
memcpy(&sin6->sin6_addr, &ina6, sizeof(ina6));
@@ -1887,13 +1897,17 @@ host_dns(struct listenerlist *al, 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;
} 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;
@@ -1956,14 +1970,18 @@ interface(struct listenerlist *al, 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;
break;
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;
break;
@@ -2023,7 +2041,9 @@ set_localaddrs(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));
@@ -2033,7 +2053,9 @@ set_localaddrs(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));
@@ -2096,6 +2118,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;
@@ -2133,6 +2156,9 @@ is_if_in_group(const char *ifname, const char *groupname)
end:
close(s);
return ret;
+#else
+ return (0);
+#endif
}
struct filter_conf *
diff --git a/smtpd/parser.c b/smtpd/parser.c
index ca67be5b..5e854e06 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>
@@ -295,7 +297,9 @@ text_to_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);
@@ -318,7 +322,9 @@ text_to_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;
@@ -327,7 +333,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 ((sin6->sin6_scope_id = if_nametoindex(cp)))
return (0);
diff --git a/smtpd/pony.c b/smtpd/pony.c
index b45e79f2..42ebe73b 100644
--- a/smtpd/pony.c
+++ b/smtpd/pony.c
@@ -25,6 +25,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/queue.c b/smtpd/queue.c
index 5f68ad86..8791fcd1 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 <libgen.h>
@@ -603,11 +607,13 @@ queue(void)
if (env->sc_queue_flags & QUEUE_COMPRESSION)
log_info("queue: queue compression enabled");
+#ifdef HAVE_GCM_CRYPTO
if (env->sc_queue_key) {
if (! crypto_setup(env->sc_queue_key, strlen(env->sc_queue_key)))
fatalx("crypto_setup: invalid key for queue encryption");
log_info("queue: queue encryption enabled");
}
+#endif
if (setgroups(1, &pw->pw_gid) ||
setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
diff --git a/smtpd/queue_api.c b/smtpd/queue_api.c
index 5c42537d..c3c2f7e5 100644
--- a/smtpd/queue_api.c
+++ b/smtpd/queue_api.c
@@ -16,12 +16,15 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "includes.h"
+
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/uio.h>
#include <imsg.h>
#include <pwd.h>
+#include <grp.h> /* needed for setgroups */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/smtpd/queue_backend.c b/smtpd/queue_backend.c
index 1b76b64b..c9e0a84f 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>
@@ -227,6 +229,7 @@ queue_message_commit(uint32_t msgid)
}
}
+#ifdef HAVE_GCM_CRYPTO
if (env->sc_queue_flags & QUEUE_ENCRYPTION) {
bsnprintf(tmppath, sizeof tmppath, "%s.enc", msgpath);
ifp = fopen(msgpath, "r");
@@ -248,6 +251,7 @@ queue_message_commit(uint32_t msgid)
return (0);
}
}
+#endif
r = handler_message_commit(msgid, msgpath);
profile_leave();
@@ -301,6 +305,7 @@ queue_message_fd_r(uint32_t msgid)
if (fdin == -1)
return (-1);
+#ifdef HAVE_GCM_CRYPTO
if (env->sc_queue_flags & QUEUE_ENCRYPTION) {
if ((fdout = mktmpfile()) == -1)
goto err;
@@ -322,6 +327,7 @@ queue_message_fd_r(uint32_t msgid)
ofp = NULL;
lseek(fdin, SEEK_SET, 0);
}
+#endif
if (env->sc_queue_flags & QUEUE_COMPRESSION) {
if ((fdout = mktmpfile()) == -1)
@@ -378,8 +384,10 @@ queue_envelope_dump_buffer(struct envelope *ep, char *evpbuf, size_t evpbufsize)
size_t evplen;
size_t complen;
char compbuf[sizeof(struct envelope)];
+#ifdef HAVE_GCM_CRYPTO
size_t enclen;
char encbuf[sizeof(struct envelope)];
+#endif
evp = evpbuf;
evplen = envelope_dump_buffer(ep, evpbuf, evpbufsize);
@@ -394,6 +402,7 @@ queue_envelope_dump_buffer(struct envelope *ep, char *evpbuf, size_t evpbufsize)
evplen = complen;
}
+#ifdef HAVE_GCM_CRYPTO
if (env->sc_queue_flags & QUEUE_ENCRYPTION) {
enclen = crypto_encrypt_buffer(evp, evplen, encbuf, sizeof encbuf);
if (enclen == 0)
@@ -401,6 +410,7 @@ queue_envelope_dump_buffer(struct envelope *ep, char *evpbuf, size_t evpbufsize)
evp = encbuf;
evplen = enclen;
}
+#endif
memmove(evpbuf, evp, evplen);
@@ -414,12 +424,15 @@ queue_envelope_load_buffer(struct envelope *ep, char *evpbuf, size_t evpbufsize)
size_t evplen;
char compbuf[sizeof(struct envelope)];
size_t complen;
+#ifdef HAVE_GCM_CRYPTO
char encbuf[sizeof(struct envelope)];
size_t enclen;
+#endif
evp = evpbuf;
evplen = evpbufsize;
+#ifdef HAVE_GCM_CRYPTO
if (env->sc_queue_flags & QUEUE_ENCRYPTION) {
enclen = crypto_decrypt_buffer(evp, evplen, encbuf, sizeof encbuf);
if (enclen == 0)
@@ -427,6 +440,7 @@ queue_envelope_load_buffer(struct envelope *ep, char *evpbuf, size_t evpbufsize)
evp = encbuf;
evplen = enclen;
}
+#endif
if (env->sc_queue_flags & QUEUE_COMPRESSION) {
complen = uncompress_chunk(evp, evplen, compbuf, sizeof compbuf);
diff --git a/smtpd/queue_fs.c b/smtpd/queue_fs.c
index 6bca2489..8cdcea30 100644
--- a/smtpd/queue_fs.c
+++ b/smtpd/queue_fs.c
@@ -16,13 +16,20 @@
* 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/stat.h>
+#ifdef HAVE_SYS_STATFS_H
+#include <sys/statfs.h>
+#endif
#include <sys/param.h>
+#if HAVE_SYS_MOUNT_H
#include <sys/mount.h>
+#endif
#include <ctype.h>
#include <err.h>
@@ -413,7 +420,11 @@ fsqueue_check_space(void)
}
used = buf.f_files - buf.f_ffree;
+#ifdef HAVE_STRUCT_STATFS_F_FAVAIL
total = buf.f_favail + used;
+#else
+ total = buf.f_files;
+#endif
if (total != 0)
used = (float)used / (float)total * 100;
else
@@ -596,7 +607,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 e51cabb4..dd914cc6 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 df9e5623..7e6f4539 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>
@@ -324,8 +326,7 @@ queue_proc_init(struct passwd *pw, int server)
if (pid == 0) {
/* child process */
dup2(sp[0], STDIN_FILENO);
- if (closefrom(STDERR_FILENO + 1) < 0)
- exit(1);
+ closefrom(STDERR_FILENO + 1);
execl(execpath, "queue_ramproc", NULL);
err(1, "execl");
diff --git a/smtpd/queue_ram.c b/smtpd/queue_ram.c
index db9f14de..6b8a0675 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/ruleset.c b/smtpd/ruleset.c
index 4e2fe128..1a4b4b0e 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 82241bf6..5d2d962e 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/queue.h>
#include <sys/tree.h>
diff --git a/smtpd/scheduler.c b/smtpd/scheduler.c
index bb72b8fa..4aeb41a0 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 <libgen.h>
diff --git a/smtpd/scheduler_api.c b/smtpd/scheduler_api.c
index 808a207c..668d30a3 100644
--- a/smtpd/scheduler_api.c
+++ b/smtpd/scheduler_api.c
@@ -16,12 +16,15 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "includes.h"
+
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/uio.h>
#include <imsg.h>
#include <pwd.h>
+#include <grp.h> /* needed for setgroups */
#include <string.h>
#include <unistd.h>
diff --git a/smtpd/scheduler_backend.c b/smtpd/scheduler_backend.c
index 7d8dbca6..1be11b51 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 d6e6d895..dea51d22 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 ffb125ba..bcd6521b 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>
@@ -132,8 +134,7 @@ scheduler_proc_init(void)
if (pid == 0) {
/* child process */
dup2(sp[0], STDIN_FILENO);
- if (closefrom(STDERR_FILENO + 1) < 0)
- exit(1);
+ closefrom(STDERR_FILENO + 1);
execl(execpath, "scheduler-proc", NULL);
err(1, "execl");
diff --git a/smtpd/scheduler_ramqueue.c b/smtpd/scheduler_ramqueue.c
index fad0ce74..daa323f8 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 2f0cc29f..a21cae95 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>
@@ -142,10 +145,16 @@ 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
+ if (bind(l->fd, (struct sockaddr *)&l->ss, SS_LEN(&l->ss)) == -1)
fatal("smtpd: bind");
}
}
@@ -182,8 +191,10 @@ smtp_setup_events(void)
purge_config(PURGE_PKI_KEYS);
+ /* XXX chl */
log_debug("debug: smtp: will accept at most %d clients",
- (getdtablesize() - getdtablecount())/2 - SMTP_FD_RESERVE);
+ /* (getdtablesize() - getdtablecount())/2 - SMTP_FD_RESERVE); */
+ (getdtablesize() - 42)/2 - SMTP_FD_RESERVE);
}
static void
@@ -221,7 +232,9 @@ smtp_enqueue(uid_t *euid)
listener = &local;
(void)strlcpy(listener->tag, "local", sizeof(listener->tag));
listener->ss.ss_family = AF_LOCAL;
+#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
listener->ss.ss_len = sizeof(struct sockaddr *);
+#endif
(void)strlcpy(listener->hostname, "localhost",
sizeof(listener->hostname));
}
@@ -315,7 +328,9 @@ smtp_can_accept(void)
{
size_t max;
- max = (getdtablesize() - getdtablecount()) / 2 - SMTP_FD_RESERVE;
+ /* XXX chl */
+ /* max = (getdtablesize() - getdtablecount()) / 2 - SMTP_FD_RESERVE; */
+ max = (getdtablesize() - 42)/2 - SMTP_FD_RESERVE;
return (sessions < max);
}
diff --git a/smtpd/smtp_session.c b/smtpd/smtp_session.c
index fc4f854d..e3de946b 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>
@@ -181,7 +183,9 @@ static int smtp_verify_certificate(struct smtp_session *);
static uint8_t dsn_notify_str_to_uint8(const char *);
static void smtp_auth_failure_pause(struct smtp_session *);
static void smtp_auth_failure_resume(int, short, void *);
+#if defined(HAVE_TLSEXT_SERVERNAME)
static int smtp_sni_callback(SSL *, int *, void *);
+#endif
static void smtp_filter_connect(struct smtp_session *, struct sockaddr *);
static void smtp_filter_rset(struct smtp_session *);
@@ -310,6 +314,7 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg)
uint32_t msgid;
int status, success, dnserror;
void *ssl_ctx;
+ void *sni = NULL;
switch (imsg->hdr.type) {
case IMSG_SMTP_DNS_PTR:
@@ -559,7 +564,12 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg)
pkiname = s->smtpname;
ssl_ctx = dict_get(env->sc_ssl_dict, pkiname);
+#if defined(HAVE_TLSEXT_SERVERNAME)
+ sni = smtp_sni_callback;
+#endif
+
ssl = ssl_smtp_init(ssl_ctx, smtp_sni_callback, s);
+
io_set_read(&s->io);
io_start_tls(&s->io, ssl);
@@ -1933,6 +1943,7 @@ smtp_auth_failure_pause(struct smtp_session *s)
evtimer_add(&s->pause, &tv);
}
+#if defined(HAVE_TLSEXT_SERVERNAME)
static int
smtp_sni_callback(SSL *ssl, int *ad, void *arg)
{
@@ -1956,6 +1967,7 @@ smtp_sni_callback(SSL *ssl, int *ad, void *arg)
SSL_set_SSL_CTX(ssl, ssl_ctx);
return SSL_TLSEXT_ERR_OK;
}
+#endif
static void
smtp_filter_rset(struct smtp_session *s)
diff --git a/smtpd/smtpctl.c b/smtpd/smtpctl.c
index 98f9c96c..fd9d2387 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>
@@ -28,6 +30,12 @@
#include <sys/un.h>
#include <sys/wait.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>
@@ -45,10 +53,14 @@
#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
int srv_connect(void);
@@ -1073,7 +1085,9 @@ static void
display(const char *s)
{
FILE *fp;
+#ifdef HAVE_GCM_CRYPTO
char *key;
+#endif
int gzipped;
char *gzcat_argv0 = strrchr(PATH_GZCAT, '/') + 1;
@@ -1081,6 +1095,7 @@ display(const char *s)
err(1, "fopen");
if (is_encrypted_fp(fp)) {
+#ifdef HAVE_GCM_CRYPTO
int i;
int fd;
FILE *ofp;
@@ -1112,6 +1127,10 @@ display(const char *s)
fclose(fp);
fp = ofp;
fseek(fp, 0, SEEK_SET);
+#else
+ printf("GCM crypto not supported!\n");
+ exit(1);
+#endif
}
gzipped = is_gzip_fp(fp);
diff --git a/smtpd/smtpd-defines.h b/smtpd/smtpd-defines.h
index 6302d13b..c276627d 100644
--- a/smtpd/smtpd-defines.h
+++ b/smtpd/smtpd-defines.h
@@ -28,9 +28,18 @@
#define SMTPD_MAXHOSTNAMELEN 256
#define SMTPD_MAXLINESIZE 2048
+#ifndef SMTPD_USER
#define SMTPD_USER "_smtpd"
+#endif
+#ifndef PATH_CHROOT
#define PATH_CHROOT "/var/empty"
-#define SMTPD_QUEUE_USER "_smtpq"
+#endif
+#ifndef SMTPD_QUEUE_USER
+#define SMTPD_QUEUE_USER "_smtpq"
+#endif
+#ifndef PATH_SPOOL
#define PATH_SPOOL "/var/spool/smtpd"
+#endif
#define TAG_CHAR '+' /* gilles+tag@ */
+
diff --git a/smtpd/smtpd.c b/smtpd/smtpd.c
index 4a5e77e3..0df4d066 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,24 +30,46 @@
#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 <imsg.h>
#include <inttypes.h>
+#ifdef HAVE_LOGIN_CAP_H
#include <login_cap.h>
+#endif
#include <paths.h>
#include <pwd.h>
#include <signal.h>
+#ifdef HAVE_SHADOW_H
+#include <shadow.h> /* needed for getspnam() */
+#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
+#ifdef HAVE_UTIL_H
#include <util.h>
+#endif
#include <openssl/ssl.h>
#include <openssl/evp.h>
@@ -53,6 +78,8 @@
#include "log.h"
#include "ssl.h"
+extern char *__progname;
+
static void parent_imsg(struct mproc *, struct imsg *);
static void usage(void);
static void parent_shutdown(int);
@@ -137,6 +164,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)
{
@@ -465,6 +496,21 @@ main(int argc, char *argv[])
struct event ev_sighup;
struct timeval tv;
+ __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
+
env = &smtpd;
flags = 0;
@@ -586,6 +632,8 @@ main(int argc, char *argv[])
if (parse_config(&smtpd, conffile, opts))
exit(1);
+ seed_rng();
+
if (strlcpy(env->sc_conffile, conffile, SMTPD_MAXPATHLEN)
>= SMTPD_MAXPATHLEN)
errx(1, "config file exceeds SMTPD_MAXPATHLEN");
@@ -680,6 +728,7 @@ main(int argc, char *argv[])
if (pidfile(NULL) < 0)
err(1, "pidfile");
+ log_debug("libevent %s (%s)", event_get_version(), event_get_method());
purge_task();
if (event_dispatch() < 0)
@@ -920,8 +969,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 ||
@@ -1013,10 +1061,12 @@ offline_enqueue(char *name)
_exit(1);
}
+#ifdef HAVE_CHFLAGS
if (chflags(path, 0) == -1) {
log_warn("warn: smtpd: chflags: %s", path);
_exit(1);
}
+#endif
pw = getpwuid(sb.st_uid);
if (pw == NULL) {
@@ -1033,10 +1083,11 @@ offline_enqueue(char *name)
if (setgroups(1, &pw->pw_gid) ||
setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
- setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) ||
- closefrom(STDERR_FILENO + 1) == -1)
+ setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
_exit(1);
+ closefrom(STDERR_FILENO + 1);
+
if ((fp = fopen(path, "r")) == NULL)
_exit(1);
@@ -1426,8 +1477,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[SMTPD_MAXLOGNAME];
char pass[SMTPD_MAXLINESIZE];
@@ -1441,6 +1493,116 @@ 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;
+
+ errno = 0;
+ do {
+ pw = getspnam(username);
+ } while (pw == NULL && errno == EINTR);
+
+ if (pw == NULL) {
+ if (errno)
+ return LKA_TEMPFAIL;
+ return LKA_PERMFAIL;
+ }
+
+ if (strcmp(pw->sp_pwdp, crypt(password, pw->sp_pwdp)) == 0)
+ return LKA_OK;
+
+ return LKA_PERMFAIL;
+}
+#endif
+
+int
+parent_auth_pwd(const char *username, const char *password)
+{
+ struct passwd *pw;
+
+ errno = 0;
+ do {
+ pw = getpwnam(username);
+ } while (pw == NULL && errno == EINTR);
+
+ if (pw == NULL) {
+ if (errno)
+ return LKA_TEMPFAIL;
+ return LKA_PERMFAIL;
+ }
+
+ if (strcmp(pw->pw_passwd, crypt(password, pw->pw_passwd)) == 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
+}
static void
parent_broadcast_verbose(uint32_t v)
diff --git a/smtpd/smtpd.conf b/smtpd/smtpd.conf
new file mode 100644
index 00000000..f47c962e
--- /dev/null
+++ b/smtpd/smtpd.conf
@@ -0,0 +1,14 @@
+# This is the smtpd server system-wide configuration file.
+# See smtpd.conf(5) for more information.
+
+# To accept external mail, replace with: listen on all
+listen on localhost
+
+# If you edit the file, you have to run "smtpctl update table aliases"
+table aliases file:/etc/mail/aliases
+
+# Uncomment the following to accept external mail for domain "example.org"
+#accept from any for domain "example.org" alias <aliases> deliver to mbox
+
+accept for local alias <aliases> deliver to mbox
+accept for any relay
diff --git a/smtpd/smtpd.conf.5 b/smtpd/smtpd.conf.5
index d4b2e92f..e575437b 100644
--- a/smtpd/smtpd.conf.5
+++ b/smtpd/smtpd.conf.5
@@ -901,9 +901,7 @@ Spool directories for mail during processing.
.Sh EXAMPLES
The default
.Nm
-file which ships with
-.Ox
-listens on the loopback network interface (lo0),
+file listens on the loopback network interface (lo0),
and allows for mail from users and daemons on the local machine,
as well as permitting email to remote servers.
Some more complex configurations are given below.
diff --git a/smtpd/smtpd.h b/smtpd/smtpd.h
index d3fe3218..79677afb 100644
--- a/smtpd/smtpd.h
+++ b/smtpd/smtpd.h
@@ -18,6 +18,16 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#if LIBEVENT_MAJOR_VERSION < 2
+#include <event.h>
+#else
+#include <event2/event_struct.h>
+#endif
+
+#include <imsg.h>
+
+#include "openbsd-compat.h"
+
#ifndef nitems
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
#endif
@@ -27,9 +37,12 @@
#include "ioev.h"
#include "iobuf.h"
-#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"
#define PROC_COUNT 7
@@ -42,22 +55,37 @@
#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"
#endif
-#define SMTPD_VERSION "master"
+#define SMTPD_VERSION "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_FILTERS
#define PATH_FILTERS "/usr/libexec/smtpd"
+#endif
+#ifndef PATH_TABLES
#define PATH_TABLES "/usr/libexec/smtpd"
+#endif
/*
diff --git a/smtpd/ssl.c b/smtpd/ssl.c
index 17511207..250327dd 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>
@@ -25,7 +27,12 @@
#include <sys/stat.h>
#include <ctype.h>
+#if LIBEVENT_MAJOR_VERSION < 2
#include <event.h>
+#else
+#include <event2/event.h>
+#include <event2/bufferevent_ssl.h>
+#endif
#include <fcntl.h>
#include <imsg.h>
#include <limits.h>
@@ -439,6 +446,8 @@ ssl_set_ephemeral_key_exchange(SSL_CTX *ctx, DH *dh)
void
ssl_set_ecdh_curve(SSL_CTX *ctx, const char *curve)
{
+#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
+#ifndef OPENSSL_NO_ECDH
int nid;
EC_KEY *ecdh;
@@ -459,6 +468,8 @@ ssl_set_ecdh_curve(SSL_CTX *ctx, const char *curve)
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
SSL_CTX_set_options(ctx, SSL_OP_SINGLE_ECDH_USE);
EC_KEY_free(ecdh);
+#endif
+#endif
}
int
diff --git a/smtpd/ssl_privsep.c b/smtpd/ssl_privsep.c
index 66dd0c9b..fdc97480 100644
--- a/smtpd/ssl_privsep.c
+++ b/smtpd/ssl_privsep.c
@@ -62,6 +62,8 @@
* Adapted from openssl's ssl_rsa.c by Pierre-Yves Ritschard .
*/
+#include "includes.h"
+
#include <sys/types.h>
#include <sys/uio.h>
diff --git a/smtpd/ssl_smtpd.c b/smtpd/ssl_smtpd.c
index d7181bda..852b55a3 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>
@@ -90,10 +92,12 @@ ssl_smtp_init(void *ssl_ctx, void *sni, void *arg)
SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, dummy_verify);
+#if defined HAVE_TLSEXT_SERVERNAME
if (cb) {
SSL_CTX_set_tlsext_servername_callback(ssl_ctx, cb);
SSL_CTX_set_tlsext_servername_arg(ssl_ctx, arg);
}
+#endif
if ((ssl = SSL_new(ssl_ctx)) == NULL)
goto err;
diff --git a/smtpd/stat_backend.c b/smtpd/stat_backend.c
index 8aa19ab2..f4cc77e4 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 681b58e8..c32ffbd3 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 47dc0062..bf5587f8 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>
@@ -406,7 +408,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);
}
@@ -728,7 +730,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);
@@ -753,7 +757,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;
@@ -762,7 +768,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_api.c b/smtpd/table_api.c
index 1efda3a4..0434b79b 100644
--- a/smtpd/table_api.c
+++ b/smtpd/table_api.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/uio.h>
@@ -24,6 +26,7 @@
#include <fcntl.h>
#include <imsg.h>
#include <pwd.h>
+#include <grp.h> /* needed for setgroups */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/smtpd/table_db.c b/smtpd/table_db.c
index 17e8e81b..d530deaa 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 febf1388..f8b2c949 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_ldap.c b/smtpd/table_ldap.c
index 42db772d..f6286921 100644
--- a/smtpd/table_ldap.c
+++ b/smtpd/table_ldap.c
@@ -16,6 +16,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "includes.h"
+
#include <sys/types.h>
#include <ctype.h>
diff --git a/smtpd/table_mysql.c b/smtpd/table_mysql.c
index 4a96216c..0da759df 100644
--- a/smtpd/table_mysql.c
+++ b/smtpd/table_mysql.c
@@ -16,6 +16,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "includes.h"
+
#include <sys/types.h>
#include <ctype.h>
diff --git a/smtpd/table_passwd.c b/smtpd/table_passwd.c
index 39fc58cf..f306a3ea 100644
--- a/smtpd/table_passwd.c
+++ b/smtpd/table_passwd.c
@@ -16,6 +16,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "includes.h"
+
#include <sys/types.h>
#include <err.h>
diff --git a/smtpd/table_postgres.c b/smtpd/table_postgres.c
index 33625822..fa1703a2 100644
--- a/smtpd/table_postgres.c
+++ b/smtpd/table_postgres.c
@@ -16,6 +16,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "includes.h"
+
#include <sys/types.h>
#include <ctype.h>
diff --git a/smtpd/table_proc.c b/smtpd/table_proc.c
index 4cd3c75f..4b4f7703 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>
@@ -140,8 +142,7 @@ table_proc_open(struct table *table)
if (priv->pid == 0) {
/* child process */
dup2(sp[0], STDIN_FILENO);
- if (closefrom(STDERR_FILENO + 1) < 0)
- exit(1);
+ closefrom(STDERR_FILENO + 1);
environ_new[0] = "PATH=" _PATH_DEFPATH;
environ_new[1] = (char *)NULL;
diff --git a/smtpd/table_redis.c b/smtpd/table_redis.c
index f30c92fd..97bc6ad0 100644
--- a/smtpd/table_redis.c
+++ b/smtpd/table_redis.c
@@ -17,6 +17,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "includes.h"
+
#include <sys/types.h>
#include <ctype.h>
diff --git a/smtpd/table_sqlite.c b/smtpd/table_sqlite.c
index 409c1b0c..b12f20b0 100644
--- a/smtpd/table_sqlite.c
+++ b/smtpd/table_sqlite.c
@@ -16,6 +16,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "includes.h"
+
#include <sys/types.h>
#include <ctype.h>
diff --git a/smtpd/table_static.c b/smtpd/table_static.c
index c10738a7..910c8485 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/table_stub.c b/smtpd/table_stub.c
index 63c249e4..317cf56c 100644
--- a/smtpd/table_stub.c
+++ b/smtpd/table_stub.c
@@ -16,6 +16,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "includes.h"
+
#include <sys/types.h>
#include <unistd.h>
diff --git a/smtpd/to.c b/smtpd/to.c
index 51a3caba..95fedfaa 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>
@@ -57,12 +59,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 temp_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
@@ -76,7 +80,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));
@@ -280,18 +286,34 @@ 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) {
+
+ /* XXX - some systems don't support
+ inet_net_pton(AF_INET6, ...); */
+ if (errno != EAFNOSUPPORT) {
+ log_warn("inet_net_pton");
+ return 0;
+ }
+ bits = temp_inet_net_pton_ipv6(s,
+ &ssin6.sin6_addr,
+ sizeof(struct in6_addr));
+ }
+ if (bits == -1) {
log_warn("warn: inet_net_pton");
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 {
@@ -300,13 +322,17 @@ text_to_netaddr(struct netaddr *netaddr, const char *s)
ssin.sin_family = AF_INET;
bits = 32;
memcpy(&ss, &ssin, sizeof(ssin));
+#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
ss.ss_len = sizeof(struct sockaddr_in);
+#endif
}
else if (inet_pton(AF_INET6, s, &ssin6.sin6_addr) == 1) {
ssin6.sin6_family = AF_INET6;
bits = 128;
memcpy(&ss, &ssin6, sizeof(ssin6));
+#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
ss.ss_len = sizeof(struct sockaddr_in6);
+#endif
}
else return 0;
}
@@ -861,3 +887,35 @@ alias_is_error(struct expandnode *alias, const char *line, size_t len)
alias->type = EXPAND_ERROR;
return 1;
}
+
+static int
+temp_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 fc392436..81eb3eb6 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/util.c b/smtpd/util.c
index f74738a5..ea5233aa 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>
diff --git a/smtpd/waitq.c b/smtpd/waitq.c
index d954354f..db4fdb45 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/queue.h>
#include <sys/tree.h>