aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog35
-rw-r--r--ChangeLog-asr224
-rw-r--r--ChangeLog-mail.local306
-rw-r--r--ChangeLog-smtpd10054
-rw-r--r--INSTALL237
-rw-r--r--LICENSE330
-rw-r--r--Makefile.am3
-rw-r--r--README34
-rw-r--r--README.md145
-rw-r--r--THANKS10
-rwxr-xr-xbootstrap151
-rw-r--r--configure.ac2519
-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/Entries28
-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.c1100
-rw-r--r--contrib/lib/libc/asr/asr.h105
-rw-r--r--contrib/lib/libc/asr/asr_debug.c380
-rw-r--r--contrib/lib/libc/asr/asr_private.h363
-rw-r--r--contrib/lib/libc/asr/asr_utils.c456
-rw-r--r--contrib/lib/libc/asr/async_resolver.3358
-rw-r--r--contrib/lib/libc/asr/getaddrinfo.c50
-rw-r--r--contrib/lib/libc/asr/getaddrinfo_async.c754
-rw-r--r--contrib/lib/libc/asr/gethostnamadr.c153
-rw-r--r--contrib/lib/libc/asr/gethostnamadr_async.c746
-rw-r--r--contrib/lib/libc/asr/getnameinfo.c49
-rw-r--r--contrib/lib/libc/asr/getnameinfo_async.c277
-rw-r--r--contrib/lib/libc/asr/getnetnamadr.c124
-rw-r--r--contrib/lib/libc/asr/getnetnamadr_async.c440
-rw-r--r--contrib/lib/libc/asr/getrrsetbyname.c79
-rw-r--r--contrib/lib/libc/asr/getrrsetbyname_async.c590
-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.c104
-rw-r--r--contrib/lib/libc/asr/res_query.c91
-rw-r--r--contrib/lib/libc/asr/res_search_async.c223
-rw-r--r--contrib/lib/libc/asr/res_send.c50
-rw-r--r--contrib/lib/libc/asr/res_send_async.c768
-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--openbsd-compat/Makefile.am14
-rw-r--r--openbsd-compat/NOTES32
-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.c325
-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.h176
-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.h612
-rw-r--r--openbsd-compat/sys-tree.h679
-rw-r--r--openbsd-compat/vis.c225
-rw-r--r--openbsd-compat/vis.h95
-rw-r--r--openbsd-compat/xmalloc.c127
-rw-r--r--openbsd-compat/xmalloc.h35
-rw-r--r--regress/Makefile.am1
-rw-r--r--regress/bin/Makefile3
-rw-r--r--regress/bin/Makefile.am25
-rw-r--r--regress/bin/Makefile.inc3
-rw-r--r--regress/bin/parse.y8
-rw-r--r--regress/bin/smtpscript/Makefile10
-rw-r--r--smtpd/Makefile7
-rw-r--r--smtpd/Makefile.am166
-rw-r--r--smtpd/aliases.c13
-rw-r--r--smtpd/auth.c6
-rw-r--r--smtpd/auth_bsd.c12
-rw-r--r--smtpd/auth_pwd.c9
-rw-r--r--smtpd/bounce.c6
-rw-r--r--smtpd/compress_backend.c6
-rw-r--r--smtpd/compress_gzip.c6
-rw-r--r--smtpd/config.c35
-rw-r--r--smtpd/control.c20
-rw-r--r--smtpd/delivery.c6
-rw-r--r--smtpd/delivery_filename.c13
-rw-r--r--smtpd/delivery_maildir.c6
-rw-r--r--smtpd/delivery_mbox.c8
-rw-r--r--smtpd/delivery_mda.c6
-rw-r--r--smtpd/dns.c14
-rw-r--r--smtpd/enqueue.c6
-rw-r--r--smtpd/envelope.c12
-rw-r--r--smtpd/expand.c12
-rw-r--r--smtpd/filter_api.c4
-rw-r--r--smtpd/forward.c6
-rw-r--r--smtpd/iobuf.c2
-rw-r--r--smtpd/ioev.c8
-rw-r--r--smtpd/libsmtpdfilter/Makefile19
-rw-r--r--smtpd/lka.c16
-rw-r--r--smtpd/lka_session.c13
-rw-r--r--smtpd/log.c9
-rw-r--r--smtpd/log.h2
-rw-r--r--smtpd/makemap.84
-rw-r--r--smtpd/makemap.c37
-rw-r--r--smtpd/makemap/Makefile25
-rw-r--r--smtpd/mda.c22
-rw-r--r--smtpd/mfa.c35
-rw-r--r--smtpd/mfa_session.c8
-rw-r--r--smtpd/mta.c14
-rw-r--r--smtpd/mta_session.c10
-rw-r--r--smtpd/parse.y38
-rw-r--r--smtpd/parser.c20
-rw-r--r--smtpd/parser.h14
-rw-r--r--smtpd/queue.c21
-rw-r--r--smtpd/queue_backend.c6
-rw-r--r--smtpd/queue_fsqueue.c11
-rw-r--r--smtpd/queue_ram.c6
-rw-r--r--smtpd/ruleset.c8
-rw-r--r--smtpd/scheduler.c7
-rw-r--r--smtpd/scheduler_backend.c6
-rw-r--r--smtpd/scheduler_ramqueue.c6
-rw-r--r--smtpd/smtp.c27
-rw-r--r--smtpd/smtp_session.c8
-rw-r--r--smtpd/smtpctl.c12
-rw-r--r--smtpd/smtpctl/Makefile27
-rw-r--r--smtpd/smtpd.815
-rw-r--r--smtpd/smtpd.c94
-rw-r--r--smtpd/smtpd.conf18
-rw-r--r--smtpd/smtpd.conf.54
-rw-r--r--smtpd/smtpd.h34
-rw-r--r--smtpd/smtpd/Makefile53
-rw-r--r--smtpd/smtpfilter.c2
-rw-r--r--smtpd/ssl.c19
-rw-r--r--smtpd/ssl_privsep.c2
-rw-r--r--smtpd/stat_backend.c6
-rw-r--r--smtpd/stat_ramstat.c5
-rw-r--r--smtpd/table.c6
-rw-r--r--smtpd/table_db.c12
-rw-r--r--smtpd/table_getpwnam.c6
-rw-r--r--smtpd/table_static.c6
-rw-r--r--smtpd/tree.c4
-rw-r--r--smtpd/user.c6
-rw-r--r--smtpd/user_pwd.c6
-rw-r--r--smtpd/util.c33
-rw-r--r--smtpd/waitq.c6
182 files changed, 29644 insertions, 377 deletions
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 00000000..c11a2cb6
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,35 @@
+2011-09-02 chl <chl@tuxfamily.org>
+
+ * configure.ac:
+ - update from openssh's upstream repository
+
+ * openbsd-compat/Makefile.am:
+ * openbsd-compat/daemon.c:
+ - add daemon()
+
+ * smtpd/libexec/mail.local/mail.local.c:
+ - add missing header
+
+
+2011-08-28 chl <chl@tuxfamily.org>
+
+ - OpenSMTPD portable is now working on Linux!
+ - import mail.local(8)
+ - Add some #ifdef VALGRIND to track memory leaks
+
+
+2010-04-30 chl <chl@tuxfamily.org>
+
+ * openbsd-compat:
+ - import/update from portable OpenSSH:
+ - fmt_scaled.c
+ - mktemp.c (updated from OpenBSD upstream)
+ - setproctitle.c
+ - vis.c
+ - limit PATH_MAX and MAXPATHLEN to 1024
+
+ * smtpd:
+ - update to latest OpenSMTPD
+
+ I managed to send a mail with Portable OpenSMTPD, but there's
+ still some bugs to fix!
diff --git a/ChangeLog-asr b/ChangeLog-asr
new file mode 100644
index 00000000..c8ffb2dc
--- /dev/null
+++ b/ChangeLog-asr
@@ -0,0 +1,224 @@
+2012-09-09 18:45 eric
+
+ * asr.c: tweak options
+
+2012-09-09 14:46 eric
+
+ * asr.c: allow to disable some features at build time
+
+2012-09-09 14:15 eric
+
+ * asr.c, asr_debug.c, asr_private.h, res_send_async.c: cleanup
+ asr_debug.c
+
+2012-09-09 11:42 eric
+
+ * asr.c, asr_debug.c, asr_private.h, res_search_async.c,
+ res_send_async.c: use proper macros for debug traces.
+
+2012-09-08 13:08 eric
+
+ * Makefile.inc, asr_resolver.c, getaddrinfo.c, gethostnamadr.c,
+ getnameinfo.c, getnetnamadr.c, getrrsetbyname.c, res_debug.c,
+ res_init.c, res_mkquery.c, res_query.c, res_send.c, sethostent.c:
+ split asr_resolver.c into different files to overlay the libc/net
+ resolver implementation.
+
+2012-09-07 15:49 eric
+
+ * asr.c: return value has no use; make it void. fix comment.
+
+2012-09-07 15:21 eric
+
+ * getnetnamadr_async.c: unused variables
+
+2012-09-06 21:59 eric
+
+ * asr.c: config parsing is done in one pass now. no need to use
+ callback anymore.
+
+2012-09-06 17:05 eric
+
+ * getaddrinfo_async.c, gethostnamadr_async.c: include yp headers if
+ necessary. remove unused variable.
+
+2012-09-06 15:57 eric
+
+ * asr_private.h: make it easy to build without debug code
+
+2012-09-06 13:26 eric
+
+ * asr.c: add a strsplit() helper to factorize code a bit.
+
+2012-09-06 10:38 eric
+
+ * async_resolver.3: YP is now supported.
+
+2012-09-06 10:36 eric
+
+ * asr.h, async_resolver.3: remove unused member, reorganize a bit
+ and sync manpage.
+
+2012-09-05 23:49 eric
+
+ * Makefile.inc, asr.c, asr_debug.c, asr_private.h,
+ getaddrinfo_async.c, hostaddr_async.c: Get rid of the
+ hostaddr_async subquery and merge its behaviour directly into
+ getaddrinfo_async_run. Simplifies everything by a great deal.
+
+2012-09-05 18:52 eric
+
+ * hostaddr_async.c: Implement basic (blocking) YP support for
+ getaddrinfo_async(). YP is now supported on all relevant
+ resolver functions.
+
+2012-09-05 17:56 eric
+
+ * asr.c, asr_debug.c, asr_private.h, getaddrinfo_async.c,
+ hostaddr_async.c: Make hostaddr_async() return a linked list of
+ struct addrinfo. First round of a getaddrinfo_async()
+ simplification. The goal is to make YP support easier to add, and
+ eventually remove the whole hostaddr_async subquery.
+
+2012-09-04 18:03 eric
+
+ * gethostnamadr_async.c: implement basic YP support for
+ gethostbyname_async()/gethostbyaddr_async() by using the blocking
+ YP API internally.
+
+2012-08-19 19:59 eric
+
+ * asr_resolver.c: Build static netent and hostent structure in a
+ nicer and hopefully not broken way. Make it almost trivial to
+ implement gethostby*_r() family of functions when needed.
+
+2012-08-19 18:17 eric
+
+ * asr.h, asr_resolver.c, async_resolver.3, gethostnamadr_async.c,
+ getnameinfo_async.c, getnetnamadr_async.c: When building dynamic
+ hostent and netent, allocate a single linear buffer to hold both
+ the structure and the data. The freehostent() and freenetent()
+ API functions are not needed anymore. While there, ensure that
+ the constructed addr and alias lists are really NULL terminated.
+
+2012-08-18 18:48 eric
+
+ * asr.c, asr_resolver.c, async_resolver.3: ensure that async_run()
+ and async_run_sync() always preserve errno.
+
+2012-08-18 15:49 eric
+
+ * asr_resolver.c, getrrsetbyname_async.c: getrrsetyname() only uses
+ ERRSET_* and is not supposed to set errno. make sure to save and
+ restore errno properly.
+
+2012-08-18 15:31 eric
+
+ * hostaddr_async.c: Simplify error reporting in hostaddr_async().
+ Only use EAI_* error codes.
+
+2012-08-18 13:19 eric
+
+ * asr_resolver.c, getaddrinfo_async.c, getnameinfo_async.c: Improve
+ error reporting in getnameinfo_async() and getaddrinfo_async().
+ They do not have to deal with h_errno at all. Also, errno is
+ only kept for EAI_SYSTEM. Small code cleanup while there.
+
+ Adapt getnameinfo() and getaddrinfo() wrappers to correctly save
+ errno and overwrite it in the EAI_SYSTEM case.
+
+ General errno handling issue reported by mikeb@.
+
+2012-07-29 22:33 eric
+
+ * asr_resolver.c: must be zero'd (found by regress)
+
+2012-07-13 16:05 eric
+
+ * getaddrinfo_async.c: properly report EAI_SERVICE when the given
+ servname is not defined for the given protocol.
+
+2012-07-12 15:03 eric
+
+ * gethostnamadr_async.c: unused variables
+
+2012-07-11 18:49 eric
+
+ * asr_resolver.c: implement res_mkquery
+
+2012-07-10 19:30 eric
+
+ * getnetnamadr_async.c: same code update and fix as for
+ gethostnamadr_async
+
+2012-07-10 17:58 eric
+
+ * gethostnamadr_async.c: simplify the code, improve error handling
+ and plug a potential fd leak on error
+
+2012-07-10 14:41 eric
+
+ * gethostnamadr_async.c: use the value actually passed to the
+ function
+
+2012-07-10 11:20 eric
+
+ * getaddrinfo_async.c: Better handling of servname in
+ getaddrinfo_async. Do not necessarily fail if there is no entry
+ for a given protocol. Fix issue reported by early testers.
+
+2012-07-08 19:01 eric
+
+ * asr_resolver.c: implement res_querydomain() required by sendmail
+
+2012-07-08 15:12 eric
+
+ * asr_resolver.c: add stub function for gethostent(), and move
+ things around a bit while here.
+
+2012-07-07 22:41 eric
+
+ * asr_debug.c, asr_private.h, res_send_async.c: rename function to
+ avoid symbol clash
+
+2012-07-07 17:40 eric
+
+ * Makefile.inc: remove bogus include of bsd.lib.mk
+
+2012-04-25 22:28 eric
+
+ * asr_debug.c, getaddrinfo_async.c, gethostnamadr_async.c,
+ getnameinfo_async.c: fix a few warnings
+
+2012-04-16 00:25 eric
+
+ * asr.c: Create a new resolver for each thread. It will be done
+ differently eventually, but it's enough for now to make the
+ blocking API fully thread-safe without locking.
+
+2012-04-15 23:42 eric
+
+ * asr_debug.c: calling getnameinfo here is a bad idea. use
+ inet_ntop.
+
+2012-04-15 17:08 jmc
+
+ * async_resolver.3: tweak previous;
+
+2012-04-14 14:06 eric
+
+ * Makefile.inc, asr.c, asr_private.h: only define DEBUG internally
+
+2012-04-14 11:24 eric
+
+ * Makefile.inc, asr.c, asr.h, asr_debug.c, asr_private.h,
+ asr_resolver.c, asr_utils.c, async_resolver.3,
+ getaddrinfo_async.c, gethostnamadr_async.c, getnameinfo_async.c,
+ getnetnamadr_async.c, getrrsetbyname_async.c, hostaddr_async.c,
+ res_search_async.c, res_send_async.c: Import asr, an experimental
+ async resolver implementation. The idea is to eventually replace
+ the existing resolver with something better. Time to start
+ working on it in tree.
+
+ ok deraadt@
+
diff --git a/ChangeLog-mail.local b/ChangeLog-mail.local
new file mode 100644
index 00000000..dfdac648
--- /dev/null
+++ b/ChangeLog-mail.local
@@ -0,0 +1,306 @@
+2011-01-10 22:00 millert
+
+ * locking.c: Back out rev 1.2 and use mkstemp(), not mktemp(). OK
+ deraadt@
+
+2010-09-03 13:35 jmc
+
+ * mail.local.8: add EXIT STATUS for /usr/libexec;
+
+2009-10-28 00:59 deraadt
+
+ * locking.c, mail.local.c: rcsid[] and sccsid[] and copyright[] are
+ essentially unmaintained (and unmaintainable). these days,
+ people use source. these id's do not provide any benefit, and do
+ hurt the small install media (the 33,000 line diff is essentially
+ mechanical) ok with the idea millert, ok dms
+
+2009-01-19 10:46 sobrado
+
+ * mail.local.8: replace standardized text concerning the exit
+ values of applications with the right mdoc macros.
+
+2008-05-26 11:22 sobrado
+
+ * mail.local.8, mail.local.c: sort flags on both the synopsis and
+ usage.
+
+ ok jmc@
+
+2007-05-31 21:19 jmc
+
+ * mail.local.8: convert to new .Dd format;
+
+2006-05-13 06:17 deraadt
+
+ * mail.local.c: delete case for ?; cdp_xe@gmx.net
+
+2006-04-02 00:48 deraadt
+
+ * locking.c, mail.local.c, mail.local.h: minor lint cleaning; ok
+ millert
+
+2006-01-02 17:22 millert
+
+ * mail.local.c: #include <sys/signal.h> not needed
+
+2005-05-29 04:11 millert
+
+ * mail.local.c: Fix case where input file lacks newline before EOF;
+ Andrey Matveev
+
+2004-08-08 21:32 deraadt
+
+ * mail.local.c: spacing
+
+2004-05-20 10:46 tom
+
+ * mail.local.8: Grammar nit.
+
+ ok david@
+
+2003-07-10 02:04 david
+
+ * locking.c: add missing includes ok deraadt@ tedu@
+
+2003-06-02 21:38 millert
+
+ * mail.local.8, mail.local.c, mail.local.h, pathnames.h: Remove the
+ advertising clause in the UCB license which Berkeley rescinded 22
+ July 1999. Proofed by myself and Theo.
+
+2002-07-04 01:39 deraadt
+
+ * locking.c, mail.local.c: KNF
+
+2002-06-02 03:27 deraadt
+
+ * mail.local.c: minor KNF
+
+2002-03-27 16:45 mpech
+
+ * mail.local.8: 'S' required in OpenBSD (LOCAL_MAILER_FLAGS). From
+ lazy form@.
+
+ millert@ ok
+
+2002-02-19 20:39 millert
+
+ * locking.c: We live in an ANSI C world. Remove lots of gratuitous
+ #ifdef __STDC__ cruft.
+
+2002-02-18 00:16 millert
+
+ * locking.c: Call S_ISLNK with correct variable; Peter Philipp
+
+2002-02-16 22:27 millert
+
+ * mail.local.h: Part one of userland __P removal. Done with a
+ simple regexp with some minor hand editing to make comments line
+ up correctly. Another pass is forthcoming that handles the cases
+ that could not be done automatically.
+
+2001-08-18 23:37 deraadt
+
+ * locking.c, mail.local.c, mail.local.h: err() -> merr(), and
+ reorder some bugs noted by giannici@neomedia.it; millert helped
+
+2001-07-09 09:04 deraadt
+
+ * mail.local.c: correct type on last arg to execl();
+ nordin@cse.ogi.edu
+
+2001-01-28 20:34 niklas
+
+ * mail.local.8, pathnames.h: $OpenBSD$
+
+2000-11-09 18:53 aaron
+
+ * mail.local.8: Change all option list specifications to ".Bl -tag
+ -width Ds". Most man pages just needed their -width parameter
+ tweaked to "Ds", which provides a nice width of 6 constant
+ characters. For consistency more than anything.
+
+2000-10-30 18:46 aaron
+
+ * mail.local.8: libexec man page fleshing. again, bored on the
+ plane home.
+
+2000-08-16 19:14 brad
+
+ * mail.local.8: /etc/sendmail.cf -> /etc/mail/sendmail.cf -- PR#
+ 1364, From: sigh@kuzirabekon.econ.nagasaki-u.ac.jp
+
+2000-04-21 23:50 millert
+
+ * mail.local.c: Use fgetln(3) instead of fgets(3) when reading in
+ the message. This way the From line escaping gets done correctly
+ even for really long lines.
+
+2000-03-29 03:28 deraadt
+
+ * mail.local.8: Xr repair
+
+1999-07-09 15:35 aaron
+
+ * mail.local.8: - remove all trailing whitespace * except when
+ it is escaped with a `\' at the end of the line - fix remaining
+ .Nm usage as well - this is from a patch I received from
+ kwesterback@home.com, who has been working on some scripts for
+ fixing formatting errors in mdoc'd man pages
+
+ Ok, so there could be a cost/benefit debate with this commit, but
+ since I have the patch we might as well commit it...
+
+1999-07-04 21:25 aaron
+
+ * mail.local.8: more macro conversion
+
+1999-03-11 02:35 pjanzen
+
+ * mail.local.8: fix more comma splices that involve misuse of
+ conjunctive adverbs
+
+1999-01-11 09:54 csapuntz
+
+ * mail.local.8:
+
+ Correct documentation on how mail.local does its locking.
+
+1998-08-17 16:32 millert
+
+ * Makefile: As prommised, mail.local is no longer setuid.
+
+1998-08-16 01:11 millert
+
+ * locking.c: go back to using mktemp, not mkstemp in baditem();
+ theo
+
+1998-08-15 23:04 millert
+
+ * Makefile, locking.c, mail.local.8, mail.local.c, mail.local.h,
+ pathnames.h: Break out locking code into its own file so it can
+ be shared with lockspool. Call lockspool when invoked with -H
+ flag for backward compatibility.
+
+1998-05-18 11:58 deraadt
+
+ * mail.local.c: readlink(path, buf, sizeof buf-1). Never forget
+ that -1.
+
+1998-02-24 06:00 millert
+
+ * mail.local.8: Xr biff 1
+
+1998-02-24 05:52 millert
+
+ * pathnames.h, mail.local.8: 1) Mode X's for mkstemp 2) Document
+ problems with using quotas on /var/mail and tell how to make
+ sendmail do the right thing.
+
+1998-02-06 16:48 gene
+
+ * mail.local.8: Grammar and clarifications.
+
+1997-08-27 20:01 deraadt
+
+ * mail.local.8: fix ' use
+
+1997-08-13 23:09 dm
+
+ * mail.local.c: a little extra paranoia
+
+1997-07-25 21:41 mickey
+
+ * mail.local.c: #if __STDC__ --> #ifdef __STDC__
+
+1997-04-04 20:41 deraadt
+
+ * mail.local.c: when mktemp() is hard to fix, use 10 X
+
+1997-03-29 03:59 millert
+
+ * mail.local.8, mail.local.c: Make ``mail.local -H'' explicately
+ indicate when the lock fails or succeeds.
+
+1997-03-28 03:16 millert
+
+ * mail.local.c: "mail.local -H" is valid usage.
+
+1997-02-12 16:12 deraadt
+
+ * mail.local.c: fix option argument parsing, nirva@ishiboo.com
+
+1997-01-17 08:12 millert
+
+ * mail.local.c: r?index -> strr?chr
+
+1997-01-16 00:41 millert
+
+ * mail.local.c: getopt(3) returns -1 when out of args, not EOF,
+ whee!
+
+1996-12-24 20:42 deraadt
+
+ * mail.local.c: comment on why this mktemp use is safe
+
+1996-12-05 16:00 deraadt
+
+ * mail.local.8: typo
+
+1996-10-16 08:30 millert
+
+ * mail.local.c: check malloc ret val
+
+1996-08-30 14:04 deraadt
+
+ * mail.local.c: use S_IWOTH
+
+1996-08-29 09:24 deraadt
+
+ * mail.local.8: more signals please
+
+1996-08-29 09:21 deraadt
+
+ * mail.local.8, mail.local.c: first cut at -H; to be used mailers
+ to grab locks in 755 spool direectories
+
+1996-08-29 06:24 deraadt
+
+ * mail.local.8: talk about quotas on spool filesystems (untested
+ idea)
+
+1996-08-29 06:19 deraadt
+
+ * mail.local.c: buf oflows, deal with 1777 spool, general DOS
+ attack protection; help from david mazieres
+
+1996-08-29 06:19 deraadt
+
+ * mail.local.8: buf oflows, deal with 1777 spool, general DOS
+ attack protection
+
+1996-08-27 22:33 dm
+
+ * mail.local.c: Fix race condition.
+
+1996-08-27 05:17 dm
+
+ * mail.local.8, mail.local.c: Use lockfiles by default, rather than
+ fcntl.
+
+1996-07-19 09:35 deraadt
+
+ * mail.local.c: race thee no more; fix from travis@evtech.com with
+ some additional stuff from me
+
+1995-10-18 09:43 deraadt
+
+ * Makefile, mail.local.8, mail.local.c, pathnames.h: Initial
+ revision
+
+1995-10-18 09:43 deraadt
+
+ * Makefile, mail.local.8, mail.local.c, pathnames.h: initial import
+ of NetBSD tree
+
diff --git a/ChangeLog-smtpd b/ChangeLog-smtpd
new file mode 100644
index 00000000..111fffcd
--- /dev/null
+++ b/ChangeLog-smtpd
@@ -0,0 +1,10054 @@
+2012-10-26 21:16 chl
+
+ * smtpctl.c: add a new uptime.human entry in stats, derived from
+ uptime, but displayed in a human readable fashion:
+
+ uptime=123456 uptime.human=1d10h17m36s
+
+ ok gilles@
+
+2012-10-25 20:14 eric
+
+ * ioev.c: Handle the case where writev() fails with EAGAIN. In
+ theory it cannot happen, but it seems that kqueue triggers the
+ event sometimes, even if the socket is not immediatly writeable.
+ Temporary workaround it while the real issue is being
+ investigated.
+
+ ok gilles@ chl@
+
+2012-10-25 16:06 eric
+
+ * mfa.c: send the semantically correct msg when RCPT fails, even if
+ the exact value does not matter.
+
+ spotted by chl@
+
+ ok gilles@ chl@
+
+2012-10-25 11:51 eric
+
+ * mda.c, queue.c: Make the mda request the message fd from the
+ queue when needed, instead of pushing the fd with the envelope.
+ This allows the mda to deal itself with session limits.
+ Envelopes are sent at full rate to the mda, which buffers them on
+ per-user queues, or sends them back for rescheduling if it
+ already has too many pending envelopes. Delivery sessions are
+ created (within per- user and global limits) to drain the queues.
+
+ This makes the server handle envelope bursts more efficiently.
+
+ ok gilles@
+
+2012-10-22 23:58 chl
+
+ * queue_fsqueue.c: switch from {open,read,close}() to
+ {fopen,fread,fclose}() in fsqueue_envelope_load(), also fix a
+ potential fd leak.
+
+ ok gilles@ eric@
+
+2012-10-17 19:14 eric
+
+ * mda.c: rename field msg -> evp.
+
+ ok gilles@
+
+2012-10-17 18:39 eric
+
+ * smtpd.8, smtpd.c: Document the -P option. While there, remove
+ reference to -T, it's incomplete, subject to changes and
+ internal.
+
+ feedback from jmc@
+
+ ok gilles@
+
+2012-10-17 10:38 eric
+
+ * smtpctl.8: consistency fix: we use "envelope-id" everywhere.
+
+ ok gilles@
+
+2012-10-16 18:47 jmc
+
+ * smtpd.conf.5: consistent macros; Tim van der Molen
+
+2012-10-16 14:02 eric
+
+ * smtpd.h: MAX_RULEBUFFER_LEN is too small, bump it.
+
+ discussed with gilles@
+
+2012-10-16 13:10 eric
+
+ * lka_session.c: Prevent a possible buffer overflow in
+ lka_expand_format() that can lead to a server crash, and let the
+ smtp session fail if that happens.
+
+ spotted by todd@, discussed with eric@ and chl@
+
+ commited for gilles@
+
+2012-10-16 00:47 jmc
+
+ * smtpctl.8: tweak previous; ok eric
+
+2012-10-15 20:32 eric
+
+ * control.c, smtpctl.8, smtpd.c: implement and document "smtpctl
+ stop"
+
+ ok gilles@
+
+2012-10-15 19:54 eric
+
+ * smtpd.c: use shorter names for process titles.
+
+ ok gilles@ chl@
+
+2012-10-14 22:18 eric
+
+ * mda.c: As discussed with gilles@, actually impose the per-user
+ limit regardless of the delivery method. Bump the limit a bit.
+
+ requested by and ok gilles@
+
+2012-10-14 20:50 eric
+
+ * mda.c: Limit the number of per-user mda (external program)
+ deliveries that can be running at the same time. It prevents a
+ user from consuming all mda "slots" with a long-running filter in
+ his .forward file. Other delivery types are not affected.
+
+ ok gilles@ chl@
+
+2012-10-14 20:45 eric
+
+ * queue.c: When pushing too many envelopes to the mda at once, we
+ can hit a filedesc exhaustion situation that kills the server.
+ For now, put a safe limit on the number of envelopes sent by the
+ queue process to the mda.
+
+ ok gilles@ chl@
+
+2012-10-14 16:26 halex
+
+ * ssl.c: enforce different permissions on different files in
+ ssl_load_file()
+
+ with gilles and eric, tested by me and gilles
+
+ ok gilles@
+
+2012-10-14 15:31 chl
+
+ * lka_session.c, queue.c: substitute wrong comas into semicolons
+
+ ok gilles@ eric@
+
+2012-10-14 15:22 gilles
+
+ * smtpctl.8: mistakenly removed an ".Xr smtpd 8"
+
+ spotted by jmc@
+
+2012-10-14 14:05 gilles
+
+ * smtpd.conf.5: replace 'plain' with 'file' as the backend source
+ name for map_file.c
+
+2012-10-14 13:59 gilles
+
+ * map_stdio.c: missing from previous commit, byebye map_stdio.c
+
+ ok eric@ and chl@
+
+2012-10-14 13:58 gilles
+
+ * control.c, lka.c, map.c, map_db.c, map_file.c, map_static.c,
+ parse.y, parser.c, parser.h, smtpctl.8, smtpctl.c, smtpd.c,
+ smtpd.h: introduce map_file.c which will deprecate map_stdio.c
+
+ The idea is to have a file-backed map but to have smtpd(8) cache
+ the maps so that it cannot be partially read if edited while mail
+ is received. The file is read and converted to a static map
+ (map_static.c), changes aren't visible to smtpd until an
+ explicit: smtpctl update map which reads file, builds a new
+ static map and invalidates the former.
+
+ partial-read issue discussed with beck@ and halex@ idea to
+ convert internally to a static map by eric@
+
+ diff ok eric@ and chl@
+
+2012-10-14 13:47 gilles
+
+ * smtpctl.8: smtpctl show runqueue no longer exists, it's been that
+ way for a while
+
+2012-10-13 23:38 gilles
+
+ * lka_session.c: missing header
+
+2012-10-13 23:33 gilles
+
+ * lka_session.c: in aliases expansion, we can avoid requesting
+ parent for ~user/.forward, if we check that user is a system user
+ first before sending the imsg
+
+2012-10-13 11:44 gilles
+
+ * makemap.c: when makemap is executed in sendmail mode, check if
+ ".db" is part of the filename and imply it otherwise so that the
+ following works:
+
+ makemap hash /etc/mail/aliases < aliases
+
+2012-10-13 10:01 eric
+
+ * aliases.c, lka.c, lka_session.c, map.c, ruleset.c: Make
+ map_lookup() and make_compare() set errno on failure to
+ distinguish between "no match" and "internal error" (e.g. missing
+ or broken db file). Adapt alias expansion and ruleset matching
+ code to check for such errors, in which case the current
+ processing is aborted, and a temporary failure is reported to the
+ smtp session.
+
+ ok gilles@
+
+2012-10-12 10:51 eric
+
+ * envelope.c, smtpd.h: Extend the "retry" field to 16 bits. The
+ new quadratic retry formula makes the maximum retry delay a bit
+ to small on 8 bits.
+
+ ok gilles@ chl@
+
+2012-10-11 23:55 gilles
+
+ * smtpd.c: - if argc / argv not empty after getopt() loop, display
+ usage
+
+2012-10-11 23:52 gilles
+
+ * mta.c: - no need to assign a separator to the last route flag
+ since we're not going to use it
+
+2012-10-11 23:51 gilles
+
+ * mfa_session.c: - no need to set imsg_type to IMSG_MFA_CLOSE when
+ we're not going to answer to SMTP ..
+
+2012-10-11 23:47 gilles
+
+ * envelope.c: - remove dead store
+
+ spotted by clang
+
+2012-10-11 23:43 gilles
+
+ * map.c, smtpd.h: - map_create() takes a map_src not a map_kind
+
+ ok eric@ and chl@
+
+2012-10-11 23:34 gilles
+
+ * compress_gzip.c: - char * -> unsigned char *
+
+ spotted by clang, ok eric@ and chl@
+
+2012-10-11 23:24 gilles
+
+ * mta_session.c, smtp_session.c: - ssize_t -> size_t
+
+ spotted with clang, ok eric@ and chl@
+
+2012-10-11 23:14 gilles
+
+ * lka_session.c, parse.y, ruleset.c, smtpd.conf.5, smtpd.h: -
+ replace "from all" and "for all" with "from any" and "for any"
+
+ ok eric@, chl@
+
+2012-10-10 22:29 gilles
+
+ * smtpd.h: F_BACKUP and ROUTE_BACKUP must be sync-ed for now,
+ otherwise smtpd won't work as a backup MX ...
+
+ bug experienced by todd, verified and analyzed by eric
+
+2012-10-10 21:39 gilles
+
+ * parser.c, parser.h, smtpctl.8, smtpctl.c, smtpd.h, util.c: teach
+ smtpctl how to display envelopes and messages using their id.
+ this allows an admin to inspect the queue without having to
+ manually extract bucket and find the path to an envelope or
+ message.
+
+ diff by Sunil Nimmagadda <sunil@poolp.org>
+
+ ok eric@, chl@ and I
+
+2012-10-10 21:38 eric
+
+ * ioev.c, ioev.h, mta_session.c: io_connect() can take an optional
+ address to bind() before connecting.
+
+ ok gilles@
+
+2012-10-10 20:02 eric
+
+ * expand.c, lka_session.c, smtpd.h: For each alias node, mark if it
+ has been expanded from an alias map or from a .forward file.
+ Local deliveries for files and filters expanded from an alias map
+ are run as user _smtpd.
+
+ issue reported by tood@
+
+ ok gilles@ todd@
+
+2012-10-10 19:57 eric
+
+ * mta.c: show the port number for a relay if specified.
+
+ ok gilles@
+
+2012-10-10 08:02 jmc
+
+ * smtpd.conf.5: a SMTP -> an SMTP;
+
+2012-10-09 23:33 eric
+
+ * lka_session.c: make "relay ... as ..." work again. It's been
+ zapped by mistake.
+
+ spotted by todd@
+
+ ok gilles@
+
+2012-10-09 22:33 gilles
+
+ * parse.y, smtp_session.c, smtpd.conf.5, smtpd.h: - allow a listen
+ statement to impose tls on its clients; - make listen statements
+ impose authentication if 'auth' is specified and to make it
+ optional if 'auth-optional' is specified; - sync documentation
+ accordingly
+
+ with ideas and input from beck@ and halex@, ok eric@
+
+2012-10-09 22:32 eric
+
+ * ssl.c: Reject ssl key/certs/CA/DH files if their
+ ownership/permissions are not correct (uid 0, no rights for g/o).
+
+ Initial diff by Sunil Nimmagadda.
+
+ ok gilles@ chl@
+
+2012-10-09 20:28 gilles
+
+ * smtpd.conf.5: fix listen examples to not use an interface
+
+2012-10-09 15:39 eric
+
+ * queue_backend.c: fix a FILE* leak when using compression.
+
+ ok gilles@
+
+2012-10-08 22:35 gilles
+
+ * parse.y, smtpd.conf.5, smtpd.h: disk space is cheap but we still
+ want to limit the default size of a body to a sane default for
+ everyone.
+
+2012-10-08 21:45 gilles
+
+ * makemap.c: when building a db map, always lowercase the key
+ before a lookup in makemap
+
+ smtpd already does it, but this allows spotting a cycle at
+ makemap time, so user isn't surprised at runtime.
+
+ while at it, be more tolerant when user specifies
+ /etc/mail/aliases instead of /etc/mail/aliases.db
+
+2012-10-08 10:46 eric
+
+ * dns.c: skip RR if type is not MX. Use hostname if the list of MX
+ is empty after the loop.
+
+ spotted by huku at grhack.net
+
+ ok gilles@
+
+2012-10-07 19:21 eric
+
+ * smtpd.h, waitq.c: Implement a simple wait queue API. The idea is
+ to allow multiple "waiters" to wait on the same "tag" for a
+ deferred result.
+
+ A waiter is a callback and a void *argument. The first waiter
+ (the one for which waitq_wait() returns true) is supposed to run
+ some code that leads to waitq_run() being run, which will destroy
+ that waitq and call all callbacks in turn.
+
+ Not used at the moment, but will be soon.
+
+ ok gilles@ chl@
+
+2012-10-07 18:57 gilles
+
+ * makemap.c: We need to provide a sendmail-like interface to
+ makemap so that some tools that assume sendmail do not break ...
+ add support for reading map source from stdin, for specifying the
+ DBTYPE of a map, and teach OUR makemap to emulate sendmail
+ interface.
+
+ ok eric@
+
+2012-10-07 17:46 chl
+
+ * bounce.c, mta_session.c, smtp.c, smtp_session.c, smtpd.h, util.c:
+ convert iobuf_queue()'s to iobuf_fqueue(). (idea from gilles@)
+ introduce iobuf_xinit() and iobuf_xfqueue(). (idea from eric@)
+
+ ok gilles@
+
+2012-10-07 16:55 gilles
+
+ * mta.c: bump max number of connections to a route from 5 to 10,
+ the limit is too low as experienced by myself and another user.
+
+ discussed with and ok eric@
+
+2012-10-05 09:00 jmc
+
+ * smtpd.conf.5: further tweak the maps description; ok gilles
+
+2012-10-05 08:25 jmc
+
+ * smtpd.conf.5: tweak previous; ok gilles
+
+2012-10-04 21:49 gilles
+
+ * parse.y, smtpd.conf.5: default map source to S_PLAIN, this allows
+ us to simplify smtpd.conf: map aliases source plain
+ "/etc/mail/aliases" can be reduced to: map aliases
+ "/etc/mail/aliases"
+
+2012-10-04 20:25 eric
+
+ * smtpd.c: delay the call to log_debug() for displaying the
+ backends used until the "real" debug mode is set.
+
+ ok gilles@ chl@
+
+2012-10-04 14:17 todd
+
+ * util.c: change to from=<...>, to=<...> instead of to=<...> for
+ logging from gilles@ ok eric@
+
+2012-10-03 23:44 gilles
+
+ * dns.c: when requesting MX entries, the result can be appear in
+ random orders.
+
+ the logic for inserting them in a lka session when acting as
+ backup MX did not take account for one specific case that could
+ lead to an early exit without smtpd getting a chance to detect
+ the entry corrsponds to itself.
+
+ in such case, a backup MX woud try to connect to itself and
+ bounce in the loop detection code ... or it would sometimes work.
+
+2012-10-03 21:42 gilles
+
+ * lka_session.c, smtpd.h: we reintroduced a bug that was fixed 2
+ years ago with the aliases rewrite:
+
+ During the entire expansion process, a username may be larger
+ than MAXLOGNAME because it may be an alias going through another
+ expansion. We should use a buffer that's large enough to fit a
+ mailaddr user-part so we avoid hitting a truncation check leading
+ to a fatal().
+
+ ok eric@, ok chl@
+
+2012-10-03 20:09 gilles
+
+ * lka_session.c: - add a EXPAND_DEPTH define for ... expansion
+ depth - bump the expansion depth from 5 to 10 - add the current
+ node depth to log_debug()
+
+ ok eric@, ok chl@
+
+2012-10-03 19:58 gilles
+
+ * delivery_filename.c, delivery_maildir.c, delivery_mbox.c,
+ delivery_mda.c, smtpd.c, smtpd.h: disallow root deliveries for
+ "deliver to filename" and "deliver to mda" rules, we only allow
+ them for mbox and maildir though users should really create a
+ root alias ...
+
+ discussed with eric@ and chl@, ok both
+
+2012-10-03 18:43 chl
+
+ * bounce.c, mta_session.c, smtp.c: don't try to cope with
+ iobuf_init() failure, make it fatal() instead.
+
+ from eric@ input
+
+ ok gilles@
+
+2012-10-02 14:37 chl
+
+ * bounce.c, mta_session.c, smtp.c: check iobuf_init() return value.
+
+ ok gilles@ eric@
+
+2012-09-30 19:25 chl
+
+ * mta_session.c, parse.y: use xmalloc(), xcalloc() and xmemdup()
+ helpers
+
+ ok gilles@
+
+2012-09-30 16:28 gilles
+
+ * lka.c, lka_session.c, parse.y, smtpd.h: - add decision to the
+ rule so that we can actually perform a reject match ie:
+
+ reject from 192.168.1.0/24 for domain "openbsd.org"
+ accept from 192.168.0.0/16 for domain "openbsd.org"
+ deliver to mbox
+
+ it was documented but not working.
+
+ ok eric@ & chl@
+
+2012-09-30 00:16 chl
+
+ * smtp.c: use xstrdup() helper
+
+ ok eric@ gilles@
+
+2012-09-29 13:02 eric
+
+ * mfa.c, mfa_session.c, smtpd.h: some mfa_session cleanups.
+
+ - move mfa_session() prototype to smtpd.h - make mfa session use
+ a tree - make static functions static - merge mfa_session_init()
+ into mfa_session()
+
+ ok chl@
+
+2012-09-29 12:35 eric
+
+ * lka.c, lka_session.c, smtpd.h: finally remove rule member from
+ struct envelope.
+
+ "wow!" gilles@
+
+2012-09-29 12:32 eric
+
+ * parse.y, smtpd.h: Remove support for "as user" for local
+ deliveries. It's not documented and not implemented.
+
+ ok gilles@
+
+2012-09-28 19:28 eric
+
+ * smtpd.c, smtpd.h: some smtpd.{c,h} cleanups:
+
+ - move struct child to smtpd.c - make it use a tree keyed on the
+ pid - change child_add to take the title directly as a const char
+ * - remove useless child_lookup() and child_del() - remove
+ CHILD_INVALID
+
+ ok chl@ gilles@
+
+2012-09-28 16:03 chl
+
+ * lka.c, mta.c: use xmemdup() and xcalloc() helpers
+
+ ok eric@
+
+2012-09-28 15:40 eric
+
+ * mda.c, smtpd.h: Move mda_session to mda.c, and make it use a tree
+ instead of a list, but still use uint32_t keys since ithe key is
+ used as peerid in msg.
+
+ ok gilles@
+
+2012-09-28 14:00 eric
+
+ * control.c, smtpd.h: smtpd.h/control.c cleanups:
+
+ - move session_socket_* prototypes under util.c - move struct
+ ctl_conn in control.c - make static functions static - remove
+ unused functions - call unlink() in control_shutdown() - make
+ control_close() take a ctl_conn * instead of a fd
+
+ ok chl@ gilles@
+
+2012-09-27 22:34 chl
+
+ * enqueue.c, makemap.c, map_stdio.c: use xstrdup() helper
+
+ ok eric@ gilles@
+
+2012-09-27 21:50 eric
+
+ * scheduler_ramqueue.c: When merging messages from an update,
+ decrement the message counter if the message already exists in
+ the main queue, otherwise it's counted twice.
+
+ ok gilles@
+
+2012-09-27 21:43 eric
+
+ * mta_session.c: fatal -> fatalx
+
+2012-09-27 20:57 eric
+
+ * expand.c, lka_session.c, smtpd.h: clarify the alias expansion
+ code.
+
+ The session manages a list of nodes to process. A node has a link
+ to the parent node from which it has been expanded, and a link to
+ the rule that led to its creation. Depending on its type and the
+ associated rule, each node is either "expanded" to create new
+ nodes or "submitted" to create a final envelope. Nodes which
+ have already been seen, either processed or not, are discarded to
+ avoid loops.
+
+ The expansion process is bootstrapped by creating an
+ EXPAND_ADDRESS node from the original dest, with no rule and no
+ parent. It is done when all nodes have been expanded or if an
+ error occurs before. The expand depth is limited 5 levels. The
+ whole expansion fails if the limit is reached.
+
+ While there, make sure that only one .forward file is queried at
+ a time, and only append the subfolder tag in the maildir case.
+
+ Fixe issues with some virtual map setups where the dest would get
+ mixed up, and make the whole expansion process generally easier
+ to follow.
+
+ ok chl@ gilles@
+
+2012-09-27 19:58 chl
+
+ * map_db.c, mfa.c: simplify calloc() + strlcpy()/memcpy() dance
+ with xmemdup() use xcalloc() helper remove newly unused variable
+
+ ok gilles@ eric@
+
+2012-09-27 19:47 chl
+
+ * config.c, control.c, dns.c, forward.c, map_static.c, map_stdio.c,
+ mda.c, stat_ramstat.c: use xmalloc()/xcalloc() helpers
+
+ while there unify usage of log_trace() in ramstat_set()
+
+ ok gilles@ eric@
+
+2012-09-27 14:26 chl
+
+ * enqueue.c: simplify malloc() + strlcpy() dance with xstrdup()
+
+ ok gilles@ eric@
+
+2012-09-26 23:06 chl
+
+ * bounce.c: fix memory leak in case of fdopen() failure
+
+ ok eric@ gilles@
+
+2012-09-26 21:52 eric
+
+ * envelope.c, lka_session.c, mda.c, smtpd.h, util.c: Stop using the
+ delivery_data union (field "to") in delivery_mda. It's confusing
+ and not necessary as it's only used for "buffer". Instead, just
+ add a "buffer" member in the structure and rename "as_user" to
+ "user".
+
+ The delivery_data union becomes an anonymous union in expandnode,
+ which is the only other place where it's used.
+
+ ok gilles@
+
+2012-09-26 18:19 jmc
+
+ * smtpd.8: last stage of rfc changes, using consistent Rs/Re
+ blocks, and moving the references into a STANDARDS section;
+
+2012-09-26 14:28 eric
+
+ * map.c: maps must be numbered from 1 up, as 0 means "no map".
+
+ ok gilles@
+
+2012-09-26 11:49 halex
+
+ * parse.y: fix double free() issue in error paths
+
+ ok eric@ gilles@
+
+2012-09-26 11:43 eric
+
+ * util.c: log final user and method used for local deliveries.
+
+ ok gilles@
+
+2012-09-25 19:38 eric
+
+ * smtpd.h, user_pwd.c: make const arguments const, and static
+ functions static.
+
+ ok chl@
+
+2012-09-25 17:36 eric
+
+ * util.c: need inttypes.h
+
+ from millert@
+
+2012-09-24 10:56 eric
+
+ * lka_session.c: spaces -> tabs
+
+2012-09-21 21:37 eric
+
+ * aliases.c, expand.c, forward.c, lka_session.c, smtpd.h: Do not
+ pass the username to forwards_get() which does not have to care
+ about this. Instead, set the username on the expand context, and
+ copy it on the expand nodes as they are inserted.
+
+ ok gilles@
+
+2012-09-21 18:40 eric
+
+ * aliases.c, expand.c, forward.c, lka_session.c, map_db.c,
+ map_static.c, map_stdio.c, smtpd.h: wrap expandtree into a
+ "struct expand".
+
+ ok gilles@
+
+2012-09-21 15:23 eric
+
+ * lka_session.c, smtpd.h: move struct lka_session definition in
+ lka_session.c
+
+ ok gilles@
+
+2012-09-21 14:33 eric
+
+ * mda.c, mta.c, mta_session.c, queue.c, smtpd.h, util.c: Add a
+ log_envelope() function that log envelope status in a uniform
+ way. It automagically adds an rcpt=<user@domain> field if "dest"
+ differs from the original "rcpt". The function takes an "extra"
+ parameter that allows to add some specific info depending on the
+ context.
+
+ ok gilles@
+
+2012-09-21 12:22 eric
+
+ * lka.c, lka_session.c, map.c, map_db.c, map_static.c, map_stdio.c,
+ ruleset.c, smtpd.h, util.c: Move ruleset_match() prototype to
+ smtpd.h and make the envelope const. Adapt a lot of functions in
+ chain to use const args where required.
+
+ ok gilles@
+
+2012-09-20 16:28 eric
+
+ * aliases.c, forward.c, smtpd.h, util.c: constify parameters that
+ are supposed to be const.
+
+ ok gilles@
+
+2012-09-20 11:27 eric
+
+ * mda.c: envelope type is necessarily D_MDA here.
+
+ ok chl@
+
+2012-09-19 22:08 eric
+
+ * smtpctl.c: use lower case for envelope fields.
+
+ requested by gilles@
+
+2012-09-19 21:40 eric
+
+ * lka.c, mfa.c: Set envelope expirancy in lka before sending the
+ envelope to mfa. The goal is to eventually have only the lka see
+ the rules.
+
+ ok gilles@ chl@
+
+2012-09-19 20:20 eric
+
+ * envelope.c, queue.c, smtp.c, smtpctl.c, smtpd.h: Remove
+ DF_ENQUEUE flag. It is mostly unused and logically broken.
+ Ignore it in existing envelopes until it gets completely dropped.
+ Change "smtpctl show queue" to display the address family of the
+ envelope source instead of the ENQUEUE flag.
+
+ ok gilles@
+
+2012-09-19 14:59 eric
+
+ * aliases.c, forward.c, makemap.c, map_db.c, map_static.c,
+ map_stdio.c: expandnodes must be bzero()'d before parsing to be
+ sure there is no bogus data left on return, since the RB compare
+ functions uses memcmp(). While there, remove all calls to
+ bzero() before alias_parse().
+
+ ok gilles@
+
+2012-09-19 14:45 eric
+
+ * aliases.c, expand.c, forward.c, makemap.c, map_db.c,
+ map_static.c, map_stdio.c: rename variables for consistency
+
+ ok gilles@
+
+2012-09-19 13:57 eric
+
+ * lka.c, smtpd.h: remove IS_RELAY and IS_MAILBOX macros.
+
+ ok gilles@
+
+2012-09-19 12:10 eric
+
+ * aliases.c, lka_session.c, smtpd.h: Remove aliases_exists() and
+ aliases_virtual_exists(). The corresponding *_get() functions can
+ be called directly.
+
+ ok gilles@
+
+2012-09-19 11:06 eric
+
+ * aliases.c, expand.c, forward.c, lka_session.c, map_db.c,
+ map_static.c, map_stdio.c, smtpd.h: start cleaning the expansion
+ code:
+
+ - change expandtree_* prefix to expand_ for better readability
+ and because the structure might change at some point - rename
+ <>_free_nodes() to <>_free() - remove unused <>_remove_node() -
+ refcounting has no purpose at all; just remove it as well as the
+ decrement/increment functions, and replace the latter with
+ <>_insert - expandnode flags is only used to know if it's been
+ processed or not, don't make it a flag but a simple field with
+ clear name.
+
+ ok gilles@ chl@
+
+2012-09-18 17:35 eric
+
+ * expand.c, lka_session.c: make use of expandtree_free_nodes() in
+ lka_session_destroy(). change to a simpler implementation for it
+ while there.
+
+ ok gilles@
+
+2012-09-18 16:23 eric
+
+ * lka_session.c, mta.c, smtpd.h, util.c: - add xmemdup() helper. -
+ remove useless block in switch.
+
+ ok gilles@
+
+2012-09-18 15:42 eric
+
+ * lka.c, lka_session.c, smtpd.h: simple lka cleanups:
+
+ - fix lka* function prototypes in smtpd.h - make static functions
+ static - merge lka_session_init() into lka_session() - make
+ lka_session.c use tree.c to store sessions
+
+ ok gilles@
+
+2012-09-18 15:13 eric
+
+ * smtpd.h: this structure is not useful and ill-named. remove it.
+
+ ok gilles@
+
+2012-09-18 14:54 eric
+
+ * aliases.c: a few cleanups: - make static functions static - pass
+ const char * rather than char * when we mean that - make
+ parse_alias() more straightforward
+
+ ok gilles@
+
+2012-09-18 14:13 eric
+
+ * lka_session.c, smtpd.h: remove C_NET. it's not used and there is
+ no plan for it at the moment.
+
+ ok gilles@
+
+2012-09-17 22:19 eric
+
+ * map.c, parse.y, smtpd.h: Add map_create() and map_add() helpers.
+ Simplify the config parser by a great deal.
+
+ While there, rename the default "localhost" map to "<localhost>"
+ to make it look more internal, and create a single "<anyhost>"
+ map referenced by "from all" rules, instead of creating a dynamic
+ one for each of them.
+
+ ok gilles@ chl@
+
+2012-09-17 20:44 gilles
+
+ * lka_session.c, smtpd.conf.5: Fix format expansion in smtpd.conf,
+ it has confused a lot of people and it turns out documentation
+ got it wrong. This commit changes formats and doc, it makes
+ situation saner:
+
+ %A = user part of sender address
+ %D = domain part of sender address
+
+ %a = user part of recipient address
+ %d = domain part of recipient address
+ %u = unix account of recipient
+
+ ok eric@
+
+2012-09-17 20:36 eric
+
+ * smtp.c: increment the session counter when a session is created.
+ fix a bug where local sessions were not accounted for.
+
+ ok gilles@
+
+2012-09-17 10:32 eric
+
+ * smtp.c: fix pasto
+
+ prompted by gilles@
+
+2012-09-17 07:46 jmc
+
+ * forward.5: various tweaks; ok gilles
+
+2012-09-16 21:16 gilles
+
+ * smtp.c: we need to ensure we have at least two descriptors
+ per-client accepted, or we will hit an imsg_read() fatal (EAGAIN)
+ when a client sends DATA, and we don't have a descriptor for it.
+
+2012-09-16 18:54 chl
+
+ * smtpd.c, smtpd.h: now that log_imsg() is only used in smtpd.c,
+ set it as static.
+
+ ok gilles@
+
+2012-09-16 18:43 chl
+
+ * control.c, lka.c, mda.c, mfa.c, mta.c, queue.c, scheduler.c,
+ smtp.c, smtpd.c: Factorize log_imsg() in imsg_dispatch() instead
+ of in each imsg_callback()'s and put it out of profiling, so it's
+ not accounted.
+
+ While there, for PROC_PARENT: - set smtpd_process for PROC_PARENT
+ - use setproctitle() like other processes
+
+ ok gilles@
+
+2012-09-16 17:55 chl
+
+ * compress_backend.c, compress_gzip.c, smtpd.h: silent warnings
+
+ reported by ajacoutot@
+
+ ok gilles@ ajacoutot@
+
+2012-09-16 13:53 gilles
+
+ * delivery_maildir.c, smtpd.h, util.c: replace BSD-licensed
+ mkdir_p() with ISC-licensed mkdirs(), this allows us to avoid a
+ dual-licensed util.c for no reason
+
+ ok chl@
+
+2012-09-16 12:48 eric
+
+ * thread_private.h: remove the thread_private hack.
+
+ ok chl@ gilles@
+
+2012-09-15 17:12 eric
+
+ * envelope.c, parse.y, ruleset.c, smtp.c, util.c: When enqueueing
+ from the local socket, the input address is faked as "::1". This
+ is confusing and even broken, as systems running with ipv6
+ disabled on lo0 will not be able to enqueue mails using the local
+ socket.
+
+ So instead, use AF_LOCAL and print it as "local" in
+ envelopes/maps. Add it to the "localhost" and "all" maps
+ accordingly, and fix the ruleset matching.
+
+ ok gilles@ chl@
+
+2012-09-14 21:22 eric
+
+ * smtp_session.c, smtpd.h, ssl.c: Remove s_ssl from the smtp
+ session since it is duplicated in the io struct. Change
+ ssl_session_init to ssl_smtp_init and make it simpler: only
+ create an SSL* from the SSL_CTX* passed as parameter, so it does
+ not have to know about the struct session itself. Kill some dead
+ prototypes while there.
+
+ ok chl@ gilles@
+
+2012-09-14 21:20 eric
+
+ * ioev.c: When printing ioev, do not segfault if there is no
+ associated iobuf. Also give info about the cipher if there is an
+ ssl context.
+
+ ok chl@ gilles@
+
+2012-09-14 19:35 jmc
+
+ * aliases.5: tweak the description of "value" somewhat; ok gilles
+
+2012-09-14 18:38 eric
+
+ * smtp.c: Check limits before allocating the session. While there,
+ move smtp_resume() in the if block; it makes more sense.
+
+ ok gilles@
+
+2012-09-14 08:27 jmc
+
+ * aliases.5: restructure this page somewhat, and make it read
+ better; ok gilles
+
+2012-09-12 20:56 gilles
+
+ * forward.5: reword a bit
+
+2012-09-12 20:50 gilles
+
+ * aliases.5: - document that aliases lookups are folded to
+ lowercase - also document that we strip the address extensions
+ before aliases lookups
+
+2012-09-12 20:36 gilles
+
+ * forward.5: missed a word :-)
+
+2012-09-12 20:34 gilles
+
+ * forward.5: - e-mail -> email , as discussed with jmc@ on
+ aliases(5) - reword first paragraph - $HOME -> ~/
+
+2012-09-12 20:30 gilles
+
+ * forward.5: - reword paragraph on ~/.forward permissions
+
+2012-09-12 19:56 gilles
+
+ * aldap.c, aldap.h, ber.c, ber.h, map_ldap.c, map_ldap.h: after a
+ bit of discussion we decided to remove these for now, we'll
+ reintroduce later when the support is ready ... after our first
+ release.
+
+ prompted by and ok eric@
+
+2012-09-12 19:53 gilles
+
+ * aliases.5, forward.5: - we lacked man pages for the aliases and
+ forward file formats rewrote from scratch using the sendmail
+ pages as a base.
+
+ with a bit of rewording by jmc@, we'll improve further in base
+
+2012-09-11 21:19 gilles
+
+ * scheduler_backend.c: - simplify scheduler_compute_schedule by
+ making it a quadratic delaying. no more if/else, we derive the
+ delay from the retry count. works for qmail, should work for
+ us too.
+
+ ok eric@
+
+2012-09-11 18:24 eric
+
+ * mta_session.c: Initialize fd correctly. This fixes a lot of
+ problems.
+
+ ok gilles@
+
+2012-09-11 17:05 eric
+
+ * mta_session.c: remove the session entry from the search tree when
+ it's dead.
+
+ ok gilles@
+
+2012-09-11 14:47 eric
+
+ * mfa_session.c, smtpd.c: log the process name and place when
+ calling fatal().
+
+ ok gilles@
+
+2012-09-11 10:37 eric
+
+ * scheduler.c, scheduler_ramqueue.c, smtpd.h: Rework the scheduler
+ internals. Fix some scheduling loop issues and handle envelope
+ scheduling/expiration better.
+
+ ok gilles@
+
+2012-09-10 16:22 eric
+
+ * queue.c: nasty typo.
+
+ ok gilles@
+
+2012-09-08 15:58 chl
+
+ * parse.y: remove unused header
+
+ ok gilles@
+
+2012-09-03 23:28 chl
+
+ * smtpfilter.c: fix the example filter to match current API by
+ using enum filter_status return value instead of plain int
+
+ ok todd@ gilles@
+
+2012-09-02 14:21 chl
+
+ * envelope.c: remove warning
+
+ asked by gilles@
+
+ ok gilles@
+
+2012-09-01 18:25 gilles
+
+ * smtpd.h: remove unused flag
+
+2012-09-01 18:09 gilles
+
+ * crypto_backend.c, parse.y, queue_backend.c, smtpd.c,
+ smtpd.conf.5, smtpd.h: - remove crypto_backend - remove support
+ for encrypted queue, it will be reintroduced later after
+ pouring more thinking into it
+
+ if you had it enabled, flush your queue before updating
+
+2012-09-01 00:40 fgsch
+
+ * crypto_backend.c: Use EVP_MAX_MD_SIZE for the key size for now as
+ discussed on icb.
+
+2012-08-31 00:38 chl
+
+ * compress_gzip.c, crypto_backend.c: increase fread()/fwrite()
+ buffer from 8k to 16k
+
+ ok gilles@
+
+2012-08-31 00:06 gilles
+
+ * parser.c, parser.h, smtpctl.c: - rename show_envelope() to
+ show_queue_envelope() - remove SHOW_RUNQUEUE it was a noop since
+ runqueues have been removed years ago from smtpd
+
+2012-08-30 23:59 chl
+
+ * crypto_backend.c, smtpd.h: change crypto_setup() prototype to use
+ const char * instead of uint8_t *
+
+ while there do some KNF: - change 8 spaces to tab - add/remove
+ some missing/extra space after if's
+
+ ok gilles@
+
+2012-08-30 21:33 chl
+
+ * compress_backend.c, compress_gzip.c, queue_backend.c, smtpd.h:
+ switch compress_backend to use FILE * instead of file
+ descriptors, like crypto_backend
+
+ ok gilles@
+
+2012-08-30 21:28 chl
+
+ * queue_backend.c: fix uninitialized variable which can be reach in
+ case of failure.
+
+ ok gilles@
+
+2012-08-30 20:25 gilles
+
+ * aldap.c, aldap.h, ber.c, ber.h, map.c, map_ldap.c, map_ldap.h,
+ parse.y, smtpd.h: - import latest aldap.[ch] and ber.[ch] from
+ ypldap - revive map_ldap.c by updating it to the current API
+
+ diff by Mathieu Masson who played puzzle with an oooold changeset
+ of mine, this import is to let us work on it in tree, it won't
+ work as is.
+
+ idea ok eric@ and chl@
+
+2012-08-30 20:19 eric
+
+ * queue_fsqueue.c: when reloading the envelopes from disk, skip
+ envelopes that are more recent than the startup time, since they
+ are already known to the scheduler.
+
+ ok gilles@
+
+2012-08-30 20:16 eric
+
+ * mta.c, mta_session.c: - correctly free the task if all rcpt where
+ rejected - fix refcounting - add some stat counters
+
+ ok gilles@ chl@
+
+2012-08-29 20:36 naddy
+
+ * parse.y, smtpd.conf.5: switch the default queue encryption to
+ AES-128 I'm committing this on behalf of gilles@
+
+2012-08-29 20:10 jmc
+
+ * smtpd.conf.5: tweak previous;
+
+2012-08-29 18:48 gilles
+
+ * smtpd.conf.5: obvious, but document that change of any encryption
+ parameter *requires* queue to be emptied first.
+
+2012-08-29 18:26 gilles
+
+ * compress_backend.c, crypto_backend.c, mta.c, parse.y,
+ queue_backend.c, smtp.c, smtpd.c, smtpd.conf.5, smtpd.h:
+ Introduce the crypto_backend API and provide support for...
+ encrypted queue using the new API. By default, OpenSMTPD does not
+ provide queue encryption, but it can be enabled with "queue
+ encryption [args]" and will transparently encrypt/decrypt
+ envelopes/messages as they hit the queue.
+
+ By default, it will use Blowfish in CBC mode with a different
+ random IV for each envelope and message. User provided key is
+ expanded using sha256 but a different cipher and digest may be
+ specified in smtpd.conf
+
+ Queue encryption is compatible with compression and if both
+ options are set it will do them in correct order and
+ transparently.
+
+ tested by chl@, a few users and myself ok chl@ and I
+
+2012-08-28 16:03 chl
+
+ * smtpd.h: remove encrypt.c prototypes leftovers
+
+ ok gilles@
+
+2012-08-28 09:52 chl
+
+ * encrypt.c: This file isn't and won't be used --> delete it.
+
+ ok gilles@
+
+2012-08-27 13:59 chl
+
+ * util.c: don't call ckdir() on each mktmpfile() call.
+
+ ok gilles@
+
+2012-08-26 19:08 eric
+
+ * queue_fsqueue.c: sane rewrite of the disk-queue traversal code,
+ and log bogus files found in there. fixes issues reported by
+ many.
+
+ ok gilles@
+
+2012-08-26 18:35 gilles
+
+ * smtpd.c: correctly check compress_backend_lookup() to avoid a
+ NULL deref
+
+2012-08-26 15:55 gilles
+
+ * smtpd.conf.5: - document queue compression
+
+2012-08-26 15:38 gilles
+
+ * compress_backend.c, compress_gzip.c, compress_zlib.c, parse.y: -
+ use the same compression algorithm, gzip, for message file and
+ envelopes - rename compress_zlib.c to compress_gzip.c
+
+ with this commit it is possible to inspect a compressed queue
+ with gzcat :)
+
+2012-08-26 13:52 gilles
+
+ * compress_zlib.c, smtpd.c, smtpd.h, util.c: - define
+ ZLIB_BUFFER_SIZE instead of hardcoding 8192 - check gzdopen()
+ failure - call gzclose() whenever a failure occurs after
+ gzdopen() - simplify slightly some checks in compress/uncompress
+ - create PATH_TEMPORARY in /var/spool/smtpd, chmod 700, owned by
+ _smtpd - compress_zlib should use PATH_TEMPORARY instread of /tmp
+ as we're chrooted and this will otherwise lead to a fatal()
+
+ ok chl@
+
+2012-08-26 13:21 gilles
+
+ * compress_zlib.c, queue_backend.c: - remove unused variable -
+ comment variables unused at this time
+
+2012-08-26 12:17 chl
+
+ * compress_backend.c, compress_zlib.c, encrypt.c: Add missing RCS
+ Id.
+
+ Reminded by jasper@
+
+ ok gilles@ eric@
+
+2012-08-26 01:35 chl
+
+ * compress_backend.c, compress_zlib.c, encrypt.c, parse.y,
+ queue_backend.c, smtpd.c, smtpd.h, util.c: Add compress_backend,
+ allowing compression of messages and envelopes in the queue. To
+ use it, just add "queue compress" in smtpd.conf. For now, only
+ zlib is used.
+
+ lots of feedback from eric@ and gilles@
+
+ ok eric@ gilles@
+
+2012-08-26 00:52 eric
+
+ * lka.c: lka must not start servicing requests until it has
+ received its full config from parent. Disable imsg from other
+ processes until then. Fix some races when the mta tries to
+ lookup an auth map too early, for example.
+
+ ok gilles@ chl@
+
+2012-08-26 00:03 gilles
+
+ * control.c, queue.c, scheduler.c, smtp.c, smtpd.h, util.c: - add
+ myself to the copyright in control.c, i've done quite a few
+ changes there in the last few years ;-) - get rid of availdesc():
+ getdtablecount() is so much more reliable - get rid of
+ env->sc_maxconn, we can be much smarter with getdtablecount()
+ and getdtablesize() - disable accept when we hit the control
+ process fd reserve - disable accept when we fail - enable accept
+ when we're back below the limit
+
+ this is not the full fd exhaustion diff, i'll merge changes from
+ relayd tomorrow, this was only required to get rid of the
+ env->sc_maxconn and availdesc() mess
+
+ "reads alright" eric@
+
+2012-08-25 23:33 gilles
+
+ * smtp.c, smtpd.h: - stop accepting clients if we hit our fd
+ reserve limit (or if we fail) - resume if we go below the fd
+ reserve
+
+ with feedback and ok eric@
+
+2012-08-25 17:47 eric
+
+ * scheduler_ramqueue.c: It's ok to try to rollback an update we
+ don't know about. It might happen if the message is aborted
+ before an envelope is sent to the scheduler. In this case, just
+ ignore it.
+
+ ok gilles@ chl@
+
+2012-08-25 17:39 gilles
+
+ * smtpd.c, smtpd.h, user_pwd.c: - offline enqueue does not need to
+ use the user_backend API, it relies on system users ... use
+ getpwuid() instead of ub->getbyuid() - since that was the only
+ caller, get rid of user_backend->getbyuid()
+
+ this is the first step towards removing the user_backend API and
+ making user lookups available through the maps API (yes, virtual
+ user support ;)
+
+ ok eric@, ok chl@
+
+2012-08-25 13:38 gilles
+
+ * smtpd.c, smtpd.h: - introduce TRACE_PROFILING - when smtpd starts
+ with -T profiling it will log_trace() some prof. info - when
+ smtpd starts with -T profstat, it will push them to stats API
+ with type STAT_TIMESPEC under key profiling.imsg.*
+
+ with this diff we can get live profiling of events with a very
+ minimal overhead :-)
+
+ ok chl@, ok eric@
+
+2012-08-25 12:23 gilles
+
+ * control.c, dns.c, mda.c, mta.c, queue.c, scheduler.c,
+ scheduler_ramqueue.c, smtp.c, smtp_session.c, smtpctl.c, smtpd.h,
+ stat_backend.c, stat_ramstat.c: - introduce struct stat_value -
+ statistics can now have a type (counter, timestamp, timeval,
+ timespec and possibly others in the future) - stat_increment()
+ / stat_decrement() now take an increment/decrement value and
+ are at the moment only of type counter - stat_set() now takes a
+ stat_value - provide helpers to convert raw values to stat_value
+
+ ok eric@, ok chl@
+
+ while at it fix a rq_queue_dump() call using a bogus timestamp in
+ scheduler ramqueue.
+
+2012-08-25 10:27 eric
+
+ * mda.c: use duration_to_text() when logging delay, for
+ consistency.
+
+ ok gilles@ chl@
+
+2012-08-25 10:17 eric
+
+ * control.c: log pause/resume from the administrator to maillog.
+ suggested by Jan Stary.
+
+ ok gilles@ chl@
+
+2012-08-24 23:24 eric
+
+ * queue.c: log forced removal and expiration of envelopes to
+ maillog. suggested by Jan Stary.
+
+ move queue loading notification to log_debug() while there.
+
+ ok gilles@
+
+2012-08-24 21:51 eric
+
+ * queue_backend.c: envelope_validate() don't take the evpid
+ anymore.
+
+2012-08-24 20:46 eric
+
+ * queue.c, scheduler.c, smtp_session.c: When an smtp session fails
+ and IMSG_QUEUE_REMOVE_MESSAGE is sent to the queue, also notify
+ the scheduler so it can rollback the current update. Send only
+ the msgid while there.
+
+ ok gilles@
+
+2012-08-24 20:26 eric
+
+ * queue.c: Error out if queue_envelope_load() failed, rather than
+ sending crap to the mta/mda.
+
+ ok gilles@
+
+2012-08-24 20:21 eric
+
+ * scheduler.c: add stat counter for the number of envelopes
+ inflight.
+
+ ok gilles@
+
+2012-08-24 15:21 chl
+
+ * envelope.c, queue_backend.c, smtpd.h: In envelope ascii
+ dump/load: - remove loading of evpid. - don't dump the msgid -
+ ignore msgid at load - remove now unused functions
+ ascii_{dump,load}_uint{32,64}_hex()
+
+ With inputs from eric@ and gilles@
+
+ ok gilles@ eric@
+
+2012-08-24 15:16 chl
+
+ * stat_ramstat.c: fix smtpctl show stats crash seen on -portable
+
+ reported by todd@
+
+ ok gilles@
+
+2012-08-24 15:13 chl
+
+ * queue_backend.c, queue_fsqueue.c, smtpd.h: Don't pass struct
+ envelope pointer in queue backend API, instead use envelope id
+ and an envelope ascii buffer.
+
+ ok eric@ gilles@
+
+2012-08-24 14:29 eric
+
+ * scheduler_backend.c, scheduler_ramqueue.c, smtpd.h: Remove the
+ rq_host and rq_batch structures from the ramqueue scheduler. The
+ scheduler should only allow admin to schedule specific envelopes
+ by id, or msgid. More advanced scheduling (per
+ host/route/whatever) should be achieved using smtpctl schedule-id
+ and proper filtering on the queue, or using ad-hoc scheduler
+ backend and tools.
+
+ ok gilles@ chl@
+
+2012-08-24 12:07 eric
+
+ * queue_fsqueue.c: When creating an envelope, check if the message
+ is incoming or queued to decide the path for the envelope. Remove
+ the need to check the envelope type.
+
+ ok gilles@ chl@
+
+2012-08-24 09:32 chl
+
+ * scheduler_backend.c: fix assignment typo
+
+ ok eric@ gilles@
+
+2012-08-23 18:10 todd
+
+ * enqueue.c: enhance -v mode of 'sendmail' binary ok chl@
+
+2012-08-23 15:16 todd
+
+ * enqueue.c: fix multiple recipient support, from sunil on irc
+ tested by me, ok gilles@
+
+2012-08-23 15:06 todd
+
+ * enqueue.c: add -R to sendmail compat flags that do nothing (for
+ now) ok gilles@
+
+2012-08-23 15:04 todd
+
+ * enqueue.c: add -N for sendmail compat DSN support; unlimited for
+ now ok gilles@
+
+2012-08-22 13:44 eric
+
+ * mta.c: also need to compare backupname if set.
+
+2012-08-22 00:22 jmc
+
+ * smtpd.conf.5: tweak previous;
+
+2012-08-21 22:19 eric
+
+ * dns.c, envelope.c, lka_session.c, mta.c, mta_session.c, parse.y,
+ smtpd.conf.5, smtpd.h: Allow smtpd to work as a backup MX,
+ relaying only to MXs with higher priority in the DNS record. For
+ example:
+
+ accept for domain "foo.org" relay backup "mx3.foo.org"
+
+ will relay mails for "foo.org" using only hosts with higher
+ priority (i.e. lower value) than "mx3.foo.org", which is supposed
+ to be the current server.
+
+ If the specified backup MX is not found in the DNS record,
+ relaying works as normal.
+
+ ok gilles@
+
+2012-08-21 22:07 eric
+
+ * mta_session.c: Try to connect to the next host if an IO error
+ occurs before the mta is ready to send a mail.
+
+ ok gilles@
+
+2012-08-21 17:14 eric
+
+ * dns.c: Use TAILQ rather than array for mx list.
+
+ ok gilles@
+
+2012-08-21 16:00 eric
+
+ * dns.c: dns sessions don't use lookup. no need to store them in a
+ tree.
+
+ ok gilles@
+
+2012-08-21 15:13 eric
+
+ * mda.c, mta.c, mta_session.c, queue.c, scheduler.c, smtpd.c,
+ smtpd.h: Re-enable loop detection, but in mta and mda this time.
+
+ ok gilles@
+
+2012-08-20 23:14 gilles
+
+ * filter_api.h, smtpd.h: MAX_LINE_SIZE is supposed to define the
+ max length of a SMTP line ... ... but SMTP_LINE_MAX *also*
+ defines it ... with a different value ... and did I mention both
+ were too small anyway ?
+
+ quick fix until we kill one or the other: bump MAX_LINE_SIZE and
+ define SMTP_LINE_MAX to be MAX_LINE_SIZE. this fixes the
+ immediate issue while we decide which one bites the dust.
+
+ fixes the crashes and "line too long" errors spotted by todd@ ok
+ todd@, ok chl@
+
+2012-08-20 20:18 eric
+
+ * control.c, stat_backend.c: Do not send more bytes than necessary
+ with IMSG_STAT_*. The INCREMENT and DECREMENT messages just
+ contain the key with the ending zero. For IMSG_STAT_SET, the
+ value is found at the beginning of the message, and the rest is
+ the key.
+
+ ok gilles@
+
+2012-08-20 20:15 gilles
+
+ * smtpfilter.c: - fix the example filter to match current API
+
+ spotted by todd@ ;-)
+
+2012-08-20 19:32 eric
+
+ * stat_ramstat.c: start iterating from min, not root.
+
+ ok gilles@
+
+2012-08-20 11:34 chl
+
+ * scheduler.c: chroot scheduler in /var/empty instead of
+ /var/spool/smtpd now that eric@ fixed the initialization layer
+ violation
+
+ committing on behalf of gilles@
+
+ ok gilles@ chl@
+
+2012-08-19 17:06 chl
+
+ * scheduler.c, scheduler_ramqueue.c: fix smtpctl schedule-all and
+ schedule-id <msgid>
+
+ with help from eric@
+
+ ok eric@
+
+2012-08-19 16:46 chl
+
+ * scheduler_ramqueue.c: avoid crash when removing non-existing
+ envelope
+
+ from eric, ok eric@
+
+ cvs:
+ ----------------------------------------------------------------------
+
+2012-08-19 16:16 chl
+
+ * config.c, dns.c, enqueue.c, envelope.c, filter_api.c,
+ filter_api.h, lka_session.c, makemap.c, mda.c, mfa_session.c,
+ parse.y, parser.c, queue_backend.c, queue_fsqueue.c, smtp.c,
+ smtp_session.c, smtpctl.c, smtpd.c, smtpd.h, smtpfilter.c, ssl.c,
+ util.c: coding style: replace all occurences of u_int* with uint*
+
+ ok eric@
+
+2012-08-19 14:56 eric
+
+ * stats.c: kill dead file that must die.
+
+ ok chl@
+
+2012-08-19 12:33 eric
+
+ * scheduler_ramqueue.c: Let the scheduler return all schedulable
+ envelopes for the same message as a single batch. The route for
+ each envelope is sorted out by the mta properly, so they are
+ grouped as a single MAIL on each route.
+
+ ok gilles@ chl@
+
+2012-08-19 12:32 chl
+
+ * envelope.c, queue_fsqueue.c, smtpd.h: Kill
+ envelope_{dump,load}_file() and replace them with
+ envelope_{dump,load}_buffer().
+
+ with input from eric@
+
+ ok eric@
+
+2012-08-19 12:28 eric
+
+ * ioev.c: Add warnings on io errors to help diagnosis.
+
+ ok gilles@ chl@
+
+2012-08-19 10:47 chl
+
+ * smtpd.c: add missing IMSG_* in imsg_to_str()
+
+ ok eric@
+
+2012-08-19 10:45 chl
+
+ * smtpd.h: fix an issue where too long lines were not spot
+ properly.
+
+ issue reported by todd@
+
+ ok eric@
+
+2012-08-18 22:52 eric
+
+ * mta_session.c, queue.c, smtpd.h: zap struct mta_batch. Only pass
+ ids where needed.
+
+ ok gilles@
+
+2012-08-18 20:18 gilles
+
+ * control.c, dns.c, lka.c, queue.c, scheduler.c,
+ scheduler_ramqueue.c, smtp.c, smtp_session.c, smtpctl.c, smtpd.c,
+ smtpd.h, stat_backend.c, stat_ramstat.c, stats.c: - introduce
+ stat_backend, an API for pluggable statistic backends >
+ statistics are no longer static structures in shared memory >
+ statistics are only set, smtpd never uses them in its logic >
+ each statistic is a key/value where key can be any (dynamic)
+ string - convert all uses of the former API to use the new one -
+ implement stat_ramstat that keeps non-persistent stats in ram
+ structure
+
+ ok eric@, ok chl@
+
+2012-08-18 18:05 chl
+
+ * smtp_session.c: Disallow empty domain/address sent after
+ HELO/EHLO command.
+
+ ok gilles@ eric@
+
+2012-08-18 17:45 eric
+
+ * mta.c, mta_session.c, smtpd.h: Major update of the mta internals.
+
+ Add a mta_route structure which describes a route through which
+ outgoing mails are to be sent. This structure holds connection
+ parameters and limits. When an envelope is received in a batch,
+ the route for it is looked up, and the envelope is added to the a
+ list of envelope to be sent for this message on that route: a
+ task. When the batch is closed, each task is added to the list
+ of tasks for their respective route.
+
+ The routes are drained when new work can happen. The route will
+ create new mta sessions if necessary. When a session is up and
+ ready, it picks the first pending task on the route if any. In
+ the other case, it just closes the connection.
+
+ Errors on the connection are reported to the route, so that the
+ route could be flagged as broken. Currently, three errors on a
+ an attempt to open a route is reported as a failure for all pen-
+ ding tasks.
+
+ ok gilles@
+
+2012-08-18 17:39 eric
+
+ * bounce.c: Limit the number of bounce sessions running at the same
+ time. When committed, a bounce is put on a runnable list of
+ bounces. This list is drained to enqueue as much bounces as
+ possible within the limit.
+
+ This avoids DoS'ing the server when lots of bounces are enqueued
+ at startup.
+
+ While there, allow new envelopes to be added to a bounce until
+ the the very last moment (i.e. when the list of recipients is
+ written).
+
+ ok gilles@ chl@
+
+2012-08-11 21:19 chl
+
+ * scheduler_ramqueue.c: fix use after free
+
+ ok eric@
+
+2012-08-11 21:18 chl
+
+ * queue.c: Add missing header needed by PRI format string Add
+ missing header needed by time()
+
+ ok eric@
+
+2012-08-11 14:43 eric
+
+ * util.c: make sure generated id is never 0.
+
+ ok gilles@
+
+2012-08-10 13:05 eric
+
+ * mta_session.c, smtp_session.c, smtpd.h: Move mta and smtp
+ specific defines into their own files. Some formatting cleanups
+ while there.
+
+ ok gilles@
+
+2012-08-10 11:16 eric
+
+ * control.c: code cleanup
+
+ ok gilles@
+
+2012-08-09 21:16 eric
+
+ * scheduler.c: Envelopes scheduled as "removed" are already deleted
+ from the scheduler. Do not delete them twice.
+
+2012-08-09 18:00 eric
+
+ * bounce.c, queue.c, smtpd.h: Allow failure reports for different
+ recipients of the same message to be grouped into a single bounce
+ message.
+
+ The bounce structure keeps a list of envelopes. For now, the
+ list is constructed by delaying the re-enqueuing of a bounce
+ envelope a bit, to wait for other bounces from the same message
+ to be part of the same report.
+
+2012-08-09 14:19 eric
+
+ * scheduler.c: dead prototype
+
+2012-08-09 13:52 eric
+
+ * bounce.c, smtpd.h: remove unused function and prototypes
+
+2012-08-09 11:48 eric
+
+ * bounce.c, lka_session.c, mda.c, mta_session.c, queue.c,
+ scheduler.c, smtp.c, smtpd.c, smtpd.h: Improve the message flows
+ to completely isolate operations on the queue backend within the
+ queue process.
+
+ The scheduler sends envelope ids to the queue process which loads
+ the envelope and forward the request to the agent responsible for
+ the delivery. The result is sent by the agent to the queue which
+ updates the storage before notifying the scheduler.
+
+ Bounces are created and enqueued (from the client side) by the
+ queue process, rather than the scheduler.
+
+ ok gilles@
+
+2012-08-08 19:33 eric
+
+ * control.c, smtpctl.c, smtpd.h: remove useless defines
+
+ ok gilles@ chl@
+
+2012-08-08 19:31 eric
+
+ * dns.c, queue_fsqueue.c: cleanup some old debug traces
+
+ ok gilles@ chl@
+
+2012-08-08 19:28 eric
+
+ * smtpd.c: log received fd in log_imsg() if any
+
+ ok gilles@ chl@
+
+2012-08-08 10:50 eric
+
+ * bounce.c, queue.c, scheduler.c, scheduler_backend.c,
+ scheduler_ramqueue.c, smtpd.h, util.c: Improve the scheduler
+ backend API.
+
+ New envelopes are pushed into the scheduler through the insert()
+ commit() rollback() transactional interface functions.
+
+ Worklists are pulled from the scheduler through a single batch()
+ interface function, which returns a list of envelope ids and the
+ type of processing. Envelopes returned in this batch are said to
+ be "in-flight", as opposed to "pending". They are supposed to be
+ processed in some way, and either updated() or deleted() at some
+ point.
+
+ The schedule()/remove() functions are used to alter the internal
+ state of "pending" envelopes to make them schedulable. The enve-
+ lopes will be part of a worklist on the next call to batch().
+
+ Rewrite the scheduler_ramqueue backend.
+
+ The initial queue loading in now done by the queue.
+
+ ok gilles@
+
+2012-08-07 23:47 eric
+
+ * smtpd.h, tree.c, util.c: Implement a set of tree_* functions for
+ storing arbitrary pointers in splay trees with uint64_t keys.
+ Also add x{m,c}alloc and xstrdup helpers.
+
+ ok gilles@
+
+2012-08-07 22:36 eric
+
+ * smtpctl.c: fix evpid parsing on 32bit archs
+
+ ok gilles@
+
+2012-07-29 22:16 eric
+
+ * mta_session.c: reset the session if no RCPT was accepted for the
+ batch.
+
+ ok gilles@
+
+2012-07-29 19:33 eric
+
+ * dns.c: fix bogus permfail when no MX is defined on a valid
+ domain.
+
+ ok gilles@
+
+2012-07-29 19:21 gilles
+
+ * aliases.c, lka_session.c, makemap.c, smtpd.h, util.c: - introduce
+ xlowercase() and allow lowercase() to fail gracefully - replace
+ all calls to lowercase() with calls to xlowercase() - in the
+ format string expansion, lowercase() all formats
+
+ we will have to reassess all calls to xlowercase() even though it
+ has never triggered as far as I know, we can probably gracefully
+ fail some of them. right now we're just keeping former
+ behaviour.
+
+ this commit fixes issue reported by Hugo Osvaldo Barrera where a
+ %u format could lead to a delivery failure (ie:
+ GILLES@openbsd.org should be expanded to gilles, not GILLES ...
+ only for local deliveries).
+
+ ok chl@ on the idea, ok eric@ on the diff
+
+2012-07-29 18:33 eric
+
+ * lka_session.c, smtpd.h: get rid of A_INVALID. little code
+ cleanup while here.
+
+ ok gilles@
+
+2012-07-29 15:56 eric
+
+ * mta.c, mta_session.c, smtpd.h: remove the session tree from the
+ global env and move it to mta_session.c, along with mta_relay and
+ mta_session definition.
+
+ ok gilles@
+
+2012-07-28 14:06 chl
+
+ * scheduler_backend.c: fix uninitialized field type in
+ scheduler_info struct.
+
+ found with valgrind on -portable.
+
+ ok gilles@
+
+2012-07-19 00:04 eric
+
+ * scheduler.c: make the scheduler less verbose by default.
+
+ suggested by Percy Piper.
+
+ ok gilles@
+
+2012-07-16 08:00 jmc
+
+ * smtpd.conf.5: sync the first example with the default conf file;
+ ok gilles
+
+2012-07-16 07:56 jmc
+
+ * smtpd.conf.5: don;t quote things unneccessarily; ok gilles
+
+2012-07-15 20:42 gilles
+
+ * smtpd.8: update examples: pkill sendmail ->
+ /etc/rc.d/sendmail stop smtpd -> /etc/rc.d/smtpd start
+
+ suggested by Seth Wright <seth@crosse.org>, ok chl@
+
+2012-07-15 19:36 gilles
+
+ * mta_session.c: when specifying a relay port that's not standart,
+ do not ntohs() the relay port as it will be done internally by
+ sa_set_port()
+
+ issue reported by Markus Bergkvist <markus@familjenbergkvist.net>
+
+2012-07-15 19:04 gilles
+
+ * smtpd.conf.5: fix example
+
+ submitted by Marcus Merighi <mcmer-openbsd@tor.at>
+
+2012-07-12 15:01 eric
+
+ * dnsdefs.h, dnsutil.h: remove unused files
+
+ ok gilles@
+
+2012-07-12 10:51 chl
+
+ * delivery_maildir.c, lka_session.c, smtpd.h, util.c: add support
+ for maildir tagging/folders.
+
+ ok gilles@ ok eric@ on previous versions of this patch
+
+2012-07-12 00:16 chl
+
+ * util.c: enable back = char in address localpart, that is
+ sometimes used by mailing lists.
+
+ ok gilles@ eric@
+
+2012-07-11 19:20 chl
+
+ * filter_api.h: Respect RFC 5321, section 4.5.3.1.: it reduces our
+ current max size for localpart, domainpart and text line.
+
+ The sizeof struct envelope goes from 8k to 6k.
+
+ ok gilles@ eric@
+
+2012-07-11 19:20 chl
+
+ * util.c: Don't respect RFC 5322, that allows some crazy characters
+ in email localpart, like !#$&'*/=?^`{|}~ ... and all the other
+ ones that can be double quoted, just refuse them.
+
+ ok gilles@ eric@
+
+2012-07-11 01:21 chl
+
+ * queue_backend.c, queue_fsqueue.c, smtpd.h: backout the: - remove
+ the /envelopes subdirectory, envelopes are at the same level than
+ the message file - kill PATH_ENVELOPES define
+
+ but keep the: - reduce the number of buckets from 0xfff to 0xff,
+ this avoid performances of the queue to decrease when we start
+ having tons of buckets
+
+ ok eric@ gilles@
+
+2012-07-10 18:11 chl
+
+ * smtpd.h, util.c: accept address literal for the recipient domain.
+ while there, change valid_{local,domain}part() prototypes to use
+ const char *.
+
+ with input from gilles@ and eric@
+
+ ok gilles@ eric@
+
+2012-07-10 13:13 gilles
+
+ * scheduler.c, scheduler_ramqueue.c, smtpd.h: - simplify the
+ scheduler loop logic further, it is ridiculously simple now and
+ I don't think we can do much better (at that level) :-p - always
+ break out of the handler after processing an envelope, this will
+ avoid a busy scheduler from not getting a chance to handle
+ SIGTERM/SIGINT YES we can now ctrl-c a maaaaad scheduler !
+
+ ok eric@, ok chl@
+
+2012-07-09 19:57 gilles
+
+ * scheduler.c, smtpd.c, smtpd.h: - introduce
+ log_trace(TRACE_SCHEDULER, ...) - simplify a tiny tiny bit the
+ scheduler loop - no functional change (yet)
+
+2012-07-09 14:16 eric
+
+ * asr.c, asr.h, dname.c, dns.c, pack.c, print.c, res_random.c,
+ sockaddr.c, thread_private.h: move to the new resolver
+ implementation, with temporary glue to use the relevant files
+ from asr directly.
+
+ ok gilles@
+
+2012-07-09 11:57 gilles
+
+ * bounce.c, control.c, queue.c, runner.c, scheduler.c,
+ scheduler_backend.c, smtpctl.c, smtpd.c, smtpd.h: - runner is the
+ terminology we used back when we had runqueues, we no longer
+ have them and runner is actually a scheduler so rename. -
+ introduce scheduler_backend which does the same to scheduler than
+ queue_backend does to queue and map_backend does to maps -
+ remove all occurences of RUNNER and runner, replace them with
+ SCHEDULER and scheduler
+
+ ok eric@, ok chl@
+
+2012-07-09 10:08 gilles
+
+ * queue_backend.c, queue_fsqueue.c, runner.c, smtpd.h: first step
+ of simplifying fsqueue:
+
+ - remove the /envelopes subdirectory, envelopes are at the same
+ level than the message file - kill PATH_ENVELOPES define -
+ reduce the number of buckets from 0xfff to 0xff, this avoid
+ performances of the queue to decrease when we start having tons
+ of buckets
+
+ this diff introduces a change to the queue layout, you will want
+ to empty your queue before updating. more cleanup to come
+
+ ok eric@, ok chl@
+
+2012-07-08 20:13 chl
+
+ * queue.c, queue_backend.c, queue_fsqueue.c, runner.c, smtpd.c,
+ smtpd.h: remove enum queue_kind from queue_fsqueue.c. incoming
+ messages are now always stored in /incoming, whatever the
+ queue_backend is. remove QOP_FD_RW and fsqueue_message_fd_rw().
+ while there check return value of generated paths before calling
+ rmtree()
+
+ with advice from gilles@ and eric@
+
+ ok gilles@ eric@
+
+2012-07-08 19:17 jmc
+
+ * smtpd.conf.5: avoid line splitting; also, one an -> a
+
+2012-07-08 17:48 gilles
+
+ * parse.y, smtpd.conf.5, util.c: - plug text_to_relayhost() in
+ parse.y to support relay URLs. - document the new URL syntax in
+ smtpd.conf.5 - replace starttls:// schema with tls://
+
+ Beware, "relay via" rules should now be expressed with a relay
+ URL:
+
+ accept [...] relay via "mx1.example.org" smtps port 465
+ becomes accept [...] relay via "smtps://mx1.example.org"
+
+ This will allow using mappings of relays with different protocols
+ and options.
+
+ Make sure to update your smtpd.conf if you relay via !
+
+ ok eric, ok chl
+
+2012-07-08 15:42 gilles
+
+ * auth_bsd.c: auth_bsd() is static
+
+2012-07-02 19:00 eric
+
+ * queue_backend.c, runner.c, scheduler.c, smtpctl.c, smtpd.c,
+ smtpd.h: Lookup queue and scheduler backends by name, rather than
+ enum. Add a command-line option to specify the backend to use at
+ runtime.
+
+ ok gilles@
+
+2012-07-02 15:22 eric
+
+ * queue_fsqueue.c: make backend functions static.
+
+ ok gilles@
+
+2012-07-02 12:32 eric
+
+ * util.c: Sleeping here is definitely not what we want to do. Use a
+ cycling counter with some randomness to generate short-lived
+ unique ids.
+
+ ok gilles@
+
+2012-06-20 22:45 eric
+
+ * bounce.c, queue.c, queue_backend.c, queue_fsqueue.c, runner.c,
+ scheduler_ramqueue.c, smtpctl.c, smtpd.h: Finally get rid of the
+ queue_kind enum in the queue API. Keep that internally in fsqueue
+ backend for now, and let the fsqueue_message() and
+ fsqueue_envelope() dispatchers do the right thing.
+
+ Based on a diff by chl@
+
+ ok chl@ gilles@
+
+2012-06-20 22:27 eric
+
+ * runner.c: fix runner spinning on message loop.
+
+ ok gilles@
+
+2012-06-18 12:21 chl
+
+ * queue.c: fix potential use of uninitialized variable.
+
+ found with valgrind on -portable.
+
+ ok gilles@
+
+2012-06-17 17:17 gilles
+
+ * runner.c, scheduler.c, scheduler_ramqueue.c, smtpd.h: - introduce
+ struct scheduler_info and the scheduler_info() function to fill
+ a struct scheduler_info given a struct envelope - adapt the
+ scheduler API and the scheduler_ramqueue backend to use the new
+ struct scheduler_info instead of a struct envelope
+
+ idea discussed with eric@ and chl@, mechanical diff, no
+ functional change
+
+2012-06-16 18:16 chl
+
+ * filter.c, filter_api.c: rename filter.c --> filter_api.c (to be
+ consistent with upcoming changes)
+
+ prompted by and ok gilles@
+
+2012-06-14 23:56 gilles
+
+ * filter.c, filter.h, filter_api.c, filter_api.h, smtpd.h,
+ smtpfilter.c: - rename filter.h -> filter_api.h to be consistent
+ with upcoming changes
+
+2012-06-14 22:59 gilles
+
+ * sockaddr.c: - make sockaddr_as_fqdn() endian-safe
+
+ bug spotted by Jan Stary fix by eric@, committing this on his
+ behalf, ok gilles@
+
+2012-06-08 13:34 chl
+
+ * queue_backend.c: add missing header needed by time()
+
+ ok eric@ gilles@
+
+2012-06-03 21:52 eric
+
+ * envelope.c, queue_backend.c, smtpd.h: Do not store the envelope
+ id within the envelope, only the message id. Make sure existing
+ envelopes can be properly loaded.
+
+ ok chl@ gilles@
+
+2012-06-01 16:55 eric
+
+ * smtp.c, smtpd.c: allow to pause some subsystems at startup.
+
+ ok gilles@ chl@
+
+2012-06-01 13:42 eric
+
+ * queue_backend.c, queue_fsqueue.c: on envelope creation, setup and
+ reset the relevant envelope fields in the wrapper function rather
+ than in individual backends.
+
+ ok gilles@
+
+2012-06-01 12:46 chl
+
+ * mta_session.c: use PRIu64 instead of llu in format string.
+
+ ok eric@
+
+2012-06-01 12:40 chl
+
+ * smtpd.h: remove unused fields
+
+ ok eric@
+
+2012-06-01 11:24 eric
+
+ * envelope.c, queue_fsqueue.c, smtpd.h: move envelope dump/load
+ functions to envelope.c
+
+ ok gilles@
+
+2012-05-29 21:53 gilles
+
+ * map.c, map_db.c, map_static.c, map_stdio.c, smtpd.h: - introduce
+ map_static.c as a backend to static maps in parse.y, this has
+ the benefit that we no longer have two code paths whenever we
+ deal with maps, we can always use the backend mechanism.
+
+ I have not plugged this in yet, I'll do it in a later commit,
+ just get it out of my sandbox
+
+2012-05-29 21:29 gilles
+
+ * smtpd.h, util.c: - introduce text_to_relayhost() which converts
+ an url into a relayhost. urls are of the form:
+ [schema://]host[:ip]
+
+ not used, yet other commits are following ;-)
+
+2012-05-25 15:52 chl
+
+ * ioev.c: remove unused variable
+
+ ok gilles@
+
+2012-05-25 15:51 chl
+
+ * delivery_filename.c, delivery_maildir.c, scheduler_ramqueue.c:
+ add missing header needed by time()
+
+ ok gilles@
+
+2012-05-24 00:46 gilles
+
+ * util.c: - introduce temp_inet_net_pton_ipv6() temporarily until
+ we have AF_INET6 support in inet_net_pton().
+
+ - in text_to_netaddr(), if we are handling an inet6 netmask AND
+ we have inet_net_pton() that failed with EAFNOSUPPORT, THEN we
+ fallback to this.
+
+ quick fix to unbreak setups that use inet6, a diff is floating to
+ have it supported at the right place.
+
+2012-05-13 15:58 jmc
+
+ * smtpd.conf.5: tweak previous; ok gilles
+
+2012-05-13 15:57 jmc
+
+ * makemap.8: replace tabs with spaces, to avoid markup problems; ok
+ gilles
+
+2012-05-13 11:18 nicm
+
+ * parser.c, smtpctl.c: Remove sizes entry so it doesn't appear as a
+ valid command in the "smtpctl show" output, and use errx rather
+ than err for the unknown message error.
+
+ ok gilles
+
+2012-05-13 02:10 gilles
+
+ * map.c, map_db.c, map_stdio.c, parse.y, ruleset.c, smtpd.h,
+ util.c: - cleanup parse.y by removing lots of code that should
+ not have been there, but in ruleset.c and util.c instead.
+
+ - introduce the new map_compare() map API call to allow iterating
+ over keys and comparing them with provided key using provided
+ function. this allows checking a partial key in a key set, very
+ useful for comparing an address to a set of netmask.
+
+ - introduce new map kind K_NETADDR - implement K_NETADDR for
+ map_db and map_stdio - teach ruleset checking how to use the
+ map_compare() with K_NETADDR
+
+ we can now do the following:
+
+ map "srcaddr" source plain "/etc/mail/srcaddr.txt"
+
+ accept from map srcaddr for domain "openbsd.org" [...]
+
+2012-05-12 23:49 gilles
+
+ * makemap.8, parse.y, smtpd.conf.5, smtpd.h: - remove unused
+ sources S_EXT, S_DYN and S_EXT from enum map_src - continue
+ simplification of parse.y - remove "for network", if we ever need
+ it we can reimport, probably no one knows of that undocumented
+ strange feature ;-) - change syntax for virtual domains
+ configuration:
+
+ accept for virtual vmap [...] <- wrong
+ accept for virtual map vmap [...] <- right
+
+ the reason for this change is that we will soon implement relay
+ rules
+ through maps and that keeping that syntax would make it
+ inconsistent
+ with the other rules.
+
+ - update man pages for makemap and smtpd.conf to reflect changes
+
+ ok eric@, looks ok chl@
+
+2012-05-12 20:41 gilles
+
+ * parse.y, smtpd.conf.5, smtpd.h: - simplify a bit maps by removing
+ fields which are still unused years after the initial ambitious
+ implementation: byebye map type & map flags
+
+ - simplify a bit parse.y by removing assignations to these
+ otherwise unused fields
+
+ - remove the DNS map source, it may be a good idea, but we can
+ just add it when we plan to implement it (if we do)
+
+ - make the { } options in map declaration, it's been annoying me
+ for a long time now, this allows the following to work:
+
+ map "foobar" source plain "/etc/mail/foobar"
+
+ - update smtpd.conf.5 accordingly ;-)
+
+2012-05-12 19:41 eric
+
+ * mta_session.c, smtpd.h: Update the internal mta implementation so
+ that a session now has a list of messages to send to the remote
+ smtp server over the same connection. It's not currently used as
+ the scheduler/runner is not aware of this yet, and the imsg
+ protocol would need to be updated.
+
+ ok gilles@
+
+2012-05-12 17:31 gilles
+
+ * lka.c: - 'secret' -> 'credentials' in some logs - log_warn()
+ admin that a map that's needed by an envelope is no longer in
+ the configuration file
+
+2012-05-12 17:29 gilles
+
+ * lka.c, map_db.c, map_stdio.c, smtpd.h: - rename all occurences of
+ K_SECRET to K_CREDENTIALS - rename all occurences of struct
+ map_secret to map_credentials - do not fatal if the credentials
+ map has disappeared, instead make the auth fail with a lookup
+ failure. the mail will be temporary failed so it stays in queue
+ until admin fixes smtpd.conf, removes mail, or lets it expires
+
+2012-05-11 14:12 eric
+
+ * mta.c, mta_session.c, smtpd.h: split the session logic off mta.c
+ into mta_session.c
+
+ ok gilles@
+
+2012-05-11 10:15 eric
+
+ * mta.c: set the status line and log envelope change in
+ mta_envelope_done(). get rid of mta_envelope_log() and makes the
+ code a little more straightforward.
+
+ ok gilles@
+
+2012-05-08 13:52 eric
+
+ * smtp_session.c: fix and re-enable connect notification to the
+ mfa. filtering now occurs before setting up ssl on smtps
+ connections.
+
+ ok chl@ gilles@
+
+2012-04-24 16:56 jmc
+
+ * smtpd.conf.5: take a stab at documenting when arguments need
+ quoted, and valid macro characters;
+
+ prompted by a diff from robert peichaer org
+
+ thanks gilles and henning for feedback ok deraadt zinke
+
+2012-04-21 14:45 gilles
+
+ * aliases.c: i got the previous fix wrong, /etc/mail/aliases should
+ use SMTPD_USER privileges. while at it, also apply the same to
+ virtual domains.
+
+2012-04-16 15:32 chl
+
+ * parse.y: add missing header needed by str* and mem* functions
+
+ ok gilles@
+
+2012-04-15 15:11 gilles
+
+ * aliases.c: when using aliases, the *real* delivery user is not
+ set on expand nodes which prevents filters / filenames from
+ working from /etc/mail/aliases. in aliases_get() during the rb
+ tree iteration, copy the username to the expand node.
+
+ diff from Christopher Zimmermann, thankkkks and sorry for the
+ delay
+
+2012-04-15 14:12 chl
+
+ * runner.c, scheduler_ramqueue.c, smtpctl.c: Remove dead
+ assignments and newly created unused variables.
+
+ Found by LLVM/Clang Static Analyzer.
+
+ ok gilles@
+
+2012-04-14 15:31 eric
+
+ * dns.c: improve readability
+
+ ok gilles@
+
+2012-04-13 09:03 jmc
+
+ * smtpd.conf.5: clarify "hostname"; from robert peichaer org ok
+ gilles
+
+2012-04-07 16:11 jmc
+
+ * smtpctl.8: grammar fix;
+
+2012-03-30 18:48 chl
+
+ * mta.c: increase timeout to 5m when connecting to a remote mail
+ server, as required by the RFC 5321 (section 4.5.3.2.1.)
+
+ ok gilles@
+
+2012-03-27 14:53 eric
+
+ * mta.c: Do not try STARTTLS if the server does not advertise
+ support for it (it apparently triggers very bizarre behaviour on
+ some servers). Also make sure we are not using AUTH over a clear
+ channel.
+
+ ok gilles@
+
+2012-03-25 10:44 eric
+
+ * mta.c: Do not fatal() when failing to connect to a relay.
+ Instead, drop the relay and try the next one.
+
+ ok gilles@
+
+2012-03-19 21:38 gilles
+
+ * runner.c: when a mailer daemon loop is detected, do not insert
+ new bounce in ramqueue
+
+ fixes an issue experienced by myself and Roman Kravchuck
+
+ ok eric@
+
+2012-03-17 14:10 gilles
+
+ * enqueue.c: llu -> PRIu64 in enqueue() to avoid warning in
+ portable
+
+ diff from Guillaume Leconte <guillaume.leconte@scality.com>
+
+2012-03-14 00:07 gilles
+
+ * scheduler_ramqueue.c: When moving back envelope from offload tree
+ to msg tree ... remove the envelope from offload tree not msg
+ tree, this corrupts the ramqueue in ways that I couldn't imagine
+ before wasting so many hours tracking it.
+
+ Fixes crash on my server under load, no crash after about 20K
+ mails processed from up to 150 concurrent sessions.
+
+2012-03-08 00:22 gilles
+
+ * aliases.c: - remove some map_find() calls that are no longer
+ needed, they are followed by a map_lookup() call that does the
+ map_find() internally
+
+ spotted and diff by Mathieu <ptr.jetable@gmail.com>
+
+2012-03-08 00:04 gilles
+
+ * delivery_filename.c, delivery_maildir.c, delivery_mbox.c,
+ delivery_mda.c: - db.h not needed here, already removed by chl@
+ but I fscked up previous commit ... remove again
+
+2012-03-07 23:54 gilles
+
+ * delivery_filename.c, delivery_maildir.c, delivery_mbox.c,
+ delivery_mda.c, queue_fsqueue.c, runner.c, scheduler_ramqueue.c,
+ smtpd.h: various reliability fixes:
+
+ - prevent queue_fsqueue from fatal() when it hits an ENOENT, it
+ can happen - change a bit the scheduler API to simplify it, fix
+ runner accordingly
+
+ - we can't remove msg/batch from ramqueue while envelope is
+ offloaded or it will cause a double, instead we add refcnt to
+ both msg/batch and only free them when it hits 0
+
+2012-02-09 08:47 jmc
+
+ * smtpctl.8: correct argument names for "resume"; from Jan Stary ok
+ gilles
+
+2012-02-04 18:11 chl
+
+ * delivery_filename.c, delivery_maildir.c, delivery_mbox.c,
+ delivery_mda.c: remove unused header
+
+ ok gilles@
+
+2012-02-02 17:52 eric
+
+ * enqueue.c: Only use mime/line-split if the input message actually
+ contains a very long line.
+
+ ok gilles@ chl@
+
+2012-02-01 21:30 eric
+
+ * mta.c: When updating an envelope status, the update is immediatly
+ sent to the queue and the envelope discarded from the mta batch.
+ Also make sure that all condition leading to the MTA_DONE state
+ have properly set the status of all pending envelopes before. No
+ envelope should be left when entering that state.
+
+ Little cleanup while there: remove mta_message_status() and
+ rename remaining mta_message_*() to mta_envelope_* to avoid
+ confusion.
+
+ ok gilles@
+
+2012-02-01 18:25 eric
+
+ * iobuf.c: fix stupid mistake in buffer code
+
+ ok gilles@
+
+2012-01-31 22:05 gilles
+
+ * queue_fsqueue.c, runner.c, scheduler_ramqueue.c, smtp.c, smtpd.h:
+ fix an issue observed this week-end while flooding ajacoutot@ :
+
+ we keep track of available fd's to prevent scheduling of messages
+ if we know that we are going to fail. however, since the envelope
+ is not removed from the scheduler, it will be rescheduled right
+ away leading to a busy loop in the scheduler. we know flag the
+ mda/mta processes as BUSY and do not schedule envelopes that
+ target a BUSY process.
+
+ also, fix a potential bug that could lead to a use after free
+ when doing a batch/message/host traversal of schedulable
+ envelopes.
+
+ while at it fix misuse of env->sc_opts as env->sc_flags, was not
+ really causing any issue as the misuse was constant ...
+
+2012-01-30 21:21 gilles
+
+ * enqueue.c: do not encode headers, it breaks the resulting message
+
+ reported by eric@ and miod@ ok chl@
+
+2012-01-30 11:02 chl
+
+ * ioev.c, scheduler_ramqueue.c: Add missing header needed by PRI
+ format string
+
+ ok eric@ gilles@
+
+2012-01-29 17:54 eric
+
+ * queue_fsqueue.c: Remove message directories right away instead of
+ moving them to purge/. Prevent hitting dir entry limits when
+ dealing with lots of mails.
+
+ ok gilles@
+
+2012-01-29 17:51 eric
+
+ * smtp_session.c: For some reason, all recipients are rejected if
+ the msg field is not initialized here. Fix it, but this requires
+ further investigation.
+
+ ok gilles@
+
+2012-01-29 16:33 eric
+
+ * smtp_session.c: disable connection filter hook for now. fixes
+ smtps.
+
+ ok gilles@
+
+2012-01-29 12:37 eric
+
+ * bounce.c, client.c, client.h, mta.c, smtp.c, smtp_session.c,
+ smtpd.h, ssl.c: Rewrite io code in smtp and mta using the
+ iobuf/ioev interface to have a better separation between io and
+ protocol logic. As a side-effect, it fixes a couple of
+ long-standing issues in the io path, and hopefully add fresh ones
+ instead. Kill client.c in the process.
+
+ ok gilles@
+
+2012-01-29 11:42 eric
+
+ * enqueue.c: fix warning
+
+ ok gilles@
+
+2012-01-29 11:40 eric
+
+ * queue_fsqueue.c: Quick fix to prevent two processes from using
+ the same temporary envelope file at the same time.
+
+ ok gilles@
+
+2012-01-29 01:32 eric
+
+ * iobuf.c, iobuf.h, ioev.c, ioev.h: Import generic network IO code.
+ The plan is to hide the boring details of IO operations such as
+ buffering or SSL, and provide a slightly nicer interface to the
+ protocol writer.
+
+ Not plugged to the rest of the code yet.
+
+ ok gilles@
+
+2012-01-28 22:15 gilles
+
+ * enqueue.c: ok, since we're already encoding =, let's just do full
+ quoted printable encoding, it's just a few additional lines ...
+
+2012-01-28 19:13 gilles
+
+ * enqueue.c: when enqueuing, check if a MUA did some MIME transfer
+ encoding, otherwise do quoted-printable transfer encoding so that
+ OpenSMTPD doesn't refuse to enqueue mails with long lines
+
+ ok eric@
+
+2012-01-28 17:54 gilles
+
+ * util.c: remove even more annoying debug logs
+
+ ok eric@
+
+2012-01-28 17:52 gilles
+
+ * smtpd.c: smtpd no longer needs to tell us that it forks a purge
+ process ever few seconds, we've seen it works and it has become
+ irritating :p
+
+2012-01-28 17:50 gilles
+
+ * runner.c, scheduler_ramqueue.c, smtpd.h: add optional display
+ handler to scheduler_backend, if not NULL the handler will be
+ called for each iteration of the runner
+
+ implement a display handler for scheduler_ramqueue to display the
+ entire ramqueue (hosttree, msgtree and linear queue) in log_debug
+
+2012-01-28 16:11 eric
+
+ * smtpd.h: remove useless state
+
+ ok gilles@
+
+2012-01-28 12:33 gilles
+
+ * ramqueue.c: no longer needed
+
+2012-01-28 12:33 gilles
+
+ * mta.c, queue.c, ramqueue.c, runner.c, scheduler.c,
+ scheduler_ramqueue.c, smtpctl.c, smtpd.h: - introduce the
+ scheduler_backend API - introduce the scheduler_ramqueue backend
+ - remove all occurences of ramqueue outside of the ramqueue
+ backend - teach runner how to use the new API
+
+ it is now possible to write custom schedulers !
+
+ ok eric@, ok chl@
+
+2012-01-27 01:01 gilles
+
+ * smtp_session.c: that log_debug is no longer needed
+
+2012-01-27 00:59 gilles
+
+ * smtp_session.c: in session_read_data() do NOT enable back read
+ event otherwise it will corrupt the session and cause a fatal.
+
+ reported by Roman Kravchuk, with this diff in OpenSMTPD survives
+ again the evil smtp_tester.py :-p
+
+2012-01-27 00:18 gilles
+
+ * smtp_session.c: Do not call session_respond() AND session_imsg()
+ from the same handler as they are exclusive. In the quit handler,
+ it will lead to a corrupted session as the F_QUIT is set and
+ session_respond() will kill the session before session_imsg() is
+ done.
+
+ For now, comment session_imsg(IMSG_MFA_QUIT) as we don't have
+ filters enabled anyways. The proper fix will be to have
+ session_imsg() called from the handler THEN upon return in smtp
+ process do the session_respond() call.
+
+ Fixes a segv reported by Roman Kravchuk. While at it, revert my
+ last commit in session_error() which was probably needed because
+ of this bug.
+
+2012-01-26 13:31 eric
+
+ * mta.c: Rewind the message fp before starting the SMTP dialog. It
+ could have been read before during an aborted session on a
+ previous MX.
+
+ reported by Vianney Bouchaud <vianney@poolp.org>
+
+ ok gilles@
+
+2012-01-24 13:20 eric
+
+ * queue_fsqueue.c, smtpctl.c, smtpd.c, smtpd.h: Add a parameter to
+ the queue backend init() call to specify wether the call is
+ issued by smtpd or smtpctl. In the latter case, only perform
+ sanity checks and do not touch directories. A running server no
+ longer lose its "incoming/" directory each time smtpctl is
+ called...
+
+ ok gilles@
+
+2012-01-21 20:50 gilles
+
+ * smtp_session.c: in session_error(), do not call session_destroy()
+ when the F_WRITEONLY session flag is set, set F_QUIT instead.
+
+ fixes a "corrupted session" fatalx() that triggers when a client
+ disconnects after sending the end of message '.' but without
+ waiting for server to acknowledge.
+
+ reported by Roman Kravchuk <kravchuk.kp@gmail.com> a while ago,
+ could not reproduce until today.
+
+2012-01-18 14:41 chl
+
+ * filter.c, filter.h, mfa.c, mfa_session.c, smtp.c, smtp_session.c,
+ smtpd.c, smtpd.h: Add new filters callbacks for: - network events
+ (CONNECT/CLOSE) - commands (QUIT/RSET)
+
+ ok gilles@ eric@
+
+2012-01-15 17:47 chl
+
+ * envelope.c: Add ascii_{load,dump}_time() to properly deal with
+ time_t.
+
+ This fixes build warnings for portable smptd.
+
+ ok eric@ gilles@
+
+2012-01-14 20:35 eric
+
+ * queue_fsqueue.c: When moving a message to the corrupt/ directory,
+ give it an alternate name if there is already an entry with the
+ same name.
+
+ ok gilles@ chl@
+
+2012-01-14 16:13 chl
+
+ * queue_backend.c: Add missing header needed by PRI format string
+
+ ok gilles@ eric@
+
+2012-01-14 13:56 eric
+
+ * queue_fsqueue.c: Change fsqueue_*_path() to report success or
+ failure instead of fatal(). Make sure at init time that all paths
+ can contain envelopes, then these calls will never fail (provided
+ that buffers are always correctly sized, which is true
+ internally).
+
+ ok gilles@ chl@
+
+2012-01-14 11:48 eric
+
+ * queue_fsqueue.c: When creating a new message (in incoming/) make
+ sure that the msgid does not already exist in queue/ to prevent
+ possible collision on commit.
+
+ ok gilles@
+
+2012-01-14 09:37 eric
+
+ * queue_fsqueue.c: Add a fsqueue_message_path() function to build
+ path to message dir and use it where appropriate.
+
+ ok gilles@ chl@
+
+2012-01-13 23:01 eric
+
+ * queue_fsqueue.c: use a simpler way to get to the parent directory
+
+ ok gilles@
+
+2012-01-13 22:58 eric
+
+ * queue.c, queue_backend.c, queue_fsqueue.c, smtpd.h:
+ queue_message_purge() and queue_message_delete() are actually the
+ same thing. Remove queue_message_purge() in favor of
+ queue_message_delete and simplify fsqueue_message_delete()
+ implementation to move the message dir to purge/
+
+ ok gilles@
+
+2012-01-13 15:27 eric
+
+ * smtp.c, smtp_session.c, smtpd.h: remove the status field from
+ struct envelope, move it to the smtp session, and cleanup the
+ DS_* flags.
+
+ ok gilles@ chl@
+
+2012-01-13 15:01 eric
+
+ * mda.c, mta.c, queue.c, runner.c, smtpd.c, smtpd.h: Stop using
+ envelope->status to report delivery outcome to the runner/queue.
+ Instead, replace IMSG_QUEUE_MESSAGE_UPDATE with three messages:
+
+ - IMSG_QUEUE_DELIVERY_OK - IMSG_QUEUE_DELIVERY_TEMPFAIL -
+ IMSG_QUEUE_DELIVERY_PERMFAIL
+
+ 1) it's less confusing as status is also used by smtp 2) it's
+ easier to see what happens just looking at imsg traces 3) it
+ makes the code path generally easier to follow 4) it's safer
+ because it enforces clear semantics and intent, whereas the
+ status field is loosely defined and could carry bogus values.
+
+ ok gilles@ chl@
+
+2012-01-13 11:53 chl
+
+ * delivery.c: kill delivery_backend_lookup() proto as it is already
+ in smtpd.h
+
+ committed on behalf of gilles@
+
+ ok gilles@ chl@
+
+2012-01-13 00:17 gilles
+
+ * ramqueue.c, runner.c: we should never use
+ ramqueue_first_envelope() as a mean to determine the first
+ schedulable envelope otherwise we end up with nsched wrong ...
+
+ heck, let's kill ramqueue_first_envelope() and be done with it ;)
+
+2012-01-12 23:59 eric
+
+ * bounce.c, runner.c, smtpctl.c: The status field in the envelope
+ is confusing. Its only purpose is to notify the runner of what
+ happened with an envelope that has been scheduled. It is not
+ part of the state of the envelope, and it is not even dumped. So
+ it should only be set by mta/mda, checked by runner to decide
+ what to do with the envelope, and ignored everywhere else.
+
+ ok gilles@
+
+2012-01-12 23:40 gilles
+
+ * ramqueue.c, runner.c: the ramqueue filling at startup was busted,
+ it would load envelopes one by one instead of doing it
+ efficiently.
+
+ fix runner_timeout() and ramqueue_load() so that at startup smtpd
+ fills the ramqueue as long as there's no schedulable envelope in
+ it, interrupts filling if there is and resume once it's
+ scheduled.
+
+ bug spotted by Nathanael Rensel, bug fix by me w/ help from eric@
+ tested by eric@ and I
+
+2012-01-12 23:00 gilles
+
+ * ramqueue.c, runner.c: now that we no longer do a stateful
+ iteration on schedule queue, we need to make
+ ramqueue_next_envelope() aware of pauses in mda/mta. while at it
+ kill the pausing of bounces since they are reinjected in smtp and
+ end up paused by the mda/mta cases.
+
+ fixes an infinite loop observed by eric@ when pausing deliveries
+ and trying to interrupt smtpd while it attempts to fetch next
+ envelope :)
+
+ tested by eric@ and I, ok eric@
+
+2012-01-12 21:59 eric
+
+ * delivery_mbox.c, mda.c, smtpd.h: use mbox backend for mbox
+ delivery.
+
+ ok gilles@
+
+2012-01-12 19:06 eric
+
+ * control.c, parser.c, parser.h, smtp.c, smtpctl.c, smtpd.c,
+ smtpd.h: Remove dead code for config reloading for now. It is not
+ functionnal and confusing.
+
+ ok gilles@
+
+2012-01-12 18:00 eric
+
+ * queue_fsqueue.c: Add a fsqueue_envelope_dump_atomic() function
+ that writes an envelope to incoming/envelope.tmp before moving it
+ to its final destination. This allows to make sure that
+ envelopes created directly in the queue (such as bounces) can't
+ let the queue in an inconsistent state if the program stops in
+ the middle of an envelope dump.
+
+ This also allow to simplify qwalk, since we don't put any
+ temporary contents anywhere in "walkable" queue dirs.
+
+ ok gilles@
+
+2012-01-12 16:01 eric
+
+ * envelope.c, smtpd.h, util.c: remove envelope_get_errormsg() and
+ move envelope_set_errormsg() to envelope.c
+
+ ok gilles@
+
+2012-01-12 13:57 eric
+
+ * smtp_session.c: alter line contents before writing it, rather
+ than after...
+
+ ok gilles@
+
+2012-01-12 13:52 eric
+
+ * smtpd.c: use absolute path as fts may chdir() during traversal.
+
+ ok gilles@
+
+2012-01-12 00:25 eric
+
+ * envelope.c: fix flags writing
+
+ ok gilles@
+
+2012-01-11 23:55 gilles
+
+ * ramqueue.c, smtpd.h: remove stateful iteration from ramqueue, if
+ we ever need to reintroduce it we'll do it, but it isn't used and
+ causes potential bugs
+
+ idea by Nathanael Rensel, diff by me, ok eric@
+
+2012-01-11 23:40 gilles
+
+ * ramqueue.c: in ramqueue_schedule(), do not reorder ramqueue
+ envelopes when forcing a reschedule of the entire queue as that
+ can lead to an infinite loop.
+
+ bug spotted and bugfix by Nathanael Rensen, thanks !
+
+ ok eric@
+
+2012-01-11 23:25 gilles
+
+ * queue_fsqueue_ascii.c: queue_fsqueue_ascii.c, you're not welcome
+ anymore
+
+2012-01-11 23:24 gilles
+
+ * envelope.c, queue_fsqueue.c, queue_fsqueue_ascii.c, smtpd.h:
+ implement an envelope_ascii API that's not tied to a specific
+ queue_backend simplify queue_fsqueue
+
+2012-01-11 23:12 eric
+
+ * mta.c: remove bogus call
+
+ ok gilles@
+
+2012-01-11 22:22 eric
+
+ * dns.c: Try to parse hostnames as IP addresses before resolving.
+ This allows relays to be given as IP address in the config file.
+
+ ok gilles@
+
+2012-01-11 21:00 gilles
+
+ * ssl.c: enable back CA support, just don't verify client ...
+
+ tested @ home
+
+2012-01-11 18:46 eric
+
+ * queue.c, queue_fsqueue.c, runner.c, smtpd.c, smtpd.h, util.c:
+ Simplify runner/queue by getting rid of Q_PURGE. Instead, let
+ smtpd periodically clear the purge/ directory. At init time, the
+ fsqueue backend simply moves the existing incoming/ dir in purge/
+ to discard aborted sessions.
+
+ ok gilles@ chl@
+
+2012-01-11 18:28 eric
+
+ * bounce.c: Finally remove the queue_message_update() function
+ which ended up being only called by bounce sessions, so most of
+ the code there was actually useless. The envelope is directly
+ deleted or updated at the relevant place.
+
+ ok gilles@
+
+2012-01-11 18:20 eric
+
+ * dns.c: Improve error reporting. Most errors during hostname
+ lookup are now correctly reported as temporary failures.
+
+ from Nathanael Rensen, tweaks by me.
+
+2012-01-11 18:07 eric
+
+ * smtpd.h: remove dead prototype
+
+ from Nathanael Rensen
+
+ ok gilles@
+
+2012-01-11 18:05 eric
+
+ * queue_fsqueue_ascii.c: fix typo
+
+ from Nathanael Rensen
+
+ ok gilles@
+
+2011-12-27 18:13 eric
+
+ * queue_fsqueue.c, smtpd.h: Q_BOUNCE is not used anymore
+
+ ok gilles@
+
+2011-12-27 15:38 eric
+
+ * bounce.c: Instead of using a separate "bounce" queue, create the
+ bounce envelope directly as an envelope of the bounced message,
+ just like "regular" envelopes.
+
+ ok gilles@
+
+2011-12-23 13:10 eric
+
+ * queue_backend.c, queue_fsqueue.c: On envelope creation, get the
+ message id in a saner way than the current confusing hack.
+
+ ok gilles@
+
+2011-12-22 19:41 eric
+
+ * queue_fsqueue.c: Add fqueue_envelope_path() function to create
+ path to envelopes.
+
+ ok chl@ gilles@
+
+2011-12-21 22:10 chl
+
+ * ssl.c: disable temporarily CA support, it prevents some remote
+ hosts from establishing a ssl session. will be investigated and
+ reenabled soon
+
+ asked and commited on behalf of gilles@
+
+ ok gilles@
+
+2011-12-19 20:57 eric
+
+ * queue_backend.c: fix/improve envelope_validate(): - return an
+ informative error string if the envelope is invalid. - take the
+ envelope id as a parameter and make sure it matches. - do not
+ expect the errorline to start with an SMTP response code, as
+ this is not always the case: a temporary failure with mda would
+ cause the envelope to be marked as corrupted. Instead, just make
+ sure that all string fields are actual strings to prevent
+ overflows later.
+
+ ok gilles@ chl@
+
+2011-12-18 23:55 chl
+
+ * smtpd.h: Sync comments with latest cleanup changes
+
+ ok eric@
+
+2011-12-18 23:53 chl
+
+ * delivery_maildir.c: use #defined error()
+
+ ok eric@
+
+2011-12-18 23:52 chl
+
+ * smtpctl.c: Add missing header needed by PRI format string
+
+ ok eric@
+
+2011-12-18 23:51 chl
+
+ * util.c: remove unused header
+
+ ok eric@
+
+2011-12-18 19:43 eric
+
+ * mda.c, mta.c, util.c: - use envelope_set_errormsg() where
+ possible. - make it use sizeof() rather than a hardcoded limit.
+
+ ok chl@ gilles@
+
+2011-12-16 18:35 eric
+
+ * queue_backend.c: simplify
+
+ ok chl@ gilles@
+
+2011-12-15 20:51 eric
+
+ * asr.c: better size check
+
+2011-12-15 18:23 eric
+
+ * enqueue.c: all leading dots must be duplicated.
+
+ ok gilles@
+
+2011-12-15 00:08 eric
+
+ * bounce.c, queue_shared.c, smtpd.h: finally kill queue_shared.c
+ and move what is left to bounce.c where it belongs.
+
+ ok gilles@
+
+2011-12-14 23:28 eric
+
+ * auth.c, auth_backend.c, auth_bsd.c, auth_pwd.c, smtpd.h: split
+ auth_backend.c for consistency
+
+ ok chl@ gilles@
+
+2011-12-14 19:42 eric
+
+ * queue_shared.c, smtpctl.c, smtpd.h: move show_queue() and related
+ functions from queue_shared.c to smtpctl.c
+
+ ok gilles@
+
+2011-12-14 18:55 eric
+
+ * queue_backend.c, queue_fsqueue.c, smtpd.h: make queue_fsqueue
+ backend consistent with the backend scheme.
+
+ ok gilles@
+
+2011-12-14 18:51 eric
+
+ * ssl.c: add missing prototype
+
+ ok gilles@
+
+2011-12-14 00:55 gilles
+
+ * smtp.c, smtpd.c, smtpd.conf.5, smtpd.h, ssl.c: *finally* make use
+ of certificate authority file if available !
+
+ bits from relayd, ok chl@, ok eric@
+
+2011-12-14 00:00 eric
+
+ * map_backend_db.c, map_backend_stdio.c, map_db.c, map_stdio.c:
+ rename files for consistency.
+
+ ok gilles@
+
+2011-12-13 23:09 eric
+
+ * map.c, map_backend.c: merge map_backend.c into map.c
+
+ ok gilles@
+
+2011-12-13 23:04 eric
+
+ * lka_session.c, smtpd.c, smtpd.h, user.c, user_backend.c,
+ user_pwd.c: split user_backend.c into user.c and user_pwd.c to be
+ consistent with the backend scheme. Also rename USER_GETPWNAM to
+ USER_PWD.
+
+ ok chl@ gilles@
+
+2011-12-13 22:47 gilles
+
+ * smtpd.conf.5: - man page had an example wrong
+
+ spotted and diff by Ptter J. Philipp <php@centroid.eu> a while
+ ago, thanks
+
+2011-12-13 22:44 gilles
+
+ * delivery.c, delivery_filename.c, delivery_maildir.c,
+ delivery_mbox.c, delivery_mda.c, lka_session.c, mda.c, parse.y,
+ queue_fsqueue_ascii.c, smtpd.c, smtpd.h: - introduce delivery
+ backend API (delivery.c) - move each delivery method to it's own
+ delivery backend - simplify smtpd.c accordingly - rename A_EXT ->
+ A_MDA since that's what we really do
+
+ ok eric@
+
+2011-12-12 18:20 eric
+
+ * smtp_session.c, smtpd.c, smtpd.h: add a session_enter_state()
+ function to change the state of an smtp session and allow those
+ state changes to be traced (add traces flags for upcoming changes
+ while there).
+
+ ok chl@ gilles@
+
+2011-12-12 18:17 eric
+
+ * smtp.c: display proc name rather than function name in debug
+ message
+
+ ok gilles@ chl@
+
+2011-12-12 17:45 chl
+
+ * lka_session.c, smtpd.h: remove comments about dead "struct
+ delivery"
+
+ "obvious ok" gilles@
+
+2011-12-11 20:58 eric
+
+ * client.c, smtpd.h, util.c: utility function for parsing and
+ validating SMTP response lines
+
+ ok gilles@
+
+2011-12-11 18:02 eric
+
+ * mta.c, smtpd.h: Make the mta code a bit more straightforward: -
+ fetch the ssl cert earlier on if needed - skip mta_pickup() when
+ handling the incoming fd
+
+ ok gilles@
+
+2011-12-08 18:04 todd
+
+ * parse.y: check for NULL ->ifa_addr, found the hard way by yours
+ truly on his phone ok chl@ & gilles@
+
+2011-12-08 18:00 todd
+
+ * lka_session.c, smtpd.c, smtpd.h, user_backend.c: rename struct
+ user to struct mta_user to avoid namespace conflict elsewhere ok
+ chl@ & gilles@
+
+2011-11-28 23:13 chl
+
+ * filter.c, filter.h, mfa_session.c: use STATUS_* filter codes,
+ instead of -1/0/1 hard coded values
+
+ ok gilles@
+
+2011-11-28 21:29 chl
+
+ * smtpd.h: fix STATE_COUNT count
+
+ ok eric@ gilles@
+
+2011-11-23 14:48 chl
+
+ * smtpctl.c: Fix Segmentation Fault when launching mailq(8)
+
+ Bug reported by Mark Patruck <mark at wrapped.cx>
+
+ ok gilles@ eric@
+
+2011-11-21 19:57 eric
+
+ * queue.c, queue_fsqueue.c, smtpd.h: get rid of the "enqueue/"
+ queue; use "incoming/" instead.
+
+ ok gilles@ chl@
+
+2011-11-16 20:38 eric
+
+ * runner.c, smtpd.h, util.c: remove unused functions
+
+ ok gilles@ chl@
+
+2011-11-16 12:18 eric
+
+ * smtpd.c, smtpd.h: Do not unlink an offline message until it has
+ been correctly enqueued. While there, simplify the
+ offline_enqueue() function by doing all the sanity checks in the
+ forked process, and remove all fatal(): on error, the offline
+ message is left untouched in the directory. Also, get rid of the
+ path_starts_with() check since all paths to offline messages are
+ now constructed internally.
+
+ ok gilles@ chl@
+
+2011-11-16 11:24 chl
+
+ * filter.c, filter.h: fix obvious variable substitution mistake
+ change code type back to int8_t
+
+ ok gilles@
+
+2011-11-16 00:22 gilles
+
+ * filter.c, filter.h, filter_api.c: - change callback prototypes in
+ filter.c to allow stricter checks - introduce STATUS_WAITING,
+ filters will reroute async DNS queries through LKA in a near
+ future - filter_api.c will contain our filter API (empty for now)
+ - Makefile to build libsmtpdfilter (not linked to the build,dev
+ stuff only)
+
+2011-11-16 00:12 gilles
+
+ * queue_fsqueue.c: wooooops defines missing from previous commit
+
+2011-11-16 00:06 gilles
+
+ * queue.c, queue_backend.c, queue_fsqueue.c, queue_shared.c,
+ ramqueue.c, runner.c, smtpctl.c, smtpd.h: Qwalk, our API to
+ linearly walk over the persistent queue, did not take the
+ queue_backend into account and assumed a filesystem with a
+ specific layout.
+
+ This commit does plenty of things:
+
+ - make qwalk an abstraction in the queue_backend API, and impose
+ queue drivers to implement qwalk_open(), qwalk() and
+ qwalk_close();
+
+ - move previous qwalk_open(), qwalk() and qwalk_close() to the
+ fsqueue driver since they were fsqueue specific ...
+
+ - make qwalk API work with msgid/evpid instead of pathnames since
+ we're going to use the queue_backend API to load envelopes by
+ evpid anyway;
+
+ - makes smtpd use *solely* the queue_backend API when
+ manipulating the queue. pathnames were removed from smtpd.h and
+ moved into the fsqueue which means we can now store a queue
+ anywhere ... as long as we write the ten functions or so
+ required for a queue driver ;-)
+
+ ok eric@, ok chl@
+
+2011-11-14 20:23 chl
+
+ * control.c, lka.c, mda.c, mfa.c, mta.c, queue.c, runner.c, smtp.c,
+ smtpd.c, smtpd.h: when receiving an unexpected imsg, print its
+ name.
+
+ with help and ideas from eric@
+
+ ok eric@ gilles@
+
+2011-11-14 17:54 eric
+
+ * enqueue.c: make sure that the offline directory has the right
+ owner/perms before enqueueing offline mail.
+
+ ok gilles@
+
+2011-11-14 12:53 eric
+
+ * queue_fsqueue.c, smtpd.c, smtpd.h, util.c: The spool and offline
+ directories are backend-independent, so they must be created
+ early by smtpd, rather than in fsqueue.
+
+ ok gilles@ chl@
+
+2011-11-10 18:37 chl
+
+ * mfa.c: Use STDIN_FILENO instead of magic constant 0
+
+ ok gilles@
+
+2011-11-07 12:14 eric
+
+ * queue.c, ramqueue.c, runner.c, smtpd.c, smtpd.h: Let the smtpd
+ process handle the enqueueing of offline messages at startup,
+ rather than playing tricks with the runner. This will allow
+ further simplifications and improvements in the runner/queue.
+
+ ok gilles@
+
+2011-11-06 17:57 eric
+
+ * queue_fsqueue.c: No need to save/restore the batch_id since the
+ envelope is not dumped as a structure anymore.
+
+ ok chl@ gilles@
+
+2011-11-06 17:55 eric
+
+ * queue_fsqueue_ascii.c: Do not dump the envelope status. It's
+ useless and not reloaded anyway.
+
+ ok chl@ gilles@
+
+2011-11-03 15:34 chl
+
+ * client.c: since smtpctl doesn't need to be build along with
+ client.c, client.c doesn't need to be build with -DCLIENT_NO_SSL
+ anymore, so get rid of #ifdef CLIENT_NO_SSL
+
+ ok eric@
+
+2011-11-02 13:01 eric
+
+ * enqueue.c: simpler implementation of smtpctl local enqueuer that
+ does not need libevent.
+
+ ok gilles@
+
+2011-10-27 16:32 chl
+
+ * bounce.c, mda.c, mta.c, parse.y, queue_fsqueue.c,
+ queue_fsqueue_ascii.c, queue_shared.c, ramqueue.c, runner.c,
+ util.c: Use PRI{x,d}64 in format strings instead of %llx, %lld or
+ %qd to print {u_,}int64_t or time_t
+
+ While there, cast some time_t to int64_t
+
+ These will fix build warnings for portable smptd
+
+ ok gilles@ eric@
+
+2011-10-27 06:23 guenther
+
+ * ssl.c: Don't offer or negotiate SSLv2 and, since we don't do SSL
+ session caching, don't try to negotiate an RFC 4507-style session
+ ticket, as it would be useless and some (broken and
+ non-compliant) servers choke on TLS extension negotiation.
+
+ ok gilles@
+
+2011-10-26 23:41 jmc
+
+ * smtpctl.8: retain alphabetical order;
+
+2011-10-26 22:47 gilles
+
+ * control.c, parser.c, queue.c, runner.c, smtpctl.8, smtpctl.c,
+ smtpd.c, smtpd.h: - fix smtpctl pause/resume so the ramqueue
+ scheduling is done correctly - rename IMSG and smtpctl
+ pause/resume parameters - update man page
+
+ tested by me, ok chl@, eric@
+
+2011-10-25 12:25 eric
+
+ * lka_session.c: rewrite the sender user/domain as specified in the
+ manpage when matching a "relay... as" rule.
+
+ mikeb can now send mails.
+
+ ok gilles@ mikeb@
+
+2011-10-23 20:37 jmc
+
+ * smtpctl.8: retain alphabetical order;
+
+2011-10-23 19:12 gilles
+
+ * parser.c, parser.h, ramqueue.c, smtpctl.8, smtpctl.c: - smtpctl
+ schedule no longer works, instead, use 'smtpctl schedule-id <id>'
+ - introduce 'smtpctl schedule-all'
+
+ ok eric@
+
+2011-10-23 19:09 eric
+
+ * mta.c: plug leak
+
+ spotted by chl@
+
+ ok chl@
+
+2011-10-23 17:36 eric
+
+ * lka.c, mta.c, parse.y, queue_fsqueue_ascii.c, ramqueue.c,
+ smtpd.h: a few important fixes:
+
+ - use correct endianness when dumping/loading port - use the
+ right flag set when dumping/loading flags - keep and use the
+ authmap name when needed, rather than an id that might change
+ when smtpd is restarted - dump/load the authmap name with the
+ envelope - remove the rule struct from rq_batch as only the relay
+ info is useful
+
+ ok gilles@
+
+2011-10-23 15:08 eric
+
+ * queue_fsqueue_ascii.c, smtpd.h: relay_as is not used anuwhere
+
+ ok gilles@
+
+2011-10-23 15:03 gilles
+
+ * queue_backend.c, queue_fsqueue.c, queue_fsqueue_ascii.c,
+ ramqueue.c, smtpd.h: introduce Q_CORRUPT and queue_backend
+ operation to move a message from schedule queue to corrupt queue
+ upon envelope loading failure.
+
+ tested by me, ok eric@
+
+2011-10-23 12:54 chl
+
+ * print.c: add missing format string
+
+ ok eric@ gilles@
+
+2011-10-23 12:44 chl
+
+ * ssl.c: add a missing DH_free() after
+ ssl_set_ephemeral_key_exchange().
+
+ tested by gilles@
+
+ ok gilles@ eric@
+
+2011-10-23 11:30 gilles
+
+ * bounce.c, lka.c, lka_session.c, mda.c, mfa.c, mfa_session.c,
+ mta.c, queue.c, queue_backend.c, queue_fsqueue.c,
+ queue_fsqueue_ascii.c, queue_shared.c, ramqueue.c, ruleset.c,
+ runner.c, smtp.c, smtp_session.c, smtpctl.c, smtpd.h, util.c:
+ fsqueue no longer stores envelopes by dumping the structure,
+ instead use a couple of load/dump functions to convert to and
+ from a human readable fmt. while at it kill struct delivery and
+ merge back its fields to the envelope.
+
+ this basically means we shouldn't require users to flush their
+ queues every time we make a change to struct envelope.
+
+ work is not done, but we're at a better state than the binary
+ fsqueue so we'll improve it in-tree.
+
+ has been running on my own box for the last 12 hours or so ok
+ eric@, chl@
+
+2011-10-22 20:03 eric
+
+ * lka_session.c: correctly set relay when expanding envelopes
+
+ ok gilles@
+
+2011-10-22 08:42 jmc
+
+ * smtpd.8, smtpd.c: tweak previous;
+
+2011-10-22 02:16 eric
+
+ * log.c, log.h, smtpd.8, smtpd.c, smtpd.h: Add a log_trace() call
+ to toggle logging of specific debugging info in verbose mode, and
+ an associated -T command line option. Use it for the imsg
+ traces.
+
+ Requested by gilles@ who doesn't like verbose to be too verbose.
+
+ ok gilles@ chl@
+
+2011-10-13 12:54 eric
+
+ * ssl.c: Drop a reference to the client SSL_CTX after SSL_new(), so
+ that it is correctly freed by SSL_free() at the end of the
+ session.
+
+ Plug a leak in the mta.
+
+ ok! gilles@
+
+2011-10-11 19:57 gilles
+
+ * aliases.c: fix parsing of :include: aliases
+
+2011-10-10 23:06 gilles
+
+ * makemap.8: document that virtual maps require a domain key
+
+2011-10-09 20:39 eric
+
+ * control.c, lka.c, mda.c, mfa.c, mta.c, queue.c, runner.c, smtp.c,
+ smtpd.c, smtpd.h: show messages sent between processes in debug
+ mode
+
+ ok gilles@ chl@
+
+2011-10-03 21:20 gilles
+
+ * smtp_session.c: - fix a segv caused by a deep recursion
+ introduced with a recent quick-fix and triggering if clients
+ sent a large number of DATA lines in one write
+
+2011-10-03 19:57 gilles
+
+ * smtpd.conf.5: clarify that network sources are to be specified in
+ CIDR notation
+
+ by David Walker, ok jmc@
+
+2011-09-28 20:19 gilles
+
+ * smtp_session.c: removing annoying debug log
+
+2011-09-27 20:53 chl
+
+ * mfa.c: check closefrom() return value use STDERR_FILENO instead
+ of hard coded value
+
+ ok gilles@
+
+2011-09-19 15:10 chl
+
+ * smtpd.h: Quick fix to avoid fatal() when we receive a line which
+ have a length of exactly 1024.
+
+ Better fix comming soon.
+
+ Committing on behalf of gilles@
+
+2011-09-18 23:37 gilles
+
+ * ramqueue.c, runner.c, smtpd.h: a single ramqueue message may be
+ shared by many ramqueue envelopes to be delivered to many
+ ramqueue hosts, therefore storing the rq_host pointer in the
+ rq_msg envelope is wrong and causes baaaaad behavior.
+
+ this commit fixes reliability issues in runner process,
+ experienced and reported by many
+
+2011-09-12 22:47 gilles
+
+ * filter.h, smtp_session.c, smtpd.h: - introduce filtermask in
+ struct smtpd - do not forward lines to mfa when FILTER_DATALINE
+ is not set in filtermask
+
+ prevents smtpd from handling mails slowly while I'm hacking on
+ filters support
+
+2011-09-11 23:45 chl
+
+ * log.c: remove unused header
+
+ ok gilles@
+
+2011-09-01 22:17 gilles
+
+ * smtp.c: move a log_debug() call to a less annoying spot so that
+ it does not get called for each single line of DATA exchanged
+ between smtp and mfa
+
+2011-09-01 21:56 eric
+
+ * bounce.c, control.c, dns.c, queue.c, ramqueue.c, runner.c,
+ smtp.c, smtp_session.c, smtpctl.c, smtpd.c, smtpd.h, ssl.c,
+ stats.c: Introduce a small set of functions to manage stat
+ counters in a simpler and hopefully saner way.
+
+ ok gilles@ chl@
+
+2011-09-01 18:23 chl
+
+ * parse.y: add missing header needed by bsearch()
+
+ ok gilles@
+
+2011-09-01 11:42 chl
+
+ * mfa_session.c, parse.y, smtp_session.c: - if no filter is setup,
+ do not overwrite the data line with filtmsg buffer - remove
+ annoying debug lines - disable back filters at smtpd.conf level
+
+ committing on behalf of gilles@
+
+2011-08-31 20:56 gilles
+
+ * filter.c, filter.h, mfa.c, mfa_session.c, parse.y, smtp.c,
+ smtp_session.c, smtpd.h: add support for per-line DATA callbacks,
+ this allows filters to take their decisions *while* the message
+ is being received by the client.
+
+2011-08-30 19:06 chl
+
+ * ramqueue.c, runner.c: Call free() into
+ ramqueue_remove_{batch,host,message,envelope}() instead of just
+ after the function call.
+
+ While there, also include stats counters into their respective
+ function.
+
+ ok gilles@
+
+2011-08-30 13:19 chl
+
+ * map_backend.c, map_backend_stdio.c: remove unused header
+
+ ok gilles@
+
+2011-08-30 09:06 chl
+
+ * smtpctl.c: fix format string
+
+ ok gilles@
+
+2011-08-29 23:43 chl
+
+ * enqueue.c, mda.c, mta.c, queue_shared.c, runner.c, smtpctl.c,
+ smtpd.c: cast all printed time_t to long long int, and change
+ format string accordingly.
+
+ ok gilles@
+
+2011-08-29 22:34 chl
+
+ * map_parser.c: remove unused file
+
+ ok gilles@
+
+2011-08-29 20:49 chl
+
+ * enqueue.c, mda.c, mta.c, queue.c, runner.c, smtp.c: add missing
+ header needed by signal()
+
+ ok gilles@
+
+2011-08-29 00:20 chl
+
+ * queue_shared.c: Clear bounce envelope structure, to avoid wrong
+ use when bounce_record_message() returns 0.
+
+ Initial report from me, tweak from gilles@
+
+ ok gilles@
+
+2011-08-28 02:03 gilles
+
+ * mfa_session.c: fix pasto in strlcpy() truncation test
+
+2011-08-28 00:37 gilles
+
+ * smtpd.h: typo
+
+2011-08-28 00:32 gilles
+
+ * filter.c, filter.h, lka_session.c, mfa.c, mfa_session.c, parse.y,
+ smtp.c, smtp_session.c, smtpd.c, smtpd.h, smtpfilter.c: initial
+ support for a session-time filtering API
+
+ currently only HELO/EHLO, MAIL, RCPT are supported, however ... I
+ have voluntarily disabled filters at smtpd.conf level so people
+ don't play with it until the API has stabilized a bit
+
+ discussed with several people in private, no one opposed the
+ feature
+
+2011-08-26 16:39 chl
+
+ * enqueue.c, mda.c, mta.c, queue_fsqueue.c, ramqueue.c, runner.c,
+ smtpctl.c, smtpd.c: add missing header needed by time()
+
+ ok gilles@
+
+2011-08-17 22:54 gilles
+
+ * ramqueue.c, runner.c: - plug a memory leak in
+ runner_remove_envelope() - cosmetic change
+
+2011-08-17 22:35 gilles
+
+ * ramqueue.c, runner.c, smtpd.h: move ramqueue_host pointer from
+ ramqueue_envelope to ramqueue_message. this allows us to save
+ one pointer from each envelope stored in ram while still allowing
+ O(1) host lookups by ramqueue_envelope.
+
+2011-08-17 22:04 gilles
+
+ * ramqueue.c, runner.c, smtpctl.8, smtpd.h: - teach smtpctl remove
+ about the new ramqueue structure - bonus #1: O(log n) removal of
+ envelopes - bonus #2: removing all envelopes that have the same
+ msgid works again
+
+2011-08-17 21:36 gilles
+
+ * ramqueue.c, smtpd.h: - introduce
+ ramqueue_lookup_{host,message,envelope} to perform lookups in
+ the new ramqueue structure - introduce ramqueue_reschedule() and
+ ramqueue_reschedule_envelope() which to reschedule a message or
+ a specific envelope.
+
+ O(n) -> O(log n) \o/
+
+2011-08-16 21:12 gilles
+
+ * parser.c, parser.h, smtpctl.c: smtpctl show sizes, displays the
+ size of queue-related structures, useful for developers to see
+ the impact of structure changes on memory and disk usage, and
+ useful for users to better understand 'smtpctl show stats'
+
+2011-08-16 21:02 gilles
+
+ * ramqueue.c, runner.c, smtpctl.c, smtpd.h: add a host-tree and an
+ envelope-tree in the ramqueue, they will be used to improve
+ scheduling and general ramqueue operations. unused yet
+
+2011-07-22 08:33 jmc
+
+ * smtpctl.8: tweak previous;
+
+2011-07-22 01:29 gilles
+
+ * control.c, parser.c, parser.h, ramqueue.c, runner.c, smtpctl.8,
+ smtpctl.c, smtpd.h: - update smtpctl.8 to reflect reality - bring
+ back 'smtpctl schedule' and 'smtpctl remove' to life
+
+ Things you should know:
+
+ The ramqueue data structure is not finished yet and lacks an
+ envelope tree for evpid lookups. I wanted to wait until I'm done
+ but too many people are affected by not being able to reschedule
+ envelopes, this is a quick fix.
+
+ So right now there's an O(rrible) complexity as both commands
+ will perform a (possibly aborted) queue scan leading to O(n). I
+ will make that O(log n) soon.
+
+ Also, smtpctl remove no longer supports removing an entire
+ message, I will fix that very soon too.
+
+2011-07-20 12:22 eric
+
+ * dns.c, mta.c, smtpd.h: Fix reporting of permanent/temporary
+ failures for MX lookups. Simplify code a bit while there.
+
+ ok gilles@
+
+2011-07-19 15:15 eric
+
+ * mta.c: Re-add the test which is needed in the case where the
+ session fails early (in MX or SECRET) and the data file is not
+ yet opened.
+
+ ok gilles@
+
+2011-07-19 15:07 eric
+
+ * ramqueue.c: fix retry delay calculation
+
+ ok gilles@
+
+2011-07-13 18:14 eric
+
+ * asr.c: print more information in request state traces
+
+ ok gilles@
+
+2011-07-13 17:08 eric
+
+ * asr.c, pack.c, print.c: fix indentation in switch
+
+ ok gilles@
+
+2011-07-13 16:52 eric
+
+ * asr.h: do not make these values look like they are flags.
+
+ ok gilles@
+
+2011-07-06 22:56 gilles
+
+ * client.c, mta.c: fix that fscking "fgetln(): bad file descriptor"
+ bug experienced by many.
+
+ long story short: datafp is reused by the possibly multiple
+ client sessions of a MTA session. fclosing it in client_close()
+ will cause the file pointer to be invalidated as soon as we fail
+ the primary MX and attempt the second.
+
+ bug introduced while trying to fix a leak causing a crash for a
+ user, now smtpd will unconditionnally fclose() in MTA_DONE and if
+ a leak still exists then we should track why the mta session
+ doesnt reach MTA_DONE.
+
+2011-07-04 21:44 gilles
+
+ * lka_session.c: %u in format string is rcpt.user not rcpt.domain
+
+ From Tim van der Molen <tbvdm@xs4all.nl>
+
+2011-07-03 19:48 nicm
+
+ * dns.c: imsg.h requires sys/queue.h and sys/uio.h.
+
+ ok eric
+
+2011-06-23 22:35 sthen
+
+ * smtpd.conf.5: Use a common text explaining how the various
+ configuration parsers using the standard OpenBSD-style parse.y
+ handle continuing lines with backslashes, paying particular
+ attention to how comments are handled (which can cause nasty
+ side-effects if you're not expecting it).
+
+ Most wording from jmc@, with suggestions from fgsch@, marc@,
+ Richard Toohey, patrick keshishian and Florian Obser, ok jmc@.
+
+2011-06-10 13:30 jmc
+
+ * smtpd.conf.5: tweak previous;
+
+2011-06-09 19:41 gilles
+
+ * lka_session.c, parse.y, smtpd.conf.5, smtpd.h: 'relay as' and
+ 'relay via as' rules allow smtpd to rewrite the user part, the
+ domain part or the entire address of the sender at the SMTP
+ sesssion level. this is not masquerade but allows smtpd to
+ communicate with hosts that do a check of SMTP sender fqdn.
+
+ sent to tech@, a couple 'no regression' feedbacks
+
+2011-06-09 05:53 deraadt
+
+ * enqueue.c: spacing
+
+2011-05-23 00:03 jmc
+
+ * smtpd.conf.5: tweak previous;
+
+2011-05-22 23:03 gilles
+
+ * parse.y, smtpd.conf.5: teach smtpd how to listen on an interface
+ group so that we can do: listen on egress listen on
+ wlan
+
+ idea unvoluntarily suggested by Mikolaj Kucharski a few weeks
+ ago, unslacked after theo suggested it again.
+
+2011-05-22 15:38 gilles
+
+ * smtpd.conf.5: fix examples so they stay do not use external
+ utilities and do not refer to external domains
+
+ prompted by deraadt@
+
+2011-05-21 21:57 gilles
+
+ * smtpd.h: remove unused commented structure
+
+2011-05-21 20:43 gilles
+
+ * map.c, map_backend.c, map_backend_db.c, map_backend_stdio.c,
+ smtpd.h: until now the map_backend API was not really useful for
+ backends that are not key/val stores. refactored a bit so that
+ smtpd can really take advantage of backends. preliminary work for
+ ldap support ;-)
+
+ no functionnal change
+
+2011-05-21 20:39 gilles
+
+ * mta.c, ruleset.c: remove annoying log_debug()
+
+2011-05-21 20:11 gilles
+
+ * lka_session.c: these log_debug()s should not have been committed
+ :)
+
+2011-05-21 20:04 gilles
+
+ * lka_session.c: when a user add himself to his own ~/.forward, the
+ delivery method was not reset by ruleset matching and since it
+ was cleared upon entering lka_session_resolve_node(), it would
+ trigger a fatal().
+
+2011-05-21 19:01 gilles
+
+ * ssl.c: make the "no DH parameters" warning a log_info()
+
+2011-05-21 18:58 gilles
+
+ * parse.y: "for all" does not necessary apply to relay rules, so do
+ not forget to look for an alias map.
+
+ fixes "accept from all for all alias myaliases deliver to mbox"
+ and makes thib "super happy"
+
+ ok thib@
+
+2011-05-17 20:54 gilles
+
+ * lka_session.c, smtpd.c, smtpd.h, user_backend.c, util.c:
+ introduce new user_backend API for smtpd to lookup the users it
+ wants to deliver mail to. the only backend supported for now is
+ USER_GETPWNAM and it is not yet possible to switch to an
+ alternate backend.
+
+ yes this means that we're very close from smtpd being able to
+ handle fully virtual accounts for both incoming and outgoing
+ messages.
+
+2011-05-17 18:42 gilles
+
+ * auth_backend.c, authenticate.c, smtpd.c, smtpd.h: smtpd now uses
+ an auth_backend API to authenticate users that are allowed to
+ send mail so they do not necessarily need a local system account.
+
+ two backends are provided by default, bsd_auth(3) and
+ getpwnam(3), however smtpd will only select bsd_auth(3) for the
+ moment and not provide a way to chose any other backend (that's
+ on purpose ;p).
+
+ bye bye authenticate() !
+
+2011-05-17 18:32 gilles
+
+ * ssl.c: somehow a previous sync with relayd missed one line... if
+ a ssl_connect() call needs to retry because of SSL_WANT_READ or
+ SSL_WANT_WRITE, set the proper event flag instead of keeping the
+ default one which is both read and write.
+
+2011-05-16 23:52 gilles
+
+ * lka_session.c: remove useless assignation
+
+2011-05-16 23:42 gilles
+
+ * lka_session.c: when a C_VDOM recipient expands to a local user,
+ envelope expansion will reprocess the envelope. since the
+ original condition we matched is still C_VDOM, it triggers an
+ expansion loop causing recipient to be rejected.
+
+ this *should* fix the issue experienced by armani@, it does on my
+ laptop.
+
+2011-05-16 23:27 jasper
+
+ * makemap.c: plug leak in make_aliases()
+
+ with/ok gilles@
+
+2011-05-16 23:05 gilles
+
+ * aliases.c, bounce.c, forward.c, lka.c, lka_session.c, mda.c,
+ mfa.c, mta.c, queue.c, queue_backend.c, queue_fsqueue.c,
+ queue_shared.c, ramqueue.c, ruleset.c, runner.c, smtp.c,
+ smtp_session.c, smtpd.c, smtpd.h, util.c: murder struct path and
+ make sure smtpd uses simpler structures that do not bring a
+ shitload of unnecessary information everywhere. this required
+ many parts of smtpd to be refactored and more specifically
+ envelope expansion.
+
+ in the process lots of code got simplified, and the envelope
+ expansion code has been isolated to lka_session.c with some
+ longstanding bugs fixed.
+
+ Diff has been tested by many with no major regression reported.
+ armani@ spotted a bug in a setup where a domain is listed a both
+ primary and virtual, I will fix that in-tree as it's becoming
+ painful to maintain this diff out.
+
+2011-05-16 12:57 blambert
+
+ * sockaddr.c: Print IPv6 addresses in hex, not decimal; from Tim
+ van der Molen
+
+ committing on behalf of gilles@
+
+2011-05-14 13:08 gilles
+
+ * ssl.c: more clang warnings fixed
+
+2011-05-14 13:06 gilles
+
+ * client.c: char -> u_char
+
+2011-05-14 13:04 gilles
+
+ * util.c: int * -> socklen_t * in getsockopt() call
+
+2011-05-10 19:04 gilles
+
+ * queue_shared.c: fix an off-by-one that made smtpd skip an
+ "invalid" bucket that was actually valid.
+
+ bugfix tested by todd@
+
+2011-05-09 11:36 eric
+
+ * makemap.c: fix segfault in newaliases after global env move.
+
+ spotted by Christopher Zimmermann ok gilles@
+
+2011-05-07 15:16 eric
+
+ * asr.c: there is already a function to set the portno.
+
+ ok gilles@
+
+2011-05-06 21:21 eric
+
+ * dns.c, smtpd.h: move dns session specific structs and prototypes
+ out of smtpd.h.
+
+ ok gilles@
+
+2011-05-04 22:45 eric
+
+ * smtpd.c: When enqueueing offline mail, use a wait list to keep
+ the number of forked processes below a reasonnable limit. This
+ prevents smtpd from fork-bombing on startup when there are lots
+ of mails in the offline queue.
+
+ ok todd@ gilles@
+
+2011-05-01 14:57 eric
+
+ * aliases.c, bounce.c, config.c, control.c, dns.c, lka.c,
+ makemap.c, map.c, mda.c, mfa.c, mta.c, parse.y, queue.c,
+ queue_backend.c, queue_fsqueue.c, queue_shared.c, ramqueue.c,
+ ruleset.c, runner.c, smtp.c, smtp_session.c, smtpctl.c, smtpd.c,
+ smtpd.h, ssl.c: the smtpd env is meant to be global, so do not
+ pass it all around.
+
+ discussed with and ok gilles@
+
+2011-04-17 15:36 gilles
+
+ * aliases.c, config.c, dns.c, enqueue.c, lka.c, makemap.c,
+ map_backend.c, map_parser.c, mda.c, mfa.c, mta.c, queue.c,
+ ramqueue.c, ruleset.c, runner.c, smtp.c, smtp_session.c,
+ smtpctl.c, smtpd.c, smtpd.h, util.c: cleanups, cosmethic changes,
+ functions that should be static are now static no functionnal
+ change
+
+2011-04-17 14:46 gilles
+
+ * smtpd.h: remove unused IMSG_ defines
+
+2011-04-17 13:39 gilles
+
+ * bounce.c, lka.c, mda.c, mfa.c, mta.c, queue.c, queue_backend.c,
+ queue_fsqueue.c, queue_shared.c, ramqueue.c, runner.c, smtp.c,
+ smtpd.h, util.c: a structure describing an envelope should be
+ called struct envelope, not struct message ...
+
+2011-04-17 13:16 gilles
+
+ * queue.c, smtpd.h: no functionnal change, getting rid of
+ deprecated prototypes
+
+2011-04-16 11:13 gilles
+
+ * queue_fsqueue.c: I accidentally changed group ownership of
+ fsqueue to _smtpd, it used to be owned by wheel. This commit
+ reverts to original behavior
+
+2011-04-15 21:03 gilles
+
+ * runner.c, smtpd.h: whenever an envelope is reinserted into the
+ ramqueue after a trip to mda or mta, call runner_reset_events()
+ so runner starts reprocessing ramqueue
+
+2011-04-15 19:30 gilles
+
+ * queue_shared.c: teach walk_queue() about the new disk-queue
+ layout
+
+2011-04-15 19:21 gilles
+
+ * util.c: valid_message_id() and valid_message_uid() are no longer
+ needed
+
+2011-04-15 19:01 gilles
+
+ * bounce.c, mda.c, mfa.c, mta.c, queue.c, queue_backend.c,
+ queue_fsqueue.c, queue_shared.c, ramqueue.c, runner.c, smtp.c,
+ smtp_session.c, smtpd.h, util.c: kill message_id and message_uid
+
+ smtpd now has an evpid associated to each delivery message, the
+ evpid is an u_int64_t where the upper 32 bits are the msgid, and
+ the 32 bits are the envelope unique identifier for that message.
+ this results in lots of space saved in both disk-based and
+ ram-based queues, but also simplifies a lot of code.
+
+ change has been stressed on my desktop, and has ran on my MX for
+ the entire afternoon without a regression.
+
+2011-04-15 13:39 gilles
+
+ * runner.c: temporarily add fsqueue_hash() prototype until runner
+ is fully converted to queue_backend API
+
+2011-04-15 01:29 gilles
+
+ * queue_fsqueue.c, queue_shared.c, runner.c: bye bye queue_hash()
+ you can now rest in peace.
+
+2011-04-15 01:26 gilles
+
+ * queue.c, queue_backend.c, queue_fsqueue.c, queue_shared.c,
+ smtpd.h: - implement missing operations for fsqueue:
+ fsqueue_envelope_create(), fsqueue_message_purge() - kill
+ deprecated functions in queue_shared.c
+
+ At this point fsqueue backend is almost complete, all that is
+ left to do is to move the qwalk() API inside the queue_backend
+ API, then make sure smtpd is no longer calling anything queue
+ related directly.
+
+2011-04-15 00:46 gilles
+
+ * smtpd.c, smtpd.h: no functionnal change
+
+2011-04-15 00:36 gilles
+
+ * queue.c, queue_fsqueue.c, queue_shared.c, ramqueue.c, runner.c,
+ smtpd.h: - implement fsqueue_message_create() and
+ fsqueue_message_commit() - change a few prototypes to allow
+ bounce messages to use the queue_backend API until it gets
+ merged in - kill functions of the queue API that have been
+ deprecated
+
+2011-04-15 00:00 gilles
+
+ * queue_shared.c: remove annoying log_debug()
+
+2011-04-14 23:53 gilles
+
+ * bounce.c, queue.c, queue_fsqueue.c, queue_shared.c, runner.c:
+ fsqueue now provides fsqueue_message_fd_r() and
+ fsqueue_message_fd_rw() to obtain a read{-only,/write} descriptor
+ to the message file.
+
+ make sure smtpd uses the new API everywhere it needs a fd, and
+ kill the many functions that were used until now.
+
+2011-04-14 23:14 gilles
+
+ * queue_fsqueue.c: fsqueue_message_delete() should use
+ fsqueue_hash() not queue_hash() as i'm going to kill it with lots
+ of violence soon.
+
+2011-04-14 22:11 gilles
+
+ * bounce.c, queue_backend.c, queue_fsqueue.c, queue_shared.c,
+ ramqueue.c, runner.c, smtpd.c, smtpd.h: fsqueue queue backend
+ will implement a filesystem queue: - fsqueue->setup() performs
+ the queue initialization; - fsqueue->message() controls messages;
+ - fsqueue->envelope() controls envelopes;
+
+ This commit brings the following to fsbackend: fsqueue_setup(),
+ fsqueue_message_delete(), fsqueue_envelope_load(),
+ fsqueue_envelope_update(), fsqueue_envelope_delete().
+
+ It also makes smtpd use the queue_backend API for these
+ operations.
+
+2011-04-14 19:06 gilles
+
+ * queue_backend.c, queue_fsqueue.c, smtpd.c, smtpd.h: smtpd makes
+ too many assumptions about the structure and layout of its
+ disk-based queue, it makes it near impossible to make changes to
+ it without editing twenty files... how am i going to implement
+ mongodb support ? :-)
+
+ bring a new queue_backend API which hides the details of the
+ disk-based queue to smtpd. it is not "plugged in" yet and I'm
+ filling the holes.
+
+2011-04-13 22:53 gilles
+
+ * control.c, mta.c, parser.c, parser.h, queue.c, queue_shared.c,
+ ramqueue.c, runner.c, smtpctl.c, smtpd.c, smtpd.h: following an
+ idea from jacekm@, smtpd now uses a ram-queue instead of doing a
+ continuous walk on the disk-queue. the implementation differs
+ from what jacekm@ commited (and I backed out) a while ago in that
+ it uses a queue and a host tree required for upcoming features.
+
+ code will be improved in tree, it requires changes to be done in
+ queue and bounce API, I just wanted to commit a working version
+ first ...
+
+ tested by todd@ and I
+
+2011-04-02 18:40 eric
+
+ * dns.c, smtpctl.c, smtpd.h: add stat counters for the lookup agent
+
+ ok gilles@
+
+2011-04-02 17:59 eric
+
+ * dname.c: saner and hopefully correct implementation for
+ dname_from_fqdn(). especially, make sure to write the ending
+ '\0'.
+
+ ok gilles@
+
+2011-03-31 12:40 eric
+
+ * dns.c: cleanup and simplification following the asr update.
+
+ - use a specific dispatch function for each type of query - make
+ the host handler work on a list of hosts by default (single host
+ queries are just a particular case) and use that to resolve the
+ MX list - various other code cleanup - remove unused headers -
+ remove orphaned prototypes - update copyright
+
+ ok gilles@
+
+2011-03-29 22:43 eric
+
+ * dns.c, smtpd.h, util.c: remove unused code now that reverse
+ lookups are done through asr.
+
+ ok gilles@
+
+2011-03-29 10:14 eric
+
+ * dns.c: make use the cname query interface from asr for reverse
+ lookups
+
+ ok gilles@
+
+2011-03-27 20:08 eric
+
+ * dns.c: add a function to factorize resetting of dnssession
+ events.
+
+ ok gilles@
+
+2011-03-27 19:39 eric
+
+ * asr.c, asr.h, dname.c, dnsdefs.h, dnsutil.h, pack.c, print.c,
+ sockaddr.c: add missing CVS markers and update copyright year.
+
+ ok gilles@
+
+2011-03-26 22:41 eric
+
+ * smtpd.h: missing file in previous commit
+
+ ok gilles@
+
+2011-03-26 22:40 eric
+
+ * dns.c: Fix the MX lookup process:
+
+ - the MX records were not always properly inserted into the
+ sorted array, which led to some MX being silently dropped. -
+ if an MX address could not be resolved, mail delivery would fail,
+ even though other valid MX exist for that domain. Now only
+ report the failure if no server address can be found at all.
+
+ grrrreeat gilles@
+
+2011-03-26 18:43 gilles
+
+ * mta.c: check that we actually have a stdio stream opened for the
+ message before trying to close it in a mta session. in case of
+ DNS errors; this pointer will remain NULL and cause a segv in
+ MTA_DONE state.
+
+2011-03-26 15:38 eric
+
+ * asr.c, asr.h, dns.c: Tweak the asr API to make things a bit
+ smoother on the user side. Then asr_run() call now returns
+ ASR_COND when a condition on a FD is expected. The exact
+ condition (readable or writeable) is specified in the asr_result
+ structure, along with the fd and timeout.
+
+ ok gilles@
+
+2011-03-26 12:04 eric
+
+ * asr.c, asr.h, dname.c, dnsutil.h, sockaddr.c: Merge a reverse
+ lookup query implementation into asr. Not used by the rest of
+ smtpd for now.
+
+ ok gilles@
+
+2011-03-26 11:59 gilles
+
+ * bounce.c, client.c, client.h, enqueue.c, mta.c, smtpd.h: have the
+ client API receive a stdio stream rather than a fd to the message
+ fd. this shifts responsibility for the fclose to the caller,
+ prevents a memory leak and makes everyone happy.
+
+ diff by Jared Yanovich, thanks !
+
+2011-03-26 11:54 eric
+
+ * dns.c, smtpd.h: use an index for iterating into the mx list.
+
+ ok gilles@
+
+2011-03-23 21:58 eric
+
+ * asr.c: The asr structure must always be freed in asr_done(). This
+ is a left-over from a former implementation where asr_ctx didn't
+ exist and struct asr was refcounted.
+
+ spotted by Jared Yanovich.
+
+ ok gilles@
+
+2011-03-23 21:38 eric
+
+ * dns.c: Simplify resolver initialization. This is done only once
+ since resolv.conf reloading is handled automatically by asr.
+
+ ok gilles@
+
+2011-03-23 21:27 eric
+
+ * asr.c: remove unused states in enum
+
+ ok gilles@
+
+2011-03-21 14:06 gilles
+
+ * bounce.c: do not close msgfd in bounce_session(), it is closed by
+ client_close()
+
+2011-03-21 14:02 gilles
+
+ * mta.c: - reset smtp_client pointer to NULL after client_close() -
+ datafd is closed in client_close()
+
+2011-03-21 10:21 gilles
+
+ * client.c, queue_shared.c: fix a memory leak in client.c and
+ properly close envelope in queue_shared.c
+
+ diff from Jared Yanovich, sent to bugs@ by Jonny Mosco
+
+2011-03-15 20:24 gilles
+
+ * smtp.c, smtpd.c, smtpd.conf.5, smtpd.h, ssl.c: let smtpd use
+ user-provided Diffie-Hellman parameters for ephemeral key
+ exchange. if no DH parameters are found, fallback to builtin
+ parameters as was done until now.
+
+ since we now accept user-provided DH parameters, make smtpd more
+ strict and fatal() if the parameters are bogus.
+
+ bump the key size of the DH parameters from 512bits to 1024bits,
+ it might be bumped further after some more research.
+
+ thanks to mikeb@ for his suggestions
+
+ diff ok mikeb@ , man ok jmc@
+
+2011-03-09 21:59 gilles
+
+ * smtp.c, smtpctl.c, smtpd.h: smtpctl show stats displays
+ inet4/inet6 repartition for incoming sessions
+
+2011-03-09 01:35 todd
+
+ * dns.c: make similar code .. more similar ok gilles@
+
+ previous commit should have read:
+
+ when copying 'struct sockaddr' data, use sa_len not sizeof(struct
+ sockaddr_in) this fixes truncation of IPv6 addresses in the mail
+ delivery path ok gilles@
+
+2011-03-09 01:34 todd
+
+ * dns.c: [no log message]
+
+2011-03-03 09:09 gilles
+
+ * util.c: fix ss_to_text() and ss_to_ptr() so IP addresses are
+ logged correctly on big-endian machines ...
+
+ spotted and tested by landry@ (and I)
+
+2010-12-19 12:24 gilles
+
+ * dns.c: If MX lookup fails, fallback to using the host itself.
+ This has always been the behavior but I introduced a regression
+ when switching to ASR.
+
+ bug reported by jmc@, bugfix tested by jmc@ and I
+
+2010-12-18 23:25 jmc
+
+ * smtpd.conf.5: document "certificate" a little better; based on a
+ diff from Sunil Nimmagadda
+
+ ok gilles
+
+2010-12-12 23:29 jsg
+
+ * dns.c: use memcpy instead of a cast/deref dance that was reading
+ past the end of the buffer.
+
+ tested by and ok gilles@
+
+2010-12-04 00:29 eric
+
+ * asr.c: be more strict on socket lifetime (fixes a fd leak).
+
+ ok gilles@
+
+2010-11-29 16:25 gilles
+
+ * asr.c, asr.h, dname.c, dns.c, dnsdefs.h, dnsutil.h, lka.c, mta.c,
+ pack.c, print.c, res_random.c, smtpd.h, sockaddr.c, util.c:
+ replace the fork-based-non-blocking-resolver-hack by shiny async
+ resolver written by eric@. it is still experimental but still
+ better than what we had earlier so ... we'll improve in tree :)
+
+ diff by me with *lots* of help from eric@, tested by todd and I
+ (and a few people out there)
+
+2010-11-28 16:32 gilles
+
+ * queue.c: remove unused functions
+
+2010-11-28 15:35 gilles
+
+ * enqueue.c, expand.c, forward.c, lka.c, makemap.c, map.c,
+ map_backend.c, map_parser.c, mda.c, mfa.c, mta.c, parse.y,
+ parser.c, queue.c, queue_shared.c, ruleset.c, runner.c, smtp.c,
+ smtp_session.c, smtpctl.c, smtpd.c: remove all unused headers
+
+2010-11-28 15:02 gilles
+
+ * aliases.c, authenticate.c, dns.c: remove unused headers
+
+2010-11-28 14:56 gilles
+
+ * aliases.c, authenticate.c, bounce.c, client.c, client.h,
+ config.c, control.c, dns.c, enqueue.c, expand.c, forward.c,
+ lka.c, log.c, log.h, makemap.c, map.c, map_backend.c,
+ map_parser.c, mda.c, mfa.c, mta.c, parse.y, parser.c, queue.c,
+ queue_shared.c, ruleset.c, runner.c, smtp.c, smtp_session.c,
+ smtpctl.c, smtpd.c, smtpd.h, ssl.c, util.c: a bit of .h cleanups,
+ no functionnal change
+
+2010-11-25 00:27 todd
+
+ * control.c, runner.c, smtp.c, smtpctl.c, smtpd.h, ssl.c: add
+ *maxactive stats "ok and no need to keep them for yourself"
+ gilles@
+
+2010-11-24 12:09 gilles
+
+ * aliases.c: we can't accept up to MAX_LOCALPART_SIZE (128 bytes)
+ for the user part of an email address at session time, then
+ fatal() when we can't fit it in a LOGIN_NAME_MAX (32 bytes)
+ buffer in the aliases expansion code.
+
+ fix aliases functions to use a buffer that's appropriate,
+ preventing a fatal() from being triggered in aliases_exist(). bug
+ experienced by and reported by Jason Houx, if you're testing
+ smtpd you want to update.
+
+2010-11-15 15:57 jsing
+
+ * queue_shared.c: Do not fatal if an attempt to open a message
+ envelope results in ENOENT. This prevents smtpd from exiting if
+ 'smtpctl schedule' is run with a valid but non-existent message
+ ID. Whilst here make ENOSPC fatal since this should not happen.
+
+ ok gilles@
+
+2010-10-29 11:16 gilles
+
+ * lka.c, mfa.c, mta.c, parse.y, smtpd.conf.5, smtpd.h: smtpd no
+ longer knows a map called "secrets" which holds credentials for
+ authenticated relaying. one can create many maps holding
+ credentials and name them however he/she wants, just like any
+ other map.
+
+ teach smtpd how to select a credentials map at the rule-level
+ allowing a setup to relay through the same MX with different
+ credentials depending on the source.
+
+ smtpd.conf.5 updated to reflect changes with help from jmc@
+
+2010-10-28 23:15 gilles
+
+ * mfa.c, parse.y, queue_shared.c, runner.c, smtpd.conf.5, smtpd.h:
+ teach smtpd how to handle per-rule delays for message expiry,
+ this allows some rules to have a longer expiry delay than the
+ default:
+
+ accept for [...] relay expire 8d # will stay 8 days in
+ queue
+
+ I added the man page bits so I don't forget but I need to reword
+ it a bit
+
+2010-10-18 15:28 sthen
+
+ * smtpctl.8: Mention that commands may be abbreviated, as done in
+ other *ctl manuals. ok gilles@
+
+2010-10-18 15:28 sthen
+
+ * parse.y: Missing semicolons to appease yyextract, ok gilles@
+
+2010-10-10 00:12 gilles
+
+ * queue_shared.c, runner.c: these need to be re-added too
+
+2010-10-10 00:11 gilles
+
+ * bounce.c: missing from previous commit
+
+2010-10-10 00:07 gilles
+
+ * queue_backend.c, queue_backend.h: no longer compiled, i will
+ reintroduce them later, lots of stuff needs to be done before we
+ can write queue backends anyway ...
+
+2010-10-10 00:05 gilles
+
+ * aliases.c, client.c, control.c, enqueue.c, expand.c, lka.c,
+ log.c, map.c, mda.c, mfa.c, mta.c, parse.y, parser.c, parser.h,
+ queue.c, smtp.c, smtp_session.c, smtpctl.8, smtpctl.c, smtpd.c,
+ smtpd.h, ssl.c, util.c: backout the "new" queue code commited 4
+ months ago. it has many good ideas, is way more optimized than
+ what we had earlier and there's definitely stuff we want to keep,
+ however it is early optimization that doesn't account for many
+ features and makes them hard (if not impossible) to write without
+ ugly workarounds that ruin the purpose of the optimizations.
+
+ the backout goes to 30 May's right before the commit and catches
+ up on all the non-queue related commits that happened since then.
+
+ i'll work on reintroducing the ideas from this queue when the
+ basic features we expect from a MTA are implemented.
+
+ suggested on tech@ about a week ago, no objections, several
+ "please make smtpd move forward" mails from hackers and tech
+ readers.
+
+2010-09-20 11:01 gilles
+
+ * lka.c, parse.y, queue.c, smtpd.h: - fix a regression caused by
+ latest commit (long story made short: do not attempt to expand
+ the local delivery buffer when relaying mail, it was kind of ok
+ before but no longer is) - use the same buffer for local
+ deliveries to files and commands
+
+ tested by jmc@ and I
+
+2010-09-13 00:38 gilles
+
+ * lka.c: oga@ spotted a bug in lka_expand() which caused it to
+ miscalculate the length of its expand buffer. this commit
+ introduces a new lka_expand() that has been simplified, that
+ fixes the bug and that is more robust. callers of lka_expand()
+ can now determine that it has failed and throw the recipient at
+ session time.
+
+ lka_expand() rewrite by oga@, changes around it by me, tested on
+ a few different setups but no feedback from tech@ so ... let me
+ know if it's breaking something for you
+
+2010-09-09 01:32 gilles
+
+ * parse.y: when I fixed the ruleset matching on rules that had more
+ than one condition by expanding them to several rules, I forgot
+ to copy the tags to the expanded rules. this commit unbreaks
+ matching rules by tag.
+
+ documentation follows shortly ...
+
+ spotted and fixed by me a while ago, jacekm@ timeout
+
+2010-09-08 23:40 gilles
+
+ * smtpd.conf.5: had planned to commit the change after oga@ and I
+ are done with little changes to lka_expand() but it looks like a
+ bit more work :-)
+
+2010-09-08 15:46 gilles
+
+ * lka.c: add support for sender expansion in smtpd.conf:
+
+ %U for sender localpart
+ %D for sender domainpart
+
+ diff sent to tech@ by Gregory Edigarov <greg@bestnet.kharkov.ua>,
+ timeout by jacekm@, ok by me
+
+2010-09-08 15:32 gilles
+
+ * dns.c: we do dns resolutions in a separate process because we
+ don't have an async resolver. if we run scarce on resources and
+ we cannot fork a separate dns process or we cannot socketpair()
+ tell the caller that we have a temporary failure rather than
+ issueing a fatal(). message will stay in queue and be rescheduled
+ later ...
+
+ bug reported and bugfix tested by Sacha El Masry
+ <lists@devilray.eu>
+
+2010-09-04 23:31 tedu
+
+ * parser.c, parser.h: move some things around to make intentions
+ clear. not really a functional change. ok claudio
+
+2010-09-03 13:22 jmc
+
+ * makemap.8, newaliases.8: add an EXIT STATUS section for
+ /usr/sbin;
+
+2010-08-03 20:42 henning
+
+ * parse.y: fix linecount bug with comments spanning multiple lines
+ problem reported with the obvious fix for bgpd by Sebastian
+ Benoit <benoit-lists at fb12.de>, also PR 6432 applied to all the
+ others by yours truly. ok theo isn't it amazing how far this
+ parser (and more) spread?
+
+2010-08-02 13:49 jacekm
+
+ * enqueue.c: Ignore SIGPIPE, the delivery of which prevented
+ /usr/sbin/sendmail from relaying the server diagnostic back to
+ the user (eg. "500 Line too long").
+
+2010-07-24 00:23 gilles
+
+ * queue.c: smtpd should NOT fatal when it permanently fails a
+ bounce delivery as this can be a normal situation and will allow
+ a local/authenticated user to trigger the fatal on purpose ...
+
+ ignore permanently failed bounce deliveries since there's not
+ much smtpd can do anyway, that's what the previous queue code
+ did.
+
+ experienced and reported by pirofti@
+
+2010-06-29 05:47 deraadt
+
+ * dns.c: force the dns buffers to be aligned using a union, until
+ the retarded "misalign strings on the stack" bug in gcc4 is fixed
+ (even when that is fixed this idiom is safer and quite common) ok
+ jacekm
+
+2010-06-10 21:34 chl
+
+ * parse.y, queue.c, smtpd.conf.5, smtpd.h: allow configure queue
+ expiry
+
+ with help from jacekm@
+
+ ok gilles@ jacekm@
+
+2010-06-09 22:00 zinovik
+
+ * smtpd.h: switch `ref' data type to int, because it is tested for
+ negative value in queue_mem_content_unref() function
+
+ ok jacekm@, gilles@
+
+2010-06-04 13:15 jacekm
+
+ * lka.c: Use correct imsg type in error reply.
+
+2010-06-02 21:16 chl
+
+ * control.c, dns.c, enqueue.c, lka.c, mda.c, mfa.c, mta.c, queue.c,
+ smtp.c, smtpd.c: check event_dispatch() return value
+
+ ok jacekm@
+
+2010-06-02 01:06 jacekm
+
+ * aliases.c, bounce.c, client.c, control.c, enqueue.c, expand.c,
+ lka.c, log.c, map.c, mda.c, mfa.c, mta.c, parse.y, parser.c,
+ parser.h, queue.c, queue_backend.c, queue_backend.h,
+ queue_shared.c, runner.c, smtp.c, smtp_session.c, smtpctl.8,
+ smtpctl.c, smtpd.c, smtpd.h, ssl.c, util.c: new queue, again;
+ gcc2 compile tested by deraadt
+
+2010-06-01 21:47 jacekm
+
+ * aliases.c, bounce.c, client.c, control.c, enqueue.c, expand.c,
+ lka.c, log.c, map.c, mda.c, mfa.c, mta.c, parse.y, parser.c,
+ parser.h, queue.c, queue_backend.c, queue_backend.h,
+ queue_shared.c, runner.c, smtp.c, smtp_session.c, smtpctl.8,
+ smtpctl.c, smtpd.c, smtpd.h, ssl.c, util.c: New queue doesn't
+ compile on gcc2, back out. Spotted by deraadt@
+
+2010-06-01 16:21 jacekm
+
+ * queue.c, smtpd.h: Schedule newly arrived mail immediately, ie.
+ place it at the beginning of the list of next items to try, or
+ near the beginning if the schedule contains expired mail, which
+ is of highest priority.
+
+2010-06-01 13:37 jacekm
+
+ * smtpctl.c: Include birth time in smtpctl show queue raw.
+
+2010-06-01 13:27 jacekm
+
+ * queue.c: It's lasttry + 1 because I initially thought passing
+ identical birth and lasttry args to queue_retry would make it
+ return birth leading looped scheduling, but that's not true so
+ drop the "+ 1".
+
+2010-06-01 13:05 jacekm
+
+ * mta.c: Better errors.
+
+2010-06-01 04:19 jacekm
+
+ * lka.c: Don't interpret garbage on stack; problem seemingly
+ exposed by my queue rewrite. Proper fix after gilles wakes up.
+
+2010-06-01 04:08 jacekm
+
+ * lka.c: Fix one case of not sending smtp session id on error.
+
+2010-06-01 01:50 jacekm
+
+ * smtpd.h: oops
+
+2010-06-01 01:38 jacekm
+
+ * aliases.c, bounce.c, client.c, control.c, enqueue.c, expand.c,
+ lka.c, log.c, map.c, mda.c, mfa.c, mta.c, parse.y, parser.c,
+ parser.h, queue.c, queue_backend.c, queue_backend.h,
+ queue_shared.c, runner.c, smtp.c, smtp_session.c, smtpctl.8,
+ smtpctl.c, smtpd.c, smtpd.h, ssl.c, util.c: Rewrite entire queue
+ code.
+
+ Major goals:
+
+ 1) Fix bad performance caused by the runner process doing full
+ queue read in 1s intervals. My Soekris can now happily accept
+ >50 msg/s while having multi-thousand queue; before, one hundred
+ queue would bring the system to its knees.
+
+ 2) Introduce Qmail-like scheduler that doesn't write as much to
+ the disk so that it needs less code for servicing error
+ conditions, which in some places can be tricky to get right.
+
+ 3) Introduce separation between the scheduler and the backend;
+ these two queue aspects shouldn't be too tied too each other.
+ This means that eg. storing queue in SQL requires rewrite of just
+ queue_backend.c.
+
+ 4) Make on-disk queue format architecture independent, and more
+ easily extensible, to reduce number of flag days in the future.
+
+ Minor goals:
+
+ ENOSPC no longer prevents delivery attempts, fixed session
+ limiting for relayed mail, improved batching of "relay via"
+ mails, human-readable mailq output, "show queue raw" command,
+ clearer logging, sending of single bounce about multiple
+ recipients, exact delay= computation, zero delay between
+ deliveries while within session limit (currently 1s delay between
+ re-scheduling is enforced), mta no longer requests content fd,
+ corrected session limit for bounce submissions, tiny <100B queue
+ files instead of multi-KB, detect loops before accepting mail,
+ reduce traffic on imsg channels by killing enormous struct
+ submit_status.
+
+2010-06-01 00:25 chl
+
+ * smtpd.c, smtpd.h: imsg_compose_event() return value was never
+ checked. Make it fatal() if needed.
+
+ ok jacekm@ gilles@
+
+2010-05-27 17:36 gilles
+
+ * config.c, lka.c, parse.y, ruleset.c, smtpd.c, smtpd.h: when a
+ rule has two conditions (ie: accept for { domain foo, domain bar
+ } ) expand to two rules each having its own condition rather than
+ one rule with a tail queue of conditions. this simplifies code a
+ bit and removes a couple hacks.
+
+ basic testing by oga and me
+
+2010-05-27 13:18 gilles
+
+ * smtpd.h: struct opt as not used anywhere else, kill it, we can
+ reintroduce it later if we feel a need for it
+
+2010-05-27 13:17 gilles
+
+ * config.c, parse.y, smtpd.h: kill struct opt from struct rule, we
+ don't use it, we don't need it
+
+2010-05-26 18:44 nicm
+
+ * buffer.c, client.c, imsg.c, imsg.h: Move imsg into libutil and
+ add a man page.
+
+ Minor bump for libutil.
+
+ Previous versions of this diff and man page looked at by various
+ people.
+
+ "you should just commit" deraadt
+
+2010-05-26 15:56 nicm
+
+ * buffer.c, client.c, client.h, imsg.c, imsg.h, mda.c, ssl.c:
+ Rename some imsg bits to make namespace collisions less likely
+ buf to ibuf, buf_read to ibuf_read, READ_BUF_SIZE to
+ IBUF_READ_SIZE.
+
+ ok henning gilles claudio jacekm deraadt
+
+2010-05-24 21:44 jmc
+
+ * smtpd.8: now that we can handle >9 args, put "-D name=value" on
+ one line: it's a bit more readable, and fixes a spacing bug we
+ had in smtpd.8;
+
+2010-05-23 20:44 jacekm
+
+ * smtpd.c: When executing external mda, call dup2, closefrom, and
+ chdir before setresuid because after dropping superuser
+ privileges the process cannot be trusted to call these.
+
+ Thanks to oga@, kettenis@, and nicm@ for confirming my paranoia.
+
+2010-05-21 10:45 jacekm
+
+ * smtpd.c: Use _exit(2) in mda helper child process.
+
+2010-05-20 20:35 gilles
+
+ * smtpd.c: S_ISREG() should be called on st.st_mode not st.st_flags
+
+2010-05-19 22:57 gilles
+
+ * aliases.c, bounce.c, expand.c, log.c, parse.y, runner.c, smtp.c,
+ ssl.c: cleanup-only commit, removes unrequired includes, no
+ functionnal change
+
+2010-05-09 17:24 gilles
+
+ * smtpd.c: in recent change, an assignation was removed which would
+ cause a bogus pointer deref if we actually went through this code
+ path (reload, does not work yet so it is disabled)
+
+2010-04-27 23:04 nicm
+
+ * imsg.h: imsg.h does not need sys/tree.h.
+
+ ok eric
+
+2010-04-27 16:39 jmc
+
+ * smtpd.conf.5: sort the map types;
+
+2010-04-27 12:17 gilles
+
+ * map_backend.c, parse.y, smtpd.conf.5, smtpd.h: this commit
+ enables "plain" as a backend for maps (that means aliases,
+ virtual AND secrets), adds a description in smtpd.conf.5 and
+ removes a mention to special map "aliases" which was removed a
+ while ago.
+
+ to use plain maps: map "myaliases" { source plain
+ "/etc/mail/aliases" }
+
+ code diff was okayd a while ago by jacekm@
+
+2010-04-27 11:49 gilles
+
+ * aliases.c, expand.c, forward.c, lka.c, makemap.c, map.c,
+ map_parser.c, smtpd.h: initial work at fixing aliases support: -
+ kill struct alias, struct expandnode is used instead - introduce
+ map_parse_alias() and map_parse_virtual() - aliases and virtual
+ code no longer assume db(3) but use the map API which lets them
+ become backend agnostic AND value-checked. this actually makes
+ the code simpler by removing all values parsing from aliases.c -
+ rename K_SECRETS -> K_SECRET, K_ALIASES -> K_ALIAS for
+ consistency the enum has singular names. - aliases, virtual
+ and forward now work with an expandtree and deal with multiple
+ levels of resolving by merging expandtree's
+
+ more coming soon ;)
+
+2010-04-24 21:16 chl
+
+ * smtp_session.c: fix format string
+
+ while there, print SIZE unconditonnally (prompted by gilles@)
+
+ ok gilles@
+
+2010-04-22 17:37 jmc
+
+ * smtpd.conf.5: - sort the keyword list - rewrite the description
+ of "size"
+
+ ok gilles jacekm
+
+2010-04-22 14:56 jacekm
+
+ * bounce.c, runner.c, smtpd.h: Fix a case of runner trying to send
+ imsg directly to smtp process instead of forwarding it via queue.
+
+2010-04-22 14:13 jacekm
+
+ * queue.c, runner.c: - kill the runner_imsg_compose wrapper to
+ reduce indirection - kill noisy log_debug
+
+2010-04-21 23:47 gilles
+
+ * lka.c, map.c, map_parser.c, smtpd.h: introduce first map parser
+ for maps of kind K_SECRETS !
+
+ map_parse_secret() converts a map value into a struct map_secret.
+ lka no longer needs to do any parsing, it simply calls
+ map_lookup() with kind K_SECRETS, checks if it returned a !NULL
+ value, and call lka_encode_secret to safely do the base64
+ encoding.
+
+2010-04-21 23:40 gilles
+
+ * makemap.c: when creating a map, make sure we do not store a
+ key/val separator at the beginning of the key (ie: "gilles: bleh"
+ should not be stored as key[gilles] val[ bleh])
+
+2010-04-21 23:04 gilles
+
+ * map.c, map_backend.c, map_parser.c, smtpd.h: map.c is growing
+ big, split it into three different files: map.c contains the map
+ API calls as usable by smtpd processes, map_backend.c contains
+ backend implementations and map_parser.c contains parser
+ implementations used internally by the map API
+
+2010-04-21 22:32 gilles
+
+ * smtp_session.c: my evbuffer_readln_crlf() hack can be killed now
+ that nicm@ has brought us an update to libevent that ships with
+ evbuffer_readln(). beers for nicm@ !
+
+2010-04-21 22:10 gilles
+
+ * map.c: change prototypes for map_*_get() functions, we need the
+ get-er function to fill the size of value for the caller.
+
+ have map_lookup() actually lookup the parser in map_parsers table
+ and call it if it is set, otherwise return raw value which is
+ similar to current behavior. currently, no map kind has a parser
+ set, so this is essentially no functionnal change.
+
+ fix map_stdio_get(), it was not used yet in -current but i
+ spotted a bug while enabling it in my sandbox. it returns key and
+ value instead of key.
+
+2010-04-21 21:53 gilles
+
+ * lka.c, map.c, ruleset.c, smtpd.h: map_lookup() takes an
+ additionnal parameter of type enum map_kind which will be used to
+ select the appropriate map parser. make sure every call to
+ map_lookup() is updated. map_lookup() currently ignores the
+ value.
+
+2010-04-21 21:45 gilles
+
+ * map.c, smtpd.h: introduce enum map_kind, the map_parsers array
+ and map_parser_lookup() which will be used to perform stronger
+ checks on map values. they are unused yet ...
+
+2010-04-21 21:37 gilles
+
+ * map.c: simplify map_lookup() by having the backend lookup done in
+ new map_backend_lookup() function, no functionnal change, first
+ of many changes to come in map.c
+
+2010-04-21 20:54 jacekm
+
+ * control.c, lka.c, mda.c, mta.c, queue.c, runner.c, smtp.c,
+ smtpctl.c, smtpd.c, smtpd.h: Runner process is just a helper for
+ queue, so tear down its imsg channels to parent, mda, mta, lka,
+ smtp, and control. This leaves just the channel to queue, which
+ forwards imsgs on runner's behalf and redirects any replies back
+ to it.
+
+ OK gilles@
+
+2010-04-21 19:50 jacekm
+
+ * enqueue.c: Fix pathetic performance when submitting large mails
+ via /usr/sbin/sendmail, caused by realloc() abuse.
+
+2010-04-21 10:29 jacekm
+
+ * control.c, lka.c, mda.c, mfa.c, mta.c, queue.c, runner.c, smtp.c:
+ Remove unusable ifdef DEBUG code.
+
+2010-04-21 02:12 jacekm
+
+ * runner.c: Fix logic error just like the one in previous revision.
+
+2010-04-20 22:55 jacekm
+
+ * runner.c: Fix crash that could happen when attempting ``smtpctl
+ remove'' while the message is being delivered.
+
+2010-04-20 22:22 jacekm
+
+ * smtpd.conf.5: Correct map definition syntax. Reported by Rene
+ Maroufi <info@maroufi.net>.
+
+2010-04-20 22:09 jacekm
+
+ * smtpd.conf.5: Document the ``alias <map>'' parameter.
+
+2010-04-20 21:35 jacekm
+
+ * smtpd.conf.5: Document ``size'' setting; OK gilles@
+
+2010-04-20 20:55 jacekm
+
+ * parse.y: Support "accept from local ..." as documented in the man
+ page.
+
+ Reported by Rene Maroufi <info@maroufi.net>
+
+2010-04-20 20:18 jacekm
+
+ * mda.c: Use correct type for ``mda_id'', ie. match with type used
+ in imsg header.
+
+2010-04-20 17:34 jacekm
+
+ * config.c, control.c, lka.c, mda.c, mfa.c, mta.c, queue.c,
+ runner.c, smtp.c, smtpd.c, smtpd.h: Kill *2400* lines of code by
+ abstracting common bits of the imsg handlers.
+
+2010-04-20 13:03 gilles
+
+ * parse.y: when a size is declared with a quantifier in smtpd.conf,
+ have parse.y use scan_scaled(3) to support the quantifiers rather
+ than rolling my own code.
+
+ prompted by jacekm@
+
+2010-04-20 03:01 jacekm
+
+ * smtpd.c: setproctitle(3) the parent process to "[priv]" to match
+ other OpenBSD daemons.
+
+2010-04-20 02:57 jacekm
+
+ * smtpd.c: Make smtpd -d produce verbose output, ie. restore
+ behaviour from before rev. 1.94.
+
+2010-04-19 22:10 jacekm
+
+ * mda.c: Use larger buffer for mda output.
+
+2010-04-19 22:09 jacekm
+
+ * smtpd.c: - use perror(3) - call _exit(2) instead of exit(3) in
+ forked processes
+
+2010-04-19 16:37 gilles
+
+ * parse.y: two lines were missing from previous commit
+
+2010-04-19 12:26 gilles
+
+ * smtp_session.c: initial support for ENHANCEDSTATUSCODES, has been
+ sitting in my tree for a month or so
+
+2010-04-19 12:12 gilles
+
+ * parse.y, smtp_session.c, smtpd.h: basic support for SIZE
+ extension, has been sitting in my tree for a month or so ...
+
+ okayd by jacekm@ a while ago
+
+2010-04-19 10:14 jacekm
+
+ * mda.c, runner.c, smtpd.c, smtpd.h: Simplify local delivery
+ codepath: - replace uses of struct batch in the parent with
+ simpler struct delivery. - replace IMSG_BATCH_* dance with
+ single IMSG_MDA_SESS_NEW. - make mda assume it delivers to
+ external program over a pipe. - fork helper process when
+ delivering to maildir or a file.
+
+ New feature: upon external mda failure use last line of its
+ output as an error message.
+
+ With input and tests from nicm@.
+
+ OK nicm@ gilles@
+
+2010-04-12 00:46 jacekm
+
+ * smtpd.h: Increase limit on the length of "user" in
+ user@domain.com to a value higher than specified in rfc. Too
+ many mailers don't conform to it, and it is harmless as far as I
+ can see.
+
+ From Tim van der Molen <tbvdm@xs4all.nl>
+
+ OK gilles@
+
+2010-04-07 20:09 nicm
+
+ * imsg.c: Remove XXX comment and just close received fd if calloc()
+ fails.
+
+ If this happens the imsg may no longer be usable as there may be
+ queued messages, but this is a) already the case with the code
+ now, and b) would be the case if recvmsg() fails anyway, so we
+ can document that -1 from imsg_read() invalidates the struct
+ imsgbuf.
+
+ discussed with and ok eric
+
+2010-03-03 12:11 jacekm
+
+ * smtpd.h: tweak mda.c rev. 1.36: eliminate risk of busy waiting
+ for socket to become writable, and make code more idiomatic.
+
+ tested by nicm@
+
+ ok gilles@
+
+2010-03-03 11:52 jacekm
+
+ * mda.c: tweak mda.c rev. 1.36: eliminate risk of busy waiting for
+ socket to become writable, and make code more idiomatic.
+
+ tested by nicm@
+
+ ok gilles@
+
+2010-03-01 23:00 gilles
+
+ * mda.c: mda_event() assumed the mbox fp to be a file when it could
+ be a pipe, do not fatal on read/write errors otherwise a broken
+ pipe in an external mda will bring smtpd down.
+
+ mda_store() assumed write would succeed and fatal otherwise,
+ change code so that EINTR/EAGAIN trigger a new write while other
+ errors gracefully return causing the message to be rescheduled
+ later.
+
+ these two prevent a fatal() from being hit when execution of a
+ filter or external mda fails (bug experienced and fix verified by
+ nicm@)
+
+ while at it, fix a small bug where logs would not display the
+ recipient when mail went through a ~/.forward / aliases
+ expansion.
+
+2010-03-01 14:04 gilles
+
+ * smtpd.c: typo in warning log
+
+ spotted by Seth Wright <seth@crosse.org>
+
+2010-02-28 13:23 gilles
+
+ * ruleset.c: the netmask fix I commited a couple days ago lacked
+ the AF_INET6 bits, this commit fixes pr user/6328
+
+ bug reported and fix verified by Martin Hedenfalk
+ <martinh@bzero.se>
+
+2010-02-26 16:06 gilles
+
+ * parse.y, ruleset.c: - fix netmask matching for AF_INET, it was
+ broken in many ways, problem was reported by nicm@ which spent
+ a couple hours with me trying to understand what was causing
+ the bug, and helping me write and test fix.
+
+2010-02-25 15:53 stevesk
+
+ * smtpd.conf.5: fix incorrect reference; ok jmc@ gilles@ jacekm@
+
+2010-02-23 23:09 stevesk
+
+ * smtpctl.8: add remove command; ok jmc@ gilles@
+
+2010-02-23 22:12 stevesk
+
+ * smtpctl.8: Add a description for message-id and message-uid (text
+ from gilles@). Also combine the two schedule commands with
+ uid/id into one. help and ok jmc@ and gilles@
+
+2010-02-17 18:37 gilles
+
+ * map.c: in map_stdio_get() use strdup on the right buffer, not on
+ a pointer that will be NULL 99% of the times... fixes segv in
+ path that's not enabled yet
+
+2010-02-17 18:27 gilles
+
+ * lka.c: erf, previous fix to lka crash was still using the wrong
+ define ...
+
+2010-02-17 14:47 gilles
+
+ * lka.c, map.c, ruleset.c, smtpd.h: the map api becomes
+ backend-agnostic with initial support for db(3) and stdio(3)
+ backends, though for now we only enable db(3). this is the first
+ commit of a serie to improve maps and everything related.
+
+ idea discussed with and diff okay jacekm@
+
+2010-02-17 09:40 gilles
+
+ * lka.c: localpart of a struct path may legally exceed MAXLOGNAME,
+ causing lka to fatalx() on a lowercase() call in some cases. make
+ sure lka uses a buffer capable of holding a localpart, and do not
+ attempt getpwnam() if we know it's going to fail anyway...
+
+ issue reported by Ben Lindstrom <mouring@eviladmin.org>
+
+2010-01-11 22:43 jacekm
+
+ * enqueue.c: Fix wrong logic in error checking of buf_dynamic,
+ found by pcc.
+
+2010-01-10 17:42 gilles
+
+ * control.c, parser.c, parser.h, runner.c, smtpctl.c, smtpd.h: -
+ teach runner how to remove a message from queue given a message
+ id/uid and assuming message is not in
+ processing/scheduled state - teach smtpctl how to request message
+ removal from runner
+
+ discussed with todd@, idea ok jacekm@
+
+2010-01-10 09:59 gilles
+
+ * smtpd.c: have smtpd errx() at startup if no hostname could be
+ detected either from a gethostname() call or from a hostname
+ directive in smtpd.conf
+
+ discussed with jacekm@, i initially intended to only warn but
+ errx seems to be a better solution for now
+
+2010-01-03 15:37 chl
+
+ * control.c, lka.c, log.c, mda.c, mfa.c, mta.c, parser.c, parser.h,
+ queue.c, runner.c, smtp.c, smtpctl.8, smtpctl.c, smtpd.c,
+ smtpd.h: Implement "log verbose" and "log brief" to enable or
+ disable verbose debug logging on runtime.
+
+ Based on claudio@'s work on ripd, ospfd, ospf6d, dvmrpd, ldpd,
+ bgpd.
+
+ With help/ideas/testing from gilles@ jacekm@ todd@
+
+ ok jacekm@
+
+2010-01-02 17:41 jacekm
+
+ * client.c, client.h: Replace 3 struct smtp_client members
+ (ssl_handshake, rcptokay, dying) with a bitmap called "flags".
+
+2010-01-02 14:42 jacekm
+
+ * client.c, client.h: Factor out parts of client_read() into
+ client_socket_read() and client_get_reply(), downsizing it from
+ 170+ to just over 30 lines. The gotos are now gone, too.
+
+2010-01-02 12:06 jacekm
+
+ * client.c, client.h: Simplify code by removing struct smtp_client
+ member, int iomode, which was used for keeping track of the
+ current polling mode. Introduce new function client_poll() that
+ determines what mode of polling is required at the time of call.
+
+2009-12-31 16:37 gilles
+
+ * smtp_session.c: when separating command from parameters in smtp
+ session, the parser tries to use ':' as a separator then
+ fallbacks to ' ' so that it can detect the command names that
+ contain more than one words (MAIL FROM and RCPT TO) or the one
+ word ones (HELO, DATA, ...).
+
+ this is incorrect and the parser can get confused if the
+ parameter to any command contains a ':', for example "HELO
+ [ipv6:...]" cause the parser to lookup for command "HELO [ipv6".
+
+ fix this by using ':' as a delimiter for 'mail from' and 'rcpt
+ to', while using ' ' as a delimiter for all other commands.
+
+ fixes bug 6285/system reported by Lionel Le Folgoc
+ <lionel@lefolgoc.net>
+
+2009-12-24 15:19 gilles
+
+ * smtpd.c, smtpd.h: kill PATH_RUNQUEUEHIGH and PATH_RUNQUEUELOW, i
+ had great plans for them but they're still unused months later
+ and there's many ways to achieve having a set of priorities on
+ envelopes without needing additionnal queues.
+
+2009-12-23 18:16 jacekm
+
+ * bounce.c, client.c, client.h, control.c, enqueue.c, mta.c,
+ util.c: Implementation of RFC 2920 PIPELINING extension, client
+ side only for now.
+
+ This restructures the client_* API internals significantly. The
+ code becomes pipelining in nature. All SMTP commands are put on
+ the output queue and dequeued as quickly as possible. Once
+ dequeued, they're moved to the receive queue so that replies can
+ be matched with previous commands.
+
+ Dequeuing commands from the output queue halts when the count of
+ commands currently in-pipeline (``cmdi'') is equal to the command
+ send window (``cmdw''). There are three cmdw values useful in
+ practice:
+
+ 0 clear pipeline, ie. inhibit all future sends 1
+ disable pipelining, ie. use old
+ ``one-request-one-reply`` mode SIZE_T_MAX enable pipelining,
+ ie. dequeue as many commands as possible
+
+ At the beginning of session cmdw is 1. When it is found that
+ peer supports PIPELINING, it grows to SIZE_T_MAX. After dequeing
+ DATA it is again 1. After sending QUIT it is 0.
+
+ Each command dequeued from the output queue becomes a buf in a
+ msgbuf. The act of combining multiple commands into a single
+ send operation did not need to be implemented: buf_write()
+ already combines bufs using iovec and sends them at once using
+ sendmsg(2).
+
+ Tested by todd@ and oga@
+
+ "looks good" to gilles@
+
+2009-12-16 22:40 jacekm
+
+ * client.c: Don't lose a line each time a chunkful of content is
+ read off the disk. Problem spotted by todd@
+
+2009-12-16 03:20 jacekm
+
+ * client.c: Fix RCPT TO failure handling, bug introduced in r1.18.
+
+2009-12-15 12:45 jacekm
+
+ * client.c, client.h: Simplify SSL code client-side, no functional
+ change.
+
+2009-12-15 01:23 jacekm
+
+ * lka.c: Must aim better.
+
+2009-12-15 00:17 jacekm
+
+ * bounce.c: Handle 6yz code as permanent error.
+
+2009-12-14 20:56 jacekm
+
+ * lka.c, queue.c, runner.c, smtpd.c, smtpd.h, util.c: Tweak the
+ logic behind setting the fd limits so that smtpd is less likely
+ to get upset by custom soft/hard ulimit settings.
+
+ Suggested by todd@
+
+2009-12-14 20:49 jacekm
+
+ * smtp.c: Set initial session limit so that IMSG_SMTP_ENQUEUE can
+ be satisfied even in absence of all other real listening sockets.
+
+ Spotted by todd@
+
+2009-12-14 19:21 jacekm
+
+ * bounce.c, runner.c, smtpctl.c, smtpd.h: Control maximum number of
+ bounce sessions similarly to how the mta and mda are now
+ controlled.
+
+2009-12-14 19:16 jacekm
+
+ * queue_shared.c: Clear S_MESSAGE_PERMFAILURE when creating the
+ bounce message. Makes the bounce mails visible in mailq output.
+
+2009-12-14 17:44 jacekm
+
+ * mda.c, mta.c, queue.c, runner.c, smtpctl.c, smtpd.h: Impose
+ sessions limit on the delivery sessions (mta and mda).
+
+2009-12-14 14:17 jacekm
+
+ * mda.c, smtpd.c, smtpd.h: Do non-blocking I/O when delivering
+ locally over a pipe.
+
+2009-12-13 23:02 jacekm
+
+ * control.c, enqueue.c, lka.c, queue.c, runner.c, smtp.c,
+ smtp_session.c, smtpctl.c, smtpd.c, smtpd.h, util.c: Use safe fd
+ limits in smtp, lka, queue, and control. Removes a possibility
+ for fd-starvation fatal when under heavy load.
+
+2009-12-13 22:48 jacekm
+
+ * smtpctl.c: typo
+
+2009-12-12 15:03 jacekm
+
+ * bounce.c, client.c, client.h, enqueue.c, mta.c: When acting as a
+ client do content reads from the disk progressively as the remote
+ accepts more data instead of doing one big read into the memory
+ in the beginning of session.
+
+2009-12-12 11:33 jacekm
+
+ * bounce.c, client.c, client.h, enqueue.c, mta.c, smtpd.h: Simplify
+ client_* api, mainly by making fatal conditions result in
+ immediate fatals instead of passing the error up (kills ~300
+ lines).
+
+ Implement sending of the QUIT command which replaces crude
+ close(2).
+
+ tested by gilles@, todd@
+
+2009-12-12 11:14 jacekm
+
+ * enqueue.c: Don't qualify empty sender address with the domain,
+ eg. in sendmail -f "<>".
+
+2009-12-10 16:02 jacekm
+
+ * mta.c: Fix a case when 2yz status would not override existing 4yz
+ one. Reported by jsing@
+
+2009-12-10 15:57 jacekm
+
+ * parse.y: Fix few read overruns found by parfait. Nudge by
+ deraadt@
+
+2009-12-07 16:33 jsing
+
+ * mta.c: Avoid dereferencing a null pointer when logging a DNS
+ lookup failure.
+
+ ok gilles@
+
+2009-12-06 01:27 jacekm
+
+ * parse.y: fix previous
+
+2009-12-05 19:42 chl
+
+ * parse.y: fix interface tagging listeners in the ipv6 case
+
+ while there factor some common code (from jacekm input)
+
+ ok jacekm@
+
+2009-12-02 20:10 mk
+
+ * control.c: log_warn() consistency.
+
+ `OK' claudio
+
+2009-11-26 23:21 chl
+
+ * control.c: fix copy & paste error: IMSG_MTA_RESUME -->
+ IMSG_MDA_RESUME
+
+ ok gilles
+
+2009-11-23 13:03 jacekm
+
+ * control.c: In "smtpd; smtpd;" the second instance would fatal
+ quickly, but it would remove the smtpd.sock file, without which
+ /usr/sbin/sendmail will fail causing mails to be queued in
+ offline.
+
+ Initially reported by ian@, may explain oga@'s e-mail burst after
+ smtpd restart.
+
+2009-11-17 10:22 jacekm
+
+ * client.c: Fix handling of 5yz response to EHLO, ie. fallback to
+ HELO.
+
+2009-11-16 11:38 jacekm
+
+ * smtp_session.c: Kill dead code.
+
+2009-11-16 10:40 jacekm
+
+ * mta.c: Minimize the delay between receiving response to "." and
+ removing the queue entry in order to avoid the risk of sending
+ duplicate mail.
+
+2009-11-14 19:49 chl
+
+ * dns.c: add missing header needed by signal()
+
+ ok gilles@
+
+2009-11-14 19:48 chl
+
+ * smtpd.c: remove duplicate header include
+
+ ok gilles@
+
+2009-11-13 21:34 chl
+
+ * enqueue.c, smtpctl.c: add missing headers needed by time()
+
+ ok jacekm@
+
+2009-11-13 13:01 jacekm
+
+ * mda.c: Add logging of failed local deliveries.
+
+2009-11-13 12:40 jacekm
+
+ * smtp_session.c: Log all 4yz and 5yz replies that we send to our
+ clients.
+
+2009-11-13 12:37 jacekm
+
+ * smtp_session.c: Include recipient address in "Recipient rejected"
+ reply.
+
+2009-11-13 12:27 jacekm
+
+ * lka.c, mta.c, smtpd.h: Log FQDN and IP of the server we handed
+ mail to. As a bonus, don't delay logging of successful
+ deliveries until all MXs were tried, plus add logging of 5yz
+ replies.
+
+ tested by todd@, "reads ok" gilles@
+
+2009-11-12 13:35 jacekm
+
+ * config.c, parse.y: Fix a memleak in parse_config(). Correct
+ return code in few error paths. Fix two memleaks in
+ purge_config().
+
+ First problem spotted by parfait, the other ones - by myself.
+
+ "looks good" gilles@
+
+2009-11-11 17:55 jacekm
+
+ * dns.c: Fix previous. When configured to relay via IP address, MX
+ lookup would fail (NXDOMAIN), leading to a bounce. Precede the
+ MX lookup with an attempt to parse the relay as numeric string.
+
+ "reads ok" gilles@
+
+2009-11-11 16:36 jacekm
+
+ * client.c, ssl.c: Check if the receive buffer has any unused space
+ before reading from socket in buf_read (and in ssl_buf_read).
+
+2009-11-11 12:41 jacekm
+
+ * client.c: Fix crlf issue in buf_getln, similar to that in
+ smtp_session.c r1.123.
+
+ ok gilles@
+
+2009-11-11 12:25 jacekm
+
+ * client.c: improve buf_getln readability, no fuctional change.
+
+2009-11-11 11:27 jacekm
+
+ * client.c: Ensure all replies are at least 4 chars long. If only
+ 3 chars were received, append a space character. This enables
+ other parts of the daemon to safely index into 4th character of
+ the reply buffer without the risk of accessing one byte beyond
+ NUL.
+
+ ok gilles@
+
+2009-11-11 11:04 chl
+
+ * bounce.c, mda.c, mta.c: add missing headers needed by time()
+
+ ok jacekm@
+
+2009-11-10 15:57 jacekm
+
+ * client.c: Eliminate space after colon in "RCPT TO:" as required
+ by RFC.
+
+2009-11-10 15:54 jacekm
+
+ * client.c: In absence of the ehlo parameter, generate one based on
+ locally bound IP address ("EHLO [1.2.3.4]") as dictated by RFC.
+
+ ok gilles@
+
+2009-11-10 15:46 jacekm
+
+ * lka.c: In relay case, avoid freeing garbage pointer by copying
+ the required struct from the temporary imsg buffer.
+
+ ok gilles@
+
+2009-11-10 11:25 jacekm
+
+ * lka.c: move format expansion to the right place, from gilles@
+
+2009-11-10 10:53 jacekm
+
+ * lka.c: sync code with comment, from gilles@
+
+2009-11-10 02:09 gilles
+
+ * lka.c: - add comments to explain the logic in the aliases
+ expansion loop - more cosmethic changes to help readability - fix
+ memory leaks - if deliverylist is empty, it means something went
+ bad during expansion, reject recipient
+
+2009-11-10 01:42 gilles
+
+ * lka.c: pfff remove a comment i pasted to help me refactor code
+ ;-)
+
+2009-11-10 01:36 gilles
+
+ * lka.c: more cleanup, let lka_resolve_path() request forward files
+ and populate expandtree, this makes a lot of code clearer and
+ removes quite a bit of complexity from various places.
+
+2009-11-10 01:24 jacekm
+
+ * client.c: Check for extension keywords on final multiline reply.
+ Skip the check for states other than CLIENT_EHLO. Verify
+ response is not shorter than 3 chars.
+
+ From Nils Frohberg ok gilles@
+
+2009-11-10 01:21 gilles
+
+ * lka.c: cosmethic changes, code reordering, no functionnal change
+
+2009-11-10 01:13 gilles
+
+ * lka.c: introduce lka_session_fail() which factors a small piece
+ of code used in three places: set code to 530, send imsg to
+ notify rejection, kill lkasession
+
+2009-11-10 00:54 gilles
+
+ * aliases.c, forward.c: now that we don't keep an expand_node in
+ memory for each expansion result, we don't need to calloc them as
+ they won't be saved in the tree.
+
+2009-11-10 00:49 gilles
+
+ * aliases.c, expand.c, forward.c, lka.c, smtpd.h: - add a reference
+ count and flags to struct expand_node - during expansion, no
+ longer create a new node for each result but try to lookup for
+ an existing equivalent node and increment its reference count
+ so that: a) we save on memory, b) we don't need to expand the
+ same users again and again just because they keep appearing in
+ expansion results. - while expanding, flag nodes as
+ F_EXPAND_DONE so that we know which nodes we already processed
+ - be smarter when expanding, if we have a clue that an iteration
+ has not brought any new result (because no new nodes were added
+ and all existing nodes have F_EXPAND_DONE), end expansion and
+ proceed to delivery. - various small cleanups
+
+ discussed with jacekm@ yesterday, rebuild aliases db, make clean
+
+2009-11-09 23:28 gilles
+
+ * lka.c: support the userpart+foobar@domainpart syntax which got
+ wiped when i wrote the virtual domains support as it was in my
+ way. this time, make it work as it should:
+ userpart+foobar@domainpart becomes:
+
+ path->user = userpart+foobar path->domain = domainpart
+ path->pw_name = userpart
+
+ discussed quickly with jacekm@
+
+2009-11-09 11:32 jacekm
+
+ * expand.c: fatal on RB_INSERT failure
+
+2009-11-09 00:25 gilles
+
+ * forward.c: forwards_get() also calls alias_to_expand_node()
+
+2009-11-09 00:20 gilles
+
+ * aliases.c, smtpd.h: add an alias_to_expand_node() function and
+ use it in aliases.c
+
+2009-11-09 00:15 gilles
+
+ * aliases.c, expand.c: move expansion code to new expand.c to
+ clearly separate it from aliases
+
+2009-11-09 00:08 gilles
+
+ * aliases.c, forward.c, lka.c, makemap.c, runner.c, smtpd.h: rework
+ a bit expansion and data structures involved in the expansion so
+ we no longer have a direct mapping between structures saved in
+ aliases/virtual db and structures used at runtime during
+ expansion.
+
+ side effects ? struct alias is smaller, databases are smaller and
+ it is no longer necessary to rebuild aliases/virtual databases
+ each time jacekm@ or I make changes to some obscure structure
+ used indirectely during expansion
+
+ rebuild databases, flush queues, make clean
+
+2009-11-08 22:40 gilles
+
+ * aliases.c, enqueue.c, forward.c, lka.c, queue.c, queue_shared.c,
+ runner.c, smtp.c, smtpd.h, util.c: - make aliases expansion use a
+ rb tree instead of a tail queue, the code doesn't take
+ advantage of the new structure yet, but this was a needed
+ change for upcoming improvements. - introduce
+ aliasestree_{lookup,insert,remove} to the aliases api - rename
+ queue_generate_id() to generate_uid() and move it to utils.c as
+ it is used all over the place and not only in queue
+
+ tree idea discussed with jacekm@, if you update rebuild aliases
+ db, make clean and flush queue
+
+2009-11-08 20:38 gilles
+
+ * forward.c, lka.c, smtpd.h, util.c: first commit of a serie to
+ cleanup, simplify and improve aliases resolution which is
+ probably the most complex code in smtpd right now. no longer use
+ a single list to hold aliases to be resolved and resolved
+ aliases, and do not use struct alias to hold resolved aliases.
+ instead use a delivery list that is a list of struct path, and
+ populate it with resolved aliases.
+
+ idea discussed with jacekm@, this needs some testing to make sure
+ it does not introduce a regression with aliases. flush your queue
+ and make clean.
+
+2009-11-06 00:30 gilles
+
+ * smtp_session.c: evbuffer_readline() assumes end of line to be \r,
+ \n, \r\n, \n\r or \r\r. smtp protocol expects lines to end with
+ \r\n.
+
+ if a client sends a very long line which is unfortunately read up
+ to \r, evbuffer_readline() will return the line, then will detect
+ another line when the buffer is filled again and starts with \n,
+ returning again with an empty line. this is a bug which trigger
+ very rarely and usually shows up as an empty line in the middle
+ of headers, causing all subsequent headers to appear as part of
+ the body to most mail user agents.
+
+ upstream fixes this with evbuffer_readln() in version 2.0 of
+ libevent, a mail will be sent to see if they can backport it,
+ meanwhile we fix it by introducing evbuffer_readln_crlf().
+
+ discussed with and ok jacekm@
+
+2009-11-05 13:26 gilles
+
+ * lka.c: another log_debug() cleanup
+
+2009-11-05 13:24 gilles
+
+ * parse.y: some structures reference the maps they use by their id,
+ if we allow 0 as a valid map id, then we have no way to know for
+ these structures if they have a reference to a map, or if the
+ member was not set. make map id start at 1.
+
+2009-11-05 13:11 jsing
+
+ * dns.c, mta.c: Consider DNS lookups that result in NXDOMAIN to be
+ a permanent failure.
+
+ ok gilles@ jacekm@
+
+2009-11-05 13:08 jsing
+
+ * bounce.c: Include a Date: header in bounce messages.
+
+ ok jacekm@ gilles@
+
+2009-11-05 13:06 gilles
+
+ * lka.c: cleanup a bit the log_debug output
+
+2009-11-05 13:05 jsing
+
+ * bounce.c, dns.c, mta.c: Introduce a 6yz status code, used
+ internally to report permanent errors. The 1yz and 6yz status
+ codes are now removed prior to reporting the status message in
+ bounce messages, which provides an easy way to distinguish
+ between local and remote status messages. Initial diff from
+ jacekm@
+
+ ok gilles@ jacekm@
+
+2009-11-05 13:02 gilles
+
+ * lka.c: - introduce lka_session_destroy() which replaces the splay
+ tree removal and free(lkasession) in lka_expand_rcpt() - while
+ at it, plug a very very unlikely memory leak which i spotted
+ while reviewing the logic
+
+2009-11-05 11:27 gilles
+
+ * lka.c, smtpd.h: - move a couple prototypes in smtpd.h - remove
+ prototypes from deprecated functions
+
+2009-11-04 09:31 jmc
+
+ * makemap.8: tweak previous;
+
+2009-11-04 00:10 gilles
+
+ * makemap.8: document the new -t set mode of makemap, and add a
+ paragraph describing the use of makemap to generate a primary
+ domains map
+
+2009-11-03 23:57 gilles
+
+ * lka.c, makemap.c, map.c, parse.y, ruleset.c, smtpd.h: teach
+ makemap how to build a set, which is a map containing only keys.
+ smtpd is now capable of looking primary domains at runtime in a
+ set, which means that the following becomes possible:
+
+ map "primary" { source db "/etc/mail/primary.db" }
+ accept for domain map "primary" deliver to mbox
+
+ while at it fix a couple bugs in the aliases resolution path
+ which caused recipients to bounce if a ruleset did not have an
+ "accept for local" rule
+
+ "diff reads good" jacekm@, flush queue & make clean
+
+2009-11-03 21:55 gilles
+
+ * aliases.c, lka.c, parse.y, smtpd.h: this commit removes the
+ hardcoded special "aliases" map and brings support for multiple
+ aliases maps that can be attached at the rule level. with it, you
+ can for example define different aliases maps for different
+ domains or different aliases maps for the same domain depending
+ on the client source:
+
+ map "localiases" { source db "/etc/mail/localiases.db" } map
+ "netaliases" { source db "/etc/mail/netaliases.db" }
+
+ accept from 192.168.0.0/16 for local alias "localiases" deliver
+ to mbox accept from all for local alias "netaliases" deliver to
+ mbox
+
+ idea discussed with jacekm@ and various other hackers, diff
+ contains some bug fixes too which were not part of the original
+ diff. man page follows very shortly ... make clean & flush queue
+ !
+
+2009-11-03 20:13 gilles
+
+ * aliases.c, lka.c, ruleset.c, smtpd.h: - remove a useless member
+ of struct cond - have virtual related functions take a map id
+ instead of a map - shrink a tiny bit ruleset matching - add
+ missing lka_resolve_path() call in aliases resolution leading to
+ issues spotted by nicm@
+
+2009-11-03 18:50 gilles
+
+ * ruleset.c: remove annoying log_debug
+
+2009-11-03 12:10 jacekm
+
+ * aliases.c, runner.c, smtpd.c: Improve error logging.
+
+2009-11-03 11:56 nicm
+
+ * lka.c: Don't need regex.h and remove two declarations that are
+ now in smtpd.h.
+
+ ok jacekm
+
+2009-11-01 23:15 gilles
+
+ * queue.c, runner.c: fix a couple log_info()s, from Tim van der
+ Molen <tbvdm@xs4all.nl>
+
+2009-10-25 23:58 gilles
+
+ * smtpd.conf.5: fix aliases map name in man page reported by
+ Emmanuel Vadot and David Hill
+
+2009-10-25 22:50 gilles
+
+ * lka.c: fix the aliases resolution path so that smtpd does not
+ accidentally skip recipients when an alias resolves to more than
+ one.
+
+ issue spotted by martijn@bunix.org
+
+2009-10-25 22:06 gilles
+
+ * smtp.c: tag should also be copied from listener to message when
+ the message is enqueued through smtpctl
+
+2009-10-25 21:43 chl
+
+ * client.c: Fix potential null dereference.
+
+ Found by LLVM/Clang Static Analyzer.
+
+ ok gilles@
+
+2009-10-25 20:46 gilles
+
+ * control.c, parser.c, smtpctl.c: smtpctl reload is work in
+ progress, do not expose it and make sure smtpd's control process
+ does not try to handle it.
+
+ spotted and reported by martijn@bunix.org
+
+2009-10-22 17:02 sobrado
+
+ * smtpctl.8, smtpd.8: write UNIX-domain in a more consistent way;
+ while here, replace a few remaining ".Tn UNIX" macros with ".Ux"
+ ones.
+
+ pointed out by ratchov@, thanks!
+
+ ok jmc@
+
+2009-10-22 14:35 sobrado
+
+ * smtpctl.8, smtpd.8: use the UNIX-related macros (.At and .Ux)
+ where appropriate.
+
+ ok jmc@
+
+2009-10-22 10:22 jmc
+
+ * smtpd.8: pesky full stop, donated by tim van der molen;
+
+2009-10-19 23:19 gilles
+
+ * makemap.8, smtpd.conf.5: update man pages
+
+2009-10-19 23:09 gilles
+
+ * parse.y: change virtual rule so that it reads: accept for virtual
+ "mapname", instead of: accept for virtual map "mapname" ...
+
+ discussed with jacekm@
+
+2009-10-19 22:48 gilles
+
+ * lka.c, parse.y, ruleset.c, smtp_session.c, smtpd.h: currently,
+ smtpd is capable of having multiple listeners with different
+ options but they will all share the same ruleset. this means that
+ there is no way to have a rule apply to a session established on
+ one listener but not applied on another.
+
+ this commit brings initial support for tagging listeners and
+ having the rules able to match these specific listeners. The
+ following will define a rule which will only apply to interfaces
+ tagged as "mynet":
+
+ listen on lo0 # implicit lo0 tag listen on fxp0
+ tag mynet listen on fxp1 tag mynet
+
+ accept on mynet for domain "example.org" deliver to mbox
+
+2009-10-19 22:00 gilles
+
+ * parse.y, smtpd.c, smtpd.h: users within virtual domains do not
+ necessarily map to a real user account, teach smtpd how to
+ deliver using specific user permissions:
+
+ accept for virtual map "foo" deliver to maildir
+ "/m/%d/%u" user foo
+
+ will deliver mail under /m/domain/user as user foo
+
+ idea and initial diff discussed with jacekm@
+
+2009-10-19 21:53 gilles
+
+ * client.c: fix compile time warning due to missing cast
+
+2009-10-18 23:45 gilles
+
+ * lka.c: actually, we want to resolve C_ALL and C_NET, we just
+ don't want to do it when their action is to be relayed.
+
+2009-10-18 22:41 gilles
+
+ * mfa.c: fix a bug that was introduced by my changes in ruleset
+ matching and which caused an envelope to be saved with action
+ A_INVALID when it matches either A_RELAY or A_RELAYVIA.
+
+ reported by various people
+
+2009-10-18 21:53 gilles
+
+ * lka.c: do not attempt to resolve aliases for C_ALL and C_NET
+ destinations
+
+2009-10-17 14:46 sobrado
+
+ * makemap.c: sort flags.
+
+2009-10-17 00:29 gilles
+
+ * smtpd.conf.5: after recent change in virtual maps support
+ smtpd.conf.5 was not fully updated and still referenced the
+ "virtual" map which no longer exists.
+
+ issue spotted by Alexander Hall <alexander@beard.se>
+
+2009-10-17 00:26 gilles
+
+ * lka.c: as of now, "accept for all deliver to mbox" is a valid
+ syntax, sadly lka is not aware of this and will fatal() when it
+ attempts to resolve a recipient for a destination that's not
+ C_DOM or C_VDOM.
+
+ issue reported by Dorian Buettner <dorian.buettner@gmx.de>
+
+2009-10-13 06:53 jmc
+
+ * smtpd.conf.5: sort;
+
+2009-10-13 01:57 gilles
+
+ * aliases.c: trim ending whitespaces in aliases files otherwhise
+ makemap will fail to parse values correctly when ran in aliases
+ mode, and smtpd will fail to parse values correctly when reading
+ an include file
+
+2009-10-13 00:49 gilles
+
+ * smtpd.conf.5: document the new "for virtual map [...]" syntax
+
+2009-10-13 00:34 gilles
+
+ * aliases.c, lka.c, mfa.c, queue.c, runner.c, smtpd.h: - fix a null
+ deref which could happen after a couple iterations of the
+ aliases/virtual domains resolution code.
+
+ - fix a logic bug which caused virtual domains not to be
+ correctly handled after one iteration of the aliases resolution
+ code.
+
+ - introduce a few helper functions to help clean up and simplify
+ the lka code.
+
+ - simplify the IS_EXT/IS_MAILBOX/IS_RELAY macros so they
+ manipulate a struct path * instead of the mess of dereferences
+ we were passing them.
+
+2009-10-12 20:19 gilles
+
+ * makemap.c: to support virtual domains properly, smtpd needed to
+ have the domain stored as a key in the virtual map, which means
+ that to support virtual domain for openbsd.org I would do:
+
+ openbsd.org whatevervalue gilles@openbsd.org
+ gilles
+
+ this commit teaches makemap how to deduce the special domain keys
+ based on the entries for that domain, so that only the second
+ line is needed now.
+
+2009-10-12 20:14 gilles
+
+ * ruleset.c: fix a bug where matching a "for all" rule with
+ multiple condition will not let us know which condition we
+ matched.
+
+2009-10-11 19:40 gilles
+
+ * aliases.c, lka.c, makemap.8, parse.y, ruleset.c, smtpd.h:
+ implement proper virtual domains instead of faking them on top of
+ primary domains. this means that:
+
+ - virtual domains no longer deliver to a local user when not told
+ to - they no longer attempt to resolve aliases when not told to -
+ they no longer need an explicit rule in smtpd.conf for EACH
+ domain - the "virtual" map is no longer hardcoded - smtpd no
+ longer needs a restart to support a new domain
+
+ instead we introduce the: accept for virtual map "mapname" [...]
+ syntax which refers to a map that can be manipulated at runtime.
+
+ idea discussed and okayd with jacekm@
+
+2009-10-07 20:19 gilles
+
+ * mfa.c, smtpd.c: now that mfa no longer does ruleset matching,
+ parent no longer needs to send it the ruleset configuration, and
+ mfa no longer needs to interpret it and load it in memory. kill
+ kill kill. as an added bonus: removes 88 lines of code :-)
+
+2009-10-07 20:09 gilles
+
+ * lka.c, mfa.c, smtpd.h: currently both mfa and lka perform ruleset
+ matching for their own purposes. make lka the only caller of
+ ruleset_match(), mfa request match through imsg which will shrink
+ its code and help me implement virtual domains properly.
+
+ idea discussed with jacekm@
+
+2009-10-07 19:30 gilles
+
+ * lka.c, mfa.c: since the bounce code rewrite, we no longer need to
+ perform ruleset match and aliases resolution on the sender before
+ envelope is written in queue:
+
+ - mfa_test_mail() no longer calls ruleset_match() -
+ lka_verify_mail() no longer resolves sender and set rule action -
+ lka_resolve_mail() becomes dead code so just kill it
+
+ ok jacekm@
+
+2009-10-07 15:29 jacekm
+
+ * ruleset.c: remove noisy log_debug, requested by gilles@
+
+2009-10-06 20:20 gilles
+
+ * smtp_session.c: disallow AUTH once a session is in progress, this
+ prevents a fatal from being triggered in smtp process when client
+ sends AUTH after MAIL.
+
+ bug reported and fix tested by James Turner <james@bsdgroup.org>
+
+2009-10-03 12:02 jacekm
+
+ * client.c: Avoid NULL dereference when the final RCPT TO is
+ refused. Reported by Didier Wiroth <dwiroth@gmail.com>
+
+2009-10-03 09:59 jacekm
+
+ * ssl.c: dont dereference garbage pointer, from martynas@
+
+2009-09-25 15:44 jmc
+
+ * makemap.8, smtpd.conf.5: move the smtpd.conf-specific map bits
+ back from makemap to smtpd.conf, along with some tweakage;
+
+ ok jacekm gilles
+
+2009-09-23 12:26 jmc
+
+ * smtpd.conf.5: minor tweaks for the filter section; ok jacekm
+
+2009-09-23 11:40 jacekm
+
+ * mda.c, smtpd.h: Plug memleak.
+
+2009-09-22 17:44 jacekm
+
+ * client.c: Make the error messages for failures at EHLO more
+ precise by distinguishing between unavailable extensions and
+ those that are available but have failed.
+
+2009-09-22 15:05 jmc
+
+ * makemap.8, smtpd.conf.5: - move the map stuff to makemap.8 - use
+ a single list for smtpd.conf keywords
+
+ ok jacekm gilles
+
+2009-09-22 14:24 jacekm
+
+ * client.c, client.h: When at MAIL FROM stage, handle the case when
+ STARTTLS is required but not available. Also, make the
+ client_next_state() calls across the code more idiomatic.
+
+2009-09-22 10:23 jj
+
+ * ssl.c: fix handling of certificates to unbreak DSA; allows
+ starttls(8) instructions to work with smtpd; ok jacekm@, on
+ behalf of gilles@ who doesnt have access to a safe machine
+
+2009-09-21 22:35 jacekm
+
+ * enqueue.c: Expand "&" in the name part of gecos similarly to how
+ sendmail and finger expand it. Based on a diff from landry@,
+ thanks!
+
+2009-09-21 12:02 jmc
+
+ * smtpd.conf.5: - some tweaks for the global section - syntax fix
+ from gilles
+
+ ok gilles
+
+2009-09-21 09:46 jmc
+
+ * smtpd.conf.5: merge EXPANSION into DESCRIPTION, since it is
+ really part of describing the file format;
+
+ ok jacekm
+
+2009-09-20 21:28 jacekm
+
+ * smtpd.8: Fix typo, noticed by Nava Carson, thanks!
+
+2009-09-19 17:51 jmc
+
+ * smtpd.conf.5: some minor improvements for this page, as well as
+ an expanded examples section to get things running;
+
+ help/ok jacekm gilles
+
+2009-09-18 02:04 jacekm
+
+ * control.c, enqueue.c, smtp.c: Remove useless Received line added
+ at the /usr/sbin/sendmail stage, it was not correctly formatted
+ anyway. Recording of sender uid has been moved to the server
+ process (getpeereid), which means it is not subject to forgery.
+ Based on problem report by Michael Lechtermann
+ <michael@lechtermann.net>
+
+2009-09-18 01:51 jacekm
+
+ * client.c: The client API is meant to require STARTTLS by default,
+ a behaviour which can be altered using client_ssl_optional().
+ Reported by Michael Lechtermann <michael@lechtermann.net>
+
+2009-09-17 16:19 jmc
+
+ * smtpd.8: tweak previous; ok jacekm
+
+2009-09-17 12:42 jacekm
+
+ * smtpd.8: Add instructions for enabling smtpd to the EXAMPLES
+ section. Suggested by sthen@
+
+2009-09-16 22:22 jacekm
+
+ * parse.y: Do not print "could not load cert" warning at startup if
+ certificate is not required. Requested by jmc@, gilles@ ok.
+
+2009-09-16 21:51 jmc
+
+ * smtpd.conf.5: +.Xr mailer.conf 5 , ok jacekm
+
+2009-09-16 17:33 jacekm
+
+ * bounce.c: Free resources when bounce enqueue fails due to a
+ timeout.
+
+2009-09-16 13:46 jacekm
+
+ * enqueue.c: Ignore sendmail's -L, -A, and -q switches: makes
+ clientmqueue cron job exit silently.
+
+2009-09-15 18:50 jacekm
+
+ * bounce.c, client.c, client.h, control.c, enqueue.c, mta.c,
+ queue.c, queue_shared.c, smtpd.h, ssl.c, util.c: Extend SMTP
+ client_* API to support SSL+AUTH, and use it in the mta process
+ to relay mails. ok gilles@
+
+2009-09-15 12:54 jacekm
+
+ * buffer.c, imsg.h: Enclose repeated buffer draining code in a new
+ msgbuf_drain() function, which is additionally exported for use
+ by others.
+
+ It will be needed by smtpd's SSL module when the SMTP client code
+ is changed to replace libevent's evbuffers with our msgbuf_* API.
+
+ ok gilles@ henning@ guenther@ eric@
+
+2009-09-12 14:24 jacekm
+
+ * smtp_session.c, smtpctl.c, smtpd.h: Simplify line len checking:
+ use one limit for all SMTP exchanges. This is not as strict as
+ various RFCs want it, but we can make it more granular later.
+ For now, let all mails flow by using the maximum of all limits
+ found in the RFCs. ok gilles@
+
+2009-09-12 11:50 gilles
+
+ * smtp_session.c: fix a wrong computation in session_readline()
+ where the length of line was deduced from the buffer size prior
+ and after evbuffer_readline() call. the problem is that this
+ accounts for the characters which evbuffer_readline() removed and
+ we do not know how many they were (\n, \r\n ..). fix just does a
+ strlen() call of line which is a bit slower but way safer.
+
+ This could very well fix the broken headers issue some people
+ reported
+
+2009-09-12 11:38 gilles
+
+ * smtp_session.c, smtpctl.c, smtpd.h: cmdlinetoolong stat was
+ incremented at the wrong place, fix
+
+2009-09-12 11:22 gilles
+
+ * smtp_session.c, smtpctl.c, smtpd.h: - fix a compile time warning
+ - add a new stats counter to distinguish between command lines
+ which exceeded the limit and data lines which exceeded the
+ limits
+
+2009-09-12 11:01 gilles
+
+ * smtp_session.c: replace a fwrite || fwrite construct with a
+ fprintf which achieves the same while being less error prone
+
+2009-09-08 11:50 landry
+
+ * mta.c: Cope with remote host sending '452 Insufficient system
+ storage'. Committing on behalf of gilles@ who doesn't have
+ access to a safe box.
+
+2009-09-04 21:11 jacekm
+
+ * runner.c: Fix scheduling of bounces that could not be delivered.
+ ok gilles@
+
+2009-09-04 20:50 jacekm
+
+ * bounce.c: Fix scheduling of bounces that could not be delivered.
+ ok gilles@
+
+2009-09-04 18:28 jacekm
+
+ * mda.c: Prepend Return-Path.
+
+2009-09-04 15:33 jacekm
+
+ * queue_shared.c, runner.c: Fix scheduling of bounce messages.
+
+ From gilles@
+
+2009-09-04 13:53 jacekm
+
+ * store.c: merged with mda.c
+
+2009-09-04 13:49 jacekm
+
+ * mda.c, smtpd.c, smtpd.h: Major mda update: - Fix: check external
+ mda / mail.local exit code. - Fix: check maildir rename(2)
+ return code. - Fix: check read(2) and write(2) return codes. -
+ Fix: in parent, batchp->env was not set to the env of the current
+ process. - Fix: clean file in tmp if maildir delivery fails. -
+ Fix: mark message as temporarily failed upon start, unmark upon
+ sucessful delivery. (safe default) - Fix: kill all message drops,
+ aka. PERMFAILUREs, with one exception: when the local user no
+ longer exists. - Cleanup: store.c is merged with its only user,
+ mda.c - Feature: in parent, child_add now returns pointer to the
+ new child struct. This is used to store and later access
+ child->mda_batch member in order to associate children with their
+ batches. - Feature: in parent, external mda / mail.local will
+ timeout after 5 minutes.
+
+2009-09-04 13:44 jacekm
+
+ * queue_shared.c, runner.c: Fix a crash when messagep->batch_id is
+ read from disk and used long after the batch has ceased to exist.
+
+ From gilles@
+
+2009-09-03 10:19 jacekm
+
+ * control.c, dns.c, lka.c, mda.c, mfa.c, mta.c, queue.c, runner.c,
+ smtp.c, smtpd.c: imsg_get sets errno so use fatal instead of
+ fatalx.
+
+2009-09-02 23:04 jacekm
+
+ * store.c: Prepend Delivered-To, not append. Discussed with
+ gilles@.
+
+2009-09-02 14:47 jacekm
+
+ * mda.c, smtpctl.c, smtpd.h: Include mbox write errors in "show
+ stats". Suggested by gilles.
+
+2009-09-02 13:11 jacekm
+
+ * mda.c: Do not lose mail when write(2) to mbox fails.
+
+2009-09-02 12:00 jacekm
+
+ * store.c: remove dead code, gilles ok
+
+2009-09-01 17:23 jacekm
+
+ * smtp_session.c: Log all 4yz/5yz responses we send when in debug
+ mode; ok gilles@
+
+2009-08-27 13:42 jacekm
+
+ * client.c, client.h: $OpenBSD$
+
+2009-08-27 13:41 jacekm
+
+ * client.c, client.h: Implement client side of the SMTP protocol in
+ a library-like module. Make bounce code and /usr/sbin/sendmail
+ interface use this new API. The mta process continues to use its
+ own implementation, but eventually will be switched to use this
+ shared module.
+
+ Buffer routines are taken from buffer.c rather than from
+ evbuffer. This is one step forward to using a single buffer API
+ across the program.
+
+ "it looks sexy" gilles@
+
+2009-08-27 13:38 jacekm
+
+ * smtpctl.c: s/relayd/smtpd/
+
+2009-08-27 13:37 jacekm
+
+ * bounce.c, enqueue.c, runner.c, smtpd.h: Implement client side of
+ the SMTP protocol in a library-like module. Make bounce code and
+ /usr/sbin/sendmail interface use this new API. The mta process
+ continues to use its own implementation, but eventually will be
+ switched to use this shared module.
+
+ Buffer routines are taken from buffer.c rather than from
+ evbuffer. This is one step forward to using a single buffer API
+ across the program.
+
+ "it looks sexy" gilles@
+
+2009-08-27 11:21 jacekm
+
+ * smtpd.c, smtpd.h, util.c: getpwnam failure that results in
+ setting errno could confuse the check for non-existent
+ ~/.forward, so make the check more robust; fix a fd leak under
+ rare circumstances; use secure_file for testing .forward file
+ security.
+
+2009-08-26 18:40 jacekm
+
+ * mta.c: fix previous
+
+2009-08-26 11:12 jacekm
+
+ * mta.c: Do not add Delivered-To to outgoing mail. It will result
+ in premature bounce as soon as it hits mx2 in mx1 -> mx2 -> mx3
+ relay chain. hint by sthen@, ok gilles@
+
+2009-08-18 20:38 gilles
+
+ * store.c: The end of headers check that is used to determine where
+ to insert our Delivered-To header was wrong and could eventually
+ lead to smtpd adding it too early and making the remaining
+ headers appear as body part to MUAs.
+
+ issue reported by Mathieu Goessens <gebura@poolp.org>
+
+2009-08-12 15:32 jacekm
+
+ * smtp_session.c: Fix unwanted rejects by parsing (and ignoring)
+ AUTH=<...> MAIL command argument. Testers, you want this.
+ Committing on gilles@'s behalf.
+
+2009-08-11 16:46 jacekm
+
+ * runner.c: call reset_flags in bounce_session failure code path.
+
+2009-08-11 16:45 jacekm
+
+ * runner.c: do not repeat flag resetting code, introduce
+ reset_flags(). discussed with gilles
+
+2009-08-09 01:02 gilles
+
+ * mta.c, queue_shared.c: - simplify a bit queue_message_update() -
+ make sure queue_message_update() creates bounces using
+ bounce_record() - when mta sends update to queue and it sees that
+ batch is flagged with F_BATCH_PERMFAIL, only update the
+ envelope error message if it doesn't have F_MESSAGE_PERMFAIL
+ set, otherwise we may lose the real reason why we failed for
+ that recipient. There's cleanup to do around that old code, i'm
+ sure we can get it simpler.
+
+ this commit fixes a bug pea@ spotted where a bounce message would
+ not display the reason of a failure when we generated it after
+ failing to deliver a relayed message.
+
+2009-08-08 21:16 ian
+
+ * smtpctl.c: mailq is a common sendmail alias for showing the
+ queue; make smtpctl implement this, ignoring sendmail options for
+ now. OK gilles@, jackekm@
+
+2009-08-08 20:33 nicm
+
+ * imsg.c: Make imsg_clear close and free any fds in the received fd
+ queue as well as freeing the msgbuf.
+
+ While here also remove an unnecessary while loop.
+
+ ok eric pyr
+
+2009-08-08 02:23 gilles
+
+ * enqueue.c: fix a small typo with no consequence in the generation
+ of message id when an enqueued message follows the offline
+ codepath. the code used ',' to separate components of the message
+ uid when it should have used '.'
+
+2009-08-08 02:18 gilles
+
+ * util.c: missing cast
+
+2009-08-08 02:16 gilles
+
+ * parser.c, smtpctl.c: missing header
+
+2009-08-08 02:02 gilles
+
+ * aliases.c, dns.c, forward.c, lka.c, makemap.c, parser.h,
+ runner.c, smtp_session.c, store.c, util.c: import some changes
+ from portable smtpd to reduce the delta between both. this
+ commit contains mostly missing casts and cosmethic changes, do
+ not expect to build this anywhere but on OpenBSD, it does not
+ contain any of the portable glue.
+
+2009-08-07 23:59 gilles
+
+ * smtp_session.c: smtp_session: ssl/ssl.h -> openssl/ssl.h
+
+2009-08-07 23:47 gilles
+
+ * mta.c: in mta: ssl/ssl.h -> openssl/ssl.h, consistent with other
+ files
+
+2009-08-07 22:21 gilles
+
+ * lka.c, smtp_session.c, smtpd.c: we were linking to libkeynote to
+ use kn_base64_encode/decode, but honestly this was a ugly hack,
+ and i'd rather include resolv.h and use __b64_encode and
+ __b64_decode as openssh does. this commit kills all references to
+ libkeynote in smtpd, should help a bit with porting ... no
+ functionnal change.
+
+2009-08-07 21:02 gilles
+
+ * authenticate.c, smtpd.c, smtpd.h: wrap auth_userokay in a new
+ function authenticate_user() and make sure that only
+ authenticate.c knows about bsd_auth, no functionnal change.
+
+2009-08-06 21:05 gilles
+
+ * mta.c: fix a crash in mta when forwarding a bounce, caused by a
+ null deref
+
+2009-08-06 19:09 gilles
+
+ * smtp_session.c: in smtp_session, fix logging so that when we
+ accepted an empty envelope for the sender, we dont log 'from=<@>'
+ but from=<> instead
+
+2009-08-06 18:46 gilles
+
+ * queue_shared.c, runner.c, smtp.c, smtpd.c, smtpd.h: - change all
+ occurences of T_DAEMON_BATCH,MESSAGE to T_BOUNCE_BATCH/MESSAGE -
+ make sure T_BOUNCE_MESSAGE is no longer OR-ed to
+ T_MDA/MTA_MESSAGE - define F_MESSAGE_BOUNCE flag and make sure
+ bounce sessions set it - teach smtpctl show queue how to
+ recognize a bounce message
+
+2009-08-06 18:29 gilles
+
+ * mta.c, runner.c, store.c: replace X-OpenSMPTD-Loop with
+ Delivered-To
+
+ idea by jacekm@ a few weeks ago, discussed with pyr
+
+2009-08-06 18:26 gilles
+
+ * bounce.c, store.c: when writing a bounce, follow the same rule as
+ for mta sessions and prepend with a dot lines starting with a dot
+
+2009-08-06 16:32 gilles
+
+ * runner.c: when a message in queue expires, generate a bounce
+ before we remove it
+
+2009-08-06 16:27 gilles
+
+ * bounce.c, smtpd.h, store.c: factorize file_copy_session() and
+ file_copy() so file_copy() can handle both deliveries to
+ mailboxes (mbox/maildir) and copying to a session.
+
+2009-08-06 16:16 gilles
+
+ * bounce.c: fix a typo in bounce message t -> to
+
+2009-08-06 16:12 gilles
+
+ * bounce.c, mta.c, runner.c, smtpd.h, util.c: - introduce
+ message_set_errormsg() to set the error description that will
+ appear in a bounce message, and message_get_errormsg() to
+ retrieve that message. - when loop is detected, call
+ message_set_errormsg() - in mta, call message_set_errormsg() for
+ each recipient failure - in mta, call message_set_errormsg() to
+ copy batch errors to recipients if we failed to deliver for a
+ session related error - when bouncing, add the recipient and
+ error reason to the bounce message
+
+2009-08-06 15:40 gilles
+
+ * bounce.c, mda.c, mta.c, queue_shared.c, runner.c, smtp.c,
+ smtpd.c, smtpd.h, store.c: This commit reworks the entire mailer
+ daemon support to actually make it work for real. As an added
+ bonus, it simplifies it, makes it follow the same code path as
+ regular messages and kills quite some code from mta, mda and
+ store. There's still some work needed but the most painful part
+ is behind us now ;)
+
+ ok jacekm@
+
+2009-08-01 17:33 gilles
+
+ * smtp_session.c: when receiving characters with the most
+ significant bit set over a session not flagged with F_8BITMIME,
+ clear the bit instead of permanently erroring the whole message.
+ some mta's do not always request 8BITMIME when they are sending
+ messages which are not 8bit clean, this lets us be less strict
+ for them while not violating RFC ourselves.
+
+ ok jacekm@
+
+2009-07-29 00:03 gilles
+
+ * queue_shared.c, runner.c, smtpd.c, smtpd.h: introduce
+ daemon_record_message() and needed glue in queue_shared.c to
+ atomically create a mailer daemon out of a message. it is
+ unreferenced for now, this commit makes no functional change.
+
+2009-07-28 23:12 jsg
+
+ * smtpd.c: Use strcmp() for string comparison not == ok jacekm@
+
+2009-07-28 22:51 gilles
+
+ * makemap.c: slightly change how makemap parses its lines so that
+ we consider # as a comment only when it starts a line or is
+ preceded by whitespaces.
+
+ fixes a bug that was reported to me twice and which i ran into,
+ ok jacekm@
+
+2009-07-28 15:54 gilles
+
+ * smtpd.c: indent
+
+2009-07-28 15:53 gilles
+
+ * store.c: add missing bit to correctly spot loops in all cases.
+ at the moment we only break out of the loop, but do not generate
+ mailer daemon, this will come soon.
+
+ ok pyr@, tested by me with help from gui at iroqwa dot org
+
+2009-07-23 20:58 eric
+
+ * buffer.c: make buf_write() behave like msgbuf_write(): send out
+ only the bytes that were filled, not the whole buffer.
+
+ ok pyr@ gilles@
+
+2009-07-19 21:06 jacekm
+
+ * smtp_session.c: fix fwrite return code checking. bug exposed by
+ recent change to fwrite, and reported by oga. ok gilles
+
+2009-06-29 12:11 martynas
+
+ * runner.c: since upper-bound is not a power of two here, use
+ arc4random_uniform instead, to avoid modulo bias. ok jacekm@,
+ gilles@
+
+2009-06-26 13:48 okan
+
+ * smtpd.h: locally define nitems() macro, #ifndef'd.
+
+ "please commit" gilles@ jacekm@
+
+2009-06-20 09:46 jacekm
+
+ * mta.c: Allocate memory for env->sc_ssl like in smtp; ok gilles@
+
+ From: Josh Elsasser <josh@elsasser.org>
+
+2009-06-08 10:30 dlg
+
+ * imsg.c: revert this change by eric@:
+
+ Make the imsg protocol network-safe.
+
+ it might be network safe, but half the imsg based daemons on my
+ firewalls dont run anymore.
+
+2009-06-07 07:56 eric
+
+ * control.c, enqueue.c, imsg.c, imsg.h, lka.c, mda.c, mta.c,
+ smtp.c: Change the way fds passed over a socket are retreived on
+ the receiving side.
+
+ Currently the receiver fetches an imsg via imsg_get() and if he
+ expects an fd, he then calls imsg_get_fd() to fetch the next fd
+ queued on the imsgbuf from which the imsg came.
+
+ This changes hides the fd queueing mechanism to the API user.
+ When closing an imsg with an fd, the message is flagged so that
+ the receiving end knows it must dequeue the fd in imsg_get() and
+ return it with the imsg structure. This way there is no (less)
+ possible screw up from imsg_get_fd() not being called directly
+ after imsg_get() by the user. The retreived imsg is
+ self-contained.
+
+ ok pyr@, "I like that" henning@
+
+2009-06-07 02:40 eric
+
+ * imsg.c: Make the imsg protocol network-safe.
+
+ ok pyr@
+
+2009-06-07 00:11 eric
+
+ * imsg.c, imsg.h: change the imsg header fields a bit to prepare
+ for upcoming changes. add a flag field, use u_int32_t for pid_t
+ and extend type to 32 bits for padding.
+
+ ok pyr@
+
+2009-06-06 20:31 pyr
+
+ * smtpd.h: Get ready for including imsg.h from a lib, when it comes
+ along.
+
+2009-06-06 10:55 pyr
+
+ * buffer.c, imsg.c: shuffle code around to achieve 0 length diff
+ nirvana between all the currently synced daemons' imsg.c, imsg.h
+ and buffer.c
+
+2009-06-06 07:04 pyr
+
+ * imsg.c: remove unnecessary and scary pid check in imsg_init. ok
+ eric@, claudio@
+
+2009-06-06 06:14 pyr
+
+ * config.c, control.c, dns.c, imsg.c, imsg.h, lka.c, mda.c, mfa.c,
+ mta.c, queue.c, runner.c, smtp.c, smtp_session.c, smtpctl.c,
+ smtpd.c, smtpd.h: Sync with relayd: Stop pushing event handling
+ in the imsg framework. Instead, provide a small glue layer on
+ top of both imsg and libevent. This finally clearly separates
+ event handling and imsg construction.
+
+ Sidetrack bonus: remove the mega-ugly hack of having a dummy
+ imsg_event_add stub in smtpctl. ok jaceckm@
+
+2009-06-06 05:22 jacekm
+
+ * smtpctl.c: if smtpctl is run in unsupported mode, exit with a
+ warning instead of defaulting to smtpctl-mode; aja@ ok
+
+2009-06-06 01:04 jacekm
+
+ * parse.y, smtpd.conf.5: if path in "deliver to maildir path" is
+ omitted, use ~/Maildir by default; from gilles@
+
+2009-06-05 23:55 jacekm
+
+ * store.c: Remove unneeded function that prepends mail with "From "
+ marker. mail.local(8) does it for us in mbox case, maildir
+ doesn't need this, and in ext. mda case we delegate it to the
+ external program.
+
+ committing on gilles@'s behalf
+
+2009-06-05 23:15 pyr
+
+ * buffer.c, imsg.h: bring buf_write which is going to be needed for
+ bgpd.
+
+2009-06-05 22:43 pyr
+
+ * buffer.c, control.c, dns.c, enqueue.c, imsg.c, imsg.h, lka.c,
+ mda.c, mfa.c, mta.c, queue.c, runner.c, smtp.c, smtp_session.c,
+ smtpd.c, smtpd.h: make smtpd's imsg lib ready, just like relayd
+ and ospfd. ok gilles@, jacekm@
+
+2009-06-05 10:50 pyr
+
+ * smtpd.h: Destroy gilles' fantasy function. ok by a
+ desillusionned gilles@
+
+2009-06-04 00:04 jacekm
+
+ * mda.c, mta.c, runner.c, smtpd.h: simplify struct batch; ok
+ gilles@
+
+2009-06-03 20:16 gilles
+
+ * smtpd.c, smtpd.h: rename sc_config to sc_conffile since that's
+ what this field is about, it will prevent a confusion with
+ sc_config which will be a pointer to the actual configuration.
+
+2009-06-03 18:31 jacekm
+
+ * lka.c: Improve error checking for the secrets encoding function;
+ ok gilles@ Pointed out by giovanni <qgiovanni@gmail.com>
+
+2009-06-03 00:23 gilles
+
+ * config.c, mta.c, parse.y, smtp.c, smtpd.c, smtpd.h, ssl.c: make
+ env->sc_listeners and env->sc_ssl pointers, one step further
+ toward configuration reloading without killing active sessions;
+ ok jacekm@
+
+2009-06-02 01:15 gilles
+
+ * lka.c, mfa.c: yet another cleanup in mfa/lka, don't roll their
+ own loops to release maps and rules when config.c provides us
+ with purge_config(), PURGE_MAPS and PURGE_RULES. kills lots of
+ lines with no functionnal change. ok jacekm@
+
+2009-06-02 00:51 gilles
+
+ * lka.c, mfa.c, ruleset.c: add new file ruleset.c with code related
+ to the ruleset matching, and kill the two or three "almost"
+ identical versions of ruleset matching loops from lka and mfa by
+ having one unified function in ruleset.c; ok jacekm@
+
+ while at it, bring maildir support back to life; trivial
+ one-liner by me
+
+2009-06-01 23:19 gilles
+
+ * lka.c: propagate the recipient domain through aliases expansion,
+ this fixes a bug that would trigger when smtpd.conf does not have
+ an "accept for local" rule and we attempt to deliver to a domain
+ for which we are a destination.
+
+ spotted by jacekm@, fix by me and ok jacekm@
+
+2009-06-01 20:24 deraadt
+
+ * lka.c, smtpd.c, smtpd.h, util.c: No need for save_getpwuid and
+ such functions which call endpwent. endpwent is not needed
+ unless setpwent (with stayopen = 1) or getpwent was used.
+ getpwuid/getpwnam do not use getpwent; i think people must be
+ assuming this. we are going to improve the man pages for this.
+ ok gilles
+
+2009-06-01 20:02 jacekm
+
+ * ssl.c: fix function name in log_debug
+
+2009-06-01 16:53 gilles
+
+ * smtp_session.c: display ssl negociation information in the
+ received line of incoming sessions; ok jacekm@
+
+2009-06-01 16:38 jacekm
+
+ * smtp.c: Don't destroy listening socket when pause/resume request
+ is received, use event_del/event_add instead; ok gilles@
+
+2009-06-01 15:20 jacekm
+
+ * control.c, dns.c, lka.c, mda.c, mfa.c, mta.c, queue.c, runner.c,
+ smtp.c, smtpd.c: Fix EV_READ/EV_WRITE testing inside IMSG
+ handlers. Based on similar change to the routing daemons by
+ claudio@; ok gilles@
+
+2009-05-31 20:34 gilles
+
+ * mta.c, smtp_session.c: when entering mta_connect() reset session
+ fd to -1 when connect timesout and we close the fd, reset session
+ fd to -1 in session_destroy(), only attempt to close session fd
+ if != -1
+
+ fixes a fatal in session_destroy() which happened because we
+ closed a fd after a timeout, but the session still assumed the fd
+ to be opened.
+
+2009-05-31 01:53 gilles
+
+ * makemap.c, mta.c, parse.y, smtpd.c, smtpd.conf.5, smtpd.h, ssl.c:
+ It is now possible to specify a certificate to use when relaying
+ to another host which requests client certificates:
+
+ accept [...] relay via [...] ssl certificate "mycert"
+
+ diff from Josh Elsasser <josh@elsasser.org>, tested and okayed by
+ me with no change but the addition of status 554 to the state
+ machine to deal with remote host telling us it doesn't like our
+ certificate.
+
+2009-05-31 01:28 gilles
+
+ * smtpd.c: fatal on setsockopt() failures
+
+2009-05-30 18:32 gilles
+
+ * mta.c: increment mta.sessions in when we allocate a new session
+ in mta
+
+2009-05-30 18:30 gilles
+
+ * mta.c, smtpctl.c: - increment stats.mta.sessions_active when
+ session is allocated in mta - reorder alphabetically and add mta
+ to the statistics
+
+2009-05-30 18:22 gilles
+
+ * smtp_session.c: fix a bug where sessions_active counter, used to
+ compute accept limits, was decremented below 0 after the recent
+ change that moved stats to shared mmap memory. session_destroy()
+ which is called from mta and smtp processes didnt differentiate
+ between them and decremented the counter when we had outgoing
+ sessions destroyed.
+
+2009-05-28 10:50 jacekm
+
+ * smtp_session.c, smtpd.h: Log the incoming message size; ok
+ gilles@
+
+2009-05-28 10:48 jacekm
+
+ * smtp_session.c: Log the "for <foo@bar.com>" part in the Received
+ field; ok gilles@
+
+2009-05-28 10:43 jacekm
+
+ * smtpd.conf.5: Match SMTPAUTH documentation with reality; ok
+ gilles@
+
+2009-05-27 18:51 jacekm
+
+ * parse.y: temporary fix to a ruleset processing bug that stems
+ from the fact that the ip address/subnet parsing isn't done in
+ the same way as in other daemons.
+
+ fix by gilles@
+
+2009-05-27 15:14 jacekm
+
+ * mta.c, smtp_session.c, store.c: Insert Received: at receive time
+ instead of delivery time; ok gilles@
+
+2009-05-27 15:11 jacekm
+
+ * smtp_session.c, smtpd.h: After a successful AUTH command
+ completes, reject any further AUTH commands.
+
+ ok gilles@
+
+2009-05-27 15:09 jacekm
+
+ * smtp_session.c, smtpctl.c, smtpd.h: request flood mitigation: 1)
+ each state may have 2 responses sent quickly; 2) more responses
+ are delayed exponentially, up to a defined limit.
+
+ Delay count is user visible (smtp.errors.delays).
+
+ ok gilles@
+
+2009-05-25 16:00 jacekm
+
+ * smtp.c, smtpd.c, smtpd.h: merge smtp_listener_setup into its only
+ caller; ok gilles@
+
+2009-05-25 15:29 jacekm
+
+ * smtp_session.c: Recent event masking scheme change turned the
+ S_GREETED and S_HELO cases in session_pickup into unreached code,
+ so remove them; ok gilles@
+
+2009-05-25 13:17 jacekm
+
+ * control.c, enqueue.c: Disallow submission using
+ /usr/sbin/sendmail while the server is paused, configuring, or
+ exiting; ok gilles@
+
+2009-05-24 17:47 jacekm
+
+ * smtp.c, smtp_session.c, smtpd.c, smtpd.h: Parent process
+ shouldn't be base64-decoding untrusted strings, move this code to
+ privsep smtp process; ok gilles@
+
+2009-05-24 16:58 jacekm
+
+ * smtp_session.c: Implement pipelining detection inside
+ session_readline, makes the calling code cleaner; ok gilles@
+
+2009-05-24 16:38 jacekm
+
+ * config.c, control.c, lka.c, mda.c, mfa.c, mta.c, queue.c,
+ runner.c, smtp.c, smtpd.c, smtpd.h: Parent process forks 3 types
+ of processes, track them all in a single tree using newly
+ introduced child struct.
+
+ Manage process titles centrally in struct smtpd.
+
+ ok gilles@
+
+2009-05-24 16:22 jacekm
+
+ * control.c, queue.c, runner.c, smtp.c, smtp_session.c, smtpctl.c,
+ smtpd.c, smtpd.h, ssl.c: Instead of keeping stats private to each
+ process, and querying every process individually whenever stats
+ need to be fetched, keep stats in MAP_ANON shared memory
+ allocated by parent.
+
+ This means control has direct access to stats and can respond
+ very quickly without troubling any other daemon processes.
+
+ ok gilles@
+
+2009-05-21 03:27 gilles
+
+ * parse.y: no longer create a dynamic map with 127.0.0.1 and ::1
+ for every single rule that has an implicit local source. instead
+ we create static "localhost" map before the configuration file is
+ parsed, we fill it with every single local address we can find,
+ and we have rules with implicit local source reference that
+ special map.
+
+ this unbreaks a behavior which I hated and which prevented:
+
+ accept for all relay
+
+ from accepting relaying if LOCAL session was initiated on any
+ interface but lo0.
+
+2009-05-21 03:07 gilles
+
+ * mfa.c: fix sockaddr_storage lenght check in mfa_check_source()
+
+2009-05-20 18:12 jacekm
+
+ * smtp_session.c: Delay enabling of EV_READ until S_INIT (smtps) or
+ S_TLS (starttls). ok gilles@
+
+2009-05-20 18:07 gilles
+
+ * control.c, lka.c, mfa.c, smtpd.c: previous commit to add reload
+ support was missing some code, this diffs contains the missing
+ parts + a memleak plug
+
+2009-05-20 16:36 gilles
+
+ * lka.c, mfa.c: replace a TAILQ_FOREACH loop with a TAILQ_FIRST
+ loop when releasing entries of the tailq, this is how it must be
+ done.
+
+2009-05-20 16:29 gilles
+
+ * control.c, lka.c, mfa.c, parse.y, smtp.c, smtp_session.c,
+ smtpd.c, smtpd.h: first step towards configuration reload in
+ smtpd, smtpctl reload will parse the configuration file again and
+ replace current configuration with new one in all processes. what
+ we don't support yet is graceful restart, clients in sessions at
+ the moment of the reload will have a temp failure thrown at 'em
+ which is ok RFC-wise but which we will try to improve anyway.
+
+ tested with various setups, "diff reads good" jacekm@
+
+2009-05-20 13:58 gilles
+
+ * smtpctl.c: fix a pasto causing "smtpctl resume mta" to try to
+ resume mda spotted and diff by giovanni <qgiovanni@gmail.com>
+
+2009-05-20 00:54 gilles
+
+ * smtpd.c: ever since we switched from delivering to mboxes
+ ourselves to using the mail.local(8) utility,
+ parent_mailbox_init() has become useless, do not call it from
+ parent_mailbox_open() anymore, and kill it.
+
+ this fixes a bug which we were many to spot and which would cause
+ smtpd to create a file /var/mail/%u upon first delivery to a
+ mbox, then leave it there forever untouched.
+
+2009-05-20 00:41 gilles
+
+ * ssl.c: remove useless check on NULL ssl cert and key, the check
+ cannot be reached as we would exit earlier if either one is NULL.
+
+ diff by giovanni <qgiovanni@gmail.com>, had been sitting in my
+ mbox for a while, okayed by jacek and I
+
+2009-05-19 14:33 jacekm
+
+ * smtp_session.c: Accept STARTTLS only after EHLO; ok gilles@
+
+2009-05-19 13:42 jacekm
+
+ * smtp_session.c, smtpd.h: - Don't advertise nor accept STARTTLS
+ command when session is secure. - Make the condition when
+ STARTTLS and AUTH are advertised & accepted more readable.
+
+ ok gilles@
+
+2009-05-19 13:37 jacekm
+
+ * smtpd.c, smtpd.h: Do not ever run /usr/sbin/sendmail, it could
+ link to sendmail interface for a different MTA. Use the binary in
+ /usr/libexec directly instead.
+
+ Based on remark claudio@ made in passing.
+
+ ok gilles@
+
+2009-05-19 13:24 jacekm
+
+ * control.c, lka.c, mda.c, mfa.c, mta.c, queue.c, runner.c, smtp.c,
+ smtpd.c, smtpd.h: Verify the amount of IMSG payload is exactly as
+ expected; ok gilles@
+
+2009-05-18 22:23 jacekm
+
+ * smtp.c, smtp_session.c, smtpctl.c, smtpd.h, ssl.c: Complete
+ rework of bufferevent event masking allowing for more
+ strictness: - Drop clients attempting command pipelining;
+ protects the daemon from all kinds of abuse. - Replace
+ F_EVLOCKED flag with F_WRITEONLY which has cleaner sematics: when
+ up, session must not be destroyed nor read from, but may be
+ written to. - Write callback becomes a central place for
+ enabling EV_READ. - Delay bufferevent creation until after ssl
+ handshake is completed.
+
+ A bunch of session error stats were added to smtpctl's "show
+ stats". These could help spotting event masking errors in the
+ future.
+
+ ok gilles@
+
+2009-05-14 17:05 eric
+
+ * control.c, enqueue.c, lka.c, mda.c, mfa.c, mta.c, queue.c,
+ runner.c, smtp.c, smtp_session.c, smtpd.c: use the nitems() macro
+ where appropriate
+
+ ok gilles@, jacekm@
+
+2009-05-14 10:29 jacekm
+
+ * smtp_session.c: correct function name in fatal
+
+2009-05-13 23:29 jacekm
+
+ * mta.c: do MX lookups in both "relay" and "relay via" case; ok
+ gilles@
+
+2009-05-13 23:20 jacekm
+
+ * aliases.c, map.c: log dbopen and db->get errors; based on diff
+ from Daniel Ouellet. looks ok to gilles@
+
+2009-05-10 16:24 jacekm
+
+ * smtp_session.c: use both read and write timeout arguments in the
+ bufferevent_settimeout call; ok gilles@
+
+2009-05-10 15:06 jacekm
+
+ * smtp_session.c: use rfc number 4954 in auth_plain handler name,
+ rfc 4616 is implied because rfc 4954 references it.
+
+2009-05-10 13:29 jacekm
+
+ * makemap.c, queue_shared.c, runner.c, smtp.c, smtp_session.c,
+ smtpd.c, smtpd.conf.5, util.c: assert copyright; ok gilles@
+
+2009-05-10 13:23 jacekm
+
+ * smtp_session.c: RFC 4954 says the response to "AUTH PLAIN" must
+ be "334 ", not "334"; ok gilles@
+
+2009-05-10 01:23 jacekm
+
+ * smtp_session.c: correct AUTH PLAIN rfc number, no functional
+ change.
+
+2009-05-09 22:04 jacekm
+
+ * control.c: fix rare memleak; ok gilles@
+
+2009-05-09 22:03 jacekm
+
+ * smtp_session.c, smtpd.h: give few states more meaningful names;
+ ok gilles@
+
+2009-05-09 20:59 jacekm
+
+ * smtp.c, smtp_session.c: fix function names in log_debug
+
+2009-05-09 19:04 jacekm
+
+ * dns.c, lka.c, mta.c, smtp.c, smtpd.h: - New API to handle all DNS
+ query types (A, MX, PTR) asynchronously.
+
+ - Improve RFC compliance: CNAMEs are resolved, equal preference
+ MXs are randomized, relaying via MX that has equal/lower
+ preference than local server is prevented, decision on when to
+ treat domain name as implicit MX is better.
+
+ ok gilles@
+
+2009-05-01 23:44 gilles
+
+ * lka.c: initialize secret to NULL otherwise we may try to free a
+ junk pointer when F_AUTH is not set. i was going to look into the
+ issue, but i have received a diff from Simon Betrang
+ <janus@errornet.de>, thanks !
+
+2009-04-29 01:11 gilles
+
+ * lka.c, mfa.c, smtpd.h: smtp auth happened to work by luck because
+ delivery to mbox action was the first action of an enum and we
+ allocated a struct using calloc, but we did not properly
+ initialize the action for authenticated users.
+
+ while at it, change the name of path action flags so that we know
+ at first sight that they are path related.
+
+ this diff fixes the immediate issue but still needs work. ok
+ jacekm@, "we'll work out a long term solution"
+
+2009-04-29 00:38 jacekm
+
+ * lka.c, smtp.c: fix a bug where client with unresolvable revdns is
+ never greeted; ok gilles@
+
+2009-04-28 23:56 jacekm
+
+ * smtp_session.c: don't use strlcpy before calling a function that
+ uses strlcpy internally anyway; ok gilles@
+
+2009-04-28 23:56 gilles
+
+ * mta.c: in mta, change the batch status to S_BATCH_TEMPFAILURE by
+ default so that we need to explicitely set success and permanent
+ failures, this way if we hit any condition that we don't
+ explicitely flag as permanent failure the delivery will be
+ rescheduled later.
+
+ while at it, made various checks more strict to prevent hiding
+ bugs and a bit of knr cleanups
+
+ discussed with and "reads good" jacekm@
+
+2009-04-28 23:55 jacekm
+
+ * smtp.c, smtp_session.c: make S_DATAREQUEST state similar to
+ S_{MAIL,RCPT}REQUEST; ok gilles@
+
+2009-04-28 23:27 jacekm
+
+ * mda.c, mfa.c, mta.c: let mta, mda, and mfa become idle - no
+ functional change; ok gilles@
+
+2009-04-27 22:17 jacekm
+
+ * smtp_session.c: kill 2-line session_msg_submit, used just once;
+ ok gilles@ long ago.
+
+2009-04-27 18:22 jacekm
+
+ * smtp.c: fix unlikely fd leak; ok gilles@
+
+2009-04-27 18:20 jacekm
+
+ * smtp_session.c: session_cleanup call in MAIL FROM handler may be
+ removed as a consequence of rev. 1.70. This makes session_destroy
+ the only caller so merge the two; ok gilles@
+
+2009-04-27 18:15 jacekm
+
+ * mfa.c: check message_id received from smtp uses valid format.
+
+2009-04-27 18:10 jacekm
+
+ * smtp_session.c: Disable EV_READ when setting F_QUIT flag up.
+ Malicious client may send more commands after QUIT, these must
+ not be processed; ok gilles@
+
+2009-04-26 21:55 gilles
+
+ * ssl_privsep.c: sync with changes in relayd, diff by reyk@ and
+ okayd by me
+
+2009-04-24 17:26 jacekm
+
+ * smtp_session.c: in session_pickup, do not handle S_RCPT state, it
+ must never be called in this state; ok gilles@
+
+2009-04-24 12:02 jacekm
+
+ * aliases.c, makemap.c, smtpd.h, util.c: Make aliases
+ case-insensitive, issue reported by Daniel Ouelett; ok gilles@
+
+2009-04-24 11:38 jacekm
+
+ * smtp.c, smtp_session.c: Enclose common imsg handling code in a
+ function, which additionally does some sanity checking. Fix a bug
+ that could lead to fatal under rare circumstances, exposed by
+ this newly added check; ok gilles@
+
+2009-04-24 10:35 jacekm
+
+ * smtp.c, smtp_session.c, smtpd.h: use same timeout at each session
+ state, and make use of bufferevent_settimeout instead of rolling
+ our own; ok gilles@
+
+2009-04-24 10:32 jacekm
+
+ * mfa.c, smtp_session.c, smtpd.h: kill unnecessary struct
+ message_recipient; ok gilles@
+
+2009-04-23 10:28 jacekm
+
+ * smtpctl.c: sort "show stats" output
+
+2009-04-21 20:39 jacekm
+
+ * runner.c, smtpd.c: small corrections to log_warns and fatals
+
+2009-04-21 20:12 jacekm
+
+ * enqueue.c, runner.c, smtpctl.c, smtpd.c, smtpd.h: Make
+ /usr/sbin/sendmail not fail due to smtpd being down.
+
+ The approach is to save cmdline + stdin in a file under a newly
+ added directory /var/spool/smtpd/offline (uid 0 gid 0 mode 1777).
+ Next time daemon starts, it uses information in that directory
+ to replay sendmail on user's behalf.
+
+ ok gilles@
+
+2009-04-21 16:37 eric
+
+ * control.c, lka.c, mda.c, mfa.c, mta.c, queue.c, runner.c, smtp.c,
+ smtpd.c: correct some fatal(x) calls and error strings
+
+ ok gilles@ jacekm@
+
+2009-04-20 20:48 jacekm
+
+ * smtp_session.c: Allow MAIL FROM only in the S_HELO state, which
+ results in behaviour dictated by rfc in "4.1.4 Order of
+ commands".
+
+ pointed out and initial diff by pea@, ok gilles@
+
+2009-04-20 19:40 jacekm
+
+ * smtp_session.c: fix previous, evtimer_set should be called only
+ once, in session_init.
+
+2009-04-20 19:07 jacekm
+
+ * smtp.c, smtp_session.c, smtpctl.c, smtpd.h: Rewrite smtp session
+ timeouts; use evtimer_* from event(3) instead of regularly
+ walking session tree in search of idle clients. Gives the smtp
+ process a chance to become idle.
+
+ As a bonus, add smtp.sessions.timeout counter to "smtpctl show
+ stats".
+
+ ok gilles@
+
+2009-04-19 14:48 jacekm
+
+ * smtp_session.c: Wrap the EV_READ+EVLOCKED dance in one well
+ documented function. Additionally, check that EVLOCKED is not
+ already set, which would indicate an attempt to send IMSG w/o
+ waiting for reply for some other IMSG sent earlier.
+
+ ok gilles@
+
+2009-04-19 14:42 jacekm
+
+ * queue_shared.c: error checking for readdir(2); ok gilles@
+
+2009-04-18 23:13 jacekm
+
+ * runner.c: correct function name in fatal
+
+2009-04-18 23:01 jacekm
+
+ * queue.c: remove dead code; made possible by previous commit.
+
+2009-04-17 18:26 jacekm
+
+ * enqueue.c: handle case when no input is provided, fixes confusing
+ error:
+
+ $ echo -n | sendmail root sendmail: write: connection closed $
+
+2009-04-16 22:13 sobrado
+
+ * newaliases.8: fix a few more typos found by spell(1); rectify a
+ double "with" pointed out by jmc@ while looking at this diff.
+
+ ok jmc@, reyk@ (for the hostapd part)
+
+2009-04-16 17:35 jacekm
+
+ * control.c, enqueue.c, mfa.c, queue.c, smtp.c, smtp_session.c,
+ smtpctl.c, smtpd.h: Total rewrite of the sendmail interface. Adds
+ support for -t, -v, and -F cmdline args. Also, date and
+ Message-Id headers are added when missing.
+
+ The main trouble with the current enqueue code is that it
+ requires dealing with problems in the control process that are
+ already solved in the smtp process, ie. duplicating a lot of code
+ which interacts with untrusted clients. This diff solves this by
+ making sendmail obtain a SMTP socket from smtp via smtpd.sock,
+ and using that socket to deliver the message. For smtpd it looks
+ as if connection was made from the network, only difference being
+ the F_MESSAGE_ENQUEUED message flag, handy when differentation
+ between local and remote deliveries is wanted.
+
+ Most of the features come from the femail program, created by
+ henning@.
+
+ Additional testing by Nigel J. Taylor.
+
+ ok gilles@, henning@ happy with smtpd using femail code
+
+2009-04-15 22:36 jacekm
+
+ * smtpd.c: don't call setproctitle for parent, at least one process
+ should display cmdline arguments the daemon was started with; ok
+ gilles@
+
+2009-04-15 22:34 jacekm
+
+ * smtpctl.c, smtpd.h, ssl.c: s/ssmtp/smtps/; ok gilles@
+
+2009-04-15 22:02 jacekm
+
+ * mta.c: fix a bug where after all MX-es were found to be
+ non-contactable, smtpd would treat the delivery as successful; ok
+ gilles@
+
+2009-04-12 18:03 gilles
+
+ * parse.y: Code assumed the certificate name to always match the
+ interface name, even when a certificate name was explicitely
+ provided. This would cause imsg to fatal() because with some
+ configurations, it would look for the wrong name in the ssl tree
+ and would fail to find the proper cert.
+
+ issue spotted by Gregory Edigarov <gregory.edigarov@gmail.com>, I
+ found the fix just a few minutes ago when I succeeded to
+ reproduce the issue...
+
+2009-04-12 17:42 gilles
+
+ * runner.c: When runner_check_loop() detects a mail loop, remove
+ the envelope. This is only half of the problem solved, we need to
+ generate a mailer daemon too. This fixes a bug in my smtpd where
+ it would try to schedule a message, detect that it is a loop and
+ not schedule it, then trying again at next queue walk ...
+
+2009-04-12 14:33 gilles
+
+ * queue_shared.c: when an error occurs while delivering a message
+ with an empty envelope as a sender, do not try to generate a
+ mailer daemon message for it.
+
+ fixes a crash experienced by sthen@ that I could reproduce
+
+2009-04-10 07:35 jmc
+
+ * smtpd.conf.5: tweaks;
+
+2009-04-09 22:32 jacekm
+
+ * smtpd.conf.5: make the manpage fairly complete, contains bits
+ from jmc@
+
+2009-04-09 22:19 todd
+
+ * smtp_session.c: fixes for smtp auth LOGIN, inspired from smtp
+ auth PLAIN fixes (NUL terminate buffers, duh!) with suggestions
+ from oga@ "please commit" jacekm@, ok gilles@ oga@
+
+2009-04-09 21:49 jacekm
+
+ * lka.c, mta.c, parse.y, smtp.c, smtp_session.c, smtpd.h, ssl.c:
+ change syntax of the "listen on" and "relay via" directives: 1)
+ kill the ssmtp keyword in "ssmtp listen on ..."; 2) kill the use
+ keyword in "... use certificate foo"; 3) tls no longer implicit,
+ user must explicitely use the tls or smtps option. 4) for "relay
+ via", move the tls/smtps options to right after the port
+ specification; makes it similar to "listen on".
+
+ These directives:
+
+ ssmtp listen on fxp0 use ceritifate "foo"
+ accept for all relay via tls "mx.bar.com"
+
+ now become:
+
+ listen on fxp0 smtps certificate "foo"
+ accept for all relay via "mx.bar.com" tls
+
+ ok gilles@
+
+2009-04-05 18:33 gilles
+
+ * lka.c: log_warn -> log_warnx
+
+2009-04-05 18:10 gilles
+
+ * enqueue.c: ignore -o option (for now at least) when working in
+ enqueue mode, this prevents smtpctl from choking and allows it to
+ work with more mua's by default.
+
+ spotted and added to my todo list by oga@
+
+2009-04-03 07:20 oga
+
+ * smtpd.c: The smtp auth PLAIN specification is weird. It's valid
+ (apparently for imap, mostly) to provide
+ "username1\0real_username\0password" as your base64 encoded
+ string for authentication. We currently don't handle that,
+ instead expecting the first byte to be a NUL. So fix that up by
+ scanning for the first string, and ignoring it if it's there. The
+ string is also stupid in that the last bit (password) may not be
+ NUL terminated, so pay attention to that in our decoding and make
+ sure that it's always terminated correctly.
+
+ It's been discussed, and this decoding really should happen in
+ the unauthenticated process, not in the privileged one, but that
+ is another diff.
+
+ Problem found by todd@, who kindly helped me debug this and
+ confirmed that it now works with kmail, mutt and thunderbird.
+
+ "if it makes more stuff work, please commit" jacekm@.
+
+ -0- - not a smtpd hacker and I resent your implication.
+
+2009-03-31 23:03 tobias
+
+ * parse.y: Fixed memory leaks which would occur if the second of
+ two memory allocations fails.
+
+ looks right deraadt, krw ok henning
+
+2009-03-29 16:18 jacekm
+
+ * control.c, lka.c, mda.c, mfa.c, mta.c, queue.c, runner.c, smtp.c,
+ smtpd.c: turn some log_debugs into log_warns or even fatals;
+ "looks ok" gilles@
+
+2009-03-23 22:48 jmc
+
+ * makemap.8, newaliases.8, smtpctl.8, smtpctl.c, smtpd.8: various
+ minor improvements; ok jacekm gilles
+
+2009-03-23 09:25 tobias
+
+ * mda.c: Fixed a leaking of a fd each time a file is delivered to a
+ mbox, which was introduced in revision 1.7.
+
+ ok and log message by gilles
+
+2009-03-22 23:53 gilles
+
+ * lka.c, runner.c, smtpd.c, smtpd.h: fix a bug in the resolution of
+ forward files which would cause usernames not to be taken into
+ account if they had no ~/.forward file AND were the result of an
+ alias expansion that expanded to more than one username.
+
+ while at it, I spotted another bug where I would check
+ T_MDA_MESSAGE on the flags field instead of the type field. the
+ bug could cause two MDA message to end up in the same batch which
+ is no longer valid.
+
+2009-03-22 14:52 ian
+
+ * smtpctl.c: trivial message repair, ok jacek@
+
+2009-03-20 10:34 gilles
+
+ * lka.c: initialize variable before using it as a counter in a loop
+
+ spotted and fix by Matthew Haub
+ <matthew.haub@alumni.adelaide.edu.au>
+
+2009-03-19 23:03 jacekm
+
+ * makemap.c: since maps may contain secrets, carry ownership and
+ perms from source file to db file; ok gilles@
+
+2009-03-19 21:27 jacekm
+
+ * smtpd.h: make action_type == 0 mean A_INVALID, not A_RELAY; ok
+ gilles@
+
+2009-03-19 01:40 gilles
+
+ * parse.y: when listen was declared without a port parameter, it
+ would get it wrong because of a missing htons()
+
+2009-03-19 01:12 gilles
+
+ * mta.c: in the event of a timeout, mxhost is passed to
+ TAILQ_REMOVE before it is initialized. spotted and diff by
+ Matthew Haub <matthew.haub@alumni.adelaide.edu.au>
+
+2009-03-19 00:51 gilles
+
+ * mta.c: remove debug X-Cipher and turn it into a useful log_info()
+
+2009-03-18 15:48 gilles
+
+ * control.c: previous commit removed "else" condition
+
+2009-03-18 11:29 gilles
+
+ * runner.c: we can no longer create batches of MDA deliveries, so
+ make sure runner does not do a batch lookup when dealing with a
+ MDA message
+
+2009-03-18 02:56 jacekm
+
+ * Makefile: unbreak make release, spotted by todd and kurt
+
+2009-03-18 01:07 gilles
+
+ * mta.c: in mta, when remote host advertises AUTH, do not attempt
+ to authenticate unless we do have F_AUTH set on the mxhost (which
+ means we explicitely mentionned authentication in config) and we
+ did find credentials in the secrets map. issue and initial diff
+ from Rivo Nurges <rix@estpak.ee>
+
+2009-03-17 01:18 gilles
+
+ * smtpd.conf.5: update a bit, but more work is needed on this man
+ page, working on it and will commit an up to date version
+ tomorrow
+
+2009-03-17 01:00 gilles
+
+ * smtpd.conf: move smtpd.conf to etc/mail/ directory. it is not
+ installed yet by the build
+
+2009-03-17 00:40 gilles
+
+ * smtpd.conf: change smtpd.conf to what it will be by default: -
+ only listen on lo0 - support aliases - accept mail for
+ "localhost" and the system hostname - accept relaying mail for
+ all domains
+
+2009-03-17 00:26 gilles
+
+ * parse.y: in accept rules, support "for local" as a destination
+ which is an alias to "localhost" and system hostname. this allows
+ us to ship with a config file that goes: accept for local
+ deliver to mbox , and which will allow us to have mail working
+ sanely out of the box.
+
+2009-03-16 23:40 gilles
+
+ * smtpctl.8: update smtpctl.8 with new smtpctl commands
+
+2009-03-16 22:15 gilles
+
+ * newaliases.8: - mention /etc/mail/virtual in FILES section
+
+2009-03-16 21:43 gilles
+
+ * makemap.8: mention /etc/mail/secrets in the FILES section
+
+2009-03-16 21:39 gilles
+
+ * ARCHITECTURE: this file has been deprecated for a while and will
+ not be updated, so lets just remove it as some people may believe
+ it actually describes the architecture ...
+
+2009-03-15 20:32 gilles
+
+ * smtp.c, smtp_session.c, smtpctl.c, smtpd.h, ssl.c: since we are
+ going to share code in smtp sessions and mta sessions, we need to
+ also share the statistics structure, still being worked on
+
+2009-03-15 20:15 gilles
+
+ * mda.c, mta.c, runner.c, smtpd.h, store.c: the mda process no
+ longer uses struct batch as its central structure to deal with
+ deliveries, it now uses struct session just like mta and smtp
+ processes. we now keep the mbox and message descriptors in the
+ session, saving space in struct message which is now as small as
+ we can make it. While at it, plugged a memory leak and did some
+ cosmethic changes
+
+ This was the last planned change to our struct message which
+ means that later changes will no longer require a queue flush
+ before rebuild.
+
+2009-03-15 19:12 gilles
+
+ * smtp.c, smtp_session.c, smtpd.h: save 4 bytes per message by
+ moving the datafp field of struct message to struct session where
+ it really belongs.
+
+2009-03-12 12:08 pea
+
+ * mta.c, smtpd.h, store.c, util.c: Add new function time_to_text to
+ correctly display the date. Use it to display the date in
+ received from header and when we store headers.
+
+ ok jacekm@
+
+2009-03-11 12:11 pea
+
+ * lka.c: getmxbyname() returning a value != 0 does not necessarily
+ means it failed
+
+ ok gilles@
+
+2009-03-11 10:58 gilles
+
+ * smtp_session.c: fix log_info(), while other processes know about
+ message uid, the smtp process only knows about message id
+
+ bug spotted by pea@
+
+2009-03-10 23:33 jacekm
+
+ * mda.c, mta.c, smtp_session.c, smtpd.h: implement basic logging,
+ needs more work; ok gilles@
+
+2009-03-10 22:14 jacekm
+
+ * smtpd.c: when calling external mda, use restricted environment;
+ ok gilles@
+
+2009-03-10 20:13 jacekm
+
+ * smtpd.c: run external mda with cwd set to $HOME or /; ok gilles@
+
+2009-03-10 20:09 jacekm
+
+ * smtpd.c: kill few lines, saving one seteuid(2) call; ok gilles@
+
+2009-03-10 19:44 jacekm
+
+ * smtpd.c: - Use setsid(2) to create new process group for external
+ mda. - Unignore SIGPIPE, otherwise it remains ignored in forked
+ mda. - Use closefrom(2) to close all descriptors apart from
+ stdin/stdout/stderr.
+
+ ok gilles@
+
+2009-03-10 14:05 jacekm
+
+ * smtpd.c: it's simpler to use pipe(2) than socketpair(2) to
+ communicate with external mda; ok gilles@
+
+2009-03-10 11:01 jacekm
+
+ * smtpd.c: fork(2) or socketpair(2) failures are temporary,
+ delivery attempt should be retried later; ok gilles@
+
+2009-03-10 02:25 jacekm
+
+ * util.c: ascribe copyright to code taken from OpenSSH, pointed out
+ by deraadt
+
+2009-03-10 00:35 jacekm
+
+ * smtpd.c, smtpd.h, util.c: run external mda directly, not via sh
+ -c; this steals addargs() API from OpenSSH; ok gilles@
+
+2009-03-09 17:31 jacekm
+
+ * lka.c, makemap.c, smtpd.h: Drop ALIAS_TEXT, plain maps got
+ implemented in a different way; ok gilles@
+
+2009-03-09 12:29 jacekm
+
+ * queue_shared.c: add hunk that should have been included in rev.
+ 1.12, fixes occasional crash; ok gilles@
+
+2009-03-09 02:43 gilles
+
+ * lka.c, mta.c, parse.y, runner.c, smtpd.conf, smtpd.h: add basic
+ support for outgoing authentication (AUTH PLAIN over ssl) which
+ can be turned on by adding "enable auth" to a "relay via" rule.
+ this made me rework the mx resolution so that it is done by the
+ mta process and not the runner process anymore.
+
+2009-03-08 22:51 gilles
+
+ * smtpd.conf: adapt example to reflect a recent change in parse.y
+
+2009-03-08 22:50 gilles
+
+ * parse.y: supporting delivery to a mbox that's not in
+ _PATH_MAILDIR is not supported, if someone comes with good
+ rationale why this is needed, we'll consider it, meanwhile it's
+ more work than it looks like and it brings a lot of pain.
+
+ discussed with jacekm@ and deraadt@
+
+2009-03-08 21:39 gilles
+
+ * control.c, smtpd.h: when operating in enqueue mode, it was easy
+ to make smtpctl fatal() by writing a small app that sent out of
+ order imsg's. prevent this by use of a state machine and read
+ event masking.
+
+ issue spotted by jacekm@, temporary fix by me. there are ideas
+ around this, but we want to experiment them a bit and they are
+ low priority.
+
+2009-03-08 20:11 gilles
+
+ * mfa.c, smtp_session.c, smtpd.h: shrink struct message a bit by
+ removing a couple fields which are no longer used and by moving
+ the rcpt count in struct session where it really belongs
+
+ while at it, remove some unused splay tree generation in mfa
+
+2009-03-08 18:54 gilles
+
+ * lka.c, mfa.c, smtpd.c, smtpd.h: ~/.forward files handling was
+ fixed recently so that it is the privileged process that does the
+ opening, this commit does some cleanup, and fixes a bug I
+ experienced today which was caused by a use-after-free.
+
+ I did some testing to make sure a user cannot cause smtpd to
+ deadlock, or loop, with broken setups (self-referencing
+ forwards/aliases, empty files, broken files...), but if you are
+ playing with aliases/forwards PLEASE let me know of any bug you
+ run into.
+
+2009-03-07 00:45 gilles
+
+ * smtpd.h: missing prototype
+
+2009-03-07 00:38 gilles
+
+ * map.c: introduce map_dblookup() which allows us to query db maps
+ for plain entries and catch (and warn) about invalid map types.
+
+2009-03-07 00:32 gilles
+
+ * makemap.c: make_plain() deals with a c-string, val->size should
+ contain the nul-byte or we will truncate the last character of
+ every value we store in a map.
+
+2009-03-07 00:29 gilles
+
+ * makemap.c: fix a bug in the generation of plain maps which would
+ cause the value not to be correctly inserted into the map.
+
+2009-03-04 01:00 gilles
+
+ * lka.c, smtpd.c: plug a memory leak, remove lka session from the
+ the lka session tree when we are done expanding aliases/forwards,
+ and cleanup a bit the expansion code so that I can soon remove
+ some of the duplication.
+
+2009-03-04 00:33 gilles
+
+ * lka.c, smtpd.h: when forwards/aliases expansion fails in an lka
+ session, make sure that mfa is notified so that the session does
+ not hang
+
+2009-03-04 00:23 gilles
+
+ * forward.c, lka.c, smtpd.c, smtpd.h: Fix a long standing issue
+ where ~/.forward files were opened by user _smtpd causing them
+ not to be handled when a user's homedir is set to mode 0700. I
+ still need to do some cleanup and make sure it works as it
+ should, but this diff provides better behavior than what we had.
+
+2009-03-03 16:47 gilles
+
+ * smtpd.c, smtpd.h, store.c: fix mbox locking by having it done by
+ mail.local(8) which in turns uses lockspool(1). this means our
+ mbox delivery follows a code path that has become almost
+ identical to external mda deliveries. this is the first of a
+ serie of diffs actually...
+
+ lockspool(1) suggestion by deraadt@, mail.local(8) idea by
+ jacekm@, and fix and testing by me
+
+2009-03-01 22:58 jacekm
+
+ * smtpd.c, smtpd.h, util.c: - Refuse delivery to mbox that is a
+ symlink, pipe, chardev, etc. etc. - Introduce secure_file, based
+ on secure_filename from OpenSSH, it checks that mbox has right
+ perms, and that path components are trustworthy, too.
+
+ ok gilles@
+
+2009-03-01 22:36 jacekm
+
+ * smtpd.c: open mbox with O_EXLOCK (better than open+flock), and
+ without O_SYNC, since fsync is done in final safe_fclose; ok
+ gilles@
+
+2009-03-01 16:06 jacekm
+
+ * smtpd.c: fix possible NULL dereference when getpwnam fails; ok
+ gilles@
+
+2009-03-01 14:08 jacekm
+
+ * smtpd.c: make the condition under which delivery is made by
+ SMTPD_USER more explicit; ok gilles@
+
+2009-03-01 14:07 jacekm
+
+ * smtpd.c: simplify *_open functions by passing them char * instead
+ of struct path *; ok gilles@
+
+2009-03-01 14:05 jacekm
+
+ * control.c: deny regular users to run "smtpctl show stats" and
+ "smtpctl schedule"; ok gilles@
+
+2009-03-01 13:12 jacekm
+
+ * queue.c, smtpctl.c, smtpd.h: In "smtpctl show stats", break
+ queue.inserts into queue.inserts.remote and queue.inserts.local;
+ ok gilles@
+
+2009-03-01 13:10 jacekm
+
+ * enqueue.c: ss_len was set to sizeof pointer, should be sizeof
+ structure; ok gilles@
+
+2009-02-25 10:30 gilles
+
+ * control.c: NULL pointer dereference spotted by Matthew Haub
+ <matthew.haub@alumni.adelaide.edu.au>
+
+2009-02-25 10:08 jacekm
+
+ * smtpd.c: remove chown's called when running with user privs, ie.
+ basically noops; ok gilles@
+
+2009-02-24 22:40 jacekm
+
+ * lka.c: fix tilde expansion (eg. ~/Mail); ok gilles@
+
+2009-02-24 13:07 gilles
+
+ * control.c, parser.c, parser.h, queue_shared.c, runner.c,
+ smtpctl.c, smtpd.h, util.c: teach smtpctl's parser how to deal
+ with parameters that are not necessarily a token so that it is
+ possible to do: smtpctl schedule <message id/uid>
+
+ introduce F_MESSAGE_FORCESCHEDULE which lets the runner schedule
+ a message even if the retry delay has not been expired.
+
+ F_MESSAGE_ENQUEUED is a valid flag for a message and should not
+ cause an\ errx() in smtpctl show queue
+
+2009-02-23 23:59 gilles
+
+ * smtpd.h, util.c: add valid_message_id() and valid_message_uid()
+ which test that a message id and uid do not look wrong. this was
+ not needed earlier because we only deal with message id's coming
+ from trusted sources, but smtpctl will soon have a new feature
+ which requires us to deal with user provided message id's.
+
+2009-02-23 01:51 chl
+
+ * queue_shared.c, smtp.c, smtpd.c, store.c: add missing headers
+ needed by time()
+
+ ok jacekm@ gilles@
+
+2009-02-23 00:29 jacekm
+
+ * queue_shared.c, runner.c: Fix race possible between runner and
+ queue when starting up. runner_reset_flags would attempt to
+ update envelope, but its envelope.tmp could be renamed by
+ queue_purge. The fix is to store envelope.tmp in a place no other
+ process writes to, and /queue/envelope.tmp is perfect for this.
+
+ ok gilles@
+
+2009-02-23 00:21 jacekm
+
+ * lka.c: reorganize code so that couple of indentation levels can
+ be removed; ok gilles@
+
+2009-02-22 20:07 chl
+
+ * control.c, lka.c, mda.c, mfa.c, mta.c, queue.c, smtp.c: add
+ missing headers
+
+ ok gilles@
+
+2009-02-22 12:59 jacekm
+
+ * mta.c, smtp_session.c, smtpd.h, util.c: put repeated inet_ntop
+ calls into new func ss_to_text, which uses getnameinfo
+ internally; ok gilles@
+
+2009-02-22 12:55 jacekm
+
+ * queue_shared.c: simplify qwalk() error handling; ok gilles@
+
+2009-02-22 12:44 form
+
+ * control.c, dns.c, enqueue.c, forward.c, lka.c, makemap.c, mta.c,
+ parse.y, queue_shared.c, runner.c, smtp.c, smtpd.c, util.c:
+ replace MAX* constants by sizeof where possible
+
+ ok jacekm@
+
+2009-02-20 19:47 jacekm
+
+ * queue.c: purge /enqueue at startup; ok gilles@
+
+2009-02-20 16:27 pea
+
+ * mta.c: Fix "Received: from" headers
+
+ ok gilles@
+
+2009-02-19 12:33 jacekm
+
+ * smtp_session.c, smtpd.h: don't let libevent buffer long lines
+ forever; ok gilles@
+
+2009-02-18 23:39 jacekm
+
+ * mfa.c, smtpd.h, util.c: - add basic syntax checking to mfa -
+ decline source routing at MAIL FROM, strip at RCPT TO
+
+ ok gilles@
+
+2009-02-18 17:42 jacekm
+
+ * mfa.c: IMSG_MFA_RCPT handlers are almost identical, put common
+ code in new mfa_test_rcpt; ok gilles@
+
+2009-02-18 13:06 jacekm
+
+ * lka.c: fix compiler warning; ok gilles@
+
+2009-02-18 01:29 gilles
+
+ * smtp.c, smtp_session.c: previous commit was incomplete, this
+ fixes ssmtp
+
+2009-02-18 01:17 gilles
+
+ * smtp.c, smtp_session.c: smtp_accept() now requests from lka that
+ it performs the hostname lookup and inserts the session into the
+ session tree. session_init() is called only when we receive the
+ resolution answer.
+
+ this fixes a race condition that would sometimes cause the
+ hostname to appear as "<unknown>" in headers just because dns was
+ lagging, and it unbreaks ssmtp support which suffered from th
+ very same race condition.
+
+2009-02-18 00:50 jacekm
+
+ * makemap.c: - flock input file while the database is being built -
+ make newaliases finish with short summary
+
+ ok gilles@
+
+2009-02-18 00:46 jacekm
+
+ * makemap.8, newaliases.8: sync makemap man page with the code.
+ create separate page for newaliases which points at makemap as
+ the preferred utility; ok gilles@
+
+2009-02-18 00:43 jacekm
+
+ * makemap.c, smtpd.h: make newaliases read aliases path from
+ smtpd.conf; idea discussed with gilles@, pyr@ and henning@, diff
+ ok gilles@.
+
+2009-02-17 23:49 jacekm
+
+ * control.c, smtpctl.c: imsg_init depends on ibuf being calloc'd.
+ fix few places where malloc is used instead; ok gilles@
+
+ Problem made visible by malloc.conf = AFGJ, and pointed out by
+ otto@
+
+2009-02-17 23:15 jacekm
+
+ * lka.c: kill unused func lka_resolve_rcpt()
+
+2009-02-17 22:53 gilles
+
+ * smtp.c, smtp_session.c: after a message has been commited to
+ queue, do not incondtionnally clear the message id and uid
+ immediately. only do it if session has been flagged with F_QUIT,
+ otherwise session_pickup() will do it when in state S_DONE.
+
+ this fixes a bug reported by pea@ where the message id was not
+ displayed in the "message accepted for delivery" line.
+
+2009-02-17 22:38 gilles
+
+ * mfa.c: - remove two debug messages
+
+2009-02-16 13:10 jacekm
+
+ * config.c: Process which connects with a pool of cloned processes
+ needs to keep open all pipes going in their direction; ok pyr@
+
+2009-02-16 11:15 jacekm
+
+ * queue_shared.c: Don't warn about F_MESSAGE_SCHEDULED flag being
+ present in on-disk version of the envelope; ok gilles@
+
+2009-02-15 14:44 jacekm
+
+ * queue_shared.c: kill local vars that are used only once; ok
+ gilles@
+
+2009-02-15 14:12 jacekm
+
+ * dns.c, lka.c, smtpd.h: If MX query fails due to DNS error, do not
+ attempt more queries; ok gilles@
+
+2009-02-15 11:32 jacekm
+
+ * config.c, control.c, lka.c, mda.c, mfa.c, mta.c, queue.c,
+ runner.c, smtp.c, smtpd.c, smtpd.h: New config.c that allows for
+ process cloning. Done by pyr@ for relayd at n2k9, and adapted to
+ smtpd; ok gilles@
+
+2009-02-15 10:58 jacekm
+
+ * dns.c: Fix a bug where list of 6 MXs or more was not handled
+ correctly. Pointed out by & ok sthen@, ok gilles@.
+
+2009-02-14 19:37 jacekm
+
+ * makemap.8, makemap.c, smtpd.h: Implement makemap -t and -o, for
+ output type and dest resp.; ok gilles@
+
+2009-02-14 18:49 jacekm
+
+ * runner.c: Initialize time_t now as necessary, fixes delivery
+ rescheduling; ok gilles@
+
+2009-02-14 01:00 jacekm
+
+ * queue_shared.c: Display envelope status & flags in "show queue";
+ ok gilles@
+
+2009-02-14 00:54 jacekm
+
+ * lka.c: Fix a crash in lka caused by wrong assumption that we
+ would never exceed MXARRAYSIZE * 2 addresses.
+
+ Commited on behalf of gilles@ who hasn't got access to a safe box
+ at the moment.
+
+2009-02-13 21:44 jacekm
+
+ * smtpctl.c: Make stats output more sysctl-like by killing spaces
+ around '='; ok gilles@
+
+2009-02-13 20:59 jacekm
+
+ * smtp_session.c: Ensure ss is never dereferenced when NULL. Can't
+ happen with current code, but it could in future, and fatal is
+ better than segv. Reported by sthen@. ok gilles@ sthen@
+
+2009-02-05 22:25 gilles
+
+ * ssl.c: when calling ssl_session_destroy() from mta, our session
+ will have a NULL s->s_l field. this commit fixes a crash in mta
+ caused by a NULL deref.
+
+2009-01-30 22:52 gilles
+
+ * smtp_session.c, smtpctl.c, smtpd.h, ssl.c: when decreasing ssl
+ related counters, make sure the session was flagged as F_SECURE.
+ while at it, add "smtp.sessions.aborted" which keeps track of
+ sessions which were interrupted before completion.
+
+2009-01-30 22:40 gilles
+
+ * smtp.c, smtp_session.c, smtpctl.c, smtpd.h, ssl.c: improve
+ statistics for smtp process. not only collect the current
+ sessions count, but also the total sessions count, ssmtp sessions
+ (both current and total) and starttls sessions (both current and
+ total)
+
+ # ./smtpctl/smtpctl show stats|grep smtp.sessions smtp.sessions =
+ 0 smtp.sessions.active = 0 smtp.sessions.ssmtp = 0
+ smtp.sessions.ssmtp.active = 0 smtp.sessions.starttls = 0
+ smtp.sessions.starttls.active = 0 #
+
+2009-01-30 22:22 gilles
+
+ * smtp.c, smtp_session.c, smtpctl.c, smtpd.h: clear the F_EVLOCK
+ flag earlier to prevent the error event handler from being called
+ again with F_EVLOCK set. this fixes a bug where disconnect after
+ smtpd sends greeting and before entering any command failed to go
+ into session_destroy().
+
+ while at it, rename the "smtp.clients" statistic to
+ "smtp.sessions" and add counters to struct s_smtp so that I can
+ add ssmtp and starttls with my next commit ;)
+
+2009-01-30 21:11 form
+
+ * smtpd.h, store.c: Do not break header for messages received via
+ smtp.
+
+ look ok gilles@
+
+2009-01-30 18:34 gilles
+
+ * smtp.c, smtp_session.c, smtpd.c, smtpd.h: bump descriptors limit
+ to the max and set the maximum connections count to three
+ quarters of that limit (a session typically has 3 descriptors).
+ when we hit that limit, we stop accepting connections, and when
+ client closes a session, we start accepting connections again.
+ this prevents us from going into a session that is likely to fail
+ because of scarce resources.
+
+ idea discussed with jacekm@, code mostly ripped from relayd
+
+2009-01-30 17:37 gilles
+
+ * queue_shared.c, smtp.c, smtp_session.c, smtpd.h: fix a very
+ annoying events masking issue which would cause a fatal() to be
+ hit under certain conditions; while tracking the bug I ran into
+ other bugs which were kind of related and could cause us to hit a
+ fatal() too.
+
+ fix by me, but with lots of testing and investigation with
+ jacekm@, ok jacekm@
+
+2009-01-30 11:09 form
+
+ * parse.y: more const -> sizeof() no binary changes
+
+ ok gilles@
+
+2009-01-30 11:03 form
+
+ * smtpd.c: fix debug message
+
+ ok gilles@
+
+2009-01-30 07:19 form
+
+ * aliases.c: o remove useless `if's o replace constants by sizeof
+ where possible
+
+ ok gilles@
+
+2009-01-29 23:34 jacekm
+
+ * smtpctl.c: fix compiler warning
+
+2009-01-29 22:59 jacekm
+
+ * control.c, parser.c, parser.h, queue.c, runner.c, smtp.c,
+ smtp_session.c, smtpctl.c, smtpd.c, smtpd.h: Implement "smtpctl
+ show stats"; ok gilles@
+
+2009-01-29 22:50 form
+
+ * forward.c: better parsing of .forward files
+
+ ok gilles@
+
+2009-01-29 16:40 gilles
+
+ * mta.c, smtp_session.c, smtpd.h: missing prototype for
+ session_respond() in mta, move session_respond()'s prototype to
+ smtpd.h spotted and diff from Oleg Safiullin <form@pdp-11.org.ru>
+
+2009-01-29 16:27 gilles
+
+ * smtp_session.c: - remove debug message
+
+2009-01-29 16:20 gilles
+
+ * enqueue.c, mta.c, smtp_session.c, smtpd.h, store.c: Received
+ header line was incomplete for mail submitted through the
+ enqueuer as well as for some outgoing messages, this is fixed now
+
+2009-01-29 15:50 gilles
+
+ * mta.c: fix a bug in mta's event masking
+
+2009-01-29 15:25 gilles
+
+ * mta.c, smtpd.h, ssl.c: initial starttls support in mta, this
+ allows:
+
+ accept for domain "openbsd.org" relay via tls
+ "mx.example.org"
+
+ to ensure the relaying of mail for whoever@openbsd.org will
+ happen through a secure tls (STARTTLS) session. failure to
+ establish a tls session will be considered as a permanent
+ failure. As a side effect:
+
+ accept for domain "openbsd.org" relay via ssl
+ "mx.example.org"
+
+ can now work as well and ensure that the relaying happens through
+ ssmtp OR tls, but never through an unsafe channel. no need to
+ specify a port, they are automatically detected if not specified.
+
+ still a work in progress, don't expect that it will work
+ flawlessly.
+
+2009-01-29 14:00 gilles
+
+ * mta.c, smtpd.h, ssl.c: bring initial support for SSL in the mta
+ part of smtpd, allowing for:
+
+ accept for domain "openbsd.org" relay via ssmtp
+ "mx1.example.org"
+
+ to ensure that deliveries for whatever@openbsd.org goes through
+ an SSL session to mx1.example.org
+
+2009-01-29 13:43 jacekm
+
+ * queue.c, queue_shared.c, runner.c, showqueue.c, smtpctl.c,
+ smtpd.h: Common queue walking code for smtpd and smtpctl. Kills
+ majority of showqueue.c, the remaining code was moved to
+ queue_shared.c; ok gilles@
+
+2009-01-29 11:18 gilles
+
+ * enqueue.c: - remove a very annoying debug printf()
+
+2009-01-29 00:46 gilles
+
+ * mta.c: fix missing prototype and format related warnings
+
+2009-01-29 00:38 gilles
+
+ * mta.c: now that mta uses a struct session, it can also use
+ session_respond() just as smtp_session.c does, so move all of the
+ evbuffer_add_printf() calls out of the way and replace them with
+ session_respond() call.
+
+2009-01-29 00:13 gilles
+
+ * mta.c, smtpd.h: mta session state belongs to struct session, not
+ struct batch, remove the state field from struct batch and
+ propagate the change
+
+2009-01-28 23:54 gilles
+
+ * mta.c, smtpd.h: everything we need for the event handling dance
+ is in struct session, the write handler has been changed to set
+ the bufferevent that's in there rather than the one in struct
+ batch. since struct batch is no longer doing anything useful for
+ events handling, we can remove many fields of it.
+
+2009-01-28 23:27 gilles
+
+ * mta.c: since we're expanding "relay via ssl foobar.org" into two
+ mxhosts (one with F_SSMTP on port 465 and one with F_STARTTLS on
+ port 25) both mxhosts should only retain the flag that they will
+ use ("via ssl" means the mxhost before expansion has both flags
+ set). this will make mta_connect() simpler when we bring ssl
+ support in the way.
+
+2009-01-28 22:44 gilles
+
+ * mta.c, parse.y, smtpd.h: first steps towards better mta code.
+ currently mta uses struct batch to store a lot of its session
+ related code, but this is just not right and this commit starts
+ making mta code aware of struct session. This will ease the
+ implementation of ssl sessions in mta.
+
+ while at it, make mta autodetect port to use if it isn't provided
+ in a rule but can be derived from a parameter (i.e: "relay via
+ ssmtp ...").
+
+2009-01-28 20:49 jacekm
+
+ * enqueue.c: cleanup; ok gilles@
+
+2009-01-28 20:38 gilles
+
+ * smtp.c, smtpd.c, smtpd.h: when pausing listeners, do not simply
+ disable their events as new clients would still be able to
+ connect. instead, at pause time we close and remove the
+ listeners, and at resume time we request the parent to
+ reconfigure all listeners.
+
+ discussed with pyr@
+
+2009-01-28 19:10 jacekm
+
+ * smtp_session.c: reuse recipient_to_path; ok gilles@
+
+2009-01-28 18:43 gilles
+
+ * lka.c, runner.c: relayhost flags were not properly copied to the
+ relayhost array of the batch we're handing over to mta. this
+ prevented mta from knowing if a session has to be established
+ over ssl or not.
+
+2009-01-28 18:29 jacekm
+
+ * queue.c, queue_shared.c, runner.c, smtp_session.c, smtpd.h: Make
+ races between queue and runner impossible by implementing the
+ policy: 1) queue never reads /queue. 2) queue writes to /queue
+ only at message injection time. 3) runner does all reading, and
+ all writing apart from 2).
+
+ ok gilles@
+
+2009-01-28 15:15 gilles
+
+ * enqueue.c: if recipient was provided as a username, append the
+ local hostname, this unbreaks:
+
+ $ echo foo | mail gilles send-mail: invalid recipient address.
+
+2009-01-28 14:29 gilles
+
+ * mta.c, runner.c, smtpd.h: bring loop detection support. we handle
+ this with a qmail-like approach which consists of checking
+ headers for a custom header, but we also count how many hops the
+ mail went through and use a hard limit (currently set to 100 as
+ was recommanded by RFC) as a safe-guard.
+
+ idea discussed with jacekm@, qmail approach suggested by claudio@
+ a long time ago
+
+2009-01-28 13:58 gilles
+
+ * queue.c, queue_shared.c, smtpd.h: move some functions from
+ queue.c to queue_shared.c as they are not only used by queue
+ process but also by runner, while at it change the prototype of
+ queue_open_message_file() so it takes the message id and not a
+ batch, runner process requires the decriptor before it even
+ starts building a batch.
+
+2009-01-28 13:56 jacekm
+
+ * util.c: in safe_fclose, ensure file is closed upon return, and
+ additionally signify temp failure to the caller if ferror is
+ true; ok gilles@
+
+2009-01-28 13:28 jacekm
+
+ * store.c: ">From" escaping and \n appending is not needed for
+ maildir; ok gilles@
+
+2009-01-28 12:27 gilles
+
+ * aliases.c, enqueue.c, mta.c, queue.c, queue_shared.c,
+ smtp_session.c, smtpd.h: add a struct path to struct message so
+ that we can keep track of the RCPT provided recipient even after
+ aliases/forwards expansion, we'll need this for loop detection.
+
+ message id and uid being MAXPATHLEN long is a waste, define
+ MAX_ID_SIZE which is currently set to 64 (but can probably be
+ further reduced) and make sure that structures and the few
+ strlcpy's use the right define.
+
+ original idea by jacekm@ a while ago
+
+2009-01-28 01:19 gilles
+
+ * enqueue.c: a bit of enqueue cleanup, and while at it set the
+ sender local address to ::1 (fallback to 127.0.0.1) before
+ sending the enqueue request.
+
+2009-01-28 01:09 gilles
+
+ * enqueue.c: - remove debug messages
+
+2009-01-28 00:39 gilles
+
+ * control.c: instead of relying on socket permissions to allow or
+ disallow imsg's that come from the external process
+ (smtpctl/send-mail/etc...), make the socket world-writeable and
+ request credentials with getpeereid().
+
+ discussed with pyr@ who was happy to hand me over UNP opened at
+ the "passing credentials through a unix socket" page, but
+ hopefully saved by dlg@ who knew about getpeereid() :-) cvs:
+ ----------------------------------------------------------------------
+ cvs: eNTER lOG. lINES BEGINNING WITH `cvs:' ARE REMOVED
+ AUTOMATICALLY cvs: cvs: cOMMITTING IN . cvs: cvs: mODIFIED
+ fILES: cvs: CONTROL.C PARSE.Y SMTP.C SMTPD.C SMTPD.H STORE.C
+
+2009-01-27 23:54 gilles
+
+ * queue_shared.c, sharedqueue.c: follow the naming convention of
+ other files, discussed with jacekm@
+
+2009-01-27 23:48 gilles
+
+ * control.c, enqueue.c, mda.c, mfa.c, queue.c, runner.c,
+ sharedqueue.c, smtpctl.c, smtpd.h, util.c: first bricks of
+ enqueue code which allows smtpctl to submit mail to queue without
+ "talking" smtp to listeners. currently, a big part of the server
+ side code is done (and requires a cleanup), next step is to get
+ it usable properly from a mail user agent.
+
+2009-01-27 16:57 gilles
+
+ * util.c: err, actually session_set_path was moved to utils.c
+ because it was used by the enqueue code i'm working on, but this
+ is no longer necessary since the enqueue code uses
+ recipient_to_path. revert part of previous commit
+
+2009-01-27 16:50 gilles
+
+ * util.c: [no log message]
+
+2009-01-27 15:32 gilles
+
+ * control.c: the data member of ibuf was not set to the environment
+ in control_accept() which caused th ev_arg member of struct event
+ to be reset after the first call to control_dispatch_ext (causing
+ a null deref at second call). this has been driving me nuts for
+ at least an hour ...
+
+2009-01-27 12:42 gilles
+
+ * smtpd.c: temporarily drop privileges to the final user before
+ each delivery attempt, wether it is maildir, mbox or external
+ mda. rearrange a bit of code to also simplify most delivery
+ methods by moving their common code to common place.
+
+ while at it change some mode_t to int where it was wrongly used
+ and unlink temporary maildir file if we fail to deliver for some
+ reason.
+
+ discussed with and ok jacek@
+
+2009-01-26 23:20 gilles
+
+ * queue.c, sharedqueue.c, smtpd.h: move some queue related
+ functions that are needed outside of smtpd to the sharedqueue.c
+ file, smtpctl cannot link queue.o without creating a mess
+ otherwise. while at it, move some prototypes to smtpd.h as they
+ will be needed by enqueue code
+
+2009-01-26 22:26 gilles
+
+ * queue.c: we had a set of functions to deal specifically with
+ incoming messages and we need the same functions for the enqueue
+ code i'm currently working on. instead of duplicating the code,
+ add a set of functions which take the queue we're working on as a
+ parameter and turn the old ones into wrappers. no functionnal
+ change ... yet
+
+ discussed with jacekm@
+
+2009-01-21 01:00 jacekm
+
+ * smtpd.c: temporary quick fix to an issue that needs more
+ thinking; ok gilles@
+
+2009-01-15 00:48 gilles
+
+ * smtpd.h: live testing shows that some clients will not even send
+ EHLO if banner does not contain ESMTP. Now that we support some
+ extensions, let's just say that we are ESMTP ...
+
+2009-01-15 00:36 gilles
+
+ * parse.y: slightly change "relay via" so that it can differentiate
+ "ssmtp", "tls" and "ssl" while providing mta with the
+ informations it needs to do its work.
+
+2009-01-14 23:41 gilles
+
+ * store.c: - simplify file_copy() and teach it how to write in
+ mboxrd format
+
+2009-01-12 20:56 jacekm
+
+ * mta.c, smtp_session.c: dot escaping, as required by rfc; ok
+ gilles@
+
+2009-01-12 20:54 jacekm
+
+ * queue.c: more checks in queue_record_incoming_envelope; ok
+ gilles@
+
+2009-01-11 00:54 gilles
+
+ * smtpd.c: - remove a comment that was no longer relevant - when
+ authenticating user, instead of doing a getpwnam() and checking
+ the passwd field, issue a call to auth_userokay(), this will
+ allow the use of login scripts to implement custom
+ authentications without bloating smtpd.
+
+2009-01-08 20:17 jacekm
+
+ * forward.c, lka.c, smtpd.c, smtpd.h, util.c: ensure getpwnam is
+ always followed by endpwent; ok gilles@ henning@
+
+2009-01-08 20:15 jacekm
+
+ * runner.c: clear processing flags early so that there's never
+ doubt whether they belong to previous or current smtpd instance;
+ ok gilles@
+
+2009-01-07 01:26 gilles
+
+ * aliases.c, forward.c, lka.c: - when performing aliases expansion,
+ do not forget to set an action to each expanded envelope, orelse
+ they will use the default action and be passed to MTA no matter
+ if recipient is local or not. bug reported by Nicholas
+ Marriott <nicholas.marriott@gmail.com>, fixed by me and
+ okayd by jacekm@, collaborative work ;-)
+
+2009-01-07 00:12 gilles
+
+ * lka.c: - do not perform a local user lookup, that includes alias
+ expansion, when a recipient is ... not a local recipient (bug
+ introduced very recently). Fix by Nicholas Marriott
+ <nicholas.marriott@gmail.com>
+
+2009-01-07 00:02 jacekm
+
+ * runner.c: rework /queue traversal; ok gilles@
+
+2009-01-06 21:17 jacekm
+
+ * queue.c, runner.c: make file update in queue_update_envelope
+ atomic; ok gilles@
+
+2009-01-04 23:35 gilles
+
+ * control.c, parser.c, parser.h, runner.c, smtp.c, smtpctl.c,
+ smtpd.h: - smtp can now pause/resume the accepting of incoming
+ messages - smtpctl recognizes "pause incoming" and "resume
+ incoming" - setup imsg communication between control process and
+ smtp process
+
+2009-01-04 23:18 gilles
+
+ * runner.c: - remove runstates global, we don't need it actually.
+ - while at it, move the runner states check a bit earlier.
+
+2009-01-04 21:52 gilles
+
+ * runner.c: make sure runner resets scheduling related flags on
+ envelopes when the queue is processed for the first time since a
+ (re)start. this ensures that deliveries scheduling can recover
+ properly in case of a badly timed shutdown.
+
+ ok jacekm@
+
+2009-01-04 20:37 gilles
+
+ * control.c, parser.c, parser.h, runner.c, smtpctl.c, smtpd.h: -
+ runner is now capable of pausing/resuming the scheduling of
+ deliveries for both mda and mta batches. - smtpctl can be used
+ to disable/enable deliveries at runtime using the pause/resume
+ commands.
+
+ ok jacekm@
+
+2009-01-04 20:26 jacekm
+
+ * runner.c: remove unnecessary "messagep->retry == 255" expiry
+ condition; ok gilles@
+
+2009-01-04 20:25 jacekm
+
+ * runner.c, smtpd.h: kill F_MESSAGE_EXPIRED; ok gilles@
+
+2009-01-04 20:23 jacekm
+
+ * runner.c: fix bug where runner would expire message that is being
+ delivered, leading to double unlink on envelope file; ok gilles@
+
+2009-01-04 18:45 gilles
+
+ * lka.c, mfa.c, smtpd.h, util.c: When matching a recipient domain
+ to a rule, do not use strcasecmp, but use new hostname_match()
+ function which recognizes * as a wildcard. We can now do: accept
+ for domain "*.example.org" to match all subdomains.
+
+ idea from Nicholas Marriott <nicholas.marriott@gmail.com>,
+ hostname_match() from me in place of his fnmatch() calls.
+
+ ok jacekm@
+
+2009-01-04 17:40 gilles
+
+ * mfa.c, parse.y, smtpd.h: - change name of "masked" member in
+ struct netaddr, it was misleading - allow "from all" so that the
+ ugly "accept from { 0.0.0.0/0, ::/0 }" construct becomes a nice
+ looking "accept from all"
+
+ ok jacekm@
+
+2009-01-04 15:46 jacekm
+
+ * lka.c, mfa.c, smtpd.h: cleanup; ok gilles@
+
+2009-01-04 01:58 gilles
+
+ * forward.c, lka.c, mfa.c, queue.c, smtp.c, smtp_session.c,
+ smtpd.h: aliases/forwards expansion was not done correctly and a
+ race could cause delivery to happen before expansion is over,
+ causing some of the recipients to never receive the mail. change
+ how the mfa, lka, queue and smtp processes communicate to ensure
+ smtp never receives an acknowledgment before ALL expanded
+ envelopes are on disk. While at it, lka was doing work which
+ belongs in mfa, fix that also.
+
+ this is based on an idea from a talk with jacekm@, change not
+ over but already better than what we had.
+
+2009-01-02 23:08 jacekm
+
+ * queue.c: fix T_DAEMON_MESSAGE notices delivery; ok gilles@
+
+2009-01-02 20:52 jacekm
+
+ * queue.c: cleanup queue_load_envelope; ok gilles@
+
+2009-01-01 17:15 jacekm
+
+ * aliases.c, config.c, control.c, dns.c, forward.c, lka.c,
+ makemap.c, map.c, mda.c, mfa.c, mta.c, queue.c, showqueue.c,
+ smtp.c, smtp_session.c, smtpd.c, ssl.c, store.c, util.c: remove
+ unnecessary includes; ok gilles@
+
+2008-12-31 10:55 jacekm
+
+ * queue.c: if mkdir/mkdtemp fails, fatal if errno != ENOSPC; ok
+ gilles@
+
+2008-12-31 10:50 jacekm
+
+ * queue.c: rename may fail due to ENOSPC, make smtpd survive this
+ condition; ok gilles@
+
+2008-12-31 10:47 jacekm
+
+ * queue.c: kill unnecessary function; ok gilles@
+
+2008-12-29 10:03 jacekm
+
+ * queue.c: Handle ENOSPC in queue_update_envelope; cleanup the code
+ a bit; ok gilles@
+
+2008-12-27 19:18 jacekm
+
+ * queue.c: kill unused function; ok gilles@
+
+2008-12-27 18:58 jacekm
+
+ * smtpctl.8: Manpage bits for "showqueue" -> "show queue" change.
+
+2008-12-27 18:45 jacekm
+
+ * runner.c: log_warn -> log_warnx
+
+2008-12-27 18:36 jacekm
+
+ * queue.c, runner.c, smtpd.h: cleanup; ok gilles@
+
+2008-12-27 18:12 jacekm
+
+ * queue.c: Put common handler code in a function; ok chl@ gilles@
+
+2008-12-27 18:03 jacekm
+
+ * queue.c, runner.c, smtpd.c, smtpd.h: Merge hash() and
+ queue_message_hash() into one func, queue_hash(). Fix callers to
+ use this interface consistently; ok chl@ gilles@
+
+2008-12-27 17:45 jacekm
+
+ * parser.c, parser.h, smtpctl.c: Break showqueue and showrunqueue
+ into 2 words; ok gilles@
+
+2008-12-26 11:28 jacekm
+
+ * smtp.c, smtpd.h: parse.y doesn't allow listen backlog
+ configuration, so "bzero default" is used. Hardcode it instead:
+ 5 is a popular choice across the tree; ok gilles@
+
+2008-12-22 14:35 jacekm
+
+ * lka.c: typo
+
+2008-12-22 14:28 jacekm
+
+ * showqueue.c: Fix few cases where "smtpctl showqueue" could exit
+ prematurely if msg is delivered between readdir and opendir, or
+ readdir and fopen, etc. etc.
+
+ Be more unforgiving about errors other than ENOENT, and err() if
+ they happen, not just warn().
+
+ ok gilles@
+
+2008-12-22 14:21 jacekm
+
+ * smtp_session.c: cleanup
+
+2008-12-22 14:18 jacekm
+
+ * smtp.c: s->s_msg.session_hostname must hold resolved hostname as
+ well; ok gilles@
+
+2008-12-22 14:14 jacekm
+
+ * lka.c: Reduce IMSG_LKA_HOST to only make NI_NAMEREQD getnameinfo
+ call. We don't need it to return NI_NUMERICHOST conversion
+ because there's no reason not to do it in smtp; ok gilles@
+
+2008-12-22 13:59 jacekm
+
+ * lka.c: delinting: salen may be used with no prior init; ok
+ gilles@
+
+2008-12-22 13:56 jacekm
+
+ * smtpd.c: Remove entry from mdaproctree after reaping mda child;
+ ok gilles@ From: Nicholas Marriott <nicholas.marriott@gmail.com>
+
+2008-12-22 01:44 jacekm
+
+ * smtp_session.c: To reset state, it's enough to set s->s_state =
+ S_HELO, rcptcount is zeroed in MAIL FROM handler; ok gilles@
+
+2008-12-21 20:27 jacekm
+
+ * smtp_session.c: fix session flags resetting; ok gilles@
+
+2008-12-21 19:51 gilles
+
+ * smtp.c, smtp_session.c: - missing prototype + smtp.c was misusing
+ session_auth_pickup() - unlike starttls, ssmtp sets the F_SECURE
+ flag on session before helo/ehlo handlers are called. this
+ means that if we clear all flags in helo/ helo handlers, we
+ prevent smtpd from advertising AUTH as it will do so only for
+ F_SECURE sessions. This commits unbreaks SMTP AUTH with smtp
+ sessions. Problem spotted by James Turner <james@bsdgroup.org>
+
+2008-12-21 14:06 jacekm
+
+ * showqueue.c: Add more compile time checking; fix warnings
+ reported by gcc. From: Nicholas Marriott
+ <nicholas.marriott@gmail.com>
+
+2008-12-21 13:59 jacekm
+
+ * makemap.c: Add more compile time checking; fix one warning
+ reported by gcc. From: Nicholas Marriott
+ <nicholas.marriott@gmail.com>
+
+2008-12-21 03:18 gilles
+
+ * smtp.c, smtp_session.c, smtpd.c, smtpd.h: - AUTH PLAIN may
+ receive credentials as a parameter to AUTH or on a
+ following line, this commit brings support for the latter which
+ was not supported yet. - AUTH LOGIN is now supported,
+ allowing smtp auth support on clients that do not support AUTH
+ PLAIN (ie: my mobile phone for instance ;)
+
+2008-12-20 01:22 gilles
+
+ * smtpd.conf, smtpd.conf.5: - update smtpd.conf to provide an
+ example of an auth enabled listener - update smtpd.conf.5 just to
+ provide an example, a better description of "enable auth"
+ will come when im done implementing it ;)
+
+2008-12-20 01:18 gilles
+
+ * lka.c, mfa.c, parse.y, smtp_session.c, smtpd.h: - import first
+ bricks of SMTP AUTH support. currently only AUTH PLAIN is
+ supported, AUTH LOGIN will follow soon. AUTH will only work if a
+ listen directive has "enable auth" keywords, AND session is
+ safe (ssmtp or starttls).
+
+2008-12-19 13:09 jacekm
+
+ * util.c: fix indentation, no binary change.
+
+2008-12-19 01:44 gilles
+
+ * smtpd.c: - fatal() if flock() has failed for any reason that's
+ not EWOULDBLOCK, this is not supposed to happen but better safe
+ than sorry. suggested by jacekm@ - while at it, remove the
+ locking of delivery file we create when doing a Maildir
+ delivery. the purpose of Maildir is to prevent the need
+ for locking in the first place ... I must have been tired that
+ day.
+
+2008-12-19 01:39 gilles
+
+ * runner.c, smtpd.c, smtpd.h: - smtpd handled mbox locking failures
+ as "regular" temporary failures which is not good at all.
+ As a result, under heavy load messages would be kept in
+ queue, and delayed for hours just because we failed locking a
+ few times. This commit makes smtpd distinguish between lock fails
+ and "regular" temporary fails. - delivery scheduler will
+ reschedule immediately a message that couldn't be delivered
+ because of a lock fail. If we fail to lock too many times we
+ fallback to previous "delay increase" logic.
+
+ "looks sane" jacekm@
+
+2008-12-19 00:57 jacekm
+
+ * smtp_session.c, smtpd.h, util.c: Introduce safe_fclose, which
+ tries to push file to the disk as quickly as possible; it fails
+ under temporary error conditions, letting caller react
+ appropriately.
+
+ ok gilles@
+
+2008-12-19 00:49 jacekm
+
+ * smtp_session.c, smtpd.h: Declarations for functions used only in
+ smtp_session.c were moved to that file from smtpd.h.
+
+ ok gilles@
+
+2008-12-19 00:38 jacekm
+
+ * smtp_session.c, smtpd.h: Check fwrite return code at DATA stage.
+
+ Add basic line length checking, as required by rfc.
+
+ It is no longer required to disable EV_READ upon
+ evbuffer_readline failure.
+
+ ok gilles@
+
+2008-12-18 23:13 gilles
+
+ * parse.y: - condition lists is wrongly described, unbreak the
+ following syntax: "accept for { domain "foo", domain "bar"
+ } ..." From Nicholas Mariott
+ <nicholas.marriott@gmail.com>
+
+2008-12-18 16:19 jacekm
+
+ * makemap.c: Don't err() on blank lines.
+
+ ok gilles@
+
+2008-12-18 16:11 jacekm
+
+ * queue.c, smtp_session.c: Cleanup /incoming before handling each
+ MAIL FROM. Improve cleanup condition to cover more cases.
+
+ ok gilles@
+
+2008-12-18 00:09 jacekm
+
+ * makemap.c: Warn if empty map is being created; this catches at
+ least usage error such as "makemap foo.db".
+
+ ok gilles@
+
+2008-12-17 23:59 jacekm
+
+ * Makefile, makemap.8, makemap.c, newaliases.8, newaliases.c: Merge
+ newaliases into makemap.
+
+ ok gilles@
+
+2008-12-17 19:47 jacekm
+
+ * queue.c, runner.c, smtpd.c, smtpd.h: Introduce /purge, where all
+ msgs scheduled for deletion are put by queue, and removed from
+ disk by runner.
+
+ On startup, clean /incoming by moving msgs within it to /purge.
+
+ ok gilles@
+
+2008-12-14 20:27 jacekm
+
+ * queue.c: Files under /incoming don't need flock(2)ing anymore.
+
+ ok gilles@
+
+2008-12-14 20:24 jacekm
+
+ * queue.c: O_TRUNC is redundant if O_EXCL is specified.
+
+ ok gilles@
+
+2008-12-14 20:20 jacekm
+
+ * queue.c: O_TRUNC is redundant if O_EXCL is specified.
+
+ ok gilles@
+
+2008-12-14 20:16 jacekm
+
+ * queue.c: queue_create_incoming_layout must return 0 on failure,
+ not -1.
+
+ ok gilles@
+
+2008-12-14 00:19 jacekm
+
+ * lka.c, mda.c, mfa.c, mta.c, queue.c, runner.c, smtp.c,
+ smtp_session.c, smtpd.h: IMSG_* namespace cleanup.
+
+ ok gilles@
+
+2008-12-13 20:18 jacekm
+
+ * newaliases.c: Detect alias duplicates.
+
+ ok gilles@
+
+2008-12-13 20:15 jacekm
+
+ * newaliases.c: Fix few parsing bugs in parse_entry, most severe of
+ which was segv on lines consisting exclusively of whitespace.
+
+ ok gilles@
+
+2008-12-13 20:11 jacekm
+
+ * newaliases.c: Simplify parse_entry; streamline the code to call
+ db->put in one place, regardless of number of preexisting
+ aliases.
+
+ Don't call db->sync; it's covered by db->close shortly before
+ rename.
+
+ ok chl@ gilles@
+
+2008-12-13 20:05 jacekm
+
+ * newaliases.c: If parse_aliases fails, don't warn about syntax
+ errors; it may fail for other reasons.
+
+ Never exit outside main; we need to return to main to clean the
+ temp file.
+
+ Check parse_entry return code; otherwise $? == 0 even when
+ invalid entries were found.
+
+ ok gilles@
+
+2008-12-13 20:02 jacekm
+
+ * newaliases.c: Use mkstemp instead of mkdtemp; also, add more X's.
+
+ Do chmod before rename to eliminate short time window when
+ aliases.db is "official" but not readable.
+
+ Use PATH_ALIASESDB instead of hardcoding "/etc/mail/.."
+
+ Check db->close return code.
+
+ ok gilles@ henning@
+
+2008-12-13 19:58 jacekm
+
+ * newaliases.c: - Correct usage text. - Drop static qualifiers. -
+ Drop unused -d switch. - Use 0/1 exit codes instead of
+ <sysexits.h> defines.
+
+ ok gilles@
+
+2008-12-13 14:15 jacekm
+
+ * aliases.c, forward.c, makemap.c, newaliases.c, smtpd.h: Declare
+ alias_parse in smtpd.h, and fix callers that pass it wrong number
+ of arguments.
+
+ ok gilles@
+
+2008-12-12 21:19 jacekm
+
+ * smtpd.h: Format string checking for bsnprintf.
+
+ ok gilles@
+
+2008-12-12 18:24 jacekm
+
+ * smtpd.8, smtpd.conf.5: Kill references to smtpdb(8).
+
+ ok gilles@
+
+2008-12-12 00:19 gilles
+
+ * parse.y, queue.c: - last snprintf -> bsnprintf
+
+2008-12-12 00:17 gilles
+
+ * queue.c: - snprintf -> bsnprintf
+
+2008-12-12 00:10 gilles
+
+ * smtpd.c: - snprintf -> bsnprintf
+
+2008-12-12 00:06 gilles
+
+ * parse.y: - snprintf -> bsnprintf
+
+2008-12-12 00:04 gilles
+
+ * aliases.c: - snprintf -> bsnprintf - makemap and newaliases need
+ util.c now
+
+2008-12-11 23:59 gilles
+
+ * runner.c, ssl.c: - snprintf -> bsnprintf
+
+2008-12-11 23:32 gilles
+
+ * runner.c: - fix a bug that would cause the runner to hit a
+ fatal() when running out of luck under load. Long story made
+ short: the runner process opens the queue and sequentially
+ opens each bucket to process messages. If a message is
+ delivered by MDA/MTA after the opendir(), then the queue
+ process will garbage collect the message from the queue and
+ the runner will attempt to opendir() a path that no longer
+ exists.
+
+ Reported by Daniel Lidberg <daniel.lidberg@gmail.com>,
+ observed by
+ jacekm@ and debugged by me, that's collaborative work ;-)
+
+2008-12-11 23:19 gilles
+
+ * smtpctl.8: - document showqueue and showrunqueue
+
+2008-12-11 23:18 gilles
+
+ * smtpd.h: - missing prototype
+
+2008-12-11 23:17 gilles
+
+ * util.c: - bsnprintf() is a wrapper to snprintf() that can be used
+ when we handle an encoding error or a truncation the same way.
+ This will turn many of our snprintf() checks into boolean
+ checks.
+
+2008-12-11 00:04 jacekm
+
+ * aliases.c, parse.y: That the "aliases" and "virtual" maps satisfy
+ m_src == S_DB is checked too late, ie. at alias resolution time,
+ and it's only a log_info.
+
+ Move the check to parse.y, and make daemon die if m_src != S_DB.
+
+ ok gilles@
+
+2008-12-07 17:00 jacekm
+
+ * queue.c: Simplify queue_record_incoming_envelope.
+
+ ok gilles@
+
+2008-12-07 16:41 jacekm
+
+ * smtp_session.c: Disable EV_READ when sending
+ IMSG_PARENT_AUTHENTICATE.
+
+ This is for consistency, code is not reached yet.
+
+ ok gilles@
+
+2008-12-07 16:38 jacekm
+
+ * smtp_session.c, smtpd.h: Replace evbuffer_add_printf calls with
+ wrapper function, session_respond, which additionally suffixes
+ <CRLF>, and enables EV_WRITE.
+
+ Remove bufferevent_enable(.., EV_WRITE) from session_command and
+ session_pickup so that EV_WRITE is enabled in exactly one place,
+ session_respond.
+
+ Change some responses slightly to make code fit 80 columns.
+
+ ok gilles@
+
+2008-12-07 04:14 gilles
+
+ * runner.c, smtpd.h: - getaddrinfo() uses negative values for its
+ error defines, our use of an u_int8_t to hold the value leads to
+ invalid checking in runner_batch_resolved(), this lead to
+ a crash in MTA because we assumed a batch had its mx
+ resolved when it had not. while at it, be more strict about
+ errors we don't know and fatal(), it should not happen.
+
+ ok jacekm@, ok chl@
+
+2008-12-07 02:55 gilles
+
+ * runner.c: - fix function name in fatal()
+
+2008-12-07 02:03 jacekm
+
+ * smtp_session.c: Don't check / reset s->s_msg.datafp where its
+ state is obviously known.
+
+2008-12-07 00:49 jacekm
+
+ * queue.c: Make queue_delete_incoming_message not fatal on ENOENT
+ condition. Also, fix function name in fatals.
+
+ ok gilles@
+
+2008-12-06 16:18 weerd
+
+ * smtpd.h: Get rid of anonymous unions. Discussed with and ok
+ gilles@
+
+2008-12-06 15:58 jacekm
+
+ * smtp_session.c: In session_destroy, use "if (s->s_state >=
+ S_MAIL)", and not "if (s->s_state > S_MAIL)". Otherwise, session
+ timeout after MAIL FROM would leave mess in queue.
+
+ ok gilles@
+
+2008-12-06 15:30 jacekm
+
+ * forward.c, map.c, queue.c, smtp_session.c, store.c: Don't include
+ <err.h> where log.c API must be used.
+
+ ok gilles@
+
+2008-12-06 15:24 gilles
+
+ * store.c: - fix spelling and grammar, From Nicholas Marriott
+ <nicm__@ntlworld.com>
+
+2008-12-06 15:23 jacekm
+
+ * parse.y: Unbreak -Werror.
+
+ ok gilles
+
+2008-12-06 14:18 sobrado
+
+ * smtpctl.8: the ellipsis allows more than one argument being
+ specified.
+
+ discussed with gilles@
+
+ ok jmc@
+
+2008-12-06 11:54 sobrado
+
+ * smtpctl.8: smtpctl(8) was committed after 4.4.
+
+ ok gilles@
+
+2008-12-06 05:49 jacekm
+
+ * smtp_session.c: NULL-ify s_msg.datafp upon fclose
+ unconditionally.
+
+ ok gilles
+
+2008-12-06 03:44 gilles
+
+ * parser.c, parser.h, showqueue.c, smtpctl.c: - teach smtpctl how
+ to inspect queue and runqueue, it supports two commands
+ `showqueue' which displays the content of the queue (all
+ envelopes) `showrunqueue` which displays envelopes scheduled
+ for delivery. The utility will be improved and extended, but
+ for now we need at least this basic support to help debug
+ queue-related issues.
+
+ Output format is spamdb-alike:
+ type|envelope uid|sender|recipient|last delivery
+ date|retry count
+
+ ok jacek@
+
+2008-12-06 03:43 jacekm
+
+ * mta.c, smtp_session.c: evbuffer_readline already strips <CRLF> so
+ that callers don't have to.
+
+ ok gilles
+
+2008-12-06 03:04 gilles
+
+ * parse.y, smtpd.conf, smtpd.conf.5: - it is now possible to
+ specify an interface instead of an address or a hostname in a
+ listen statement (ie: listen on lo0) request by deraadt@ a
+ while ago, ok jacekm@
+
+2008-12-05 20:09 gilles
+
+ * aliases.c, dns.c, lka.c, mda.c, mta.c, runner.c: - more err/errx
+ -> fatal/fatalx, warn/warnx -> log_warn/log_warnx contains
+ bits based on an old diff from Jacek Masiulaniec and other bits
+ from me.
+
+2008-12-05 18:31 gilles
+
+ * aliases.c: - err -> fatal(), old diff from Jacek Masiulaniec
+ <jacekm@dobremiasto.net>
+
+2008-12-05 18:29 gilles
+
+ * smtp_session.c: - cosmethic, no functionnal change
+
+2008-12-05 07:56 jmc
+
+ * smtpctl.8: tweaks;
+
+2008-12-05 04:28 gilles
+
+ * Makefile, parser.c, parser.h, smtpctl.8, smtpctl.c: - smtpctl
+ utility to control the smtpd, don't expect too much yet as it is
+ just an empty clone of relayctl with the glue needed to
+ have it exchange imsg with smtpd correctly. code mostly
+ by pyr@, reviewed by chl@ and I a while ago.
+
+2008-12-05 03:51 gilles
+
+ * control.c, lka.c, mda.c, mta.c, queue.c, runner.c, smtpd.c,
+ smtpd.h: - last part of the new queue code: the runner process
+ (unprivileged and chrooted) is now in charge of doing the
+ scheduling of deliveries, and the dispatching of messages
+ to MDA and MTA. queue process only does
+ inserts/updates/removals from the queue and can no longer be
+ so busy that it delays answers to imsg from smtp server.
+
+2008-12-05 00:02 gilles
+
+ * smtp_session.c: - in session_read(), set EV_WRITE if we are going
+ to send a "transaction failed" error. found by Jacek
+ Masiulaniec <jacekm@dobremiasto.net>
+
+2008-12-04 18:24 cloder
+
+ * imsg.c, log.c, parse.y, smtpd.h: Declare printf-style functions
+ with __attribute__((format(printf,x,x))) and fix some of the
+ errors caught by this. Part of a general push to make yyerror()
+ -Wformat clean throughout the tree.
+
+2008-12-04 16:16 gilles
+
+ * Makefile: - allow smtpd to build again
+
+2008-12-04 14:36 todd
+
+ * Makefile: move smtpd build to smtpd subdir so we can traverse to
+ newaliases and makemap ok gilles@
+
+2008-12-04 07:22 jmc
+
+ * makemap.8, newaliases.8: some basic cleanup;
+
+2008-12-04 05:09 gilles
+
+ * smtp_session.c: - when in state S_DATACONTENT, do not disable
+ EV_READ if the last line we read is empty, instead return and
+ only disable EV_READ when we read "."
+
+2008-12-04 03:04 gilles
+
+ * smtp_session.c: - when doing the session timeout lookup, do not
+ remove the last session that timed out twice.
+
+2008-12-04 02:16 gilles
+
+ * smtp_session.c, smtpd.h: - fix event masking for DATA and make
+ DATA look more like MAIL and RCPT with regard to
+ communication with queue process (one state before sending
+ imsg, another state when imsg has returned). this fixes an
+ issue that I observed when clients send DATA and content without
+ even looking at server replies.
+
+2008-12-04 01:10 ian
+
+ * parse.y: obvious 'missing space' typo in message, ok gilles@ krw@
+
+2008-12-03 22:20 gilles
+
+ * makemap.8, makemap.c: - smtpd's db maps are incompatible with
+ sendmail's and needs a distinct makemap utility, this is
+ needed for virtual users support amongst other things.
+ links to smtpd's aliases.c and only provides a frontent to
+ parse map descriptions. contains code from pyr@, chl@ and
+ I. Should have also been imported with smtpd.
+
+2008-12-03 22:13 gilles
+
+ * newaliases.8, newaliases.c: smtpd's aliases db is incompatible
+ with sendmail's and requires a distinct newaliases
+ utility. newaliases links to the aliases.c file from
+ smtpd and only provides a frontend to parse aliases file.
+ contains code from pyr@, chl@ and I, it should have been imported
+ with smtpd.
+
+2008-12-03 21:11 gilles
+
+ * Makefile, debug.c: - these were used to debug the previous queue
+ scheduler, they are no longer needed and aren't referenced
+ anywhere any longer
+
+2008-12-03 21:08 gilles
+
+ * queue.c: - remove log_debug() that's no longer needed
+
+2008-12-03 18:58 gilles
+
+ * queue.c, smtp.c, smtp_session.c, smtpd.c, smtpd.h: - fix event
+ masking issues in smtp process which could lead to a fatal() if
+ queue process did not answer fast enough to an imsg. spotted
+ by Jacek Masiulaniec <jacekm@dobremiasto.net> - queue
+ layout was mostly to bootstrap the project, it does not behave
+ good under load, it does complex things to stay in a recoverable
+ state and it probably didnt do it too well. New queue code
+ is simpler, smaller and allows for atomic submissions (a
+ mail can never be in a state where it needs to be recovered).
+ It still needs some work but works better than previous code,
+ no regression.
+
+2008-12-01 23:54 gilles
+
+ * dns.c: - in mxsort, fix type of loop counter, it will never be <
+ 0 if it is unsigned and when running out of luck it will cause
+ the lookup process to crash.
+
+2008-11-26 00:06 gilles
+
+ * forward.c, smtpd.h: - more prototype moving to smtpd.h
+
+2008-11-26 00:03 gilles
+
+ * dns.c, smtpd.h: - move prototype to smtpd.h
+
+2008-11-26 00:01 gilles
+
+ * aliases.c, smtpd.h: - move prototypes to smtpd.h
+
+2008-11-25 21:35 gilles
+
+ * smtp_session.c: - plug memory leak
+
+2008-11-25 21:26 gilles
+
+ * lka.c, mta.c, parse.y, queue.c, smtpd.h: - recent change in
+ parse.y caused htons() to be called twice on the port
+ provided to "relay via" rules, once in parse.y once in lka.c,
+ fix. - rename struct address to struct relayhost, introduce
+ struct mxhost which not only holds the sockaddr_storage, but
+ also additionnal flags we want forwarded to the mta process.
+ - propagate the change
+
+2008-11-25 16:58 gilles
+
+ * smtp_session.c: - update email address for bug reports when
+ replying to HELP
+
+2008-11-25 16:55 gilles
+
+ * smtp_session.c, smtpd.h: - F_IMSG_SENT is no longer used, kill
+ suggested by Jacek Masiulaniec <jacekm@dobremiasto.net>
+
+2008-11-25 00:55 gilles
+
+ * queue.c, smtp_session.c: - when using fread/fwrite, do not swap
+ the size and nmemb arguments. no functionnal change here,
+ just making use of fonctions the way C intended it ;-)
+ From Jacek Masiulaniec <jacekm@dobremiasto.net>
+
+2008-11-24 23:30 gilles
+
+ * mta.c, smtp.c: - not really a bug since we don't use other
+ descriptor flags, but in smtp_setup_events() and mta_connect(),
+ our fcntl() use clears flags. use session_socket_blockmode()
+ instead, it makes more sense anyway. From Jacek Masiulaniec
+ <jacekm@dobremiasto.net>
+
+2008-11-22 23:22 gilles
+
+ * smtpd.c: - do not set nochdir in daemon() call, we want parent
+ and lka to have their wd reset to / rather than current working
+ directory. From Jacek Masiulaniec <jacekm@dobremiasto.net>
+
+2008-11-22 21:26 gilles
+
+ * parse.y: - allow the optionnal ssmtp keywork in "relay via"
+ rules, while at it allow port to become optionnal
+ (implicit 25) or provided by value or name.
+
+2008-11-17 22:56 chl
+
+ * log.c, smtp.c, smtp_session.c, store.c: add missing header needed
+ by time(), ctime_r() and tzset().
+
+ ok gilles@
+
+2008-11-17 22:52 gilles
+
+ * smtp_session.c: - clear session flags upon helo/ehlo
+
+2008-11-17 22:50 gilles
+
+ * smtp_session.c, smtpd.h: - until now a client could issue a
+ command from an extension even though it greeted with helo and
+ not ehlo. introduce session flag F_EHLO and make sure the
+ session_command() dispatch only looks at extensions when a
+ session does not have the F_EHLO flag.
+
+2008-11-17 22:32 gilles
+
+ * forward.c: - err() -> fatal() - printf() -> log_debug() - be more
+ verbose in debug mode
+
+2008-11-17 22:27 gilles
+
+ * smtpd.h: - remove prototypes for the atomic API, we don't use it
+ anymore
+
+2008-11-17 22:27 chl
+
+ * control.c: add missing header needed by signal().
+
+2008-11-17 22:23 gilles
+
+ * Makefile, atomic.c: - we don't need this anymore
+
+2008-11-17 22:05 gilles
+
+ * queue.c: - remove some unused prototypes
+
+2008-11-17 22:03 gilles
+
+ * queue.c: - queue_record_daemon() no longer used, remove
+ definition
+
+2008-11-17 21:37 gilles
+
+ * queue.c, smtpd.c: - replace uses of O_EXLOCK and
+ O_EXLOCK|O_NONBLOCK with the corresponding open()/flock()
+ constructs as chl@ says it prevents him from doing a
+ portable build.
+
+ discussed with chl@, diff is common work from him and myself
+
+2008-11-17 21:16 gilles
+
+ * aliases.c: - fix error message in aliases_virtual_exist()
+
+ By Alexander Hall <alexander@beard.se>
+
+2008-11-17 21:14 gilles
+
+ * smtpd.c: - exit() -> _exit() - err() -> fatal()
+
+ Both by Jacek Masiulaniec <jacekm@dobremiasto.net>
+
+2008-11-17 21:11 gilles
+
+ * smtp_session.c: - remove several constructs where format strings
+ are used in an evbuffer printf with constant parameters,
+ turn them into a constant string. - when client sends EHLO
+ without a parameter, send the appropriate error message ("EHLO
+ takes ..." instead of "HELO takes ...")
+
+ From Jacek Masiulaniec <jacekm@dobremiasto.net>
+
+2008-11-14 00:24 gilles
+
+ * parse.y, smtp.c: - rephrase the "cannot load cert" warning that
+ is output at startup when a listen directive has no matching
+ certificate. it sounds like a critical failure when it just
+ means "no tls support". - minor log_debug() addition in smtp.c
+
+2008-11-11 22:17 gilles
+
+ * queue.c: - mistakenly removed this lock
+
+2008-11-11 22:13 gilles
+
+ * queue.c: - introduce queue_init_submissions() which will sanitize
+ the disk-based queue at startup: catches left overs from
+ interrupted sessions, reset F_MESSAGE_INPROCESS so that
+ messages which were in MTA or MDA gets scheduled again.
+ - temporarily comment chl@'s O_EXLOCK -> fcntl change until we
+ figure why it locks my mailbox under load
+
+2008-11-11 22:02 gilles
+
+ * smtpd.c: - temporarily comment chl@'s O_EXLOCK -> fcntl() change
+ until we understand what causes the mailbox lock bug i'm
+ observing under heavy load.
+
+2008-11-11 21:59 gilles
+
+ * store.c: - now that we fdopen() message file descriptor, do not
+ forget to fclose()
+
+2008-11-11 03:14 tedu
+
+ * mta.c, smtp.c: some small improvements. ok gilles
+
+2008-11-11 02:08 gilles
+
+ * queue.c, smtp.c, smtp_session.c, smtpd.h: - queue process no
+ longer schedules messages which do not have flag
+ F_MESSAGE_COMPLETE - submit recipients to the queue as we read
+ them from RCPT instead of submiting them all at once when
+ DATA is over. this prevents us from having to keep a potentially
+ large number of recipients in memory during the whole
+ session. - remove all code that dealt with the recipients queue
+ of a message as it is no longer used. - several small
+ changes to make sure the server is always in a recoverable
+ state in case of an unexpected shutdown.
+
+2008-11-11 02:01 chl
+
+ * queue.c, smtpd.c: remove the use of O_EXLOCK, when open()ing a
+ file, and use flock() instead.
+
+ ok gilles@
+
+2008-11-11 00:18 gilles
+
+ * smtp_session.c, smtpd.h: - open the message file earlier after a
+ successful MAIL command instead of waiting for the DATA
+ command. this currently has no impact on the session but is
+ needed for another change that will make submission of
+ recipients safer with regard to "unexpected shutdowns at bad
+ timings"
+
+2008-11-10 23:35 gilles
+
+ * aliases.c, mta.c, parse.y, smtpd.h: - define MAX_LINE_SIZE which
+ is the maximum length of a line we allow from a client. it
+ must be set to the highest value we have from all of the
+ extensions which are/will be implemented. - replace all
+ occurences of STRLEN define with MAX_LINE_SIZE, kill STRLEN
+
+2008-11-10 22:29 chl
+
+ * lka.c, queue.c, smtpd.h: rename h_errno field into
+ getaddrinfo_error, to avoid confusion with errno.
+
+ h_errno has been obsoleted since the gethostbyname() -->
+ getaddrinfo() replacement.
+
+ ok gilles@
+
+2008-11-10 21:10 chl
+
+ * smtpd.h: fix store_write_header() prototype.
+
+ ok gilles@
+
+2008-11-10 18:24 deraadt
+
+ * Makefile, parse.y, queue.c, smtp_session.c, smtpd.c, smtpd.h,
+ ssl_privsep.c: spaces fixed while reading code
+
+2008-11-10 17:33 gilles
+
+ * store.c: - remove last occurences of the atomic api in store.c,
+ smtpd no longer uses atomic api when dealing with files but uses
+ stdio instead
+
+2008-11-10 04:55 tedu
+
+ * aliases.c: last character in line is at len - 1. ok gilles
+
+2008-11-10 04:54 tedu
+
+ * dns.c: insertion sort is faster than bubble sort. ok gilles
+
+2008-11-10 04:41 gilles
+
+ * smtpd.c: - simplify the passing of ssl cert/key during ssl
+ configuration, from Jacek Masiulaniec
+ <jacekm@dobremiasto.net>
+
+2008-11-10 04:16 gilles
+
+ * queue.c: - in queue, do not use the atomic api when dealing with
+ real files change based on a comment from deraadt@
+
+ - in queue_register_submission(), if an envelope cannot be fully
+ written because of some error (ie: disk full), not only
+ return error but also remove the partial envelope from
+ file system. this prevents the queue process from trying
+ (failing) to reload it over and over.
+
+2008-11-10 03:34 gilles
+
+ * mta.c: - plug a descriptor leak when session is aborted by a
+ server error instead of a client QUIT or client timeout
+
+2008-11-10 03:13 gilles
+
+ * parse.y: - move '=>' into the lex loop, requested by and with
+ help from deraadt@
+
+2008-11-10 02:14 gilles
+
+ * queue.c: - in queue_load_submissions(), if
+ queue_message_from_id() fails for some reason just warn
+ instead of aborting the whole smtpd.
+
+2008-11-10 01:57 gilles
+
+ * aliases.c, parse.y, queue.c, smtpd.c, ssl.c: - snprintf() can
+ return -1, make sure every call is checked properly
+
+2008-11-10 01:29 gilles
+
+ * parse.y: - recognize '=>' as one token instead of trying to match
+ '=' and '>'. this prevents: "foo = > bar" from being
+ valid
+
+2008-11-10 01:22 gilles
+
+ * smtpd.h: - make READ_BUF_SIZE a power of 2
+
+2008-11-05 13:49 sobrado
+
+ * atomic.c: add gilles@ as copyright holder for this file.
+
+2008-11-05 13:14 sobrado
+
+ * aliases.c, atomic.c, config.c, control.c, debug.c, dns.c,
+ forward.c, lka.c, map.c, mda.c, mfa.c, mta.c, parse.y, queue.c,
+ smtp.c, smtp_session.c, smtpd.c, smtpd.conf, smtpd.h, ssl.c,
+ store.c: add a few missing id tags; there are a bunch of files,
+ and developers will probably miss this change when working on
+ more important matters, so it is probably better to sort them
+ now. there is a risk of losing the tags if a change needs to be
+ reverted too.
+
+ written with excellent advice from jmc@
+
+ ok gilles@
+
+2008-11-02 09:19 jmc
+
+ * ARCHITECTURE, smtpd.8, smtpd.c, smtpd.conf.5: various minor
+ tweaks, including spelling fixes from Brian Keefer and Jim
+ Razmus;
+
+2008-11-02 01:01 sobrado
+
+ * smtpd.conf.5: write the command description (the .Nd macro) in a
+ more usual way; improve spacing in the FILES section.
+
+ ok gilles@
+
+2008-11-02 00:42 sobrado
+
+ * smtpd.8: remove a superfluous .Pq macro; cites bibliography in a
+ more standard way; fix the reference to RFC 5321.
+
+ ok gilles@
+
+2008-11-01 22:41 gilles
+
+ * parse.y: - put back all copyright holders - add myself as a
+ copyright holder
+
+2008-11-01 22:41 deraadt
+
+ * store.c: correct order of includes
+
+2008-11-01 22:35 gilles
+
+ * ARCHITECTURE, Makefile, aliases.c, atomic.c, buffer.c, config.c,
+ control.c, debug.c, dns.c, forward.c, imsg.c, lka.c, log.c,
+ map.c, mda.c, mfa.c, mta.c, parse.y, queue.c, smtp.c,
+ smtp_session.c, smtpd.8, smtpd.c, smtpd.conf, smtpd.conf.5,
+ smtpd.h, ssl.c, ssl_privsep.c, store.c: smtpd is a smtp server
+ implementation for OpenBSD. It is a work in progress which still
+ lacks many features. bringing it in tree will help working on it
+ more easily.
+
+ "at this stage it should go in" henning@, "move ahead" deraadt@
+
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..27ee69d2
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,330 @@
+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
+ 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.]
+
+
+
+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
+==============
+
+
+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
+ Theo de Raadt
+ Ted Unangst
+
+ * 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
+ 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
+
+ * 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 holders:
+
+ 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) setresguid, xmalloc
+
+ * 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".
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/README b/README
deleted file mode 100644
index e3bf044e..00000000
--- a/README
+++ /dev/null
@@ -1,34 +0,0 @@
-Preliminary note
-================
-
-OpenSMTPD is a FREE implementation of the server-side SMTP protocol as defined
-by RFC 5321, with some additional standart extensions.
-
-It allows ordinary machines to exchange e-mails with other systems speaking
-the SMTP protocol.
-
-OpenSMTPD runs on top of the OpenBSD operating system but also has a portable
-version that can build and run on several systems, including:
-
- - Linux
- - FreeBSD
- - NetBSD
- - DragonFly
- - MacOSX
-
-For more information:
-
- http://www.opensmtpd.org/portable.html
-
-
-People interested about OpenSMTPD are encouraged to subscribe to our mailing
-list:
-
- http://www.opensmtpd.org/mailing.html
-
-
-and to join the IRC channel:
-
- #OpenSMTPD @ irc.freenode.net
-
-Cheers !
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..71c08f81
--- /dev/null
+++ b/README.md
@@ -0,0 +1,145 @@
+Preliminary note
+================
+
+[smtpd](http://www.openbsd.org/cgi-bin/cvsweb/src/usr.sbin/smtpd/) also known as
+OpenSMTPD is a [smtp server implementation for OpenBSD](http://http://opensmtpd.org/smtpd.8.html).
+It is still a work in progress which still lacks many features.
+
+Then, on top of that, all OpenSMTPD's features are not ported yet. For instance,
+authentification still doesn't work.
+
+People interested about portable OpenSMTPD, or about OpenSMTPD in general, are
+encouraged to join the IRC channel #opensmtpd @ FreeNode.net.
+
+
+How to use Portable OpenSMTPD
+=============================
+
+Dependencies
+------------
+
+OpenSMTPD relies on:
+* [autoconf](http://www.gnu.org/software/autoconf/)
+* [automake](http://www.gnu.org/software/automake/)
+* [Berkeley DB](http://www.oracle.com/technetwork/products/berkeleydb/overview/index.html)
+* [bison](http://www.gnu.org/software/bison/) (or [byacc](http://invisible-island.net/byacc/byacc.html))
+* [libevent](http://libevent.org/)
+* [libtool](http://www.gnu.org/software/libtool/)
+* [openssl](http://www.openssl.org/)
+* [zlib](http://www.zlib.net/)
+
+
+Get the source
+--------------
+
+ git clone git://github.com/clongeau/opensmtpd.git
+
+or
+
+ wget http://www.opensmtpd.org/archives/opensmtpd-latest.tar.gz
+ tar xzvf opensmtpd-latest.tar.gz
+
+
+Build
+-----
+
+ cd opensmtpd
+ ./bootstrap
+ ./configure
+ make
+ sudo make install
+
+### Special notes for FreeBSD/DragonFlyBSD/Mac OS X:
+
+Please launch configure with special directive about libevent directory:
+
+#### FreeBSD:
+
+ ./configure --with-libevent-dir=/usr/local
+
+#### DragonFlyBSD:
+
+ ./configure --with-libevent-dir=/usr/pkg
+
+#### Mac OS X:
+
+ ./configure --with-libevent-dir=/opt/local
+ make CFLAGS="-DBIND_8_COMPAT=1"
+
+
+Install
+-------
+
+ sudo make install
+
+
+Configure /etc/smtpd.conf
+-------------------------
+
+Please have a look at the complete format description of [smtpd.conf configuration file](http://opensmtpd.org/smtpd.conf.5.html)
+
+Add _smtpd user
+---------------
+
+### NetBSD, Linux (Debian, ArchLinux, ...)
+
+ mkdir /var/empty
+ useradd -c "SMTP Daemon" -d /var/empty -s /sbin/nologin _smtpd
+
+### DragonFlyBSD, FreeBSD
+
+ pw useradd _smtpd -c "SMTP Daemon" -d /var/empty -s /sbin/nologin
+
+### Mac OS X
+
+First we need a group with an unused GID below 500, list the current ones used:
+
+ /usr/bin/dscl . -list /Groups PrimaryGroupID | sort -n -k2,2
+
+Add a group - here we have picked 444:
+
+ /usr/bin/sudo /usr/bin/dscl . -create /Groups/_smtpd PrimaryGroupID 444
+
+Then the user. Again we need an unused UID below 500, list the current ones used:
+
+ /usr/bin/dscl . -list /Users UniqueID | sort -n -k2,2
+
+Add a user - here we have picked 444:
+
+ /usr/bin/sudo /usr/bin/dscl . -create /Users/_smtpd UniqueID 444
+ /usr/bin/sudo /usr/bin/dscl . -delete /Users/_smtpd AuthenticationAuthority
+ /usr/bin/sudo /usr/bin/dscl . -delete /Users/_smtpd PasswordPolicyOptions
+ /usr/bin/sudo /usr/bin/dscl . -delete /Users/_smtpd dsAttrTypeNative:KerberosKeys
+ /usr/bin/sudo /usr/bin/dscl . -delete /Users/_smtpd dsAttrTypeNative:ShadowHashData
+ /usr/bin/sudo /usr/bin/dscl . -create /Users/_smtpd RealName "SMTP Daemon"
+ /usr/bin/sudo /usr/bin/dscl . -create /Users/_stmpd Password "*"
+ /usr/bin/sudo /usr/bin/dscl . -create /Users/_smtpd PrimaryGroupID 444
+ /usr/bin/sudo /usr/bin/dscl . -create /Users/_smtpd NFSHomeDirectory \
+ /var/empty
+ /usr/bin/sudo /usr/bin/dscl . -create /Users/_smtpd UserShell /usr/bin/false
+
+
+Launch smtpd
+------------
+
+First, kill any running sendmail/exim/qmail/postfix or other.
+
+Then:
+
+ smtpd &
+
+or in debug and verbose mode
+
+ smtpd -dv
+
+
+Manual pages
+------------
+
+* [aliases](http://opensmtpd.org/aliases.5.html) -
+* [forward](http://opensmtpd.org/forward.5.html) -
+* [smtpd](http://opensmtpd.org/smtpd.8.html) - Simple Mail Transfer Protocol daemon
+* [smtpd.conf](http://opensmtpd.org/smtpd.conf.5.html) - Simple Mail Transfer Protocol daemon configuration file
+* [smtpctl](http://opensmtpd.org/smtpctl.8.html) - control the Simple Mail Transfer Protocol daemon
+* [newaliases](http://opensmtpd.org/newaliases.8.html) - generate aliases mappings for the Simple Mail Transfer Protocol daemon
+* [makemap](http://opensmtpd.org/makemap.8.html) - generate mappings for the Simple Mail Transfer Protocol daemon
diff --git a/THANKS b/THANKS
new file mode 100644
index 00000000..08950ad8
--- /dev/null
+++ b/THANKS
@@ -0,0 +1,10 @@
+Freddy DISSAUX IPv6 FreeBSD
+Alexandre Lissy Mandriva
+Brad Arrington ArchLinux
+Todd T. Fries Nokia N900 debian/armel
+Francois Tigeot DragonFlyBSD fixes / pkgsrc
+Ashish SHUKLA FreeBSD port
+Jean-Loup Colautti Debian package
+Rune Lynge MacOS X port
+
+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..6cfcf9db
--- /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 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..a4558587
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,2519 @@
+# $Id: configure.ac,v 1.483 2011/10/02 07:49:24 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.2.1p0], [Charles Longeau <chl@openbsd.org>])
+AC_LANG([C])
+AC_CONFIG_MACRO_DIR([m4])
+
+AC_CONFIG_HEADER([config.h])
+AC_CANONICAL_HOST
+AC_C_BIGENDIAN
+
+AM_INIT_AUTOMAKE
+
+# Checks for programs.
+AC_PROG_CC
+AM_PROG_CC_C_O
+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_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
+
+#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
+
+#l157
+if test "$GCC" = "yes" || test "$GCC" = "egcs"; then
+ CFLAGS="$CFLAGS -Wall -Wpointer-arith -Wuninitialized"
+ GCC_VER=`$CC -v 2>&1 | $AWK '/gcc version /{print $3}'`
+ case $GCC_VER in
+ 1.*) no_attrib_nonnull=1 ;;
+ 2.8* | 2.9*)
+ CFLAGS="$CFLAGS -Wsign-compare"
+ no_attrib_nonnull=1
+ ;;
+ 2.*) no_attrib_nonnull=1 ;;
+ 3.*) CFLAGS="$CFLAGS -Wsign-compare" ;;
+ 4.*) CFLAGS="$CFLAGS -Wsign-compare -Wno-pointer-sign" ;;
+ *) ;;
+ esac
+
+ 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
+
+if test "x$no_attrib_nonnull" != "x1" ; then
+ AC_DEFINE(HAVE_ATTRIBUTE__NONNULL__, 1, [Have attribute nonnull])
+fi
+#l244
+
+#l295
+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
+ ]
+)
+#l305
+
+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 \
+ sys/dir.h \
+ sys/file.h \
+ sys/ndir.h \
+ sys/pstat.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
+
+#l357
+# login_cap.h requires sys/types.h on NetBSD
+AC_CHECK_HEADERS([login_cap.h], [], [], [
+#include <sys/types.h>
+])
+#l360
+
+#l372
+# 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"
+ ;;
+*-*-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
+ ;;
+*-*-freebsd*)
+ check_for_libcrypt_later=1
+ ;;
+*-*-openbsd*)
+ echo "Please use -current"
+ ;;
+*-*-solaris*)
+ if test "x$withval" != "xno" ; then
+ need_dash_r=1
+ fi
+ ;;
+*-*-sunos4*)
+ CPPFLAGS="$CPPFLAGS -DSUNOS4"
+ ;;
+esac
+#l959
+
+#l976
+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
+ ])
+])
+#l1012
+
+#l1063
+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 <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]) ]
+)
+#l1161
+
+#l1172
+dnl Checks for libutil functions
+AC_CHECK_HEADERS([libutil.h])
+AC_SEARCH_LIBS([fmt_scaled], [util bsd])
+AC_CHECK_FUNCS([fmt_scaled])
+AC_CHECK_HEADERS([libutil.h])
+AC_SEARCH_LIBS([fmt_scaled], [util bsd])
+#l1180
+
+#l1209
+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
+#l1215
+
+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 \
+ memmove \
+ setproctitle \
+ setregid \
+ setreuid \
+ strlcat \
+ strlcpy \
+ strnvis \
+ strtonum \
+ strmode \
+ sysconf \
+ waitpid \
+ )
+
+#l1627
+# 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 *])], [])])
+#l1641
+
+#l1648
+AC_CHECK_DECL([strsep],
+ [AC_CHECK_FUNCS([strsep])],
+ [],
+ [
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+ ])
+#l1655
+
+#l1672
+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>
+ ])
+#l1687
+
+#l1697
+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])
+#l1744
+
+#l1754
+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])])]
+)
+#l1758
+
+##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
+
+#l1767
+# 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
+#l1876
+
+#l1924
+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
+#l2049
+
+#l2068
+# 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
+ ]
+)
+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"
+ ]
+ )
+ ]
+)
+#l2261
+
+#l2321
+# 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
+#l2331
+
+#l2381
+### 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([OpenSSH 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])
+#l2566
+
+#l2691
+# 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 "OpenSSH 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
+#l3171
+
+#l3205
+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/types.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
+#l3429
+
+##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> ]
+)
+##chl part
+
+
+#l3651
+# 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])
+#l3663
+
+#l3707
+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
+#l3787
+
+#l3817
+# 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])
+#l3848
+
+#l4073
+# 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])
+#l4111
+
+
+dnl AC_DEFINE([_GNU_SOURCE], [], [Enable GNU Extensions])
+
+
+#l4348
+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
+#l4360
+
+##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
+ contrib/Makefile
+ contrib/libexec/Makefile
+ contrib/libexec/mail.local/Makefile
+ regress/Makefile
+ regress/bin/Makefile
+ ])
+
+#l4364
+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, sshd 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 " sshd 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 " sshd 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 sshd, 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..81e461fa
--- /dev/null
+++ b/contrib/lib/libc/asr/CVS/Entries
@@ -0,0 +1,28 @@
+/asr_utils.c/1.1/Sat Apr 14 09:24:18 2012//
+/getrrsetbyname_async.c/1.2/Result of merge//
+/hostaddr_async.c/1.2/Result of merge//
+/getnameinfo_async.c/1.4/Result of merge//
+/asr_resolver.c/1.10/Result of merge//
+/asr.h/1.3/Result of merge//
+/async_resolver.3/1.6/Sat Sep 8 09:11:38 2012//
+/getaddrinfo_async.c/1.8/Result of merge+Sat Sep 8 09:11:38 2012//
+/gethostnamadr_async.c/1.8/Result of merge//
+/getnetnamadr_async.c/1.4/Result of merge//
+/Makefile.inc/1.5/Tue Sep 11 20:09:17 2012//
+/asr.c/1.13/Result of merge+Tue Sep 11 20:09:18 2012//
+/asr_debug.c/1.8/Result of merge+Tue Sep 11 20:09:18 2012//
+/asr_private.h/1.8/Tue Sep 11 20:09:18 2012//
+/getaddrinfo.c/1.1/Sat Sep 8 11:08:21 2012//
+/gethostnamadr.c/1.1/Sat Sep 8 11:08:21 2012//
+/getnameinfo.c/1.1/Sat Sep 8 11:08:21 2012//
+/getnetnamadr.c/1.1/Sat Sep 8 11:08:21 2012//
+/getrrsetbyname.c/1.1/Sat Sep 8 11:08:21 2012//
+/res_debug.c/1.1/Sat Sep 8 11:08:21 2012//
+/res_init.c/1.1/Sat Sep 8 11:08:21 2012//
+/res_mkquery.c/1.1/Sat Sep 8 11:08:21 2012//
+/res_query.c/1.1/Sat Sep 8 11:08:21 2012//
+/res_search_async.c/1.2/Result of merge//
+/res_send.c/1.1/Sat Sep 8 11:08:21 2012//
+/res_send_async.c/1.4/Result of merge//
+/sethostent.c/1.1/Sat Sep 8 11:08:21 2012//
+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..2ed24029
--- /dev/null
+++ b/contrib/lib/libc/asr/asr.c
@@ -0,0 +1,1100 @@
+/* $OpenBSD: asr.c,v 1.13 2012/09/09 16:45:14 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 bind file\nnameserver 127.0.0.1\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);
+ 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);
+ }
+
+ 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);
+ if (asr->a_path)
+ 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_refcount);
+ if ((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 && !(as->as.dns.flags & ASYNC_EXTIBUF))
+ 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);
+ if (as->as.hostnamadr.dname)
+ free(as->as.hostnamadr.dname);
+ 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;
+ }
+
+ asr_check_reload(asr);
+ asr_ctx_ref(asr->a_ctx);
+ return (asr->a_ctx);
+}
+
+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_refcount);
+ 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 tp;
+#endif
+
+ if (asr->a_path == NULL)
+ return;
+
+#if ASR_OPT_RELOADCONF
+ if (clock_gettime(CLOCK_MONOTONIC, &tp) == -1)
+ return;
+
+ if ((tp.tv_sec - asr->a_rtime) < RELOAD_DELAY)
+ return;
+ asr->a_rtime = tp.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) {
+ strlcpy(buf, domain, buflen);
+ } else if (name[len - 1] != '.') {
+ if (domain[0] == '.')
+ domain += 1;
+ strlcpy(buf, name, buflen);
+ strlcat(buf, ".", buflen);
+ strlcat(buf, domain, buflen);
+ } else {
+ strlcpy(buf, name, buflen);
+ }
+
+ return (strlen(buf));
+}
+
+/*
+ * Concatenate a name and a domain name. The result has no trailing dot.
+ */
+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;
+ ac->ac_family[0] = AF_INET;
+ ac->ac_family[1] = AF_INET6;
+ ac->ac_family[2] = -1;
+
+ ac->ac_hostfile = DEFAULT_HOSTFILE;
+
+ ac->ac_nscount = 0;
+ ac->ac_nstimeout = 1000;
+ ac->ac_nsretries = 3;
+
+ 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")) {
+ /* ignore the line if we already set lookup */
+ if (ac->ac_dbcount != 0)
+ return;
+ if (n - 1 > ASR_MAXDB)
+ return;
+ /* 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;
+ for(i = 1; i < n; i++, ac->ac_dbcount++) {
+ if (!strcmp(tok[i], "yp")) {
+ ac->ac_db[i-1] = ASR_DB_YP;
+ } else if (!strcmp(tok[i], "bind")) {
+ ac->ac_db[i-1] = ASR_DB_DNS;
+ } else if (!strcmp(tok[i], "file")) {
+ ac->ac_db[i-1] = ASR_DB_FILE;
+ } else {
+ /* ignore the line */
+ ac->ac_dbcount = 0;
+ return;
+ }
+ }
+ } 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);
+ }
+
+ 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 0 if it could generate a new domain name, or -1 when all
+ * possibilites have been exhausted.
+ */
+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;
+ strlcpy(buf, name, len);
+ return (0);
+ }
+ /* 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;
+ strlcpy(buf, name, len);
+ return (0);
+ }
+ /* 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..0bdfb62a
--- /dev/null
+++ b/contrib/lib/libc/asr/asr.h
@@ -0,0 +1,105 @@
+/* $OpenBSD: asr.h,v 1.3 2012/09/06 08:36:52 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, unsigned char *, int,
+ struct asr *);
+struct async *res_query_async(const char *, int, int, unsigned char *, int,
+ struct asr *);
+struct async *res_search_async(const char *, int, int, unsigned char *, 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..8d3d57c9
--- /dev/null
+++ b/contrib/lib/libc/asr/asr_debug.c
@@ -0,0 +1,380 @@
+/* $OpenBSD: asr_debug.c,v 1.8 2012/09/09 12:15:32 eric Exp $ */
+/*
+ * Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <resolv.h>
+
+#include "asr.h"
+#include "asr_private.h"
+
+static const char* rcodetostr(uint16_t);
+static const char* print_dname(const char *, char *, size_t);
+static const char* print_header(const struct 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 packed p;
+ struct header h;
+ struct query q;
+ struct rr rr;
+ int i, an, ns, ar, n;
+
+ if (f == NULL)
+ return;
+
+ packed_init(&p, (char *)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)?"inet":"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..16b46243
--- /dev/null
+++ b/contrib/lib/libc/asr/asr_private.h
@@ -0,0 +1,363 @@
+/* $OpenBSD: asr_private.h,v 1.8 2012/09/09 12:15:32 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 packed {
+ char *data;
+ 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_EXTIBUF 0x00001000
+#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 bufpos;
+ size_t datalen; /* for tcp io */
+ } dns;
+
+ struct {
+ int flags;
+ int class;
+ int type;
+ char *name;
+ struct async *subq;
+ int saved_h_errno;
+ unsigned char *ibuf;
+ size_t ibuflen;
+ size_t ibufsize;
+ } search;
+
+ struct {
+ int flags;
+ int class;
+ int type;
+ char *name;
+ struct async *subq;
+ } rrset;
+
+ struct {
+ char *name;
+ int family;
+ char *dname;
+ struct async *subq;
+ char addr[16];
+ int addrlen;
+ } 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 packed_init(struct packed*, char*, size_t);
+int pack_header(struct packed*, const struct header*);
+int pack_query(struct packed*, uint16_t, uint16_t, const char*);
+int unpack_header(struct packed*, struct header*);
+int unpack_query(struct packed*, struct query*);
+int unpack_rr(struct packed*, 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, unsigned char *, int,
+ struct asr_ctx *);
+struct async *res_search_async_ctx(const char *, int, int, unsigned char *, 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..d718eaab
--- /dev/null
+++ b/contrib/lib/libc/asr/asr_utils.c
@@ -0,0 +1,456 @@
+/* $OpenBSD: asr_utils.c,v 1.1 2012/04/14 09:24:18 eric Exp $ */
+/*
+ * Copyright (c) 2009-2012 Eric Faurot <eric@faurot.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.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 packed*, void*, size_t);
+static int unpack_u16(struct packed*, uint16_t*);
+static int unpack_u32(struct packed*, uint32_t*);
+static int unpack_inaddr(struct packed*, struct in_addr*);
+static int unpack_in6addr(struct packed*, struct in6_addr*);
+static int unpack_dname(struct packed*, char*, size_t);
+
+static int pack_data(struct packed*, const void*, size_t);
+static int pack_u16(struct packed*, uint16_t);
+static int pack_dname(struct packed*, 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 = 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
+packed_init(struct packed *pack, char *data, size_t len)
+{
+ pack->data = data;
+ pack->len = len;
+ pack->offset = 0;
+ pack->err = NULL;
+}
+
+static int
+unpack_data(struct packed *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->data + p->offset, len);
+ p->offset += len;
+
+ return (0);
+}
+
+static int
+unpack_u16(struct packed *p, uint16_t *u16)
+{
+ if (unpack_data(p, u16, 2) == -1)
+ return (-1);
+
+ *u16 = ntohs(*u16);
+
+ return (0);
+}
+
+static int
+unpack_u32(struct packed *p, uint32_t *u32)
+{
+ if (unpack_data(p, u32, 4) == -1)
+ return (-1);
+
+ *u32 = ntohl(*u32);
+
+ return (0);
+}
+
+static int
+unpack_inaddr(struct packed *p, struct in_addr *a)
+{
+ return (unpack_data(p, a, 4));
+}
+
+static int
+unpack_in6addr(struct packed *p, struct in6_addr *a6)
+{
+ return (unpack_data(p, a6, 16));
+}
+
+static int
+unpack_dname(struct packed *p, char *dst, size_t max)
+{
+ ssize_t e;
+
+ if (p->err)
+ return (-1);
+
+ e = dname_expand(p->data, 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 packed *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 packed *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 packed *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->data + 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 packed *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->data + p->offset, data, len);
+ p->offset += len;
+
+ return (0);
+}
+
+static int
+pack_u16(struct packed *p, uint16_t v)
+{
+ v = htons(v);
+
+ return (pack_data(p, &v, 2));
+}
+
+static int
+pack_dname(struct packed *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 packed *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 packed *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;
+
+ 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:
+ 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;
+ 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..acb26781
--- /dev/null
+++ b/contrib/lib/libc/asr/async_resolver.3
@@ -0,0 +1,358 @@
+.\" $OpenBSD: async_resolver.3,v 1.6 2012/09/06 08:38:15 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: September 6 2012 $
+.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" "unsigned char *ans" "int anslen" "struct asr *asr"
+.Ft struct async*
+.Fn res_query_async "const char *name" "int class" "int type" "unsigned char *ans" "int anslen" "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 a configuration file cannot be loaded at context creation time, it falls
+back to the equivalent of:
+.Bd -literal -offset indent
+lookup bind file
+nameserver 127.0.0.1
+.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 they take a resolver context as
+last argument, and 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 no answer buffer is provided, a new one is allocated to fit the response
+and returned as the
+.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 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..c1e3ec23
--- /dev/null
+++ b/contrib/lib/libc/asr/getaddrinfo_async.c
@@ -0,0 +1,754 @@
+/* $OpenBSD: getaddrinfo_async.c,v 1.8 2012/09/06 15:05:16 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>
+#ifdef YP
+#include <rpc/rpc.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+#include "ypinternal.h"
+#endif
+
+#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)
+/* 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;
+ char fqdn[MAXDNAME];
+ 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;
+ }
+
+#ifdef EAI_PROTOCOL
+ if (ai->ai_protocol &&
+ ai->ai_protocol != IPPROTO_UDP &&
+ ai->ai_protocol != IPPROTO_TCP) {
+ ar->ar_gai_errno = EAI_PROTOCOL;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+#endif
+
+ if (ai->ai_socktype == SOCK_RAW &&
+ as->as.ai.servname != NULL) {
+ 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_FAIL;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+
+ /* start domain lookup */
+ async_set_state(as, ASR_STATE_NEXT_DOMAIN);
+ break;
+
+ case ASR_STATE_NEXT_DOMAIN:
+ r = asr_iter_domain(as, as->as.ai.hostname, fqdn, sizeof(fqdn));
+ if (r == -1) {
+ async_set_state(as, ASR_STATE_NOT_FOUND);
+ break;
+ }
+ if (r > (int)sizeof(fqdn)) {
+ ar->ar_gai_errno = EAI_OVERFLOW;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+ if (as->as.ai.fqdn)
+ free(as->as.ai.fqdn);
+ if ((as->as.ai.fqdn = strdup(fqdn)) == NULL) {
+ ar->ar_gai_errno = EAI_MEMORY;
+ async_set_state(as, ASR_STATE_HALT);
+ break;
+ }
+ as->as_db_idx = 0;
+ 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_NEXT_DOMAIN);
+ 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;
+ as->as.ai.subq = res_query_async_ctx(as->as.ai.fqdn,
+ C_IN, (family == AF_INET6) ? T_AAAA : T_A, NULL, 0,
+ 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_DB);
+ 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;
+
+ 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;
+
+ if (matches[i].protocol == IPPROTO_TCP)
+ port = as->as.ai.port_tcp;
+ else if (matches[i].protocol == 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 = matches[i].protocol;
+ 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.fqdn, 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)
+ c = tokens[1];
+ 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);
+}
+
+static int
+addrinfo_from_pkt(struct async *as, char *pkt, size_t pktlen)
+{
+ struct packed 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;
+
+ packed_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;
+
+ 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)
+ c = tokens[1];
+ 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);
+}
+#endif
diff --git a/contrib/lib/libc/asr/gethostnamadr.c b/contrib/lib/libc/asr/gethostnamadr.c
new file mode 100644
index 00000000..8bce1116
--- /dev/null
+++ b/contrib/lib/libc/asr/gethostnamadr.c
@@ -0,0 +1,153 @@
+/* $OpenBSD: gethostnamadr.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 <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;
+
+ end = buf + len;
+ ptr = (char**)buf; /* XXX align */
+
+ for (naliases = 0; h->h_aliases[naliases]; naliases++)
+ ;
+ for (naddrs = 0; h->h_addr_list[naddrs]; naddrs++)
+ ;
+
+ 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;
+
+ pos = (char*)(ptr + (naliases + 1) + (naddrs + 1));
+ if (pos > end) {
+ r->h_aliases = _empty;
+ r->h_addr_list = _empty;
+ return;
+ }
+ bzero(ptr, pos - (char*)ptr);
+
+ 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;
+ }
+
+ 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..4f3aa68a
--- /dev/null
+++ b/contrib/lib/libc/asr/gethostnamadr_async.c
@@ -0,0 +1,746 @@
+/* $OpenBSD: gethostnamadr_async.c,v 1.8 2012/09/06 15:05:16 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>
+#ifdef YP
+#include <rpc/rpc.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+#include "ypinternal.h"
+#endif
+
+#include "asr.h"
+#include "asr_private.h"
+
+
+#define MAXALIASES 16
+#define MAXADDRS 16
+
+#define HOSTENT_PTR(h) ((char**)(((char*)h) + sizeof (*h)))
+#define HOSTENT_POS(h) HOSTENT_PTR(h)[0]
+#define HOSTENT_STOP(h) HOSTENT_PTR(h)[1]
+#define HOSTENT_LEFT(h) (HOSTENT_STOP(h) - HOSTENT_POS(h))
+
+ssize_t addr_as_fqdn(const char *, int, char *, size_t);
+
+static int gethostnamadr_async_run(struct async *, struct async_res *);
+static struct hostent *hostent_alloc(int);
+static int hostent_set_cname(struct hostent *, const char *, int);
+static int hostent_add_alias(struct hostent *, const char *, int);
+static int hostent_add_addr(struct hostent *, const void *, int);
+static struct hostent *hostent_file_match(FILE *, int, int, const char *, int);
+static struct hostent *hostent_from_packet(int, int, char *, size_t);
+#ifdef YP
+static struct hostent *_yp_gethostnamadr(int, const void *);
+static struct hostent *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)
+{
+ int r, type;
+ FILE *f;
+ char dname[MAXDNAME], *data;
+
+ 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;
+ }
+
+ if (as->as_type == ASR_GETHOSTBYNAME)
+ async_set_state(as, ASR_STATE_NEXT_DOMAIN);
+ else
+ async_set_state(as, ASR_STATE_NEXT_DB);
+ break;
+
+ case ASR_STATE_NEXT_DOMAIN:
+
+ r = asr_iter_domain(as, as->as.hostnamadr.name, dname, sizeof(dname));
+ if (r == -1) {
+ async_set_state(as, ASR_STATE_NOT_FOUND);
+ break;
+ }
+
+ if (as->as.hostnamadr.dname)
+ free(as->as.hostnamadr.dname);
+ if ((as->as.hostnamadr.dname = strdup(dname)) == NULL) {
+ ar->ar_h_errno = NETDB_INTERNAL;
+ ar->ar_errno = errno;
+ async_set_state(as, ASR_STATE_HALT);
+ }
+
+ as->as_db_idx = 0;
+ async_set_state(as, ASR_STATE_NEXT_DB);
+ break;
+
+ case ASR_STATE_NEXT_DB:
+
+ if (asr_iter_db(as) == -1) {
+ if (as->as_type == ASR_GETHOSTBYNAME)
+ async_set_state(as, ASR_STATE_NEXT_DOMAIN);
+ else
+ 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_query_async_ctx(
+ as->as.hostnamadr.dname,
+ C_IN, type, NULL, 0, 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, NULL, 0, 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.dname;
+ else
+ data = as->as.hostnamadr.addr;
+
+ ar->ar_hostent = hostent_file_match(f, as->as_type,
+ as->as.hostnamadr.family, data,
+ as->as.hostnamadr.addrlen);
+
+ fclose(f);
+
+ if (ar->ar_hostent == 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_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.dname;
+ else
+ data = as->as.hostnamadr.addr;
+ ar->ar_hostent = _yp_gethostnamadr(as->as_type, data);
+ if (ar->ar_hostent == 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_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);
+ async_set_state(as, ASR_STATE_NEXT_DB);
+ break;
+ }
+
+ /* Read the hostent from the packet. */
+
+ ar->ar_hostent = hostent_from_packet(as->as_type,
+ as->as.hostnamadr.family, ar->ar_data, ar->ar_datalen);
+ free(ar->ar_data);
+
+ if (ar->ar_hostent == 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(ar->ar_hostent,
+ as->as.hostnamadr.addr,
+ as->as.hostnamadr.addrlen) == -1) {
+ free(ar->ar_hostent);
+ 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 &&
+ ar->ar_hostent->h_addr_list[0] == NULL) {
+ free(ar->ar_hostent);
+ async_set_state(as, ASR_STATE_NEXT_DB);
+ break;
+ }
+
+ 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_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;
+}
+
+/*
+ * 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 *
+hostent_file_match(FILE *f, int reqtype, int family, const char *data, int datalen)
+{
+ char *tokens[MAXTOKEN], addr[16];
+ struct hostent *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)
+ if (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_length) == -1)
+ goto fail;
+ return (h);
+fail:
+ free(h);
+ return (NULL);
+}
+
+/*
+ * Fill the hostent from the given DNS packet.
+ */
+static struct hostent *
+hostent_from_packet(int reqtype, int family, char *pkt, size_t pktlen)
+{
+ struct hostent *h;
+ struct packed p;
+ struct header hdr;
+ struct query q;
+ struct rr rr;
+
+ if ((h = hostent_alloc(family)) == NULL)
+ return (NULL);
+
+ packed_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_GETHOSTBYNAME) {
+ if (hostent_add_alias(h, rr.rr_dname, 1) == -1)
+ goto fail;
+ } else {
+ if (hostent_set_cname(h, rr.rr_dname, 1) == -1)
+ goto fail;
+ }
+ break;
+
+ case T_PTR:
+ if (reqtype != ASR_GETHOSTBYADDR)
+ break;
+ 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)
+ goto fail;
+ 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)
+ goto fail;
+ 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 *
+hostent_alloc(int family)
+{
+ struct hostent *h;
+ size_t alloc;
+
+ alloc = sizeof(*h) + (2 + MAXALIASES + MAXADDRS) * sizeof(char*) + 1024;
+ if ((h = calloc(1, alloc)) == NULL)
+ return (NULL);
+
+ h->h_addrtype = family;
+ h->h_length = (family == AF_INET) ? 4 : 16;
+ h->h_aliases = HOSTENT_PTR(h) + 2;
+ h->h_addr_list = h->h_aliases + MAXALIASES;
+
+ HOSTENT_STOP(h) = (char*)(h) + alloc;
+ HOSTENT_POS(h) = (char*)(h->h_addr_list + MAXADDRS);
+
+ return (h);
+}
+
+static int
+hostent_set_cname(struct hostent *h, const char *name, int isdname)
+{
+ char buf[MAXDNAME];
+
+ if (h->h_name)
+ return (0);
+
+ if (isdname) {
+ asr_strdname(name, buf, sizeof buf);
+ buf[strlen(buf) - 1] = '\0';
+ name = buf;
+ }
+ if (strlen(name) + 1 >= HOSTENT_LEFT(h))
+ return (1);
+
+ strlcpy(HOSTENT_POS(h), name, HOSTENT_LEFT(h));
+ h->h_name = HOSTENT_POS(h);
+ HOSTENT_POS(h) += strlen(name) + 1;
+
+ return (0);
+}
+
+static int
+hostent_add_alias(struct hostent *h, const char *name, int isdname)
+{
+ char buf[MAXDNAME];
+ size_t i;
+
+ for (i = 0; i < MAXALIASES - 1; i++)
+ if (h->h_aliases[i] == NULL)
+ break;
+ if (i == MAXALIASES - 1)
+ return (0);
+
+ if (isdname) {
+ asr_strdname(name, buf, sizeof buf);
+ buf[strlen(buf)-1] = '\0';
+ name = buf;
+ }
+ if (strlen(name) + 1 >= HOSTENT_LEFT(h))
+ return (1);
+
+ strlcpy(HOSTENT_POS(h), name, HOSTENT_LEFT(h));
+ h->h_aliases[i] = HOSTENT_POS(h);
+ HOSTENT_POS(h) += strlen(name) + 1;
+
+ return (0);
+}
+
+static int
+hostent_add_addr(struct hostent *h, const void *addr, int size)
+{
+ int i;
+
+ for (i = 0; i < MAXADDRS - 1; i++)
+ if (h->h_addr_list[i] == NULL)
+ break;
+ if (i == MAXADDRS - 1)
+ return (0);
+
+ if (size >= HOSTENT_LEFT(h))
+ return (1);
+
+ memmove(HOSTENT_POS(h), addr, size);
+ h->h_addr_list[i] = HOSTENT_POS(h);
+ HOSTENT_POS(h) += 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 *
+_yp_gethostnamadr(int type, const void *data)
+{
+ static char *domain = NULL;
+ struct hostent *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 *
+hostent_from_yp(int family, char *line)
+{
+ struct hostent *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_name)
+ hostent_set_cname(h, tokens[1], 0);
+ else if (strcmp(h->h_name, tokens[1]))
+ i = 1;
+ for (; i < ntok; i++)
+ hostent_add_alias(h, tokens[i], 0);
+ }
+
+ if (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..37e3e22a
--- /dev/null
+++ b/contrib/lib/libc/asr/getnameinfo_async.c
@@ -0,0 +1,277 @@
+/* $OpenBSD: getnameinfo_async.c,v 1.4 2012/08/19 16:17:40 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"
+
+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)
+{
+ 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)
+ /* errno set */
+ return (-1);
+
+ return (0);
+}
diff --git a/contrib/lib/libc/asr/getnetnamadr.c b/contrib/lib/libc/asr/getnetnamadr.c
new file mode 100644
index 00000000..28315123
--- /dev/null
+++ b/contrib/lib/libc/asr/getnetnamadr.c
@@ -0,0 +1,124 @@
+/* $OpenBSD: getnetnamadr.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 <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;
+
+ end = buf + len;
+ ptr = (char**)buf; /* XXX align */
+
+ 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;
+ return;
+ }
+ bzero(ptr, pos - (char *)ptr);
+
+ 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..c535434a
--- /dev/null
+++ b/contrib/lib/libc/asr/getnetnamadr_async.c
@@ -0,0 +1,440 @@
+/* $OpenBSD: getnetnamadr_async.c,v 1.4 2012/09/07 13:21:34 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
+
+#define NETENT_PTR(n) ((char**)(((char*)n) + sizeof (*n)))
+#define NETENT_POS(n) NETENT_PTR(n)[0]
+#define NETENT_STOP(n) NETENT_PTR(n)[1]
+#define NETENT_LEFT(n) (NETENT_STOP(n) - NETENT_POS(n))
+
+ssize_t addr_as_fqdn(const char *, int, char *, size_t);
+
+static int getnetnamadr_async_run(struct async *, struct async_res *);
+static struct netent *netent_alloc(int);
+static int netent_set_cname(struct netent *, const char *, int);
+static int netent_add_alias(struct netent *, const char *, int);
+static struct netent *netent_file_match(FILE *, int, const char *);
+static struct netent *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)
+{
+ int r, type;
+ 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, NULL, 0, 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, NULL, 0, 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;
+
+ ar->ar_netent = netent_file_match(f, as->as_type, data);
+ fclose(f);
+
+ if (ar->ar_netent == 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_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;
+ }
+
+ ar->ar_netent = netent_from_packet(as->as_type, ar->ar_data,
+ ar->ar_datalen);
+ free(ar->ar_data);
+
+ if (ar->ar_netent == 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)
+ ar->ar_netent->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 &&
+ ar->ar_netent->n_net == 0) {
+ /* XXX wrong */
+ free(ar->ar_netent);
+ async_set_state(as, ASR_STATE_NEXT_DB);
+ } else {
+ 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 *
+netent_file_match(FILE *f, int reqtype, const char *data)
+{
+ struct netent *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_net = inet_network(tokens[1]);
+ return (e);
+fail:
+ free(e);
+ return (NULL);
+}
+
+static struct netent *
+netent_from_packet(int reqtype, char *pkt, size_t pktlen)
+{
+ struct netent *n;
+ struct packed p;
+ struct header hdr;
+ struct query q;
+ struct rr rr;
+
+ if ((n = netent_alloc(AF_INET)) == NULL)
+ return (NULL);
+
+ packed_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_addrtype != AF_INET)
+ break;
+ if (netent_set_cname(n, rr.rr_dname, 1) == -1)
+ goto fail;
+ n->n_net = ntohl(rr.rr.in_a.addr.s_addr);
+ break;
+ }
+ }
+
+ return (n);
+fail:
+ free(n);
+ return (NULL);
+}
+
+static struct netent *
+netent_alloc(int family)
+{
+ struct netent *n;
+ size_t alloc;
+
+ alloc = sizeof(*n) + (2 + MAXALIASES) * sizeof(char*) + 1024;
+ if ((n = calloc(1, alloc)) == NULL)
+ return (NULL);
+
+ n->n_addrtype = family;
+ n->n_aliases = NETENT_PTR(n) + 2;
+
+ NETENT_STOP(n) = (char*)(n) + alloc;
+ NETENT_POS(n) = (char *)(n->n_aliases + MAXALIASES);
+
+ return (n);
+}
+
+static int
+netent_set_cname(struct netent *n, const char *name, int isdname)
+{
+ char buf[MAXDNAME];
+
+ if (n->n_name)
+ return (0);
+
+ if (isdname) {
+ asr_strdname(name, buf, sizeof buf);
+ buf[strlen(buf) - 1] = '\0';
+ name = buf;
+ }
+ if (strlen(name) + 1 >= NETENT_LEFT(n))
+ return (1);
+
+ strlcpy(NETENT_POS(n), name, NETENT_LEFT(n));
+ n->n_name = NETENT_POS(n);
+ NETENT_POS(n) += strlen(name) + 1;
+
+ return (0);
+}
+
+static int
+netent_add_alias(struct netent *n, const char *name, int isdname)
+{
+ char buf[MAXDNAME];
+ size_t i;
+
+ for (i = 0; i < MAXALIASES - 1; i++)
+ if (n->n_aliases[i] == NULL)
+ break;
+ if (i == MAXALIASES - 1)
+ return (0);
+
+ if (isdname) {
+ asr_strdname(name, buf, sizeof buf);
+ buf[strlen(buf)-1] = '\0';
+ name = buf;
+ }
+ if (strlen(name) + 1 >= NETENT_LEFT(n))
+ return (1);
+
+ strlcpy(NETENT_POS(n), name, NETENT_LEFT(n));
+ n->n_aliases[i] = NETENT_POS(n);
+ NETENT_POS(n) += strlen(name) + 1;
+
+ 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..a9ec809b
--- /dev/null
+++ b/contrib/lib/libc/asr/getrrsetbyname_async.c
@@ -0,0 +1,590 @@
+/* $OpenBSD: getrrsetbyname_async.c,v 1.2 2012/08/18 13:49:13 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,
+ NULL, 0, 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.2 2012/08/18 13:49:13 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..dedf558c
--- /dev/null
+++ b/contrib/lib/libc/asr/res_mkquery.c
@@ -0,0 +1,104 @@
+/* $OpenBSD: res_mkquery.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 <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 packed 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] != '.') {
+ strlcpy(fqdn, dname, sizeof fqdn);
+ if (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;
+
+ packed_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 ] != '.')) {
+ domain = ndom;
+ strlcpy(ndom, domain, sizeof ndom);
+ strlcat(ndom, ".", sizeof ndom);
+ }
+
+ if (asr_make_fqdn(name, domain, fqdn, sizeof fqdn) == 0) {
+ h_errno = NO_RECOVERY;
+ 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..b0c1cf15
--- /dev/null
+++ b/contrib/lib/libc/asr/res_query.c
@@ -0,0 +1,91 @@
+/* $OpenBSD: res_query.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 <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;
+
+ if (ans == NULL || anslen <= 0) {
+ h_errno = NO_RECOVERY;
+ errno = EINVAL;
+ return (-1);
+ }
+
+ as = res_query_async(name, class, type, ans, anslen, 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);
+
+ 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;
+
+ if (ans == NULL || anslen <= 0) {
+ h_errno = NO_RECOVERY;
+ errno = EINVAL;
+ return (-1);
+ }
+
+ as = res_search_async(name, class, type, ans, anslen, 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);
+
+ 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..6399c7f3
--- /dev/null
+++ b/contrib/lib/libc/asr/res_search_async.c
@@ -0,0 +1,223 @@
+/* $OpenBSD: res_search_async.c,v 1.2 2012/09/09 09:42:06 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>
+
+/*
+ * TODO:
+ *
+ * - make it possible to reuse ibuf if it was NULL when first called,
+ * to avoid reallocating buffers everytime.
+ */
+
+#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, unsigned char *ans,
+ int anslen, 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, ans, anslen, ac);
+ asr_ctx_unref(ac);
+
+ return (as);
+}
+
+struct async *
+res_search_async_ctx(const char *name, int class, int type, unsigned char *ans,
+ int anslen, 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 */
+
+ if (ans) {
+ as->as.search.flags |= ASYNC_EXTIBUF;
+ as->as.search.ibuf = ans;
+ as->as.search.ibufsize = anslen;
+ } else {
+ as->as.search.ibuf = NULL;
+ as->as.search.ibufsize = 0;
+ }
+ as->as.search.ibuflen = 0;
+
+ 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 > sizeof(fqdn)) {
+ 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.search.ibuf, as->as.search.ibufsize, 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;
+ }
+
+ /*
+ * If we don't use an external buffer, the packet was allocated
+ * by the subquery and it must be freed now.
+ */
+ if ((as->as.search.flags & ASYNC_EXTIBUF) == 0)
+ free(ar->ar_data);
+
+ /*
+ * The original resolver does something like this, to
+ */
+ 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..77d1a69c
--- /dev/null
+++ b/contrib/lib/libc/asr/res_send.c
@@ -0,0 +1,50 @@
+/* $OpenBSD: res_send.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 <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;
+
+ if (ans == NULL || anslen <= 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ as = res_send_async(buf, buflen, ans, anslen, NULL);
+ if (as == NULL)
+ return (-1); /* errno set */
+
+ async_run_sync(as, &ar);
+
+ if (ar.ar_errno) {
+ errno = ar.ar_errno;
+ return (-1);
+ }
+
+ 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..387c131a
--- /dev/null
+++ b/contrib/lib/libc/asr/res_send_async.c
@@ -0,0 +1,768 @@
+/* $OpenBSD: res_send_async.c,v 1.4 2012/09/09 12:15:32 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 <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, unsigned char *ans,
+ int anslen, struct asr *asr)
+{
+ struct asr_ctx *ac;
+ struct async *as;
+ struct packed 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;
+
+ if (ans) {
+ as->as.dns.flags |= ASYNC_EXTIBUF;
+ as->as.dns.ibuf = ans;
+ as->as.dns.ibufsize = anslen;
+ as->as.dns.ibuflen = 0;
+ } else {
+ as->as.dns.ibuf = NULL;
+ as->as.dns.ibufsize = 0;
+ as->as.dns.ibuflen = 0;
+ }
+
+ as->as.dns.flags |= ASYNC_EXTOBUF;
+ as->as.dns.obuf = (unsigned char*)buf;
+ as->as.dns.obuflen = buflen;
+ as->as.dns.obufsize = buflen;
+
+ packed_init(&p, (char*)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, unsigned char *ans,
+ int anslen, 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, ans, anslen, ac);
+ asr_ctx_unref(ac);
+
+ return (as);
+}
+
+struct async *
+res_query_async_ctx(const char *name, int class, int type, unsigned char *ans,
+ int anslen, 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;
+
+ if (ans) {
+ as->as.dns.flags |= ASYNC_EXTIBUF;
+ as->as.dns.ibuf = ans;
+ as->as.dns.ibufsize = anslen;
+ } else {
+ as->as.dns.ibuf = NULL;
+ as->as.dns.ibufsize = 0;
+ }
+ as->as.dns.ibuflen = 0;
+
+ /* This adds a "." to name if it doesn't already has one.
+ * That's how res_query() behaves (trough 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) {
+ 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 packed 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;
+
+ packed_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 */
+
+ as->as_timeout = as->as_ctx->ac_nstimeout;
+
+ 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;
+
+ /* Allocate input buf if needed */
+ if (as->as.dns.ibuf == NULL) {
+ 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 iovec iov[2];
+ uint16_t len;
+ ssize_t n;
+ int i, se;
+ socklen_t sl;
+#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_timeout = as->as_ctx->ac_nstimeout;
+ return (1);
+ }
+
+ i = 0;
+
+ /* Check if the connection succeeded. */
+ if (as->as.dns.datalen == 0) {
+ sl = sizeof(se);
+ if (getsockopt(as->as_fd, SOL_SOCKET, SO_ERROR, &se, &sl) == -1)
+ goto close; /* errno set */
+ if (se) {
+ errno = se;
+ goto close;
+ }
+
+ as->as.dns.bufpos = 0;
+
+ /* Send the packet length first */
+ len = htons(as->as.dns.obuflen);
+ iov[i].iov_base = &len;
+ iov[i].iov_len = sizeof(len);
+ i++;
+ }
+
+ iov[i].iov_base = as->as.dns.obuf + as->as.dns.bufpos;
+ iov[i].iov_len = as->as.dns.obuflen - as->as.dns.bufpos;
+ i++;
+
+ n = writev(as->as_fd, iov, i);
+ if (n == -1)
+ goto close; /* errno set */
+
+ /*
+ * We want at least the packet length to be written out the first time.
+ * Technically we could recover but that makes little sense to support
+ * that.
+ */
+ if (as->as.dns.datalen == 0 && n < 2) {
+ errno = EIO;
+ goto close;
+ }
+
+ if (as->as.dns.datalen == 0) {
+ as->as.dns.datalen = len;
+ n -= 2;
+ }
+
+ as->as.dns.bufpos += n;
+ if (as->as.dns.bufpos == as->as.dns.obuflen) {
+ /* All sent. Prepare for TCP read */
+ as->as.dns.datalen = 0;
+ return (0);
+ }
+
+ /* More data to write */
+ as->as_timeout = as->as_ctx->ac_nstimeout;
+ 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)
+{
+ uint16_t len;
+ ssize_t n;
+ int save_errno;
+
+ /* We must read the packet len first */
+ if (as->as.dns.datalen == 0) {
+ n = read(as->as_fd, &len, sizeof(len));
+ if (n == -1)
+ goto close; /* errno set */
+ /*
+ * If the server has sent us only the first byte, we fail.
+ * Technically, we could recover but it might not be worth
+ * supporting that.
+ */
+ if (n < 2) {
+ errno = EIO;
+ goto close;
+ }
+
+ as->as.dns.datalen = ntohs(len);
+ as->as.dns.bufpos = 0;
+ as->as.dns.ibuflen = 0;
+
+ if (ensure_ibuf(as, as->as.dns.datalen) == -1)
+ goto close; /* errno set */
+ }
+
+ n = read(as->as_fd, as->as.dns.ibuf + as->as.dns.ibuflen,
+ as->as.dns.datalen - as->as.dns.ibuflen);
+ if (n == -1)
+ goto close; /* errno set */
+ if (n == 0) {
+ errno = ECONNRESET;
+ goto close;
+ }
+ as->as.dns.ibuflen += n;
+
+ /* See if we got all the advertised bytes. */
+ if (as->as.dns.ibuflen != as->as.dns.datalen)
+ 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.
+ * If not (or not allocated) allocated enough space, unless the
+ * buffer is external (owned by the caller), in which case it fails.
+ */
+static int
+ensure_ibuf(struct async *as, size_t n)
+{
+ char *t;
+
+ if (as->as.dns.flags & ASYNC_EXTIBUF) {
+ if (n <= as->as.dns.ibufsize)
+ return (0);
+ errno = EINVAL;
+ return (-1);
+ }
+
+ 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 packed p;
+ struct header h;
+ struct query q;
+ struct rr rr;
+ int r;
+
+ packed_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/openbsd-compat/Makefile.am b/openbsd-compat/Makefile.am
new file mode 100644
index 00000000..f09f4d79
--- /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 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..537af38e
--- /dev/null
+++ b/openbsd-compat/NOTES
@@ -0,0 +1,32 @@
+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
+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/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
+mktemp.c portable openssh
+openbsd-compat.h portable openssh
+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..761ae60f
--- /dev/null
+++ b/openbsd-compat/imsg.c
@@ -0,0 +1,325 @@
+/* $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(int n)
+{
+ int i, 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;
+ return (-1);
+ }
+
+ if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) {
+ if (errno == EMSGSIZE)
+ goto fail;
+ if (errno != EINTR && errno != EAGAIN)
+ goto fail;
+ goto again;
+ }
+
+ ibuf->r.wpos += n;
+
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_RIGHTS) {
+ int i;
+ int j;
+
+ /*
+ * We only accept one file descriptor. Due to C
+ * padding rules, our control buffer might contain
+ * more than one fd, and we must close them.
+ */
+ j = ((char *)cmsg + cmsg->cmsg_len -
+ (char *)CMSG_DATA(cmsg)) / sizeof(int);
+ for (i = 0; i < j; i++) {
+ fd = ((int *)CMSG_DATA(cmsg))[i];
+ if (i == 0) {
+ 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..d0ae5e6f
--- /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(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..b228b445
--- /dev/null
+++ b/openbsd-compat/openbsd-compat.h
@@ -0,0 +1,176 @@
+/* $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_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/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..5cf0587b
--- /dev/null
+++ b/openbsd-compat/sys-queue.h
@@ -0,0 +1,612 @@
+/* $OpenBSD: queue.h,v 1.32 2007/04/30 18:42:34 pedro 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_PREVPTR(var, varp, head, field) \
+ for ((varp) = &SLIST_FIRST((head)); \
+ ((var) = *(varp)) != SLIST_END(head); \
+ (varp) = &SLIST_NEXT((var), field))
+
+/*
+ * 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_NEXT(head, 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))
+
+/*
+ * 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))
+
+/*
+ * 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)
+
+/*
+ * 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_REVERSE(var, head, headname, field) \
+ for((var) = TAILQ_LAST(head, headname); \
+ (var) != TAILQ_END(head); \
+ (var) = TAILQ_PREV(var, headname, field))
+
+/*
+ * 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_REVERSE(var, head, field) \
+ for((var) = CIRCLEQ_LAST(head); \
+ (var) != CIRCLEQ_END(head); \
+ (var) = CIRCLEQ_PREV(var, field))
+
+/*
+ * 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..d4949b5e
--- /dev/null
+++ b/openbsd-compat/sys-tree.h
@@ -0,0 +1,679 @@
+/* $OpenBSD: tree.h,v 1.10 2007/10/29 23:49:41 djm 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 */
+
+#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)
+#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) \
+void name##_RB_INSERT_COLOR(struct name *, struct type *); \
+void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
+struct type *name##_RB_REMOVE(struct name *, struct type *); \
+struct type *name##_RB_INSERT(struct name *, struct type *); \
+struct type *name##_RB_FIND(struct name *, struct type *); \
+struct type *name##_RB_NEXT(struct type *); \
+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) \
+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; \
+} \
+ \
+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; \
+} \
+ \
+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 */ \
+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 */ \
+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); \
+} \
+ \
+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); \
+} \
+ \
+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_NEXT(name, x, y) name##_RB_NEXT(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))
+
+#endif /* _SYS_TREE_H_ */
diff --git a/openbsd-compat/vis.c b/openbsd-compat/vis.c
new file mode 100644
index 00000000..3a087b34
--- /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)
+
+#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..4cfc0f95
--- /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)
+
+#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 */
diff --git a/openbsd-compat/xmalloc.c b/openbsd-compat/xmalloc.c
new file mode 100644
index 00000000..d4f18727
--- /dev/null
+++ b/openbsd-compat/xmalloc.c
@@ -0,0 +1,127 @@
+/* $OpenBSD: xmalloc.c,v 1.8 2007/02/22 06:42:10 otto Exp $ */
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ * All rights reserved
+ * Versions of malloc and friends that check their results, and never return
+ * failure (they call fatal if they encounter an error).
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose. Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#include "includes.h"
+
+#include <err.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "log.h"
+#include "xmalloc.h"
+
+void *
+__xmalloc(size_t size)
+{
+ void *ptr;
+
+ if (size == 0)
+ fatal("xmalloc: zero size");
+ ptr = malloc(size);
+ if (ptr == NULL)
+ err(255, "fatal: xmalloc: out of memory (allocating %lu bytes)", (u_long) size);
+ return ptr;
+}
+
+void *
+__xcalloc(size_t nmemb, size_t size)
+{
+ void *ptr;
+
+ if (size == 0 || nmemb == 0)
+ fatal("xcalloc: zero size");
+ if (SIZE_T_MAX / nmemb < size)
+ fatal("xcalloc: nmemb * size > SIZE_T_MAX");
+ ptr = calloc(nmemb, size);
+ if (ptr == NULL)
+ err(255, "fatal: xcalloc: out of memory (allocating %lu bytes)",
+ (u_long)(size * nmemb));
+ return ptr;
+}
+
+void *
+__xrealloc(void *ptr, size_t nmemb, size_t size)
+{
+ void *new_ptr;
+ size_t new_size = nmemb * size;
+
+ if (new_size == 0)
+ fatal("xrealloc: zero size");
+ if (SIZE_T_MAX / nmemb < size)
+ fatal("xrealloc: nmemb * size > SIZE_T_MAX");
+ if (ptr == NULL)
+ new_ptr = malloc(new_size);
+ else
+ new_ptr = realloc(ptr, new_size);
+ if (new_ptr == NULL)
+ err(255, "fatal: xrealloc: out of memory (new_size %lu bytes)",
+ (u_long) new_size);
+ return new_ptr;
+}
+
+void
+__xfree(void *ptr)
+{
+ if (ptr == NULL)
+ fatal("xfree: NULL pointer given as argument");
+ free(ptr);
+}
+
+char *
+__xstrdup(const char *str)
+{
+ size_t len;
+ char *cp;
+
+ len = strlen(str) + 1;
+ cp = __xmalloc(len);
+ strlcpy(cp, str, len);
+ return cp;
+}
+
+int
+xasprintf(char **ret, const char *fmt, ...)
+{
+ va_list ap;
+ int i;
+
+ va_start(ap, fmt);
+ i = vasprintf(ret, fmt, ap);
+ va_end(ap);
+
+ if (i < 0 || *ret == NULL)
+ fatal("xasprintf: could not allocate memory");
+
+ return (i);
+}
+
+int
+xsnprintf(char *str, size_t size, const char *fmt, ...)
+{
+ va_list ap;
+ int i;
+
+ va_start(ap, fmt);
+ i = vsnprintf(str, size, fmt, ap);
+ va_end(ap);
+
+ if (i == -1 || i >= (int)size)
+ fatal("xsnprintf: overflow");
+
+ return (i);
+}
diff --git a/openbsd-compat/xmalloc.h b/openbsd-compat/xmalloc.h
new file mode 100644
index 00000000..da1c4cbb
--- /dev/null
+++ b/openbsd-compat/xmalloc.h
@@ -0,0 +1,35 @@
+/* $OpenBSD: xmalloc.h,v 1.3 2007/01/29 16:22:29 xsa Exp $ */
+
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ * All rights reserved
+ * Created: Mon Mar 20 22:09:17 1995 ylo
+ *
+ * Versions of malloc and friends that check their results, and never return
+ * failure (they call fatal if they encounter an error).
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose. Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#ifndef XMALLOC_H
+#define XMALLOC_H
+
+void *__xmalloc(size_t);
+void *__xcalloc(size_t, size_t);
+void *__xrealloc(void *, size_t, size_t);
+void __xfree(void *);
+char *__xstrdup(const char *);
+int xasprintf(char **, const char *, ...)
+ __attribute__((__format__ (printf, 2, 3)))
+ __attribute__((__nonnull__ (2)));
+int xsnprintf(char *, size_t, const char *, ...)
+ __attribute__((__format__ (printf, 3, 4)))
+ __attribute__((__nonnull__ (3)));
+// __attribute__((__bounded__ (__string__,1,2)));
+
+#endif /* XMALLOC_H */
diff --git a/regress/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..79274921
--- /dev/null
+++ b/regress/bin/Makefile.am
@@ -0,0 +1,25 @@
+bin_PROGRAMS= smtpscript
+
+smtpscript_SOURCES= smtpscript.c iobuf.c parse.y
+
+# 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 f0611549..7f254847 100644
--- a/regress/bin/parse.y
+++ b/regress/bin/parse.y
@@ -23,9 +23,11 @@
*/
%{
+#include "includes.h"
+
#include <sys/types.h>
-#include <sys/queue.h>
-#include <sys/tree.h>
+#include "sys-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.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 94a5fc7b..00000000
--- a/regress/bin/smtpscript/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-.PATH: ${.CURDIR}/..
-
-PROG= smtpscript
-SRCS= smtpscript.c iobuf.c parse.y
-NOMAN= noman
-
-LDADD= -lutil
-CPPFLAGS+= -I${.CURDIR}/..
-
-.include <bsd.prog.mk>
diff --git a/smtpd/Makefile b/smtpd/Makefile
deleted file mode 100644
index 98cb2c8c..00000000
--- a/smtpd/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# $OpenBSD: Makefile,v 1.9 2009/03/18 01:56:52 jacekm Exp $
-
-.include <bsd.own.mk>
-
-SUBDIR = makemap smtpd smtpctl
-
-.include <bsd.subdir.mk>
diff --git a/smtpd/Makefile.am b/smtpd/Makefile.am
new file mode 100644
index 00000000..55bf9147
--- /dev/null
+++ b/smtpd/Makefile.am
@@ -0,0 +1,166 @@
+# 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
+
+sbin_PROGRAMS= smtpd smtpctl
+pkglibexec_PROGRAMS= makemap
+
+makemap_SOURCES= parse.y makemap.c aliases.c expand.c log.c util.c \
+ table.c table_db.c table_getpwnam.c table_static.c \
+ tree.c
+
+makemap_CFLAGS= -DNO_IO
+
+smtpd_SOURCES= aliases.c auth.c bounce.c compress_backend.c config.c \
+ control.c delivery.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 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 stat_backend.c table.c \
+ tree.c user.c util.c
+# backends
+smtpd_SOURCES+= auth_bsd.c
+smtpd_SOURCES+= auth_pwd.c
+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+= queue_fsqueue.c
+smtpd_SOURCES+= queue_ram.c
+smtpd_SOURCES+= scheduler_ramqueue.c
+smtpd_SOURCES+= stat_ramstat.c
+#smtpd_SOURCES+= stat_sqlite.c
+smtpd_SOURCES+= table_db.c
+smtpd_SOURCES+= table_getpwnam.c
+smtpd_SOURCES+= table_static.c
+smtpd_SOURCES+= user_pwd.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
+
+smtpd_CFLAGS= -DIO_SSL -DASR_OPT_THREADSAFE=0
+
+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
+
+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/aliases.c b/smtpd/aliases.c
index 08045b87..763b2c5a 100644
--- a/smtpd/aliases.c
+++ b/smtpd/aliases.c
@@ -16,20 +16,27 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <ctype.h>
#include <errno.h>
#include <event.h>
-#include <imsg.h>
+#include "imsg.h"
#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/auth.c b/smtpd/auth.c
index 0c54f781..a694f16b 100644
--- a/smtpd/auth.c
+++ b/smtpd/auth.c
@@ -16,9 +16,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
diff --git a/smtpd/auth_bsd.c b/smtpd/auth_bsd.c
index b9aba84e..d0fbb6fb 100644
--- a/smtpd/auth_bsd.c
+++ b/smtpd/auth_bsd.c
@@ -16,14 +16,18 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
+#ifdef BSD_AUTH
#include <bsd_auth.h>
+#endif
#include <event.h>
#include <imsg.h>
#include <stdio.h>
@@ -39,5 +43,9 @@ struct auth_backend auth_backend_bsd = {
static int
auth_bsd(char *username, char *password)
{
+#ifdef BSD_AUTH
return auth_userokay(username, NULL, "auth-smtp", password);
+#else
+ return 0;
+#endif
}
diff --git a/smtpd/auth_pwd.c b/smtpd/auth_pwd.c
index 1e44f72a..49df634c 100644
--- a/smtpd/auth_pwd.c
+++ b/smtpd/auth_pwd.c
@@ -16,13 +16,18 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
+#ifdef HAVE_CRYPT_H
+#include <crypt.h> /* needed for crypt() */
+#endif
#include <event.h>
#include <imsg.h>
#include <pwd.h>
diff --git a/smtpd/bounce.c b/smtpd/bounce.c
index 7772f6fd..37ce100c 100644
--- a/smtpd/bounce.c
+++ b/smtpd/bounce.c
@@ -18,9 +18,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
diff --git a/smtpd/compress_backend.c b/smtpd/compress_backend.c
index 802adf77..d3c60d6a 100644
--- a/smtpd/compress_backend.c
+++ b/smtpd/compress_backend.c
@@ -16,9 +16,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
diff --git a/smtpd/compress_gzip.c b/smtpd/compress_gzip.c
index 2d388268..8256fce1 100644
--- a/smtpd/compress_gzip.c
+++ b/smtpd/compress_gzip.c
@@ -17,9 +17,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
diff --git a/smtpd/config.c b/smtpd/config.c
index edb62a56..b251d682 100644
--- a/smtpd/config.c
+++ b/smtpd/config.c
@@ -16,9 +16,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
@@ -220,3 +222,32 @@ config_peers(struct peer *p, uint peercount)
}
}
}
+
+#ifdef VALGRIND
+void free_peers(void)
+{
+ u_int i;
+
+ for (i = 0; i < PROC_COUNT; i++)
+ if (env->sc_ievs[i])
+ free(env->sc_ievs[i]);
+}
+
+void free_pipes(void)
+{
+ u_int i;
+ u_int j;
+
+ for (i = 0; i < PROC_COUNT; i++)
+ for (j = 0; j < PROC_COUNT; j++) {
+
+ if (i >= j || env->sc_instances[i] == 0 ||
+ env->sc_instances[j] == 0)
+ continue;
+
+ free(env->sc_pipes[i][j]);
+ free(env->sc_pipes[j][i]);
+
+ }
+}
+#endif
diff --git a/smtpd/control.c b/smtpd/control.c
index 92e7c2f6..7ff514b2 100644
--- a/smtpd/control.c
+++ b/smtpd/control.c
@@ -18,9 +18,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/socket.h>
@@ -30,7 +32,8 @@
#include <errno.h>
#include <event.h>
#include <fcntl.h>
-#include <imsg.h>
+#include <grp.h> /* needed for setgroups */
+#include "imsg.h"
#include <pwd.h>
#include <signal.h>
#include <stdio.h>
@@ -268,6 +271,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);
@@ -293,7 +303,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);
@@ -347,7 +357,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 1f959276..26757dd3 100644
--- a/smtpd/delivery.c
+++ b/smtpd/delivery.c
@@ -16,9 +16,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
diff --git a/smtpd/delivery_filename.c b/smtpd/delivery_filename.c
index f4bc4880..750fd4bf 100644
--- a/smtpd/delivery_filename.c
+++ b/smtpd/delivery_filename.c
@@ -16,9 +16,14 @@
* 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>
+#include "sys-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
@@ -70,7 +75,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_maildir.c b/smtpd/delivery_maildir.c
index b8cec128..6f795908 100644
--- a/smtpd/delivery_maildir.c
+++ b/smtpd/delivery_maildir.c
@@ -16,9 +16,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
diff --git a/smtpd/delivery_mbox.c b/smtpd/delivery_mbox.c
index afab9831..58622225 100644
--- a/smtpd/delivery_mbox.c
+++ b/smtpd/delivery_mbox.c
@@ -16,9 +16,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
@@ -36,7 +38,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 8dae5f8b..187894e9 100644
--- a/smtpd/delivery_mda.c
+++ b/smtpd/delivery_mda.c
@@ -16,9 +16,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
diff --git a/smtpd/dns.c b/smtpd/dns.c
index 1caf4060..e6de6461 100644
--- a/smtpd/dns.c
+++ b/smtpd/dns.c
@@ -18,10 +18,12 @@
* 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>
-#include <sys/queue.h>
+#include "sys-tree.h"
+#include "sys-queue.h"
#include <sys/uio.h>
#include <netinet/in.h>
@@ -29,7 +31,9 @@
#include <arpa/nameser.h>
#include <event.h>
-#include <imsg.h>
+#include <netdb.h>
+#include <resolv.h>
+#include "imsg.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -146,7 +150,7 @@ dns_async(struct imsgev *asker, int type, struct dns *query)
return;
case IMSG_DNS_PTR:
s->as = getnameinfo_async((struct sockaddr*)&query->ss,
- query->ss.ss_len,
+ SS_LEN(&query->ss),
s->query.host, sizeof(s->query.host), NULL, 0, 0, NULL);
stat_increment("lka.session.cname", 1);
if (s->as == NULL) {
@@ -327,7 +331,7 @@ next:
dns_reply(query, IMSG_DNS_HOST);
s->mxfound++;
}
- freeaddrinfo(ar.ar_addrinfo);
+ asr_freeaddrinfo(ar.ar_addrinfo);
}
s->as = NULL;
diff --git a/smtpd/enqueue.c b/smtpd/enqueue.c
index 4c959a6c..9e1d7dfb 100644
--- a/smtpd/enqueue.c
+++ b/smtpd/enqueue.c
@@ -17,10 +17,12 @@
* 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-queue.h"
#include <sys/socket.h>
-#include <sys/tree.h>
+#include "sys-tree.h"
#include <sys/types.h>
#include <ctype.h>
diff --git a/smtpd/envelope.c b/smtpd/envelope.c
index 5235b5ba..843f6b36 100644
--- a/smtpd/envelope.c
+++ b/smtpd/envelope.c
@@ -16,9 +16,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
@@ -31,7 +33,7 @@
#include <errno.h>
#include <event.h>
#include <fcntl.h>
-#include <imsg.h>
+#include "imsg.h"
#include <inttypes.h>
#include <libgen.h>
#include <pwd.h>
@@ -514,14 +516,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 b2b2113c..a5720b54 100644
--- a/smtpd/expand.c
+++ b/smtpd/expand.c
@@ -17,9 +17,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.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 4be84923..deacc1bf 100644
--- a/smtpd/filter_api.c
+++ b/smtpd/filter_api.c
@@ -16,8 +16,10 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "includes.h"
+
#include <sys/types.h>
-#include <sys/queue.h>
+#include "sys-queue.h"
#include <sys/uio.h>
#include <err.h>
diff --git a/smtpd/forward.c b/smtpd/forward.c
index ff1a5580..3464bce0 100644
--- a/smtpd/forward.c
+++ b/smtpd/forward.c
@@ -16,9 +16,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
diff --git a/smtpd/iobuf.c b/smtpd/iobuf.c
index a9e4a2de..5fd9f677 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/param.h>
#include <sys/socket.h>
#include <sys/uio.h>
diff --git a/smtpd/ioev.c b/smtpd/ioev.c
index d9d5633f..37d1438d 100644
--- a/smtpd/ioev.c
+++ b/smtpd/ioev.c
@@ -15,8 +15,10 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "includes.h"
+
#include <sys/param.h>
-#include <sys/queue.h>
+#include "sys-queue.h"
#include <sys/socket.h>
#include <err.h>
@@ -588,10 +590,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 6c627f47..00000000
--- a/smtpd/libsmtpdfilter/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-<<<<<<< HEAD
-# $OpenBSD: Makefile,v 1.2 2012/06/16 16:16:09 chl Exp $
-=======
-# $OpenBSD: Makefile,v 1.3 2012/08/02 13:38:39 okan Exp $
->>>>>>> master
-
-.PATH: ${.CURDIR}/..
-
-LIB= smtpdfilter
-SRCS= filter_api.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 f898227d..72359265 100644
--- a/smtpd/lka.c
+++ b/smtpd/lka.c
@@ -17,9 +17,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/wait.h>
@@ -30,7 +32,9 @@
#include <err.h>
#include <errno.h>
#include <event.h>
-#include <imsg.h>
+#include <netdb.h>
+#include <grp.h> /* needed for setgroups */
+#include "imsg.h"
#include <pwd.h>
#include <resolv.h>
#include <signal.h>
@@ -254,6 +258,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 99ec94a0..f6d88c0f 100644
--- a/smtpd/lka_session.c
+++ b/smtpd/lka_session.c
@@ -17,9 +17,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/wait.h>
@@ -29,7 +31,7 @@
#include <ctype.h>
#include <errno.h>
#include <event.h>
-#include <imsg.h>
+#include "imsg.h"
#include <resolv.h>
#include <pwd.h>
#include <signal.h>
@@ -325,6 +327,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.as_user, xn->u.user, sizeof(fwreq.as_user));
imsg_compose_event(env->sc_ievs[PROC_PARENT],
diff --git a/smtpd/log.c b/smtpd/log.c
index df0c074f..38cc285f 100644
--- a/smtpd/log.c
+++ b/smtpd/log.c
@@ -16,9 +16,11 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "includes.h"
+
#include <sys/types.h>
-#include <sys/queue.h>
-#include <sys/tree.h>
+#include "sys-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
@@ -30,6 +32,8 @@
#include <string.h>
#include <syslog.h>
#include <time.h>
+#include <unistd.h> /* getpid */
+
#include "log.h"
@@ -77,6 +81,7 @@ vlog(int pri, const char *fmt, va_list ap)
char *nfmt;
if (debug) {
+ fprintf(stderr, "%d: ", getpid());
/* best effort in out of mem situations */
if (asprintf(&nfmt, "%s\n", fmt) == -1) {
vfprintf(stderr, fmt, ap);
diff --git a/smtpd/log.h b/smtpd/log.h
index 1b58f205..7e80929b 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.8 b/smtpd/makemap.8
index fe08a98a..bab64466 100644
--- a/smtpd/makemap.8
+++ b/smtpd/makemap.8
@@ -85,8 +85,8 @@ In addition to adding an entry to the primary domain map,
one must add a filter rule that accepts mail for the domain
map, for example:
.Bd -literal -offset indent
-map primary "/etc/mail/primary"
-accept for domain map primary deliver to mbox
+map "primary" { source db "/etc/mail/primary.db" }
+accept for domain map "primary" deliver to mbox
.Ed
.Sh VIRTUAL DOMAINS
Virtual domains are kept in maps.
diff --git a/smtpd/makemap.c b/smtpd/makemap.c
index 969a7469..92ec614b 100644
--- a/smtpd/makemap.c
+++ b/smtpd/makemap.c
@@ -17,15 +17,26 @@
* 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-tree.h"
+#include "sys-queue.h"
#include <sys/param.h>
#include <sys/socket.h>
-#include <db.h>
#include <ctype.h>
+#ifdef HAVE_DB_H
+#include <db.h>
+#elif defined(HAVE_DB1_DB_H)
+#include <db1/db.h>
+#elif defined(HAVE_DB_185_H)
+#include <db_185.h>
+#endif
#include <err.h>
#include <errno.h>
#include <event.h>
@@ -34,13 +45,18 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <util.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;
@@ -191,7 +207,16 @@ main(int argc, char *argv[])
if (mkstemp(dbname) == -1)
err(1, "mkstemp");
- 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 ff5cca0e..00000000
--- a/smtpd/makemap/Makefile
+++ /dev/null
@@ -1,25 +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 \
- table_static.c table_db.c table_getpwnam.c tree.c
-
-DPADD+= ${LIBUTIL} ${LIBCRYPTO}
-LDADD+= -lutil -lcrypto
-.include <bsd.prog.mk>
diff --git a/smtpd/mda.c b/smtpd/mda.c
index 556e16eb..e38f4eec 100644
--- a/smtpd/mda.c
+++ b/smtpd/mda.c
@@ -19,9 +19,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
@@ -29,7 +31,8 @@
#include <err.h>
#include <errno.h>
#include <event.h>
-#include <imsg.h>
+#include <grp.h> /* needed for setgroups */
+#include "imsg.h"
#include <inttypes.h>
#include <pwd.h>
#include <signal.h>
@@ -38,7 +41,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"
@@ -100,6 +105,10 @@ mda_imsg(struct imsgev *iev, struct imsg *imsg)
uint32_t id;
int n;
+#ifdef VALGRIND
+ bzero(&deliver, sizeof(deliver));
+#endif
+
if (iev->proc == PROC_QUEUE) {
switch (imsg->hdr.type) {
@@ -330,6 +339,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 9032b4d5..e42cdc7e 100644
--- a/smtpd/mfa.c
+++ b/smtpd/mfa.c
@@ -17,17 +17,20 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "includes.h"
+
#include <sys/types.h>
#include <sys/wait.h>
-#include <sys/queue.h>
-#include <sys/tree.h>
+#include "sys-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <err.h>
#include <errno.h>
#include <event.h>
-#include <imsg.h>
+#include <grp.h> /* needed for setgroups */
+#include "imsg.h"
#include <pwd.h>
#include <signal.h>
#include <stdio.h>
@@ -170,6 +173,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);
}
@@ -246,6 +256,10 @@ mfa_test_connect(struct envelope *e)
{
struct submit_status ss;
+#ifdef VALGRIND
+ bzero(&ss, sizeof(ss));
+#endif
+
ss.id = e->session_id;
ss.code = 530;
ss.envelope = *e;
@@ -258,6 +272,10 @@ mfa_test_helo(struct envelope *e)
{
struct submit_status ss;
+#ifdef VALGRIND
+ bzero(&ss, sizeof(ss));
+#endif
+
ss.id = e->session_id;
ss.code = 530;
ss.envelope = *e;
@@ -270,6 +288,10 @@ mfa_test_mail(struct envelope *e)
{
struct submit_status ss;
+#ifdef VALGRIND
+ bzero(&ss, sizeof(ss));
+#endif
+
ss.id = e->session_id;
ss.code = 530;
ss.u.maddr = e->sender;
@@ -301,6 +323,10 @@ mfa_test_rcpt(struct envelope *e)
{
struct submit_status ss;
+#ifdef VALGRIND
+ bzero(&ss, sizeof(ss));
+#endif
+
ss.id = e->session_id;
ss.code = 530;
ss.u.maddr = e->rcpt;
@@ -420,8 +446,7 @@ mfa_fork_filter(struct filter *filter)
/* filter */
dup2(sockpair[0], STDIN_FILENO);
- if (closefrom(STDERR_FILENO + 1) < 0)
- exit(1);
+ closefrom(STDERR_FILENO + 1);
execl(filter->path, filter->name, NULL);
exit(1);
diff --git a/smtpd/mfa_session.c b/smtpd/mfa_session.c
index 3309550d..36fb8fc8 100644
--- a/smtpd/mfa_session.c
+++ b/smtpd/mfa_session.c
@@ -16,9 +16,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/wait.h>
@@ -28,7 +30,7 @@
#include <ctype.h>
#include <errno.h>
#include <event.h>
-#include <imsg.h>
+#include "imsg.h"
#include <resolv.h>
#include <signal.h>
#include <stdio.h>
diff --git a/smtpd/mta.c b/smtpd/mta.c
index 246c40bb..69c21d75 100644
--- a/smtpd/mta.c
+++ b/smtpd/mta.c
@@ -19,9 +19,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
@@ -32,6 +34,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>
@@ -215,6 +218,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);
}
diff --git a/smtpd/mta_session.c b/smtpd/mta_session.c
index 759e716d..95bab2a8 100644
--- a/smtpd/mta_session.c
+++ b/smtpd/mta_session.c
@@ -19,9 +19,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
@@ -272,6 +274,10 @@ mta_enter_state(struct mta_session *s, int newstate)
int max_reuse;
ssize_t q;
+#ifdef VALGRIND
+ bzero(&batch, sizeof(batch));
+#endif
+
again:
oldstate = s->state;
diff --git a/smtpd/parse.y b/smtpd/parse.y
index e4d85494..4e423832 100644
--- a/smtpd/parse.y
+++ b/smtpd/parse.y
@@ -22,9 +22,12 @@
*/
%{
+#include "includes.h"
+
#include <sys/types.h>
-#include <sys/queue.h>
-#include <sys/tree.h>
+#include <sys/time.h>
+#include "sys-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
@@ -39,16 +42,19 @@
#include <errno.h>
#include <event.h>
#include <ifaddrs.h>
-#include <imsg.h>
+#include "imsg.h"
#include <inttypes.h>
#include <netdb.h>
#include <paths.h>
#include <pwd.h>
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#ifdef HAVE_UTIL_H
#include <util.h>
+#endif
#include "smtpd.h"
#include "log.h"
@@ -1468,7 +1474,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;
@@ -1489,7 +1497,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));
@@ -1537,13 +1547,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;
@@ -1615,14 +1629,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;
@@ -1664,6 +1682,10 @@ set_localaddrs(void)
table_add(m, "0.0.0.0/0", NULL);
table_add(m, "::/0", NULL);
+#ifdef VALGRIND
+ bzero(&ss, sizeof(ss));
+#endif
+
if (getifaddrs(&ifap) == -1)
fatal("getifaddrs");
@@ -1677,14 +1699,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(m, 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(m, ss_to_text(&ss), NULL);
break;
}
@@ -1742,6 +1768,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;
@@ -1779,4 +1810,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 f7b255bb..adfb6eb1 100644
--- a/smtpd/parser.c
+++ b/smtpd/parser.c
@@ -18,10 +18,12 @@
* 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>
-#include <sys/tree.h>
+#include "sys-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <event.h>
@@ -33,20 +35,6 @@
#include "parser.h"
-enum token_type {
- NOTOKEN,
- ENDTOKEN,
- KEYWORD,
- VARIABLE
-};
-
-struct token {
- enum token_type type;
- const char *keyword;
- int value;
- const struct token *next;
-};
-
static const struct token t_log[];
static const struct token t_main[];
static const struct token t_pause[];
diff --git a/smtpd/parser.h b/smtpd/parser.h
index 1687c2db..ba4893ed 100644
--- a/smtpd/parser.h
+++ b/smtpd/parser.h
@@ -45,4 +45,18 @@ struct parse_result {
const char *data;
};
+enum token_type {
+ NOTOKEN,
+ ENDTOKEN,
+ KEYWORD,
+ VARIABLE
+};
+
+struct token {
+ enum token_type type;
+ const char *keyword;
+ int value;
+ const struct token *next;
+};
+
struct parse_result *parse(int, char *[]);
diff --git a/smtpd/queue.c b/smtpd/queue.c
index 14b0f183..d0acb611 100644
--- a/smtpd/queue.c
+++ b/smtpd/queue.c
@@ -18,16 +18,20 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "includes.h"
+
#include <sys/types.h>
-#include <sys/queue.h>
-#include <sys/tree.h>
+#include "sys-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <err.h>
#include <event.h>
-#include <imsg.h>
+#include <fcntl.h>
+#include <grp.h> /* needed for setgroups */
+#include "imsg.h"
#include <inttypes.h>
#include <libgen.h>
#include <pwd.h>
@@ -59,6 +63,10 @@ queue_imsg(struct imsgev *iev, struct imsg *imsg)
uint64_t id;
uint32_t msgid;
+#ifdef VALGRIND
+ bzero(&ss, sizeof(ss));
+#endif
+
if (iev->proc == PROC_SMTP) {
e = imsg->data;
@@ -356,6 +364,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 90e7e43a..d4d46495 100644
--- a/smtpd/queue_backend.c
+++ b/smtpd/queue_backend.c
@@ -16,9 +16,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
diff --git a/smtpd/queue_fsqueue.c b/smtpd/queue_fsqueue.c
index eaa34d74..e52b9673 100644
--- a/smtpd/queue_fsqueue.c
+++ b/smtpd/queue_fsqueue.c
@@ -16,9 +16,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
@@ -523,7 +525,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_ram.c b/smtpd/queue_ram.c
index 9f2e09c7..fc42c1fa 100644
--- a/smtpd/queue_ram.c
+++ b/smtpd/queue_ram.c
@@ -16,9 +16,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
diff --git a/smtpd/ruleset.c b/smtpd/ruleset.c
index dcc135aa..d2f81f08 100644
--- a/smtpd/ruleset.c
+++ b/smtpd/ruleset.c
@@ -16,9 +16,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
@@ -124,7 +126,7 @@ ruleset_cmp_source(const char *s1, const char *s2)
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 ruleset_match_mask(&n1.ss, &n2);
diff --git a/smtpd/scheduler.c b/smtpd/scheduler.c
index e5c406c7..1bf838bd 100644
--- a/smtpd/scheduler.c
+++ b/smtpd/scheduler.c
@@ -19,9 +19,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
@@ -31,6 +33,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 0e144d66..0a03a365 100644
--- a/smtpd/scheduler_backend.c
+++ b/smtpd/scheduler_backend.c
@@ -16,9 +16,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
diff --git a/smtpd/scheduler_ramqueue.c b/smtpd/scheduler_ramqueue.c
index 3a05db17..cb97a5c9 100644
--- a/smtpd/scheduler_ramqueue.c
+++ b/smtpd/scheduler_ramqueue.c
@@ -17,9 +17,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
diff --git a/smtpd/smtp.c b/smtpd/smtp.c
index c501248b..72902b90 100644
--- a/smtpd/smtp.c
+++ b/smtpd/smtp.c
@@ -18,16 +18,19 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <err.h>
#include <errno.h>
#include <event.h>
-#include <imsg.h>
+#include <grp.h> /* needed for setgroups */
+#include "imsg.h"
#include <netdb.h>
#include <pwd.h>
#include <signal.h>
@@ -294,6 +297,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);
}
@@ -384,8 +394,10 @@ smtp_setup_events(void)
ssl_setup(l);
}
+ /* 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
@@ -553,12 +565,7 @@ smtp_destroy(struct session *session)
static int
smtp_can_accept(void)
{
- uint32_t max;
-
- max = (getdtablesize() - getdtablecount())/2 - SMTP_FD_RESERVE;
- if (sessions < max)
- return 1;
- return 0;
+ return (!available_fds(SMTP_FD_RESERVE + 2));
}
/*
diff --git a/smtpd/smtp_session.c b/smtpd/smtp_session.c
index 983019af..deffe96d 100644
--- a/smtpd/smtp_session.c
+++ b/smtpd/smtp_session.c
@@ -19,9 +19,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
@@ -450,6 +452,7 @@ session_rfc5321_mail_handler(struct session *s, char *args)
session_enter_state(s, S_MAIL_MFA);
session_imsg(s, PROC_MFA, IMSG_MFA_MAIL, 0, 0, -1, &s->s_msg,
sizeof(s->s_msg));
+
return 1;
}
@@ -1094,6 +1097,7 @@ session_destroy(struct session *s, const char * reason)
if (s->s_flags & F_ZOMBIE)
goto finalize;
+ log_debug("session_destroy: s->datafp = %p", s->datafp);
if (s->datafp != NULL)
fclose(s->datafp);
diff --git a/smtpd/smtpctl.c b/smtpd/smtpctl.c
index 3854190e..97bd7f8c 100644
--- a/smtpd/smtpctl.c
+++ b/smtpd/smtpctl.c
@@ -19,13 +19,21 @@
* 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>
-#include <sys/tree.h>
+#include "sys-queue.h"
+#include "sys-tree.h"
#include <sys/un.h>
#include <sys/param.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 3c046ad1..00000000
--- a/smtpd/smtpctl/Makefile
+++ /dev/null
@@ -1,27 +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
-
-LDADD+= -lutil -lz
-DPADD+= ${LIBUTIL} ${LIBZ}
-.include <bsd.prog.mk>
diff --git a/smtpd/smtpd.8 b/smtpd/smtpd.8
index 3edb2e09..09c280a9 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 05020be8..9c1fdb78 100644
--- a/smtpd/smtpd.c
+++ b/smtpd/smtpd.c
@@ -18,9 +18,12 @@
* 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>
+#include "sys-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/wait.h>
@@ -31,9 +34,13 @@
#include <dirent.h>
#include <err.h>
#include <errno.h>
-#include <fcntl.h>
#include <event.h>
-#include <imsg.h>
+#include <fcntl.h>
+#include <grp.h> /* needed for setgroups */
+#ifdef HAVE_LOGIN_CAP_H
+#include <login_cap.h>
+#endif
+#include "imsg.h"
#include <paths.h>
#include <pwd.h>
#include <signal.h>
@@ -114,6 +121,30 @@ static int profstat;
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
+}
+#endif /* VALGRIND */
+
static void
parent_imsg(struct imsgev *iev, struct imsg *imsg)
{
@@ -254,6 +285,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);
}
@@ -303,10 +343,15 @@ parent_send_config_listeners(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");
imsg_compose_event(env->sc_ievs[PROC_SMTP], IMSG_CONF_LISTENER,
0, 0, l->fd, l, sizeof(*l));
@@ -488,7 +533,7 @@ parent_sig_handler(int sig, short event, void *p)
int
main(int argc, char *argv[])
{
- int c;
+ int c, i;
int debug, verbose;
int opts, flags;
const char *conffile = CONF_FILE;
@@ -508,6 +553,19 @@ main(int argc, char *argv[])
{ PROC_QUEUE, imsg_dispatch }
};
+ /* 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;
@@ -607,6 +665,8 @@ main(int argc, char *argv[])
if (parse_config(&smtpd, conffile, opts))
exit(1);
+ seed_rng();
+
if (strlcpy(env->sc_conffile, conffile, MAXPATHLEN) >= MAXPATHLEN)
errx(1, "config file exceeds MAXPATHLEN");
@@ -712,6 +772,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");
@@ -790,7 +852,10 @@ child_add(pid_t pid, int type, const char *title)
void
imsg_event_add(struct imsgev *iev)
{
+ int err;
+
if (iev->handler == NULL) {
+ log_debug("imsg_event_add: iev->handler=NULL");
imsg_flush(&iev->ibuf);
return;
}
@@ -799,9 +864,11 @@ imsg_event_add(struct imsgev *iev)
if (iev->ibuf.w.queued)
iev->events |= EV_WRITE;
- event_del(&iev->ev);
+ if ((err = event_del(&iev->ev)) != 0)
+ fatal("imsg_event_add: event_del");
event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data);
- event_add(&iev->ev, NULL);
+ if ((err = event_add(&iev->ev, NULL)) != 0)
+ fatal("imsg_event_add: event_add");
}
void
@@ -960,8 +1027,7 @@ forkmda(struct imsgev *iev, uint32_t id,
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, &u.gid) ||
setresgid(u.gid, u.gid, u.gid) ||
setresuid(u.uid, u.uid, u.uid))
@@ -1060,10 +1126,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) {
@@ -1080,10 +1148,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);
@@ -1212,7 +1281,6 @@ imsg_dispatch(int fd, short event, void *p)
return;
}
}
-
if (event & EV_WRITE) {
if (msgbuf_write(&iev->ibuf.w) == -1)
err(1, "%s: msgbuf_write", proc_to_str(smtpd_process));
diff --git a/smtpd/smtpd.conf b/smtpd/smtpd.conf
new file mode 100644
index 00000000..bc6aa32d
--- /dev/null
+++ b/smtpd/smtpd.conf
@@ -0,0 +1,18 @@
+# $OpenBSD: smtpd.conf,v 1.5 2012/10/11 21:16:28 gilles Exp $
+
+# 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
+#
+# XXX try to find a portable way to get the IP interface
+#listen on lo0
+listen on 127.0.0.1
+
+map aliases source db "/etc/mail/aliases.db"
+
+# 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 a86bedf5..61371921 100644
--- a/smtpd/smtpd.conf.5
+++ b/smtpd/smtpd.conf.5
@@ -480,9 +480,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 8db7395c..bf98c6cf 100644
--- a/smtpd/smtpd.h
+++ b/smtpd/smtpd.h
@@ -18,6 +18,16 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#if LIBEVENT_MAJOR_VERSION < 2
+#include <event.h>
+#else
+#include <event2/event_struct.h>
+#endif
+
+#include "imsg.h"
+
+#include "openbsd-compat.h"
+
#ifndef nitems
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
#endif
@@ -26,7 +36,11 @@
#include "ioev.h"
#include "iobuf.h"
-#define CONF_FILE "/etc/mail/smtpd.conf"
+
+#ifndef SMTPD_CONFDIR
+#define SMTPD_CONFDIR "/etc"
+#endif
+#define CONF_FILE SMTPD_CONFDIR "/smtpd.conf"
#define MAX_LISTEN 16
#define PROC_COUNT 9
#define MAX_NAME_SIZE 64
@@ -47,14 +61,21 @@
#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"
-#define SMTPD_FILTER_USER "_smtpmfa"
-#define SMTPD_SOCKET "/var/run/smtpd.sock"
-#define SMTPD_BANNER "220 %s ESMTP OpenSMTPD"
+#endif
+#define SMTPD_FILTER_USER SMTPD_USER "mfa"
+#ifndef SMTPD_SOCKDIR
+#define SMTPD_SOCKDIR "/var/run"
+#endif
+#define SMTPD_SOCKET SMTPD_SOCKDIR "/smtpd.sock"
+#define SMTPD_BANNER "220 %s ESMTP OpenSMTPD-portable"
#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"
@@ -982,6 +1003,10 @@ void configure(void);
void init_pipes(void);
void config_pipes(struct peer *, uint);
void config_peers(struct peer *, uint);
+#ifdef VALGRIND
+void free_pipes(void);
+void free_peers(void);
+#endif
/* control.c */
@@ -1236,6 +1261,7 @@ int text_to_netaddr(struct netaddr *, const char *);
int text_to_relayhost(struct relayhost *, const char *);
void *xmalloc(size_t, const char *);
void *xcalloc(size_t, size_t, const char *);
+void *xrealloc(void *, size_t, const char *);
char *xstrdup(const char *, const char *);
void *xmemdup(const void *, size_t, const char *);
void iobuf_xinit(struct iobuf *, size_t, size_t, const char *);
diff --git a/smtpd/smtpd/Makefile b/smtpd/smtpd/Makefile
deleted file mode 100644
index 13fe166c..00000000
--- a/smtpd/smtpd/Makefile
+++ /dev/null
@@ -1,53 +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 auth.c bounce.c compress_backend.c config.c \
- control.c delivery.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 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 stat_backend.c table.c \
- tree.c user.c util.c
-
-# backends
-SRCS+= auth_bsd.c
-SRCS+= auth_pwd.c
-SRCS+= compress_gzip.c
-SRCS+= delivery_filename.c
-SRCS+= delivery_maildir.c
-SRCS+= delivery_mbox.c
-SRCS+= delivery_mda.c
-SRCS+= table_db.c
-SRCS+= table_getpwnam.c
-SRCS+= table_static.c
-SRCS+= queue_fsqueue.c
-SRCS+= queue_ram.c
-SRCS+= scheduler_ramqueue.c
-SRCS+= stat_ramstat.c
-#SRCS+= stat_sqlite.c
-SRCS+= user_pwd.c
-
-# resolver
-SRCS+= asr.c asr_debug.c asr_utils.c gethostnamadr_async.c \
- res_send_async.c getaddrinfo_async.c getnameinfo_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+= -DASR_OPT_THREADSAFE=0
-YFLAGS=
-
-.include <bsd.prog.mk>
diff --git a/smtpd/smtpfilter.c b/smtpd/smtpfilter.c
index 01c81a99..cb8cc00d 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 e88cd923..c3556e45 100644
--- a/smtpd/ssl.c
+++ b/smtpd/ssl.c
@@ -17,15 +17,22 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
#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 <pwd.h>
@@ -160,7 +167,7 @@ ssl_load_certfile(const char *name, uint8_t flags)
(void)strlcpy(s->ssl_name, key.ssl_name, sizeof(s->ssl_name));
if (! bsnprintf(certfile, sizeof(certfile),
- "/etc/mail/certs/%s.crt", name))
+ SMTPD_CONFDIR "/certs/%s.crt", name))
goto err;
s->ssl_cert = ssl_load_file(certfile, &s->ssl_cert_len, 0755);
@@ -168,7 +175,7 @@ ssl_load_certfile(const char *name, uint8_t flags)
goto err;
if (! bsnprintf(certfile, sizeof(certfile),
- "/etc/mail/certs/%s.key", name))
+ SMTPD_CONFDIR "/certs/%s.key", name))
goto err;
s->ssl_key = ssl_load_file(certfile, &s->ssl_key_len, 0700);
@@ -176,7 +183,7 @@ ssl_load_certfile(const char *name, uint8_t flags)
goto err;
if (! bsnprintf(certfile, sizeof(certfile),
- "/etc/mail/certs/%s.ca", name))
+ SMTPD_CONFDIR "/certs/%s.ca", name))
goto err;
s->ssl_ca = ssl_load_file(certfile, &s->ssl_ca_len, 0755);
@@ -187,7 +194,7 @@ ssl_load_certfile(const char *name, uint8_t flags)
}
if (! bsnprintf(certfile, sizeof(certfile),
- "/etc/mail/certs/%s.dh", name))
+ SMTPD_CONFDIR "/certs/%s.dh", name))
goto err;
s->ssl_dhparams = ssl_load_file(certfile, &s->ssl_dhparams_len, 0755);
diff --git a/smtpd/ssl_privsep.c b/smtpd/ssl_privsep.c
index 20c02cfe..9f018372 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/stat_backend.c b/smtpd/stat_backend.c
index 8a935d70..e40b0edd 100644
--- a/smtpd/stat_backend.c
+++ b/smtpd/stat_backend.c
@@ -14,10 +14,12 @@
* 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>
-#include <sys/tree.h>
+#include "sys-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <event.h>
diff --git a/smtpd/stat_ramstat.c b/smtpd/stat_ramstat.c
index 43165214..2f774c63 100644
--- a/smtpd/stat_ramstat.c
+++ b/smtpd/stat_ramstat.c
@@ -13,11 +13,12 @@
* 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 <sys/queue.h>
-#include <sys/tree.h>
+#include "sys-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <event.h>
diff --git a/smtpd/table.c b/smtpd/table.c
index 902076d3..6f769bff 100644
--- a/smtpd/table.c
+++ b/smtpd/table.c
@@ -16,9 +16,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
diff --git a/smtpd/table_db.c b/smtpd/table_db.c
index e53298f1..de1bdf20 100644
--- a/smtpd/table_db.c
+++ b/smtpd/table_db.c
@@ -16,13 +16,21 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.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 <event.h>
diff --git a/smtpd/table_getpwnam.c b/smtpd/table_getpwnam.c
index 10277f25..d7a6bdaa 100644
--- a/smtpd/table_getpwnam.c
+++ b/smtpd/table_getpwnam.c
@@ -16,9 +16,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
diff --git a/smtpd/table_static.c b/smtpd/table_static.c
index 92445c7f..3accab4c 100644
--- a/smtpd/table_static.c
+++ b/smtpd/table_static.c
@@ -16,9 +16,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
diff --git a/smtpd/tree.c b/smtpd/tree.c
index fe83d333..da41574f 100644
--- a/smtpd/tree.c
+++ b/smtpd/tree.c
@@ -16,8 +16,10 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "includes.h"
+
#include <sys/types.h>
-#include <sys/tree.h>
+#include "sys-tree.h"
#include <sys/socket.h> /* for smtpd.h */
#include <sys/queue.h> /* for smtpd.h */
diff --git a/smtpd/user.c b/smtpd/user.c
index 12aad9d6..749ab9b9 100644
--- a/smtpd/user.c
+++ b/smtpd/user.c
@@ -16,9 +16,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
diff --git a/smtpd/user_pwd.c b/smtpd/user_pwd.c
index 341a897b..33dec408 100644
--- a/smtpd/user_pwd.c
+++ b/smtpd/user_pwd.c
@@ -16,9 +16,11 @@
* 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-queue.h"
+#include "sys-tree.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
diff --git a/smtpd/util.c b/smtpd/util.c
index f4528286..0f4ee44b 100644
--- a/smtpd/util.c
+++ b/smtpd/util.c
@@ -19,10 +19,12 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "includes.h"
+
#include <sys/types.h>
#include <sys/param.h>
-#include <sys/queue.h>
-#include <sys/tree.h>
+#include "sys-queue.h"
+#include "sys-tree.h"
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/resource.h>
@@ -78,6 +80,17 @@ xcalloc(size_t nmemb, size_t size, const char *where)
return (r);
}
+void *
+xrealloc(void *p, size_t size, const char *where)
+{
+ void *r;
+
+ if ((r = realloc(p, size)) == NULL)
+ errx(1, "%s: realloc(%p, %zu)", where, p, size);
+
+ return (r);
+}
+
char *
xstrdup(const char *str, const char *where)
{
@@ -636,7 +649,9 @@ 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 {
bzero(&ssin6, sizeof(struct sockaddr_in6));
@@ -659,7 +674,9 @@ text_to_netaddr(struct netaddr *netaddr, const char *s)
}
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 {
@@ -668,13 +685,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;
}
@@ -857,7 +878,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");
@@ -898,6 +919,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");
@@ -950,7 +973,9 @@ log_in6addr(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));
@@ -971,7 +996,7 @@ log_sockaddr(struct sockaddr *sa)
{
static char buf[NI_MAXHOST];
- if (getnameinfo(sa, sa->sa_len, buf, sizeof(buf), NULL, 0,
+ if (getnameinfo(sa, SA_LEN(sa), buf, sizeof(buf), NULL, 0,
NI_NUMERICHOST))
return ("(unknown)");
else
diff --git a/smtpd/waitq.c b/smtpd/waitq.c
index eefc990c..fee793a0 100644
--- a/smtpd/waitq.c
+++ b/smtpd/waitq.c
@@ -16,9 +16,11 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "includes.h"
+
#include <sys/types.h>
-#include <sys/tree.h>
-#include <sys/queue.h>
+#include "sys-queue.h"
+#include "sys-tree.h"
#include <sys/uio.h>
#include <imsg.h>