aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--INSTALL237
-rw-r--r--LICENSE358
-rw-r--r--Makefile.am3
-rw-r--r--THANKS16
-rwxr-xr-xbootstrap151
-rw-r--r--configure.ac2853
-rw-r--r--contrib/CVS/Entries4
-rw-r--r--contrib/CVS/Repository1
-rw-r--r--contrib/CVS/Root1
-rw-r--r--contrib/Makefile.am3
-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.c1112
-rw-r--r--contrib/lib/libc/asr/asr.h101
-rw-r--r--contrib/lib/libc/asr/asr_debug.c379
-rw-r--r--contrib/lib/libc/asr/asr_private.h367
-rw-r--r--contrib/lib/libc/asr/asr_utils.c494
-rw-r--r--contrib/lib/libc/asr/async_resolver.3372
-rw-r--r--contrib/lib/libc/asr/getaddrinfo.c50
-rw-r--r--contrib/lib/libc/asr/getaddrinfo_async.c736
-rw-r--r--contrib/lib/libc/asr/gethostnamadr.c162
-rw-r--r--contrib/lib/libc/asr/gethostnamadr_async.c781
-rw-r--r--contrib/lib/libc/asr/getnameinfo.c49
-rw-r--r--contrib/lib/libc/asr/getnameinfo_async.c299
-rw-r--r--contrib/lib/libc/asr/getnetnamadr.c128
-rw-r--r--contrib/lib/libc/asr/getnetnamadr_async.c447
-rw-r--r--contrib/lib/libc/asr/getrrsetbyname.c79
-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.c44
-rw-r--r--contrib/lib/libc/asr/res_mkquery.c108
-rw-r--r--contrib/lib/libc/asr/res_query.c105
-rw-r--r--contrib/lib/libc/asr/res_search_async.c200
-rw-r--r--contrib/lib/libc/asr/res_send.c57
-rw-r--r--contrib/lib/libc/asr/res_send_async.c742
-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/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.am17
-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.m494
-rw-r--r--openbsd-compat/Makefile.am14
-rw-r--r--openbsd-compat/NOTES34
-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-arc4random.c154
-rw-r--r--openbsd-compat/bsd-closefrom.c109
-rw-r--r--openbsd-compat/bsd-getpeereid.c73
-rw-r--r--openbsd-compat/bsd-waitpid.c53
-rw-r--r--openbsd-compat/bsd-waitpid.h51
-rw-r--r--openbsd-compat/clock_gettime.c59
-rw-r--r--openbsd-compat/daemon.c82
-rw-r--r--openbsd-compat/defines.h792
-rw-r--r--openbsd-compat/dirname.c72
-rw-r--r--openbsd-compat/entropy.c247
-rw-r--r--openbsd-compat/entropy.h37
-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.c335
-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.h180
-rw-r--r--openbsd-compat/pw_dup.c93
-rw-r--r--openbsd-compat/setproctitle.c164
-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
-rwxr-xr-xpublish.sh2
-rw-r--r--regress/Makefile.am1
-rw-r--r--regress/bin/Makefile3
-rw-r--r--regress/bin/Makefile.am27
-rw-r--r--regress/bin/Makefile.inc3
-rw-r--r--regress/bin/parse.y4
-rw-r--r--regress/bin/smtpscript/Makefile12
-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/Makefile7
-rw-r--r--smtpd/Makefile.am177
-rw-r--r--smtpd/aldap.c2
-rw-r--r--smtpd/aliases.c7
-rw-r--r--smtpd/backends/Makefile8
-rw-r--r--smtpd/backends/Makefile.am33
-rw-r--r--smtpd/backends/backend-queue-null/Makefile11
-rw-r--r--smtpd/backends/backend-queue-ram/Makefile12
-rw-r--r--smtpd/backends/backend-queue-stub/Makefile10
-rw-r--r--smtpd/backends/backend-table-ldap/Makefile12
-rw-r--r--smtpd/backends/backend-table-sqlite/Makefile13
-rw-r--r--smtpd/backends/backend-table-stub/Makefile10
-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/table_ldap.c2
-rw-r--r--smtpd/backends/table_sqlite.c2
-rw-r--r--smtpd/backends/table_stub.c2
-rw-r--r--smtpd/ber.c2
-rw-r--r--smtpd/bounce.c2
-rw-r--r--smtpd/ca.c2
-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.c14
-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/expand.c8
-rw-r--r--smtpd/filter_api.c2
-rw-r--r--smtpd/filters/Makefile6
-rw-r--r--smtpd/filters/Makefile.am38
-rw-r--r--smtpd/filters/asr_event.c2
-rw-r--r--smtpd/filters/filter-dnsbl/Makefile16
-rw-r--r--smtpd/filters/filter-monkey/Makefile8
-rw-r--r--smtpd/filters/filter-stub/Makefile8
-rw-r--r--smtpd/filters/filter-trace/Makefile8
-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/libsmtpdfilter/Makefile16
-rw-r--r--smtpd/lka.c10
-rw-r--r--smtpd/lka_session.c7
-rw-r--r--smtpd/log.c2
-rw-r--r--smtpd/log.h2
-rw-r--r--smtpd/makemap.c29
-rw-r--r--smtpd/makemap/Makefile29
-rw-r--r--smtpd/mda.c16
-rw-r--r--smtpd/mfa.c10
-rw-r--r--smtpd/mfa_session.c6
-rw-r--r--smtpd/mproc.c8
-rw-r--r--smtpd/mta.c30
-rw-r--r--smtpd/mta_session.c4
-rw-r--r--smtpd/parse.y32
-rw-r--r--smtpd/parser.c2
-rw-r--r--smtpd/queue.c11
-rw-r--r--smtpd/queue_backend.c2
-rw-r--r--smtpd/queue_fsqueue.c14
-rw-r--r--smtpd/queue_null.c2
-rw-r--r--smtpd/queue_proc.c3
-rw-r--r--smtpd/queue_ram.c2
-rw-r--r--smtpd/ruleset.c2
-rw-r--r--smtpd/scheduler.c3
-rw-r--r--smtpd/scheduler_backend.c2
-rw-r--r--smtpd/scheduler_null.c2
-rw-r--r--smtpd/scheduler_ramqueue.c2
-rw-r--r--smtpd/smtp.c20
-rw-r--r--smtpd/smtp_session.c2
-rw-r--r--smtpd/smtpctl.c8
-rw-r--r--smtpd/smtpctl/Makefile29
-rw-r--r--smtpd/smtpd.815
-rw-r--r--smtpd/smtpd.c237
-rw-r--r--smtpd/smtpd.conf14
-rw-r--r--smtpd/smtpd.conf.54
-rw-r--r--smtpd/smtpd.h36
-rw-r--r--smtpd/smtpd/Makefile58
-rw-r--r--smtpd/smtpfilter.c2
-rw-r--r--smtpd/ssl.c7
-rw-r--r--smtpd/ssl_privsep.c2
-rw-r--r--smtpd/ssl_smtpd.c2
-rw-r--r--smtpd/stat_backend.c2
-rw-r--r--smtpd/stat_ramstat.c1
-rw-r--r--smtpd/table.c10
-rw-r--r--smtpd/table_db.c9
-rw-r--r--smtpd/table_getpwnam.c2
-rw-r--r--smtpd/table_proc.c3
-rw-r--r--smtpd/table_static.c2
-rw-r--r--smtpd/to.c64
-rw-r--r--smtpd/tree.c2
-rw-r--r--smtpd/util.c6
-rw-r--r--smtpd/waitq.c2
222 files changed, 19806 insertions, 360 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..d587dde9
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,358 @@
+This file is part of the OpenSMTPD software.
+
+The licences which components of this software fall under are as
+follows. First, we will summarize and say that all components
+are under a BSD licence, or a licence more free than that.
+
+OpenSMTPD contains no GPL code.
+
+Portable OpenSMTPD is divided in 4 parts:
+- Original OpenSMTPD
+- asr
+- mail.local
+- openbsd-compat
+
+
+
+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
+ 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.
+ Todd C. Miller
+ Damien 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 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
+ 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
+ Eric P. Allman
+ Damien Miller
+
+ * 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) bootstrap
+
+ # 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.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 00000000..16052de7
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,3 @@
+SUBDIRS = openbsd-compat smtpd contrib regress
+
+ACLOCAL_AMFLAGS = -I m4
diff --git a/THANKS b/THANKS
new file mode 100644
index 00000000..a9f4aa86
--- /dev/null
+++ b/THANKS
@@ -0,0 +1,16 @@
+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
+
+
+Miod Vallat Hosting hackathons with ducks and cheese
+
+
+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..99167db1
--- /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 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..0d059b4f
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,2853 @@
+# $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], [5.3.1p-current], [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([SED], [sed])
+AC_PATH_PROG([TEST_MINUS_S_SH], [bash])
+AC_PATH_PROG([TEST_MINUS_S_SH], [ksh])
+AC_PATH_PROG([TEST_MINUS_S_SH], [sh])
+AC_PATH_PROG([SH], [sh])
+AC_PATH_PROG([GROFF], [groff])
+AC_PATH_PROG([NROFF], [nroff])
+AC_PATH_PROG([MANDOC], [mandoc])
+AC_PROG_YACC
+#AC_PATH_PROG(BYACC, byacc)
+AC_PATH_PROG(MAIL_LOCAL, mail.local)
+
+AM_INIT_AUTOMAKE
+AM_CONDITIONAL(HAVE_MAIL_LOCAL, [test -n "$MAIL_LOCAL"])
+
+LT_INIT
+
+#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([-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([-Wpointer-sign], [-Wno-pointer-sign])
+ OSSH_CHECK_CFLAG_COMPILE([-Wunused-result], [-Wno-unused-result])
+ OSSH_CHECK_CFLAG_COMPILE([-fno-strict-aliasing])
+ OSSH_CHECK_CFLAG_COMPILE([-D_FORTIFY_SOURCE=2])
+ 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
+ ]
+)
+#l291
+
+AC_CHECK_HEADERS([ \
+ crypt.h \
+ dirent.h \
+ fcntl.h \
+ ndir.h \
+ mach/mach_time.h \
+ netdb.h \
+ pam/pam_appl.h \
+ security/pam_appl.h \
+ shadow.h \
+ sys/dir.h \
+ sys/file.h \
+ sys/ndir.h \
+ sys/pstat.h \
+ sys/statfs.h \
+ sys/un.h \
+ ucred.h \
+ util.h \
+ vis.h
+])
+
+##chl
+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) ***])
+])])])
+
+AC_MSG_CHECKING([if dbopen will link])
+AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+#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
+ ]], [[
+ dbopen (0, 0, 0, 0, 0);
+ ]])],
+ AC_MSG_RESULT([yes]),
+ [AC_MSG_RESULT([no])
+ saved_LIBS="$LIBS"
+ LIBS="$LIBS -ldb"
+ AC_MSG_CHECKING([for dbopen in -ldb])
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+#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
+ ]], [[
+ dbopen (0, 0, 0, 0, 0);
+ ]])],
+ [AC_MSG_RESULT([yes])],
+ [AC_MSG_RESULT([no])
+ LIBS="$saved_LIBS -ldb1"
+ AC_MSG_CHECKING([for dbopen in -ldb1])
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+#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
+ ]], [[
+ dbopen (0, 0, 0, 0, 0);
+ ]])],
+ [AC_MSG_RESULT([yes])],
+ [LIBS="$saved_LIBS"
+ AC_MSG_RESULT([no])])
+ ])
+ ])
+##end of chl
+
+#l374
+# 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>
+])
+#l382
+
+#l389
+# 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*)
+ SSHDLIBS="$SSHDLIBS -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*)
+ 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
+ AC_DEFINE([BROKEN_STRNVIS], [1], [NetBSD strnvis has swapped parameters])
+ ;;
+*-*-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 has swapped parameters])
+ ;;
+*-*-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 http://www.opensmtpd.org/archives/opensmtpd-5.3.1.tar.gz"
+ ;;
+*-*-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([yp_match], , [AC_CHECK_LIB([nsl], [yp_match])])
+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
+ ])
+])
+#l1056
+
+#l1060
+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"]) ]
+)
+#l1164
+
+#l1170
+dnl Checks for libutil functions
+AC_CHECK_HEADERS([bsd/libutil.h libutil.h])
+AC_SEARCH_LIBS([fmt_scaled], [util bsd])
+#AC_SEARCH_LIBS([login], [util bsd])
+#AC_SEARCH_LIBS([logout], [util bsd])
+#AC_SEARCH_LIBS([logwtmp], [util bsd])
+#AC_SEARCH_LIBS([openpty], [util bsd])
+#AC_SEARCH_LIBS([updwtmp], [util bsd])
+#AC_CHECK_FUNCS([fmt_scaled login logout openpty updwtmp logwtmp])
+AC_CHECK_FUNCS([fmt_scaled])
+#l1178
+
+#l1236
+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
+#l1264
+
+#l1513
+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 \
+ fgetln \
+ freeaddrinfo \
+ getaddrinfo \
+ getnameinfo \
+ getopt \
+ getpeereid \
+ getspnam \
+ memmove \
+ pw_dup \
+ setproctitle \
+ setregid \
+ setreuid \
+ strlcat \
+ strlcpy \
+ strnvis \
+ strtonum \
+ strmode \
+ sysconf \
+ waitpid \
+])
+#l1615
+
+#l1629
+# 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 *])], [])])
+#l1643
+
+#l1650
+AC_CHECK_DECL([strsep],
+ [AC_CHECK_FUNCS([strsep])],
+ [],
+ [
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+ ])
+#l1657
+
+#l1674
+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>
+ ])
+#l1689
+
+#l1695
+AC_CHECK_DECLS([offsetof], , , [
+#include <stddef.h>
+ ])
+
+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])
+#l1746
+
+#l1756
+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])])]
+)
+#l1760
+
+##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_CHECK_FUNC([clock_gettime],
+ [AC_DEFINE([HAVE_CLOCK_GETTIME], [1], [Define if your libraries define clock_gettime()])],
+ [AC_CHECK_LIB([rt], [clock_gettime],
+ [LIBS="$LIBS -lrt"; AC_DEFINE([HAVE_CLOCK_GETTIME])])]
+)
+
+AC_SEARCH_LIBS(res_9_b64_ntop, resolv)
+##chl
+
+#l1769
+# 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
+#l1878
+
+#l1926
+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
+#l2051
+
+#l2070
+# 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"
+ ]
+ )
+ ]
+)
+#l2263
+
+#l2373
+# 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
+#l2383
+
+#l2433
+### 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"
+
+ SSHDLIBS="$SSHDLIBS -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
+ ;;
+ *)
+ SSHDLIBS="$SSHDLIBS -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
+
+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])
+#l2618
+
+SMTPD_LOOKUP_USER=_smtpl
+AC_ARG_WITH([lookup-user],
+ [ --with-lookup-user=user Specify non-privileged user for lookup process],
+ [
+ if test -n "$withval" && test "x$withval" != "xno" && \
+ test "x${withval}" != "xyes"; then
+ SMTPD_LOOKUP_USER=$withval
+ fi
+ ]
+)
+AC_DEFINE_UNQUOTED([SMTPD_LOOKUP_USER], ["$SMTPD_LOOKUP_USER"],
+ [non-privileged user for lookup process])
+AC_SUBST([SMTPD_LOOKUP_USER])
+
+SMTPD_FILTER_USER=_smtpf
+AC_ARG_WITH([filter-user],
+ [ --with-filter-user=user Specify non-privileged user for filter process],
+ [
+ if test -n "$withval" && test "x$withval" != "xno" && \
+ test "x${withval}" != "xyes"; then
+ SMTPD_FILTER_USER=$withval
+ fi
+ ]
+)
+AC_DEFINE_UNQUOTED([SMTPD_FILTER_USER], ["$SMTPD_FILTER_USER"],
+ [non-privileged user for filter process])
+AC_SUBST([SMTPD_FILTER_USER])
+
+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])
+
+#l2803
+# 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
+#l3283
+
+#l3317
+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
+
+AC_CACHE_CHECK([for pw_class field in struct passwd],
+ ac_cv_have_pw_class_in_struct_passwd, [
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <pwd.h> ]],
+ [[ struct passwd p; p.pw_class = 0; ]])],
+ [ ac_cv_have_pw_class_in_struct_passwd="yes" ],
+ [ ac_cv_have_pw_class_in_struct_passwd="no"
+ ])
+])
+if test "x$ac_cv_have_pw_class_in_struct_passwd" = "xyes" ; then
+ AC_DEFINE([HAVE_PW_CLASS_IN_PASSWD], [1],
+ [Define if your password has a pw_class field])
+fi
+
+AC_CACHE_CHECK([for pw_expire field in struct passwd],
+ ac_cv_have_pw_expire_in_struct_passwd, [
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <pwd.h> ]],
+ [[ struct passwd p; p.pw_expire = 0; ]])],
+ [ ac_cv_have_pw_expire_in_struct_passwd="yes" ],
+ [ ac_cv_have_pw_expire_in_struct_passwd="no"
+ ])
+])
+if test "x$ac_cv_have_pw_expire_in_struct_passwd" = "xyes" ; then
+ AC_DEFINE([HAVE_PW_EXPIRE_IN_PASSWD], [1],
+ [Define if your password has a pw_expire field])
+fi
+
+AC_CACHE_CHECK([for pw_change field in struct passwd],
+ ac_cv_have_pw_change_in_struct_passwd, [
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <pwd.h> ]],
+ [[ struct passwd p; p.pw_change = 0; ]])],
+ [ ac_cv_have_pw_change_in_struct_passwd="yes" ],
+ [ ac_cv_have_pw_change_in_struct_passwd="no"
+ ])
+])
+if test "x$ac_cv_have_pw_change_in_struct_passwd" = "xyes" ; then
+ AC_DEFINE([HAVE_PW_CHANGE_IN_PASSWD], [1],
+ [Define if your password has a pw_change field])
+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
+#l3541
+
+##chl part
+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
+
+
+#l3781
+# 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])
+#l3793
+
+#l3816
+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])
+#l3825
+
+#l3837
+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
+#l3917
+
+#l3947
+# 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])
+#l3978
+
+#l4203
+# 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])
+#l4241
+
+
+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])
+
+
+# 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* 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 ***])]
+ )
+
+ AC_CHECK_LIB([sqlite3], [sqlite3_open], ,
+ [
+ saved_CPPFLAGS="$CPPFLAGS"
+ saved_LDFLAGS="$LDFLAGS"
+ save_LIBS="$LIBS"
+ 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 ***])
+ ]
+ )
+ ]
+ )
+ EXPERIMENTAL_SQLITE=yes
+ fi
+ ]
+)
+AM_CONDITIONAL([HAVE_SQLITE], [test $EXPERIMENTAL_SQLITE = yes])
+
+
+dnl AC_DEFINE([_GNU_SOURCE], [], [Enable GNU Extensions])
+
+
+#l4514
+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_EXEEXT
+#l4526
+
+##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])
+ ]
+)
+
+AC_SEARCH_LIBS([bufferevent_openssl_socket_new], [event event_openssl], [])
+
+
+LIBS="$LIBS ${SSHDLIBS}"
+##end of chl
+
+AC_CONFIG_FILES([Makefile
+ openbsd-compat/Makefile
+ smtpd/Makefile
+ smtpd/backends/Makefile
+ smtpd/filters/Makefile
+ contrib/Makefile
+ contrib/libexec/Makefile
+ contrib/libexec/mail.local/Makefile
+ regress/Makefile
+ regress/bin/Makefile
+ ])
+
+#l4530
+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}/mail.local` ; E=`eval echo ${E}`
+F=`eval echo ${mandir}/${mansubdir}X` ; F=`eval echo ${F}`
+G=`eval echo ${sockdir}` ; G=`eval echo ${G}`
+H=`eval echo ${PRIVSEP_PATH}` ; H=`eval echo ${H}`
+I=`eval echo ${user_path}` ; I=`eval echo ${I}`
+J=`eval echo ${superuser_path}` ; J=`eval echo ${J}`
+
+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 " Manual pages: $F"
+echo " smtpd.sock dir: $G"
+echo " Privilege separation chroot path: $H"
+if test "x$external_path_file" = "x/etc/login.conf" ; then
+echo " At runtime, smtpd will use the path defined in $external_path_file"
+echo " Make sure the path to scp is present, otherwise scp will not work"
+else
+echo " smtpd default user PATH: $I"
+ if test ! -z "$external_path_file"; then
+echo " (If PATH is set in $external_path_file it will be used instead. If"
+echo " used, ensure the path to scp is present, otherwise scp will not work.)"
+ fi
+fi
+if test ! -z "$superuser_path" ; then
+echo " smtpd superuser user PATH: $J"
+fi
+echo " Manpage format: $MANTYPE"
+echo " PAM support: $PAM_MSG"
+#echo " OSF SIA support: $SIA_MSG"
+#echo " KerberosV support: $KRB5_MSG"
+#echo " SELinux support: $SELINUX_MSG"
+#echo " Smartcard support: $SCARD_MSG"
+#echo " S/KEY support: $SKEY_MSG"
+#echo " TCP Wrappers support: $TCPW_MSG"
+#echo " MD5 password support: $MD5_MSG"
+#echo " libedit support: $LIBEDIT_MSG"
+#echo " Solaris process contract support: $SPC_MSG"
+#echo " IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG"
+#echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_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
+
+#if test ! -z "$NO_PEERCHECK" ; then
+# echo "WARNING: the operating system that you are using does not"
+# echo "appear to support getpeereid(), getpeerucred() or the"
+# echo "SO_PEERCRED getsockopt() option. These facilities are used to"
+# echo "enforce security checks to prevent unauthorised connections to"
+# echo "ssh-agent. Their absence increases the risk that a malicious"
+# echo "user can connect to your agent."
+# echo ""
+#fi
+
+if test "$AUDIT_MODULE" = "bsm" ; then
+ echo "WARNING: BSM audit support is currently considered EXPERIMENTAL."
+ echo "See the Solaris section in README.platform for details."
+fi
+#l4463
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..d1e9f516
--- /dev/null
+++ b/contrib/Makefile.am
@@ -0,0 +1,3 @@
+if !HAVE_MAIL_LOCAL
+SUBDIRS = libexec
+endif
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..4f1c6b9a
--- /dev/null
+++ b/contrib/lib/libc/asr/CVS/Entries
@@ -0,0 +1,26 @@
+/getnameinfo_async.c/1.6/Result of merge//
+/Makefile.inc/1.5/Sat Nov 24 17:15:45 2012//
+/asr_debug.c/1.12/Result of merge//
+/asr_utils.c/1.7/Result of merge//
+/asr.c/1.25/Result of merge//
+/asr.h/1.6/Result of merge//
+/asr_private.h/1.17/Tue Apr 30 12:44:41 2013//
+/async_resolver.3/1.11/Tue Apr 30 12:44:41 2013//
+/getaddrinfo.c/1.1/Tue Apr 30 12:41:30 2013//
+/getaddrinfo_async.c/1.17/Result of merge+Tue Apr 30 12:44:41 2013//
+/gethostnamadr.c/1.6/Tue Apr 30 12:41:30 2013//
+/gethostnamadr_async.c/1.19/Result of merge//
+/getnameinfo.c/1.1/Tue Apr 30 12:41:30 2013//
+/getnetnamadr.c/1.4/Tue Apr 30 12:41:30 2013//
+/getnetnamadr_async.c/1.9/Result of merge//
+/getrrsetbyname.c/1.1/Tue Apr 30 12:41:30 2013//
+/getrrsetbyname_async.c/1.4/Result of merge//
+/res_debug.c/1.1/Tue Apr 30 12:41:30 2013//
+/res_init.c/1.1/Tue Apr 30 12:41:30 2013//
+/res_mkquery.c/1.5/Tue Apr 30 12:41:30 2013//
+/res_query.c/1.3/Tue Apr 30 12:44:42 2013//
+/res_search_async.c/1.7/Result of merge//
+/res_send.c/1.3/Tue Apr 30 12:44:42 2013//
+/res_send_async.c/1.17/Result of merge//
+/sethostent.c/1.1/Tue Apr 30 12:41:30 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..5cfab870
--- /dev/null
+++ b/contrib/lib/libc/asr/asr.c
@@ -0,0 +1,1112 @@
+/* $OpenBSD: asr.c,v 1.25 2013/04/30 12:02:39 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_HOSTALIASES
+static char *asr_hostalias(const char *, char *, size_t);
+#endif
+#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". */
+struct asr *
+async_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
+async_resolver_done(struct asr *asr)
+{
+ 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
+async_abort(struct async *as)
+{
+ async_free(as);
+}
+
+/*
+ * Resume the "as" async query resolution. Return one of ASYNC_COND,
+ * ASYNC_YIELD or ASYNC_DONE and put query-specific return values in
+ * the user-allocated memory at "ar".
+ */
+int
+async_run(struct async *as, struct async_res *ar)
+{
+ int r, saved_errno = errno;
+
+ DPRINT("asr: async_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: async_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)
+ async_free(as);
+
+ errno = saved_errno;
+
+ return (r);
+}
+
+/*
+ * Same as above, but run in a loop that handles the fd conditions result.
+ */
+int
+async_run_sync(struct async *as, struct async_res *ar)
+{
+ struct pollfd fds[1];
+ int r, saved_errno = errno;
+
+ while ((r = async_run(as, ar)) == ASYNC_COND) {
+ fds[0].fd = ar->ar_fd;
+ fds[0].events = (ar->ar_cond == ASYNC_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 async_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 async *
+async_new(struct asr_ctx *ac, int type)
+{
+ struct async *as;
+
+ DPRINT("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
+async_free(struct async *as)
+{
+ DPRINT("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)
+ 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)
+ 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)
+ 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)
+ 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)
+ 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)
+ 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(struct asr *asr)
+{
+ 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 = async_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 < ac->ac_nscount; i++)
+ free(ac->ac_ns[i]);
+ for (i = 0; i < ac->ac_domcount; 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));
+}
+
+/*
+ * Concatenate a name and a domain name. The result has no trailing dot.
+ * Return the resulting string length, or 0 in case of error.
+ */
+size_t
+asr_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);
+}
+
+/*
+ * 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 < ac->ac_domcount; 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 (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 async *as)
+{
+ if (as->as_db_idx >= as->as_ctx->ac_dbcount) {
+ DPRINT("asr_iter_db: done\n");
+ return (-1);
+ }
+
+ as->as_db_idx += 1;
+ as->as_ns_idx = 0;
+ DPRINT("asr_iter_db: %i\n", as->as_db_idx);
+
+ return (0);
+}
+
+/*
+ * Set the async context nameserver index to the next nameserver of the
+ * currently used DB (assuming it is DNS), cycling over the list until the
+ * maximum retry counter is reached. Return 0 on success, or -1 if all
+ * nameservers were used.
+ */
+int
+asr_iter_ns(struct async *as)
+{
+ for (;;) {
+ if (as->as_ns_cycles >= as->as_ctx->ac_nsretries)
+ return (-1);
+
+ as->as_ns_idx += 1;
+ if (as->as_ns_idx <= as->as_ctx->ac_nscount)
+ break;
+ as->as_ns_idx = 0;
+ as->as_ns_cycles++;
+ DPRINT("asr: asr_iter_ns(): cycle %i\n", as->as_ns_cycles);
+ }
+
+ as->as_timeout = 1000 * (as->as_ctx->ac_nstimeout << as->as_ns_cycles);
+ if (as->as_ns_cycles > 0)
+ as->as_timeout /= as->as_ctx->ac_nscount;
+ if (as->as_timeout < 1000)
+ as->as_timeout = 1000;
+
+ return (0);
+}
+
+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
+asr_iter_domain(struct async *as, const char *name, char * buf, size_t len)
+{
+#if ASR_OPT_HOSTALIASES
+ char *alias;
+#endif
+
+ 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: asr_iter_domain(\"%s\") fqdn\n", name);
+ as->as_dom_flags |= ASYNC_DOM_FQDN;
+ as->as_dom_step = DOM_DONE;
+ return (asr_domcat(name, NULL, buf, len));
+ }
+
+#if ASR_OPT_HOSTALIASES
+ /*
+ * If "name" has no dots, it might be an alias. If so,
+ * That's also the only result.
+ */
+ if ((as->as_ctx->ac_options & RES_NOALIASES) == 0 &&
+ asr_ndots(name) == 0 &&
+ (alias = asr_hostalias(name, buf, len)) != NULL) {
+ DPRINT("asr: asr_iter_domain(\"%s\") is alias \"%s\"\n",
+ name, alias);
+ as->as_dom_flags |= ASYNC_DOM_HOSTALIAS;
+ as->as_dom_step = DOM_DONE;
+ return (asr_domcat(alias, NULL, buf, len));
+ }
+#endif
+
+ /*
+ * 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).
+ */
+ if ((asr_ndots(name)) >= as->as_ctx->ac_ndots) {
+ DPRINT("asr: 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: 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 (asr_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: 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: asr_iter_domain(\"%s\") done\n", name);
+ return (-1);
+ }
+}
+
+#if ASR_OPT_HOSTALIASES
+/*
+ * 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.
+ */
+static char *
+asr_hostalias(const char *name, char *abuf, size_t abufsz)
+{
+ FILE *fp;
+ size_t len;
+ char *file, *buf, *tokens[2];
+ int ntok;
+
+ file = getenv("HOSTALIASES");
+ if (file == NULL || issetugid() != 0 || (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);
+ return (NULL);
+}
+#endif
diff --git a/contrib/lib/libc/asr/asr.h b/contrib/lib/libc/asr/asr.h
new file mode 100644
index 00000000..0e6b6aac
--- /dev/null
+++ b/contrib/lib/libc/asr/asr.h
@@ -0,0 +1,101 @@
+/* $OpenBSD: asr.h,v 1.6 2013/04/30 12:02:39 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 <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+
+/*
+ * This part is the generic API for the async mechanism. It could be useful
+ * beyond the resolver.
+ */
+
+/* Return values for async_run() */
+#define ASYNC_COND 0 /* wait for fd condition */
+#define ASYNC_YIELD 1 /* partial result */
+#define ASYNC_DONE 2 /* done */
+
+/* Expected fd conditions */
+#define ASYNC_READ 1
+#define ASYNC_WRITE 2
+
+/* This opaque structure holds an async query state. */
+struct async;
+
+/*
+ * This is the structure through which async_run() returns async
+ * results to the caller.
+ */
+struct async_res {
+ int ar_cond;
+ int ar_fd;
+ int ar_timeout;
+
+ int ar_errno;
+ int ar_h_errno;
+ int ar_gai_errno;
+ int ar_rrset_errno;
+
+ int ar_count;
+
+ int ar_rcode;
+ void *ar_data;
+ int ar_datalen;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sain;
+ struct sockaddr_in6 sain6;
+ } ar_sa;
+
+ struct addrinfo *ar_addrinfo;
+ struct rrsetinfo *ar_rrsetinfo;
+ struct hostent *ar_hostent;
+ struct netent *ar_netent;
+};
+
+int async_run(struct async *, struct async_res *);
+int async_run_sync(struct async *, struct async_res *);
+void async_abort(struct async *);
+
+/* This opaque structure holds an async resolver context. */
+struct asr;
+
+struct asr *async_resolver(const char *);
+void async_resolver_done(struct asr *);
+
+/* Async version of the resolver API */
+
+struct async *res_send_async(const unsigned char *, int, struct asr *);
+struct async *res_query_async(const char *, int, int, struct asr *);
+struct async *res_search_async(const char *, int, int, struct asr *);
+
+struct async *getrrsetbyname_async(const char *, unsigned int, unsigned int,
+ unsigned int, struct asr *);
+
+struct async *gethostbyname_async(const char *, struct asr *);
+struct async *gethostbyname2_async(const char *, int, struct asr *);
+struct async *gethostbyaddr_async(const void *, socklen_t, int, struct asr *);
+
+struct async *getnetbyname_async(const char *, struct asr *);
+struct async *getnetbyaddr_async(in_addr_t, int, struct asr *);
+
+struct async *getaddrinfo_async(const char *, const char *,
+ const struct addrinfo *, struct asr *);
+struct async *getnameinfo_async(const struct sockaddr *, socklen_t, char *,
+ size_t, char *, size_t, int, struct asr *);
+void asr_freeaddrinfo(struct addrinfo *);
diff --git a/contrib/lib/libc/asr/asr_debug.c b/contrib/lib/libc/asr/asr_debug.c
new file mode 100644
index 00000000..931456de
--- /dev/null
+++ b/contrib/lib/libc/asr/asr_debug.c
@@ -0,0 +1,379 @@
+/* $OpenBSD: asr_debug.c,v 1.12 2013/04/09 06:42:17 otto 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 header *, char *, size_t);
+static const char *print_query(const struct query *, char *, size_t);
+static const char *print_rr(const struct 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 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 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 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 unpack p;
+ struct header h;
+ struct query q;
+ struct rr rr;
+ int i, an, ns, ar, n;
+
+ if (f == NULL)
+ return;
+
+ unpack_init(&p, data, len);
+
+ if (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 (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 (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");
+ for (i = 0; i < ac->ac_dbcount; i++) {
+ switch (ac->ac_db[i]) {
+ case ASR_DB_FILE:
+ fprintf(f, " file");
+ break;
+ case ASR_DB_DNS:
+ fprintf(f, " dns");
+ break;
+ case ASR_DB_YP:
+ fprintf(f, " yp");
+ break;
+ default:
+ fprintf(f, " ?%i", ac->ac_db[i]);
+ }
+ }
+ 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_YIELD);
+ 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..275d18eb
--- /dev/null
+++ b/contrib/lib/libc/asr/asr_private.h
@@ -0,0 +1,367 @@
+/* $OpenBSD: asr_private.h,v 1.17 2013/04/30 12:02:39 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 pack {
+ char *buf;
+ size_t len;
+ size_t offset;
+ const char *err;
+};
+
+struct unpack {
+ const char *buf;
+ size_t len;
+ size_t offset;
+ const char *err;
+};
+
+struct header {
+ uint16_t id;
+ uint16_t flags;
+ uint16_t qdcount;
+ uint16_t ancount;
+ uint16_t nscount;
+ uint16_t arcount;
+};
+
+struct query {
+ char q_dname[MAXDNAME];
+ uint16_t q_type;
+ uint16_t q_class;
+};
+
+struct 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,
+};
+
+enum asr_db_type {
+ ASR_DB_FILE,
+ ASR_DB_DNS,
+ ASR_DB_YP,
+};
+
+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;
+ int ac_db[ASR_MAXDB];
+ 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_DOM_FQDN 0x00000001
+#define ASYNC_DOM_NDOTS 0x00000002
+#define ASYNC_DOM_HOSTALIAS 0x00000004
+#define ASYNC_DOM_DOMAIN 0x00000008
+#define ASYNC_DOM_ASIS 0x00000010
+
+#define ASYNC_NODATA 0x00000100
+#define ASYNC_AGAIN 0x00000200
+
+#define ASYNC_EXTOBUF 0x00002000
+
+
+struct async {
+ int (*as_run)(struct async *, struct async_res *);
+ 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_ns_idx;
+ int as_ns_cycles;
+
+ 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 */
+
+ /* 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 async *subq;
+ int saved_h_errno;
+ } search;
+
+ struct {
+ int flags;
+ int class;
+ int type;
+ char *name;
+ struct async *subq;
+ } rrset;
+
+ struct {
+ char *name;
+ int family;
+ struct async *subq;
+ char addr[16];
+ int addrlen;
+ int subq_h_errno;
+ } hostnamadr;
+
+ struct {
+ char *name;
+ int family;
+ struct async *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 async *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 async *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 pack_init(struct pack *, char *, size_t);
+int pack_header(struct pack *, const struct header *);
+int pack_query(struct pack *, uint16_t, uint16_t, const char *);
+
+void unpack_init(struct unpack *, const char *, size_t);
+int unpack_header(struct unpack *, struct header *);
+int unpack_query(struct unpack *, struct query *);
+int unpack_rr(struct unpack *, struct rr *);
+int sockaddr_from_str(struct sockaddr *, int, const char *);
+ssize_t dname_from_fqdn(const char *, char *, size_t);
+
+/* asr.c */
+struct asr_ctx *asr_use_resolver(struct asr *);
+void asr_ctx_unref(struct asr_ctx *);
+struct async *async_new(struct asr_ctx *, int);
+void async_free(struct async *);
+size_t asr_make_fqdn(const char *, const char *, char *, size_t);
+size_t asr_domcat(const char *, const char *, char *, size_t);
+char *asr_strdname(const char *, char *, size_t);
+int asr_iter_db(struct async *);
+int asr_iter_ns(struct async *);
+int asr_iter_domain(struct async *, const char *, char *, size_t);
+int asr_parse_namedb_line(FILE *, char **, int);
+
+/* <*>_async.h */
+struct async *res_query_async_ctx(const char *, int, int, struct asr_ctx *);
+struct async *res_search_async_ctx(const char *, int, int, struct asr_ctx *);
+struct async *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..74c5509e
--- /dev/null
+++ b/contrib/lib/libc/asr/asr_utils.c
@@ -0,0 +1,494 @@
+/* $OpenBSD: asr_utils.c,v 1.7 2013/04/14 22:23:08 deraadt 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 unpack *, void *, size_t);
+static int unpack_u16(struct unpack *, uint16_t *);
+static int unpack_u32(struct unpack *, uint32_t *);
+static int unpack_inaddr(struct unpack *, struct in_addr *);
+static int unpack_in6addr(struct unpack *, struct in6_addr *);
+static int unpack_dname(struct unpack *, char *, size_t);
+
+static int pack_data(struct pack *, const void *, size_t);
+static int pack_u16(struct pack *, uint16_t);
+static int pack_dname(struct pack *, const char *);
+
+static int
+dname_check_label(const char *s, size_t l)
+{
+ if (l == 0 || l > 63)
+ return (-1);
+
+ for (l--; l; l--, s++)
+ if (!(isalnum(*s) || *s == '_' || *s == '-'))
+ return (-1);
+
+ return (0);
+}
+
+ssize_t
+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
+pack_init(struct pack *pack, char *buf, size_t len)
+{
+ pack->buf = buf;
+ pack->len = len;
+ pack->offset = 0;
+ pack->err = NULL;
+}
+
+void
+unpack_init(struct 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 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 unpack *p, uint16_t *u16)
+{
+ if (unpack_data(p, u16, 2) == -1)
+ return (-1);
+
+ *u16 = ntohs(*u16);
+
+ return (0);
+}
+
+static int
+unpack_u32(struct unpack *p, uint32_t *u32)
+{
+ if (unpack_data(p, u32, 4) == -1)
+ return (-1);
+
+ *u32 = ntohl(*u32);
+
+ return (0);
+}
+
+static int
+unpack_inaddr(struct unpack *p, struct in_addr *a)
+{
+ return (unpack_data(p, a, 4));
+}
+
+static int
+unpack_in6addr(struct unpack *p, struct in6_addr *a6)
+{
+ return (unpack_data(p, a6, 16));
+}
+
+static int
+unpack_dname(struct 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
+unpack_header(struct unpack *p, struct 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
+unpack_query(struct unpack *p, struct 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
+unpack_rr(struct unpack *p, struct 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 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 pack *p, uint16_t v)
+{
+ v = htons(v);
+
+ return (pack_data(p, &v, 2));
+}
+
+static int
+pack_dname(struct 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
+pack_header(struct pack *p, const struct header *h)
+{
+ struct 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
+pack_query(struct 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
+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 (sockaddr_from_str(sa, PF_INET, str) == 0)
+ return (0);
+ return 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);
+}
diff --git a/contrib/lib/libc/asr/async_resolver.3 b/contrib/lib/libc/asr/async_resolver.3
new file mode 100644
index 00000000..10216920
--- /dev/null
+++ b/contrib/lib/libc/asr/async_resolver.3
@@ -0,0 +1,372 @@
+.\" $OpenBSD: async_resolver.3,v 1.11 2013/04/30 12:02:39 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.
+.\"
+.Dd $Mdocdate: April 30 2013 $
+.Dt ASYN_RESOLVER 3
+.Os
+.Sh NAME
+.Nm async_resolver ,
+.Nm async_resolver_done ,
+.Nm async_run ,
+.Nm async_run_sync ,
+.Nm async_abort ,
+.Nm res_send_async ,
+.Nm res_query_async ,
+.Nm res_search_async ,
+.Nm getrrsetbyname_async ,
+.Nm gethostbyname_async ,
+.Nm gethostbyname2_async ,
+.Nm gethostbyaddr_async ,
+.Nm getnetbyname_async ,
+.Nm getnetbyaddr_async ,
+.Nm freenetent ,
+.Nm getaddrinfo_async ,
+.Nm getnameinfo_async
+.Nd asynchronous resolver functions
+.Sh SYNOPSIS
+.Fd #include <asr.h>
+.Ft struct asr *
+.Fn async_resolver "const char *conf"
+.Ft void
+.Fn async_resolver_done "struct asr *asr"
+.Ft int
+.Fn async_run "struct async *as" "struct async_res *ar"
+.Ft int
+.Fn async_run_sync "struct async *as" "struct async_res *ar"
+.Ft void
+.Fn async_abort "struct async *as"
+.Ft struct async *
+.Fn res_send_async "const unsigned char *pkt" "int pktlen" "struct asr *asr"
+.Ft struct async *
+.Fn res_query_async "const char *name" "int class" "int type" "struct asr *asr"
+.Ft struct async *
+.Fn res_search_async "const char *name" "int class" "int type" "struct asr *asr"
+.Ft struct async *
+.Fn getrrsetbyname_async "const char *hostname" "unsigned int rdclass" "unsigned int rdtype" "unsigned int flags" "struct asr *asr"
+.Ft struct async *
+.Fn gethostbyname_async "const char *name" "struct asr *asr"
+.Ft struct async *
+.Fn gethostbyname2_async "const char *name" "int af" "struct asr *asr"
+.Ft struct async *
+.Fn gethostbyaddr_async "const void *addr" "socklen_t len" "int af" "struct asr *asr"
+.Ft struct async *
+.Fn getnetbyname_async "const char *name" "struct asr *asr"
+.Ft struct async *
+.Fn getnetbyaddr_async "in_addr_t net" "int type" "struct asr *asr"
+.Ft struct async *
+.Fn getaddrinfo_async "const char *hostname" "const char *servname" "const struct addrinfo *hints" "struct asr *asr"
+.Ft struct async *
+.Fn getnameinfo_async "const struct sockaddr *sa" "socklen_t salen" "char *host" "size_t hostlen" "char *serv" "size_t servlen" "int flags" "struct asr *asr"
+.Sh DESCRIPTION
+The
+.Nm asr
+functions provide a simple interface for asynchronous address
+resolution and nameserver querying.
+They should be used in place of the classical resolver functions
+of libc when blocking is not desirable.
+.Pp
+The principle of operation is as follows:
+All async requests are made against an
+.Nm asr
+context which basically defines a list of sources to query and a
+strategy to do so.
+The user creates a query through one of the dedicated functions.
+A query is a state-machine that can be run to try to fulfill a
+particular request.
+This is done by calling in a generic API that performs the state
+transitions until it needs to give the control back to the user,
+either because a result is available, or because the next transition
+implies a blocking call (a file descriptor needs to be read from or
+written to).
+The user is responsible for dealing with the situation (fetch the result,
+or wait until the fd conditions are met), and call back into the resolving
+machinery when it is ready to proceed.
+.Pp
+.Fn async_resolver
+is the function used to create a new resolver context.
+The
+.Fa conf
+argument is a path to the resolver configuration file
+as described in
+.Xr resolv.conf 5 .
+If NULL, the default
+.Pa /etc/resolv.conf
+file is used.
+The context tracks file changes to automatically update its configuration
+if needed, replacing the current setup if a valid one can be reloaded from
+the file.
+If the configuration file cannot be loaded at context creation time, it falls
+back to:
+.Bd -literal -offset indent
+lookup file
+.Ed
+.Pp
+If the first character of the
+.Fa conf
+string is a '!', the configuration is read from the rest of the string rather
+than loaded from a file.
+No further update occurs in this case.
+.Pp
+.Fn async_resolver_done
+is used to discard the
+.Fa asr
+context when it is not used anymore.
+Once called, that context is invalidated and cannot be used to create new
+queries.
+Internally, the context is refcounted, so that existing queries made against
+it will be able to complete safely.
+All relevant resources are effectively freed when all such queries are cleared.
+.Pp
+The
+.Fn async_run
+function drives the resolving process.
+It runs the
+.Fa as
+asynchronous query until an answer is available, or until it cannot continue
+without blocking.
+The results are returned to the user through the
+.Fa ar
+parameter, which must be a valid pointer to user allocated memory.
+.Fa ar
+is defined as:
+.Bd -literal -offset indent
+struct async_res {
+ int ar_cond;
+ int ar_fd;
+ int ar_timeout;
+
+ int ar_errno;
+ int ar_h_errno;
+ int ar_gai_errno;
+ int ar_rrset_errno;
+
+ int ar_count;
+
+ int ar_rcode;
+ void *ar_data;
+ int ar_datalen;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sain;
+ struct sockaddr_in6 sain6;
+ } ar_sa;
+
+ struct addrinfo *ar_addrinfo;
+ struct rrsetinfo *ar_rrsetinfo;
+ struct hostent *ar_hostent;
+ struct netent *ar_netent;
+};
+.Ed
+.Pp
+The function returns one of the following values:
+.Bl -tag -width "ASYNC_YIELD " -offset indent
+.It ASYNC_COND
+The query cannot be processed further until a specific condition on a
+file descriptor becomes true.
+The following members of the
+.Fa ar
+structure are filled:
+.Pp
+.Bl -tag -width "ar_timeout " -compact
+.It Fa ar_cond
+One of ASYNC_READ or ASYNC_WRITE.
+.It Fa ar_fd
+The file descriptor waiting for an IO operation.
+.It Fa ar_timeout
+The timeout, expressed in milliseconds.
+.El
+.Pp
+The caller is expected to call
+.Fn async_run
+again once the condition holds or the timeout expires.
+.It ASYNC_DONE
+The query is completed.
+The members relevant to the actual async query type are set accordingly,
+including error conditions.
+In any case, the query is cleared and its address is invalidated.
+.It ASR_YIELD
+A partial result is available.
+This code is used for async queries that behave as iterators over the result
+set.
+The query-specific members of
+.Fa ar
+are set accordingly and the resolving process can be resumed by calling
+.Fn async_run .
+.El
+.Pp
+Note that although the query itself may fail (the error being properly reported
+in the
+.Fa ar
+structure), the
+.Fn async_run
+function itself cannot fail and it always preserves errno.
+.Pp
+The
+.Fn async_run_sync
+function is a wrapper around
+.Fn async_run
+that handles the read/write conditions, thus falling back to a blocking
+interface.
+It only returns partial and complete results through ASYNC_YIELD and ASYNC_DONE
+respectively.
+It also preserves errno.
+.Pp
+The
+.Fn async_abort
+function clears a running query.
+It can be called after a partial result has been retrieved or when the query
+is waiting on a file descriptor.
+Note that a completed query is already cleared when
+.Fn async_run
+returns, so
+.Fn async_abort
+must not be called in this case.
+.Pp
+The remaining functions are used to initiate different kinds of query
+on the
+.Fa asr
+resolver context.
+The specific operational details for each of them are described below.
+All functions return NULL if they could not allocate the necessary resources
+to initiate the query.
+All other errors (especially invalid parameters)
+are reported when calling
+.Fn async_run .
+They usually have the same interface as an exisiting resolver function, with
+an additional
+.Ar asr
+contex argument, which specifies the context to use for this request.
+If NULL, the default thread-local context is used.
+.Pp
+The
+.Fn res_send_async ,
+.Fn res_query_async
+and
+.Fn res_search_async
+functions are asynchronous versions of the standard libc resolver routines.
+Their interface is very similar, except that the response buffer is always
+allocated internally. The return value is found upon completion in the
+.Fa ar_datalen
+member of the response structure.
+In addition, the
+.Fa ar_sa
+union contains the address of the DNS server that sent the response,
+.Fa ar_rcode
+contains the code returned by the server in the DNS response packet, and
+.Fa ar_count
+contains the number of answers in the packet.
+If a response is received it placed in a newly allocated buffer
+and returned as
+.Fa ar_data
+member.
+This buffer must be freed by the caller.
+On error, the
+.Fa ar_errno
+and
+.Fa ar_h_errno
+members are set accordingly.
+.Pp
+The
+.Fn getrrsetbyname_async
+function is an asynchronous version of
+.Xr getrrsetbyname 3 .
+Upon completion, the return code is found in
+.Fa ar_rrset_errno
+and the address to the newly allocated result set is set in
+.Fa ar_rrsetinfo .
+As for the blocking function, it must be freed by calling
+.Xr freerrset 3 .
+.Pp
+The
+.Fn gethostbyname_async ,
+.Fn gethostbyname2_async
+and
+.Fn gethostbyaddr_async
+functions provide an asynchronous version of the network host entry functions.
+Upon completion,
+.Ar ar_h_errno
+is set and the resulting hostent address, if found, is set
+in the
+.Ar ar_hostent
+field.
+Note that unlike their blocking counterparts, these functions always return a
+pointer to newly allocated memory, which must be released by the caller using
+.Xr free 3 .
+.Pp
+Similarly, the
+.Fn getnetbyname_async
+and
+.Fn getnetbyaddr_async
+functions provide an asynchronous version of the network entry functions.
+Upon completion,
+.Ar ar_h_errno
+is set and the resulting netent address, if found, is set
+in the
+.Ar ar_netent
+field.
+The memory there is also allocated for the request, and it must be freed by
+.Xr free 3 .
+.Pp
+The
+.Fn getaddrinfo_async
+function is an asynchronous version of the
+.Xr getaddrinfo 3
+call.
+It provides a chain of addrinfo structures with all valid combinations of
+socket address for the given
+.Fa hostname ,
+.Fa servname
+and
+.Fa hints .
+Those three parameters have the same meaning as for the blocking counterpart.
+Upon completion the return code is set in
+.Fa ar_gai_errno .
+The
+.Fa ar_errno
+member may also be set.
+On success, the
+.Fa ar_addrinfo
+member points to a newly allocated list of addrinfo.
+This list must be freed with
+.Xr freeaddrinfo 3 .
+The
+.Fa ar_count
+contains the number of elements in the list.
+.Sh WORKING WITH THREADS
+This implementation of the asynchronous resolver interface is thread-safe
+and lock-free internally, but the following restriction applies:
+Two different threads must not create queries on the same context or
+run queries originating from the same context at the same time.
+If they want to do that, all calls must be protected by a mutex around
+that context.
+.Pp
+It is generally not a problem since the main point of the asynchronous
+resolver is to multiplex queries within a single thread of control,
+so sharing a resolver among threads is not useful.
+.Pp
+Note that this restriction only applies to resolver contexts explicitly
+created by the caller, as a thread-local context is used by default.
+.Sh SEE ALSO
+.Xr getaddrinfo 3 ,
+.Xr gethostbyname 3 ,
+.Xr getnameinfo 3 ,
+.Xr getnetbyname 3 ,
+.Xr getrrsetbyname 3 ,
+.Xr res_send 3 ,
+.Xr resolv.conf 5
+.Sh CAVEATS
+This DNS resolver implementation doesn't support
+the EDNS0 protocol extension yet.
diff --git a/contrib/lib/libc/asr/getaddrinfo.c b/contrib/lib/libc/asr/getaddrinfo.c
new file mode 100644
index 00000000..84b11ce5
--- /dev/null
+++ b/contrib/lib/libc/asr/getaddrinfo.c
@@ -0,0 +1,50 @@
+/* $OpenBSD: getaddrinfo.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 <errno.h>
+#include <resolv.h>
+
+#include "asr.h"
+
+int
+getaddrinfo(const char *hostname, const char *servname,
+ const struct addrinfo *hints, struct addrinfo **res)
+{
+ struct async *as;
+ struct async_res ar;
+ int saved_errno = errno;
+
+ as = getaddrinfo_async(hostname, servname, hints, NULL);
+ if (as == NULL) {
+ if (errno == ENOMEM) {
+ errno = saved_errno;
+ return (EAI_MEMORY);
+ }
+ return (EAI_SYSTEM);
+ }
+
+ async_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..5d9ace72
--- /dev/null
+++ b/contrib/lib/libc/asr/getaddrinfo_async.c
@@ -0,0 +1,736 @@
+/* $OpenBSD: getaddrinfo_async.c,v 1.17 2013/04/30 12:02:39 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>
+#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 <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 async *, struct async_res *);
+static int get_port(const char *, const char *, int);
+static int iter_family(struct async *, int);
+static int addrinfo_add(struct async *, const struct sockaddr *, const char *);
+static int addrinfo_from_file(struct async *, int, FILE *);
+static int addrinfo_from_pkt(struct async *, char *, size_t);
+#ifdef YP
+static int addrinfo_from_yp(struct async *, 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))
+
+struct async *
+getaddrinfo_async(const char *hostname, const char *servname,
+ const struct addrinfo *hints, struct asr *asr)
+{
+ struct asr_ctx *ac;
+ struct async *as;
+
+ ac = asr_use_resolver(asr);
+ if ((as = async_new(ac, ASR_GETADDRINFO)) == NULL)
+ goto abort; /* errno set */
+ as->as_run = getaddrinfo_async_run;
+
+ if (hostname && (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)
+ async_free(as);
+ asr_ctx_unref(ac);
+ return (NULL);
+}
+
+static int
+getaddrinfo_async_run(struct async *as, struct async_res *ar)
+{
+#ifdef YP
+ static char *domain = NULL;
+ char *res;
+ int len;
+#endif
+ 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 */
+ 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 (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_DB);
+ break;
+ }
+ 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:
+ family = (as->as.ai.hints.ai_family == AF_UNSPEC) ?
+ AS_FAMILY(as) : as->as.ai.hints.ai_family;
+ if (as->as.ai.fqdn) {
+ as->as.ai.subq = res_query_async_ctx(
+ as->as.ai.fqdn, C_IN,
+ (family == AF_INET6) ? T_AAAA : T_A,
+ as->as_ctx);
+ }
+ else {
+ as->as.ai.subq = res_search_async_ctx(
+ as->as.ai.hostname, 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;
+ /* XXX
+ * ipnodes.byname could also contain IPv4 address
+ */
+ r = yp_match(domain, (family == AF_INET6) ?
+ "ipnodes.byname" : "hosts.byname",
+ as->as.ai.hostname, strlen(as->as.ai.hostname),
+ &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 = async_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 async *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);
+}
+
+/*
+ * 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 async *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 async *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 (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 async *as, char *pkt, size_t pktlen)
+{
+ struct unpack p;
+ struct header h;
+ struct query q;
+ struct rr rr;
+ int i;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sain;
+ struct sockaddr_in6 sain6;
+ } u;
+ char buf[MAXDNAME], *c;
+
+ unpack_init(&p, pkt, pktlen);
+ unpack_header(&p, &h);
+ for (; h.qdcount; h.qdcount--)
+ unpack_query(&p, &q);
+
+ for (i = 0; i < h.ancount; i++) {
+ unpack_rr(&p, &rr);
+ if (rr.rr_type != q.q_type ||
+ rr.rr_class != q.q_class)
+ continue;
+
+ if (as->as.ai.fqdn == NULL) {
+ asr_strdname(q.q_dname, buf, sizeof buf);
+ buf[strlen(buf) - 1] = '\0';
+ as->as.ai.fqdn = strdup(buf);
+ if (as->as.ai.fqdn == NULL)
+ return (-1); /* errno set */
+ }
+
+ 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 = buf;
+ } 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 async *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 (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..6833166d
--- /dev/null
+++ b/contrib/lib/libc/asr/gethostnamadr.c
@@ -0,0 +1,162 @@
+/* $OpenBSD: gethostnamadr.c,v 1.6 2013/04/14 22:23:08 deraadt 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 <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "asr.h"
+
+static struct hostent *_gethostbyname(const char *, int);
+static void _fillhostent(const struct hostent *, struct hostent *, char *buf,
+ size_t);
+
+static struct hostent _hostent;
+static char _entbuf[4096];
+
+static char *_empty[] = { NULL, };
+
+static void
+_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;
+
+ 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;
+
+ 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;
+ 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;
+ r->h_aliases[i] = pos;
+ pos += n + 1;
+ }
+
+ pos = (char *)ALIGN(pos);
+ if (pos >= end)
+ return;
+
+ for (i = 0; i < naddrs; i++) {
+ if (r->h_length > end - pos)
+ return;
+ memmove(pos, h->h_addr_list[i], r->h_length);
+ r->h_addr_list[i] = pos;
+ pos += r->h_length;
+ }
+}
+
+static struct hostent *
+_gethostbyname(const char *name, int af)
+{
+ struct async *as;
+ struct async_res ar;
+
+ if (af == -1)
+ as = gethostbyname_async(name, NULL);
+ else
+ as = gethostbyname2_async(name, af, NULL);
+
+ if (as == NULL) {
+ h_errno = NETDB_INTERNAL;
+ return (NULL);
+ }
+
+ async_run_sync(as, &ar);
+
+ errno = ar.ar_errno;
+ h_errno = ar.ar_h_errno;
+ if (ar.ar_hostent == NULL)
+ return (NULL);
+
+ _fillhostent(ar.ar_hostent, &_hostent, _entbuf, sizeof(_entbuf));
+ free(ar.ar_hostent);
+
+ return (&_hostent);
+}
+
+struct hostent *
+gethostbyname(const char *name)
+{
+ return _gethostbyname(name, -1);
+}
+
+struct hostent *
+gethostbyname2(const char *name, int af)
+{
+ return _gethostbyname(name, af);
+}
+
+struct hostent *
+gethostbyaddr(const void *addr, socklen_t len, int af)
+{
+ struct async *as;
+ struct async_res ar;
+
+ as = gethostbyaddr_async(addr, len, af, NULL);
+ if (as == NULL) {
+ h_errno = NETDB_INTERNAL;
+ return (NULL);
+ }
+
+ async_run_sync(as, &ar);
+
+ errno = ar.ar_errno;
+ h_errno = ar.ar_h_errno;
+ if (ar.ar_hostent == NULL)
+ return (NULL);
+
+ _fillhostent(ar.ar_hostent, &_hostent, _entbuf, sizeof(_entbuf));
+ free(ar.ar_hostent);
+
+ 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..785f3f4e
--- /dev/null
+++ b/contrib/lib/libc/asr/gethostnamadr_async.c
@@ -0,0 +1,781 @@
+/* $OpenBSD: gethostnamadr_async.c,v 1.19 2013/04/30 12:02:39 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 <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;
+};
+
+ssize_t addr_as_fqdn(const char *, int, char *, size_t);
+
+static int gethostnamadr_async_run(struct async *, struct async_res *);
+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 async *
+gethostbyname_async(const char *name, struct asr *asr)
+{
+ return gethostbyname2_async(name, AF_INET, asr);
+}
+
+struct async *
+gethostbyname2_async(const char *name, int af, struct asr *asr)
+{
+ struct asr_ctx *ac;
+ struct async *as;
+
+ /* the original segfaults */
+ if (name == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ ac = asr_use_resolver(asr);
+ if ((as = 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)
+ async_free(as);
+ asr_ctx_unref(ac);
+ return (NULL);
+}
+
+struct async *
+gethostbyaddr_async(const void *addr, socklen_t len, int af, struct asr *asr)
+{
+ struct asr_ctx *ac;
+ struct async *as;
+
+ ac = asr_use_resolver(asr);
+ as = gethostbyaddr_async_ctx(addr, len, af, ac);
+ asr_ctx_unref(ac);
+
+ return (as);
+}
+
+struct async *
+gethostbyaddr_async_ctx(const void *addr, socklen_t len, int af,
+ struct asr_ctx *ac)
+{
+ struct async *as;
+
+ if ((as = 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)
+ async_free(as);
+ return (NULL);
+}
+
+static int
+gethostnamadr_async_run(struct async *as, struct async_res *ar)
+{
+ struct hostent_ext *h;
+ int r, type, saved_errno;
+ FILE *f;
+ char dname[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(*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 {
+ addr_as_fqdn(as->as.hostnamadr.addr,
+ as->as.hostnamadr.family,
+ dname, sizeof(dname));
+ as->as.hostnamadr.subq = res_query_async_ctx(
+ dname, 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 = 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 = 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 = async_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 unpack p;
+ struct header hdr;
+ struct query q;
+ struct rr rr;
+ char dname[MAXDNAME];
+
+ if ((h = hostent_alloc(family)) == NULL)
+ return (NULL);
+
+ unpack_init(&p, pkt, pktlen);
+ unpack_header(&p, &hdr);
+ for (; hdr.qdcount; hdr.qdcount--)
+ unpack_query(&p, &q);
+ strlcpy(dname, q.q_dname, sizeof(dname));
+
+ for (; hdr.ancount; hdr.ancount--) {
+ 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)
+ goto fail;
+ /* XXX See if we need MULTI_PTRS_ARE_ALIASES */
+ 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';
+ 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';
+ 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);
+}
+
+ssize_t
+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);
+}
+
+#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..0349732a
--- /dev/null
+++ b/contrib/lib/libc/asr/getnameinfo.c
@@ -0,0 +1,49 @@
+/* $OpenBSD: getnameinfo.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 <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 async *as;
+ struct async_res ar;
+ int saved_errno = errno;
+
+ 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);
+ }
+
+ async_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..57ea3234
--- /dev/null
+++ b/contrib/lib/libc/asr/getnameinfo_async.c
@@ -0,0 +1,299 @@
+/* $OpenBSD: getnameinfo_async.c,v 1.6 2013/03/29 21:20:50 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 async *, struct async_res *);
+static int _servname(struct async *);
+static int _numerichost(struct async *);
+
+struct async *
+getnameinfo_async(const struct sockaddr *sa, socklen_t slen, char *host,
+ size_t hostlen, char *serv, size_t servlen, int flags, struct asr *asr)
+{
+ struct asr_ctx *ac;
+ struct async *as;
+
+ ac = asr_use_resolver(asr);
+ if ((as = 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)
+ async_free(as);
+ asr_ctx_unref(ac);
+ return (NULL);
+}
+
+static int
+getnameinfo_async_run(struct async *as, struct async_res *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 = async_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 async *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 async *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..63cc0754
--- /dev/null
+++ b/contrib/lib/libc/asr/getnetnamadr.c
@@ -0,0 +1,128 @@
+/* $OpenBSD: getnetnamadr.c,v 1.4 2013/04/04 17:50:19 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 async *as;
+ struct async_res ar;
+
+ as = getnetbyname_async(name, NULL);
+ if (as == NULL) {
+ h_errno = NETDB_INTERNAL;
+ return (NULL);
+ }
+
+ async_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 async *as;
+ struct async_res ar;
+
+ as = getnetbyaddr_async(net, type, NULL);
+ if (as == NULL) {
+ h_errno = NETDB_INTERNAL;
+ return (NULL);
+ }
+
+ async_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..7a1266cc
--- /dev/null
+++ b/contrib/lib/libc/asr/getnetnamadr_async.c
@@ -0,0 +1,447 @@
+/* $OpenBSD: getnetnamadr_async.c,v 1.9 2013/04/30 12:02:39 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 <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;
+};
+
+ssize_t addr_as_fqdn(const char *, int, char *, size_t);
+
+static int getnetnamadr_async_run(struct async *, struct async_res *);
+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 async *
+getnetbyname_async(const char *name, struct asr *asr)
+{
+ struct asr_ctx *ac;
+ struct async *as;
+
+ /* The current resolver segfaults. */
+ if (name == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ ac = asr_use_resolver(asr);
+ if ((as = 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)
+ async_free(as);
+ asr_ctx_unref(ac);
+ return (NULL);
+}
+
+struct async *
+getnetbyaddr_async(in_addr_t net, int family, struct asr *asr)
+{
+ struct asr_ctx *ac;
+ struct async *as;
+
+ ac = asr_use_resolver(asr);
+ if ((as = 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)
+ async_free(as);
+ asr_ctx_unref(ac);
+ return (NULL);
+}
+
+static int
+getnetnamadr_async_run(struct async *as, struct async_res *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);
+ 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 = async_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 unpack p;
+ struct header hdr;
+ struct query q;
+ struct rr rr;
+
+ if ((n = netent_alloc(AF_INET)) == NULL)
+ return (NULL);
+
+ unpack_init(&p, pkt, pktlen);
+ unpack_header(&p, &hdr);
+ for (; hdr.qdcount; hdr.qdcount--)
+ unpack_query(&p, &q);
+ for (; hdr.ancount; hdr.ancount--) {
+ 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';
+ 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';
+ 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..12bb56b0
--- /dev/null
+++ b/contrib/lib/libc/asr/getrrsetbyname.c
@@ -0,0 +1,79 @@
+/* $OpenBSD: getrrsetbyname.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 <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 async *as;
+ struct async_res ar;
+ int r, saved_errno = errno;
+
+ as = getrrsetbyname_async(name, class, type, flags, NULL);
+ if (as == NULL) {
+ r = (errno == ENOMEM) ? ERRSET_NOMEMORY : ERRSET_FAIL;
+ errno = saved_errno;
+ return (r);
+ }
+
+ async_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..f5dc5dfb
--- /dev/null
+++ b/contrib/lib/libc/asr/getrrsetbyname_async.c
@@ -0,0 +1,589 @@
+/* $OpenBSD: getrrsetbyname_async.c,v 1.4 2013/04/30 12:02:39 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 async *, struct async_res *);
+static void get_response(struct async_res *, const char *, int);
+
+struct async *
+getrrsetbyname_async(const char *hostname, unsigned int rdclass,
+ unsigned int rdtype, unsigned int flags, struct asr *asr)
+{
+ struct asr_ctx *ac;
+ struct async *as;
+
+ ac = asr_use_resolver(asr);
+ if ((as = 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)
+ async_free(as);
+
+ asr_ctx_unref(ac);
+ return (NULL);
+}
+
+static int
+getrrsetbyname_async_run(struct async *as, struct async_res *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 ((async_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.4 2013/04/30 12:02:39 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 async_res *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..1ba38cd0
--- /dev/null
+++ b/contrib/lib/libc/asr/res_init.c
@@ -0,0 +1,44 @@
+/* $OpenBSD: res_init.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 <resolv.h>
+
+#include "asr.h"
+
+/*
+ * XXX these function is actually internal to asr, but we use it here to force
+ * the creation a default resolver context in res_init().
+ */
+struct asr_ctx *asr_use_resolver(struct asr *);
+void asr_ctx_unref(struct asr_ctx *);
+
+struct __res_state _res;
+struct __res_state_ext _res_ext;
+
+int h_errno;
+
+int
+res_init(void)
+{
+ async_resolver_done(NULL);
+ asr_ctx_unref(asr_use_resolver(NULL));
+
+ 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..ffd7a34a
--- /dev/null
+++ b/contrib/lib/libc/asr/res_mkquery.c
@@ -0,0 +1,108 @@
+/* $OpenBSD: res_mkquery.c,v 1.5 2013/04/01 20:22:27 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 pack p;
+ struct 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 (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;
+
+ pack_init(&p, buf, buflen);
+ pack_header(&p, &h);
+ 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..7a6a1db0
--- /dev/null
+++ b/contrib/lib/libc/asr/res_query.c
@@ -0,0 +1,105 @@
+/* $OpenBSD: res_query.c,v 1.3 2013/04/30 12:02:39 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 "asr.h"
+
+int
+res_query(const char *name, int class, int type, u_char *ans, int anslen)
+{
+ struct async *as;
+ struct async_res ar;
+ size_t len;
+
+ 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 */
+ }
+
+ async_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 async *as;
+ struct async_res ar;
+ size_t len;
+
+ 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 */
+ }
+
+ async_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..466a520e
--- /dev/null
+++ b/contrib/lib/libc/asr/res_search_async.c
@@ -0,0 +1,200 @@
+/* $OpenBSD: res_search_async.c,v 1.7 2013/04/30 12:02:39 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 async *, struct async_res *);
+
+/*
+ * Unlike res_query_async(), this function returns a valid packet only if
+ * h_errno is NETDB_SUCCESS.
+ */
+struct async *
+res_search_async(const char *name, int class, int type, struct asr *asr)
+{
+ struct asr_ctx *ac;
+ struct async *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 async *
+res_search_async_ctx(const char *name, int class, int type, struct asr_ctx *ac)
+{
+ struct async *as;
+
+ DPRINT("asr: res_search_async_ctx(\"%s\", %i, %i)\n", name, class,
+ type);
+
+ if ((as = 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)
+ async_free(as);
+ return (NULL);
+}
+
+#define HERRNO_UNSET -2
+
+static int
+res_search_async_run(struct async *as, struct async_res *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 = asr_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 = async_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 | ASYNC_DOM_ASIS))
+ 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;
+}
diff --git a/contrib/lib/libc/asr/res_send.c b/contrib/lib/libc/asr/res_send.c
new file mode 100644
index 00000000..5135a8d1
--- /dev/null
+++ b/contrib/lib/libc/asr/res_send.c
@@ -0,0 +1,57 @@
+/* $OpenBSD: res_send.c,v 1.3 2013/04/30 12:02:39 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 "asr.h"
+
+int
+res_send(const u_char *buf, int buflen, u_char *ans, int anslen)
+{
+ struct async *as;
+ struct async_res ar;
+ size_t len;
+
+ if (ans == NULL || anslen <= 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ as = res_send_async(buf, buflen, NULL);
+ if (as == NULL)
+ return (-1); /* errno set */
+
+ async_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..21be784f
--- /dev/null
+++ b/contrib/lib/libc/asr/res_send_async.c
@@ -0,0 +1,742 @@
+/* $OpenBSD: res_send_async.c,v 1.17 2013/04/30 12:02:39 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 async *, struct async_res *);
+static int sockaddr_connect(const struct sockaddr *, int);
+static int udp_send(struct async *);
+static int udp_recv(struct async *);
+static int tcp_write(struct async *);
+static int tcp_read(struct async *);
+static int validate_packet(struct async *);
+static int setup_query(struct async *, const char *, const char *, int, int);
+static int ensure_ibuf(struct async *, size_t);
+
+
+#define AS_NS_SA(p) ((p)->as_ctx->ac_ns[(p)->as_ns_idx - 1])
+
+
+struct async *
+res_send_async(const unsigned char *buf, int buflen, struct asr *asr)
+{
+ struct asr_ctx *ac;
+ struct async *as;
+ struct unpack p;
+ struct header h;
+ struct query q;
+
+ DPRINT_PACKET("asr: res_send_async()", buf, buflen);
+
+ ac = asr_use_resolver(asr);
+ if ((as = 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;
+
+ unpack_init(&p, buf, buflen);
+ unpack_header(&p, &h);
+ 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)
+ 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
+ * (ans == NULL).
+ */
+struct async *
+res_query_async(const char *name, int class, int type, struct asr *asr)
+{
+ struct asr_ctx *ac;
+ struct async *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 async *
+res_query_async_ctx(const char *name, int class, int type, struct asr_ctx *a_ctx)
+{
+ struct async *as;
+
+ DPRINT("asr: res_query_async_ctx(\"%s\", %i, %i)\n", name, class, type);
+
+ if ((as = 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)
+ async_free(as);
+
+ return (NULL);
+}
+
+static int
+res_send_async_run(struct async *as, struct async_res *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 (asr_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 = ASYNC_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 = ASYNC_READ;
+ ar->ar_fd = as->as_fd;
+ ar->ar_timeout = as->as_timeout;
+ return (ASYNC_COND);
+ case 1:
+ ar->ar_cond = ASYNC_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 = ASYNC_READ;
+ ar->ar_fd = as->as_fd;
+ ar->ar_timeout = as->as_timeout;
+ return (ASYNC_COND);
+ }
+ break;
+
+ case ASR_STATE_PACKET:
+
+ memmove(&ar->ar_sa.sa, 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 async *as, const char *name, const char *dom,
+ int class, int type)
+{
+ struct pack p;
+ struct 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 (dname_from_fqdn(fqdn, dname, sizeof(dname)) == -1) {
+ errno = EINVAL;
+ DPRINT("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;
+
+ pack_init(&p, as->as.dns.obuf, as->as.dns.obufsize);
+ pack_header(&p, &h);
+ 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 async *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 async *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 async *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 async *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 async *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 async *as)
+{
+ struct unpack p;
+ struct header h;
+ struct query q;
+ struct rr rr;
+ int r;
+
+ unpack_init(&p, as->as.dns.ibuf, as->as.dns.ibuflen);
+
+ 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;
+
+ 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--)
+ unpack_rr(&p, &rr);
+
+ if (p.err || (p.offset != as->as.dns.ibuflen))
+ goto inval;
+
+ return (0);
+
+ inval:
+ errno = EINVAL;
+ return (-1);
+}
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..0ee645e2
--- /dev/null
+++ b/contrib/libexec/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = mail.local
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..bafadb15
--- /dev/null
+++ b/contrib/libexec/mail.local/Makefile.am
@@ -0,0 +1,17 @@
+libexec_PROGRAMS = mail.local
+
+mail_local_SOURCES = mail.local.c locking.c $(top_srcdir)/smtpd/log.c
+
+EXTRA_DIST = mail.local.h pathnames.h
+
+INCLUDES = -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
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..4f5777ff
--- /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 < 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))
+ != 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..db084395
--- /dev/null
+++ b/m4/aclocal-openssh.m4
@@ -0,0 +1,94 @@
+dnl $Id: aclocal.m4,v 1.8 2011/05/20 01:45:25 djm Exp $
+dnl
+dnl OpenSSH-specific autoconf macros
+dnl
+
+dnl OSSH_CHECK_CFLAG_COMPILE(check_flag[, define_flag])
+dnl Check that $CC accepts a flag 'check_flag'. If it is supported append
+dnl 'define_flag' to $CFLAGS. If 'define_flag' is not specified, then append
+dnl 'check_flag'.
+AC_DEFUN([OSSH_CHECK_CFLAG_COMPILE], [{
+ AC_MSG_CHECKING([if $CC supports $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; }]])],
+ [ AC_MSG_RESULT([yes])
+ CFLAGS="$saved_CFLAGS $_define_flag"],
+ [ 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/openbsd-compat/Makefile.am b/openbsd-compat/Makefile.am
new file mode 100644
index 00000000..255b207b
--- /dev/null
+++ b/openbsd-compat/Makefile.am
@@ -0,0 +1,14 @@
+noinst_LIBRARIES = libopenbsd-compat.a
+
+libopenbsd_compat_a_SOURCES = \
+ base64.c basename.c bsd-arc4random.c bsd-closefrom.c \
+ bsd-getpeereid.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
+
+EXTRA_DIST = base64.h bsd-waitpid.h defines.h entropy.h imsg.h includes.h \
+ openbsd-compat.h sys-queue.h sys-tree.h vis.h xmalloc.h
+
+INCLUDES = -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..f01d5703
--- /dev/null
+++ b/openbsd-compat/NOTES
@@ -0,0 +1,34 @@
+List of files and where they come from
+
+base64.{c,h} portable openssh
+basename.c portable openssh
+bsd-arc4random.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
+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/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-arc4random.c b/openbsd-compat/bsd-arc4random.c
new file mode 100644
index 00000000..d957596c
--- /dev/null
+++ b/openbsd-compat/bsd-arc4random.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 1999,2000,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>
+
+#include <err.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "log.h"
+
+#ifndef HAVE_ARC4RANDOM
+
+#include <openssl/rand.h>
+#include <openssl/rc4.h>
+#include <openssl/err.h>
+
+/* Size of key to use */
+#define SEED_SIZE 20
+
+/* Number of bytes to reseed after */
+#define REKEY_BYTES (1 << 24)
+
+static int rc4_ready = 0;
+static RC4_KEY rc4;
+
+unsigned int
+arc4random(void)
+{
+ unsigned int r = 0;
+ static int first_time = 1;
+
+ if (rc4_ready <= 0) {
+ if (first_time)
+ seed_rng();
+ first_time = 0;
+ arc4random_stir();
+ }
+
+ RC4(&rc4, sizeof(r), (unsigned char *)&r, (unsigned char *)&r);
+
+ rc4_ready -= sizeof(r);
+
+ return(r);
+}
+
+void
+arc4random_stir(void)
+{
+ unsigned char rand_buf[SEED_SIZE];
+ int i;
+
+ memset(&rc4, 0, sizeof(rc4));
+#ifdef VALGRIND
+ memset(rand_buf, 0, sizeof(rand_buf));
+#endif
+ if (RAND_bytes(rand_buf, sizeof(rand_buf)) <= 0)
+ err(255, "fatal: Couldn't obtain random bytes (error %ld)",
+ ERR_get_error());
+ RC4_set_key(&rc4, sizeof(rand_buf), rand_buf);
+
+ /*
+ * Discard early keystream, as per recommendations in:
+ * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
+ */
+ for(i = 0; i <= 256; i += sizeof(rand_buf))
+ RC4(&rc4, sizeof(rand_buf), rand_buf, rand_buf);
+
+ memset(rand_buf, 0, sizeof(rand_buf));
+
+ rc4_ready = REKEY_BYTES;
+}
+#endif /* !HAVE_ARC4RANDOM */
+
+#ifndef HAVE_ARC4RANDOM_BUF
+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 /* !HAVE_ARC4RANDOM_BUF */
+
+#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;
+
+#if (ULONG_MAX > 0xffffffffUL)
+ min = 0x100000000UL % upper_bound;
+#else
+ /* Calculate (2**32 % upper_bound) avoiding 64-bit math */
+ if (upper_bound > 0x80000000)
+ min = 1 + ~upper_bound; /* 2**32 - upper_bound */
+ else {
+ /* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */
+ min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound;
+ }
+#endif
+
+ /*
+ * 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 */
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-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/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..8ff15601
--- /dev/null
+++ b/openbsd-compat/defines.h
@@ -0,0 +1,792 @@
+/*
+ * 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 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
+
+#ifndef MAIL_DIRECTORY
+# define MAIL_DIRECTORY "/var/spool/mail"
+#endif
+
+/* remove it
+#ifndef MAILDIR
+# define MAILDIR MAIL_DIRECTORY
+#endif */
+
+#if !defined(_PATH_MAILDIR) && defined(MAILDIR)
+# define _PATH_MAILDIR MAILDIR
+#endif /* !defined(_PATH_MAILDIR) && defined(MAILDIR) */
+
+#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..2d4e1518
--- /dev/null
+++ b/openbsd-compat/entropy.c
@@ -0,0 +1,247 @@
+/*
+ * 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"
+
+/* wrapper for signal interface */
+typedef void (*mysig_t)(int);
+mysig_t mysignal(int sig, mysig_t act);
+
+#define signal(a,b) mysignal(a,b)
+
+#include <sys/wait.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/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..7223ad77
--- /dev/null
+++ b/openbsd-compat/imsg-buffer.c
@@ -0,0 +1,307 @@
+/* $OpenBSD: imsg-buffer.c,v 1.2 2012/06/02 21:46:53 gilles 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 == EAGAIN || 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 == EAGAIN || 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..7163630f
--- /dev/null
+++ b/openbsd-compat/imsg.c
@@ -0,0 +1,335 @@
+/* $OpenBSD: imsg.c,v 1.2 2012/06/02 21:46:53 gilles 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 == ECONNRESET || errno == ETIMEDOUT) {
+ n = 0;
+ goto fail;
+ }
+ if (errno == ENOBUFS || errno == ENOMEM) {
+ errno = EAGAIN;
+ goto fail;
+ }
+ 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, 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, 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..1718b69a
--- /dev/null
+++ b/openbsd-compat/imsg.h
@@ -0,0 +1,113 @@
+/* $OpenBSD: imsg.h,v 1.2 2010/06/23 07:53:55 nicm 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, 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 *, 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..ddc2bf78
--- /dev/null
+++ b/openbsd-compat/openbsd-compat.h
@@ -0,0 +1,180 @@
+/* $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_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_DIRNAME
+char *dirname(const char *path);
+#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
+
+#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_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_PW_DUP
+struct passwd *pw_dup(const struct passwd *);
+#endif
+
+#ifndef HAVE_STRTONUM
+long long strtonum(const char *nptr, long long minval, long long maxval, const char **errstr);
+#endif
+
+#ifndef HAVE_STRMODE
+void strmode(int mode, char *p);
+#endif
+
+#ifndef HAVE_FMT_SCALED
+#define FMT_SCALED_STRSIZE 7
+int scan_scaled(char *scaled, long long *result);
+int fmt_scaled(long long number, char *result);
+#endif
+
+#endif /* _OPENBSD_COMPAT_H */
diff --git a/openbsd-compat/pw_dup.c b/openbsd-compat/pw_dup.c
new file mode 100644
index 00000000..0ef8b69b
--- /dev/null
+++ b/openbsd-compat/pw_dup.c
@@ -0,0 +1,93 @@
+/* $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, csize, gsize, dsize, ssize, total;
+ 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_PW_CLASS_IN_PASSWD
+ 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_PW_CLASS_IN_PASSWD
+ 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..2965f689
--- /dev/null
+++ b/openbsd-compat/setproctitle.c
@@ -0,0 +1,164 @@
+/* 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;
+ 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));
+
+ va_start(ap, fmt);
+ if (fmt != NULL) {
+ len = strlcat(buf, ": ", sizeof(buf));
+ if (len < sizeof(buf))
+ vsnprintf(buf + len, sizeof(buf) - len , fmt, ap);
+ }
+ va_end(ap);
+ 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/publish.sh b/publish.sh
index b48e2588..ac09d697 100755
--- a/publish.sh
+++ b/publish.sh
@@ -22,7 +22,7 @@ esac
#
build_tarball()
{
- V=5.3.x
+ V=5.3.1
P=p1
ASRSRC=/usr/src/lib/libc/asr
ASRFILES="asr.c asr_debug.c asr_utils.c gethostnamadr_async.c
diff --git a/regress/Makefile.am b/regress/Makefile.am
new file mode 100644
index 00000000..aa858a40
--- /dev/null
+++ b/regress/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = bin
diff --git a/regress/bin/Makefile b/regress/bin/Makefile
deleted file mode 100644
index 6a628f2a..00000000
--- a/regress/bin/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-SUBDIR+= smtpscript
-
-.include <bsd.subdir.mk>
diff --git a/regress/bin/Makefile.am b/regress/bin/Makefile.am
new file mode 100644
index 00000000..23dc498f
--- /dev/null
+++ b/regress/bin/Makefile.am
@@ -0,0 +1,27 @@
+bin_PROGRAMS= smtpscript
+
+smtpscript_SOURCES= smtpscript.c iobuf.c parse.y ssl.c
+
+smtpscript_CFLAGS= -DIO_SSL
+
+# compat
+smtpscript_SOURCES+= $(top_srcdir)/smtpd/log.c
+
+INCLUDES= -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
+CPPFLAGS= -I$(srcdir) @CPPFLAGS@ @DEFS@
+
+install-exec-hook:
+ $(MKDIR_P) $(DESTDIR)$(bindir)
+
+uninstall-hook:
+ rm $(DESTDIR)$(bindir)/smtpscript(EXEEXT)
diff --git a/regress/bin/Makefile.inc b/regress/bin/Makefile.inc
deleted file mode 100644
index be93057b..00000000
--- a/regress/bin/Makefile.inc
+++ /dev/null
@@ -1,3 +0,0 @@
-CFLAGS= -Wall -W
-
-BINDIR?= /usr/bin
diff --git a/regress/bin/parse.y b/regress/bin/parse.y
index 14942cde..a42dfa5d 100644
--- a/regress/bin/parse.y
+++ b/regress/bin/parse.y
@@ -23,6 +23,8 @@
*/
%{
+#include "includes.h"
+
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/tree.h>
@@ -43,7 +45,9 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#ifdef HAVE_UTIL_H
#include <util.h>
+#endif
#include "smtpscript.h"
diff --git a/regress/bin/smtpscript/Makefile b/regress/bin/smtpscript/Makefile
deleted file mode 100644
index 3679481c..00000000
--- a/regress/bin/smtpscript/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-.PATH: ${.CURDIR}/..
-
-PROG= smtpscript
-SRCS= smtpscript.c iobuf.c parse.y ssl.c
-NOMAN= noman
-
-LDADD+= -lutil -lssl -lcrypto
-DPADD+= ${LIBEVENT} ${LIBUTIL} ${LIBSSL} ${LIBCRYPTO}
-CPPFLAGS+= -I${.CURDIR}/..
-CPPFLAGS+= -DIO_SSL
-
-.include <bsd.prog.mk>
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/Makefile b/smtpd/Makefile
deleted file mode 100644
index e912f1e0..00000000
--- a/smtpd/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# $OpenBSD: Makefile,v 1.58 2013/01/26 09:37:24 gilles Exp $
-
-.include <bsd.own.mk>
-
-SUBDIR = makemap smtpd smtpctl backends filters
-
-.include <bsd.subdir.mk>
diff --git a/smtpd/Makefile.am b/smtpd/Makefile.am
new file mode 100644
index 00000000..44c15981
--- /dev/null
+++ b/smtpd/Makefile.am
@@ -0,0 +1,177 @@
+# In OpenBSD, smtpd's files are installed this way:
+#
+# /etc/mail/smtpd.conf
+# /usr/bin/mailq --> /usr/sbin/mailwrapper --> /usr/sbin/smtpctl
+# /usr/bin/newaliases --> /usr/sbin/mailwrapper --> /usr/libexec/smtpd/makemap
+# /usr/libexec/mail.local
+# /usr/sbin/makemap --> /usr/sbin/mailwrapper --> /usr/libexec/smtpd/makemap
+# /usr/sbin/smtpctl
+# /usr/sbin/smtpd
+#
+#
+# For OpenSMTPD portable, here's where files are installed:
+# (assuming PREFIX=/usr/local)
+#
+# /usr/local/etc/smtpd.conf
+# /usr/local/bin/mailq --> /usr/sbin/smtpctl
+# /usr/local/bin/newaliases --> /usr/local/libexec/opensmtpd-portable/makemap
+# /usr/local/libexec/mail.local
+# /usr/local/sbin/makemap --> /usr/local/libexec/opensmtpd-portable/makemap
+# /usr/local/sbin/smtpctl
+# /usr/local/sbin/smtpd
+
+SUBDIRS = backends filters
+
+sbin_PROGRAMS= smtpd smtpctl
+pkglibexec_PROGRAMS= makemap
+
+makemap_SOURCES= parse.y makemap.c aliases.c expand.c log.c util.c \
+ table.c dict.c tree.c to.c
+
+makemap_SOURCES+= table_static.c
+makemap_SOURCES+= table_db.c
+makemap_SOURCES+= table_getpwnam.c
+makemap_SOURCES+= table_proc.c
+
+makemap_CFLAGS= -DNO_IO
+
+smtpd_SOURCES= aliases.c bounce.c ca.c compress_backend.c config.c \
+ control.c delivery.c dict.c dns.c envelope.c \
+ expand.c forward.c iobuf.c ioev.c lka.c \
+ lka_session.c log.c mda.c mfa.c mfa_session.c mproc.c \
+ mta.c mta_session.c parse.y queue.c queue_backend.c \
+ ruleset.c scheduler.c scheduler_backend.c smtp.c \
+ smtp_session.c smtpd.c ssl.c ssl_privsep.c ssl_smtpd.c \
+ stat_backend.c table.c to.c tree.c util.c waitq.c
+
+# backends
+smtpd_SOURCES+= compress_gzip.c
+smtpd_SOURCES+= delivery_filename.c
+smtpd_SOURCES+= delivery_maildir.c
+smtpd_SOURCES+= delivery_mbox.c
+smtpd_SOURCES+= delivery_mda.c
+smtpd_SOURCES+= delivery_lmtp.c
+smtpd_SOURCES+= table_db.c
+smtpd_SOURCES+= table_getpwnam.c
+smtpd_SOURCES+= table_static.c
+smtpd_SOURCES+= table_proc.c
+smtpd_SOURCES+= queue_proc.c
+smtpd_SOURCES+= queue_fsqueue.c
+smtpd_SOURCES+= queue_null.c
+smtpd_SOURCES+= queue_ram.c
+smtpd_SOURCES+= scheduler_ramqueue.c
+smtpd_SOURCES+= scheduler_null.c
+smtpd_SOURCES+= stat_ramstat.c
+
+# resolver
+smtpd_SOURCES+= ../contrib/lib/libc/asr/asr.c \
+ ../contrib/lib/libc/asr/asr_debug.c \
+ ../contrib/lib/libc/asr/asr_utils.c \
+ ../contrib/lib/libc/asr/gethostnamadr_async.c \
+ ../contrib/lib/libc/asr/res_send_async.c \
+ ../contrib/lib/libc/asr/getaddrinfo_async.c \
+ ../contrib/lib/libc/asr/getnameinfo_async.c \
+ ../contrib/lib/libc/asr/res_search_async.c
+
+smtpd_CFLAGS= -DIO_SSL -DASR_OPT_THREADSAFE=0
+smtpd_CFLAGS+= -DCA_FILE=\"$(CA_FILE)\"
+
+smtpctl_SOURCES= enqueue.c parser.c log.c envelope.c \
+ queue_backend.c queue_fsqueue.c \
+ smtpctl.c util.c \
+ compress_backend.c compress_gzip.c \
+ to.c tree.c expand.c
+
+smtpctl_CFLAGS= -DNO_IO
+
+INCLUDES= -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@
+
+PATHS= -DSMTPD_CONFDIR=\"$(sysconfdir)\" \
+ -DPATH_SMTPCTL=\"$(sbindir)/smtpctl\" \
+ -DPATH_MAILLOCAL=\"$(libexecdir)/mail.local\"
+
+MANPAGES= aliases.5.out forward.5.out makemap.8.out \
+ newaliases.8.out smtpctl.8.out smtpd.8.out \
+ smtpd.conf.5.out
+MANPAGES_IN= aliases.5 forward.5 makemap.8 \
+ newaliases.8 smtpctl.8 smtpd.8 \
+ smtpd.conf.5
+
+CONFIGFILES= smtpd.conf.out
+CONFIGFILES_IN= smtpd.conf
+
+EXTRA_DIST= filter_api.h iobuf.h ioev.h log.h parser.h smtpd.h \
+ ../contrib/lib/libc/asr/asr.h \
+ ../contrib/lib/libc/asr/asr_private.h \
+ $(CONFIGFILES_IN) $(MANPAGES_IN)
+
+PATHSUBS= -e 's|/etc/mail/|$(sysconfdir)/|g' \
+ -e 's|/usr/libexec|$(libexecdir)|g' \
+ -e 's|/var/run/smtpd.sock|$(sockdir)/smtpd.sock|g'
+
+FIXPATHSCMD= $(SED) $(PATHSUBS)
+
+$(MANPAGES): $(MANPAGES_IN)
+ if test "$(MANTYPE)" = "cat"; then \
+ manpage=$(srcdir)/`echo $@ | sed 's/\.[1-9]\.out$$/\.0/'`; \
+ else \
+ manpage=$(srcdir)/`echo $@ | sed 's/\.out$$//'`; \
+ fi; \
+ if test "$(MANTYPE)" = "man"; then \
+ $(FIXPATHSCMD) $${manpage} | $(AWK) -f $(srcdir)/mdoc2man.awk > $@; \
+ else \
+ $(FIXPATHSCMD) $${manpage} > $@; \
+ fi
+
+$(CONFIGFILES): $(CONFIGFILES_IN)
+ conffile=`echo $@ | sed 's/.out$$//'`; \
+ $(FIXPATHSCMD) $(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
+
+ ln -f $(DESTDIR)$(sbindir)/smtpctl$(EXEEXT) \
+ $(DESTDIR)$(bindir)/mailq$(EXEEXT);
+
+ ln -f $(DESTDIR)$(pkglibexecdir)/makemap$(EXEEXT) \
+ $(DESTDIR)$(bindir)/newaliases$(EXEEXT);
+
+ ln -f $(DESTDIR)$(pkglibexecdir)/makemap$(EXEEXT) \
+ $(DESTDIR)$(sbindir)/makemap$(EXEEXT);
+
+ $(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 makemap.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/makemap.8
+ $(INSTALL) -m 644 newaliases.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/newaliases.8
+ $(INSTALL) -m 644 smtpctl.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/smtpctl.8
+ $(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
+
+
+uninstall-hook:
+ rm $(DESTDIR)$(bindir)/newaliases$(EXEEXT) \
+ $(DESTDIR)$(sbindir)/makemap$(EXEEXT)
diff --git a/smtpd/aldap.c b/smtpd/aldap.c
index abd5cf1d..0a0889fe 100644
--- a/smtpd/aldap.c
+++ b/smtpd/aldap.c
@@ -18,6 +18,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 f5edb795..fe1a4eaf 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/Makefile b/smtpd/backends/Makefile
deleted file mode 100644
index b2ede750..00000000
--- a/smtpd/backends/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-SUBDIR+= backend-queue-null
-SUBDIR+= backend-queue-ram
-SUBDIR+= backend-queue-stub
-SUBDIR+= backend-table-ldap
-SUBDIR+= backend-table-sqlite
-SUBDIR+= backend-table-stub
-
-.include <bsd.subdir.mk>
diff --git a/smtpd/backends/Makefile.am b/smtpd/backends/Makefile.am
new file mode 100644
index 00000000..3a54bf22
--- /dev/null
+++ b/smtpd/backends/Makefile.am
@@ -0,0 +1,33 @@
+pkglibexec_PROGRAMS= backend-queue-null backend-queue-ram backend-queue-stub
+if HAVE_LDAP
+pkglibexec_PROGRAMS+= backend-table-ldap
+endif
+if HAVE_SQLITE
+pkglibexec_PROGRAMS+= backend-table-sqlite
+endif
+pkglibexec_PROGRAMS+= backend-table-stub
+
+INCLUDES= -I$(top_srcdir)/smtpd \
+ -I$(top_srcdir)/openbsd-compat
+
+LIBCOMPAT= $(top_builddir)/openbsd-compat/libopenbsd-compat.a
+
+LDADD= $(LIBCOMPAT)
+
+SRCS= ../log.c
+
+backend_queue_null_SOURCES=$(SRCS) ../queue_api.c queue_utils.c queue_null.c
+
+backend_queue_ram_SOURCES=$(SRCS) ../queue_api.c queue_utils.c queue_ram.c ../tree.c
+
+backend_queue_stub_SOURCES=$(SRCS) ../queue_api.c queue_stub.c
+
+if HAVE_LDAP
+backend_table_ldap_SOURCES=$(SRCS) table_ldap.c ../table_api.c ../aldap.c ../ber.c
+endif
+
+if HAVE_SQLITE
+backend_table_sqlite_SOURCES=$(SRCS) table_sqlite.c ../table_api.c
+endif
+
+backend_table_stub_SOURCES=$(SRCS) table_stub.c ../table_api.c \ No newline at end of file
diff --git a/smtpd/backends/backend-queue-null/Makefile b/smtpd/backends/backend-queue-null/Makefile
deleted file mode 100644
index c28883a7..00000000
--- a/smtpd/backends/backend-queue-null/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-.PATH: ${.CURDIR}/.. ${.CURDIR}/../..
-
-PROG= backend-queue-null
-
-SRCS+= queue_api.c
-SRCS+= queue_utils.c
-SRCS+= queue_null.c
-
-NOMAN= noman
-
-.include <bsd.prog.mk>
diff --git a/smtpd/backends/backend-queue-ram/Makefile b/smtpd/backends/backend-queue-ram/Makefile
deleted file mode 100644
index 97c2ee17..00000000
--- a/smtpd/backends/backend-queue-ram/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-.PATH: ${.CURDIR}/.. ${.CURDIR}/../..
-
-PROG= backend-queue-ram
-
-SRCS+= queue_api.c
-SRCS+= queue_utils.c
-SRCS+= queue_ram.c
-SRCS+= tree.c
-
-NOMAN= noman
-
-.include <bsd.prog.mk>
diff --git a/smtpd/backends/backend-queue-stub/Makefile b/smtpd/backends/backend-queue-stub/Makefile
deleted file mode 100644
index 5e9d8ecd..00000000
--- a/smtpd/backends/backend-queue-stub/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-.PATH: ${.CURDIR}/.. ${.CURDIR}/../..
-
-PROG= backend-queue-stub
-
-SRCS+= queue_api.c
-SRCS+= queue_stub.c
-
-NOMAN= noman
-
-.include <bsd.prog.mk>
diff --git a/smtpd/backends/backend-table-ldap/Makefile b/smtpd/backends/backend-table-ldap/Makefile
deleted file mode 100644
index 504ef363..00000000
--- a/smtpd/backends/backend-table-ldap/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-.PATH: ${.CURDIR}/.. ${.CURDIR}/../..
-
-PROG= backend-table-ldap
-
-SRCS= table_ldap.c
-SRCS+= table_api.c
-SRCS+= aldap.c
-SRCS+= ber.c
-
-NOMAN= noman
-
-.include <bsd.prog.mk>
diff --git a/smtpd/backends/backend-table-sqlite/Makefile b/smtpd/backends/backend-table-sqlite/Makefile
deleted file mode 100644
index 542d5656..00000000
--- a/smtpd/backends/backend-table-sqlite/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-.PATH: ${.CURDIR}/.. ${.CURDIR}/../..
-
-PROG= backend-table-sqlite
-
-SRCS= table_sqlite.c
-SRCS+= table_api.c
-
-NOMAN= noman
-
-DPADD+= ${LIBSQLITE3}
-LDADD+= -lsqlite3
-
-.include <bsd.prog.mk>
diff --git a/smtpd/backends/backend-table-stub/Makefile b/smtpd/backends/backend-table-stub/Makefile
deleted file mode 100644
index 062a520c..00000000
--- a/smtpd/backends/backend-table-stub/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-.PATH: ${.CURDIR}/.. ${.CURDIR}/../..
-
-PROG= backend-table-stub
-
-SRCS= table_stub.c
-SRCS+= table_api.c
-
-NOMAN= noman
-
-.include <bsd.prog.mk>
diff --git a/smtpd/backends/queue_null.c b/smtpd/backends/queue_null.c
index efef4bbd..58fff210 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 6b900550..2b2b8baf 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 a322dd53..46622400 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 <getopt.h>
diff --git a/smtpd/backends/queue_utils.c b/smtpd/backends/queue_utils.c
index b74ce59d..05e58b11 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/table_ldap.c b/smtpd/backends/table_ldap.c
index 7d015ebf..9f35b95a 100644
--- a/smtpd/backends/table_ldap.c
+++ b/smtpd/backends/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/backends/table_sqlite.c b/smtpd/backends/table_sqlite.c
index b19c4570..8ba9a76d 100644
--- a/smtpd/backends/table_sqlite.c
+++ b/smtpd/backends/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/backends/table_stub.c b/smtpd/backends/table_stub.c
index 0a473fff..ade9f038 100644
--- a/smtpd/backends/table_stub.c
+++ b/smtpd/backends/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 <getopt.h>
diff --git a/smtpd/ber.c b/smtpd/ber.c
index 01da3135..8b203bc8 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 0e9172d4..4e9fcab8 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 970ccb92..50504bf5 100644
--- a/smtpd/ca.c
+++ b/smtpd/ca.c
@@ -16,6 +16,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "includes.h"
+
#include <sys/types.h>
#include <openssl/err.h>
diff --git a/smtpd/compress_backend.c b/smtpd/compress_backend.c
index ea498ebd..29b6ef54 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 f2b42803..47bb9817 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 4d89d93f..9b3f8a5a 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 c2a54d01..be0fcfb7 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>
@@ -275,6 +278,13 @@ control(void)
static void
control_shutdown(void)
{
+#ifdef VALGRIND
+ child_free();
+ free_peers();
+ clean_setproctitle();
+ event_base_free(NULL);
+#endif
+
log_info("info: control process exiting");
unlink(SMTPD_SOCKET);
_exit(0);
@@ -300,7 +310,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);
@@ -343,7 +353,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/delivery.c b/smtpd/delivery.c
index 836f0376..89f73144 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 bc340ca5..63b91501 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 aef06ae7..8c9c1dd4 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 9019a730..db8d7ba5 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 acb1c627..3b95b9f9 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 82f99b05..b2d2fbfd 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 fb82a2f4..81f112eb 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 8ceff3ce..a353c727 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>
@@ -29,6 +31,8 @@
#include <arpa/nameser.h>
#include <event.h>
+#include <netdb.h>
+#include <resolv.h>
#include <imsg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -132,7 +136,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);
async_run_event(as, dns_dispatch_ptr, s);
return;
@@ -179,7 +183,7 @@ dns_dispatch_host(int ev, struct async_res *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 4dd32f91..988f47ea 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 06126e0a..aa3910f0 100644
--- a/smtpd/envelope.c
+++ b/smtpd/envelope.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>
@@ -568,14 +570,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/expand.c b/smtpd/expand.c
index 120324c7..83553737 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_api.c b/smtpd/filter_api.c
index 95b5f0b8..2108e922 100644
--- a/smtpd/filter_api.c
+++ b/smtpd/filter_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>
diff --git a/smtpd/filters/Makefile b/smtpd/filters/Makefile
deleted file mode 100644
index a61ea609..00000000
--- a/smtpd/filters/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-SUBDIR= filter-dnsbl
-SUBDIR+= filter-monkey
-SUBDIR+= filter-stub
-SUBDIR+= filter-trace
-
-.include <bsd.subdir.mk>
diff --git a/smtpd/filters/Makefile.am b/smtpd/filters/Makefile.am
new file mode 100644
index 00000000..8e435fed
--- /dev/null
+++ b/smtpd/filters/Makefile.am
@@ -0,0 +1,38 @@
+SRCS = ../filter_api.c ../mproc.c ../log.c ../tree.c ../util.c
+
+INCLUDES= -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)
+
+CFLAGS= -DNO_IO -DBUILD_FILTER
+
+pkglibexec_PROGRAMS=filter-dnsbl filter-monkey filter-stub filter-trace
+
+filter_dnsbl_SOURCES = $(SRCS)
+filter_dnsbl_SOURCES+= filter_dnsbl.c asr_event.c
+
+# resolver
+filter_dnsbl_SOURCES+= $(top_srcdir)/contrib/lib/libc/asr/asr.c \
+ $(top_srcdir)/contrib/lib/libc/asr/asr_debug.c \
+ $(top_srcdir)/contrib/lib/libc/asr/asr_utils.c \
+ $(top_srcdir)/contrib/lib/libc/asr/gethostnamadr_async.c \
+ $(top_srcdir)/contrib/lib/libc/asr/res_send_async.c \
+ $(top_srcdir)/contrib/lib/libc/asr/getaddrinfo_async.c \
+ $(top_srcdir)/contrib/lib/libc/asr/getnameinfo_async.c \
+ $(top_srcdir)/contrib/lib/libc/asr/res_search_async.c
+
+filter_dnsbl_CFLAGS= -DASR_OPT_THREADSAFE=0
+
+filter_monkey_SOURCES= $(SRCS)
+filter_monkey_SOURCES+= filter_monkey.c
+
+filter_stub_SOURCES= $(SRCS)
+filter_stub_SOURCES+= filter_stub.c
+
+filter_trace_SOURCES= $(SRCS)
+filter_trace_SOURCES+= filter_trace.c
+
diff --git a/smtpd/filters/asr_event.c b/smtpd/filters/asr_event.c
index b89b27b0..9df16b4c 100644
--- a/smtpd/filters/asr_event.c
+++ b/smtpd/filters/asr_event.c
@@ -15,6 +15,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/filters/filter-dnsbl/Makefile b/smtpd/filters/filter-dnsbl/Makefile
deleted file mode 100644
index 9f4d9b10..00000000
--- a/smtpd/filters/filter-dnsbl/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-.PATH: ${.CURDIR}/.. ${.CURDIR}/../.. /usr/src/lib/libc/asr
-
-PROG= filter-dnsbl
-SRCS= filter_dnsbl.c
-SRCS+= asr_event.c
-
-# resolver
-SRCS+= asr.c asr_debug.c asr_utils.c getaddrinfo_async.c \
- res_send_async.c res_search_async.c
-
-NOMAN= noman
-
-CFLAGS+= -I/usr/src/lib/libc/asr
-CFLAGS+= -DASR_OPT_THREADSAFE=0
-
-.include <bsd.prog.mk>
diff --git a/smtpd/filters/filter-monkey/Makefile b/smtpd/filters/filter-monkey/Makefile
deleted file mode 100644
index 8371cd23..00000000
--- a/smtpd/filters/filter-monkey/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-.PATH: ${.CURDIR}/.. ${.CURDIR}/../..
-
-PROG= filter-monkey
-SRCS= filter_monkey.c
-
-NOMAN= noman
-
-.include <bsd.prog.mk>
diff --git a/smtpd/filters/filter-stub/Makefile b/smtpd/filters/filter-stub/Makefile
deleted file mode 100644
index e7775e08..00000000
--- a/smtpd/filters/filter-stub/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-.PATH: ${.CURDIR}/.. ${.CURDIR}/../..
-
-PROG= filter-stub
-SRCS= filter_stub.c
-
-NOMAN= noman
-
-.include <bsd.prog.mk>
diff --git a/smtpd/filters/filter-trace/Makefile b/smtpd/filters/filter-trace/Makefile
deleted file mode 100644
index 0c8d2507..00000000
--- a/smtpd/filters/filter-trace/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-.PATH: ${.CURDIR}/.. ${.CURDIR}/../..
-
-PROG= filter-trace
-SRCS= filter_trace.c
-
-NOMAN= noman
-
-.include <bsd.prog.mk>
diff --git a/smtpd/filters/filter_dnsbl.c b/smtpd/filters/filter_dnsbl.c
index 6ca07cbc..bdda46c3 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>
diff --git a/smtpd/filters/filter_monkey.c b/smtpd/filters/filter_monkey.c
index f82eb69a..83d222b4 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 <getopt.h>
diff --git a/smtpd/filters/filter_stub.c b/smtpd/filters/filter_stub.c
index 936a25b5..1b25fe52 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 3f2df8ae..c83c466d 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 <getopt.h>
diff --git a/smtpd/forward.c b/smtpd/forward.c
index 681beb84..7f3a7ff6 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 579b9a10..9fe269b4 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 f9fa6e96..fcd24526 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>
@@ -597,10 +599,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/libsmtpdfilter/Makefile b/smtpd/libsmtpdfilter/Makefile
deleted file mode 100644
index d9bc7092..00000000
--- a/smtpd/libsmtpdfilter/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-# $OpenBSD: Makefile,v 1.3 2012/08/02 13:38:39 okan Exp $
-
-.PATH: ${.CURDIR}/..
-
-CFLAGS = -DNO_IO
-LIB = smtpdfilter
-SRCS = filter_api.c dict.c tree.c util.c iobuf.c log.c
-DEBUGLIBS = no
-NOPROFILE = yes
-NOPIC= yes
-
-install:
- @echo -n
-
-.include <bsd.own.mk>
-.include <bsd.lib.mk>
diff --git a/smtpd/lka.c b/smtpd/lka.c
index eb7378f5..c3eeb70a 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>
@@ -565,6 +569,12 @@ lka_sig_handler(int sig, short event, void *p)
void
lka_shutdown(void)
{
+#ifdef VALGRIND
+ child_free();
+ free_peers();
+ clean_setproctitle();
+ event_base_free(NULL);
+#endif
log_info("info: lookup agent exiting");
_exit(0);
}
diff --git a/smtpd/lka_session.c b/smtpd/lka_session.c
index 1f486248..e60e43fa 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>
@@ -365,6 +367,11 @@ lka_expand(struct lka_session *lks, struct rule *rule, struct expandnode *xn)
/* no aliases found, query forward file */
lks->rule = rule;
lks->node = xn;
+
+#ifdef VALGRIND
+ bzero(&fwreq, sizeof(fwreq));
+#endif
+
fwreq.id = lks->id;
(void)strlcpy(fwreq.user, lk.userinfo.username, sizeof(fwreq.user));
(void)strlcpy(fwreq.directory, lk.userinfo.directory, sizeof(fwreq.directory));
diff --git a/smtpd/log.c b/smtpd/log.c
index 394b761d..8f9cad8b 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 19367f8b..b4d00278 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 55a6c747..fe529fa9 100644
--- a/smtpd/makemap.c
+++ b/smtpd/makemap.c
@@ -17,13 +17,24 @@
* 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>
#include <sys/queue.h>
#include <sys/socket.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 <errno.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/makemap/Makefile b/smtpd/makemap/Makefile
deleted file mode 100644
index 0f9dec1c..00000000
--- a/smtpd/makemap/Makefile
+++ /dev/null
@@ -1,29 +0,0 @@
-# $OpenBSD: Makefile,v 1.16 2012/10/14 11:58:23 gilles Exp $
-
-.PATH: ${.CURDIR}/..
-
-PROG= makemap
-BINOWN= root
-
-BINMODE?=555
-
-BINDIR= /usr/libexec/smtpd
-MAN= makemap.8 newaliases.8
-
-CFLAGS+= -g3 -ggdb -I${.CURDIR}/..
-CFLAGS+= -Wall -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS+= -Wmissing-declarations
-CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
-CFLAGS+= -Wsign-compare -Wbounded
-CFLAGS+= -DNO_IO
-
-SRCS= parse.y makemap.c aliases.c expand.c log.c util.c table.c dict.c tree.c to.c
-
-SRCS+= table_static.c
-SRCS+= table_db.c
-SRCS+= table_getpwnam.c
-SRCS+= table_proc.c
-
-DPADD+= ${LIBUTIL} ${LIBCRYPTO} ${LIBZ}
-LDADD+= -lutil -lcrypto -lz
-.include <bsd.prog.mk>
diff --git a/smtpd/mda.c b/smtpd/mda.c
index 7f5c01f8..53de17b0 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"
@@ -157,6 +162,10 @@ mda_imsg(struct mproc *p, struct imsg *imsg)
}
}
+#ifdef VALGRIND
+ bzero(&deliver, sizeof(deliver));
+#endif
+
if (p->proc == PROC_QUEUE) {
switch (imsg->hdr.type) {
@@ -484,6 +493,13 @@ mda_sig_handler(int sig, short event, void *p)
static void
mda_shutdown(void)
{
+#ifdef VALGRIND
+ child_free();
+ free_peers();
+ clean_setproctitle();
+ event_base_free(NULL);
+#endif
+
log_info("info: mail delivery agent exiting");
_exit(0);
}
diff --git a/smtpd/mfa.c b/smtpd/mfa.c
index 11889191..f3f2dbef 100644
--- a/smtpd/mfa.c
+++ b/smtpd/mfa.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/wait.h>
#include <sys/queue.h>
@@ -26,6 +28,7 @@
#include <err.h>
#include <errno.h>
#include <event.h>
+#include <grp.h> /* needed for setgroups */
#include <imsg.h>
#include <pwd.h>
#include <signal.h>
@@ -203,6 +206,13 @@ mfa_shutdown(void)
pid = waitpid(WAIT_MYPGRP, NULL, 0);
} while (pid != -1 || (pid == -1 && errno == EINTR));
+#ifdef VALGRIND
+ child_free();
+ free_peers();
+ clean_setproctitle();
+ event_base_free(NULL);
+#endif
+
log_info("info: mail filter exiting");
_exit(0);
}
diff --git a/smtpd/mfa_session.c b/smtpd/mfa_session.c
index a907b139..3075824f 100644
--- a/smtpd/mfa_session.c
+++ b/smtpd/mfa_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>
@@ -171,8 +173,8 @@ mfa_filter_connect(uint64_t id, const struct sockaddr *local,
q = mfa_query(s, QT_QUERY, HOOK_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 = MFA_OK;
diff --git a/smtpd/mproc.c b/smtpd/mproc.c
index a881021d..c13abaac 100644
--- a/smtpd/mproc.c
+++ b/smtpd/mproc.c
@@ -16,6 +16,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "includes.h"
+
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/tree.h>
@@ -60,9 +62,7 @@ mproc_fork(struct mproc *p, const char *path, const char *arg)
if (p->pid == 0) {
/* child process */
dup2(sp[0], STDIN_FILENO);
- if (closefrom(STDERR_FILENO + 1) < 0)
- exit(1);
-
+ closefrom(STDERR_FILENO + 1);
execl(path, arg, NULL);
err(1, "execl");
}
@@ -559,7 +559,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 22775e8a..58043c47 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>
@@ -407,6 +410,13 @@ mta_sig_handler(int sig, short event, void *p)
static void
mta_shutdown(void)
{
+#ifdef VALGRIND
+ child_free();
+ free_peers();
+ clean_setproctitle();
+ event_base_free(NULL);
+#endif
+
log_info("info: mail transfer agent exiting");
_exit(0);
}
@@ -1389,13 +1399,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);
}
@@ -1439,11 +1449,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);
@@ -1516,7 +1526,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;
@@ -1525,7 +1535,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);
}
@@ -1569,11 +1579,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 8553c884..0b78249e 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>
@@ -475,7 +477,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;
sa_set_port(sa, portno);
diff --git a/smtpd/parse.y b/smtpd/parse.y
index 98a1486c..775d85aa 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 "smtpd.h"
#include "log.h"
@@ -1526,7 +1532,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;
@@ -1547,7 +1555,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));
@@ -1595,13 +1605,17 @@ host_dns(const char *s, const char *tag, const char *cert,
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 = 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 = port;
@@ -1686,14 +1700,18 @@ interface(const char *s, const char *tag, const char *cert,
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 = 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 = port;
break;
@@ -1741,6 +1759,10 @@ set_localaddrs(void)
table_add(t, "0.0.0.0/0", NULL);
table_add(t, "::/0", NULL);
+#ifdef VALGRIND
+ bzero(&ss, sizeof(ss));
+#endif
+
if (getifaddrs(&ifap) == -1)
fatal("getifaddrs");
@@ -1754,14 +1776,18 @@ set_localaddrs(void)
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);
break;
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);
break;
}
@@ -1819,6 +1845,11 @@ bad:
int
is_if_in_group(const char *ifname, const char *groupname)
{
+#ifndef OpenBSD
+ if (strcmp(groupname, "all") == 0)
+ return (1);
+ return (0);
+#else
unsigned int len;
struct ifgroupreq ifgr;
struct ifg_req *ifg;
@@ -1856,4 +1887,5 @@ is_if_in_group(const char *ifname, const char *groupname)
end:
close(s);
return ret;
+#endif
}
diff --git a/smtpd/parser.c b/smtpd/parser.c
index 2ed0a08f..0f5020a1 100644
--- a/smtpd/parser.c
+++ b/smtpd/parser.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/queue.h>
diff --git a/smtpd/queue.c b/smtpd/queue.c
index 1c7ceeb1..01f09fd8 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>
@@ -516,6 +520,13 @@ queue_sig_handler(int sig, short event, void *p)
static void
queue_shutdown(void)
{
+#ifdef VALGRIND
+// child_free();
+ free_peers();
+ clean_setproctitle();
+ event_base_free(NULL);
+#endif
+
log_info("info: queue handler exiting");
_exit(0);
}
diff --git a/smtpd/queue_backend.c b/smtpd/queue_backend.c
index 482446e4..dc042e67 100644
--- a/smtpd/queue_backend.c
+++ b/smtpd/queue_backend.c
@@ -16,6 +16,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "includes.h"
+
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/tree.h>
diff --git a/smtpd/queue_fsqueue.c b/smtpd/queue_fsqueue.c
index 00348562..cb6c833d 100644
--- a/smtpd/queue_fsqueue.c
+++ b/smtpd/queue_fsqueue.c
@@ -16,11 +16,16 @@
* 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>
#include <sys/mount.h>
@@ -114,7 +119,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
@@ -666,7 +675,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 40fac324..0393e557 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 b5df0fee..190cbfb6 100644
--- a/smtpd/queue_proc.c
+++ b/smtpd/queue_proc.c
@@ -82,8 +82,7 @@ queue_proc_init(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(path, "queue_ramproc", NULL);
err(1, "execl");
diff --git a/smtpd/queue_ram.c b/smtpd/queue_ram.c
index 9ba6eacb..764831cf 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 ff67285a..07498c09 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/scheduler.c b/smtpd/scheduler.c
index 1c168016..b67c1cd5 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_backend.c b/smtpd/scheduler_backend.c
index 8dfef173..1d9627da 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 c90ecb77..c651eebb 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_ramqueue.c b/smtpd/scheduler_ramqueue.c
index 72a7d4c1..b545117f 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 be5ab37e..55f87728 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>
@@ -224,6 +227,13 @@ smtp_sig_handler(int sig, short event, void *p)
static void
smtp_shutdown(void)
{
+#ifdef VALGRIND
+// child_free();
+ free_peers();
+ clean_setproctitle();
+ event_base_free(NULL);
+#endif
+
log_info("info: smtp server exiting");
_exit(0);
}
@@ -321,8 +331,10 @@ smtp_setup_events(void)
purge_config(PURGE_SSL);
+ /* 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
@@ -360,7 +372,9 @@ smtp_enqueue(uid_t *euid)
listener = &local;
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
}
/*
@@ -450,7 +464,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 5ba4d9a4..f53c83fb 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>
diff --git a/smtpd/smtpctl.c b/smtpd/smtpctl.c
index 275d8264..87502c30 100644
--- a/smtpd/smtpctl.c
+++ b/smtpd/smtpctl.c
@@ -20,6 +20,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>
@@ -27,6 +29,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>
diff --git a/smtpd/smtpctl/Makefile b/smtpd/smtpctl/Makefile
deleted file mode 100644
index a4d95a55..00000000
--- a/smtpd/smtpctl/Makefile
+++ /dev/null
@@ -1,29 +0,0 @@
-# $OpenBSD: Makefile,v 1.29 2012/10/07 15:46:38 chl Exp $
-
-.PATH: ${.CURDIR}/..
-
-PROG= smtpctl
-BINOWN= root
-
-BINMODE?=555
-
-BINDIR= /usr/sbin
-MAN= smtpctl.8
-
-CFLAGS+= -g3 -ggdb -I${.CURDIR}/..
-CFLAGS+= -Wall -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS+= -Wmissing-declarations
-CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
-CFLAGS+= -Wsign-compare -Wbounded
-CFLAGS+= -DNO_IO
-
-SRCS= enqueue.c parser.c log.c envelope.c
-SRCS+= queue_backend.c queue_fsqueue.c
-SRCS+= smtpctl.c util.c
-SRCS+= compress_backend.c compress_gzip.c
-SRCS+= to.c expand.c tree.c
-
-LDADD+= -lutil -lz
-DPADD+= ${LIBUTIL} ${LIBZ}
-
-.include <bsd.prog.mk>
diff --git a/smtpd/smtpd.8 b/smtpd/smtpd.8
index e4d298a4..1e5a8104 100644
--- a/smtpd/smtpd.8
+++ b/smtpd/smtpd.8
@@ -88,17 +88,8 @@ Do not listen on SMTP sockets.
Produce more verbose output.
.El
.Pp
-.Nm
-is not enabled by default.
-In order to use it as the system mailer,
-ensure the mail queue is empty,
-then stop
-.Xr sendmail 8 :
-.Bd -literal -offset indent
-# /etc/rc.d/sendmail stop
-.Ed
-.Pp
-Modify the current
+If you are running a BSD Operating System,
+you should use and modify
.Xr mailwrapper 8
settings by editing
.Pa /etc/mailer.conf :
@@ -114,8 +105,6 @@ Rebuild the aliases database,
and enable the daemon:
.Bd -literal -offset indent
# newaliases
-# echo "sendmail_flags=NO" \*(Gt\*(Gt /etc/rc.conf.local
-# echo "smtpd_flags=" \*(Gt\*(Gt /etc/rc.conf.local
# /etc/rc.d/smtpd start
.Ed
.Sh FILES
diff --git a/smtpd/smtpd.c b/smtpd/smtpd.c
index 15e5b1f0..a303e942 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,18 +30,38 @@
#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>
@@ -137,6 +160,53 @@ int foreground = 0;
struct tree children;
+/* Saved arguments to main(). */
+char **saved_argv;
+int saved_argc;
+
+#ifdef VALGRIND
+void clean_setproctitle(void)
+{
+ int i;
+
+ log_debug("clean_setproctitle");
+
+ for (i = 0; i < saved_argc; i++)
+ free(saved_argv[i]);
+
+ free(saved_argv);
+
+#if defined(SPT_TYPE) && SPT_TYPE == SPT_REUSEARGV
+ for (i = 0; environ[i] != NULL; i++)
+ free(environ[i]);
+ free(environ);
+#endif
+}
+
+void
+child_free(void)
+{
+ void *iter;
+ struct child *child;
+
+ iter = NULL;
+ while (tree_iter(&children, &iter, NULL, (void**)&child))
+ if (child) {
+ free(child);
+ child = NULL;
+ }
+}
+
+void
+free_all(void)
+{
+ child_free();
+ purge_config(PURGE_EVERYTHING);
+ clean_setproctitle();
+ EVP_cleanup();
+}
+#endif /* VALGRIND */
+
static void
parent_imsg(struct mproc *p, struct imsg *imsg)
{
@@ -312,6 +382,15 @@ parent_shutdown(void)
pid = waitpid(WAIT_MYPGRP, NULL, 0);
} while (pid != -1 || (pid == -1 && errno == EINTR));
+#ifdef VALGRIND
+ child_free();
+ purge_config(PURGE_EVERYTHING);
+ free_pipes();
+ free_peers();
+ clean_setproctitle();
+ event_base_free(NULL);
+#endif
+
log_warnx("warn: parent terminating");
exit(0);
}
@@ -357,10 +436,15 @@ parent_send_config_smtp(void)
if ((l->fd = socket(l->ss.ss_family, SOCK_STREAM, 0)) == -1)
fatal("smtpd: socket");
opt = 1;
+#ifdef SO_REUSEADDR
if (setsockopt(l->fd, SOL_SOCKET, SO_REUSEADDR, &opt,
sizeof(opt)) < 0)
+#else
+ if (setsockopt(l->fd, SOL_SOCKET, SO_REUSEPORT, &opt,
+ sizeof(opt)) < 0)
+#endif
fatal("smtpd: setsockopt");
- if (bind(l->fd, (struct sockaddr *)&l->ss, l->ss.ss_len) == -1)
+ if (bind(l->fd, (struct sockaddr *)&l->ss, SS_LEN(&l->ss)) == -1)
fatal("smtpd: bind");
m_compose(p_smtp, IMSG_CONF_LISTENER, 0, 0, l->fd,
l, sizeof(*l));
@@ -592,6 +676,19 @@ main(int argc, char *argv[])
struct rule *r;
struct ssl *ssl;
+ /* 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;
@@ -701,6 +798,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");
@@ -783,7 +882,7 @@ main(int argc, char *argv[])
if (!(l->flags & F_SSL))
continue;
ssl = NULL;
- if (! ssl_load_certfile(&ssl, "/etc/mail/certs",
+ if (! ssl_load_certfile(&ssl, SMTPD_CONFDIR "/certs",
l->ssl_cert_name, F_SCERT))
errx(1, "cannot load certificate: %s", l->ssl_cert_name);
dict_set(env->sc_ssl_dict, ssl->ssl_name, ssl);
@@ -796,7 +895,7 @@ main(int argc, char *argv[])
if (! r->r_value.relayhost.cert[0])
continue;
ssl = NULL;
- if (! ssl_load_certfile(&ssl, "/etc/mail/certs",
+ if (! ssl_load_certfile(&ssl, SMTPD_CONFDIR "/certs",
r->r_value.relayhost.cert, F_CCERT))
errx(1, "cannot load certificate: %s", r->r_value.relayhost.cert);
dict_set(env->sc_ssl_dict, ssl->ssl_name, ssl);
@@ -844,6 +943,8 @@ main(int argc, char *argv[])
purge_timeout.tv_usec = 0;
evtimer_add(&purge_ev, &purge_timeout);
+ log_debug("libevent %s (%s)", event_get_version(), event_get_method());
+
if (event_dispatch() < 0)
fatal("smtpd: event_dispatch");
@@ -934,6 +1035,9 @@ purge_task(int fd, short ev, void *arg)
setresuid(uid, uid, uid))
fatal("smtpd: cannot drop privileges");
rmtree("/", 1);
+#ifdef VALGRIND
+ free_all();
+#endif
_exit(0);
break;
default:
@@ -1044,8 +1148,7 @@ forkmda(struct mproc *p, uint64_t id, struct deliver *deliver)
dup2(allout, STDOUT_FILENO) < 0 ||
dup2(allout, STDERR_FILENO) < 0)
error("forkmda: dup2");
- if (closefrom(STDERR_FILENO + 1) < 0)
- error("closefrom");
+ closefrom(STDERR_FILENO + 1);
if (setgroups(1, &deliver->userinfo.gid) ||
setresgid(deliver->userinfo.gid, deliver->userinfo.gid, deliver->userinfo.gid) ||
setresuid(deliver->userinfo.uid, deliver->userinfo.uid, deliver->userinfo.uid))
@@ -1144,10 +1247,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) {
@@ -1164,10 +1269,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);
@@ -1198,6 +1304,10 @@ offline_enqueue(char *name)
envp[1] = (char *)NULL;
environ = envp;
+#ifdef VALGRIND
+ free_all();
+#endif
+
execvp(PATH_SMTPCTL, args.list);
_exit(1);
}
@@ -1523,8 +1633,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];
@@ -1538,6 +1649,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("smtpd", 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..2764b43e
--- /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/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 2f6780a0..87f6253b 100644
--- a/smtpd/smtpd.conf.5
+++ b/smtpd/smtpd.conf.5
@@ -606,9 +606,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 6b2a4bda..c5de0b25 100644
--- a/smtpd/smtpd.h
+++ b/smtpd/smtpd.h
@@ -18,6 +18,18 @@
* 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 <sys/param.h>
+
+#include <imsg.h>
+
+#include "openbsd-compat.h"
+
#ifndef nitems
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
#endif
@@ -27,8 +39,11 @@
#include "ioev.h"
#include "iobuf.h"
-#define CONF_FILE "/etc/mail/smtpd.conf"
-#define CA_FILE "/etc/ssl/cert.pem"
+
+#ifndef SMTPD_CONFDIR
+#define SMTPD_CONFDIR "/etc"
+#endif
+#define CONF_FILE SMTPD_CONFDIR "/smtpd.conf"
#define MAX_LISTEN 16
#define PROC_COUNT 10
#define MAX_NAME_SIZE 64
@@ -48,20 +63,33 @@
#define SMTPD_QUEUE_INTERVAL (15 * 60)
#define SMTPD_QUEUE_MAXINTERVAL (4 * 60 * 60)
#define SMTPD_QUEUE_EXPIRY (4 * 24 * 60 * 60)
+#ifndef SMTPD_USER
#define SMTPD_USER "_smtpd"
+#endif
+#ifndef SMTPD_LOOKUP_USER
#define SMTPD_LOOKUP_USER "_smtpl"
+#endif
+#ifndef SMTPD_FILTER_USER
#define SMTPD_FILTER_USER "_smtpf"
+#endif
+#ifndef SMTPD_QUEUE_USER
#define SMTPD_QUEUE_USER "_smtpq"
-#define SMTPD_SOCKET "/var/run/smtpd.sock"
+#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 "5.3"
+#define SMTPD_VERSION "5.3p1"
#define SMTPD_BANNER "220 %s ESMTP %s"
#define SMTPD_SESSION_TIMEOUT 300
#define SMTPD_BACKLOG 5
+#ifndef PATH_SMTPCTL
#define PATH_SMTPCTL "/usr/sbin/smtpctl"
+#endif
#define PATH_SPOOL "/var/spool/smtpd"
#define PATH_OFFLINE "/offline"
diff --git a/smtpd/smtpd/Makefile b/smtpd/smtpd/Makefile
deleted file mode 100644
index 10e1c042..00000000
--- a/smtpd/smtpd/Makefile
+++ /dev/null
@@ -1,58 +0,0 @@
-# $OpenBSD: Makefile,v 1.57 2012/10/14 11:58:23 gilles Exp $
-
-.PATH: ${.CURDIR}/.. /usr/src/lib/libc/asr
-
-PROG= smtpd
-
-SRCS= aliases.c bounce.c ca.c compress_backend.c config.c \
- control.c delivery.c dict.c dns.c envelope.c \
- expand.c forward.c iobuf.c ioev.c lka.c lka_session.c \
- log.c mda.c mfa.c mfa_session.c mproc.c \
- mta.c mta_session.c parse.y queue.c queue_backend.c \
- ruleset.c scheduler.c scheduler_backend.c \
- smtp.c smtp_session.c smtpd.c ssl.c ssl_privsep.c \
- ssl_smtpd.c stat_backend.c table.c to.c tree.c util.c \
- waitq.c
-
-# backends
-SRCS+= compress_gzip.c
-SRCS+= delivery_filename.c
-SRCS+= delivery_maildir.c
-SRCS+= delivery_mbox.c
-SRCS+= delivery_mda.c
-SRCS+= delivery_lmtp.c
-SRCS+= table_db.c
-SRCS+= table_getpwnam.c
-SRCS+= table_proc.c
-SRCS+= table_static.c
-SRCS+= queue_fsqueue.c
-SRCS+= queue_null.c
-SRCS+= queue_proc.c
-SRCS+= queue_ram.c
-SRCS+= scheduler_ramqueue.c
-SRCS+= scheduler_null.c
-SRCS+= stat_ramstat.c
-
-# resolver
-SRCS+= asr.c asr_debug.c asr_utils.c gethostnamadr_async.c \
- res_send_async.c getaddrinfo_async.c getnameinfo_async.c \
- res_search_async.c
-
-MAN= smtpd.8 smtpd.conf.5
-BINDIR= /usr/sbin
-
-LDADD+= -levent -lutil -lssl -lcrypto -lm -lz
-DPADD+= ${LIBEVENT} ${LIBUTIL} ${LIBSSL} ${LIBCRYPTO} ${LIBM} ${LIBZ}
-CFLAGS+= -g3 -ggdb -I${.CURDIR}/.. -I/usr/src/lib/libc/asr
-CFLAGS+= -Wall -Wstrict-prototypes -Wmissing-prototypes
-CFLAGS+= -Wmissing-declarations
-CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
-CFLAGS+= -Wsign-compare -Wbounded
-#CFLAGS+= -Werror # during development phase (breaks some archs)
-CFLAGS+= -DIO_SSL
-CFLAGS+= -DQUEUE_PROFILING
-CFLAGS+= -DASR_OPT_THREADSAFE=0
-YFLAGS=
-
-.include <bsd.prog.mk>
-
diff --git a/smtpd/smtpfilter.c b/smtpd/smtpfilter.c
index d39f6ec5..02fc6e48 100644
--- a/smtpd/smtpfilter.c
+++ b/smtpd/smtpfilter.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/ssl.c b/smtpd/ssl.c
index e7ba0d2b..2f141576 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>
diff --git a/smtpd/ssl_privsep.c b/smtpd/ssl_privsep.c
index ffd62166..0c93397f 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 dfdfb92c..a50282c1 100644
--- a/smtpd/ssl_smtpd.c
+++ b/smtpd/ssl_smtpd.c
@@ -18,6 +18,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "includes.h"
+
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/tree.h>
diff --git a/smtpd/stat_backend.c b/smtpd/stat_backend.c
index 79962761..4b6393dd 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 bdf11ad8..14cfd855 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 db080c68..bd51feb1 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>
@@ -371,7 +373,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);
}
@@ -665,7 +667,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);
@@ -688,7 +692,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;
@@ -697,7 +703,7 @@ parse_sockaddr(struct sockaddr *sa, int family, const char *str)
if (IN6_IS_ADDR_LINKLOCAL(&in6a) ||
IN6_IS_ADDR_MC_LINKLOCAL(&in6a) ||
- IN6_IS_ADDR_MC_INTFACELOCAL(&in6a))
+ IN6_IS_ADDR_MC_NODELOCAL(&in6a))
if ((sin6->sin6_scope_id = if_nametoindex(cp)))
return (0);
diff --git a/smtpd/table_db.c b/smtpd/table_db.c
index 82542dc1..f44a7566 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 35d4af6c..337e1859 100644
--- a/smtpd/table_getpwnam.c
+++ b/smtpd/table_getpwnam.c
@@ -16,6 +16,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "includes.h"
+
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/tree.h>
diff --git a/smtpd/table_proc.c b/smtpd/table_proc.c
index afa4576f..5f5da9b3 100644
--- a/smtpd/table_proc.c
+++ b/smtpd/table_proc.c
@@ -87,8 +87,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_static.c b/smtpd/table_static.c
index 7cd029d8..b0f33746 100644
--- a/smtpd/table_static.c
+++ b/smtpd/table_static.c
@@ -17,6 +17,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "includes.h"
+
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/tree.h>
diff --git a/smtpd/to.c b/smtpd/to.c
index f58070af..1c6219c7 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;
bzero(&sa_in6, 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;
}
@@ -593,7 +619,7 @@ text_to_userinfo(struct userinfo *userinfo, const char *s)
*p++ = *s++;
if (*s++ != ':')
goto error;
- userinfo->uid = strtonum(buf, 0, UID_MAX, &errstr);
+ userinfo->uid = strtonum(buf, 0, UINT_MAX, &errstr);
if (errstr)
goto error;
@@ -603,7 +629,7 @@ text_to_userinfo(struct userinfo *userinfo, const char *s)
*p++ = *s++;
if (*s++ != ':')
goto error;
- userinfo->gid = strtonum(buf, 0, GID_MAX, &errstr);
+ userinfo->gid = strtonum(buf, 0, UINT_MAX, &errstr);
if (errstr)
goto error;
@@ -833,3 +859,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 8e0b7fee..8a7aca6c 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 0296763f..69eca9d6 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>
@@ -613,7 +615,7 @@ sa_set_port(struct sockaddr *sa, int port)
struct addrinfo hints, *res;
int error;
- error = getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0,
+ error = getnameinfo(sa, SA_LEN(sa), hbuf, sizeof(hbuf), NULL, 0,
NI_NUMERICHOST);
if (error)
fatalx("sa_set_port: getnameinfo failed");
@@ -654,6 +656,8 @@ fdlimit(double percent)
fatalx("fdlimit: parameter out of range");
if (getrlimit(RLIMIT_NOFILE, &rl) == -1)
fatal("fdlimit: getrlimit");
+ if (rl.rlim_max == RLIM_INFINITY)
+ rl.rlim_max = OPEN_MAX;
rl.rlim_cur = percent * rl.rlim_max;
if (setrlimit(RLIMIT_NOFILE, &rl) == -1)
fatal("fdlimit: setrlimit");
diff --git a/smtpd/waitq.c b/smtpd/waitq.c
index 6bc10d72..16c14652 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>