summaryrefslogtreecommitdiffstats
path: root/third_party/heimdal/lib/roken
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:20:00 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:20:00 +0000
commit8daa83a594a2e98f39d764422bfbdbc62c9efd44 (patch)
tree4099e8021376c7d8c05bdf8503093d80e9c7bad0 /third_party/heimdal/lib/roken
parentInitial commit. (diff)
downloadsamba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.tar.xz
samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.zip
Adding upstream version 2:4.20.0+dfsg.upstream/2%4.20.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/heimdal/lib/roken')
-rw-r--r--third_party/heimdal/lib/roken/ChangeLog2229
-rw-r--r--third_party/heimdal/lib/roken/Makefile.am293
-rw-r--r--third_party/heimdal/lib/roken/NTMakefile312
-rw-r--r--third_party/heimdal/lib/roken/base32-test.c106
-rw-r--r--third_party/heimdal/lib/roken/base32.c313
-rw-r--r--third_party/heimdal/lib/roken/base32.h61
-rw-r--r--third_party/heimdal/lib/roken/base64-test.c97
-rw-r--r--third_party/heimdal/lib/roken/base64.c270
-rw-r--r--third_party/heimdal/lib/roken/base64.h55
-rw-r--r--third_party/heimdal/lib/roken/bswap.c74
-rw-r--r--third_party/heimdal/lib/roken/chown.c42
-rw-r--r--third_party/heimdal/lib/roken/cloexec.c75
-rw-r--r--third_party/heimdal/lib/roken/closefrom.c57
-rw-r--r--third_party/heimdal/lib/roken/clz.c69
-rw-r--r--third_party/heimdal/lib/roken/concat.c110
-rw-r--r--third_party/heimdal/lib/roken/copyhostent.c98
-rw-r--r--third_party/heimdal/lib/roken/ct.c82
-rw-r--r--third_party/heimdal/lib/roken/daemon.c80
-rw-r--r--third_party/heimdal/lib/roken/detach.c226
-rw-r--r--third_party/heimdal/lib/roken/dirent-test.c278
-rw-r--r--third_party/heimdal/lib/roken/dirent.c235
-rw-r--r--third_party/heimdal/lib/roken/dirent.hin66
-rw-r--r--third_party/heimdal/lib/roken/dlfcn.hin109
-rw-r--r--third_party/heimdal/lib/roken/dlfcn_w32.c700
-rw-r--r--third_party/heimdal/lib/roken/doxygen.c44
-rw-r--r--third_party/heimdal/lib/roken/dumpdata.c249
-rw-r--r--third_party/heimdal/lib/roken/ecalloc.384
-rw-r--r--third_party/heimdal/lib/roken/ecalloc.c53
-rw-r--r--third_party/heimdal/lib/roken/emalloc.c53
-rw-r--r--third_party/heimdal/lib/roken/environment.c162
-rw-r--r--third_party/heimdal/lib/roken/eread.c51
-rw-r--r--third_party/heimdal/lib/roken/erealloc.c53
-rw-r--r--third_party/heimdal/lib/roken/err.c46
-rw-r--r--third_party/heimdal/lib/roken/err.hin99
-rw-r--r--third_party/heimdal/lib/roken/errx.c45
-rw-r--r--third_party/heimdal/lib/roken/esetenv.c45
-rw-r--r--third_party/heimdal/lib/roken/estrdup.c53
-rw-r--r--third_party/heimdal/lib/roken/ewrite.c51
-rw-r--r--third_party/heimdal/lib/roken/fchown.c42
-rw-r--r--third_party/heimdal/lib/roken/flock.c154
-rw-r--r--third_party/heimdal/lib/roken/fnmatch.c175
-rw-r--r--third_party/heimdal/lib/roken/fnmatch.hin66
-rw-r--r--third_party/heimdal/lib/roken/freeaddrinfo.c54
-rw-r--r--third_party/heimdal/lib/roken/freehostent.c59
-rw-r--r--third_party/heimdal/lib/roken/fseeko.c48
-rw-r--r--third_party/heimdal/lib/roken/ftello.c48
-rw-r--r--third_party/heimdal/lib/roken/gai_strerror.c74
-rw-r--r--third_party/heimdal/lib/roken/get_window_size.c132
-rw-r--r--third_party/heimdal/lib/roken/getaddrinfo-test.c151
-rw-r--r--third_party/heimdal/lib/roken/getaddrinfo.c414
-rw-r--r--third_party/heimdal/lib/roken/getaddrinfo_hostspec.c101
-rw-r--r--third_party/heimdal/lib/roken/getarg.3341
-rw-r--r--third_party/heimdal/lib/roken/getarg.c607
-rw-r--r--third_party/heimdal/lib/roken/getarg.h112
-rw-r--r--third_party/heimdal/lib/roken/getauxval.c263
-rw-r--r--third_party/heimdal/lib/roken/getauxval.h176
-rw-r--r--third_party/heimdal/lib/roken/getcwd.c54
-rw-r--r--third_party/heimdal/lib/roken/getdtablesize.c99
-rw-r--r--third_party/heimdal/lib/roken/getegid.c46
-rw-r--r--third_party/heimdal/lib/roken/geteuid.c46
-rw-r--r--third_party/heimdal/lib/roken/getgid.c45
-rw-r--r--third_party/heimdal/lib/roken/gethostname.c70
-rw-r--r--third_party/heimdal/lib/roken/getifaddrs-test.c137
-rw-r--r--third_party/heimdal/lib/roken/getifaddrs.c1314
-rw-r--r--third_party/heimdal/lib/roken/getifaddrs_w32.c161
-rw-r--r--third_party/heimdal/lib/roken/getipnodebyaddr.c71
-rw-r--r--third_party/heimdal/lib/roken/getipnodebyname.c83
-rw-r--r--third_party/heimdal/lib/roken/getnameinfo.c124
-rw-r--r--third_party/heimdal/lib/roken/getnameinfo_verified.c94
-rw-r--r--third_party/heimdal/lib/roken/getopt.c124
-rw-r--r--third_party/heimdal/lib/roken/getprogname.c48
-rw-r--r--third_party/heimdal/lib/roken/gettimeofday.c94
-rw-r--r--third_party/heimdal/lib/roken/getuid.c45
-rw-r--r--third_party/heimdal/lib/roken/getuserinfo.c334
-rw-r--r--third_party/heimdal/lib/roken/getusershell.c185
-rw-r--r--third_party/heimdal/lib/roken/h_errno.c38
-rw-r--r--third_party/heimdal/lib/roken/hex-test.c115
-rw-r--r--third_party/heimdal/lib/roken/hex.c108
-rw-r--r--third_party/heimdal/lib/roken/hex.h57
-rw-r--r--third_party/heimdal/lib/roken/hostent_find_fqdn.c56
-rw-r--r--third_party/heimdal/lib/roken/hstrerror.c78
-rw-r--r--third_party/heimdal/lib/roken/ifaddrs.hin79
-rw-r--r--third_party/heimdal/lib/roken/inet_aton.c46
-rw-r--r--third_party/heimdal/lib/roken/inet_ntop.c151
-rw-r--r--third_party/heimdal/lib/roken/inet_pton.c116
-rw-r--r--third_party/heimdal/lib/roken/initgroups.c42
-rw-r--r--third_party/heimdal/lib/roken/innetgr.c45
-rw-r--r--third_party/heimdal/lib/roken/install-sh251
-rw-r--r--third_party/heimdal/lib/roken/issuid.c278
-rw-r--r--third_party/heimdal/lib/roken/localtime_r.c60
-rw-r--r--third_party/heimdal/lib/roken/lstat.c42
-rw-r--r--third_party/heimdal/lib/roken/memmem.c72
-rw-r--r--third_party/heimdal/lib/roken/memmove.c62
-rw-r--r--third_party/heimdal/lib/roken/memset_s.c51
-rw-r--r--third_party/heimdal/lib/roken/mergesort.c50
-rw-r--r--third_party/heimdal/lib/roken/mergesort_r.c338
-rw-r--r--third_party/heimdal/lib/roken/mini_inetd.c197
-rw-r--r--third_party/heimdal/lib/roken/missing190
-rw-r--r--third_party/heimdal/lib/roken/mkdir.c53
-rw-r--r--third_party/heimdal/lib/roken/mkdtemp.c86
-rw-r--r--third_party/heimdal/lib/roken/mkinstalldirs40
-rw-r--r--third_party/heimdal/lib/roken/mkostemp.c87
-rw-r--r--third_party/heimdal/lib/roken/mkstemp.c82
-rw-r--r--third_party/heimdal/lib/roken/ndbm_wrap.c227
-rw-r--r--third_party/heimdal/lib/roken/ndbm_wrap.h93
-rw-r--r--third_party/heimdal/lib/roken/net_read.c118
-rw-r--r--third_party/heimdal/lib/roken/net_write.c134
-rw-r--r--third_party/heimdal/lib/roken/parse_bytes-test.c89
-rw-r--r--third_party/heimdal/lib/roken/parse_bytes.c81
-rw-r--r--third_party/heimdal/lib/roken/parse_bytes.h50
-rw-r--r--third_party/heimdal/lib/roken/parse_reply-test.c126
-rw-r--r--third_party/heimdal/lib/roken/parse_time-test.c119
-rw-r--r--third_party/heimdal/lib/roken/parse_time.3173
-rw-r--r--third_party/heimdal/lib/roken/parse_time.c104
-rw-r--r--third_party/heimdal/lib/roken/parse_time.h72
-rw-r--r--third_party/heimdal/lib/roken/parse_units.c524
-rw-r--r--third_party/heimdal/lib/roken/parse_units.h116
-rw-r--r--third_party/heimdal/lib/roken/putenv.c79
-rw-r--r--third_party/heimdal/lib/roken/qsort.c201
-rw-r--r--third_party/heimdal/lib/roken/rand.c74
-rw-r--r--third_party/heimdal/lib/roken/rcmd.c49
-rw-r--r--third_party/heimdal/lib/roken/readv.c64
-rw-r--r--third_party/heimdal/lib/roken/realloc.c47
-rw-r--r--third_party/heimdal/lib/roken/recvmsg.c66
-rw-r--r--third_party/heimdal/lib/roken/rename.c49
-rw-r--r--third_party/heimdal/lib/roken/resolve-test.c309
-rw-r--r--third_party/heimdal/lib/roken/resolve.c956
-rw-r--r--third_party/heimdal/lib/roken/resolve.h251
-rw-r--r--third_party/heimdal/lib/roken/rkpty.c392
-rw-r--r--third_party/heimdal/lib/roken/roken-common.h569
-rw-r--r--third_party/heimdal/lib/roken/roken.awk54
-rw-r--r--third_party/heimdal/lib/roken/roken.h.in1394
-rw-r--r--third_party/heimdal/lib/roken/roken_gethostby.c292
-rw-r--r--third_party/heimdal/lib/roken/rtbl.3201
-rw-r--r--third_party/heimdal/lib/roken/rtbl.c558
-rw-r--r--third_party/heimdal/lib/roken/rtbl.h124
-rw-r--r--third_party/heimdal/lib/roken/search.hin44
-rw-r--r--third_party/heimdal/lib/roken/secure_getenv.c47
-rw-r--r--third_party/heimdal/lib/roken/secure_getenv.h42
-rw-r--r--third_party/heimdal/lib/roken/sendmsg.c148
-rw-r--r--third_party/heimdal/lib/roken/setegid.c54
-rw-r--r--third_party/heimdal/lib/roken/setenv.c74
-rw-r--r--third_party/heimdal/lib/roken/seteuid.c54
-rw-r--r--third_party/heimdal/lib/roken/setprogname.c91
-rw-r--r--third_party/heimdal/lib/roken/signal.c77
-rw-r--r--third_party/heimdal/lib/roken/simple_exec.c325
-rw-r--r--third_party/heimdal/lib/roken/simple_exec_w32.c431
-rw-r--r--third_party/heimdal/lib/roken/sleep.c55
-rw-r--r--third_party/heimdal/lib/roken/snprintf-test.c268
-rw-r--r--third_party/heimdal/lib/roken/snprintf.c729
-rw-r--r--third_party/heimdal/lib/roken/socket.c372
-rw-r--r--third_party/heimdal/lib/roken/socket_wrapper.c1911
-rw-r--r--third_party/heimdal/lib/roken/socket_wrapper.h146
-rw-r--r--third_party/heimdal/lib/roken/sockstartup_w32.c75
-rw-r--r--third_party/heimdal/lib/roken/stdbool.hin13
-rw-r--r--third_party/heimdal/lib/roken/stdint.hin43
-rw-r--r--third_party/heimdal/lib/roken/strcasecmp.c55
-rw-r--r--third_party/heimdal/lib/roken/strcollect.c93
-rw-r--r--third_party/heimdal/lib/roken/strdup.c47
-rw-r--r--third_party/heimdal/lib/roken/strerror.c54
-rw-r--r--third_party/heimdal/lib/roken/strerror_r.c84
-rw-r--r--third_party/heimdal/lib/roken/strftime.c402
-rw-r--r--third_party/heimdal/lib/roken/strlcat.c60
-rw-r--r--third_party/heimdal/lib/roken/strlcpy.c73
-rw-r--r--third_party/heimdal/lib/roken/strlwr.c50
-rw-r--r--third_party/heimdal/lib/roken/strncasecmp.c59
-rw-r--r--third_party/heimdal/lib/roken/strndup.c53
-rw-r--r--third_party/heimdal/lib/roken/strnlen.c46
-rw-r--r--third_party/heimdal/lib/roken/strpftime-test.c295
-rw-r--r--third_party/heimdal/lib/roken/strpftime-test.h61
-rw-r--r--third_party/heimdal/lib/roken/strpool.c114
-rw-r--r--third_party/heimdal/lib/roken/strptime.c449
-rw-r--r--third_party/heimdal/lib/roken/strsep.c58
-rw-r--r--third_party/heimdal/lib/roken/strsep_copy.c66
-rw-r--r--third_party/heimdal/lib/roken/strtok_r.c62
-rw-r--r--third_party/heimdal/lib/roken/strtoll.c155
-rw-r--r--third_party/heimdal/lib/roken/strtoull.c129
-rw-r--r--third_party/heimdal/lib/roken/strupr.c50
-rw-r--r--third_party/heimdal/lib/roken/swab.c50
-rw-r--r--third_party/heimdal/lib/roken/syslog.hin248
-rw-r--r--third_party/heimdal/lib/roken/syslogc.c339
-rw-r--r--third_party/heimdal/lib/roken/test-auxval.c235
-rw-r--r--third_party/heimdal/lib/roken/test-detach.c100
-rw-r--r--third_party/heimdal/lib/roken/test-getuserinfo.c136
-rw-r--r--third_party/heimdal/lib/roken/test-mem.c215
-rw-r--r--third_party/heimdal/lib/roken/test-mem.h39
-rw-r--r--third_party/heimdal/lib/roken/test-mini_inetd.c371
-rw-r--r--third_party/heimdal/lib/roken/test-readenv.c115
-rw-r--r--third_party/heimdal/lib/roken/timegm.c85
-rw-r--r--third_party/heimdal/lib/roken/timeval.c286
-rw-r--r--third_party/heimdal/lib/roken/tm2time.c58
-rw-r--r--third_party/heimdal/lib/roken/tsearch-test.c125
-rw-r--r--third_party/heimdal/lib/roken/tsearch.c175
-rw-r--r--third_party/heimdal/lib/roken/unsetenv.c69
-rw-r--r--third_party/heimdal/lib/roken/unvis.c283
-rw-r--r--third_party/heimdal/lib/roken/verr.c44
-rw-r--r--third_party/heimdal/lib/roken/verrx.c44
-rw-r--r--third_party/heimdal/lib/roken/version-script.map241
-rw-r--r--third_party/heimdal/lib/roken/versionsupport.h139
-rw-r--r--third_party/heimdal/lib/roken/vis-extras.h27
-rw-r--r--third_party/heimdal/lib/roken/vis.c649
-rw-r--r--third_party/heimdal/lib/roken/vis.hin170
-rw-r--r--third_party/heimdal/lib/roken/vsyslog.c113
-rw-r--r--third_party/heimdal/lib/roken/vwarn.c43
-rw-r--r--third_party/heimdal/lib/roken/vwarnx.c44
-rw-r--r--third_party/heimdal/lib/roken/warn.c46
-rw-r--r--third_party/heimdal/lib/roken/warnerr.c58
-rw-r--r--third_party/heimdal/lib/roken/warnx.c45
-rw-r--r--third_party/heimdal/lib/roken/win32_alloc.c76
-rw-r--r--third_party/heimdal/lib/roken/win32_version.c128
-rw-r--r--third_party/heimdal/lib/roken/write_pid.c129
-rw-r--r--third_party/heimdal/lib/roken/writev.c61
-rw-r--r--third_party/heimdal/lib/roken/xdbm.h52
-rw-r--r--third_party/heimdal/lib/roken/xfree.c42
214 files changed, 36535 insertions, 0 deletions
diff --git a/third_party/heimdal/lib/roken/ChangeLog b/third_party/heimdal/lib/roken/ChangeLog
new file mode 100644
index 0000000..518987b
--- /dev/null
+++ b/third_party/heimdal/lib/roken/ChangeLog
@@ -0,0 +1,2229 @@
+2008-07-12 Love Hörnquist Åstrand <lha@kth.se>
+
+ * rkpty.c: Always print output for status.
+
+2008-04-27 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * getaddrinfo-test.c: drop )
+
+ * Makefile.am: Add rkpty.
+
+ * rkpty.c: More includes.
+
+ * rkpty.c: Add timeout, add password command, add diffrent
+ verbosity levels.
+
+2008-04-26 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * rkpty.c: pty testing application
+
+2008-04-07 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * resolve.c: Use unsigned where appropriate.
+
+2008-02-23 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * Makefile.am: make AM_CPPFLAGS +=
+
+2008-02-22 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * Makefile.am: Use AM_CPPFLAGS instead, not really right, but
+ definatly better then CPPFLAGS. Thanks to Mike Whitton for
+ pointing this out.
+
+2008-01-12 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * Makefile.am: add missing files.
+
+2007-08-09 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * strftime.c: rewrite str[pf]time for testing.
+
+ * strptime.c: rewrite str[pf]time for testing.
+
+ * Makefile.am: add TEST_STRPFTIME
+
+2007-07-17 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * ndbm_wrap.c (dbm_get): set dsize to 0 on failure.
+
+ * Makefile.am: add ndbm_wrap.[ch] to EXTRA_DIST
+
+ * ndbm_wrap.c (dbm_fetch): set dsize to 0 on failure.
+
+2007-07-16 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * socket_wrapper.c: Implement swrap_dup too.
+
+ * socket_wrapper.c: Add dup(dummy stub) and dup2(real).
+
+ * socket_wrapper.h: Add dup(dummy stub) and dup2(real).
+
+2007-07-10 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * Makefile.am: New library version.
+
+2007-06-19 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * roken_gethostby.c: set proxy_port to 0 to pacify BEAM.
+
+2007-06-07 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * use "roken.h" consitantly
+
+2007-06-03 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * test-readenv.c: Free environment.
+
+ * environment.c (free_environment): free result of
+ read_environment().
+
+ * roken-common.h (free_environment): free result of
+ read_environment().
+
+2007-05-10 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * fnmatch.c: Do recursive call to rk_fnmatch
+
+2007-01-12 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * resolve.c: Try harder to call res_ndestroy().
+
+2006-12-27 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * Makefile.am: make sure built headers are copied to the
+ ${build_topdir}/include
+
+2006-12-15 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * unvis.c: Use internal version of rk_unvis
+
+ * unvis.c: Always include rk_versions.
+
+ * vis.c: Always include rk_versions.
+
+ * vis.hin: Fix argument for unvis and strsvisx.
+
+ * unvis.c: prefix unvis functions with rk_, and prototypes.
+
+2006-12-13 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * vis.c: Provide some prototypes for the rk_vis functions.
+
+2006-12-11 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * ifaddrs.hin: Prefix getifaddrs functions with rk_ and do symbol
+ renaming.
+
+ * fnmatch.c: Prefix fnmatch functions with rk_ and do symbol
+ renaming.
+
+ * vis.hin: Prefix strvis functions with rk_ and do symbol
+ renaming.
+
+ * vis.c: prefix strvis functions with rk_
+
+ * Makefile.am: Install extra posix headers in <roken/...> to avoid
+ dup headers.
+
+2006-11-09 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * socket_wrapper.c (swrap_sendto): fail on to unknown si->type
+
+2006-11-06 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * socket_wrapper.c: A few fixes to have Heimdal pass the make
+ check under socket_wrapper. The first is a missing 'break' before
+ the (heimdal specific) IPv6 support. The second works around the
+ fact that sendto() *may* object to a destination being specified.
+ It appears to be that on Linux, this objects (with EISCONN) for
+ unix stream sockets, but not for TCP sockets. The alternate fix
+ would be to have the KDC use 'send()' in this case. Andrew Bartlett.
+
+2006-10-20 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * Makefile.am: split dist and nondist HEADERS
+
+2006-10-19 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * roken.h.in: Add timegm glue.
+
+ * timegm.c: add timegm()
+
+ * socket_wrapper.c: Include <roken.h>, gives os socklen_t on IRIX
+ 6.4.
+
+ * socket_wrapper.c: Maybe include <sys/time.h> and/or maybe
+ include <time.h>.
+
+2006-10-17 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * roken.h.in: Revert prevois for now, the problem is that we have
+ to include symbols unconditionally, even for those that just needs
+ protos.
+
+ * roken.h.in: Provide symbol renaming, let see what breaks.
+
+ * socket_wrapper.c: Maybe include <sys/filio.h>.
+
+2006-10-10 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * socket_wrapper.c: more consitity check, remove dead code, add
+ socket length code, add missing break, make diffrent chars of type
+ type files for case-insensitiv filesystems
+
+ * socket_wrapper.c: try even hard to not use socket wrapper for
+ socket_wrapper itself.
+
+ * socket_wrapper.c: Force no socket wrapper for socket_wrapper
+ itself.
+
+2006-10-09 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * socket_wrapper.c: Maybe include <config.h>.
+
+ * socket_wrapper.c: Protect AF_INET6 with #ifdef HAVE_IPV6.
+
+ * socket_wrapper.c: Use a symbol for the v6 address.
+
+ * socket_wrapper.c: Add IPv6 suppport.
+
+ * socket_wrapper.[ch]: Include socket wrapper from samba4 (rev
+ 19179).
+
+2006-10-07 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * Makefile.am: Add build_HEADERZ to EXTRA_DIST
+
+ * Makefile.am: Add man_MANS to EXTRA_DIST
+
+ * Makefile.am: Add to all objects BUILD_ROKEN_LIB.
+
+2006-09-16 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * roken.h.in: Add samba socket wrapper fragment.
+
+ * Makefile.am: Add samba socket wrapper fragment.
+
+2006-09-05 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * snprintf.c: reapply patch that went away in last commit
+
+ * snprintf-test.c: unbreak from previous commit
+
+ * snprintf.c: Add size_t formater (z modifer).
+
+ * snprintf-test.c: add tests for size_t printf formater
+
+2006-06-30 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * rtbl.h: Add extern "C" for C++.
+
+ * rtbl.c: Add rtbl_add_column_entryv functions, printf like
+
+ * rtbl.h: Add rtbl_add_column_entryv functions, printf like
+
+2006-06-22 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * glob.hin: Add extern "C" for C++. From joerg at britannica dot
+ bec dot de
+
+ * fnmatch.hin: Add extern "C" for C++. From joerg at britannica
+ dot bec dot de
+
+2006-04-20 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * fnmatch.hin (fnmatch): CPP rename to rk_fnmatch
+
+2006-04-14 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * resolve.c (dns_srv_order): change a if (ptr == NULL) continue
+ into a assert(ptr != NULL) since it could never happen, found by
+ the IBM code checker (beam). Thanks to Florian Krohm for
+ explaining it.
+
+2006-04-02 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * roken_gethostby.c (roken_gethostby): make addr_list one larger
+ to avoid a off-by-one error. Found by IBM checker.
+
+ * resolve.c: Plug memory leak found by IBM checker (and try to
+ please it).
+
+2006-02-06 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * resolve.c: Spelling, from Alexey Dobriyan, via Jason McIntyre
+
+2006-01-13 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * getcap.c: Don't use db support unless its build into libc but we
+ dont check for that now, so just disable the code. This removes
+ the dependency on libdb for roken, and that is a good thing since
+ it causes problem with nss plugins that uses DB3 that also
+ provides the same symbol, but with a diffrent ABI. so when the
+ application calls getpwnamn() and it linked to roken, it craches
+ in the nss functions.
+
+2006-01-09 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * hex.c (hex_decode): support decoding odd number of characters,
+ in the odd len case, the first character ends up in the first byte
+ in the lower nibble.
+
+ * hex-test.c: Check that we can decode single character hex chars.
+
+2005-12-12 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * getifaddrs.c: Try handle HP/UX 11.nn, its diffrent from Solaris
+ large SIOCGIFCONF.
+
+2005-09-28 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * roken-common.h: Move rk_UNCONST to roken.h.in since it might use
+ uintptr_t depending on avaibility.
+
+ * roken.h.in: Include <stdint.h> if it exists. If avaiable, use
+ uintptr_t to define rk_UNCONST.
+
+2005-09-22 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * roken-common.h: Add rk_dumpdata.
+
+ * dumpdata.c: Add rk_dumpdata() that write a chunk of data into a
+ file for later processing by some other tool (like asn1_print).
+
+2005-09-13 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * strptime.c: cast to unsigned char to make sure its not negative
+ when passing it to is* functions
+
+2005-09-01 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * socket.c: Add socket_set_ipv6only.
+
+ * roken-common.h: Add socket_set_ipv6only, remove some argument
+ names.
+
+2005-08-25 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * strpool.c (rk_strpoolprintf): remove debug printf, plug memory
+ leak
+
+2005-08-23 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * setprogname.c (setprogname): const poision
+
+ * print_version.c: Removed, moved to libvers.
+
+2005-08-22 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * resolve.c (dns_lookup_int): if we have res_ndestroy, prefeer
+ that before res_nclose
+
+2005-08-12 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * getaddrinfo-test.c: Rename optind to optidx to avoid shadowing.
+
+2005-08-05 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * gai_strerror.c: sprinkel more const
+
+ * gai_strerror.c, roken.h.in: Make return value of gai_strerror
+ const to match SUSv3. Prompted by Stefan Metzmacher change to
+ Samba.
+
+2005-07-19 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * roken.h.in: Remove parameter names to avoid shadow warnings.
+
+2005-07-13 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * getifaddrs.c (nl_getlist): poll to get messages from kernel, and
+ retry if the message was lost
+ (free_nlmsglist): free all linked elements, not just the first one
+
+2005-07-08 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * snprintf-test.c: Check a very simple format string
+
+2005-07-07 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * roken.h.in: If we have <strings.h> include it, its needed for
+ strcasecmp() on those platforms that are SUS3/iso c99 strict (like
+ AIX)
+
+ * roken-common.h: remove duplicate ;
+
+2005-07-06 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * roken-common.h: rk_strpoolprintf first variable identifier is 3
+
+2005-06-30 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * base64.h: remove variable names
+
+2005-06-29 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * roken-common.h: fix format attribute
+
+ * Makefile.am (libroken_la_SOURCES): += strpool.c
+
+ * roken-common.h: add strpool, a printf collector to make it
+ eaiser to collect strings into one string
+
+ * strpool.c: add strpool, a printf collector to make it eaiser to
+ collect strings into one string
+
+2005-06-23 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * base64.c: Add const, from Andrew Abartlet <abartlet@samba.org>
+
+2005-06-21 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * strpftime-test.c: test for "%Y%m"
+
+ * esetenv.c: unconst
+
+ * strptime.c: Write a new parse_number function that is possible
+ to limit that amount of numbers used, with this strptime can
+ handle strptime("200505", "%Y%m", &tm);
+
+2005-06-16 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * getaddrinfo.c: avoid shadowing sin
+
+ * resolve-test.c: rename optind to optidx to avoid shadowing
+
+ * strptime.c: UNCONST return value from strptime
+
+ * strftime.c: rk_UNCONST argument mktime
+
+ * getnameinfo.c: avoid shadowing sin
+
+ * socket.c: avoid shadowing sin
+
+ * resolve.c (parse_record): fix casting to avoid losing const
+
+ * roken.awk: since we got no feedback regarding people running
+ heimdal on the crays, remove the quoted # version
+
+ * environment.c: rename index to idx to avoid shadowing
+
+2005-05-29 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * parse_reply-test.c: avoid signedness warnings
+
+ * test-mem.c: avoid signedness warnings
+
+2005-05-27 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * hex.c: include "roken.h" to avoid undefined size_t/ssize_t
+
+2005-05-24 Dave Love <fx@gnu.org>
+
+ * Makefile.am (snprintf_test_SOURCES): Add snprintf-test.h.
+
+2005-05-20 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * environment.c (rk_read_env_file): move assignment to later to
+ make pre c99 compiler happy
+
+2005-05-18 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * strptime.c: use english spelling of March
+
+2005-05-17 Johan Danielsson <joda@pdc.kth.se>
+
+ * Makefile.am: only link with dblib if we need it
+
+ * Makefile.am: add test_readenv
+
+ * test-readenv.c: test for read_environment()
+
+ * environment.c: eliminate duplicates
+
+2005-05-13 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * issuid.c (issuid): change the #ifdef order to avoid unreachable
+ code warning.
+
+2005-05-10 Dave Love <fx@gnu.org>
+
+ * roken.h.in: Get daemon declared on Solaris (it's in unistd.h but
+ masked by a feature test), just to avoid a warning, since it has
+ int args. Include err.h unconditionally, since it's always
+ supplied.
+
+2005-05-04 Dave Love <fx@gnu.org>
+
+ * snprintf-test.c: Include snprintf-test.h earlier.
+
+2005-05-03 Dave Love <fx@gnu.org>
+
+ * snprintf.c: Include snprintf-test.h earlier.
+
+ * test-mem.c: Add member fd to map.
+ (rk_test_mem_alloc, rk_test_mem_free): Use it.
+
+2005-04-30 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * getifaddrs.c: add break on default: statements, from Douglas
+ E. Engert
+
+ * snprintf.c (vsnprintf): don't write the NUL into the string if
+ the length was 0
+
+ * snprintf-test.c: add check that snprintf doesn't write the NUL
+ into the last byte when its a zero length input string
+
+ * parse_time-test.c: Include <err.h>.
+
+2005-04-27 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * parse_time-test.c: improve testing
+
+ * roken-common.h: add rk_realloc
+
+ * Makefile.am: add realloc
+
+ * realloc.c: add rk_realloc, unbroken version of realloc
+
+2005-04-26 Dave Love <fx@gnu.org>
+
+ * getusershell.c: Include roken.h
+
+2005-04-18 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * unvis.c: cast to unsigned char to make sure its not negative
+ when passing it to is* functions
+
+ * strptime.c: cast to unsigned char to make sure its not negative
+ when passing it to to* functions
+
+2005-04-13 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * simple_exec.c: don't close stderr, close all fd that is num 3
+ and larger
+
+ * simple_exec.c (pipe_execv): use closefrom
+
+ * add closefrom
+
+2005-04-12 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * add ROKEN_LIB_FUNCTION to all exported functions
+
+2005-04-10 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * resolve-test.c: print DS
+
+2005-04-07 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * parse_time-test.c: remove unused variable
+
+2005-04-04 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * strpftime-test.c: print size_t by casting to unsigned long
+
+ * base64-test.c: print size_t by casting to unsigned long
+
+ * hex-test.c: print size_t by casting to unsigned long
+
+ * resolve-test.c: print size_t by casting to unsigned long
+
+2005-04-01 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * snprintf-test.c (try): reset va_list argument between reuse,
+ from Peter Kruty <xkruty@fi.muni.cz>
+
+2005-03-30 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * roken_gethostby.c (roken_gethostby): s/sin/addr/ to avoid
+ shadowing
+
+ * resolve.c (dns_lookup_int): s/stat/state/ to avoid shadowing
+
+ * parse_units.c: avoid shadowing div
+
+2005-03-26 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * snprintf.c: use defined(TEST_SNPRINTF) like on all other places
+ in the same file
+
+2005-03-21 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * hex.c: check for overflows
+
+2005-03-18 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * vis.c: use RCSID instead of __RCSID
+
+2005-03-06 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * Makefile.am: check_PROGRAMS += hex-test
+
+ * hex-test.c: hex encoding/decoding test
+
+ * hex.c: fix decodeing, it processed to much data and thus
+ returned the wrong length
+
+2005-03-04 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * Makefile.am: add hex.[ch]
+
+ * hex.c: add hex encoder/decoder
+
+2005-03-02 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * daemon.c fnmatch.c fnmatch.hin getcap.c getopt.c getusershell.c
+ glob.c glob.hin iruserok.c unvis.c vis.hin:
+
+ In 1997, the University of California, Berkeley issued a statement
+ retroactively relicensing all code held under their copyright from
+ a 4-clause 'traditional' BSD license to a new 3-clause 'revised'
+ BSD license, which removed the advertising clause.
+
+ From NetBSD, via Joel Baker, and Alistair G. Crooks
+
+ * getaddrinfo-test.c: remove stray ( in output
+
+ * vis.c: Update new revision from NetBSD (copyright update)
+
+2005-02-24 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * Makefile.am: bump version to 17:0:1
+
+2005-01-19 Dave Love <d.love@dl.ac.uk>
+
+ * getusershell.c: Include ctype.h, cast argument to isspace to
+ unsigned char.
+
+2004-10-31 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * parse_time.3, parse_units.c: Change the behavior of the
+ parse_unit code to return the number of bytes needed to print the
+ whole string (minus the trailing '\0'), just like snprintf. Idea
+ from bugreport from Gabriel Kihlman <gk@stacken.kth.se>.
+
+ * parse_time-test.c Makefile.am test-mem.c test-mem.h: test parse_time
+
+2004-10-16 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * resolve.c: put dns_type_to_string and dns_string_to_type in the
+ abi
+
+ * resolve.c: add ds_record
+
+ * resolve.h: add ds_record
+
+2004-10-06 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * ndbm_wrap.c: undefine open so this works on solaris with large
+ file support From netbsd's pkgsrc via Gavan Fantom
+
+2004-09-13 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * resolve-test.c: add --version/--help
+
+2004-09-12 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * Makefile.am: make resolve-test a noinst program
+
+2004-09-11 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * resolve-test.c: test program for libroken resolve from resolve.c
+
+ * Makefile.am: add resolve-test
+
+ * resolve.h: add constant for max DNS protocol packet size
+
+ * resolve.c (dns_lookup_int): grow the answer buffer to the size
+ the server send to us if the answer buffer was too small (limited
+ to the dns protocol max packet size)
+
+2004-08-26 Johan Danielsson <joda@pdc.kth.se>
+
+ * err.hin: no need to declare __progname here
+
+ * Makefile.am: always clean generated headers
+
+2004-06-26 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * rtbl.3: use .In for header, remove trailing space
+
+2004-06-23 Johan Danielsson <joda@pdc.kth.se>
+
+ * rtbl.h: add protos and macros
+
+ * rtbl.c: implement a bunch of stuff:
+ - column separator (instead of global column prefix)
+ - per column suffix
+ - indexing columns by id-number instead of column header
+ - optional header supression (via settable flags)
+ - ability to end a row
+ - don't extend last column to full width
+
+2004-06-20 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * resolve.[ch]: add and use and bind9 version of rr type
+ (rk_ns_t_XXX) instead of the old bind4 version (T_XXX)
+
+2004-05-25 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * resolve.c (stot): add AAAA
+
+2004-02-17 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * getarg.c (add_string): catch error from realloc
+
+2004-02-12 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * roken-common.h: add simple_execve_timed
+
+ * roken-common.h: add timed simple_exec
+
+ * simple_exec.c: add timed simple_exec
+
+2004-01-05 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * gai_strerror.c: correct ifdef for EAI_ADDRFAMILY
+
+2003-12-14 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * resolve.c: parse dns header, add support for SSHFP
+
+ * resolve.h: add cpp rewrite for sshfp_record
+
+ * resolve.h: add SSHFP, clean up the the dns_header
+
+2003-12-14 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * resolve.h: remove HEADER (only used for crays)
+
+ * resolve.c: number-of fields no longer stored in network order
+
+2003-12-13 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * resolve.c: remove depency on c99 types in resolv.h
+
+ * resolve.h: remove depency on c99 types
+
+2003-12-06 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * resolv.h: add more T_ types and inline the dns headers, all this
+ for bind9 resolvers
+
+2003-12-02 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * gai_strerror.c: EAI_ADDRFAMILY and EAI_NODATA is deprecated
+
+ * roken-common.h: use EAI_NONAME instead of EAI_ADDRFAMILY to
+ check for if we need EAI_ macros
+
+2003-10-04 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * strptime.c: let t and n match zero or more whitespaces
+
+2003-08-29 Love Hörnquist Åstrand <lha@it.su.se>
+
+ * ndbm_wrap.c: patch for working with DB4 on heimdal-discuss
+ From: Luke Howard <lukeh@PADL.COM>
+
+2003-08-27 Johan Danielsson <joda@pdc.kth.se>
+
+ * Makefile.am: don't include discovered files in EXTRA_SOURCES;
+ don't depend on all header files, just the built ones
+
+2003-08-15 Johan Danielsson <joda@pdc.kth.se>
+
+ * emalloc.3: manpage
+
+2003-07-11 Love <lha@stacken.kth.se>
+
+ * resolve.c: AIX have broken res_nsearch() in 5.1 (5.0 also ?) so
+ just don't use res_nsearch on AIX
+
+2003-06-29 Johan Danielsson <joda@pdc.kth.se>
+
+ * snprintf.c: * don't ever print sign for unsigned conversions *
+ don't break when right justifying a number past the end of the
+ buffer * handle zero precision and the value zero more correctly
+
+2003-06-14 Love <lha@stacken.kth.se>
+
+ * glob.hin: prefix glob symbols with rk_
+
+2003-04-22 Love <lha@stacken.kth.se>
+
+ * resolve.c: copy NUL too, from janj@wenf.org via openbsd
+
+2003-04-16 Love <lha@stacken.kth.se>
+
+ * parse_units.h: remove typedef for units to avoid problems with
+ shadowing
+
+ * resolve.c: use strlcpy, from openbsd
+
+ * getcap.c: use strlcpy, from openbsd
+
+ * getarg.3: Change .Fd #include <header.h> to .In header.h
+ from Thomas Klausner <wiz@netbsd.org>
+
+2003-04-15 Love <lha@stacken.kth.se>
+
+ * socket.c (socket_set_tos): if setsockopt failed with EINVAL
+ failed, just ignore it, sock was probably a just a non AF_INET
+ socket
+
+2003-04-14 Love <lha@stacken.kth.se>
+
+ * strncasecmp.c: cast argument to toupper to unsigned char, from
+ Christian Biere <christianbiere@gmx.de> via NetBSD
+
+ * strlwr.c: cast argument to tolower to unsigned char, from
+ Christian Biere <christianbiere@gmx.de> via NetBSD
+
+ * strcasecmp.c: cast argument to toupper to unsigned char, from
+ Christian Biere <christianbiere@gmx.de> via NetBSD
+
+2003-03-19 Love <lha@stacken.kth.se>
+
+ * getarg.3: spelling, from <jmc@prioris.mini.pw.edu.pl>
+
+2003-03-07 Love <lha@stacken.kth.se>
+
+ * parse_bytes.c: use struct units instead of units
+
+ * parse_time.c: use struct units instead of units
+
+2003-03-04 Love <lha@stacken.kth.se>
+
+ * roken.awk: use full prototype for main
+
+2002-10-15 Johan Danielsson <joda@pdc.kth.se>
+
+ * resolve.c: check length of txt records
+
+2002-09-10 Johan Danielsson <joda@pdc.kth.se>
+
+ * roken.awk: include config.h before stdio.h (breaks with
+ _FILE_OFFSET_BITS on solaris otherwise)
+
+2002-09-09 Johan Danielsson <joda@pdc.kth.se>
+
+ * resolve.c: fix res_nsearch call, but don't use it for now, AIX5
+ has a broken version that trashes memory
+
+ * roken-common.h: fix typo in previous
+
+ * roken-common.h: change IRIX == 4 to IRIX4
+
+2002-09-04 Assar Westerlund <assar@kth.se>
+
+ * getifaddrs.c: remove some warnings from the linux-portion
+
+ * getnameinfo_verified.c (getnameinfo_verified): handle the case
+ of forward but no backward DNS information, and also describe the
+ desired behaviour. from Love <lha@stacken.kth.se>
+
+2002-09-04 Johan Danielsson <joda@pdc.kth.se>
+
+ * rtbl.c (rtbl_destroy): free whole table
+
+ * resolve.c: use res_nsearch if we have it (from Larry Greenfield)
+
+2002-09-03 Assar Westerlund <assar@kth.se>
+
+ * getifaddrs.c: add Linux AF_NETLINK getifaddrs from Hideaki
+ YOSHIFUJI of the Usagi project
+
+ * parse_reply-test.c: make this build and return 77 if there is no
+ mmap
+
+ * Makefile.am (parse_reply-test): add
+ * parse_reply-test.c: add a test case for parse_reply reading past
+ the given buffer
+ * resolve.c (parse_reply): update the arguments to more reasonable
+ types. allow parse_reply-test to call it
+
+2002-08-28 Johan Danielsson <joda@pdc.kth.se>
+
+ * resolve.c (dns_srv_order): do alignment tricks with the random()
+ state (from NetBSD)
+
+2002-08-27 Assar Westerlund <assar@kth.se>
+
+ * resolve.c (parse_reply): verify the lengths (both external and
+ internal) are consistent and not too long
+ (dns_lookup_int): be conservative in the length sent in to to
+ parse_reply
+
+2002-08-26 Assar Westerlund <assar@kth.se>
+
+ * roken.h.in: add prototypes for str, unvis functions
+ * resolve.h: add fallback definition for T_AAAA
+
+2002-08-22 Johan Danielsson <joda@pdc.kth.se>
+
+ * roken.h.in: we may need a prototype for strndup
+
+2002-08-20 Johan Danielsson <joda@pdc.kth.se>
+
+ * roken.h.in: typedef ssize_t here
+
+ * getarg.c: don't put Ns before comma
+
+ * resolve.c: _res might not be available
+
+ * localtime_r.c: include stdio.h and roken.h
+
+ * strftime.c: only use altzone if we have it
+
+ * roken-common.h: AI_NUMERICHOST needs special handling
+
+ * strlcat.c: add some consistency checks
+
+ * strlcpy.c: make the logic simpler, and handle dst_sz == 0
+
+2002-08-19 Johan Danielsson <joda@pdc.kth.se>
+
+ * resolve.h: prefix these functions to avoid conflicts with other
+ packages
+
+2002-08-14 Johan Danielsson <joda@pdc.kth.se>
+
+ * strsep_copy.c: don't write to buf if len == 0
+
+2002-05-31 Assar Westerlund <assar@pdc.kth.se>
+
+ * Makefile.am: *_LDADD: add LDADD, so that libroken is used
+
+2002-05-17 Johan Danielsson <joda@pdc.kth.se>
+
+ * xdbm.h: remove old dbm part
+
+2002-04-30 Johan Danielsson <joda@pdc.kth.se>
+
+ * ndbm_wrap.{c,h}: ndbm wrapper for newer db libraries
+
+2002-04-18 Johan Danielsson <joda@pdc.kth.se>
+
+ * roken.h.in: move mini_inetd protos to after addrinfo definition
+
+ * snprintf.c (append_number): make rep const
+
+ * getarg.h: rename optind and optarg to avoid some gcc warnings
+
+ * getarg.c: rename optind and optarg to avoid some gcc warnings
+
+2002-02-18 Johan Danielsson <joda@pdc.kth.se>
+
+ * mini_inetd.c: mini_inetd_addrinfo that takes an addrinfo instead
+ of a port number
+
+2001-11-30 Assar Westerlund <assar@sics.se>
+
+ * getifaddrs.c: support SIOCGLIFCONF and SIOCGLIFFLAGS which are
+ used on Solaris 8 to retrieve addresses larger than `struct
+ sockaddr'. From Magnus Ahltorp <ahltorp@nada.kth.se> (with some
+ modifications by me)
+
+2001-10-27 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am (libroken_la_LDFLAGS): set version to 15:0:6
+
+2001-10-22 Assar Westerlund <assar@sics.se>
+
+ * localtime_r.c: add
+
+2001-10-02 Johan Danielsson <joda@pdc.kth.se>
+
+ * resolve.c (dns_srv_order): don't try to return a value
+
+2001-09-24 Johan Danielsson <joda@pdc.kth.se>
+
+ * snprintf.c: va_{start,end} fixes; from Thomas Klausner
+
+2001-09-20 Assar Westerlund <assar@sics.se>
+
+ * resolve.c (dns_srv_order): make sure of not reading after the
+ array
+
+2001-09-17 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am (libroken_la_LDFLAGS): bump to 14:4:5
+ * snprintf.c: rename 'struct state' -> 'struct snprintf_test' to
+ avoid collision with resolv.h on aix
+
+2001-09-04 Assar Westerlund <assar@sics.se>
+
+ * parse_bytes-test.c, parse_bytes.c, parse_bytes.h, parse_units.c,
+ parse_units.h: use int instead of size_t as return values to be
+ compatible with snprintf
+
+ * strftime.c (strftime): check for return values from snprintf() <
+ 0
+
+2001-09-03 Johan Danielsson <joda@pdc.kth.se>
+
+ * socket.c: restrict is a keyword
+
+2001-09-03 Assar Westerlund <assar@sics.se>
+
+ * write_pid.c: handle atexit or on_exit
+
+ * Makefile.am (EXTRA_libroken_la_SOURCES): add vis.hin to help
+ solaris make
+
+2001-08-30 Johan Danielsson <joda@pdc.kth.se>
+
+ * Makefile.am: use LDADD directly
+
+2001-08-28 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am (libroken_la_LDFLAGS): set to 14:3:5
+
+ * issuid.c (issuid): call issetugid if it exists
+
+2001-08-24 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am: make it play better with recent automake
+
+2001-08-21 Assar Westerlund <assar@sics.se>
+
+ * glob.c: provide a fallback for ARG_MAX. from <tol@stacken.kth.se>
+
+ * roken.h.in: remove all winsock.h
+ for now, it does more harm than good under cygwin and if it should be
+ used, the correct conditional needs to be found
+ from <tol@stacken.kth.se>
+
+2001-08-17 Johan Danielsson <joda@pdc.kth.se>
+
+ * getaddrinfo.c: include a definition of in6addr_loopback if it
+ doesn't exist
+
+2001-08-10 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am (libroken_la_LDFLAGS): update to 14:2:5
+
+2001-08-08 Assar Westerlund <assar@sics.se>
+
+ * hstrerror.c: move h_errno to its own file (h_errno.c)
+
+2001-08-04 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am: add getarg.3
+
+2001-08-01 Assar Westerlund <assar@sics.se>
+
+ * mini_inetd.c (mini_inetd): explicitly use PF_UNSPEC. be more
+ resilient to bind/listen failing.
+
+2001-07-31 Assar Westerlund <assar@sics.se>
+
+ * getifaddrs.c (getifaddrs2): remove unused variables
+
+2001-07-31 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am (libroken_la_LDFLAGS): update version to 14:1:5
+
+2001-07-23 Assar Westerlund <assar@sics.se>
+
+ * getarg.c (arg_match_long): fix parsing of arg_counter optional
+ argument
+
+2001-07-19 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am (libroken_la_LDFLAGS): bump version to 14:0:5
+
+2001-07-17 Assar Westerlund <assar@sics.se>
+
+ * snprintf-test.h: add a file with renaming of the snprintf
+ functions, to be used for running the tests
+
+2001-07-11 Assar Westerlund <assar@sics.se>
+
+ * snprintf-test.c: add more %X tests, and long and conditional
+ long long tests
+ * snprintf.c: add support for printing long long (if available)
+
+2001-07-10 Assar Westerlund <assar@sics.se>
+
+ * getaddrinfo.c (add_hostent): adapt to const hostent_find_fqdn
+ * hostent_find_fqdn.c (hostent_find_fqdn): const-ize
+
+2001-07-09 Assar Westerlund <assar@sics.se>
+
+ * roken-common.h (hostent_find_fqdn): add
+ * hostent_find_fqdn.c: separate out hostent_find_fqdn
+
+ * warnerr.c: move out getprogname, setprogname
+
+2001-07-03 Assar Westerlund <assar@sics.se>
+
+ * warnerr.c (setprogname): add const cast
+ * vis.c (SVIS): add some (unsigned char) before calling isfoo*
+ * Makefile.am (libroken_la_LDFLAGS:) set version to 13:0:4
+
+ * Makefile.am: add snprintf_test
+ * snprintf.c: rewrite so that it does not stop as soon as there
+ are no more characters to print, we need to figure out how long
+ the string would have to be. this also fixes snprintf(NULL, 0
+
+2001-06-21 Assar Westerlund <assar@sics.se>
+
+ * simple_exec.c (pipe_execv): remove unused variable
+
+2001-06-20 Johan Danielsson <joda@pdc.kth.se>
+
+ * getdtablesize.c: fix typo in obviously never used sysctl case
+
+ * simple_exec.c: rename check_status to wait_for_process, and
+ export it; function pipe_execv similar to popen, but with more
+ control over input and output
+
+ * roken-common.h: prototypes for wait_for_process and pipe_execv
+
+2001-06-17 Assar Westerlund <assar@sics.se>
+
+ * roken-common.h: move emalloc et al to roken.h.in
+ * Makefile.am: make emalloc,ecalloc,erealloc,estrdup conditional
+ * emalloc.c, erealloc.c, estrup.c: use errx, since errno might not
+ be set reliably
+ * ecalloc.c: add for symmetry
+
+2001-06-09 Johan Danielsson <joda@pdc.kth.se>
+
+ * resolve.c: dns_srv_order to order srv records
+
+2001-06-08 Johan Danielsson <joda@pdc.kth.se>
+
+ * getarg.c: Grog tries to figure out if to use mdoc.old instead of
+ mdoc by looking at some macros that were only present in the old
+ version, and by looking at the number of .Oo's present. In
+ mdoc.old .Oo was a toggle, but in mdoc it's closed by .Oc, so if
+ the number of .Oo's is bigger than the number of .Oc's, it figures
+ it must be mdoc.old. This doesn't however account for called Oc's,
+ and thus grog thinks that valid pages are mdoc.old when they
+ infact are mdoc. So let's make sure that Oc's are not called by
+ other macros.
+
+2001-05-29 Assar Westerlund <assar@sics.se>
+
+ * base64-test.c (main): initialize numerr
+
+2001-05-28 Johan Danielsson <joda@pdc.kth.se>
+
+ * base64.c: clean up the decode mess somewhat
+
+ * base64-test.c: base64 tests
+
+2001-05-18 Johan Danielsson <joda@pdc.kth.se>
+
+ * roken.h.in: just use standard C types with bswap*
+
+ * bswap.c: just use standard C types
+
+2001-05-17 Assar Westerlund <assar@sics.se>
+
+ * roken.h.in: include all the headers that AC_GROK_TYPES tries for
+ finding u_int17_t et al
+
+ * Makefile.am: bump version to 12:0:3
+ * roken.h.in: re-add set_progname and get_progname for backwards
+ compatability
+ * warnerr.c: re-add set_progname and get_progname for backwards
+ compatability
+
+2001-05-12 Assar Westerlund <assar@sics.se>
+
+ * glob.c: add limits.h, from <shadow@dementia.org>
+
+2001-05-11 Johan Danielsson <joda@pdc.kth.se>
+
+ * Makefile.am: bswap.c
+
+ * bswap.c: bswap{16,32}
+
+2001-05-08 Assar Westerlund <assar@sics.se>
+
+ * freeaddrinfo.c (freeaddrinfo): also free every `struct
+ addrinfo'. from <tmartin@mirapoint.com>
+
+2001-04-25 Assar Westerlund <assar@sics.se>
+
+ * getarg.h (free_getarg_strings): add prototype
+ * getarg.c (free_getarg_strings): add function
+
+2001-04-21 Johan Danielsson <joda@pdc.kth.se>
+
+ * getarg.c: pack short flag options togther, to shorten the usage
+ string
+
+2001-04-17 Johan Danielsson <joda@pdc.kth.se>
+
+ * getifaddrs.c (getifaddrs2): close socket when done
+
+2001-03-26 Johan Danielsson <joda@pdc.kth.se>
+
+ * roken.awk: END has to be last with Sun's awk
+
+2001-03-26 Assar Westerlund <assar@sics.se>
+
+ * parse_units.c (parse_something): do not check the return value
+ from strtod, it might return != 0.0 when the string has no digits.
+ just testing if it consumed any characters is enough and more
+ resilient
+ * glob.c: add GLOB_LIMIT (from NetBSD)
+
+2001-02-20 Assar Westerlund <assar@sics.se>
+
+ * warnerr.c (warnerr): do not use __progname
+ * roken.h.in (setprogname, getprogname): add prototypes
+ * warnerr.c (setprogname, getprogname): rename to. change all
+ callers
+
+2001-02-12 Assar Westerlund <assar@sics.se>
+
+ * getnameinfo_verified.c (getnameinfo_verified): do the first
+ getnameinfo with NI_NUMERICSERV to avoid the error that bind 8.2.3
+ reports on not finding the service
+ (ENI_NOSERVNAME). reported by Ake Sandgren <ake@cs.umu.se>
+
+2001-02-09 Assar Westerlund <assar@sics.se>
+
+ * getnameinfo.c (doit): call inet_ntop with correct af, noted by
+ Ake Sandgren <ake@cs.umu.se>
+
+2001-02-08 Assar Westerlund <assar@sics.se>
+
+ * getnameinfo_verified.c (getnameinfo_verified): always capture
+ the service from getnameinfo so it can be sent back to getaddrinfo
+ and set socktype to avoid getaddrinfo not returning any addresses
+
+2001-01-30 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am (libroken_la_LDFLAGS): bump version to 11:1:2
+ * print_version.c (print_version): add 2001
+
+2001-01-29 Assar Westerlund <assar@sics.se>
+
+ * getifaddrs.c (getifaddrs2): copy the entire sockaddr
+
+ * roken-common.h (_PATH_BSHELL): add
+
+2001-01-27 Assar Westerlund <assar@sics.se>
+
+ * roken.h.in: move __attribute__ to roken-common.h
+
+ * esetenv.c (esetenv): cast to handle a setenv that takes a `char
+ * which is the case on Unicos
+
+2000-12-29 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am (EXTRA_libroken_la_SOURCES): ifaddrs.h ->
+ ifaddrs.hin
+
+2000-12-25 Assar Westerlund <assar@sics.se>
+
+ * getarg.c (print_arg): add a case for arg_strings
+
+2000-12-15 Johan Danielsson <joda@pdc.kth.se>
+
+ * snprintf.c (append_string): handle NULL strings by printing
+ `(null)'
+
+2000-12-12 Johan Danielsson <joda@pdc.kth.se>
+
+ * roken-common.h: add c++ externs
+
+ * roken.h.in: fix last commit differently
+
+2000-12-11 Assar Westerlund <assar@sics.se>
+
+ * err.hin (warnerr): remove, it's not part of the err.h interface
+ * roken-common.h (warnerr): moved here from err.hin
+ * Makefile.am (libroken_la_LDFLAGS): set version to 11:0:2
+ * vis.c: s/u_int32_t/unsigned/ for systems that do not define
+ u_int32_t
+
+2000-12-10 Johan Danielsson <joda@pdc.kth.se>
+
+ * Makefile.am: rename some headers to avoid conflict with possible
+ system headers
+
+2000-12-06 Johan Danielsson <joda@pdc.kth.se>
+
+ * vis.c: make sure _DIAGASSERT is defined
+
+ * unvis.c: make sure _DIAGASSERT is defined
+
+ * Makefile.am: unvis.c, and vis.h
+
+ * vis.h: vis.h from NetBSD
+
+ * unvis.c: unvis from NetBSD
+
+ * roken.h.in: cleanup previous
+
+ * roken-common.h: make `extern "C"' into a macro, this make emacs
+ much happier
+
+ * vis.c: strvis implementation from NetBSD
+
+ * roken.h.in: add prototypes for strvis*
+
+2000-12-05 Johan Danielsson <joda@pdc.kth.se>
+
+ * ifaddrs.h: fix freeifaddrs prototype, and add ifa_broadaddr
+ macro
+
+ * getifaddrs.c: free some memory
+
+2000-12-04 Johan Danielsson <joda@pdc.kth.se>
+
+ * ifaddrs.h: getifaddrs implementation using SIOCGIFCONFIG etc
+
+ * getifaddrs.c: getifaddrs implementation using SIOCGIFCONFIG etc
+
+2000-10-08 Assar Westerlund <assar@sics.se>
+
+ * mini_inetd.c (mini_inetd): check that fds are not too large to
+ select on
+
+2000-09-24 Assar Westerlund <assar@sics.se>
+
+ * esetenv.c: new file/function
+
+2000-08-16 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am: bump version to 10:0:1
+
+2000-08-10 Assar Westerlund <assar@sics.se>
+
+ * mini_inetd.c (accept_it): type-correctness on parameters to
+ accept
+
+2000-08-07 Johan Danielsson <joda@pdc.kth.se>
+
+ * roken.h.in: add proto compat for getsockname
+
+2000-08-04 Johan Danielsson <joda@pdc.kth.se>
+
+ * write_pid.c: conditionalise pidfile
+
+ * write_pid.c: add pidfile function
+
+2000-07-25 Johan Danielsson <joda@pdc.kth.se>
+
+ * Makefile.am: bump version to 9:0:0
+
+ * warnerr.c: add get_progname
+
+2000-07-24 Assar Westerlund <assar@sics.se>
+
+ * getaddrinfo.c (add_hostent): if there's no fqdn in `he' try
+ reverse resolving to see if there's a fuller name there. don't
+ use just-freed memory
+
+2000-07-22 Assar Westerlund <assar@sics.se>
+
+ * xdbm.h: do not define ndbm functions in terms of dbm functions
+ if we're using db
+
+2000-07-20 Assar Westerlund <assar@sics.se>
+
+ * rtbl.c (rtbl_format): avoid printing an empty row at the end
+
+2000-07-19 Johan Danielsson <joda@pdc.kth.se>
+
+ * Makefile.am: make this compatible with `make dist'
+
+ * Makefile.am: revert version number for now
+
+2000-07-18 Johan Danielsson <joda@pdc.kth.se>
+
+ * configure.in: AM_PROG_LIBTOOL -> AC_PROG_LIBTOOL
+
+2000-07-17 Johan Danielsson <joda@pdc.kth.se>
+
+ * Makefile.am: set ACLOCAL_AMFLAGS
+
+2000-07-15 Johan Danielsson <joda@pdc.kth.se>
+
+ * getaddrinfo_hostspec.c: add new function that takes socktype
+ hint as parameter
+
+2000-07-09 Assar Westerlund <assar@sics.se>
+
+ * rtbl.c (rtbl_add_column): initialize `col' completely
+
+ * configure.in: bring headers and functions more in-line with
+ what's actually being used
+
+2000-07-08 Johan Danielsson <joda@pdc.kth.se>
+
+ * roken.h.in: declare ether_addr and sockaddr_dl for AIX
+
+ * rtbl.{c,h}: simple table functions
+
+2000-07-08 Assar Westerlund <assar@sics.se>
+
+ * configure.in (AM_INIT_AUTOMAKE): bump version to 10
+ * configure.in (AC_BROKEN): add strsep_copy
+ * Makefile.am (ACLOCAL): fetch files from cf
+
+2000-07-01 Assar Westerlund <assar@sics.se>
+
+ * roken-common.h (pid_file_*): fix protos
+
+2000-06-28 Assar Westerlund <assar@sics.se>
+
+ * getnameinfo_verified.c (getnameinfo_verified): free memory
+ returned from getaddrinfo
+
+2000-06-27 Assar Westerlund <assar@sics.se>
+
+ * resolve.c: export string_to_type and type_to_string
+ * resolve.c: add key,sig,cert update test-program
+ * resolve.h: add key,sig,cert
+
+2000-06-21 Assar Westerlund <assar@sics.se>
+
+ * resolve.h: add T_SIG, T_KEY
+ * resolve.c: add SIG and KEY
+ * Makefile.am (libroken_la_SOURCES): add environment.c and
+ write_pid.c
+
+ * write_pid.c: new file for writing a pid file.
+
+ * environment.c: new file with functionality for reading
+ /etc/environment. From Ake Sandgren <ake@cs.umu.se>
+
+2000-06-12 Johan Danielsson <joda@pdc.kth.se>
+
+ * strsep_copy.c: strsep, but with const stringp so returns string
+ in separate buffer
+
+2000-05-23 Assar Westerlund <assar@sics.se>
+
+ * vsyslog.c (vsyslog): calculate length of new format string
+ correctly
+
+2000-05-22 Johan Danielsson <joda@pdc.kth.se>
+
+ * getusershell.c: implment the AIX version use
+ /etc/security/login.cfg
+
+2000-05-21 Assar Westerlund <assar@sics.se>
+
+ * vsyslog.c (vsyslog): actually handle `%m'
+
+2000-05-15 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am (libroken_la_LDFLAGS): set version to 8:1:3
+
+ * roken-common.h: moved __attribute__ to roken.h.in
+
+2000-04-14 Assar Westerlund <assar@sics.se>
+
+ * getaddrinfo_hostspec.c (roken_getaddrinfo_hostspec): copy the
+ correct length from `hostspec'. based on a patch from Love
+ <lha@s3.kth.se>
+
+2000-04-09 Assar Westerlund <assar@sics.se>
+
+ * xdbm.h: only include one of db.h and the dbm-series
+
+2000-04-05 Assar Westerlund <assar@sics.se>
+
+ * resolve.c (_resolve_debug): explicitly set to zero. this moves
+ the variable from bss to data and the dynamic linker on MacOS
+ X/Darwin seems unhappy with stuff in the bss segment.
+
+2000-04-03 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am: set version to 8:0:3
+
+2000-03-11 Assar Westerlund <assar@sics.se>
+
+ * roken.h.in (_SS_PAD1SIZE): try to write an inpenetrable
+ expression that also works on Crays
+
+2000-03-09 Assar Westerlund <assar@sics.se>
+
+ * getarg.c (arg_match_short): backup optind when there's a missing
+ argument so that the error can point at the flag and not the
+ non-existant argument
+
+2000-03-03 Assar Westerlund <assar@sics.se>
+
+ * Makefile.in (SOURCES): add timeval.c
+ * Makefile.am (libroken_la_SOURCES): add timeval.c
+ * timeval.c: new file
+
+2000-02-19 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am: set version to 7:1:2
+
+2000-02-16 Assar Westerlund <assar@sics.se>
+
+ * snprintf.c (PARSE_INT_FORMAT): note that shorts are actually
+ transmitted as ints
+ (according to the integer protomotion rules) in variable arguments
+ lists. Therefore, we should not call va_arg with short but rather
+ with int. See <http://www.debian.org/Bugs/db/57/57919.html> for
+ original bug report
+
+2000-02-13 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am: bump version to 7:0:2
+
+ * getarg.c (mandoc_template): also fix no- prefix in .Sh OPTIONS
+ * getarg.c (mandoc_template): better man-stuff for negative
+ options
+
+2000-02-07 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am: set version to 6:0:1
+
+2000-02-06 Assar Westerlund <assar@sics.se>
+
+ * xdbm.h: hopefully catch a few more declarations by including
+ <ndbm.h> even if <db.h> was found
+
+2000-01-26 Assar Westerlund <assar@sics.se>
+
+ * mini_inetd.c (mini_inetd): separate number of allocated sockets
+ and number of actual ones
+ * mini_inetd.c (mini_inetd): count sockets properly. and fail if
+ we cannot bind any
+ * mini_inetd.c (mini_inetd): make failing to create a socket
+ non-fatal
+
+2000-01-09 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am(libroken_la_SOURCES): add strcollect.c
+ * Makefile.in: add strcollect.[co]
+ * simple_exec.c: use vstrcollect
+ * roken-common.h (_PATH_DEV): add
+ (strcollect, vstrcollect): add prototypes
+ * strcollect.c: new file. functions for collapsing an `va_list'
+ into an `char **'
+
+2000-01-06 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am: bump version to 5:0:0
+
+1999-12-30 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am (strpftime_test_SOURCES): correct source file name
+
+ * roken.h.in (sockaddr_storage): change padding so that we have
+ one char[] of pad and then an unsigned long[] (for alignment and
+ padding). this works much better in practice.
+
+1999-12-22 Assar Westerlund <assar@sics.se>
+
+ * roken.h.in (sockaddr_storage): drop leading underscore on
+ `public' fields. this was the consensus on the ipng mailing list
+
+1999-12-21 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am (strpftime-test): define sources to avoid having
+ '.o'
+ * Makefile.am (print_version.h): use $(EXEEXT)
+ * Makefile.am (roken.h): add $(EXEEXT) to make this work on cygwin
+ et al
+
+1999-12-20 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am (libroken_la_LDFLAGS): bump version to 4:3:0
+
+ * getaddrinfo.c (get_nodes): use getipnodebyname instead of
+ gethostbyname(2)
+
+1999-12-16 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am (libroken_la_LDFLAGS): bump version to 4:2:0
+
+ * roken.h.in (struct sockaddr_storage): redefine with the example
+ code from rfc2553
+
+ * getaddrinfo.c (get_null): set loopback with correct endianess
+ for v4. dunno about v6.
+
+1999-12-13 Assar Westerlund <assar@sics.se>
+
+ * roken.h.in: add prototypes for str[pf]time
+
+ * signal.c: macosx = rhapsody ~= nextstep also can't handle
+ various definitions of the same symbol.
+
+1999-12-12 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am: bump version to 4:1:0
+
+1999-12-06 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am: bump version to 4:0:0
+
+1999-12-05 Assar Westerlund <assar@sics.se>
+
+ * Makefile.in: replace inaddr2str with getnameinfo_verified
+
+ * roken-common.h (INADDR_LOOPBACK): add fallback definition
+
+ * roken-common.h: move getnameinfo_verified to roken.h.in
+ * roken.h.in (inaddr2str): remove
+ * Makefile.am (libroken_la_SOURCES); removed inaddr2str
+ * roken-common.h (getnameinfo_verified): add prototype
+ * getnameinfo_verified.c: new file
+
+1999-12-04 Assar Westerlund <assar@sics.se>
+
+ * roken-common.h: add constants for getaddrinfo, getnameinfo
+ * roken.h.in (socklen_t): make independent of sockaddr_storage
+ (AI_*, NI_*, EAI_*): move to roken-common.h
+
+1999-12-03 Assar Westerlund <assar@sics.se>
+
+ * mini_inetd.c (mini_inted): rewrite to use `getaddrinfo'
+ * getaddrinfo.c (const_v*): no sizeof(sizeof())
+ * getaddrinfo.c (add_hostent): search for the canonical name among
+ all aliases
+ (getaddrinfo): handle AI_NUMERICHOST correctly
+ * Makefile.am (EXTRA_libroken_la_SOURCES): add freeaddinfo,
+ getaddrinfo, getnameinfo, gai_strerror
+ (getaddrinfo_test): add
+ * Makefile.in (SOURCES): add freeaddinfo, getaddrinfo,
+ getnameinfo, gai_strerror
+ (getaddrinfo_test): add
+ * roken.h.in: arpa/inet.h: include
+ (socklen_t): add
+ (struct addrinfo): add
+ (EAI_*): add
+ (NI_*): add
+ (AI_*): add
+ (getaddrinfo, getnameinfo, freeaddrinfo, gai_strerror): add
+ * getnameinfo.c: new file
+ * getaddrinfo-test.c: new file
+ * gai_strerror.c: new file
+ * getaddrinfo.c: new file
+ * freeaddrinfo.c: new file
+
+1999-11-25 Assar Westerlund <assar@sics.se>
+
+ * getopt.c (getopt): return -1 instead of EOF. From
+ <art@stacken.kth.se>
+
+1999-11-13 Assar Westerlund <assar@sics.se>
+
+ * strftime.c (strftime): handle `%z' and `%Z' in a tm_gmtoff-less
+ world
+
+ * getcap.c: make sure to use db only if we have both the library
+ and the header file
+
+1999-11-12 Assar Westerlund <assar@sics.se>
+
+ * getarg.h: add arg_counter
+ * getarg.c: add a new type of argument: `arg_counter' re-organize
+ the code somewhat
+
+ * Makefile.am: add strptime and strpftime-test
+
+ * snprintf.c (xyzprintf): try to do the right thing with an % at
+ the end of the format string
+
+ * strptime.c (strptime): implement '%U', '%V', '%W'
+ * strftime.c (strftime): implement '%U', '%V', '%W', '%z'
+
+ * strftime.c (strftime): correct %E and %O handling. do something
+ reasonable with "...%"
+
+ * strftime.c: replace the BSD implementation by one of our own
+ coding
+
+ * strptime.c : new file
+ * strpftime-test.c: new file
+
+1999-11-07 Assar Westerlund <assar@sics.se>
+
+ * parse_bytes-test.c: new file
+
+ * Makefile.am: add parse_bytes-test
+
+ * parse_units.c (parse_something): try to handle the case of no
+ value specified a little bit better
+
+1999-11-04 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am: bump version to 3:2:0
+
+1999-10-30 Assar Westerlund <assar@sics.se>
+
+ * snprintf.c (PARSE_INT_FORMAT): add redundant casts to work
+ around a gcc-bug that manifests itself on Linux-PPC. From Tom
+ Rini <trini@kernel.crashing.org>
+
+1999-10-28 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am: bump version to 3:1:0
+
+ * roken.h.in: use `unsigned char' instead of `u_int8_t' to avoid
+ having to have that definition. this is the easy way out instead
+ of getting the definition here where it's needed. flame me.
+
+Fri Oct 22 15:39:31 1999 Bjoern Groenvall <bg@sics.se>
+
+ * k_getpwuid.c (k_getpwuid): getspuid() does not exist (even
+ though it should), use getspnam().
+
+1999-10-20 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am: set version to 3:0:0
+
+1999-10-18 Johan Danielsson <joda@pdc.kth.se>
+
+ * getarg.3: document arg_collect
+
+ * getarg.c: change the way arg_collect works; it's still quite
+ horrible though
+
+ * getarg.h: change type of the collect function
+
+1999-10-17 Assar Westerlund <assar@sics.se>
+
+ * xdbm.h: undo last commit
+
+ * xdbm.h: reorder db includes
+
+1999-10-10 Assar Westerlund <assar@sics.se>
+
+ * socket.c: const-ize and comment
+
+ * net_write.c: const-ize
+
+ * base64.c: const-ize
+
+1999-10-06 Assar Westerlund <assar@sics.se>
+
+ * getarg.c (getarg): also set optind when returning error
+
+1999-09-26 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am: add parse_bytes.[ch]
+
+1999-09-24 Johan Danielsson <joda@pdc.kth.se>
+
+ * getarg.3: getarg manpage
+
+ * getarg.{c,h}: add a callback type to do more complicated processing
+
+ * getarg.{c,h}: add floating point support
+
+1999-09-16 Assar Westerlund <assar@sics.se>
+
+ * strlcat.c (strlcat): call strlcpy
+
+ * strlcpy.c: update name and prototype
+
+ * strlcat.c: update name and prototype
+
+ * roken.h.in: rename strc{py,at}_truncate to strlc{py,at}
+
+ * Makefile.am: rename strc{py,at}_truncate -> strlc{py,at}
+
+ * Makefile.in: rename strc{py,at}_truncate -> strlc{py,at}
+
+ * strcpy_truncate.c (strcpy_truncate): change return value to be
+ the length of `src'
+
+1999-08-16 Assar Westerlund <assar@sics.se>
+
+ * getcap.c: try to make this work on systems with DB
+
+1999-08-16 Johan Danielsson <joda@pdc.kth.se>
+
+ * getcap.c: protect from db-less systems
+
+1999-08-09 Johan Danielsson <joda@pdc.kth.se>
+
+ * simple_exec.c: add simple_exec{ve,le}
+
+ * getcap.c: getcap from NetBSD
+
+1999-08-06 Assar Westerlund <assar@sics.se>
+
+ * roken.h.in (sockaddr_storage): cater for those that have
+ v6-support also
+
+1999-08-05 Assar Westerlund <assar@sics.se>
+
+ * inet_ntop.c (inet_ntop_v4): remember to call ntohl
+
+1999-08-04 Assar Westerlund <assar@sics.se>
+
+ * roken-common.h: add shutdown constants
+
+ * mini_inetd.c (listen_v4, listen_v6): handle the case of the
+ protocol not being supported
+
+1999-08-01 Assar Westerlund <assar@sics.se>
+
+ * mini_inetd.c (socket_set_reuseaddr): remove duplicate
+
+1999-07-29 Assar Westerlund <assar@sics.se>
+
+ * mini_inetd.c (mini_inetd): fix my stupid bugs
+
+1999-07-28 Assar Westerlund <assar@sics.se>
+
+ * roken-common.h: add socket* functions
+
+ * Makefile.am (libroken_la_SOURCES): add socket.c
+
+ * socket.c: new file, originally from appl/ftp/common
+
+ * Makefile.am: set version to 2:0:2
+
+ * roken.h.in (inet_pton): add prototype
+
+ * Makefile.am (EXTRA_libroken_la_SOURCES): add inet_pton
+
+ * inet_pton.c: new file
+
+ * getipnodebyname.c (getipnodebyname): try gethostbyname2 if we
+ have it
+
+1999-07-27 Assar Westerlund <assar@sics.se>
+
+ * mini_inetd.c: support IPv6
+
+1999-07-26 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am: set version to 1:0:1
+
+ * roken.h.in (inet_ntop): add prototype
+
+ * roken-common.h: (INET{,6}_ADDRSTRLEN): add
+
+ * inet_ntop.c: new file
+
+ * Makefile.am (EXTRA_libroken_la_SOURCES): add inet_ntop.c
+
+ * Makefile.am: move some files from libroken_la_SOURCES to
+ EXTRA_libroken_la_SOURCES
+
+ * snprintf.c: some signed vs unsigned casts
+
+1999-07-24 Assar Westerlund <assar@sics.se>
+
+ * roken.h.in (struct sockaddr_storage): define it needed
+
+1999-07-19 Assar Westerlund <assar@sics.se>
+
+ * Makefile.am (libroken_la_SOURCES): add copyhostent.c,
+ freehostent.c, getipnodebyname.c, getipnodebyaddr.c
+
+ * roken.h.in: <netdb.h>: include
+ (copyhostent, freehostent, getipnodebyname, getipnodebyaddr): add
+ prototypes
+
+ * roken-common.h: new constants for getipnodeby*
+
+ * Makefile.in (SOURCES): add freehostent, copyhostent,
+ getipnodebyname, getipnodebyaddr
+
+ * freehostent.c: new file
+
+ * copyhostent.c: new file
+
+ * getipnodebyaddr.c: new file
+
+ * getipnodebyname.c: new file
+
+1999-07-13 Assar Westerlund <assar@sics.se>
+
+ * roken.h.in (k_getpwnam): update prototype
+
+ * k_getpwnam.c (k_getpwnam): const-ize
+
+ * get_default_username.c (get_default_username): a better way of
+ guessing when the user has su:ed
+
+1999-07-08 Johan Danielsson <joda@pdc.kth.se>
+
+ * roken.awk: use puts, as suggested by Jeffrey Hutzelman
+ <jhutz+@cmu.edu>
+
+1999-07-06 Assar Westerlund <assar@sics.se>
+
+ * readv.c (readv): typo
+
+1999-07-03 Assar Westerlund <assar@sics.se>
+
+ * writev.c (writev): error check malloc properly
+
+ * sendmsg.c (sendmsg): error check malloc properly
+
+ * resolve.c (parse_reply): error check malloc properly
+
+ * recvmsg.c (recvmsg): error check malloc properly
+
+ * readv.c (readv): error check malloc properly
+
+1999-06-23 Assar Westerlund <assar@sics.se>
+
+ * parse_units.c (acc_units): move the special case of 0 -> 1 to
+ parse_something to avoid having it happen at the end of the string
+
+1999-06-15 Assar Westerlund <assar@sics.se>
+
+ * Makefile.in: add get_default_username
+
+ * get_default_username.c: new file
+
+ * roken.h.in (get_default_username): add prototype
+
+ * Makefile.am: add get_default_username
+
+1999-05-08 Assar Westerlund <assar@sics.se>
+
+ * xdbm.h: also try <db.h> with DB_DBM_HSEARCH == 1
+
+ * strnlen.c (strnlen): update prototype
+
+ * Makefile.am: strndup.c: add
+
+ * Makefile.in: strndup.c: add
+
+ * roken.h.in (strndup): add
+ (strnlen): update prototype
+
+ * strndup.c: new file
+
+Fri Apr 16 17:59:30 1999 Assar Westerlund <assar@sics.se>
+
+ * roken.h.in: include strsep prototype if needed
+
+Thu Apr 15 14:04:03 1999 Johan Danielsson <joda@hella.pdc.kth.se>
+
+ * Makefile.am: make make-print-version.o depend on version.h
+
+Wed Apr 7 14:11:00 1999 Johan Danielsson <joda@hella.pdc.kth.se>
+
+ * Makefile.am: make it compile w/o krb4
+
+Sat Mar 27 17:33:03 1999 Johan Danielsson <joda@blubb.pdc.kth.se>
+
+ * snprintf.c (vasnprintf): correct check if realloc returns NULL
+
+Sat Mar 27 12:37:55 1999 Johan Danielsson <joda@hella.pdc.kth.se>
+
+ * Makefile.am: link print_version with -ldes to avoid unresolved
+ references if -lkrb is shared
+
+Sat Mar 20 03:42:30 1999 Assar Westerlund <assar@sics.se>
+
+ * roken-common.h (eread, ewrite): add
+
+ * simple_exec.c: add <roken.h>
+
+Fri Mar 19 21:29:58 1999 Assar Westerlund <assar@sics.se>
+
+ * Makefile.in: add eread, ewrite
+
+ * eread.c, ewrite.c: new files
+
+ * Makefile.am (libroken_la_SOURCES): add eread and ewrite
+
+Fri Mar 19 14:52:57 1999 Johan Danielsson <joda@hella.pdc.kth.se>
+
+ * Makefile.am: add version-info
+
+Thu Mar 18 12:53:32 1999 Johan Danielsson <joda@hella.pdc.kth.se>
+
+ * Makefile.am: remove include_dir hack
+
+ * Makefile.am: parse_units.h
+
+ * Makefile.am: include Makefile.am.common
+
+Sat Mar 13 23:31:35 1999 Assar Westerlund <assar@sics.se>
+
+ * Makefile.in (SOURCES): add glob.c
+
+Thu Mar 11 15:02:21 1999 Johan Danielsson <joda@hella.pdc.kth.se>
+
+ * iruserok.c: move innetgr() to separate file
+
+ * innetgr.c: move innetgr() to separate file
+
+ * hstrerror.c (hstrerror): add const to return type
+
+ * erealloc.c: fix types in format string
+
+ * emalloc.c: fix types in format string
+
+Wed Mar 10 16:36:55 1999 Johan Danielsson <joda@hella.pdc.kth.se>
+
+ * resolve.c: ugly fix for crays
+
+Mon Mar 8 11:52:20 1999 Johan Danielsson <joda@hella.pdc.kth.se>
+
+ * roken.h.in: protos for {un,}setenv
+
+1999-02-16 Assar Westerlund <assar@sics.se>
+
+ * Makefile.in (SOURCES): add fnmatch
+
+ * roken-common.h (abs): add
+
+Sat Feb 13 17:12:53 1999 Assar Westerlund <assar@sics.se>
+
+ * emalloc.c, erealloc.c, estrup.c: new files
+
+ * roken.h.in (mkstemp, gethostname): also includes prototypes if
+ they are needed.
+
+1998-12-23 Assar Westerlund <assar@sics.se>
+
+ * roken.h.in: mkstemp: add prototype
+
+1998-12-20 Assar Westerlund <assar@sics.se>
+
+ * snprintf.c, iruserok.c, parse-units.c: unsigned char-correctness
+
+ * roken.h.in (inet_aton): also chedk NEED_INET_ATON_PROTO
+
+ * roken-common.h: __attribute__: check for autoconf'd
+ HAVE___ATTRIBUTE__ instead of GNUC
+
+Sun Dec 6 19:53:21 1998 Assar Westerlund <assar@sics.se>
+
+ * parse_units.c (parse_something): func is called with val == 0 if
+ no unit was given
+ (acc_flags, acc_units): update to new standard
+
+Fri Nov 27 03:09:42 1998 Assar Westerlund <assar@sics.se>
+
+ * resolve.c (stot): constify
+ (type_to_string): always declare
+ (dns_lookup_int): correct debug output
+
+Thu Nov 26 23:43:55 1998 Assar Westerlund <assar@sics.se>
+
+ * resolve.c (dns_lookup_int): send rr_class to res_search
+
+Thu Nov 26 17:09:47 1998 Johan Danielsson <joda@hella.pdc.kth.se>
+
+ * resolve.c: some cleanup
+
+ * resolve.h: add T_NAPTR
+
+Sun Nov 22 10:23:07 1998 Assar Westerlund <assar@sics.se>
+
+ * Makefile.in (WFLAGS): set
+
+ * k_getpwnam.c (k_getpwnam): check for `struct spwd'
+
+ * k_getpwuid.c (k_getpwuid): check for `struct spwd'
+
+Tue Sep 8 05:18:31 1998 Assar Westerlund <assar@sics.se>
+
+ * recvmsg.c (recvmsg): patch from bpreece@unity.ncsu.edu
+
+Fri Sep 4 16:29:27 1998 Johan Danielsson <joda@emma.pdc.kth.se>
+
+ * vsyslog.c: asprintf -> vasprintf
+
+Tue Aug 18 22:25:52 1998 Assar Westerlund <assar@sics.se>
+
+ * getarg.h (arg_printusage): new signature
+
+ * getarg.c (arg_printusage): new parameter `progname'. NULL means
+ __progname.
+
+Sun Aug 9 14:53:44 1998 Johan Danielsson <joda@emma.pdc.kth.se>
+
+ * Makefile.am: net_{read,write}.c
+
+Fri Jul 24 21:56:02 1998 Assar Westerlund <assar@sics.se>
+
+ * simple_exec.c (simple_execvp): loop around waitpid when errno ==
+ EINTR
+
+Thu Jul 23 20:24:35 1998 Johan Danielsson <joda@emma.pdc.kth.se>
+
+ * Makefile.am: net_{read,write}.c
+
+Wed Jul 22 21:38:35 1998 Assar Westerlund <assar@sics.se>
+
+ * simple_exec.c (simple_execlp): initialize `argv'
+
+Mon Jul 13 23:01:22 1998 Assar Westerlund <assar@sics.se>
+
+ * inaddr2str.c (inaddr2str): don't advance hostent->h_addr_list,
+ use a copy instead
+
+Fri Jul 10 01:20:08 1998 Assar Westerlund <assar@sics.se>
+
+ * roken.h.in (net_write, net_read): add prototypes
+
+ * Makefile.in: net_{read,write}.c: add
+
+ * net_{read,write}.c: new files
+
+Tue Jun 30 17:29:09 1998 Assar Westerlund <assar@sics.se>
+
+ * roken.h.in (issuid): add
+
+ * get_window_size.c: fix misspelling of TIOCGWINSZ and bad use of
+ fields
+
+Sun May 31 03:24:34 1998 Johan Danielsson <joda@emma.pdc.kth.se>
+
+ * getarg.c (mandoc_template): Put short and long options in
+ SYNOPSIS within the same [ ] pair.
+
+Sat May 30 00:13:01 1998 Johan Danielsson <joda@emma.pdc.kth.se>
+
+ * getarg.c (arg_printusage): try to keep options shorter than
+ column width
+
+ * get_window_size.c (get_window_size): check COLUMNS and LINES
+
+Fri May 29 00:05:04 1998 Johan Danielsson <joda@emma.pdc.kth.se>
+
+ * getarg.c (mandoc_template): Put short and long options in
+ DESCRIPTION on the same line.
+
+ * getarg.c (arg_match_long): make sure you only get an exact match
+ if the strings are the same length
+
+Thu May 14 02:23:40 1998 Assar Westerlund <assar@sics.se>
+
+ * roken.awk: stupid cray awk wants \#
+
+Fri May 1 01:29:36 1998 Assar Westerlund <assar@sics.se>
+
+ * print_version.c (print_version): according to ISO/ANSI C the
+ elements of `arg' are not constant and therefore not settable at
+ compile-time. Set the at run-time instead.
+
+Sun Apr 19 10:00:06 1998 Assar Westerlund <assar@sics.se>
+
+ * roken.h.in: include paths.h
+
+Sun Apr 5 12:30:49 1998 Assar Westerlund <assar@sics.se>
+
+ * Makefile.in (SOURCES): add roken_gethostby.c to make solaris
+ make happy
+
+Thu Mar 19 20:41:25 1998 Johan Danielsson <joda@emma.pdc.kth.se>
+
+ * simple_exec.c: Simple fork+exec system() replacement.
+
+Fri Mar 6 00:21:53 1998 Johan Danielsson <joda@emma.pdc.kth.se>
+
+ * roken_gethostby.c: Make `roken_gethostby_setup' take URL-like
+ specification instead of split up versions. Makes it easier for
+ calling applications.
+
+ * roken_gethostby.c: Another miracle of the 20th century:
+ gethostby* over HTTP.
+
+Sat Feb 21 15:18:36 1998 assar westerlund <assar@sics.se>
+
+ * parse_time.c (unparse_time_approx): new function that calls
+ `unparse_units_approx'
+
+ * parse_units.c (unparse_units_approx): new function that will
+ only print the first unit.
+
+ * Makefile.in: include parse_{time,units}
+
+Thu Feb 12 03:30:08 1998 Assar Westerlund <assar@sics.se>
+
+ * parse_time.c (print_time_table): don't return a void value.
+
+Tue Feb 3 11:06:24 1998 Johan Danielsson <joda@emma.pdc.kth.se>
+
+ * getarg.c (mandoc_template): Change date format to full month
+ name, and day of month without leading zero.
+
+Thu Jan 22 21:23:23 1998 Johan Danielsson <joda@emma.pdc.kth.se>
+
+ * getarg.c: Fix long form of negative flags.
+
+Mon Dec 29 23:31:10 1997 Johan Danielsson <joda@emma.pdc.kth.se>
+
+ * roken.h.in: Include <err.h>, to get linux __progname.
+
+Sun Dec 21 09:45:18 1997 Assar Westerlund <assar@sics.se>
+
+ * parse_time.c (print_time_table): new function
+
+ * parse_units.c (print_flags_table, print_units_table): new
+ functions.
+
+Thu Dec 4 02:51:46 1997 Assar Westerlund <assar@sics.se>
+
+ * iruserok.c: moved here.
+
+ * snprintf.c (sn_append_char): don't write any terminating zero.
+ (as_reserve): don't loop. better heuristic for how much space to
+ realloc.
+ (vasnprintf): simplify initializing to one.
+
+Sun Nov 30 14:56:59 1997 Johan Danielsson <joda@emma.pdc.kth.se>
+
+ * getarg.c: Add mandoc help back-end to getarg.
+
+Wed Nov 12 01:09:17 1997 Johan Danielsson <joda@emma.pdc.kth.se>
+
+ * verr.c, verrx.c: Fix warnings by moving exit from.
+
+Tue Nov 11 21:12:09 1997 Johan Danielsson <joda@emma.pdc.kth.se>
+
+ * parse_units.c: Change the list of separating characters (between
+ units) to comma, space, and tab, removing digits. Having digits in
+ this list makes a flag like `T42 generate a parse error. This
+ change makes `17m3s' an invalid time-spec (you need a space).
+
+Tue Nov 11 02:38:44 1997 Assar Westerlund <assar@sics.se>
+
+ * roken.h: add <sys/socket.h>
+
+Sun Nov 9 04:48:46 1997 Johan Danielsson <joda@emma.pdc.kth.se>
+
+ * fnmatch.c: Add fnmatch from NetBSD
+
+Sun Nov 9 02:00:08 1997 Assar Westerlund <assar@sics.se>
+
+ * parse_units.c (parse_something): ignore white-space and ','
+
+Mon Nov 3 22:38:32 1997 Assar Westerlund <assar@sics.se>
+
+ * roken.h: fclose prototype
+
+ * roken.h: add prototype for vsyslog
+
+ * Makefile.in: add some more source files to make soriasis make
+ happy
+
+Sat Nov 1 00:19:21 1997 Assar Westerlund <assar@sics.se>
+
+ * roken.h: include <sys/uio.h> and <errno.h>.
+ prototypes for readv and writev
+
+ * readv.c, writev.c: new files
+
+Wed Oct 29 02:21:38 1997 Assar Westerlund <assar@sics.se>
+
+ * roken.h: Add ugly macros for openlog, gethostbyname,
+ gethostbyaddr, and getservbyname for the benefit of Crays. Add
+ default definition of MAXPATHLEN
diff --git a/third_party/heimdal/lib/roken/Makefile.am b/third_party/heimdal/lib/roken/Makefile.am
new file mode 100644
index 0000000..1f530c7
--- /dev/null
+++ b/third_party/heimdal/lib/roken/Makefile.am
@@ -0,0 +1,293 @@
+# $Id$
+
+include $(top_srcdir)/Makefile.am.common
+
+ACLOCAL_AMFLAGS = -I ../../cf
+
+CLEANFILES = roken.h make-roken.c $(XHEADERS)
+
+lib_LTLIBRARIES = libroken.la
+
+libroken_la_LDFLAGS = -version-info 20:0:1
+libroken_la_CPPFLAGS = -DBUILD_ROKEN_LIB
+
+if versionscript
+libroken_la_LDFLAGS += $(LDFLAGS_VERSION_SCRIPT)$(srcdir)/version-script.map
+endif
+
+AM_CPPFLAGS += $(libroken_la_CPPFLAGS)
+if HAVE_DBHEADER
+AM_CPPFLAGS += -I$(DBHEADER)
+endif
+
+bin_PROGRAMS = rkvis rkbase32 rkbase64
+noinst_PROGRAMS = snprintf-test resolve-test rkpty test-detach test-auxval rtbl timeval
+
+CHECK_LOCAL = snprintf-test resolve-test rkpty make-roken
+
+check_PROGRAMS = \
+ base32-test \
+ base64-test \
+ getaddrinfo-test \
+ getifaddrs-test \
+ hex-test \
+ test-auxval \
+ test-getuserinfo \
+ test-readenv \
+ resolve-test \
+ parse_bytes-test \
+ parse_reply-test \
+ parse_time-test \
+ snprintf-test \
+ strpftime-test \
+ timeval \
+ tsearch-test
+
+TESTS = $(check_PROGRAMS)
+
+LDADD = libroken.la
+make_roken_LDADD =
+
+noinst_LTLIBRARIES = libtest.la
+libtest_la_SOURCES = strftime.c strptime.c snprintf.c tsearch.c
+libtest_la_CFLAGS = -DTEST_SNPRINTF -DTEST_STRPFTIME
+
+parse_reply_test_SOURCES = parse_reply-test.c resolve.c
+parse_reply_test_CFLAGS = -DTEST_RESOLVE
+
+test_readenv_SOURCES = test-readenv.c test-mem.c
+test_auxval_SOURCES = test-auxval.c
+test_getuserinfo_SOURCES = test-getuserinfo.c
+test_getuserinfo_LDADD = libtest.la $(LDADD)
+
+if have_err_h
+err_h =
+else
+err_h = err.h
+endif
+
+if have_fnmatch_h
+fnmatch_h =
+else
+fnmatch_h = fnmatch.h
+endif
+
+if have_ifaddrs_h
+ifaddrs_h =
+else
+ifaddrs_h = ifaddrs.h
+endif
+
+if have_search_h
+search_h =
+else
+search_h = search.h
+endif
+
+if have_vis_h
+vis_h =
+else
+vis_h = vis.h
+endif
+
+timeval_SOURCES = timeval.c
+timeval_CPPFLAGS = -DTEST
+
+rkvis_SOURCES = vis.c $(vis_h) vis-extras.h
+rkvis_CPPFLAGS = -DTEST
+
+rkbase32_SOURCES = base32.c
+rkbase32_CPPFLAGS = -DTEST
+
+rkbase64_SOURCES = base64.c
+rkbase64_CPPFLAGS = -DTEST
+
+rtbl_SOURCES = rtbl.c
+rtbl_CPPFLAGS = -DTEST
+
+test_detach_SOURCES = test-detach.c
+
+rkpty_LDADD = $(LIB_openpty) $(LDADD)
+
+parse_time_test_SOURCES = parse_time-test.c test-mem.c
+
+strpftime_test_SOURCES = strpftime-test.c strpftime-test.h
+strpftime_test_LDADD = libtest.la $(LDADD)
+strpftime_test_CFLAGS = -DTEST_STRPFTIME
+snprintf_test_SOURCES = snprintf-test.c
+snprintf_test_LDADD = libtest.la $(LDADD)
+snprintf_test_CFLAGS = -DTEST_SNPRINTF
+tsearch_test_SOURCES = tsearch-test.c
+tsearch_test_LDADD = libtest.la $(LDADD)
+tsearch_test_CFLAGS = -DTEST_TSEARCH
+
+resolve_test_SOURCES = resolve-test.c
+
+libroken_la_SOURCES = \
+ base32.c \
+ base64.c \
+ bswap.c \
+ concat.c \
+ cloexec.c \
+ clz.c \
+ ct.c \
+ detach.c \
+ doxygen.c \
+ dumpdata.c \
+ environment.c \
+ eread.c \
+ esetenv.c \
+ ewrite.c \
+ fseeko.c \
+ ftello.c \
+ getaddrinfo_hostspec.c \
+ get_window_size.c \
+ getarg.c \
+ getauxval.c \
+ getauxval.h \
+ getnameinfo_verified.c \
+ getprogname.c \
+ getuserinfo.c \
+ h_errno.c \
+ hex.c \
+ hostent_find_fqdn.c \
+ issuid.c \
+ memmem.c \
+ mini_inetd.c \
+ mkdir.c \
+ mkdtemp.c \
+ mkostemp.c \
+ net_read.c \
+ net_write.c \
+ parse_bytes.c \
+ parse_time.c \
+ parse_units.c \
+ qsort.c \
+ rand.c \
+ realloc.c \
+ resolve.c \
+ roken_gethostby.c \
+ rtbl.c \
+ rtbl.h \
+ secure_getenv.c \
+ secure_getenv.h \
+ setprogname.c \
+ signal.c \
+ simple_exec.c \
+ snprintf.c \
+ socket.c \
+ strcollect.c \
+ strerror_r.c \
+ strpool.c \
+ timeval.c \
+ tm2time.c \
+ unvis.c \
+ vis.c \
+ $(vis_h) \
+ vis-extras.h \
+ warnerr.c \
+ write_pid.c \
+ xfree.c \
+ xdbm.h
+
+EXTRA_libroken_la_SOURCES = \
+ err.hin \
+ fnmatch.hin \
+ ifaddrs.hin \
+ search.hin \
+ vis.hin
+
+libroken_la_LIBADD = @LTLIBOBJS@ $(LIB_crypt) $(LIB_pidfile)
+if SUNOS
+libroken_la_LIBADD += -lnsl -lsocket
+endif
+
+$(LTLIBOBJS) $(libroken_la_OBJECTS): roken.h $(XHEADERS)
+
+BUILT_SOURCES = roken.h $(err_h) $(fnmatch_h) $(ifaddrs_h) $(search_h) $(vis_h)
+
+## these are controlled by configure
+XHEADERS = $(err_h) $(fnmatch_h) $(ifaddrs_h) $(search_h) $(vis_h)
+CLEANFILES += err.h fnmatch.h ifaddrs.h search.h vis.h
+
+dist_include_HEADERS = \
+ base32.h \
+ base64.h \
+ getarg.h \
+ hex.h \
+ parse_bytes.h \
+ parse_time.h \
+ parse_units.h \
+ resolve.h \
+ roken-common.h \
+ rtbl.h \
+ xdbm.h
+
+if have_socket_wrapper
+libroken_la_SOURCES += socket_wrapper.c socket_wrapper.h
+dist_include_HEADERS += socket_wrapper.h
+endif
+
+build_HEADERZ = test-mem.h $(XHEADERS)
+
+nodist_include_HEADERS = roken.h
+rokenincludedir = $(includedir)/roken
+nodist_rokeninclude_HEADERS = $(XHEADERS)
+
+man_MANS = getarg.3 parse_time.3 rtbl.3 ecalloc.3
+
+SUFFIXES += .hin
+.hin.h:
+ cp $< $@
+
+# Make make-roken deprecated in 1.4 when we know that roken-h-process.pl works
+if !CROSS_COMPILE
+
+noinst_PROGRAMS += make-roken
+BUILT_SOURCES += make-roken.c
+
+nodist_make_roken_SOURCES = make-roken.c
+
+roken.h: make-roken$(EXEEXT)
+ @./make-roken$(EXEEXT) > tmp.h ;\
+ if [ -f roken.h ] && cmp -s tmp.h roken.h ; then rm -f tmp.h ; \
+ else rm -f roken.h; mv tmp.h roken.h; fi
+
+make-roken.c: roken.h.in roken.awk
+ $(AWK) -f $(srcdir)/roken.awk $(srcdir)/roken.h.in > make-roken.c
+
+else
+
+roken.h: $(top_srcdir)/cf/roken-h-process.pl roken.h.in
+ perl $(top_srcdir)/cf/roken-h-process.pl \
+ -c $(top_builddir)/include/config.h \
+ -p $(srcdir)/roken.h.in -o roken.h
+
+endif
+
+
+EXTRA_DIST = \
+ NTMakefile \
+ roken.awk roken.h.in \
+ $(man_MANS) \
+ dirent.c \
+ dirent.hin \
+ dirent-test.c \
+ dlfcn.hin \
+ dlfcn_w32.c \
+ getifaddrs_w32.c \
+ ndbm_wrap.c \
+ ndbm_wrap.h \
+ rename.c \
+ simple_exec_w32.c \
+ sleep.c \
+ sockstartup_w32.c \
+ stdbool.hin \
+ stdint.hin \
+ syslogc.c \
+ syslog.hin \
+ test-auxval.c \
+ test-mem.h \
+ test-mini_inetd.c \
+ win32_alloc.c \
+ version-script.map
diff --git a/third_party/heimdal/lib/roken/NTMakefile b/third_party/heimdal/lib/roken/NTMakefile
new file mode 100644
index 0000000..5749efd
--- /dev/null
+++ b/third_party/heimdal/lib/roken/NTMakefile
@@ -0,0 +1,312 @@
+########################################################################
+#
+# Copyright (c) 2009 - 2017, Secure Endpoints Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# - 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 COPYRIGHT HOLDERS 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
+# COPYRIGHT HOLDER 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.
+#
+
+RELDIR=lib\roken
+
+!include ../../windows/NTMakefile.w32
+
+libroken_la_OBJS = \
+ $(OBJ)\base32.obj \
+ $(OBJ)\base64.obj \
+ $(OBJ)\bswap.obj \
+ $(OBJ)\concat.obj \
+ $(OBJ)\cloexec.obj \
+ $(OBJ)\clz.obj \
+ $(OBJ)\ct.obj \
+ $(OBJ)\detach.obj \
+ $(OBJ)\dirent.obj \
+ $(OBJ)\dlfcn_w32.obj \
+ $(OBJ)\dumpdata.obj \
+ $(OBJ)\ecalloc.obj \
+ $(OBJ)\emalloc.obj \
+ $(OBJ)\environment.obj \
+ $(OBJ)\eread.obj \
+ $(OBJ)\erealloc.obj \
+ $(OBJ)\err.obj \
+ $(OBJ)\errx.obj \
+ $(OBJ)\esetenv.obj \
+ $(OBJ)\estrdup.obj \
+ $(OBJ)\ewrite.obj \
+ $(OBJ)\flock.obj \
+ $(OBJ)\fnmatch.obj \
+ $(OBJ)\fseeko.obj \
+ $(OBJ)\ftello.obj \
+ $(OBJ)\getauxval.obj \
+ $(OBJ)\getaddrinfo_hostspec.obj \
+ $(OBJ)\get_window_size.obj \
+ $(OBJ)\getarg.obj \
+ $(OBJ)\getifaddrs_w32.obj \
+ $(OBJ)\getnameinfo_verified.obj \
+ $(OBJ)\getopt.obj \
+ $(OBJ)\getprogname.obj \
+ $(OBJ)\gettimeofday.obj \
+ $(OBJ)\getuserinfo.obj \
+ $(OBJ)\hex.obj \
+ $(OBJ)\hostent_find_fqdn.obj \
+ $(OBJ)\inet_aton.obj \
+ $(OBJ)\issuid.obj \
+ $(OBJ)\localtime_r.obj \
+ $(OBJ)\lstat.obj \
+ $(OBJ)\memmem.obj \
+ $(OBJ)\memset_s.obj \
+ $(OBJ)\mergesort_r.obj \
+ $(OBJ)\mkdir.obj \
+ $(OBJ)\mini_inetd.obj \
+ $(OBJ)\mkdtemp.obj \
+ $(OBJ)\mkstemp.obj \
+ $(OBJ)\mkostemp.obj \
+ $(OBJ)\net_read.obj \
+ $(OBJ)\net_write.obj \
+ $(OBJ)\parse_bytes.obj \
+ $(OBJ)\parse_time.obj \
+ $(OBJ)\parse_units.obj \
+ $(OBJ)\realloc.obj \
+ $(OBJ)\rename.obj \
+ $(OBJ)\resolve.obj \
+ $(OBJ)\rand.obj \
+ $(OBJ)\roken_gethostby.obj \
+ $(OBJ)\rtbl.obj \
+ $(OBJ)\secure_getenv.obj \
+ $(OBJ)\sendmsg.obj \
+ $(OBJ)\setenv.obj \
+ $(OBJ)\setprogname.obj \
+ $(OBJ)\simple_exec_w32.obj \
+ $(OBJ)\sleep.obj \
+ $(OBJ)\snprintf.obj \
+ $(OBJ)\socket.obj \
+ $(OBJ)\sockstartup_w32.obj \
+ $(OBJ)\strcollect.obj \
+ $(OBJ)\strerror_r.obj \
+ $(OBJ)\strftime.obj \
+ $(OBJ)\strlcat.obj \
+ $(OBJ)\strlcpy.obj \
+ $(OBJ)\strndup.obj \
+ $(OBJ)\strpool.obj \
+ $(OBJ)\strptime.obj \
+ $(OBJ)\strsep.obj \
+ $(OBJ)\strsep_copy.obj \
+ $(OBJ)\strtok_r.obj \
+ $(OBJ)\strtoll.obj \
+ $(OBJ)\strtoull.obj \
+ $(OBJ)\syslogc.obj \
+ $(OBJ)\timegm.obj \
+ $(OBJ)\timeval.obj \
+ $(OBJ)\tm2time.obj \
+ $(OBJ)\tsearch.obj \
+ $(OBJ)\unvis.obj \
+ $(OBJ)\verr.obj \
+ $(OBJ)\verrx.obj \
+ $(OBJ)\vis.obj \
+ $(OBJ)\vwarn.obj \
+ $(OBJ)\vwarnx.obj \
+ $(OBJ)\warn.obj \
+ $(OBJ)\warnerr.obj \
+ $(OBJ)\warnx.obj \
+ $(OBJ)\win32_alloc.obj \
+ $(OBJ)\win32_version.obj \
+ $(OBJ)\writev.obj \
+ $(OBJ)\xfree.obj
+
+!if $(NMAKE_WINVER) < 0x0600
+libroken_la_OBJS=$(libroken_la_OBJS) \
+ $(OBJ)\inet_ntop.obj \
+ $(OBJ)\inet_pton.obj
+!endif
+
+{}.c{$(OBJ)}.obj::
+ $(C2OBJ_P) -DBUILD_ROKEN_LIB
+
+$(LIBROKEN): $(libroken_la_OBJS)
+ $(LIBCON_C) -out:$@ @<<
+$(**: =
+)
+<<
+
+$(OBJ)\make-roken.exe: $(OBJ)\make-roken.obj
+ $(EXECONLINK)
+
+$(OBJ)\make-roken.c: roken.h.in roken.awk $(INCDIR)\config.h
+ $(AWK) -f roken.awk roken.h.in > $(OBJ)\make-roken.c || $(RM) $(OBJ)\make-roken.c
+
+$(INCDIR)\roken.h: $(OBJ)\make-roken.exe
+ $(OBJ)\make-roken.exe > $@ || $(RM) $@
+
+INCFILES = \
+ $(INCDIR)\base32.h \
+ $(INCDIR)\base64.h \
+ $(INCDIR)\dirent.h \
+ $(INCDIR)\dlfcn.h \
+ $(INCDIR)\err.h \
+ $(INCDIR)\fnmatch.h \
+ $(INCDIR)\getarg.h \
+ $(INCDIR)\hex.h \
+ $(INCDIR)\ifaddrs.h \
+ $(INCDIR)\parse_bytes.h \
+ $(INCDIR)\parse_time.h \
+ $(INCDIR)\parse_units.h \
+ $(INCDIR)\resolve.h \
+ $(INCDIR)\roken.h \
+ $(INCDIR)\roken-common.h \
+ $(INCDIR)\rtbl.h \
+ $(INCDIR)\search.h \
+ $(INCDIR)\stdbool.h \
+ $(INCDIR)\syslog.h \
+ $(INCDIR)\vis.h \
+ $(INCDIR)\vis-extras.h \
+!ifndef HAVE_STDINT_H
+ $(INCDIR)\stdint.h \
+!endif
+ $(INCDIR)\versionsupport.h \
+ $(INCDIR)\xdbm.h
+
+clean::
+ -$(RM) $(XHEADERS)
+
+all:: $(INCFILES) $(LIBROKEN)
+
+clean::
+ -$(RM) $(LIBROKEN)
+
+TMP_PROGS = $(OBJ)\snprintf-test.exe $(OBJ)\resolve-test.exe $(OBJ)\test-getuserinfo.exe
+
+# Tests
+
+TEST_PROGS = \
+ $(OBJ)\base32-test.exe \
+ $(OBJ)\base64-test.exe \
+ $(OBJ)\getaddrinfo-test.exe \
+ $(OBJ)\getifaddrs-test.exe \
+ $(OBJ)\hex-test.exe \
+ $(OBJ)\test-detach.exe \
+ $(OBJ)\test-getuserinfo.exe \
+ $(OBJ)\test-readenv.exe \
+ $(OBJ)\parse_bytes-test.exe \
+ $(OBJ)\parse_reply-test.exe \
+ $(OBJ)\parse_time-test.exe \
+ $(OBJ)\snprintf-test.exe \
+ $(OBJ)\strpftime-test.exe \
+ $(OBJ)\dirent-test.exe \
+ $(OBJ)\test-mini_inetd.exe
+
+$(OBJ)\strftime_test.obj: strftime.c
+ $(C2OBJ) -DTEST_SNPRINTF -DTEST_STRPFTIME -DBUILD_ROKEN_LIB
+
+$(OBJ)\strptime_test.obj: strptime.c
+ $(C2OBJ) -DTEST_SNPRINTF -DTEST_STRPFTIME -DBUILD_ROKEN_LIB
+
+$(OBJ)\snprintf_test.obj: snprintf.c
+ $(C2OBJ) -DTEST_SNPRINTF -DTEST_STRPFTIME -DBUILD_ROKEN_LIB
+
+$(OBJ)\libtest.lib: $(OBJ)\strftime_test.obj $(OBJ)\strptime_test.obj $(OBJ)\snprintf_test.obj
+ $(LIBCON)
+
+$(OBJ)\parse_reply-test.obj: parse_reply-test.c
+ $(C2OBJ) -DTEST_RESOLVE -DBUILD_ROKEN_LIB
+
+$(OBJ)\resolve_test.obj: resolve.c
+ $(C2OBJ) -DTEST_RESOLVE -DBUILD_ROKEN_LIB
+
+$(OBJ)\parse_reply-test.exe: $(OBJ)\parse_reply-test.obj $(OBJ)\resolve_test.obj $(LIBROKEN)
+ $(EXECONLINK) DnsAPI.lib
+
+$(OBJ)\test-readenv.exe: $(OBJ)\test-readenv.obj $(OBJ)\test-mem.obj $(LIBROKEN)
+ $(EXECONLINK)
+
+$(OBJ)\parse_time-test.exe: $(OBJ)\parse_time-test.obj $(OBJ)\test-mem.obj $(LIBROKEN)
+ $(EXECONLINK)
+
+$(OBJ)\strpftime-test.obj: strpftime-test.c
+ $(C2OBJ) -DTEST_STRPFTIME -DBUILD_ROKEN_LIB
+
+$(OBJ)\strpftime-test.exe: $(OBJ)\strpftime-test.obj $(OBJ)\libtest.lib $(LIBROKEN)
+ $(EXECONLINK)
+
+$(OBJ)\snprintf-test.obj: snprintf-test.c
+ $(C2OBJ) -DTEST_SNPRINTF -DBUILD_ROKEN_LIB
+
+$(OBJ)\snprintf-test.exe: $(OBJ)\snprintf-test.obj $(OBJ)\libtest.lib $(LIBROKEN)
+ $(EXECONLINK)
+
+$(OBJ)\resolve-test.exe: $(OBJ)\resolve-test.obj $(LIBROKEN)
+ $(EXECONLINK) DnsAPI.lib
+
+$(OBJ)\base32-test.exe: $(OBJ)\base32-test.obj $(OBJ)\base32.obj $(LIBROKEN)
+ $(EXECONLINK)
+
+$(OBJ)\base64-test.exe: $(OBJ)\base64-test.obj $(OBJ)\base64.obj $(LIBROKEN)
+ $(EXECONLINK)
+
+$(OBJ)\getaddrinfo-test.exe: $(OBJ)\getaddrinfo-test.obj $(LIBROKEN)
+ $(EXECONLINK)
+
+$(OBJ)\hex-test.exe: $(OBJ)\hex-test.obj $(LIBROKEN)
+ $(EXECONLINK)
+
+$(OBJ)\parse_bytes-test.exe: $(OBJ)\parse_bytes-test.obj $(LIBROKEN)
+ $(EXECONLINK)
+
+$(OBJ)\test-detach.exe: $(OBJ)\test-detach.obj $(OBJ)\detach.obj $(LIBROKEN)
+ $(EXECONLINK)
+
+$(OBJ)\test-getuserinfo.exe: $(OBJ)\test-getuserinfo.obj $(OBJ)\getuserinfo.obj $(LIBROKEN)
+ $(EXECONLINK) Secur32.lib Shell32.lib
+
+$(OBJ)\dirent-test.exe: $(OBJ)\dirent-test.obj $(LIBROKEN)
+ $(EXECONLINK)
+
+$(OBJ)\getifaddrs-test.exe: $(OBJ)\getifaddrs-test.obj $(LIBROKEN)
+ $(EXECONLINK)
+
+$(OBJ)\test-mini_inetd.exe: $(OBJ)\test-mini_inetd.obj $(LIBROKEN)
+ $(EXECONLINK)
+
+test-binaries: $(TEST_PROGS) $(TMP_PROGS)
+
+test-run:
+ cd $(OBJ)
+ -test-mini_inetd.exe
+ -dirent-test.exe
+ -base32-test.exe
+ -base64-test.exe
+ -getaddrinfo-test.exe www.h5l.org http
+ -getifaddrs-test.exe
+ -hex-test.exe
+ -test-readenv.exe
+ -parse_bytes-test.exe
+# Need to rewrite this test:
+# -parse_reply-test.exe
+ -parse_time-test.exe
+ -snprintf-test.exe
+ -strpftime-test.exe
+ cd $(SRCDIR)
+
+test:: test-binaries test-run
+
diff --git a/third_party/heimdal/lib/roken/base32-test.c b/third_party/heimdal/lib/roken/base32-test.c
new file mode 100644
index 0000000..e30c193
--- /dev/null
+++ b/third_party/heimdal/lib/roken/base32-test.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 1999 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+#include <base32.h>
+
+int
+main(int argc, char **argv)
+{
+ int numerr = 0;
+ int numtest = 1;
+ struct test {
+ int preserve_order;
+ void *data;
+ size_t len;
+ const char *result;
+ } *t, tests[] = {
+ { 0, "", 0 , "" },
+ { 0, "f", 1, "MY======" },
+ { 0, "fo", 2, "MZXQ====" },
+ { 0, "foo", 3, "MZXW6===" },
+ { 0, "foob", 4, "MZXW6YQ=" },
+ { 0, "fooba", 5, "MZXW6YTB" },
+ { 0, "foobar", 6, "MZXW6YTBOI======" },
+ { 1, "", 0 , "" },
+ { 1, "f", 1, "CO======" },
+ { 1, "fo", 2, "CPNG====" },
+ { 1, "foo", 3, "CPNMU===" },
+ { 1, "foob", 4, "CPNMUOG=" },
+ { 1, "fooba", 5, "CPNMUOJ1" },
+ { 1, "foobar", 6, "CPNMUOJ1E8======" },
+ { 0, NULL, 0, NULL }
+ };
+ for(t = tests; t->data; t++) {
+ char *str;
+ int len;
+
+ (void) rk_base32_encode(t->data, t->len, &str, t->preserve_order);
+ if (strcmp(str, t->result) != 0) {
+ fprintf(stderr, "failed test %d: %s != %s\n", numtest,
+ str, t->result);
+ numerr++;
+ }
+ free(str);
+ str = strdup(t->result);
+ len = rk_base32_decode(t->result, str, t->preserve_order);
+ if (len != t->len) {
+ fprintf(stderr, "failed test %d: len %lu != %lu\n", numtest,
+ (unsigned long)len, (unsigned long)t->len);
+ numerr++;
+ } else if(memcmp(str, t->data, t->len) != 0) {
+ fprintf(stderr, "failed test %d: data\n", numtest);
+ numerr++;
+ }
+ free(str);
+ numtest++;
+ }
+
+ {
+ char str[32];
+
+ if (rk_base32_decode("M=M=", str, 1) != -1) {
+ fprintf(stderr, "failed test %d: successful decode of `M=M='\n",
+ numtest++);
+ numerr++;
+ }
+ if (rk_base32_decode("MQ===", str, 1) != -1) {
+ fprintf(stderr, "failed test %d: successful decode of `MQ==='\n",
+ numtest++);
+ numerr++;
+ }
+ }
+ return numerr;
+}
diff --git a/third_party/heimdal/lib/roken/base32.c b/third_party/heimdal/lib/roken/base32.c
new file mode 100644
index 0000000..9eb999a
--- /dev/null
+++ b/third_party/heimdal/lib/roken/base32.c
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 2020 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#ifdef TEST
+#include <stdio.h>
+#include <getarg.h>
+#include <err.h>
+#endif
+#include "base32.h"
+#include "roken.h"
+
+static const unsigned char base32_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
+static const unsigned char base32op_chars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_base32_encode(const void *data, int size, char **str, enum rk_base32_flags flags)
+{
+ const unsigned char *chars =
+ (flags & RK_BASE32_FLAG_PRESERVE_ORDER) ? base32op_chars :
+ base32_chars;
+ uint64_t c;
+ char *s, *p;
+ int i;
+ const unsigned char *q;
+
+ if (size > INT_MAX/8 || size < 0) {
+ *str = NULL;
+ errno = ERANGE;
+ return -1;
+ }
+
+ p = s = malloc(((size + 5 - 1) / 5) * 8 + 1);
+ if (p == NULL) {
+ *str = NULL;
+ return -1;
+ }
+ q = (const unsigned char *) data;
+
+ for (i = 0; i < size;) {
+ /* 5 bytes of input will give us 8 output bytes' worth of bits */
+ c = q[i++];
+ c <<= 8;
+ if (i < size)
+ c += q[i];
+ i++;
+ c <<= 8;
+ if (i < size)
+ c += q[i];
+ i++;
+ c <<= 8;
+ if (i < size)
+ c += q[i];
+ i++;
+ c <<= 8;
+ if (i < size)
+ c += q[i];
+ i++;
+ p[0] = chars[(c & 0x000000f800000000ULL) >> 35];
+ p[1] = chars[(c & 0x00000007c0000000ULL) >> 30];
+ p[2] = chars[(c & 0x000000003e000000ULL) >> 25];
+ p[3] = chars[(c & 0x0000000001f00000ULL) >> 20];
+ p[4] = chars[(c & 0x00000000000f8000ULL) >> 15];
+ p[5] = chars[(c & 0x0000000000007c00ULL) >> 10];
+ p[6] = chars[(c & 0x00000000000003e0ULL) >> 5];
+ p[7] = chars[(c & 0x000000000000001fULL) >> 0];
+ switch (i - size) {
+ case 4: p[2] = p[3] = '='; HEIM_FALLTHROUGH;
+ case 3: p[4] = '='; HEIM_FALLTHROUGH;
+ case 2: p[5] = p[6] = '='; HEIM_FALLTHROUGH;
+ case 1: p[7] = '='; HEIM_FALLTHROUGH;
+ default: break;
+ }
+ p += 8;
+ }
+ *p = 0;
+ *str = s;
+ return (int) strlen(s);
+}
+
+#define DECODE_ERROR ((uint64_t)-1)
+
+static int
+pos(char c, int preserve_order)
+{
+ /* EBCDIC need not apply */
+ if (preserve_order) {
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'A' && c <= 'V')
+ return c - 'A' + ('9' - '0') + 1;
+ } else {
+ if (c >= 'A' && c <= 'Z')
+ return c - 'A';
+ if (c >= '2' && c <= '7')
+ return c - '2' + ('Z' - 'A') + 1;
+ }
+ return -1;
+}
+
+static uint64_t
+token_decode(const char *token, enum rk_base32_flags flags)
+{
+ uint64_t marker = 0;
+ uint64_t val = 0;
+ int preserve_order = !!(flags & RK_BASE32_FLAG_PRESERVE_ORDER);
+ int i, c;
+
+ for (i = 0; i < 8 && token[i] != '\0'; i++) {
+ val <<= 5;
+ if (token[i] == '=')
+ marker++;
+ else if (marker)
+ return DECODE_ERROR;
+ else if ((c = pos(token[i], preserve_order)) == -1 &&
+ (flags & RK_BASE32_FLAG_STOP_ON_GARBAGE))
+ break;
+ else if (c == -1)
+ return DECODE_ERROR;
+ else
+ val |= c;
+ }
+ if (i < 8 || marker > 6)
+ return DECODE_ERROR;
+ return (marker << 40) | val;
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_base32_decode(const char *str, void *data, enum rk_base32_flags flags)
+{
+ const char *p;
+ unsigned char *q;
+ int preserve_order = !!(flags & RK_BASE32_FLAG_PRESERVE_ORDER);
+
+ q = data;
+ for (p = str; *p && (*p == '=' || pos(*p, preserve_order) != -1); p += 8) {
+ uint64_t val = token_decode(p, flags);
+ uint64_t marker = (val >> 40) & 0xffULL;
+
+ if (val == DECODE_ERROR) {
+ errno = EINVAL;
+ return -1;
+ }
+ *q++ = (val >> 32) & 0xffULL;
+ if (marker < 6)
+ *q++ = (val >> 24) & 0xffULL;
+ if (marker < 4)
+ *q++ = (val >> 16) & 0xffULL;
+ if (marker < 3)
+ *q++ = (val >> 8) & 0xffULL;
+ if (marker < 1)
+ *q++ = val & 0xffULL;
+ if (marker && !(flags & RK_BASE32_FLAG_INTERIOR_PADDING_OK))
+ break;
+ }
+ if (q - (unsigned char *) data > INT_MAX) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ return q - (unsigned char *) data;
+}
+
+#ifdef TEST
+static int interior_padding_ok;
+static int preserve_order_flag;
+static int stop_on_garbage;
+static int decode_flag;
+static int help_flag;
+
+/*
+ * The short options are compatible with a subset of the FreeBSD contrib
+ * vis(1). Heimdal additions have long option names only.
+ */
+static struct getargs args[] = {
+ { "preserve-order", 'P', arg_flag, &preserve_order_flag,
+ "Use order-preserving alphabet", NULL },
+ { "interior-padding-ok", 'O', arg_flag, &interior_padding_ok,
+ "Decode concatenated padded base32 strings as one", NULL },
+ { "stop-on-garbage", 'G', arg_flag, &stop_on_garbage,
+ "Do not error on garbage", NULL },
+ { "decode", 'd', arg_flag, &decode_flag, "Decode", NULL },
+ { "help", 'h', arg_flag, &help_flag, "Print help message", NULL },
+};
+static size_t num_args = sizeof(args)/sizeof(args[0]);
+
+int
+main(int argc, char **argv)
+{
+ enum rk_base32_flags flags = 0;
+ unsigned char *buf = NULL;
+ size_t buflen = 0;
+ size_t bufsz = 0;
+ int goptind = 0;
+ int ret;
+
+ setprogname("rkbase32");
+ if (getarg(args, num_args, argc, argv, &goptind) || help_flag) {
+ arg_printusage(args, num_args, NULL, "FILE | -");
+ return help_flag ? 0 : 1;
+ }
+
+ argc -= goptind;
+ argv += goptind;
+
+ flags |= preserve_order_flag ? RK_BASE32_FLAG_PRESERVE_ORDER : 0;
+ flags |= interior_padding_ok ? RK_BASE32_FLAG_INTERIOR_PADDING_OK : 0;
+ flags |= stop_on_garbage ? RK_BASE32_FLAG_STOP_ON_GARBAGE : 0;
+
+ if (help_flag)
+ return arg_printusage(args, num_args, NULL, "FILE | -- -"), 0;
+ if (argc != 1)
+ return arg_printusage(args, num_args, NULL, "FILE | -- -"), 1;
+
+ if (strcmp(argv[0], "-") == 0) {
+ unsigned char *tmp;
+ unsigned char d[4096];
+ size_t bytes;
+
+ while (!feof(stdin) && !ferror(stdin)) {
+ bytes = fread(d, 1, sizeof(d), stdin);
+ if (bytes == 0)
+ continue;
+ if (buflen + bytes > bufsz) {
+ if ((tmp = realloc(buf, bufsz + (bufsz >> 2) + sizeof(d))) == NULL)
+ err(1, "Could not read stdin");
+ buf = tmp;
+ bufsz = bufsz + (bufsz >> 2) + sizeof(d);
+ }
+ memcpy(buf + buflen, d, bytes);
+ buflen += bytes;
+ }
+ if (ferror(stdin))
+ err(1, "Could not read stdin");
+ } else {
+ void *d;
+
+ if ((errno = rk_undumpdata(argv[0], &d, &bufsz)))
+ err(1, "Could not read %s", argv[0]);
+ buflen = bufsz;
+ buf = d;
+ }
+
+ if (decode_flag) {
+ unsigned char *d;
+
+ if (buflen == bufsz) {
+ unsigned char *tmp;
+
+ if ((tmp = realloc(buf, bufsz + 1)) == NULL)
+ err(1, "Could not decode data");
+ buf = tmp;
+ bufsz++;
+ }
+ buf[buflen] = '\0';
+
+ if ((d = malloc(buflen * 5 / 8 + 4)) == NULL)
+ err(1, "Could not decode data");
+
+ if ((ret = rk_base32_decode((const char *)buf, d, flags)) < 0)
+ err(1, "Could not decode data");
+ if (fwrite(d, ret, 1, stdout) != 1)
+ err(1, "Could not write decoded data");
+ free(d);
+ } else if (buf) { /* buf can be NULL if we read from an empty file */
+ char *e;
+
+ if ((ret = rk_base32_encode(buf, buflen, &e, flags)) < 0)
+ err(1, "Could not encode data");
+ if (fwrite(e, ret, 1, stdout) != 1)
+ err(1, "Could not write decoded data");
+ free(e);
+ if (fwrite("\n", 1, 1, stdout) != 1)
+ err(1, "Could not write decoded data");
+ }
+ free(buf);
+ return 0;
+}
+#endif
diff --git a/third_party/heimdal/lib/roken/base32.h b/third_party/heimdal/lib/roken/base32.h
new file mode 100644
index 0000000..1dc0dd0
--- /dev/null
+++ b/third_party/heimdal/lib/roken/base32.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
+ */
+
+/* $Id$ */
+
+#ifndef _BASE32_H_
+#define _BASE32_H_
+
+#ifndef ROKEN_LIB_FUNCTION
+#ifdef _WIN32
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL __cdecl
+#else
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL
+#endif
+#endif
+
+enum rk_base32_flags {
+ RK_BASE32_FLAG_PRESERVE_ORDER = 1,
+ RK_BASE32_FLAG_STOP_ON_GARBAGE = 2,
+ RK_BASE32_FLAG_INTERIOR_PADDING_OK = 4,
+};
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_base32_encode(const void *, int, char **, enum rk_base32_flags);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_base32_decode(const char *, void *, enum rk_base32_flags);
+
+#endif
diff --git a/third_party/heimdal/lib/roken/base64-test.c b/third_party/heimdal/lib/roken/base64-test.c
new file mode 100644
index 0000000..8fb3f52
--- /dev/null
+++ b/third_party/heimdal/lib/roken/base64-test.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 1999 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+#include <base64.h>
+
+int
+main(int argc, char **argv)
+{
+ int numerr = 0;
+ int numtest = 1;
+ struct test {
+ void *data;
+ size_t len;
+ const char *result;
+ } *t, tests[] = {
+ { "", 0 , "" },
+ { "1", 1, "MQ==" },
+ { "22", 2, "MjI=" },
+ { "333", 3, "MzMz" },
+ { "4444", 4, "NDQ0NA==" },
+ { "55555", 5, "NTU1NTU=" },
+ { "abc:def", 7, "YWJjOmRlZg==" },
+ { NULL, 0, NULL }
+ };
+ for(t = tests; t->data; t++) {
+ char *str;
+ int len;
+
+ (void) rk_base64_encode(t->data, t->len, &str);
+ if(strcmp(str, t->result) != 0) {
+ fprintf(stderr, "failed test %d: %s != %s\n", numtest,
+ str, t->result);
+ numerr++;
+ }
+ free(str);
+ str = strdup(t->result);
+ len = rk_base64_decode(t->result, str);
+ if(len != t->len) {
+ fprintf(stderr, "failed test %d: len %lu != %lu\n", numtest,
+ (unsigned long)len, (unsigned long)t->len);
+ numerr++;
+ } else if(memcmp(str, t->data, t->len) != 0) {
+ fprintf(stderr, "failed test %d: data\n", numtest);
+ numerr++;
+ }
+ free(str);
+ numtest++;
+ }
+
+ {
+ char str[32];
+ if(rk_base64_decode("M=M=", str) != -1) {
+ fprintf(stderr, "failed test %d: successful decode of `M=M='\n",
+ numtest++);
+ numerr++;
+ }
+ if(rk_base64_decode("MQ===", str) != -1) {
+ fprintf(stderr, "failed test %d: successful decode of `MQ==='\n",
+ numtest++);
+ numerr++;
+ }
+ }
+ return numerr;
+}
diff --git a/third_party/heimdal/lib/roken/base64.c b/third_party/heimdal/lib/roken/base64.c
new file mode 100644
index 0000000..1391c82
--- /dev/null
+++ b/third_party/heimdal/lib/roken/base64.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 1995-2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#ifdef TEST
+#include <stdio.h>
+#include <getarg.h>
+#include <err.h>
+#endif
+#include "base64.h"
+#include "roken.h"
+
+#define base64_chars "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
+
+static int
+pos(char c)
+{
+#if 'A' == '\301'
+ const char *p;
+ for (p = base64_chars; *p; p++)
+ if (*p == c)
+ return p - base64_chars;
+ return -1;
+#else
+ if (c >= 'A' && c <= 'Z')
+ return c - 'A';
+ if (c >= 'a' && c <= 'z')
+ return ('Z' + 1 - 'A') + c - 'a';
+ if (c >= '0' && c <= '9')
+ return ('Z' + 1 - 'A') +
+ ('z' + 1 - 'a') + c - '0';
+ if (c == '+')
+ return 62;
+ if (c == '/')
+ return 63;
+ return -1;
+#endif
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_base64_encode(const void *data, int size, char **str)
+{
+ char *s, *p;
+ int i;
+ int c;
+ const unsigned char *q;
+
+ if (size > INT_MAX/4 || size < 0) {
+ *str = NULL;
+ errno = ERANGE;
+ return -1;
+ }
+
+ p = s = (char *) malloc(size * 4 / 3 + 4);
+ if (p == NULL) {
+ *str = NULL;
+ return -1;
+ }
+ q = (const unsigned char *) data;
+
+ for (i = 0; i < size;) {
+ c = q[i++];
+ c *= 256;
+ if (i < size)
+ c += q[i];
+ i++;
+ c *= 256;
+ if (i < size)
+ c += q[i];
+ i++;
+ p[0] = base64_chars[(c & 0x00fc0000) >> 18];
+ p[1] = base64_chars[(c & 0x0003f000) >> 12];
+ p[2] = base64_chars[(c & 0x00000fc0) >> 6];
+ p[3] = base64_chars[(c & 0x0000003f) >> 0];
+ if (i > size)
+ p[3] = '=';
+ if (i > size + 1)
+ p[2] = '=';
+ p += 4;
+ }
+ *p = 0;
+ *str = s;
+ return (int) strlen(s);
+}
+
+#define DECODE_ERROR 0xffffffff
+
+static unsigned int
+token_decode(const char *token)
+{
+ int i;
+ unsigned int val = 0;
+ int marker = 0;
+ for (i = 0; i < 4 && token[i] != '\0'; i++) {
+ val *= 64;
+ if (token[i] == '=')
+ marker++;
+ else if (marker > 0)
+ return DECODE_ERROR;
+ else
+ val += pos(token[i]);
+ }
+ if (i < 4 || marker > 2)
+ return DECODE_ERROR;
+ return (marker << 24) | val;
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_base64_decode(const char *str, void *data)
+{
+ const char *p;
+ unsigned char *q;
+
+ q = data;
+ for (p = str; *p && (*p == '=' || pos(*p) != -1); p += 4) {
+ unsigned int val = token_decode(p);
+ unsigned int marker = (val >> 24) & 0xff;
+ if (val == DECODE_ERROR) {
+ errno = EINVAL;
+ return -1;
+ }
+ *q++ = (val >> 16) & 0xff;
+ if (marker < 2)
+ *q++ = (val >> 8) & 0xff;
+ if (marker < 1)
+ *q++ = val & 0xff;
+ }
+ if (q - (unsigned char *) data > INT_MAX) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ return q - (unsigned char *) data;
+}
+
+#ifdef TEST
+static int decode_flag;
+static int help_flag;
+
+/*
+ * The short options are compatible with a subset of the FreeBSD contrib
+ * vis(1). Heimdal additions have long option names only.
+ */
+static struct getargs args[] = {
+ { "decode", 'd', arg_flag, &decode_flag, "Decode", NULL },
+ { "help", 'h', arg_flag, &help_flag, "Print help message", NULL },
+};
+static size_t num_args = sizeof(args)/sizeof(args[0]);
+
+int
+main(int argc, char **argv)
+{
+ unsigned char *buf = NULL;
+ size_t buflen = 0;
+ size_t bufsz = 0;
+ int goptind = 0;
+ int ret;
+
+ setprogname("rkbase64");
+ if (getarg(args, num_args, argc, argv, &goptind) || help_flag) {
+ arg_printusage(args, num_args, NULL, "FILE | -");
+ return help_flag ? 0 : 1;
+ }
+
+ argc -= goptind;
+ argv += goptind;
+
+ if (help_flag)
+ return arg_printusage(args, num_args, NULL, "FILE | -- -"), 0;
+ if (argc != 1)
+ return arg_printusage(args, num_args, NULL, "FILE | -- -"), 1;
+
+ if (strcmp(argv[0], "-") == 0) {
+ unsigned char *tmp;
+ unsigned char d[4096];
+ size_t bytes;
+
+ while (!feof(stdin) && !ferror(stdin)) {
+ bytes = fread(d, 1, sizeof(d), stdin);
+ if (bytes == 0)
+ continue;
+ if (buflen + bytes > bufsz) {
+ if ((tmp = realloc(buf, bufsz + (bufsz >> 2) + sizeof(d))) == NULL)
+ err(1, "Could not read stdin");
+ buf = tmp;
+ bufsz = bufsz + (bufsz >> 2) + sizeof(d);
+ }
+ memcpy(buf + buflen, d, bytes);
+ buflen += bytes;
+ }
+ if (ferror(stdin))
+ err(1, "Could not read stdin");
+ } else {
+ void *d;
+ if ((errno = rk_undumpdata(argv[0], &d, &bufsz)))
+ err(1, "Could not read %s", argv[0]);
+ buflen = bufsz;
+ buf = d;
+ }
+
+ if (decode_flag) {
+ unsigned char *d;
+
+ if (buflen == bufsz) {
+ unsigned char *tmp;
+
+ if ((tmp = realloc(buf, bufsz + 1)) == NULL)
+ err(1, "Could not decode data");
+ buf = tmp;
+ bufsz++;
+ }
+ buf[buflen] = '\0';
+
+ if ((d = malloc(buflen * 3 / 4 + 4)) == NULL)
+ err(1, "Could not decode data");
+
+ if ((ret = rk_base64_decode((const char *)buf, d)) < 0)
+ err(1, "Could not decode data");
+ if (fwrite(d, ret, 1, stdout) != 1)
+ err(1, "Could not write decoded data");
+ free(d);
+ } else if (buf) { /* buf can be NULL if we read from an empty file */
+ char *e;
+
+ if ((ret = rk_base64_encode(buf, buflen, &e)) < 0)
+ err(1, "Could not encode data");
+ if (fwrite(e, ret, 1, stdout) != 1)
+ err(1, "Could not write decoded data");
+ free(e);
+ if (fwrite("\n", 1, 1, stdout) != 1)
+ err(1, "Could not write decoded data");
+ }
+ free(buf);
+ return 0;
+}
+#endif
diff --git a/third_party/heimdal/lib/roken/base64.h b/third_party/heimdal/lib/roken/base64.h
new file mode 100644
index 0000000..734a6b5
--- /dev/null
+++ b/third_party/heimdal/lib/roken/base64.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
+ */
+
+/* $Id$ */
+
+#ifndef _BASE64_H_
+#define _BASE64_H_
+
+#ifndef ROKEN_LIB_FUNCTION
+#ifdef _WIN32
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL __cdecl
+#else
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL
+#endif
+#endif
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_base64_encode(const void *, int, char **);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_base64_decode(const char *, void *);
+
+#endif
diff --git a/third_party/heimdal/lib/roken/bswap.c b/third_party/heimdal/lib/roken/bswap.c
new file mode 100644
index 0000000..b0c4248
--- /dev/null
+++ b/third_party/heimdal/lib/roken/bswap.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+#include "roken.h"
+
+#ifndef HAVE_BSWAP64
+
+ROKEN_LIB_FUNCTION uint64_t ROKEN_LIB_CALL
+bswap64 (uint64_t val)
+{
+ return
+ (val & 0xffULL) << 56 |
+ (val & 0xff00ULL) << 40 |
+ (val & 0xff0000ULL) << 24 |
+ (val & 0xff000000ULL) << 8 |
+ (val & 0xff00000000ULL) >> 8 |
+ (val & 0xff0000000000ULL) >> 24 |
+ (val & 0xff000000000000ULL) >> 40 |
+ (val & 0xff00000000000000ULL) >> 56 ;
+}
+#endif
+
+#ifndef HAVE_BSWAP32
+
+ROKEN_LIB_FUNCTION unsigned int ROKEN_LIB_CALL
+bswap32 (unsigned int val)
+{
+ return (val & 0xff) << 24 |
+ (val & 0xff00) << 8 |
+ (val & 0xff0000) >> 8 |
+ (val & 0xff000000) >> 24;
+}
+#endif
+
+#ifndef HAVE_BSWAP16
+
+ROKEN_LIB_FUNCTION unsigned short ROKEN_LIB_CALL
+bswap16 (unsigned short val)
+{
+ return (val & 0xff) << 8 |
+ (val & 0xff00) >> 8;
+}
+#endif
diff --git a/third_party/heimdal/lib/roken/chown.c b/third_party/heimdal/lib/roken/chown.c
new file mode 100644
index 0000000..90a82d9
--- /dev/null
+++ b/third_party/heimdal/lib/roken/chown.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+chown(const char *path, uid_t owner, gid_t group)
+{
+ return 0;
+}
diff --git a/third_party/heimdal/lib/roken/cloexec.c b/third_party/heimdal/lib/roken/cloexec.c
new file mode 100644
index 0000000..59ffa50
--- /dev/null
+++ b/third_party/heimdal/lib/roken/cloexec.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2008 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+void ROKEN_LIB_FUNCTION
+rk_cloexec(int fd)
+{
+#ifdef HAVE_FCNTL
+ int ret;
+
+ ret = fcntl(fd, F_GETFD);
+ if (ret == -1)
+ return;
+ if (fcntl(fd, F_SETFD, ret | FD_CLOEXEC) == -1)
+ return;
+#endif
+}
+
+void ROKEN_LIB_FUNCTION
+rk_cloexec_file(FILE *f)
+{
+#ifdef HAVE_FCNTL
+ rk_cloexec(fileno(f));
+#endif
+}
+
+void ROKEN_LIB_FUNCTION
+rk_cloexec_dir(DIR * d)
+{
+#ifndef _WIN32
+ rk_cloexec(dirfd(d));
+#endif
+}
+
+void ROKEN_LIB_FUNCTION
+rk_cloexec_socket(rk_socket_t s)
+{
+#ifndef _WIN32
+ rk_cloexec((int)s);
+#endif
+}
+
diff --git a/third_party/heimdal/lib/roken/closefrom.c b/third_party/heimdal/lib/roken/closefrom.c
new file mode 100644
index 0000000..1a950f7
--- /dev/null
+++ b/third_party/heimdal/lib/roken/closefrom.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "roken.h"
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_closefrom(int fd)
+{
+ int num = getdtablesize();
+
+ if (num < 0)
+ num = 1024; /* XXX */
+
+ for (; fd <= num; fd++)
+ close(fd);
+
+ return 0;
+}
diff --git a/third_party/heimdal/lib/roken/clz.c b/third_party/heimdal/lib/roken/clz.c
new file mode 100644
index 0000000..1a36234
--- /dev/null
+++ b/third_party/heimdal/lib/roken/clz.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <config.h>
+#include <assert.h>
+
+#include "roken.h"
+
+#if defined(_MSC_VER)
+#include <intrin.h>
+#if defined(_WIN64)
+#pragma intrinsic(_BitScanReverse64)
+#else
+#pragma intrinsic(_BitScanReverse)
+#endif
+#endif
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_clzll(uint64_t x)
+{
+#if defined(_MSC_VER)
+ unsigned long r = 0;
+#elif !(defined(__GNUC__) && __GNUC__ >= 4)
+ int r = 0;
+#endif
+
+ assert(x != 0);
+
+#if defined(_MSC_VER)
+# if defined(_WIN64)
+ _BitScanReverse64(&r, x);
+# else
+ if (_BitScanReverse(&r, (uint32_t)(x >> 32)))
+ return 63 - (r + 32);
+ _BitScanReverse(&r, (uint32_t)(x & 0xFFFFFFFF));
+# endif
+
+ return 63 - r;
+#elif (defined(__GNUC__) && __GNUC__ >= 4)
+ return __builtin_clzll(x);
+#else
+ while (!(x & ((uint64_t)1 << 63))) {
+ x <<= 1;
+ ++r;
+ }
+
+ return r;
+#endif /* _MSC_VER || __GNUC__ */
+}
diff --git a/third_party/heimdal/lib/roken/concat.c b/third_party/heimdal/lib/roken/concat.c
new file mode 100644
index 0000000..0b4ac46
--- /dev/null
+++ b/third_party/heimdal/lib/roken/concat.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+roken_concat (char *s, size_t len, ...)
+{
+ int ret;
+ va_list args;
+
+ va_start(args, len);
+ ret = roken_vconcat (s, len, args);
+ va_end(args);
+ return ret;
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+roken_vconcat (char *s, size_t len, va_list args)
+{
+ const char *a;
+
+ while ((a = va_arg(args, const char*))) {
+ size_t n = strlen (a);
+
+ if (n >= len)
+ return -1;
+ memcpy (s, a, n);
+ s += n;
+ len -= n;
+ }
+ *s = '\0';
+ return 0;
+}
+
+ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL
+roken_vmconcat (char **s, size_t max_len, va_list args)
+{
+ const char *a;
+ char *p, *q;
+ size_t len = 0;
+ *s = NULL;
+ p = malloc(1);
+ if(p == NULL)
+ return 0;
+ len = 1;
+ while ((a = va_arg(args, const char*))) {
+ size_t n = strlen (a);
+
+ if(max_len && len + n > max_len){
+ free(p);
+ return 0;
+ }
+ q = realloc(p, len + n);
+ if(q == NULL){
+ free(p);
+ return 0;
+ }
+ p = q;
+ memcpy (p + len - 1, a, n);
+ len += n;
+ }
+ p[len - 1] = '\0';
+ *s = p;
+ return len;
+}
+
+ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL
+roken_mconcat (char **s, size_t max_len, ...)
+{
+ size_t ret;
+ va_list args;
+
+ va_start(args, max_len);
+ ret = roken_vmconcat (s, max_len, args);
+ va_end(args);
+ return ret;
+}
diff --git a/third_party/heimdal/lib/roken/copyhostent.c b/third_party/heimdal/lib/roken/copyhostent.c
new file mode 100644
index 0000000..9b9dba2
--- /dev/null
+++ b/third_party/heimdal/lib/roken/copyhostent.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+/*
+ * return a malloced copy of `h'
+ */
+
+ROKEN_LIB_FUNCTION struct hostent * ROKEN_LIB_CALL
+rk_copyhostent(const struct hostent *h)
+{
+ struct hostent *res;
+ char **p;
+ int i, n;
+
+ res = malloc (sizeof (*res));
+ if (res == NULL)
+ return NULL;
+ res->h_name = NULL;
+ res->h_aliases = NULL;
+ res->h_addrtype = h->h_addrtype;
+ res->h_length = h->h_length;
+ res->h_addr_list = NULL;
+ res->h_name = strdup (h->h_name);
+ if (res->h_name == NULL) {
+ freehostent (res);
+ return NULL;
+ }
+ for (n = 0, p = h->h_aliases; *p != NULL; ++p)
+ ++n;
+ res->h_aliases = malloc ((n + 1) * sizeof(*res->h_aliases));
+ if (res->h_aliases == NULL) {
+ freehostent (res);
+ return NULL;
+ }
+ for (i = 0; i < n + 1; ++i)
+ res->h_aliases[i] = NULL;
+ for (i = 0; i < n; ++i) {
+ res->h_aliases[i] = strdup (h->h_aliases[i]);
+ if (res->h_aliases[i] == NULL) {
+ freehostent (res);
+ return NULL;
+ }
+ }
+
+ for (n = 0, p = h->h_addr_list; *p != NULL; ++p)
+ ++n;
+ res->h_addr_list = malloc ((n + 1) * sizeof(*res->h_addr_list));
+ if (res->h_addr_list == NULL) {
+ freehostent (res);
+ return NULL;
+ }
+ for (i = 0; i < n + 1; ++i) {
+ res->h_addr_list[i] = NULL;
+ }
+ for (i = 0; i < n; ++i) {
+ res->h_addr_list[i] = malloc (h->h_length);
+ if (res->h_addr_list[i] == NULL) {
+ freehostent (res);
+ return NULL;
+ }
+ memcpy (res->h_addr_list[i], h->h_addr_list[i], h->h_length);
+ }
+ return res;
+}
diff --git a/third_party/heimdal/lib/roken/ct.c b/third_party/heimdal/lib/roken/ct.c
new file mode 100644
index 0000000..79f312d
--- /dev/null
+++ b/third_party/heimdal/lib/roken/ct.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2009 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+#include "roken.h"
+
+/**
+ * Constant time compare to memory regions. The reason for making it
+ * constant time is to make sure that timeing information leak from
+ * where in the function the diffrence is.
+ *
+ * ct_memcmp() can't be used to order memory regions like memcmp(),
+ * for example, use ct_memcmp() with qsort().
+ *
+ * We use volatile to avoid optimizations where the compiler and/or
+ * linker turn this ct_memcmp() into a plain memcmp(). The pointers
+ * themselves are also marked volatile (not just the memory pointed at)
+ * because in some GCC versions there is a bug which can be worked
+ * around by doing this.
+ *
+ * @param p1 memory region 1 to compare
+ * @param p2 memory region 2 to compare
+ * @param len length of memory
+ *
+ * @return 0 when the memory regions are equal, non zero if not
+ *
+ * @ingroup roken
+ */
+
+int
+ct_memcmp(const volatile void * volatile p1,
+ const volatile void * volatile p2,
+ size_t len)
+{
+ /*
+ * There's no need for s1 and s2 to be volatile; only p1 and p2 have
+ * to be in order to work around GCC bugs.
+ *
+ * However, s1 and s2 do have to point to volatile, as we don't know
+ * if the object was originally defined as volatile, and if it was
+ * then we'd get undefined behavior here if s1/s2 were declared to
+ * point to non-volatile memory.
+ */
+ const volatile unsigned char *s1 = p1;
+ const volatile unsigned char *s2 = p2;
+ size_t i;
+ int r = 0;
+
+ for (i = 0; i < len; i++)
+ r |= (s1[i] ^ s2[i]);
+ return !!r;
+}
diff --git a/third_party/heimdal/lib/roken/daemon.c b/third_party/heimdal/lib/roken/daemon.c
new file mode 100644
index 0000000..6128beb
--- /dev/null
+++ b/third_party/heimdal/lib/roken/daemon.c
@@ -0,0 +1,80 @@
+/*-
+ * 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)daemon.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <config.h>
+
+#ifndef HAVE_DAEMON
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "roken.h"
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+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)
+ chdir("/");
+
+ if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
+ dup2(fd, STDIN_FILENO);
+ dup2(fd, STDOUT_FILENO);
+ dup2(fd, STDERR_FILENO);
+ if (fd > 2)
+ (void) close(fd);
+ }
+ return (0);
+}
+
+#endif /* HAVE_DAEMON */
diff --git a/third_party/heimdal/lib/roken/detach.c b/third_party/heimdal/lib/roken/detach.c
new file mode 100644
index 0000000..4a00682
--- /dev/null
+++ b/third_party/heimdal/lib/roken/detach.c
@@ -0,0 +1,226 @@
+/*-
+ * Copyright (c) 2015
+ * Cryptonector LLC. 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. Cryptonector LLC may not 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 <config.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifdef WIN32
+#include <io.h>
+#include <stdlib.h>
+#else
+#include <unistd.h>
+#endif
+#include "roken.h"
+
+#ifdef WIN32
+#define dup2 _dup2
+#endif
+
+static int pipefds[2] = {-1, -1};
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+roken_detach_prep(int argc, char **argv, char *special_arg)
+{
+ ssize_t bytes;
+ size_t i;
+ pid_t child;
+ char **new_argv;
+ char buf[1];
+ char fildes[21];
+ int status;
+
+ pipefds[0] = -1;
+ pipefds[1] = -1;
+
+#ifdef WIN32
+ if (_pipe(pipefds, 4, _O_NOINHERIT | O_BINARY) == -1)
+ err(1, "failed to setup to detach daemon (_pipe failed)");
+#else
+ if (pipe(pipefds) == -1)
+ err(1, "failed to setup to detach daemon (pipe failed)");
+#endif
+
+ new_argv = calloc(argc + 3, sizeof(*new_argv));
+ if (new_argv == NULL)
+ err(1, "Out of memory");
+
+#ifdef WIN32
+ pipefds[1] = _dup(pipefds[1]); /* The new fd will be inherited */
+ if (pipefds[1] == -1)
+ err(1, "Out of memory");
+#else
+ (void) fcntl(pipefds[1], F_SETFD,
+ fcntl(pipefds[1], F_GETFD & ~(O_CLOEXEC)));
+#endif
+
+ if (snprintf(fildes, sizeof(fildes), "%d", pipefds[1]) >= sizeof(fildes))
+ err(1, "failed to setup to detach daemon (fd number %d too large)",
+ pipefds[1]);
+
+ new_argv[0] = argv[0];
+ new_argv[1] = special_arg;
+ new_argv[2] = fildes;
+ for (i = 1; argv[i] != NULL; i++)
+ new_argv[i + 2] = argv[i];
+ new_argv[argc + 2] = NULL;
+
+#ifndef WIN32
+ fflush(stdout);
+ child = fork();
+#else
+ {
+ intptr_t child_handle;
+
+ _flushall();
+ child_handle = spawnvp(_P_NOWAIT, argv[0], new_argv);
+ if (child_handle == -1)
+ child = (pid_t)-1;
+ else
+ child = GetProcessId((HANDLE)child_handle);
+ }
+#endif
+ if (child == (pid_t)-1)
+ err(1, "failed to setup to fork daemon (fork failed)");
+
+#ifndef WIN32
+ if (child == 0) {
+ int fd;
+
+ (void) close(pipefds[0]);
+ pipefds[0] = -1;
+ /*
+ * Keep stdout/stderr for now so output and errors prior to
+ * detach_finish() can be seen by the user.
+ */
+ fd = open(_PATH_DEVNULL, O_RDWR, 0);
+ if (fd == -1)
+ err(1, "failed to open /dev/null");
+ (void) dup2(fd, STDIN_FILENO);
+ if (fd > STDERR_FILENO)
+ (void) close(fd);
+ if (getenv("ROKEN_DETACH_USE_EXEC")) {
+ (void) execvp(argv[0], new_argv);
+ err(1, "failed to self-re-exec");
+ }
+ free(new_argv);
+ return pipefds[1];
+ }
+#endif
+
+ /* Parent */
+ free(new_argv);
+ (void) close(pipefds[1]);
+ pipefds[1] = -1;
+ do {
+ bytes = read(pipefds[0], buf, sizeof(buf));
+ } while (bytes == -1 && errno == EINTR);
+ (void) close(pipefds[0]);
+ pipefds[0] = -1;
+ if (bytes == -1) {
+ /*
+ * No need to wait for the process. We've killed it. If it
+ * doesn't want to exit, we'd have to wait potentially forever,
+ * but we want to indicate failure to the user as soon as
+ * possible. A wait with timeout would end the same way
+ * (attempting to kill the process).
+ */
+ err(1, "failed to setup daemon child (read from child pipe)");
+ }
+ if (bytes == 0) {
+ warnx("daemon child preparation failed, waiting for child");
+ status = wait_for_process(child);
+ if (SE_IS_ERROR(status) || SE_PROCSTATUS(status) != 0)
+ errx(SE_PROCSTATUS(status),
+ "daemon child preparation failed (child exited)");
+ }
+ _exit(0);
+ /* NOTREACHED */
+ return -1;
+}
+
+#ifdef WIN32
+#ifdef dup2
+#undef dup2
+#endif
+#define dup2 _dup2
+#endif
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+roken_detach_finish(const char *dir, int daemon_child_fd)
+{
+ char buf[1] = "";
+ ssize_t bytes;
+ int fd;
+
+ rk_pidfile(NULL);
+ if (pipefds[1] == -1 && daemon_child_fd != -1)
+ pipefds[1] = daemon_child_fd;
+ if (pipefds[0] != -1)
+ (void) close(pipefds[0]);
+ if (pipefds[1] == -1)
+ return;
+
+#ifdef HAVE_SETSID
+ if (setsid() == -1)
+ err(1, "failed to detach from tty");
+#endif
+
+#ifndef WIN32
+ /*
+ * Hopefully we've written any pidfiles by now, if they had to be in
+ * the current directory...
+ *
+ * The daemons do re-open logs and so on, therefore this chdir()
+ * call needs to be optional for testing.
+ */
+ if (dir != NULL && chdir(dir) == -1)
+ err(1, "failed to chdir to /");
+#endif
+
+ do {
+ bytes = write(pipefds[1], buf, sizeof(buf));
+ } while (bytes == -1 && errno == EINTR);
+ if (bytes == -1)
+ err(1, "failed to signal parent while detaching");
+ (void) close(pipefds[1]);
+ if (bytes != sizeof(buf))
+ errx(1, "failed to signal parent while detaching");
+
+ fd = open(_PATH_DEVNULL, O_RDWR, 0);
+ if (fd == -1)
+ err(1, "failed to open /dev/null");
+ /*
+ * Maybe we should check that our output got written, if redirected
+ * to a file. File utils normally do this.
+ */
+ (void) dup2(fd, STDOUT_FILENO);
+ (void) dup2(fd, STDERR_FILENO);
+ if (fd > 2)
+ (void) close(fd);
+}
diff --git a/third_party/heimdal/lib/roken/dirent-test.c b/third_party/heimdal/lib/roken/dirent-test.c
new file mode 100644
index 0000000..2c6b505
--- /dev/null
+++ b/third_party/heimdal/lib/roken/dirent-test.c
@@ -0,0 +1,278 @@
+/***********************************************************************
+ * Copyright (c) 2009, Secure Endpoints Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDER 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 <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <direct.h>
+#include <errno.h>
+#include <io.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <string.h>
+#include "dirent.h"
+
+/* Note that we create a known directory structure in a subdirectory
+ of the current directory to run our tests. */
+
+#define TESTDIR "dirent-test-dir"
+
+const char * dir_entries[] = {
+ "A",
+ "B",
+ "C",
+ "CAA",
+ "CAAA",
+ "CABBBB",
+ "CAABBB.txt",
+ "A filename with spaces"
+};
+
+const char * entries_begin_with_C[] = {
+ "C",
+ "CAA",
+ "CAAA",
+ "CABBBB",
+ "CAABBB.txt"
+};
+
+const char * entries_end_with_A[] = {
+ "A",
+ "CAA",
+ "CAAA"
+};
+
+const int n_dir_entries = sizeof(dir_entries)/sizeof(dir_entries[0]);
+
+int teardown_test(void);
+
+void fail_test(const char * reason, ...)
+{
+ va_list args;
+
+ va_start(args, reason);
+ vfprintf(stderr, reason, args);
+ va_end(args);
+
+ fprintf(stderr, " : errno = %d (%s)\n", errno, strerror(errno));
+ teardown_test();
+ abort();
+}
+
+void fail_test_nf(const char * format, ...)
+{
+ va_list args;
+
+ fprintf(stderr, "FAIL:");
+
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+
+ fprintf(stderr, " : errno = %d (%s)\n", errno, strerror(errno));
+}
+
+int touch(const char * filename)
+{
+ int fd;
+
+ fd = _open(filename, _O_CREAT, _S_IREAD| _S_IWRITE);
+
+ if (fd == -1)
+ return -1;
+
+ return _close(fd);
+}
+
+int setup_test(void)
+{
+ int i;
+
+ fprintf(stderr, "Creating test directory %s ...\n", TESTDIR);
+
+ if (_mkdir(TESTDIR))
+ fail_test("Can't create test directory \"" TESTDIR "\"");
+
+ if (_chdir(TESTDIR))
+ fail_test("Can't change to test directory");
+
+ for (i=0; i < n_dir_entries; i++) {
+ if (touch(dir_entries[i]))
+ fail_test("Can't create test file '%s'", dir_entries[i]);
+ }
+
+ fprintf(stderr, "Done with test setup.\n");
+
+ return 0;
+}
+
+int teardown_test(void)
+{
+ char dirname[_MAX_PATH];
+ size_t len;
+ int i;
+
+ printf ("Begin cleanup...\n");
+
+ if (_getcwd(dirname, sizeof(dirname)/sizeof(char)) != NULL &&
+
+ (len = strlen(dirname)) > sizeof(TESTDIR)/sizeof(char) &&
+
+ strcmp(dirname + len + 1 - sizeof(TESTDIR)/sizeof(char), TESTDIR) == 0) {
+
+ HEIM_FALLTHROUGH;
+
+ } else {
+ /* did we create the directory? */
+
+ if (!_rmdir( TESTDIR )) {
+ fprintf(stderr, "Removed test directory\n");
+ return 0;
+ } else {
+ if (errno == ENOTEMPTY) {
+ if (_chdir(TESTDIR)) {
+ fprintf(stderr, "Can't change to test directory. Aborting cleanup.\n");
+ return -1;
+ } else {
+ HEIM_FALLTHROUGH;
+ }
+ } else {
+ return -1;
+ }
+ }
+ }
+
+ fprintf(stderr, "Cleaning up test directory %s ...\n", TESTDIR);
+
+ for (i=0; i < n_dir_entries; i++) {
+ if (_unlink(dir_entries[i])) {
+ /* if the test setup failed, we expect this to happen for
+ at least some files */
+ }
+ }
+
+ if (_chdir("..")) {
+ fprintf(stderr, "Can't escape test directory. Giving in.\n");
+ return -1;
+ }
+
+ if (_rmdir( TESTDIR )) {
+ fprintf(stderr, "Can't remove test directory.\n");
+ return -1;
+ }
+
+ printf("Cleaned up test directory\n");
+ return 0;
+}
+
+int check_list(const char * filespec, const char ** list, int n, int expect_dot_and_dotdot)
+{
+ DIR * d;
+ struct dirent * e;
+ int n_found = 0;
+ int i;
+ int rv = 0;
+ int retry = 1;
+
+ d = opendir(filespec);
+ if (d == NULL) {
+ fail_test_nf("opendir failed for [%s]", filespec);
+ return -1;
+ }
+
+ printf("Checking filespec [%s]... ", filespec);
+
+ retry:
+ while ((e = readdir(d)) != NULL) {
+ n_found ++;
+
+ if (expect_dot_and_dotdot &&
+ (strcmp(e->d_name, ".") == 0 ||
+ strcmp(e->d_name, "..") == 0))
+ continue;
+
+ for (i=0; i < n; i++) {
+ if (strcmp(list[i], e->d_name) == 0)
+ break;
+ }
+
+ if (i == n) {
+ fail_test_nf("Found unexpected entry [%s]", e->d_name);
+ rv = -1;
+ }
+ }
+
+ if (n_found != n) {
+ fail_test_nf("Unexpected number of entries [%d]. Expected %d", n_found, n);
+ rv = -1;
+ }
+
+ if (retry) {
+ retry = 0;
+ n_found = 0;
+
+ rewinddir(d);
+ goto retry;
+ }
+
+ if (closedir(d)) {
+ fail_test_nf("closedir() failed");
+ }
+
+ printf("done\n");
+
+ return rv;
+}
+
+int run_tests()
+{
+ /* assumes that the test directory has been set up and we have
+ changed into the test directory. */
+
+ check_list("*", dir_entries, n_dir_entries + 2, 1);
+ check_list("*.*", dir_entries, n_dir_entries + 2, 1);
+ check_list("C*", entries_begin_with_C, sizeof(entries_begin_with_C)/sizeof(entries_begin_with_C[0]), 0);
+ check_list("*A", entries_end_with_A, sizeof(entries_end_with_A)/sizeof(entries_end_with_A[0]), 0);
+
+ return 0;
+}
+
+int main(int argc, char ** argv)
+{
+ if (setup_test())
+ return 1;
+
+ run_tests();
+
+ teardown_test();
+
+ return 0;
+}
diff --git a/third_party/heimdal/lib/roken/dirent.c b/third_party/heimdal/lib/roken/dirent.c
new file mode 100644
index 0000000..36f1bc9
--- /dev/null
+++ b/third_party/heimdal/lib/roken/dirent.c
@@ -0,0 +1,235 @@
+/***********************************************************************
+ * Copyright (c) 2009, Secure Endpoints Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDER 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<config.h>
+
+#include <stdlib.h>
+#include <io.h>
+#include <string.h>
+#include <errno.h>
+#include "dirent.h"
+
+#ifndef _WIN32
+#error Only implemented for Win32
+#endif
+
+struct _dirent_dirinfo {
+ int magic;
+ long n_entries;
+ long nc_entries;
+ long cursor;
+ struct dirent **entries;
+};
+#define DIRINFO_MAGIC 0xf8c0639d
+#define IS_DP(p) ((p) && ((DIR *)(p))->magic == DIRINFO_MAGIC)
+
+#define INITIAL_ENTRIES 16
+
+/**
+ * Create a filespec for use with _findfirst() using a path spec
+ *
+ * If the last component of the path spec contains wildcards, we let
+ * it be. If the last component doesn't end with a slash, we add one.
+ */
+static const char *
+filespec_from_dir_path(const char * path, char * buffer, size_t cch_buffer)
+{
+ char *comp, *t;
+ size_t pos;
+ int found_sep = 0;
+
+ if (strcpy_s(buffer, cch_buffer, path) != 0)
+ return NULL;
+
+ comp = strrchr(buffer, '\\');
+ if (comp == NULL)
+ comp = buffer;
+ else
+ found_sep = 1;
+
+ t = strrchr(comp, '/');
+ if (t != NULL) {
+ comp = t;
+ found_sep = 1;
+ }
+
+ if (found_sep)
+ comp++;
+
+ pos = strcspn(comp, "*?");
+ if (comp[pos] != '\0')
+ return buffer;
+
+ /* We don't append a slash if pos == 0 because that changes the
+ * meaning:
+ *
+ * "*.*" is all files in the current directory.
+ * "\*.*" is all files in the root directory of the current drive.
+ */
+ if (pos > 0 && comp[pos - 1] != '\\' &&
+ comp[pos - 1] != '/') {
+ strcat_s(comp, cch_buffer - (comp - buffer), "\\");
+ }
+
+ strcat_s(comp, cch_buffer - (comp - buffer), "*.*");
+
+ return buffer;
+}
+
+ROKEN_LIB_FUNCTION DIR * ROKEN_LIB_CALL
+opendir(const char * path)
+{
+ DIR * dp;
+ struct _finddata_t fd;
+ intptr_t fd_handle;
+ const char *filespec;
+ char path_buffer[1024]="";
+
+ memset(&fd, 0, sizeof(fd));
+
+ filespec = filespec_from_dir_path(path, path_buffer, sizeof(path_buffer)/sizeof(char));
+ if (filespec == NULL)
+ return NULL;
+
+ fd_handle = _findfirst(filespec, &fd);
+
+ if (fd_handle == -1)
+ return NULL;
+
+ dp = malloc(sizeof(*dp));
+ if (dp == NULL)
+ goto done;
+
+ memset(dp, 0, sizeof(*dp));
+ dp->magic = DIRINFO_MAGIC;
+ dp->cursor = 0;
+ dp->n_entries = 0;
+ dp->nc_entries = INITIAL_ENTRIES;
+ dp->entries = calloc(dp->nc_entries, sizeof(dp->entries[0]));
+
+ if (dp->entries == NULL) {
+ closedir(dp);
+ dp = NULL;
+ goto done;
+ }
+
+ do {
+ size_t len = strlen(fd.name);
+ struct dirent * e;
+
+ if (dp->n_entries == dp->nc_entries) {
+ struct dirent ** ne;
+
+ dp->nc_entries *= 2;
+ ne = realloc(dp->entries, sizeof(dp->entries[0]) * dp->nc_entries);
+
+ if (ne == NULL) {
+ closedir(dp);
+ dp = NULL;
+ goto done;
+ }
+
+ dp->entries = ne;
+ }
+
+ e = malloc(sizeof(*e) + len * sizeof(char));
+ if (e == NULL) {
+ closedir(dp);
+ dp = NULL;
+ goto done;
+ }
+
+ e->d_ino = 0; /* no inodes :( */
+ strcpy_s(e->d_name, len + 1, fd.name);
+
+ dp->entries[dp->n_entries++] = e;
+
+ } while (_findnext(fd_handle, &fd) == 0);
+
+ done:
+ if (fd_handle != -1)
+ _findclose(fd_handle);
+
+ return dp;
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+closedir(DIR * dp)
+{
+ if (!IS_DP(dp))
+ return EINVAL;
+
+ if (dp->entries) {
+ long i;
+
+ for (i=0; i < dp->n_entries; i++) {
+ free(dp->entries[i]);
+ }
+
+ free(dp->entries);
+ }
+
+ free(dp);
+
+ return 0;
+}
+
+ROKEN_LIB_FUNCTION struct dirent * ROKEN_LIB_CALL
+readdir(DIR * dp)
+{
+ if (!IS_DP(dp) ||
+ dp->cursor < 0 ||
+ dp->cursor >= dp->n_entries)
+
+ return NULL;
+
+ return dp->entries[dp->cursor++];
+}
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rewinddir(DIR * dp)
+{
+ if (IS_DP(dp))
+ dp->cursor = 0;
+}
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+seekdir(DIR * dp, long offset)
+{
+ if (IS_DP(dp) && offset >= 0 && offset < dp->n_entries)
+ dp->cursor = offset;
+}
+
+ROKEN_LIB_FUNCTION long ROKEN_LIB_CALL
+telldir(DIR * dp)
+{
+ return dp->cursor;
+}
diff --git a/third_party/heimdal/lib/roken/dirent.hin b/third_party/heimdal/lib/roken/dirent.hin
new file mode 100644
index 0000000..c9a86c6
--- /dev/null
+++ b/third_party/heimdal/lib/roken/dirent.hin
@@ -0,0 +1,66 @@
+/***********************************************************************
+ * Copyright (c) 2009, Secure Endpoints Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDER 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.
+ *
+ **********************************************************************/
+
+#ifndef __DIRENT_H__
+#define __DIRENT_H__
+
+#ifndef ROKEN_LIB_FUNCTION
+#ifdef _WIN32
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL __cdecl
+#else
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL
+#endif
+#endif
+
+#include<sys/types.h>
+
+struct dirent {
+ ino_t d_ino;
+ char d_name[1];
+};
+
+typedef struct _dirent_dirinfo DIR;
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL closedir(DIR *);
+
+ROKEN_LIB_FUNCTION DIR * ROKEN_LIB_CALL opendir(const char *);
+
+ROKEN_LIB_FUNCTION struct dirent * ROKEN_LIB_CALL readdir(DIR *);
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL rewinddir(DIR *);
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL seekdir(DIR *, long);
+
+ROKEN_LIB_FUNCTION long ROKEN_LIB_CALL telldir(DIR *);
+
+#endif
diff --git a/third_party/heimdal/lib/roken/dlfcn.hin b/third_party/heimdal/lib/roken/dlfcn.hin
new file mode 100644
index 0000000..4f2341b
--- /dev/null
+++ b/third_party/heimdal/lib/roken/dlfcn.hin
@@ -0,0 +1,109 @@
+/***********************************************************************
+ * Copyright (c) 2009, Secure Endpoints Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDER 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.
+ *
+ **********************************************************************/
+
+#ifndef __dlfcn_h__
+#define __dlfcn_h__
+
+#include <windows.h>
+
+#ifndef ROKEN_LIB_FUNCTION
+#ifdef _WIN32
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL __cdecl
+#else
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL
+#endif
+#endif
+
+#ifdef _WIN32
+typedef int (__stdcall *DLSYM_RET_TYPE)();
+#else
+#define DLSYM_RET_TYPE void *
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Relocations are performed when the object is loaded. */
+#define RTLD_NOW 0
+
+/* Relocations are performed at an implementation-defined time.
+ * Windows API does not support lazy symbol resolving (when first reference
+ * to a given symbol occurs). So RTLD_LAZY implementation is same as RTLD_NOW.
+ */
+#define RTLD_LAZY RTLD_NOW
+
+/* All symbols are available for relocation processing of other modules. */
+#define RTLD_GLOBAL (1 << 1)
+
+/* All symbols are not made available for relocation processing by other modules. */
+#define RTLD_LOCAL (1 << 2)
+
+/* These two were added in The Open Group Base Specifications Issue 6.
+ * Note: All other RTLD_* flags in any dlfcn.h are not standard compliant.
+ */
+
+/* The symbol lookup happens in the normal global scope. */
+#define RTLD_DEFAULT ((void *)0LL)
+
+/* Specifies the next object after this one that defines name. */
+#define RTLD_NEXT ((void *)-1LL)
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+dlclose(void *);
+
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+dlerror(void);
+
+ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL
+dlopen(const char *, int);
+
+ROKEN_LIB_FUNCTION DLSYM_RET_TYPE ROKEN_LIB_CALL
+dlsym(void *, const char *);
+
+typedef struct Dl_info
+{
+ const char *dli_fname; /* Filename of defining object (thread unsafe and reused on every call to dladdr) */
+ void *dli_fbase; /* Load address of that object */
+ const char *dli_sname; /* Name of nearest lower symbol */
+ void *dli_saddr; /* Exact value of nearest symbol */
+} Dl_info, Dl_info_t;
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+dladdr(void *addr, Dl_info *dli);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* __dlfcn_h__ */
diff --git a/third_party/heimdal/lib/roken/dlfcn_w32.c b/third_party/heimdal/lib/roken/dlfcn_w32.c
new file mode 100644
index 0000000..9da3f6f
--- /dev/null
+++ b/third_party/heimdal/lib/roken/dlfcn_w32.c
@@ -0,0 +1,700 @@
+/*
+ * dlfcn-win32
+ * Copyright (c) 2007 Ramiro Polla
+ * Copyright (c) 2015 Tiancheng "Timothy" Gu
+ * Copyright (c) 2019 Pali Rohár <pali.rohar@gmail.com>
+ * Copyright (c) 2020 Ralf Habacker <ralf.habacker@freenet.de>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/*
+ * Copied from https://github.com/dlfcn-win32/dlfcn-win32 and modified only to
+ * fit Heimdal's lib/roken.
+ */
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#endif
+#ifdef _DEBUG
+#define _CRTDBG_MAP_ALLOC
+#include <stdlib.h>
+#include <crtdbg.h>
+#endif
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef _MSC_VER
+/* https://docs.microsoft.com/en-us/cpp/intrinsics/returnaddress */
+#pragma intrinsic(_ReturnAddress)
+#else
+/* https://gcc.gnu.org/onlinedocs/gcc/Return-Address.html */
+#ifndef _ReturnAddress
+#define _ReturnAddress() (__builtin_extract_return_addr(__builtin_return_address(0)))
+#endif
+#endif
+
+#ifdef DLFCN_WIN32_SHARED
+#define DLFCN_WIN32_EXPORTS
+#endif
+#include "dlfcn.h"
+
+/* Note:
+ * MSDN says these functions are not thread-safe. We make no efforts to have
+ * any kind of thread safety.
+ */
+
+typedef struct local_object {
+ HMODULE hModule;
+ struct local_object *previous;
+ struct local_object *next;
+} local_object;
+
+static local_object first_object;
+
+/* These functions implement a double linked list for the local objects. */
+static local_object *local_search( HMODULE hModule )
+{
+ local_object *pobject;
+
+ if( hModule == NULL )
+ return NULL;
+
+ for( pobject = &first_object; pobject; pobject = pobject->next )
+ if( pobject->hModule == hModule )
+ return pobject;
+
+ return NULL;
+}
+
+static BOOL local_add( HMODULE hModule )
+{
+ local_object *pobject;
+ local_object *nobject;
+
+ if( hModule == NULL )
+ return TRUE;
+
+ pobject = local_search( hModule );
+
+ /* Do not add object again if it's already on the list */
+ if( pobject )
+ return TRUE;
+
+ for( pobject = &first_object; pobject->next; pobject = pobject->next );
+
+ nobject = (local_object*) malloc( sizeof( local_object ) );
+
+ if( !nobject )
+ {
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ return FALSE;
+ }
+
+ pobject->next = nobject;
+ nobject->next = NULL;
+ nobject->previous = pobject;
+ nobject->hModule = hModule;
+
+ return TRUE;
+}
+
+static void local_rem( HMODULE hModule )
+{
+ local_object *pobject;
+
+ if( hModule == NULL )
+ return;
+
+ pobject = local_search( hModule );
+
+ if( !pobject )
+ return;
+
+ if( pobject->next )
+ pobject->next->previous = pobject->previous;
+ if( pobject->previous )
+ pobject->previous->next = pobject->next;
+
+ free( pobject );
+}
+
+/* POSIX says dlerror( ) doesn't have to be thread-safe, so we use one
+ * static buffer.
+ * MSDN says the buffer cannot be larger than 64K bytes, so we set it to
+ * the limit.
+ */
+static char error_buffer[65535];
+static BOOL error_occurred;
+
+static void save_err_str( const char *str )
+{
+ DWORD dwMessageId;
+ DWORD ret;
+ size_t pos, len;
+
+ dwMessageId = GetLastError( );
+
+ if( dwMessageId == 0 )
+ return;
+
+ len = strlen( str );
+ if( len > sizeof( error_buffer ) - 5 )
+ len = sizeof( error_buffer ) - 5;
+
+ /* Format error message to:
+ * "<argument to function that failed>": <Windows localized error message>
+ */
+ pos = 0;
+ error_buffer[pos++] = '"';
+ memcpy( error_buffer+pos, str, len );
+ pos += len;
+ error_buffer[pos++] = '"';
+ error_buffer[pos++] = ':';
+ error_buffer[pos++] = ' ';
+
+ ret = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwMessageId,
+ MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
+ error_buffer+pos, (DWORD) (sizeof(error_buffer)-pos), NULL );
+ pos += ret;
+
+ /* When FormatMessageA() fails it returns zero and does not touch buffer
+ * so add trailing null byte */
+ if( ret == 0 )
+ error_buffer[pos] = '\0';
+
+ if( pos > 1 )
+ {
+ /* POSIX says the string must not have trailing <newline> */
+ if( error_buffer[pos-2] == '\r' && error_buffer[pos-1] == '\n' )
+ error_buffer[pos-2] = '\0';
+ }
+
+ error_occurred = TRUE;
+}
+
+static void save_err_ptr_str( const void *ptr )
+{
+ char ptr_buf[2 + 2 * sizeof( ptr ) + 1];
+ char num;
+ size_t i;
+
+ ptr_buf[0] = '0';
+ ptr_buf[1] = 'x';
+
+ for( i = 0; i < 2 * sizeof( ptr ); i++ )
+ {
+ num = ( ( (ULONG_PTR) ptr ) >> ( 8 * sizeof( ptr ) - 4 * ( i + 1 ) ) ) & 0xF;
+ ptr_buf[2+i] = num + ( ( num < 0xA ) ? '0' : ( 'A' - 0xA ) );
+ }
+
+ ptr_buf[2 + 2 * sizeof( ptr )] = 0;
+
+ save_err_str( ptr_buf );
+}
+
+/* Load Psapi.dll at runtime, this avoids linking caveat */
+static BOOL MyEnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded )
+{
+ static BOOL (WINAPI *EnumProcessModulesPtr)(HANDLE, HMODULE *, DWORD, LPDWORD);
+ HMODULE psapi;
+
+ if( !EnumProcessModulesPtr )
+ {
+ psapi = LoadLibraryA( "Psapi.dll" );
+ if( psapi )
+ EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) GetProcAddress( psapi, "EnumProcessModules" );
+ if( !EnumProcessModulesPtr )
+ return 0;
+ }
+
+ return EnumProcessModulesPtr( hProcess, lphModule, cb, lpcbNeeded );
+}
+
+ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL
+dlopen( const char *file, int mode )
+{
+ HMODULE hModule;
+ UINT uMode;
+
+ error_occurred = FALSE;
+
+ /* Do not let Windows display the critical-error-handler message box */
+ uMode = SetErrorMode( SEM_FAILCRITICALERRORS );
+
+ if( file == 0 )
+ {
+ /* POSIX says that if the value of file is 0, a handle on a global
+ * symbol object must be provided. That object must be able to access
+ * all symbols from the original program file, and any objects loaded
+ * with the RTLD_GLOBAL flag.
+ * The return value from GetModuleHandle( ) allows us to retrieve
+ * symbols only from the original program file. EnumProcessModules() is
+ * used to access symbols from other libraries. For objects loaded
+ * with the RTLD_LOCAL flag, we create our own list later on. They are
+ * excluded from EnumProcessModules() iteration.
+ */
+ hModule = GetModuleHandle( NULL );
+
+ if( !hModule )
+ save_err_str( "(null)" );
+ }
+ else
+ {
+ HANDLE hCurrentProc;
+ DWORD dwProcModsBefore, dwProcModsAfter;
+ char lpFileName[MAX_PATH];
+ size_t i, len;
+
+ len = strlen( file );
+
+ if( len >= sizeof( lpFileName ) )
+ {
+ SetLastError( ERROR_FILENAME_EXCED_RANGE );
+ save_err_str( file );
+ hModule = NULL;
+ }
+ else
+ {
+ /* MSDN says backslashes *must* be used instead of forward slashes. */
+ for( i = 0; i < len; i++ )
+ {
+ if( file[i] == '/' )
+ lpFileName[i] = '\\';
+ else
+ lpFileName[i] = file[i];
+ }
+ lpFileName[len] = '\0';
+
+ hCurrentProc = GetCurrentProcess( );
+
+ if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsBefore ) == 0 )
+ dwProcModsBefore = 0;
+
+ /* POSIX says the search path is implementation-defined.
+ * LOAD_WITH_ALTERED_SEARCH_PATH is used to make it behave more closely
+ * to UNIX's search paths (start with system folders instead of current
+ * folder).
+ */
+ hModule = LoadLibraryExA( lpFileName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
+
+ if( !hModule )
+ {
+ save_err_str( lpFileName );
+ }
+ else
+ {
+ if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsAfter ) == 0 )
+ dwProcModsAfter = 0;
+
+ /* If the object was loaded with RTLD_LOCAL, add it to list of local
+ * objects, so that its symbols cannot be retrieved even if the handle for
+ * the original program file is passed. POSIX says that if the same
+ * file is specified in multiple invocations, and any of them are
+ * RTLD_GLOBAL, even if any further invocations use RTLD_LOCAL, the
+ * symbols will remain global. If number of loaded modules was not
+ * changed after calling LoadLibraryEx(), it means that library was
+ * already loaded.
+ */
+ if( (mode & RTLD_LOCAL) && dwProcModsBefore != dwProcModsAfter )
+ {
+ if( !local_add( hModule ) )
+ {
+ save_err_str( lpFileName );
+ FreeLibrary( hModule );
+ hModule = NULL;
+ }
+ }
+ else if( !(mode & RTLD_LOCAL) && dwProcModsBefore == dwProcModsAfter )
+ {
+ local_rem( hModule );
+ }
+ }
+ }
+ }
+
+ /* Return to previous state of the error-mode bit flags. */
+ SetErrorMode( uMode );
+
+ return (void *) hModule;
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+dlclose( void *handle )
+{
+ HMODULE hModule = (HMODULE) handle;
+ BOOL ret;
+
+ error_occurred = FALSE;
+
+ ret = FreeLibrary( hModule );
+
+ /* If the object was loaded with RTLD_LOCAL, remove it from list of local
+ * objects.
+ */
+ if( ret )
+ local_rem( hModule );
+ else
+ save_err_ptr_str( handle );
+
+ /* dlclose's return value in inverted in relation to FreeLibrary's. */
+ ret = !ret;
+
+ return (int) ret;
+}
+
+__declspec(noinline) /* Needed for _ReturnAddress() */
+ROKEN_LIB_FUNCTION DLSYM_RET_TYPE ROKEN_LIB_CALL
+dlsym( void *handle, const char *name )
+{
+ FARPROC symbol;
+ HMODULE hCaller;
+ HMODULE hModule;
+ HANDLE hCurrentProc;
+
+ error_occurred = FALSE;
+
+ symbol = NULL;
+ hCaller = NULL;
+ hModule = GetModuleHandle( NULL );
+ hCurrentProc = GetCurrentProcess( );
+
+ if( handle == RTLD_DEFAULT )
+ {
+ /* The symbol lookup happens in the normal global scope; that is,
+ * a search for a symbol using this handle would find the same
+ * definition as a direct use of this symbol in the program code.
+ * So use same lookup procedure as when filename is NULL.
+ */
+ handle = hModule;
+ }
+ else if( handle == RTLD_NEXT )
+ {
+ /* Specifies the next object after this one that defines name.
+ * This one refers to the object containing the invocation of dlsym().
+ * The next object is the one found upon the application of a load
+ * order symbol resolution algorithm. To get caller function of dlsym()
+ * use _ReturnAddress() intrinsic. To get HMODULE of caller function
+ * use standard GetModuleHandleExA() function.
+ */
+ if( !GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCSTR) _ReturnAddress( ), &hCaller ) )
+ goto end;
+ }
+
+ if( handle != RTLD_NEXT )
+ {
+ symbol = GetProcAddress( (HMODULE) handle, name );
+
+ if( symbol != NULL )
+ goto end;
+ }
+
+ /* If the handle for the original program file is passed, also search
+ * in all globally loaded objects.
+ */
+
+ if( hModule == handle || handle == RTLD_NEXT )
+ {
+ HMODULE *modules;
+ DWORD cbNeeded;
+ DWORD dwSize;
+ size_t i;
+
+ /* GetModuleHandle( NULL ) only returns the current program file. So
+ * if we want to get ALL loaded module including those in linked DLLs,
+ * we have to use EnumProcessModules( ).
+ */
+ if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwSize ) != 0 )
+ {
+ modules = malloc( dwSize );
+ if( modules )
+ {
+ if( MyEnumProcessModules( hCurrentProc, modules, dwSize, &cbNeeded ) != 0 && dwSize == cbNeeded )
+ {
+ for( i = 0; i < dwSize / sizeof( HMODULE ); i++ )
+ {
+ if( handle == RTLD_NEXT && hCaller )
+ {
+ /* Next modules can be used for RTLD_NEXT */
+ if( hCaller == modules[i] )
+ hCaller = NULL;
+ continue;
+ }
+ if( local_search( modules[i] ) )
+ continue;
+ symbol = GetProcAddress( modules[i], name );
+ if( symbol != NULL )
+ {
+ free( modules );
+ goto end;
+ }
+ }
+
+ }
+ free( modules );
+ }
+ else
+ {
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ goto end;
+ }
+ }
+ }
+
+end:
+ if( symbol == NULL )
+ {
+ if( GetLastError() == 0 )
+ SetLastError( ERROR_PROC_NOT_FOUND );
+ save_err_str( name );
+ }
+
+ return *(void **) (&symbol);
+}
+
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+dlerror( void )
+{
+ /* If this is the second consecutive call to dlerror, return NULL */
+ if( !error_occurred )
+ return NULL;
+
+ /* POSIX says that invoking dlerror( ) a second time, immediately following
+ * a prior invocation, shall result in NULL being returned.
+ */
+ error_occurred = FALSE;
+
+ return error_buffer;
+}
+
+/* See https://docs.microsoft.com/en-us/archive/msdn-magazine/2002/march/inside-windows-an-in-depth-look-into-the-win32-portable-executable-file-format-part-2
+ * for details */
+
+/* Get specific image section */
+static BOOL get_image_section( HMODULE module, int index, void **ptr, DWORD *size )
+{
+ IMAGE_DOS_HEADER *dosHeader;
+ IMAGE_OPTIONAL_HEADER *optionalHeader;
+
+ dosHeader = (IMAGE_DOS_HEADER *) module;
+
+ if( dosHeader->e_magic != 0x5A4D )
+ return FALSE;
+
+ optionalHeader = (IMAGE_OPTIONAL_HEADER *) ( (BYTE *) module + dosHeader->e_lfanew + 24 );
+
+ if( optionalHeader->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC )
+ return FALSE;
+
+ if( index < 0 || index > IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR )
+ return FALSE;
+
+ if( optionalHeader->DataDirectory[index].Size == 0 || optionalHeader->DataDirectory[index].VirtualAddress == 0 )
+ return FALSE;
+
+ if( size != NULL )
+ *size = optionalHeader->DataDirectory[index].Size;
+
+ *ptr = (void *)( (BYTE *) module + optionalHeader->DataDirectory[index].VirtualAddress );
+
+ return TRUE;
+}
+
+/* Return symbol name for a given address */
+static const char *get_symbol_name( HMODULE module, IMAGE_IMPORT_DESCRIPTOR *iid, void *addr, void **func_address )
+{
+ int i;
+ void *candidateAddr = NULL;
+ const char *candidateName = NULL;
+ BYTE *base = (BYTE *) module; /* Required to have correct calculations */
+
+ for( i = 0; iid[i].Characteristics != 0 && iid[i].FirstThunk != 0; i++ )
+ {
+ IMAGE_THUNK_DATA *thunkILT = (IMAGE_THUNK_DATA *)( base + iid[i].Characteristics );
+ IMAGE_THUNK_DATA *thunkIAT = (IMAGE_THUNK_DATA *)( base + iid[i].FirstThunk );
+
+ for( ; thunkILT->u1.AddressOfData != 0; thunkILT++, thunkIAT++ )
+ {
+ IMAGE_IMPORT_BY_NAME *nameData;
+
+ if( IMAGE_SNAP_BY_ORDINAL( thunkILT->u1.Ordinal ) )
+ continue;
+
+ if( (void *) thunkIAT->u1.Function > addr || candidateAddr >= (void *) thunkIAT->u1.Function )
+ continue;
+
+ candidateAddr = (void *) thunkIAT->u1.Function;
+ nameData = (IMAGE_IMPORT_BY_NAME *)( base + (ULONG_PTR) thunkILT->u1.AddressOfData );
+ candidateName = (const char *) nameData->Name;
+ }
+ }
+
+ *func_address = candidateAddr;
+ return candidateName;
+}
+
+static BOOL is_valid_address( void *addr )
+{
+ MEMORY_BASIC_INFORMATION info;
+ SIZE_T result;
+
+ if( addr == NULL )
+ return FALSE;
+
+ /* check valid pointer */
+ result = VirtualQuery( addr, &info, sizeof( info ) );
+
+ if( result == 0 || info.AllocationBase == NULL || info.AllocationProtect == 0 || info.AllocationProtect == PAGE_NOACCESS )
+ return FALSE;
+
+ return TRUE;
+}
+
+/* Return state if address points to an import thunk
+ *
+ * An import thunk is setup with a 'jmp' instruction followed by an
+ * absolute address (32bit) or relative offset (64bit) pointing into
+ * the import address table (iat), which is partially maintained by
+ * the runtime linker.
+ */
+static BOOL is_import_thunk( void *addr )
+{
+ return *(short *) addr == 0x25ff ? TRUE : FALSE;
+}
+
+/* Return adress from the import address table (iat),
+ * if the original address points to a thunk table entry.
+ */
+static void *get_address_from_import_address_table( void *iat, DWORD iat_size, void *addr )
+{
+ BYTE *thkp = (BYTE *) addr;
+ /* Get offset from thunk table (after instruction 0xff 0x25)
+ * 4018c8 <_VirtualQuery>: ff 25 4a 8a 00 00
+ */
+ ULONG offset = *(ULONG *)( thkp + 2 );
+#ifdef _WIN64
+ /* On 64 bit the offset is relative
+ * 4018c8: ff 25 4a 8a 00 00 jmpq *0x8a4a(%rip) # 40a318 <__imp_VirtualQuery>
+ * And can be also negative (MSVC in WDK)
+ * 100002f20: ff 25 3a e1 ff ff jmpq *-0x1ec6(%rip) # 0x100001060
+ * So cast to signed LONG type
+ */
+ BYTE *ptr = (BYTE *)( thkp + 6 + (LONG) offset );
+#else
+ /* On 32 bit the offset is absolute
+ * 4019b4: ff 25 90 71 40 00 jmp *0x40719
+ */
+ BYTE *ptr = (BYTE *) offset;
+#endif
+
+ if( !is_valid_address( ptr ) || ptr < (BYTE *) iat || ptr > (BYTE *) iat + iat_size )
+ return NULL;
+
+ return *(void **) ptr;
+}
+
+/* Holds module filename */
+static char module_filename[2*MAX_PATH];
+
+static BOOL fill_module_info( void *addr, Dl_info *info )
+{
+ HMODULE hModule;
+ DWORD dwSize;
+
+ if( !GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, addr, &hModule ) || hModule == NULL )
+ return FALSE;
+
+ dwSize = GetModuleFileNameA( hModule, module_filename, sizeof( module_filename ) );
+
+ if( dwSize == 0 || dwSize == sizeof( module_filename ) )
+ return FALSE;
+
+ info->dli_fbase = (void *) hModule;
+ info->dli_fname = module_filename;
+
+ return TRUE;
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+dladdr( void *addr, Dl_info *info )
+{
+ void *realAddr, *funcAddress = NULL;
+ HMODULE hModule;
+ IMAGE_IMPORT_DESCRIPTOR *iid;
+ DWORD iidSize = 0;
+
+ if( addr == NULL || info == NULL )
+ return 0;
+
+ hModule = GetModuleHandleA( NULL );
+ if( hModule == NULL )
+ return 0;
+
+ if( !is_valid_address( addr ) )
+ return 0;
+
+ realAddr = addr;
+
+ if( !get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_IMPORT, (void **) &iid, &iidSize ) )
+ return 0;
+
+ if( is_import_thunk( addr ) )
+ {
+ void *iat;
+ void *iatAddr = NULL;
+ DWORD iatSize = 0;
+
+ if( !get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_IAT, &iat, &iatSize ) )
+ {
+ /* Fallback for cases where the iat is not defined,
+ * for example i586-mingw32msvc-gcc */
+ if( iid == NULL || iid->Characteristics == 0 || iid->FirstThunk == 0 )
+ return 0;
+
+ iat = (void *)( (BYTE *) hModule + iid->FirstThunk );
+ /* We assume that in this case iid and iat's are in linear order */
+ iatSize = iidSize - (DWORD) ( (BYTE *) iat - (BYTE *) iid );
+ }
+
+ iatAddr = get_address_from_import_address_table( iat, iatSize, addr );
+ if( iatAddr == NULL )
+ return 0;
+
+ realAddr = iatAddr;
+ }
+
+ if( !fill_module_info( realAddr, info ) )
+ return 0;
+
+ info->dli_sname = get_symbol_name( hModule, iid, realAddr, &funcAddress );
+
+ info->dli_saddr = !info->dli_sname ? NULL : funcAddress ? funcAddress : realAddr;
+ return 1;
+}
+
+#ifdef DLFCN_WIN32_SHARED
+BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
+{
+ (void) hinstDLL;
+ (void) fdwReason;
+ (void) lpvReserved;
+ return TRUE;
+}
+#endif
diff --git a/third_party/heimdal/lib/roken/doxygen.c b/third_party/heimdal/lib/roken/doxygen.c
new file mode 100644
index 0000000..0d30a47
--- /dev/null
+++ b/third_party/heimdal/lib/roken/doxygen.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2009 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
+ */
+
+/*! @mainpage Heimdal Roken support library
+ *
+ * @section intro Introduction
+ *
+ * Heimdal's roken implememnts missing functions and make it easier to
+ * work with almost unixies like cygwin and AIX.
+ *
+ * The project web page: http://www.h5l.org/
+ */
+
+/** @defgroup roken Heimdal roken library */
diff --git a/third_party/heimdal/lib/roken/dumpdata.c b/third_party/heimdal/lib/roken/dumpdata.c
new file mode 100644
index 0000000..a8b3efe
--- /dev/null
+++ b/third_party/heimdal/lib/roken/dumpdata.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+/*
+ * Write datablob to a filename, don't care about errors.
+ */
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rk_dumpdata (const char *filename, const void *buf, size_t size)
+{
+ int fd;
+
+ fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0640);
+ if (fd < 0)
+ return;
+ net_write(fd, buf, size);
+ close(fd);
+}
+
+/* For not-regular files */
+static int
+undump_not_file(int fd, char **out, size_t *size, int nul_terminate)
+{
+ size_t lim = 10 * 1024 * 1024;
+ size_t bufsz = 0;
+ size_t sz = 0;
+ char *buf = NULL;
+ char *tmp;
+
+ *out = NULL;
+ if (size && *size != 0 && *size < lim)
+ lim = *size;
+ if (size)
+ *size = 0;
+
+ /*
+ * We can't use net_read() if we're on WIN32 because that really wants a
+ * socket FD, which is in a distinct FD namespace from those returned by
+ * open() on Windows.
+ */
+ do {
+ ssize_t bytes;
+
+ if (sz == bufsz) {
+ if (bufsz == 0)
+ bufsz = 1024;
+ else
+ bufsz += bufsz >> 1;
+
+ tmp = realloc(buf, bufsz);
+ if (tmp == NULL) {
+ free(buf);
+ return ENOMEM;
+ }
+ buf = tmp;
+ }
+
+ bytes = read(fd, buf + sz, bufsz - sz);
+ if (bytes == 0)
+ break;
+ if (bytes < 0 &&
+ (errno == EAGAIN || errno == EWOULDBLOCK))
+ continue;
+ if (bytes < 0) {
+ free(buf);
+ return errno;
+ }
+ sz += bytes;
+ } while (sz < lim);
+
+ *out = buf;
+ if (size)
+ *size = sz;
+
+ if (!nul_terminate)
+ return 0;
+
+ if (bufsz > sz) {
+ buf[sz] = '\0';
+ return 0;
+ }
+
+ *out = tmp = realloc(buf, bufsz + 1);
+ if (tmp == NULL) {
+ free(buf);
+ return ENOMEM;
+ }
+ buf = tmp;
+ buf[sz] = '\0';
+ return 0;
+}
+
+/*
+ * Read all data from a file, care about errors.
+ *
+ * If `*size' is not zero and the file is not a regular file, then up to that
+ * many bytes will be read.
+ *
+ * Returns zero on success or a system error code on failure.
+ */
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_undumpdata(const char *filename, void **buf, size_t *size)
+{
+ struct stat sb;
+ int fd, ret;
+ ssize_t sret;
+
+ *buf = NULL;
+
+ fd = open(filename, O_RDONLY, 0);
+ if (fd < 0)
+ return errno;
+ if (fstat(fd, &sb) != 0){
+ ret = errno;
+ goto out;
+ }
+ if (!S_ISREG(sb.st_mode)) {
+ char *char_buf;
+
+ ret = undump_not_file(fd, &char_buf, size, 0);
+ (void) close(fd);
+ *buf = char_buf;
+ return ret;
+ }
+
+ if (sb.st_size < 0)
+ sb.st_size = 0;
+ *buf = malloc(sb.st_size);
+ if (*buf == NULL) {
+ ret = ENOMEM;
+ goto out;
+ }
+ *size = sb.st_size;
+
+ sret = read(fd, *buf, *size);
+ if (sret < 0)
+ ret = errno;
+ else if (sret != (ssize_t)*size)
+ ret = EINVAL;
+ else
+ ret = 0;
+
+ out:
+ if (ret) {
+ free(*buf);
+ *buf = NULL;
+ }
+ close(fd);
+ return ret;
+}
+
+/*
+ * Read all text from a file.
+ *
+ * Outputs a C string. It is up to the caller to check for embedded NULs.
+ * The number of bytes read will be stored in `*size' if `size' is not NULL.
+ *
+ * If `size' is not NULL and `*size' is not zero and the file is not a regular
+ * file, then up to that many bytes will be read.
+ *
+ * Returns zero on success or a system error code on failure.
+ */
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_undumptext(const char *filename, char **out, size_t *size)
+{
+ struct stat sb;
+ int fd, ret;
+ ssize_t sret;
+ char *buf;
+
+ *out = NULL;
+
+ fd = open(filename, O_RDONLY, 0);
+ if (fd < 0)
+ return errno;
+ if (fstat(fd, &sb) != 0) {
+ (void) close(fd);
+ return errno;
+ }
+ if (!S_ISREG(sb.st_mode)) {
+ ret = undump_not_file(fd, out, size, 1);
+ (void) close(fd);
+ return ret;
+ }
+
+ if (sb.st_size < 0)
+ sb.st_size = 0;
+ buf = malloc(sb.st_size + 1);
+ if (buf == NULL) {
+ ret = ENOMEM;
+ goto out;
+ }
+ if (size)
+ *size = sb.st_size;
+
+ sret = read(fd, buf, sb.st_size);
+ if (sret < 0)
+ ret = errno;
+ else if (sret != (ssize_t)sb.st_size)
+ ret = EINVAL;
+ else
+ ret = 0;
+
+out:
+ if (ret) {
+ free(buf);
+ } else {
+ buf[sb.st_size] = '\0';
+ *out = buf;
+ }
+ close(fd);
+ return ret;
+}
diff --git a/third_party/heimdal/lib/roken/ecalloc.3 b/third_party/heimdal/lib/roken/ecalloc.3
new file mode 100644
index 0000000..a2863df
--- /dev/null
+++ b/third_party/heimdal/lib/roken/ecalloc.3
@@ -0,0 +1,84 @@
+.\" Copyright (c) 2001, 2003 Kungliga Tekniska Högskolan
+.\" (Royal Institute of Technology, Stockholm, Sweden).
+.\" 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
+.\" $Id$
+.\"
+.Dd August 14, 2003
+.Dt ECALLOC 3
+.Os HEIMDAL
+.Sh NAME
+.Nm ecalloc ,
+.Nm emalloc ,
+.Nm eread ,
+.Nm erealloc ,
+.Nm esetenv ,
+.Nm estrdup ,
+.Nm ewrite
+.Nd exit-on-failure wrapper functions
+.Sh LIBRARY
+The roken library (libroken, -lroken)
+.Sh SYNOPSIS
+.Fd #include <roken.h>
+.Ft "void *"
+.Fn ecalloc "size_t number" "size_t size"
+.Ft "void *"
+.Fn emalloc "size_t sz"
+.Ft ssize_t
+.Fn eread "int fd" "void *buf" "size_t nbytes"
+.Ft "void *"
+.Fn erealloc "void *ptr" "size_t sz"
+.Ft void
+.Fn esetenv "const char *var" "const char *val" "int rewrite"
+.Ft "char *"
+.Fn estrdup "const char *str"
+.Ft ssize_t
+.Fn ewrite "int fd" "const void *buf" "size_t nbytes"
+.Sh DESCRIPTION
+These functions do the same as the ones without the
+.Dq e
+prefix, but if there is an error they will print a message with
+.Xr errx 3 ,
+and exit. For
+.Nm eread
+and
+.Nm ewrite
+this is also true for partial data.
+.Pp
+This is useful in applications when there is no need for a more
+advanced failure mode.
+.Sh SEE ALSO
+.Xr read 2 ,
+.Xr write 2 ,
+.Xr calloc 3 ,
+.Xr errx 3 ,
+.Xr malloc 3 ,
+.Xr realloc 3 ,
+.Xr setenv 3 ,
+.Xr strdup 3
diff --git a/third_party/heimdal/lib/roken/ecalloc.c b/third_party/heimdal/lib/roken/ecalloc.c
new file mode 100644
index 0000000..04b3733
--- /dev/null
+++ b/third_party/heimdal/lib/roken/ecalloc.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1999 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <stdlib.h>
+#include <err.h>
+
+#include "roken.h"
+
+/*
+ * Like calloc but never fails.
+ */
+
+ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL
+ecalloc (size_t number, size_t size)
+{
+ void *tmp = calloc (number, size);
+
+ if (tmp == NULL && number * size != 0)
+ errx (1, "calloc %lu failed", (unsigned long)number * size);
+ return tmp;
+}
diff --git a/third_party/heimdal/lib/roken/emalloc.c b/third_party/heimdal/lib/roken/emalloc.c
new file mode 100644
index 0000000..2520230
--- /dev/null
+++ b/third_party/heimdal/lib/roken/emalloc.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1999 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <stdlib.h>
+#include <err.h>
+
+#include "roken.h"
+
+/*
+ * Like malloc but never fails.
+ */
+
+ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL
+emalloc (size_t sz)
+{
+ void *tmp = malloc (sz);
+
+ if (tmp == NULL && sz != 0)
+ errx (1, "malloc %lu failed", (unsigned long)sz);
+ return tmp;
+}
diff --git a/third_party/heimdal/lib/roken/environment.c b/third_party/heimdal/lib/roken/environment.c
new file mode 100644
index 0000000..a14f27b
--- /dev/null
+++ b/third_party/heimdal/lib/roken/environment.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2000, 2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "roken.h"
+
+/* find assignment in env list; len is length of variable including
+ * equal
+ */
+
+static int
+find_var(char **env, char *assignment, size_t len)
+{
+ int i;
+ for(i = 0; env != NULL && env[i] != NULL; i++)
+ if(strncmp(env[i], assignment, len) == 0)
+ return i;
+ return -1;
+}
+
+/*
+ * return count of environment assignments from open file F in
+ * assigned and list of malloced strings in env, return 0 or errno
+ * number
+ */
+
+static int
+read_env_file(FILE *F, char ***env, int *assigned)
+{
+ size_t alloced = 0;
+ size_t idx = 0;
+ int i;
+ char **l;
+ char buf[BUFSIZ], *p, *r;
+ char **tmp;
+ int ret = 0;
+
+ *assigned = 0;
+
+ l = *env;
+ for (idx = 0; l != NULL && l[idx] != NULL; idx++)
+ ;
+ if (l)
+ alloced = idx + 1;
+
+ /* This is somewhat more relaxed on what it accepts then
+ * Wietses sysv_environ from K4 was...
+ */
+ while (fgets(buf, BUFSIZ, F) != NULL) {
+ buf[strcspn(buf, "#\n")] = '\0';
+
+ for(p = buf; isspace((unsigned char)*p); p++);
+ if (*p == '\0')
+ continue;
+
+ /* Here one should check that it's a 'valid' env string... */
+ r = strchr(p, '=');
+ if (r == NULL)
+ continue;
+
+ if((i = find_var(l, p, r - p + 1)) >= 0) {
+ char *val;
+
+ if ((size_t)i >= alloced)
+ continue; /* Doesn't happen (fix scan-build noise) */
+ val = strdup(p);
+ if(val == NULL) {
+ ret = ENOMEM;
+ break;
+ }
+ free(l[i]);
+ l[i] = val;
+ (*assigned)++;
+ continue;
+ }
+
+ tmp = realloc(l, (idx+2) * sizeof (char *));
+ if(tmp == NULL) {
+ ret = ENOMEM;
+ break;
+ }
+
+ l = tmp;
+ l[idx] = strdup(p);
+ if(l[idx] == NULL) {
+ ret = ENOMEM;
+ break;
+ }
+ l[++idx] = NULL;
+ alloced = idx + 1;
+ (*assigned)++;
+ }
+ if(ferror(F))
+ ret = errno;
+ *env = l;
+ return ret;
+}
+
+/*
+ * return count of environment assignments from file and
+ * list of malloced strings in `env'
+ */
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+read_environment(const char *file, char ***env)
+{
+ int assigned;
+ FILE *F;
+
+ if ((F = fopen(file, "r")) == NULL)
+ return 0;
+
+ read_env_file(F, env, &assigned);
+ fclose(F);
+ return assigned;
+}
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+free_environment(char **env)
+{
+ int i;
+ if (env == NULL)
+ return;
+ for (i = 0; env[i]; i++)
+ free(env[i]);
+ free(env);
+}
diff --git a/third_party/heimdal/lib/roken/eread.c b/third_party/heimdal/lib/roken/eread.c
new file mode 100644
index 0000000..ba30f02
--- /dev/null
+++ b/third_party/heimdal/lib/roken/eread.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+/*
+ * Like read but never fails (and never returns partial data).
+ */
+
+ROKEN_LIB_FUNCTION ssize_t ROKEN_LIB_CALL
+eread (int fd, void *buf, size_t nbytes)
+{
+ ssize_t ret;
+
+ ret = net_read (fd, buf, nbytes);
+ if (ret < 0)
+ err (1, "read");
+ return ret;
+}
diff --git a/third_party/heimdal/lib/roken/erealloc.c b/third_party/heimdal/lib/roken/erealloc.c
new file mode 100644
index 0000000..1c30ecc
--- /dev/null
+++ b/third_party/heimdal/lib/roken/erealloc.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1999 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <stdlib.h>
+#include <err.h>
+
+#include "roken.h"
+
+/*
+ * Like realloc but never fails.
+ */
+
+ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL
+erealloc (void *ptr, size_t sz)
+{
+ void *tmp = realloc (ptr, sz);
+
+ if (tmp == NULL && sz != 0)
+ errx (1, "realloc %lu failed", (unsigned long)sz);
+ return tmp;
+}
diff --git a/third_party/heimdal/lib/roken/err.c b/third_party/heimdal/lib/roken/err.c
new file mode 100644
index 0000000..592ed69
--- /dev/null
+++ b/third_party/heimdal/lib/roken/err.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+#include "err.h"
+
+ROKEN_LIB_NORETURN_FUNCTION void ROKEN_LIB_CALL
+err(int eval, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ verr(eval, fmt, ap);
+ va_end(ap);
+}
diff --git a/third_party/heimdal/lib/roken/err.hin b/third_party/heimdal/lib/roken/err.hin
new file mode 100644
index 0000000..905b1eb
--- /dev/null
+++ b/third_party/heimdal/lib/roken/err.hin
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 1995 - 2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
+ */
+
+/* $Id$ */
+
+#ifndef __ERR_H__
+#define __ERR_H__
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#if !defined(__GNUC__) && !defined(__attribute__)
+#define __attribute__(x)
+#endif
+
+#ifndef ROKEN_LIB_FUNCTION
+ #define ROKEN_LIB_FUNCTION
+#endif
+#ifndef ROKEN_LIB_NORETURN_FUNCTION
+ #ifdef _WIN32
+ #define ROKEN_LIB_NORETURN_FUNCTION __declspec(noreturn)
+ #else
+ #define ROKEN_LIB_NORETURN_FUNCTION
+ #endif
+#endif
+#ifndef ROKEN_LIB_CALL
+ #ifdef _WIN32
+ #define ROKEN_LIB_CALL __cdecl
+ #else
+ #define ROKEN_LIB_CALL
+ #endif
+#endif
+
+ROKEN_LIB_NORETURN_FUNCTION void ROKEN_LIB_CALL
+verr(int eval, const char *fmt, va_list ap)
+ __attribute__ ((__noreturn__, __format__ (__printf__, 2, 0)));
+
+ROKEN_LIB_NORETURN_FUNCTION void ROKEN_LIB_CALL
+err(int eval, const char *fmt, ...)
+ __attribute__ ((__noreturn__, __format__ (__printf__, 2, 3)));
+
+ROKEN_LIB_NORETURN_FUNCTION void ROKEN_LIB_CALL
+verrx(int eval, const char *fmt, va_list ap)
+ __attribute__ ((__noreturn__, __format__ (__printf__, 2, 0)));
+
+ROKEN_LIB_NORETURN_FUNCTION void ROKEN_LIB_CALL
+errx(int eval, const char *fmt, ...)
+ __attribute__ ((__noreturn__, __format__ (__printf__, 2, 3)));
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+vwarn(const char *fmt, va_list ap)
+ __attribute__ ((__format__ (__printf__, 1, 0)));
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+warn(const char *fmt, ...)
+ __attribute__ ((__format__ (__printf__, 1, 2)));
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+vwarnx(const char *fmt, va_list ap)
+ __attribute__ ((__format__ (__printf__, 1, 0)));
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+warnx(const char *fmt, ...)
+ __attribute__ ((__format__ (__printf__, 1, 2)));
+
+#endif /* __ERR_H__ */
diff --git a/third_party/heimdal/lib/roken/errx.c b/third_party/heimdal/lib/roken/errx.c
new file mode 100644
index 0000000..121c707
--- /dev/null
+++ b/third_party/heimdal/lib/roken/errx.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "err.h"
+
+ROKEN_LIB_NORETURN_FUNCTION void ROKEN_LIB_CALL
+errx(int eval, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ verrx(eval, fmt, ap);
+ va_end(ap);
+}
diff --git a/third_party/heimdal/lib/roken/esetenv.c b/third_party/heimdal/lib/roken/esetenv.c
new file mode 100644
index 0000000..3cbf5ed
--- /dev/null
+++ b/third_party/heimdal/lib/roken/esetenv.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2000, 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+#include <err.h>
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+esetenv(const char *var, const char *val, int rewrite)
+{
+ if (setenv (rk_UNCONST(var), rk_UNCONST(val), rewrite))
+ errx (1, "failed setting environment variable %s", var);
+}
diff --git a/third_party/heimdal/lib/roken/estrdup.c b/third_party/heimdal/lib/roken/estrdup.c
new file mode 100644
index 0000000..d275a28
--- /dev/null
+++ b/third_party/heimdal/lib/roken/estrdup.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1999 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <stdlib.h>
+#include <err.h>
+
+#include "roken.h"
+
+/*
+ * Like strdup but never fails.
+ */
+
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+estrdup (const char *str)
+{
+ char *tmp = strdup (str);
+
+ if (tmp == NULL)
+ errx (1, "strdup failed");
+ return tmp;
+}
diff --git a/third_party/heimdal/lib/roken/ewrite.c b/third_party/heimdal/lib/roken/ewrite.c
new file mode 100644
index 0000000..fce5705
--- /dev/null
+++ b/third_party/heimdal/lib/roken/ewrite.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+/*
+ * Like write but never fails (and never returns partial data).
+ */
+
+ROKEN_LIB_FUNCTION ssize_t ROKEN_LIB_CALL
+ewrite (int fd, const void *buf, size_t nbytes)
+{
+ ssize_t ret;
+
+ ret = net_write (fd, buf, nbytes);
+ if (ret < 0)
+ err (1, "write");
+ return ret;
+}
diff --git a/third_party/heimdal/lib/roken/fchown.c b/third_party/heimdal/lib/roken/fchown.c
new file mode 100644
index 0000000..050c2dd
--- /dev/null
+++ b/third_party/heimdal/lib/roken/fchown.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+fchown(int fd, uid_t owner, gid_t group)
+{
+ return 0;
+}
diff --git a/third_party/heimdal/lib/roken/flock.c b/third_party/heimdal/lib/roken/flock.c
new file mode 100644
index 0000000..068d099
--- /dev/null
+++ b/third_party/heimdal/lib/roken/flock.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#ifndef HAVE_FLOCK
+
+#include "roken.h"
+
+#define OP_MASK (LOCK_SH | LOCK_EX | LOCK_UN)
+
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_flock(int fd, int operation)
+{
+#if defined(HAVE_FCNTL) && defined(F_SETLK)
+ struct flock arg;
+ int code, cmd;
+
+ arg.l_whence = SEEK_SET;
+ arg.l_start = 0;
+ arg.l_len = 0; /* means to EOF */
+
+ if (operation & LOCK_NB)
+ cmd = F_SETLK;
+ else
+ cmd = F_SETLKW; /* Blocking */
+
+ switch (operation & OP_MASK) {
+ case LOCK_UN:
+ arg.l_type = F_UNLCK;
+ code = fcntl(fd, F_SETLK, &arg);
+ break;
+ case LOCK_SH:
+ arg.l_type = F_RDLCK;
+ code = fcntl(fd, cmd, &arg);
+ break;
+ case LOCK_EX:
+ arg.l_type = F_WRLCK;
+ code = fcntl(fd, cmd, &arg);
+ break;
+ default:
+ errno = EINVAL;
+ code = -1;
+ break;
+ }
+ return code;
+
+#elif defined(_WIN32)
+ /* Windows */
+
+#define FLOCK_OFFSET_LOW 0
+#define FLOCK_OFFSET_HIGH 0
+#define FLOCK_LENGTH_LOW 0x00000000
+#define FLOCK_LENGTH_HIGH 0x80000000
+
+ HANDLE hFile;
+ OVERLAPPED ov;
+ BOOL rv = FALSE;
+ DWORD f = 0;
+
+ hFile = (HANDLE) _get_osfhandle(fd);
+ if (hFile == NULL || hFile == INVALID_HANDLE_VALUE) {
+ _set_errno(EBADF);
+ return -1;
+ }
+
+ ZeroMemory(&ov, sizeof(ov));
+ ov.hEvent = NULL;
+ ov.Offset = FLOCK_OFFSET_LOW;
+ ov.OffsetHigh = FLOCK_OFFSET_HIGH;
+
+ if (operation & LOCK_NB)
+ f = LOCKFILE_FAIL_IMMEDIATELY;
+
+ switch (operation & OP_MASK) {
+ case LOCK_UN: /* Unlock */
+ rv = UnlockFileEx(hFile, 0,
+ FLOCK_LENGTH_LOW, FLOCK_LENGTH_HIGH, &ov);
+ break;
+
+ case LOCK_SH: /* Shared lock */
+ rv = LockFileEx(hFile, f, 0,
+ FLOCK_LENGTH_LOW, FLOCK_LENGTH_HIGH, &ov);
+ break;
+
+ case LOCK_EX: /* Exclusive lock */
+ rv = LockFileEx(hFile, f|LOCKFILE_EXCLUSIVE_LOCK, 0,
+ FLOCK_LENGTH_LOW, FLOCK_LENGTH_HIGH,
+ &ov);
+ break;
+
+ default:
+ _set_errno(EINVAL);
+ return -1;
+ }
+
+ if (!rv) {
+ switch (GetLastError()) {
+ case ERROR_SHARING_VIOLATION:
+ case ERROR_LOCK_VIOLATION:
+ case ERROR_IO_PENDING:
+ _set_errno(EWOULDBLOCK);
+ break;
+
+ case ERROR_ACCESS_DENIED:
+ _set_errno(EACCES);
+ break;
+
+ default:
+ _set_errno(ENOLCK);
+ }
+ return -1;
+ }
+
+ return 0;
+
+#else
+ return -1;
+#endif
+}
+
+#endif
+
diff --git a/third_party/heimdal/lib/roken/fnmatch.c b/third_party/heimdal/lib/roken/fnmatch.c
new file mode 100644
index 0000000..34da19f
--- /dev/null
+++ b/third_party/heimdal/lib/roken/fnmatch.c
@@ -0,0 +1,175 @@
+/* $NetBSD: fnmatch.c,v 1.11 1995/02/27 03:43:06 cgd Exp $ */
+
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Guido van Rossum.
+ *
+ * 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 4/16/94";
+#else
+static char rcsid[] = "$NetBSD: fnmatch.c,v 1.11 1995/02/27 03:43:06 cgd Exp $";
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
+ * Compares a filename or pathname to a pattern.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <roken.h>
+
+#include <fnmatch.h>
+#include <string.h>
+
+#define EOS '\0'
+
+static const char *rangematch (const char *, int, int);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_fnmatch(const char *pattern, const char *string, int flags)
+{
+ const char *stringstart;
+ char c, test;
+
+ for (stringstart = string;;)
+ switch (c = *pattern++) {
+ case EOS:
+ return (*string == EOS ? 0 : FNM_NOMATCH);
+ case '?':
+ if (*string == EOS)
+ return (FNM_NOMATCH);
+ if (*string == '/' && (flags & FNM_PATHNAME))
+ return (FNM_NOMATCH);
+ if (*string == '.' && (flags & FNM_PERIOD) &&
+ (string == stringstart ||
+ ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
+ return (FNM_NOMATCH);
+ ++string;
+ break;
+ case '*':
+ c = *pattern;
+ /* Collapse multiple stars. */
+ while (c == '*')
+ c = *++pattern;
+
+ if (*string == '.' && (flags & FNM_PERIOD) &&
+ (string == stringstart ||
+ ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
+ return (FNM_NOMATCH);
+
+ /* Optimize for pattern with * at end or before /. */
+ if (c == EOS)
+ if (flags & FNM_PATHNAME)
+ return (strchr(string, '/') == NULL ?
+ 0 : FNM_NOMATCH);
+ else
+ return (0);
+ else if (c == '/' && flags & FNM_PATHNAME) {
+ if ((string = strchr(string, '/')) == NULL)
+ return (FNM_NOMATCH);
+ break;
+ }
+
+ /* General case, use recursion. */
+ while ((test = *string) != EOS) {
+ if (!rk_fnmatch(pattern, string, flags & ~FNM_PERIOD))
+ return (0);
+ if (test == '/' && flags & FNM_PATHNAME)
+ break;
+ ++string;
+ }
+ return (FNM_NOMATCH);
+ case '[':
+ if (*string == EOS)
+ return (FNM_NOMATCH);
+ if (*string == '/' && flags & FNM_PATHNAME)
+ return (FNM_NOMATCH);
+ if ((pattern =
+ rangematch(pattern, *string, flags)) == NULL)
+ return (FNM_NOMATCH);
+ ++string;
+ break;
+ case '\\':
+ if (!(flags & FNM_NOESCAPE)) {
+ if ((c = *pattern++) == EOS) {
+ c = '\\';
+ --pattern;
+ }
+ }
+ HEIM_FALLTHROUGH;
+ default:
+ if (c != *string++)
+ return (FNM_NOMATCH);
+ break;
+ }
+ /* NOTREACHED */
+}
+
+static const char *
+rangematch(const char *pattern, int test, int flags)
+{
+ int negate, ok;
+ char c, c2;
+
+ /*
+ * A bracket expression starting with an unquoted circumflex
+ * character produces unspecified results (IEEE 1003.2-1992,
+ * 3.13.2). This implementation treats it like '!', for
+ * consistency with the regular expression syntax.
+ * J.T. Conklin (conklin@ngai.kaleida.com)
+ */
+ if (negate = (*pattern == '!' || *pattern == '^'))
+ ++pattern;
+
+ for (ok = 0; (c = *pattern++) != ']';) {
+ if (c == '\\' && !(flags & FNM_NOESCAPE))
+ c = *pattern++;
+ if (c == EOS)
+ return (NULL);
+ if (*pattern == '-'
+ && (c2 = *(pattern+1)) != EOS && c2 != ']') {
+ pattern += 2;
+ if (c2 == '\\' && !(flags & FNM_NOESCAPE))
+ c2 = *pattern++;
+ if (c2 == EOS)
+ return (NULL);
+ if (c <= test && test <= c2)
+ ok = 1;
+ } else if (c == test)
+ ok = 1;
+ }
+ return (ok == negate ? NULL : pattern);
+}
diff --git a/third_party/heimdal/lib/roken/fnmatch.hin b/third_party/heimdal/lib/roken/fnmatch.hin
new file mode 100644
index 0000000..fd96656
--- /dev/null
+++ b/third_party/heimdal/lib/roken/fnmatch.hin
@@ -0,0 +1,66 @@
+/* $NetBSD: fnmatch.h,v 1.5 1994/10/26 00:55:53 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1992, 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.
+ *
+ * @(#)fnmatch.h 8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _FNMATCH_H_
+#define _FNMATCH_H_
+
+#ifndef ROKEN_LIB_FUNCTION
+#ifdef _WIN32
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL __stdcall
+#else
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL
+#endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define FNM_NOMATCH 1 /* Match failed. */
+
+#define FNM_NOESCAPE 0x01 /* Disable backslash escaping. */
+#define FNM_PATHNAME 0x02 /* Slash must be matched by slash. */
+#define FNM_PERIOD 0x04 /* Period must be matched by period. */
+
+int ROKEN_LIB_FUNCTION
+rk_fnmatch (const char *, const char *, int);
+
+#define fnmatch(a,b,c) rk_fnmatch(a,b,c)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_FNMATCH_H_ */
diff --git a/third_party/heimdal/lib/roken/freeaddrinfo.c b/third_party/heimdal/lib/roken/freeaddrinfo.c
new file mode 100644
index 0000000..80a7487
--- /dev/null
+++ b/third_party/heimdal/lib/roken/freeaddrinfo.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1999 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+/*
+ * free the list of `struct addrinfo' starting at `ai'
+ */
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rk_freeaddrinfo(struct addrinfo *ai)
+{
+ struct addrinfo *tofree;
+
+ while(ai != NULL) {
+ free (ai->ai_canonname);
+ free (ai->ai_addr);
+ tofree = ai;
+ ai = ai->ai_next;
+ free (tofree);
+ }
+}
diff --git a/third_party/heimdal/lib/roken/freehostent.c b/third_party/heimdal/lib/roken/freehostent.c
new file mode 100644
index 0000000..05dd0fe
--- /dev/null
+++ b/third_party/heimdal/lib/roken/freehostent.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+/*
+ * free a malloced hostent
+ */
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rk_freehostent(struct hostent *h)
+{
+ char **p;
+
+ free (h->h_name);
+ if (h->h_aliases != NULL) {
+ for (p = h->h_aliases; *p != NULL; ++p)
+ free (*p);
+ free (h->h_aliases);
+ }
+ if (h->h_addr_list != NULL) {
+ for (p = h->h_addr_list; *p != NULL; ++p)
+ free (*p);
+ free (h->h_addr_list);
+ }
+ free (h);
+}
diff --git a/third_party/heimdal/lib/roken/fseeko.c b/third_party/heimdal/lib/roken/fseeko.c
new file mode 100644
index 0000000..b6ffaa2
--- /dev/null
+++ b/third_party/heimdal/lib/roken/fseeko.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2017 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+#ifndef HAVE_FSEEKO
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+fseeko(FILE *f, off_t o, int w)
+{
+#ifdef HAVE__FSEEKI64
+ return _fseeki64(f, o, w);
+#else
+ return fseek(f, o, w);
+#endif
+}
+#endif
diff --git a/third_party/heimdal/lib/roken/ftello.c b/third_party/heimdal/lib/roken/ftello.c
new file mode 100644
index 0000000..cd3b84b
--- /dev/null
+++ b/third_party/heimdal/lib/roken/ftello.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2017 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+#ifndef HAVE_FTELLO
+ROKEN_LIB_FUNCTION off_t ROKEN_LIB_CALL
+ftello(FILE *f)
+{
+#ifdef HAVE__FTELLI64
+ return _ftelli64(f);
+#else
+ return ftell(f);
+#endif
+}
+#endif
diff --git a/third_party/heimdal/lib/roken/gai_strerror.c b/third_party/heimdal/lib/roken/gai_strerror.c
new file mode 100644
index 0000000..1e326be
--- /dev/null
+++ b/third_party/heimdal/lib/roken/gai_strerror.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+static struct gai_error {
+ int code;
+ const char *str;
+} errors[] = {
+{EAI_NOERROR, "no error"},
+#ifdef EAI_ADDRFAMILY
+{EAI_ADDRFAMILY, "address family for nodename not supported"},
+#endif
+{EAI_AGAIN, "temporary failure in name resolution"},
+{EAI_BADFLAGS, "invalid value for ai_flags"},
+{EAI_FAIL, "non-recoverable failure in name resolution"},
+{EAI_FAMILY, "ai_family not supported"},
+{EAI_MEMORY, "memory allocation failure"},
+#ifdef EAI_NODATA
+{EAI_NODATA, "no address associated with nodename"},
+#endif
+{EAI_NONAME, "nodename nor servname provided, or not known"},
+{EAI_SERVICE, "servname not supported for ai_socktype"},
+{EAI_SOCKTYPE, "ai_socktype not supported"},
+{EAI_SYSTEM, "system error returned in errno"},
+{0, NULL},
+};
+
+/*
+ *
+ */
+
+ROKEN_LIB_FUNCTION const char * ROKEN_LIB_CALL
+gai_strerror(int ecode)
+{
+ struct gai_error *g;
+
+ for (g = errors; g->str != NULL; ++g)
+ if (g->code == ecode)
+ return g->str;
+ return "unknown error code in gai_strerror";
+}
diff --git a/third_party/heimdal/lib/roken/get_window_size.c b/third_party/heimdal/lib/roken/get_window_size.c
new file mode 100644
index 0000000..5a4a175
--- /dev/null
+++ b/third_party/heimdal/lib/roken/get_window_size.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#if 0 /* Where were those needed? /confused */
+#ifdef HAVE_SYS_PROC_H
+#include <sys/proc.h>
+#endif
+
+#ifdef HAVE_SYS_TTY_H
+#include <sys/tty.h>
+#endif
+#endif
+
+#ifdef HAVE_TERMIOS_H
+#include <termios.h>
+#endif
+
+#include "roken.h"
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+get_window_size(int fd, int *lines, int *columns)
+{
+ char *s;
+
+#if defined(TIOCGWINSZ)
+ {
+ struct winsize ws;
+ int ret;
+ ret = ioctl(fd, TIOCGWINSZ, &ws);
+ if (ret != -1) {
+ if (lines)
+ *lines = ws.ws_row;
+ if (columns)
+ *columns = ws.ws_col;
+ return 0;
+ }
+ }
+#elif defined(TIOCGSIZE)
+ {
+ struct ttysize ts;
+ int ret;
+ ret = ioctl(fd, TIOCGSIZE, &ts);
+ if (ret != -1) {
+ if (lines)
+ *lines = ts.ws_lines;
+ if (columns)
+ *columns = ts.ts_cols;
+ return 0;
+ }
+ }
+#elif defined(HAVE__SCRSIZE)
+ {
+ int dst[2];
+
+ _scrsize(dst);
+ if (lines)
+ *lines = dst[1];
+ if (columns)
+ *columns = dst[0];
+ return 0;
+ }
+#elif defined(_WIN32)
+ {
+ intptr_t fh = 0;
+ CONSOLE_SCREEN_BUFFER_INFO sb_info;
+
+ fh = _get_osfhandle(fd);
+ if (fh != (intptr_t) INVALID_HANDLE_VALUE &&
+ GetConsoleScreenBufferInfo((HANDLE) fh, &sb_info)) {
+ if (lines)
+ *lines = 1 + sb_info.srWindow.Bottom - sb_info.srWindow.Top;
+ if (columns)
+ *columns = 1 + sb_info.srWindow.Right - sb_info.srWindow.Left;
+
+ return 0;
+ }
+ }
+#endif
+ if (columns) {
+ if ((s = getenv("COLUMNS")))
+ *columns = atoi(s);
+ else
+ return -1;
+ }
+ if (lines) {
+ if ((s = getenv("LINES")))
+ *lines = atoi(s);
+ else
+ return -1;
+ }
+ return 0;
+}
diff --git a/third_party/heimdal/lib/roken/getaddrinfo-test.c b/third_party/heimdal/lib/roken/getaddrinfo-test.c
new file mode 100644
index 0000000..6bdc603
--- /dev/null
+++ b/third_party/heimdal/lib/roken/getaddrinfo-test.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 1999 - 2000 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+#include "getarg.h"
+
+static int flags;
+static int family;
+static int socktype;
+
+static int verbose_counter;
+static int version_flag;
+static int help_flag;
+
+static struct getargs args[] = {
+ {"verbose", 0, arg_counter, &verbose_counter,"verbose", NULL},
+ {"flags", 0, arg_integer, &flags, "flags", NULL},
+ {"family", 0, arg_integer, &family, "family", NULL},
+ {"socktype",0, arg_integer, &socktype, "socktype", NULL},
+ {"version", 0, arg_flag, &version_flag, "print version",NULL},
+ {"help", 0, arg_flag, &help_flag, NULL, NULL}
+};
+
+static void
+usage(int ret)
+{
+ arg_printusage (args,
+ sizeof(args) / sizeof(args[0]),
+ NULL,
+ "[nodename servname...]");
+ exit (ret);
+}
+
+static void
+doit (const char *nodename, const char *servname)
+{
+ struct addrinfo hints;
+ struct addrinfo *res, *r;
+ int ret;
+
+ if (verbose_counter)
+ printf ("(%s,%s)... ", nodename ? nodename : "null", servname);
+
+ memset (&hints, 0, sizeof(hints));
+ hints.ai_flags = flags;
+ hints.ai_family = family;
+ hints.ai_socktype = socktype;
+
+ ret = getaddrinfo (nodename, servname, &hints, &res);
+ if (ret)
+ errx(1, "error: %s\n", gai_strerror(ret));
+
+ if (verbose_counter)
+ printf ("\n");
+
+ for (r = res; r != NULL; r = r->ai_next) {
+ char addrstr[256];
+
+ if (inet_ntop (r->ai_family,
+ socket_get_address (r->ai_addr),
+ addrstr, sizeof(addrstr)) == NULL) {
+ if (verbose_counter)
+ printf ("\tbad address?\n");
+ continue;
+ }
+ if (verbose_counter) {
+ printf ("\tfamily = %d, socktype = %d, protocol = %d, "
+ "address = \"%s\", port = %d",
+ r->ai_family, r->ai_socktype, r->ai_protocol,
+ addrstr,
+ ntohs(socket_get_port (r->ai_addr)));
+ if (r->ai_canonname)
+ printf (", canonname = \"%s\"", r->ai_canonname);
+ printf ("\n");
+ }
+ }
+ freeaddrinfo (res);
+}
+
+int
+main(int argc, char **argv)
+{
+ int optidx = 0;
+ int i;
+
+ setprogname (argv[0]);
+
+ if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv,
+ &optidx))
+ usage (1);
+
+ if (help_flag)
+ usage (0);
+
+ if (version_flag) {
+ fprintf (stderr, "%s from %s-%s\n", getprogname(), PACKAGE, VERSION);
+ return 0;
+ }
+
+ if (rk_SOCK_INIT())
+ errx(1, "Failed to initialize sockets (%s)", strerror(rk_SOCK_ERRNO));
+
+ argc -= optidx;
+ argv += optidx;
+
+ if (argc % 2 != 0)
+ usage (1);
+
+ for (i = 0; i < argc; i += 2) {
+ const char *nodename = argv[i];
+
+ if (strcmp (nodename, "null") == 0)
+ nodename = NULL;
+
+ doit (nodename, argv[i+1]);
+ }
+ rk_SOCK_EXIT();
+ return 0;
+}
diff --git a/third_party/heimdal/lib/roken/getaddrinfo.c b/third_party/heimdal/lib/roken/getaddrinfo.c
new file mode 100644
index 0000000..47affba
--- /dev/null
+++ b/third_party/heimdal/lib/roken/getaddrinfo.c
@@ -0,0 +1,414 @@
+/*
+ * Copyright (c) 1999 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+/*
+ * uses hints->ai_socktype and hints->ai_protocol
+ */
+
+static int
+get_port_protocol_socktype (const char *servname,
+ const struct addrinfo *hints,
+ int *port,
+ int *protocol,
+ int *socktype)
+{
+ struct servent *se;
+ const char *proto_str = NULL;
+
+ *socktype = 0;
+
+ if (hints != NULL && hints->ai_protocol != 0) {
+ struct protoent *protoent = getprotobynumber (hints->ai_protocol);
+
+ if (protoent == NULL)
+ return EAI_SOCKTYPE; /* XXX */
+
+ proto_str = protoent->p_name;
+ *protocol = protoent->p_proto;
+ }
+
+ if (hints != NULL)
+ *socktype = hints->ai_socktype;
+
+ if (*socktype == SOCK_STREAM) {
+ se = getservbyname (servname, proto_str ? proto_str : "tcp");
+ if (proto_str == NULL)
+ *protocol = IPPROTO_TCP;
+ } else if (*socktype == SOCK_DGRAM) {
+ se = getservbyname (servname, proto_str ? proto_str : "udp");
+ if (proto_str == NULL)
+ *protocol = IPPROTO_UDP;
+ } else if (*socktype == 0) {
+ if (proto_str != NULL) {
+ se = getservbyname (servname, proto_str);
+ } else {
+ se = getservbyname (servname, "tcp");
+ *protocol = IPPROTO_TCP;
+ *socktype = SOCK_STREAM;
+ if (se == NULL) {
+ se = getservbyname (servname, "udp");
+ *protocol = IPPROTO_UDP;
+ *socktype = SOCK_DGRAM;
+ }
+ }
+ } else
+ return EAI_SOCKTYPE;
+
+ if (se == NULL) {
+ char *endstr;
+
+ *port = htons(strtol (servname, &endstr, 10));
+ if (servname == endstr)
+ return EAI_NONAME;
+ } else {
+ *port = se->s_port;
+ }
+ return 0;
+}
+
+static int
+add_one (int port, int protocol, int socktype,
+ struct addrinfo ***ptr,
+ int (*func)(struct addrinfo *, void *data, int port),
+ void *data,
+ char *canonname)
+{
+ struct addrinfo *a;
+ int ret;
+
+ a = malloc (sizeof (*a));
+ if (a == NULL)
+ return EAI_MEMORY;
+ memset (a, 0, sizeof(*a));
+ a->ai_flags = 0;
+ a->ai_next = NULL;
+ a->ai_protocol = protocol;
+ a->ai_socktype = socktype;
+ a->ai_canonname = canonname;
+ ret = (*func)(a, data, port);
+ if (ret) {
+ free (a);
+ return ret;
+ }
+ **ptr = a;
+ *ptr = &a->ai_next;
+ return 0;
+}
+
+static int
+const_v4 (struct addrinfo *a, void *data, int port)
+{
+ struct sockaddr_in *sin4;
+ struct in_addr *addr = (struct in_addr *)data;
+
+ a->ai_family = PF_INET;
+ a->ai_addrlen = sizeof(*sin4);
+ a->ai_addr = malloc (sizeof(*sin4));
+ if (a->ai_addr == NULL)
+ return EAI_MEMORY;
+ sin4 = (struct sockaddr_in *)a->ai_addr;
+ memset (sin4, 0, sizeof(*sin4));
+ sin4->sin_family = AF_INET;
+ sin4->sin_port = port;
+ sin4->sin_addr = *addr;
+ return 0;
+}
+
+#ifdef HAVE_IPV6
+static int
+const_v6 (struct addrinfo *a, void *data, int port)
+{
+ struct sockaddr_in6 *sin6;
+ struct in6_addr *addr = (struct in6_addr *)data;
+
+ a->ai_family = PF_INET6;
+ a->ai_addrlen = sizeof(*sin6);
+ a->ai_addr = malloc (sizeof(*sin6));
+ if (a->ai_addr == NULL)
+ return EAI_MEMORY;
+ sin6 = (struct sockaddr_in6 *)a->ai_addr;
+ memset (sin6, 0, sizeof(*sin6));
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = port;
+ sin6->sin6_addr = *addr;
+ return 0;
+}
+#endif
+
+/* this is mostly a hack for some versions of AIX that has a prototype
+ for in6addr_loopback but no actual symbol in libc */
+#if defined(HAVE_IPV6) && !defined(HAVE_IN6ADDR_LOOPBACK) && defined(IN6ADDR_LOOPBACK_INIT)
+#define in6addr_loopback _roken_in6addr_loopback
+struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
+#endif
+
+static int
+get_null (const struct addrinfo *hints,
+ int port, int protocol, int socktype,
+ struct addrinfo **res)
+{
+ struct in_addr v4_addr;
+#ifdef HAVE_IPV6
+ struct in6_addr v6_addr;
+#endif
+ struct addrinfo *first = NULL;
+ struct addrinfo **current = &first;
+ int family = PF_UNSPEC;
+ int ret = EAI_FAMILY;
+
+ if (hints != NULL)
+ family = hints->ai_family;
+
+ if (hints && hints->ai_flags & AI_PASSIVE) {
+ v4_addr.s_addr = INADDR_ANY;
+#ifdef HAVE_IPV6
+ v6_addr = in6addr_any;
+#endif
+ } else {
+ v4_addr.s_addr = htonl(INADDR_LOOPBACK);
+#ifdef HAVE_IPV6
+ v6_addr = in6addr_loopback;
+#endif
+ }
+
+#ifdef HAVE_IPV6
+ if (family == PF_INET6 || family == PF_UNSPEC) {
+ ret = add_one (port, protocol, socktype,
+ &current, const_v6, &v6_addr, NULL);
+ }
+#endif
+ if (family == PF_INET || family == PF_UNSPEC) {
+ ret = add_one (port, protocol, socktype,
+ &current, const_v4, &v4_addr, NULL);
+ }
+ *res = first;
+ return ret;
+}
+
+static int
+add_hostent (int port, int protocol, int socktype,
+ struct addrinfo ***current,
+ int (*func)(struct addrinfo *, void *data, int port),
+ struct hostent *he, int *flags)
+{
+ int ret;
+ char *canonname = NULL;
+ char **h;
+
+ if (*flags & AI_CANONNAME) {
+ struct hostent *he2 = NULL;
+ const char *tmp_canon;
+
+ tmp_canon = hostent_find_fqdn (he);
+ if (strchr (tmp_canon, '.') == NULL) {
+ int error;
+
+ he2 = getipnodebyaddr (he->h_addr_list[0], he->h_length,
+ he->h_addrtype, &error);
+ if (he2 != NULL) {
+ const char *tmp = hostent_find_fqdn (he2);
+
+ if (strchr (tmp, '.') != NULL)
+ tmp_canon = tmp;
+ }
+ }
+
+ canonname = strdup (tmp_canon);
+ if (he2 != NULL)
+ freehostent (he2);
+ if (canonname == NULL)
+ return EAI_MEMORY;
+ }
+
+ for (h = he->h_addr_list; *h != NULL; ++h) {
+ ret = add_one (port, protocol, socktype,
+ current, func, *h, canonname);
+ if (ret)
+ return ret;
+ if (*flags & AI_CANONNAME) {
+ *flags &= ~AI_CANONNAME;
+ canonname = NULL;
+ }
+ }
+ return 0;
+}
+
+static int
+get_number (const char *nodename,
+ const struct addrinfo *hints,
+ int port, int protocol, int socktype,
+ struct addrinfo **res)
+{
+ struct addrinfo *first = NULL;
+ struct addrinfo **current = &first;
+ int family = PF_UNSPEC;
+ int ret;
+
+ if (hints != NULL) {
+ family = hints->ai_family;
+ }
+
+#ifdef HAVE_IPV6
+ if (family == PF_INET6 || family == PF_UNSPEC) {
+ struct in6_addr v6_addr;
+
+ if (inet_pton (PF_INET6, nodename, &v6_addr) == 1) {
+ ret = add_one (port, protocol, socktype,
+ &current, const_v6, &v6_addr, NULL);
+ *res = first;
+ return ret;
+ }
+ }
+#endif
+ if (family == PF_INET || family == PF_UNSPEC) {
+ struct in_addr v4_addr;
+
+ if (inet_pton (PF_INET, nodename, &v4_addr) == 1) {
+ ret = add_one (port, protocol, socktype,
+ &current, const_v4, &v4_addr, NULL);
+ *res = first;
+ return ret;
+ }
+ }
+ return EAI_NONAME;
+}
+
+static int
+get_nodes (const char *nodename,
+ const struct addrinfo *hints,
+ int port, int protocol, int socktype,
+ struct addrinfo **res)
+{
+ struct addrinfo *first = NULL;
+ struct addrinfo **current = &first;
+ int family = PF_UNSPEC;
+ int flags = 0;
+ int ret = EAI_NONAME;
+ int error;
+
+ if (hints != NULL) {
+ family = hints->ai_family;
+ flags = hints->ai_flags;
+ }
+
+#ifdef HAVE_IPV6
+ if (family == PF_INET6 || family == PF_UNSPEC) {
+ struct hostent *he;
+
+ he = getipnodebyname (nodename, PF_INET6, 0, &error);
+
+ if (he != NULL) {
+ ret = add_hostent (port, protocol, socktype,
+ &current, const_v6, he, &flags);
+ freehostent (he);
+ }
+ }
+#endif
+ if (family == PF_INET || family == PF_UNSPEC) {
+ struct hostent *he;
+
+ he = getipnodebyname (nodename, PF_INET, 0, &error);
+
+ if (he != NULL) {
+ ret = add_hostent (port, protocol, socktype,
+ &current, const_v4, he, &flags);
+ freehostent (he);
+ }
+ }
+ *res = first;
+ return ret;
+}
+
+/*
+ * hints:
+ *
+ * struct addrinfo {
+ * int ai_flags;
+ * int ai_family;
+ * int ai_socktype;
+ * int ai_protocol;
+ * ...
+ * };
+ */
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_getaddrinfo(const char *nodename,
+ const char *servname,
+ const struct addrinfo *hints,
+ struct addrinfo **res)
+{
+ int ret;
+ int port = 0;
+ int protocol = 0;
+ int socktype = 0;
+
+ *res = NULL;
+
+ if (servname == NULL && nodename == NULL)
+ return EAI_NONAME;
+
+ if (hints != NULL
+ && hints->ai_family != PF_UNSPEC
+ && hints->ai_family != PF_INET
+#ifdef HAVE_IPV6
+ && hints->ai_family != PF_INET6
+#endif
+ )
+ return EAI_FAMILY;
+
+ if (servname != NULL) {
+ ret = get_port_protocol_socktype (servname, hints,
+ &port, &protocol, &socktype);
+ if (ret)
+ return ret;
+ }
+ if (nodename != NULL) {
+ ret = get_number (nodename, hints, port, protocol, socktype, res);
+ if (ret) {
+ if(hints && hints->ai_flags & AI_NUMERICHOST)
+ ret = EAI_NONAME;
+ else
+ ret = get_nodes (nodename, hints, port, protocol, socktype,
+ res);
+ }
+ } else {
+ ret = get_null (hints, port, protocol, socktype, res);
+ }
+ if (ret)
+ rk_freeaddrinfo(*res);
+ return ret;
+}
diff --git a/third_party/heimdal/lib/roken/getaddrinfo_hostspec.c b/third_party/heimdal/lib/roken/getaddrinfo_hostspec.c
new file mode 100644
index 0000000..4541219
--- /dev/null
+++ b/third_party/heimdal/lib/roken/getaddrinfo_hostspec.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2000 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+/* getaddrinfo via string specifying host and port */
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+roken_getaddrinfo_hostspec2(const char *hostspec,
+ int socktype,
+ int port,
+ struct addrinfo **ai)
+{
+ const char *p;
+ char portstr[NI_MAXSERV];
+ char host[MAXHOSTNAMELEN];
+ struct addrinfo hints;
+ int hostspec_len;
+
+ struct hst {
+ const char *prefix;
+ int socktype;
+ int protocol;
+ int port;
+ } *hstp, hst[] = {
+ { "http://", SOCK_STREAM, IPPROTO_TCP, 80 },
+ { "http/", SOCK_STREAM, IPPROTO_TCP, 80 },
+ { "tcp/", SOCK_STREAM, IPPROTO_TCP, 0 },
+ { "udp/", SOCK_DGRAM, IPPROTO_UDP, 0 },
+ { NULL, 0, 0, 0 }
+ };
+
+ memset(&hints, 0, sizeof(hints));
+
+ hints.ai_socktype = socktype;
+
+ for(hstp = hst; hstp->prefix; hstp++) {
+ if(strncmp(hostspec, hstp->prefix, strlen(hstp->prefix)) == 0) {
+ hints.ai_socktype = hstp->socktype;
+ hints.ai_protocol = hstp->protocol;
+ if(port == 0)
+ port = hstp->port;
+ hostspec += strlen(hstp->prefix);
+ break;
+ }
+ }
+
+ p = strchr (hostspec, ':');
+ if (p != NULL) {
+ char *end;
+
+ port = strtol (p + 1, &end, 0);
+ hostspec_len = p - hostspec;
+ } else {
+ hostspec_len = strlen(hostspec);
+ }
+ snprintf (portstr, sizeof(portstr), "%u", port);
+
+ snprintf (host, sizeof(host), "%.*s", hostspec_len, hostspec);
+ return getaddrinfo (host, portstr, &hints, ai);
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+roken_getaddrinfo_hostspec(const char *hostspec,
+ int port,
+ struct addrinfo **ai)
+{
+ return roken_getaddrinfo_hostspec2(hostspec, 0, port, ai);
+}
diff --git a/third_party/heimdal/lib/roken/getarg.3 b/third_party/heimdal/lib/roken/getarg.3
new file mode 100644
index 0000000..0d01d8f
--- /dev/null
+++ b/third_party/heimdal/lib/roken/getarg.3
@@ -0,0 +1,341 @@
+.\" Copyright (c) 1999 - 2002 Kungliga Tekniska Högskolan
+.\" (Royal Institute of Technology, Stockholm, Sweden).
+.\" 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
+.\"
+.\" $Id$
+.Dd September 24, 1999
+.Dt GETARG 3
+.Os ROKEN
+.Sh NAME
+.Nm getarg ,
+.Nm arg_printusage
+.Nd collect command line options
+.Sh SYNOPSIS
+.In getarg.h
+.Ft int
+.Fn getarg "struct getargs *args" "size_t num_args" "int argc" "char **argv" "int *optind"
+.Ft void
+.Fn arg_printusage "struct getargs *args" "size_t num_args" "const char *progname" "const char *extra_string"
+.Sh DESCRIPTION
+.Fn getarg
+collects any command line options given to a program in an easily used way.
+.Fn arg_printusage
+pretty-prints the available options, with a short help text.
+.Pp
+.Fa args
+is the option specification to use, and it's an array of
+.Fa struct getargs
+elements.
+.Fa num_args
+is the size of
+.Fa args
+(in elements).
+.Fa argc
+and
+.Fa argv
+are the argument count and argument vector to extract option from.
+.Fa optind
+is a pointer to an integer where the index to the last processed
+argument is stored, it must be initialised to the first index (minus
+one) to process (normally 0) before the first call.
+.Pp
+.Fa arg_printusage
+take the same
+.Fa args
+and
+.Fa num_args
+as getarg;
+.Fa progname
+is the name of the program (to be used in the help text), and
+.Fa extra_string
+is a string to print after the actual options to indicate more
+arguments. The usefulness of this function is realised only be people
+who has used programs that has help strings that doesn't match what
+the code does.
+.Pp
+The
+.Fa getargs
+struct has the following elements.
+.Bd -literal
+struct getargs{
+ const char *long_name;
+ char short_name;
+ enum { arg_integer,
+ arg_string,
+ arg_flag,
+ arg_negative_flag,
+ arg_strings,
+ arg_double,
+ arg_collect
+ } type;
+ void *value;
+ const char *help;
+ const char *arg_help;
+};
+.Ed
+.Pp
+.Fa long_name
+is the long name of the option, it can be
+.Dv NULL ,
+if you don't want a long name.
+.Fa short_name
+is the characted to use as short option, it can be zero. If the option
+has a value the
+.Fa value
+field gets filled in with that value interpreted as specified by the
+.Fa type
+field.
+.Fa help
+is a longer help string for the option as a whole, if it's
+.Dv NULL
+the help text for the option is omitted (but it's still displayed in
+the synopsis).
+.Fa arg_help
+is a description of the argument, if
+.Dv NULL
+a default value will be used, depending on the type of the option:
+.Pp
+.Bl -hang -width arg_negative_flag
+.It arg_integer
+the argument is a signed integer, and
+.Fa value
+should point to an
+.Fa int .
+.It Fa arg_string
+the argument is a string, and
+.Fa value
+should point to a
+.Fa char* .
+.It Fa arg_flag
+the argument is a flag, and
+.Fa value
+should point to a
+.Fa int .
+It gets filled in with either zero or one, depending on how the option
+is given, the normal case being one. Note that if the option isn't
+given, the value isn't altered, so it should be initialised to some
+useful default.
+.It Fa arg_negative_flag
+this is the same as
+.Fa arg_flag
+but it reverses the meaning of the flag (a given short option clears
+the flag), and the synopsis of a long option is negated.
+.It Fa arg_strings
+the argument can be given multiple times, and the values are collected
+in an array;
+.Fa value
+should be a pointer to a
+.Fa struct getarg_strings
+structure, which holds a length and a string pointer.
+.It Fa arg_double
+argument is a double precision floating point value, and
+.Fa value
+should point to a
+.Fa double .
+.It Fa arg_collect
+allows more fine-grained control of the option parsing process.
+.Fa value
+should be a pointer to a
+.Fa getarg_collect_info
+structure:
+.Bd -literal
+typedef int (*getarg_collect_func)(int short_opt,
+ int argc,
+ char **argv,
+ int *optind,
+ int *optarg,
+ void *data);
+
+typedef struct getarg_collect_info {
+ getarg_collect_func func;
+ void *data;
+} getarg_collect_info;
+.Ed
+.Pp
+With the
+.Fa func
+member set to a function to call, and
+.Fa data
+to some application specific data. The parameters to the collect function are:
+.Bl -inset
+.It Fa short_flag
+non-zero if this call is via a short option flag, zero otherwise
+.It Fa argc , argv
+the whole argument list
+.It Fa optind
+pointer to the index in argv where the flag is
+.It Fa optarg
+pointer to the index in argv[*optind] where the flag name starts
+.It Fa data
+application specific data
+.El
+.Pp
+You can modify
+.Fa *optind ,
+and
+.Fa *optarg ,
+but to do this correct you (more or less) have to know about the inner
+workings of getarg.
+.Pp
+You can skip parts of arguments by increasing
+.Fa *optarg
+(you could
+implement the
+.Fl z Ns Ar 3
+set of flags from
+.Nm gzip
+with this), or whole argument strings by increasing
+.Fa *optind
+(let's say you want a flag
+.Fl c Ar x y z
+to specify a coordinate); if you also have to set
+.Fa *optarg
+to a sane value.
+.Pp
+The collect function should return one of
+.Dv ARG_ERR_NO_MATCH , ARG_ERR_BAD_ARG , ARG_ERR_NO_ARG, ENOMEM
+on error, zero otherwise.
+.Pp
+For your convenience there is a function,
+.Fn getarg_optarg ,
+that returns the traditional argument string, and you pass it all
+arguments, sans data, that where given to the collection function.
+.Pp
+Don't use this more this unless you absolutely have to.
+.El
+.Pp
+Option parsing is similar to what
+.Xr getopt
+uses. Short options without arguments can be compressed
+.Pf ( Fl xyz
+is the same as
+.Fl x y z ) ,
+and short
+options with arguments take these as either the rest of the
+argv-string or as the next option
+.Pf ( Fl o Ns Ar foo ,
+or
+.Fl o Ar foo ) .
+.Pp
+Long option names are prefixed with -- (double dash), and the value
+with a = (equal),
+.Fl Fl foo= Ns Ar bar .
+Long option flags can either be specified as they are
+.Pf ( Fl Fl help ) ,
+or with an (boolean parsable) option
+.Pf ( Fl Fl help= Ns Ar yes ,
+.Fl Fl help= Ns Ar true ,
+or similar), or they can also be negated
+.Pf ( Fl Fl no-help
+is the same as
+.Fl Fl help= Ns no ) ,
+and if you're really confused you can do it multiple times
+.Pf ( Fl Fl no-no-help= Ns Ar false ,
+or even
+.Fl Fl no-no-help= Ns Ar maybe ) .
+.Sh EXAMPLE
+.Bd -literal
+#include <stdio.h>
+#include <string.h>
+#include <getarg.h>
+
+char *source = "Ouagadougou";
+char *destination;
+int weight;
+int include_catalog = 1;
+int help_flag;
+
+struct getargs args[] = {
+ { "source", 's', arg_string, &source,
+ "source of shippment", "city" },
+ { "destination", 'd', arg_string, &destination,
+ "destination of shippment", "city" },
+ { "weight", 'w', arg_integer, &weight,
+ "weight of shippment", "tons" },
+ { "catalog", 'c', arg_negative_flag, &include_catalog,
+ "include product catalog" },
+ { "help", 'h', arg_flag, &help_flag }
+};
+
+int num_args = sizeof(args) / sizeof(args[0]); /* number of elements in args */
+
+const char *progname = "ship++";
+
+int
+main(int argc, char **argv)
+{
+ int optind = 0;
+ if (getarg(args, num_args, argc, argv, &optind)) {
+ arg_printusage(args, num_args, progname, "stuff...");
+ exit (1);
+ }
+ if (help_flag) {
+ arg_printusage(args, num_args, progname, "stuff...");
+ exit (0);
+ }
+ if (destination == NULL) {
+ fprintf(stderr, "%s: must specify destination\en", progname);
+ exit(1);
+ }
+ if (strcmp(source, destination) == 0) {
+ fprintf(stderr, "%s: destination must be different from source\en");
+ exit(1);
+ }
+ /* include more stuff here ... */
+ exit(2);
+}
+.Ed
+.Pp
+The output help output from this program looks like this:
+.Bd -literal
+$ ship++ --help
+Usage: ship++ [--source=city] [-s city] [--destination=city] [-d city]
+ [--weight=tons] [-w tons] [--no-catalog] [-c] [--help] [-h] stuff...
+-s city, --source=city source of shippment
+-d city, --destination=city destination of shippment
+-w tons, --weight=tons weight of shippment
+-c, --no-catalog include product catalog
+.Ed
+.Sh BUGS
+It should be more flexible, so it would be possible to use other more
+complicated option syntaxes, such as what
+.Xr ps 1 ,
+and
+.Xr tar 1 ,
+uses, or the AFS model where you can skip the flag names as long as
+the options come in the correct order.
+.Pp
+Options with multiple arguments should be handled better.
+.Pp
+Should be integrated with SL.
+.Pp
+It's very confusing that the struct you pass in is called getargS.
+.Sh SEE ALSO
+.Xr getopt 3
diff --git a/third_party/heimdal/lib/roken/getarg.c b/third_party/heimdal/lib/roken/getarg.c
new file mode 100644
index 0000000..76f3c80
--- /dev/null
+++ b/third_party/heimdal/lib/roken/getarg.c
@@ -0,0 +1,607 @@
+/*
+ * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "roken.h"
+#include "getarg.h"
+
+#define ISFLAG(X) ((X).type == arg_flag || (X).type == arg_negative_flag)
+
+static size_t
+print_arg (char *string,
+ size_t len,
+ int mdoc,
+ int longp,
+ struct getargs *arg,
+ char *(i18n)(const char *))
+{
+ const char *s;
+
+ *string = '\0';
+
+ if (ISFLAG(*arg) || (!longp && arg->type == arg_counter))
+ return 0;
+
+ if(mdoc){
+ if(longp)
+ strlcat(string, "= Ns", len);
+ strlcat(string, " Ar ", len);
+ } else {
+ if (longp)
+ strlcat (string, "=", len);
+ else
+ strlcat (string, " ", len);
+ }
+
+ if (arg->arg_help)
+ s = (*i18n)(arg->arg_help);
+ else if (arg->type == arg_integer || arg->type == arg_counter)
+ s = "integer";
+ else if (arg->type == arg_string)
+ s = "string";
+ else if (arg->type == arg_strings)
+ s = "strings";
+ else if (arg->type == arg_double)
+ s = "float";
+ else
+ s = "<undefined>";
+
+ strlcat(string, s, len);
+ return 1 + strlen(s);
+}
+
+static void
+mandoc_template(struct getargs *args,
+ size_t num_args,
+ const char *progname,
+ const char *extra_string,
+ char *(i18n)(const char *))
+{
+ size_t i;
+ char timestr[64], cmd[64];
+ char buf[128];
+ const char *p;
+ time_t t;
+
+ printf(".\\\" Things to fix:\n");
+ printf(".\\\" * correct section, and operating system\n");
+ printf(".\\\" * remove Op from mandatory flags\n");
+ printf(".\\\" * use better macros for arguments (like .Pa for files)\n");
+ printf(".\\\"\n");
+ t = time(NULL);
+ strftime(timestr, sizeof(timestr), "%B %e, %Y", localtime(&t));
+ printf(".Dd %s\n", timestr);
+ p = strrchr(progname, '/');
+ if(p) p++; else p = progname;
+ strlcpy(cmd, p, sizeof(cmd));
+ strupr(cmd);
+
+ printf(".Dt %s SECTION\n", cmd);
+ printf(".Os OPERATING_SYSTEM\n");
+ printf(".Sh NAME\n");
+ printf(".Nm %s\n", p);
+ printf(".Nd in search of a description\n");
+ printf(".Sh SYNOPSIS\n");
+ printf(".Nm\n");
+ for(i = 0; i < num_args; i++){
+ /* we seem to hit a limit on number of arguments if doing
+ short and long flags with arguments -- split on two lines */
+ if(ISFLAG(args[i]) ||
+ args[i].short_name == 0 || args[i].long_name == NULL) {
+ printf(".Op ");
+
+ if(args[i].short_name) {
+ print_arg(buf, sizeof(buf), 1, 0, args + i, i18n);
+ printf("Fl %c%s", args[i].short_name, buf);
+ if(args[i].long_name)
+ printf(" | ");
+ }
+ if(args[i].long_name) {
+ print_arg(buf, sizeof(buf), 1, 1, args + i, i18n);
+ printf("Fl Fl %s%s%s",
+ args[i].type == arg_negative_flag ? "no-" : "",
+ args[i].long_name, buf);
+ }
+ printf("\n");
+ } else {
+ print_arg(buf, sizeof(buf), 1, 0, args + i, i18n);
+ printf(".Oo Fl %c%s \\*(Ba Xo\n", args[i].short_name, buf);
+ print_arg(buf, sizeof(buf), 1, 1, args + i, i18n);
+ printf(".Fl Fl %s%s\n.Xc\n.Oc\n", args[i].long_name, buf);
+ }
+ /*
+ if(args[i].type == arg_strings)
+ fprintf (stderr, "...");
+ */
+ }
+ if (extra_string && *extra_string)
+ printf (".Ar %s\n", extra_string);
+ printf(".Sh DESCRIPTION\n");
+ printf("Supported options:\n");
+ printf(".Bl -tag -width Ds\n");
+ for(i = 0; i < num_args; i++){
+ printf(".It Xo\n");
+ if(args[i].short_name){
+ printf(".Fl %c", args[i].short_name);
+ print_arg(buf, sizeof(buf), 1, 0, args + i, i18n);
+ printf("%s", buf);
+ if(args[i].long_name)
+ printf(" ,");
+ printf("\n");
+ }
+ if(args[i].long_name){
+ printf(".Fl Fl %s%s",
+ args[i].type == arg_negative_flag ? "no-" : "",
+ args[i].long_name);
+ print_arg(buf, sizeof(buf), 1, 1, args + i, i18n);
+ printf("%s\n", buf);
+ }
+ printf(".Xc\n");
+ if(args[i].help)
+ printf("%s\n", args[i].help);
+ /*
+ if(args[i].type == arg_strings)
+ fprintf (stderr, "...");
+ */
+ }
+ printf(".El\n");
+ printf(".\\\".Sh ENVIRONMENT\n");
+ printf(".\\\".Sh FILES\n");
+ printf(".\\\".Sh EXAMPLES\n");
+ printf(".\\\".Sh DIAGNOSTICS\n");
+ printf(".\\\".Sh SEE ALSO\n");
+ printf(".\\\".Sh STANDARDS\n");
+ printf(".\\\".Sh HISTORY\n");
+ printf(".\\\".Sh AUTHORS\n");
+ printf(".\\\".Sh BUGS\n");
+}
+
+static int
+check_column(FILE *f, int col, int len, int columns)
+{
+ if(col + len > columns) {
+ fprintf(f, "\n");
+ col = fprintf(f, " ");
+ }
+ return col;
+}
+
+static char *
+builtin_i18n(const char *str)
+{
+ return rk_UNCONST(str);
+}
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+arg_printusage (struct getargs *args,
+ size_t num_args,
+ const char *progname,
+ const char *extra_string)
+{
+ arg_printusage_i18n(args, num_args, "Usage",
+ progname, extra_string, builtin_i18n);
+}
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+arg_printusage_i18n (struct getargs *args,
+ size_t num_args,
+ const char *usage,
+ const char *progname,
+ const char *extra_string,
+ char *(*i18n)(const char *))
+{
+ size_t i, max_len = 0;
+ char buf[128];
+ int col = 0, columns;
+
+ if (progname == NULL)
+ progname = getprogname();
+
+ if (i18n == NULL)
+ i18n = builtin_i18n;
+
+ if(getenv("GETARGMANDOC")){
+ mandoc_template(args, num_args, progname, extra_string, i18n);
+ return;
+ }
+ if(get_window_size(2, NULL, &columns) == -1)
+ columns = 80;
+ col = 0;
+ col += fprintf (stderr, "%s: %s", usage, progname);
+ buf[0] = '\0';
+ for (i = 0; i < num_args; ++i) {
+ if(args[i].short_name && ISFLAG(args[i])) {
+ char s[2];
+ if(buf[0] == '\0')
+ strlcpy(buf, "[-", sizeof(buf));
+ s[0] = args[i].short_name;
+ s[1] = '\0';
+ strlcat(buf, s, sizeof(buf));
+ }
+ }
+ if(buf[0] != '\0') {
+ strlcat(buf, "]", sizeof(buf));
+ col = check_column(stderr, col, strlen(buf) + 1, columns);
+ col += fprintf(stderr, " %s", buf);
+ }
+
+ for (i = 0; i < num_args; ++i) {
+ size_t len = 0;
+
+ if (args[i].long_name) {
+ buf[0] = '\0';
+ strlcat(buf, "[--", sizeof(buf));
+ len += 2;
+ if(args[i].type == arg_negative_flag) {
+ strlcat(buf, "no-", sizeof(buf));
+ len += 3;
+ }
+ strlcat(buf, args[i].long_name, sizeof(buf));
+ len += strlen(args[i].long_name);
+ len += print_arg(buf + strlen(buf), sizeof(buf) - strlen(buf),
+ 0, 1, &args[i], i18n);
+ strlcat(buf, "]", sizeof(buf));
+ if(args[i].type == arg_strings)
+ strlcat(buf, "...", sizeof(buf));
+ col = check_column(stderr, col, strlen(buf) + 1, columns);
+ col += fprintf(stderr, " %s", buf);
+ }
+ if (args[i].short_name && !ISFLAG(args[i])) {
+ snprintf(buf, sizeof(buf), "[-%c", args[i].short_name);
+ len += 2;
+ len += print_arg(buf + strlen(buf), sizeof(buf) - strlen(buf),
+ 0, 0, &args[i], i18n);
+ strlcat(buf, "]", sizeof(buf));
+ if(args[i].type == arg_strings)
+ strlcat(buf, "...", sizeof(buf));
+ col = check_column(stderr, col, strlen(buf) + 1, columns);
+ col += fprintf(stderr, " %s", buf);
+ }
+ if (args[i].long_name && args[i].short_name)
+ len += 2; /* ", " */
+ max_len = max(max_len, len);
+ }
+ if (extra_string) {
+ check_column(stderr, col, strlen(extra_string) + 1, columns);
+ fprintf (stderr, " %s\n", extra_string);
+ } else
+ fprintf (stderr, "\n");
+ for (i = 0; i < num_args; ++i) {
+ if (args[i].help) {
+ size_t count = 0;
+
+ if (args[i].short_name) {
+ count += fprintf (stderr, "-%c", args[i].short_name);
+ print_arg (buf, sizeof(buf), 0, 0, &args[i], i18n);
+ count += fprintf(stderr, "%s", buf);
+ }
+ if (args[i].short_name && args[i].long_name)
+ count += fprintf (stderr, ", ");
+ if (args[i].long_name) {
+ count += fprintf (stderr, "--");
+ if (args[i].type == arg_negative_flag)
+ count += fprintf (stderr, "no-");
+ count += fprintf (stderr, "%s", args[i].long_name);
+ print_arg (buf, sizeof(buf), 0, 1, &args[i], i18n);
+ count += fprintf(stderr, "%s", buf);
+ }
+ while(count++ <= max_len)
+ putc (' ', stderr);
+ fprintf (stderr, "%s\n", (*i18n)(args[i].help));
+ }
+ }
+}
+
+static int
+add_string(getarg_strings *s, char *value)
+{
+ char **strings;
+
+ strings = realloc(s->strings, (s->num_strings + 1) * sizeof(*s->strings));
+ if (strings == NULL) {
+ free(s->strings);
+ s->strings = NULL;
+ s->num_strings = 0;
+ return ENOMEM;
+ }
+ s->strings = strings;
+ s->strings[s->num_strings] = value;
+ s->num_strings++;
+ return 0;
+}
+
+static int
+arg_match_long(struct getargs *args, size_t num_args,
+ char *argv, int argc, char **rargv, int *goptind)
+{
+ size_t i;
+ char *goptarg = NULL;
+ int negate = 0;
+ int partial_match = 0;
+ struct getargs *partial = NULL;
+ struct getargs *current = NULL;
+ int argv_len;
+ char *p;
+ int p_len;
+
+ argv_len = strlen(argv);
+ p = strchr (argv, '=');
+ if (p != NULL)
+ argv_len = p - argv;
+
+ for (i = 0; i < num_args; ++i) {
+ if(args[i].long_name) {
+ int len = strlen(args[i].long_name);
+ p = argv;
+ p_len = argv_len;
+ negate = 0;
+
+ for (;;) {
+ if (strncmp (args[i].long_name, p, p_len) == 0) {
+ if(p_len == len)
+ current = &args[i];
+ else {
+ ++partial_match;
+ partial = &args[i];
+ }
+ goptarg = p + p_len;
+ } else if (ISFLAG(args[i]) && strncmp (p, "no-", 3) == 0) {
+ negate = !negate;
+ p += 3;
+ p_len -= 3;
+ continue;
+ }
+ break;
+ }
+ if (current)
+ break;
+ }
+ }
+ if (current == NULL) {
+ if (partial_match == 1)
+ current = partial;
+ else
+ return ARG_ERR_NO_MATCH;
+ }
+
+ if(*goptarg == '\0'
+ && !ISFLAG(*current)
+ && current->type != arg_collect
+ && current->type != arg_counter)
+ return ARG_ERR_NO_MATCH;
+ switch(current->type){
+ case arg_integer:
+ {
+ int tmp;
+ if(sscanf(goptarg + 1, "%d", &tmp) != 1)
+ return ARG_ERR_BAD_ARG;
+ *(int*)current->value = tmp;
+ return 0;
+ }
+ case arg_string:
+ {
+ *(char**)current->value = goptarg + 1;
+ return 0;
+ }
+ case arg_strings:
+ {
+ return add_string((getarg_strings*)current->value, goptarg + 1);
+ }
+ case arg_flag:
+ case arg_negative_flag:
+ {
+ int *flag = current->value;
+ if(*goptarg == '\0' ||
+ strcmp(goptarg + 1, "yes") == 0 ||
+ strcmp(goptarg + 1, "true") == 0){
+ *flag = !negate;
+ return 0;
+ } else if (*goptarg && strcmp(goptarg + 1, "maybe") == 0) {
+ *flag = rk_random() & 1;
+ } else {
+ *flag = negate;
+ return 0;
+ }
+ return ARG_ERR_BAD_ARG;
+ }
+ case arg_counter :
+ {
+ int val;
+
+ if (*goptarg == '\0')
+ val = 1;
+ else if(sscanf(goptarg + 1, "%d", &val) != 1)
+ return ARG_ERR_BAD_ARG;
+ *(int *)current->value += val;
+ return 0;
+ }
+ case arg_double:
+ {
+ double tmp;
+ if(sscanf(goptarg + 1, "%lf", &tmp) != 1)
+ return ARG_ERR_BAD_ARG;
+ *(double*)current->value = tmp;
+ return 0;
+ }
+ case arg_collect:{
+ struct getarg_collect_info *c = current->value;
+ int o = argv - rargv[*goptind];
+ return (*c->func)(FALSE, argc, rargv, goptind, &o, c->data);
+ }
+
+ default:
+ abort ();
+ UNREACHABLE(return 0);
+ }
+}
+
+static int
+arg_match_short (struct getargs *args, size_t num_args,
+ char *argv, int argc, char **rargv, int *goptind)
+{
+ size_t j, k;
+
+ for(j = 1; j > 0 && j < strlen(rargv[*goptind]); j++) {
+ for(k = 0; k < num_args; k++) {
+ char *goptarg;
+
+ if(args[k].short_name == 0)
+ continue;
+ if(argv[j] == args[k].short_name) {
+ if(args[k].type == arg_flag) {
+ *(int*)args[k].value = 1;
+ break;
+ }
+ if(args[k].type == arg_negative_flag) {
+ *(int*)args[k].value = 0;
+ break;
+ }
+ if(args[k].type == arg_counter) {
+ ++*(int *)args[k].value;
+ break;
+ }
+ if(args[k].type == arg_collect) {
+ struct getarg_collect_info *c = args[k].value;
+ int a = (int)j;
+
+ if((*c->func)(TRUE, argc, rargv, goptind, &a, c->data))
+ return ARG_ERR_BAD_ARG;
+ j = a;
+ break;
+ }
+
+ if(argv[j + 1])
+ goptarg = &argv[j + 1];
+ else {
+ ++*goptind;
+ goptarg = rargv[*goptind];
+ }
+ if(goptarg == NULL) {
+ --*goptind;
+ return ARG_ERR_NO_ARG;
+ }
+ if(args[k].type == arg_integer) {
+ int tmp;
+ if(sscanf(goptarg, "%d", &tmp) != 1)
+ return ARG_ERR_BAD_ARG;
+ *(int*)args[k].value = tmp;
+ return 0;
+ } else if(args[k].type == arg_string) {
+ *(char**)args[k].value = goptarg;
+ return 0;
+ } else if(args[k].type == arg_strings) {
+ return add_string((getarg_strings*)args[k].value, goptarg);
+ } else if(args[k].type == arg_double) {
+ double tmp;
+ if(sscanf(goptarg, "%lf", &tmp) != 1)
+ return ARG_ERR_BAD_ARG;
+ *(double*)args[k].value = tmp;
+ return 0;
+ }
+ return ARG_ERR_BAD_ARG;
+ }
+ }
+ if (k == num_args)
+ return ARG_ERR_NO_MATCH;
+ }
+ return 0;
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+getarg(struct getargs *args, size_t num_args,
+ int argc, char **argv, int *goptind)
+{
+ int i;
+ int ret = 0;
+
+ rk_random_init();
+ (*goptind)++;
+ for(i = *goptind; i < argc; i++) {
+ if(argv[i][0] != '-')
+ break;
+ if(argv[i][1] == '-'){
+ if(argv[i][2] == 0){
+ i++;
+ break;
+ }
+ ret = arg_match_long (args, num_args, argv[i] + 2,
+ argc, argv, &i);
+ } else {
+ ret = arg_match_short (args, num_args, argv[i],
+ argc, argv, &i);
+ }
+ if(ret)
+ break;
+ }
+ *goptind = i;
+ return ret;
+}
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+free_getarg_strings (getarg_strings *s)
+{
+ free (s->strings);
+}
+
+#if TEST
+int foo_flag = 2;
+int flag1 = 0;
+int flag2 = 0;
+int bar_int;
+char *baz_string;
+
+struct getargs args[] = {
+ { NULL, '1', arg_flag, &flag1, "one", NULL },
+ { NULL, '2', arg_flag, &flag2, "two", NULL },
+ { "foo", 'f', arg_negative_flag, &foo_flag, "foo", NULL },
+ { "bar", 'b', arg_integer, &bar_int, "bar", "seconds"},
+ { "baz", 'x', arg_string, &baz_string, "baz", "name" },
+};
+
+int main(int argc, char **argv)
+{
+ int goptind = 0;
+ while (getarg(args, 5, argc, argv, &goptind))
+ printf("Bad arg: %s\n", argv[goptind]);
+ printf("flag1 = %d\n", flag1);
+ printf("flag2 = %d\n", flag2);
+ printf("foo_flag = %d\n", foo_flag);
+ printf("bar_int = %d\n", bar_int);
+ printf("baz_flag = %s\n", baz_string);
+ arg_printusage (args, 5, argv[0], "nothing here");
+}
+#endif
diff --git a/third_party/heimdal/lib/roken/getarg.h b/third_party/heimdal/lib/roken/getarg.h
new file mode 100644
index 0000000..1065c7c
--- /dev/null
+++ b/third_party/heimdal/lib/roken/getarg.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
+ */
+
+/* $Id$ */
+
+#ifndef __GETARG_H__
+#define __GETARG_H__
+
+#include <stddef.h>
+
+#ifndef ROKEN_LIB_FUNCTION
+#ifdef _WIN32
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL __cdecl
+#else
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL
+#endif
+#endif
+
+struct getargs{
+ const char *long_name;
+ char short_name;
+ enum { arg_integer,
+ arg_string,
+ arg_flag,
+ arg_negative_flag,
+ arg_strings,
+ arg_double,
+ arg_collect,
+ arg_counter
+ } type;
+ void *value;
+ const char *help;
+ const char *arg_help;
+};
+
+enum {
+ ARG_ERR_NO_MATCH = 1,
+ ARG_ERR_BAD_ARG,
+ ARG_ERR_NO_ARG
+};
+
+typedef struct getarg_strings {
+ int num_strings;
+ char **strings;
+} getarg_strings;
+
+typedef int (*getarg_collect_func)(int short_opt,
+ int argc,
+ char **argv,
+ int *goptind,
+ int *goptarg,
+ void *data);
+
+typedef struct getarg_collect_info {
+ getarg_collect_func func;
+ void *data;
+} getarg_collect_info;
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+getarg(struct getargs *args, size_t num_args,
+ int argc, char **argv, int *goptind);
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+arg_printusage (struct getargs *args,
+ size_t num_args,
+ const char *progname,
+ const char *extra_string);
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+arg_printusage_i18n (struct getargs *args,
+ size_t num_args,
+ const char *usage,
+ const char *progname,
+ const char *extra_string,
+ char *(*i18n)(const char *));
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+free_getarg_strings (getarg_strings *);
+
+#endif /* __GETARG_H__ */
diff --git a/third_party/heimdal/lib/roken/getauxval.c b/third_party/heimdal/lib/roken/getauxval.c
new file mode 100644
index 0000000..785b161
--- /dev/null
+++ b/third_party/heimdal/lib/roken/getauxval.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2016 - 2017 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#ifdef HAVE_SYS_AUXV_H
+#include <sys/auxv.h>
+#endif
+
+#if defined(ENABLE_PTHREAD_SUPPORT) && defined(HAVE_PTHREAD_H)
+#include <pthread.h>
+#endif
+
+#include <errno.h>
+
+#include "roken.h"
+#include "getauxval.h"
+
+int rk_injected_auxv = 0; /* shared with issuid() for testing */
+static int has_proc_auxv = 1;
+static int proc_auxv_ret = 0;
+
+#if defined(ENABLE_PTHREAD_SUPPORT) && defined(HAVE_PTHREAD_H)
+pthread_once_t readprocauxv_once = PTHREAD_ONCE_INIT;
+#endif
+
+/*
+ * There's no standard maximum.
+ *
+ * At the time of this writing we observe some 20 or so auxv entries.
+ * If eventually that grows much larger then rk_getprocaux*() will see a
+ * truncated auxv.
+ */
+#define MAX_AUXV_COUNT 128
+static auxv_t auxv[MAX_AUXV_COUNT];
+
+static void
+do_readprocauxv(void)
+{
+ char *p = (void *)auxv;
+ ssize_t bytes = 0;
+ size_t sz = sizeof(auxv) - sizeof(auxv[0]); /* leave terminator */
+ int save_errno = errno;
+ int fd;
+
+ errno = 0;
+ memset(auxv, 0, sizeof(auxv)); /* terminates our copy */
+ if ((fd = open("/proc/self/auxv", O_RDONLY)) == -1) {
+ if (errno == ENOENT)
+ has_proc_auxv = 0;
+ goto out;
+ }
+
+ do {
+ if ((bytes = read(fd, p, sz)) > 0) {
+ sz -= bytes;
+ p += bytes;
+ }
+ } while (sz && ((bytes == -1 && errno == EINTR) || bytes > 0));
+
+out:
+ proc_auxv_ret = errno;
+ if (fd != -1)
+ (void) close(fd);
+ if (sz == 0 && bytes > 0)
+ warnx("/proc/self/auxv has more entries than expected");
+ errno = save_errno;
+ return;
+}
+
+static int
+readprocauxv(void)
+{
+#if defined(ENABLE_PTHREAD_SUPPORT) && defined(HAVE_PTHREAD_H)
+ pthread_once(&readprocauxv_once, do_readprocauxv);
+#else
+ do_readprocauxv();
+#endif
+ return proc_auxv_ret;
+}
+
+/**
+ * Looks up an auxv entry in /proc/self/auxv. Preserves errno.
+ *
+ * @return a pointer to an auxv_t if found, else NULL.
+ */
+ROKEN_LIB_FUNCTION const auxv_t * ROKEN_LIB_CALL
+rk_getauxv(unsigned long type)
+{
+ auxv_t *a;
+
+ if (!has_proc_auxv || type > INT_MAX)
+ return NULL;
+
+ if (readprocauxv() != 0)
+ return NULL;
+
+ for (a = auxv; a - auxv < MAX_AUXV_COUNT; a++) {
+ if ((int)a->a_type == (int)type)
+ return a;
+ if (a->a_type == 0 && a->a_un.a_val == 0)
+ break;
+ }
+ return NULL;
+}
+
+#ifdef HAVE_GETAUXVAL
+static unsigned long
+rk_getprocauxval(unsigned long type)
+{
+ const auxv_t *a = rk_getauxv(type);
+
+ if (a == NULL) {
+ errno = ENOENT;
+ return 0;
+ }
+ return a->a_un.a_val;
+}
+#endif
+
+/**
+ * Like the nearly-standard getauxval(). If the auxval is not found
+ * returns zero and always sets errno to ENOENT. Otherwise if auxval is
+ * found it leaves errno as it was, even if the value is zero.
+ *
+ * @return The value of the ELF auxiliary value for the given type, or
+ * zero and sets errno to ENOENT.
+ */
+ROKEN_LIB_FUNCTION unsigned long ROKEN_LIB_CALL
+rk_getauxval(unsigned long type)
+{
+#ifdef HAVE_GETAUXVAL
+#ifdef GETAUXVAL_SETS_ERRNO
+ if (rk_injected_auxv)
+ return rk_getprocauxval(type);
+ return getauxval(type);
+#else
+ unsigned long ret;
+ unsigned long ret2;
+ static int getauxval_sets_errno = -1;
+ const auxv_t *a;
+ int save_errno = errno;
+
+ if (rk_injected_auxv)
+ return rk_getprocauxval(type);
+
+ errno = 0;
+ ret = getauxval(type);
+ if (ret != 0 || errno == ENOENT || getauxval_sets_errno == 1) {
+ if (ret != 0)
+ errno = save_errno;
+ else if (getauxval_sets_errno > 0 && errno == 0)
+ errno = save_errno;
+ return ret;
+ }
+
+ if (getauxval_sets_errno == 0) {
+ errno = save_errno;
+ a = rk_getauxv(type);
+ if (a == NULL) {
+ errno = ENOENT;
+ return 0;
+ }
+ return a->a_un.a_val;
+ }
+
+ /*
+ * We've called getauxval() and it returned 0, but we don't know if
+ * getauxval() sets errno = ENOENT when entries are not found.
+ *
+ * Attempt to detect whether getauxval() sets errno = ENOENT by
+ * calling it with what should be a bogus type.
+ */
+
+ errno = 0;
+ ret2 = getauxval(~type);
+ if (ret2 == 0 && errno == ENOENT) {
+ getauxval_sets_errno = 1;
+ errno = save_errno;
+ return ret;
+ }
+
+ getauxval_sets_errno = 0;
+ errno = save_errno;
+ if ((a = rk_getauxv(type)) == NULL) {
+ errno = ENOENT;
+ return 0;
+ }
+ return a->a_un.a_val;
+#endif
+#else
+ const auxv_t *a;
+
+ if ((a = rk_getauxv(type)) == NULL) {
+ errno = ENOENT;
+ return 0;
+ }
+ return a->a_un.a_val;
+#endif
+}
+
+/**
+ * *Internal* function for testing by injecting or overwriting an ELF
+ * auxiliary vector entry.
+ *
+ * @return zero on success or ENOSPC if there are too many ELF auxiliary
+ * entries.
+ */
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_injectauxv(auxv_t *e)
+{
+ size_t i;
+ int ret;
+
+ /*
+ * This function is racy, but as an internal function never meant to
+ * be called in a threaded program, we don't care.
+ */
+
+ if ((ret = readprocauxv()) != 0)
+ return ret;
+
+ rk_injected_auxv = 1;
+ for (i = 0; i < MAX_AUXV_COUNT - 1 && auxv[i].a_type != 0; i++) {
+ /* e->a_type == 0 -> truncate auxv, delete all entries */
+ if (auxv[i].a_type == e->a_type || e->a_type == 0)
+ break;
+ }
+ if (i == MAX_AUXV_COUNT - 1)
+ return ENOSPC;
+ auxv[i] = e[0];
+ return 0;
+}
diff --git a/third_party/heimdal/lib/roken/getauxval.h b/third_party/heimdal/lib/roken/getauxval.h
new file mode 100644
index 0000000..3088f0c
--- /dev/null
+++ b/third_party/heimdal/lib/roken/getauxval.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2016 - 2017 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
+ */
+
+#ifndef RK_GETAUXVAL_H
+#define RK_GETAUXVAL_H
+
+#include <config.h>
+
+#ifdef HAVE_SYS_AUXV_H
+#include <sys/auxv.h>
+#endif
+
+#ifdef HAVE_SYS_EXEC_ELF_H
+#include <sys/exec_elf.h>
+#endif
+
+#ifndef HAVE_AUXV_T
+/*
+ * Illumos defines auxv_t per the ABI standards, but all other OSes seem
+ * to use { long; long; } instead, depends on sizeof(long) ==
+ * sizeof(void *), and they do not define an auxv_t.
+ *
+ * sizeof(long) != sizeof(void *) on WIN64, but Windows doesn't have
+ * /proc/self/auxv anyways. Just in case we use uintptr_t.
+ */
+typedef struct rk_auxv {
+ uintptr_t a_type;
+ union {
+ uintptr_t a_val;
+ uintptr_t a_ptr; /* This would be void * */
+ uintptr_t a_fnc; /* This would be void (*)(void) */
+ } a_un;
+} auxv_t;
+#endif
+
+#ifdef __linux__
+/*
+ * Older glibcs have no <sys/auxv.h>, but do nonetheless have an ELF
+ * auxiliary vector, and with the values for these types that appear in
+ * <sys/auxv.h> in later versions.
+ *
+ * Note that Travis-CI still uses Ubuntu 14 for its Linux build
+ * environment, which has such an older glibc version.
+ */
+#ifndef AT_UID
+#define AT_UID 11
+#endif
+#ifndef AT_EUID
+#define AT_EUID 12
+#endif
+#ifndef AT_GID
+#define AT_GID 13
+#endif
+#ifndef AT_EGID
+#define AT_EGID 14
+#endif
+#ifndef AT_SECURE
+#define AT_SECURE 23
+#endif
+#endif
+
+#if __sun
+#if !defined(AT_UID) && defined(AT_SUN_RUID)
+#define AT_UID AT_SUN_RUID
+#endif
+#if !defined(AT_EUID) && defined(AT_SUN_UID)
+#define AT_EUID AT_SUN_UID
+#endif
+#if !defined(AT_GID) && defined(AT_SUN_RGID)
+#define AT_GID AT_SUN_RGID
+#endif
+#if !defined(AT_EGID) && defined(AT_SUN_GID)
+#define AT_EGID AT_SUN_GID
+#endif
+#endif /* __sun */
+
+/* NetBSD calls AT_UID AT_RUID. Everyone else calls it AT_UID. */
+#if defined(AT_EUID) && defined(AT_RUID) && !defined(AT_UID)
+#define AT_UID AT_RUID
+#endif
+#if defined(AT_EGID) && defined(AT_RGID) && !defined(AT_GID)
+#define AT_GID AT_RGID
+#endif
+
+#if defined(AT_EUID) && defined(AT_UID) && !defined(AT_RUID)
+#define AT_RUID AT_UID
+#endif
+#if defined(AT_EGID) && defined(AT_GID) && !defined(AT_RGID)
+#define AT_RGID AT_GID
+#endif
+
+
+/*
+ * There are three different names for the type whose value is the path
+ * to the executable being run by the process.
+ */
+#if defined(AT_EXECFN) && !defined(AT_EXECPATH)
+#define AT_EXECPATH AT_EXECFN
+#endif
+#if defined(AT_EXECFN) && !defined(AT_SUN_EXECNAME)
+#define AT_SUN_EXECNAME AT_EXECFN
+#endif
+#if defined(AT_EXECPATH) && !defined(AT_EXECFN)
+#define AT_EXECFN AT_EXECPATH
+#endif
+#if defined(AT_EXECPATH) && !defined(AT_SUN_EXECNAME)
+#define AT_SUN_EXECNAME AT_EXECPATH
+#endif
+#if defined(AT_SUN_EXECNAME) && !defined(AT_EXECFN)
+#define AT_EXECFN AT_SUN_EXECNAME
+#endif
+#if defined(AT_SUN_EXECNAME) && !defined(AT_EXECPATH)
+#define AT_EXECPATH AT_SUN_EXECNAME
+#endif
+
+/* We need this for part of the getauxval() brokenness detection below */
+#ifdef __GLIBC__
+#ifdef __GLIBC_PREREQ
+#define HAVE_GLIBC_API_VERSION_SUPPORT(maj, min) __GLIBC_PREREQ(maj, min)
+#else
+#define HAVE_GLIBC_API_VERSION_SUPPORT(maj, min) \
+ ((__GLIBC << 16) + GLIBC_MINOR >= ((maj) << 16) + (min))
+#endif
+
+/*
+ * Detect whether getauxval() is broken.
+ *
+ * Do change this check in order to manually test rk_getauxval() for
+ * older glibcs.
+ */
+#if HAVE_GLIBC_API_VERSION_SUPPORT(2, 19)
+#define GETAUXVAL_SETS_ERRNO
+/* #else it's broken */
+#endif
+#endif
+
+ROKEN_LIB_FUNCTION const auxv_t * ROKEN_LIB_CALL
+ rk_getauxv(unsigned long type);
+
+ROKEN_LIB_FUNCTION unsigned long ROKEN_LIB_CALL
+ rk_getauxval(unsigned long);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+ rk_injectauxv(auxv_t *e);
+
+#endif /* RK_GETAUXVAL_H */
diff --git a/third_party/heimdal/lib/roken/getcwd.c b/third_party/heimdal/lib/roken/getcwd.c
new file mode 100644
index 0000000..f8917b2
--- /dev/null
+++ b/third_party/heimdal/lib/roken/getcwd.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#include "roken.h"
+
+ROKEN_LIB_FUNCTION char* ROKEN_LIB_CALL
+getcwd(char *path, size_t size)
+{
+ char xxx[MaxPathLen];
+ char *ret;
+ ret = getwd(xxx);
+ if(ret)
+ strlcpy(path, xxx, size);
+ return ret;
+}
diff --git a/third_party/heimdal/lib/roken/getdtablesize.c b/third_party/heimdal/lib/roken/getdtablesize.c
new file mode 100644
index 0000000..08c0661
--- /dev/null
+++ b/third_party/heimdal/lib/roken/getdtablesize.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 1995-2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#elif defined(HAVE_SYS_TIME_H)
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+#ifdef HAVE_SYS_SYSCTL_H
+#include <sys/sysctl.h>
+#endif
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+getdtablesize(void)
+{
+ int files = -1;
+#if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
+ files = sysconf(_SC_OPEN_MAX);
+#else /* !defined(HAVE_SYSCONF) */
+#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
+ struct rlimit res;
+ if (getrlimit(RLIMIT_NOFILE, &res) == 0)
+ files = res.rlim_cur;
+#else /* !definded(HAVE_GETRLIMIT) */
+#if defined(HAVE_SYSCTL) && defined(CTL_KERN) && defined(KERN_MAXFILES)
+ int mib[2];
+ size_t len;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_MAXFILES;
+ len = sizeof(files);
+ sysctl(&mib, 2, &files, sizeof(files), NULL, 0);
+#endif /* defined(HAVE_SYSCTL) */
+#endif /* !definded(HAVE_GETRLIMIT) */
+#endif /* !defined(HAVE_SYSCONF) */
+
+#ifdef OPEN_MAX
+ if (files < 0)
+ files = OPEN_MAX;
+#endif
+
+#ifdef NOFILE
+ if (files < 0)
+ files = NOFILE;
+#endif
+
+ return files;
+}
diff --git a/third_party/heimdal/lib/roken/getegid.c b/third_party/heimdal/lib/roken/getegid.c
new file mode 100644
index 0000000..663fb1d
--- /dev/null
+++ b/third_party/heimdal/lib/roken/getegid.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+#ifndef HAVE_GETEGID
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+getegid(void)
+{
+ return getgid();
+}
+
+#endif
diff --git a/third_party/heimdal/lib/roken/geteuid.c b/third_party/heimdal/lib/roken/geteuid.c
new file mode 100644
index 0000000..598a739
--- /dev/null
+++ b/third_party/heimdal/lib/roken/geteuid.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+#ifndef HAVE_GETEUID
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+geteuid(void)
+{
+ return getuid();
+}
+
+#endif
diff --git a/third_party/heimdal/lib/roken/getgid.c b/third_party/heimdal/lib/roken/getgid.c
new file mode 100644
index 0000000..b24ceeb
--- /dev/null
+++ b/third_party/heimdal/lib/roken/getgid.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+#include "roken.h"
+
+#ifndef HAVE_GETGID
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+getgid(void)
+{
+ return 17;
+}
+
+#endif
diff --git a/third_party/heimdal/lib/roken/gethostname.c b/third_party/heimdal/lib/roken/gethostname.c
new file mode 100644
index 0000000..8389091
--- /dev/null
+++ b/third_party/heimdal/lib/roken/gethostname.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+#include "roken.h"
+
+#ifndef HAVE_GETHOSTNAME
+
+#ifdef HAVE_SYS_UTSNAME_H
+#include <sys/utsname.h>
+#endif
+
+/*
+ * Return the local host's name in "name", up to "namelen" characters.
+ * "name" will be null-terminated if "namelen" is big enough.
+ * The return code is 0 on success, -1 on failure. (The calling
+ * interface is identical to gethostname(2).)
+ */
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+gethostname(char *name, int namelen)
+{
+#if defined(HAVE_UNAME)
+ {
+ struct utsname utsname;
+ int ret;
+
+ ret = uname (&utsname);
+ if (ret < 0)
+ return ret;
+ strlcpy (name, utsname.nodename, namelen);
+ return 0;
+ }
+#else
+ strlcpy (name, "some.random.host", namelen);
+ return 0;
+#endif
+}
+
+#endif /* GETHOSTNAME */
diff --git a/third_party/heimdal/lib/roken/getifaddrs-test.c b/third_party/heimdal/lib/roken/getifaddrs-test.c
new file mode 100644
index 0000000..252763d
--- /dev/null
+++ b/third_party/heimdal/lib/roken/getifaddrs-test.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2009 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Portions Copyright (c) 2009, Secure Endpoints Inc. 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+#include <err.h>
+#include "getarg.h"
+
+#include "roken.h"
+
+#include <ifaddrs.h>
+
+static int verbose_counter;
+static int version_flag;
+static int help_flag;
+
+static struct getargs args[] = {
+ {"verbose", 0, arg_counter, &verbose_counter,"verbose", NULL},
+ {"version", 0, arg_flag, &version_flag, "print version",NULL},
+ {"help", 0, arg_flag, &help_flag, NULL, NULL}
+};
+
+static void
+usage(int ret)
+{
+ arg_printusage (args,
+ sizeof(args) / sizeof(args[0]),
+ NULL, "");
+ exit (ret);
+}
+
+
+static void
+print_addr(const char *s, struct sockaddr *sa)
+{
+ int i;
+ printf(" %s=%d/", s, sa->sa_family);
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ for(i = 0; i < sa->sa_len - ((long)sa->sa_data - (long)&sa->sa_family); i++)
+ printf("%02x", ((unsigned char*)sa->sa_data)[i]);
+#else
+ for(i = 0; i < sizeof(sa->sa_data); i++)
+ printf("%02x", ((unsigned char*)sa->sa_data)[i]);
+#endif
+ printf("\n");
+}
+
+static void
+print_ifaddrs(struct ifaddrs *x)
+{
+ struct ifaddrs *p;
+
+ for(p = x; p; p = p->ifa_next) {
+ if (verbose_counter) {
+ printf("%s\n", p->ifa_name);
+ printf(" flags=%x\n", p->ifa_flags);
+ if(p->ifa_addr)
+ print_addr("addr", p->ifa_addr);
+ if(p->ifa_dstaddr)
+ print_addr("dstaddr", p->ifa_dstaddr);
+ if(p->ifa_netmask)
+ print_addr("netmask", p->ifa_netmask);
+ printf(" %p\n", p->ifa_data);
+ }
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ struct ifaddrs *addrs = NULL;
+ int ret, optidx = 0;
+
+ setprogname (argv[0]);
+
+ if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv,
+ &optidx))
+ usage (1);
+
+ if (help_flag)
+ usage (0);
+
+ if (version_flag) {
+ fprintf (stderr, "%s from %s-%s\n", getprogname(), PACKAGE, VERSION);
+ return 0;
+ }
+
+ if (rk_SOCK_INIT())
+ errx(1, "Failed to initialize sockets (%s)", strerror(rk_SOCK_ERRNO));
+
+ ret = getifaddrs(&addrs);
+ if (ret != 0)
+ err(1, "getifaddrs");
+
+ if (addrs == NULL)
+ errx(1, "address == NULL");
+
+ print_ifaddrs(addrs);
+
+ /* Check that freeifaddrs doesn't crash */
+ freeifaddrs(addrs);
+
+ rk_SOCK_EXIT();
+
+ return 0;
+}
diff --git a/third_party/heimdal/lib/roken/getifaddrs.c b/third_party/heimdal/lib/roken/getifaddrs.c
new file mode 100644
index 0000000..3d5584a
--- /dev/null
+++ b/third_party/heimdal/lib/roken/getifaddrs.c
@@ -0,0 +1,1314 @@
+/*
+ * Copyright (c) 2000 - 2002, 2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+#include "roken.h"
+
+#ifdef __osf__
+/* hate */
+struct rtentry;
+struct mbuf;
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif /* HAVE_SYS_SOCKIO_H */
+
+#ifdef HAVE_NETINET_IN6_VAR_H
+#include <netinet/in6_var.h>
+#endif /* HAVE_NETINET_IN6_VAR_H */
+
+#include <ifaddrs.h>
+
+#ifdef HAVE_IFADDRS_H
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rk_freeifaddrs(struct ifaddrs *ifp);
+#endif
+
+#ifdef __hpux
+#define lifconf if_laddrconf
+#define lifc_len iflc_len
+#define lifc_buf iflc_buf
+#define lifc_req iflc_req
+
+#define lifreq if_laddrreq
+#define lifr_addr iflr_addr
+#define lifr_name iflr_name
+#define lifr_dstaddr iflr_dstaddr
+#define lifr_broadaddr iflr_broadaddr
+#define lifr_flags iflr_flags
+#define lifr_index iflr_index
+#endif
+
+#ifdef AF_NETLINK
+
+/*
+ * The linux - AF_NETLINK version of getifaddrs - from Usagi.
+ * Linux does not return v6 addresses from SIOCGIFCONF.
+ */
+
+/* $USAGI: ifaddrs.c,v 1.18 2002/03/06 01:50:46 yoshfuji Exp $ */
+
+/**************************************************************************
+ * ifaddrs.c
+ * Copyright (C)2000 Hideaki YOSHIFUJI, 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 author 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 AUTHOR 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 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.
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <time.h>
+#include <malloc.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <asm/types.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include <netpacket/packet.h>
+#include <net/ethernet.h> /* the L2 protocols */
+#include <sys/uio.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <ifaddrs.h>
+#include <netinet/in.h>
+
+#define __set_errno(e) (errno = (e))
+#define __close(fd) (close(fd))
+#undef ifa_broadaddr
+#define ifa_broadaddr ifa_dstaddr
+#define IFA_NETMASK
+
+/* ====================================================================== */
+struct nlmsg_list{
+ struct nlmsg_list *nlm_next;
+ struct nlmsghdr *nlh;
+ int size;
+ time_t seq;
+};
+
+struct rtmaddr_ifamap {
+ void *address;
+ void *local;
+#ifdef IFA_NETMASK
+ void *netmask;
+#endif
+ void *broadcast;
+#ifdef HAVE_IFADDRS_IFA_ANYCAST
+ void *anycast;
+#endif
+ int address_len;
+ int local_len;
+#ifdef IFA_NETMASK
+ int netmask_len;
+#endif
+ int broadcast_len;
+#ifdef HAVE_IFADDRS_IFA_ANYCAST
+ int anycast_len;
+#endif
+};
+
+/* ====================================================================== */
+static size_t
+ifa_sa_len(sa_family_t family, int len)
+{
+ size_t size;
+ switch(family){
+ case AF_INET:
+ size = sizeof(struct sockaddr_in);
+ break;
+ case AF_INET6:
+ size = sizeof(struct sockaddr_in6);
+ break;
+ case AF_PACKET:
+ size = (size_t)(((struct sockaddr_ll *)NULL)->sll_addr) + len;
+ if (size < sizeof(struct sockaddr_ll))
+ size = sizeof(struct sockaddr_ll);
+ break;
+ default:
+ size = (size_t)(((struct sockaddr *)NULL)->sa_data) + len;
+ if (size < sizeof(struct sockaddr))
+ size = sizeof(struct sockaddr);
+ break;
+ }
+ return size;
+}
+
+static void
+ifa_make_sockaddr(sa_family_t family,
+ struct sockaddr *sa,
+ void *p, size_t len,
+ uint32_t scope, uint32_t scopeid)
+{
+ if (sa == NULL) return;
+ switch(family){
+ case AF_INET:
+ memcpy(&((struct sockaddr_in*)sa)->sin_addr, (char *)p, len);
+ break;
+ case AF_INET6:
+ memcpy(&((struct sockaddr_in6*)sa)->sin6_addr, (char *)p, len);
+ if (IN6_IS_ADDR_LINKLOCAL(p) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(p)){
+ ((struct sockaddr_in6*)sa)->sin6_scope_id = scopeid;
+ }
+ break;
+ case AF_PACKET:
+ memcpy(((struct sockaddr_ll*)sa)->sll_addr, (char *)p, len);
+ ((struct sockaddr_ll*)sa)->sll_halen = len;
+ break;
+ default:
+ memcpy(sa->sa_data, p, len); /*XXX*/
+ break;
+ }
+ sa->sa_family = family;
+#ifdef HAVE_SOCKADDR_SA_LEN
+ sa->sa_len = ifa_sa_len(family, len);
+#endif
+}
+
+#ifndef IFA_NETMASK
+static struct sockaddr *
+ifa_make_sockaddr_mask(sa_family_t family,
+ struct sockaddr *sa,
+ uint32_t prefixlen)
+{
+ int i;
+ char *p = NULL, c;
+ uint32_t max_prefixlen = 0;
+
+ if (sa == NULL) return NULL;
+ switch(family){
+ case AF_INET:
+ memset(&((struct sockaddr_in*)sa)->sin_addr, 0, sizeof(((struct sockaddr_in*)sa)->sin_addr));
+ p = (char *)&((struct sockaddr_in*)sa)->sin_addr;
+ max_prefixlen = 32;
+ break;
+ case AF_INET6:
+ memset(&((struct sockaddr_in6*)sa)->sin6_addr, 0, sizeof(((struct sockaddr_in6*)sa)->sin6_addr));
+ p = (char *)&((struct sockaddr_in6*)sa)->sin6_addr;
+#if 0 /* XXX: fill scope-id? */
+ if (IN6_IS_ADDR_LINKLOCAL(p) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(p)){
+ ((struct sockaddr_in6*)sa)->sin6_scope_id = scopeid;
+ }
+#endif
+ max_prefixlen = 128;
+ break;
+ default:
+ return NULL;
+ }
+ sa->sa_family = family;
+#ifdef HAVE_SOCKADDR_SA_LEN
+ sa->sa_len = ifa_sa_len(family, len);
+#endif
+ if (p){
+ if (prefixlen > max_prefixlen)
+ prefixlen = max_prefixlen;
+ for (i=0; i<(prefixlen / 8); i++)
+ *p++ = 0xff;
+ c = 0xff;
+ c <<= (8 - (prefixlen % 8));
+ *p = c;
+ }
+ return sa;
+}
+#endif
+
+/* ====================================================================== */
+static int
+nl_sendreq(int sd, int request, int flags, int *seq)
+{
+ char reqbuf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
+ NLMSG_ALIGN(sizeof(struct rtgenmsg))];
+ struct sockaddr_nl nladdr;
+ struct nlmsghdr *req_hdr;
+ struct rtgenmsg *req_msg;
+ time_t t = time(NULL);
+
+ if (seq) *seq = t;
+ memset(&reqbuf, 0, sizeof(reqbuf));
+ req_hdr = (struct nlmsghdr *)reqbuf;
+ req_msg = (struct rtgenmsg *)NLMSG_DATA(req_hdr);
+ req_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*req_msg));
+ req_hdr->nlmsg_type = request;
+ req_hdr->nlmsg_flags = flags | NLM_F_REQUEST;
+ req_hdr->nlmsg_pid = 0;
+ req_hdr->nlmsg_seq = t;
+ req_msg->rtgen_family = AF_UNSPEC;
+ memset(&nladdr, 0, sizeof(nladdr));
+ nladdr.nl_family = AF_NETLINK;
+ return (sendto(sd, (void *)req_hdr, req_hdr->nlmsg_len, 0,
+ (struct sockaddr *)&nladdr, sizeof(nladdr)));
+}
+
+static int
+nl_recvmsg(int sd, int request, int seq,
+ void *buf, size_t buflen,
+ int *flags)
+{
+ struct msghdr msg;
+ struct iovec iov = { buf, buflen };
+ struct sockaddr_nl nladdr;
+ int read_len;
+
+ for (;;){
+ msg.msg_name = (void *)&nladdr;
+ msg.msg_namelen = sizeof(nladdr);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_flags = 0;
+ read_len = recvmsg(sd, &msg, 0);
+ if ((read_len < 0 && errno == EINTR) || (msg.msg_flags & MSG_TRUNC))
+ continue;
+ if (flags) *flags = msg.msg_flags;
+ break;
+ }
+ return read_len;
+}
+
+static int
+nl_getmsg(int sd, int request, int seq,
+ struct nlmsghdr **nlhp,
+ int *done)
+{
+ struct nlmsghdr *nh;
+ size_t bufsize = 65536, lastbufsize = 0;
+ void *buff = NULL;
+ int result = 0, read_size;
+ int msg_flags;
+ pid_t pid = getpid();
+ for (;;){
+ void *newbuff = realloc(buff, bufsize);
+ if (newbuff == NULL || bufsize < lastbufsize) {
+ result = -1;
+ break;
+ }
+ buff = newbuff;
+ result = read_size = nl_recvmsg(sd, request, seq, buff, bufsize, &msg_flags);
+ if (read_size < 0 || (msg_flags & MSG_TRUNC)){
+ lastbufsize = bufsize;
+ bufsize *= 2;
+ continue;
+ }
+ if (read_size == 0) break;
+ nh = (struct nlmsghdr *)buff;
+ for (nh = (struct nlmsghdr *)buff;
+ NLMSG_OK(nh, read_size);
+ nh = (struct nlmsghdr *)NLMSG_NEXT(nh, read_size)){
+ if (nh->nlmsg_pid != pid ||
+ nh->nlmsg_seq != seq)
+ continue;
+ if (nh->nlmsg_type == NLMSG_DONE){
+ (*done)++;
+ break; /* ok */
+ }
+ if (nh->nlmsg_type == NLMSG_ERROR){
+ struct nlmsgerr *nlerr = (struct nlmsgerr *)NLMSG_DATA(nh);
+ result = -1;
+ if (nh->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
+ __set_errno(EIO);
+ else
+ __set_errno(-nlerr->error);
+ break;
+ }
+ }
+ break;
+ }
+ if (result < 0)
+ if (buff){
+ int saved_errno = errno;
+ free(buff);
+ __set_errno(saved_errno);
+ }
+ *nlhp = (struct nlmsghdr *)buff;
+ return result;
+}
+
+static int
+nl_getlist(int sd, int seq,
+ int request,
+ struct nlmsg_list **nlm_list,
+ struct nlmsg_list **nlm_end)
+{
+ struct nlmsghdr *nlh = NULL;
+ int status;
+ int done = 0;
+ int tries = 3;
+
+ try_again:
+ status = nl_sendreq(sd, request, NLM_F_ROOT|NLM_F_MATCH, &seq);
+ if (status < 0)
+ return status;
+ if (seq == 0)
+ seq = (int)time(NULL);
+ while(!done){
+ struct pollfd pfd;
+
+ pfd.fd = sd;
+ pfd.events = POLLIN | POLLPRI;
+ pfd.revents = 0;
+ status = poll(&pfd, 1, 1000);
+ if (status < 0)
+ return status;
+ else if (status == 0) {
+ seq++;
+ if (tries-- > 0)
+ goto try_again;
+ return -1;
+ }
+
+ status = nl_getmsg(sd, request, seq, &nlh, &done);
+ if (status < 0)
+ return status;
+ if (nlh){
+ struct nlmsg_list *nlm_next = (struct nlmsg_list *)malloc(sizeof(struct nlmsg_list));
+ if (nlm_next == NULL){
+ int saved_errno = errno;
+ free(nlh);
+ __set_errno(saved_errno);
+ status = -1;
+ } else {
+ nlm_next->nlm_next = NULL;
+ nlm_next->nlh = (struct nlmsghdr *)nlh;
+ nlm_next->size = status;
+ nlm_next->seq = seq;
+ if (*nlm_list == NULL){
+ *nlm_list = nlm_next;
+ *nlm_end = nlm_next;
+ } else {
+ (*nlm_end)->nlm_next = nlm_next;
+ *nlm_end = nlm_next;
+ }
+ }
+ }
+ }
+ return status >= 0 ? seq : status;
+}
+
+/* ---------------------------------------------------------------------- */
+static void
+free_nlmsglist(struct nlmsg_list *nlm0)
+{
+ struct nlmsg_list *nlm, *nlm_next;
+ int saved_errno;
+ if (!nlm0)
+ return;
+ saved_errno = errno;
+ for (nlm=nlm0; nlm; nlm=nlm_next){
+ if (nlm->nlh)
+ free(nlm->nlh);
+ nlm_next=nlm->nlm_next;
+ free(nlm);
+ }
+ __set_errno(saved_errno);
+}
+
+static void
+free_data(void *data, void *ifdata)
+{
+ int saved_errno = errno;
+ if (data != NULL) free(data);
+ if (ifdata != NULL) free(ifdata);
+ __set_errno(saved_errno);
+}
+
+/* ---------------------------------------------------------------------- */
+static void
+nl_close(int sd)
+{
+ int saved_errno = errno;
+ if (sd >= 0) __close(sd);
+ __set_errno(saved_errno);
+}
+
+/* ---------------------------------------------------------------------- */
+static int
+nl_open(void)
+{
+ struct sockaddr_nl nladdr;
+ int sd;
+
+ sd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sd < 0) return -1;
+ memset(&nladdr, 0, sizeof(nladdr));
+ nladdr.nl_family = AF_NETLINK;
+ if (bind(sd, (struct sockaddr*)&nladdr, sizeof(nladdr)) < 0){
+ nl_close(sd);
+ return -1;
+ }
+ return sd;
+}
+
+/* ====================================================================== */
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_getifaddrs(struct ifaddrs **ifap)
+{
+ int sd;
+ struct nlmsg_list *nlmsg_list, *nlmsg_end, *nlm;
+ /* - - - - - - - - - - - - - - - */
+ int icnt;
+ size_t dlen, xlen, nlen;
+ uint32_t max_ifindex = 0;
+
+ pid_t pid = getpid();
+ int seq;
+ int result;
+ int build ; /* 0 or 1 */
+
+/* ---------------------------------- */
+ /* initialize */
+ icnt = dlen = xlen = nlen = 0;
+ nlmsg_list = nlmsg_end = NULL;
+
+ if (ifap)
+ *ifap = NULL;
+
+/* ---------------------------------- */
+ /* open socket and bind */
+ sd = nl_open();
+ if (sd < 0)
+ return -1;
+
+/* ---------------------------------- */
+ /* gather info */
+ if ((seq = nl_getlist(sd, 0, RTM_GETLINK,
+ &nlmsg_list, &nlmsg_end)) < 0){
+ free_nlmsglist(nlmsg_list);
+ nl_close(sd);
+ return -1;
+ }
+ if ((seq = nl_getlist(sd, seq+1, RTM_GETADDR,
+ &nlmsg_list, &nlmsg_end)) < 0){
+ free_nlmsglist(nlmsg_list);
+ nl_close(sd);
+ return -1;
+ }
+
+/* ---------------------------------- */
+ /* Estimate size of result buffer and fill it */
+ for (build=0; build<=1; build++){
+ struct ifaddrs *ifl = NULL, *ifa = NULL;
+ struct nlmsghdr *nlh, *nlh0;
+ char *data = NULL, *xdata = NULL;
+ void *ifdata = NULL;
+ char *ifname = NULL, **iflist = NULL;
+ uint16_t *ifflist = NULL;
+ struct rtmaddr_ifamap ifamap;
+
+ if (build){
+ data = calloc(1,
+ NLMSG_ALIGN(sizeof(struct ifaddrs[icnt]))
+ + dlen + xlen + nlen);
+ ifa = (struct ifaddrs *)data;
+ ifdata = calloc(1,
+ NLMSG_ALIGN(sizeof(char *[max_ifindex+1]))
+ + NLMSG_ALIGN(sizeof(uint16_t [max_ifindex+1])));
+ if (ifap != NULL)
+ *ifap = (ifdata != NULL) ? ifa : NULL;
+ else{
+ free_data(data, ifdata);
+ result = 0;
+ break;
+ }
+ if (data == NULL || ifdata == NULL){
+ free_data(data, ifdata);
+ result = -1;
+ break;
+ }
+ ifl = NULL;
+ data += NLMSG_ALIGN(sizeof(struct ifaddrs)) * icnt;
+ xdata = data + dlen;
+ ifname = xdata + xlen;
+ iflist = ifdata;
+ ifflist = (uint16_t *)(((char *)iflist) + NLMSG_ALIGN(sizeof(char *[max_ifindex+1])));
+ }
+
+ for (nlm=nlmsg_list; nlm; nlm=nlm->nlm_next){
+ int nlmlen = nlm->size;
+ if (!(nlh0 = nlm->nlh))
+ continue;
+ for (nlh = nlh0;
+ NLMSG_OK(nlh, nlmlen);
+ nlh=NLMSG_NEXT(nlh,nlmlen)){
+ struct ifinfomsg *ifim = NULL;
+ struct ifaddrmsg *ifam = NULL;
+ struct rtattr *rta;
+
+ size_t nlm_struct_size = 0;
+ sa_family_t nlm_family = 0;
+ uint32_t nlm_scope = 0, nlm_index = 0;
+ size_t sockaddr_size = 0;
+ uint32_t nlm_prefixlen = 0;
+ size_t rtasize;
+
+ memset(&ifamap, 0, sizeof(ifamap));
+
+ /* check if the message is what we want */
+ if (nlh->nlmsg_pid != pid ||
+ nlh->nlmsg_seq != nlm->seq)
+ continue;
+ if (nlh->nlmsg_type == NLMSG_DONE){
+ break; /* ok */
+ }
+ switch (nlh->nlmsg_type){
+ case RTM_NEWLINK:
+ ifim = (struct ifinfomsg *)NLMSG_DATA(nlh);
+ nlm_struct_size = sizeof(*ifim);
+ nlm_family = ifim->ifi_family;
+ nlm_scope = 0;
+ nlm_index = ifim->ifi_index;
+ nlm_prefixlen = 0;
+ if (build)
+ ifflist[nlm_index] = ifa->ifa_flags = ifim->ifi_flags;
+ break;
+ case RTM_NEWADDR:
+ ifam = (struct ifaddrmsg *)NLMSG_DATA(nlh);
+ nlm_struct_size = sizeof(*ifam);
+ nlm_family = ifam->ifa_family;
+ nlm_scope = ifam->ifa_scope;
+ nlm_index = ifam->ifa_index;
+ nlm_prefixlen = ifam->ifa_prefixlen;
+ if (build)
+ ifa->ifa_flags = ifflist[nlm_index];
+ break;
+ default:
+ continue;
+ }
+
+ if (!build){
+ if (max_ifindex < nlm_index)
+ max_ifindex = nlm_index;
+ } else {
+ if (ifl != NULL)
+ ifl->ifa_next = ifa;
+ }
+
+ rtasize = NLMSG_PAYLOAD(nlh, nlmlen) - NLMSG_ALIGN(nlm_struct_size);
+ for (rta = (struct rtattr *)(((char *)NLMSG_DATA(nlh)) + NLMSG_ALIGN(nlm_struct_size));
+ RTA_OK(rta, rtasize);
+ rta = RTA_NEXT(rta, rtasize)){
+ struct sockaddr **sap = NULL;
+ void *rtadata = RTA_DATA(rta);
+ size_t rtapayload = RTA_PAYLOAD(rta);
+ socklen_t sa_len;
+
+ switch(nlh->nlmsg_type){
+ case RTM_NEWLINK:
+ switch(rta->rta_type){
+ case IFLA_ADDRESS:
+ case IFLA_BROADCAST:
+ if (build){
+ sap = (rta->rta_type == IFLA_ADDRESS) ? &ifa->ifa_addr : &ifa->ifa_broadaddr;
+ *sap = (struct sockaddr *)data;
+ }
+ sa_len = ifa_sa_len(AF_PACKET, rtapayload);
+ if (rta->rta_type == IFLA_ADDRESS)
+ sockaddr_size = NLMSG_ALIGN(sa_len);
+ if (!build){
+ dlen += NLMSG_ALIGN(sa_len);
+ } else {
+ memset(*sap, 0, sa_len);
+ ifa_make_sockaddr(AF_PACKET, *sap, rtadata,rtapayload, 0,0);
+ ((struct sockaddr_ll *)*sap)->sll_ifindex = nlm_index;
+ ((struct sockaddr_ll *)*sap)->sll_hatype = ifim->ifi_type;
+ data += NLMSG_ALIGN(sa_len);
+ }
+ break;
+ case IFLA_IFNAME:/* Name of Interface */
+ if (!build)
+ nlen += NLMSG_ALIGN(rtapayload + 1);
+ else{
+ ifa->ifa_name = ifname;
+ if (iflist[nlm_index] == NULL)
+ iflist[nlm_index] = ifa->ifa_name;
+ strncpy(ifa->ifa_name, rtadata, rtapayload);
+ ifa->ifa_name[rtapayload] = '\0';
+ ifname += NLMSG_ALIGN(rtapayload + 1);
+ }
+ break;
+ case IFLA_STATS:/* Statistics of Interface */
+ if (!build)
+ xlen += NLMSG_ALIGN(rtapayload);
+ else{
+ ifa->ifa_data = xdata;
+ memcpy(ifa->ifa_data, rtadata, rtapayload);
+ xdata += NLMSG_ALIGN(rtapayload);
+ }
+ break;
+ case IFLA_UNSPEC:
+ break;
+ case IFLA_MTU:
+ break;
+ case IFLA_LINK:
+ break;
+ case IFLA_QDISC:
+ break;
+ default:
+ break;
+ }
+ break;
+ case RTM_NEWADDR:
+ if (nlm_family == AF_PACKET) break;
+ switch(rta->rta_type){
+ case IFA_ADDRESS:
+ ifamap.address = rtadata;
+ ifamap.address_len = rtapayload;
+ break;
+ case IFA_LOCAL:
+ ifamap.local = rtadata;
+ ifamap.local_len = rtapayload;
+ break;
+ case IFA_BROADCAST:
+ ifamap.broadcast = rtadata;
+ ifamap.broadcast_len = rtapayload;
+ break;
+#ifdef HAVE_IFADDRS_IFA_ANYCAST
+ case IFA_ANYCAST:
+ ifamap.anycast = rtadata;
+ ifamap.anycast_len = rtapayload;
+ break;
+#endif
+ case IFA_LABEL:
+ if (!build)
+ nlen += NLMSG_ALIGN(rtapayload + 1);
+ else{
+ ifa->ifa_name = ifname;
+ if (iflist[nlm_index] == NULL)
+ iflist[nlm_index] = ifname;
+ strncpy(ifa->ifa_name, rtadata, rtapayload);
+ ifa->ifa_name[rtapayload] = '\0';
+ ifname += NLMSG_ALIGN(rtapayload + 1);
+ }
+ break;
+ case IFA_UNSPEC:
+ break;
+ case IFA_CACHEINFO:
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ if (nlh->nlmsg_type == RTM_NEWADDR &&
+ nlm_family != AF_PACKET) {
+ if (!ifamap.local) {
+ ifamap.local = ifamap.address;
+ ifamap.local_len = ifamap.address_len;
+ }
+ if (!ifamap.address) {
+ ifamap.address = ifamap.local;
+ ifamap.address_len = ifamap.local_len;
+ }
+ if (ifamap.address_len != ifamap.local_len ||
+ (ifamap.address != NULL &&
+ memcmp(ifamap.address, ifamap.local, ifamap.address_len) != 0)) {
+ /* p2p; address is peer and local is ours */
+ ifamap.broadcast = ifamap.address;
+ ifamap.broadcast_len = ifamap.address_len;
+ ifamap.address = ifamap.local;
+ ifamap.address_len = ifamap.local_len;
+ }
+ if (ifamap.address) {
+#ifndef IFA_NETMASK
+ sockaddr_size = NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.address_len));
+#endif
+ if (!build)
+ dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.address_len));
+ else {
+ ifa->ifa_addr = (struct sockaddr *)data;
+ ifa_make_sockaddr(nlm_family, ifa->ifa_addr, ifamap.address, ifamap.address_len,
+ nlm_scope, nlm_index);
+ data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.address_len));
+ }
+ }
+#ifdef IFA_NETMASK
+ if (ifamap.netmask) {
+ if (!build)
+ dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.netmask_len));
+ else {
+ ifa->ifa_netmask = (struct sockaddr *)data;
+ ifa_make_sockaddr(nlm_family, ifa->ifa_netmask, ifamap.netmask, ifamap.netmask_len,
+ nlm_scope, nlm_index);
+ data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.netmask_len));
+ }
+ }
+#endif
+ if (ifamap.broadcast) {
+ if (!build)
+ dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.broadcast_len));
+ else {
+ ifa->ifa_broadaddr = (struct sockaddr *)data;
+ ifa_make_sockaddr(nlm_family, ifa->ifa_broadaddr, ifamap.broadcast, ifamap.broadcast_len,
+ nlm_scope, nlm_index);
+ data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.broadcast_len));
+ }
+ }
+#ifdef HAVE_IFADDRS_IFA_ANYCAST
+ if (ifamap.anycast) {
+ if (!build)
+ dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.anycast_len));
+ else {
+ ifa->ifa_anycast = (struct sockaddr *)data;
+ ifa_make_sockaddr(nlm_family, ifa->ifa_anyaddr, ifamap.anycast, ifamap.anycast_len,
+ nlm_scope, nlm_index);
+ data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.anycast_len));
+ }
+ }
+#endif
+ }
+ if (!build){
+#ifndef IFA_NETMASK
+ dlen += sockaddr_size;
+#endif
+ icnt++;
+ } else {
+ if (ifa->ifa_name == NULL)
+ ifa->ifa_name = iflist[nlm_index];
+#ifndef IFA_NETMASK
+ if (ifa->ifa_addr &&
+ ifa->ifa_addr->sa_family != AF_UNSPEC &&
+ ifa->ifa_addr->sa_family != AF_PACKET){
+ ifa->ifa_netmask = (struct sockaddr *)data;
+ ifa_make_sockaddr_mask(ifa->ifa_addr->sa_family, ifa->ifa_netmask, nlm_prefixlen);
+ }
+ data += sockaddr_size;
+#endif
+ ifl = ifa++;
+ }
+ }
+ }
+ if (!build){
+ if (icnt == 0 && (dlen + nlen + xlen == 0)){
+ if (ifap != NULL)
+ *ifap = NULL;
+ break; /* cannot found any addresses */
+ }
+ }
+ else
+ free_data(NULL, ifdata);
+ }
+
+/* ---------------------------------- */
+ /* Finalize */
+ free_nlmsglist(nlmsg_list);
+ nl_close(sd);
+ return 0;
+}
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rk_freeifaddrs(struct ifaddrs *ifp)
+{
+ /* AF_NETLINK method uses a single allocation for all interfaces */
+ free(ifp);
+}
+
+#else /* !AF_NETLINK */
+
+/*
+ * The generic SIOCGIFCONF version.
+ */
+
+static int
+getifaddrs2(struct ifaddrs **ifap,
+ int af, int siocgifconf, int siocgifflags,
+ size_t ifreq_sz)
+{
+ int ret;
+ int fd;
+ size_t buf_size;
+ char *buf;
+ struct ifconf ifconf;
+ char *p;
+ size_t sz;
+ struct sockaddr sa_zero;
+ struct ifreq *ifr;
+ struct ifaddrs *start = NULL, **end = &start;
+
+ buf = NULL;
+
+ memset (&sa_zero, 0, sizeof(sa_zero));
+ fd = socket(af, SOCK_DGRAM, 0);
+ if (fd < 0)
+ return -1;
+
+ buf_size = 8192;
+ for (;;) {
+ buf = calloc(1, buf_size);
+ if (buf == NULL) {
+ ret = ENOMEM;
+ goto error_out;
+ }
+ ifconf.ifc_len = buf_size;
+ ifconf.ifc_buf = buf;
+
+ /*
+ * Solaris returns EINVAL when the buffer is too small.
+ */
+ if (ioctl (fd, siocgifconf, &ifconf) < 0 && errno != EINVAL) {
+ ret = errno;
+ goto error_out;
+ }
+ /*
+ * Can the difference between a full and a overfull buf
+ * be determined?
+ */
+
+ if (ifconf.ifc_len < buf_size)
+ break;
+ free (buf);
+ buf_size *= 2;
+ }
+
+ for (p = ifconf.ifc_buf;
+ p < ifconf.ifc_buf + ifconf.ifc_len;
+ p += sz) {
+ struct ifreq ifreq;
+ struct sockaddr *sa;
+ size_t salen;
+
+ ifr = (struct ifreq *)p;
+ sa = &ifr->ifr_addr;
+
+ sz = ifreq_sz;
+ salen = sizeof(struct sockaddr);
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ salen = sa->sa_len;
+ sz = max(sz, sizeof(ifr->ifr_name) + sa->sa_len);
+#endif
+#ifdef SA_LEN
+ salen = SA_LEN(sa);
+ sz = max(sz, sizeof(ifr->ifr_name) + SA_LEN(sa));
+#endif
+ memset (&ifreq, 0, sizeof(ifreq));
+ memcpy (ifreq.ifr_name, ifr->ifr_name, sizeof(ifr->ifr_name));
+
+ if (ioctl(fd, siocgifflags, &ifreq) < 0) {
+ ret = errno;
+ goto error_out;
+ }
+
+ *end = malloc(sizeof(**end));
+ if (*end == NULL) {
+ ret = ENOMEM;
+ goto error_out;
+ }
+
+ (*end)->ifa_next = NULL;
+ (*end)->ifa_name = strdup(ifr->ifr_name);
+ if ((*end)->ifa_name == NULL) {
+ ret = ENOMEM;
+ goto error_out;
+ }
+ (*end)->ifa_flags = ifreq.ifr_flags;
+ (*end)->ifa_addr = malloc(salen);
+ if ((*end)->ifa_addr == NULL) {
+ ret = ENOMEM;
+ goto error_out;
+ }
+ memcpy((*end)->ifa_addr, sa, salen);
+ (*end)->ifa_netmask = NULL;
+
+#if 0
+ /* fix these when we actually need them */
+ if(ifreq.ifr_flags & IFF_BROADCAST) {
+ (*end)->ifa_broadaddr = malloc(sizeof(ifr->ifr_broadaddr));
+ if ((*end)->ifa_broadaddr == NULL) {
+ ret = ENOMEM;
+ goto error_out;
+ }
+ memcpy((*end)->ifa_broadaddr, &ifr->ifr_broadaddr,
+ sizeof(ifr->ifr_broadaddr));
+ } else if(ifreq.ifr_flags & IFF_POINTOPOINT) {
+ (*end)->ifa_dstaddr = malloc(sizeof(ifr->ifr_dstaddr));
+ if ((*end)->ifa_dstaddr == NULL) {
+ ret = ENOMEM;
+ goto error_out;
+ }
+ memcpy((*end)->ifa_dstaddr, &ifr->ifr_dstaddr,
+ sizeof(ifr->ifr_dstaddr));
+ } else
+ (*end)->ifa_dstaddr = NULL;
+#else
+ (*end)->ifa_dstaddr = NULL;
+#endif
+
+ (*end)->ifa_data = NULL;
+
+ end = &(*end)->ifa_next;
+
+ }
+ *ifap = start;
+ close(fd);
+ free(buf);
+ return 0;
+ error_out:
+ rk_freeifaddrs(start);
+ close(fd);
+ free(buf);
+ errno = ret;
+ return -1;
+}
+
+#if defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS)
+static int
+getlifaddrs2(struct ifaddrs **ifap,
+ int af, int siocgifconf, int siocgifflags,
+ size_t ifreq_sz)
+{
+ int ret;
+ int fd;
+ size_t buf_size;
+ char *buf;
+ struct lifconf ifconf;
+ char *p;
+ size_t sz;
+ struct sockaddr sa_zero;
+ struct lifreq *ifr;
+ struct ifaddrs *start = NULL, **end = &start;
+
+ buf = NULL;
+
+ memset (&sa_zero, 0, sizeof(sa_zero));
+ fd = socket(af, SOCK_DGRAM, 0);
+ if (fd < 0)
+ return -1;
+
+ buf_size = 8192;
+ for (;;) {
+ buf = calloc(1, buf_size);
+ if (buf == NULL) {
+ ret = ENOMEM;
+ goto error_out;
+ }
+#ifndef __hpux
+ ifconf.lifc_family = af;
+ ifconf.lifc_flags = 0;
+#endif
+ ifconf.lifc_len = buf_size;
+ ifconf.lifc_buf = buf;
+
+ /*
+ * Solaris returns EINVAL when the buffer is too small.
+ */
+ if (ioctl (fd, siocgifconf, &ifconf) < 0 && errno != EINVAL) {
+ ret = errno;
+ goto error_out;
+ }
+ /*
+ * Can the difference between a full and a overfull buf
+ * be determined?
+ */
+
+ if (ifconf.lifc_len < buf_size)
+ break;
+ free (buf);
+ buf_size *= 2;
+ }
+
+ for (p = ifconf.lifc_buf;
+ p < ifconf.lifc_buf + ifconf.lifc_len;
+ p += sz) {
+ struct lifreq ifreq;
+ struct sockaddr_storage *sa;
+ size_t salen;
+
+ ifr = (struct lifreq *)p;
+ sa = &ifr->lifr_addr;
+
+ sz = ifreq_sz;
+ salen = sizeof(struct sockaddr_storage);
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ salen = sa->sa_len;
+ sz = max(sz, sizeof(ifr->ifr_name) + sa->sa_len);
+#endif
+#ifdef SA_LEN
+ salen = SA_LEN(sa);
+ sz = max(sz, sizeof(ifr->ifr_name) + SA_LEN(sa));
+#endif
+ memset (&ifreq, 0, sizeof(ifreq));
+ memcpy (ifreq.lifr_name, ifr->lifr_name, sizeof(ifr->lifr_name));
+
+ if (ioctl(fd, siocgifflags, &ifreq) < 0) {
+ ret = errno;
+ goto error_out;
+ }
+
+ *end = malloc(sizeof(**end));
+ if (*end == NULL) {
+ ret = ENOMEM;
+ goto error_out;
+ }
+
+ (*end)->ifa_next = NULL;
+ (*end)->ifa_name = strdup(ifr->lifr_name);
+ if ((*end)->ifa_name == NULL) {
+ ret = ENOMEM;
+ goto error_out;
+ }
+ (*end)->ifa_flags = ifreq.lifr_flags;
+ (*end)->ifa_addr = malloc(salen);
+ if ((*end)->ifa_addr == NULL) {
+ ret = ENOMEM;
+ goto error_out;
+ }
+ memcpy((*end)->ifa_addr, sa, salen);
+ (*end)->ifa_netmask = NULL;
+
+#if 0
+ /* fix these when we actually need them */
+ if(ifreq.ifr_flags & IFF_BROADCAST) {
+ (*end)->ifa_broadaddr = malloc(sizeof(ifr->ifr_broadaddr));
+ if ((*end)->ifa_broadaddr == NULL) {
+ ret = ENOMEM;
+ goto error_out;
+ }
+ memcpy((*end)->ifa_broadaddr, &ifr->ifr_broadaddr,
+ sizeof(ifr->ifr_broadaddr));
+ } else if(ifreq.ifr_flags & IFF_POINTOPOINT) {
+ (*end)->ifa_dstaddr = malloc(sizeof(ifr->ifr_dstaddr));
+ if ((*end)->ifa_dstaddr == NULL) {
+ ret = ENOMEM;
+ goto error_out;
+ }
+ memcpy((*end)->ifa_dstaddr, &ifr->ifr_dstaddr,
+ sizeof(ifr->ifr_dstaddr));
+ } else
+ (*end)->ifa_dstaddr = NULL;
+#else
+ (*end)->ifa_dstaddr = NULL;
+#endif
+
+ (*end)->ifa_data = NULL;
+
+ end = &(*end)->ifa_next;
+
+ }
+ *ifap = start;
+ close(fd);
+ free(buf);
+ return 0;
+ error_out:
+ rk_freeifaddrs(start);
+ close(fd);
+ free(buf);
+ errno = ret;
+ return -1;
+}
+#endif /* defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS) */
+
+/**
+ * Join two struct ifaddrs lists by appending supp to base.
+ * Either may be NULL. The new list head (usually base) will be
+ * returned.
+ */
+static struct ifaddrs *
+append_ifaddrs(struct ifaddrs *base, struct ifaddrs *supp) {
+ if (!base)
+ return supp;
+
+ if (!supp)
+ return base;
+
+ while (base->ifa_next)
+ base = base->ifa_next;
+
+ base->ifa_next = supp;
+
+ return base;
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_getifaddrs(struct ifaddrs **ifap)
+{
+ int ret = -1;
+ errno = ENXIO;
+#if defined(AF_INET6) && defined(SIOCGIF6CONF) && defined(SIOCGIF6FLAGS)
+ if (ret)
+ ret = getifaddrs2 (ifap, AF_INET6, SIOCGIF6CONF, SIOCGIF6FLAGS,
+ sizeof(struct in6_ifreq));
+#endif
+#if defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS)
+ /* Do IPv6 and IPv4 queries separately then join the result.
+ *
+ * HP-UX only returns IPv6 addresses using SIOCGLIFCONF,
+ * SIOCGIFCONF has to be used for IPv4 addresses. The result is then
+ * merged.
+ *
+ * Solaris needs particular care, because a SIOCGLIFCONF lookup using
+ * AF_UNSPEC can fail in a Zone requiring an AF_INET lookup, so we just
+ * do them separately the same as for HP-UX. See
+ * http://repo.or.cz/w/heimdal.git/commitdiff/76afc31e9ba2f37e64c70adc006ade9e37e9ef73
+ */
+ if (ret) {
+ int v6err, v4err;
+ struct ifaddrs *v6addrs, *v4addrs;
+
+ v6err = getlifaddrs2 (&v6addrs, AF_INET6, SIOCGLIFCONF, SIOCGLIFFLAGS,
+ sizeof(struct lifreq));
+ v4err = getifaddrs2 (&v4addrs, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS,
+ sizeof(struct ifreq));
+ if (v6err)
+ v6addrs = NULL;
+ if (v4err)
+ v4addrs = NULL;
+
+ if (v6addrs) {
+ if (v4addrs)
+ *ifap = append_ifaddrs(v6addrs, v4addrs);
+ else
+ *ifap = v6addrs;
+ } else if (v4addrs) {
+ *ifap = v4addrs;
+ } else {
+ *ifap = NULL;
+ }
+
+ ret = (v6err || v4err) ? -1 : 0;
+ }
+#endif
+#if defined(HAVE_IPV6) && defined(SIOCGIFCONF)
+ if (ret)
+ ret = getifaddrs2 (ifap, AF_INET6, SIOCGIFCONF, SIOCGIFFLAGS,
+ sizeof(struct ifreq));
+#endif
+#if defined(AF_INET) && defined(SIOCGIFCONF) && defined(SIOCGIFFLAGS)
+ if (ret)
+ ret = getifaddrs2 (ifap, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS,
+ sizeof(struct ifreq));
+#endif
+ return ret;
+}
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rk_freeifaddrs(struct ifaddrs *ifp)
+{
+ struct ifaddrs *p, *q;
+
+ for(p = ifp; p; ) {
+ free(p->ifa_name);
+ if(p->ifa_addr)
+ free(p->ifa_addr);
+ if(p->ifa_dstaddr)
+ free(p->ifa_dstaddr);
+ if(p->ifa_netmask)
+ free(p->ifa_netmask);
+ if(p->ifa_data)
+ free(p->ifa_data);
+ q = p;
+ p = p->ifa_next;
+ free(q);
+ }
+}
+
+#endif /* !AF_NETLINK */
+
+#ifdef TEST
+
+void
+print_addr(const char *s, struct sockaddr *sa)
+{
+ int i;
+ printf(" %s=%d/", s, sa->sa_family);
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ for(i = 0; i < sa->sa_len - ((long)sa->sa_data - (long)&sa->sa_family); i++)
+ printf("%02x", ((unsigned char*)sa->sa_data)[i]);
+#else
+ for(i = 0; i < sizeof(sa->sa_data); i++)
+ printf("%02x", ((unsigned char*)sa->sa_data)[i]);
+#endif
+ printf("\n");
+}
+
+void
+print_ifaddrs(struct ifaddrs *x)
+{
+ struct ifaddrs *p;
+
+ for(p = x; p; p = p->ifa_next) {
+ printf("%s\n", p->ifa_name);
+ printf(" flags=%x\n", p->ifa_flags);
+ if(p->ifa_addr)
+ print_addr("addr", p->ifa_addr);
+ if(p->ifa_dstaddr)
+ print_addr("dstaddr", p->ifa_dstaddr);
+ if(p->ifa_netmask)
+ print_addr("netmask", p->ifa_netmask);
+ printf(" %p\n", p->ifa_data);
+ }
+}
+
+int
+main()
+{
+ struct ifaddrs *a = NULL, *b;
+ getifaddrs2(&a, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS, sizeof(struct ifreq));
+ print_ifaddrs(a);
+ printf("---\n");
+ getifaddrs(&b);
+ print_ifaddrs(b);
+ return 0;
+}
+#endif
diff --git a/third_party/heimdal/lib/roken/getifaddrs_w32.c b/third_party/heimdal/lib/roken/getifaddrs_w32.c
new file mode 100644
index 0000000..beb29b3
--- /dev/null
+++ b/third_party/heimdal/lib/roken/getifaddrs_w32.c
@@ -0,0 +1,161 @@
+/***********************************************************************
+ * Copyright (c) 2009, Secure Endpoints Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDER 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<config.h>
+
+#include <roken.h>
+
+#include <ifaddrs.h>
+
+#ifndef _WIN32
+#error This is a Windows specific implementation.
+#endif
+
+static struct sockaddr *
+dupaddr(const sockaddr_gen * src)
+{
+ sockaddr_gen * d = malloc(sizeof(*d));
+
+ if (d) {
+ memcpy(d, src, sizeof(*d));
+ }
+
+ return (struct sockaddr *) d;
+}
+
+int ROKEN_LIB_FUNCTION
+rk_getifaddrs(struct ifaddrs **ifpp)
+{
+ SOCKET s = INVALID_SOCKET;
+ size_t il_len = 8192;
+ int ret = -1;
+ INTERFACE_INFO *il = NULL;
+
+ *ifpp = NULL;
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s == INVALID_SOCKET)
+ return -1;
+
+ for (;;) {
+ DWORD cbret = 0;
+
+ il = malloc(il_len);
+ if (!il)
+ break;
+
+ ZeroMemory(il, il_len);
+
+ if (WSAIoctl(s, SIO_GET_INTERFACE_LIST, NULL, 0,
+ (LPVOID) il, (DWORD) il_len, &cbret,
+ NULL, NULL) == 0) {
+ il_len = cbret;
+ break;
+ }
+
+ free (il);
+ il = NULL;
+
+ if (WSAGetLastError() == WSAEFAULT && cbret > il_len) {
+ il_len = cbret;
+ } else {
+ break;
+ }
+ }
+
+ if (!il)
+ goto _exit;
+
+ /* il is an array of INTERFACE_INFO structures. il_len has the
+ actual size of the buffer. The number of elements is
+ il_len/sizeof(INTERFACE_INFO) */
+
+ {
+ size_t n = il_len / sizeof(INTERFACE_INFO);
+ size_t i;
+
+ for (i = 0; i < n; i++ ) {
+ struct ifaddrs *ifp;
+
+ ifp = malloc(sizeof(*ifp));
+ if (ifp == NULL)
+ break;
+
+ ZeroMemory(ifp, sizeof(*ifp));
+
+ ifp->ifa_next = NULL;
+ ifp->ifa_name = NULL;
+ ifp->ifa_flags = il[i].iiFlags;
+ ifp->ifa_addr = dupaddr(&il[i].iiAddress);
+ ifp->ifa_netmask = dupaddr(&il[i].iiNetmask);
+ ifp->ifa_broadaddr = dupaddr(&il[i].iiBroadcastAddress);
+ ifp->ifa_data = NULL;
+
+ *ifpp = ifp;
+ ifpp = &ifp->ifa_next;
+ }
+
+ if (i == n)
+ ret = 0;
+ }
+
+ _exit:
+
+ if (s != INVALID_SOCKET)
+ closesocket(s);
+
+ if (il)
+ free (il);
+
+ return ret;
+}
+
+void ROKEN_LIB_FUNCTION
+rk_freeifaddrs(struct ifaddrs *ifp)
+{
+ struct ifaddrs *p, *q;
+
+ for(p = ifp; p; ) {
+ if (p->ifa_name)
+ free(p->ifa_name);
+ if(p->ifa_addr)
+ free(p->ifa_addr);
+ if(p->ifa_dstaddr)
+ free(p->ifa_dstaddr);
+ if(p->ifa_netmask)
+ free(p->ifa_netmask);
+ if(p->ifa_data)
+ free(p->ifa_data);
+ q = p;
+ p = p->ifa_next;
+ free(q);
+ }
+}
diff --git a/third_party/heimdal/lib/roken/getipnodebyaddr.c b/third_party/heimdal/lib/roken/getipnodebyaddr.c
new file mode 100644
index 0000000..afebe91
--- /dev/null
+++ b/third_party/heimdal/lib/roken/getipnodebyaddr.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+/*
+ * lookup `src, len' (address family `af') in DNS and return a pointer
+ * to a malloced struct hostent or NULL.
+ */
+
+ROKEN_LIB_FUNCTION struct hostent * ROKEN_LIB_CALL
+rk_getipnodebyaddr(const void *src, size_t len, int af, int *error_num)
+{
+ struct hostent *tmp;
+
+ tmp = gethostbyaddr (src, len, af);
+ if (tmp == NULL) {
+ switch (h_errno) {
+ case HOST_NOT_FOUND :
+ case TRY_AGAIN :
+ case NO_RECOVERY :
+ *error_num = h_errno;
+ break;
+ case NO_DATA :
+ *error_num = NO_ADDRESS;
+ break;
+ default :
+ *error_num = NO_RECOVERY;
+ break;
+ }
+ return NULL;
+ }
+ tmp = copyhostent (tmp);
+ if (tmp == NULL) {
+ *error_num = TRY_AGAIN;
+ return NULL;
+ }
+ return tmp;
+}
diff --git a/third_party/heimdal/lib/roken/getipnodebyname.c b/third_party/heimdal/lib/roken/getipnodebyname.c
new file mode 100644
index 0000000..ee430c7
--- /dev/null
+++ b/third_party/heimdal/lib/roken/getipnodebyname.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+#ifndef HAVE_H_ERRNO
+static int h_errno = NO_RECOVERY;
+#endif
+
+/*
+ * lookup `name' (address family `af') in DNS and return a pointer
+ * to a malloced struct hostent or NULL.
+ */
+
+ROKEN_LIB_FUNCTION struct hostent * ROKEN_LIB_CALL
+rk_getipnodebyname(const char *name, int af, int flags, int *error_num)
+{
+ struct hostent *tmp;
+
+#ifdef HAVE_GETHOSTBYNAME2
+ tmp = gethostbyname2 (name, af);
+#else
+ if (af != AF_INET) {
+ *error_num = NO_ADDRESS;
+ return NULL;
+ }
+ tmp = gethostbyname (name);
+#endif
+ if (tmp == NULL) {
+ switch (h_errno) {
+ case HOST_NOT_FOUND :
+ case TRY_AGAIN :
+ case NO_RECOVERY :
+ *error_num = h_errno;
+ break;
+ case NO_DATA :
+ *error_num = NO_ADDRESS;
+ break;
+ default :
+ *error_num = NO_RECOVERY;
+ break;
+ }
+ return NULL;
+ }
+ tmp = copyhostent (tmp);
+ if (tmp == NULL) {
+ *error_num = TRY_AGAIN;
+ return NULL;
+ }
+ return tmp;
+}
diff --git a/third_party/heimdal/lib/roken/getnameinfo.c b/third_party/heimdal/lib/roken/getnameinfo.c
new file mode 100644
index 0000000..9d11860
--- /dev/null
+++ b/third_party/heimdal/lib/roken/getnameinfo.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 1999 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+static int
+doit (int af,
+ const void *addr,
+ size_t addrlen,
+ int port,
+ char *host, size_t hostlen,
+ char *serv, size_t servlen,
+ int flags)
+{
+ if (host != NULL) {
+ if (flags & NI_NUMERICHOST) {
+ if (inet_ntop (af, addr, host, hostlen) == NULL)
+ return EAI_SYSTEM;
+ } else {
+ struct hostent *he = gethostbyaddr (addr,
+ addrlen,
+ af);
+ if (he != NULL) {
+ strlcpy (host, hostent_find_fqdn(he), hostlen);
+ if (flags & NI_NOFQDN) {
+ char *dot = strchr (host, '.');
+ if (dot != NULL)
+ *dot = '\0';
+ }
+ } else if (flags & NI_NAMEREQD) {
+ return EAI_NONAME;
+ } else if (inet_ntop (af, addr, host, hostlen) == NULL)
+ return EAI_SYSTEM;
+ }
+ }
+
+ if (serv != NULL) {
+ if (flags & NI_NUMERICSERV) {
+ snprintf (serv, servlen, "%u", ntohs(port));
+ } else {
+ const char *proto = "tcp";
+ struct servent *se;
+
+ if (flags & NI_DGRAM)
+ proto = "udp";
+
+ se = getservbyport (port, proto);
+ if (se == NULL) {
+ snprintf (serv, servlen, "%u", ntohs(port));
+ } else {
+ strlcpy (serv, se->s_name, servlen);
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ *
+ */
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_getnameinfo(const struct sockaddr *sa, socklen_t salen,
+ char *host, size_t hostlen,
+ char *serv, size_t servlen,
+ int flags)
+{
+ switch (sa->sa_family) {
+#ifdef HAVE_IPV6
+ case AF_INET6 : {
+ const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
+
+ return doit (AF_INET6, &sin6->sin6_addr, sizeof(sin6->sin6_addr),
+ sin6->sin6_port,
+ host, hostlen,
+ serv, servlen,
+ flags);
+ }
+#endif
+ case AF_INET : {
+ const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa;
+
+ return doit (AF_INET, &sin4->sin_addr, sizeof(sin4->sin_addr),
+ sin4->sin_port,
+ host, hostlen,
+ serv, servlen,
+ flags);
+ }
+ default :
+ return EAI_FAMILY;
+ }
+}
diff --git a/third_party/heimdal/lib/roken/getnameinfo_verified.c b/third_party/heimdal/lib/roken/getnameinfo_verified.c
new file mode 100644
index 0000000..6175291
--- /dev/null
+++ b/third_party/heimdal/lib/roken/getnameinfo_verified.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 1999 - 2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+/*
+ * Try to obtain a verified name for the address in `sa, salen' (much
+ * similar to getnameinfo).
+ * Verified in this context means that forwards and backwards lookups
+ * in DNS are consistent. If that fails, return an error if the
+ * NI_NAMEREQD flag is set or return the numeric address as a string.
+ */
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+getnameinfo_verified(const struct sockaddr *sa, socklen_t salen,
+ char *host, size_t hostlen,
+ char *serv, size_t servlen,
+ int flags)
+{
+ int ret;
+ struct addrinfo *ai, *a;
+ char servbuf[NI_MAXSERV];
+ struct addrinfo hints;
+ void *saaddr;
+ size_t sasize;
+
+ if (host == NULL)
+ return EAI_NONAME;
+
+ if (serv == NULL) {
+ serv = servbuf;
+ servlen = sizeof(servbuf);
+ }
+
+ ret = getnameinfo (sa, salen, host, hostlen, serv, servlen,
+ flags | NI_NUMERICSERV);
+ if (ret)
+ goto fail;
+
+ memset (&hints, 0, sizeof(hints));
+ hints.ai_socktype = SOCK_STREAM;
+ ret = getaddrinfo (host, serv, &hints, &ai);
+ if (ret)
+ goto fail;
+
+ saaddr = socket_get_address(sa);
+ sasize = socket_addr_size(sa);
+ for (a = ai; a != NULL; a = a->ai_next) {
+ if (sasize == socket_addr_size(a->ai_addr) &&
+ memcmp(saaddr, socket_get_address(a->ai_addr), sasize) == 0) {
+ freeaddrinfo (ai);
+ return 0;
+ }
+ }
+ freeaddrinfo (ai);
+ fail:
+ if (flags & NI_NAMEREQD)
+ return EAI_NONAME;
+ ret = getnameinfo (sa, salen, host, hostlen, serv, servlen,
+ flags | NI_NUMERICSERV | NI_NUMERICHOST);
+ return ret;
+}
diff --git a/third_party/heimdal/lib/roken/getopt.c b/third_party/heimdal/lib/roken/getopt.c
new file mode 100644
index 0000000..f035f74
--- /dev/null
+++ b/third_party/heimdal/lib/roken/getopt.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 1987, 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getopt.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#ifndef __STDC__
+#define const
+#endif
+#include <config.h>
+#include "roken.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * get option letter from argument vector
+ */
+ROKEN_LIB_VARIABLE int opterr = 1; /* if error message should be printed */
+ROKEN_LIB_VARIABLE int optind = 1; /* index into parent argv vector */
+ROKEN_LIB_VARIABLE int optopt; /* character checked for validity */
+int optreset; /* reset getopt */
+ROKEN_LIB_VARIABLE char *optarg; /* argument associated with option */
+
+#define BADCH (int)'?'
+#define BADARG (int)':'
+#define EMSG ""
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+getopt(int nargc, char * const *nargv, const char *ostr)
+{
+ static char *place = EMSG; /* option letter processing */
+ char *oli; /* option letter list index */
+ char *p;
+
+ if (optreset || !*place) { /* update scanning pointer */
+ optreset = 0;
+ if (optind >= nargc || *(place = nargv[optind]) != '-') {
+ place = EMSG;
+ return(-1);
+ }
+ if (place[1] && *++place == '-') { /* found "--" */
+ ++optind;
+ place = EMSG;
+ return(-1);
+ }
+ } /* option letter okay? */
+ if ((optopt = (int)*place++) == (int)':' ||
+ !(oli = strchr(ostr, optopt))) {
+ /*
+ * if the user didn't specify '-' as an option,
+ * assume it means -1 (EOF).
+ */
+ if (optopt == (int)'-')
+ return(-1);
+ if (!*place)
+ ++optind;
+ if (opterr && *ostr != ':') {
+ if (!(p = strrchr(*nargv, '/')))
+ p = *nargv;
+ else
+ ++p;
+ fprintf(stderr, "%s: illegal option -- %c\n",
+ p, optopt);
+ }
+ return(BADCH);
+ }
+ if (*++oli != ':') { /* don't need argument */
+ optarg = NULL;
+ if (!*place)
+ ++optind;
+ }
+ else { /* need an argument */
+ if (*place) /* no white space */
+ optarg = place;
+ else if (nargc <= ++optind) { /* no arg */
+ place = EMSG;
+ if (!(p = strrchr(*nargv, '/')))
+ p = *nargv;
+ else
+ ++p;
+ if (*ostr == ':')
+ return(BADARG);
+ if (opterr)
+ fprintf(stderr,
+ "%s: option requires an argument -- %c\n",
+ p, optopt);
+ return(BADCH);
+ }
+ else /* white space */
+ optarg = nargv[optind];
+ place = EMSG;
+ ++optind;
+ }
+ return(optopt); /* dump back option letter */
+}
diff --git a/third_party/heimdal/lib/roken/getprogname.c b/third_party/heimdal/lib/roken/getprogname.c
new file mode 100644
index 0000000..a310208
--- /dev/null
+++ b/third_party/heimdal/lib/roken/getprogname.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1995-2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+#ifndef HAVE___PROGNAME
+const char *__progname;
+#endif
+
+#ifndef HAVE_GETPROGNAME
+ROKEN_LIB_FUNCTION const char * ROKEN_LIB_CALL
+getprogname(void)
+{
+ return __progname;
+}
+#endif /* HAVE_GETPROGNAME */
diff --git a/third_party/heimdal/lib/roken/gettimeofday.c b/third_party/heimdal/lib/roken/gettimeofday.c
new file mode 100644
index 0000000..918b6f6
--- /dev/null
+++ b/third_party/heimdal/lib/roken/gettimeofday.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+#include "roken.h"
+#ifndef HAVE_GETTIMEOFDAY
+
+#ifdef _WIN32
+
+typedef BOOL (WINAPI *LPFN_GETSYSTEMTIME) (LPFILETIME);
+
+static LPFN_GETSYSTEMTIME lpGetSystemTime = NULL;
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+gettimeofday (struct timeval *tp, void *ignore)
+{
+ FILETIME ft;
+ ULARGE_INTEGER li;
+ ULONGLONG ull;
+
+ if (lpGetSystemTime == NULL) {
+ HANDLE h1;
+ LPFN_GETSYSTEMTIME fn;
+
+ h1 = GetModuleHandle(TEXT("kernel32.dll")); /* no refcount increase */
+ fn = (LPFN_GETSYSTEMTIME)GetProcAddress(h1,
+ "GetSystemTimePreciseAsFileTime");
+ if (fn == NULL)
+ fn = (LPFN_GETSYSTEMTIME)GetProcAddress(h1,
+ "GetSystemTimeAsFileTime");
+ lpGetSystemTime = fn;
+ }
+
+ lpGetSystemTime(&ft);
+ li.LowPart = ft.dwLowDateTime;
+ li.HighPart = ft.dwHighDateTime;
+ ull = li.QuadPart;
+
+ ull -= 116444736000000000i64;
+ ull /= 10i64; /* ull is now in microseconds */
+
+ tp->tv_usec = (ull % 1000000i64);
+ tp->tv_sec = (ull / 1000000i64);
+
+ return 0;
+}
+#else
+
+/*
+ * Simple gettimeofday that only returns seconds.
+ */
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+gettimeofday (struct timeval *tp, void *ignore)
+{
+ time_t t;
+
+ t = time(NULL);
+ tp->tv_sec = (long) t;
+ tp->tv_usec = 0;
+ return 0;
+}
+
+#endif /* !_WIN32 */
+#endif
diff --git a/third_party/heimdal/lib/roken/getuid.c b/third_party/heimdal/lib/roken/getuid.c
new file mode 100644
index 0000000..63fdec1
--- /dev/null
+++ b/third_party/heimdal/lib/roken/getuid.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+#include "roken.h"
+
+#ifndef HAVE_GETUID
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+getuid(void)
+{
+ return 17;
+}
+
+#endif
diff --git a/third_party/heimdal/lib/roken/getuserinfo.c b/third_party/heimdal/lib/roken/getuserinfo.c
new file mode 100644
index 0000000..09f4c73
--- /dev/null
+++ b/third_party/heimdal/lib/roken/getuserinfo.c
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2017 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+#include "roken.h"
+
+#ifdef WIN32
+#include <Shlobj.h> // need to include definitions of constants
+#define SECURITY_WIN32
+#include <security.h>
+#else
+#include <sys/types.h>
+#include <pwd.h>
+#include <unistd.h>
+#endif
+
+/**
+ * Returns the user's SHELL.
+ */
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+roken_get_shell(char *shell, size_t shellsz)
+{
+ char *p;
+
+#ifndef WIN32
+#ifdef HAVE_GETPWNAM_R
+ size_t buflen = 2048;
+
+ if (sysconf(_SC_GETPW_R_SIZE_MAX) > 0)
+ buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
+#endif
+
+ if (issuid())
+ return "/bin/sh";
+
+ p = secure_getenv("SHELL");
+ if (p != NULL && p[0] != '\0') {
+ if (strlcpy(shell, p, shellsz) < shellsz)
+ return shell;
+ errno = ERANGE;
+ return NULL;
+ }
+
+#ifdef HAVE_GETPWNAM_R
+ {
+ struct passwd pwd;
+ struct passwd *pwdp;
+ char buf[buflen];
+ char user[128];
+ const char *username = roken_get_username(user, sizeof(user));
+
+ if (username &&
+ getpwnam_r(username, &pwd, buf, buflen, &pwdp) == 0 &&
+ pwdp != NULL && pwdp->pw_shell != NULL) {
+ if (strlcpy(shell, pwdp->pw_shell, shellsz) < shellsz)
+ return shell;
+ errno = ERANGE;
+ return NULL;
+ }
+ }
+#endif
+ errno = 0;
+ return "/bin/sh";
+#else
+ /* Windows */
+ p = getenv("SHELL");
+ if (p != NULL && p[0] != '\0') {
+ if (strlcpy(shell, p, shellsz) < shellsz)
+ return shell;
+ errno = ERANGE;
+ return NULL;
+ }
+ errno = 0;
+ return NULL;
+#endif
+}
+
+/**
+ * Returns the home directory.
+ */
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+roken_get_homedir(char *home, size_t homesz)
+{
+ char *p;
+
+#ifdef WIN32
+ if (homesz < MAX_PATH) {
+ errno = ERANGE;
+ return NULL;
+ }
+
+ if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PROFILE, NULL,
+ SHGFP_TYPE_CURRENT, home)))
+ return home;
+
+ if ((p = getenv("HOMEDRIVE")) != NULL && p[0] != '\0') {
+ if (strlcpy(home, p, homesz) >= homesz) {
+ errno = ERANGE;
+ return NULL;
+ }
+ if ((p = getenv("HOMEPATH")) != NULL) {
+ if (strlcat(home, p, homesz) < homesz)
+ return home;
+ errno = ERANGE;
+ return NULL;
+ }
+ return home;
+ }
+ HEIM_FALLTHROUGH;
+#else
+#ifdef HAVE_GETPWNAM_R
+ size_t buflen = 2048;
+
+ if (sysconf(_SC_GETPW_R_SIZE_MAX) > 0)
+ buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
+#endif
+
+ if (issuid()) {
+ errno = 0;
+ return NULL;
+ }
+
+ p = secure_getenv("HOME");
+ if (p != NULL && p[0] != '\0') {
+ if (strlcpy(home, p, homesz) < homesz)
+ return home;
+ errno = ERANGE;
+ return NULL;
+ }
+
+#ifdef HAVE_GETPWNAM_R
+ {
+ char user[128];
+ const char *username = roken_get_username(user, sizeof(user));
+ struct passwd pwd;
+ struct passwd *pwdp;
+ char buf[buflen];
+
+ if (username &&
+ getpwnam_r(username, &pwd, buf, buflen, &pwdp) == 0 &&
+ pwdp != NULL && pwdp->pw_dir != NULL) {
+ if (strlcpy(home, pwdp->pw_dir, homesz) < homesz)
+ return home;
+ errno = ERANGE;
+ return NULL;
+ }
+ }
+#endif
+#endif
+ errno = 0;
+ return NULL;
+}
+
+/**
+ * Returns the home directory on Unix, or the AppData directory on
+ * Windows.
+ */
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+roken_get_appdatadir(char *appdata, size_t appdatasz)
+{
+#ifdef WIN32
+ char *p;
+#endif
+
+#ifndef WIN32
+ return roken_get_homedir(appdata, appdatasz);
+#else
+ if (appdatasz < MAX_PATH) {
+ errno = ERANGE;
+ return NULL;
+ }
+
+ if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL,
+ SHGFP_TYPE_CURRENT, appdata)))
+ return appdata;
+
+ if ((p = getenv("APPDATA")) != NULL && p[0] != '\0') {
+ if (strlcpy(appdata, p, appdatasz) < appdatasz)
+ return appdata;
+ errno = ERANGE;
+ return NULL;
+ }
+
+ errno = 0;
+ return NULL;
+#endif
+}
+
+/**
+ * Return a bare username. This is used for, e.g., constructing default
+ * principal names.
+ *
+ * On POSIX systems, if the caller is not set-uid-like, then this will return
+ * the value of the USER or LOGNAME environment variables (in that order of
+ * preference), else the username found by looking up the effective UID.
+ */
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+roken_get_username(char *user, size_t usersz)
+{
+ char *p;
+
+#ifdef WIN32
+ ULONG sz = usersz;
+
+ if (GetUserNameEx(NameSamCompatible, user, &sz)) {
+ /*
+ * There's no EXTENDED_NAME_FORMAT for "bare username". We we
+ * have to parse one.
+ */
+ p = strchr(user, '\\');
+ if (p != NULL) {
+ p++;
+ memmove(user, p, strlen(p) + 1);
+ }
+ return user;
+ } else {
+ DWORD err = GetLastError();
+ if (err == ERROR_MORE_DATA) {
+ errno = ERANGE;
+ return NULL;
+ }
+ /* %USERNAME% is generally bare */
+ p = getenv("USERNAME");
+ if (p != NULL && p[0] != '\0') {
+ if (strchr(p, '\\') != NULL)
+ p = strchr(p, '\\') + 1;
+ if (strlcpy(user, p, usersz) < usersz)
+ return user;
+ errno = ERANGE;
+ return NULL;
+ }
+ }
+#else
+#ifdef HAVE_GETPWUID_R
+ size_t buflen = 2048;
+
+ if (sysconf(_SC_GETPW_R_SIZE_MAX) > 0)
+ buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
+#endif
+
+ p = secure_getenv("USER");
+ if (p == NULL || p[0] == '\0')
+ p = secure_getenv("LOGNAME");
+ if (p != NULL && p[0] != '\0') {
+ if (strlcpy(user, p, usersz) < usersz)
+ return user;
+ errno = ERANGE;
+ return NULL;
+ }
+
+#ifdef HAVE_GETPWUID_R
+ {
+ struct passwd pwd;
+ struct passwd *pwdp;
+ char buf[buflen];
+
+ if (getpwuid_r(getuid(), &pwd, buf, buflen, &pwdp) == 0 &&
+ pwdp != NULL && pwdp->pw_name != NULL) {
+ if (strlcpy(user, pwdp->pw_name, usersz) < usersz)
+ return user;
+ errno = ERANGE;
+ return NULL;
+ }
+ }
+#endif
+#endif
+ errno = 0;
+ return NULL;
+}
+
+/**
+ * Return a bare username. This is used for, e.g., constructing default
+ * principal names.
+ *
+ * On POSIX systems this returns the name recorded in the system as currently
+ * logged in on the current terminal.
+ */
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+roken_get_loginname(char *user, size_t usersz)
+{
+#ifdef WIN32
+ return roken_get_username(user, usersz);
+#else
+#ifdef HAVE_GETLOGIN_R
+ if ((errno = getlogin_r(user, usersz)) == 0)
+ return user;
+ if (errno != ENOENT)
+ return NULL;
+#else
+#ifdef HAVE_GETLOGIN
+ if ((p = getlogin()) != NULL && p[0] != '\0') {
+ if (strlcpy(user, p, usersz) < usersz)
+ return user;
+ errno = ERANGE;
+ return NULL;
+ }
+ if (errno != ENOENT)
+ return NULL;
+#endif
+#endif
+ errno = 0;
+ return NULL;
+#endif
+}
diff --git a/third_party/heimdal/lib/roken/getusershell.c b/third_party/heimdal/lib/roken/getusershell.c
new file mode 100644
index 0000000..6f7145d
--- /dev/null
+++ b/third_party/heimdal/lib/roken/getusershell.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 1985, 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 <config.h>
+
+#ifndef HAVE_GETUSERSHELL
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef HAVE_USERSEC_H
+struct aud_rec;
+#include <usersec.h>
+#endif
+#ifdef HAVE_USERCONF_H
+#include <userconf.h>
+#endif
+#include "roken.h"
+
+#ifndef _PATH_SHELLS
+#define _PATH_SHELLS "/etc/shells"
+#endif
+
+#ifndef _PATH_BSHELL
+#define _PATH_BSHELL "/bin/sh"
+#endif
+
+#ifndef _PATH_CSHELL
+#define _PATH_CSHELL "/bin/csh"
+#endif
+
+/*
+ * Local shells should NOT be added here. They should be added in
+ * /etc/shells.
+ */
+
+static char *okshells[] = { _PATH_BSHELL, _PATH_CSHELL, NULL };
+static char **curshell, **shells, *strings;
+static char **initshells (void);
+
+/*
+ * Get a list of shells from _PATH_SHELLS, if it exists.
+ */
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+getusershell()
+{
+ char *ret;
+
+ if (curshell == NULL)
+ curshell = initshells();
+ ret = *curshell;
+ if (ret != NULL)
+ curshell++;
+ return (ret);
+}
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+endusershell()
+{
+ if (shells != NULL)
+ free(shells);
+ shells = NULL;
+ if (strings != NULL)
+ free(strings);
+ strings = NULL;
+ curshell = NULL;
+}
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+setusershell()
+{
+ curshell = initshells();
+}
+
+static char **
+initshells()
+{
+ char **sp, *cp;
+#ifdef HAVE_GETCONFATTR
+ char *tmp;
+ int nsh;
+#else
+ FILE *fp;
+#endif
+ struct stat statb;
+
+ free(shells);
+ shells = NULL;
+ free(strings);
+ strings = NULL;
+#ifdef HAVE_GETCONFATTR
+ if(getconfattr(SC_SYS_LOGIN, SC_SHELLS, &tmp, SEC_LIST) != 0)
+ return okshells;
+
+ for(cp = tmp, nsh = 0; *cp; cp += strlen(cp) + 1, nsh++);
+
+ shells = calloc(nsh + 1, sizeof(*shells));
+ if(shells == NULL)
+ return okshells;
+
+ strings = malloc(cp - tmp);
+ if(strings == NULL) {
+ free(shells);
+ shells = NULL;
+ return okshells;
+ }
+ memcpy(strings, tmp, cp - tmp);
+ for(sp = shells, cp = strings; *cp; cp += strlen(cp) + 1, sp++)
+ *sp = cp;
+#else
+ if ((fp = fopen(_PATH_SHELLS, "r")) == NULL)
+ return (okshells);
+ if (fstat(fileno(fp), &statb) == -1) {
+ fclose(fp);
+ return (okshells);
+ }
+ if ((strings = malloc((u_int)statb.st_size)) == NULL) {
+ fclose(fp);
+ return (okshells);
+ }
+ shells = calloc((unsigned)statb.st_size / 3, sizeof (char *));
+ if (shells == NULL) {
+ fclose(fp);
+ free(strings);
+ strings = NULL;
+ return (okshells);
+ }
+ sp = shells;
+ cp = strings;
+ while (fgets(cp, MaxPathLen + 1, fp) != NULL) {
+ while (*cp != '#' && *cp != '/' && *cp != '\0')
+ cp++;
+ if (*cp == '#' || *cp == '\0')
+ continue;
+ *sp++ = cp;
+ while (!isspace((unsigned char)*cp) && *cp != '#' && *cp != '\0')
+ cp++;
+ *cp++ = '\0';
+ }
+ fclose(fp);
+#endif
+ *sp = NULL;
+ return (shells);
+}
+#endif /* HAVE_GETUSERSHELL */
diff --git a/third_party/heimdal/lib/roken/h_errno.c b/third_party/heimdal/lib/roken/h_errno.c
new file mode 100644
index 0000000..7e49f80
--- /dev/null
+++ b/third_party/heimdal/lib/roken/h_errno.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#ifndef HAVE_H_ERRNO
+int h_errno = -17; /* Some magic number */
+#endif
diff --git a/third_party/heimdal/lib/roken/hex-test.c b/third_party/heimdal/lib/roken/hex-test.c
new file mode 100644
index 0000000..01f21c8
--- /dev/null
+++ b/third_party/heimdal/lib/roken/hex-test.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 1999 - 2001, 2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+#include <hex.h>
+
+int
+main(int argc, char **argv)
+{
+ int numerr = 0;
+ int numtest = 1;
+ struct test {
+ void *data;
+ ssize_t len;
+ const char *result;
+ } *t, tests[] = {
+ { "", 0 , "" },
+ { "a", 1, "61" },
+ { "ab", 2, "6162" },
+ { "abc", 3, "616263" },
+ { "abcd", 4, "61626364" },
+ { "abcde", 5, "6162636465" },
+ { "abcdef", 6, "616263646566" },
+ { "abcdefg", 7, "61626364656667" },
+ { "=", 1, "3D" },
+ /* Embedded NUL, non-ASCII / binary */
+ { "\0\x01\x1a\xad\xf1\xff", 6, "00011AADF1FF" },
+ /* Invalid encodings */
+ { "", -1, "00.11AADF1FF" },
+ { "", -1, "000x1AADF1FF" },
+ { "", -1, "00011?ADF1FF" },
+ { NULL, 0, NULL }
+ };
+ for(t = tests; t->data; t++) {
+ ssize_t len;
+ char *str;
+
+ if (t->len > -1) {
+ (void) hex_encode(t->data, t->len, &str);
+ if (strcmp(str, t->result) != 0) {
+ fprintf(stderr, "failed test %d: %s != %s\n", numtest,
+ str, t->result);
+ numerr++;
+ }
+ free(str);
+ }
+ str = strdup(t->result);
+ len = strlen(str);
+ len = hex_decode(t->result, str, len);
+ if (len != t->len) {
+ fprintf(stderr, "failed test %d: len %lu != %ld\n", numtest,
+ (long)len, (long)t->len);
+ numerr++;
+ } else if (t->len > -1 && memcmp(str, t->data, t->len) != 0) {
+ fprintf(stderr, "failed test %d: data\n", numtest);
+ numerr++;
+ }
+ free(str);
+ numtest++;
+ }
+
+ {
+ unsigned char buf[2] = { 0, 0xff } ;
+ int len;
+
+ len = hex_decode("A", buf, 1);
+ if (len != 1) {
+ fprintf(stderr, "len != 1");
+ numerr++;
+ }
+ if (buf[0] != 10) {
+ fprintf(stderr, "buf != 10");
+ numerr++;
+ }
+ if (buf[1] != 0xff) {
+ fprintf(stderr, "buf != 0xff");
+ numerr++;
+ }
+
+ }
+
+ return numerr;
+}
diff --git a/third_party/heimdal/lib/roken/hex.c b/third_party/heimdal/lib/roken/hex.c
new file mode 100644
index 0000000..5cd2026
--- /dev/null
+++ b/third_party/heimdal/lib/roken/hex.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2004-2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+#include "roken.h"
+#include <ctype.h>
+#include "hex.h"
+
+static const char hexchar[16] = "0123456789ABCDEF";
+
+static inline int
+pos(char c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'A' && c <= 'F')
+ return 10 + c - 'A';
+ if (c >= 'a' && c <= 'f')
+ return 10 + c - 'a';
+ return -1;
+}
+
+ROKEN_LIB_FUNCTION ssize_t ROKEN_LIB_CALL
+hex_encode(const void *data, size_t size, char **str)
+{
+ const unsigned char *q = data;
+ size_t i;
+ char *p;
+
+ p = calloc(size + 1, 2);
+ if (p == NULL) {
+ *str = NULL;
+ return -1;
+ }
+
+ for (i = 0; i < size; i++) {
+ p[i * 2] = hexchar[(*q >> 4) & 0xf];
+ p[i * 2 + 1] = hexchar[*q & 0xf];
+ q++;
+ }
+ p[i * 2] = '\0';
+ *str = p;
+
+ return i * 2;
+}
+
+ROKEN_LIB_FUNCTION ssize_t ROKEN_LIB_CALL
+hex_decode(const char *str, void *data, size_t len)
+{
+ size_t l;
+ unsigned char *p = data;
+ size_t i;
+ int d;
+
+ l = strlen(str);
+
+ /* check for overflow, same as (l+1)/2 but overflow safe */
+ if ((l/2) + (l&1) > len)
+ return -1;
+
+ if (l & 1) {
+ if ((d = pos(str[0])) == -1)
+ return -1;
+ p[0] = d;
+ str++;
+ p++;
+ }
+ for (i = 0; i < l / 2; i++) {
+ if ((d = pos(str[i * 2])) == -1)
+ return -1;
+ p[i] = d << 4;
+ if ((d = pos(str[(i * 2) + 1])) == -1)
+ return -1;
+ p[i] |= d;
+ }
+ return i + (l & 1);
+}
diff --git a/third_party/heimdal/lib/roken/hex.h b/third_party/heimdal/lib/roken/hex.h
new file mode 100644
index 0000000..c266268
--- /dev/null
+++ b/third_party/heimdal/lib/roken/hex.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
+ */
+
+/* $Id$ */
+
+#ifndef _rk_HEX_H_
+#define _rk_HEX_H_ 1
+
+#ifndef ROKEN_LIB_FUNCTION
+#ifdef _WIN32
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL __cdecl
+#else
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL
+#endif
+#endif
+
+#define hex_encode rk_hex_encode
+#define hex_decode rk_hex_decode
+
+ROKEN_LIB_FUNCTION ssize_t ROKEN_LIB_CALL
+ hex_encode(const void *, size_t, char **);
+ROKEN_LIB_FUNCTION ssize_t ROKEN_LIB_CALL
+ hex_decode(const char *, void *, size_t);
+
+#endif /* _rk_HEX_H_ */
diff --git a/third_party/heimdal/lib/roken/hostent_find_fqdn.c b/third_party/heimdal/lib/roken/hostent_find_fqdn.c
new file mode 100644
index 0000000..dc3c17f
--- /dev/null
+++ b/third_party/heimdal/lib/roken/hostent_find_fqdn.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1999 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+/*
+ * Try to find a fqdn (with `.') in he if possible, else return h_name
+ */
+
+ROKEN_LIB_FUNCTION const char * ROKEN_LIB_CALL
+hostent_find_fqdn (const struct hostent *he)
+{
+ const char *ret = he->h_name;
+ const char **h;
+
+ if (strchr (ret, '.') == NULL)
+ for (h = (const char **)he->h_aliases; *h != NULL; ++h) {
+ if (strchr (*h, '.') != NULL) {
+ ret = *h;
+ break;
+ }
+ }
+ return ret;
+}
diff --git a/third_party/heimdal/lib/roken/hstrerror.c b/third_party/heimdal/lib/roken/hstrerror.c
new file mode 100644
index 0000000..70b6301
--- /dev/null
+++ b/third_party/heimdal/lib/roken/hstrerror.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1995 - 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#ifndef HAVE_HSTRERROR
+
+#if (defined(SunOS) && (SunOS >= 50))
+#define hstrerror broken_proto
+#endif
+#include "roken.h"
+#if (defined(SunOS) && (SunOS >= 50))
+#undef hstrerror
+#endif
+
+#if !(defined(HAVE_H_ERRLIST) && defined(HAVE_H_NERR))
+static const char *const h_errlist[] = {
+ "Resolver Error 0 (no error)",
+ "Unknown host", /* 1 HOST_NOT_FOUND */
+ "Host name lookup failure", /* 2 TRY_AGAIN */
+ "Unknown server error", /* 3 NO_RECOVERY */
+ "No address associated with name", /* 4 NO_ADDRESS */
+};
+
+static
+const
+int h_nerr = { sizeof h_errlist / sizeof h_errlist[0] };
+#else
+
+#if !HAVE_DECL_H_ERRLIST
+extern const char *h_errlist[];
+extern int h_nerr;
+#endif
+
+#endif
+
+ROKEN_LIB_FUNCTION const char * ROKEN_LIB_CALL
+hstrerror(int herr)
+{
+ if (0 <= herr && herr < h_nerr)
+ return h_errlist[herr];
+ else if(herr == -17)
+ return "unknown error";
+ else
+ return "Error number out of range (hstrerror)";
+}
+
+#endif
diff --git a/third_party/heimdal/lib/roken/ifaddrs.hin b/third_party/heimdal/lib/roken/ifaddrs.hin
new file mode 100644
index 0000000..8896391
--- /dev/null
+++ b/third_party/heimdal/lib/roken/ifaddrs.hin
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2000 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
+ */
+
+/* $Id$ */
+
+#ifndef __ifaddrs_h__
+#define __ifaddrs_h__
+
+#ifndef ROKEN_LIB_FUNCTION
+#ifdef _WIN32
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL _stdcall
+#else
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL
+#endif
+#endif
+
+/*
+ * the interface is defined in terms of the fields below, and this is
+ * sometimes #define'd, so there seems to be no simple way of solving
+ * this and this seemed the best. */
+
+#undef ifa_dstaddr
+
+struct ifaddrs {
+ struct ifaddrs *ifa_next;
+ char *ifa_name;
+ unsigned int ifa_flags;
+ struct sockaddr *ifa_addr;
+ struct sockaddr *ifa_netmask;
+ struct sockaddr *ifa_dstaddr;
+ void *ifa_data;
+};
+
+#ifndef ifa_broadaddr
+#define ifa_broadaddr ifa_dstaddr
+#endif
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_getifaddrs(struct ifaddrs**);
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rk_freeifaddrs(struct ifaddrs*);
+
+#define getifaddrs(a) rk_getifaddrs(a)
+#define freeifaddrs(a) rk_freeifaddrs(a)
+
+#endif /* __ifaddrs_h__ */
diff --git a/third_party/heimdal/lib/roken/inet_aton.c b/third_party/heimdal/lib/roken/inet_aton.c
new file mode 100644
index 0000000..31644a0
--- /dev/null
+++ b/third_party/heimdal/lib/roken/inet_aton.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+/* Minimal implementation of inet_aton.
+ * Cannot distinguish between failure and a local broadcast address. */
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+inet_aton(const char *cp, struct in_addr *addr)
+{
+ addr->s_addr = inet_addr(cp);
+ return (addr->s_addr == INADDR_NONE) ? 0 : 1;
+}
diff --git a/third_party/heimdal/lib/roken/inet_ntop.c b/third_party/heimdal/lib/roken/inet_ntop.c
new file mode 100644
index 0000000..b3c327c
--- /dev/null
+++ b/third_party/heimdal/lib/roken/inet_ntop.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 1999 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+/*
+ *
+ */
+
+static const char *
+inet_ntop_v4 (const void *src, char *dst, size_t size)
+{
+ const char digits[] = "0123456789";
+ int i;
+ struct in_addr *addr = (struct in_addr *)src;
+ u_long a = ntohl(addr->s_addr);
+ const char *orig_dst = dst;
+
+ if (size < INET_ADDRSTRLEN) {
+ errno = ENOSPC;
+ return NULL;
+ }
+ for (i = 0; i < 4; ++i) {
+ int n = (a >> (24 - i * 8)) & 0xFF;
+ int non_zerop = 0;
+
+ if (non_zerop || n / 100 > 0) {
+ *dst++ = digits[n / 100];
+ n %= 100;
+ non_zerop = 1;
+ }
+ if (non_zerop || n / 10 > 0) {
+ *dst++ = digits[n / 10];
+ n %= 10;
+ non_zerop = 1;
+ }
+ *dst++ = digits[n];
+ if (i != 3)
+ *dst++ = '.';
+ }
+ *dst++ = '\0';
+ return orig_dst;
+}
+
+#ifdef HAVE_IPV6
+static const char *
+inet_ntop_v6 (const void *src, char *dst, size_t size)
+{
+ const char xdigits[] = "0123456789abcdef";
+ int i;
+ const struct in6_addr *addr = (struct in6_addr *)src;
+ const u_char *ptr = addr->s6_addr;
+ const char *orig_dst = dst;
+ int compressed = 0;
+
+ if (size < INET6_ADDRSTRLEN) {
+ errno = ENOSPC;
+ return NULL;
+ }
+ for (i = 0; i < 8; ++i) {
+ int non_zerop = 0;
+
+ if (compressed == 0 &&
+ ptr[0] == 0 && ptr[1] == 0 &&
+ i <= 5 &&
+ ptr[2] == 0 && ptr[3] == 0 &&
+ ptr[4] == 0 && ptr[5] == 0) {
+
+ compressed = 1;
+
+ if (i == 0)
+ *dst++ = ':';
+ *dst++ = ':';
+
+ for (ptr += 6, i += 3;
+ i < 8 && ptr[0] == 0 && ptr[1] == 0;
+ ++i, ptr += 2);
+
+ if (i >= 8)
+ break;
+ }
+
+ if (non_zerop || (ptr[0] >> 4)) {
+ *dst++ = xdigits[ptr[0] >> 4];
+ non_zerop = 1;
+ }
+ if (non_zerop || (ptr[0] & 0x0F)) {
+ *dst++ = xdigits[ptr[0] & 0x0F];
+ non_zerop = 1;
+ }
+ if (non_zerop || (ptr[1] >> 4)) {
+ *dst++ = xdigits[ptr[1] >> 4];
+ non_zerop = 1;
+ }
+ *dst++ = xdigits[ptr[1] & 0x0F];
+ if (i != 7)
+ *dst++ = ':';
+ ptr += 2;
+ }
+ *dst++ = '\0';
+ return orig_dst;
+}
+#endif /* HAVE_IPV6 */
+
+ROKEN_LIB_FUNCTION const char * ROKEN_LIB_CALL
+inet_ntop(int af, const void *src, char *dst, size_t size)
+{
+ switch (af) {
+ case AF_INET :
+ return inet_ntop_v4 (src, dst, size);
+#ifdef HAVE_IPV6
+ case AF_INET6 :
+ return inet_ntop_v6 (src, dst, size);
+#endif
+ default :
+ errno = EAFNOSUPPORT;
+ return NULL;
+ }
+}
diff --git a/third_party/heimdal/lib/roken/inet_pton.c b/third_party/heimdal/lib/roken/inet_pton.c
new file mode 100644
index 0000000..e44fb19
--- /dev/null
+++ b/third_party/heimdal/lib/roken/inet_pton.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 1999 - 2000 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+#ifdef HAVE_WINSOCK
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+inet_pton(int af, const char *csrc, void *dst)
+{
+ char * src;
+
+ if (csrc == NULL || (src = strdup(csrc)) == NULL) {
+ _set_errno( ENOMEM );
+ return 0;
+ }
+
+ switch (af) {
+ case AF_INET:
+ {
+ struct sockaddr_in si4;
+ INT r;
+ INT s = sizeof(si4);
+
+ si4.sin_family = AF_INET;
+ r = WSAStringToAddress(src, AF_INET, NULL, (LPSOCKADDR) &si4, &s);
+ free(src);
+ src = NULL;
+
+ if (r == 0) {
+ memcpy(dst, &si4.sin_addr, sizeof(si4.sin_addr));
+ return 1;
+ }
+ }
+ break;
+
+ case AF_INET6:
+ {
+ struct sockaddr_in6 si6;
+ INT r;
+ INT s = sizeof(si6);
+
+ si6.sin6_family = AF_INET6;
+ r = WSAStringToAddress(src, AF_INET6, NULL, (LPSOCKADDR) &si6, &s);
+ free(src);
+ src = NULL;
+
+ if (r == 0) {
+ memcpy(dst, &si6.sin6_addr, sizeof(si6.sin6_addr));
+ return 1;
+ }
+ }
+ break;
+
+ default:
+ _set_errno( EAFNOSUPPORT );
+ return -1;
+ }
+
+ /* the call failed */
+ {
+ int le = WSAGetLastError();
+
+ if (le == WSAEINVAL)
+ return 0;
+
+ _set_errno(le);
+ return -1;
+ }
+}
+
+#else /* !HAVE_WINSOCK */
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+inet_pton(int af, const char *src, void *dst)
+{
+ if (af != AF_INET) {
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+ return inet_aton (src, dst);
+}
+
+#endif
diff --git a/third_party/heimdal/lib/roken/initgroups.c b/third_party/heimdal/lib/roken/initgroups.c
new file mode 100644
index 0000000..2ba944c
--- /dev/null
+++ b/third_party/heimdal/lib/roken/initgroups.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+initgroups(const char *name, gid_t basegid)
+{
+ return 0;
+}
diff --git a/third_party/heimdal/lib/roken/innetgr.c b/third_party/heimdal/lib/roken/innetgr.c
new file mode 100644
index 0000000..e1783bb
--- /dev/null
+++ b/third_party/heimdal/lib/roken/innetgr.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 KTH 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 KTH AND ITS 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 KTH OR ITS 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 <config.h>
+#include "roken.h"
+
+#ifndef HAVE_INNETGR
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+innetgr(const char *netgroup, const char *machine,
+ const char *user, const char *domain)
+{
+ return 0;
+}
+#endif
+
diff --git a/third_party/heimdal/lib/roken/install-sh b/third_party/heimdal/lib/roken/install-sh
new file mode 100644
index 0000000..e9de238
--- /dev/null
+++ b/third_party/heimdal/lib/roken/install-sh
@@ -0,0 +1,251 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ chmodcmd=""
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
diff --git a/third_party/heimdal/lib/roken/issuid.c b/third_party/heimdal/lib/roken/issuid.c
new file mode 100644
index 0000000..b9b7440
--- /dev/null
+++ b/third_party/heimdal/lib/roken/issuid.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 1998 - 2017 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#ifdef HAVE_SYS_AUXV_H
+#include <sys/auxv.h>
+#endif
+
+#include <errno.h>
+
+#include "roken.h"
+#include "getauxval.h"
+
+extern int rk_injected_auxv;
+
+/**
+ * Returns non-zero if the caller's process started as set-uid or
+ * set-gid (and therefore the environment cannot be trusted).
+ *
+ * As much as possible this implements the same functionality and
+ * semantics as OpenBSD's issetugid() (as opposed to FreeBSD's).
+ *
+ * Preserves errno.
+ *
+ * @return Non-zero if the environment is not trusted.
+ */
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+issuid(void)
+{
+#ifdef WIN32
+ return 0; /* No set-id programs or anything like it on Windows */
+#else
+ /*
+ * We want to use issetugid(), but issetugid() is not the same on
+ * all OSes.
+ *
+ * On OpenBSD (where issetugid() originated), Illumos derivatives,
+ * and Solaris, issetugid() returns true IFF the program exec()ed
+ * was set-uid or set-gid.
+ *
+ * FreeBSD departed from OpenBSD's issetugid() semantics, and other
+ * BSDs (NetBSD, DragonFly) and OS X adopted FreeBSD's.
+ *
+ * FreeBSDs' issetugid() returns true if the program exec()ed was
+ * set-uid or set-gid, or if the process has switched UIDs/GIDs or
+ * otherwise changed privileges or is a descendant of such a process
+ * and has not exec()ed since.
+ *
+ * The FreeBSD/NetBSD issetugid() does us no good because we _want_
+ * to trust the environment when the process started life as
+ * non-set-uid root (or otherwise privileged). There's nothing
+ * about _dropping_ privileges (without having gained them first)
+ * that taints the environment. It's not like calling system(),
+ * say, might change the environment of the caller.
+ *
+ * We want OpenBSD's issetugid() semantics.
+ *
+ * Linux, meanwhile, has no issetugid() (at least glibc doesn't
+ * anyways) but has an equivalent: getauxval(AT_SECURE).
+ *
+ * To be really specific: we want getauxval(AT_SECURE) semantics
+ * because there may be ways in which a process might gain privilege
+ * at exec time other than by exec'ing a set-id program.
+ *
+ * Where we use getauxval(), we really use our getauxval(), the one
+ * that isn't broken the way glibc's used to be. Our getauxval()
+ * also works on more systems than actually provide one.
+ *
+ * In order to avoid FreeBSD issetugid() semantics, where available,
+ * we use the ELF auxilliary vector to implement OpenBSD semantics
+ * before finally falling back on issetugid().
+ *
+ * All of this is as of April 2017, and might become stale in the
+ * future.
+ */
+ static int we_are_suid = -1; /* Memoize; -1 == dunno */
+ int save_errno = errno;
+#if defined(AT_EUID) && defined(AT_UID) && defined(AT_EGID) && defined(AT_GID)
+ int seen = 0;
+#endif
+
+ if (we_are_suid >= 0 && !rk_injected_auxv)
+ return we_are_suid;
+
+#ifdef AT_SECURE
+ errno = 0;
+ if (rk_getauxval(AT_SECURE) != 0) {
+ errno = save_errno;
+ return we_are_suid = 1;
+ } else if (errno == 0) {
+ errno = save_errno;
+ return we_are_suid = 0;
+ }
+ /* errno == ENOENT; AT_SECURE not found; fall through */
+#endif
+
+#if defined(AT_EUID) && defined(AT_UID) && defined(AT_EGID) && defined(AT_GID)
+ {
+ unsigned long euid;
+ unsigned long uid;
+
+ errno = 0;
+ euid = rk_getauxval(AT_EUID);
+ if (errno == 0)
+ seen |= 1;
+ errno = 0;
+ uid = rk_getauxval(AT_UID);
+ if (errno == 0)
+ seen |= 2;
+ if (euid != uid) {
+ errno = save_errno;
+ return we_are_suid = 1;
+ }
+ }
+ /* Check GIDs */
+ {
+ unsigned long egid;
+ unsigned long gid;
+
+ errno = 0;
+ egid = rk_getauxval(AT_EGID);
+ if (errno == 0)
+ seen |= 4;
+ errno = 0;
+ gid = rk_getauxval(AT_GID);
+ if (errno == 0)
+ seen |= 8;
+ if (egid != gid) {
+ errno = save_errno;
+ return we_are_suid = 1;
+ }
+ }
+ errno = save_errno;
+ if (seen == 15)
+ return we_are_suid = 0;
+#endif
+
+#if defined(HAVE_ISSETUGID)
+ /* If issetugid() == 0 then we're definitely OK then */
+ if (issetugid() == 0)
+ return we_are_suid = 0;
+ /* issetugid() == 1 might have been a false positive; fall through */
+#endif
+
+#ifdef AT_EXECFN
+ /*
+ * There's an auxval by which to find the path of the program this
+ * process exec'ed.
+ *
+ * We can stat() it. If the program did a chroot() and the chroot
+ * has a program with the same path but not set-uid/set-gid, of
+ * course, we lose here. But a) that's a bit of a stretch, b)
+ * there's not much more we can do here.
+ *
+ * Also, this is technically a TOCTOU race, though for set-id
+ * programs this is exceedingly unlikely to be an actual TOCTOU
+ * race.
+ *
+ * TODO We should really make sure that none of the path components of the
+ * execpath are symlinks.
+ */
+ {
+ unsigned long p = rk_getauxval(AT_EXECPATH);
+ struct stat st;
+
+ if (p != 0 && *(const char *)p == '/' &&
+ stat((const char *)p, &st) == 0) {
+ if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID)) {
+ errno = save_errno;
+ return we_are_suid = 1;
+ }
+ errno = save_errno;
+ return we_are_suid = 0;
+ }
+ }
+ /* Fall through */
+#endif
+
+#if defined(HAVE_ISSETUGID)
+ errno = save_errno;
+ return we_are_suid = 1;
+#else
+ /*
+ * Paranoia: for extra safety we ought to default to returning 1.
+ *
+ * But who knows what that might break where users link statically
+ * (so no auxv), say.
+ *
+ * We'll check the actual real and effective IDs (as opposed to the
+ * ones at main() start time.
+ *
+ * For now we stick to returning zero by default. We've been rather
+ * heroic above trying to find out if we're suid, and we're running
+ * on a rather old or uncool OS if we've gotten here.
+ */
+
+#if defined(HAVE_GETRESUID)
+ /*
+ * If r/e/suid are all the same then chances are very good we did
+ * not start as set-uid. Though this could be a login program that
+ * started out as privileged and is calling Heimdal "as the user".
+ *
+ * Again, such a program would have to be statically linked to get
+ * here.
+ */
+ {
+ uid_t r, e, s;
+ if (getresuid(&r, &e, &s) == 0) {
+ if (r != e || r != s) {
+ errno = save_errno;
+ return we_are_suid = 1;
+ }
+ }
+ }
+#endif
+#if defined(HAVE_GETRESGID)
+ {
+ gid_t r, e, s;
+ if (getresgid(&r, &e, &s) == 0) {
+ if (r != e || r != s) {
+ errno = save_errno;
+ return we_are_suid = 1;
+ }
+ }
+ }
+#endif
+#if defined(HAVE_GETRESUID) && defined(HAVE_GETRESGID)
+ errno = save_errno;
+ return we_are_suid = 0;
+
+#else /* avoid compiler warnings about dead code */
+
+#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
+ if (getuid() != geteuid())
+ return we_are_suid = 1;
+#endif
+#if defined(HAVE_GETGID) && defined(HAVE_GETEGID)
+ if (getgid() != getegid())
+ return we_are_suid = 1;
+#endif
+
+ errno = save_errno;
+ return we_are_suid = 0;
+#endif /* !defined(HAVE_GETRESUID) || !defined(HAVE_GETRESGID) */
+#endif /* !defined(HAVE_ISSETUGID) */
+#endif /* WIN32 */
+}
diff --git a/third_party/heimdal/lib/roken/localtime_r.c b/third_party/heimdal/lib/roken/localtime_r.c
new file mode 100644
index 0000000..fa3d126
--- /dev/null
+++ b/third_party/heimdal/lib/roken/localtime_r.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2000 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <stdio.h>
+#include <time.h>
+#include "roken.h"
+
+#ifndef HAVE_LOCALTIME_R
+
+ROKEN_LIB_FUNCTION struct tm * ROKEN_LIB_CALL
+localtime_r(const time_t *timer, struct tm *result)
+{
+#ifdef _MSC_VER
+
+ return (localtime_s(result, timer) == 0)? result : NULL;
+
+#else
+ struct tm *tm;
+
+ tm = localtime((time_t *)timer);
+ if (tm == NULL)
+ return NULL;
+ *result = *tm;
+ return result;
+#endif
+}
+
+#endif
diff --git a/third_party/heimdal/lib/roken/lstat.c b/third_party/heimdal/lib/roken/lstat.c
new file mode 100644
index 0000000..4692588
--- /dev/null
+++ b/third_party/heimdal/lib/roken/lstat.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+lstat(const char *path, struct stat *buf)
+{
+ return stat(path, buf);
+}
diff --git a/third_party/heimdal/lib/roken/memmem.c b/third_party/heimdal/lib/roken/memmem.c
new file mode 100644
index 0000000..3f9c6bc
--- /dev/null
+++ b/third_party/heimdal/lib/roken/memmem.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef HAVE_MEMMEM
+#include "roken.h"
+ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL
+memmem(const void *haystack,
+ size_t haystacklen,
+ const void *needle,
+ size_t needlelen)
+{
+ const unsigned char *hs = haystack;
+ const unsigned char *n = needle;
+ size_t hsi, ni;
+
+ if (haystacklen < needlelen || haystacklen == 0)
+ return NULL;
+ /*
+ * Imagine a haystack of length 5 and needle of length 2, then the largest
+ * index in the haystack at which we can bother looking for the needle is:
+ *
+ * 0 1 2 3 4
+ * +---------+
+ * |?|?|?|?|?|
+ * +---------+
+ * ^
+ * \
+ * here, at index 3, which is 5 - 2, and less than (5 - 2 + 1).
+ */
+ for (hsi = 0, ni = 0; hsi < (haystacklen - needlelen + 1); hsi++, ni = 0) {
+ while (ni < needlelen && n[ni] == hs[hsi + ni])
+ ni++;
+ if (ni == needlelen)
+ return rk_UNCONST(&hs[hsi]);
+ }
+ return NULL;
+}
+#endif
diff --git a/third_party/heimdal/lib/roken/memmove.c b/third_party/heimdal/lib/roken/memmove.c
new file mode 100644
index 0000000..1825d7e
--- /dev/null
+++ b/third_party/heimdal/lib/roken/memmove.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+/*
+ * memmove for systems that doesn't have it
+ */
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+ROKEN_LIB_FUNCTION void* ROKEN_LIB_CALL
+memmove(void *s1, const void *s2, size_t n)
+{
+ char *s=(char*)s2, *d=(char*)s1;
+
+ if(d > s){
+ s+=n-1;
+ d+=n-1;
+ while(n){
+ *d--=*s--;
+ n--;
+ }
+ }else if(d < s)
+ while(n){
+ *d++=*s++;
+ n--;
+ }
+ return s1;
+}
diff --git a/third_party/heimdal/lib/roken/memset_s.c b/third_party/heimdal/lib/roken/memset_s.c
new file mode 100644
index 0000000..207fe19
--- /dev/null
+++ b/third_party/heimdal/lib/roken/memset_s.c
@@ -0,0 +1,51 @@
+/***********************************************************************
+ * Copyright (c) 2015, Your File System Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDER 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 <config.h>
+#include "roken.h"
+
+int ROKEN_LIB_FUNCTION
+memset_s(void *s, size_t smax, int c, size_t n)
+{
+ volatile unsigned char *p = s;
+
+#ifdef _WIN32
+ if (c == 0) {
+ SecureZeroMemory(s, n);
+ return 0;
+ }
+#endif
+
+ while (n--)
+ *p++ = c;
+
+ return 0;
+}
diff --git a/third_party/heimdal/lib/roken/mergesort.c b/third_party/heimdal/lib/roken/mergesort.c
new file mode 100644
index 0000000..ba51889
--- /dev/null
+++ b/third_party/heimdal/lib/roken/mergesort.c
@@ -0,0 +1,50 @@
+/***********************************************************************
+ * Copyright (c) 2020, AuriStor, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDER 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 <config.h>
+#include "roken.h"
+
+static int
+mergesort_compar_thunk(const void *a, const void *b, void *thunk)
+{
+ int (*compar)(const void *, const void *) = thunk;
+
+ return compar(a, b);
+}
+
+int ROKEN_LIB_FUNCTION
+mergesort(void *base, size_t nel, size_t width,
+ int (*compar)(const void *, const void *))
+{
+ return rk_mergesort_r(base, nel, width,
+ mergesort_compar_thunk, compar);
+}
+
diff --git a/third_party/heimdal/lib/roken/mergesort_r.c b/third_party/heimdal/lib/roken/mergesort_r.c
new file mode 100644
index 0000000..4fbcd70
--- /dev/null
+++ b/third_party/heimdal/lib/roken/mergesort_r.c
@@ -0,0 +1,338 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Peter McIlroy.
+ *
+ * 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 <config.h>
+#include "roken.h"
+
+/*
+ * Hybrid exponential search/linear search merge sort with hybrid
+ * natural/pairwise first pass. Requires about .3% more comparisons
+ * for random data than LSMS with pairwise first pass alone.
+ * It works for objects as small as two bytes.
+ */
+
+#define NATURAL
+#define THRESHOLD 16 /* Best choice for natural merge cut-off. */
+
+/* #define NATURAL to get hybrid natural merge.
+ * (The default is pairwise merging.)
+ */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef int (*cmp_t)(const void *, const void *, void *);
+
+static void setup(u_char *, u_char *, size_t, size_t, cmp_t, void *);
+static void insertionsort(u_char *, size_t, size_t, cmp_t, void *);
+
+#define ISIZE sizeof(int)
+#define PSIZE sizeof(u_char *)
+#define ICOPY_LIST(src, dst, last) \
+ do \
+ *(int*)dst = *(int*)src, src += ISIZE, dst += ISIZE; \
+ while(src < last)
+#define ICOPY_ELT(src, dst, i) \
+ do \
+ *(int*) dst = *(int*) src, src += ISIZE, dst += ISIZE; \
+ while (i -= ISIZE)
+
+#define CCOPY_LIST(src, dst, last) \
+ do \
+ *dst++ = *src++; \
+ while (src < last)
+#define CCOPY_ELT(src, dst, i) \
+ do \
+ *dst++ = *src++; \
+ while (i -= 1)
+
+/*
+ * Find the next possible pointer head. (Trickery for forcing an array
+ * to do double duty as a linked list when objects do not align with word
+ * boundaries.
+ */
+/* Assumption: PSIZE is a power of 2. */
+#define EVAL(p) (u_char **) \
+ ((((uintptr_t)p + PSIZE - 1) & ~(PSIZE - 1)))
+
+/*
+ * Arguments are as for qsort_r, except thunk is moved to the last
+ * parameter for glibc compatibility. See:
+ * https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=214248
+ */
+int
+mergesort_r(void *base, size_t nmemb, size_t size, cmp_t cmp, void *thunk)
+{
+ size_t i;
+ int sense;
+ int big, iflag;
+ u_char *f1, *f2, *t, *b, *tp2, *q, *l1, *l2;
+ u_char *list2, *list1, *p2, *p, *last, **p1;
+ u_char *freeme = NULL;
+
+ if (size < PSIZE / 2) { /* Pointers must fit into 2 * size. */
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (nmemb == 0)
+ return (0);
+
+ /*
+ * XXX
+ * Stupid subtraction for the Cray.
+ */
+ iflag = 0;
+ if (!(size % ISIZE) && !(((uintptr_t)base) % ISIZE))
+ iflag = 1;
+
+ if ((list2 = freeme = malloc(nmemb * size + PSIZE)) == NULL)
+ return (-1);
+
+ list1 = base;
+ setup(list1, list2, nmemb, size, cmp, thunk);
+ last = list2 + nmemb * size;
+ i = big = 0;
+ while (*EVAL(list2) != last) {
+ l2 = list1;
+ p1 = EVAL(list1);
+ for (tp2 = p2 = list2; p2 != last; p1 = EVAL(l2)) {
+ p2 = *EVAL(p2);
+ f1 = l2;
+ f2 = l1 = list1 + (p2 - list2);
+ if (p2 != last)
+ p2 = *EVAL(p2);
+ l2 = list1 + (p2 - list2);
+ while (f1 < l1 && f2 < l2) {
+ if (cmp(f1, f2, thunk) <= 0) {
+ q = f2;
+ b = f1, t = l1;
+ sense = -1;
+ } else {
+ q = f1;
+ b = f2, t = l2;
+ sense = 0;
+ }
+ if (!big) { /* here i = 0 */
+ while ((b += size) < t && cmp(q, b, thunk) >sense)
+ if (++i == 6) {
+ big = 1;
+ goto EXPONENTIAL;
+ }
+ } else {
+EXPONENTIAL: for (i = size; ; i <<= 1)
+ if ((p = (b + i)) >= t) {
+ if ((p = t - size) > b &&
+ cmp(q, p, thunk) <= sense)
+ t = p;
+ else
+ b = p;
+ break;
+ } else if (cmp(q, p, thunk) <= sense) {
+ t = p;
+ if (i == size)
+ big = 0;
+ goto FASTCASE;
+ } else
+ b = p;
+ while (t > b+size) {
+ i = (((t - b) / size) >> 1) * size;
+ if (cmp(q, p = b + i, thunk) <= sense)
+ t = p;
+ else
+ b = p;
+ }
+ goto COPY;
+FASTCASE: while (i > size)
+ if (cmp(q,
+ p = b + (i >>= 1), thunk) <= sense)
+ t = p;
+ else
+ b = p;
+COPY: b = t;
+ }
+ i = size;
+ if (q == f1) {
+ if (iflag) {
+ ICOPY_LIST(f2, tp2, b);
+ ICOPY_ELT(f1, tp2, i);
+ } else {
+ CCOPY_LIST(f2, tp2, b);
+ CCOPY_ELT(f1, tp2, i);
+ }
+ } else {
+ if (iflag) {
+ ICOPY_LIST(f1, tp2, b);
+ ICOPY_ELT(f2, tp2, i);
+ } else {
+ CCOPY_LIST(f1, tp2, b);
+ CCOPY_ELT(f2, tp2, i);
+ }
+ }
+ }
+ if (f2 < l2) {
+ if (iflag)
+ ICOPY_LIST(f2, tp2, l2);
+ else
+ CCOPY_LIST(f2, tp2, l2);
+ } else if (f1 < l1) {
+ if (iflag)
+ ICOPY_LIST(f1, tp2, l1);
+ else
+ CCOPY_LIST(f1, tp2, l1);
+ }
+ *p1 = l2;
+ }
+ tp2 = list1; /* swap list1, list2 */
+ list1 = list2;
+ list2 = tp2;
+ last = list2 + nmemb*size;
+ }
+ if (base == list2)
+ memmove(list2, list1, nmemb*size);
+ free(freeme);
+ return (0);
+}
+
+#define swap(a, b) { \
+ s = b; \
+ i = size; \
+ do { \
+ tmp = *a; *a++ = *s; *s++ = tmp; \
+ } while (--i); \
+ a -= size; \
+ }
+#define reverse(bot, top) { \
+ s = top; \
+ do { \
+ i = size; \
+ do { \
+ tmp = *bot; *bot++ = *s; *s++ = tmp; \
+ } while (--i); \
+ s -= size2; \
+ } while(bot < s); \
+}
+
+/*
+ * Optional hybrid natural/pairwise first pass. Eats up list1 in runs of
+ * increasing order, list2 in a corresponding linked list. Checks for runs
+ * when THRESHOLD/2 pairs compare with same sense. (Only used when NATURAL
+ * is defined. Otherwise simple pairwise merging is used.)
+ */
+void
+setup(u_char *list1, u_char *list2, size_t n, size_t size, cmp_t cmp, void *thunk)
+{
+ int i, length, size2, tmp, sense;
+ u_char *f1, *f2, *s, *l2, *last, *p2;
+
+ size2 = size*2;
+ if (n <= 5) {
+ insertionsort(list1, n, size, cmp, thunk);
+ *EVAL(list2) = (u_char*) list2 + n*size;
+ return;
+ }
+ /*
+ * Avoid running pointers out of bounds; limit n to evens
+ * for simplicity.
+ */
+ i = 4 + (n & 1);
+ insertionsort(list1 + (n - i) * size, i, size, cmp, thunk);
+ last = list1 + size * (n - i);
+ *EVAL(list2 + (last - list1)) = list2 + n * size;
+
+#ifdef NATURAL
+ p2 = list2;
+ f1 = list1;
+ sense = (cmp(f1, f1 + size, thunk) > 0);
+ for (; f1 < last; sense = !sense) {
+ length = 2;
+ /* Find pairs with same sense. */
+ for (f2 = f1 + size2; f2 < last; f2 += size2) {
+ if ((cmp(f2, f2+ size, thunk) > 0) != sense)
+ break;
+ length += 2;
+ }
+ if (length < THRESHOLD) { /* Pairwise merge */
+ do {
+ p2 = *EVAL(p2) = f1 + size2 - list1 + list2;
+ if (sense > 0)
+ swap (f1, f1 + size);
+ } while ((f1 += size2) < f2);
+ } else { /* Natural merge */
+ l2 = f2;
+ for (f2 = f1 + size2; f2 < l2; f2 += size2) {
+ if ((cmp(f2-size, f2, thunk) > 0) != sense) {
+ p2 = *EVAL(p2) = f2 - list1 + list2;
+ if (sense > 0)
+ reverse(f1, f2-size);
+ f1 = f2;
+ }
+ }
+ if (sense > 0)
+ reverse (f1, f2-size);
+ f1 = f2;
+ if (f2 < last || cmp(f2 - size, f2, thunk) > 0)
+ p2 = *EVAL(p2) = f2 - list1 + list2;
+ else
+ p2 = *EVAL(p2) = list2 + n*size;
+ }
+ }
+#else /* pairwise merge only. */
+ for (f1 = list1, p2 = list2; f1 < last; f1 += size2) {
+ p2 = *EVAL(p2) = p2 + size2;
+ if (cmp (f1, f1 + size) > 0)
+ swap(f1, f1 + size);
+ }
+#endif /* NATURAL */
+}
+
+/*
+ * This is to avoid out-of-bounds addresses in sorting the
+ * last 4 elements.
+ */
+static void
+insertionsort(u_char *a, size_t n, size_t size, cmp_t cmp, void *thunk)
+{
+ u_char *ai, *s, *t, *u, tmp;
+ int i;
+
+ for (ai = a+size; --n >= 1; ai += size)
+ for (t = ai; t > a; t -= size) {
+ u = t - size;
+ if (cmp(u, t, thunk) <= 0)
+ break;
+ swap(u, t);
+ }
+}
diff --git a/third_party/heimdal/lib/roken/mini_inetd.c b/third_party/heimdal/lib/roken/mini_inetd.c
new file mode 100644
index 0000000..a9398f4
--- /dev/null
+++ b/third_party/heimdal/lib/roken/mini_inetd.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 1995 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <err.h>
+#include "roken.h"
+
+/*
+ * accept a connection on `s' and pretend it's served by inetd.
+ */
+
+static void
+accept_it (rk_socket_t s, rk_socket_t *ret_socket)
+{
+ rk_socket_t as;
+
+ as = accept(s, NULL, NULL);
+ if(rk_IS_BAD_SOCKET(as))
+ err (1, "accept");
+
+ if (ret_socket) {
+
+ *ret_socket = as;
+
+ } else {
+ int fd = socket_to_fd(as, 0);
+
+ /* We would use _O_RDONLY for the socket_to_fd() call for
+ STDIN, but there are instances where we assume that STDIN
+ is a r/w socket. */
+
+ dup2(fd, STDIN_FILENO);
+ dup2(fd, STDOUT_FILENO);
+
+ rk_closesocket(as);
+ }
+}
+
+/**
+ * Listen on a specified addresses
+ *
+ * Listens on the specified addresses for incoming connections. If
+ * the \a ret_socket parameter is \a NULL, on return STDIN and STDOUT
+ * will be connected to an accepted socket. If the \a ret_socket
+ * parameter is non-NULL, the accepted socket will be returned in
+ * *ret_socket. In the latter case, STDIN and STDOUT will be left
+ * unmodified.
+ *
+ * This function does not return if there is an error or if no
+ * connection is established.
+ *
+ * @param[in] ai Addresses to listen on
+ * @param[out] ret_socket If non-NULL receives the accepted socket.
+ *
+ * @see mini_inetd()
+ */
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+mini_inetd_addrinfo (struct addrinfo *ai, rk_socket_t *ret_socket)
+{
+ int ret;
+ struct addrinfo *a;
+ int n, nalloc, i;
+ rk_socket_t *fds;
+ fd_set orig_read_set, read_set;
+ rk_socket_t max_fd = (rk_socket_t)-1;
+
+ for (nalloc = 0, a = ai; a != NULL; a = a->ai_next)
+ ++nalloc;
+
+ fds = malloc (nalloc * sizeof(*fds));
+ if (fds == NULL) {
+ errx (1, "mini_inetd: out of memory");
+ UNREACHABLE(return);
+ }
+
+ FD_ZERO(&orig_read_set);
+
+ for (i = 0, a = ai; a != NULL; a = a->ai_next) {
+ fds[i] = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
+ if (rk_IS_BAD_SOCKET(fds[i]))
+ continue;
+ socket_set_reuseaddr (fds[i], 1);
+ socket_set_ipv6only(fds[i], 1);
+ if (rk_IS_SOCKET_ERROR(bind (fds[i], a->ai_addr, a->ai_addrlen))) {
+ warn ("bind af = %d", a->ai_family);
+ rk_closesocket(fds[i]);
+ fds[i] = rk_INVALID_SOCKET;
+ continue;
+ }
+ if (rk_IS_SOCKET_ERROR(listen (fds[i], SOMAXCONN))) {
+ warn ("listen af = %d", a->ai_family);
+ rk_closesocket(fds[i]);
+ fds[i] = rk_INVALID_SOCKET;
+ continue;
+ }
+#ifndef NO_LIMIT_FD_SETSIZE
+ if (fds[i] >= FD_SETSIZE)
+ errx (1, "fd too large");
+#endif
+ FD_SET(fds[i], &orig_read_set);
+ max_fd = max(max_fd, fds[i]);
+ ++i;
+ }
+ if (i == 0)
+ errx (1, "no sockets");
+ n = i;
+
+ do {
+ read_set = orig_read_set;
+
+ ret = select (max_fd + 1, &read_set, NULL, NULL, NULL);
+ if (rk_IS_SOCKET_ERROR(ret) && rk_SOCK_ERRNO != EINTR)
+ err (1, "select");
+ } while (ret <= 0);
+
+ for (i = 0; i < n; ++i)
+ if (FD_ISSET (fds[i], &read_set)) {
+ accept_it (fds[i], ret_socket);
+ for (i = 0; i < n; ++i)
+ rk_closesocket(fds[i]);
+ free(fds);
+ return;
+ }
+ abort ();
+}
+
+/**
+ * Listen on a specified port
+ *
+ * Listens on the specified port for incoming connections. If the \a
+ * ret_socket parameter is \a NULL, on return STDIN and STDOUT will be
+ * connected to an accepted socket. If the \a ret_socket parameter is
+ * non-NULL, the accepted socket will be returned in *ret_socket. In
+ * the latter case, STDIN and STDOUT will be left unmodified.
+ *
+ * This function does not return if there is an error or if no
+ * connection is established.
+ *
+ * @param[in] port Port to listen on
+ * @param[out] ret_socket If non-NULL receives the accepted socket.
+ *
+ * @see mini_inetd_addrinfo()
+ */
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+mini_inetd(int port, rk_socket_t * ret_socket)
+{
+ int error;
+ struct addrinfo *ai, hints;
+ char portstr[NI_MAXSERV];
+
+ memset (&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_family = PF_UNSPEC;
+
+ snprintf (portstr, sizeof(portstr), "%d", ntohs(port));
+
+ error = getaddrinfo (NULL, portstr, &hints, &ai);
+ if (error)
+ errx (1, "getaddrinfo: %s", gai_strerror (error));
+
+ mini_inetd_addrinfo(ai, ret_socket);
+
+ freeaddrinfo(ai);
+}
+
diff --git a/third_party/heimdal/lib/roken/missing b/third_party/heimdal/lib/roken/missing
new file mode 100644
index 0000000..7789652
--- /dev/null
+++ b/third_party/heimdal/lib/roken/missing
@@ -0,0 +1,190 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+# Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+# Franc,ois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+fi
+
+case "$1" in
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+
+Supported PROGRAM values:
+ aclocal touch file \`aclocal.m4'
+ autoconf touch file \`configure'
+ autoheader touch file \`config.h.in'
+ automake touch all \`Makefile.in' files
+ bison create \`y.tab.[ch]', if possible, from existing .[ch]
+ flex create \`lex.yy.c', if possible, from existing .c
+ lex create \`lex.yy.c', if possible, from existing .c
+ makeinfo touch the output file
+ yacc create \`y.tab.[ch]', if possible, from existing .[ch]"
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing - GNU libit 0.0"
+ ;;
+
+ -*)
+ echo 1>&2 "$0: Unknown \`$1' option"
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+ ;;
+
+ aclocal)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`acinclude.m4' or \`configure.in'. You might want
+ to install the \`Automake' and \`Perl' packages. Grab them from
+ any GNU archive site."
+ touch aclocal.m4
+ ;;
+
+ autoconf)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`configure.in'. You might want to install the
+ \`Autoconf' and \`GNU m4' packages. Grab them from any GNU
+ archive site."
+ touch configure
+ ;;
+
+ autoheader)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`acconfig.h' or \`configure.in'. You might want
+ to install the \`Autoconf' and \`GNU m4' packages. Grab them
+ from any GNU archive site."
+ files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' configure.in`
+ test -z "$files" && files="config.h"
+ touch_files=
+ for f in $files; do
+ case "$f" in
+ *:*) touch_files="$touch_files "`echo "$f" |
+ sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+ *) touch_files="$touch_files $f.in";;
+ esac
+ done
+ touch $touch_files
+ ;;
+
+ automake)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'.
+ You might want to install the \`Automake' and \`Perl' packages.
+ Grab them from any GNU archive site."
+ find . -type f -name Makefile.am -print |
+ sed 's/\.am$/.in/' |
+ while read f; do touch "$f"; done
+ ;;
+
+ bison|yacc)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.y' file. You may need the \`Bison' package
+ in order for those modifications to take effect. You can get
+ \`Bison' from any GNU archive site."
+ rm -f y.tab.c y.tab.h
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.y)
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.c
+ fi
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.h
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f y.tab.h ]; then
+ echo >y.tab.h
+ fi
+ if [ ! -f y.tab.c ]; then
+ echo 'main() { return 0; }' >y.tab.c
+ fi
+ ;;
+
+ lex|flex)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.l' file. You may need the \`Flex' package
+ in order for those modifications to take effect. You can get
+ \`Flex' from any GNU archive site."
+ rm -f lex.yy.c
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.l)
+ SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" lex.yy.c
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f lex.yy.c ]; then
+ echo 'main() { return 0; }' >lex.yy.c
+ fi
+ ;;
+
+ makeinfo)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.texi' or \`.texinfo' file, or any other file
+ indirectly affecting the aspect of the manual. The spurious
+ call might also be the consequence of using a buggy \`make' (AIX,
+ DU, IRIX). You might want to install the \`Texinfo' package or
+ the \`GNU make' package. Grab either from any GNU archive site."
+ file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+ if test -z "$file"; then
+ file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+ file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
+ fi
+ touch $file
+ ;;
+
+ *)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, and you do not seem to have it handy on your
+ system. You might have modified some files without having the
+ proper tools for further handling them. Check the \`README' file,
+ it often tells you about the needed prerequirements for installing
+ this package. You may also peek at any GNU archive site, in case
+ some other package would contain this missing \`$1' program."
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/third_party/heimdal/lib/roken/mkdir.c b/third_party/heimdal/lib/roken/mkdir.c
new file mode 100644
index 0000000..5ed4c0d
--- /dev/null
+++ b/third_party/heimdal/lib/roken/mkdir.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#ifdef WIN32
+#include <direct.h>
+#endif
+
+#include "roken.h"
+#ifndef WIN32
+ #undef rk_mkdir
+#endif
+
+int ROKEN_LIB_FUNCTION
+rk_mkdir(const char *pathname, mode_t mode)
+{
+#ifdef WIN32
+ return _mkdir(pathname);
+#else
+ return mkdir(pathname, mode);
+#endif
+}
diff --git a/third_party/heimdal/lib/roken/mkdtemp.c b/third_party/heimdal/lib/roken/mkdtemp.c
new file mode 100644
index 0000000..c9f7463
--- /dev/null
+++ b/third_party/heimdal/lib/roken/mkdtemp.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2020 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <string.h>
+#include <errno.h>
+
+#include <roken.h>
+
+#ifndef O_APPEND
+#define O_APPEND 0
+#endif
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
+#ifndef O_SYNC
+#define O_SYNC 0
+#endif
+
+#ifndef HAVE_MKDTEMP
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+mkdtemp(char *template)
+{
+ size_t len = strlen(template) - 1;
+ size_t start, i;
+ pid_t val = getpid();
+
+ for (i = 0; i < len && i < 7 && template[len - i] == 'X'; i++) {
+ template[len - i] = '0' + val % 10;
+ val /= 10;
+ if (!val)
+ val = getpid();
+ }
+
+ if (i < 6) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ start = len - i;
+ do {
+ if (mkdir(template, 0700) == 0)
+ return template;
+ for (i = start + 1; i < len; i++) {
+ if (++(template[i]) == '9' + 1)
+ template[i] = 'a';
+ if (template[i] <= 'z')
+ break;
+ template[i] = 'a';
+ }
+ } while(1);
+}
+#endif
diff --git a/third_party/heimdal/lib/roken/mkinstalldirs b/third_party/heimdal/lib/roken/mkinstalldirs
new file mode 100644
index 0000000..6b3b5fc
--- /dev/null
+++ b/third_party/heimdal/lib/roken/mkinstalldirs
@@ -0,0 +1,40 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+# $Id$
+
+errstatus=0
+
+for file
+do
+ set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+ shift
+
+ pathcomp=
+ for d
+ do
+ pathcomp="$pathcomp$d"
+ case "$pathcomp" in
+ -* ) pathcomp=./$pathcomp ;;
+ esac
+
+ if test ! -d "$pathcomp"; then
+ echo "mkdir $pathcomp"
+
+ mkdir "$pathcomp" || lasterr=$?
+
+ if test ! -d "$pathcomp"; then
+ errstatus=$lasterr
+ fi
+ fi
+
+ pathcomp="$pathcomp/"
+ done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
diff --git a/third_party/heimdal/lib/roken/mkostemp.c b/third_party/heimdal/lib/roken/mkostemp.c
new file mode 100644
index 0000000..8d739d8
--- /dev/null
+++ b/third_party/heimdal/lib/roken/mkostemp.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2019 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#include <errno.h>
+
+#include <roken.h>
+
+#ifndef O_APPEND
+#define O_APPEND 0
+#endif
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
+#ifndef O_SYNC
+#define O_SYNC 0
+#endif
+
+#ifndef HAVE_MKOSTEMP
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+mkostemp(char *template, int flags)
+{
+ int fd = mkstemp(template);
+
+ if (flags == 0)
+ return fd;
+
+ if ((flags & O_CLOEXEC))
+ rk_cloexec(fd);
+
+ /* fcntl F_SETFL O_APPEND and O_SYNC. */
+#ifdef HAVE_FCNTL
+ if ((flags & (O_APPEND | O_SYNC))) {
+ int fl;
+
+ if ((fl = fcntl(fd, F_GETFL)) == -1 ||
+ fcntl(fd, F_SETFD, fl | (flags & (O_APPEND | O_SYNC))) == -1) {
+ int save_errno = errno;
+
+ (void) unlink(template);
+ (void) close(fd);
+ errno = save_errno;
+ return -1;
+ }
+ }
+#endif
+ return fd;
+}
+#endif
diff --git a/third_party/heimdal/lib/roken/mkstemp.c b/third_party/heimdal/lib/roken/mkstemp.c
new file mode 100644
index 0000000..a3ca6c7
--- /dev/null
+++ b/third_party/heimdal/lib/roken/mkstemp.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#include <errno.h>
+
+#include <roken.h>
+
+#ifndef HAVE_MKSTEMP
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+mkstemp(char *template)
+{
+ int start, i;
+ pid_t val;
+ val = getpid();
+ start = strlen(template) - 1;
+ while(template[start] == 'X') {
+ template[start] = '0' + val % 10;
+ val /= 10;
+ start--;
+ }
+
+ do{
+ int fd;
+ fd = open(template, O_RDWR | O_CREAT | O_EXCL, 0600);
+ if(fd >= 0 || errno != EEXIST)
+ return fd;
+ i = start + 1;
+ do{
+ if(template[i] == 0)
+ return -1;
+ template[i]++;
+ if(template[i] == '9' + 1)
+ template[i] = 'a';
+ if(template[i] <= 'z')
+ break;
+ template[i] = 'a';
+ i++;
+ }while(1);
+ }while(1);
+}
+
+#endif
diff --git a/third_party/heimdal/lib/roken/ndbm_wrap.c b/third_party/heimdal/lib/roken/ndbm_wrap.c
new file mode 100644
index 0000000..f8403da
--- /dev/null
+++ b/third_party/heimdal/lib/roken/ndbm_wrap.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "ndbm_wrap.h"
+#if defined(HAVE_DBHEADER)
+#include <db.h>
+#elif defined(HAVE_DB6_DB_H)
+#include <db6/db.h>
+#elif defined(HAVE_DB5_DB_H)
+#include <db5/db.h>
+#elif defined(HAVE_DB4_DB_H)
+#include <db4/db.h>
+#elif defined(HAVE_DB3_DB_H)
+#include <db3/db.h>
+#else
+#include <db.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+/* XXX undefine open so this works on Solaris with large file support */
+#undef open
+
+#define DBT2DATUM(DBT, DATUM) do { (DATUM)->dptr = (DBT)->data; (DATUM)->dsize = (DBT)->size; } while(0)
+#define DATUM2DBT(DATUM, DBT) do { (DBT)->data = (DATUM)->dptr; (DBT)->size = (DATUM)->dsize; } while(0)
+#define RETURN(X) return ((X) == 0) ? 0 : -1
+
+#ifdef HAVE_DB3
+static DBC *cursor;
+#endif
+
+#define D(X) ((DB*)(X))
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+dbm_close (DBM *db)
+{
+#ifdef HAVE_DB3
+ D(db)->close(D(db), 0);
+ cursor = NULL;
+#else
+ D(db)->close(D(db));
+#endif
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+dbm_delete (DBM *db, datum dkey)
+{
+ DBT key;
+ DATUM2DBT(&dkey, &key);
+#ifdef HAVE_DB3
+ RETURN(D(db)->del(D(db), NULL, &key, 0));
+#else
+ RETURN(D(db)->del(D(db), &key, 0));
+#endif
+}
+
+datum
+dbm_fetch (DBM *db, datum dkey)
+{
+ datum dvalue;
+ DBT key, value;
+ DATUM2DBT(&dkey, &key);
+ if(D(db)->get(D(db),
+#ifdef HAVE_DB3
+ NULL,
+#endif
+ &key, &value, 0) != 0) {
+ dvalue.dptr = NULL;
+ dvalue.dsize = 0;
+ }
+ else
+ DBT2DATUM(&value, &dvalue);
+
+ return dvalue;
+}
+
+static datum
+dbm_get (DB *db, int flags)
+{
+ DBT key, value;
+ datum d;
+#ifdef HAVE_DB3
+ if(cursor == NULL)
+ db->cursor(db, NULL, &cursor, 0);
+ if(cursor->c_get(cursor, &key, &value, flags) != 0) {
+ d.dptr = NULL;
+ d.dsize = 0;
+ } else
+ DBT2DATUM(&value, &d);
+#else
+ db->seq(db, &key, &value, flags);
+ DBT2DATUM(&value, &d);
+#endif
+ return d;
+}
+
+#ifndef DB_FIRST
+#define DB_FIRST R_FIRST
+#define DB_NEXT R_NEXT
+#define DB_NOOVERWRITE R_NOOVERWRITE
+#define DB_KEYEXIST 1
+#endif
+
+ROKEN_LIB_FUNCTION datum ROKEN_LIB_CALL
+dbm_firstkey (DBM *db)
+{
+ return dbm_get(D(db), DB_FIRST);
+}
+
+ROKEN_LIB_FUNCTION datum ROKEN_LIB_CALL
+dbm_nextkey (DBM *db)
+{
+ return dbm_get(D(db), DB_NEXT);
+}
+
+ROKEN_LIB_FUNCTION DBM* ROKEN_LIB_CALL
+dbm_open (const char *file, int flags, mode_t mode)
+{
+#ifdef HAVE_DB3
+ int myflags = 0;
+#endif
+ DB *db;
+ char *fn = malloc(strlen(file) + 4);
+ if(fn == NULL)
+ return NULL;
+ strcpy(fn, file);
+ strcat(fn, ".db");
+#ifdef HAVE_DB3
+ if (flags & O_CREAT)
+ myflags |= DB_CREATE;
+
+ if (flags & O_EXCL)
+ myflags |= DB_EXCL;
+
+ if (flags & O_RDONLY)
+ myflags |= DB_RDONLY;
+
+ if (flags & O_TRUNC)
+ myflags |= DB_TRUNCATE;
+ if(db_create(&db, NULL, 0) != 0) {
+ free(fn);
+ return NULL;
+ }
+
+#if (DB_VERSION_MAJOR > 3) && (DB_VERSION_MINOR > 0)
+ if(db->open(db, NULL, fn, NULL, DB_BTREE, myflags, mode) != 0) {
+#else
+ if(db->open(db, fn, NULL, DB_BTREE, myflags, mode) != 0) {
+#endif
+ free(fn);
+ db->close(db, 0);
+ return NULL;
+ }
+#else
+ db = dbopen(fn, flags, mode, DB_BTREE, NULL);
+#endif
+ free(fn);
+ return (DBM*)db;
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+dbm_store (DBM *db, datum dkey, datum dvalue, int flags)
+{
+ int ret;
+ DBT key, value;
+ int myflags = 0;
+ if((flags & DBM_REPLACE) == 0)
+ myflags |= DB_NOOVERWRITE;
+ DATUM2DBT(&dkey, &key);
+ DATUM2DBT(&dvalue, &value);
+ ret = D(db)->put(D(db),
+#ifdef HAVE_DB3
+ NULL,
+#endif
+&key, &value, myflags);
+ if(ret == DB_KEYEXIST)
+ return 1;
+ RETURN(ret);
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+dbm_error (DBM *db)
+{
+ return 0;
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+dbm_clearerr (DBM *db)
+{
+ return 0;
+}
+
diff --git a/third_party/heimdal/lib/roken/ndbm_wrap.h b/third_party/heimdal/lib/roken/ndbm_wrap.h
new file mode 100644
index 0000000..a2ec4f2
--- /dev/null
+++ b/third_party/heimdal/lib/roken/ndbm_wrap.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
+ */
+
+/* $Id$ */
+
+#ifndef __ndbm_wrap_h__
+#define __ndbm_wrap_h__
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#ifndef ROKEN_LIB_FUNCTION
+#ifdef _WIN32
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL __cdecl
+#else
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL
+#endif
+#endif
+
+#ifndef dbm_rename
+#define dbm_rename(X) __roken_ ## X
+#endif
+
+#define dbm_open dbm_rename(dbm_open)
+#define dbm_close dbm_rename(dbm_close)
+#define dbm_delete dbm_rename(dbm_delete)
+#define dbm_fetch dbm_rename(dbm_fetch)
+#define dbm_get dbm_rename(dbm_get)
+#define dbm_firstkey dbm_rename(dbm_firstkey)
+#define dbm_nextkey dbm_rename(dbm_nextkey)
+#define dbm_store dbm_rename(dbm_store)
+#define dbm_error dbm_rename(dbm_error)
+#define dbm_clearerr dbm_rename(dbm_clearerr)
+
+#define datum dbm_rename(datum)
+
+typedef struct {
+ void *dptr;
+ size_t dsize;
+} datum;
+
+#define DBM_REPLACE 1
+typedef struct DBM DBM;
+
+#if 0
+typedef struct {
+ int dummy;
+} DBM;
+#endif
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL dbm_clearerr (DBM*);
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL dbm_close (DBM*);
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL dbm_delete (DBM*, datum);
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL dbm_error (DBM*);
+ROKEN_LIB_FUNCTION datum ROKEN_LIB_CALL dbm_fetch (DBM*, datum);
+ROKEN_LIB_FUNCTION datum ROKEN_LIB_CALL dbm_firstkey (DBM*);
+ROKEN_LIB_FUNCTION datum ROKEN_LIB_CALL dbm_nextkey (DBM*);
+ROKEN_LIB_FUNCTION DBM* ROKEN_LIB_CALL dbm_open (const char*, int, mode_t);
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL dbm_store (DBM*, datum, datum, int);
+
+#endif /* __ndbm_wrap_h__ */
diff --git a/third_party/heimdal/lib/roken/net_read.c b/third_party/heimdal/lib/roken/net_read.c
new file mode 100644
index 0000000..df1ac53
--- /dev/null
+++ b/third_party/heimdal/lib/roken/net_read.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+/*
+ * Like read but never return partial data.
+ */
+
+#ifndef _WIN32
+
+ROKEN_LIB_FUNCTION ssize_t ROKEN_LIB_CALL
+net_read (rk_socket_t fd, void *buf, size_t nbytes)
+{
+ char *cbuf = (char *)buf;
+ ssize_t count;
+ size_t rem = nbytes;
+
+ while (rem > 0) {
+ count = read (fd, cbuf, rem);
+ if (count < 0) {
+ if (errno == EINTR)
+ continue;
+ else
+ return count;
+ } else if (count == 0) {
+ return count;
+ }
+ cbuf += count;
+ rem -= count;
+ }
+ return nbytes;
+}
+
+#else
+
+ROKEN_LIB_FUNCTION ssize_t ROKEN_LIB_CALL
+net_read(rk_socket_t sock, void *buf, size_t nbytes)
+{
+ char *cbuf = (char *)buf;
+ ssize_t count;
+ size_t rem = nbytes;
+
+#ifdef SOCKET_IS_NOT_AN_FD
+ int use_read = 0;
+#endif
+
+ while (rem > 0) {
+#ifdef SOCKET_IS_NOT_AN_FD
+ if (use_read)
+ count = _read (sock, cbuf, rem);
+ else
+ count = recv (sock, cbuf, rem, 0);
+
+ if (use_read == 0 &&
+ rk_IS_SOCKET_ERROR(count) &&
+ (rk_SOCK_ERRNO == WSANOTINITIALISED ||
+ rk_SOCK_ERRNO == WSAENOTSOCK)) {
+ use_read = 1;
+
+ count = _read (sock, cbuf, rem);
+ }
+#else
+ count = recv (sock, cbuf, rem, 0);
+#endif
+ if (count < 0) {
+
+ /* With WinSock, the error EINTR (WSAEINTR), is used to
+ indicate that a blocking call was cancelled using
+ WSACancelBlockingCall(). */
+
+#ifndef HAVE_WINSOCK
+ if (rk_SOCK_ERRNO == EINTR)
+ continue;
+#endif
+ return count;
+ } else if (count == 0) {
+ return count;
+ }
+ cbuf += count;
+ rem -= count;
+ }
+ return nbytes;
+}
+
+#endif
diff --git a/third_party/heimdal/lib/roken/net_write.c b/third_party/heimdal/lib/roken/net_write.c
new file mode 100644
index 0000000..e66f56b
--- /dev/null
+++ b/third_party/heimdal/lib/roken/net_write.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+/*
+ * Like write but blocking sockets never return partial data, i.e. we retry on
+ * EINTR. With non-blocking sockets (EWOULDBLOCK or EAGAIN) we return the
+ * number of bytes written.
+ */
+
+#ifndef _WIN32
+
+ROKEN_LIB_FUNCTION ssize_t ROKEN_LIB_CALL
+net_write (rk_socket_t fd, const void *buf, size_t nbytes)
+{
+ const char *cbuf = (const char *)buf;
+ ssize_t count;
+ size_t rem = nbytes;
+
+ while (rem > 0) {
+ count = write (fd, cbuf, rem);
+ if (count < 0) {
+ switch (errno) {
+ case EINTR:
+ continue;
+#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
+ case EAGAIN:
+#endif
+ case EWOULDBLOCK:
+ return nbytes - rem;
+ default:
+ return count;
+ }
+ }
+ cbuf += count;
+ rem -= count;
+ }
+ return nbytes;
+}
+
+#else /* defined(_WIN32) */
+
+ROKEN_LIB_FUNCTION ssize_t ROKEN_LIB_CALL
+net_write(rk_socket_t sock, const void *buf, size_t nbytes)
+{
+ const char *cbuf = (const char *)buf;
+ ssize_t count;
+ size_t rem = nbytes;
+#ifdef SOCKET_IS_NOT_AN_FD
+ int use_write = 0;
+#endif
+
+ while (rem > 0) {
+#ifdef SOCKET_IS_NOT_AN_FD
+ if (use_write)
+ count = _write (sock, cbuf, rem);
+ else
+ count = send (sock, cbuf, rem, 0);
+
+ if (use_write == 0 &&
+ rk_IS_SOCKET_ERROR(count) &&
+ (rk_SOCK_ERRNO == WSANOTINITIALISED ||
+ rk_SOCK_ERRNO == WSAENOTSOCK)) {
+ use_write = 1;
+
+ count = _write (sock, cbuf, rem);
+ }
+#else
+ count = send (sock, cbuf, rem, 0);
+#endif
+ if (count < 0) {
+#ifdef SOCKET_IS_NOT_AN_FD
+ if (!use_write) {
+ switch (rk_SOCK_ERRNO) {
+ case WSAEINTR:
+ continue;
+ case WSAEWOULDBLOCK:
+ return nbytes - rem;
+ default:
+ return count;
+ }
+ } else
+#endif
+ {
+ switch (errno) {
+ case EINTR:
+ continue;
+ case EWOULDBLOCK:
+ return nbytes - rem;
+ default:
+ return count;
+ }
+ }
+ }
+ cbuf += count;
+ rem -= count;
+ }
+ return nbytes;
+}
+
+#endif
diff --git a/third_party/heimdal/lib/roken/parse_bytes-test.c b/third_party/heimdal/lib/roken/parse_bytes-test.c
new file mode 100644
index 0000000..8f3831c
--- /dev/null
+++ b/third_party/heimdal/lib/roken/parse_bytes-test.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+#include "parse_bytes.h"
+
+static struct testcase {
+ int canonicalp;
+ int64_t val;
+ const char *def_unit;
+ const char *str;
+} tests[] = {
+ {0, 0, NULL, "0 bytes"},
+ {1, 0, NULL, "0"},
+ {0, 1, NULL, "1"},
+ {1, 1, NULL, "1 byte"},
+ {0, 0, "kilobyte", "0"},
+ {0, 1024, "kilobyte", "1"},
+ {1, 1024, "kilobyte", "1 kilobyte"},
+ {1, 1024 * 1024, NULL, "1 megabyte"},
+ {0, 1025, NULL, "1 kilobyte 1"},
+ {1, 1025, NULL, "1 kilobyte 1 byte"},
+ {1, 1024ULL * 1024 * 1024 * 1024, NULL, "1 terabyte"},
+};
+
+int
+main(int argc, char **argv)
+{
+ int i;
+ int ret = 0;
+
+ for (i = 0; i < sizeof(tests)/sizeof(tests[0]); ++i) {
+ char buf[256];
+ int64_t val = parse_bytes (tests[i].str, tests[i].def_unit);
+
+ if (val != tests[i].val) {
+ printf ("parse_bytes (%s, %s) = %lld != %lld\n",
+ tests[i].str,
+ tests[i].def_unit ? tests[i].def_unit : "none",
+ (long long)val, (long long)tests[i].val);
+ ++ret;
+ }
+ if (tests[i].canonicalp) {
+ (void) unparse_bytes (tests[i].val, buf, sizeof(buf));
+ if (strcmp (tests[i].str, buf) != 0) {
+ printf ("unparse_bytes (%lld) = \"%s\" != \"%s\"\n",
+ (long long)tests[i].val, buf, tests[i].str);
+ ++ret;
+ }
+ }
+ }
+ if (ret) {
+ printf ("%d errors\n", ret);
+ return 1;
+ } else
+ return 0;
+}
diff --git a/third_party/heimdal/lib/roken/parse_bytes.c b/third_party/heimdal/lib/roken/parse_bytes.c
new file mode 100644
index 0000000..01ad553
--- /dev/null
+++ b/third_party/heimdal/lib/roken/parse_bytes.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <parse_units.h>
+#include "parse_bytes.h"
+
+static struct units bytes_units[] = {
+ { "petabyte", 1024ULL * 1024 * 1024 * 1024 * 1024 },
+ { "PB", 1024ULL * 1024 * 1024 * 1024 * 1024 },
+ { "terabyte", 1024ULL * 1024 * 1024 * 1024 },
+ { "TB", 1024ULL * 1024 * 1024 * 1024 },
+ { "gigabyte", 1024 * 1024 * 1024 },
+ { "gbyte", 1024 * 1024 * 1024 },
+ { "GB", 1024 * 1024 * 1024 },
+ { "megabyte", 1024 * 1024 },
+ { "mbyte", 1024 * 1024 },
+ { "MB", 1024 * 1024 },
+ { "kilobyte", 1024 },
+ { "KB", 1024 },
+ { "byte", 1 },
+ { NULL, 0 }
+};
+
+static struct units bytes_short_units[] = {
+ { "PB", 1024ULL * 1024 * 1024 * 1024 * 1024 },
+ { "TB", 1024ULL * 1024 * 1024 * 1024 },
+ { "GB", 1024 * 1024 * 1024 },
+ { "MB", 1024 * 1024 },
+ { "KB", 1024 },
+ { NULL, 0 }
+};
+
+ROKEN_LIB_FUNCTION int64_t ROKEN_LIB_CALL
+parse_bytes(const char *s, const char *def_unit)
+{
+ return parse_units (s, bytes_units, def_unit);
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+unparse_bytes(int64_t t, char *s, size_t len)
+{
+ return unparse_units (t, bytes_units, s, len);
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+unparse_bytes_short (int64_t t, char *s, size_t len)
+{
+ return unparse_units_approx (t, bytes_short_units, s, len);
+}
diff --git a/third_party/heimdal/lib/roken/parse_bytes.h b/third_party/heimdal/lib/roken/parse_bytes.h
new file mode 100644
index 0000000..5148fc6
--- /dev/null
+++ b/third_party/heimdal/lib/roken/parse_bytes.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1999 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
+ */
+
+/* $Id$ */
+
+#ifndef __PARSE_BYTES_H__
+#define __PARSE_BYTES_H__
+
+#include <roken.h>
+
+ROKEN_LIB_FUNCTION int64_t ROKEN_LIB_CALL
+parse_bytes(const char *s, const char *def_unit);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+unparse_bytes(int64_t t, char *s, size_t len);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+unparse_bytes_short(int64_t t, char *s, size_t len);
+
+#endif /* __PARSE_BYTES_H__ */
diff --git a/third_party/heimdal/lib/roken/parse_reply-test.c b/third_party/heimdal/lib/roken/parse_reply-test.c
new file mode 100644
index 0000000..5e40b81
--- /dev/null
+++ b/third_party/heimdal/lib/roken/parse_reply-test.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+#include <fcntl.h>
+
+#include "roken.h"
+#include "resolve.h"
+
+struct dns_reply*
+parse_reply(const unsigned char *, size_t);
+
+enum { MAX_BUF = 36};
+
+static struct testcase {
+ unsigned char buf[MAX_BUF];
+ size_t buf_len;
+} tests[] = {
+ {{0x12, 0x67, 0x84, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 'f', 'o', 'o', 0x00,
+ 0x00, 0x10, 0x00, 0x01,
+ 0x03, 'f', 'o', 'o', 0x00,
+ 0x00, 0x10, 0x00, 0x01,
+ 0x00, 0x00, 0x12, 0x67, 0xff, 0xff}, 36}
+};
+
+#ifndef MAP_FAILED
+#define MAP_FAILED (-1)
+#endif
+
+static sig_atomic_t val = 0;
+
+static RETSIGTYPE
+segv_handler(int sig)
+{
+ val = 1;
+}
+
+int
+main(int argc, char **argv)
+{
+#ifndef HAVE_MMAP
+ return 77; /* signal to automake that this test
+ cannot be run */
+#else /* HAVE_MMAP */
+ int ret;
+ int i;
+ struct sigaction sa;
+
+ sigemptyset (&sa.sa_mask);
+ sa.sa_flags = 0;
+ sa.sa_handler = segv_handler;
+ sigaction (SIGSEGV, &sa, NULL);
+
+ for (i = 0; val == 0 && i < sizeof(tests)/sizeof(tests[0]); ++i) {
+ const struct testcase *t = &tests[i];
+ unsigned char *p1, *p2;
+ int flags;
+ int fd;
+ size_t pagesize = getpagesize();
+ unsigned char *buf;
+
+#ifdef MAP_ANON
+ flags = MAP_ANON;
+ fd = -1;
+#else
+ flags = 0;
+ fd = open ("/dev/zero", O_RDONLY);
+ if(fd < 0)
+ err (1, "open /dev/zero");
+#endif
+ flags |= MAP_PRIVATE;
+
+ p1 = (unsigned char *)mmap(0, 2 * pagesize, PROT_READ | PROT_WRITE,
+ flags, fd, 0);
+ if (p1 == (unsigned char *)MAP_FAILED)
+ err (1, "mmap");
+ p2 = p1 + pagesize;
+ ret = mprotect ((void *)p2, pagesize, 0);
+ if (ret < 0)
+ err (1, "mprotect");
+ buf = p2 - t->buf_len;
+ memcpy (buf, t->buf, t->buf_len);
+ parse_reply (buf, t->buf_len);
+ ret = munmap ((void *)p1, 2 * pagesize);
+ if (ret < 0)
+ err (1, "munmap");
+ }
+ return val;
+#endif /* HAVE_MMAP */
+}
diff --git a/third_party/heimdal/lib/roken/parse_time-test.c b/third_party/heimdal/lib/roken/parse_time-test.c
new file mode 100644
index 0000000..95b4513
--- /dev/null
+++ b/third_party/heimdal/lib/roken/parse_time-test.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+#include "parse_time.h"
+#include "test-mem.h"
+#include "err.h"
+
+static struct testcase {
+ size_t size;
+ int val;
+ char *str;
+} tests[] = {
+ { 8, 1, "1 second" },
+ { 17, 61, "1 minute 1 second" },
+ { 18, 62, "1 minute 2 seconds" },
+ { 8, 60, "1 minute" },
+ { 6, 3600, "1 hour" },
+ { 15, 3601, "1 hour 1 second" },
+ { 16, 3602, "1 hour 2 seconds" },
+ { 9, 300, "5 minutes" },
+ { 1, 0, "0" },
+};
+
+int
+main(int argc, char **argv)
+{
+ size_t sz;
+ size_t buf_sz;
+ int i, j;
+
+ for (i = 0; i < sizeof(tests)/sizeof(tests[0]); ++i) {
+ char *buf;
+
+ sz = unparse_time(tests[i].val, NULL, 0);
+ if (sz != tests[i].size)
+ errx(1, "sz (%lu) != tests[%d].size (%lu)",
+ (unsigned long)sz, i, (unsigned long)tests[i].size);
+
+ for (buf_sz = 0; buf_sz < tests[i].size + 2; buf_sz++) {
+
+ buf = rk_test_mem_alloc(RK_TM_OVERRUN, "overrun",
+ NULL, buf_sz);
+ sz = unparse_time(tests[i].val, buf, buf_sz);
+ if (sz != tests[i].size)
+ errx(1, "sz (%lu) != tests[%d].size (%lu) with in size %lu",
+ (unsigned long)sz, i,
+ (unsigned long)tests[i].size,
+ (unsigned long)buf_sz);
+ if (buf_sz > 0 && memcmp(buf, tests[i].str, buf_sz - 1) != 0)
+ errx(1, "test %i wrong result %s vs %s", i, buf, tests[i].str);
+ if (buf_sz > 0 && buf[buf_sz - 1] != '\0')
+ errx(1, "test %i not zero terminated", i);
+ rk_test_mem_free("overrun");
+
+ buf = rk_test_mem_alloc(RK_TM_UNDERRUN, "underrun",
+ NULL, tests[i].size);
+ sz = unparse_time(tests[i].val, buf, min(buf_sz, tests[i].size));
+ if (sz != tests[i].size)
+ errx(1, "sz (%lu) != tests[%d].size (%lu) with insize %lu",
+ (unsigned long)sz, i,
+ (unsigned long)tests[i].size,
+ (unsigned long)buf_sz);
+ if (buf_sz > 0 && strncmp(buf, tests[i].str, min(buf_sz, tests[i].size) - 1) != 0)
+ errx(1, "test %i wrong result %s vs %s", i, buf, tests[i].str);
+ if (buf_sz > 0 && buf[min(buf_sz, tests[i].size) - 1] != '\0')
+ errx(1, "test %i not zero terminated", i);
+ rk_test_mem_free("underrun");
+ }
+
+ buf = rk_test_mem_alloc(RK_TM_OVERRUN, "overrun",
+ tests[i].str, tests[i].size + 1);
+ j = parse_time(buf, "s");
+ if (j != tests[i].val)
+ errx(1, "parse_time failed for test %d", i);
+ rk_test_mem_free("overrun");
+
+ buf = rk_test_mem_alloc(RK_TM_UNDERRUN, "underrun",
+ tests[i].str, tests[i].size + 1);
+ j = parse_time(buf, "s");
+ if (j != tests[i].val)
+ errx(1, "parse_time failed for test %d", i);
+ rk_test_mem_free("underrun");
+
+ }
+ return 0;
+}
diff --git a/third_party/heimdal/lib/roken/parse_time.3 b/third_party/heimdal/lib/roken/parse_time.3
new file mode 100644
index 0000000..7881eab
--- /dev/null
+++ b/third_party/heimdal/lib/roken/parse_time.3
@@ -0,0 +1,173 @@
+.\" Copyright (c) 2004 Kungliga Tekniska Högskolan
+.\" (Royal Institute of Technology, Stockholm, Sweden).
+.\" 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
+.\" $Id: parse_time.3,v 1.3 2013/06/17 18:57:45 robert Exp $
+.\"
+.Dd November 17, 2013
+.Dt PARSE_TIME 3
+.Os HEIMDAL
+.Sh NAME
+.Nm parse_time ,
+.Nm print_time_table ,
+.Nm unparse_time ,
+.Nm unparse_time_approx ,
+.Nd parse and unparse time intervals
+.Sh LIBRARY
+The roken library (libroken, -lroken)
+.Sh SYNOPSIS
+.Fd #include <parse_time.h>
+.Ft int
+.Fn parse_time "const char *timespec" "const char *def_unit"
+.Ft void
+.Fn print_time_table "FILE *f"
+.Ft size_t
+.Fn unparse_time "int seconds" "char *buf" "size_t len"
+.Ft size_t
+.Fn unparse_time_approx "int seconds" "char *buf" "size_t len"
+.Sh DESCRIPTION
+The
+.Fn parse_time
+function converts the period of time specified
+into a number of seconds.
+The
+.Fa timespec
+can be any number of
+.Aq number unit
+pairs separated by comma and whitespace. The number can be
+negative. Numbers without explicit units are taken as being
+.Fa def_unit .
+.Pp
+The
+.Fn unparse_time
+and
+.Fn unparse_time_approx
+do the opposite of
+.Fn parse_time ,
+that is they take a number of seconds and express that as human
+readable strings.
+.Fa unparse_time
+produces an exact time, while
+.Fa unparse_time_approx
+restricts the result to include only one unit.
+.Pp
+.Fn print_time_table
+prints a descriptive list of available units on the passed file
+descriptor.
+.Pp
+The possible units include:
+.Bl -tag -width "month" -compact -offset indent
+.It Li second , s
+.It Li minute , m
+.It Li hour , h
+.It day
+.It week
+seven days
+.It month
+30 days
+.It year
+365 days
+.El
+.Pp
+Units names can be arbitrarily abbreviated (as long as they are
+unique).
+.Sh RETURN VALUES
+.Fn parse_time
+returns the number of seconds that represents the expression in
+.Fa timespec
+or -1 on error.
+.Fn unparse_time
+and
+.Fn unparse_time_approx
+return the number of characters written to
+.Fa buf .
+if the return value is greater than or equal to the
+.Fa len
+argument, the string was too short and some of the printed characters
+were discarded.
+.Sh EXAMPLES
+.Bd -literal
+#include <stdio.h>
+#include <parse_time.h>
+
+int
+main(int argc, char **argv)
+{
+ int i;
+ int result;
+ char buf[128];
+ print_time_table(stdout);
+ for (i = 1; i < argc; i++) {
+ result = parse_time(argv[i], "second");
+ if(result == -1) {
+ fprintf(stderr, "%s: parse error\\n", argv[i]);
+ continue;
+ }
+ printf("--\\n");
+ printf("parse_time = %d\\n", result);
+ unparse_time(result, buf, sizeof(buf));
+ printf("unparse_time = %s\\n", buf);
+ unparse_time_approx(result, buf, sizeof(buf));
+ printf("unparse_time_approx = %s\\n", buf);
+ }
+ return 0;
+}
+.Ed
+.Bd -literal
+$ ./a.out "1 minute 30 seconds" "90 s" "1 y -1 s"
+1 year = 365 days
+1 month = 30 days
+1 week = 7 days
+1 day = 24 hours
+1 hour = 60 minutes
+1 minute = 60 seconds
+1 second
+--
+parse_time = 90
+unparse_time = 1 minute 30 seconds
+unparse_time_approx = 1 minute
+--
+parse_time = 90
+unparse_time = 1 minute 30 seconds
+unparse_time_approx = 1 minute
+--
+parse_time = 31535999
+unparse_time = 12 months 4 days 23 hours 59 minutes 59 seconds
+unparse_time_approx = 12 months
+.Ed
+.Sh BUGS
+Since
+.Fn parse_time
+returns -1 on error there is no way to parse "minus one second".
+Currently "s" at the end of units is ignored. This is a hack for
+English plural forms. If these functions are ever localised, this
+scheme will have to change.
+.\".Sh SEE ALSO
+.\".Xr parse_bytes 3
+.\".Xr parse_units 3
diff --git a/third_party/heimdal/lib/roken/parse_time.c b/third_party/heimdal/lib/roken/parse_time.c
new file mode 100644
index 0000000..f5a99e3
--- /dev/null
+++ b/third_party/heimdal/lib/roken/parse_time.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 1997, 1998 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <parse_units.h>
+#include "parse_time.h"
+
+static struct units time_units[] = {
+ {"year", 365 * 24 * 60 * 60},
+ {"month", 30 * 24 * 60 * 60},
+ {"week", 7 * 24 * 60 * 60},
+ {"day", 24 * 60 * 60},
+ {"hour", 60 * 60},
+ {"h", 60 * 60},
+ {"minute", 60},
+ {"m", 60},
+ {"second", 1},
+ {"s", 1},
+ {NULL, 0},
+};
+
+ROKEN_LIB_FUNCTION int64_t ROKEN_LIB_CALL
+parse_time (const char *s, const char *def_unit)
+{
+ return parse_units (s, time_units, def_unit);
+}
+
+ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL
+unparse_time(int64_t t, char *s, size_t len)
+{
+ return unparse_units (t, time_units, s, len);
+}
+
+ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL
+unparse_time_approx(int64_t t, char *s, size_t len)
+{
+ return unparse_units_approx (t, time_units, s, len);
+}
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+print_time_table (FILE *f)
+{
+ print_units_table (time_units, f);
+}
+
+#undef parse_time
+#undef unparse_time
+#undef unparse_time_approx
+#undef print_time_table
+
+ROKEN_LIB_FUNCTION int64_t ROKEN_LIB_CALL
+parse_time(const char *s, const char *def_unit)
+{
+ return rk_parse_units(s, time_units, def_unit);
+}
+
+ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL
+unparse_time(int64_t t, char *s, size_t len)
+{
+ return rk_unparse_units(t, time_units, s, len);
+}
+
+ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL
+unparse_time_approx(int64_t t, char *s, size_t len)
+{
+ return rk_unparse_units_approx(t, time_units, s, len);
+}
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+print_time_table(FILE *f)
+{
+ rk_print_units_table(time_units, f);
+}
diff --git a/third_party/heimdal/lib/roken/parse_time.h b/third_party/heimdal/lib/roken/parse_time.h
new file mode 100644
index 0000000..c0f08f9
--- /dev/null
+++ b/third_party/heimdal/lib/roken/parse_time.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
+ */
+
+/* $Id$ */
+
+#ifndef __PARSE_TIME_H__
+#define __PARSE_TIME_H__
+
+#include <roken.h>
+
+ROKEN_LIB_FUNCTION int64_t ROKEN_LIB_CALL
+parse_time (const char *s, const char *def_unit);
+
+ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL
+unparse_time(int64_t t, char *s, size_t len);
+
+ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL
+unparse_time_approx(int64_t t, char *s, size_t len);
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+print_time_table (FILE *f);
+
+/* And again, but renamed */
+
+#define parse_time rk_parse_time
+#define unparse_time rk_unparse_time
+#define unparse_time_approx rk_unparse_time_approx
+#define print_time_table rk_print_time_table
+
+ROKEN_LIB_FUNCTION int64_t ROKEN_LIB_CALL
+parse_time (const char *s, const char *def_unit);
+
+ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL
+unparse_time(int64_t t, char *s, size_t len);
+
+ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL
+unparse_time_approx(int64_t t, char *s, size_t len);
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+print_time_table (FILE *f);
+
+#endif /* __PARSE_TIME_H__ */
diff --git a/third_party/heimdal/lib/roken/parse_units.c b/third_party/heimdal/lib/roken/parse_units.c
new file mode 100644
index 0000000..017eedf
--- /dev/null
+++ b/third_party/heimdal/lib/roken/parse_units.c
@@ -0,0 +1,524 @@
+/*
+ * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include "roken.h"
+#include "parse_units.h"
+
+/*
+ * Parse string in `s' according to `units' and return value.
+ * def_unit defines the default unit.
+ */
+
+static int64_t
+parse_something_signed(const char *s, const struct units *units,
+ const char *def_unit,
+ int64_t (*func)(int64_t res, int64_t val, uint64_t mult),
+ int64_t init,
+ int accept_no_val_p)
+{
+ const char *p;
+ int64_t res = init;
+ unsigned def_mult = 1;
+
+ if (def_unit != NULL) {
+ const struct units *u;
+
+ for (u = units; u->name; ++u) {
+ if (strcasecmp (u->name, def_unit) == 0) {
+ def_mult = u->mult;
+ break;
+ }
+ }
+ if (u->name == NULL)
+ return -1;
+ }
+
+ p = s;
+ while (*p) {
+ int64_t val;
+ char *next;
+ const struct units *u, *partial_unit;
+ size_t u_len;
+ unsigned partial;
+ int no_val_p = 0;
+
+ while (isspace((unsigned char)*p) || *p == ',')
+ ++p;
+
+ val = strtoll(p, &next, 0);
+ if (p == next) {
+ val = 0;
+ if(!accept_no_val_p)
+ return -1;
+ no_val_p = 1;
+ }
+ p = next;
+ while (isspace((unsigned char)*p))
+ ++p;
+ if (*p == '\0') {
+ res = (*func)(res, val, def_mult);
+ if (res < 0)
+ return res;
+ break;
+ } else if (*p == '+') {
+ ++p;
+ val = 1;
+ } else if (*p == '-') {
+ ++p;
+ val = -1;
+ }
+ if (no_val_p && val == 0)
+ val = 1;
+ u_len = strcspn (p, ", \t");
+ partial = 0;
+ partial_unit = NULL;
+ if (u_len > 1 && p[u_len - 1] == 's')
+ --u_len;
+ for (u = units; u->name; ++u) {
+ if (strncasecmp (p, u->name, u_len) == 0) {
+ if (u_len == strlen (u->name)) {
+ p += u_len;
+ res = (*func)(res, val, u->mult);
+ if (res < 0)
+ return res;
+ break;
+ } else {
+ ++partial;
+ partial_unit = u;
+ }
+ }
+ }
+ if (u->name == NULL) {
+ if (partial == 1) {
+ p += u_len;
+ res = (*func)(res, val, partial_unit->mult);
+ if (res < 0)
+ return res;
+ } else {
+ return -1;
+ }
+ }
+ if (*p == 's')
+ ++p;
+ while (isspace((unsigned char)*p))
+ ++p;
+ }
+ return res;
+}
+
+static uint64_t
+parse_something_unsigned(const char *s, const struct units *units,
+ const char *def_unit,
+ uint64_t (*func)(uint64_t res, int64_t val, uint64_t mult),
+ uint64_t init,
+ int accept_no_val_p)
+{
+ const char *p;
+ int64_t res = init;
+ unsigned def_mult = 1;
+
+ if (def_unit != NULL) {
+ const struct units *u;
+
+ for (u = units; u->name; ++u) {
+ if (strcasecmp (u->name, def_unit) == 0) {
+ def_mult = u->mult;
+ break;
+ }
+ }
+ if (u->name == NULL)
+ return -1;
+ }
+
+ p = s;
+ while (*p) {
+ int64_t val;
+ char *next;
+ const struct units *u, *partial_unit;
+ size_t u_len;
+ unsigned partial;
+ int no_val_p = 0;
+
+ while (isspace((unsigned char)*p) || *p == ',')
+ ++p;
+
+ val = strtoll(p, &next, 0);
+ if (p == next) {
+ val = 0;
+ if(!accept_no_val_p)
+ return -1;
+ no_val_p = 1;
+ }
+ p = next;
+ while (isspace((unsigned char)*p))
+ ++p;
+ if (*p == '\0') {
+ res = (*func)(res, val, def_mult);
+ if (res < 0)
+ return res;
+ break;
+ } else if (*p == '+') {
+ ++p;
+ val = 1;
+ } else if (*p == '-') {
+ ++p;
+ val = -1;
+ }
+ if (no_val_p && val == 0)
+ val = 1;
+ u_len = strcspn (p, ", \t");
+ partial = 0;
+ partial_unit = NULL;
+ if (u_len > 1 && p[u_len - 1] == 's')
+ --u_len;
+ for (u = units; u->name; ++u) {
+ if (strncasecmp (p, u->name, u_len) == 0) {
+ if (u_len == strlen (u->name)) {
+ p += u_len;
+ res = (*func)(res, val, u->mult);
+ if (res < 0)
+ return res;
+ break;
+ } else {
+ ++partial;
+ partial_unit = u;
+ }
+ }
+ }
+ if (u->name == NULL) {
+ if (partial == 1) {
+ p += u_len;
+ res = (*func)(res, val, partial_unit->mult);
+ if (res < 0)
+ return res;
+ } else {
+ return -1;
+ }
+ }
+ if (*p == 's')
+ ++p;
+ while (isspace((unsigned char)*p))
+ ++p;
+ }
+ return res;
+}
+
+/*
+ * The string consists of a sequence of `n unit'
+ */
+
+static int64_t
+acc_units(int64_t res, int64_t val, uint64_t mult)
+{
+ return res + val * mult;
+}
+
+ROKEN_LIB_FUNCTION int64_t ROKEN_LIB_CALL
+parse_units (const char *s, const struct units *units,
+ const char *def_unit)
+{
+ return parse_something_signed(s, units, def_unit, acc_units, 0, 0);
+}
+
+/*
+ * The string consists of a sequence of `[+-]flag'. `orig' consists
+ * the original set of flags, those are then modified and returned as
+ * the function value.
+ */
+
+static uint64_t
+acc_flags(uint64_t res, int64_t val, uint64_t mult)
+{
+ if(val == 1)
+ return res | mult;
+ else if(val == -1)
+ return res & ~mult;
+ else if (val == 0)
+ return mult;
+ else
+ return -1;
+}
+
+ROKEN_LIB_FUNCTION uint64_t ROKEN_LIB_CALL
+parse_flags(const char *s, const struct units *units, uint64_t orig)
+{
+ return parse_something_unsigned (s, units, NULL, acc_flags, orig, 1);
+}
+
+/*
+ * Return a string representation according to `units' of `num' in `s'
+ * with maximum length `len'. The actual length is the function value.
+ */
+
+static int
+unparse_something_signed(int64_t num, const struct units *units, char *s,
+ size_t len,
+ int64_t (*get_divisor)(int64_t, uint64_t),
+ int (*print)(char *, size_t, int64_t, const char *, int64_t),
+ int64_t (*update)(int64_t, uint64_t),
+ const char *zero_string)
+{
+ const struct units *u;
+ int ret = 0, tmp;
+
+ if (num == 0)
+ return snprintf (s, len, "%s", zero_string);
+ if (len)
+ s[0] = '\0';
+ if (num < 0)
+ return -1;
+
+ for (u = units; num > 0 && u->name; ++u) {
+ long long divisor = get_divisor(num, u->mult);
+
+ if (divisor) {
+ num = (*update)(num, u->mult);
+ tmp = (*print)(s, len, divisor, u->name, num);
+ if (tmp < 0)
+ return tmp;
+ if ((size_t)tmp > len) {
+ len = 0;
+ s = NULL;
+ } else {
+ len -= tmp;
+ s += tmp;
+ }
+ ret += tmp;
+ }
+ }
+ return ret;
+}
+
+static int
+unparse_something_unsigned(uint64_t num, const struct units *units, char *s,
+ size_t len,
+ uint64_t (*get_divisor)(uint64_t, uint64_t),
+ int (*print)(char *, size_t, uint64_t, const char *, uint64_t),
+ uint64_t (*update)(uint64_t, uint64_t),
+ const char *zero_string)
+{
+ const struct units *u;
+ int64_t tmp;
+ int ret = 0;
+
+ if (num == 0)
+ return snprintf (s, len, "%s", zero_string);
+ if (len)
+ s[0] = '\0';
+
+ for (u = units; num > 0 && u->name; ++u) {
+ long long divisor = get_divisor(num, u->mult);
+
+ if (divisor) {
+ num = (*update) (num, u->mult);
+ tmp = (*print) (s, len, divisor, u->name, num);
+ if (tmp < 0)
+ return tmp;
+ if ((size_t)tmp > len) {
+ len = 0;
+ s = NULL;
+ } else {
+ len -= tmp;
+ s += tmp;
+ }
+ ret += tmp;
+ }
+ }
+ return ret;
+}
+
+static int
+print_unit(char *s, size_t len, int64_t divisor, const char *name, int64_t rem)
+{
+ return snprintf(s, len, "%lld %s%s%s", (long long)divisor, name,
+ divisor == 1 ? "" : "s", rem > 0 ? " " : "");
+}
+
+static int64_t
+get_divisor_unit(int64_t in, uint64_t mult)
+{
+ return in / mult;
+}
+
+static int64_t
+update_unit(int64_t in, uint64_t mult)
+{
+ return in % mult;
+}
+
+static int64_t
+update_unit_approx(int64_t in, uint64_t mult)
+{
+ if (in / mult > 0)
+ return 0;
+ else
+ return update_unit (in, mult);
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+unparse_units(int64_t num, const struct units *units, char *s, size_t len)
+{
+ return unparse_something_signed(num, units, s, len,
+ get_divisor_unit, print_unit, update_unit,
+ "0");
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+unparse_units_approx(int64_t num, const struct units *units, char *s, size_t len)
+{
+ return unparse_something_signed(num, units, s, len, get_divisor_unit,
+ print_unit, update_unit_approx, "0");
+}
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+print_units_table (const struct units *units, FILE *f)
+{
+ const struct units *u, *u2;
+ size_t max_sz = 0;
+
+ for (u = units; u->name; ++u) {
+ max_sz = max(max_sz, strlen(u->name));
+ }
+
+ for (u = units; u->name;) {
+ char buf[1024];
+ const struct units *next;
+
+ for (next = u + 1; next->name && next->mult == u->mult; ++next)
+ ;
+
+ if (next->name) {
+ for (u2 = next;
+ u2->name && u->mult % u2->mult != 0;
+ ++u2)
+ ;
+ if (u2->name == NULL)
+ --u2;
+ unparse_units (u->mult, u2, buf, sizeof(buf));
+ fprintf (f, "1 %*s = %s\n", (int)max_sz, u->name, buf);
+ } else {
+ fprintf (f, "1 %s\n", u->name);
+ }
+ u = next;
+ }
+}
+
+static uint64_t
+get_divisor_flag(uint64_t in, uint64_t mult)
+{
+ return in & mult;
+}
+
+static int
+print_flag(char *s, size_t len, uint64_t divisor, const char *name, uint64_t rem)
+{
+ return snprintf (s, len, "%s%s", name, rem > 0 ? ", " : "");
+}
+
+static uint64_t
+update_flag(uint64_t in, uint64_t mult)
+{
+ return in & ~mult;
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+unparse_flags (uint64_t num, const struct units *units, char *s, size_t len)
+{
+ return unparse_something_unsigned(num, units, s, len, get_divisor_flag,
+ print_flag, update_flag, "");
+}
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+print_flags_table (const struct units *units, FILE *f)
+{
+ const struct units *u;
+
+ for(u = units; u->name; ++u)
+ fprintf(f, "%s%s", u->name, (u+1)->name ? ", " : "\n");
+}
+
+#undef parse_units
+#undef unparse_units
+#undef unparse_units_approx
+#undef print_units_table
+#undef parse_flags
+#undef unparse_flags
+#undef print_flags_table
+
+ROKEN_LIB_FUNCTION int64_t ROKEN_LIB_CALL
+parse_units(const char *s, const struct units *units,
+ const char *def_unit)
+{
+ return rk_parse_units(s, units, def_unit);
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+unparse_units(int64_t num, const struct units *units, char *s, size_t len)
+{
+ return rk_unparse_units(num, units, s, len);
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+unparse_units_approx(int64_t num, const struct units *units, char *s, size_t len)
+{
+ return rk_unparse_units_approx(num, units, s, len);
+}
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+print_units_table(const struct units *units, FILE *f)
+{
+ rk_print_units_table(units, f);
+}
+
+ROKEN_LIB_FUNCTION uint64_t ROKEN_LIB_CALL
+parse_flags(const char *s, const struct units *units, int orig)
+{
+ return rk_parse_flags(s, units, orig);
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+unparse_flags(uint64_t num, const struct units *units, char *s, size_t len)
+{
+ return rk_unparse_flags(num, units, s, len);
+}
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+print_flags_table (const struct units *units, FILE *f)
+{
+ rk_print_flags_table(units, f);
+}
diff --git a/third_party/heimdal/lib/roken/parse_units.h b/third_party/heimdal/lib/roken/parse_units.h
new file mode 100644
index 0000000..d17897d
--- /dev/null
+++ b/third_party/heimdal/lib/roken/parse_units.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
+ */
+
+/* $Id$ */
+
+#ifndef __PARSE_UNITS_H__
+#define __PARSE_UNITS_H__
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#ifndef ROKEN_LIB_FUNCTION
+#ifdef _WIN32
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL __cdecl
+#else
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL
+#endif
+#endif
+
+struct units {
+ const char *name;
+ uint64_t mult;
+};
+
+ROKEN_LIB_FUNCTION int64_t ROKEN_LIB_CALL
+parse_units (const char *s, const struct units *units,
+ const char *def_unit);
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+print_units_table (const struct units *units, FILE *f);
+
+ROKEN_LIB_FUNCTION uint64_t ROKEN_LIB_CALL
+parse_flags (const char *s, const struct units *units,
+ int orig);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+unparse_units(int64_t num, const struct units *units, char *s, size_t len);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+unparse_units_approx(int64_t num, const struct units *units, char *s,
+ size_t len);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+unparse_flags(uint64_t num, const struct units *units, char *s, size_t len);
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+print_flags_table (const struct units *units, FILE *f);
+
+/* And again, but renamed */
+
+#define parse_units rk_parse_units
+#define unparse_units rk_unparse_units
+#define unparse_units_approx rk_unparse_units_approx
+#define print_units_table rk_print_units_table
+#define parse_flags rk_parse_flags
+#define unparse_flags rk_unparse_flags
+#define print_flags_table rk_print_flags_table
+
+ROKEN_LIB_FUNCTION int64_t ROKEN_LIB_CALL
+parse_units (const char *s, const struct units *units,
+ const char *def_unit);
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+print_units_table (const struct units *units, FILE *f);
+
+ROKEN_LIB_FUNCTION uint64_t ROKEN_LIB_CALL
+parse_flags(const char *s, const struct units *units,
+ uint64_t orig);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+unparse_units(int64_t num, const struct units *units, char *s, size_t len);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+unparse_units_approx(int64_t num, const struct units *units, char *s,
+ size_t len);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+unparse_flags(uint64_t num, const struct units *units, char *s, size_t len);
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+print_flags_table (const struct units *units, FILE *f);
+
+#endif /* __PARSE_UNITS_H__ */
diff --git a/third_party/heimdal/lib/roken/putenv.c b/third_party/heimdal/lib/roken/putenv.c
new file mode 100644
index 0000000..647eb7a
--- /dev/null
+++ b/third_party/heimdal/lib/roken/putenv.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <stdlib.h>
+
+#if !HAVE_DECL_ENVIRON
+extern char **environ;
+#endif
+
+/*
+ * putenv --
+ * String points to a string of the form name=value.
+ *
+ * Makes the value of the environment variable name equal to
+ * value by altering an existing variable or creating a new one.
+ */
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+putenv(const char *string)
+{
+ int i;
+ const char *eq = (const char *)strchr(string, '=');
+ int len;
+
+ if (eq == NULL)
+ return 1;
+ len = eq - string;
+
+ if(environ == NULL) {
+ environ = malloc(sizeof(char*));
+ if(environ == NULL)
+ return 1;
+ environ[0] = NULL;
+ }
+
+ for(i = 0; environ[i] != NULL; i++)
+ if(strncmp(string, environ[i], len) == 0) {
+ environ[i] = string;
+ return 0;
+ }
+ environ = realloc(environ, sizeof(char*) * (i + 2));
+ if(environ == NULL)
+ return 1;
+ environ[i] = string;
+ environ[i+1] = NULL;
+ return 0;
+}
diff --git a/third_party/heimdal/lib/roken/qsort.c b/third_party/heimdal/lib/roken/qsort.c
new file mode 100644
index 0000000..5849d86
--- /dev/null
+++ b/third_party/heimdal/lib/roken/qsort.c
@@ -0,0 +1,201 @@
+/*-
+ * Copyright (c) 1992, 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.
+ * 4. 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.
+ */
+
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)qsort.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#endif
+
+#include <config.h>
+
+#ifdef NEED_QSORT
+
+#include "roken.h"
+
+#include <stdlib.h>
+
+#ifdef I_AM_QSORT_R
+typedef int cmp_t(void *, const void *, const void *);
+#else
+typedef int cmp_t(const void *, const void *);
+#endif
+static inline char *med3(char *, char *, char *, cmp_t *, void *);
+static inline void swapfunc(char *, char *, int, int);
+
+/*
+ * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
+ */
+#define swapcode(TYPE, parmi, parmj, n) { \
+ long i = (n) / sizeof (TYPE); \
+ TYPE *pi = (TYPE *) (parmi); \
+ TYPE *pj = (TYPE *) (parmj); \
+ do { \
+ TYPE t = *pi; \
+ *pi++ = *pj; \
+ *pj++ = t; \
+ } while (--i > 0); \
+}
+
+#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
+ es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
+
+static inline void
+swapfunc(char *a, char *b, int n, int swaptype)
+{
+ if(swaptype <= 1)
+ swapcode(long, a, b, n)
+ else
+ swapcode(char, a, b, n)
+}
+
+#define swap(a, b) \
+ if (swaptype == 0) { \
+ long t = *(long *)(a); \
+ *(long *)(a) = *(long *)(b); \
+ *(long *)(b) = t; \
+ } else \
+ swapfunc(a, b, es, swaptype)
+
+#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
+
+#ifdef I_AM_QSORT_R
+#define CMP(t, x, y) (cmp((t), (x), (y)))
+#else
+#define CMP(t, x, y) (cmp((x), (y)))
+#endif
+
+static inline char *
+med3(char *a, char *b, char *c, cmp_t *cmp, void *thunk
+#ifndef I_AM_QSORT_R
+/* __unused */
+#endif
+)
+{
+ return CMP(thunk, a, b) < 0 ?
+ (CMP(thunk, b, c) < 0 ? b : (CMP(thunk, a, c) < 0 ? c : a ))
+ :(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c ));
+}
+
+#ifdef I_AM_QSORT_R
+void
+rk_qsort_r(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp)
+#else
+#define thunk NULL
+void
+rk_qsort(void *a, size_t n, size_t es, cmp_t *cmp)
+#endif
+{
+ char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
+ size_t d, r;
+ int cmp_result;
+ int swaptype, swap_cnt;
+
+loop: SWAPINIT(a, es);
+ swap_cnt = 0;
+ if (n < 7) {
+ for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
+ for (pl = pm;
+ pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
+ pl -= es)
+ swap(pl, pl - es);
+ return;
+ }
+ pm = (char *)a + (n / 2) * es;
+ if (n > 7) {
+ pl = a;
+ pn = (char *)a + (n - 1) * es;
+ if (n > 40) {
+ d = (n / 8) * es;
+ pl = med3(pl, pl + d, pl + 2 * d, cmp, thunk);
+ pm = med3(pm - d, pm, pm + d, cmp, thunk);
+ pn = med3(pn - 2 * d, pn - d, pn, cmp, thunk);
+ }
+ pm = med3(pl, pm, pn, cmp, thunk);
+ }
+ swap(a, pm);
+ pa = pb = (char *)a + es;
+
+ pc = pd = (char *)a + (n - 1) * es;
+ for (;;) {
+ while (pb <= pc && (cmp_result = CMP(thunk, pb, a)) <= 0) {
+ if (cmp_result == 0) {
+ swap_cnt = 1;
+ swap(pa, pb);
+ pa += es;
+ }
+ pb += es;
+ }
+ while (pb <= pc && (cmp_result = CMP(thunk, pc, a)) >= 0) {
+ if (cmp_result == 0) {
+ swap_cnt = 1;
+ swap(pc, pd);
+ pd -= es;
+ }
+ pc -= es;
+ }
+ if (pb > pc)
+ break;
+ swap(pb, pc);
+ swap_cnt = 1;
+ pb += es;
+ pc -= es;
+ }
+ if (swap_cnt == 0) { /* Switch to insertion sort */
+ for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
+ for (pl = pm;
+ pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
+ pl -= es)
+ swap(pl, pl - es);
+ return;
+ }
+
+ pn = (char *)a + n * es;
+ r = min(pa - (char *)a, pb - pa);
+ vecswap(a, pb - r, r);
+ r = min(pd - pc, pn - pd - es);
+ vecswap(pb, pn - r, r);
+ if ((r = pb - pa) > es)
+#ifdef I_AM_QSORT_R
+ rk_qsort_r(a, r / es, es, thunk, cmp);
+#else
+ rk_qsort(a, r / es, es, cmp);
+#endif
+ if ((r = pd - pc) > es) {
+ /* Iterate rather than recurse to save stack space */
+ a = pn - r;
+ n = r / es;
+ goto loop;
+ }
+/* rk_qsort(pn - r, r / es, es, cmp);*/
+}
+
+#endif /* NEED_QSORT */
diff --git a/third_party/heimdal/lib/roken/rand.c b/third_party/heimdal/lib/roken/rand.c
new file mode 100644
index 0000000..59ff47a
--- /dev/null
+++ b/third_party/heimdal/lib/roken/rand.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+#ifdef HAVE_WIN32_RAND_S
+static int hasRand_s = 1;
+#include "versionsupport.h"
+#endif
+
+void ROKEN_LIB_FUNCTION
+rk_random_init(void)
+{
+#if defined(HAVE_ARC4RANDOM)
+ /* nothing to do */;
+#elif defined(HAVE_SRANDOMDEV)
+ srandomdev();
+#elif defined(HAVE_RANDOM)
+ srandom(time(NULL));
+#else
+# ifdef HAVE_WIN32_RAND_S
+ hasRand_s = IsWindowsXPOrGreater();
+# endif
+ srand (time(NULL));
+#endif
+}
+
+#ifdef HAVE_WIN32_RAND_S
+unsigned int ROKEN_LIB_FUNCTION
+rk_random(void)
+{
+ if (hasRand_s) {
+ unsigned int n;
+ int code;
+
+ code = rand_s(&n);
+ if (code == 0)
+ return n;
+ }
+
+ return rand();
+}
+#endif
diff --git a/third_party/heimdal/lib/roken/rcmd.c b/third_party/heimdal/lib/roken/rcmd.c
new file mode 100644
index 0000000..7fa85a3
--- /dev/null
+++ b/third_party/heimdal/lib/roken/rcmd.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+#include <stdio.h>
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rcmd(char **ahost,
+ unsigned short inport,
+ const char *locuser,
+ const char *remuser,
+ const char *cmd,
+ int *fd2p)
+{
+ fprintf(stderr, "Only kerberized services are implemented\n");
+ return -1;
+}
diff --git a/third_party/heimdal/lib/roken/readv.c b/third_party/heimdal/lib/roken/readv.c
new file mode 100644
index 0000000..a156015
--- /dev/null
+++ b/third_party/heimdal/lib/roken/readv.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+ROKEN_LIB_FUNCTION ssize_t ROKEN_LIB_CALL
+readv(int d, const struct iovec *iov, int iovcnt)
+{
+ ssize_t ret, nb;
+ size_t tot = 0;
+ int i;
+ char *buf, *p;
+
+ for(i = 0; i < iovcnt; ++i)
+ tot += iov[i].iov_len;
+ buf = malloc(tot);
+ if (tot != 0 && buf == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+ nb = ret = read (d, buf, tot);
+ p = buf;
+ while (nb > 0) {
+ ssize_t cnt = min(nb, iov->iov_len);
+
+ memcpy (iov->iov_base, p, cnt);
+ p += cnt;
+ nb -= cnt;
+ }
+ free(buf);
+ return ret;
+}
diff --git a/third_party/heimdal/lib/roken/realloc.c b/third_party/heimdal/lib/roken/realloc.c
new file mode 100644
index 0000000..fefa90d
--- /dev/null
+++ b/third_party/heimdal/lib/roken/realloc.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+#undef realloc
+
+#include <stdlib.h>
+#include "roken.h"
+#undef realloc
+
+ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL
+rk_realloc(void *ptr, size_t size)
+{
+ if (ptr == NULL)
+ return malloc(size);
+ return realloc(ptr, size);
+}
diff --git a/third_party/heimdal/lib/roken/recvmsg.c b/third_party/heimdal/lib/roken/recvmsg.c
new file mode 100644
index 0000000..aba298b
--- /dev/null
+++ b/third_party/heimdal/lib/roken/recvmsg.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+ROKEN_LIB_FUNCTION ssize_t ROKEN_LIB_CALL
+recvmsg(int s, struct msghdr *msg, int flags)
+{
+ ssize_t ret, nb;
+ size_t tot = 0;
+ int i;
+ char *buf, *p;
+ struct iovec *iov = msg->msg_iov;
+
+ for(i = 0; i < msg->msg_iovlen; ++i)
+ tot += iov[i].iov_len;
+ buf = malloc(tot);
+ if (tot != 0 && buf == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+ nb = ret = recvfrom (s, buf, tot, flags, msg->msg_name, &msg->msg_namelen);
+ p = buf;
+ while (nb > 0) {
+ ssize_t cnt = min(nb, iov->iov_len);
+
+ memcpy (iov->iov_base, p, cnt);
+ p += cnt;
+ nb -= cnt;
+ ++iov;
+ }
+ free(buf);
+ return ret;
+}
diff --git a/third_party/heimdal/lib/roken/rename.c b/third_party/heimdal/lib/roken/rename.c
new file mode 100644
index 0000000..d7348d3
--- /dev/null
+++ b/third_party/heimdal/lib/roken/rename.c
@@ -0,0 +1,49 @@
+/***********************************************************************
+ * Copyright (c) 2010, Secure Endpoints Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDER 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 <config.h>
+#include "roken.h"
+
+/* rename() for platforms where the native implementation doesn't
+ * unlink newname. */
+int rk_rename(const char * oldname, const char * newname)
+{
+ int ret;
+
+ ret = rename(oldname, newname);
+ if (ret != 0 && (errno == EEXIST || errno == EACCES)) {
+ ret = unlink(newname);
+ if (ret == 0)
+ ret = rename(oldname, newname);
+ }
+
+ return ret;
+}
diff --git a/third_party/heimdal/lib/roken/resolve-test.c b/third_party/heimdal/lib/roken/resolve-test.c
new file mode 100644
index 0000000..581600a
--- /dev/null
+++ b/third_party/heimdal/lib/roken/resolve-test.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 1995 - 2016 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+#include "getarg.h"
+#include <assert.h>
+#ifdef HAVE_ARPA_NAMESER_H
+#include <arpa/nameser.h>
+#endif
+#ifdef HAVE_RESOLV_H
+#include <resolv.h>
+#endif
+#include "resolve.h"
+
+static int srv_rr_order = 1;
+static int loop_integer = 1;
+static int version_flag = 0;
+static int help_flag = 0;
+
+static struct getargs args[] = {
+ {"srv-rr-order", 0,
+ arg_negative_flag, &srv_rr_order,
+ "do not test SRV RR ordering", NULL },
+ {"loop", 0, arg_integer, &loop_integer,
+ "loop resolving", NULL },
+ {"version", 0, arg_flag, &version_flag,
+ "print version", NULL },
+ {"help", 0, arg_flag, &help_flag,
+ NULL, NULL }
+};
+
+static void
+usage (int ret)
+{
+ arg_printusage (args,
+ sizeof(args)/sizeof(*args),
+ NULL,
+ "dns-record resource-record-type");
+ exit (ret);
+}
+
+#define NUMRRS 16
+
+static
+int
+test_rk_dns_srv_order(size_t run)
+{
+ struct rk_dns_reply reply;
+ struct rk_resource_record rrs[NUMRRS];
+ struct rk_resource_record *rr;
+ struct rk_srv_record srvs[NUMRRS];
+ size_t i, prio0;
+ int fail = 0;
+
+ (void) memset(&reply, 0, sizeof(reply));
+ (void) memset(srvs, 0, sizeof(srvs));
+ (void) memset(rrs, 0, sizeof(rrs));
+
+ /* Test with two equal weight zero SRV records */
+ rrs[0].type = rk_ns_t_srv;
+ rrs[0].u.srv = &srvs[0];
+ rrs[0].next = &rrs[1];
+ srvs[0].priority = 10;
+ srvs[0].weight = 0;
+
+ rrs[1].type = rk_ns_t_srv;
+ rrs[1].u.srv = &srvs[1];
+ rrs[1].next = NULL;
+ srvs[1].priority = 10;
+ srvs[1].weight = 0;
+ reply.head = &rrs[0];
+
+ rk_dns_srv_order(&reply);
+ assert(reply.head != NULL);
+ printf("%p %p\n", &rrs[0], rrs[0].next);
+
+ /*
+ * Test four priority groups with priority 1--5 and weigths 0--3 in the
+ * first two groups, and 1--4 in the last two groups. Test multiple zero
+ * weights, by further coercing the weight to zero if <= run/2.
+ */
+ for (i = 0; i < NUMRRS; i++) {
+ rrs[i].type = rk_ns_t_srv;
+ rrs[i].u.srv = &srvs[i];
+ srvs[i].priority = 1 + i / 4;
+ srvs[i].weight = i % 4 + i / 8;
+ if (srvs[i].weight <= run/2)
+ srvs[i].weight = 0;
+ }
+ /* Shuffle the RRs */
+ for (i = 0; i < NUMRRS - 1; i++) {
+ struct rk_resource_record tmp;
+ size_t j = rk_random() % (NUMRRS - i);
+
+ if (j > 0) {
+ tmp = rrs[i+j];
+ rrs[i+j] = rrs[i];
+ rrs[i] = tmp;
+ }
+ }
+ for (i = 0; i < NUMRRS; i++)
+ rrs[i].next = &rrs[i + 1];
+ rrs[i - 1].next = NULL;
+ reply.head = &rrs[0];
+
+ for (i = 0, rr = reply.head; i < NUMRRS; i++) {
+ if (rr == NULL)
+ break;
+ printf("SRV RR order run %lu input: prio %lu weight %lu\n",
+ (unsigned long)run, (unsigned long)rr->u.srv->priority,
+ (unsigned long)rr->u.srv->weight);
+ rr = rr->next;
+ }
+
+ rk_dns_srv_order(&reply);
+ assert(reply.head != NULL);
+
+ /*
+ * After sorting, ensure monotone priority ordering with jumps by 1 at
+ * group boundaries.
+ */
+ prio0 = 0;
+ for (i = 0, rr = reply.head; i < NUMRRS; i++) {
+ if (rr == NULL)
+ break;
+ if (rr->u.srv->priority < prio0 ||
+ (rr->u.srv->priority != prio0 &&
+ (i % 4 != 0 || rr->u.srv->priority > prio0 + 1))) {
+ printf("SRV RR order run %zu failed\n", run);
+ fail = 1;
+ }
+ prio0 = rr->u.srv->priority;
+ printf("SRV RR order run %lu output: prio %lu weight %lu\n",
+ (unsigned long)run, (unsigned long)rr->u.srv->priority,
+ (unsigned long)rr->u.srv->weight);
+ rr = rr->next;
+ }
+ assert(i == NUMRRS);
+
+ return fail;
+}
+
+int
+main(int argc, char **argv)
+{
+ struct rk_dns_reply *r;
+ struct rk_resource_record *rr;
+ int optidx = 0, i, exit_code = 0;
+
+ setprogname (argv[0]);
+ rk_random_init();
+
+ if (getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
+ usage(1);
+
+ if (help_flag)
+ usage (0);
+
+ if (version_flag) {
+ printf("some version\n");
+ exit(0);
+ }
+
+ argc -= optidx;
+ argv += optidx;
+
+ if (argc != 2 && argc != 0 && !srv_rr_order)
+ usage(1);
+
+ if (srv_rr_order) {
+ exit_code += test_rk_dns_srv_order(0);
+ exit_code += test_rk_dns_srv_order(1);
+ exit_code += test_rk_dns_srv_order(2);
+ exit_code += test_rk_dns_srv_order(3);
+ exit_code += test_rk_dns_srv_order(4);
+ exit_code += test_rk_dns_srv_order(5);
+ }
+
+ if (srv_rr_order && argc == 0)
+ exit(exit_code ? 1 : 0);
+
+ if (argc != 2)
+ usage(1);
+
+ for (i = 0; i < loop_integer; i++) {
+
+ r = rk_dns_lookup(argv[0], argv[1]);
+ if (r == NULL) {
+ printf("No reply.\n");
+ exit_code = 1;
+ break;
+ }
+ if (r->q.type == rk_ns_t_srv)
+ rk_dns_srv_order(r);
+
+ for (rr = r->head; rr;rr=rr->next) {
+ printf("%-30s %-5s %-6d ", rr->domain, rk_dns_type_to_string(rr->type), rr->ttl);
+ switch (rr->type) {
+ case rk_ns_t_ns:
+ case rk_ns_t_cname:
+ case rk_ns_t_ptr:
+ printf("%s\n", (char*)rr->u.data);
+ break;
+ case rk_ns_t_a:
+ printf("%s\n", inet_ntoa(*rr->u.a));
+ break;
+ case rk_ns_t_mx:
+ case rk_ns_t_afsdb: {
+ printf("%d %s\n", rr->u.mx->preference, rr->u.mx->domain);
+ break;
+ }
+ case rk_ns_t_srv: {
+ struct rk_srv_record *srv = rr->u.srv;
+ printf("%d %d %d %s\n", srv->priority, srv->weight,
+ srv->port, srv->target);
+ break;
+ }
+ case rk_ns_t_txt: {
+ printf("%s\n", rr->u.txt);
+ break;
+ }
+ case rk_ns_t_sig: {
+ struct rk_sig_record *sig = rr->u.sig;
+ const char *type_string = rk_dns_type_to_string (sig->type);
+
+ printf("type %u (%s), algorithm %u, labels %u, orig_ttl %u, "
+ "sig_expiration %u, sig_inception %u, key_tag %u, "
+ "signer %s\n",
+ sig->type, type_string ? type_string : "",
+ sig->algorithm, sig->labels, sig->orig_ttl,
+ sig->sig_expiration, sig->sig_inception, sig->key_tag,
+ sig->signer);
+ break;
+ }
+ case rk_ns_t_key: {
+ struct rk_key_record *key = rr->u.key;
+
+ printf("flags %u, protocol %u, algorithm %u\n",
+ key->flags, key->protocol, key->algorithm);
+ break;
+ }
+ case rk_ns_t_sshfp: {
+ struct rk_sshfp_record *sshfp = rr->u.sshfp;
+ size_t j;
+
+ printf ("alg %u type %u length %lu data ", sshfp->algorithm,
+ sshfp->type, (unsigned long)sshfp->sshfp_len);
+ for (j = 0; j < sshfp->sshfp_len; j++)
+ printf("%02X", sshfp->sshfp_data[j]);
+ printf("\n");
+
+ break;
+ }
+ case rk_ns_t_ds: {
+ struct rk_ds_record *ds = rr->u.ds;
+ size_t j;
+
+ printf("key tag %u alg %u type %u length %lu data ",
+ ds->key_tag, ds->algorithm, ds->digest_type,
+ (unsigned long)ds->digest_len);
+ for (j = 0; j < ds->digest_len; j++)
+ printf("%02X", ds->digest_data[j]);
+ printf("\n");
+
+ break;
+ }
+ default:
+ printf("\n");
+ break;
+ }
+ }
+ rk_dns_free_data(r);
+ }
+
+ return exit_code ? 1 : 0;
+}
diff --git a/third_party/heimdal/lib/roken/resolve.c b/third_party/heimdal/lib/roken/resolve.c
new file mode 100644
index 0000000..31da413
--- /dev/null
+++ b/third_party/heimdal/lib/roken/resolve.c
@@ -0,0 +1,956 @@
+/*
+ * Copyright (c) 1995 - 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+#ifdef HAVE_ARPA_NAMESER_H
+#include <arpa/nameser.h>
+#endif
+#ifdef HAVE_RESOLV_H
+#include <resolv.h>
+#endif
+#ifdef HAVE_DNS_H
+#include <dns.h>
+#endif
+#include "resolve.h"
+
+#include <assert.h>
+
+#ifdef _AIX /* AIX have broken res_nsearch() in 5.1 (5.0 also ?) */
+#undef HAVE_RES_NSEARCH
+#endif
+
+#define DECL(X) {#X, rk_ns_t_##X}
+
+static struct stot{
+ const char *name;
+ int type;
+}stot[] = {
+ DECL(a),
+ DECL(aaaa),
+ DECL(ns),
+ DECL(cname),
+ DECL(soa),
+ DECL(ptr),
+ DECL(mx),
+ DECL(txt),
+ DECL(afsdb),
+ DECL(sig),
+ DECL(key),
+ DECL(srv),
+ DECL(naptr),
+ DECL(sshfp),
+ DECL(ds),
+ {NULL, 0}
+};
+
+int _resolve_debug = 0;
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_dns_string_to_type(const char *name)
+{
+ struct stot *p = stot;
+ for(p = stot; p->name; p++)
+ if(strcasecmp(name, p->name) == 0)
+ return p->type;
+ return -1;
+}
+
+ROKEN_LIB_FUNCTION const char * ROKEN_LIB_CALL
+rk_dns_type_to_string(int type)
+{
+ struct stot *p = stot;
+ for(p = stot; p->name; p++)
+ if(type == p->type)
+ return p->name;
+ return NULL;
+}
+
+#if ((defined(HAVE_RES_SEARCH) || defined(HAVE_RES_NSEARCH)) && defined(HAVE_DN_EXPAND)) || defined(HAVE_WINDNS)
+
+static void
+dns_free_rr(struct rk_resource_record *rr)
+{
+ if(rr->domain)
+ free(rr->domain);
+ if(rr->u.data)
+ free(rr->u.data);
+ free(rr);
+}
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rk_dns_free_data(struct rk_dns_reply *r)
+{
+ struct rk_resource_record *rr;
+ if(r->q.domain)
+ free(r->q.domain);
+ for(rr = r->head; rr;){
+ struct rk_resource_record *tmp = rr;
+ rr = rr->next;
+ dns_free_rr(tmp);
+ }
+ free (r);
+}
+
+#ifndef HAVE_WINDNS
+
+static int
+parse_record(const unsigned char *data, const unsigned char *end_data,
+ const unsigned char **pp, struct rk_resource_record **ret_rr)
+{
+ struct rk_resource_record *rr;
+ int type, class, ttl;
+ unsigned size;
+ int status;
+ char host[MAXDNAME];
+ const unsigned char *p = *pp;
+
+ *ret_rr = NULL;
+
+ status = dn_expand(data, end_data, p, host, sizeof(host));
+ if(status < 0)
+ return -1;
+ if (p + status + 10 > end_data)
+ return -1;
+
+ p += status;
+ type = (p[0] << 8) | p[1];
+ p += 2;
+ class = (p[0] << 8) | p[1];
+ p += 2;
+ ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
+ p += 4;
+ size = (p[0] << 8) | p[1];
+ p += 2;
+
+ if (p + size > end_data)
+ return -1;
+
+ rr = calloc(1, sizeof(*rr));
+ if(rr == NULL)
+ return -1;
+ rr->domain = strdup(host);
+ if(rr->domain == NULL) {
+ dns_free_rr(rr);
+ return -1;
+ }
+ rr->type = type;
+ rr->class = class;
+ rr->ttl = ttl;
+ rr->size = size;
+ switch(type){
+ case rk_ns_t_ns:
+ case rk_ns_t_cname:
+ case rk_ns_t_ptr:
+ status = dn_expand(data, end_data, p, host, sizeof(host));
+ if(status < 0) {
+ dns_free_rr(rr);
+ return -1;
+ }
+ rr->u.txt = strdup(host);
+ if(rr->u.txt == NULL) {
+ dns_free_rr(rr);
+ return -1;
+ }
+ break;
+ case rk_ns_t_mx:
+ case rk_ns_t_afsdb:{
+ size_t hostlen;
+
+ status = dn_expand(data, end_data, p + 2, host, sizeof(host));
+ if(status < 0){
+ dns_free_rr(rr);
+ return -1;
+ }
+ if ((size_t)status + 2 > size) {
+ dns_free_rr(rr);
+ return -1;
+ }
+
+ hostlen = strlen(host);
+ rr->u.mx = (struct mx_record*)malloc(sizeof(struct mx_record) +
+ hostlen);
+ if(rr->u.mx == NULL) {
+ dns_free_rr(rr);
+ return -1;
+ }
+ rr->u.mx->preference = (p[0] << 8) | p[1];
+ strlcpy(rr->u.mx->domain, host, hostlen + 1);
+ break;
+ }
+ case rk_ns_t_srv:{
+ size_t hostlen;
+ status = dn_expand(data, end_data, p + 6, host, sizeof(host));
+ if(status < 0){
+ dns_free_rr(rr);
+ return -1;
+ }
+ if ((size_t)status + 6 > size) {
+ dns_free_rr(rr);
+ return -1;
+ }
+
+ hostlen = strlen(host);
+ rr->u.srv =
+ (struct srv_record*)malloc(sizeof(struct srv_record) +
+ hostlen);
+ if(rr->u.srv == NULL) {
+ dns_free_rr(rr);
+ return -1;
+ }
+ rr->u.srv->priority = (p[0] << 8) | p[1];
+ rr->u.srv->weight = (p[2] << 8) | p[3];
+ rr->u.srv->port = (p[4] << 8) | p[5];
+ strlcpy(rr->u.srv->target, host, hostlen + 1);
+ break;
+ }
+ case rk_ns_t_txt:{
+ if(size == 0 || size < (unsigned)(*p + 1)) {
+ dns_free_rr(rr);
+ return -1;
+ }
+ rr->u.txt = (char*)malloc(*p + 1);
+ if(rr->u.txt == NULL) {
+ dns_free_rr(rr);
+ return -1;
+ }
+ strncpy(rr->u.txt, (const char*)(p + 1), *p);
+ rr->u.txt[*p] = '\0';
+ break;
+ }
+ case rk_ns_t_key : {
+ size_t key_len;
+
+ if (size < 4) {
+ dns_free_rr(rr);
+ return -1;
+ }
+
+ key_len = size - 4;
+ rr->u.key = malloc (sizeof(*rr->u.key) + key_len - 1);
+ if (rr->u.key == NULL) {
+ dns_free_rr(rr);
+ return -1;
+ }
+
+ rr->u.key->flags = (p[0] << 8) | p[1];
+ rr->u.key->protocol = p[2];
+ rr->u.key->algorithm = p[3];
+ rr->u.key->key_len = key_len;
+ memcpy (rr->u.key->key_data, p + 4, key_len);
+ break;
+ }
+ case rk_ns_t_sig : {
+ size_t sig_len, hostlen;
+
+ if(size <= 18) {
+ dns_free_rr(rr);
+ return -1;
+ }
+ status = dn_expand (data, end_data, p + 18, host, sizeof(host));
+ if (status < 0) {
+ dns_free_rr(rr);
+ return -1;
+ }
+ if ((size_t)status + 18 > size) {
+ dns_free_rr(rr);
+ return -1;
+ }
+
+ /* the signer name is placed after the sig_data, to make it
+ easy to free this structure; the size calculation below
+ includes the zero-termination if the structure itself.
+ don't you just love C?
+ */
+ sig_len = size - 18 - status;
+ hostlen = strlen(host);
+ rr->u.sig = malloc(sizeof(*rr->u.sig)
+ + hostlen + sig_len);
+ if (rr->u.sig == NULL) {
+ dns_free_rr(rr);
+ return -1;
+ }
+ rr->u.sig->type = (p[0] << 8) | p[1];
+ rr->u.sig->algorithm = p[2];
+ rr->u.sig->labels = p[3];
+ rr->u.sig->orig_ttl = (p[4] << 24) | (p[5] << 16)
+ | (p[6] << 8) | p[7];
+ rr->u.sig->sig_expiration = (p[8] << 24) | (p[9] << 16)
+ | (p[10] << 8) | p[11];
+ rr->u.sig->sig_inception = (p[12] << 24) | (p[13] << 16)
+ | (p[14] << 8) | p[15];
+ rr->u.sig->key_tag = (p[16] << 8) | p[17];
+ rr->u.sig->sig_len = sig_len;
+ memcpy (rr->u.sig->sig_data, p + 18 + status, sig_len);
+ rr->u.sig->signer = &rr->u.sig->sig_data[sig_len];
+ strlcpy(rr->u.sig->signer, host, hostlen + 1);
+ break;
+ }
+
+ case rk_ns_t_cert : {
+ size_t cert_len;
+
+ if (size < 5) {
+ dns_free_rr(rr);
+ return -1;
+ }
+
+ cert_len = size - 5;
+ rr->u.cert = malloc (sizeof(*rr->u.cert) + cert_len - 1);
+ if (rr->u.cert == NULL) {
+ dns_free_rr(rr);
+ return -1;
+ }
+
+ rr->u.cert->type = (p[0] << 8) | p[1];
+ rr->u.cert->tag = (p[2] << 8) | p[3];
+ rr->u.cert->algorithm = p[4];
+ rr->u.cert->cert_len = cert_len;
+ memcpy (rr->u.cert->cert_data, p + 5, cert_len);
+ break;
+ }
+ case rk_ns_t_sshfp : {
+ size_t sshfp_len;
+
+ if (size < 2) {
+ dns_free_rr(rr);
+ return -1;
+ }
+
+ sshfp_len = size - 2;
+
+ rr->u.sshfp = malloc (sizeof(*rr->u.sshfp) + sshfp_len - 1);
+ if (rr->u.sshfp == NULL) {
+ dns_free_rr(rr);
+ return -1;
+ }
+
+ rr->u.sshfp->algorithm = p[0];
+ rr->u.sshfp->type = p[1];
+ rr->u.sshfp->sshfp_len = sshfp_len;
+ memcpy (rr->u.sshfp->sshfp_data, p + 2, sshfp_len);
+ break;
+ }
+ case rk_ns_t_ds: {
+ size_t digest_len;
+
+ if (size < 4) {
+ dns_free_rr(rr);
+ return -1;
+ }
+
+ digest_len = size - 4;
+
+ rr->u.ds = malloc (sizeof(*rr->u.ds) + digest_len - 1);
+ if (rr->u.ds == NULL) {
+ dns_free_rr(rr);
+ return -1;
+ }
+
+ rr->u.ds->key_tag = (p[0] << 8) | p[1];
+ rr->u.ds->algorithm = p[2];
+ rr->u.ds->digest_type = p[3];
+ rr->u.ds->digest_len = digest_len;
+ memcpy (rr->u.ds->digest_data, p + 4, digest_len);
+ break;
+ }
+ default:
+ rr->u.data = (unsigned char*)malloc(size);
+ if(size != 0 && rr->u.data == NULL) {
+ dns_free_rr(rr);
+ return -1;
+ }
+ if (size)
+ memcpy(rr->u.data, p, size);
+ }
+ *pp = p + size;
+ *ret_rr = rr;
+
+ return 0;
+}
+
+#ifndef TEST_RESOLVE
+static
+#endif
+struct rk_dns_reply*
+parse_reply(const unsigned char *data, size_t len)
+{
+ const unsigned char *p;
+ int status;
+ size_t i;
+ char host[MAXDNAME];
+ const unsigned char *end_data = data + len;
+ struct rk_dns_reply *r;
+ struct rk_resource_record **rr;
+
+ r = calloc(1, sizeof(*r));
+ if (r == NULL)
+ return NULL;
+
+ p = data;
+
+ r->h.id = (p[0] << 8) | p[1];
+ r->h.flags = 0;
+ if (p[2] & 0x01)
+ r->h.flags |= rk_DNS_HEADER_RESPONSE_FLAG;
+ r->h.opcode = (p[2] >> 1) & 0xf;
+ if (p[2] & 0x20)
+ r->h.flags |= rk_DNS_HEADER_AUTHORITIVE_ANSWER;
+ if (p[2] & 0x40)
+ r->h.flags |= rk_DNS_HEADER_TRUNCATED_MESSAGE;
+ if (p[2] & 0x80)
+ r->h.flags |= rk_DNS_HEADER_RECURSION_DESIRED;
+ if (p[3] & 0x01)
+ r->h.flags |= rk_DNS_HEADER_RECURSION_AVAILABLE;
+ if (p[3] & 0x04)
+ r->h.flags |= rk_DNS_HEADER_AUTHORITIVE_ANSWER;
+ if (p[3] & 0x08)
+ r->h.flags |= rk_DNS_HEADER_CHECKING_DISABLED;
+ r->h.response_code = (p[3] >> 4) & 0xf;
+ r->h.qdcount = (p[4] << 8) | p[5];
+ r->h.ancount = (p[6] << 8) | p[7];
+ r->h.nscount = (p[8] << 8) | p[9];
+ r->h.arcount = (p[10] << 8) | p[11];
+
+ p += 12;
+
+ if(r->h.qdcount != 1) {
+ free(r);
+ return NULL;
+ }
+ status = dn_expand(data, end_data, p, host, sizeof(host));
+ if(status < 0){
+ rk_dns_free_data(r);
+ return NULL;
+ }
+ r->q.domain = strdup(host);
+ if(r->q.domain == NULL) {
+ rk_dns_free_data(r);
+ return NULL;
+ }
+ if (p + status + 4 > end_data) {
+ rk_dns_free_data(r);
+ return NULL;
+ }
+ p += status;
+ r->q.type = (p[0] << 8 | p[1]);
+ p += 2;
+ r->q.class = (p[0] << 8 | p[1]);
+ p += 2;
+
+ rr = &r->head;
+ for(i = 0; i < r->h.ancount; i++) {
+ if(parse_record(data, end_data, &p, rr) != 0) {
+ rk_dns_free_data(r);
+ return NULL;
+ }
+ rr = &(*rr)->next;
+ }
+ for(i = 0; i < r->h.nscount; i++) {
+ if(parse_record(data, end_data, &p, rr) != 0) {
+ rk_dns_free_data(r);
+ return NULL;
+ }
+ rr = &(*rr)->next;
+ }
+ for(i = 0; i < r->h.arcount; i++) {
+ if(parse_record(data, end_data, &p, rr) != 0) {
+ rk_dns_free_data(r);
+ return NULL;
+ }
+ rr = &(*rr)->next;
+ }
+ *rr = NULL;
+ return r;
+}
+
+#ifdef HAVE_RES_NSEARCH
+#ifdef HAVE_RES_NDESTROY
+#define rk_res_free(x) res_ndestroy(x)
+#else
+#define rk_res_free(x) res_nclose(x)
+#endif
+#endif
+
+#if defined(HAVE_DNS_SEARCH)
+#define resolve_search(h,n,c,t,r,l) \
+ ((int)dns_search(h,n,c,t,r,l,(struct sockaddr *)&from,&fromsize))
+#define resolve_free_handle(h) dns_free(h)
+#elif defined(HAVE_RES_NSEARCH)
+#define resolve_search(h,n,c,t,r,l) res_nsearch(h,n,c,t,r,l)
+#define resolve_free_handle(h) rk_res_free(h);
+#else
+#define resolve_search(h,n,c,t,r,l) res_search(n,c,t,r,l)
+#define handle 0
+#define resolve_free_handle(h)
+#endif
+
+
+static struct rk_dns_reply *
+dns_lookup_int(const char *domain, int rr_class, int rr_type)
+{
+ struct rk_dns_reply *r;
+ void *reply = NULL;
+ int size, len;
+#if defined(HAVE_DNS_SEARCH)
+ struct sockaddr_storage from;
+ uint32_t fromsize = sizeof(from);
+ dns_handle_t handle;
+
+ handle = dns_open(NULL);
+ if (handle == NULL)
+ return NULL;
+#elif defined(HAVE_RES_NSEARCH)
+ struct __res_state state;
+ struct __res_state *handle = &state;
+
+ memset(&state, 0, sizeof(state));
+ if(res_ninit(handle))
+ return NULL; /* is this the best we can do? */
+#endif
+
+ len = 1500;
+ while(1) {
+ if (reply) {
+ free(reply);
+ reply = NULL;
+ }
+ if (_resolve_debug) {
+#if defined(HAVE_DNS_SEARCH)
+ dns_set_debug(handle, 1);
+#elif defined(HAVE_RES_NSEARCH)
+ state.options |= RES_DEBUG;
+#endif
+ fprintf(stderr, "dns_lookup(%s, %d, %s), buffer size %d\n", domain,
+ rr_class, rk_dns_type_to_string(rr_type), len);
+ }
+ reply = malloc(len);
+ if (reply == NULL) {
+ resolve_free_handle(handle);
+ return NULL;
+ }
+
+ size = resolve_search(handle, domain, rr_class, rr_type, reply, len);
+
+ if (_resolve_debug) {
+ fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n",
+ domain, rr_class, rk_dns_type_to_string(rr_type), size);
+ }
+ if (size > len) {
+ /* resolver thinks it know better, go for it */
+ len = size;
+ } else if (size > 0) {
+ /* got a good reply */
+ break;
+ } else if (size <= 0 && len < rk_DNS_MAX_PACKET_SIZE) {
+ len *= 2;
+ if (len > rk_DNS_MAX_PACKET_SIZE)
+ len = rk_DNS_MAX_PACKET_SIZE;
+ } else {
+ /* the end, leave */
+ resolve_free_handle(handle);
+ free(reply);
+ return NULL;
+ }
+ }
+
+ len = min(len, size);
+ r = parse_reply(reply, len);
+ free(reply);
+
+ resolve_free_handle(handle);
+
+ return r;
+}
+
+ROKEN_LIB_FUNCTION struct rk_dns_reply * ROKEN_LIB_CALL
+rk_dns_lookup(const char *domain, const char *type_name)
+{
+ int type;
+
+ type = rk_dns_string_to_type(type_name);
+ if(type == -1) {
+ if(_resolve_debug)
+ fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n",
+ type_name);
+ return NULL;
+ }
+ return dns_lookup_int(domain, rk_ns_c_in, type);
+}
+
+#endif /* !HAVE_WINDNS */
+
+static int
+compare_srv(const void *a, const void *b)
+{
+ const struct rk_resource_record *const* aa = a, *const* bb = b;
+
+ if((*aa)->u.srv->priority == (*bb)->u.srv->priority)
+ return ((*aa)->u.srv->weight - (*bb)->u.srv->weight);
+ return ((*aa)->u.srv->priority - (*bb)->u.srv->priority);
+}
+
+/* try to rearrange the srv-records by the algorithm in RFC2782 */
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rk_dns_srv_order(struct rk_dns_reply *r)
+{
+ struct rk_resource_record **srvs, **ss, **headp;
+ struct rk_resource_record *rr;
+ int num_srv = 0;
+ unsigned int srv_found = FALSE;
+
+ rk_random_init();
+
+ for(rr = r->head; rr; rr = rr->next)
+ if(rr->type == rk_ns_t_srv) {
+ num_srv++;
+ srv_found = TRUE;
+ }
+
+ if(srv_found == FALSE)
+ return;
+
+ srvs = malloc(num_srv * sizeof(*srvs));
+ if(srvs == NULL)
+ return; /* XXX not much to do here */
+
+ /* unlink all srv-records from the linked list and put them in
+ a vector */
+ for(ss = srvs, headp = &r->head; *headp; )
+ if((*headp)->type == rk_ns_t_srv) {
+ *ss = *headp;
+ *headp = (*headp)->next;
+ (*ss)->next = NULL;
+ ss++;
+ } else
+ headp = &(*headp)->next;
+
+ /* sort them by priority and weight */
+ qsort(srvs, num_srv, sizeof(*srvs), compare_srv);
+
+ headp = &r->head;
+
+ for (ss = srvs; ss < srvs + num_srv; ) {
+ int sum, zeros, rnd, count; /* zeros -> weight scaling */
+ struct rk_resource_record **ee, **tt;
+
+ /*
+ * find the last record with the same priority and count the sum of all
+ * weights
+ */
+ for (sum = 0, zeros = 0, tt = ss; tt < srvs + num_srv; tt++) {
+ assert(*tt != NULL);
+ if((*tt)->u.srv->priority != (*ss)->u.srv->priority)
+ break;
+ sum += (*tt)->u.srv->weight;
+ if ((*tt)->u.srv->weight == 0)
+ zeros++;
+ }
+ /* make sure scale (`zeros') is > 0 then scale out */
+ sum += zeros ? 1 : zeros++;
+ sum *= zeros;
+ ee = tt;
+
+ /*
+ * ss is now the first record of this priority and ee is the first of
+ * the next or the first past the end of srvs
+ */
+ while (ss < ee) {
+ rnd = rk_random() % sum + 1;
+ for (count = 0, tt = ss; tt < ee; tt++) {
+ if (*tt == NULL)
+ continue; /* this one's already been picked */
+ if ((*tt)->u.srv->weight == 0)
+ count++;
+ else
+ count += (*tt)->u.srv->weight * zeros;
+ if (count >= rnd)
+ break;
+ }
+ assert(tt < ee);
+
+ /* push the selected record */
+ (*tt)->next = *headp;
+ *headp = *tt;
+ headp = &(*tt)->next;
+ /*
+ * reduce the sum so the next iteration is sure to reach the random
+ * total after examining all the remaining records.
+ */
+ if ((*tt)->u.srv->weight == 0)
+ sum--;
+ else
+ sum -= (*tt)->u.srv->weight * zeros;
+ *tt = NULL;
+ while (ss < ee && *ss == NULL)
+ ss++;
+ }
+ }
+
+ free(srvs);
+ return;
+}
+
+#ifdef HAVE_WINDNS
+
+#include <WinDNS.h>
+
+static struct rk_resource_record *
+parse_dns_record(PDNS_RECORD pRec)
+{
+ struct rk_resource_record * rr;
+
+ if (pRec == NULL)
+ return NULL;
+
+ rr = calloc(1, sizeof(*rr));
+
+ rr->domain = strdup(pRec->pName);
+ rr->type = pRec->wType;
+ rr->class = 0;
+ rr->ttl = pRec->dwTtl;
+ rr->size = 0;
+
+ switch (rr->type) {
+ case rk_ns_t_ns:
+ case rk_ns_t_cname:
+ case rk_ns_t_ptr:
+ rr->u.txt = strdup(pRec->Data.NS.pNameHost);
+ if(rr->u.txt == NULL) {
+ dns_free_rr(rr);
+ return NULL;
+ }
+ break;
+
+ case rk_ns_t_mx:
+ case rk_ns_t_afsdb:{
+ size_t hostlen = strnlen(pRec->Data.MX.pNameExchange, DNS_MAX_NAME_LENGTH);
+
+ rr->u.mx = (struct mx_record *)malloc(sizeof(struct mx_record) +
+ hostlen);
+ if (rr->u.mx == NULL) {
+ dns_free_rr(rr);
+ return NULL;
+ }
+
+ strcpy_s(rr->u.mx->domain, hostlen + 1, pRec->Data.MX.pNameExchange);
+ rr->u.mx->preference = pRec->Data.MX.wPreference;
+ break;
+ }
+
+ case rk_ns_t_srv:{
+ size_t hostlen = strnlen(pRec->Data.SRV.pNameTarget, DNS_MAX_NAME_LENGTH);
+
+ rr->u.srv =
+ (struct srv_record*)malloc(sizeof(struct srv_record) +
+ hostlen);
+ if(rr->u.srv == NULL) {
+ dns_free_rr(rr);
+ return NULL;
+ }
+
+ rr->u.srv->priority = pRec->Data.SRV.wPriority;
+ rr->u.srv->weight = pRec->Data.SRV.wWeight;
+ rr->u.srv->port = pRec->Data.SRV.wPort;
+ strcpy_s(rr->u.srv->target, hostlen + 1, pRec->Data.SRV.pNameTarget);
+
+ break;
+ }
+
+ case rk_ns_t_txt:{
+ size_t len;
+
+ if (pRec->Data.TXT.dwStringCount == 0) {
+ rr->u.txt = strdup("");
+ break;
+ }
+
+ len = strnlen(pRec->Data.TXT.pStringArray[0], DNS_MAX_TEXT_STRING_LENGTH);
+
+ rr->u.txt = (char *)malloc(len + 1);
+ strcpy_s(rr->u.txt, len + 1, pRec->Data.TXT.pStringArray[0]);
+
+ break;
+ }
+
+ case rk_ns_t_key : {
+ size_t key_len;
+
+ if (pRec->wDataLength < 4) {
+ dns_free_rr(rr);
+ return NULL;
+ }
+
+ key_len = pRec->wDataLength - 4;
+ rr->u.key = malloc (sizeof(*rr->u.key) + key_len - 1);
+ if (rr->u.key == NULL) {
+ dns_free_rr(rr);
+ return NULL;
+ }
+
+ rr->u.key->flags = pRec->Data.KEY.wFlags;
+ rr->u.key->protocol = pRec->Data.KEY.chProtocol;
+ rr->u.key->algorithm = pRec->Data.KEY.chAlgorithm;
+ rr->u.key->key_len = key_len;
+ memcpy_s (rr->u.key->key_data, key_len,
+ pRec->Data.KEY.Key, key_len);
+ break;
+ }
+
+ case rk_ns_t_sig : {
+ size_t sig_len, hostlen;
+
+ if(pRec->wDataLength <= 18) {
+ dns_free_rr(rr);
+ return NULL;
+ }
+
+ sig_len = pRec->wDataLength;
+
+ hostlen = strnlen(pRec->Data.SIG.pNameSigner, DNS_MAX_NAME_LENGTH);
+
+ rr->u.sig = malloc(sizeof(*rr->u.sig)
+ + hostlen + sig_len);
+ if (rr->u.sig == NULL) {
+ dns_free_rr(rr);
+ return NULL;
+ }
+ rr->u.sig->type = pRec->Data.SIG.wTypeCovered;
+ rr->u.sig->algorithm = pRec->Data.SIG.chAlgorithm;
+ rr->u.sig->labels = pRec->Data.SIG.chLabelCount;
+ rr->u.sig->orig_ttl = pRec->Data.SIG.dwOriginalTtl;
+ rr->u.sig->sig_expiration = pRec->Data.SIG.dwExpiration;
+ rr->u.sig->sig_inception = pRec->Data.SIG.dwTimeSigned;
+ rr->u.sig->key_tag = pRec->Data.SIG.wKeyTag;
+ rr->u.sig->sig_len = sig_len;
+ memcpy_s (rr->u.sig->sig_data, sig_len,
+ pRec->Data.SIG.Signature, sig_len);
+ rr->u.sig->signer = &rr->u.sig->sig_data[sig_len];
+ strcpy_s(rr->u.sig->signer, hostlen + 1, pRec->Data.SIG.pNameSigner);
+ break;
+ }
+
+#ifdef DNS_TYPE_DS
+ case rk_ns_t_ds: {
+ rr->u.ds = malloc (sizeof(*rr->u.ds) + pRec->Data.DS.wDigestLength - 1);
+ if (rr->u.ds == NULL) {
+ dns_free_rr(rr);
+ return NULL;
+ }
+
+ rr->u.ds->key_tag = pRec->Data.DS.wKeyTag;
+ rr->u.ds->algorithm = pRec->Data.DS.chAlgorithm;
+ rr->u.ds->digest_type = pRec->Data.DS.chDigestType;
+ rr->u.ds->digest_len = pRec->Data.DS.wDigestLength;
+ memcpy_s (rr->u.ds->digest_data, pRec->Data.DS.wDigestLength,
+ pRec->Data.DS.Digest, pRec->Data.DS.wDigestLength);
+ break;
+ }
+#endif
+
+ default:
+ dns_free_rr(rr);
+ return NULL;
+ }
+
+ rr->next = parse_dns_record(pRec->pNext);
+ return rr;
+}
+
+ROKEN_LIB_FUNCTION struct rk_dns_reply * ROKEN_LIB_CALL
+rk_dns_lookup(const char *domain, const char *type_name)
+{
+ DNS_STATUS status;
+ int type;
+ PDNS_RECORD pRec = NULL;
+ struct rk_dns_reply * r = NULL;
+
+ __try {
+
+ type = rk_dns_string_to_type(type_name);
+ if(type == -1) {
+ if(_resolve_debug)
+ fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n",
+ type_name);
+ return NULL;
+ }
+
+ status = DnsQuery_UTF8(domain, type, DNS_QUERY_STANDARD, NULL,
+ &pRec, NULL);
+ if (status != ERROR_SUCCESS)
+ return NULL;
+
+ r = calloc(1, sizeof(*r));
+ r->q.domain = strdup(domain);
+ r->q.type = type;
+ r->q.class = 0;
+
+ r->head = parse_dns_record(pRec);
+
+ if (r->head == NULL) {
+ rk_dns_free_data(r);
+ return NULL;
+ } else {
+ return r;
+ }
+
+ } __finally {
+
+ if (pRec)
+ DnsRecordListFree(pRec, DnsFreeRecordList);
+
+ }
+}
+#endif /* HAVE_WINDNS */
+
+#else /* NOT defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */
+
+ROKEN_LIB_FUNCTION struct rk_dns_reply * ROKEN_LIB_CALL
+rk_dns_lookup(const char *domain, const char *type_name)
+{
+ return NULL;
+}
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rk_dns_free_data(struct rk_dns_reply *r)
+{
+}
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rk_dns_srv_order(struct rk_dns_reply *r)
+{
+}
+
+#endif
diff --git a/third_party/heimdal/lib/roken/resolve.h b/third_party/heimdal/lib/roken/resolve.h
new file mode 100644
index 0000000..fc1e97f
--- /dev/null
+++ b/third_party/heimdal/lib/roken/resolve.h
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 1995 - 2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
+ */
+
+/* $Id$ */
+
+#ifndef __RESOLVE_H__
+#define __RESOLVE_H__
+
+#ifndef ROKEN_LIB_FUNCTION
+#ifdef _WIN32
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL __cdecl
+#else
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL
+#endif
+#endif
+
+enum {
+ rk_ns_c_in = 1
+};
+
+enum {
+ rk_ns_t_invalid = 0, /* Cookie. */
+ rk_ns_t_a = 1, /* Host address. */
+ rk_ns_t_ns = 2, /* Authoritative server. */
+ rk_ns_t_md = 3, /* Mail destination. */
+ rk_ns_t_mf = 4, /* Mail forwarder. */
+ rk_ns_t_cname = 5, /* Canonical name. */
+ rk_ns_t_soa = 6, /* Start of authority zone. */
+ rk_ns_t_mb = 7, /* Mailbox domain name. */
+ rk_ns_t_mg = 8, /* Mail group member. */
+ rk_ns_t_mr = 9, /* Mail rename name. */
+ rk_ns_t_null = 10, /* Null resource record. */
+ rk_ns_t_wks = 11, /* Well known service. */
+ rk_ns_t_ptr = 12, /* Domain name pointer. */
+ rk_ns_t_hinfo = 13, /* Host information. */
+ rk_ns_t_minfo = 14, /* Mailbox information. */
+ rk_ns_t_mx = 15, /* Mail routing information. */
+ rk_ns_t_txt = 16, /* Text strings. */
+ rk_ns_t_rp = 17, /* Responsible person. */
+ rk_ns_t_afsdb = 18, /* AFS cell database. */
+ rk_ns_t_x25 = 19, /* X_25 calling address. */
+ rk_ns_t_isdn = 20, /* ISDN calling address. */
+ rk_ns_t_rt = 21, /* Router. */
+ rk_ns_t_nsap = 22, /* NSAP address. */
+ rk_ns_t_nsap_ptr = 23, /* Reverse NSAP lookup (deprecated). */
+ rk_ns_t_sig = 24, /* Security signature. */
+ rk_ns_t_key = 25, /* Security key. */
+ rk_ns_t_px = 26, /* X.400 mail mapping. */
+ rk_ns_t_gpos = 27, /* Geographical position (withdrawn). */
+ rk_ns_t_aaaa = 28, /* Ip6 Address. */
+ rk_ns_t_loc = 29, /* Location Information. */
+ rk_ns_t_nxt = 30, /* Next domain (security). */
+ rk_ns_t_eid = 31, /* Endpoint identifier. */
+ rk_ns_t_nimloc = 32, /* Nimrod Locator. */
+ rk_ns_t_srv = 33, /* Server Selection. */
+ rk_ns_t_atma = 34, /* ATM Address */
+ rk_ns_t_naptr = 35, /* Naming Authority PoinTeR */
+ rk_ns_t_kx = 36, /* Key Exchange */
+ rk_ns_t_cert = 37, /* Certification record */
+ rk_ns_t_a6 = 38, /* IPv6 address (deprecates AAAA) */
+ rk_ns_t_dname = 39, /* Non-terminal DNAME (for IPv6) */
+ rk_ns_t_sink = 40, /* Kitchen sink (experimentatl) */
+ rk_ns_t_opt = 41, /* EDNS0 option (meta-RR) */
+ rk_ns_t_apl = 42, /* Address prefix list (RFC 3123) */
+ rk_ns_t_ds = 43, /* Delegation Signer (RFC 3658) */
+ rk_ns_t_sshfp = 44, /* SSH fingerprint */
+ rk_ns_t_tkey = 249, /* Transaction key */
+ rk_ns_t_tsig = 250, /* Transaction signature. */
+ rk_ns_t_ixfr = 251, /* Incremental zone transfer. */
+ rk_ns_t_axfr = 252, /* Transfer zone of authority. */
+ rk_ns_t_mailb = 253, /* Transfer mailbox records. */
+ rk_ns_t_maila = 254, /* Transfer mail agent records. */
+ rk_ns_t_any = 255, /* Wildcard match. */
+ rk_ns_t_zxfr = 256, /* BIND-specific, nonstandard. */
+ rk_ns_t_max = 65536
+};
+
+#ifndef MAXDNAME
+#define MAXDNAME 1025
+#endif
+
+#define mx_record rk_mx_record
+#define srv_record rk_srv_record
+#define key_record rk_key_record
+#define sig_record rk_sig_record
+#define cert_record rk_cert_record
+#define sshfp_record rk_sshfp_record
+
+struct rk_dns_query{
+ char *domain;
+ unsigned type;
+ unsigned class;
+};
+
+struct rk_mx_record{
+ unsigned preference;
+ char domain[1];
+};
+
+struct rk_srv_record{
+ unsigned priority;
+ unsigned weight;
+ unsigned port;
+ char target[1];
+};
+
+struct rk_key_record {
+ unsigned flags;
+ unsigned protocol;
+ unsigned algorithm;
+ size_t key_len;
+ u_char key_data[1];
+};
+
+struct rk_sig_record {
+ unsigned type;
+ unsigned algorithm;
+ unsigned labels;
+ unsigned orig_ttl;
+ unsigned sig_expiration;
+ unsigned sig_inception;
+ unsigned key_tag;
+ char *signer;
+ size_t sig_len;
+ char sig_data[1]; /* also includes signer */
+};
+
+struct rk_cert_record {
+ unsigned type;
+ unsigned tag;
+ unsigned algorithm;
+ size_t cert_len;
+ u_char cert_data[1];
+};
+
+struct rk_sshfp_record {
+ unsigned algorithm;
+ unsigned type;
+ size_t sshfp_len;
+ u_char sshfp_data[1];
+};
+
+struct rk_ds_record {
+ unsigned key_tag;
+ unsigned algorithm;
+ unsigned digest_type;
+ size_t digest_len;
+ u_char digest_data[1];
+};
+
+struct rk_resource_record{
+ char *domain;
+ unsigned type;
+ unsigned class;
+ unsigned ttl;
+ unsigned size;
+ union {
+ void *data;
+ struct rk_mx_record *mx;
+ struct rk_mx_record *afsdb; /* mx and afsdb are identical */
+ struct rk_srv_record *srv;
+ struct in_addr *a;
+ char *txt;
+ struct rk_key_record *key;
+ struct rk_cert_record *cert;
+ struct rk_sig_record *sig;
+ struct rk_sshfp_record *sshfp;
+ struct rk_ds_record *ds;
+ }u;
+ struct rk_resource_record *next;
+};
+
+#define rk_DNS_MAX_PACKET_SIZE 0xffff
+
+struct rk_dns_header {
+ unsigned id;
+ unsigned flags;
+#define rk_DNS_HEADER_RESPONSE_FLAG 1
+#define rk_DNS_HEADER_AUTHORITIVE_ANSWER 2
+#define rk_DNS_HEADER_TRUNCATED_MESSAGE 4
+#define rk_DNS_HEADER_RECURSION_DESIRED 8
+#define rk_DNS_HEADER_RECURSION_AVAILABLE 16
+#define rk_DNS_HEADER_AUTHENTIC_DATA 32
+#define rk_DNS_HEADER_CHECKING_DISABLED 64
+ unsigned opcode;
+ unsigned response_code;
+ unsigned qdcount;
+ unsigned ancount;
+ unsigned nscount;
+ unsigned arcount;
+};
+
+struct rk_dns_reply{
+ struct rk_dns_header h;
+ struct rk_dns_query q;
+ struct rk_resource_record *head;
+};
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ROKEN_LIB_FUNCTION struct rk_dns_reply* ROKEN_LIB_CALL
+ rk_dns_lookup(const char *, const char *);
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+ rk_dns_free_data(struct rk_dns_reply *);
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+ rk_dns_string_to_type(const char *name);
+ROKEN_LIB_FUNCTION const char * ROKEN_LIB_CALL
+ rk_dns_type_to_string(int type);
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+ rk_dns_srv_order(struct rk_dns_reply*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __RESOLVE_H__ */
diff --git a/third_party/heimdal/lib/roken/rkpty.c b/third_party/heimdal/lib/roken/rkpty.c
new file mode 100644
index 0000000..f7bfaca
--- /dev/null
+++ b/third_party/heimdal/lib/roken/rkpty.c
@@ -0,0 +1,392 @@
+/*
+ * Copyright (c) 2008 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 "config.h"
+
+#ifndef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_PTY_H
+#include <pty.h>
+#endif
+#ifdef HAVE_UTIL_H
+#include <util.h>
+#endif
+#ifdef HAVE_LIBUTIL_H
+#include <libutil.h>
+#endif
+
+#ifdef STREAMSPTY
+#include <stropts.h>
+#endif /* STREAMPTY */
+
+#include "roken.h"
+#include <getarg.h>
+
+struct command {
+ enum { CMD_EXPECT = 0, CMD_SEND, CMD_PASSWORD } type;
+ unsigned int lineno;
+ char *str;
+ struct command *next;
+};
+
+/*
+ *
+ */
+
+static struct command *commands, **next = &commands;
+
+static sig_atomic_t alarmset = 0;
+
+static int timeout = 10;
+static int verbose;
+static int help_flag;
+static int version_flag;
+
+static int master;
+static int slave;
+static char line[256] = { 0 };
+
+static void
+caught_signal(int signo)
+{
+ alarmset = signo;
+}
+
+
+static void
+open_pty(void)
+{
+#ifdef _AIX
+ printf("implement open_pty\n");
+ exit(77);
+#endif
+#if defined(HAVE_OPENPTY) || defined(__osf__) /* XXX */
+ if(openpty(&master, &slave, line, 0, 0) == 0)
+ return;
+#endif /* HAVE_OPENPTY .... */
+#ifdef STREAMSPTY
+ {
+ char *clone[] = {
+ "/dev/ptc",
+ "/dev/ptmx",
+ "/dev/ptm",
+ "/dev/ptym/clone",
+ NULL
+ };
+ char **q;
+
+ for(q = clone; *q; q++){
+ master = open(*q, O_RDWR);
+ if(master >= 0){
+#ifdef HAVE_GRANTPT
+ grantpt(master);
+#endif
+#ifdef HAVE_UNLOCKPT
+ unlockpt(master);
+#endif
+#ifdef HAVE_PTSNAME_R
+ if (ptsname_r(master, line, sizeof(line)) == -1)
+ err("Failed to open the pty master %s", *q);
+#else
+ {
+ char *s = ptsname(master);
+
+ if (s == NULL)
+ err("Failed to open the pty master %s", *q);
+ strlcpy(line, s, sizeof(line));
+ }
+#endif
+ slave = open(line, O_RDWR);
+ if (slave < 0)
+ errx(1, "failed to open slave when using %s", *q);
+ ioctl(slave, I_PUSH, "ptem");
+ ioctl(slave, I_PUSH, "ldterm");
+
+ return;
+ }
+ }
+ }
+#endif /* STREAMSPTY */
+
+ /* more cases, like open /dev/ptmx, etc */
+
+ exit(77);
+}
+
+/*
+ *
+ */
+
+static char *
+iscmd(const char *buf, const char *s)
+{
+ size_t len = strlen(s);
+ if (strncmp(buf, s, len) != 0)
+ return NULL;
+ return estrdup(buf + len);
+}
+
+static void
+parse_configuration(const char *fn)
+{
+ struct command *c;
+ char s[1024];
+ char *str;
+ unsigned int lineno = 0;
+ FILE *cmd;
+
+ cmd = fopen(fn, "r");
+ if (cmd == NULL)
+ err(1, "open: %s", fn);
+
+ while (fgets(s, sizeof(s), cmd) != NULL) {
+
+ s[strcspn(s, "#\n")] = '\0';
+ lineno++;
+
+ c = calloc(1, sizeof(*c));
+ if (c == NULL)
+ errx(1, "malloc");
+
+ c->lineno = lineno;
+ (*next) = c;
+ next = &(c->next);
+
+ if ((str = iscmd(s, "expect ")) != NULL) {
+ c->type = CMD_EXPECT;
+ c->str = str;
+ } else if ((str = iscmd(s, "send ")) != NULL) {
+ c->type = CMD_SEND;
+ c->str = str;
+ } else if ((str = iscmd(s, "password ")) != NULL) {
+ c->type = CMD_PASSWORD;
+ c->str = str;
+ } else
+ errx(1, "Invalid command on line %d: %s", lineno, s);
+ }
+
+ fclose(cmd);
+}
+
+
+/*
+ *
+ */
+
+static int
+eval_parent(pid_t pid)
+{
+ struct command *c;
+ char in;
+ size_t len = 0;
+ ssize_t sret;
+
+ for (c = commands; c != NULL; c = c->next) {
+ switch(c->type) {
+ case CMD_EXPECT:
+ if (verbose)
+ printf("[expecting %s]", c->str);
+ len = 0;
+ alarm(timeout);
+ while((sret = read(master, &in, sizeof(in))) > 0) {
+ alarm(timeout);
+ printf("%c", in);
+ if (c->str[len] != in) {
+ len = 0;
+ continue;
+ }
+ len++;
+ if (c->str[len] == '\0')
+ break;
+ }
+ alarm(0);
+ if (alarmset == SIGALRM)
+ errx(1, "timeout waiting for %s (line %u)",
+ c->str, c->lineno);
+ else if (alarmset)
+ errx(1, "got a signal %d waiting for %s (line %u)",
+ (int)alarmset, c->str, c->lineno);
+ if (sret <= 0)
+ errx(1, "end command while waiting for %s (line %u)",
+ c->str, c->lineno);
+ break;
+ case CMD_SEND:
+ case CMD_PASSWORD: {
+ size_t i = 0;
+ const char *msg = (c->type == CMD_PASSWORD) ? "****" : c->str;
+
+ if (verbose)
+ printf("[send %s]", msg);
+
+ len = strlen(c->str);
+
+ while (i < len) {
+ if (c->str[i] == '\\' && i < len - 1) {
+ char ctrl;
+ i++;
+ switch(c->str[i]) {
+ case 'n': ctrl = '\n'; break;
+ case 'r': ctrl = '\r'; break;
+ case 't': ctrl = '\t'; break;
+ default:
+ errx(1, "unknown control char %c (line %u)",
+ c->str[i], c->lineno);
+ }
+ if (net_write(master, &ctrl, 1) != 1)
+ errx(1, "command refused input (line %u)", c->lineno);
+ } else {
+ if (net_write(master, &c->str[i], 1) != 1)
+ errx(1, "command refused input (line %u)", c->lineno);
+ }
+ i++;
+ }
+ break;
+ }
+ default:
+ abort();
+ }
+ }
+ while(read(master, &in, sizeof(in)) > 0)
+ printf("%c", in);
+
+ if (verbose)
+ printf("[end of program]\n");
+
+ /*
+ * Fetch status from child
+ */
+ {
+ int ret, status;
+
+ ret = waitpid(pid, &status, 0);
+ if (ret == -1)
+ err(1, "waitpid");
+ if (WIFEXITED(status) && WEXITSTATUS(status))
+ return WEXITSTATUS(status);
+ else if (WIFSIGNALED(status)) {
+ printf("killed by signal: %d\n", WTERMSIG(status));
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ *
+ */
+
+static struct getargs args[] = {
+ { "timeout", 't', arg_integer, &timeout, "timout", "seconds" },
+ { "verbose", 'v', arg_counter, &verbose, "verbose debugging", NULL },
+ { "version", 0, arg_flag, &version_flag, "print version", NULL },
+ { "help", 0, arg_flag, &help_flag, NULL, NULL }
+};
+
+static void
+usage(int ret)
+{
+ arg_printusage (args, sizeof(args)/sizeof(*args), NULL, "infile command..");
+ exit (ret);
+}
+
+int
+main(int argc, char **argv)
+{
+ int optidx = 0;
+ pid_t pid;
+
+ setprogname(argv[0]);
+
+ if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
+ usage(1);
+
+ if (help_flag)
+ usage (0);
+
+ if (version_flag) {
+ fprintf (stderr, "%s from %s-%s\n", getprogname(), PACKAGE, VERSION);
+ return 0;
+ }
+
+ argv += optidx;
+ argc -= optidx;
+
+ if (argc < 2)
+ usage(1);
+
+ parse_configuration(argv[0]);
+
+ argv += 1;
+
+ open_pty();
+
+ pid = fork();
+ switch (pid) {
+ case -1:
+ err(1, "Failed to fork");
+ case 0:
+
+ if(setsid()<0)
+ err(1, "setsid");
+
+ dup2(slave, STDIN_FILENO);
+ dup2(slave, STDOUT_FILENO);
+ dup2(slave, STDERR_FILENO);
+ closefrom(STDERR_FILENO + 1);
+
+ execvp(argv[0], argv); /* add NULL to end of array ? */
+ err(1, "Failed to exec: %s", argv[0]);
+ default:
+ close(slave);
+ {
+ struct sigaction sa;
+
+ sa.sa_handler = caught_signal;
+ sa.sa_flags = 0;
+ sigemptyset (&sa.sa_mask);
+
+ sigaction(SIGALRM, &sa, NULL);
+ }
+
+ return eval_parent(pid);
+ }
+}
diff --git a/third_party/heimdal/lib/roken/roken-common.h b/third_party/heimdal/lib/roken/roken-common.h
new file mode 100644
index 0000000..906b000
--- /dev/null
+++ b/third_party/heimdal/lib/roken/roken-common.h
@@ -0,0 +1,569 @@
+/*
+ * Copyright (c) 1995 - 2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
+ */
+
+/* $Id$ */
+
+#ifndef __ROKEN_COMMON_H__
+#define __ROKEN_COMMON_H__
+
+#ifndef ROKEN_LIB_FUNCTION
+#ifdef _WIN32
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL __cdecl
+#else
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL
+#endif
+#endif
+
+#ifdef __cplusplus
+#define ROKEN_CPP_START extern "C" {
+#define ROKEN_CPP_END }
+#else
+#define ROKEN_CPP_START
+#define ROKEN_CPP_END
+#endif
+
+#ifndef INADDR_NONE
+#define INADDR_NONE 0xffffffff
+#endif
+
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK 0x7f000001
+#endif
+
+#ifndef SOMAXCONN
+#define SOMAXCONN 5
+#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 max
+#define max(a,b) (((a)>(b))?(a):(b))
+#endif
+
+#ifndef min
+#define min(a,b) (((a)<(b))?(a):(b))
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef LOG_DAEMON
+#define openlog(id,option,facility) openlog((id),(option))
+#define LOG_DAEMON 0
+#endif
+#ifndef LOG_ODELAY
+#define LOG_ODELAY 0
+#endif
+#ifndef LOG_NDELAY
+#define LOG_NDELAY 0x08
+#endif
+#ifndef LOG_CONS
+#define LOG_CONS 0
+#endif
+#ifndef LOG_AUTH
+#define LOG_AUTH 0
+#endif
+#ifndef LOG_AUTHPRIV
+#define LOG_AUTHPRIV LOG_AUTH
+#endif
+
+#ifndef F_OK
+#define F_OK 0
+#endif
+
+#ifndef O_ACCMODE
+#define O_ACCMODE 003
+#endif
+
+#ifndef O_NOFOLLOW
+#define O_NOFOLLOW 0
+#endif
+
+#ifdef _WIN32
+
+#define _PATH_DEVNULL "\\\\.\\NUL"
+
+#else
+
+#ifndef _PATH_DEV
+#define _PATH_DEV "/dev/"
+#endif
+
+#ifndef _PATH_DEVNULL
+#define _PATH_DEVNULL "/dev/null"
+#endif
+
+#ifndef _PATH_HEQUIV
+#define _PATH_HEQUIV "/etc/hosts.equiv"
+#endif
+
+#ifndef _PATH_VARRUN
+#define _PATH_VARRUN "/var/run/"
+#endif
+
+#ifndef _PATH_BSHELL
+#define _PATH_BSHELL "/bin/sh"
+#endif
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN (1024+4)
+#endif
+
+#endif /* !_WIN32 */
+
+#ifndef PATH_MAX
+#ifdef MAX_PATH
+#define PATH_MAX MAX_PATH
+#else
+#define PATH_MAX 4096
+#endif
+#endif
+
+#ifndef MAX_PATH
+#define MAX_PATH PATH_MAX
+#endif
+
+#ifndef RETSIGTYPE
+#define RETSIGTYPE void
+#endif
+
+#ifndef SIG_ERR
+#define SIG_ERR ((RETSIGTYPE (*)(int))-1)
+#endif
+
+/*
+ * error code for getipnodeby{name,addr}
+ */
+
+#ifndef HOST_NOT_FOUND
+#define HOST_NOT_FOUND 1
+#endif
+
+#ifndef TRY_AGAIN
+#define TRY_AGAIN 2
+#endif
+
+#ifndef NO_RECOVERY
+#define NO_RECOVERY 3
+#endif
+
+#ifndef NO_DATA
+#define NO_DATA 4
+#endif
+
+#ifndef NO_ADDRESS
+#define NO_ADDRESS NO_DATA
+#endif
+
+/*
+ * error code for getaddrinfo
+ */
+
+#ifndef EAI_NOERROR
+#define EAI_NOERROR 0 /* no error */
+#endif
+
+#ifndef EAI_NONAME
+
+#define EAI_ADDRFAMILY 1 /* address family for nodename not supported */
+#define EAI_AGAIN 2 /* temporary failure in name resolution */
+#define EAI_BADFLAGS 3 /* invalid value for ai_flags */
+#define EAI_FAIL 4 /* non-recoverable failure in name resolution */
+#define EAI_FAMILY 5 /* ai_family not supported */
+#define EAI_MEMORY 6 /* memory allocation failure */
+#define EAI_NODATA 7 /* no address associated with nodename */
+#define EAI_NONAME 8 /* nodename nor servname provided, or not known */
+#define EAI_SERVICE 9 /* servname not supported for ai_socktype */
+#define EAI_SOCKTYPE 10 /* ai_socktype not supported */
+#define EAI_SYSTEM 11 /* system error returned in errno */
+
+#endif /* EAI_NONAME */
+
+/* flags for getaddrinfo() */
+
+#ifndef AI_PASSIVE
+#define AI_PASSIVE 0x01
+#define AI_CANONNAME 0x02
+#endif /* AI_PASSIVE */
+
+#ifndef AI_NUMERICHOST
+#define AI_NUMERICHOST 0x04
+#endif
+
+#ifndef AI_NUMERICSERV
+#define AI_NUMERICSERV 0x08
+#endif
+
+/* flags for getnameinfo() */
+
+#ifndef NI_DGRAM
+#define NI_DGRAM 0x01
+#define NI_NAMEREQD 0x02
+#define NI_NOFQDN 0x04
+#define NI_NUMERICHOST 0x08
+#define NI_NUMERICSERV 0x10
+#endif
+
+/*
+ * constants for getnameinfo
+ */
+
+#ifndef NI_MAXHOST
+#define NI_MAXHOST 1025
+#define NI_MAXSERV 32
+#endif
+
+/*
+ * constants for inet_ntop
+ */
+
+#ifndef INET_ADDRSTRLEN
+#define INET_ADDRSTRLEN 16
+#endif
+
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 46
+#endif
+
+/*
+ * for shutdown(2)
+ */
+
+#ifndef SHUT_RD
+#define SHUT_RD 0
+#endif
+
+#ifndef SHUT_WR
+#define SHUT_WR 1
+#endif
+
+#ifndef SHUT_RDWR
+#define SHUT_RDWR 2
+#endif
+
+#ifndef HAVE___ATTRIBUTE__
+#define __attribute__(x)
+#endif
+
+/*
+ * for dlopen(3)
+ */
+#ifndef RTLD_LAZY
+#define RTLD_LAZY 0
+#endif
+
+#ifndef RTLD_NOW
+#define RTLD_NOW 0
+#endif
+
+#ifndef RTLD_GLOBAL
+#define RTLD_GLOBAL 0
+#endif
+
+#ifndef RTLD_LOCAL
+#define RTLD_LOCAL 0
+#endif
+
+#ifndef RTLD_GROUP
+#define RTLD_GROUP 0
+#endif
+
+#ifndef RTLD_NODELETE
+#define RTLD_NODELETE 0
+#endif
+
+ROKEN_CPP_START
+
+#ifndef IRIX4 /* fix for compiler bug */
+#ifndef _WIN32
+#ifdef RETSIGTYPE
+typedef RETSIGTYPE (*SigAction)(int);
+SigAction signal(int iSig, SigAction pAction); /* BSD compatible */
+#endif
+#endif
+#endif
+
+#define SE_E_UNSPECIFIED (-1)
+#define SE_E_FORKFAILED (-2)
+#define SE_E_WAITPIDFAILED (-3)
+#define SE_E_EXECTIMEOUT (-4)
+#define SE_E_NOEXEC 126
+#define SE_E_NOTFOUND 127
+
+#define SE_PROCSTATUS(st) (((st) >= 0 && (st) < 126)? st: -1)
+#define SE_PROCSIGNAL(st) (((st) >= 128)? (st) - 128: -1)
+#define SE_IS_ERROR(st) ((st) < 0 || (st) >= 126)
+
+
+#define simple_execve rk_simple_execve
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+simple_execve(const char*, char*const[], char*const[]);
+
+#define simple_execve_timed rk_simple_execve_timed
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+simple_execve_timed(const char *, char *const[],
+ char *const [], time_t (*)(void *),
+ void *, time_t);
+
+#define simple_execvp rk_simple_execvp
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+simple_execvp(const char*, char *const[]);
+
+#define simple_execvp_timed rk_simple_execvp_timed
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+simple_execvp_timed(const char *, char *const[],
+ time_t (*)(void *), void *, time_t);
+
+#define simple_execlp rk_simple_execlp
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+simple_execlp(const char*, ...);
+
+#define simple_execle rk_simple_execle
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+simple_execle(const char*, ...);
+
+#define wait_for_process rk_wait_for_process
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+wait_for_process(pid_t);
+
+#define wait_for_process_timed rk_wait_for_process_timed
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+wait_for_process_timed(pid_t, time_t (*)(void *),
+ void *, time_t);
+
+#define pipe_execv rk_pipe_execv
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+pipe_execv(FILE**, FILE**, FILE**, const char*, ...);
+
+#define print_version rk_print_version
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+print_version(const char *);
+
+#define eread rk_eread
+ROKEN_LIB_FUNCTION ssize_t ROKEN_LIB_CALL
+eread (int fd, void *buf, size_t nbytes);
+
+#define ewrite rk_ewrite
+ROKEN_LIB_FUNCTION ssize_t ROKEN_LIB_CALL
+ewrite (int fd, const void *buf, size_t nbytes);
+
+struct hostent;
+
+#define hostent_find_fqdn rk_hostent_find_fqdn
+ROKEN_LIB_FUNCTION const char * ROKEN_LIB_CALL
+hostent_find_fqdn (const struct hostent *);
+
+#define esetenv rk_esetenv
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+esetenv(const char *, const char *, int);
+
+#define socket_set_address_and_port rk_socket_set_address_and_port
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+socket_set_address_and_port (struct sockaddr *, const void *, int);
+
+#define socket_addr_size rk_socket_addr_size
+ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL
+socket_addr_size (const struct sockaddr *);
+
+#define socket_set_any rk_socket_set_any
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+socket_set_any (struct sockaddr *, int);
+
+#define socket_sockaddr_size rk_socket_sockaddr_size
+ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL
+socket_sockaddr_size (const struct sockaddr *);
+
+#define socket_get_address rk_socket_get_address
+ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL
+socket_get_address (const struct sockaddr *);
+
+#define socket_get_port rk_socket_get_port
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+socket_get_port (const struct sockaddr *);
+
+#define socket_set_port rk_socket_set_port
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+socket_set_port (struct sockaddr *, int);
+
+#define socket_set_portrange rk_socket_set_portrange
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+socket_set_portrange (rk_socket_t, int, int);
+
+#define socket_set_debug rk_socket_set_debug
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+socket_set_debug (rk_socket_t);
+
+#define socket_set_tos rk_socket_set_tos
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+socket_set_tos (rk_socket_t, int);
+
+#define socket_set_nonblocking rk_socket_set_nonblocking
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+socket_set_nonblocking(rk_socket_t, int);
+
+#define socket_set_reuseaddr rk_socket_set_reuseaddr
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+socket_set_reuseaddr (rk_socket_t, int);
+
+#define socket_set_ipv6only rk_socket_set_ipv6only
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+socket_set_ipv6only (rk_socket_t, int);
+
+#define socket_set_keepalive rk_socket_set_keepalive
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+socket_set_keepalive (rk_socket_t, int);
+
+#define socket_to_fd rk_socket_to_fd
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+socket_to_fd(rk_socket_t, int);
+
+#define vstrcollect rk_vstrcollect
+ROKEN_LIB_FUNCTION char ** ROKEN_LIB_CALL
+vstrcollect(va_list *ap);
+
+#define strcollect rk_strcollect
+ROKEN_LIB_FUNCTION char ** ROKEN_LIB_CALL
+strcollect(char *first, ...);
+
+ROKEN_LIB_FUNCTION time_t ROKEN_LIB_CALL
+rk_time_add(time_t, time_t);
+
+ROKEN_LIB_FUNCTION time_t ROKEN_LIB_CALL
+rk_time_sub(time_t, time_t);
+
+#define timevalfix rk_timevalfix
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+timevalfix(struct timeval *t1);
+
+#define timevaladd rk_timevaladd
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+timevaladd(struct timeval *t1, const struct timeval *t2);
+
+#define timevalsub rk_timevalsub
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+timevalsub(struct timeval *t1, const struct timeval *t2);
+
+#define pid_file_write rk_pid_file_write
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+pid_file_write (const char *progname);
+
+#define pid_file_delete rk_pid_file_delete
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+pid_file_delete (char **);
+
+#define read_environment rk_read_environment
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+read_environment(const char *file, char ***env);
+
+#define free_environment rk_free_environment
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+free_environment(char **);
+
+#define warnerr rk_warnerr
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rk_warnerr(int doerrno, const char *fmt, va_list ap)
+ ROKEN_PRINTF_ATTRIBUTE((__printf__, 2, 0));
+
+ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL
+rk_realloc(void *, size_t);
+
+struct rk_strpool;
+
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+rk_strpoolcollect(struct rk_strpool *);
+
+ROKEN_LIB_FUNCTION struct rk_strpool * ROKEN_LIB_CALL
+rk_strpoolprintf(struct rk_strpool *, const char *, ...)
+ ROKEN_PRINTF_ATTRIBUTE((__printf__, 2, 3));
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rk_strpoolfree(struct rk_strpool *);
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rk_dumpdata (const char *, const void *, size_t);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_undumpdata (const char *, void **, size_t *);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_undumptext (const char *, char **, size_t *);
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rk_xfree (void *);
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rk_cloexec(int);
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rk_cloexec_file(FILE *);
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rk_cloexec_dir(DIR *);
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rk_cloexec_socket(rk_socket_t);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+ct_memcmp(const volatile void * volatile,
+ const volatile void * volatile,
+ size_t);
+
+void ROKEN_LIB_FUNCTION
+rk_random_init(void);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_mkdir(const char *, mode_t);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_clzll(uint64_t);
+
+ROKEN_CPP_END
+
+#endif /* __ROKEN_COMMON_H__ */
diff --git a/third_party/heimdal/lib/roken/roken.awk b/third_party/heimdal/lib/roken/roken.awk
new file mode 100644
index 0000000..00e60f0
--- /dev/null
+++ b/third_party/heimdal/lib/roken/roken.awk
@@ -0,0 +1,54 @@
+# $Id$
+
+BEGIN {
+ print "#include <config.h>"
+ print "#include <stdio.h>"
+ print "#ifdef HAVE_SYS_TYPES_H"
+ print "#include <sys/types.h>"
+ print "#endif"
+ print "#ifdef HAVE_SYS_SOCKET_H"
+ print "#include <sys/socket.h>"
+ print "#endif"
+ print "#ifdef HAVE_ERRNO_H"
+ print "#include <errno.h>"
+ print "#endif"
+ print "#if !defined(__has_extension)"
+ print "#define __has_extension(x) 0"
+ print "#endif"
+ print "#ifndef ROKEN_REQUIRE_GNUC"
+ print "#define ROKEN_REQUIRE_GNUC(m,n,p) \\"
+ print " (((__GNUC__ * 10000) + (__GNUC_MINOR__ * 100) + __GNUC_PATCHLEVEL__) >= \\"
+ print " (((m) * 10000) + ((n) * 100) + (p)))"
+ print "#endif"
+ print ""
+ print "int main(int argc, char **argv)"
+ print "{"
+ print "puts(\"/* This is an OS dependent, generated file */\");"
+ print "puts(\"\\n\");"
+ print "puts(\"#ifndef __ROKEN_H__\");"
+ print "puts(\"#define __ROKEN_H__\");"
+ print "puts(\"\");"
+}
+
+$1 == "#ifdef" || $1 == "#ifndef" || $1 == "#if" || $1 == "#else" || $1 == "#elif" || $1 == "#endif" {
+ print $0;
+ next
+}
+
+{
+ s = ""
+ for(i = 1; i <= length; i++){
+ x = substr($0, i, 1)
+ if(x == "\"" || x == "\\")
+ s = s "\\";
+ s = s x;
+ }
+ print "puts(\"" s "\");"
+}
+
+END {
+ print "puts(\"\");"
+ print "puts(\"#endif /* __ROKEN_H__ */\");"
+ print "return 0;"
+ print "}"
+}
diff --git a/third_party/heimdal/lib/roken/roken.h.in b/third_party/heimdal/lib/roken/roken.h.in
new file mode 100644
index 0000000..c72d259
--- /dev/null
+++ b/third_party/heimdal/lib/roken/roken.h.in
@@ -0,0 +1,1394 @@
+/* -*- C -*- */
+/*
+ * Copyright (c) 1995-2017 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
+ */
+
+# if defined(_WIN32) && _MSC_VER >= 1400
+/* _CRT_RAND_S must be defined before including stdlib.h */
+# define _CRT_RAND_S
+# define HAVE_WIN32_RAND_S 1
+# endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <string.h>
+#include <limits.h>
+#include <signal.h>
+
+#ifdef HAVE_UTIL_H
+#include <util.h>
+#endif
+
+# ifndef ROKEN_LIB_FUNCTION
+# ifdef _WIN32
+# ifdef ROKEN_LIB_DYNAMIC
+# define ROKEN_LIB_FUNCTION __declspec(dllimport)
+# else
+# define ROKEN_LIB_FUNCTION
+# endif
+# else
+# define ROKEN_LIB_FUNCTION
+# endif
+# endif
+
+# ifndef ROKEN_LIB_NORETURN_FUNCTION
+# ifdef _WIN32
+# ifdef ROKEN_LIB_DYNAMIC
+# define ROKEN_LIB_NORETURN_FUNCTION __declspec(dllimport noreturn)
+# else
+# define ROKEN_LIB_NORETURN_FUNCTION __declspec(noreturn)
+# endif
+# else
+# define ROKEN_LIB_NORETURN_FUNCTION
+# endif
+# endif
+
+# ifndef ROKEN_LIB_CALL
+# ifdef _WIN32
+# define ROKEN_LIB_CALL __cdecl
+# else
+# define ROKEN_LIB_CALL
+# endif
+# endif
+
+# ifndef ROKEN_LIB_VARIABLE
+# ifdef _WIN32
+# ifdef ROKEN_LIB_DYNAMIC
+# define ROKEN_LIB_VARIABLE __declspec(dllimport)
+# else
+# define ROKEN_LIB_VARIABLE
+# endif
+# else
+# define ROKEN_LIB_VARIABLE
+# endif
+# endif
+
+#if !defined(__has_extension)
+#define __has_extension(x) 0
+#endif
+
+#ifndef ROKEN_REQUIRE_GNUC
+#define ROKEN_REQUIRE_GNUC(m,n,p) \
+ (((__GNUC__ * 10000) + (__GNUC_MINOR__ * 100) + __GNUC_PATCHLEVEL__) >= \
+ (((m) * 10000) + ((n) * 100) + (p)))
+#endif
+
+#ifndef ROKEN_DEPRECATED
+#if __has_extension(deprecated) || ROKEN_REQUIRE_GNUC(3,1,0)
+#define ROKEN_DEPRECATED __attribute__ ((__deprecated__))
+#elif defined(_MSC_VER) && (_MSC_VER>1200)
+#define ROKEN_DEPRECATED __declspec(deprecated)
+#else
+#define ROKEN_DEPRECATED
+#endif
+#endif
+
+#ifndef ROKEN_PRINTF_ATTRIBUTE
+#if __has_extension(format) || ROKEN_REQUIRE_GNUC(3,1,0)
+#define ROKEN_PRINTF_ATTRIBUTE(x) __attribute__ ((__format__ x))
+#else
+#define ROKEN_PRINTF_ATTRIBUTE(x)
+#endif
+#endif
+
+#ifndef ROKEN_NORETURN_ATTRIBUTE
+#if __has_extension(noreturn) || ROKEN_REQUIRE_GNUC(3,1,0)
+#define ROKEN_NORETURN_ATTRIBUTE __attribute__ ((__noreturn__))
+#else
+#define ROKEN_NORETURN_ATTRIBUTE
+#endif
+#endif
+
+#ifndef ROKEN_UNUSED_ATTRIBUTE
+#if __has_extension(unused) || ROKEN_REQUIRE_GNUC(3,1,0)
+#define ROKEN_UNUSED_ATTRIBUTE __attribute__ ((__unused__))
+#else
+#define ROKEN_UNUSED_ATTRIBUTE
+#endif
+#endif
+
+#ifndef ROKEN_WARN_UNUSED_RESULT_ATTRIBUTE
+#if __has_extension(warn_unused_result) || ROKEN_REQUIRE_GNUC(3,3,0)
+#define ROKEN_WARN_UNUSED_RESULT_ATTRIBUTE __attribute__ ((__warn_unused_result__))
+#else
+#define ROKEN_WARN_UNUSED_RESULT_ATTRIBUTE
+#endif
+#endif
+
+#ifdef HAVE_WINSOCK
+/* Declarations for Microsoft Windows */
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+/*
+ * error codes for inet_ntop/inet_pton
+ */
+typedef SOCKET rk_socket_t;
+
+#define rk_closesocket(x) closesocket(x)
+#define rk_INVALID_SOCKET INVALID_SOCKET
+#define rk_IS_BAD_SOCKET(s) ((s) == INVALID_SOCKET)
+#define rk_IS_SOCKET_ERROR(rv) ((rv) == SOCKET_ERROR)
+#define rk_SOCK_ERRNO WSAGetLastError()
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL rk_SOCK_IOCTL(SOCKET s, long cmd, int * argp);
+
+#define rk_SOCK_INIT() rk_WSAStartup()
+#define rk_SOCK_EXIT() rk_WSACleanup()
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL rk_WSAStartup(void);
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL rk_WSACleanup(void);
+
+#else /* not WinSock */
+
+typedef int rk_socket_t;
+
+#define rk_closesocket(x) close(x)
+#define rk_SOCK_IOCTL(s,c,a) ioctl((s),(c),(a))
+#define rk_IS_BAD_SOCKET(s) ((s) < 0)
+#define rk_IS_SOCKET_ERROR(rv) ((rv) < 0)
+#define rk_SOCK_ERRNO errno
+#define rk_INVALID_SOCKET (-1)
+
+static inline ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL rk_SOCK_INIT(void) {
+ return 0;
+}
+
+#define rk_SOCK_EXIT() do { } while(0)
+
+#endif /* WinSock */
+
+#ifndef IN_LOOPBACKNET
+#define IN_LOOPBACKNET 127
+#endif
+
+#ifdef _MSC_VER
+#ifndef HAVE_STDINT_H
+#include <intsafe.h>
+#endif
+
+/* Declarations for Microsoft Visual C runtime on Windows */
+
+#include<process.h>
+
+#include<io.h>
+
+#ifndef __BIT_TYPES_DEFINED__
+#define __BIT_TYPES_DEFINED__
+
+typedef __int8 int8_t;
+typedef __int16 int16_t;
+typedef __int32 int32_t;
+typedef __int64 int64_t;
+typedef unsigned __int8 uint8_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+typedef uint8_t u_int8_t;
+typedef uint16_t u_int16_t;
+typedef uint32_t u_int32_t;
+typedef uint64_t u_int64_t;
+
+#endif /* __BIT_TYPES_DEFINED__ */
+
+#define UNREACHABLE(x) x
+#define UNUSED_ARGUMENT(x) ((void) x)
+
+#define RETSIGTYPE void
+
+#define VOID_RETSIGTYPE 1
+
+#ifdef VOID_RETSIGTYPE
+#define SIGRETURN(x) return
+#else
+#define SIGRETURN(x) return (RETSIGTYPE)(x)
+#endif
+
+#ifndef CPP_ONLY
+
+typedef int pid_t;
+
+typedef unsigned int gid_t;
+
+typedef unsigned int uid_t;
+
+typedef unsigned short mode_t;
+
+#endif
+
+#ifndef __cplusplus
+#define inline __inline
+#endif
+
+#else
+
+#define UNREACHABLE(x)
+#define UNUSED_ARGUMENT(x)
+
+#endif
+
+#ifdef _AIX
+struct ether_addr;
+struct sockaddr_dl;
+#endif
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_ERRNO_H
+#include <sys/errno.h>
+#endif
+#ifdef HAVE_SYS_BITYPES_H
+#include <sys/bitypes.h>
+#endif
+#ifdef HAVE_BIND_BITYPES_H
+#include <bind/bitypes.h>
+#endif
+#ifdef HAVE_NETINET_IN6_MACHTYPES_H
+#include <netinet/in6_machtypes.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+#ifdef HAVE_GRP_H
+#include <grp.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
+#ifdef HAVE_NETINET6_IN6_H
+#include <netinet6/in6.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_NAMESER_H
+#include <arpa/nameser.h>
+#endif
+#ifdef HAVE_RESOLV_H
+#include <resolv.h>
+#endif
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <err.h>
+#ifdef HAVE_TERMIOS_H
+#include <termios.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#elif defined(HAVE_SYS_TIME_H)
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+
+#ifdef WIN32
+#include <direct.h>
+#endif
+
+#ifdef BACKSLASH_PATH_DELIM
+#define rk_PATH_DELIM '\\'
+#endif
+
+#ifndef HAVE_SSIZE_T
+#ifndef SSIZE_T_DEFINED
+#ifdef ssize_t
+#undef ssize_t
+#endif
+#ifdef _WIN64
+typedef __int64 ssize_t;
+#else
+typedef int ssize_t;
+#endif
+#define SSIZE_T_DEFINED
+#endif /* SSIZE_T_DEFINED */
+#endif /* HAVE_SSIZE_T */
+
+#include <roken-common.h>
+
+ROKEN_CPP_START
+
+#ifdef HAVE_UINTPTR_T
+#define rk_UNCONST(x) ((void *)(uintptr_t)(const void *)(x))
+#else
+#define rk_UNCONST(x) ((void *)(unsigned long)(const void *)(x))
+#endif
+
+#if !defined(HAVE_SETSID) && defined(HAVE__SETSID)
+#define setsid _setsid
+#endif
+
+#ifdef _MSC_VER
+/* Additional macros for Visual C/C++ runtime */
+
+#define close _close
+
+#define getpid _getpid
+
+#define open _open
+
+#define chdir _chdir
+
+#define fsync _commit
+
+#define _PIPE_BUFFER_SZ 8192
+#define pipe(fds) _pipe((fds), _PIPE_BUFFER_SZ, O_BINARY);
+
+#define ftruncate(fd, sz) _chsize((fd), (sz))
+
+#if !defined(HAVE_UCRT)
+#define snprintf rk_snprintf
+#define vsnprintf rk_vsnprintf
+#define vasnprintf rk_vasnprintf
+#define vasprintf rk_vasprintf
+#define asnprintf rk_asnprintf
+#define asprintf rk_asprintf
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_snprintf (char *str, size_t sz, const char *format, ...);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_asprintf (char **ret, const char *format, ...);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_asnprintf (char **ret, size_t max_sz, const char *format, ...);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_vasprintf (char **ret, const char *format, va_list args);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_vasnprintf (char **ret, size_t max_sz, const char *format, va_list args);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_vsnprintf (char *str, size_t sz, const char *format, va_list args);
+#endif /* !defined(HAVE_UCRT) */
+
+/* missing stat.h predicates */
+
+#define S_ISREG(m) (((m) & _S_IFREG) == _S_IFREG)
+
+#define S_ISDIR(m) (((m) & _S_IFDIR) == _S_IFDIR)
+
+#define S_ISCHR(m) (((m) & _S_IFCHR) == _S_IFCHR)
+
+#define S_ISFIFO(m) (((m) & _S_IFIFO) == _S_IFIFO)
+
+/* The following are not implemented:
+
+ S_ISLNK(m)
+ S_ISSOCK(m)
+ S_ISBLK(m)
+*/
+
+/* The following symbolic constants are provided for rk_mkdir mode */
+
+#define S_IRWXU 00700 /* user (file owner) has read, write and execute permission */
+#define S_IRUSR 00400 /* user has read permission */
+#define S_IWUSR 00200 /* user has write permission */
+#define S_IXUSR 00100 /* user has execute permission */
+#define S_IRWXG 00070 /* group has read, write and execute permission */
+#define S_IRGRP 00040 /* group has read permission */
+#define S_IWGRP 00020 /* group has write permission */
+#define S_IXGRP 00010 /* group has execute permission */
+#define S_IRWXO 00007 /* others have read, write and execute permission */
+#define S_IROTH 00004 /* others have read permission */
+#define S_IWOTH 00002 /* others have write permission */
+#define S_IXOTH 00001 /* others have execute permission */
+
+#if !defined(ROKEN_NO_DEFINE_ALLOCATORS)
+/* Ensure that a common memory allocator is used by all */
+#define calloc rk_calloc
+#define free rk_free
+#define malloc rk_malloc
+#define realloc rk_realloc
+#define strdup rk_strdup
+#define wcsdup rk_wcsdup
+#endif
+
+ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL
+rk_calloc(size_t, size_t);
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rk_free(void *);
+
+ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL
+rk_malloc(size_t);
+
+ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL
+rk_realloc(void *, size_t);
+
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+rk_strdup(const char *);
+
+ROKEN_LIB_FUNCTION unsigned short * ROKEN_LIB_CALL
+rk_wcsdup(const unsigned short *);
+
+#endif /* _MSC_VER */
+
+#ifndef HAVE_MEMMEM
+#define memmem rk_smemmem
+ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL memmem(const void *, size_t, const void *, size_t);
+#endif
+
+#ifdef HAVE_WINSOCK
+
+/* While we are at it, define WinSock specific scatter gather socket
+ I/O. */
+
+#define iovec _WSABUF
+#define iov_base buf
+#define iov_len len
+
+struct msghdr {
+ void *msg_name;
+ socklen_t msg_namelen;
+ struct iovec *msg_iov;
+ size_t msg_iovlen;
+ void *msg_control;
+ socklen_t msg_controllen;
+ int msg_flags;
+};
+
+#define sendmsg sendmsg_w32
+
+ROKEN_LIB_FUNCTION ssize_t ROKEN_LIB_CALL
+sendmsg_w32(rk_socket_t s, const struct msghdr * msg, int flags);
+
+#endif /* HAVE_WINSOCK */
+
+#ifndef HAVE_PUTENV
+#define putenv rk_putenv
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL putenv(const char *);
+#endif
+
+#if !defined(HAVE_SETENV) || defined(NEED_SETENV_PROTO)
+#ifndef HAVE_SETENV
+#define setenv rk_setenv
+#endif
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL setenv(const char *, const char *, int);
+#endif
+
+#if !defined(HAVE_UNSETENV) || defined(NEED_UNSETENV_PROTO)
+#ifndef HAVE_UNSETENV
+#define unsetenv rk_unsetenv
+#endif
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL unsetenv(const char *);
+#endif
+
+#if !defined(HAVE_GETUSERSHELL) || defined(NEED_GETUSERSHELL_PROTO)
+#ifndef HAVE_GETUSERSHELL
+#define getusershell rk_getusershell
+#define endusershell rk_endusershell
+#endif
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL getusershell(void);
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL endusershell(void);
+#endif
+
+#if !defined(HAVE_SNPRINTF) || defined(NEED_SNPRINTF_PROTO)
+#ifndef HAVE_SNPRINTF
+#define snprintf rk_snprintf
+#endif
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+ rk_snprintf (char *, size_t, const char *, ...)
+ ROKEN_PRINTF_ATTRIBUTE((__printf__, 3, 4));
+#endif
+
+#if !defined(HAVE_VSNPRINTF) || defined(NEED_VSNPRINTF_PROTO)
+#ifndef HAVE_VSNPRINTF
+#define vsnprintf rk_vsnprintf
+#endif
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+ rk_vsnprintf (char *, size_t, const char *, va_list)
+ ROKEN_PRINTF_ATTRIBUTE((__printf__, 3, 0));
+#endif
+
+#if !defined(HAVE_ASPRINTF) || defined(NEED_ASPRINTF_PROTO)
+#ifndef HAVE_ASPRINTF
+#define asprintf rk_asprintf
+#endif
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+ rk_asprintf (char **, const char *, ...)
+ ROKEN_PRINTF_ATTRIBUTE((__printf__, 2, 3));
+#endif
+
+#if !defined(HAVE_VASPRINTF) || defined(NEED_VASPRINTF_PROTO)
+#ifndef HAVE_VASPRINTF
+#define vasprintf rk_vasprintf
+#endif
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+ rk_vasprintf (char **, const char *, va_list)
+ ROKEN_PRINTF_ATTRIBUTE((__printf__, 2, 0));
+#endif
+
+#if !defined(HAVE_ASNPRINTF) || defined(NEED_ASNPRINTF_PROTO)
+#ifndef HAVE_ASNPRINTF
+#define asnprintf rk_asnprintf
+#endif
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+ rk_asnprintf (char **, size_t, const char *, ...)
+ ROKEN_PRINTF_ATTRIBUTE((__printf__, 3, 4));
+#endif
+
+#if !defined(HAVE_VASNPRINTF) || defined(NEED_VASNPRINTF_PROTO)
+#ifndef HAVE_VASNPRINTF
+#define vasnprintf rk_vasnprintf
+#endif
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+ vasnprintf (char **, size_t, const char *, va_list)
+ ROKEN_PRINTF_ATTRIBUTE((__printf__, 3, 0));
+#endif
+
+#if !defined(HAVE_EVASPRINTF) || defined(NEED_EVASPRINTF_PROTO)
+#define evasprintf rk_evasprintf
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+rk_evasprintf(const char *format, va_list args);
+#endif
+
+#if !defined(HAVE_EASPRINTF) || defined(NEED_EASPRINTF_PROTO)
+#define easprintf rk_easprintf
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+rk_easprintf(const char *format, ...);
+#endif
+
+#ifndef HAVE_STRDUP
+#define strdup rk_strdup
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL strdup(const char *);
+#endif
+
+#if !defined(HAVE_STRNDUP) || defined(NEED_STRNDUP_PROTO)
+#ifndef HAVE_STRNDUP
+#define strndup rk_strndup
+#endif
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL strndup(const char *, size_t);
+#endif
+
+#ifndef HAVE_STRLWR
+#define strlwr rk_strlwr
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL strlwr(char *);
+#endif
+
+#ifndef HAVE_STRNLEN
+#define strnlen rk_strnlen
+ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL strnlen(const char*, size_t);
+#endif
+
+#if !defined(HAVE_STRSEP) || defined(NEED_STRSEP_PROTO)
+#ifndef HAVE_STRSEP
+#define strsep rk_strsep
+#endif
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL strsep(char**, const char*);
+#endif
+
+#if !defined(HAVE_STRSEP_COPY) || defined(NEED_STRSEP_COPY_PROTO)
+#ifndef HAVE_STRSEP_COPY
+#define strsep_copy rk_strsep_copy
+#endif
+ROKEN_LIB_FUNCTION ssize_t ROKEN_LIB_CALL strsep_copy(const char**, const char*, char*, size_t);
+#endif
+
+#ifndef HAVE_STRCASECMP
+#define strcasecmp rk_strcasecmp
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL strcasecmp(const char *, const char *);
+#endif
+
+#ifdef NEED_FCLOSE_PROTO
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL fclose(FILE *);
+#endif
+
+#ifdef NEED_STRTOK_R_PROTO
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL strtok_r(char *, const char *, char **);
+#endif
+
+#ifndef HAVE_STRUPR
+#define strupr rk_strupr
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL strupr(char *);
+#endif
+
+#ifndef HAVE_STRLCPY
+#define strlcpy rk_strlcpy
+ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL strlcpy (char *, const char *, size_t);
+#endif
+
+#ifndef HAVE_STRLCAT
+#define strlcat rk_strlcat
+ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL strlcat (char *, const char *, size_t);
+#endif
+
+#ifndef HAVE_GETDTABLESIZE
+#define getdtablesize rk_getdtablesize
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL getdtablesize(void);
+#endif
+
+#if !defined(HAVE_STRERROR) && !defined(strerror)
+#define strerror rk_strerror
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL strerror(int);
+#endif
+
+#if (!defined(HAVE_STRERROR_R) && !defined(strerror_r)) || (!defined(STRERROR_R_PROTO_COMPATIBLE) && defined(HAVE_STRERROR_R))
+int ROKEN_LIB_FUNCTION rk_strerror_r(int, char *, size_t);
+#else
+#define rk_strerror_r strerror_r
+#endif
+
+#if !defined(HAVE_HSTRERROR) || defined(NEED_HSTRERROR_PROTO)
+#ifndef HAVE_HSTRERROR
+#define hstrerror rk_hstrerror
+#endif
+/* This causes a fatal error under Psoriasis */
+#ifndef SunOS
+ROKEN_LIB_FUNCTION const char * ROKEN_LIB_CALL hstrerror(int);
+#endif
+#endif
+
+#if !HAVE_DECL_H_ERRNO
+extern int h_errno;
+#endif
+
+#if !defined(HAVE_INET_ATON) || defined(NEED_INET_ATON_PROTO)
+#ifndef HAVE_INET_ATON
+#define inet_aton rk_inet_aton
+#endif
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL inet_aton(const char *, struct in_addr *);
+#endif
+
+#ifndef HAVE_INET_NTOP
+#define inet_ntop rk_inet_ntop
+ROKEN_LIB_FUNCTION const char * ROKEN_LIB_CALL
+inet_ntop(int af, const void *src, char *dst, size_t size);
+#endif
+
+#ifndef HAVE_INET_PTON
+#define inet_pton rk_inet_pton
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+inet_pton(int, const char *, void *);
+#endif
+
+#ifndef HAVE_GETCWD
+#define getcwd rk_getcwd
+ROKEN_LIB_FUNCTION char* ROKEN_LIB_CALL getcwd(char *, size_t);
+#endif
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+
+#ifndef HAVE_SETEUID
+#define seteuid rk_seteuid
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL seteuid(uid_t);
+#endif
+
+#ifndef HAVE_SETEGID
+#define setegid rk_setegid
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL setegid(gid_t);
+#endif
+
+#ifndef HAVE_LSTAT
+#define lstat rk_lstat
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL lstat(const char *, struct stat *);
+#endif
+
+#if !defined(HAVE_MKSTEMP) || defined(NEED_MKSTEMP_PROTO)
+#ifndef HAVE_MKSTEMP
+#define mkstemp rk_mkstemp
+#endif
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL mkstemp(char *);
+#endif
+
+#ifndef HAVE_MKOSTEMP
+#define mkostemp rk_mkostemp
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL mkostemp(char *, int);
+#endif
+
+#ifndef HAVE_MKDTEMP
+#define mkdtemp rk_mkdtemp
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL mkdtemp(char *);
+#endif
+
+#ifndef HAVE_INITGROUPS
+#define initgroups rk_initgroups
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL initgroups(const char *, gid_t);
+#endif
+
+#ifndef HAVE_FCHOWN
+#define fchown rk_fchown
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL fchown(int, uid_t, gid_t);
+#endif
+
+#ifdef RENAME_DOES_NOT_UNLINK
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL rk_rename(const char *, const char *);
+#else
+#define rk_rename(__rk_rn_from,__rk_rn_to) rename(__rk_rn_from,__rk_rn_to)
+#endif
+
+#ifdef WIN32
+#define mkdir rk_mkdir
+#else
+#define rk_mkdir(__rk_rn_name, __rk_rn_mode) mkdir(__rk_rn_name,__rk_rn_mode)
+#endif
+
+
+#if !defined(HAVE_DAEMON) || defined(NEED_DAEMON_PROTO)
+#ifndef HAVE_DAEMON
+#define daemon rk_daemon
+#endif
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL daemon(int, int);
+#endif
+
+#ifndef HAVE_CHOWN
+#define chown rk_chown
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL chown(const char *, uid_t, gid_t);
+#endif
+
+#ifndef HAVE_RCMD
+#define rcmd rk_rcmd
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+ rcmd(char **, unsigned short, const char *,
+ const char *, const char *, int *);
+#endif
+
+#if !defined(HAVE_INNETGR) || defined(NEED_INNETGR_PROTO)
+#ifndef HAVE_INNETGR
+#define innetgr rk_innetgr
+#endif
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL innetgr(const char*, const char*,
+ const char*, const char*);
+#endif
+
+#if !defined(HAVE_GETHOSTNAME) || defined(NEED_GETHOSTNAME_PROTO)
+#ifndef HAVE_GETHOSTNAME
+#define gethostname rk_gethostname
+#endif
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL gethostname(char *, int);
+#endif
+
+#ifndef HAVE_WRITEV
+#define writev rk_writev
+ROKEN_LIB_FUNCTION ssize_t ROKEN_LIB_CALL
+writev(int, const struct iovec *, int);
+#endif
+
+#ifndef HAVE_READV
+#define readv rk_readv
+ROKEN_LIB_FUNCTION ssize_t ROKEN_LIB_CALL
+readv(int, const struct iovec *, int);
+#endif
+
+#ifdef NO_PIDFILES
+#define rk_pidfile(x) ((void) 0)
+#else
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL rk_pidfile (const char*);
+#endif
+
+#ifndef HAVE_BSWAP64
+#define bswap64 rk_bswap64
+ROKEN_LIB_FUNCTION uint64_t ROKEN_LIB_CALL bswap64(uint64_t);
+#endif
+
+#ifndef HAVE_BSWAP32
+#define bswap32 rk_bswap32
+ROKEN_LIB_FUNCTION unsigned int ROKEN_LIB_CALL bswap32(unsigned int);
+#endif
+
+#ifndef HAVE_BSWAP16
+#define bswap16 rk_bswap16
+ROKEN_LIB_FUNCTION unsigned short ROKEN_LIB_CALL bswap16(unsigned short);
+#endif
+
+#ifndef HAVE_FLOCK
+#ifndef LOCK_SH
+#define LOCK_SH 1 /* Shared lock */
+#endif
+#ifndef LOCK_EX
+#define LOCK_EX 2 /* Exclusive lock */
+#endif
+#ifndef LOCK_NB
+#define LOCK_NB 4 /* Don't block when locking */
+#endif
+#ifndef LOCK_UN
+#define LOCK_UN 8 /* Unlock */
+#endif
+
+#define flock(_x,_y) rk_flock(_x,_y)
+int rk_flock(int fd, int operation);
+#endif /* HAVE_FLOCK */
+
+#ifndef HAVE_DIRFD
+#ifdef HAVE_DIR_DD_FD
+#define dirfd(x) ((x)->dd_fd)
+#elif defined(HAVE_DIR_D_FD)
+#define dirfd(x) ((x)->d_fd)
+#else
+#ifndef _WIN32 /* Windows code never calls dirfd */
+#error Missing dirfd() and ->dd_fd and ->d_fd
+#endif
+#endif
+#endif
+
+ROKEN_LIB_FUNCTION time_t ROKEN_LIB_CALL tm2time (struct tm, int);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL roken_concat (char *, size_t, ...);
+
+ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL roken_mconcat (char **, size_t, ...);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL roken_vconcat (char *, size_t, va_list);
+
+ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL
+ roken_vmconcat (char **, size_t, va_list);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL roken_detach_prep(int, char **, char *);
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL roken_detach_finish(const char *, int);
+
+ROKEN_LIB_FUNCTION ssize_t ROKEN_LIB_CALL
+ net_write (rk_socket_t, const void *, size_t);
+
+ROKEN_LIB_FUNCTION ssize_t ROKEN_LIB_CALL
+ net_read (rk_socket_t, void *, size_t);
+
+ROKEN_LIB_FUNCTION unsigned long ROKEN_LIB_CALL
+ rk_getauxval(unsigned long);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+ issuid(void);
+
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+ rk_secure_getenv(const char *);
+
+#ifndef HAVE_SECURE_GETENV
+#undef secure_getenv
+#define secure_getenv(e) rk_secure_getenv(e)
+#endif
+
+#ifndef HAVE_STRUCT_WINSIZE
+struct winsize {
+ unsigned short ws_row, ws_col;
+ unsigned short ws_xpixel, ws_ypixel;
+};
+#endif
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL get_window_size(int fd, int *, int *);
+
+#ifndef HAVE_VSYSLOG
+#define vsyslog rk_vsyslog
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL vsyslog(int, const char *, va_list);
+#endif
+
+#ifndef HAVE_GETOPT
+#define getopt rk_getopt
+#define optarg rk_optarg
+#define optind rk_optind
+#define opterr rk_opterr
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+getopt(int nargc, char * const *nargv, const char *ostr);
+#endif
+
+#if !HAVE_DECL_OPTARG
+ROKEN_LIB_VARIABLE extern char *optarg;
+#endif
+#if !HAVE_DECL_OPTIND
+ROKEN_LIB_VARIABLE extern int optind;
+#endif
+#if !HAVE_DECL_OPTERR
+ROKEN_LIB_VARIABLE extern int opterr;
+#endif
+
+#ifndef HAVE_GETIPNODEBYNAME
+#define getipnodebyname rk_getipnodebyname
+#endif
+ROKEN_LIB_FUNCTION struct hostent * ROKEN_LIB_CALL
+rk_getipnodebyname(const char *, int, int, int *);
+
+#ifndef HAVE_GETIPNODEBYADDR
+#define getipnodebyaddr rk_getipnodebyaddr
+#endif
+ROKEN_LIB_FUNCTION struct hostent * ROKEN_LIB_CALL
+rk_getipnodebyaddr(const void *, size_t, int, int *);
+
+#ifndef HAVE_FREEHOSTENT
+#define freehostent rk_freehostent
+#endif
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rk_freehostent(struct hostent *);
+
+#ifndef HAVE_COPYHOSTENT
+#define copyhostent rk_copyhostent
+#endif
+ROKEN_LIB_FUNCTION struct hostent * ROKEN_LIB_CALL
+rk_copyhostent(const struct hostent *);
+
+#ifndef HAVE_SOCKLEN_T
+typedef int socklen_t;
+#endif
+
+#ifndef HAVE_STRUCT_SOCKADDR_STORAGE
+
+#ifndef HAVE_SA_FAMILY_T
+typedef unsigned short sa_family_t;
+#endif
+
+#ifdef HAVE_IPV6
+#define _SS_MAXSIZE sizeof(struct sockaddr_in6)
+#else
+#define _SS_MAXSIZE sizeof(struct sockaddr_in)
+#endif
+
+#define _SS_ALIGNSIZE sizeof(unsigned long)
+
+#if HAVE_STRUCT_SOCKADDR_SA_LEN
+
+typedef unsigned char roken_sa_family_t;
+
+#define _SS_PAD1SIZE ((2 * _SS_ALIGNSIZE - sizeof (roken_sa_family_t) - sizeof(unsigned char)) % _SS_ALIGNSIZE)
+#define _SS_PAD2SIZE (_SS_MAXSIZE - (sizeof (roken_sa_family_t) + sizeof(unsigned char) + _SS_PAD1SIZE + _SS_ALIGNSIZE))
+
+struct sockaddr_storage {
+ unsigned char ss_len;
+ roken_sa_family_t ss_family;
+ char __ss_pad1[_SS_PAD1SIZE];
+ unsigned long __ss_align[_SS_PAD2SIZE / sizeof(unsigned long) + 1];
+};
+
+#else /* !HAVE_STRUCT_SOCKADDR_SA_LEN */
+
+typedef unsigned short roken_sa_family_t;
+
+#define _SS_PAD1SIZE ((2 * _SS_ALIGNSIZE - sizeof (roken_sa_family_t)) % _SS_ALIGNSIZE)
+#define _SS_PAD2SIZE (_SS_MAXSIZE - (sizeof (roken_sa_family_t) + _SS_PAD1SIZE + _SS_ALIGNSIZE))
+
+struct sockaddr_storage {
+ roken_sa_family_t ss_family;
+ char __ss_pad1[_SS_PAD1SIZE];
+ unsigned long __ss_align[_SS_PAD2SIZE / sizeof(unsigned long) + 1];
+};
+
+#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
+
+#endif /* HAVE_STRUCT_SOCKADDR_STORAGE */
+
+#ifndef HAVE_STRUCT_ADDRINFO
+struct addrinfo {
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ size_t ai_addrlen;
+ char *ai_canonname;
+ struct sockaddr *ai_addr;
+ struct addrinfo *ai_next;
+};
+#endif
+
+#ifndef HAVE_GETADDRINFO
+#define getaddrinfo rk_getaddrinfo
+#endif
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_getaddrinfo(const char *,
+ const char *,
+ const struct addrinfo *,
+ struct addrinfo **);
+
+#ifndef HAVE_GETNAMEINFO
+#define getnameinfo rk_getnameinfo
+#endif
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_getnameinfo(const struct sockaddr *, socklen_t,
+ char *, size_t,
+ char *, size_t,
+ int);
+
+#ifndef HAVE_FREEADDRINFO
+#define freeaddrinfo rk_freeaddrinfo
+#endif
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rk_freeaddrinfo(struct addrinfo *);
+
+#ifndef HAVE_GAI_STRERROR
+#define gai_strerror rk_gai_strerror
+ROKEN_LIB_FUNCTION const char * ROKEN_LIB_CALL
+gai_strerror(int);
+#endif
+
+#ifdef NO_SLEEP
+
+ROKEN_LIB_FUNCTION unsigned int ROKEN_LIB_CALL
+sleep(unsigned int seconds);
+
+ROKEN_LIB_FUNCTION unsigned int ROKEN_LIB_CALL
+usleep(unsigned int useconds);
+
+#endif
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+getnameinfo_verified(const struct sockaddr *, socklen_t,
+ char *, size_t,
+ char *, size_t,
+ int);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+roken_getaddrinfo_hostspec(const char *, int, struct addrinfo **);
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+roken_getaddrinfo_hostspec2(const char *, int, int, struct addrinfo **);
+
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+roken_get_homedir(char *, size_t);
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+roken_get_appdatadir(char *, size_t);
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+roken_get_username(char *, size_t);
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+roken_get_loginname(char *, size_t);
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+roken_get_shell(char *, size_t);
+
+#ifndef HAVE_STRFTIME
+#define strftime rk_strftime
+ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL
+strftime (char *, size_t, const char *, const struct tm *);
+#endif
+
+#ifndef HAVE_STRPTIME
+#define strptime rk_strptime
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+strptime (const char *, const char *, struct tm *);
+#endif
+
+#ifndef HAVE_GETTIMEOFDAY
+#define gettimeofday rk_gettimeofday
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+gettimeofday (struct timeval *, void *);
+#endif
+
+#ifndef HAVE_EMALLOC
+#define emalloc rk_emalloc
+ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL emalloc (size_t);
+#endif
+#ifndef HAVE_ECALLOC
+#define ecalloc rk_ecalloc
+ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL ecalloc(size_t, size_t);
+#endif
+#ifndef HAVE_EREALLOC
+#define erealloc rk_erealloc
+ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL erealloc (void *, size_t);
+#endif
+#ifndef HAVE_ESTRDUP
+#define estrdup rk_estrdup
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL estrdup (const char *);
+#endif
+
+/*
+ * kludges and such
+ */
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+roken_gethostby_setup(const char*, const char*);
+ROKEN_LIB_FUNCTION struct hostent* ROKEN_LIB_CALL
+roken_gethostbyname(const char*);
+ROKEN_LIB_FUNCTION struct hostent* ROKEN_LIB_CALL
+roken_gethostbyaddr(const void*, size_t, int);
+
+#ifdef GETSERVBYNAME_PROTO_COMPATIBLE
+#define roken_getservbyname(x,y) getservbyname(x,y)
+#else
+#define roken_getservbyname(x,y) getservbyname((char *)x, (char *)y)
+#endif
+
+#ifdef OPENLOG_PROTO_COMPATIBLE
+#define roken_openlog(a,b,c) openlog(a,b,c)
+#else
+#define roken_openlog(a,b,c) openlog((char *)a,b,c)
+#endif
+
+#ifdef GETSOCKNAME_PROTO_COMPATIBLE
+#define roken_getsockname(a,b,c) getsockname(a,b,c)
+#else
+#define roken_getsockname(a,b,c) getsockname(a, b, (void*)c)
+#endif
+
+#ifndef HAVE_SETPROGNAME
+#define setprogname rk_setprogname
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL setprogname(const char *);
+#endif
+
+#ifndef HAVE_GETPROGNAME
+#define getprogname rk_getprogname
+ROKEN_LIB_FUNCTION const char * ROKEN_LIB_CALL getprogname(void);
+#endif
+
+#if !defined(HAVE_SETPROGNAME) && !defined(HAVE_GETPROGNAME) && !HAVE_DECL___PROGNAME
+extern const char *__progname;
+#endif
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+mini_inetd_addrinfo (struct addrinfo*, rk_socket_t *);
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+mini_inetd (int, rk_socket_t *);
+
+#ifndef HAVE_LOCALTIME_R
+#define localtime_r rk_localtime_r
+ROKEN_LIB_FUNCTION struct tm * ROKEN_LIB_CALL
+localtime_r(const time_t *, struct tm *);
+#endif
+
+#if !defined(HAVE_STRTOLL) || defined(NEED_STRTOLL_PROTO)
+#ifndef HAVE_STRTOLL
+#define strtoll rk_strtoll
+#endif
+ROKEN_LIB_FUNCTION long long ROKEN_LIB_CALL
+strtoll(const char * nptr, char ** endptr, int base);
+#endif
+
+#if !defined(HAVE_STRTOULL) || defined(NEED_STRTOULL_PROTO)
+#ifndef HAVE_STRTOULL
+#define strtoull rk_strtoull
+#endif
+ROKEN_LIB_FUNCTION unsigned long long ROKEN_LIB_CALL
+strtoull(const char * nptr, char ** endptr, int base);
+#endif
+
+#if !defined(HAVE_STRSVIS) || defined(NEED_STRSVIS_PROTO)
+#ifndef HAVE_STRSVIS
+#define strsvis rk_strsvis
+#endif
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+strsvis(char *, const char *, int, const char *);
+#endif
+
+#if !defined(HAVE_STRSVISX) || defined(NEED_STRSVISX_PROTO)
+#ifndef HAVE_STRSVISX
+#define strsvisx rk_strsvisx
+#endif
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+strsvisx(char *, const char *, size_t, int, const char *);
+#endif
+
+#if !defined(HAVE_STRUNVIS) || defined(NEED_STRUNVIS_PROTO)
+#ifndef HAVE_STRUNVIS
+#define strunvis rk_strunvis
+#endif
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+strunvis(char *, const char *);
+#endif
+
+#if !defined(HAVE_STRVIS) || defined(NEED_STRVIS_PROTO)
+#ifndef HAVE_STRVIS
+#define strvis rk_strvis
+#endif
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+strvis(char *, const char *, int);
+#endif
+
+#if !defined(HAVE_STRVISX) || defined(NEED_STRVISX_PROTO)
+#ifndef HAVE_STRVISX
+#define strvisx rk_strvisx
+#endif
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+strvisx(char *, const char *, size_t, int);
+#endif
+
+#if !defined(HAVE_SVIS) || defined(NEED_SVIS_PROTO)
+#ifndef HAVE_SVIS
+#define svis rk_svis
+#endif
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+svis(char *, int, int, int, const char *);
+#endif
+
+#if !defined(HAVE_UNVIS) || defined(NEED_UNVIS_PROTO)
+#ifndef HAVE_UNVIS
+#define unvis rk_unvis
+#endif
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+unvis(char *, int, int *, int);
+#endif
+
+#if !defined(HAVE_VIS) || defined(NEED_VIS_PROTO)
+#ifndef HAVE_VIS
+#define vis rk_vis
+#endif
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+vis(char *, int, int, int);
+#endif
+
+#if !defined(HAVE_CLOSEFROM)
+#define closefrom rk_closefrom
+#endif
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_closefrom(int);
+
+#if !defined(HAVE_TIMEGM)
+#define timegm rk_timegm
+ROKEN_LIB_FUNCTION time_t ROKEN_LIB_CALL
+rk_timegm(struct tm *tm);
+#endif
+
+#ifdef NEED_QSORT
+#define qsort rk_qsort
+void
+rk_qsort(void *, size_t, size_t, int (*)(const void *, const void *));
+#endif
+
+#if !defined(HAVE_MERGESORT)
+#define mergesort rk_mergesort
+int
+mergesort(void *base, size_t nel, size_t width,
+ int (*compar)(const void *, const void *));
+#endif
+
+#if !defined(HAVE_MERGESORT_R)
+#define mergesort_r rk_mergesort_r
+int
+mergesort_r(void *base, size_t nel, size_t width,
+ int (*compar)(const void *, const void *, void *), void *thunk);
+#endif
+
+#ifndef HAVE_MEMSET_S
+#define memset_s rk_memset_s
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL memset_s(void *s, size_t smax,
+ int c, size_t n);
+#endif
+
+#if defined(HAVE_ARC4RANDOM)
+# define rk_random() arc4random()
+#elif defined(HAVE_RANDOM)
+# define rk_random() random()
+#else
+# ifdef HAVE_WIN32_RAND_S
+ROKEN_LIB_FUNCTION unsigned int ROKEN_LIB_CALL
+rk_random(void);
+# else
+# define rk_random() rand()
+# endif
+#endif
+
+#ifndef HAVE_TDELETE
+#define tdelete(a,b,c) rk_tdelete(a,b,c)
+#endif
+#ifndef HAVE_TFIND
+#define tfind(a,b,c) rk_tfind(a,b,c)
+#endif
+#ifndef HAVE_TSEARCH
+#define tsearch(a,b,c) rk_tsearch(a,b,c)
+#endif
+#ifndef HAVE_TWALK
+#define twalk(a,b) rk_twalk(a,b)
+#endif
+
+#if defined(__linux__) && defined(SOCK_CLOEXEC) && !defined(SOCKET_WRAPPER_REPLACE) && !defined(__SOCKET_WRAPPER_H__)
+#undef socket
+#define socket(_fam,_type,_prot) rk_socket(_fam,_type,_prot)
+int ROKEN_LIB_FUNCTION rk_socket(int, int, int);
+#endif
+
+/* Microsoft VC 2010 POSIX definitions */
+#ifndef EAFNOSUPPORT
+#define EAFNOSUPPORT 102
+#endif
+#ifndef EINPROGRESS
+#define EINPROGRESS 112
+#endif
+#ifndef ELOOP
+#define ELOOP 114
+#endif
+#ifndef ENOTSOCK
+#define ENOTSOCK 128
+#endif
+#ifndef ENOTSUP
+#define ENOTSUP 129
+#endif
+#ifndef EOVERFLOW
+#define EOVERFLOW 132
+#endif
+#ifndef ETIMEDOUT
+#define ETIMEDOUT 138
+#endif
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK 140
+#endif
+
+#ifdef WIN32
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+win32_getLibraryVersion(const char *libname, char **outname, char **outversion);
+#endif
+
+#ifdef SOCKET_WRAPPER_REPLACE
+#include <socket_wrapper.h>
+#endif
+
+ROKEN_CPP_END
diff --git a/third_party/heimdal/lib/roken/roken_gethostby.c b/third_party/heimdal/lib/roken/roken_gethostby.c
new file mode 100644
index 0000000..a2febd0
--- /dev/null
+++ b/third_party/heimdal/lib/roken/roken_gethostby.c
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 1998 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+#undef roken_gethostbyname
+#undef roken_gethostbyaddr
+
+static struct sockaddr_in dns_addr;
+static char *dns_req;
+
+static int
+make_address(const char *address, struct in_addr *ip)
+{
+ if(inet_aton(address, ip) == 0){
+ /* try to resolve as hostname, it might work if the address we
+ are trying to lookup is local, for instance a web proxy */
+ struct hostent *he = gethostbyname(address);
+ if(he) {
+ unsigned char *p = (unsigned char*)he->h_addr;
+ ip->s_addr = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
+ } else {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int
+setup_int(const char *proxy_host, short proxy_port,
+ const char *dns_host, short dns_port,
+ const char *dns_path)
+{
+ memset(&dns_addr, 0, sizeof(dns_addr));
+ if(dns_req)
+ free(dns_req);
+ dns_req = NULL;
+ if(proxy_host) {
+ if(make_address(proxy_host, &dns_addr.sin_addr) != 0)
+ return -1;
+ dns_addr.sin_port = htons(proxy_port);
+ if (asprintf(&dns_req, "http://%s:%d%s", dns_host, dns_port, dns_path) < 0)
+ return -1;
+ } else {
+ if(make_address(dns_host, &dns_addr.sin_addr) != 0)
+ return -1;
+ dns_addr.sin_port = htons(dns_port);
+ if (asprintf(&dns_req, "%s", dns_path) < 0)
+ return -1;
+ }
+ dns_addr.sin_family = AF_INET;
+ return 0;
+}
+
+static int
+split_spec(const char *spec, char **host, int *port, char **path, int def_port)
+{
+ char *p;
+ *host = strdup(spec);
+ if (*host == NULL)
+ return -1;
+ p = strchr(*host, ':');
+ if(p) {
+ *p++ = '\0';
+ if(sscanf(p, "%d", port) != 1)
+ *port = def_port;
+ } else
+ *port = def_port;
+ p = strchr(p ? p : *host, '/');
+ if(p) {
+ if(path) {
+ *path = strdup(p);
+ if (*path == NULL) {
+ free(*host);
+ *host = NULL;
+ return -1;
+ }
+ }
+ *p = '\0';
+ }else
+ if(path)
+ *path = NULL;
+ return 0;
+}
+
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+roken_gethostby_setup(const char *proxy_spec, const char *dns_spec)
+{
+ char *proxy_host = NULL;
+ int proxy_port = 0;
+ char *dns_host = NULL, *dns_path = NULL;
+ int dns_port;
+ int ret;
+
+ ret = split_spec(dns_spec, &dns_host, &dns_port, &dns_path, 80);
+ if(ret)
+ goto out;
+ if(proxy_spec) {
+ ret = split_spec(proxy_spec, &proxy_host, &proxy_port, NULL, 80);
+ if (ret)
+ goto out;
+ }
+ ret = setup_int(proxy_host, proxy_port, dns_host, dns_port, dns_path);
+ if (ret)
+ goto out;
+
+out:
+ free(proxy_host);
+ free(dns_host);
+ free(dns_path);
+ return ret;
+}
+
+
+/* Try to lookup a name or an ip-address using http as transport
+ mechanism. See the end of this file for an example program. */
+static struct hostent*
+roken_gethostby(const char *hostname)
+{
+ int s;
+ struct sockaddr_in addr;
+ char *request = NULL;
+ char buf[1024];
+ int offset = 0;
+ int n;
+ char *p, *foo;
+ size_t len;
+
+ if(dns_addr.sin_family == 0)
+ return NULL; /* no configured host */
+ addr = dns_addr;
+ if (asprintf(&request, "GET %s?%s HTTP/1.0\r\n\r\n", dns_req, hostname) < 0)
+ return NULL;
+ if(request == NULL)
+ return NULL;
+ s = socket(AF_INET, SOCK_STREAM, 0);
+ if(s < 0) {
+ free(request);
+ return NULL;
+ }
+ if(connect(s, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
+ close(s);
+ free(request);
+ return NULL;
+ }
+
+ len = strlen(request);
+ if(write(s, request, len) != (ssize_t)len) {
+ close(s);
+ free(request);
+ return NULL;
+ }
+ free(request);
+ while(1) {
+ n = read(s, buf + offset, sizeof(buf) - offset);
+ if(n <= 0)
+ break;
+ offset += n;
+ }
+ buf[offset] = '\0';
+ close(s);
+ p = strstr(buf, "\r\n\r\n"); /* find end of header */
+ if(p) p += 4;
+ else return NULL;
+ foo = NULL;
+ p = strtok_r(p, " \t\r\n", &foo);
+ if(p == NULL)
+ return NULL;
+ {
+ /* make a hostent to return */
+#define MAX_ADDRS 16
+ static struct hostent he;
+ static char addrs[4 * MAX_ADDRS];
+ static char *addr_list[MAX_ADDRS + 1];
+ int num_addrs = 0;
+
+ he.h_name = p;
+ he.h_aliases = NULL;
+ he.h_addrtype = AF_INET;
+ he.h_length = 4;
+
+ while((p = strtok_r(NULL, " \t\r\n", &foo)) && num_addrs < MAX_ADDRS) {
+ struct in_addr ip;
+ inet_aton(p, &ip);
+ ip.s_addr = ntohl(ip.s_addr);
+ addr_list[num_addrs] = &addrs[num_addrs * 4];
+ addrs[num_addrs * 4 + 0] = (ip.s_addr >> 24) & 0xff;
+ addrs[num_addrs * 4 + 1] = (ip.s_addr >> 16) & 0xff;
+ addrs[num_addrs * 4 + 2] = (ip.s_addr >> 8) & 0xff;
+ addrs[num_addrs * 4 + 3] = (ip.s_addr >> 0) & 0xff;
+ addr_list[++num_addrs] = NULL;
+ }
+ he.h_addr_list = addr_list;
+ return &he;
+ }
+}
+
+ROKEN_LIB_FUNCTION struct hostent* ROKEN_LIB_CALL
+roken_gethostbyname(const char *hostname)
+{
+ struct hostent *he;
+ he = gethostbyname(hostname);
+ if(he)
+ return he;
+ return roken_gethostby(hostname);
+}
+
+ROKEN_LIB_FUNCTION struct hostent* ROKEN_LIB_CALL
+roken_gethostbyaddr(const void *addr, size_t len, int type)
+{
+ struct in_addr a;
+ const char *p;
+ struct hostent *he;
+ he = gethostbyaddr(addr, len, type);
+ if(he)
+ return he;
+ if(type != AF_INET || len != 4)
+ return NULL;
+ p = addr;
+ a.s_addr = htonl((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
+ return roken_gethostby(inet_ntoa(a));
+}
+
+#if 0
+
+/* this program can be used as a cgi `script' to lookup names and
+ ip-addresses */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <sys/param.h>
+
+int
+main(int argc, char **argv)
+{
+ char *query = getenv("QUERY_STRING");
+ char host[MAXHOSTNAMELEN];
+ int i;
+ struct hostent *he;
+
+ printf("Content-type: text/plain\n\n");
+ if(query == NULL)
+ exit(0);
+ he = gethostbyname(query);
+ strncpy(host, he->h_name, sizeof(host));
+ host[sizeof(host) - 1] = '\0';
+ he = gethostbyaddr(he->h_addr, he->h_length, AF_INET);
+ printf("%s\n", he->h_name);
+ for(i = 0; he->h_addr_list[i]; i++) {
+ struct in_addr ip;
+ unsigned char *p = (unsigned char*)he->h_addr_list[i];
+ ip.s_addr = htonl((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
+ printf("%s\n", inet_ntoa(ip));
+ }
+ exit(0);
+}
+
+#endif
diff --git a/third_party/heimdal/lib/roken/rtbl.3 b/third_party/heimdal/lib/roken/rtbl.3
new file mode 100644
index 0000000..0d70918
--- /dev/null
+++ b/third_party/heimdal/lib/roken/rtbl.3
@@ -0,0 +1,201 @@
+.\" Copyright (c) 2004 Kungliga Tekniska Högskolan
+.\" (Royal Institute of Technology, Stockholm, Sweden).
+.\" 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
+.\" $Id$
+.\"
+.Dd June 26, 2004
+.Dt RTBL 3
+.Os HEIMDAL
+.Sh NAME
+.Nm rtbl_create ,
+.Nm rtbl_destroy ,
+.Nm rtbl_set_flags ,
+.Nm rtbl_get_flags ,
+.Nm rtbl_set_prefix ,
+.Nm rtbl_set_separator ,
+.Nm rtbl_set_column_prefix ,
+.Nm rtbl_set_column_affix_by_id ,
+.Nm rtbl_add_column ,
+.Nm rtbl_add_column_by_id ,
+.Nm rtbl_add_column_entry ,
+.Nm rtbl_add_column_entry_by_id ,
+.Nm rtbl_new_row ,
+.Nm rtbl_format
+.Nd format data in simple tables
+.Sh LIBRARY
+The roken library (libroken, -lroken)
+.Sh SYNOPSIS
+.In rtbl.h
+.Ft int
+.Fn rtbl_add_column "rtbl_t table" "const char *column_name" "unsigned int flags"
+.Ft int
+.Fn rtbl_add_column_by_id "rtbl_t table" "unsigned int column_id" "const char *column_header" "unsigned int flags"
+.Ft int
+.Fn rtbl_add_column_entry "rtbl_t table" "const char *column_name" "const char *cell_entry"
+.Ft int
+.Fn rtbl_add_column_entry_by_id "rtbl_t table" "unsigned int column_id" "const char *cell_entry"
+.Ft rtbl_t
+.Fn rtbl_create "void"
+.Ft void
+.Fn rtbl_destroy "rtbl_t table"
+.Ft int
+.Fn rtbl_new_row "rtbl_t table"
+.Ft int
+.Fn rtbl_set_column_affix_by_id "rtbl_t table" "unsigned int column_id "const char *prefix" "const char *suffix"
+.Ft int
+.Fn rtbl_set_column_prefix "rtbl_t table" "const char *column_name" "const char *prefix"
+.Ft "unsigned int"
+.Fn rtbl_get_flags "rtbl_t table"
+.Ft void
+.Fn rtbl_set_flags "rtbl_t table" "unsigned int flags"
+.Ft int
+.Fn rtbl_set_prefix "rtbl_t table" "const char *prefix"
+.Ft int
+.Fn rtbl_set_separator "rtbl_t table" "const char *separator"
+.Ft int
+.Fn rtbl_format "rtbl_t table "FILE *file"
+.Sh DESCRIPTION
+This set of functions assemble a simple table consisting of rows and
+columns, allowing it to be printed with certain options. Typical use
+would be output from tools such as
+.Xr ls 1
+or
+.Xr netstat 1 ,
+where you have a fixed number of columns, but don't know the column
+widths before hand.
+.Pp
+A table is created with
+.Fn rtbl_create
+and destroyed with
+.Fn rtbl_destroy .
+.Pp
+Global flags on the table are set with
+.Fa rtbl_set_flags
+and retrieved with
+.Fa rtbl_get_flags .
+At present the only defined flag is
+.Dv RTBL_HEADER_STYLE_NONE
+which suppresses printing the header.
+.Pp
+Before adding data to the table, one or more columns need to be
+created. This would normally be done with
+.Fn rtbl_add_column_by_id ,
+.Fa column_id
+is any number of your choice (it's used only to identify columns),
+.Fa column_header
+is the header to print at the top of the column, and
+.Fa flags
+are flags specific to this column. Currently the only defined flag is
+.Dv RTBL_ALIGN_RIGHT ,
+aligning column entries to the right. Columns are printed in the order
+they are added.
+.Pp
+There's also a way to add columns by column name with
+.Fn rtbl_add_column ,
+but this is less flexible (you need unique header names), and is
+considered deprecated.
+.Pp
+To add data to a column you use
+.Fn rtbl_add_column_entry_by_id ,
+where the
+.Fa column_id
+is the same as when the column was added (adding data to a
+non-existent column is undefined), and
+.Fa cell_entry
+is whatever string you wish to include in that cell. It should not
+include newlines.
+For columns added with
+.Fn rtbl_add_column
+you must use
+.Fn rtbl_add_column_entry
+instead.
+.Pp
+.Fn rtbl_new_row
+fills all columns with blank entries until they all have the same
+number of rows.
+.Pp
+Each column can have a separate prefix and suffix, set with
+.Fa rtbl_set_column_affix_by_id ;
+.Fa rtbl_set_column_prefix
+allows setting the prefix only by column name. In addition to this,
+columns may be separated by a string set with
+.Fa rtbl_set_separator ( Ns
+by default columns are not seprated by anything).
+.Pp
+The finished table is printed to
+.Fa file
+with
+.Fa rtbl_format .
+.Sh EXAMPLES
+This program:
+.Bd -literal -offset xxxx
+#include <stdio.h>
+#include <rtbl.h>
+int
+main(int argc, char **argv)
+{
+ rtbl_t table;
+ table = rtbl_create();
+ rtbl_set_separator(table, " ");
+ rtbl_add_column_by_id(table, 0, "Column A", 0);
+ rtbl_add_column_by_id(table, 1, "Column B", RTBL_ALIGN_RIGHT);
+ rtbl_add_column_by_id(table, 2, "Column C", 0);
+ rtbl_add_column_entry_by_id(table, 0, "A-1");
+ rtbl_add_column_entry_by_id(table, 0, "A-2");
+ rtbl_add_column_entry_by_id(table, 0, "A-3");
+ rtbl_add_column_entry_by_id(table, 1, "B-1");
+ rtbl_add_column_entry_by_id(table, 2, "C-1");
+ rtbl_add_column_entry_by_id(table, 2, "C-2");
+ rtbl_add_column_entry_by_id(table, 1, "B-2");
+ rtbl_add_column_entry_by_id(table, 1, "B-3");
+ rtbl_add_column_entry_by_id(table, 2, "C-3");
+ rtbl_add_column_entry_by_id(table, 0, "A-4");
+ rtbl_new_row(table);
+ rtbl_add_column_entry_by_id(table, 1, "B-4");
+ rtbl_new_row(table);
+ rtbl_add_column_entry_by_id(table, 2, "C-4");
+ rtbl_new_row(table);
+ rtbl_format(table, stdout);
+ rtbl_destroy(table);
+ return 0;
+}
+.Ed
+.Pp
+will output the following:
+.Bd -literal -offset xxxx
+Column A Column B Column C
+A-1 B-1 C-1
+A-2 B-2 C-2
+A-3 B-3 C-3
+A-4
+ B-4
+ C-4
+.Ed
+.\" .Sh SEE ALSO
diff --git a/third_party/heimdal/lib/roken/rtbl.c b/third_party/heimdal/lib/roken/rtbl.c
new file mode 100644
index 0000000..1e9e72b
--- /dev/null
+++ b/third_party/heimdal/lib/roken/rtbl.c
@@ -0,0 +1,558 @@
+/*
+ * Copyright (c) 2000, 2002, 2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+#include <ctype.h>
+#include "rtbl.h"
+
+struct column_entry {
+ char *data;
+};
+
+struct column_data {
+ char *header;
+ char *prefix;
+ int width;
+ unsigned flags;
+ size_t num_rows;
+ struct column_entry *rows;
+ unsigned int column_id;
+ char *suffix;
+};
+
+struct rtbl_data {
+ char *column_prefix;
+ size_t num_columns;
+ struct column_data **columns;
+ unsigned int flags;
+ char *column_separator;
+};
+
+ROKEN_LIB_FUNCTION rtbl_t ROKEN_LIB_CALL
+rtbl_create (void)
+{
+ return calloc (1, sizeof (struct rtbl_data));
+}
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rtbl_set_flags (rtbl_t table, unsigned int flags)
+{
+ table->flags = flags;
+}
+
+ROKEN_LIB_FUNCTION unsigned int ROKEN_LIB_CALL
+rtbl_get_flags (rtbl_t table)
+{
+ return table->flags;
+}
+
+static struct column_data *
+rtbl_get_column_by_id (rtbl_t table, unsigned int id)
+{
+ size_t i;
+ for(i = 0; i < table->num_columns; i++)
+ if(table->columns[i]->column_id == id)
+ return table->columns[i];
+ return NULL;
+}
+
+static struct column_data *
+rtbl_get_column (rtbl_t table, const char *column)
+{
+ size_t i;
+ for(i = 0; i < table->num_columns; i++)
+ if(strcmp(table->columns[i]->header, column) == 0)
+ return table->columns[i];
+ return NULL;
+}
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rtbl_destroy (rtbl_t table)
+{
+ size_t i, j;
+
+ for (i = 0; i < table->num_columns; i++) {
+ struct column_data *c = table->columns[i];
+
+ for (j = 0; j < c->num_rows; j++)
+ free (c->rows[j].data);
+ free (c->rows);
+ free (c->header);
+ free (c->prefix);
+ free (c->suffix);
+ free (c);
+ }
+ free (table->column_prefix);
+ free (table->column_separator);
+ free (table->columns);
+ free (table);
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rtbl_add_column_by_id (rtbl_t table, unsigned int id,
+ const char *header, unsigned int flags)
+{
+ struct column_data *col, **tmp;
+
+ tmp = realloc (table->columns, (table->num_columns + 1) * sizeof (*tmp));
+ if (tmp == NULL)
+ return ENOMEM;
+ table->columns = tmp;
+ col = malloc (sizeof (*col));
+ if (col == NULL)
+ return ENOMEM;
+ col->header = strdup (header);
+ if (col->header == NULL) {
+ free (col);
+ return ENOMEM;
+ }
+ col->prefix = NULL;
+ col->width = 0;
+ col->flags = flags;
+ col->num_rows = 0;
+ col->rows = NULL;
+ col->column_id = id;
+ col->suffix = NULL;
+ table->columns[table->num_columns++] = col;
+ return 0;
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rtbl_add_column (rtbl_t table, const char *header, unsigned int flags)
+{
+ return rtbl_add_column_by_id(table, 0, header, flags);
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rtbl_new_row(rtbl_t table)
+{
+ size_t max_rows = 0;
+ size_t c;
+ for (c = 0; c < table->num_columns; c++)
+ if(table->columns[c]->num_rows > max_rows)
+ max_rows = table->columns[c]->num_rows;
+ for (c = 0; c < table->num_columns; c++) {
+ struct column_entry *tmp;
+
+ if(table->columns[c]->num_rows == max_rows)
+ continue;
+ tmp = realloc(table->columns[c]->rows,
+ max_rows * sizeof(table->columns[c]->rows[0]));
+ if(tmp == NULL)
+ return ENOMEM;
+ table->columns[c]->rows = tmp;
+ while(table->columns[c]->num_rows < max_rows) {
+ if((tmp[table->columns[c]->num_rows++].data = strdup("")) == NULL)
+ return ENOMEM;
+ }
+ }
+ return 0;
+}
+
+static void
+column_compute_width (rtbl_t table, struct column_data *column)
+{
+ size_t i;
+
+ if(table->flags & RTBL_HEADER_STYLE_NONE)
+ column->width = 0;
+ else
+ column->width = (int)strlen (column->header);
+ for (i = 0; i < column->num_rows; i++)
+ column->width = max (column->width, (int) strlen (column->rows[i].data));
+}
+
+/* DEPRECATED */
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rtbl_set_prefix (rtbl_t table, const char *prefix)
+{
+ if (table->column_prefix)
+ free (table->column_prefix);
+ table->column_prefix = strdup (prefix);
+ if (table->column_prefix == NULL)
+ return ENOMEM;
+ return 0;
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rtbl_set_separator (rtbl_t table, const char *separator)
+{
+ if (table->column_separator)
+ free (table->column_separator);
+ table->column_separator = strdup (separator);
+ if (table->column_separator == NULL)
+ return ENOMEM;
+ return 0;
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rtbl_set_column_prefix (rtbl_t table, const char *column,
+ const char *prefix)
+{
+ struct column_data *c = rtbl_get_column (table, column);
+
+ if (c == NULL)
+ return -1;
+ if (c->prefix)
+ free (c->prefix);
+ c->prefix = strdup (prefix);
+ if (c->prefix == NULL)
+ return ENOMEM;
+ return 0;
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rtbl_set_column_affix_by_id(rtbl_t table, unsigned int id,
+ const char *prefix, const char *suffix)
+{
+ struct column_data *c = rtbl_get_column_by_id (table, id);
+
+ if (c == NULL)
+ return -1;
+ if (c->prefix)
+ free (c->prefix);
+ if(prefix == NULL)
+ c->prefix = NULL;
+ else {
+ c->prefix = strdup (prefix);
+ if (c->prefix == NULL)
+ return ENOMEM;
+ }
+
+ if (c->suffix)
+ free (c->suffix);
+ if(suffix == NULL)
+ c->suffix = NULL;
+ else {
+ c->suffix = strdup (suffix);
+ if (c->suffix == NULL)
+ return ENOMEM;
+ }
+ return 0;
+}
+
+
+static const char *
+get_column_prefix (rtbl_t table, struct column_data *c)
+{
+ if (c == NULL)
+ return "";
+ if (c->prefix)
+ return c->prefix;
+ if (table->column_prefix)
+ return table->column_prefix;
+ return "";
+}
+
+static const char *
+get_column_suffix (rtbl_t table, struct column_data *c)
+{
+ if (c && c->suffix)
+ return c->suffix;
+ return "";
+}
+
+static int
+add_column_entry (struct column_data *c, const char *data)
+{
+ struct column_entry row, *tmp;
+
+ row.data = strdup (data);
+ if (row.data == NULL)
+ return ENOMEM;
+ tmp = realloc (c->rows, (c->num_rows + 1) * sizeof (*tmp));
+ if (tmp == NULL) {
+ free (row.data);
+ return ENOMEM;
+ }
+ c->rows = tmp;
+ c->rows[c->num_rows++] = row;
+ return 0;
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rtbl_add_column_entry_by_id (rtbl_t table, unsigned int id, const char *data)
+{
+ struct column_data *c = rtbl_get_column_by_id (table, id);
+
+ if (c == NULL)
+ return -1;
+
+ return add_column_entry(c, data);
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rtbl_add_column_entryv_by_id (rtbl_t table, unsigned int id,
+ const char *fmt, ...)
+{
+ va_list ap;
+ char *str;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = vasprintf(&str, fmt, ap);
+ va_end(ap);
+ if (ret == -1)
+ return -1;
+ ret = rtbl_add_column_entry_by_id(table, id, str);
+ free(str);
+ return ret;
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rtbl_add_column_entry (rtbl_t table, const char *column, const char *data)
+{
+ struct column_data *c = rtbl_get_column (table, column);
+
+ if (c == NULL)
+ return -1;
+
+ return add_column_entry(c, data);
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rtbl_add_column_entryv (rtbl_t table, const char *column, const char *fmt, ...)
+{
+ va_list ap;
+ char *str;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = vasprintf(&str, fmt, ap);
+ va_end(ap);
+ if (ret == -1)
+ return -1;
+ ret = rtbl_add_column_entry(table, column, str);
+ free(str);
+ return ret;
+}
+
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rtbl_format (rtbl_t table, FILE * f)
+{
+ char *str = rtbl_format_str(table);
+ if (str == NULL)
+ return ENOMEM;
+ fprintf(f, "%s", str);
+ free(str);
+ return 0;
+}
+
+static char *
+rtbl_format_pretty(rtbl_t table)
+{
+ struct rk_strpool *p = NULL;
+ size_t i, j;
+
+ for (i = 0; i < table->num_columns; i++)
+ column_compute_width (table, table->columns[i]);
+ if((table->flags & RTBL_HEADER_STYLE_NONE) == 0) {
+ for (i = 0; i < table->num_columns; i++) {
+ struct column_data *c = table->columns[i];
+
+ if(table->column_separator != NULL && i > 0)
+ p = rk_strpoolprintf(p, "%s", table->column_separator);
+ p = rk_strpoolprintf(p, "%s", get_column_prefix (table, c));
+ if (c == NULL) {
+ /* do nothing if no column */
+ } else if(i == table->num_columns - 1 && c->suffix == NULL)
+ /* last column, so no need to pad with spaces */
+ p = rk_strpoolprintf(p, "%-*s", 0, c->header);
+ else
+ p = rk_strpoolprintf(p, "%-*s", (int)c->width, c->header);
+ p = rk_strpoolprintf(p, "%s", get_column_suffix (table, c));
+ }
+ p = rk_strpoolprintf(p, "\n");
+ }
+
+ for (j = 0;; j++) {
+ int flag = 0;
+
+ /* are there any more rows left? */
+ for (i = 0; flag == 0 && i < table->num_columns; ++i) {
+ struct column_data *c = table->columns[i];
+
+ if (c->num_rows > j) {
+ ++flag;
+ break;
+ }
+ }
+ if (flag == 0)
+ break;
+
+ for (i = 0; i < table->num_columns; i++) {
+ int w;
+ struct column_data *c = table->columns[i];
+
+ if(table->column_separator != NULL && i > 0)
+ p = rk_strpoolprintf(p, "%s", table->column_separator);
+
+ w = c->width;
+
+ if ((c->flags & RTBL_ALIGN_RIGHT) == 0) {
+ if(i == table->num_columns - 1 && c->suffix == NULL)
+ /* last column, so no need to pad with spaces */
+ w = 0;
+ else
+ w = -w;
+ }
+ p = rk_strpoolprintf(p, "%s", get_column_prefix (table, c));
+ if (c->num_rows <= j)
+ p = rk_strpoolprintf(p, "%*s", w, "");
+ else
+ p = rk_strpoolprintf(p, "%*s", w, c->rows[j].data);
+ p = rk_strpoolprintf(p, "%s", get_column_suffix (table, c));
+ }
+ p = rk_strpoolprintf(p, "\n");
+ }
+
+ return rk_strpoolcollect(p);
+}
+
+static char *
+rtbl_format_json(rtbl_t table)
+{
+ struct rk_strpool *p = NULL;
+ size_t i, j;
+ int comma;
+
+ p = rk_strpoolprintf(p, "[");
+ for (j = 0;; j++) {
+ int flag = 0;
+
+ /* are there any more rows left? */
+ for (i = 0; flag == 0 && i < table->num_columns; ++i) {
+ struct column_data *c = table->columns[i];
+
+ if (c->num_rows > j) {
+ ++flag;
+ break;
+ }
+ }
+ if (flag == 0)
+ break;
+
+ p = rk_strpoolprintf(p, "%s{", j > 0 ? "," : "");
+
+ comma = 0;
+ for (i = 0; i < table->num_columns; i++) {
+ struct column_data *c = table->columns[i];
+
+ if (c->num_rows > j) {
+ char *header = c->header;
+ while (isspace((unsigned char)header[0])) /* trim off prefixed whitespace */
+ header++;
+ p = rk_strpoolprintf(p, "%s\"%s\" : \"%s\"",
+ comma ? "," : "", header,
+ c->rows[j].data);
+ comma = 1;
+ }
+ }
+ p = rk_strpoolprintf(p, "}");
+ }
+ p = rk_strpoolprintf(p, "]");
+
+ return rk_strpoolcollect(p);
+}
+
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+rtbl_format_str (rtbl_t table)
+{
+ if (table->flags & RTBL_JSON)
+ return rtbl_format_json(table);
+
+ return rtbl_format_pretty(table);
+}
+
+#ifdef TEST
+int
+main (int argc, char **argv)
+{
+ rtbl_t table;
+
+ table = rtbl_create ();
+ rtbl_add_column_by_id (table, 0, "Issued", 0);
+ rtbl_add_column_by_id (table, 1, "Expires", 0);
+ rtbl_add_column_by_id (table, 2, "Foo", RTBL_ALIGN_RIGHT);
+ rtbl_add_column_by_id (table, 3, "Principal", 0);
+
+ rtbl_add_column_entry_by_id (table, 0, "Jul 7 21:19:29");
+ rtbl_add_column_entry_by_id (table, 1, "Jul 8 07:19:29");
+ rtbl_add_column_entry_by_id (table, 2, "73");
+ rtbl_add_column_entry_by_id (table, 2, "0");
+ rtbl_add_column_entry_by_id (table, 2, "-2000");
+ rtbl_add_column_entry_by_id (table, 3, "krbtgt/NADA.KTH.SE@NADA.KTH.SE");
+
+ rtbl_add_column_entry_by_id (table, 0, "Jul 7 21:19:29");
+ rtbl_add_column_entry_by_id (table, 1, "Jul 8 07:19:29");
+ rtbl_add_column_entry_by_id (table, 3, "afs/pdc.kth.se@NADA.KTH.SE");
+
+ rtbl_add_column_entry_by_id (table, 0, "Jul 7 21:19:29");
+ rtbl_add_column_entry_by_id (table, 1, "Jul 8 07:19:29");
+ rtbl_add_column_entry_by_id (table, 3, "afs@NADA.KTH.SE");
+
+ rtbl_set_separator (table, " ");
+
+ rtbl_format (table, stdout);
+
+ rtbl_destroy (table);
+
+ printf("\n");
+
+ table = rtbl_create ();
+ rtbl_add_column_by_id (table, 0, "Column A", 0);
+ rtbl_set_column_affix_by_id (table, 0, "<", ">");
+ rtbl_add_column_by_id (table, 1, "Column B", 0);
+ rtbl_set_column_affix_by_id (table, 1, "[", "]");
+ rtbl_add_column_by_id (table, 2, "Column C", 0);
+ rtbl_set_column_affix_by_id (table, 2, "(", ")");
+
+ rtbl_add_column_entry_by_id (table, 0, "1");
+ rtbl_new_row(table);
+ rtbl_add_column_entry_by_id (table, 1, "2");
+ rtbl_new_row(table);
+ rtbl_add_column_entry_by_id (table, 2, "3");
+ rtbl_new_row(table);
+
+ rtbl_set_separator (table, " ");
+ rtbl_format (table, stdout);
+
+ rtbl_destroy (table);
+
+ return 0;
+}
+
+#endif
diff --git a/third_party/heimdal/lib/roken/rtbl.h b/third_party/heimdal/lib/roken/rtbl.h
new file mode 100644
index 0000000..274f75c
--- /dev/null
+++ b/third_party/heimdal/lib/roken/rtbl.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2000,2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
+ */
+/* $Id$ */
+
+#ifndef __rtbl_h__
+#define __rtbl_h__
+
+#ifndef ROKEN_LIB_FUNCTION
+#ifdef _WIN32
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL __cdecl
+#else
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL
+#endif
+#endif
+
+#if !defined(__GNUC__) && !defined(__attribute__)
+#define __attribute__(x)
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rtbl_data;
+typedef struct rtbl_data *rtbl_t;
+
+#define RTBL_ALIGN_LEFT 0
+#define RTBL_ALIGN_RIGHT 1
+
+/* flags */
+#define RTBL_HEADER_STYLE_NONE 1
+#define RTBL_JSON 2
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rtbl_add_column (rtbl_t, const char*, unsigned int);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rtbl_add_column_by_id (rtbl_t, unsigned int, const char*, unsigned int);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rtbl_add_column_entryv_by_id (rtbl_t table, unsigned int id,
+ const char *fmt, ...)
+ __attribute__ ((__format__ (__printf__, 3, 0)));
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rtbl_add_column_entry (rtbl_t, const char*, const char*);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rtbl_add_column_entryv (rtbl_t, const char*, const char*, ...)
+ __attribute__ ((__format__ (__printf__, 3, 0)));
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rtbl_add_column_entry_by_id (rtbl_t, unsigned int, const char*);
+
+ROKEN_LIB_FUNCTION rtbl_t ROKEN_LIB_CALL
+rtbl_create (void);
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rtbl_destroy (rtbl_t);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rtbl_format (rtbl_t, FILE*);
+
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+rtbl_format_str (rtbl_t);
+
+ROKEN_LIB_FUNCTION unsigned int ROKEN_LIB_CALL
+rtbl_get_flags (rtbl_t);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rtbl_new_row (rtbl_t);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rtbl_set_column_affix_by_id (rtbl_t, unsigned int, const char*, const char*);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rtbl_set_column_prefix (rtbl_t, const char*, const char*);
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rtbl_set_flags (rtbl_t, unsigned int);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rtbl_set_prefix (rtbl_t, const char*);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rtbl_set_separator (rtbl_t, const char*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __rtbl_h__ */
diff --git a/third_party/heimdal/lib/roken/search.hin b/third_party/heimdal/lib/roken/search.hin
new file mode 100644
index 0000000..f8592c4
--- /dev/null
+++ b/third_party/heimdal/lib/roken/search.hin
@@ -0,0 +1,44 @@
+/*-
+ * Written by J.T. Conklin <jtc@netbsd.org>
+ * Public domain.
+ *
+ * $NetBSD: search.h,v 1.12 1999/02/22 10:34:28 christos Exp $
+ */
+
+#ifndef _rk_SEARCH_H_
+#define _rk_SEARCH_H_ 1
+
+#ifndef ROKEN_LIB_FUNCTION
+#ifdef _WIN32
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL __cdecl
+#else
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL
+#endif
+#endif
+
+#ifndef _WIN32
+#include <sys/cdefs.h>
+#endif
+#include <sys/types.h>
+
+typedef enum {
+ preorder,
+ postorder,
+ endorder,
+ leaf
+} VISIT;
+
+ROKEN_CPP_START
+
+ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL rk_tdelete(const void *, void **,
+ int (*)(const void *, const void *));
+ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL rk_tfind(const void *, void * const *,
+ int (*)(const void *, const void *));
+ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL rk_tsearch(const void *, void **, int (*)(const void *, const void *));
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL rk_twalk(const void *, void (*)(const void *, VISIT, int));
+
+ROKEN_CPP_END
+
+#endif /* !_rk_SEARCH_H_ */
diff --git a/third_party/heimdal/lib/roken/secure_getenv.c b/third_party/heimdal/lib/roken/secure_getenv.c
new file mode 100644
index 0000000..d97d03d
--- /dev/null
+++ b/third_party/heimdal/lib/roken/secure_getenv.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <errno.h>
+
+#include "roken.h"
+#include "secure_getenv.h"
+
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+rk_secure_getenv(const char *name)
+{
+ if (issuid())
+ return NULL;
+ return getenv(name);
+}
diff --git a/third_party/heimdal/lib/roken/secure_getenv.h b/third_party/heimdal/lib/roken/secure_getenv.h
new file mode 100644
index 0000000..a3f5363
--- /dev/null
+++ b/third_party/heimdal/lib/roken/secure_getenv.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+ rk_secure_getenv(const char *);
+
+#ifndef HAVE_SECURE_GETENV
+#undef secure_getenv
+#define secure_getenv(e) rk_secure_getenv(e)
+#endif
diff --git a/third_party/heimdal/lib/roken/sendmsg.c b/third_party/heimdal/lib/roken/sendmsg.c
new file mode 100644
index 0000000..c685377
--- /dev/null
+++ b/third_party/heimdal/lib/roken/sendmsg.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+#ifndef _WIN32
+
+ROKEN_LIB_FUNCTION ssize_t ROKEN_LIB_CALL
+sendmsg(rk_socket_t s, const struct msghdr *msg, int flags)
+{
+ ssize_t ret;
+ size_t tot = 0;
+ int i;
+ char *buf, *p;
+ struct iovec *iov = msg->msg_iov;
+
+ for(i = 0; i < msg->msg_iovlen; ++i)
+ tot += iov[i].iov_len;
+ buf = malloc(tot);
+ if (tot != 0 && buf == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+ p = buf;
+ for (i = 0; i < msg->msg_iovlen; ++i) {
+ memcpy (p, iov[i].iov_base, iov[i].iov_len);
+ p += iov[i].iov_len;
+ }
+ ret = sendto (s, buf, tot, flags, msg->msg_name, msg->msg_namelen);
+ free (buf);
+ return ret;
+}
+
+#else /* _WIN32 */
+
+/***********************************************************************
+ * Copyright (c) 2009, Secure Endpoints Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of Secure Endpoints Inc. 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDER 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.
+ *
+ **********************************************************************/
+
+/**
+ * Implementation of sendmsg() for WIN32
+ *
+ * We are using a contrived definition of msghdr which actually uses
+ * an array of ::_WSABUF structures instead of ::iovec . This allows
+ * us to call WSASend directly using the given ::msghdr instead of
+ * having to allocate another array of ::_WSABUF and copying data for
+ * each call.
+ *
+ * Limitations:
+ *
+ * - msg->msg_name is ignored. So is msg->control.
+ * - WSASend() only supports ::MSG_DONTROUTE, ::MSG_OOB and
+ * ::MSG_PARTIAL.
+ *
+ * @param[in] s The socket to use.
+ * @param[in] msg The message
+ * @param[in] flags Flags. A combination of ::MSG_DONTROUTE,
+ * ::MSG_OOB and ::MSG_PARTIAL
+ *
+ * @return The number of bytes sent, on success. Or -1 on error.
+ */
+ROKEN_LIB_FUNCTION ssize_t ROKEN_LIB_CALL
+sendmsg_w32(rk_socket_t s, const struct msghdr * msg, int flags)
+{
+ int srv;
+ DWORD num_bytes_sent = 0;
+
+ /* TODO: For _WIN32_WINNT >= 0x0600 we can use WSASendMsg using
+ WSAMSG which is a much more direct analogue to sendmsg(). */
+
+ srv = WSASend(s, msg->msg_iov, msg->msg_iovlen,
+ &num_bytes_sent, flags, NULL, NULL);
+
+ if (srv == 0)
+ return (int) num_bytes_sent;
+
+ /* srv == SOCKET_ERROR and WSAGetLastError() == WSA_IO_PENDING
+ indicates that a non-blocking transfer has been scheduled.
+ We'll have to check for that if we ever support non-blocking
+ I/O. */
+
+ return -1;
+}
+
+#endif /* !_WIN32 */
diff --git a/third_party/heimdal/lib/roken/setegid.c b/third_party/heimdal/lib/roken/setegid.c
new file mode 100644
index 0000000..d9aef12
--- /dev/null
+++ b/third_party/heimdal/lib/roken/setegid.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "roken.h"
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+setegid(gid_t egid)
+{
+#ifdef HAVE_SETREGID
+ return setregid(-1, egid);
+#endif
+
+#ifdef HAVE_SETRESGID
+ return setresgid(-1, egid, -1);
+#endif
+
+ return -1;
+}
diff --git a/third_party/heimdal/lib/roken/setenv.c b/third_party/heimdal/lib/roken/setenv.c
new file mode 100644
index 0000000..b4dbefe
--- /dev/null
+++ b/third_party/heimdal/lib/roken/setenv.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * This is the easy way out, use putenv to implement setenv. We might
+ * leak some memory but that is ok since we are usally about to exec
+ * anyway.
+ */
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+setenv(const char *var, const char *val, int rewrite)
+{
+#ifndef _WIN32
+ char *t = NULL;
+
+ if (!rewrite && getenv(var) != 0)
+ return 0;
+
+ if (asprintf (&t, "%s=%s", var, val) < 0 || t == NULL)
+ return -1;
+
+ if (putenv(t) == 0)
+ return 0;
+ else
+ return -1;
+#else /* Win32 */
+ char dummy[8];
+
+ if (!rewrite && GetEnvironmentVariable(var, dummy, sizeof(dummy)/sizeof(char)) != 0)
+ return 0;
+
+ if (SetEnvironmentVariable(var, val) == 0)
+ return -1;
+ else
+ return 0;
+#endif
+}
diff --git a/third_party/heimdal/lib/roken/seteuid.c b/third_party/heimdal/lib/roken/seteuid.c
new file mode 100644
index 0000000..2d8c148
--- /dev/null
+++ b/third_party/heimdal/lib/roken/seteuid.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "roken.h"
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+seteuid(uid_t euid)
+{
+#ifdef HAVE_SETREUID
+ return setreuid(-1, euid);
+#endif
+
+#ifdef HAVE_SETRESUID
+ return setresuid(-1, euid, -1);
+#endif
+
+ return -1;
+}
diff --git a/third_party/heimdal/lib/roken/setprogname.c b/third_party/heimdal/lib/roken/setprogname.c
new file mode 100644
index 0000000..d24106a
--- /dev/null
+++ b/third_party/heimdal/lib/roken/setprogname.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 1995-2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+#ifndef HAVE___PROGNAME
+extern const char *__progname;
+#endif
+
+#ifndef HAVE_SETPROGNAME
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+setprogname(const char *argv0)
+{
+
+#ifndef HAVE___PROGNAME
+
+ const char *p;
+ if(argv0 == NULL)
+ return;
+ p = strrchr(argv0, '/');
+
+#ifdef BACKSLASH_PATH_DELIM
+ {
+ const char * pb;
+
+ pb = strrchr((p != NULL)? p : argv0, '\\');
+ if (pb != NULL)
+ p = pb;
+ }
+#endif
+
+ if(p == NULL)
+ p = argv0;
+ else
+ p++;
+
+#ifdef _WIN32
+ {
+ char * fn = strdup(p);
+ char * ext;
+
+ strlwr(fn);
+ ext = strrchr(fn, '.');
+ if (ext != NULL && strcmp(ext, ".exe") == 0)
+ *ext = '\0';
+
+ __progname = fn;
+ }
+#else
+
+ __progname = p;
+
+#endif
+
+#endif /* HAVE___PROGNAME */
+}
+
+#endif /* HAVE_SETPROGNAME */
diff --git a/third_party/heimdal/lib/roken/signal.c b/third_party/heimdal/lib/roken/signal.c
new file mode 100644
index 0000000..284f1e7
--- /dev/null
+++ b/third_party/heimdal/lib/roken/signal.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 1995 - 2000 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <signal.h>
+#include "roken.h"
+
+/*
+ * We would like to always use this signal but there is a link error
+ * on NEXTSTEP
+ */
+#if !defined(NeXT) && !defined(__APPLE__)
+/*
+ * Bugs:
+ *
+ * Do we need any extra hacks for SIGCLD and/or SIGCHLD?
+ */
+
+ROKEN_LIB_FUNCTION SigAction ROKEN_LIB_CALL
+signal(int iSig, SigAction pAction)
+{
+ struct sigaction saNew, saOld;
+
+ saNew.sa_handler = pAction;
+ sigemptyset(&saNew.sa_mask);
+ saNew.sa_flags = 0;
+
+ if (iSig == SIGALRM)
+ {
+#ifdef SA_INTERRUPT
+ saNew.sa_flags |= SA_INTERRUPT;
+#endif
+ }
+ else
+ {
+#ifdef SA_RESTART
+ saNew.sa_flags |= SA_RESTART;
+#endif
+ }
+
+ if (sigaction(iSig, &saNew, &saOld) < 0)
+ return(SIG_ERR);
+
+ return(saOld.sa_handler);
+}
+#endif
diff --git a/third_party/heimdal/lib/roken/simple_exec.c b/third_party/heimdal/lib/roken/simple_exec.c
new file mode 100644
index 0000000..552e121
--- /dev/null
+++ b/third_party/heimdal/lib/roken/simple_exec.c
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 1998 - 2001, 2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <stdarg.h>
+#include <stdlib.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+
+#include "roken.h"
+
+#define EX_NOEXEC 126
+#define EX_NOTFOUND 127
+
+/* return values:
+ SE_E_UNSPECIFIED on `unspecified' system errors
+ SE_E_FORKFAILED on fork failures
+ SE_E_WAITPIDFAILED on waitpid errors
+ SE_E_EXECTIMEOUT exec timeout
+ 0- is return value from subprocess
+ SE_E_NOEXEC if the program couldn't be executed
+ SE_E_NOTFOUND if the program couldn't be found
+ 128- is 128 + signal that killed subprocess
+
+ possible values `func' can return:
+ ((time_t)-2) exit loop w/o killing child and return
+ `exec timeout'/-4 from simple_exec
+ ((time_t)-1) kill child with SIGTERM and wait for child to exit
+ 0 don't timeout again
+ n seconds to next timeout
+ */
+
+static int sig_alarm;
+
+static RETSIGTYPE
+sigtimeout(int sig)
+{
+ sig_alarm = 1;
+ SIGRETURN(0);
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+wait_for_process_timed(pid_t pid, time_t (*func)(void *),
+ void *ptr, time_t timeout)
+{
+ RETSIGTYPE (*old_func)(int sig) = NULL;
+ unsigned int oldtime = 0;
+ int ret;
+
+ sig_alarm = 0;
+
+ if (func) {
+ old_func = signal(SIGALRM, sigtimeout);
+ oldtime = alarm(timeout);
+ }
+
+ while(1) {
+ int status;
+
+ while(waitpid(pid, &status, 0) < 0) {
+ if (errno != EINTR) {
+ ret = SE_E_WAITPIDFAILED;
+ goto out;
+ }
+ if (func == NULL)
+ continue;
+ if (sig_alarm == 0)
+ continue;
+ timeout = (*func)(ptr);
+ if (timeout == (time_t)-1) {
+ kill(pid, SIGTERM);
+ continue;
+ } else if (timeout == (time_t)-2) {
+ ret = SE_E_EXECTIMEOUT;
+ goto out;
+ }
+ alarm(timeout);
+ }
+ if(WIFSTOPPED(status))
+ continue;
+ if(WIFEXITED(status)) {
+ ret = WEXITSTATUS(status);
+ break;
+ }
+ if(WIFSIGNALED(status)) {
+ ret = WTERMSIG(status) + 128;
+ break;
+ }
+ }
+ out:
+ if (func) {
+ signal(SIGALRM, old_func);
+ alarm(oldtime);
+ }
+ return ret;
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+wait_for_process(pid_t pid)
+{
+ return wait_for_process_timed(pid, NULL, NULL, 0);
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+pipe_execv(FILE **stdin_fd, FILE **stdout_fd, FILE **stderr_fd,
+ const char *file, ...)
+{
+ int in_fd[2] = {-1, -1};
+ int out_fd[2] = {-1, -1};
+ int err_fd[2] = {-1, -1};
+ pid_t pid;
+ va_list ap;
+ char **argv;
+ int ret = 0;
+
+ if(stdin_fd != NULL)
+ ret = pipe(in_fd);
+ if(ret != -1 && stdout_fd != NULL)
+ ret = pipe(out_fd);
+ if(ret != -1 && stderr_fd != NULL)
+ ret = pipe(err_fd);
+
+ if (ret == -1) {
+ close(in_fd[0]);
+ close(in_fd[1]);
+ close(out_fd[0]);
+ close(out_fd[1]);
+ close(err_fd[0]);
+ close(err_fd[1]);
+ return SE_E_UNSPECIFIED;
+ }
+
+ pid = fork();
+ switch(pid) {
+ case 0:
+ va_start(ap, file);
+ argv = vstrcollect(&ap);
+ va_end(ap);
+ if(argv == NULL)
+ exit(-1);
+
+ /* close pipes we're not interested in */
+ if(stdin_fd != NULL)
+ close(in_fd[1]);
+ if(stdout_fd != NULL)
+ close(out_fd[0]);
+ if(stderr_fd != NULL)
+ close(err_fd[0]);
+
+ /* pipe everything caller doesn't care about to /dev/null */
+ if(stdin_fd == NULL)
+ in_fd[0] = open(_PATH_DEVNULL, O_RDONLY);
+ if(stdout_fd == NULL)
+ out_fd[1] = open(_PATH_DEVNULL, O_WRONLY);
+ if(stderr_fd == NULL)
+ err_fd[1] = open(_PATH_DEVNULL, O_WRONLY);
+
+ /* move to proper descriptors */
+ if(in_fd[0] != STDIN_FILENO) {
+ dup2(in_fd[0], STDIN_FILENO);
+ close(in_fd[0]);
+ }
+ if(out_fd[1] != STDOUT_FILENO) {
+ dup2(out_fd[1], STDOUT_FILENO);
+ close(out_fd[1]);
+ }
+ if(err_fd[1] != STDERR_FILENO) {
+ dup2(err_fd[1], STDERR_FILENO);
+ close(err_fd[1]);
+ }
+
+ closefrom(3);
+
+ execv(file, argv);
+ exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC);
+ case -1:
+ if(stdin_fd != NULL) {
+ close(in_fd[0]);
+ close(in_fd[1]);
+ }
+ if(stdout_fd != NULL) {
+ close(out_fd[0]);
+ close(out_fd[1]);
+ }
+ if(stderr_fd != NULL) {
+ close(err_fd[0]);
+ close(err_fd[1]);
+ }
+ return SE_E_FORKFAILED;
+ default:
+ if(stdin_fd != NULL) {
+ close(in_fd[0]);
+ *stdin_fd = fdopen(in_fd[1], "w");
+ }
+ if(stdout_fd != NULL) {
+ close(out_fd[1]);
+ *stdout_fd = fdopen(out_fd[0], "r");
+ }
+ if(stderr_fd != NULL) {
+ close(err_fd[1]);
+ *stderr_fd = fdopen(err_fd[0], "r");
+ }
+ }
+ return pid;
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+simple_execvp_timed(const char *file, char *const args[],
+ time_t (*func)(void *), void *ptr, time_t timeout)
+{
+ pid_t pid = fork();
+ switch(pid){
+ case -1:
+ return SE_E_FORKFAILED;
+ case 0:
+ execvp(file, args);
+ exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC);
+ default:
+ return wait_for_process_timed(pid, func, ptr, timeout);
+ }
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+simple_execvp(const char *file, char *const args[])
+{
+ return simple_execvp_timed(file, args, NULL, NULL, 0);
+}
+
+/* gee, I'd like a execvpe */
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+simple_execve_timed(const char *file, char *const args[], char *const envp[],
+ time_t (*func)(void *), void *ptr, time_t timeout)
+{
+ pid_t pid = fork();
+ switch(pid){
+ case -1:
+ return SE_E_FORKFAILED;
+ case 0:
+ execve(file, args, envp);
+ exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC);
+ default:
+ return wait_for_process_timed(pid, func, ptr, timeout);
+ }
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+simple_execve(const char *file, char *const args[], char *const envp[])
+{
+ return simple_execve_timed(file, args, envp, NULL, NULL, 0);
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+simple_execlp(const char *file, ...)
+{
+ va_list ap;
+ char **argv;
+ int ret;
+
+ va_start(ap, file);
+ argv = vstrcollect(&ap);
+ va_end(ap);
+ if(argv == NULL)
+ return SE_E_UNSPECIFIED;
+ ret = simple_execvp(file, argv);
+ free(argv);
+ return ret;
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+simple_execle(const char *file, ... /* ,char *const envp[] */)
+{
+ va_list ap;
+ char **argv;
+ char *const* envp;
+ int ret;
+
+ va_start(ap, file);
+ argv = vstrcollect(&ap);
+ envp = va_arg(ap, char **);
+ va_end(ap);
+ if(argv == NULL)
+ return SE_E_UNSPECIFIED;
+ ret = simple_execve(file, argv, envp);
+ free(argv);
+ return ret;
+}
diff --git a/third_party/heimdal/lib/roken/simple_exec_w32.c b/third_party/heimdal/lib/roken/simple_exec_w32.c
new file mode 100644
index 0000000..264cdb2
--- /dev/null
+++ b/third_party/heimdal/lib/roken/simple_exec_w32.c
@@ -0,0 +1,431 @@
+/***********************************************************************
+ * Copyright (c) 2009, Secure Endpoints Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDER 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 <config.h>
+
+#include <roken.h>
+#include <strsafe.h>
+
+#ifndef _WIN32
+#error This implementation is Windows specific.
+#endif
+
+/**
+ * wait_for_process_timed waits for a process to terminate or until a
+ * specified timeout occurs.
+ *
+ * @param[in] pid Process id for the monitored process
+
+ * @param[in] func Timeout callback function. When the wait times out,
+ * the callback function is called. The possible return values
+ * from the callback function are:
+ *
+ * - ((time_t) -2) Exit loop without killing child and return SE_E_EXECTIMEOUT.
+ * - ((time_t) -1) Kill child with SIGTERM and wait for child to exit.
+ * - 0 Don't timeout again
+ * - n Seconds to next timeout
+ *
+ * @param[in] ptr Optional parameter for func()
+ *
+ * @param[in] timeout Seconds to first timeout.
+ *
+ * @retval SE_E_UNSPECIFIED Unspecified system error
+ * @retval SE_E_FORKFAILED Fork failure (not applicable for _WIN32 targets)
+ * @retval SE_E_WAITPIDFAILED waitpid errors
+ * @retval SE_E_EXECTIMEOUT exec timeout
+ * @retval 0 <= Return value from subprocess
+ * @retval SE_E_NOTFOUND The program coudln't be found
+ * @retval 128- The signal that killed the subprocess +128.
+ */
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+wait_for_process_timed(pid_t pid, time_t (*func)(void *),
+ void *ptr, time_t timeout)
+{
+ HANDLE hProcess;
+ DWORD wrv = 0;
+ DWORD dtimeout;
+ int rv = 0;
+
+ hProcess = OpenProcess(SYNCHRONIZE, FALSE, pid);
+
+ if (hProcess == NULL) {
+ return SE_E_WAITPIDFAILED;
+ }
+
+ dtimeout = (DWORD) ((timeout == 0)? INFINITE: timeout * 1000);
+
+ do {
+ wrv = WaitForSingleObject(hProcess, dtimeout);
+
+ if (wrv == WAIT_OBJECT_0) {
+
+ DWORD prv = 0;
+
+ GetExitCodeProcess(hProcess, &prv);
+ rv = (int) prv;
+ break;
+
+ } else if (wrv == WAIT_TIMEOUT) {
+
+ if (func == NULL)
+ continue;
+
+ timeout = (*func)(ptr);
+
+ if (timeout == (time_t)-1) {
+
+ if (TerminateProcess(hProcess, 128 + 9)) {
+ dtimeout = INFINITE;
+ continue;
+ }
+ rv = SE_E_UNSPECIFIED;
+ break;
+
+ } else if (timeout == (time_t) -2) {
+
+ rv = SE_E_EXECTIMEOUT;
+ break;
+
+ } else {
+
+ dtimeout = (DWORD) ((timeout == 0)? INFINITE: timeout * 1000);
+ continue;
+
+ }
+
+ } else {
+
+ rv = SE_E_UNSPECIFIED;
+ break;
+
+ }
+
+ } while(TRUE);
+
+ CloseHandle(hProcess);
+
+ return rv;
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+wait_for_process(pid_t pid)
+{
+ return wait_for_process_timed(pid, NULL, NULL, 0);
+}
+
+static char *
+collect_commandline(const char * fn, va_list * ap)
+{
+ size_t len = 0;
+ size_t alloc_len = 0;
+ const char * s;
+ char * cmd = NULL;
+
+ for (s = fn; s; s = (char *) va_arg(*ap, char *)) {
+ size_t cmp_len;
+ int need_quote = FALSE;
+
+ if (FAILED(StringCchLength(s, MAX_PATH, &cmp_len))) {
+ if (cmd)
+ free(cmd);
+ return NULL;
+ }
+
+ if (cmp_len == 0)
+ continue;
+
+ if (strchr(s, ' ') && /* need to quote any component that
+ has embedded spaces, but not if
+ they are already quoted. */
+ s[0] != '"' &&
+ s[cmp_len - 1] != '"') {
+ need_quote = TRUE;
+ cmp_len += 2 * sizeof(char);
+ }
+
+ if (s != fn)
+ cmp_len += 1 * sizeof(char);
+
+ if (alloc_len < len + cmp_len + 1) {
+ char * nc;
+
+ alloc_len += ((len + cmp_len - alloc_len) / MAX_PATH + 1) * MAX_PATH;
+ nc = (char *) realloc(cmd, alloc_len * sizeof(char));
+ if (nc == NULL) {
+ if (cmd)
+ free(cmd);
+ return NULL;
+ }
+ cmd = nc;
+ }
+
+ if (cmd == NULL)
+ return NULL;
+
+ if (s != fn)
+ cmd[len++] = ' ';
+
+ if (need_quote) {
+ StringCchPrintf(cmd + len, alloc_len - len, "\"%s\"", s);
+ } else {
+ StringCchCopy(cmd + len, alloc_len - len, s);
+ }
+
+ len += cmp_len;
+ }
+
+ return cmd;
+}
+
+ROKEN_LIB_FUNCTION pid_t ROKEN_LIB_CALL
+pipe_execv(FILE **stdin_fd, FILE **stdout_fd, FILE **stderr_fd,
+ const char *file, ...)
+{
+ HANDLE hOut_r = NULL;
+ HANDLE hOut_w = NULL;
+ HANDLE hIn_r = NULL;
+ HANDLE hIn_w = NULL;
+ HANDLE hErr_r = NULL;
+ HANDLE hErr_w = NULL;
+
+ SECURITY_ATTRIBUTES sa;
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+
+ char * commandline = NULL;
+
+ pid_t rv = (pid_t) -1;
+
+ {
+ va_list ap;
+
+ va_start(ap, file);
+ commandline = collect_commandline(file, &ap);
+
+ if (commandline == NULL)
+ return rv;
+ }
+
+ ZeroMemory(&si, sizeof(si));
+ ZeroMemory(&pi, sizeof(pi));
+ ZeroMemory(&sa, sizeof(sa));
+
+ pi.hProcess = NULL;
+ pi.hThread = NULL;
+
+ sa.nLength = sizeof(sa);
+ sa.bInheritHandle = TRUE;
+ sa.lpSecurityDescriptor = NULL;
+
+ if ((stdout_fd && !CreatePipe(&hOut_r, &hOut_w, &sa, 0 /* Use default */)) ||
+
+ (stdin_fd && !CreatePipe(&hIn_r, &hIn_w, &sa, 0)) ||
+
+ (stderr_fd && !CreatePipe(&hErr_r, &hErr_w, &sa, 0)) ||
+
+ (!stdout_fd && (hOut_w = CreateFile("CON", GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
+ &sa, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) ||
+
+ (!stdin_fd && (hIn_r = CreateFile("CON",GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
+ &sa, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) ||
+
+ (!stderr_fd && (hErr_w = CreateFile("CON", GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
+ &sa, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE))
+
+ goto _exit;
+
+ /* We don't want the child processes inheriting these */
+ if (hOut_r)
+ SetHandleInformation(hOut_r, HANDLE_FLAG_INHERIT, FALSE);
+
+ if (hIn_w)
+ SetHandleInformation(hIn_w, HANDLE_FLAG_INHERIT, FALSE);
+
+ if (hErr_r)
+ SetHandleInformation(hErr_r, HANDLE_FLAG_INHERIT, FALSE);
+
+ si.cb = sizeof(si);
+ si.lpReserved = NULL;
+ si.lpDesktop = NULL;
+ si.lpTitle = NULL;
+ si.dwFlags = STARTF_USESTDHANDLES;
+ si.hStdInput = hIn_r;
+ si.hStdOutput = hOut_w;
+ si.hStdError = hErr_w;
+
+ if (!CreateProcess(file, commandline, NULL, NULL,
+ TRUE, /* bInheritHandles */
+ CREATE_NO_WINDOW, /* dwCreationFlags */
+ NULL, /* lpEnvironment */
+ NULL, /* lpCurrentDirectory */
+ &si,
+ &pi)) {
+
+ rv = (pid_t) (GetLastError() == ERROR_FILE_NOT_FOUND)? 127 : -1;
+ goto _exit;
+ }
+
+ if (stdin_fd) {
+ *stdin_fd = _fdopen(_open_osfhandle((intptr_t) hIn_w, 0), "wb");
+ if (*stdin_fd)
+ hIn_w = NULL;
+ }
+
+ if (stdout_fd) {
+ *stdout_fd = _fdopen(_open_osfhandle((intptr_t) hOut_r, _O_RDONLY), "rb");
+ if (*stdout_fd)
+ hOut_r = NULL;
+ }
+
+ if (stderr_fd) {
+ *stderr_fd = _fdopen(_open_osfhandle((intptr_t) hErr_r, _O_RDONLY), "rb");
+ if (*stderr_fd)
+ hErr_r = NULL;
+ }
+
+ rv = (pid_t) pi.dwProcessId;
+
+ _exit:
+
+ if (pi.hProcess) CloseHandle(pi.hProcess);
+
+ if (pi.hThread) CloseHandle(pi.hThread);
+
+ if (hIn_r) CloseHandle(hIn_r);
+
+ if (hIn_w) CloseHandle(hIn_w);
+
+ if (hOut_r) CloseHandle(hOut_r);
+
+ if (hOut_w) CloseHandle(hOut_w);
+
+ if (hErr_r) CloseHandle(hErr_r);
+
+ if (hErr_w) CloseHandle(hErr_w);
+
+ return rv;
+}
+
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+simple_execvp_timed(const char *file, char *const args[],
+ time_t (*func)(void *), void *ptr, time_t timeout)
+{
+ intptr_t hp;
+ int rv;
+
+ hp = spawnvp(_P_NOWAIT, file, args);
+
+ if (hp == -1)
+ return (errno == ENOENT)? 127: 126;
+ else if (hp == 0)
+ return 0;
+
+ rv = wait_for_process_timed(GetProcessId((HANDLE) hp), func, ptr, timeout);
+
+ CloseHandle((HANDLE) hp);
+
+ return rv;
+}
+
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+simple_execvp(const char *file, char *const args[])
+{
+ return simple_execvp_timed(file, args, NULL, NULL, 0);
+}
+
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+simple_execve_timed(const char *file, char *const args[], char *const envp[],
+ time_t (*func)(void *), void *ptr, time_t timeout)
+{
+ intptr_t hp;
+ int rv;
+
+ hp = spawnve(_P_NOWAIT, file, args, envp);
+
+ if (hp == -1)
+ return (errno == ENOENT)? 127: 126;
+ else if (hp == 0)
+ return 0;
+
+ rv = wait_for_process_timed(GetProcessId((HANDLE) hp), func, ptr, timeout);
+
+ CloseHandle((HANDLE) hp);
+
+ return rv;
+}
+
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+simple_execve(const char *file, char *const args[], char *const envp[])
+{
+ return simple_execve_timed(file, args, envp, NULL, NULL, 0);
+}
+
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+simple_execlp(const char *file, ...)
+{
+ va_list ap;
+ char **argv;
+ int ret;
+
+ va_start(ap, file);
+ argv = vstrcollect(&ap);
+ va_end(ap);
+ if(argv == NULL)
+ return SE_E_UNSPECIFIED;
+ ret = simple_execvp(file, argv);
+ free(argv);
+ return ret;
+}
+
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+simple_execle(const char *file, ... /* ,char *const envp[] */)
+{
+ va_list ap;
+ char **argv;
+ char *const* envp;
+ int ret;
+
+ va_start(ap, file);
+ argv = vstrcollect(&ap);
+ envp = va_arg(ap, char **);
+ va_end(ap);
+ if(argv == NULL)
+ return SE_E_UNSPECIFIED;
+ ret = simple_execve(file, argv, envp);
+ free(argv);
+ return ret;
+}
diff --git a/third_party/heimdal/lib/roken/sleep.c b/third_party/heimdal/lib/roken/sleep.c
new file mode 100644
index 0000000..53f416e
--- /dev/null
+++ b/third_party/heimdal/lib/roken/sleep.c
@@ -0,0 +1,55 @@
+/***********************************************************************
+ * Copyright (c) 2009, 2014, Secure Endpoints Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDER 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 <config.h>
+
+#include <roken.h>
+
+#ifndef _WIN32
+#error Only implemented on Windows
+#endif
+
+ROKEN_LIB_FUNCTION unsigned int ROKEN_LIB_CALL
+sleep(unsigned int seconds)
+{
+ if (SleepEx(1000 * (DWORD) seconds, FALSE) != 0)
+ return 1; /* XXX Should get time before and after */
+ return 0;
+}
+
+/* We can only sleep in millisecond increments */
+ROKEN_LIB_FUNCTION unsigned int ROKEN_LIB_CALL
+usleep(unsigned int useconds)
+{
+ if (SleepEx((DWORD)(useconds / 1000), FALSE) != 0)
+ return 1000; /* XXX Should get time before and after */
+ return 0;
+}
diff --git a/third_party/heimdal/lib/roken/snprintf-test.c b/third_party/heimdal/lib/roken/snprintf-test.c
new file mode 100644
index 0000000..e51402d
--- /dev/null
+++ b/third_party/heimdal/lib/roken/snprintf-test.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2000 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 KTH 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 KTH AND ITS 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 KTH OR ITS 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 <config.h>
+#include "roken.h"
+#include <limits.h>
+
+extern int rk_snprintf(char *, size_t, const char *, ...);
+extern int rk_vsnprintf(char *, size_t, const char *, va_list);
+
+static int
+try (const char *format, ...)
+{
+ int ret;
+ va_list ap;
+ char buf1[256], buf2[256];
+
+ va_start (ap, format);
+ ret = rk_vsnprintf (buf1, sizeof(buf1), format, ap);
+ if (ret >= sizeof(buf1))
+ errx (1, "increase buf and try again");
+ va_end (ap);
+ va_start (ap, format);
+ vsprintf (buf2, format, ap);
+ ret = strcmp (buf1, buf2);
+ if (ret)
+ printf ("failed: format = \"%s\", \"%s\" != \"%s\"\n",
+ format, buf1, buf2);
+ va_end (ap);
+ return ret;
+}
+
+static int
+cmp_with_sprintf_int (void)
+{
+ int tot = 0;
+ int int_values[] = {INT_MIN, -17, -1, 0, 1, 17, 4711, 65535, INT_MAX};
+ int i;
+
+ for (i = 0; i < sizeof(int_values) / sizeof(int_values[0]); ++i) {
+ tot += try ("%d", int_values[i]);
+ tot += try ("%x", int_values[i]);
+ tot += try ("%X", int_values[i]);
+ tot += try ("%o", int_values[i]);
+ tot += try ("%#x", int_values[i]);
+ tot += try ("%#X", int_values[i]);
+ tot += try ("%#o", int_values[i]);
+ tot += try ("%10d", int_values[i]);
+ tot += try ("%10x", int_values[i]);
+ tot += try ("%10X", int_values[i]);
+ tot += try ("%10o", int_values[i]);
+ tot += try ("%#10x", int_values[i]);
+ tot += try ("%#10X", int_values[i]);
+ tot += try ("%#10o", int_values[i]);
+ tot += try ("%-10d", int_values[i]);
+ tot += try ("%-10x", int_values[i]);
+ tot += try ("%-10X", int_values[i]);
+ tot += try ("%-10o", int_values[i]);
+ tot += try ("%-#10x", int_values[i]);
+ tot += try ("%-#10X", int_values[i]);
+ tot += try ("%-#10o", int_values[i]);
+ }
+ return tot;
+}
+
+static int
+cmp_with_sprintf_long (void)
+{
+ int tot = 0;
+ long long_values[] = {LONG_MIN, -17, -1, 0, 1, 17, 4711, 65535, LONG_MAX};
+ int i;
+
+ for (i = 0; i < sizeof(long_values) / sizeof(long_values[0]); ++i) {
+ tot += try ("%ld", long_values[i]);
+ tot += try ("%lx", long_values[i]);
+ tot += try ("%lX", long_values[i]);
+ tot += try ("%lo", long_values[i]);
+ tot += try ("%#lx", long_values[i]);
+ tot += try ("%#lX", long_values[i]);
+ tot += try ("%#lo", long_values[i]);
+ tot += try ("%10ld", long_values[i]);
+ tot += try ("%10lx", long_values[i]);
+ tot += try ("%10lX", long_values[i]);
+ tot += try ("%10lo", long_values[i]);
+ tot += try ("%#10lx", long_values[i]);
+ tot += try ("%#10lX", long_values[i]);
+ tot += try ("%#10lo", long_values[i]);
+ tot += try ("%-10ld", long_values[i]);
+ tot += try ("%-10lx", long_values[i]);
+ tot += try ("%-10lX", long_values[i]);
+ tot += try ("%-10lo", long_values[i]);
+ tot += try ("%-#10lx", long_values[i]);
+ tot += try ("%-#10lX", long_values[i]);
+ tot += try ("%-#10lo", long_values[i]);
+ }
+ return tot;
+}
+
+#ifdef HAVE_LONG_LONG
+
+/* XXX doesn't work as expected on lp64 platforms with sizeof(long
+ * long) == sizeof(long) */
+
+static int
+cmp_with_sprintf_long_long (void)
+{
+ int tot = 0;
+ long long long_long_values[] = {
+ ((long long)LONG_MIN) - (sizeof(long long) > sizeof(long)),
+ LONG_MIN, -17, -1, 0, 1, 17, 4711, 65535, LONG_MAX,
+ ((long long)LONG_MAX) + (sizeof(long long) > sizeof(long))
+ };
+ int i;
+
+ for (i = 0; i < sizeof(long_long_values) / sizeof(long_long_values[0]); ++i) {
+ tot += try ("%lld", long_long_values[i]);
+ tot += try ("%llx", long_long_values[i]);
+ tot += try ("%llX", long_long_values[i]);
+ tot += try ("%llo", long_long_values[i]);
+ tot += try ("%#llx", long_long_values[i]);
+ tot += try ("%#llX", long_long_values[i]);
+ tot += try ("%#llo", long_long_values[i]);
+ tot += try ("%10lld", long_long_values[i]);
+ tot += try ("%10llx", long_long_values[i]);
+ tot += try ("%10llX", long_long_values[i]);
+ tot += try ("%10llo", long_long_values[i]);
+ tot += try ("%#10llx", long_long_values[i]);
+ tot += try ("%#10llX", long_long_values[i]);
+ tot += try ("%#10llo", long_long_values[i]);
+ tot += try ("%-10lld", long_long_values[i]);
+ tot += try ("%-10llx", long_long_values[i]);
+ tot += try ("%-10llX", long_long_values[i]);
+ tot += try ("%-10llo", long_long_values[i]);
+ tot += try ("%-#10llx", long_long_values[i]);
+ tot += try ("%-#10llX", long_long_values[i]);
+ tot += try ("%-#10llo", long_long_values[i]);
+ }
+ return tot;
+}
+
+#endif
+
+#if 0
+static int
+cmp_with_sprintf_float (void)
+{
+ int tot = 0;
+ double double_values[] = {-99999, -999, -17.4, -4.3, -3.0, -1.5, -1,
+ 0, 0.1, 0.2342374852, 0.2340007,
+ 3.1415926, 14.7845, 34.24758, 9999, 9999999};
+ int i;
+
+ for (i = 0; i < sizeof(double_values) / sizeof(double_values[0]); ++i) {
+ tot += try ("%f", double_values[i]);
+ tot += try ("%10f", double_values[i]);
+ tot += try ("%.2f", double_values[i]);
+ tot += try ("%7.0f", double_values[i]);
+ tot += try ("%5.2f", double_values[i]);
+ tot += try ("%0f", double_values[i]);
+ tot += try ("%#f", double_values[i]);
+ tot += try ("%e", double_values[i]);
+ tot += try ("%10e", double_values[i]);
+ tot += try ("%.2e", double_values[i]);
+ tot += try ("%7.0e", double_values[i]);
+ tot += try ("%5.2e", double_values[i]);
+ tot += try ("%0e", double_values[i]);
+ tot += try ("%#e", double_values[i]);
+ tot += try ("%E", double_values[i]);
+ tot += try ("%10E", double_values[i]);
+ tot += try ("%.2E", double_values[i]);
+ tot += try ("%7.0E", double_values[i]);
+ tot += try ("%5.2E", double_values[i]);
+ tot += try ("%0E", double_values[i]);
+ tot += try ("%#E", double_values[i]);
+ tot += try ("%g", double_values[i]);
+ tot += try ("%10g", double_values[i]);
+ tot += try ("%.2g", double_values[i]);
+ tot += try ("%7.0g", double_values[i]);
+ tot += try ("%5.2g", double_values[i]);
+ tot += try ("%0g", double_values[i]);
+ tot += try ("%#g", double_values[i]);
+ tot += try ("%G", double_values[i]);
+ tot += try ("%10G", double_values[i]);
+ tot += try ("%.2G", double_values[i]);
+ tot += try ("%7.0G", double_values[i]);
+ tot += try ("%5.2G", double_values[i]);
+ tot += try ("%0G", double_values[i]);
+ tot += try ("%#G", double_values[i]);
+ }
+ return tot;
+}
+#endif
+
+static int
+test_null (void)
+{
+ return rk_snprintf (NULL, 0, "foo") != 3;
+}
+
+static int
+test_sizet (void)
+{
+ int tot = 0;
+ size_t sizet_values[] = { 0, 1, 2, 200, 4294967295u }; /* SIZE_MAX */
+ char *result[] = { "0", "1", "2", "200", "4294967295" };
+ int i;
+
+ for (i = 0; i < sizeof(sizet_values) / sizeof(sizet_values[0]); ++i) {
+#if 0
+ tot += try("%zu", sizet_values[i]);
+ tot += try("%zx", sizet_values[i]);
+ tot += try("%zX", sizet_values[i]);
+#else
+ char buf[256];
+ rk_snprintf(buf, sizeof(buf), "%zu", sizet_values[i]);
+ if (strcmp(buf, result[i]) != 0) {
+ printf("%s != %s", buf, result[i]);
+ tot++;
+ }
+#endif
+ }
+ return tot;
+}
+
+
+int
+main (int argc, char **argv)
+{
+ int ret = 0;
+
+ ret += cmp_with_sprintf_int ();
+ ret += cmp_with_sprintf_long ();
+#ifdef HAVE_LONG_LONG
+ ret += cmp_with_sprintf_long_long ();
+#endif
+ ret += test_null ();
+ ret += test_sizet ();
+ return ret;
+}
diff --git a/third_party/heimdal/lib/roken/snprintf.c b/third_party/heimdal/lib/roken/snprintf.c
new file mode 100644
index 0000000..54018ba
--- /dev/null
+++ b/third_party/heimdal/lib/roken/snprintf.c
@@ -0,0 +1,729 @@
+/*
+ * Copyright (c) 1995-2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "roken.h"
+#include <assert.h>
+
+enum format_flags {
+ minus_flag = 1,
+ plus_flag = 2,
+ space_flag = 4,
+ alternate_flag = 8,
+ zero_flag = 16
+};
+
+/*
+ * Common state
+ */
+
+struct snprintf_state {
+ unsigned char *str;
+ unsigned char *s;
+ unsigned char *theend;
+ size_t sz;
+ size_t max_sz;
+ void (*append_char)(struct snprintf_state *, unsigned char);
+ /* XXX - methods */
+};
+
+#if !defined(HAVE_VSNPRINTF) || defined(TEST_SNPRINTF)
+static int
+sn_reserve (struct snprintf_state *state, size_t n)
+{
+ return state->s + n > state->theend;
+}
+
+static void
+sn_append_char (struct snprintf_state *state, unsigned char c)
+{
+ if (!sn_reserve (state, 1))
+ *state->s++ = c;
+}
+#endif
+
+static int
+as_reserve (struct snprintf_state *state, size_t n)
+{
+ if (state->s + n > state->theend) {
+ int off = state->s - state->str;
+ unsigned char *tmp;
+
+ if (state->max_sz && state->sz >= state->max_sz)
+ return 1;
+
+ state->sz = max(state->sz * 2, state->sz + n);
+ if (state->max_sz)
+ state->sz = min(state->sz, state->max_sz);
+ tmp = realloc (state->str, state->sz);
+ if (tmp == NULL)
+ return 1;
+ state->str = tmp;
+ state->s = state->str + off;
+ state->theend = state->str + state->sz - 1;
+ }
+ return 0;
+}
+
+static void
+as_append_char (struct snprintf_state *state, unsigned char c)
+{
+ if(!as_reserve (state, 1))
+ *state->s++ = c;
+}
+
+/* longest integer types */
+
+#ifdef HAVE_LONG_LONG
+typedef unsigned long long u_longest;
+typedef long long longest;
+#else
+typedef unsigned long u_longest;
+typedef long longest;
+#endif
+
+#ifndef HAVE_UINTPTR_T
+typedef u_longest uintptr_t;
+#endif
+
+
+
+static size_t
+pad(struct snprintf_state *state, int width, char c)
+{
+ size_t len = 0;
+ while(width-- > 0){
+ (*state->append_char)(state, c);
+ ++len;
+ }
+ return len;
+}
+
+/* return true if we should use alternatve hex form */
+static int
+use_alternative (int flags, u_longest num, unsigned base)
+{
+ return (flags & alternate_flag) && base == 16 && num != 0;
+}
+
+static int
+append_number(struct snprintf_state *state,
+ u_longest num, unsigned base, const char *rep,
+ int width, int prec, int flags, int minusp)
+{
+ int len = 0;
+ u_longest n = num;
+ char nstr[64]; /* enough for <192 bit octal integers */
+ int nstart, nlen;
+ char signchar;
+
+ /* given precision, ignore zero flag */
+ if(prec != -1)
+ flags &= ~zero_flag;
+ else
+ prec = 1;
+
+ /* format number as string */
+ nstart = sizeof(nstr);
+ nlen = 0;
+ nstr[--nstart] = '\0';
+ do {
+ assert(nstart > 0);
+ nstr[--nstart] = rep[n % base];
+ ++nlen;
+ n /= base;
+ } while(n);
+
+ /* zero value with zero precision should produce no digits */
+ if(prec == 0 && num == 0) {
+ nlen--;
+ nstart++;
+ }
+
+ /* figure out what char to use for sign */
+ if(minusp)
+ signchar = '-';
+ else if((flags & plus_flag))
+ signchar = '+';
+ else if((flags & space_flag))
+ signchar = ' ';
+ else
+ signchar = '\0';
+
+ if((flags & alternate_flag) && base == 8) {
+ /* if necessary, increase the precision to
+ make first digit a zero */
+
+ /* XXX C99 claims (regarding # and %o) that "if the value and
+ precision are both 0, a single 0 is printed", but there is
+ no such wording for %x. This would mean that %#.o would
+ output "0", but %#.x "". This does not make sense, and is
+ also not what other printf implementations are doing. */
+
+ if(prec <= nlen && nstr[nstart] != '0' && nstr[nstart] != '\0')
+ prec = nlen + 1;
+ }
+
+ /* possible formats:
+ pad | sign | alt | zero | digits
+ sign | alt | zero | digits | pad minus_flag
+ sign | alt | zero | digits zero_flag */
+
+ /* if not right justifying or padding with zeros, we need to
+ compute the length of the rest of the string, and then pad with
+ spaces */
+ if(!(flags & (minus_flag | zero_flag))) {
+ if(prec > nlen)
+ width -= prec;
+ else
+ width -= nlen;
+
+ if(use_alternative(flags, num, base))
+ width -= 2;
+
+ if(signchar != '\0')
+ width--;
+
+ /* pad to width */
+ len += pad(state, width, ' ');
+ }
+ if(signchar != '\0') {
+ (*state->append_char)(state, signchar);
+ ++len;
+ }
+ if(use_alternative(flags, num, base)) {
+ (*state->append_char)(state, '0');
+ (*state->append_char)(state, rep[10] + 23); /* XXX */
+ len += 2;
+ }
+ if(flags & zero_flag) {
+ /* pad to width with zeros */
+ if(prec - nlen > width - len - nlen)
+ len += pad(state, prec - nlen, '0');
+ else
+ len += pad(state, width - len - nlen, '0');
+ } else
+ /* pad to prec with zeros */
+ len += pad(state, prec - nlen, '0');
+
+ while(nstr[nstart] != '\0') {
+ (*state->append_char)(state, nstr[nstart++]);
+ ++len;
+ }
+
+ if(flags & minus_flag)
+ len += pad(state, width - len, ' ');
+
+ return len;
+}
+
+/*
+ * return length
+ */
+
+static size_t
+append_string (struct snprintf_state *state,
+ const unsigned char *arg,
+ int width,
+ int prec,
+ int flags)
+{
+ size_t len = 0;
+
+ if(arg == NULL)
+ arg = (const unsigned char*)"(null)";
+
+ if(prec != -1)
+ width -= prec;
+ else
+ width -= strlen((const char *)arg);
+ if(!(flags & minus_flag))
+ len += pad(state, width, ' ');
+
+ if (prec != -1) {
+ while (prec-- && *arg) {
+ (*state->append_char) (state, *arg++);
+ ++len;
+ }
+ } else {
+ while (*arg) {
+ (*state->append_char) (state, *arg++);
+ ++len;
+ }
+ }
+ if(flags & minus_flag)
+ len += pad(state, width, ' ');
+ return len;
+}
+
+static int
+append_char(struct snprintf_state *state,
+ unsigned char arg,
+ int width,
+ int flags)
+{
+ int len = 0;
+
+ while(!(flags & minus_flag) && --width > 0) {
+ (*state->append_char) (state, ' ') ;
+ ++len;
+ }
+ (*state->append_char) (state, arg);
+ ++len;
+ while((flags & minus_flag) && --width > 0) {
+ (*state->append_char) (state, ' ');
+ ++len;
+ }
+ return len;
+}
+
+/*
+ * This can't be made into a function...
+ */
+
+#ifdef HAVE_LONG_LONG
+
+#define PARSE_INT_FORMAT(res, arg, unsig) \
+if (long_long_flag) \
+ res = (unsig long long)va_arg(arg, unsig long long); \
+else if (long_flag) \
+ res = (unsig long)va_arg(arg, unsig long); \
+else if (size_t_flag) \
+ res = (unsig long)va_arg(arg, size_t); \
+else if (short_flag) \
+ res = (unsig short)va_arg(arg, unsig int); \
+else \
+ res = (unsig int)va_arg(arg, unsig int)
+
+#else
+
+#define PARSE_INT_FORMAT(res, arg, unsig) \
+if (long_flag) \
+ res = (unsig long)va_arg(arg, unsig long); \
+else if (size_t_flag) \
+ res = (unsig long)va_arg(arg, size_t); \
+else if (short_flag) \
+ res = (unsig short)va_arg(arg, unsig int); \
+else \
+ res = (unsig int)va_arg(arg, unsig int)
+
+#endif
+
+/*
+ * zyxprintf - return length, as snprintf
+ */
+
+static size_t
+xyzprintf (struct snprintf_state *state, const char *char_format, va_list ap)
+{
+ const unsigned char *format = (const unsigned char *)char_format;
+ unsigned char c;
+ size_t len = 0;
+
+ while((c = *format++)) {
+ if (c == '%') {
+ int flags = 0;
+ int width = 0;
+ int prec = -1;
+ int size_t_flag = 0;
+ int long_long_flag = 0;
+ int long_flag = 0;
+ int short_flag = 0;
+
+ /* flags */
+ while((c = *format++)){
+ if(c == '-')
+ flags |= minus_flag;
+ else if(c == '+')
+ flags |= plus_flag;
+ else if(c == ' ')
+ flags |= space_flag;
+ else if(c == '#')
+ flags |= alternate_flag;
+ else if(c == '0')
+ flags |= zero_flag;
+ else if(c == '\'')
+ ; /* just ignore */
+ else
+ break;
+ }
+
+ if((flags & space_flag) && (flags & plus_flag))
+ flags ^= space_flag;
+
+ if((flags & minus_flag) && (flags & zero_flag))
+ flags ^= zero_flag;
+
+ /* width */
+ if (isdigit(c))
+ do {
+ width = width * 10 + c - '0';
+ c = *format++;
+ } while(isdigit(c));
+ else if(c == '*') {
+ width = va_arg(ap, int);
+ c = *format++;
+ }
+
+ /* precision */
+ if (c == '.') {
+ prec = 0;
+ c = *format++;
+ if (isdigit(c))
+ do {
+ prec = prec * 10 + c - '0';
+ c = *format++;
+ } while(isdigit(c));
+ else if (c == '*') {
+ prec = va_arg(ap, int);
+ c = *format++;
+ }
+ }
+
+ /* size */
+
+ if (c == 'h') {
+ short_flag = 1;
+ c = *format++;
+ } else if (c == 'z') {
+ size_t_flag = 1;
+ c = *format++;
+ } else if (c == 'l') {
+ long_flag = 1;
+ c = *format++;
+ if (c == 'l') {
+ long_long_flag = 1;
+ c = *format++;
+ }
+ }
+
+ if(c != 'd' && c != 'i')
+ flags &= ~(plus_flag | space_flag);
+
+ switch (c) {
+ case 'c' :
+ len += append_char(state, va_arg(ap, int), width, flags);
+ break;
+ case 's' :
+ len += append_string(state,
+ va_arg(ap, unsigned char*),
+ width,
+ prec,
+ flags);
+ break;
+ case 'd' :
+ case 'i' : {
+ int64_t arg;
+ uint64_t num;
+ int minusp = 0;
+
+ PARSE_INT_FORMAT(arg, ap, signed);
+
+ if (arg == INT64_MIN) {
+ minusp = 1;
+ num = (uint64_t)INT64_MAX + 1;
+ } else if (arg < 0) {
+ minusp = 1;
+ num = -arg;
+ } else
+ num = arg;
+
+ len += append_number (state, num, 10, "0123456789",
+ width, prec, flags, minusp);
+ break;
+ }
+ case 'u' : {
+ u_longest arg;
+
+ PARSE_INT_FORMAT(arg, ap, unsigned);
+
+ len += append_number (state, arg, 10, "0123456789",
+ width, prec, flags, 0);
+ break;
+ }
+ case 'o' : {
+ u_longest arg;
+
+ PARSE_INT_FORMAT(arg, ap, unsigned);
+
+ len += append_number (state, arg, 010, "01234567",
+ width, prec, flags, 0);
+ break;
+ }
+ case 'x' : {
+ u_longest arg;
+
+ PARSE_INT_FORMAT(arg, ap, unsigned);
+
+ len += append_number (state, arg, 0x10, "0123456789abcdef",
+ width, prec, flags, 0);
+ break;
+ }
+ case 'X' :{
+ u_longest arg;
+
+ PARSE_INT_FORMAT(arg, ap, unsigned);
+
+ len += append_number (state, arg, 0x10, "0123456789ABCDEF",
+ width, prec, flags, 0);
+ break;
+ }
+ case 'p' : {
+ uintptr_t arg = (uintptr_t)va_arg(ap, void*);
+
+ len += append_number (state, arg, 0x10, "0123456789ABCDEF",
+ width, prec, flags, 0);
+ break;
+ }
+ case 'n' : {
+ int *arg = va_arg(ap, int*);
+ *arg = state->s - state->str;
+ break;
+ }
+ case '\0' :
+ --format;
+ HEIM_FALLTHROUGH;
+ case '%' :
+ (*state->append_char)(state, c);
+ ++len;
+ break;
+ default :
+ (*state->append_char)(state, '%');
+ (*state->append_char)(state, c);
+ len += 2;
+ break;
+ }
+ } else {
+ (*state->append_char) (state, c);
+ ++len;
+ }
+ }
+ return len;
+}
+
+#if !defined(HAVE_SNPRINTF) || defined(TEST_SNPRINTF)
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_snprintf (char *str, size_t sz, const char *format, ...)
+{
+ va_list args;
+ int ret;
+
+ va_start(args, format);
+ ret = vsnprintf (str, sz, format, args);
+ va_end(args);
+
+#ifdef PARANOIA
+ {
+ int ret2;
+ char *tmp;
+
+ tmp = malloc (sz);
+ if (tmp == NULL)
+ abort ();
+
+ va_start(args, format);
+ ret2 = vsprintf (tmp, format, args);
+ va_end(args);
+ if (ret != ret2 || strcmp(str, tmp) != 0)
+ abort ();
+ free (tmp);
+ }
+#endif
+
+ return ret;
+}
+#endif
+
+#if !defined(HAVE_ASPRINTF) || defined(TEST_SNPRINTF)
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_asprintf (char **ret, const char *format, ...)
+{
+ va_list args;
+ int val;
+
+ va_start(args, format);
+ val = vasprintf (ret, format, args);
+ va_end(args);
+
+#ifdef PARANOIA
+ {
+ int ret2;
+ char *tmp;
+ tmp = malloc (val + 1);
+ if (tmp == NULL)
+ abort ();
+
+ va_start(args, format);
+ ret2 = vsprintf (tmp, format, args);
+ va_end(args);
+ if (val != ret2 || strcmp(*ret, tmp) != 0)
+ abort ();
+ free (tmp);
+ }
+#endif
+
+ return val;
+}
+#endif
+
+#if !defined(HAVE_ASNPRINTF) || defined(TEST_SNPRINTF)
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_asnprintf (char **ret, size_t max_sz, const char *format, ...)
+{
+ va_list args;
+ int val;
+
+ va_start(args, format);
+ val = vasnprintf (ret, max_sz, format, args);
+
+#ifdef PARANOIA
+ {
+ int ret2;
+ char *tmp;
+ tmp = malloc (val + 1);
+ if (tmp == NULL)
+ abort ();
+
+ ret2 = vsprintf (tmp, format, args);
+ if (val != ret2 || strcmp(*ret, tmp) != 0)
+ abort ();
+ free (tmp);
+ }
+#endif
+
+ va_end(args);
+ return val;
+}
+#endif
+
+#if !defined(HAVE_VASPRINTF) || defined(TEST_SNPRINTF)
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_vasprintf (char **ret, const char *format, va_list args)
+{
+ return vasnprintf (ret, 0, format, args);
+}
+#endif
+
+
+#if !defined(HAVE_VASNPRINTF) || defined(TEST_SNPRINTF)
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_vasnprintf (char **ret, size_t max_sz, const char *format, va_list args)
+{
+ size_t st;
+ struct snprintf_state state;
+
+ state.max_sz = max_sz;
+ state.sz = 1;
+ state.str = malloc(state.sz);
+ if (state.str == NULL) {
+ *ret = NULL;
+ return -1;
+ }
+ state.s = state.str;
+ state.theend = state.s + state.sz - 1;
+ state.append_char = as_append_char;
+
+ st = xyzprintf (&state, format, args);
+ if (st > state.sz) {
+ free (state.str);
+ *ret = NULL;
+ return -1;
+ } else {
+ char *tmp;
+
+ *state.s = '\0';
+ tmp = realloc (state.str, st+1);
+ if (tmp == NULL) {
+ free (state.str);
+ *ret = NULL;
+ return -1;
+ }
+ *ret = tmp;
+ return st;
+ }
+}
+#endif
+
+#if !defined(HAVE_VSNPRINTF) || defined(TEST_SNPRINTF)
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_vsnprintf (char *str, size_t sz, const char *format, va_list args)
+{
+ struct snprintf_state state;
+ int ret;
+ unsigned char *ustr = (unsigned char *)str;
+
+ state.max_sz = 0;
+ state.sz = sz;
+ state.str = ustr;
+ state.s = ustr;
+ state.theend = ustr + sz - (sz > 0);
+ state.append_char = sn_append_char;
+
+ ret = xyzprintf (&state, format, args);
+ if (state.s != NULL && sz != 0)
+ *state.s = '\0';
+ return ret;
+}
+#endif
+
+#if !defined(HAVE_EVASPRINTF) || defined(TEST_SNPRINTF)
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+rk_evasprintf(const char *format, va_list args)
+{
+ char *s = NULL;
+
+ if (vasprintf(&s, format, args) == -1 || s == NULL)
+ errx(1, "Out of memory");
+ return s;
+}
+#endif
+
+#if !defined(HAVE_EASPRINTF) || defined(TEST_SNPRINTF)
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+rk_easprintf(const char *format, ...)
+{
+ va_list args;
+ char *s = NULL;
+
+ va_start(args, format);
+ if (vasprintf(&s, format, args) == -1 || s == NULL)
+ errx(1, "Out of memory");
+ va_end(args);
+ return s;
+}
+#endif
diff --git a/third_party/heimdal/lib/roken/socket.c b/third_party/heimdal/lib/roken/socket.c
new file mode 100644
index 0000000..5b578c8
--- /dev/null
+++ b/third_party/heimdal/lib/roken/socket.c
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) 1999 - 2000 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+#include <err.h>
+
+/*
+ * Set `sa' to the unitialized address of address family `af'
+ */
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+socket_set_any (struct sockaddr *sa, int af)
+{
+ switch (af) {
+ case AF_INET : {
+ struct sockaddr_in *sin4 = (struct sockaddr_in *)sa;
+
+ memset (sin4, 0, sizeof(*sin4));
+ sin4->sin_family = AF_INET;
+ sin4->sin_port = 0;
+ sin4->sin_addr.s_addr = INADDR_ANY;
+ break;
+ }
+#ifdef HAVE_IPV6
+ case AF_INET6 : {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
+
+ memset (sin6, 0, sizeof(*sin6));
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = 0;
+ sin6->sin6_addr = in6addr_any;
+ break;
+ }
+#endif
+ default :
+ errx (1, "unknown address family %d", sa->sa_family);
+ break;
+ }
+}
+
+/*
+ * set `sa' to (`ptr', `port')
+ */
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+socket_set_address_and_port (struct sockaddr *sa, const void *ptr, int port)
+{
+ switch (sa->sa_family) {
+ case AF_INET : {
+ struct sockaddr_in *sin4 = (struct sockaddr_in *)sa;
+
+ memset (sin4, 0, sizeof(*sin4));
+ sin4->sin_family = AF_INET;
+ sin4->sin_port = port;
+ memcpy (&sin4->sin_addr, ptr, sizeof(struct in_addr));
+ break;
+ }
+#ifdef HAVE_IPV6
+ case AF_INET6 : {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
+
+ memset (sin6, 0, sizeof(*sin6));
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = port;
+ memcpy (&sin6->sin6_addr, ptr, sizeof(struct in6_addr));
+ break;
+ }
+#endif
+ default :
+ errx (1, "unknown address family %d", sa->sa_family);
+ break;
+ }
+}
+
+/*
+ * Return the size of an address of the type in `sa'
+ */
+
+ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL
+socket_addr_size (const struct sockaddr *sa)
+{
+ switch (sa->sa_family) {
+ case AF_INET :
+ return sizeof(struct in_addr);
+#ifdef HAVE_IPV6
+ case AF_INET6 :
+ return sizeof(struct in6_addr);
+#endif
+ default :
+ return 0;
+ }
+}
+
+/*
+ * Return the size of a `struct sockaddr' in `sa'.
+ */
+
+ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL
+socket_sockaddr_size (const struct sockaddr *sa)
+{
+ switch (sa->sa_family) {
+ case AF_INET :
+ return sizeof(struct sockaddr_in);
+#ifdef HAVE_IPV6
+ case AF_INET6 :
+ return sizeof(struct sockaddr_in6);
+#endif
+ default:
+ return 0;
+ }
+}
+
+/*
+ * Return the binary address of `sa'.
+ */
+
+ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL
+socket_get_address (const struct sockaddr *sa)
+{
+ switch (sa->sa_family) {
+ case AF_INET : {
+ const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa;
+ return rk_UNCONST(&sin4->sin_addr);
+ }
+#ifdef HAVE_IPV6
+ case AF_INET6 : {
+ const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
+ return rk_UNCONST(&sin6->sin6_addr);
+ }
+#endif
+ default:
+ return NULL;
+ }
+}
+
+/*
+ * Return the port number from `sa'.
+ */
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+socket_get_port (const struct sockaddr *sa)
+{
+ switch (sa->sa_family) {
+ case AF_INET : {
+ const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa;
+ return sin4->sin_port;
+ }
+#ifdef HAVE_IPV6
+ case AF_INET6 : {
+ const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
+ return sin6->sin6_port;
+ }
+#endif
+ default :
+ return 0;
+ }
+}
+
+/*
+ * Set the port in `sa' to `port'.
+ */
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+socket_set_port (struct sockaddr *sa, int port)
+{
+ switch (sa->sa_family) {
+ case AF_INET : {
+ struct sockaddr_in *sin4 = (struct sockaddr_in *)sa;
+ sin4->sin_port = port;
+ break;
+ }
+#ifdef HAVE_IPV6
+ case AF_INET6 : {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
+ sin6->sin6_port = port;
+ break;
+ }
+#endif
+ default :
+ errx (1, "unknown address family %d", sa->sa_family);
+ break;
+ }
+}
+
+/*
+ * Set the range of ports to use when binding with port = 0.
+ */
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+socket_set_portrange (rk_socket_t sock, int restr, int af)
+{
+#if defined(IP_PORTRANGE)
+ if (af == AF_INET) {
+ int on = restr ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT;
+ (void) setsockopt(sock, IPPROTO_IP, IP_PORTRANGE, &on, sizeof(on));
+ }
+#endif
+#if defined(IPV6_PORTRANGE)
+ if (af == AF_INET6) {
+ int on = restr ? IPV6_PORTRANGE_HIGH : IPV6_PORTRANGE_DEFAULT;
+ (void) setsockopt(sock, IPPROTO_IPV6, IPV6_PORTRANGE, &on, sizeof(on));
+ }
+#endif
+}
+
+/*
+ * Enable debug on `sock'.
+ */
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+socket_set_debug (rk_socket_t sock)
+{
+#if defined(SO_DEBUG) && defined(HAVE_SETSOCKOPT)
+ int on = 1;
+ (void) setsockopt(sock, SOL_SOCKET, SO_DEBUG, (void *) &on, sizeof (on));
+#endif
+}
+
+/*
+ * Set the type-of-service of `sock' to `tos'.
+ */
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+socket_set_tos (rk_socket_t sock, int tos)
+{
+#if defined(IP_TOS) && defined(HAVE_SETSOCKOPT)
+ (void) setsockopt (sock, IPPROTO_IP, IP_TOS, (void *) &tos, sizeof(int));
+#endif
+}
+
+/*
+ * Set the non-blocking-ness of the socket.
+ */
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+socket_set_nonblocking(rk_socket_t sock, int nonblock)
+{
+#if defined(O_NONBLOCK)
+ int flags = fcntl(sock, F_GETFL, 0);
+ if (flags == -1)
+ return;
+ if (nonblock)
+ flags |= O_NONBLOCK;
+ else
+ flags &= ~O_NONBLOCK;
+ (void) fcntl(sock, F_SETFL, flags);
+#elif defined(FIOBIO)
+ int flags = !!nonblock;
+
+ (void) ioctl(sock, FIOBIO, &flags);
+#endif
+}
+
+/*
+ * set the reuse of addresses on `sock' to `val'.
+ */
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+socket_set_reuseaddr (rk_socket_t sock, int val)
+{
+#if defined(SO_REUSEADDR) && defined(HAVE_SETSOCKOPT)
+ (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&val,
+ sizeof(val));
+#endif
+}
+
+/*
+ * Set the that the `sock' should bind to only IPv6 addresses.
+ */
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+socket_set_ipv6only (rk_socket_t sock, int val)
+{
+#if defined(IPV6_V6ONLY) && defined(HAVE_SETSOCKOPT)
+ (void) setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&val,
+ sizeof(val));
+#endif
+}
+
+/*
+ * Set the that the `sock' keepalive setting.
+ */
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+socket_set_keepalive(rk_socket_t sock, int val)
+{
+ (void) setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&val,
+ sizeof(val));
+}
+
+/**
+ * Create a file descriptor from a socket
+ *
+ * While the socket handle in \a sock can be used with WinSock
+ * functions after calling socket_to_fd(), it should not be closed
+ * with rk_closesocket(). The socket will be closed when the associated
+ * file descriptor is closed.
+ */
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+socket_to_fd(rk_socket_t sock, int flags)
+{
+#ifndef _WIN32
+ return sock;
+#else
+ return _open_osfhandle((intptr_t) sock, flags);
+#endif
+}
+
+#ifdef HAVE_WINSOCK
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_SOCK_IOCTL(SOCKET s, long cmd, int * argp) {
+ u_long ul = (argp)? *argp : 0;
+ int rv;
+
+ rv = ioctlsocket(s, cmd, &ul);
+ if (argp)
+ *argp = (int) ul;
+ return rv;
+}
+#endif
+
+#ifndef HEIMDAL_SMALLER
+#undef socket
+
+int rk_socket(int, int, int);
+
+int
+rk_socket(int domain, int type, int protocol)
+{
+ int s;
+ s = socket (domain, type, protocol);
+#ifdef SOCK_CLOEXEC
+ if ((SOCK_CLOEXEC & type) && s < 0 && errno == EINVAL) {
+ type &= ~SOCK_CLOEXEC;
+ s = socket (domain, type, protocol);
+ }
+#endif
+ return s;
+}
+
+#endif /* HEIMDAL_SMALLER */
diff --git a/third_party/heimdal/lib/roken/socket_wrapper.c b/third_party/heimdal/lib/roken/socket_wrapper.c
new file mode 100644
index 0000000..9438949
--- /dev/null
+++ b/third_party/heimdal/lib/roken/socket_wrapper.c
@@ -0,0 +1,1911 @@
+/*
+ * Copyright (C) Jelmer Vernooij 2005 <jelmer@samba.org>
+ * Copyright (C) Stefan Metzmacher 2006 <metze@samba.org>
+ *
+ * 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 author 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 AUTHOR 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 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.
+ *
+ */
+
+/*
+ Socket wrapper library. Passes all socket communication over
+ unix domain sockets if the environment variable SOCKET_WRAPPER_DIR
+ is set.
+*/
+
+#define SOCKET_WRAPPER_NOT_REPLACE
+
+#ifdef _SAMBA_BUILD_
+
+#include "includes.h"
+#include "system/network.h"
+#include "system/filesys.h"
+
+#ifdef malloc
+#undef malloc
+#endif
+#ifdef calloc
+#undef calloc
+#endif
+#ifdef strdup
+#undef strdup
+#endif
+
+#else /* _SAMBA_BUILD_ */
+
+#include <config.h>
+#undef SOCKET_WRAPPER_REPLACE
+
+#include <sys/types.h>
+#ifdef TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#elif defined(HAVE_SYS_TIME_H)
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h>
+#endif
+#include <errno.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include "roken.h"
+
+#include "socket_wrapper.h"
+
+#define HAVE_GETTIMEOFDAY_TZ 1
+
+#define _PUBLIC_
+
+#endif
+
+#define SWRAP_DLIST_ADD(list,item) do { \
+ if (!(list)) { \
+ (item)->prev = NULL; \
+ (item)->next = NULL; \
+ (list) = (item); \
+ } else { \
+ (item)->prev = NULL; \
+ (item)->next = (list); \
+ (list)->prev = (item); \
+ (list) = (item); \
+ } \
+} while (0)
+
+#define SWRAP_DLIST_REMOVE(list,item) do { \
+ if ((list) == (item)) { \
+ (list) = (item)->next; \
+ if (list) { \
+ (list)->prev = NULL; \
+ } \
+ } else { \
+ if ((item)->prev) { \
+ (item)->prev->next = (item)->next; \
+ } \
+ if ((item)->next) { \
+ (item)->next->prev = (item)->prev; \
+ } \
+ } \
+ (item)->prev = NULL; \
+ (item)->next = NULL; \
+} while (0)
+
+/* LD_PRELOAD doesn't work yet, so REWRITE_CALLS is all we support
+ * for now */
+#define REWRITE_CALLS
+
+#ifdef REWRITE_CALLS
+#define real_accept accept
+#define real_connect connect
+#define real_bind bind
+#define real_listen listen
+#define real_getpeername getpeername
+#define real_getsockname getsockname
+#define real_getsockopt getsockopt
+#define real_setsockopt setsockopt
+#define real_recvfrom recvfrom
+#define real_sendto sendto
+#define real_ioctl ioctl
+#define real_recv recv
+#define real_send send
+#define real_socket socket
+#define real_close close
+#define real_dup dup
+#define real_dup2 dup2
+#endif
+
+#ifdef HAVE_GETTIMEOFDAY_TZ
+#define swrapGetTimeOfDay(tval) gettimeofday(tval,NULL)
+#else
+#define swrapGetTimeOfDay(tval) gettimeofday(tval)
+#endif
+
+/* we need to use a very terse format here as IRIX 6.4 silently
+ truncates names to 16 chars, so if we use a longer name then we
+ can't tell which port a packet came from with recvfrom()
+
+ with this format we have 8 chars left for the directory name
+*/
+#define SOCKET_FORMAT "%c%02X%04X"
+#define SOCKET_TYPE_CHAR_TCP 'T'
+#define SOCKET_TYPE_CHAR_UDP 'U'
+#define SOCKET_TYPE_CHAR_TCP_V6 'X'
+#define SOCKET_TYPE_CHAR_UDP_V6 'Y'
+
+#define MAX_WRAPPED_INTERFACES 16
+
+#define SW_IPV6_ADDRESS 1
+
+static struct sockaddr *sockaddr_dup(const void *data, socklen_t len)
+{
+ struct sockaddr *ret = (struct sockaddr *)malloc(len);
+ memcpy(ret, data, len);
+ return ret;
+}
+
+static void set_port(int family, int prt, struct sockaddr *addr)
+{
+ switch (family) {
+ case AF_INET:
+ ((struct sockaddr_in *)addr)->sin_port = htons(prt);
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ ((struct sockaddr_in6 *)addr)->sin6_port = htons(prt);
+ break;
+#endif
+ }
+}
+
+static int socket_length(int family)
+{
+ switch (family) {
+ case AF_INET:
+ return sizeof(struct sockaddr_in);
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ return sizeof(struct sockaddr_in6);
+#endif
+ }
+ return -1;
+}
+
+
+
+struct socket_info
+{
+ int fd;
+
+ int family;
+ int type;
+ int protocol;
+ int bound;
+ int bcast;
+ int is_server;
+
+ char *path;
+ char *tmp_path;
+
+ struct sockaddr *myname;
+ socklen_t myname_len;
+
+ struct sockaddr *peername;
+ socklen_t peername_len;
+
+ struct {
+ unsigned long pck_snd;
+ unsigned long pck_rcv;
+ } io;
+
+ struct socket_info *prev, *next;
+};
+
+static struct socket_info *sockets;
+
+
+static const char *socket_wrapper_dir(void)
+{
+ const char *s = getenv("SOCKET_WRAPPER_DIR");
+ if (s == NULL) {
+ return NULL;
+ }
+ if (strncmp(s, "./", 2) == 0) {
+ s += 2;
+ }
+ return s;
+}
+
+static unsigned int socket_wrapper_default_iface(void)
+{
+ const char *s = getenv("SOCKET_WRAPPER_DEFAULT_IFACE");
+ if (s) {
+ unsigned int iface;
+ if (sscanf(s, "%u", &iface) == 1) {
+ if (iface >= 1 && iface <= MAX_WRAPPED_INTERFACES) {
+ return iface;
+ }
+ }
+ }
+
+ return 1;/* 127.0.0.1 */
+}
+
+static int convert_un_in(const struct sockaddr_un *un, struct sockaddr *in, socklen_t *len)
+{
+ unsigned int iface;
+ unsigned int prt;
+ const char *p;
+ char type;
+
+ p = strrchr(un->sun_path, '/');
+ if (p) p++; else p = un->sun_path;
+
+ if (sscanf(p, SOCKET_FORMAT, &type, &iface, &prt) != 3) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (iface == 0 || iface > MAX_WRAPPED_INTERFACES) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (prt > 0xFFFF) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ switch(type) {
+ case SOCKET_TYPE_CHAR_TCP:
+ case SOCKET_TYPE_CHAR_UDP: {
+ struct sockaddr_in *in2 = (struct sockaddr_in *)in;
+
+ if ((*len) < sizeof(*in2)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ memset(in2, 0, sizeof(*in2));
+ in2->sin_family = AF_INET;
+ in2->sin_addr.s_addr = htonl((127<<24) | iface);
+ in2->sin_port = htons(prt);
+
+ *len = sizeof(*in2);
+ break;
+ }
+#ifdef HAVE_IPV6
+ case SOCKET_TYPE_CHAR_TCP_V6:
+ case SOCKET_TYPE_CHAR_UDP_V6: {
+ struct sockaddr_in6 *in2 = (struct sockaddr_in6 *)in;
+
+ if ((*len) < sizeof(*in2)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ memset(in2, 0, sizeof(*in2));
+ in2->sin6_family = AF_INET6;
+ in2->sin6_addr.s6_addr[0] = SW_IPV6_ADDRESS;
+ in2->sin6_port = htons(prt);
+
+ *len = sizeof(*in2);
+ break;
+ }
+#endif
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int convert_in_un_remote(struct socket_info *si, const struct sockaddr *inaddr, struct sockaddr_un *un,
+ int *bcast)
+{
+ char type = '\0';
+ unsigned int prt;
+ unsigned int iface;
+ int is_bcast = 0;
+
+ if (bcast) *bcast = 0;
+
+ switch (si->family) {
+ case AF_INET: {
+ const struct sockaddr_in *in =
+ (const struct sockaddr_in *)inaddr;
+ unsigned int addr = ntohl(in->sin_addr.s_addr);
+ char u_type = '\0';
+ char b_type = '\0';
+ char a_type = '\0';
+
+ switch (si->type) {
+ case SOCK_STREAM:
+ u_type = SOCKET_TYPE_CHAR_TCP;
+ break;
+ case SOCK_DGRAM:
+ u_type = SOCKET_TYPE_CHAR_UDP;
+ a_type = SOCKET_TYPE_CHAR_UDP;
+ b_type = SOCKET_TYPE_CHAR_UDP;
+ break;
+ }
+
+ prt = ntohs(in->sin_port);
+ if (a_type && addr == 0xFFFFFFFF) {
+ /* 255.255.255.255 only udp */
+ is_bcast = 2;
+ type = a_type;
+ iface = socket_wrapper_default_iface();
+ } else if (b_type && addr == 0x7FFFFFFF) {
+ /* 127.255.255.255 only udp */
+ is_bcast = 1;
+ type = b_type;
+ iface = socket_wrapper_default_iface();
+ } else if ((addr & 0xFFFFFF00) == 0x7F000000) {
+ /* 127.0.0.X */
+ is_bcast = 0;
+ type = u_type;
+ iface = (addr & 0x000000FF);
+ } else {
+ errno = ENETUNREACH;
+ return -1;
+ }
+ if (bcast) *bcast = is_bcast;
+ break;
+ }
+#ifdef HAVE_IPV6
+ case AF_INET6: {
+ const struct sockaddr_in6 *in =
+ (const struct sockaddr_in6 *)inaddr;
+
+ switch (si->type) {
+ case SOCK_STREAM:
+ type = SOCKET_TYPE_CHAR_TCP_V6;
+ break;
+ case SOCK_DGRAM:
+ type = SOCKET_TYPE_CHAR_UDP_V6;
+ break;
+ }
+
+ /* XXX no multicast/broadcast */
+
+ prt = ntohs(in->sin6_port);
+ iface = SW_IPV6_ADDRESS;
+
+ break;
+ }
+#endif
+ default:
+ errno = ENETUNREACH;
+ return -1;
+ }
+
+ if (prt == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (is_bcast) {
+ snprintf(un->sun_path, sizeof(un->sun_path), "%s/EINVAL",
+ socket_wrapper_dir());
+ /* the caller need to do more processing */
+ return 0;
+ }
+
+ snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
+ socket_wrapper_dir(), type, iface, prt);
+
+ return 0;
+}
+
+static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *inaddr, struct sockaddr_un *un,
+ int *bcast)
+{
+ char type = '\0';
+ unsigned int prt;
+ unsigned int iface;
+ struct stat st;
+ int is_bcast = 0;
+
+ if (bcast) *bcast = 0;
+
+ switch (si->family) {
+ case AF_INET: {
+ const struct sockaddr_in *in =
+ (const struct sockaddr_in *)inaddr;
+ unsigned int addr = ntohl(in->sin_addr.s_addr);
+ char u_type = '\0';
+ char d_type = '\0';
+ char b_type = '\0';
+ char a_type = '\0';
+
+ prt = ntohs(in->sin_port);
+
+ switch (si->type) {
+ case SOCK_STREAM:
+ u_type = SOCKET_TYPE_CHAR_TCP;
+ d_type = SOCKET_TYPE_CHAR_TCP;
+ break;
+ case SOCK_DGRAM:
+ u_type = SOCKET_TYPE_CHAR_UDP;
+ d_type = SOCKET_TYPE_CHAR_UDP;
+ a_type = SOCKET_TYPE_CHAR_UDP;
+ b_type = SOCKET_TYPE_CHAR_UDP;
+ break;
+ }
+
+ if (addr == 0) {
+ /* 0.0.0.0 */
+ is_bcast = 0;
+ type = d_type;
+ iface = socket_wrapper_default_iface();
+ } else if (a_type && addr == 0xFFFFFFFF) {
+ /* 255.255.255.255 only udp */
+ is_bcast = 2;
+ type = a_type;
+ iface = socket_wrapper_default_iface();
+ } else if (b_type && addr == 0x7FFFFFFF) {
+ /* 127.255.255.255 only udp */
+ is_bcast = 1;
+ type = b_type;
+ iface = socket_wrapper_default_iface();
+ } else if ((addr & 0xFFFFFF00) == 0x7F000000) {
+ /* 127.0.0.X */
+ is_bcast = 0;
+ type = u_type;
+ iface = (addr & 0x000000FF);
+ } else {
+ errno = EADDRNOTAVAIL;
+ return -1;
+ }
+ break;
+ }
+#ifdef HAVE_IPV6
+ case AF_INET6: {
+ const struct sockaddr_in6 *in =
+ (const struct sockaddr_in6 *)inaddr;
+
+ switch (si->type) {
+ case SOCK_STREAM:
+ type = SOCKET_TYPE_CHAR_TCP_V6;
+ break;
+ case SOCK_DGRAM:
+ type = SOCKET_TYPE_CHAR_UDP_V6;
+ break;
+ }
+
+ /* XXX no multicast/broadcast */
+
+ prt = ntohs(in->sin6_port);
+ iface = SW_IPV6_ADDRESS;
+
+ break;
+ }
+#endif
+ default:
+ errno = ENETUNREACH;
+ return -1;
+ }
+
+
+ if (bcast) *bcast = is_bcast;
+
+ if (prt == 0) {
+ /* handle auto-allocation of ephemeral ports */
+ for (prt = 5001; prt < 10000; prt++) {
+ snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
+ socket_wrapper_dir(), type, iface, prt);
+ if (stat(un->sun_path, &st) == 0) continue;
+
+ set_port(si->family, prt, si->myname);
+ }
+ }
+
+ snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
+ socket_wrapper_dir(), type, iface, prt);
+ return 0;
+}
+
+static struct socket_info *find_socket_info(int fd)
+{
+ struct socket_info *i;
+ for (i = sockets; i; i = i->next) {
+ if (i->fd == fd)
+ return i;
+ }
+
+ return NULL;
+}
+
+static int sockaddr_convert_to_un(struct socket_info *si, const struct sockaddr *in_addr, socklen_t in_len,
+ struct sockaddr_un *out_addr, int alloc_sock, int *bcast)
+{
+ if (!out_addr)
+ return 0;
+
+ out_addr->sun_family = AF_UNIX;
+
+ switch (in_addr->sa_family) {
+ case AF_INET:
+#ifdef HAVE_IPV6
+ case AF_INET6:
+#endif
+ switch (si->type) {
+ case SOCK_STREAM:
+ case SOCK_DGRAM:
+ break;
+ default:
+ errno = ESOCKTNOSUPPORT;
+ return -1;
+ }
+ if (alloc_sock) {
+ return convert_in_un_alloc(si, in_addr, out_addr, bcast);
+ } else {
+ return convert_in_un_remote(si, in_addr, out_addr, bcast);
+ }
+ default:
+ break;
+ }
+
+ errno = EAFNOSUPPORT;
+ return -1;
+}
+
+static int sockaddr_convert_from_un(const struct socket_info *si,
+ const struct sockaddr_un *in_addr,
+ socklen_t un_addrlen,
+ int family,
+ struct sockaddr *out_addr,
+ socklen_t *out_addrlen)
+{
+ if (out_addr == NULL || out_addrlen == NULL)
+ return 0;
+
+ if (un_addrlen == 0) {
+ *out_addrlen = 0;
+ return 0;
+ }
+
+ switch (family) {
+ case AF_INET:
+#ifdef HAVE_IPV6
+ case AF_INET6:
+#endif
+ switch (si->type) {
+ case SOCK_STREAM:
+ case SOCK_DGRAM:
+ break;
+ default:
+ errno = ESOCKTNOSUPPORT;
+ return -1;
+ }
+ return convert_un_in(in_addr, out_addr, out_addrlen);
+ default:
+ break;
+ }
+
+ errno = EAFNOSUPPORT;
+ return -1;
+}
+
+enum swrap_packet_type {
+ SWRAP_CONNECT_SEND,
+ SWRAP_CONNECT_UNREACH,
+ SWRAP_CONNECT_RECV,
+ SWRAP_CONNECT_ACK,
+ SWRAP_ACCEPT_SEND,
+ SWRAP_ACCEPT_RECV,
+ SWRAP_ACCEPT_ACK,
+ SWRAP_RECVFROM,
+ SWRAP_SENDTO,
+ SWRAP_SENDTO_UNREACH,
+ SWRAP_PENDING_RST,
+ SWRAP_RECV,
+ SWRAP_RECV_RST,
+ SWRAP_SEND,
+ SWRAP_SEND_RST,
+ SWRAP_CLOSE_SEND,
+ SWRAP_CLOSE_RECV,
+ SWRAP_CLOSE_ACK
+};
+
+struct swrap_file_hdr {
+ unsigned long magic;
+ unsigned short version_major;
+ unsigned short version_minor;
+ long timezone;
+ unsigned long sigfigs;
+ unsigned long frame_max_len;
+#define SWRAP_FRAME_LENGTH_MAX 0xFFFF
+ unsigned long link_type;
+};
+#define SWRAP_FILE_HDR_SIZE 24
+
+struct swrap_packet {
+ struct {
+ unsigned long seconds;
+ unsigned long micro_seconds;
+ unsigned long recorded_length;
+ unsigned long full_length;
+ } frame;
+#define SWRAP_PACKET__FRAME_SIZE 16
+
+ struct {
+ struct {
+ unsigned char ver_hdrlen;
+ unsigned char tos;
+ unsigned short packet_length;
+ unsigned short identification;
+ unsigned char flags;
+ unsigned char fragment;
+ unsigned char ttl;
+ unsigned char protocol;
+ unsigned short hdr_checksum;
+ unsigned long src_addr;
+ unsigned long dest_addr;
+ } hdr;
+#define SWRAP_PACKET__IP_HDR_SIZE 20
+
+ union {
+ struct {
+ unsigned short source_port;
+ unsigned short dest_port;
+ unsigned long seq_num;
+ unsigned long ack_num;
+ unsigned char hdr_length;
+ unsigned char control;
+ unsigned short window;
+ unsigned short checksum;
+ unsigned short urg;
+ } tcp;
+#define SWRAP_PACKET__IP_P_TCP_SIZE 20
+ struct {
+ unsigned short source_port;
+ unsigned short dest_port;
+ unsigned short length;
+ unsigned short checksum;
+ } udp;
+#define SWRAP_PACKET__IP_P_UDP_SIZE 8
+ struct {
+ unsigned char type;
+ unsigned char code;
+ unsigned short checksum;
+ unsigned long unused;
+ } icmp;
+#define SWRAP_PACKET__IP_P_ICMP_SIZE 8
+ } p;
+ } ip;
+};
+#define SWRAP_PACKET_SIZE 56
+
+static const char *socket_wrapper_pcap_file(void)
+{
+ static int initialized = 0;
+ static const char *s = NULL;
+ static const struct swrap_file_hdr h;
+ static const struct swrap_packet p;
+
+ if (initialized == 1) {
+ return s;
+ }
+ initialized = 1;
+
+ /*
+ * TODO: don't use the structs use plain buffer offsets
+ * and PUSH_U8(), PUSH_U16() and PUSH_U32()
+ *
+ * for now make sure we disable PCAP support
+ * if the struct has alignment!
+ */
+ if (sizeof(h) != SWRAP_FILE_HDR_SIZE) {
+ return NULL;
+ }
+ if (sizeof(p) != SWRAP_PACKET_SIZE) {
+ return NULL;
+ }
+ if (sizeof(p.frame) != SWRAP_PACKET__FRAME_SIZE) {
+ return NULL;
+ }
+ if (sizeof(p.ip.hdr) != SWRAP_PACKET__IP_HDR_SIZE) {
+ return NULL;
+ }
+ if (sizeof(p.ip.p.tcp) != SWRAP_PACKET__IP_P_TCP_SIZE) {
+ return NULL;
+ }
+ if (sizeof(p.ip.p.udp) != SWRAP_PACKET__IP_P_UDP_SIZE) {
+ return NULL;
+ }
+ if (sizeof(p.ip.p.icmp) != SWRAP_PACKET__IP_P_ICMP_SIZE) {
+ return NULL;
+ }
+
+ s = getenv("SOCKET_WRAPPER_PCAP_FILE");
+ if (s == NULL) {
+ return NULL;
+ }
+ if (strncmp(s, "./", 2) == 0) {
+ s += 2;
+ }
+ return s;
+}
+
+static struct swrap_packet *swrap_packet_init(struct timeval *tval,
+ const struct sockaddr_in *src_addr,
+ const struct sockaddr_in *dest_addr,
+ int socket_type,
+ const unsigned char *payload,
+ size_t payload_len,
+ unsigned long tcp_seq,
+ unsigned long tcp_ack,
+ unsigned char tcp_ctl,
+ int unreachable,
+ size_t *_packet_len)
+{
+ struct swrap_packet *ret;
+ struct swrap_packet *packet;
+ size_t packet_len;
+ size_t alloc_len;
+ size_t nonwire_len = sizeof(packet->frame);
+ size_t wire_hdr_len = 0;
+ size_t wire_len = 0;
+ size_t icmp_hdr_len = 0;
+ size_t icmp_truncate_len = 0;
+ unsigned char protocol = 0, icmp_protocol = 0;
+ unsigned short src_port = src_addr->sin_port;
+ unsigned short dest_port = dest_addr->sin_port;
+
+ switch (socket_type) {
+ case SOCK_STREAM:
+ protocol = 0x06; /* TCP */
+ wire_hdr_len = sizeof(packet->ip.hdr) + sizeof(packet->ip.p.tcp);
+ wire_len = wire_hdr_len + payload_len;
+ break;
+
+ case SOCK_DGRAM:
+ protocol = 0x11; /* UDP */
+ wire_hdr_len = sizeof(packet->ip.hdr) + sizeof(packet->ip.p.udp);
+ wire_len = wire_hdr_len + payload_len;
+ break;
+ }
+
+ if (unreachable) {
+ icmp_protocol = protocol;
+ protocol = 0x01; /* ICMP */
+ if (wire_len > 64 ) {
+ icmp_truncate_len = wire_len - 64;
+ }
+ icmp_hdr_len = sizeof(packet->ip.hdr) + sizeof(packet->ip.p.icmp);
+ wire_hdr_len += icmp_hdr_len;
+ wire_len += icmp_hdr_len;
+ }
+
+ packet_len = nonwire_len + wire_len;
+ alloc_len = packet_len;
+ if (alloc_len < sizeof(struct swrap_packet)) {
+ alloc_len = sizeof(struct swrap_packet);
+ }
+ ret = (struct swrap_packet *)malloc(alloc_len);
+ if (!ret) return NULL;
+
+ packet = ret;
+
+ packet->frame.seconds = tval->tv_sec;
+ packet->frame.micro_seconds = tval->tv_usec;
+ packet->frame.recorded_length = wire_len - icmp_truncate_len;
+ packet->frame.full_length = wire_len - icmp_truncate_len;
+
+ packet->ip.hdr.ver_hdrlen = 0x45; /* version 4 and 5 * 32 bit words */
+ packet->ip.hdr.tos = 0x00;
+ packet->ip.hdr.packet_length = htons(wire_len - icmp_truncate_len);
+ packet->ip.hdr.identification = htons(0xFFFF);
+ packet->ip.hdr.flags = 0x40; /* BIT 1 set - means don't fraqment */
+ packet->ip.hdr.fragment = htons(0x0000);
+ packet->ip.hdr.ttl = 0xFF;
+ packet->ip.hdr.protocol = protocol;
+ packet->ip.hdr.hdr_checksum = htons(0x0000);
+ packet->ip.hdr.src_addr = src_addr->sin_addr.s_addr;
+ packet->ip.hdr.dest_addr = dest_addr->sin_addr.s_addr;
+
+ if (unreachable) {
+ packet->ip.p.icmp.type = 0x03; /* destination unreachable */
+ packet->ip.p.icmp.code = 0x01; /* host unreachable */
+ packet->ip.p.icmp.checksum = htons(0x0000);
+ packet->ip.p.icmp.unused = htonl(0x00000000);
+
+ /* set the ip header in the ICMP payload */
+ packet = (struct swrap_packet *)(((unsigned char *)ret) + icmp_hdr_len);
+ packet->ip.hdr.ver_hdrlen = 0x45; /* version 4 and 5 * 32 bit words */
+ packet->ip.hdr.tos = 0x00;
+ packet->ip.hdr.packet_length = htons(wire_len - icmp_hdr_len);
+ packet->ip.hdr.identification = htons(0xFFFF);
+ packet->ip.hdr.flags = 0x40; /* BIT 1 set - means don't fraqment */
+ packet->ip.hdr.fragment = htons(0x0000);
+ packet->ip.hdr.ttl = 0xFF;
+ packet->ip.hdr.protocol = icmp_protocol;
+ packet->ip.hdr.hdr_checksum = htons(0x0000);
+ packet->ip.hdr.src_addr = dest_addr->sin_addr.s_addr;
+ packet->ip.hdr.dest_addr = src_addr->sin_addr.s_addr;
+
+ src_port = dest_addr->sin_port;
+ dest_port = src_addr->sin_port;
+ }
+
+ switch (socket_type) {
+ case SOCK_STREAM:
+ packet->ip.p.tcp.source_port = src_port;
+ packet->ip.p.tcp.dest_port = dest_port;
+ packet->ip.p.tcp.seq_num = htonl(tcp_seq);
+ packet->ip.p.tcp.ack_num = htonl(tcp_ack);
+ packet->ip.p.tcp.hdr_length = 0x50; /* 5 * 32 bit words */
+ packet->ip.p.tcp.control = tcp_ctl;
+ packet->ip.p.tcp.window = htons(0x7FFF);
+ packet->ip.p.tcp.checksum = htons(0x0000);
+ packet->ip.p.tcp.urg = htons(0x0000);
+
+ break;
+
+ case SOCK_DGRAM:
+ packet->ip.p.udp.source_port = src_addr->sin_port;
+ packet->ip.p.udp.dest_port = dest_addr->sin_port;
+ packet->ip.p.udp.length = htons(8 + payload_len);
+ packet->ip.p.udp.checksum = htons(0x0000);
+
+ break;
+ }
+
+ if (payload && payload_len > 0) {
+ unsigned char *p = (unsigned char *)ret;
+ p += nonwire_len;
+ p += wire_hdr_len;
+ memcpy(p, payload, payload_len);
+ }
+
+ *_packet_len = packet_len - icmp_truncate_len;
+ return ret;
+}
+
+static int swrap_get_pcap_fd(const char *fname)
+{
+ static int fd = -1;
+
+ if (fd != -1) return fd;
+
+ fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0644);
+ if (fd != -1) {
+ struct swrap_file_hdr file_hdr;
+ file_hdr.magic = 0xA1B2C3D4;
+ file_hdr.version_major = 0x0002;
+ file_hdr.version_minor = 0x0004;
+ file_hdr.timezone = 0x00000000;
+ file_hdr.sigfigs = 0x00000000;
+ file_hdr.frame_max_len = SWRAP_FRAME_LENGTH_MAX;
+ file_hdr.link_type = 0x0065; /* 101 RAW IP */
+
+ write(fd, &file_hdr, sizeof(file_hdr));
+ return fd;
+ }
+
+ fd = open(fname, O_WRONLY|O_APPEND, 0644);
+
+ return fd;
+}
+
+static void swrap_dump_packet(struct socket_info *si, const struct sockaddr *addr,
+ enum swrap_packet_type type,
+ const void *buf, size_t len)
+{
+ const struct sockaddr_in *src_addr;
+ const struct sockaddr_in *dest_addr;
+ const char *file_name;
+ unsigned long tcp_seq = 0;
+ unsigned long tcp_ack = 0;
+ unsigned char tcp_ctl = 0;
+ int unreachable = 0;
+ struct timeval tv;
+ struct swrap_packet *packet;
+ size_t packet_len = 0;
+ int fd;
+
+ file_name = socket_wrapper_pcap_file();
+ if (!file_name) {
+ return;
+ }
+
+ switch (si->family) {
+ case AF_INET:
+#ifdef HAVE_IPV6
+ case AF_INET6:
+#endif
+ break;
+ default:
+ return;
+ }
+
+ switch (type) {
+ case SWRAP_CONNECT_SEND:
+ if (si->type != SOCK_STREAM) return;
+
+ src_addr = (const struct sockaddr_in *)si->myname;
+ dest_addr = (const struct sockaddr_in *)addr;
+
+ tcp_seq = si->io.pck_snd;
+ tcp_ack = si->io.pck_rcv;
+ tcp_ctl = 0x02; /* SYN */
+
+ si->io.pck_snd += 1;
+
+ break;
+
+ case SWRAP_CONNECT_RECV:
+ if (si->type != SOCK_STREAM) return;
+
+ dest_addr = (const struct sockaddr_in *)si->myname;
+ src_addr = (const struct sockaddr_in *)addr;
+
+ tcp_seq = si->io.pck_rcv;
+ tcp_ack = si->io.pck_snd;
+ tcp_ctl = 0x12; /** SYN,ACK */
+
+ si->io.pck_rcv += 1;
+
+ break;
+
+ case SWRAP_CONNECT_UNREACH:
+ if (si->type != SOCK_STREAM) return;
+
+ dest_addr = (const struct sockaddr_in *)si->myname;
+ src_addr = (const struct sockaddr_in *)addr;
+
+ /* Unreachable: resend the data of SWRAP_CONNECT_SEND */
+ tcp_seq = si->io.pck_snd - 1;
+ tcp_ack = si->io.pck_rcv;
+ tcp_ctl = 0x02; /* SYN */
+ unreachable = 1;
+
+ break;
+
+ case SWRAP_CONNECT_ACK:
+ if (si->type != SOCK_STREAM) return;
+
+ src_addr = (const struct sockaddr_in *)si->myname;
+ dest_addr = (const struct sockaddr_in *)addr;
+
+ tcp_seq = si->io.pck_snd;
+ tcp_ack = si->io.pck_rcv;
+ tcp_ctl = 0x10; /* ACK */
+
+ break;
+
+ case SWRAP_ACCEPT_SEND:
+ if (si->type != SOCK_STREAM) return;
+
+ dest_addr = (const struct sockaddr_in *)si->myname;
+ src_addr = (const struct sockaddr_in *)addr;
+
+ tcp_seq = si->io.pck_rcv;
+ tcp_ack = si->io.pck_snd;
+ tcp_ctl = 0x02; /* SYN */
+
+ si->io.pck_rcv += 1;
+
+ break;
+
+ case SWRAP_ACCEPT_RECV:
+ if (si->type != SOCK_STREAM) return;
+
+ src_addr = (const struct sockaddr_in *)si->myname;
+ dest_addr = (const struct sockaddr_in *)addr;
+
+ tcp_seq = si->io.pck_snd;
+ tcp_ack = si->io.pck_rcv;
+ tcp_ctl = 0x12; /* SYN,ACK */
+
+ si->io.pck_snd += 1;
+
+ break;
+
+ case SWRAP_ACCEPT_ACK:
+ if (si->type != SOCK_STREAM) return;
+
+ dest_addr = (const struct sockaddr_in *)si->myname;
+ src_addr = (const struct sockaddr_in *)addr;
+
+ tcp_seq = si->io.pck_rcv;
+ tcp_ack = si->io.pck_snd;
+ tcp_ctl = 0x10; /* ACK */
+
+ break;
+
+ case SWRAP_SEND:
+ src_addr = (const struct sockaddr_in *)si->myname;
+ dest_addr = (const struct sockaddr_in *)si->peername;
+
+ tcp_seq = si->io.pck_snd;
+ tcp_ack = si->io.pck_rcv;
+ tcp_ctl = 0x18; /* PSH,ACK */
+
+ si->io.pck_snd += len;
+
+ break;
+
+ case SWRAP_SEND_RST:
+ dest_addr = (const struct sockaddr_in *)si->myname;
+ src_addr = (const struct sockaddr_in *)si->peername;
+
+ if (si->type == SOCK_DGRAM) {
+ swrap_dump_packet(si, si->peername,
+ SWRAP_SENDTO_UNREACH,
+ buf, len);
+ return;
+ }
+
+ tcp_seq = si->io.pck_rcv;
+ tcp_ack = si->io.pck_snd;
+ tcp_ctl = 0x14; /** RST,ACK */
+
+ break;
+
+ case SWRAP_PENDING_RST:
+ dest_addr = (const struct sockaddr_in *)si->myname;
+ src_addr = (const struct sockaddr_in *)si->peername;
+
+ if (si->type == SOCK_DGRAM) {
+ return;
+ }
+
+ tcp_seq = si->io.pck_rcv;
+ tcp_ack = si->io.pck_snd;
+ tcp_ctl = 0x14; /* RST,ACK */
+
+ break;
+
+ case SWRAP_RECV:
+ dest_addr = (const struct sockaddr_in *)si->myname;
+ src_addr = (const struct sockaddr_in *)si->peername;
+
+ tcp_seq = si->io.pck_rcv;
+ tcp_ack = si->io.pck_snd;
+ tcp_ctl = 0x18; /* PSH,ACK */
+
+ si->io.pck_rcv += len;
+
+ break;
+
+ case SWRAP_RECV_RST:
+ dest_addr = (const struct sockaddr_in *)si->myname;
+ src_addr = (const struct sockaddr_in *)si->peername;
+
+ if (si->type == SOCK_DGRAM) {
+ return;
+ }
+
+ tcp_seq = si->io.pck_rcv;
+ tcp_ack = si->io.pck_snd;
+ tcp_ctl = 0x14; /* RST,ACK */
+
+ break;
+
+ case SWRAP_SENDTO:
+ src_addr = (const struct sockaddr_in *)si->myname;
+ dest_addr = (const struct sockaddr_in *)addr;
+
+ si->io.pck_snd += len;
+
+ break;
+
+ case SWRAP_SENDTO_UNREACH:
+ dest_addr = (const struct sockaddr_in *)si->myname;
+ src_addr = (const struct sockaddr_in *)addr;
+
+ unreachable = 1;
+
+ break;
+
+ case SWRAP_RECVFROM:
+ dest_addr = (const struct sockaddr_in *)si->myname;
+ src_addr = (const struct sockaddr_in *)addr;
+
+ si->io.pck_rcv += len;
+
+ break;
+
+ case SWRAP_CLOSE_SEND:
+ if (si->type != SOCK_STREAM) return;
+
+ src_addr = (const struct sockaddr_in *)si->myname;
+ dest_addr = (const struct sockaddr_in *)si->peername;
+
+ tcp_seq = si->io.pck_snd;
+ tcp_ack = si->io.pck_rcv;
+ tcp_ctl = 0x11; /* FIN, ACK */
+
+ si->io.pck_snd += 1;
+
+ break;
+
+ case SWRAP_CLOSE_RECV:
+ if (si->type != SOCK_STREAM) return;
+
+ dest_addr = (const struct sockaddr_in *)si->myname;
+ src_addr = (const struct sockaddr_in *)si->peername;
+
+ tcp_seq = si->io.pck_rcv;
+ tcp_ack = si->io.pck_snd;
+ tcp_ctl = 0x11; /* FIN,ACK */
+
+ si->io.pck_rcv += 1;
+
+ break;
+
+ case SWRAP_CLOSE_ACK:
+ if (si->type != SOCK_STREAM) return;
+
+ src_addr = (const struct sockaddr_in *)si->myname;
+ dest_addr = (const struct sockaddr_in *)si->peername;
+
+ tcp_seq = si->io.pck_snd;
+ tcp_ack = si->io.pck_rcv;
+ tcp_ctl = 0x10; /* ACK */
+
+ break;
+ default:
+ return;
+ }
+
+ swrapGetTimeOfDay(&tv);
+
+ packet = swrap_packet_init(&tv, src_addr, dest_addr, si->type,
+ (const unsigned char *)buf, len,
+ tcp_seq, tcp_ack, tcp_ctl, unreachable,
+ &packet_len);
+ if (!packet) {
+ return;
+ }
+
+ fd = swrap_get_pcap_fd(file_name);
+ if (fd != -1) {
+ write(fd, packet, packet_len);
+ }
+
+ free(packet);
+}
+
+_PUBLIC_ int swrap_socket(int family, int type, int protocol)
+{
+ struct socket_info *si;
+ int fd;
+
+ if (!socket_wrapper_dir()) {
+ return real_socket(family, type, protocol);
+ }
+
+ switch (family) {
+ case AF_INET:
+#ifdef HAVE_IPV6
+ case AF_INET6:
+#endif
+ break;
+ case AF_UNIX:
+ return real_socket(family, type, protocol);
+ default:
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+
+ switch (type) {
+ case SOCK_STREAM:
+ break;
+ case SOCK_DGRAM:
+ break;
+ default:
+ errno = EPROTONOSUPPORT;
+ return -1;
+ }
+
+#if 0
+ switch (protocol) {
+ case 0:
+ break;
+ default:
+ errno = EPROTONOSUPPORT;
+ return -1;
+ }
+#endif
+
+ fd = real_socket(AF_UNIX, type, 0);
+
+ if (fd == -1) return -1;
+
+ si = (struct socket_info *)calloc(1, sizeof(struct socket_info));
+
+ si->family = family;
+ si->type = type;
+ si->protocol = protocol;
+ si->fd = fd;
+
+ SWRAP_DLIST_ADD(sockets, si);
+
+ return si->fd;
+}
+
+_PUBLIC_ int swrap_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
+{
+ struct socket_info *parent_si, *child_si;
+ int fd;
+ struct sockaddr_un un_addr;
+ socklen_t un_addrlen = sizeof(un_addr);
+ struct sockaddr_un un_my_addr;
+ socklen_t un_my_addrlen = sizeof(un_my_addr);
+ struct sockaddr *my_addr;
+ socklen_t my_addrlen, len;
+ int ret;
+
+ parent_si = find_socket_info(s);
+ if (!parent_si) {
+ return real_accept(s, addr, addrlen);
+ }
+
+ /*
+ * assume out sockaddr have the same size as the in parent
+ * socket family
+ */
+ my_addrlen = socket_length(parent_si->family);
+ if (my_addrlen < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ my_addr = malloc(my_addrlen);
+ if (my_addr == NULL) {
+ return -1;
+ }
+
+ memset(&un_addr, 0, sizeof(un_addr));
+ memset(&un_my_addr, 0, sizeof(un_my_addr));
+
+ ret = real_accept(s, (struct sockaddr *)&un_addr, &un_addrlen);
+ if (ret == -1) {
+ free(my_addr);
+ return ret;
+ }
+
+ fd = ret;
+
+ len = my_addrlen;
+ ret = sockaddr_convert_from_un(parent_si, &un_addr, un_addrlen,
+ parent_si->family, my_addr, &len);
+ if (ret == -1) {
+ free(my_addr);
+ close(fd);
+ return ret;
+ }
+
+ child_si = (struct socket_info *)malloc(sizeof(struct socket_info));
+ memset(child_si, 0, sizeof(*child_si));
+
+ child_si->fd = fd;
+ child_si->family = parent_si->family;
+ child_si->type = parent_si->type;
+ child_si->protocol = parent_si->protocol;
+ child_si->bound = 1;
+ child_si->is_server = 1;
+
+ child_si->peername_len = len;
+ child_si->peername = sockaddr_dup(my_addr, len);
+
+ if (addr != NULL && addrlen != NULL) {
+ *addrlen = len;
+ if (*addrlen >= len)
+ memcpy(addr, my_addr, len);
+ *addrlen = 0;
+ }
+
+ ret = real_getsockname(fd, (struct sockaddr *)&un_my_addr, &un_my_addrlen);
+ if (ret == -1) {
+ free(child_si);
+ close(fd);
+ return ret;
+ }
+
+ len = my_addrlen;
+ ret = sockaddr_convert_from_un(child_si, &un_my_addr, un_my_addrlen,
+ child_si->family, my_addr, &len);
+ if (ret == -1) {
+ free(child_si);
+ free(my_addr);
+ close(fd);
+ return ret;
+ }
+
+ child_si->myname_len = len;
+ child_si->myname = sockaddr_dup(my_addr, len);
+ free(my_addr);
+
+ SWRAP_DLIST_ADD(sockets, child_si);
+
+ swrap_dump_packet(child_si, addr, SWRAP_ACCEPT_SEND, NULL, 0);
+ swrap_dump_packet(child_si, addr, SWRAP_ACCEPT_RECV, NULL, 0);
+ swrap_dump_packet(child_si, addr, SWRAP_ACCEPT_ACK, NULL, 0);
+
+ return fd;
+}
+
+static int autobind_start_init;
+static int autobind_start;
+
+/* using sendto() or connect() on an unbound socket would give the
+ recipient no way to reply, as unlike UDP and TCP, a unix domain
+ socket can't auto-assign emphemeral port numbers, so we need to
+ assign it here */
+static int swrap_auto_bind(struct socket_info *si)
+{
+ struct sockaddr_un un_addr;
+ int i;
+ char type;
+ int ret;
+ int port;
+ struct stat st;
+
+ if (autobind_start_init != 1) {
+ autobind_start_init = 1;
+ autobind_start = getpid();
+ autobind_start %= 50000;
+ autobind_start += 10000;
+ }
+
+ un_addr.sun_family = AF_UNIX;
+
+ switch (si->family) {
+ case AF_INET: {
+ struct sockaddr_in in;
+
+ switch (si->type) {
+ case SOCK_STREAM:
+ type = SOCKET_TYPE_CHAR_TCP;
+ break;
+ case SOCK_DGRAM:
+ type = SOCKET_TYPE_CHAR_UDP;
+ break;
+ default:
+ errno = ESOCKTNOSUPPORT;
+ return -1;
+ }
+
+ memset(&in, 0, sizeof(in));
+ in.sin_family = AF_INET;
+ in.sin_addr.s_addr = htonl(127<<24 |
+ socket_wrapper_default_iface());
+
+ si->myname_len = sizeof(in);
+ si->myname = sockaddr_dup(&in, si->myname_len);
+ break;
+ }
+#ifdef HAVE_IPV6
+ case AF_INET6: {
+ struct sockaddr_in6 in6;
+
+ switch (si->type) {
+ case SOCK_STREAM:
+ type = SOCKET_TYPE_CHAR_TCP_V6;
+ break;
+ case SOCK_DGRAM:
+ type = SOCKET_TYPE_CHAR_UDP_V6;
+ break;
+ default:
+ errno = ESOCKTNOSUPPORT;
+ return -1;
+ }
+
+ memset(&in6, 0, sizeof(in6));
+ in6.sin6_family = AF_INET6;
+ in6.sin6_addr.s6_addr[0] = SW_IPV6_ADDRESS;
+ si->myname_len = sizeof(in6);
+ si->myname = sockaddr_dup(&in6, si->myname_len);
+ break;
+ }
+#endif
+ default:
+ errno = ESOCKTNOSUPPORT;
+ return -1;
+ }
+
+ if (autobind_start > 60000) {
+ autobind_start = 10000;
+ }
+
+ for (i=0;i<1000;i++) {
+ port = autobind_start + i;
+ snprintf(un_addr.sun_path, sizeof(un_addr.sun_path),
+ "%s/"SOCKET_FORMAT, socket_wrapper_dir(),
+ type, socket_wrapper_default_iface(), port);
+ if (stat(un_addr.sun_path, &st) == 0) continue;
+
+ ret = real_bind(si->fd, (struct sockaddr *)&un_addr, sizeof(un_addr));
+ if (ret == -1) return ret;
+
+ si->tmp_path = strdup(un_addr.sun_path);
+ si->bound = 1;
+ autobind_start = port + 1;
+ break;
+ }
+ if (i == 1000) {
+ errno = ENFILE;
+ return -1;
+ }
+
+ set_port(si->family, port, si->myname);
+
+ return 0;
+}
+
+
+_PUBLIC_ int swrap_connect(int s, const struct sockaddr *serv_addr, socklen_t addrlen)
+{
+ int ret;
+ struct sockaddr_un un_addr;
+ struct socket_info *si = find_socket_info(s);
+
+ if (!si) {
+ return real_connect(s, serv_addr, addrlen);
+ }
+
+ if (si->bound == 0) {
+ ret = swrap_auto_bind(si);
+ if (ret == -1) return -1;
+ }
+
+ if (si->family != serv_addr->sa_family) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = sockaddr_convert_to_un(si, (const struct sockaddr *)serv_addr, addrlen, &un_addr, 0, NULL);
+ if (ret == -1) return -1;
+
+ swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_SEND, NULL, 0);
+
+ ret = real_connect(s, (struct sockaddr *)&un_addr,
+ sizeof(struct sockaddr_un));
+
+ /* to give better errors */
+ if (ret == -1 && errno == ENOENT) {
+ errno = EHOSTUNREACH;
+ }
+
+ if (ret == 0) {
+ si->peername_len = addrlen;
+ si->peername = sockaddr_dup(serv_addr, addrlen);
+
+ swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_RECV, NULL, 0);
+ swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_ACK, NULL, 0);
+ } else {
+ swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_UNREACH, NULL, 0);
+ }
+
+ return ret;
+}
+
+_PUBLIC_ int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen)
+{
+ int ret;
+ struct sockaddr_un un_addr;
+ struct socket_info *si = find_socket_info(s);
+
+ if (!si) {
+ return real_bind(s, myaddr, addrlen);
+ }
+
+ si->myname_len = addrlen;
+ si->myname = sockaddr_dup(myaddr, addrlen);
+
+ ret = sockaddr_convert_to_un(si, (const struct sockaddr *)myaddr, addrlen, &un_addr, 1, &si->bcast);
+ if (ret == -1) return -1;
+
+ unlink(un_addr.sun_path);
+
+ ret = real_bind(s, (struct sockaddr *)&un_addr,
+ sizeof(struct sockaddr_un));
+
+ if (ret == 0) {
+ si->bound = 1;
+ }
+
+ return ret;
+}
+
+_PUBLIC_ int swrap_listen(int s, int backlog)
+{
+ int ret;
+ struct socket_info *si = find_socket_info(s);
+
+ if (!si) {
+ return real_listen(s, backlog);
+ }
+
+ ret = real_listen(s, backlog);
+
+ return ret;
+}
+
+_PUBLIC_ int swrap_getpeername(int s, struct sockaddr *name, socklen_t *addrlen)
+{
+ struct socket_info *si = find_socket_info(s);
+
+ if (!si) {
+ return real_getpeername(s, name, addrlen);
+ }
+
+ if (!si->peername)
+ {
+ errno = ENOTCONN;
+ return -1;
+ }
+
+ memcpy(name, si->peername, si->peername_len);
+ *addrlen = si->peername_len;
+
+ return 0;
+}
+
+_PUBLIC_ int swrap_getsockname(int s, struct sockaddr *name, socklen_t *addrlen)
+{
+ struct socket_info *si = find_socket_info(s);
+
+ if (!si) {
+ return real_getsockname(s, name, addrlen);
+ }
+
+ memcpy(name, si->myname, si->myname_len);
+ *addrlen = si->myname_len;
+
+ return 0;
+}
+
+_PUBLIC_ int swrap_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
+{
+ struct socket_info *si = find_socket_info(s);
+
+ if (!si) {
+ return real_getsockopt(s, level, optname, optval, optlen);
+ }
+
+ if (level == SOL_SOCKET) {
+ return real_getsockopt(s, level, optname, optval, optlen);
+ }
+
+ errno = ENOPROTOOPT;
+ return -1;
+}
+
+_PUBLIC_ int swrap_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
+{
+ struct socket_info *si = find_socket_info(s);
+
+ if (!si) {
+ return real_setsockopt(s, level, optname, optval, optlen);
+ }
+
+ if (level == SOL_SOCKET) {
+ return real_setsockopt(s, level, optname, optval, optlen);
+ }
+
+ switch (si->family) {
+ case AF_INET:
+ return 0;
+ default:
+ errno = ENOPROTOOPT;
+ return -1;
+ }
+}
+
+_PUBLIC_ ssize_t swrap_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
+{
+ struct sockaddr_un un_addr;
+ socklen_t un_addrlen = sizeof(un_addr);
+ int ret;
+ struct socket_info *si = find_socket_info(s);
+
+ if (!si) {
+ return real_recvfrom(s, buf, len, flags, from, fromlen);
+ }
+
+ /* irix 6.4 forgets to null terminate the sun_path string :-( */
+ memset(&un_addr, 0, sizeof(un_addr));
+ ret = real_recvfrom(s, buf, len, flags, (struct sockaddr *)&un_addr, &un_addrlen);
+ if (ret == -1)
+ return ret;
+
+ if (sockaddr_convert_from_un(si, &un_addr, un_addrlen,
+ si->family, from, fromlen) == -1) {
+ return -1;
+ }
+
+ swrap_dump_packet(si, from, SWRAP_RECVFROM, buf, ret);
+
+ return ret;
+}
+
+
+_PUBLIC_ ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
+{
+ struct sockaddr_un un_addr;
+ int ret;
+ struct socket_info *si = find_socket_info(s);
+ int bcast = 0;
+
+ if (!si) {
+ return real_sendto(s, buf, len, flags, to, tolen);
+ }
+
+ switch (si->type) {
+ case SOCK_STREAM:
+ ret = real_send(s, buf, len, flags);
+ break;
+ case SOCK_DGRAM:
+ if (si->bound == 0) {
+ ret = swrap_auto_bind(si);
+ if (ret == -1) return -1;
+ }
+
+ ret = sockaddr_convert_to_un(si, to, tolen, &un_addr, 0, &bcast);
+ if (ret == -1) return -1;
+
+ if (bcast) {
+ struct stat st;
+ unsigned int iface;
+ unsigned int prt = ntohs(((const struct sockaddr_in *)to)->sin_port);
+ char type;
+
+ type = SOCKET_TYPE_CHAR_UDP;
+
+ for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) {
+ snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/"SOCKET_FORMAT,
+ socket_wrapper_dir(), type, iface, prt);
+ if (stat(un_addr.sun_path, &st) != 0) continue;
+
+ /* ignore the any errors in broadcast sends */
+ real_sendto(s, buf, len, flags, (struct sockaddr *)&un_addr, sizeof(un_addr));
+ }
+
+ swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
+
+ return len;
+ }
+
+ ret = real_sendto(s, buf, len, flags, (struct sockaddr *)&un_addr, sizeof(un_addr));
+ break;
+ default:
+ ret = -1;
+ errno = EHOSTUNREACH;
+ break;
+ }
+
+ /* to give better errors */
+ if (ret == -1 && errno == ENOENT) {
+ errno = EHOSTUNREACH;
+ }
+
+ if (ret == -1) {
+ swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
+ swrap_dump_packet(si, to, SWRAP_SENDTO_UNREACH, buf, len);
+ } else {
+ swrap_dump_packet(si, to, SWRAP_SENDTO, buf, ret);
+ }
+
+ return ret;
+}
+
+_PUBLIC_ int swrap_ioctl(int s, int r, void *p)
+{
+ int ret;
+ struct socket_info *si = find_socket_info(s);
+ int value;
+
+ if (!si) {
+ return real_ioctl(s, r, p);
+ }
+
+ ret = real_ioctl(s, r, p);
+
+ switch (r) {
+ case FIONREAD:
+ value = *((int *)p);
+ if (ret == -1 && errno != EAGAIN && errno != ENOBUFS) {
+ swrap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0);
+ } else if (value == 0) { /* END OF FILE */
+ swrap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0);
+ }
+ break;
+ }
+
+ return ret;
+}
+
+_PUBLIC_ ssize_t swrap_recv(int s, void *buf, size_t len, int flags)
+{
+ int ret;
+ struct socket_info *si = find_socket_info(s);
+
+ if (!si) {
+ return real_recv(s, buf, len, flags);
+ }
+
+ ret = real_recv(s, buf, len, flags);
+ if (ret == -1 && errno != EAGAIN && errno != ENOBUFS) {
+ swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
+ } else if (ret == 0) { /* END OF FILE */
+ swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
+ } else {
+ swrap_dump_packet(si, NULL, SWRAP_RECV, buf, ret);
+ }
+
+ return ret;
+}
+
+
+_PUBLIC_ ssize_t swrap_send(int s, const void *buf, size_t len, int flags)
+{
+ int ret;
+ struct socket_info *si = find_socket_info(s);
+
+ if (!si) {
+ return real_send(s, buf, len, flags);
+ }
+
+ ret = real_send(s, buf, len, flags);
+
+ if (ret == -1) {
+ swrap_dump_packet(si, NULL, SWRAP_SEND, buf, len);
+ swrap_dump_packet(si, NULL, SWRAP_SEND_RST, NULL, 0);
+ } else {
+ swrap_dump_packet(si, NULL, SWRAP_SEND, buf, ret);
+ }
+
+ return ret;
+}
+
+_PUBLIC_ int swrap_close(int fd)
+{
+ struct socket_info *si = find_socket_info(fd);
+ int ret;
+
+ if (!si) {
+ return real_close(fd);
+ }
+
+ SWRAP_DLIST_REMOVE(sockets, si);
+
+ if (si->myname && si->peername) {
+ swrap_dump_packet(si, NULL, SWRAP_CLOSE_SEND, NULL, 0);
+ }
+
+ ret = real_close(fd);
+
+ if (si->myname && si->peername) {
+ swrap_dump_packet(si, NULL, SWRAP_CLOSE_RECV, NULL, 0);
+ swrap_dump_packet(si, NULL, SWRAP_CLOSE_ACK, NULL, 0);
+ }
+
+ if (si->path) free(si->path);
+ if (si->myname) free(si->myname);
+ if (si->peername) free(si->peername);
+ if (si->tmp_path) {
+ unlink(si->tmp_path);
+ free(si->tmp_path);
+ }
+ free(si);
+
+ return ret;
+}
+
+static int
+dup_internal(const struct socket_info *si_oldd, int fd)
+{
+ struct socket_info *si_newd;
+
+ si_newd = (struct socket_info *)calloc(1, sizeof(struct socket_info));
+
+ si_newd->fd = fd;
+
+ si_newd->family = si_oldd->family;
+ si_newd->type = si_oldd->type;
+ si_newd->protocol = si_oldd->protocol;
+ si_newd->bound = si_oldd->bound;
+ si_newd->bcast = si_oldd->bcast;
+ if (si_oldd->path)
+ si_newd->path = strdup(si_oldd->path);
+ if (si_oldd->tmp_path)
+ si_newd->tmp_path = strdup(si_oldd->tmp_path);
+ si_newd->myname =
+ sockaddr_dup(si_oldd->myname, si_oldd->myname_len);
+ si_newd->myname_len = si_oldd->myname_len;
+ si_newd->peername =
+ sockaddr_dup(si_oldd->peername, si_oldd->peername_len);
+ si_newd->peername_len = si_oldd->peername_len;
+
+ si_newd->io = si_oldd->io;
+
+ SWRAP_DLIST_ADD(sockets, si_newd);
+
+ return fd;
+}
+
+
+_PUBLIC_ int swrap_dup(int oldd)
+{
+ struct socket_info *si;
+ int fd;
+
+ si = find_socket_info(oldd);
+ if (si == NULL)
+ return real_dup(oldd);
+
+ fd = real_dup(si->fd);
+ if (fd < 0)
+ return fd;
+
+ return dup_internal(si, fd);
+}
+
+
+_PUBLIC_ int swrap_dup2(int oldd, int newd)
+{
+ struct socket_info *si_newd, *si_oldd;
+ int fd;
+
+ if (newd == oldd)
+ return newd;
+
+ si_oldd = find_socket_info(oldd);
+ si_newd = find_socket_info(newd);
+
+ if (si_oldd == NULL && si_newd == NULL)
+ return real_dup2(oldd, newd);
+
+ fd = real_dup2(si_oldd->fd, newd);
+ if (fd < 0)
+ return fd;
+
+ /* close new socket first */
+ if (si_newd)
+ swrap_close(newd);
+
+ return dup_internal(si_oldd, fd);
+}
diff --git a/third_party/heimdal/lib/roken/socket_wrapper.h b/third_party/heimdal/lib/roken/socket_wrapper.h
new file mode 100644
index 0000000..06fd633
--- /dev/null
+++ b/third_party/heimdal/lib/roken/socket_wrapper.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) Jelmer Vernooij 2005 <jelmer@samba.org>
+ * Copyright (C) Stefan Metzmacher 2006 <metze@samba.org>
+ *
+ * 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 author 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 AUTHOR 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 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.
+ *
+ */
+
+#ifndef __SOCKET_WRAPPER_H__
+#define __SOCKET_WRAPPER_H__
+
+int swrap_socket(int family, int type, int protocol);
+int swrap_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
+int swrap_connect(int s, const struct sockaddr *serv_addr, socklen_t addrlen);
+int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen);
+int swrap_listen(int s, int backlog);
+int swrap_getpeername(int s, struct sockaddr *name, socklen_t *addrlen);
+int swrap_getsockname(int s, struct sockaddr *name, socklen_t *addrlen);
+int swrap_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen);
+int swrap_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);
+ssize_t swrap_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
+ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen);
+int swrap_ioctl(int s, int req, void *ptr);
+ssize_t swrap_recv(int s, void *buf, size_t len, int flags);
+ssize_t swrap_send(int s, const void *buf, size_t len, int flags);
+int swrap_close(int);
+int swrap_dup(int);
+int swrap_dup2(int, int);
+
+#ifdef SOCKET_WRAPPER_REPLACE
+
+#ifdef accept
+#undef accept
+#endif
+#define accept(s,addr,addrlen) swrap_accept(s,addr,addrlen)
+
+#ifdef connect
+#undef connect
+#endif
+#define connect(s,serv_addr,addrlen) swrap_connect(s,serv_addr,addrlen)
+
+#ifdef bind
+#undef bind
+#endif
+#define bind(s,myaddr,addrlen) swrap_bind(s,myaddr,addrlen)
+
+#ifdef listen
+#undef listen
+#endif
+#define listen(s,blog) swrap_listen(s,blog)
+
+#ifdef getpeername
+#undef getpeername
+#endif
+#define getpeername(s,name,addrlen) swrap_getpeername(s,name,addrlen)
+
+#ifdef getsockname
+#undef getsockname
+#endif
+#define getsockname(s,name,addrlen) swrap_getsockname(s,name,addrlen)
+
+#ifdef getsockopt
+#undef getsockopt
+#endif
+#define getsockopt(s,level,optname,optval,optlen) swrap_getsockopt(s,level,optname,optval,optlen)
+
+#ifdef setsockopt
+#undef setsockopt
+#endif
+#define setsockopt(s,level,optname,optval,optlen) swrap_setsockopt(s,level,optname,optval,optlen)
+
+#ifdef recvfrom
+#undef recvfrom
+#endif
+#define recvfrom(s,buf,len,flags,from,fromlen) swrap_recvfrom(s,buf,len,flags,from,fromlen)
+
+#ifdef sendto
+#undef sendto
+#endif
+#define sendto(s,buf,len,flags,to,tolen) swrap_sendto(s,buf,len,flags,to,tolen)
+
+#ifdef ioctl
+#undef ioctl
+#endif
+#define ioctl(s,req,ptr) swrap_ioctl(s,req,ptr)
+
+#ifdef recv
+#undef recv
+#endif
+#define recv(s,buf,len,flags) swrap_recv(s,buf,len,flags)
+
+#ifdef send
+#undef send
+#endif
+#define send(s,buf,len,flags) swrap_send(s,buf,len,flags)
+
+#ifdef socket
+#undef socket
+#endif
+#define socket(domain,type,protocol) swrap_socket(domain,type,protocol)
+
+#ifdef close
+#undef close
+#endif
+#define close(s) swrap_close(s)
+
+#ifdef dup
+#undef dup
+#endif
+#define dup(oldd) swrap_dup(oldd)
+
+#ifdef dup2
+#undef dup2
+#endif
+#define dup2(oldd, newd) swrap_dup2(oldd, newd)
+
+#endif
+
+#endif /* __SOCKET_WRAPPER_H__ */
diff --git a/third_party/heimdal/lib/roken/sockstartup_w32.c b/third_party/heimdal/lib/roken/sockstartup_w32.c
new file mode 100644
index 0000000..35eb3ae
--- /dev/null
+++ b/third_party/heimdal/lib/roken/sockstartup_w32.c
@@ -0,0 +1,75 @@
+/***********************************************************************
+ * Copyright (c) 2009, Secure Endpoints Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDER 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<config.h>
+
+#include <roken.h>
+
+#ifndef _WIN32
+#error Only implemented for Windows
+#endif
+
+volatile LONG _startup_count = 0;
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_WSAStartup(void)
+{
+ WSADATA wsad;
+
+ if (!WSAStartup( MAKEWORD(2, 2), &wsad )) {
+ if (wsad.wVersion != MAKEWORD(2, 2)) {
+ /* huh? We can't use 2.2? */
+ WSACleanup();
+ return -1;
+ }
+
+ InterlockedIncrement(&_startup_count);
+ return 0;
+ }
+
+ return -1;
+}
+
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_WSACleanup(void)
+{
+ LONG l;
+
+ if ((l = InterlockedDecrement(&_startup_count)) < 0) {
+ l = InterlockedIncrement(&_startup_count) - 1;
+ }
+
+ if (l >= 0) {
+ return WSACleanup();
+ }
+ return -1;
+}
diff --git a/third_party/heimdal/lib/roken/stdbool.hin b/third_party/heimdal/lib/roken/stdbool.hin
new file mode 100644
index 0000000..cdaee5b
--- /dev/null
+++ b/third_party/heimdal/lib/roken/stdbool.hin
@@ -0,0 +1,13 @@
+#ifndef _STDBOOL_H
+#define _STDBOOL_H
+
+#ifndef __GNUC__
+typedef int _Bool;
+#endif
+
+#define bool _Bool
+#define true 1
+#define false 0
+#define __bool_true_false_are_defined 1
+
+#endif /* _STDBOOL_H */
diff --git a/third_party/heimdal/lib/roken/stdint.hin b/third_party/heimdal/lib/roken/stdint.hin
new file mode 100644
index 0000000..e552d9d
--- /dev/null
+++ b/third_party/heimdal/lib/roken/stdint.hin
@@ -0,0 +1,43 @@
+#ifndef _STDINT_H
+#define _STDINT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef short int int16_t;
+typedef unsigned short int uint16_t;
+typedef int int32_t;
+typedef unsigned int uint32_t;
+#ifdef _MSC_VER
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#else
+typedef long long int64_t;
+typedef unsigned long long uint64_t;
+#endif
+
+#ifdef _MSC_VER
+#include <intsafe.h>
+#else
+#define INT8_MAX 0x7F
+#define INT8_MIN (-INT8_MAX - 1)
+#define UINT8_MAX 0xFF
+#define INT16_MAX 0x7FFF
+#define INT16_MIN (-INT16_MAX - 1)
+#define UINT16_MAX 0xFFFF
+#define INT32_MAX 0x7FFFFFFF
+#define INT32_MIN (-INT32_MIN - 1)
+#define UINT32_MAX 0xFFFFFFFF
+#define INT64_MAX 0x7FFFFFFFFFFFFFFFLL
+#define INT64_MIN (-INT64_MAX - 1)
+#define UINT64_MAX 0xFFFFFFFFFFFFFFFFLL
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _STDINT_H */
diff --git a/third_party/heimdal/lib/roken/strcasecmp.c b/third_party/heimdal/lib/roken/strcasecmp.c
new file mode 100644
index 0000000..00a0a8e
--- /dev/null
+++ b/third_party/heimdal/lib/roken/strcasecmp.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1998 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <string.h>
+#include <ctype.h>
+#include <stddef.h>
+#include "roken.h"
+
+#ifndef HAVE_STRCASECMP
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+strcasecmp(const char *s1, const char *s2)
+{
+ while(toupper((unsigned char)*s1) == toupper((unsigned char)*s2)) {
+ if(*s1 == '\0')
+ return 0;
+ s1++;
+ s2++;
+ }
+ return toupper((unsigned char)*s1) - toupper((unsigned char)*s2);
+}
+
+#endif
diff --git a/third_party/heimdal/lib/roken/strcollect.c b/third_party/heimdal/lib/roken/strcollect.c
new file mode 100644
index 0000000..0afc3f0
--- /dev/null
+++ b/third_party/heimdal/lib/roken/strcollect.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 1998, 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "roken.h"
+
+enum { initial = 10, increment = 5 };
+
+static char **
+sub (char **argv, int i, int argc, va_list *ap)
+{
+ do {
+ if(i == argc) {
+ /* realloc argv */
+ char **tmp = realloc(argv, (argc + increment) * sizeof(*argv));
+ if(tmp == NULL) {
+ free(argv);
+ errno = ENOMEM;
+ return NULL;
+ }
+ argv = tmp;
+ argc += increment;
+ }
+ argv[i++] = va_arg(*ap, char*);
+ } while(argv[i - 1] != NULL);
+ return argv;
+}
+
+/*
+ * return a malloced vector of pointers to the strings in `ap'
+ * terminated by NULL.
+ */
+
+ROKEN_LIB_FUNCTION char ** ROKEN_LIB_CALL
+vstrcollect(va_list *ap)
+{
+ return sub (NULL, 0, 0, ap);
+}
+
+/*
+ *
+ */
+
+ROKEN_LIB_FUNCTION char ** ROKEN_LIB_CALL
+strcollect(char *first, ...)
+{
+ va_list ap;
+ char **ret = malloc (initial * sizeof(char *));
+
+ if (ret == NULL)
+ return ret;
+
+ ret[0] = first;
+ va_start(ap, first);
+ ret = sub (ret, 1, initial, &ap);
+ va_end(ap);
+ return ret;
+}
diff --git a/third_party/heimdal/lib/roken/strdup.c b/third_party/heimdal/lib/roken/strdup.c
new file mode 100644
index 0000000..ce00456
--- /dev/null
+++ b/third_party/heimdal/lib/roken/strdup.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef HAVE_STRDUP
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+strdup(const char *old)
+{
+ char *t = malloc(strlen(old)+1);
+ if (t != 0)
+ strcpy(t, old);
+ return t;
+}
+#endif
diff --git a/third_party/heimdal/lib/roken/strerror.c b/third_party/heimdal/lib/roken/strerror.c
new file mode 100644
index 0000000..93afee0
--- /dev/null
+++ b/third_party/heimdal/lib/roken/strerror.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+extern int sys_nerr;
+extern const char *const sys_errlist[];
+
+ROKEN_LIB_FUNCTION char* ROKEN_LIB_CALL
+strerror(int eno)
+{
+ static char emsg[1024];
+
+ if(eno < 0 || eno >= sys_nerr)
+ snprintf(emsg, sizeof(emsg), "Error %d occurred.", eno);
+ else
+ snprintf(emsg, sizeof(emsg), "%s", sys_errlist[eno]);
+
+ return emsg;
+}
diff --git a/third_party/heimdal/lib/roken/strerror_r.c b/third_party/heimdal/lib/roken/strerror_r.c
new file mode 100644
index 0000000..85271ec
--- /dev/null
+++ b/third_party/heimdal/lib/roken/strerror_r.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#if (!defined(HAVE_STRERROR_R) && !defined(strerror_r)) || (!defined(STRERROR_R_PROTO_COMPATIBLE) && defined(HAVE_STRERROR_R))
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include "roken.h"
+
+#ifdef _MSC_VER
+
+int ROKEN_LIB_FUNCTION
+rk_strerror_r(int eno, char * strerrbuf, size_t buflen)
+{
+ errno_t err;
+
+ err = strerror_s(strerrbuf, buflen, eno);
+ if (err != 0) {
+ int code;
+ code = sprintf_s(strerrbuf, buflen, "Error % occurred.", eno);
+ err = ((code != 0)? errno : 0);
+ }
+
+ return err;
+}
+
+#else /* _MSC_VER */
+
+int ROKEN_LIB_FUNCTION
+rk_strerror_r(int eno, char *strerrbuf, size_t buflen)
+{
+ /* Assume is the linux broken strerror_r (returns the a buffer (char *) if the input buffer wasn't use */
+#ifdef HAVE_STRERROR_R
+ const char *str;
+ str = strerror_r(eno, strerrbuf, buflen);
+ if (str != strerrbuf)
+ if (strlcpy(strerrbuf, str, buflen) >= buflen)
+ return ERANGE;
+ return 0;
+#else
+ int ret;
+ ret = strlcpy(strerrbuf, strerror(eno), buflen);
+ if (ret > buflen)
+ return ERANGE;
+ return 0;
+#endif
+}
+
+#endif /* !_MSC_VER */
+
+#endif
diff --git a/third_party/heimdal/lib/roken/strftime.c b/third_party/heimdal/lib/roken/strftime.c
new file mode 100644
index 0000000..7be9307
--- /dev/null
+++ b/third_party/heimdal/lib/roken/strftime.c
@@ -0,0 +1,402 @@
+/*
+ * Copyright (c) 1999 - 2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 KTH 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 KTH AND ITS 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 KTH OR ITS 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 <config.h>
+#include "roken.h"
+#ifdef TEST_STRPFTIME
+#include "strpftime-test.h"
+#endif
+
+#if defined(_WIN32)
+# define timezone _timezone
+# define tzname _tzname
+#endif
+
+static const char *abb_weekdays[] = {
+ "Sun",
+ "Mon",
+ "Tue",
+ "Wed",
+ "Thu",
+ "Fri",
+ "Sat",
+};
+
+static const char *full_weekdays[] = {
+ "Sunday",
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+};
+
+static const char *abb_month[] = {
+ "Jan",
+ "Feb",
+ "Mar",
+ "Apr",
+ "May",
+ "Jun",
+ "Jul",
+ "Aug",
+ "Sep",
+ "Oct",
+ "Nov",
+ "Dec"
+};
+
+static const char *full_month[] = {
+ "January",
+ "February",
+ "Mars",
+ "April",
+ "May",
+ "June",
+ "July",
+ "August",
+ "September",
+ "October",
+ "November",
+ "December"
+};
+
+static const char *ampm[] = {
+ "AM",
+ "PM"
+};
+
+/*
+ * Convert hour in [0, 24] to [12 1 - 11 12 1 - 11 12]
+ */
+
+static int
+hour_24to12 (int hour)
+{
+ int ret = hour % 12;
+
+ if (ret == 0)
+ ret = 12;
+ return ret;
+}
+
+/*
+ * Return AM or PM for `hour'
+ */
+
+static const char *
+hour_to_ampm (int hour)
+{
+ return ampm[hour / 12];
+}
+
+/*
+ * Return the week number of `tm' (Sunday being the first day of the week)
+ * as [0, 53]
+ */
+
+static int
+week_number_sun (const struct tm *tm)
+{
+ return (tm->tm_yday + 7 - (tm->tm_yday % 7 - tm->tm_wday + 7) % 7) / 7;
+}
+
+/*
+ * Return the week number of `tm' (Monday being the first day of the week)
+ * as [0, 53]
+ */
+
+static int
+week_number_mon (const struct tm *tm)
+{
+ int wday = (tm->tm_wday + 6) % 7;
+
+ return (tm->tm_yday + 7 - (tm->tm_yday % 7 - wday + 7) % 7) / 7;
+}
+
+/*
+ * Return the week number of `tm' (Monday being the first day of the
+ * week) as [01, 53]. Week number one is the one that has four or more
+ * days in that year.
+ */
+
+static int
+week_number_mon4 (const struct tm *tm)
+{
+ int wday = (tm->tm_wday + 6) % 7;
+ int w1day = (wday - tm->tm_yday % 7 + 7) % 7;
+ int ret;
+
+ ret = (tm->tm_yday + w1day) / 7;
+ if (w1day >= 4)
+ --ret;
+ if (ret == -1)
+ ret = 53;
+ else
+ ++ret;
+ return ret;
+}
+
+/*
+ *
+ */
+
+ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL
+strftime (char *buf, size_t maxsize, const char *format,
+ const struct tm *tm)
+{
+ size_t n = 0;
+ int ret;
+
+ while (*format != '\0' && n < maxsize) {
+ if (*format == '%') {
+ ++format;
+ if(*format == 'E' || *format == 'O')
+ ++format;
+ switch (*format) {
+ case 'a' :
+ ret = snprintf (buf, maxsize - n,
+ "%s", abb_weekdays[tm->tm_wday]);
+ break;
+ case 'A' :
+ ret = snprintf (buf, maxsize - n,
+ "%s", full_weekdays[tm->tm_wday]);
+ break;
+ case 'h' :
+ case 'b' :
+ ret = snprintf (buf, maxsize - n,
+ "%s", abb_month[tm->tm_mon]);
+ break;
+ case 'B' :
+ ret = snprintf (buf, maxsize - n,
+ "%s", full_month[tm->tm_mon]);
+ break;
+ case 'c' :
+ ret = snprintf (buf, maxsize - n,
+ "%d:%02d:%02d %02d:%02d:%02d",
+ tm->tm_year,
+ tm->tm_mon + 1,
+ tm->tm_mday,
+ tm->tm_hour,
+ tm->tm_min,
+ tm->tm_sec);
+ break;
+ case 'C' :
+ ret = snprintf (buf, maxsize - n,
+ "%02d", (tm->tm_year + 1900) / 100);
+ break;
+ case 'd' :
+ ret = snprintf (buf, maxsize - n,
+ "%02d", tm->tm_mday);
+ break;
+ case 'D' :
+ ret = snprintf (buf, maxsize - n,
+ "%02d/%02d/%02d",
+ tm->tm_mon + 1,
+ tm->tm_mday,
+ (tm->tm_year + 1900) % 100);
+ break;
+ case 'e' :
+ ret = snprintf (buf, maxsize - n,
+ "%2d", tm->tm_mday);
+ break;
+ case 'F':
+ ret = snprintf (buf, maxsize - n,
+ "%04d-%02d-%02d", tm->tm_year + 1900,
+ tm->tm_mon + 1, tm->tm_mday);
+ break;
+ case 'g':
+ /* last two digits of week-based year */
+ abort();
+ case 'G':
+ /* week-based year */
+ abort();
+ case 'H' :
+ ret = snprintf (buf, maxsize - n,
+ "%02d", tm->tm_hour);
+ break;
+ case 'I' :
+ ret = snprintf (buf, maxsize - n,
+ "%02d",
+ hour_24to12 (tm->tm_hour));
+ break;
+ case 'j' :
+ ret = snprintf (buf, maxsize - n,
+ "%03d", tm->tm_yday + 1);
+ break;
+ case 'k' :
+ ret = snprintf (buf, maxsize - n,
+ "%2d", tm->tm_hour);
+ break;
+ case 'l' :
+ ret = snprintf (buf, maxsize - n,
+ "%2d",
+ hour_24to12 (tm->tm_hour));
+ break;
+ case 'm' :
+ ret = snprintf (buf, maxsize - n,
+ "%02d", tm->tm_mon + 1);
+ break;
+ case 'M' :
+ ret = snprintf (buf, maxsize - n,
+ "%02d", tm->tm_min);
+ break;
+ case 'n' :
+ ret = snprintf (buf, maxsize - n, "\n");
+ break;
+ case 'p' :
+ ret = snprintf (buf, maxsize - n, "%s",
+ hour_to_ampm (tm->tm_hour));
+ break;
+ case 'r' :
+ ret = snprintf (buf, maxsize - n,
+ "%02d:%02d:%02d %s",
+ hour_24to12 (tm->tm_hour),
+ tm->tm_min,
+ tm->tm_sec,
+ hour_to_ampm (tm->tm_hour));
+ break;
+ case 'R' :
+ ret = snprintf (buf, maxsize - n,
+ "%02d:%02d",
+ tm->tm_hour,
+ tm->tm_min);
+ break;
+ case 's' :
+ ret = snprintf (buf, maxsize - n,
+ "%d", (int)mktime(rk_UNCONST(tm)));
+ break;
+ case 'S' :
+ ret = snprintf (buf, maxsize - n,
+ "%02d", tm->tm_sec);
+ break;
+ case 't' :
+ ret = snprintf (buf, maxsize - n, "\t");
+ break;
+ case 'T' :
+ case 'X' :
+ ret = snprintf (buf, maxsize - n,
+ "%02d:%02d:%02d",
+ tm->tm_hour,
+ tm->tm_min,
+ tm->tm_sec);
+ break;
+ case 'u' :
+ ret = snprintf (buf, maxsize - n,
+ "%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday);
+ break;
+ case 'U' :
+ ret = snprintf (buf, maxsize - n,
+ "%02d", week_number_sun (tm));
+ break;
+ case 'V' :
+ ret = snprintf (buf, maxsize - n,
+ "%02d", week_number_mon4 (tm));
+ break;
+ case 'w' :
+ ret = snprintf (buf, maxsize - n,
+ "%d", tm->tm_wday);
+ break;
+ case 'W' :
+ ret = snprintf (buf, maxsize - n,
+ "%02d", week_number_mon (tm));
+ break;
+ case 'x' :
+ ret = snprintf (buf, maxsize - n,
+ "%d:%02d:%02d",
+ tm->tm_year,
+ tm->tm_mon + 1,
+ tm->tm_mday);
+ break;
+ case 'y' :
+ ret = snprintf (buf, maxsize - n,
+ "%02d", (tm->tm_year + 1900) % 100);
+ break;
+ case 'Y' :
+ ret = snprintf (buf, maxsize - n,
+ "%d", tm->tm_year + 1900);
+ break;
+ case 'z':
+ ret = snprintf (buf, maxsize - n,
+ "%ld",
+#if defined(HAVE_STRUCT_TM_TM_GMTOFF)
+ (long)tm->tm_gmtoff
+#elif defined(HAVE_TIMEZONE)
+#ifdef HAVE_ALTZONE
+ tm->tm_isdst ?
+ (long)altzone :
+#endif
+ (long)timezone
+#else
+#error Where in timezone chaos are you?
+#endif
+ );
+ break;
+ case 'Z' :
+ ret = snprintf (buf, maxsize - n,
+ "%s",
+
+#if defined(HAVE_STRUCT_TM_TM_ZONE)
+ tm->tm_zone
+#elif defined(HAVE_TIMEZONE)
+ tzname[tm->tm_isdst]
+#else
+#error what?
+#endif
+ );
+ break;
+ case '\0' :
+ --format;
+ HEIM_FALLTHROUGH;
+ case '%' :
+ ret = snprintf (buf, maxsize - n,
+ "%%");
+ break;
+ default :
+ ret = snprintf (buf, maxsize - n,
+ "%%%c", *format);
+ break;
+ }
+ if (ret < 0 || ret >= (int)(maxsize - n))
+ return 0;
+ n += ret;
+ buf += ret;
+ ++format;
+ } else {
+ *buf++ = *format++;
+ ++n;
+ }
+ }
+ *buf = '\0';
+ return n;
+}
diff --git a/third_party/heimdal/lib/roken/strlcat.c b/third_party/heimdal/lib/roken/strlcat.c
new file mode 100644
index 0000000..e8fe1b7
--- /dev/null
+++ b/third_party/heimdal/lib/roken/strlcat.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1995-2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+#include "roken.h"
+
+#ifndef HAVE_STRLCAT
+
+ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL
+strlcat (char *dst, const char *src, size_t dst_sz)
+{
+ size_t len;
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+ len = strnlen_s(dst, dst_sz);
+#elif defined(HAVE_STRNLEN)
+ len = strnlen(dst, dst_sz);
+#else
+ len = strlen(dst);
+#endif
+
+ if (dst_sz <= len)
+ /* the total size of dst is less than the string it contains;
+ this could be considered bad input, but we might as well
+ handle it */
+ return len + strlen(src);
+
+ return len + strlcpy (dst + len, src, dst_sz - len);
+}
+
+#endif
diff --git a/third_party/heimdal/lib/roken/strlcpy.c b/third_party/heimdal/lib/roken/strlcpy.c
new file mode 100644
index 0000000..0fe2b97
--- /dev/null
+++ b/third_party/heimdal/lib/roken/strlcpy.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 1995-2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+#include "roken.h"
+
+#ifndef HAVE_STRLCPY
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+
+ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL
+strlcpy (char *dst, const char *src, size_t dst_cch)
+{
+ errno_t e;
+
+ if (dst_cch > 0)
+ e = strncpy_s(dst, dst_cch, src, _TRUNCATE);
+
+ return strlen (src);
+}
+
+#else
+
+ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL
+strlcpy (char *dst, const char *src, size_t dst_sz)
+{
+ size_t n;
+
+ for (n = 0; n < dst_sz; n++) {
+ if ((*dst++ = *src++) == '\0')
+ break;
+ }
+
+ if (n < dst_sz)
+ return n;
+ if (n > 0)
+ *(dst - 1) = '\0';
+ return n + strlen (src);
+}
+
+#endif
+
+#endif
diff --git a/third_party/heimdal/lib/roken/strlwr.c b/third_party/heimdal/lib/roken/strlwr.c
new file mode 100644
index 0000000..68bd4ed
--- /dev/null
+++ b/third_party/heimdal/lib/roken/strlwr.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "roken.h"
+
+#ifndef HAVE_STRLWR
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+strlwr(char *str)
+{
+ char *s;
+
+ for(s = str; *s; s++)
+ *s = tolower((unsigned char)*s);
+ return str;
+}
+#endif
diff --git a/third_party/heimdal/lib/roken/strncasecmp.c b/third_party/heimdal/lib/roken/strncasecmp.c
new file mode 100644
index 0000000..f244fb5
--- /dev/null
+++ b/third_party/heimdal/lib/roken/strncasecmp.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1998 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <string.h>
+#include <ctype.h>
+#include <stddef.h>
+
+#ifndef HAVE_STRNCASECMP
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+strncasecmp(const char *s1, const char *s2, size_t n)
+{
+ while(n > 0
+ && toupper((unsigned char)*s1) == toupper((unsigned char)*s2))
+ {
+ if(*s1 == '\0')
+ return 0;
+ s1++;
+ s2++;
+ n--;
+ }
+ if(n == 0)
+ return 0;
+ return toupper((unsigned char)*s1) - toupper((unsigned char)*s2);
+}
+
+#endif
diff --git a/third_party/heimdal/lib/roken/strndup.c b/third_party/heimdal/lib/roken/strndup.c
new file mode 100644
index 0000000..e67c998
--- /dev/null
+++ b/third_party/heimdal/lib/roken/strndup.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1995 - 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "roken.h"
+
+#ifndef HAVE_STRNDUP
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+strndup(const char *old, size_t sz)
+{
+ size_t len = strnlen (old, sz);
+ char *t = malloc(len + 1);
+
+ if (t != NULL) {
+ memcpy (t, old, len);
+ t[len] = '\0';
+ }
+ return t;
+}
+#endif /* HAVE_STRNDUP */
diff --git a/third_party/heimdal/lib/roken/strnlen.c b/third_party/heimdal/lib/roken/strnlen.c
new file mode 100644
index 0000000..f26cd84
--- /dev/null
+++ b/third_party/heimdal/lib/roken/strnlen.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1995 - 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL
+strnlen(const char *s, size_t len)
+{
+ size_t i;
+
+ for(i = 0; i < len && s[i]; i++)
+ ;
+ return i;
+}
diff --git a/third_party/heimdal/lib/roken/strpftime-test.c b/third_party/heimdal/lib/roken/strpftime-test.c
new file mode 100644
index 0000000..8524ff5
--- /dev/null
+++ b/third_party/heimdal/lib/roken/strpftime-test.c
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 KTH 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 KTH AND ITS 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 KTH OR ITS 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 <config.h>
+#include <roken.h>
+#ifdef TEST_STRPFTIME
+#include "strpftime-test.h"
+#endif
+
+enum { MAXSIZE = 26 };
+
+static struct testcase {
+ time_t t;
+ struct {
+ const char *format;
+ const char *result;
+ } vals[MAXSIZE];
+} tests[] = {
+ {0,
+ {
+ {"%A", "Thursday"},
+ {"%a", "Thu"},
+ {"%B", "January"},
+ {"%b", "Jan"},
+ {"%C", "19"},
+ {"%d", "01"},
+ {"%e", " 1"},
+ {"%H", "00"},
+ {"%I", "12"},
+ {"%j", "001"},
+ {"%k", " 0"},
+ {"%l", "12"},
+ {"%M", "00"},
+ {"%m", "01"},
+ {"%n", "\n"},
+ {"%p", "AM"},
+ {"%S", "00"},
+ {"%t", "\t"},
+ {"%w", "4"},
+ {"%Y", "1970"},
+ {"%y", "70"},
+ {"%U", "00"},
+ {"%W", "00"},
+ {"%V", "01"},
+ {"%%", "%"},
+ {NULL, NULL}}
+ },
+ {90000,
+ {
+ {"%A", "Friday"},
+ {"%a", "Fri"},
+ {"%B", "January"},
+ {"%b", "Jan"},
+ {"%C", "19"},
+ {"%d", "02"},
+ {"%e", " 2"},
+ {"%H", "01"},
+ {"%I", "01"},
+ {"%j", "002"},
+ {"%k", " 1"},
+ {"%l", " 1"},
+ {"%M", "00"},
+ {"%m", "01"},
+ {"%n", "\n"},
+ {"%p", "AM"},
+ {"%S", "00"},
+ {"%t", "\t"},
+ {"%w", "5"},
+ {"%Y", "1970"},
+ {"%y", "70"},
+ {"%U", "00"},
+ {"%W", "00"},
+ {"%V", "01"},
+ {"%%", "%"},
+ {NULL, NULL}
+ }
+ },
+ {216306,
+ {
+ {"%A", "Saturday"},
+ {"%a", "Sat"},
+ {"%B", "January"},
+ {"%b", "Jan"},
+ {"%C", "19"},
+ {"%d", "03"},
+ {"%e", " 3"},
+ {"%H", "12"},
+ {"%I", "12"},
+ {"%j", "003"},
+ {"%k", "12"},
+ {"%l", "12"},
+ {"%M", "05"},
+ {"%m", "01"},
+ {"%n", "\n"},
+ {"%p", "PM"},
+ {"%S", "06"},
+ {"%t", "\t"},
+ {"%w", "6"},
+ {"%Y", "1970"},
+ {"%y", "70"},
+ {"%U", "00"},
+ {"%W", "00"},
+ {"%V", "01"},
+ {"%%", "%"},
+ {NULL, NULL}
+ }
+ },
+ {259200,
+ {
+ {"%A", "Sunday"},
+ {"%a", "Sun"},
+ {"%B", "January"},
+ {"%b", "Jan"},
+ {"%C", "19"},
+ {"%d", "04"},
+ {"%e", " 4"},
+ {"%H", "00"},
+ {"%I", "12"},
+ {"%j", "004"},
+ {"%k", " 0"},
+ {"%l", "12"},
+ {"%M", "00"},
+ {"%m", "01"},
+ {"%n", "\n"},
+ {"%p", "AM"},
+ {"%S", "00"},
+ {"%t", "\t"},
+ {"%w", "0"},
+ {"%Y", "1970"},
+ {"%y", "70"},
+ {"%U", "01"},
+ {"%W", "00"},
+ {"%V", "01"},
+ {"%%", "%"},
+ {NULL, NULL}
+ }
+ },
+ {915148800,
+ {
+ {"%A", "Friday"},
+ {"%a", "Fri"},
+ {"%B", "January"},
+ {"%b", "Jan"},
+ {"%C", "19"},
+ {"%d", "01"},
+ {"%e", " 1"},
+ {"%H", "00"},
+ {"%I", "12"},
+ {"%j", "001"},
+ {"%k", " 0"},
+ {"%l", "12"},
+ {"%M", "00"},
+ {"%m", "01"},
+ {"%n", "\n"},
+ {"%p", "AM"},
+ {"%S", "00"},
+ {"%t", "\t"},
+ {"%w", "5"},
+ {"%Y", "1999"},
+ {"%y", "99"},
+ {"%U", "00"},
+ {"%W", "00"},
+ {"%V", "53"},
+ {"%%", "%"},
+ {NULL, NULL}}
+ },
+ {942161105,
+ {
+
+ {"%A", "Tuesday"},
+ {"%a", "Tue"},
+ {"%B", "November"},
+ {"%b", "Nov"},
+ {"%C", "19"},
+ {"%d", "09"},
+ {"%e", " 9"},
+ {"%H", "15"},
+ {"%I", "03"},
+ {"%j", "313"},
+ {"%k", "15"},
+ {"%l", " 3"},
+ {"%M", "25"},
+ {"%m", "11"},
+ {"%n", "\n"},
+ {"%p", "PM"},
+ {"%S", "05"},
+ {"%t", "\t"},
+ {"%w", "2"},
+ {"%Y", "1999"},
+ {"%y", "99"},
+ {"%U", "45"},
+ {"%W", "45"},
+ {"%V", "45"},
+ {"%%", "%"},
+ {NULL, NULL}
+ }
+ }
+};
+
+int
+main(int argc, char **argv)
+{
+ int i, j;
+ int ret = 0;
+
+ for (i = 0; i < sizeof(tests)/sizeof(tests[0]); ++i) {
+ struct tm *tm;
+
+ tm = gmtime (&tests[i].t);
+
+ for (j = 0; tests[i].vals[j].format != NULL; ++j) {
+ char buf[128];
+ size_t len;
+ struct tm tm2;
+ char *ptr;
+
+ len = strftime (buf, sizeof(buf), tests[i].vals[j].format, tm);
+ if (len != strlen (buf)) {
+ printf ("length of strftime(\"%s\") = %lu (\"%s\")\n",
+ tests[i].vals[j].format, (unsigned long)len,
+ buf);
+ ++ret;
+ continue;
+ }
+ if (strcmp (buf, tests[i].vals[j].result) != 0) {
+ printf ("result of strftime(\"%s\") = \"%s\" != \"%s\"\n",
+ tests[i].vals[j].format, buf,
+ tests[i].vals[j].result);
+ ++ret;
+ continue;
+ }
+ memset (&tm2, 0, sizeof(tm2));
+ ptr = strptime (tests[i].vals[j].result,
+ tests[i].vals[j].format,
+ &tm2);
+ if (ptr == NULL || *ptr != '\0') {
+ printf ("bad return value from strptime("
+ "\"%s\", \"%s\")\n",
+ tests[i].vals[j].result,
+ tests[i].vals[j].format);
+ ++ret;
+ }
+ strftime (buf, sizeof(buf), tests[i].vals[j].format, &tm2);
+ if (strcmp (buf, tests[i].vals[j].result) != 0) {
+ printf ("reverse of \"%s\" failed: \"%s\" vs \"%s\"\n",
+ tests[i].vals[j].format,
+ buf, tests[i].vals[j].result);
+ ++ret;
+ }
+ }
+ }
+ {
+ struct tm tm;
+ memset(&tm, 0, sizeof(tm));
+ strptime ("200505", "%Y%m", &tm);
+ if (tm.tm_year != 105)
+ ++ret;
+ if (tm.tm_mon != 4)
+ ++ret;
+ }
+ if (ret) {
+ printf ("%d errors\n", ret);
+ return 1;
+ } else
+ return 0;
+}
diff --git a/third_party/heimdal/lib/roken/strpftime-test.h b/third_party/heimdal/lib/roken/strpftime-test.h
new file mode 100644
index 0000000..157c776
--- /dev/null
+++ b/third_party/heimdal/lib/roken/strpftime-test.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 KTH 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 KTH AND ITS 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 KTH OR ITS 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.
+ */
+
+/* $Id: snprintf-test.h 10377 2001-07-19 18:39:14Z assar $ */
+
+#ifndef __STRFTIME_TEST_H__
+#define __STRFTIME_TEST_H__
+
+/*
+ * we cannot use the real names of the functions when testing, since
+ * they might have different prototypes as the system functions, hence
+ * these evil hacks
+ */
+
+#ifdef strftime
+#undef strftime
+#endif
+#define strftime test_strftime
+#ifdef strptime
+#undef strptime
+#endif
+#define strptime test_strptime
+
+ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL
+strftime (char *buf, size_t maxsize, const char *format,
+ const struct tm *tm);
+
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+strptime (const char *buf, const char *format, struct tm *timeptr);
+
+#endif /* __STRFTIME_TEST_H__ */
diff --git a/third_party/heimdal/lib/roken/strpool.c b/third_party/heimdal/lib/roken/strpool.c
new file mode 100644
index 0000000..032bae1
--- /dev/null
+++ b/third_party/heimdal/lib/roken/strpool.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include "roken.h"
+
+struct rk_strpool {
+ char *str;
+ size_t len; /* strlen() of str */
+ size_t sz; /* Allocated size */
+};
+
+/*
+ *
+ */
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rk_strpoolfree(struct rk_strpool *p)
+{
+ if (p && p->str) {
+ free(p->str);
+ p->str = NULL;
+ }
+ free(p);
+}
+
+/*
+ *
+ */
+
+ROKEN_LIB_FUNCTION struct rk_strpool * ROKEN_LIB_CALL
+rk_strpoolprintf(struct rk_strpool *p, const char *fmt, ...)
+{
+ va_list ap;
+ char *str;
+ int len;
+
+ va_start(ap, fmt);
+ len = vasprintf(&str, fmt, ap);
+ va_end(ap);
+ if (str == NULL)
+ return rk_strpoolfree(p), NULL;
+
+ if (p == NULL) {
+ if ((p = malloc(sizeof(*p))) == NULL)
+ return free(str), NULL;
+ p->str = str;
+ p->len = p->sz = len;
+ return p;
+ } /* else grow the buffer and append `str', but don't grow too fast */
+
+ if (len + p->len + 1 > p->sz) {
+ size_t sz = p->len + len + 9 + (p->sz >> 2);
+ char *str2;
+
+ if ((str2 = realloc(p->str, sz)) == NULL)
+ return rk_strpoolfree(p), NULL;
+ p->str = str2;
+ p->sz = sz;
+ }
+ memcpy(p->str + p->len, str, len + 1);
+ p->len += len;
+ free(str);
+ return p;
+}
+
+/*
+ *
+ */
+
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+rk_strpoolcollect(struct rk_strpool *p)
+{
+ char *str;
+ if (p == NULL)
+ return strdup("");
+ str = p->str;
+ p->str = NULL;
+ free(p);
+ return str;
+}
diff --git a/third_party/heimdal/lib/roken/strptime.c b/third_party/heimdal/lib/roken/strptime.c
new file mode 100644
index 0000000..b9345c0
--- /dev/null
+++ b/third_party/heimdal/lib/roken/strptime.c
@@ -0,0 +1,449 @@
+/*
+ * Copyright (c) 1999, 2003, 2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 KTH 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 KTH AND ITS 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 KTH OR ITS 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 <config.h>
+#include "roken.h"
+#ifdef TEST_STRPFTIME
+#include "strpftime-test.h"
+#endif
+#include <ctype.h>
+
+static const char *abb_weekdays[] = {
+ "Sun",
+ "Mon",
+ "Tue",
+ "Wed",
+ "Thu",
+ "Fri",
+ "Sat",
+ NULL
+};
+
+static const char *full_weekdays[] = {
+ "Sunday",
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ NULL
+};
+
+static const char *abb_month[] = {
+ "Jan",
+ "Feb",
+ "Mar",
+ "Apr",
+ "May",
+ "Jun",
+ "Jul",
+ "Aug",
+ "Sep",
+ "Oct",
+ "Nov",
+ "Dec",
+ NULL
+};
+
+static const char *full_month[] = {
+ "January",
+ "February",
+ "March",
+ "April",
+ "May",
+ "June",
+ "July",
+ "August",
+ "September",
+ "October",
+ "November",
+ "December",
+ NULL,
+};
+
+static const char *ampm[] = {
+ "am",
+ "pm",
+ NULL
+};
+
+/*
+ * Try to match `*buf' to one of the strings in `strs'. Return the
+ * index of the matching string (or -1 if none). Also advance buf.
+ */
+
+static int
+match_string (const char **buf, const char **strs)
+{
+ int i = 0;
+
+ for (i = 0; strs[i] != NULL; ++i) {
+ int len = strlen (strs[i]);
+
+ if (strncasecmp (*buf, strs[i], len) == 0) {
+ *buf += len;
+ return i;
+ }
+ }
+ return -1;
+}
+
+/*
+ * Try to match `*buf' to at the most `n' characters and return the
+ * resulting number in `num'. Returns 0 or an error. Also advance
+ * buf.
+ */
+
+static int
+parse_number (const char **buf, int n, int *num)
+{
+ char *s, *str;
+ int i;
+
+ str = malloc(n + 1);
+ if (str == NULL)
+ return -1;
+
+ /* skip whitespace */
+ for (; **buf != '\0' && isspace((unsigned char)(**buf)); (*buf)++)
+ ;
+
+ /* parse at least n characters */
+ for (i = 0; **buf != '\0' && i < n && isdigit((unsigned char)(**buf)); i++, (*buf)++)
+ str[i] = **buf;
+ str[i] = '\0';
+
+ *num = strtol (str, &s, 10);
+ free(str);
+ if (s == str)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * tm_year is relative this year
+ */
+
+const int tm_year_base = 1900;
+
+/*
+ * Return TRUE iff `year' was a leap year.
+ */
+
+static int
+is_leap_year (int year)
+{
+ return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0);
+}
+
+/*
+ * Return the weekday [0,6] (0 = Sunday) of the first day of `year'
+ */
+
+static int
+first_day (int year)
+{
+ int ret = 4;
+
+ for (; year > 1970; --year)
+ ret = (ret + (is_leap_year (year) ? 366 : 365)) % 7;
+ return ret;
+}
+
+/*
+ * Set `timeptr' given `wnum' (week number [0, 53])
+ */
+
+static void
+set_week_number_sun (struct tm *timeptr, int wnum)
+{
+ int fday = first_day (timeptr->tm_year + tm_year_base);
+
+ timeptr->tm_yday = wnum * 7 + timeptr->tm_wday - fday;
+ if (timeptr->tm_yday < 0) {
+ timeptr->tm_wday = fday;
+ timeptr->tm_yday = 0;
+ }
+}
+
+/*
+ * Set `timeptr' given `wnum' (week number [0, 53])
+ */
+
+static void
+set_week_number_mon (struct tm *timeptr, int wnum)
+{
+ int fday = (first_day (timeptr->tm_year + tm_year_base) + 6) % 7;
+
+ timeptr->tm_yday = wnum * 7 + (timeptr->tm_wday + 6) % 7 - fday;
+ if (timeptr->tm_yday < 0) {
+ timeptr->tm_wday = (fday + 1) % 7;
+ timeptr->tm_yday = 0;
+ }
+}
+
+/*
+ * Set `timeptr' given `wnum' (week number [0, 53])
+ */
+
+static void
+set_week_number_mon4 (struct tm *timeptr, int wnum)
+{
+ int fday = (first_day (timeptr->tm_year + tm_year_base) + 6) % 7;
+ int offset = 0;
+
+ if (fday < 4)
+ offset += 7;
+
+ timeptr->tm_yday = offset + (wnum - 1) * 7 + timeptr->tm_wday - fday;
+ if (timeptr->tm_yday < 0) {
+ timeptr->tm_wday = fday;
+ timeptr->tm_yday = 0;
+ }
+}
+
+/*
+ *
+ */
+
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+strptime (const char *buf, const char *format, struct tm *timeptr)
+{
+ char c;
+
+ for (; (c = *format) != '\0'; ++format) {
+ char *s;
+ int ret;
+
+ if (isspace ((unsigned char)c)) {
+ while (isspace ((unsigned char)*buf))
+ ++buf;
+ } else if (c == '%' && format[1] != '\0') {
+ c = *++format;
+ if (c == 'E' || c == 'O')
+ c = *++format;
+ switch (c) {
+ case 'A' :
+ ret = match_string (&buf, full_weekdays);
+ if (ret < 0)
+ return NULL;
+ timeptr->tm_wday = ret;
+ break;
+ case 'a' :
+ ret = match_string (&buf, abb_weekdays);
+ if (ret < 0)
+ return NULL;
+ timeptr->tm_wday = ret;
+ break;
+ case 'B' :
+ ret = match_string (&buf, full_month);
+ if (ret < 0)
+ return NULL;
+ timeptr->tm_mon = ret;
+ break;
+ case 'b' :
+ case 'h' :
+ ret = match_string (&buf, abb_month);
+ if (ret < 0)
+ return NULL;
+ timeptr->tm_mon = ret;
+ break;
+ case 'C' :
+ if (parse_number(&buf, 2, &ret))
+ return NULL;
+ timeptr->tm_year = (ret * 100) - tm_year_base;
+ break;
+ case 'c' :
+ abort ();
+ case 'D' : /* %m/%d/%y */
+ s = strptime (buf, "%m/%d/%y", timeptr);
+ if (s == NULL)
+ return NULL;
+ buf = s;
+ break;
+ case 'd' :
+ case 'e' :
+ if (parse_number(&buf, 2, &ret))
+ return NULL;
+ timeptr->tm_mday = ret;
+ break;
+ case 'H' :
+ case 'k' :
+ if (parse_number(&buf, 2, &ret))
+ return NULL;
+ timeptr->tm_hour = ret;
+ break;
+ case 'I' :
+ case 'l' :
+ if (parse_number(&buf, 2, &ret))
+ return NULL;
+ if (ret == 12)
+ timeptr->tm_hour = 0;
+ else
+ timeptr->tm_hour = ret;
+ break;
+ case 'j' :
+ if (parse_number(&buf, 3, &ret))
+ return NULL;
+ if (ret == 0)
+ return NULL;
+ timeptr->tm_yday = ret - 1;
+ break;
+ case 'm' :
+ if (parse_number(&buf, 2, &ret))
+ return NULL;
+ if (ret == 0)
+ return NULL;
+ timeptr->tm_mon = ret - 1;
+ break;
+ case 'M' :
+ if (parse_number(&buf, 2, &ret))
+ return NULL;
+ timeptr->tm_min = ret;
+ break;
+ case 'n' :
+ while (isspace ((unsigned char)*buf))
+ buf++;
+ break;
+ case 'p' :
+ ret = match_string (&buf, ampm);
+ if (ret < 0)
+ return NULL;
+ if (timeptr->tm_hour == 0) {
+ if (ret == 1)
+ timeptr->tm_hour = 12;
+ } else
+ timeptr->tm_hour += 12;
+ break;
+ case 'r' : /* %I:%M:%S %p */
+ s = strptime (buf, "%I:%M:%S %p", timeptr);
+ if (s == NULL)
+ return NULL;
+ buf = s;
+ break;
+ case 'R' : /* %H:%M */
+ s = strptime (buf, "%H:%M", timeptr);
+ if (s == NULL)
+ return NULL;
+ buf = s;
+ break;
+ case 'S' :
+ if (parse_number(&buf, 2, &ret))
+ return NULL;
+ timeptr->tm_sec = ret;
+ break;
+ case 't' :
+ while (isspace ((unsigned char)*buf))
+ buf++;
+ break;
+ case 'T' : /* %H:%M:%S */
+ case 'X' :
+ s = strptime (buf, "%H:%M:%S", timeptr);
+ if (s == NULL)
+ return NULL;
+ buf = s;
+ break;
+ case 'u' :
+ if (parse_number(&buf, 1, &ret))
+ return NULL;
+ if (ret <= 0)
+ return NULL;
+ timeptr->tm_wday = ret - 1;
+ break;
+ case 'w' :
+ if (parse_number(&buf, 1, &ret))
+ return NULL;
+ timeptr->tm_wday = ret;
+ break;
+ case 'U' :
+ if (parse_number(&buf, 2, &ret))
+ return NULL;
+ set_week_number_sun (timeptr, ret);
+ break;
+ case 'V' :
+ if (parse_number(&buf, 2, &ret))
+ return NULL;
+ set_week_number_mon4 (timeptr, ret);
+ break;
+ case 'W' :
+ if (parse_number(&buf, 2, &ret))
+ return NULL;
+ set_week_number_mon (timeptr, ret);
+ break;
+ case 'x' :
+ s = strptime (buf, "%Y:%m:%d", timeptr);
+ if (s == NULL)
+ return NULL;
+ buf = s;
+ break;
+ case 'y' :
+ if (parse_number(&buf, 2, &ret))
+ return NULL;
+ if (ret < 70)
+ timeptr->tm_year = 100 + ret;
+ else
+ timeptr->tm_year = ret;
+ break;
+ case 'Y' :
+ if (parse_number(&buf, 4, &ret))
+ return NULL;
+ timeptr->tm_year = ret - tm_year_base;
+ break;
+ case 'Z' :
+ abort ();
+ case '\0' :
+ --format;
+ HEIM_FALLTHROUGH;
+ case '%' :
+ if (*buf == '%')
+ ++buf;
+ else
+ return NULL;
+ break;
+ default :
+ if (*buf == '%' || *++buf == c)
+ ++buf;
+ else
+ return NULL;
+ break;
+ }
+ } else {
+ if (*buf == c)
+ ++buf;
+ else
+ return NULL;
+ }
+ }
+ return rk_UNCONST(buf);
+}
diff --git a/third_party/heimdal/lib/roken/strsep.c b/third_party/heimdal/lib/roken/strsep.c
new file mode 100644
index 0000000..76b447c
--- /dev/null
+++ b/third_party/heimdal/lib/roken/strsep.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <string.h>
+
+#include "roken.h"
+
+#ifndef HAVE_STRSEP
+
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+strsep(char **str, const char *delim)
+{
+ char *save = *str;
+ if(*str == NULL)
+ return NULL;
+ *str = *str + strcspn(*str, delim);
+ if(**str == 0)
+ *str = NULL;
+ else{
+ **str = 0;
+ (*str)++;
+ }
+ return save;
+}
+
+#endif
diff --git a/third_party/heimdal/lib/roken/strsep_copy.c b/third_party/heimdal/lib/roken/strsep_copy.c
new file mode 100644
index 0000000..1228f1a
--- /dev/null
+++ b/third_party/heimdal/lib/roken/strsep_copy.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2000, 2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <string.h>
+
+#include "roken.h"
+
+#ifndef HAVE_STRSEP_COPY
+
+/* strsep, but with const stringp, so return string in buf */
+
+ROKEN_LIB_FUNCTION ssize_t ROKEN_LIB_CALL
+strsep_copy(const char **stringp, const char *delim, char *buf, size_t len)
+{
+ const char *save = *stringp;
+ size_t l;
+ if(save == NULL)
+ return -1;
+ *stringp = *stringp + strcspn(*stringp, delim);
+ l = min(len, (size_t)(*stringp - save));
+ if(len > 0) {
+ memcpy(buf, save, l);
+ buf[l] = '\0';
+ }
+
+ l = *stringp - save;
+ if(**stringp == '\0')
+ *stringp = NULL;
+ else
+ (*stringp)++;
+ return l;
+}
+
+#endif
diff --git a/third_party/heimdal/lib/roken/strtok_r.c b/third_party/heimdal/lib/roken/strtok_r.c
new file mode 100644
index 0000000..16a9daf
--- /dev/null
+++ b/third_party/heimdal/lib/roken/strtok_r.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <string.h>
+
+#include "roken.h"
+
+#ifndef HAVE_STRTOK_R
+
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+strtok_r(char *s1, const char *s2, char **lasts)
+{
+ char *ret;
+
+ if (s1 == NULL)
+ s1 = *lasts;
+ while(*s1 && strchr(s2, *s1))
+ ++s1;
+ if(*s1 == '\0')
+ return NULL;
+ ret = s1;
+ while(*s1 && !strchr(s2, *s1))
+ ++s1;
+ if(*s1)
+ *s1++ = '\0';
+ *lasts = s1;
+ return ret;
+}
+
+#endif /* HAVE_STRTOK_R */
diff --git a/third_party/heimdal/lib/roken/strtoll.c b/third_party/heimdal/lib/roken/strtoll.c
new file mode 100644
index 0000000..96c1b25
--- /dev/null
+++ b/third_party/heimdal/lib/roken/strtoll.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * 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.
+ * 4. 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 <config.h>
+
+#include <string.h>
+
+#include "roken.h"
+
+#ifndef HAVE_STRTOLL
+
+/* #include <sys/cdefs.h> */
+
+#include <limits.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+/*
+ * Convert a string to a long long integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+ROKEN_LIB_FUNCTION long long ROKEN_LIB_CALL
+strtoll(const char * nptr, char ** endptr, int base)
+{
+ const char *s;
+ unsigned long long acc;
+ long long ret = 0;
+ char c;
+ unsigned long long cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * Skip white space and pick up leading +/- sign if any.
+ * If base is 0, allow 0x for hex and 0 for octal, else
+ * assume decimal; if base is already 16, allow 0x.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace((unsigned char)c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X') &&
+ ((s[1] >= '0' && s[1] <= '9') ||
+ (s[1] >= 'A' && s[1] <= 'F') ||
+ (s[1] >= 'a' && s[1] <= 'f'))) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ acc = any = 0;
+ if (base < 2 || base > 36)
+ goto noconv;
+
+ /*
+ * Compute the cutoff value between legal numbers and illegal
+ * numbers. That is the largest legal value, divided by the
+ * base. An input number that is greater than this value, if
+ * followed by a legal input character, is too big. One that
+ * is equal to this value may be valid or not; the limit
+ * between valid and invalid numbers is then based on the last
+ * digit. For instance, if the range for quads is
+ * [-9223372036854775808..9223372036854775807] and the input base
+ * is 10, cutoff will be set to 922337203685477580 and cutlim to
+ * either 7 (neg==0) or 8 (neg==1), meaning that if we have
+ * accumulated a value > 922337203685477580, or equal but the
+ * next digit is > 7 (or 8), the number is too big, and we will
+ * return a range error.
+ *
+ * Set 'any' if any `digits' consumed; make it negative to indicate
+ * overflow.
+ */
+ cutoff = neg ? (unsigned long long)-(LLONG_MIN + LLONG_MAX) + LLONG_MAX
+ : LLONG_MAX;
+ cutlim = cutoff % base;
+ cutoff /= base;
+ for ( ; ; c = *s++) {
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'A' && c <= 'Z')
+ c -= 'A' - 10;
+ else if (c >= 'a' && c <= 'z')
+ c -= 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ ret = neg ? LLONG_MIN : LLONG_MAX;
+ errno = ERANGE;
+ } else if (!any) {
+noconv:
+ errno = EINVAL;
+ } else if (neg) {
+ ret = -(long long)acc;
+ } else {
+ ret = acc;
+ }
+ if (endptr != NULL)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return ret;
+}
+#endif /* !HAVE_STRTOLL */
diff --git a/third_party/heimdal/lib/roken/strtoull.c b/third_party/heimdal/lib/roken/strtoull.c
new file mode 100644
index 0000000..0516e18
--- /dev/null
+++ b/third_party/heimdal/lib/roken/strtoull.c
@@ -0,0 +1,129 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * 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.
+ * 4. 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 <config.h>
+
+#include <string.h>
+
+#include "roken.h"
+
+#ifndef HAVE_STRTOULL
+
+/* #include <sys/cdefs.h> */
+
+#include <limits.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+/*
+ * Convert a string to an unsigned long long integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+ROKEN_LIB_FUNCTION unsigned long long ROKEN_LIB_CALL
+strtoull(const char * nptr, char ** endptr, int base)
+{
+ const char *s;
+ unsigned long long acc;
+ char c;
+ unsigned long long cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * See strtoq for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace((unsigned char)c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X') &&
+ ((s[1] >= '0' && s[1] <= '9') ||
+ (s[1] >= 'A' && s[1] <= 'F') ||
+ (s[1] >= 'a' && s[1] <= 'f'))) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ acc = any = 0;
+ if (base < 2 || base > 36)
+ goto noconv;
+
+ cutoff = ULLONG_MAX / base;
+ cutlim = ULLONG_MAX % base;
+ for ( ; ; c = *s++) {
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'A' && c <= 'Z')
+ c -= 'A' - 10;
+ else if (c >= 'a' && c <= 'z')
+ c -= 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = ULLONG_MAX;
+ errno = ERANGE;
+ } else if (!any) {
+noconv:
+ errno = EINVAL;
+ } else if (neg)
+ acc = -(long long)acc;
+ if (endptr != NULL)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
+#endif /* !HAVE_STRTOULL */
diff --git a/third_party/heimdal/lib/roken/strupr.c b/third_party/heimdal/lib/roken/strupr.c
new file mode 100644
index 0000000..fdff7f4
--- /dev/null
+++ b/third_party/heimdal/lib/roken/strupr.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "roken.h"
+
+#ifndef HAVE_STRUPR
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+strupr(char *str)
+{
+ char *s;
+
+ for(s = str; *s; s++)
+ *s = toupper((unsigned char)*s);
+ return str;
+}
+#endif
diff --git a/third_party/heimdal/lib/roken/swab.c b/third_party/heimdal/lib/roken/swab.c
new file mode 100644
index 0000000..9b8d1d1
--- /dev/null
+++ b/third_party/heimdal/lib/roken/swab.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+#include "roken.h"
+
+#ifndef HAVE_SWAB
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+swab (char *from, char *to, int nbytes)
+{
+ while(nbytes >= 2) {
+ *(to + 1) = *from;
+ *to = *(from + 1);
+ to += 2;
+ from += 2;
+ nbytes -= 2;
+ }
+}
+#endif
diff --git a/third_party/heimdal/lib/roken/syslog.hin b/third_party/heimdal/lib/roken/syslog.hin
new file mode 100644
index 0000000..f68dd11
--- /dev/null
+++ b/third_party/heimdal/lib/roken/syslog.hin
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 1982, 1986, 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.
+ * 4. 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.
+ *
+ * @(#)syslog.h 8.1 (Berkeley) 6/2/93
+ */
+
+/***********************************************************************
+ * Copyright (c) 2009, Secure Endpoints Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDER 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.
+ *
+ **********************************************************************/
+
+#ifndef _SYS_SYSLOG_H
+#define _SYS_SYSLOG_H 1
+
+#include <stdarg.h>
+
+/*
+ * priorities/facilities are encoded into a single 32-bit quantity, where the
+ * bottom 3 bits are the priority (0-7) and the top 28 bits are the facility
+ * (0-big number). Both the priorities and the facilities map roughly
+ * one-to-one to strings in the syslogd(8) source code. This mapping is
+ * included in this file.
+ *
+ * priorities (these are ordered)
+ */
+#define LOG_EMERG 0 /* system is unusable */
+#define LOG_ALERT 1 /* action must be taken immediately */
+#define LOG_CRIT 2 /* critical conditions */
+#define LOG_ERR 3 /* error conditions */
+#define LOG_WARNING 4 /* warning conditions */
+#define LOG_NOTICE 5 /* normal but significant condition */
+#define LOG_INFO 6 /* informational */
+#define LOG_DEBUG 7 /* debug-level messages */
+
+#define LOG_PRIMASK 0x07 /* mask to extract priority part (internal) */
+ /* extract priority */
+#define LOG_PRI(p) ((p) & LOG_PRIMASK)
+#define LOG_MAKEPRI(fac, pri) (((fac) << 3) | (pri))
+
+#ifdef SYSLOG_NAMES
+#define INTERNAL_NOPRI 0x10 /* the "no priority" priority */
+ /* mark "facility" */
+#define INTERNAL_MARK LOG_MAKEPRI(LOG_NFACILITIES, 0)
+typedef struct _code {
+ char *c_name;
+ int c_val;
+} CODE;
+
+CODE prioritynames[] =
+ {
+ { "alert", LOG_ALERT },
+ { "crit", LOG_CRIT },
+ { "debug", LOG_DEBUG },
+ { "emerg", LOG_EMERG },
+ { "err", LOG_ERR },
+ { "error", LOG_ERR }, /* DEPRECATED */
+ { "info", LOG_INFO },
+ { "none", INTERNAL_NOPRI }, /* INTERNAL */
+ { "notice", LOG_NOTICE },
+ { "panic", LOG_EMERG }, /* DEPRECATED */
+ { "warn", LOG_WARNING }, /* DEPRECATED */
+ { "warning", LOG_WARNING },
+ { NULL, -1 }
+ };
+#endif
+
+/* facility codes */
+#define LOG_KERN (0<<3) /* kernel messages */
+#define LOG_USER (1<<3) /* random user-level messages */
+#define LOG_MAIL (2<<3) /* mail system */
+#define LOG_DAEMON (3<<3) /* system daemons */
+#define LOG_AUTH (4<<3) /* security/authorization messages */
+#define LOG_SYSLOG (5<<3) /* messages generated internally by syslogd */
+#define LOG_LPR (6<<3) /* line printer subsystem */
+#define LOG_NEWS (7<<3) /* network news subsystem */
+#define LOG_UUCP (8<<3) /* UUCP subsystem */
+#define LOG_CRON (9<<3) /* clock daemon */
+#define LOG_AUTHPRIV (10<<3) /* security/authorization messages (private) */
+#define LOG_FTP (11<<3) /* ftp daemon */
+
+ /* other codes through 15 reserved for system use */
+#define LOG_LOCAL0 (16<<3) /* reserved for local use */
+#define LOG_LOCAL1 (17<<3) /* reserved for local use */
+#define LOG_LOCAL2 (18<<3) /* reserved for local use */
+#define LOG_LOCAL3 (19<<3) /* reserved for local use */
+#define LOG_LOCAL4 (20<<3) /* reserved for local use */
+#define LOG_LOCAL5 (21<<3) /* reserved for local use */
+#define LOG_LOCAL6 (22<<3) /* reserved for local use */
+#define LOG_LOCAL7 (23<<3) /* reserved for local use */
+
+#define LOG_NFACILITIES 24 /* current number of facilities */
+#define LOG_FACMASK 0x03f8 /* mask to extract facility part */
+ /* facility of pri */
+#define LOG_FAC(p) (((p) & LOG_FACMASK) >> 3)
+
+#ifdef SYSLOG_NAMES
+CODE facilitynames[] =
+ {
+ { "auth", LOG_AUTH },
+ { "authpriv", LOG_AUTHPRIV },
+ { "cron", LOG_CRON },
+ { "daemon", LOG_DAEMON },
+ { "ftp", LOG_FTP },
+ { "kern", LOG_KERN },
+ { "lpr", LOG_LPR },
+ { "mail", LOG_MAIL },
+ { "mark", INTERNAL_MARK }, /* INTERNAL */
+ { "news", LOG_NEWS },
+ { "security", LOG_AUTH }, /* DEPRECATED */
+ { "syslog", LOG_SYSLOG },
+ { "user", LOG_USER },
+ { "uucp", LOG_UUCP },
+ { "local0", LOG_LOCAL0 },
+ { "local1", LOG_LOCAL1 },
+ { "local2", LOG_LOCAL2 },
+ { "local3", LOG_LOCAL3 },
+ { "local4", LOG_LOCAL4 },
+ { "local5", LOG_LOCAL5 },
+ { "local6", LOG_LOCAL6 },
+ { "local7", LOG_LOCAL7 },
+ { NULL, -1 }
+ };
+#endif
+
+/*
+ * arguments to setlogmask.
+ */
+#define LOG_MASK(pri) (1 << (pri)) /* mask for one priority */
+#define LOG_UPTO(pri) ((1 << ((pri)+1)) - 1) /* all priorities through pri */
+
+/*
+ * Option flags for openlog.
+ *
+ * LOG_ODELAY no longer does anything.
+ * LOG_NDELAY is the inverse of what it used to be.
+ */
+#define LOG_PID 0x01 /* log the pid with each message */
+#define LOG_CONS 0x02 /* log on the console if errors in sending */
+#define LOG_ODELAY 0x04 /* delay open until first syslog() (default) */
+#define LOG_NDELAY 0x08 /* don't delay open */
+#define LOG_NOWAIT 0x10 /* don't wait for console forks: DEPRECATED */
+#define LOG_PERROR 0x20 /* log to stderr as well */
+
+#define SYSLOG_PORT 514
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Close desriptor used to write to system logger. */
+extern void closelog (void);
+
+/* Open connection to system logger. */
+extern void openlog (char *__ident, int __option, int __facility);
+
+/* Set the log mask level. */
+extern int setlogmask (int __mask);
+
+/* Generate a log message using FMT string and option arguments. */
+extern void syslog (int __pri, char *__fmt, ...);
+
+/* Generate a log message using FMT and using arguments pointed to by AP. */
+extern void vsyslog (int __pri, char *__fmt, va_list __ap);
+
+#ifdef _WIN32
+ /* Windows specific.
+
+ init_syslog() *must* be called before calling any of the above
+ functions. exit_syslog() will be scheduled using atexit().
+ However, it is not an error and encouraged to call
+ exit_syslog() before the application exits.
+
+ During operation, the application is free to call exit_syslog()
+ followed by init_syslog() to re-initialize the library. i.e. if
+ a different syslog host is to be used.
+
+ */
+
+ /* Initializes the syslog library and sets the syslog host. The
+ hostname parameter is of the form "<hostname>[:<port>]". The
+ <port> may be a numeric port or it may be a name of a service.
+ If the <port> is specified using a service name, it will be
+ looked up using getservbyname().
+
+ On failure, the hostname and port will be set to "localhost"
+ and SYSLOG_PORT respectively.
+ */
+ extern void init_syslog(const char * hostname);
+
+ extern void exit_syslog(void);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* syslog.h */
diff --git a/third_party/heimdal/lib/roken/syslogc.c b/third_party/heimdal/lib/roken/syslogc.c
new file mode 100644
index 0000000..f4fb539
--- /dev/null
+++ b/third_party/heimdal/lib/roken/syslogc.c
@@ -0,0 +1,339 @@
+/***********************************************************************
+ * Copyright (c) 2009, Secure Endpoints Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDER 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.
+ *
+ **********************************************************************/
+
+/*
+ * Based on code by Alexander Yaworsky
+ */
+
+#include <config.h>
+
+#include <roken.h>
+
+#define SYSLOG_DGRAM_SIZE 1024
+
+static BOOL syslog_opened = FALSE;
+
+static int syslog_mask = 0xFF;
+static char syslog_ident[ 128 ] = "";
+static int syslog_facility = LOG_USER;
+static char syslog_procid_str[ 20 ];
+
+static SOCKADDR_IN syslog_hostaddr;
+static SOCKET syslog_socket = INVALID_SOCKET;
+static char local_hostname[ MAX_COMPUTERNAME_LENGTH + 1 ];
+
+static char syslog_hostname[ MAX_COMPUTERNAME_LENGTH + 1 ] = "localhost";
+static unsigned short syslog_port = SYSLOG_PORT;
+
+static int datagramm_size;
+
+volatile BOOL initialized = FALSE;
+BOOL wsa_initialized = FALSE;
+CRITICAL_SECTION cs_syslog;
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+init_syslog(const char * hostname)
+{
+ WSADATA wsd;
+ char * service;
+
+ if ( initialized )
+ return;
+
+ if( WSAStartup( MAKEWORD( 2, 2 ), &wsd ) ) {
+ fprintf(stderr, "Can't initialize WinSock\n");
+ /* we let the rest of the initialization code go through,
+ although none of the syslog calls would succeed. */
+ } else {
+ wsa_initialized = TRUE;
+ }
+
+ if (hostname)
+ strcpy_s(syslog_hostname, sizeof(syslog_hostname), hostname);
+ else
+ strcpy_s(syslog_hostname, sizeof(syslog_hostname), "");
+
+ service = strchr(syslog_hostname, ':');
+
+ if (service) {
+ int tp;
+
+ *service++ = '\0';
+
+ if ((tp = atoi(service)) <= 0) {
+ struct servent * se;
+
+ se = getservbyname(service, "udp");
+
+ syslog_port = (se == NULL)? SYSLOG_PORT: se->s_port;
+ } else {
+ syslog_port = (unsigned short) tp;
+ }
+ } else {
+ syslog_port = SYSLOG_PORT;
+ }
+
+ InitializeCriticalSection(&cs_syslog);
+ initialized = TRUE;
+
+ atexit(exit_syslog);
+}
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+exit_syslog(void)
+{
+ if ( !initialized )
+ return;
+
+ closelog();
+
+ if ( wsa_initialized )
+ WSACleanup();
+
+ DeleteCriticalSection(&cs_syslog);
+ initialized = FALSE;
+}
+
+static void init_logger_addr()
+{
+ struct hostent * phe = NULL;
+
+ memset( &syslog_hostaddr, 0, sizeof(SOCKADDR_IN) );
+ syslog_hostaddr.sin_family = AF_INET;
+
+ if (syslog_hostname[0] == '\0')
+ goto use_default;
+
+ phe = gethostbyname( syslog_hostname );
+ if( !phe )
+ goto use_default;
+
+ memcpy( &syslog_hostaddr.sin_addr.s_addr, phe->h_addr, phe->h_length );
+
+ syslog_hostaddr.sin_port = htons( syslog_port );
+ return;
+
+use_default:
+ syslog_hostaddr.sin_addr.S_un.S_addr = htonl( 0x7F000001 );
+ syslog_hostaddr.sin_port = htons( SYSLOG_PORT );
+}
+
+/******************************************************************************
+ * closelog
+ *
+ * Close desriptor used to write to system logger.
+ */
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+closelog()
+{
+ if ( !initialized )
+ return;
+
+ EnterCriticalSection(&cs_syslog);
+ if( syslog_opened ) {
+ closesocket( syslog_socket );
+ syslog_socket = INVALID_SOCKET;
+ syslog_opened = FALSE;
+ }
+ LeaveCriticalSection(&cs_syslog);
+}
+
+/******************************************************************************
+ * openlog
+ *
+ * Open connection to system logger.
+ */
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+openlog( char* ident, int option, int facility )
+{
+ BOOL failed = FALSE;
+ SOCKADDR_IN sa_local;
+ DWORD n;
+ int size;
+
+ if ( !initialized )
+ return;
+
+ EnterCriticalSection(&cs_syslog);
+
+ if( syslog_opened )
+ goto done;
+
+ failed = TRUE;
+
+ syslog_facility = facility? facility : LOG_USER;
+
+ if( option & LOG_PID )
+ sprintf_s( syslog_procid_str, sizeof(syslog_procid_str), "[%lu]", GetCurrentProcessId() );
+ else
+ syslog_procid_str[0] = '\0';
+
+ /* FIXME: handle other options */
+
+ n = sizeof(local_hostname);
+ if( !GetComputerName( local_hostname, &n ) )
+ goto done;
+
+ syslog_socket = INVALID_SOCKET;
+
+ init_logger_addr();
+
+ for( n = 0;; n++ )
+ {
+ syslog_socket = socket( AF_INET, SOCK_DGRAM, 0 );
+ if( INVALID_SOCKET == syslog_socket )
+ goto done;
+
+ memset( &sa_local, 0, sizeof(SOCKADDR_IN) );
+ sa_local.sin_family = AF_INET;
+ if( bind( syslog_socket, (SOCKADDR*) &sa_local, sizeof(SOCKADDR_IN) ) == 0 )
+ break;
+ rk_closesocket( syslog_socket );
+ syslog_socket = INVALID_SOCKET;
+ if( n == 100 )
+ goto done;
+ Sleep(0);
+ }
+
+ /* get size of datagramm */
+ size = sizeof(datagramm_size);
+ if( getsockopt( syslog_socket, SOL_SOCKET, SO_MAX_MSG_SIZE, (char*) &datagramm_size, &size ) )
+ goto done;
+ if( datagramm_size - strlen(local_hostname) - (ident? strlen(ident) : 0) < 64 )
+ goto done;
+ if( datagramm_size > SYSLOG_DGRAM_SIZE )
+ datagramm_size = SYSLOG_DGRAM_SIZE;
+
+ if (ident)
+ strcpy_s(syslog_ident, sizeof(syslog_ident), ident);
+
+ syslog_facility = (facility ? facility : LOG_USER);
+ failed = FALSE;
+
+ done:
+ if( failed ) {
+ if( syslog_socket != INVALID_SOCKET )
+ rk_closesocket( syslog_socket );
+ }
+ syslog_opened = !failed;
+
+ LeaveCriticalSection(&cs_syslog);
+}
+
+/******************************************************************************
+ * setlogmask
+ *
+ * Set the log mask level.
+ */
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+setlogmask( int mask )
+{
+ int ret;
+
+ if ( !initialized )
+ return 0;
+
+ EnterCriticalSection(&cs_syslog);
+
+ ret = syslog_mask;
+ if( mask )
+ syslog_mask = mask;
+
+ LeaveCriticalSection(&cs_syslog);
+
+ return ret;
+}
+
+/******************************************************************************
+ * syslog
+ *
+ * Generate a log message using FMT string and option arguments.
+ */
+ROKEN_LIB_FUNCTION void
+syslog( int pri, char* fmt, ... )
+{
+ va_list ap;
+
+ va_start( ap, fmt );
+ vsyslog( pri, fmt, ap );
+ va_end( ap );
+}
+
+/******************************************************************************
+ * vsyslog
+ *
+ * Generate a log message using FMT and using arguments pointed to by AP.
+ */
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+vsyslog( int pri, char* fmt, va_list ap )
+{
+ static char *month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+ char datagramm[ SYSLOG_DGRAM_SIZE ];
+ SYSTEMTIME stm;
+ int len;
+ char *p;
+
+ if ( !initialized )
+ return;
+
+ EnterCriticalSection(&cs_syslog);
+
+ if( !(LOG_MASK( LOG_PRI( pri )) & syslog_mask) )
+ goto done;
+
+ openlog( NULL, 0, pri & LOG_FACMASK );
+ if( !syslog_opened )
+ goto done;
+
+ if( !(pri & LOG_FACMASK) )
+ pri |= syslog_facility;
+
+ GetLocalTime( &stm );
+ len = sprintf_s( datagramm, sizeof(datagramm),
+ "<%d>%s %2d %02d:%02d:%02d %s %s%s: ",
+ pri,
+ month[ stm.wMonth - 1 ], stm.wDay, stm.wHour, stm.wMinute, stm.wSecond,
+ local_hostname, syslog_ident, syslog_procid_str );
+ vsprintf_s( datagramm + len, datagramm_size - len, fmt, ap );
+ p = strchr( datagramm, '\n' );
+ if( p )
+ *p = 0;
+ p = strchr( datagramm, '\r' );
+ if( p )
+ *p = 0;
+
+ sendto( syslog_socket, datagramm, strlen(datagramm), 0, (SOCKADDR*) &syslog_hostaddr, sizeof(SOCKADDR_IN) );
+
+ done:
+ LeaveCriticalSection(&cs_syslog);
+}
+
diff --git a/third_party/heimdal/lib/roken/test-auxval.c b/third_party/heimdal/lib/roken/test-auxval.c
new file mode 100644
index 0000000..80ad9e0
--- /dev/null
+++ b/third_party/heimdal/lib/roken/test-auxval.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 1999 - 2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "roken.h"
+#include "getauxval.h"
+
+static void
+check_secure_getenv(char **env)
+{
+ size_t i;
+ char *v, *p;
+
+ for (i = 0; env[i] != NULL; i++) {
+ if ((v = strdup(env[i])) == NULL)
+ err(1, "could not allocate copy of %s", env[i]);
+ if ((p = strchr(v, '='))) {
+ *p = '\0';
+ if (issuid() && rk_secure_getenv(v) != NULL)
+ err(1, "rk_secure_getenv() returned non-NULL when issuid()!");
+ if (!issuid() && rk_secure_getenv(v) == NULL)
+ err(1, "rk_secure_getenv() returned NULL when !issuid()");
+ }
+ free(v);
+ }
+}
+
+static void
+inject_suid(int suid)
+{
+#if defined(AT_SECURE) || (defined(AT_EUID) && defined(AT_RUID) && defined(AT_EGID) && defined(AT_RGID))
+ auxv_t e;
+#ifdef AT_SECURE
+ unsigned long secure = suid ? 1 : 0;
+#endif
+#if defined(AT_EUID) && defined(AT_RUID) && defined(AT_EGID) && defined(AT_RGID)
+ unsigned long eid = suid ? 0 : 1000;
+
+ /* Inject real UID and GID */
+ e.a_un.a_val = 1000;
+ e.a_type = AT_UID;
+ if ((errno = rk_injectauxv(&e)) != 0)
+ err(1, "rk_injectauxv(AT_RUID) failed");
+ e.a_type = AT_GID;
+ if ((errno = rk_injectauxv(&e)) != 0)
+ err(1, "rk_injectauxv(AT_RGID) failed");
+
+ /* Inject effective UID and GID */
+ e.a_un.a_val = eid;
+ e.a_type = AT_EUID;
+ if ((errno = rk_injectauxv(&e)) != 0)
+ err(1, "rk_injectauxv(AT_EUID) failed");
+ e.a_type = AT_EGID;
+ if ((errno = rk_injectauxv(&e)) != 0)
+ err(1, "rk_injectauxv(AT_RGID) failed");
+#endif
+
+#ifdef AT_SECURE
+ e.a_un.a_val = secure;
+ e.a_type = AT_SECURE;
+ if ((errno = rk_injectauxv(&e)) != 0)
+ err(1, "rk_injectauxv(AT_SECURE) failed");
+#endif
+
+ return;
+#else
+ warnx("No ELF auxv types to inject");
+#endif
+}
+
+static
+unsigned long
+getprocauxval(unsigned long type)
+{
+ const auxv_t *e;
+
+ if ((e = rk_getauxv(type)) == NULL) {
+ errno = ENOENT;
+ return 0;
+ }
+ return e->a_un.a_val;
+}
+
+/* returns 1 if auxval type is handled specially by libc */
+static int
+is_special_auxv_p(long type)
+{
+#ifdef AT_HWCAP
+ if (type == AT_HWCAP)
+ return 1;
+#endif
+#ifdef AT_HWCAP2
+ if (type == AT_HWCAP2)
+ return 1;
+#endif
+
+ return 0;
+}
+
+int
+main(int argc, char **argv, char **env)
+{
+ unsigned long max_t = 0;
+ unsigned long a[2];
+ unsigned long v;
+ ssize_t bytes;
+ int am_suid = issuid();
+ int fd;
+
+ (void) argc;
+ (void) argv;
+
+ if (getuid() == geteuid() && getgid() == getegid()) {
+ if (issuid())
+ errx(1, "issuid() false positive? Check AT_SECURE?");
+ } else {
+ if (!issuid())
+ errx(1, "issuid() did not detect set-uid-ness!");
+ }
+
+ if ((fd = open("/proc/self/auxv", O_RDONLY)) == -1)
+ return 0;
+
+ /*
+ * Check that for every ELF auxv entry in /proc/self/auxv we
+ * find the correct answer from the rk_get*auxval() functions.
+ */
+ do {
+ bytes = read(fd, a, sizeof(a));
+ if (bytes != sizeof(a)) {
+ if (bytes == -1)
+ err(1, "Error reading from /proc/self/auxv");
+ if (bytes == 0)
+ warnx("Did not see terminator in /proc/self/auxv");
+ else
+ warnx("Partial entry in /proc/self/auxv or test interrupted");
+ (void) close(fd);
+ return 1;
+ }
+ if (a[0] > max_t)
+ max_t = a[0];
+ if (a[0] == 0) {
+ if (a[1] != 0)
+ warnx("AT_NULL with non-zero value %lu?!", a[1]);
+ continue;
+ } else if (is_special_auxv_p(a[0]))
+ continue;
+
+ errno = EACCES;
+
+ if ((v = rk_getauxval(a[0])) != a[1])
+ errx(1, "rk_getauxval(%lu) should have been %lu, was %lu",
+ a[0], a[1], v);
+ if (errno != EACCES)
+ errx(1, "rk_getauxval(%lu) did not preserve errno", a[0]);
+
+ if ((v = getprocauxval(a[0])) != a[1])
+ errx(1, "rk_getauxval(%lu) should have been %lu, was %lu",
+ a[0], a[1], v);
+ if (errno != EACCES)
+ errx(1, "rk_getauxv(%lu) did not preserve errno", a[0]);
+
+ printf("auxv type %lu -> %lu\n", a[0], a[1]);
+ } while (a[0] != 0 || a[1] != 0);
+
+ (void) close(fd);
+ if (max_t == 0) {
+ warnx("No entries in /proc/self/auxv or it is not available on this "
+ "system or this program is linked statically; cannot test "
+ "rk_getauxval()");
+ return 0;
+ }
+
+ errno = EACCES;
+ if ((v = rk_getauxval(max_t + 1)) != 0)
+ errx(1, "rk_getauxval((max_type_seen = %lu) + 1) should have been "
+ "0, was %lu", max_t, v);
+ if (errno != ENOENT)
+ errx(1, "rk_getauxval((max_type_seen = %lu) + 1) did not set "
+ "errno = ENOENT!", max_t);
+
+ errno = EACCES;
+ if ((v = getprocauxval(max_t + 1)) != 0)
+ errx(1, "rk_getauxv((max_type_seen = %lu) + 1) should have been "
+ "0, was %lu", max_t, v);
+ if (errno != ENOENT)
+ errx(1, "rk_getauxv((max_type_seen = %lu) + 1) did not set "
+ "errno = ENOENT!", max_t);
+
+ check_secure_getenv(env);
+ inject_suid(!am_suid);
+ if ((am_suid && issuid()) || (!am_suid && !issuid()))
+ errx(1, "rk_injectprocauxv() failed");
+ check_secure_getenv(env);
+
+ return 0;
+}
diff --git a/third_party/heimdal/lib/roken/test-detach.c b/third_party/heimdal/lib/roken/test-detach.c
new file mode 100644
index 0000000..0f4636e
--- /dev/null
+++ b/third_party/heimdal/lib/roken/test-detach.c
@@ -0,0 +1,100 @@
+/***********************************************************************
+ * Copyright (c) 2015, Cryptonector LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDER 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 <config.h>
+
+#include <sys/types.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#ifdef WIN32
+#include <process.h>
+#ifdef getpid
+#undef getpid
+#endif
+#define getpid _getpid
+#else
+#include <unistd.h>
+#endif
+#include "roken.h"
+
+int main(int argc, char **argv)
+{
+/*
+ * XXXrcd: let's see how much further the tests get when we disable this
+ * on Windows.
+ */
+#ifndef WIN32
+ char *ends;
+ long n;
+ int fd = -1;
+ pid_t parent = getpid();
+ pid_t child;
+
+ if (argc == 2 && strcmp(argv[1], "--reexec") != 0)
+ errx(1, "Usage: test-detach [--reexec] [--daemon-child FD]");
+ if (argc == 3 || argc == 4) {
+ parent = getppid();
+ errno = 0;
+ n = strtol(argv[2], &ends, 10);
+ fd = n;
+ if (errno != 0)
+ err(1, "Usage: test-detach [--daemon-child fd]");
+ if (n < 0 || ends == NULL || *ends != '\0' || n != fd)
+ errx(1, "Usage: test-detach [--daemon-child fd]");
+ } else {
+ if (argc == 2)
+ /* Make sure we re-exec on the child-side of fork() (not WIN32) */
+ putenv("ROKEN_DETACH_USE_EXEC=1");
+ fd = roken_detach_prep(argc, argv, "--daemon-child");
+ if (fd == -1)
+ errx(1, "bad");
+ }
+ if (parent == getpid())
+ errx(1, "detach prep failed");
+ child = getpid();
+ roken_detach_finish(NULL, fd);
+ if (child != getpid())
+ errx(1, "detach finish failed");
+ /*
+ * These printfs will not appear: stderr will have been replaced
+ * with /dev/null.
+ */
+ fprintf(stderr, "Now should be the child: %ld, wrote to parent\n", (long)getpid());
+ sleep(5);
+ fprintf(stderr, "Daemon child done\n");
+ return 0;
+#else
+ return 0;
+#endif
+}
diff --git a/third_party/heimdal/lib/roken/test-getuserinfo.c b/third_party/heimdal/lib/roken/test-getuserinfo.c
new file mode 100644
index 0000000..4feae17
--- /dev/null
+++ b/third_party/heimdal/lib/roken/test-getuserinfo.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2017 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
+ */
+
+#ifndef WIN32
+#include <err.h>
+#endif
+#include "roken.h"
+
+static void
+print1(const char *name, const char *tabs, const char *s2)
+{
+ (void) printf("%s:%s%s\n", name, tabs, s2 ? s2 : "<NULL>");
+}
+
+int
+main(void)
+{
+ char buf[MAX_PATH * 2];
+#ifndef WIN32
+ char buf2[MAX_PATH * 2];
+ int ret = 0;
+ if (!issuid() && getuid() != 0) {
+ const char *s = NULL;
+ const char *s2 = NULL;
+
+ if (getenv("USER") != NULL && strlen(getenv("USER")) != 0 &&
+ (s = roken_get_username(buf, sizeof(buf))) == NULL) {
+ warnx("roken_get_username() returned NULL but $USER is set");
+ ret++;
+ }
+ if (getenv("USER") != NULL && strlen(getenv("USER")) != 0 && s &&
+ strcmp(getenv("USER"), s) != 0) {
+ warnx("roken_get_username() != getenv(\"USER\")");
+ ret++;
+ }
+
+ if (getenv("HOME") != NULL && strlen(getenv("HOME")) != 0 &&
+ (s = roken_get_homedir(buf, sizeof(buf))) == NULL) {
+ warnx("roken_get_homedir() returned NULL but $HOME is set");
+ ret++;
+ }
+ if (getenv("HOME") != NULL && strlen(getenv("HOME")) != 0 && s &&
+ strcmp(getenv("HOME"), s) != 0) {
+ warnx("roken_get_homedir() != getenv(\"HOME\")");
+ ret++;
+ }
+
+ if (getenv("HOME") != NULL && strlen(getenv("HOME")) != 0 && s &&
+ (s2 = roken_get_appdatadir(buf, sizeof(buf))) == NULL) {
+ warnx("roken_get_appdatadir() returned NULL but $HOME is set "
+ "and roken_get_homedir() returned not-NULL");
+ ret++;
+ }
+ if (getenv("HOME") != NULL && strlen(getenv("HOME")) != 0 &&
+ s && s2 && strcmp(s, s2) != 0) {
+ warnx("roken_get_homedir() != roken_get_appdatadir()");
+ ret++;
+ }
+ if (getenv("SHELL") != NULL && strlen(getenv("SHELL")) != 0 &&
+ strcmp(getenv("SHELL"), roken_get_shell(buf, sizeof(buf))) != 0) {
+ warnx("roken_get_shell() != getenv(\"SHELL\")");
+ ret++;
+ }
+ }
+#endif
+
+ print1("Username", "\t", roken_get_username(buf, sizeof(buf)));
+ print1("Loginname", "\t", roken_get_loginname(buf, sizeof(buf)));
+ print1("Home", "\t\t", roken_get_homedir(buf, sizeof(buf)));
+ print1("Appdatadir", "\t", roken_get_appdatadir(buf, sizeof(buf)));
+ print1("Shell", "\t\t", roken_get_shell(buf, sizeof(buf)));
+
+#ifndef WIN32
+ if (!issuid() && getuid() != 0) {
+ const char *s, *s2;
+
+ putenv("USER=h5lfoouser");
+ putenv("HOME=/no/such/dir/h5lfoouser");
+ putenv("SHELL=/no/such/shell");
+ if ((s = roken_get_username(buf, sizeof(buf))) == NULL ||
+ strcmp("h5lfoouser", s) != 0) {
+ warnx("roken_get_username() (%s) did not honor $USER", s);
+ ret++;
+ }
+ if ((s = roken_get_homedir(buf, sizeof(buf))) == NULL ||
+ strcmp("/no/such/dir/h5lfoouser", s) != 0) {
+ warnx("roken_get_homedir() (%s) did not honor $HOME", s);
+ ret++;
+ }
+ s = roken_get_homedir(buf, sizeof(buf));
+ s2 = roken_get_appdatadir(buf2, sizeof(buf2));
+ if (strcmp(s, s2) != 0) {
+ warnx("roken_get_homedir() != roken_get_appdatadir() (%s)",
+ roken_get_appdatadir(buf, sizeof(buf)));
+ ret++;
+ }
+ if ((s = roken_get_shell(buf, sizeof(buf))) == NULL ||
+ strcmp("/no/such/shell", s) != 0) {
+ warnx("roken_get_shell() (%s) did not honor $SHELL", s);
+ ret++;
+ }
+ }
+ return ret;
+#endif
+ return 0;
+}
diff --git a/third_party/heimdal/lib/roken/test-mem.c b/third_party/heimdal/lib/roken/test-mem.c
new file mode 100644
index 0000000..5ae1017
--- /dev/null
+++ b/third_party/heimdal/lib/roken/test-mem.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 1999 - 2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <err.h>
+#include "roken.h"
+
+#include "test-mem.h"
+
+/* #undef HAVE_MMAP */
+
+struct {
+ void *start;
+ size_t size;
+ void *data_start;
+ size_t data_size;
+ enum rk_test_mem_type type;
+ int fd;
+} map;
+
+#ifdef HAVE_SIGACTION
+
+struct sigaction sa, osa;
+
+#else
+
+void (* osigh)(int);
+
+#endif
+
+char *testname;
+
+static RETSIGTYPE
+segv_handler(int sig)
+{
+ int fd;
+ ssize_t ret;
+ char msg[] = "SIGSEGV i current test: ";
+
+ fd = open("/dev/stdout", O_WRONLY, 0600);
+ if (fd >= 0) {
+ ret = write(fd, msg, sizeof(msg) - 1);
+ if (ret != -1)
+ ret = write(fd, testname, strlen(testname));
+ if (ret != -1)
+ ret = write(fd, "\n", 1);
+ close(fd);
+ }
+ _exit(1);
+}
+
+#define TESTREC() \
+ if (testname) \
+ errx(1, "test %s run recursively on %s", name, testname); \
+ testname = strdup(name); \
+ if (testname == NULL) \
+ errx(1, "malloc");
+
+
+ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL
+rk_test_mem_alloc(enum rk_test_mem_type type, const char *name,
+ void *buf, size_t size)
+{
+#ifndef HAVE_MMAP
+ unsigned char *p;
+
+ TESTREC();
+
+ p = malloc(size + 2);
+ if (p == NULL)
+ errx(1, "malloc");
+ map.type = type;
+ map.start = p;
+ map.size = size + 2;
+ p[0] = 0xff;
+ p[map.size-1] = 0xff;
+ map.data_start = p + 1;
+#else
+ unsigned char *p;
+ int flags, ret, fd;
+ size_t pagesize = getpagesize();
+
+ TESTREC();
+
+ map.type = type;
+
+#ifdef MAP_ANON
+ flags = MAP_ANON;
+ fd = -1;
+#else
+ flags = 0;
+ fd = open ("/dev/zero", O_RDONLY);
+ if(fd < 0)
+ err (1, "open /dev/zero");
+#endif
+ map.fd = fd;
+ flags |= MAP_PRIVATE;
+
+ map.size = size + pagesize - (size % pagesize) + pagesize * 2;
+
+ p = (unsigned char *)mmap(0, map.size, PROT_READ | PROT_WRITE,
+ flags, fd, 0);
+ if (p == (unsigned char *)MAP_FAILED)
+ err (1, "mmap");
+
+ map.start = p;
+
+ ret = mprotect ((void *)p, pagesize, 0);
+ if (ret < 0)
+ err (1, "mprotect");
+
+ ret = mprotect (p + map.size - pagesize, pagesize, 0);
+ if (ret < 0)
+ err (1, "mprotect");
+
+ switch (type) {
+ case RK_TM_OVERRUN:
+ map.data_start = p + map.size - pagesize - size;
+ break;
+ case RK_TM_UNDERRUN:
+ map.data_start = p + pagesize;
+ break;
+ default:
+ abort();
+ }
+#endif
+#ifdef HAVE_SIGACTION
+ sigemptyset (&sa.sa_mask);
+ sa.sa_flags = 0;
+#ifdef SA_RESETHAND
+ sa.sa_flags |= SA_RESETHAND;
+#endif
+ sa.sa_handler = segv_handler;
+ sigaction (SIGSEGV, &sa, &osa);
+#else
+ osigh = signal(SIGSEGV, segv_handler);
+#endif
+
+ map.data_size = size;
+ if (buf)
+ memcpy(map.data_start, buf, size);
+ return map.data_start;
+}
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rk_test_mem_free(const char *map_name)
+{
+#ifndef HAVE_MMAP
+ unsigned char *p = map.start;
+
+ if (testname == NULL)
+ errx(1, "test_mem_free call on no free");
+
+ if (p[0] != 0xff)
+ errx(1, "%s: %s underrun %x\n", testname, map_name, p[0]);
+ if (p[map.size-1] != 0xff)
+ errx(1, "%s: %s overrun %x\n", testname, map_name, p[map.size - 1]);
+ free(map.start);
+#else
+ int ret;
+
+ if (testname == NULL)
+ errx(1, "test_mem_free call on no free");
+
+ ret = munmap (map.start, map.size);
+ if (ret < 0)
+ err (1, "munmap");
+ if (map.fd > 0)
+ close(map.fd);
+#endif
+ free(testname);
+ testname = NULL;
+
+#ifdef HAVE_SIGACTION
+ sigaction (SIGSEGV, &osa, NULL);
+#else
+ signal (SIGSEGV, osigh);
+#endif
+}
diff --git a/third_party/heimdal/lib/roken/test-mem.h b/third_party/heimdal/lib/roken/test-mem.h
new file mode 100644
index 0000000..4d900b4
--- /dev/null
+++ b/third_party/heimdal/lib/roken/test-mem.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 1999 - 2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
+ */
+
+enum rk_test_mem_type { RK_TM_OVERRUN, RK_TM_UNDERRUN };
+
+ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL
+ rk_test_mem_alloc(enum rk_test_mem_type, const char *, void *, size_t);
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+ rk_test_mem_free(const char *);
diff --git a/third_party/heimdal/lib/roken/test-mini_inetd.c b/third_party/heimdal/lib/roken/test-mini_inetd.c
new file mode 100644
index 0000000..7ab996a
--- /dev/null
+++ b/third_party/heimdal/lib/roken/test-mini_inetd.c
@@ -0,0 +1,371 @@
+/***********************************************************************
+ * Copyright (c) 2009, Secure Endpoints Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDER 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 <config.h>
+#include <roken.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define PORT 8013
+#define PORT_S "8013"
+
+char * prog = "Master";
+int is_client = 0;
+
+static int
+get_address(int flags, struct addrinfo ** ret)
+{
+ struct addrinfo ai;
+ int rv;
+
+ memset(&ai, 0, sizeof(ai));
+
+ ai.ai_flags = flags | AI_NUMERICHOST;
+ ai.ai_family = AF_INET;
+ ai.ai_socktype = SOCK_STREAM;
+ ai.ai_protocol = PF_UNSPEC;
+
+ rv = getaddrinfo("127.0.0.1", PORT_S, &ai, ret);
+ if (rv)
+ warnx("getaddrinfo: %s", gai_strerror(rv));
+ return rv;
+}
+
+static int
+get_connected_socket(rk_socket_t * s_ret)
+{
+ struct addrinfo * ai = NULL;
+ int rv = 0;
+ rk_socket_t s = rk_INVALID_SOCKET;
+
+ rv = get_address(0, &ai);
+ if (rv)
+ return rv;
+
+ s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (rk_IS_BAD_SOCKET(s)) {
+ rv = 1;
+ goto done;
+ }
+
+ rv = connect(s, ai->ai_addr, ai->ai_addrlen);
+ if (rk_IS_SOCKET_ERROR(rv))
+ goto done;
+
+ *s_ret = s;
+ s = rk_INVALID_SOCKET;
+ rv = 0;
+
+ done:
+ if (!rk_IS_BAD_SOCKET(s))
+ rk_closesocket(s);
+
+ if (ai)
+ freeaddrinfo(ai);
+
+ return (rv) ? rk_SOCK_ERRNO : 0;
+}
+
+const char * test_strings[] = {
+ "Hello",
+ "01234566789012345689012345678901234567890123456789",
+ "Another test",
+ "exit"
+};
+
+static int
+test_simple_echo_client(void)
+{
+ rk_socket_t s = rk_INVALID_SOCKET;
+ int rv;
+ char buf[81];
+ int i;
+
+ fprintf(stderr, "[%s] Getting connected socket...", getprogname());
+ rv = get_connected_socket(&s);
+ if (rv) {
+ fprintf(stderr, "\n[%s] get_connected_socket() failed (%s)\n",
+ getprogname(), strerror(rk_SOCK_ERRNO));
+ return 1;
+ }
+
+ fprintf(stderr, "[%s] done\n", getprogname());
+
+ for (i=0; i < sizeof(test_strings)/sizeof(test_strings[0]); i++) {
+ rv = send(s, test_strings[i], strlen(test_strings[i]), 0);
+ if (rk_IS_SOCKET_ERROR(rv)) {
+ fprintf(stderr, "[%s] send() failure (%s)\n",
+ getprogname(), strerror(rk_SOCK_ERRNO));
+ rk_closesocket(s);
+ return 1;
+ }
+
+ rv = recv(s, buf, sizeof(buf), 0);
+ if (rk_IS_SOCKET_ERROR(rv)) {
+ fprintf (stderr, "[%s] recv() failure (%s)\n",
+ getprogname(), strerror(rk_SOCK_ERRNO));
+ rk_closesocket(s);
+ return 1;
+ }
+
+ if (rv == 0) {
+ fprintf (stderr, "[%s] No data received\n", prog);
+ rk_closesocket(s);
+ return 1;
+ }
+
+ if (rv != strlen(test_strings[i])) {
+ fprintf (stderr, "[%s] Data length mismatch %d != %zu\n", prog, rv, strlen(test_strings[i]));
+ rk_closesocket(s);
+ return 1;
+ }
+ }
+
+ fprintf (stderr, "[%s] Done\n", prog);
+ rk_closesocket(s);
+ return 0;
+}
+
+static int
+test_simple_echo_socket(void)
+{
+ fprintf (stderr, "[%s] Process ID %d\n", prog, GetCurrentProcessId());
+ fprintf (stderr, "[%s] Starting echo test with sockets\n", prog);
+
+ if (is_client) {
+ return test_simple_echo_client();
+ } else {
+
+ rk_socket_t s = rk_INVALID_SOCKET;
+
+ fprintf (stderr, "[%s] Listening for connections...\n", prog);
+ mini_inetd(htons(PORT), &s);
+ if (rk_IS_BAD_SOCKET(s)) {
+ fprintf (stderr, "[%s] Connect failed (%s)\n",
+ getprogname(), strerror(rk_SOCK_ERRNO));
+ } else {
+ fprintf (stderr, "[%s] Connected\n", prog);
+ }
+
+ {
+ char buf[81];
+ int rv, srv;
+
+ while ((rv = recv(s, buf, sizeof(buf), 0)) != 0 && !rk_IS_SOCKET_ERROR(rv)) {
+ buf[rv] = 0;
+ fprintf(stderr, "[%s] Received [%s]\n", prog, buf);
+
+ /* simple echo */
+ srv = send(s, buf, rv, 0);
+ if (srv != rv) {
+ if (rk_IS_SOCKET_ERROR(srv))
+ fprintf(stderr, "[%s] send() error [%s]\n",
+ getprogname(), strerror(rk_SOCK_ERRNO));
+ else
+ fprintf(stderr, "[%s] send() size mismatch %d != %d",
+ getprogname(), srv, rv);
+ }
+
+ if (strcmp(buf, "exit") == 0) {
+ fprintf(stderr, "[%s] Exiting...\n", prog);
+ shutdown(s, SD_SEND);
+ rk_closesocket(s);
+ return 0;
+ }
+ }
+
+ fprintf(stderr, "[%s] recv() failed (%s)\n",
+ getprogname(),
+ strerror(rk_SOCK_ERRNO));
+ }
+
+ rk_closesocket(s);
+ }
+
+ return 1;
+}
+
+static int
+test_simple_echo(void)
+{
+ fprintf (stderr, "[%s] Starting echo test\n", prog);
+
+ if (is_client) {
+
+ return test_simple_echo_client();
+
+ } else {
+
+ fprintf (stderr, "[%s] Listening for connections...\n", prog);
+ mini_inetd(htons(PORT), NULL);
+ fprintf (stderr, "[%s] Connected\n", prog);
+
+ {
+ char buf[81];
+ while (gets(buf)) {
+ fprintf(stderr, "[%s] Received [%s]\n", prog, buf);
+
+ if (strcmp(buf, "exit") == 0)
+ return 0;
+
+ /* simple echo */
+ puts(buf);
+ }
+
+ fprintf(stderr, "[%s] gets() failed (%s)\n", prog, _strerror("gets"));
+ }
+ }
+
+ return 1;
+}
+
+static int
+do_client(void)
+{
+ int rv = 0;
+
+ if (rk_SOCK_INIT())
+ errx(1, "Failed to initialize sockets (%s)", strerror(rk_SOCK_ERRNO));
+
+ prog = "Client";
+ is_client = 1;
+
+ fprintf(stderr, "Starting client...\n");
+
+ rv = test_simple_echo_socket();
+
+ rk_SOCK_EXIT();
+
+ return rv;
+}
+
+static int
+do_server(void)
+{
+ int rv = 0;
+
+ if (rk_SOCK_INIT())
+ errx(1, "Failed to initialize sockets (%s)", strerror(rk_SOCK_ERRNO));
+
+ prog = "Server";
+
+ fprintf(stderr, "Starting server...\n");
+
+ rv = test_simple_echo_socket();
+
+ rk_SOCK_EXIT();
+
+ return rv;
+}
+
+static time_t
+wait_callback(void *p)
+{
+ return (time_t)-1;
+}
+
+static int
+do_test(char * path)
+{
+ intptr_t p_server;
+ intptr_t p_client;
+ int client_rv;
+ int server_rv;
+
+ p_server = _spawnl(_P_NOWAIT, path, path, "--server", NULL);
+ if (p_server <= 0) {
+ fprintf(stderr, "%s: %s", path, _strerror("Can't start server process"));
+ return 1;
+ }
+#ifdef _WIN32
+ /* On Windows, the _spawn*() functions return a process handle on
+ success. We need a process ID for use with
+ wait_for_process_timed(). */
+
+ p_server = GetProcessId((HANDLE) p_server);
+#endif
+ fprintf(stderr, "Created server process ID %d\n", p_server);
+
+ p_client = _spawnl(_P_NOWAIT, path, path, "--client", NULL);
+ if (p_client <= 0) {
+ fprintf(stderr, "%s: %s", path, _strerror("Can't start client process"));
+ fprintf(stderr, "Waiting for server process to terminate ...");
+ wait_for_process_timed(p_server, wait_callback, NULL, 5);
+ fprintf(stderr, "DONE\n");
+ return 1;
+ }
+#ifdef _WIN32
+ p_client = GetProcessId((HANDLE) p_client);
+#endif
+ fprintf(stderr, "Created client process ID %d\n", p_client);
+
+ fprintf(stderr, "Waiting for client process to terminate ...");
+ client_rv = wait_for_process_timed(p_client, wait_callback, NULL, 5);
+ if (SE_IS_ERROR(client_rv)) {
+ fprintf(stderr, "\nwait_for_process_timed() failed for client. rv=%d\n", client_rv);
+ } else {
+ fprintf(stderr, "DONE\n");
+ }
+
+ fprintf(stderr, "Waiting for server process to terminate ...");
+ server_rv = wait_for_process_timed(p_server, wait_callback, NULL, 5);
+ if (SE_IS_ERROR(server_rv)) {
+ fprintf(stderr, "\nwait_for_process_timed() failed for server. rv=%d\n", server_rv);
+ } else {
+ fprintf(stderr, "DONE\n");
+ }
+
+ if (client_rv == 0 && server_rv == 0) {
+ fprintf(stderr, "PASS\n");
+ return 0;
+ } else {
+ fprintf(stderr, "FAIL: Client rv=%d, Server rv=%d\n", client_rv, server_rv);
+ return 1;
+ }
+}
+
+int main(int argc, char ** argv)
+{
+ setprogname(argv[0]);
+
+ if (argc == 2 && strcmp(argv[1], "--client") == 0)
+ return do_client();
+ else if (argc == 2 && strcmp(argv[1], "--server") == 0)
+ return do_server();
+ else if (argc == 1)
+ return do_test(argv[0]);
+ else {
+ printf ("%s: Test mini_inetd() function. Run with no arguments to start test\n",
+ argv[0]);
+ return 1;
+ }
+}
diff --git a/third_party/heimdal/lib/roken/test-readenv.c b/third_party/heimdal/lib/roken/test-readenv.c
new file mode 100644
index 0000000..24a6661
--- /dev/null
+++ b/third_party/heimdal/lib/roken/test-readenv.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+#include "test-mem.h"
+
+char *s1 = "VAR1=VAL1#comment\n\
+VAR2=VAL2 VAL2 #comment\n\
+#this another comment\n\
+\n\
+VAR3=FOO";
+
+char *s2 = "VAR1=ENV2\n\
+";
+
+static void
+make_file(char *tmpl, size_t l)
+{
+ int fd;
+ strlcpy(tmpl, "env.XXXXXX", l);
+ fd = mkstemp(tmpl);
+ if(fd < 0)
+ err(1, "mkstemp");
+ close(fd);
+}
+
+static void
+write_file(const char *fn, const char *s)
+{
+ FILE *f;
+ f = fopen(fn, "w");
+ if(f == NULL) {
+ unlink(fn);
+ err(1, "fopen");
+ }
+ if(fwrite(s, 1, strlen(s), f) != strlen(s))
+ err(1, "short write");
+ if(fclose(f) != 0) {
+ unlink(fn);
+ err(1, "fclose");
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ char **env = NULL;
+ int count = 0;
+ char fn[MAXPATHLEN];
+ int error = 0;
+
+ make_file(fn, sizeof(fn));
+
+ write_file(fn, s1);
+ count = read_environment(fn, &env);
+ if(count != 3) {
+ warnx("test 1: variable count %d != 3", count);
+ error++;
+ }
+
+ write_file(fn, s2);
+ count = read_environment(fn, &env);
+ if(count != 1) {
+ warnx("test 2: variable count %d != 1", count);
+ error++;
+ }
+
+ unlink(fn);
+ count = read_environment(fn, &env);
+ if(count != 0) {
+ warnx("test 3: variable count %d != 0", count);
+ error++;
+ }
+ for(count = 0; env && env[count]; count++);
+ if(count != 3) {
+ warnx("total variable count %d != 3", count);
+ error++;
+ }
+ free_environment(env);
+
+
+ return error;
+}
diff --git a/third_party/heimdal/lib/roken/timegm.c b/third_party/heimdal/lib/roken/timegm.c
new file mode 100644
index 0000000..e6c8992
--- /dev/null
+++ b/third_party/heimdal/lib/roken/timegm.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 1997, 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+static int
+is_leap(unsigned y)
+{
+ y += 1900;
+ return (y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0);
+}
+
+/*
+ * XXX This is a simplifed version of timegm, it needs to support out of
+ * bounds values.
+ */
+
+time_t
+rk_timegm (struct tm *tm)
+{
+ static const unsigned ndays[2][12] ={
+ {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+ {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
+ time_t res = 0;
+ unsigned i;
+
+ if (tm->tm_year < 0)
+ return -1;
+ if (tm->tm_mon < 0 || tm->tm_mon > 11)
+ return -1;
+ if (tm->tm_mday < 1 || tm->tm_mday > ndays[is_leap(tm->tm_year)][tm->tm_mon])
+ return -1;
+ if (tm->tm_hour < 0 || tm->tm_hour > 23)
+ return -1;
+ if (tm->tm_min < 0 || tm->tm_min > 59)
+ return -1;
+ if (tm->tm_sec < 0 || tm->tm_sec > 59)
+ return -1;
+
+ for (i = 70; i < tm->tm_year; ++i)
+ res += is_leap(i) ? 366 : 365;
+
+ for (i = 0; i < tm->tm_mon; ++i)
+ res += ndays[is_leap(tm->tm_year)][i];
+ res += tm->tm_mday - 1;
+ res *= 24;
+ res += tm->tm_hour;
+ res *= 60;
+ res += tm->tm_min;
+ res *= 60;
+ res += tm->tm_sec;
+ return res;
+}
diff --git a/third_party/heimdal/lib/roken/timeval.c b/third_party/heimdal/lib/roken/timeval.c
new file mode 100644
index 0000000..71fdd00
--- /dev/null
+++ b/third_party/heimdal/lib/roken/timeval.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
+ */
+
+/*
+ * Timeval stuff
+ */
+
+#include <config.h>
+
+#include "roken.h"
+
+ROKEN_LIB_FUNCTION time_t ROKEN_LIB_CALL
+rk_time_add(time_t t, time_t delta)
+{
+ if (delta == 0)
+ return t;
+
+#ifdef TIME_T_SIGNED
+ /* Signed overflow is UB in C */
+#if SIZEOF_TIME_T == 4
+ if (t >= 0 && delta > 0 && INT32_MAX - t < delta)
+ /* Time left to hit INT32_MAX is less than what we want to add */
+ return INT32_MAX;
+ else if (t == INT32_MIN && delta < 0)
+ /* Avoid computing -t when t == INT32_MIN! */
+ return INT32_MIN;
+ else if (t < 0 && delta < 0 && INT32_MIN + (-t) > delta)
+ /* Time left to hit INT32_MIN is less than what we want to subtract */
+ return INT32_MIN;
+ else
+ return t + delta;
+#elif SIZEOF_TIME_T == 8
+ if (t >= 0 && delta > 0 && INT64_MAX - t < delta)
+ return INT64_MAX;
+ else if (t == INT64_MIN && delta < 0)
+ /* Avoid computing -t when t == INT64_MIN! */
+ return INT64_MIN;
+ else if (t < 0 && delta < 0 && INT64_MIN + (-t) > delta)
+ return INT64_MIN;
+ else
+ return t + delta;
+#else
+#error "Unexpected sizeof(time_t)"
+#endif
+#else
+
+ /* Unsigned overflow is defined in C */
+#if SIZEOF_TIME_T == 4
+ if (t + delta < t)
+ return UINT32_MAX;
+#elif SIZEOF_TIME_T == 8
+ if (t + delta < t)
+ return UINT64_MAX;
+#else
+#error "Unexpected sizeof(time_t)"
+#endif
+ return t + delta;
+#endif
+}
+
+ROKEN_LIB_FUNCTION time_t ROKEN_LIB_CALL
+rk_time_sub(time_t t, time_t delta)
+{
+ if (delta == 0)
+ return t;
+#ifdef TIME_T_SIGNED
+ if (delta > 0)
+ return rk_time_add(t, -delta);
+#if SIZEOF_TIME_T == 4
+ if (delta == INT32_MIN) {
+ if (t < 0) {
+ t = t + INT32_MAX;
+ return t + 1;
+ }
+ return INT32_MAX;
+ }
+ /* Safe to compute -delta, so use rk_time_add() to add -delta */
+ return rk_time_add(t, -delta);
+#elif SIZEOF_TIME_T == 8
+ if (delta == INT64_MIN) {
+ if (t < 0) {
+ t = t + INT64_MAX;
+ return t + 1;
+ }
+ return INT64_MAX;
+ }
+ return rk_time_add(t, -delta);
+#else
+#error "Unexpected sizeof(time_t)"
+#endif
+#else
+ /* Both t and delta are non-negative. */
+ if (delta > t)
+ return 0;
+ return t - delta;
+#endif
+}
+
+/*
+ * Make `t1' consistent.
+ */
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+timevalfix(struct timeval *t1)
+{
+ if (t1->tv_usec < 0) {
+ t1->tv_sec = rk_time_sub(t1->tv_sec, 1);
+ t1->tv_usec = 1000000;
+ }
+ if (t1->tv_usec >= 1000000) {
+ t1->tv_sec = rk_time_add(t1->tv_sec, 1);
+ t1->tv_usec -= 1000000;
+ }
+}
+
+/*
+ * t1 += t2
+ */
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+timevaladd(struct timeval *t1, const struct timeval *t2)
+{
+ t1->tv_sec = rk_time_add(t1->tv_sec, t2->tv_sec);
+ t1->tv_usec += t2->tv_usec;
+ timevalfix(t1);
+}
+
+/*
+ * t1 -= t2
+ */
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+timevalsub(struct timeval *t1, const struct timeval *t2)
+{
+ t1->tv_sec = rk_time_sub(t1->tv_sec, t2->tv_sec);
+ t1->tv_usec -= t2->tv_usec;
+ timevalfix(t1);
+}
+
+#ifdef TEST
+int
+main(int argc, char **argv)
+{
+ time_t t, delta, r;
+ int e = 0;
+
+ if (argc == 0)
+ return 0; /* Apparently POSIX and Linux allow this case */
+
+ argc--;
+ argv++;
+
+ while (argc > 0) {
+ int64_t n;
+ time_t a;
+ char *ends;
+
+ if (argc < 3)
+ errx(1, "Usage: [TIME +|- DELTA [== TIME]]");
+
+ errno = 0;
+ n = strtoll(argv[0], &ends, 0);
+ if (errno)
+ err(1, "Time value is invalid");
+ if (*ends != '\0')
+ errx(1, "Time value is invalid");
+ t = n;
+
+ n = strtoll(argv[2], &ends, 0);
+ if (errno)
+ err(1, "Delta value is invalid");
+ if (*ends != '\0')
+ errx(1, "Delta value is invalid");
+ delta = n;
+
+ if (argv[1][0] == '+' && argv[1][1] == '\0')
+ r = rk_time_add(t, delta);
+ else if (argv[1][0] == '-' && argv[1][1] == '\0')
+ r = rk_time_sub(t, delta);
+ else
+ errx(1, "Operator must be a + or a - arithmetic operator");
+
+ if (delta == 0 && r != t) {
+ warnx("%s %s %s != %s!", argv[0], argv[1], argv[2], argv[0]);
+ e = 1;
+ }
+ if (t == 0 && r != delta) {
+ warnx("%s %s %s != %s!", argv[0], argv[1], argv[2], argv[2]);
+ e = 1;
+ }
+
+ if (argc > 4 && strcmp(argv[3], "==") == 0) {
+ n = strtoll(argv[4], &ends, 0);
+ if (errno)
+ err(1, "Time value is invalid");
+ if (*ends != '\0')
+ errx(1, "Time value is invalid");
+ a = n;
+ if (a != r) {
+ warnx("%s %s %s != %s!", argv[0], argv[1], argv[2], argv[4]);
+ e = 1;
+ }
+ argc -= 5;
+ argv += 5;
+ } else {
+#ifdef TIME_T_SIGNED
+ printf("%s %s %s == %lld\n", argv[0], argv[1], argv[2],
+ (long long)r);
+#else
+ printf("%s %s %s == %llu\n", argv[0], argv[1], argv[2],
+ (unsigned long long)r);
+#endif
+ argc -= 3;
+ argv += 3;
+ }
+ }
+
+#define CHECK(e) do { if (!(e)) errx(1, "Expression not true: " #e "!"); } while (0)
+#ifdef TIME_T_SIGNED
+#if SIZEOF_TIME_T == 4
+ CHECK(rk_time_add(INT32_MIN, -1) == INT32_MIN);
+ CHECK(rk_time_sub(INT32_MIN, 1) == INT32_MIN);
+ CHECK(rk_time_sub(-1, INT32_MAX) == INT32_MIN);
+ CHECK(rk_time_add(INT32_MAX, 0) == INT32_MAX);
+ CHECK(rk_time_add(INT32_MAX, 1) == INT32_MAX);
+ CHECK(rk_time_add(1, INT32_MAX) == INT32_MAX);
+ CHECK(rk_time_add(0, INT32_MAX) == INT32_MAX);
+#elif SIZEOF_TIME_T == 8
+ CHECK(rk_time_add(INT64_MIN, -1) == INT64_MIN);
+ CHECK(rk_time_sub(INT64_MIN, 1) == INT64_MIN);
+ CHECK(rk_time_sub(-1, INT64_MAX) == INT64_MIN);
+ CHECK(rk_time_add(INT64_MAX, 0) == INT64_MAX);
+ CHECK(rk_time_add(INT64_MAX, 1) == INT64_MAX);
+ CHECK(rk_time_add(1, INT64_MAX) == INT64_MAX);
+ CHECK(rk_time_add(0, INT64_MAX) == INT64_MAX);
+#endif
+ CHECK(rk_time_add(0, -1) == -1);
+ CHECK(rk_time_sub(0, 1) == -1);
+#else
+#if SIZEOF_TIME_T == 4
+ CHECK(rk_time_add(UINT32_MAX, 0) == UINT32_MAX);
+ CHECK(rk_time_add(UINT32_MAX, 1) == UINT32_MAX);
+ CHECK(rk_time_add(1, UINT32_MAX) == UINT32_MAX);
+ CHECK(rk_time_add(0, UINT32_MAX) == UINT32_MAX);
+#elif SIZEOF_TIME_T == 8
+ CHECK(rk_time_add(UINT64_MAX, 0) == UINT64_MAX);
+ CHECK(rk_time_add(UINT64_MAX, 1) == UINT64_MAX);
+ CHECK(rk_time_add(1, UINT64_MAX) == UINT64_MAX);
+ CHECK(rk_time_add(0, UINT64_MAX) == UINT64_MAX);
+#endif
+#endif
+ CHECK(rk_time_add(0, 1) == 1);
+ CHECK(rk_time_add(1, 0) == 1);
+ return e;
+}
+#endif
diff --git a/third_party/heimdal/lib/roken/tm2time.c b/third_party/heimdal/lib/roken/tm2time.c
new file mode 100644
index 0000000..ba69a04
--- /dev/null
+++ b/third_party/heimdal/lib/roken/tm2time.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1995, 1996, 1997, 2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#ifdef TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#elif defined(HAVE_SYS_TIME_H)
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#include "roken.h"
+
+ROKEN_LIB_FUNCTION time_t ROKEN_LIB_CALL
+tm2time (struct tm tm, int local)
+{
+ time_t t;
+
+ tm.tm_isdst = local ? -1 : 0;
+
+ t = mktime (&tm);
+
+ if (!local)
+ t += t - mktime (gmtime (&t));
+ return t;
+}
diff --git a/third_party/heimdal/lib/roken/tsearch-test.c b/third_party/heimdal/lib/roken/tsearch-test.c
new file mode 100644
index 0000000..b9d9963
--- /dev/null
+++ b/third_party/heimdal/lib/roken/tsearch-test.c
@@ -0,0 +1,125 @@
+/*
+ * Tree search generalized from Knuth (6.2.2) Algorithm T just like
+ * the AT&T man page says.
+ *
+ * The node_t structure is for internal use only, lint doesn't grok it.
+ *
+ * Written by reading the System V Interface Definition, not the code.
+ *
+ * Totally public domain.
+ */
+
+#include <config.h>
+
+#include "roken.h"
+#include "search.h"
+
+struct node {
+ char *string;
+ int order;
+};
+
+extern void *rk_tdelete(const void *, void **,
+ int (*)(const void *, const void *));
+extern void *rk_tfind(const void *, void * const *,
+ int (*)(const void *, const void *));
+extern void *rk_tsearch(const void *, void **, int (*)(const void *, const void *));
+extern void rk_twalk(const void *, void (*)(const void *, VISIT, int));
+
+void *rootnode = NULL;
+int numerr = 0;
+
+/*
+ * This routine compares two nodes, based on an
+ * alphabetical ordering of the string field.
+ */
+int
+node_compare(const void *node1, const void *node2)
+{
+ return strcmp(((const struct node *) node1)->string,
+ ((const struct node *) node2)->string);
+}
+
+static int walkorder = -1;
+
+void
+list_node(const void *ptr, VISIT order, int level)
+{
+ const struct node *p = *(const struct node **) ptr;
+
+ if (order == postorder || order == leaf) {
+ walkorder++;
+ if (p->order != walkorder) {
+ warnx("sort failed: expected %d next, got %d\n", walkorder,
+ p->order);
+ numerr++;
+ }
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ int numtest = 1;
+ struct node *t, *p, tests[] = {
+ { "", 0 },
+ { "ab", 3 },
+ { "abc", 4 },
+ { "abcdefg", 8 },
+ { "abcd", 5 },
+ { "a", 2 },
+ { "abcdef", 7 },
+ { "abcde", 6 },
+ { "=", 1 },
+ { NULL }
+ };
+
+ for(t = tests; t->string; t++) {
+ /* Better not be there */
+ p = (struct node *)rk_tfind((void *)t, (void **)&rootnode,
+ node_compare);
+
+ if (p) {
+ warnx("erroneous list: found %d\n", p->order);
+ numerr++;
+ }
+
+ /* Put node into the tree. */
+ p = (struct node *) rk_tsearch((void *)t, (void **)&rootnode,
+ node_compare);
+
+ if (!p) {
+ warnx("erroneous list: missing %d\n", t->order);
+ numerr++;
+ }
+ }
+
+ rk_twalk(rootnode, list_node);
+
+ for(t = tests; t->string; t++) {
+ /* Better be there */
+ p = (struct node *) rk_tfind((void *)t, (void **)&rootnode,
+ node_compare);
+
+ if (!p) {
+ warnx("erroneous list: missing %d\n", t->order);
+ numerr++;
+ }
+
+ /* pull out node */
+ (void) rk_tdelete((void *)t, (void **)&rootnode,
+ node_compare);
+
+ /* Better not be there */
+ p = (struct node *) rk_tfind((void *)t, (void **)&rootnode,
+ node_compare);
+
+ if (p) {
+ warnx("erroneous list: found %d\n", p->order);
+ numerr++;
+ }
+
+ }
+
+ return numerr;
+}
diff --git a/third_party/heimdal/lib/roken/tsearch.c b/third_party/heimdal/lib/roken/tsearch.c
new file mode 100644
index 0000000..e5df846
--- /dev/null
+++ b/third_party/heimdal/lib/roken/tsearch.c
@@ -0,0 +1,175 @@
+/*
+ * Tree search generalized from Knuth (6.2.2) Algorithm T just like
+ * the AT&T man page says.
+ *
+ * The node_t structure is for internal use only, lint doesn't grok it.
+ *
+ * Written by reading the System V Interface Definition, not the code.
+ *
+ * Totally public domain.
+ *
+ * $NetBSD: tsearch.c,v 1.3 1999/09/16 11:45:37 lukem Exp $
+ * $NetBSD: twalk.c,v 1.1 1999/02/22 10:33:16 christos Exp $
+ * $NetBSD: tdelete.c,v 1.2 1999/09/16 11:45:37 lukem Exp $
+ * $NetBSD: tfind.c,v 1.2 1999/09/16 11:45:37 lukem Exp $
+ */
+
+#include <config.h>
+#include "roken.h"
+#include "search.h"
+#include <stdlib.h>
+
+typedef struct node {
+ char *key;
+ struct node *llink, *rlink;
+} node_t;
+
+/*
+ * find or insert datum into search tree
+ *
+ * Parameters:
+ * vkey: key to be located
+ * vrootp: address of tree root
+ */
+
+ROKEN_LIB_FUNCTION void *
+rk_tsearch(const void *vkey, void **vrootp,
+ int (*compar)(const void *, const void *))
+{
+ node_t *q;
+ node_t **rootp = (node_t **)vrootp;
+
+ if (rootp == NULL)
+ return NULL;
+
+ while (*rootp != NULL) { /* Knuth's T1: */
+ int r;
+
+ if ((r = (*compar)(vkey, (*rootp)->key)) == 0) /* T2: */
+ return *rootp; /* we found it! */
+
+ rootp = (r < 0) ?
+ &(*rootp)->llink : /* T3: follow left branch */
+ &(*rootp)->rlink; /* T4: follow right branch */
+ }
+
+ q = malloc(sizeof(node_t)); /* T5: key not found */
+ if (q != 0) { /* make new node */
+ *rootp = q; /* link new node to old */
+ /* LINTED const castaway ok */
+ q->key = rk_UNCONST(vkey); /* initialize new node */
+ q->llink = q->rlink = NULL;
+ }
+ return q;
+}
+
+/*
+ * Walk the nodes of a tree
+ *
+ * Parameters:
+ * root: Root of the tree to be walked
+ */
+static void
+trecurse(const node_t *root, void (*action)(const void *, VISIT, int),
+ int level)
+{
+
+ if (root->llink == NULL && root->rlink == NULL)
+ (*action)(root, leaf, level);
+ else {
+ (*action)(root, preorder, level);
+ if (root->llink != NULL)
+ trecurse(root->llink, action, level + 1);
+ (*action)(root, postorder, level);
+ if (root->rlink != NULL)
+ trecurse(root->rlink, action, level + 1);
+ (*action)(root, endorder, level);
+ }
+}
+
+/*
+ * Walk the nodes of a tree
+ *
+ * Parameters:
+ * vroot: Root of the tree to be walked
+ */
+ROKEN_LIB_FUNCTION void
+rk_twalk(const void *vroot,
+ void (*action)(const void *, VISIT, int))
+{
+ if (vroot != NULL && action != NULL)
+ trecurse(vroot, action, 0);
+}
+
+/*
+ * delete node with given key
+ *
+ * vkey: key to be deleted
+ * vrootp: address of the root of the tree
+ * compar: function to carry out node comparisons
+ */
+ROKEN_LIB_FUNCTION void *
+rk_tdelete(const void * vkey, void ** vrootp,
+ int (*compar)(const void *, const void *))
+{
+ node_t **rootp = (node_t **)vrootp;
+ node_t *q, *r;
+ int cmp;
+
+ if (rootp == NULL || *rootp == NULL)
+ return NULL;
+
+ while ((cmp = (*compar)(vkey, (*rootp)->key)) != 0) {
+ rootp = (cmp < 0) ?
+ &(*rootp)->llink : /* follow llink branch */
+ &(*rootp)->rlink; /* follow rlink branch */
+ if (*rootp == NULL)
+ return NULL; /* key not found */
+ }
+ r = (*rootp)->rlink; /* D1: */
+ if ((q = (*rootp)->llink) == NULL) /* Left NULL? */
+ q = r;
+ else if (r != NULL) { /* Right link is NULL? */
+ if (r->llink == NULL) { /* D2: Find successor */
+ r->llink = q;
+ q = r;
+ } else { /* D3: Find NULL link */
+ for (q = r->llink; q->llink != NULL; q = r->llink)
+ r = q;
+ r->llink = q->rlink;
+ q->llink = (*rootp)->llink;
+ q->rlink = (*rootp)->rlink;
+ }
+ }
+ free(*rootp); /* D4: Free node */
+ *rootp = q; /* link parent to new node */
+ return *rootp;
+}
+
+/*
+ * find a node, or return 0
+ *
+ * Parameters:
+ * vkey: key to be found
+ * vrootp: address of the tree root
+ */
+ROKEN_LIB_FUNCTION void *
+rk_tfind(const void *vkey, void * const *vrootp,
+ int (*compar)(const void *, const void *))
+{
+ node_t **rootp = (node_t **)vrootp;
+
+ if (rootp == NULL)
+ return NULL;
+
+ while (*rootp != NULL) { /* T1: */
+ int r;
+
+ if ((r = (*compar)(vkey, (*rootp)->key)) == 0) /* T2: */
+ return *rootp; /* key found */
+ rootp = (r < 0) ?
+ &(*rootp)->llink : /* T3: follow left branch */
+ &(*rootp)->rlink; /* T4: follow right branch */
+ }
+ return NULL;
+}
diff --git a/third_party/heimdal/lib/roken/unsetenv.c b/third_party/heimdal/lib/roken/unsetenv.c
new file mode 100644
index 0000000..55ba5e3
--- /dev/null
+++ b/third_party/heimdal/lib/roken/unsetenv.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "roken.h"
+
+#if !HAVE_DECL_ENVIRON
+extern char **environ;
+#endif
+
+/*
+ * unsetenv --
+ */
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+unsetenv(const char *name)
+{
+ int len;
+ const char *np;
+ char **p;
+
+ if (name == 0 || environ == 0)
+ return;
+
+ for (np = name; *np && *np != '='; np++)
+ /* nop */;
+ len = np - name;
+
+ for (p = environ; *p != 0; p++)
+ if (strncmp(*p, name, len) == 0 && (*p)[len] == '=')
+ break;
+
+ for (; *p != 0; p++)
+ *p = *(p + 1);
+}
+
diff --git a/third_party/heimdal/lib/roken/unvis.c b/third_party/heimdal/lib/roken/unvis.c
new file mode 100644
index 0000000..6ceda4a
--- /dev/null
+++ b/third_party/heimdal/lib/roken/unvis.c
@@ -0,0 +1,283 @@
+/* $NetBSD: unvis.c,v 1.19 2000/01/22 22:19:13 mycroft 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.
+ */
+
+#if 1
+#include <config.h>
+#include "roken.h"
+#ifndef _DIAGASSERT
+#define _DIAGASSERT(X)
+#endif
+#else
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)unvis.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: unvis.c,v 1.19 2000/01/22 22:19:13 mycroft Exp $");
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#define __LIBC12_SOURCE__
+
+#include "namespace.h"
+#endif
+#include <sys/types.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <vis.h>
+
+#if 0
+#ifdef __weak_alias
+__weak_alias(strunvis,_strunvis)
+__weak_alias(unvis,_unvis)
+#endif
+
+__warn_references(unvis,
+ "warning: reference to compatibility unvis(); include <vis.h> for correct reference")
+#endif
+
+/*
+ * decode driven by state machine
+ */
+#define S_GROUND 0 /* haven't seen escape char */
+#define S_START 1 /* start decoding special sequence */
+#define S_META 2 /* metachar started (M) */
+#define S_META1 3 /* metachar more, regular char (-) */
+#define S_CTRL 4 /* control char started (^) */
+#define S_OCTAL2 5 /* octal digit 2 */
+#define S_OCTAL3 6 /* octal digit 3 */
+
+#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+ rk_strunvis (char *, const char *);
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+ rk_unvis (char *, int, int *, int);
+
+/*
+ * unvis - decode characters previously encoded by vis
+ */
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_unvis(char *cp, int c, int *astate, int flag)
+{
+
+ _DIAGASSERT(cp != NULL);
+ _DIAGASSERT(astate != NULL);
+
+ if (flag & UNVIS_END) {
+ if (*astate == S_OCTAL2 || *astate == S_OCTAL3) {
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ }
+ return (*astate == S_GROUND ? UNVIS_NOCHAR : UNVIS_SYNBAD);
+ }
+
+ switch (*astate) {
+
+ case S_GROUND:
+ *cp = 0;
+ if (c == '\\') {
+ *astate = S_START;
+ return (0);
+ }
+ *cp = c;
+ return (UNVIS_VALID);
+
+ case S_START:
+ switch(c) {
+ case '\\':
+ *cp = c;
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ *cp = (c - '0');
+ *astate = S_OCTAL2;
+ return (0);
+ case 'M':
+ *cp = (u_char)0200;
+ *astate = S_META;
+ return (0);
+ case '^':
+ *astate = S_CTRL;
+ return (0);
+ case 'n':
+ *cp = '\n';
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case 'r':
+ *cp = '\r';
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case 'b':
+ *cp = '\b';
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case 'a':
+ *cp = '\007';
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case 'v':
+ *cp = '\v';
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case 't':
+ *cp = '\t';
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case 'f':
+ *cp = '\f';
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case 's':
+ *cp = ' ';
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case 'E':
+ *cp = '\033';
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+ case '\n':
+ /*
+ * hidden newline
+ */
+ *astate = S_GROUND;
+ return (UNVIS_NOCHAR);
+ case '$':
+ /*
+ * hidden marker
+ */
+ *astate = S_GROUND;
+ return (UNVIS_NOCHAR);
+ }
+ *astate = S_GROUND;
+ return (UNVIS_SYNBAD);
+
+ case S_META:
+ if (c == '-')
+ *astate = S_META1;
+ else if (c == '^')
+ *astate = S_CTRL;
+ else {
+ *astate = S_GROUND;
+ return (UNVIS_SYNBAD);
+ }
+ return (0);
+
+ case S_META1:
+ *astate = S_GROUND;
+ *cp |= c;
+ return (UNVIS_VALID);
+
+ case S_CTRL:
+ if (c == '?')
+ *cp |= 0177;
+ else
+ *cp |= c & 037;
+ *astate = S_GROUND;
+ return (UNVIS_VALID);
+
+ case S_OCTAL2: /* second possible octal digit */
+ if (isoctal(c)) {
+ /*
+ * yes - and maybe a third
+ */
+ *cp = (*cp << 3) + (c - '0');
+ *astate = S_OCTAL3;
+ return (0);
+ }
+ /*
+ * no - done with current sequence, push back passed char
+ */
+ *astate = S_GROUND;
+ return (UNVIS_VALIDPUSH);
+
+ case S_OCTAL3: /* third possible octal digit */
+ *astate = S_GROUND;
+ if (isoctal(c)) {
+ *cp = (*cp << 3) + (c - '0');
+ return (UNVIS_VALID);
+ }
+ /*
+ * we were done, push back passed char
+ */
+ return (UNVIS_VALIDPUSH);
+
+ default:
+ /*
+ * decoder in unknown state - (probably uninitialized)
+ */
+ *astate = S_GROUND;
+ return (UNVIS_SYNBAD);
+ }
+}
+
+/*
+ * strunvis - decode src into dst
+ *
+ * Number of chars decoded into dst is returned, -1 on error.
+ * Dst is null terminated.
+ */
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_strunvis(char *dst, const char *src)
+{
+ char c;
+ char *start = dst;
+ int state = 0;
+
+ _DIAGASSERT(src != NULL);
+ _DIAGASSERT(dst != NULL);
+
+ while ((c = *src++) != '\0') {
+ again:
+ switch (rk_unvis(dst, (unsigned char)c, &state, 0)) {
+ case UNVIS_VALID:
+ dst++;
+ break;
+ case UNVIS_VALIDPUSH:
+ dst++;
+ goto again;
+ case 0:
+ case UNVIS_NOCHAR:
+ break;
+ default:
+ return (-1);
+ }
+ }
+ if (unvis(dst, (unsigned char)c, &state, UNVIS_END) == UNVIS_VALID)
+ dst++;
+ *dst = '\0';
+ return (dst - start);
+}
diff --git a/third_party/heimdal/lib/roken/verr.c b/third_party/heimdal/lib/roken/verr.c
new file mode 100644
index 0000000..9201e6d
--- /dev/null
+++ b/third_party/heimdal/lib/roken/verr.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 1995 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+#include <err.h>
+
+ROKEN_LIB_NORETURN_FUNCTION void ROKEN_LIB_CALL
+verr(int eval, const char *fmt, va_list ap)
+{
+ rk_warnerr(1, fmt, ap);
+ exit(eval);
+}
diff --git a/third_party/heimdal/lib/roken/verrx.c b/third_party/heimdal/lib/roken/verrx.c
new file mode 100644
index 0000000..7b148a4
--- /dev/null
+++ b/third_party/heimdal/lib/roken/verrx.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 1995 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+#include <err.h>
+
+ROKEN_LIB_NORETURN_FUNCTION void ROKEN_LIB_CALL
+verrx(int eval, const char *fmt, va_list ap)
+{
+ rk_warnerr(0, fmt, ap);
+ exit(eval);
+}
diff --git a/third_party/heimdal/lib/roken/version-script.map b/third_party/heimdal/lib/roken/version-script.map
new file mode 100644
index 0000000..b48e06b
--- /dev/null
+++ b/third_party/heimdal/lib/roken/version-script.map
@@ -0,0 +1,241 @@
+HEIMDAL_ROKEN_2.0 {
+ global:
+ arg_printusage;
+ arg_printusage_i18n;
+ cgetclose;
+ cgetmatch;
+ cgetnum;
+ cgetset;
+ cgetustr;
+ ct_memcmp;
+ err;
+ errx;
+ free_getarg_strings;
+ fseeko;
+ ftello;
+ get_window_size;
+ getarg;
+ getnameinfo_verified;
+ hex_decode;
+ hex_encode;
+ issuid;
+ mini_inetd;
+ mini_inetd_addrinfo;
+ net_read;
+ net_write;
+ parse_bytes;
+ parse_flags;
+ parse_time;
+ parse_units;
+ print_flags_table;
+ print_time_table;
+ print_units_table;
+ rk_asnprintf;
+ rk_asprintf;
+ rk_base32_decode;
+ rk_base32_encode;
+ rk_base64_decode;
+ rk_base64_encode;
+ rk_bswap16;
+ rk_bswap32;
+ rk_bswap64;
+ rk_cloexec;
+ rk_cloexec_dir;
+ rk_cloexec_file;
+ rk_cloexec_socket;
+ rk_closefrom;
+ rk_clzll;
+ rk_copyhostent;
+ rk_dns_free_data;
+ rk_dns_lookup;
+ rk_dns_srv_order;
+ rk_dns_string_to_type;
+ rk_dns_type_to_string;
+ rk_dumpdata;
+ rk_easprintf;
+ rk_ecalloc;
+ rk_emalloc;
+ rk_eread;
+ rk_erealloc;
+ rk_esetenv;
+ rk_estrdup;
+ rk_evasprintf;
+ rk_ewrite;
+ rk_flock;
+ rk_fnmatch;
+ rk_free_environment;
+ rk_freeaddrinfo;
+ rk_freehostent;
+ rk_freeifaddrs;
+ rk_gai_strerror;
+ rk_getaddrinfo;
+ rk_getauxv;
+ rk_getauxval;
+ rk_getifaddrs;
+ rk_getipnodebyaddr;
+ rk_getipnodebyname;
+ rk_getnameinfo;
+ rk_getprogname;
+ rk_glob;
+ rk_globfree;
+ rk_hex_decode;
+ rk_hex_encode;
+ rk_hostent_find_fqdn;
+ rk_inet_ntop;
+ rk_inet_pton;
+ rk_injectauxv;
+ rk_localtime_r;
+ rk_memmem;
+ rk_memset_s;
+ rk_mergesort;
+ rk_mergesort_r;
+ rk_mkdir;
+ rk_mkdtemp;
+ rk_mkostemp;
+ rk_mkstemp;
+ rk_parse_flags;
+ rk_parse_time;
+ rk_parse_units;
+ rk_pid_file_delete;
+ rk_pid_file_write;
+ rk_pidfile;
+ rk_pipe_execv;
+ rk_print_flags_table;
+ rk_print_time_table;
+ rk_print_units_table;
+ rk_random_init;
+ rk_read_environment;
+ rk_readv;
+ rk_realloc;
+ rk_secure_getenv;
+ rk_setprogname;
+ rk_simple_execle;
+ rk_simple_execlp;
+ rk_simple_execve;
+ rk_simple_execve_timed;
+ rk_simple_execvp;
+ rk_simple_execvp_timed;
+ rk_socket;
+ rk_socket_addr_size;
+ rk_socket_get_address;
+ rk_socket_get_port;
+ rk_socket_set_address_and_port;
+ rk_socket_set_any;
+ rk_socket_set_debug;
+ rk_socket_set_ipv6only;
+ rk_socket_set_keepalive;
+ rk_socket_set_nonblocking;
+ rk_socket_set_port;
+ rk_socket_set_portrange;
+ rk_socket_set_reuseaddr;
+ rk_socket_set_tos;
+ rk_socket_sockaddr_size;
+ rk_strasvis;
+ rk_strasvisx;
+ rk_stravis;
+ rk_stravisx;
+ rk_strcollect;
+ rk_strerror;
+ rk_strerror_r;
+ rk_strftime;
+ rk_strlcat;
+ rk_strlcpy;
+ rk_strlwr;
+ rk_strndup;
+ rk_strnlen;
+ rk_strpoolcollect;
+ rk_strpoolfree;
+ rk_strpoolprintf;
+ rk_strptime;
+ rk_strrasvis;
+ rk_strrasvisx;
+ rk_strsep_copy;
+ rk_strsvis;
+ rk_strsvisx;
+ rk_strtoll;
+ rk_strtoull;
+ rk_strunvis;
+ rk_strunvisx;
+ rk_strupr;
+ rk_strvis;
+ rk_strvisx;
+ rk_svis;
+ rk_tdelete;
+ rk_tfind;
+ rk_timegm;
+ rk_time_add;
+ rk_time_sub;
+ rk_timevaladd;
+ rk_timevalfix;
+ rk_timevalsub;
+ rk_tsearch;
+ rk_twalk;
+ rk_undumpdata;
+ rk_undumptext;
+ rk_unparse_flags;
+ rk_unparse_time;
+ rk_unparse_time_approx;
+ rk_unparse_units;
+ rk_unparse_units_approx;
+ rk_unvis;
+ rk_vasnprintf;
+ rk_vasprintf;
+ rk_vis;
+ rk_vsnprintf;
+ rk_vstrcollect;
+ rk_wait_for_process;
+ rk_wait_for_process_timed;
+ rk_warnerr;
+ rk_xfree;
+ roken_concat;
+ roken_detach_finish;
+ roken_detach_prep;
+ roken_getaddrinfo_hostspec2;
+ roken_getaddrinfo_hostspec;
+ roken_gethostby_setup;
+ roken_gethostbyaddr;
+ roken_gethostbyname;
+ roken_get_appdatadir;
+ roken_get_homedir;
+ roken_get_shell;
+ roken_get_username;
+ roken_get_loginname;
+ roken_mconcat;
+ roken_vconcat;
+ roken_vmconcat;
+ rtbl_add_column;
+ rtbl_add_column_by_id;
+ rtbl_add_column_entry;
+ rtbl_add_column_entry_by_id;
+ rtbl_add_column_entryv;
+ rtbl_add_column_entryv_by_id;
+ rtbl_create;
+ rtbl_destroy;
+ rtbl_format;
+ rtbl_get_flags;
+ rtbl_new_row;
+ rtbl_set_column_affix_by_id;
+ rtbl_set_column_prefix;
+ rtbl_set_flags;
+ rtbl_set_prefix;
+ rtbl_set_separator;
+ signal;
+ simple_execl;
+ tm2time;
+ unparse_bytes;
+ unparse_bytes_short;
+ unparse_flags;
+ unparse_time;
+ unparse_time_approx;
+ unparse_units;
+ unparse_units_approx;
+ verr;
+ verrx;
+ vwarn;
+ vwarnx;
+ warn;
+ warnx;
+ writev;
+ local:
+ *;
+};
diff --git a/third_party/heimdal/lib/roken/versionsupport.h b/third_party/heimdal/lib/roken/versionsupport.h
new file mode 100644
index 0000000..09adce3
--- /dev/null
+++ b/third_party/heimdal/lib/roken/versionsupport.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2018-2019, AuriStor, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDER 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.
+ *
+ */
+
+#ifndef _VERSIONSUPPORT_H_
+#define _VERSIONSUPPORT_H_ 1
+
+/*
+ * IsWindowsVersionOrGreater() is provided by Windows SDK 8.1 or greater.
+ * As AuriStorFS supports building with SDK 7.0 and greater we must
+ * provide our own. VerifyVersionInfoW() is present on Windows XP and
+ * later.
+ */
+
+#ifndef _WIN32_WINNT_WIN7
+#define _WIN32_WINNT_WIN7 0x0601
+#endif
+
+#ifndef _WIN32_WINNT_WIN8
+#define _WIN32_WINNT_WIN8 0x0602
+#endif
+
+#ifndef _WIN32_WINNT_WINBLUE
+#define _WIN32_WINNT_WINBLUE 0x0603
+#endif
+
+/* Based upon VersionHelpers.h */
+FORCEINLINE BOOL
+IsWindowsVersionOrGreater(WORD wMajorVersion,
+ WORD wMinorVersion,
+ WORD wServicePackMajor)
+{
+ OSVERSIONINFOEXW osvi;
+ DWORDLONG dwlConditionMask = 0;
+
+ dwlConditionMask = VerSetConditionMask(dwlConditionMask,
+ VER_MAJORVERSION,
+ VER_GREATER_EQUAL);
+ dwlConditionMask = VerSetConditionMask(dwlConditionMask,
+ VER_MINORVERSION,
+ VER_GREATER_EQUAL);
+ dwlConditionMask = VerSetConditionMask(dwlConditionMask,
+ VER_SERVICEPACKMAJOR,
+ VER_GREATER_EQUAL);
+
+ memset(&osvi, 0, sizeof(OSVERSIONINFOEXW));
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
+ osvi.dwMajorVersion = wMajorVersion;
+ osvi.dwMinorVersion = wMinorVersion;
+ osvi.wServicePackMajor = wServicePackMajor;
+
+ return VerifyVersionInfoW(&osvi,
+ (VER_MAJORVERSION |
+ VER_MINORVERSION |
+ VER_SERVICEPACKMAJOR),
+ dwlConditionMask);
+}
+
+FORCEINLINE BOOL
+IsWindowsXPOrGreater(VOID)
+{
+ return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP),
+ LOBYTE(_WIN32_WINNT_WINXP),
+ 0);
+}
+
+FORCEINLINE BOOL
+IsWindows7OrGreater(VOID)
+{
+ return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7),
+ LOBYTE(_WIN32_WINNT_WIN7),
+ 0);
+}
+
+FORCEINLINE BOOL
+IsWindows8OrGreater(VOID)
+{
+ return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8),
+ LOBYTE(_WIN32_WINNT_WIN8),
+ 0);
+}
+
+FORCEINLINE BOOL
+IsWindows8Point1OrGreater(VOID)
+{
+ return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINBLUE),
+ LOBYTE(_WIN32_WINNT_WINBLUE),
+ 0);
+}
+
+#define IS_WINDOWS_VERSION_OR_GREATER_CACHED(fn) \
+ \
+FORCEINLINE BOOL \
+fn##Cached(VOID) \
+{ \
+ static LONG lIsVersionOrGreater = -1; \
+ \
+ if (lIsVersionOrGreater == -1) { \
+ LONG lResult = fn(); \
+ InterlockedCompareExchangeRelease(&lIsVersionOrGreater, \
+ lResult, -1); \
+ } \
+ \
+ return lIsVersionOrGreater == 1; \
+}
+
+IS_WINDOWS_VERSION_OR_GREATER_CACHED(IsWindowsXPOrGreater)
+IS_WINDOWS_VERSION_OR_GREATER_CACHED(IsWindows7OrGreater)
+IS_WINDOWS_VERSION_OR_GREATER_CACHED(IsWindows8OrGreater)
+IS_WINDOWS_VERSION_OR_GREATER_CACHED(IsWindows8Point1OrGreater)
+
+#endif /* _VERSIONSUPPORT_H_ */
diff --git a/third_party/heimdal/lib/roken/vis-extras.h b/third_party/heimdal/lib/roken/vis-extras.h
new file mode 100644
index 0000000..693edf8
--- /dev/null
+++ b/third_party/heimdal/lib/roken/vis-extras.h
@@ -0,0 +1,27 @@
+#ifndef _VIS_EXTRAS_H_
+#define _VIS_EXTRAS_H_
+
+#include <roken.h>
+
+ROKEN_CPP_START
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+ rk_strasvis(char **, const char *, int, const char *);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+ rk_strasvisx(char **, const char *, size_t, int, const char *);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+ rk_strrasvis(char **, size_t *, const char *, int, const char *);
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+ rk_strrasvisx(char **, size_t *, const char *, size_t, int, const char *);
+
+ROKEN_CPP_END
+
+#define strasvis(a, b, c, d) rk_strasvis(a, b, c, d)
+#define strasvisx(a, b, c, d) rk_strasvisx(a, b, c, d)
+#define strrasvis(a, b, c, d) rk_strrasvis(a, b, c, d)
+#define strrasvisx(a, b, c, d) rk_strrasvisx(a, b, c, d)
+
+#endif /* !_VIS_EXTRAS_H_ */
diff --git a/third_party/heimdal/lib/roken/vis.c b/third_party/heimdal/lib/roken/vis.c
new file mode 100644
index 0000000..0fe44ae
--- /dev/null
+++ b/third_party/heimdal/lib/roken/vis.c
@@ -0,0 +1,649 @@
+/* $NetBSD: vis.c,v 1.37 2008/07/25 22:29:23 dsl 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.
+ */
+
+/*-
+ * Copyright (c) 1999, 2005 The NetBSD Foundation, Inc.
+ * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define _DEFAULT_SOURCE
+#include <config.h>
+#include "roken.h"
+#ifdef TEST
+#include "getarg.h"
+#endif
+#ifndef _DIAGASSERT
+#define _DIAGASSERT(X)
+#endif
+
+#include <sys/types.h>
+#include <assert.h>
+#include <ctype.h>
+#ifdef TEST
+#include <err.h>
+#endif
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <vis.h>
+
+#if !HAVE_VIS || !HAVE_SVIS
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#endif
+
+#if !HAVE_VIS || !HAVE_SVIS || TEST
+/*
+ * We use makextralist() in main(), so we need it even if we have all the VIS
+ * routines in the host's C libraries.
+ */
+
+/* 5 is for VIS_SP, VIS_TAB, VIS_NL, VIS_DQ, and VIS_NOSLASH */
+#define MAXEXTRAS (sizeof(char_glob) - 1 + sizeof(char_shell) - 1 + 5)
+
+#ifndef VIS_SHELL
+#define VIS_SHELL 0x2000
+#endif
+#ifndef VIS_GLOB
+#define VIS_GLOB 0x0100
+#endif
+
+#ifndef VIS_SP
+#define VIS_SP 0x0004 /* also encode space */
+#endif
+#ifndef VIS_TAB
+#define VIS_TAB 0x0008 /* also encode tab */
+#endif
+#ifndef VIS_NL
+#define VIS_NL 0x0010 /* also encode newline */
+#endif
+#ifndef VIS_WHITE
+#define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL)
+#endif
+#ifndef VIS_SAFE
+#define VIS_SAFE 0x0020 /* only encode "unsafe" characters */
+#endif
+#ifndef VIS_DQ
+#define VIS_DQ 0x8000 /* also encode double quotes */
+#endif
+
+
+/*
+ * Expand list of extra characters to not visually encode.
+ */
+static char *
+makeextralist(int flags, const char *src)
+{
+ static const char char_glob[] = "*?[#";
+ static const char char_shell[] = "'`\";&<>()|{}]\\$!^~";
+ char *dst, *d;
+ size_t len;
+
+ len = strlen(src);
+ if ((dst = d = calloc(1, len + MAXEXTRAS + 1)) == NULL)
+ return NULL;
+
+ memcpy(dst, src, len);
+ d += len;
+
+ if (flags & VIS_GLOB) {
+ memcpy(d, char_glob, sizeof(char_glob) - 1);
+ d += sizeof(char_glob) - 1;
+ }
+ if (flags & VIS_SHELL) {
+ memcpy(d, char_shell, sizeof(char_shell) - 1);
+ d += sizeof(char_shell) - 1;
+ }
+
+ if (flags & VIS_SP) *d++ = ' ';
+ if (flags & VIS_TAB) *d++ = '\t';
+ if (flags & VIS_NL) *d++ = '\n';
+ if (flags & VIS_DQ) *d++ = '"';
+ if ((flags & VIS_NOSLASH) == 0) *d++ = '\\';
+
+ return dst;
+}
+#endif
+
+#if !HAVE_VIS || !HAVE_SVIS
+static char *do_svis(char *, int, int, int, const char *);
+
+#undef BELL
+#if defined(__STDC__)
+#define BELL '\a'
+#else
+#define BELL '\007'
+#endif
+
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+ rk_vis (char *, int, int, int);
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+ rk_svis (char *, int, int, int, const char *);
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+ rk_strvis (char *, const char *, int);
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+ rk_strsvis (char *, const char *, int, const char *);
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+ rk_strvisx (char *, const char *, size_t, int);
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+ rk_strsvisx (char *, const char *, size_t, int, const char *);
+
+#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
+#define iswhite(c) (c == ' ' || c == '\t' || c == '\n')
+#define issafe(c) (c == '\b' || c == BELL || c == '\r')
+#define xtoa(c) "0123456789abcdef"[c]
+
+/*
+ * This is do_hvis, for HTTP style (RFC 1808)
+ */
+static char *
+do_hvis(char *dst, int c, int flag, int nextc, const char *extra)
+{
+ if (!isascii(c) || !isalnum(c) || strchr("$-_.+!*'(),", c) != NULL ||
+ strchr(extra, c)) {
+ *dst++ = '%';
+ *dst++ = xtoa(((unsigned int)c >> 4) & 0xf);
+ *dst++ = xtoa((unsigned int)c & 0xf);
+ } else {
+ dst = do_svis(dst, c, flag, nextc, extra);
+ }
+ return dst;
+}
+
+/*
+ * This is do_vis, the central code of vis.
+ * dst: Pointer to the destination buffer
+ * c: Character to encode
+ * flag: Flag word
+ * nextc: The character following 'c'
+ * extra: Pointer to the list of extra characters to be
+ * backslash-protected.
+ */
+static char *
+do_svis(char *dst, int c, int flag, int nextc, const char *extra)
+{
+ int isextra;
+ isextra = strchr(extra, c) != NULL;
+ if (!isextra && isascii(c) && (isgraph(c) || iswhite(c) ||
+ ((flag & VIS_SAFE) && issafe(c)))) {
+ *dst++ = c;
+ return dst;
+ }
+ if (flag & VIS_CSTYLE) {
+ switch (c) {
+ case '\n':
+ *dst++ = '\\'; *dst++ = 'n';
+ return dst;
+ case '\r':
+ *dst++ = '\\'; *dst++ = 'r';
+ return dst;
+ case '\b':
+ *dst++ = '\\'; *dst++ = 'b';
+ return dst;
+ case BELL:
+ *dst++ = '\\'; *dst++ = 'a';
+ return dst;
+ case '\v':
+ *dst++ = '\\'; *dst++ = 'v';
+ return dst;
+ case '\t':
+ *dst++ = '\\'; *dst++ = 't';
+ return dst;
+ case '\f':
+ *dst++ = '\\'; *dst++ = 'f';
+ return dst;
+ case ' ':
+ *dst++ = '\\'; *dst++ = 's';
+ return dst;
+ case '\0':
+ *dst++ = '\\'; *dst++ = '0';
+ if (isoctal(nextc)) {
+ *dst++ = '0';
+ *dst++ = '0';
+ }
+ return dst;
+ default:
+ if (isgraph(c)) {
+ *dst++ = '\\'; *dst++ = c;
+ return dst;
+ }
+ }
+ }
+ if (isextra || ((c & 0177) == ' ') || (flag & VIS_OCTAL)) {
+ *dst++ = '\\';
+ *dst++ = (u_char)(((unsigned int)(u_char)c >> 6) & 03) + '0';
+ *dst++ = (u_char)(((unsigned int)(u_char)c >> 3) & 07) + '0';
+ *dst++ = (u_char)( c & 07) + '0';
+ } else {
+ if ((flag & VIS_NOSLASH) == 0) *dst++ = '\\';
+ if (c & 0200) {
+ c &= 0177; *dst++ = 'M';
+ }
+ if (iscntrl(c)) {
+ *dst++ = '^';
+ if (c == 0177)
+ *dst++ = '?';
+ else
+ *dst++ = c + '@';
+ } else {
+ *dst++ = '-'; *dst++ = c;
+ }
+ }
+ return dst;
+}
+
+
+/*
+ * svis - visually encode characters, also encoding the characters
+ * pointed to by `extra'
+ */
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+rk_svis(char *dst, int c, int flag, int nextc, const char *extra)
+{
+ char *nextra = NULL;
+
+ _DIAGASSERT(dst != NULL);
+ _DIAGASSERT(extra != NULL);
+ nextra = makeextralist(flag, extra);
+ if (!nextra) {
+ *dst = '\0'; /* can't create nextra, return "" */
+ return dst;
+ }
+ if (flag & VIS_HTTPSTYLE)
+ dst = do_hvis(dst, c, flag, nextc, nextra);
+ else
+ dst = do_svis(dst, c, flag, nextc, nextra);
+ free(nextra);
+ *dst = '\0';
+ return dst;
+}
+
+
+/*
+ * strsvis, strsvisx - visually encode characters from src into dst
+ *
+ * Extra is a pointer to a \0-terminated list of characters to
+ * be encoded, too. These functions are useful e. g. to
+ * encode strings in such a way so that they are not interpreted
+ * by a shell.
+ *
+ * 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.
+ *
+ * Strsvisx encodes exactly len bytes from src into dst.
+ * This is useful for encoding a block of data.
+ */
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_strsvis(char *dst, const char *csrc, int flag, const char *extra)
+{
+ int c;
+ char *start;
+ char *nextra = NULL;
+ const unsigned char *src = (const unsigned char *)csrc;
+
+ _DIAGASSERT(dst != NULL);
+ _DIAGASSERT(src != NULL);
+ _DIAGASSERT(extra != NULL);
+ nextra = makeextralist(flag, extra);
+ if (!nextra) {
+ *dst = '\0'; /* can't create nextra, return "" */
+ return 0;
+ }
+ if (flag & VIS_HTTPSTYLE) {
+ for (start = dst; (c = *src++) != '\0'; /* empty */)
+ dst = do_hvis(dst, c, flag, *src, nextra);
+ } else {
+ for (start = dst; (c = *src++) != '\0'; /* empty */)
+ dst = do_svis(dst, c, flag, *src, nextra);
+ }
+ free(nextra);
+ *dst = '\0';
+ return (dst - start);
+}
+
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_strsvisx(char *dst, const char *csrc, size_t len, int flag, const char *extra)
+{
+ unsigned char c;
+ char *start;
+ char *nextra = NULL;
+ const unsigned char *src = (const unsigned char *)csrc;
+
+ _DIAGASSERT(dst != NULL);
+ _DIAGASSERT(src != NULL);
+ _DIAGASSERT(extra != NULL);
+ nextra = makeextralist(flag, extra);
+ if (! nextra) {
+ *dst = '\0'; /* can't create nextra, return "" */
+ return 0;
+ }
+
+ if (flag & VIS_HTTPSTYLE) {
+ for (start = dst; len > 0; len--) {
+ c = *src++;
+ dst = do_hvis(dst, c, flag, *src, nextra);
+ }
+ } else {
+ for (start = dst; len > 0; len--) {
+ c = *src++;
+ dst = do_svis(dst, c, flag, *src, nextra);
+ }
+ }
+ free(nextra);
+ *dst = '\0';
+ return (dst - start);
+}
+#endif
+
+/*
+ * Heimdal innovations: functions that allocate or reallocate a destination
+ * buffer as needed. Based on OpenBSD's stravis().
+ */
+
+#include <vis-extras.h>
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_strasvis(char **out, const char *csrc, int flag, const char *extra)
+{
+ return rk_strasvisx(out, csrc, strlen(csrc), flag, extra);
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_strrasvis(char **out, size_t *outsz, const char *csrc, int flag, const char *extra)
+{
+ return rk_strrasvisx(out, outsz, csrc, strlen(csrc), flag, extra);
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_strasvisx(char **out, const char *csrc, size_t len, int flag, const char *extra)
+{
+ size_t sz = 0;
+
+ *out = NULL;
+ return rk_strrasvisx(out, &sz, csrc, strlen(csrc), flag, extra);
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_strrasvisx(char **out,
+ size_t *outsz,
+ const char *csrc,
+ size_t len,
+ int flag,
+ const char *extra)
+{
+ size_t want = 4 * len + 4;
+ size_t have = *outsz;
+ char *s = *out;
+ int r;
+
+ _DIAGASSERT(dst != NULL);
+ _DIAGASSERT(src != NULL);
+ _DIAGASSERT(extra != NULL);
+ if (want < len || want > INT_MAX) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ if (have < want) {
+ if ((s = realloc(s, want)) == NULL)
+ return -1;
+ *outsz = want;
+ *out = s;
+ }
+ if (*out == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ **out = '\0'; /* Makes source debugging nicer, that's all */
+ r = strsvisx(*out, csrc, len, flag, extra);
+ return r;
+}
+
+#if !HAVE_VIS
+/*
+ * vis - visually encode characters
+ */
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+rk_vis(char *dst, int c, int flag, int nextc)
+{
+ char *extra = NULL;
+ unsigned char uc = (unsigned char)c;
+
+ _DIAGASSERT(dst != NULL);
+
+ extra = makeextralist(flag, "");
+ if (! extra) {
+ *dst = '\0'; /* can't create extra, return "" */
+ return dst;
+ }
+ if (flag & VIS_HTTPSTYLE)
+ dst = do_hvis(dst, uc, flag, nextc, extra);
+ else
+ dst = do_svis(dst, uc, flag, nextc, extra);
+ free(extra);
+ *dst = '\0';
+ return dst;
+}
+
+
+/*
+ * strvis, 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.
+ *
+ * Strvisx encodes exactly len bytes from src into dst.
+ * This is useful for encoding a block of data.
+ */
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_strvis(char *dst, const char *src, int flag)
+{
+ char *extra = NULL;
+ int rv;
+
+ extra = makeextralist(flag, "");
+ if (!extra) {
+ *dst = '\0'; /* can't create extra, return "" */
+ return 0;
+ }
+ rv = strsvis(dst, src, flag, extra);
+ free(extra);
+ return rv;
+}
+
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+rk_strvisx(char *dst, const char *src, size_t len, int flag)
+{
+ char *extra = NULL;
+ int rv;
+
+ extra = makeextralist(flag, "");
+ if (!extra) {
+ *dst = '\0'; /* can't create extra, return "" */
+ return 0;
+ }
+ rv = strsvisx(dst, src, len, flag, extra);
+ free(extra);
+ return rv;
+}
+#endif
+
+#ifdef TEST
+static const char *extra_arg = "";
+static int cstyle_flag;
+static int glob_flag;
+static int help_flag;
+static int http_flag;
+static int httponly_flag;
+static int line_flag;
+static int octal_flag;
+static int safe_flag;
+static int shell_flag;
+static int stdin_flag;
+static int tab_flag;
+static int whitespace_flag;
+
+/*
+ * The short options are compatible with a subset of the FreeBSD contrib
+ * vis(1). Heimdal additions have long option names only.
+ */
+static struct getargs args[] = {
+ { "c", 'C', arg_flag, &cstyle_flag, "C style", "C style" },
+ { "extra", 'e', arg_string, &extra_arg, "also encode extra", "also encode extra"},
+ { "glob", 'g', arg_flag, &glob_flag, "escape glob specials", "escape glob specials" },
+ { "help", 0, arg_flag, &help_flag, "help", "help"},
+ { "line", 0, arg_flag, &line_flag, "read and escape stdin without escaping newlines", NULL },
+ { "octal", 'o', arg_flag, &octal_flag, "octal escape", "octal escape" },
+ { "safe", 's', arg_flag, &safe_flag, "only encode \"unsafe\" characters", "only encode \"unsafe\" characters" },
+ { "shell", 'S', arg_flag, &shell_flag, "encode shell meta-characters", "encode shell meta-characters" },
+ { "stdin", 0, arg_flag, &stdin_flag, "read and escape stdin", NULL },
+ { "tab", 't', arg_flag, &tab_flag, "encode tabs", "encode tabs" },
+ { "url", 'h', arg_flag, &http_flag, "url escape", "url escape" },
+ { "url-only", 0, arg_flag, &httponly_flag, "url escape", "url escape" },
+ { "whitespace", 'w', arg_flag, &whitespace_flag, "encode whitespace", "encode whitespace" },
+ { 0, 0, 0, 0, 0, 0}
+};
+static size_t num_args = sizeof(args)/sizeof(args[0]);
+
+int
+main(int argc, char **argv)
+{
+ size_t sz = 0;
+ char *nextra = NULL;
+ char *s = NULL;
+ int goptind = 0;
+ int flags = 0;
+
+ setprogname("vis");
+ if (getarg(args, num_args, argc, argv, &goptind) || help_flag) {
+ arg_printusage(args, num_args, NULL, "strings...");
+ return help_flag ? 0 : 1;
+ }
+
+ argc -= goptind;
+ argv += goptind;
+
+ if (argc == 0 && !stdin_flag && !line_flag) {
+ arg_printusage(args, num_args, NULL, "strings...");
+ return 1;
+ }
+
+ if (http_flag && cstyle_flag)
+ errx(1, "--http and --cstyle are mutually exclusive");
+
+ flags |= cstyle_flag ? VIS_CSTYLE : 0;
+ flags |= http_flag ? VIS_HTTPSTYLE : 0;
+ flags |= httponly_flag ? VIS_HTTPSTYLE | VIS_NOESCAPE : 0;
+ flags |= octal_flag ? VIS_OCTAL : 0;
+ flags |= safe_flag ? VIS_SAFE : 0;
+ flags |= tab_flag ? VIS_TAB : 0;
+ flags |= whitespace_flag ? VIS_WHITE : 0;
+
+ if ((nextra = makeextralist(flags, extra_arg)) == NULL)
+ err(1, "Out of memory");
+
+ while (argc) {
+ if (rk_strrasvis(&s, &sz, argv[0], flags, nextra) < 0)
+ err(2, "Out of memory");
+ printf("%s\n", s);
+ argc--;
+ }
+ if (line_flag) {
+ ssize_t nbytes;
+ size_t linesz = 0;
+ char *line = NULL;
+
+ while (!feof(stdin) &&
+ (nbytes = getline(&line, &linesz, stdin)) > 0) {
+ const char *nl = "";
+
+ if (line[nbytes - 1] == '\n') {
+ line[--nbytes] = '\0';
+ nl = "\n";
+ }
+
+ if (rk_strrasvisx(&s, &sz, line, nbytes, flags, nextra) < 0)
+ err(2, "Out of memory");
+ printf("%s%s", s, nl);
+ }
+ fflush(stdout);
+ if (ferror(stdin))
+ errx(2, "I/O error");
+ } else if (stdin_flag) {
+ size_t nbytes;
+ char buf[2048 + 1];
+ char vbuf[4 * (sizeof(buf) - 1) + 1];
+
+ while (!feof(stdin) &&
+ (nbytes = fread(buf, 1, sizeof(buf) - 1, stdin))) {
+ buf[nbytes] = '\0';
+ strsvis(vbuf, buf, flags, nextra);
+ printf("%s", vbuf);
+ }
+ fflush(stdout);
+ if (ferror(stdin))
+ errx(2, "I/O error");
+ }
+
+ free(nextra);
+ free(s);
+ return 0;
+}
+#endif
diff --git a/third_party/heimdal/lib/roken/vis.hin b/third_party/heimdal/lib/roken/vis.hin
new file mode 100644
index 0000000..f1027f5
--- /dev/null
+++ b/third_party/heimdal/lib/roken/vis.hin
@@ -0,0 +1,170 @@
+/* $NetBSD: vis.h,v 1.16 2005/09/13 01:44:32 christos 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.
+ *
+ * @(#)vis.h 8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _VIS_H_
+#define _VIS_H_
+
+#ifndef ROKEN_LIB_FUNCTION
+#ifdef _WIN32
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL __cdecl
+#else
+#define ROKEN_LIB_FUNCTION
+#define ROKEN_LIB_CALL
+#endif
+#endif
+
+#include <sys/types.h>
+
+#include <roken.h>
+
+/*
+ * to select alternate encoding format
+ */
+#define VIS_OCTAL 0x0001 /* use octal \ddd format */
+#define VIS_CSTYLE 0x0002 /* use \[nrft0..] where appropiate */
+
+/*
+ * to alter set of characters encoded (default is to encode all
+ * non-graphic except space, tab, and newline).
+ */
+#define VIS_SP 0x0004 /* also encode space */
+#define VIS_TAB 0x0008 /* also encode tab */
+#define VIS_NL 0x0010 /* also encode newline */
+#define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL)
+#define VIS_SAFE 0x0020 /* only encode "unsafe" characters */
+#define VIS_DQ 0x8000 /* also encode double quotes */
+
+/*
+ * other
+ */
+#define VIS_NOSLASH 0x0040 /* inhibit printing '\' */
+#define VIS_HTTPSTYLE 0x0080 /* http-style escape % HEX HEX */
+#define VIS_HTTP1808 0x0080 /* http-style escape % hex hex */
+#define VIS_GLOB 0x0100 /* encode glob(3) magic characters */
+#if 0
+/*
+ * Not yet. FreeBSD calls 0x0400 VIS_HTTP1866, but if that means RFC1866,
+ * that's HTML 2.0, not HTTP. Argh.
+ */
+#define VIS_MIMESTYLE 0x0200 /* mime-style escape = HEX HEX */
+#define VIS_HTML1866 0x0400 /* HTML-style &#num; or &string; */
+#endif
+#define VIS_NOESCAPE 0x0800 /* don't decode `\'; URL-encode only when given
+ * with VIS_HTTPSTYLE */
+#if 0
+#define _VIS_END 0x1000 /* for unvis */
+#endif
+#define VIS_SHELL 0x2000 /* encode shell special characters [not glob] */
+#define VIS_META (VIS_WHITE | VIS_GLOB | VIS_SHELL)
+#define VIS_NOLOCALE 0x4000 /* encode using the C locale */
+
+/*
+ * 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 */
+
+ROKEN_CPP_START
+
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+ rk_vis(char *, int, int, int);
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+ rk_svis(char *, int, int, int, const char *);
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+ rk_strvis(char *, const char *, int);
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+ rk_strsvis(char *, const char *, int, const char *);
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+ rk_strvisx(char *, const char *, size_t, int);
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+ rk_strsvisx(char *, const char *, size_t, int, const char *);
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+ rk_strunvis(char *, const char *);
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+ rk_strunvisx(char *, const char *, int);
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+ rk_unvis(char *, int, int *, int);
+
+ROKEN_CPP_END
+
+#ifndef HAVE_VIS
+#undef vis
+#define vis(a,b,c,d) rk_vis(a,b,c,d)
+#endif
+
+#ifndef HAVE_SVIS
+#undef svis
+#define svis(a,b,c,d,e) rk_svis(a,b,c,d,e)
+#endif
+
+#ifndef HAVE_STRVIS
+#undef strvis
+#define strvis(a,b,c) rk_strvis(a,b,c)
+#endif
+
+#ifndef HAVE_STRSVIS
+#undef strsvis
+#define strsvis(a,b,c,d) rk_strsvis(a,b,c,d)
+#endif
+
+#ifndef HAVE_STRVISX
+#undef strvisx
+#define strvisx(a,b,c,d) rk_strvisx(a,b,c,d)
+#endif
+
+#ifndef HAVE_STRSVISX
+#undef strsvisx
+#define strsvisx(a,b,c,d,e) rk_strsvisx(a,b,c,d,e)
+#endif
+
+#ifndef HAVE_STRUNVIS
+#undef strunvis
+#define strunvis(a,b) rk_strunvis(a,b)
+#endif
+
+
+#ifndef HAVE_UNVIS
+#undef unvis
+#define unvis(a,b,c,d) rk_unvis(a,b,c,d)
+#endif
+
+#endif /* !_VIS_H_ */
diff --git a/third_party/heimdal/lib/roken/vsyslog.c b/third_party/heimdal/lib/roken/vsyslog.c
new file mode 100644
index 0000000..aea7086
--- /dev/null
+++ b/third_party/heimdal/lib/roken/vsyslog.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 1995 - 2000 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#ifndef HAVE_VSYSLOG
+
+#include <stdio.h>
+#include <syslog.h>
+#include <stdarg.h>
+
+#include "roken.h"
+
+/*
+ * the theory behind this is that we might be trying to call vsyslog
+ * when there's no memory left, and we should try to be as useful as
+ * possible. And the format string should say something about what's
+ * failing.
+ */
+
+static void
+simple_vsyslog(int pri, const char *fmt, va_list ap)
+{
+ syslog (pri, "%s", fmt);
+}
+
+/*
+ * do like syslog but with a `va_list'
+ */
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+vsyslog(int pri, const char *fmt, va_list ap)
+{
+ char *fmt2;
+ const char *p;
+ char *p2;
+ int ret;
+ int saved_errno = errno;
+ int fmt_len = strlen (fmt);
+ int fmt2_len = fmt_len;
+ char *buf;
+
+ fmt2 = malloc (fmt_len + 1);
+ if (fmt2 == NULL) {
+ simple_vsyslog (pri, fmt, ap);
+ return;
+ }
+
+ for (p = fmt, p2 = fmt2; *p != '\0'; ++p) {
+ if (p[0] == '%' && p[1] == 'm') {
+ const char *e = strerror (saved_errno);
+ int e_len = strlen (e);
+ char *tmp;
+ int pos;
+
+ pos = p2 - fmt2;
+ fmt2_len += e_len - 2;
+ tmp = realloc (fmt2, fmt2_len + 1);
+ if (tmp == NULL) {
+ free (fmt2);
+ simple_vsyslog (pri, fmt, ap);
+ return;
+ }
+ fmt2 = tmp;
+ p2 = fmt2 + pos;
+ memmove (p2, e, e_len);
+ p2 += e_len;
+ ++p;
+ } else
+ *p2++ = *p;
+ }
+ *p2 = '\0';
+
+ ret = vasprintf (&buf, fmt2, ap);
+ free (fmt2);
+ if (ret < 0 || buf == NULL) {
+ simple_vsyslog (pri, fmt, ap);
+ return;
+ }
+ syslog (pri, "%s", buf);
+ free (buf);
+}
+#endif
diff --git a/third_party/heimdal/lib/roken/vwarn.c b/third_party/heimdal/lib/roken/vwarn.c
new file mode 100644
index 0000000..8f1706d
--- /dev/null
+++ b/third_party/heimdal/lib/roken/vwarn.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1995 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+#include <err.h>
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+vwarn(const char *fmt, va_list ap)
+{
+ rk_warnerr(1, fmt, ap);
+}
diff --git a/third_party/heimdal/lib/roken/vwarnx.c b/third_party/heimdal/lib/roken/vwarnx.c
new file mode 100644
index 0000000..6fb1d8c
--- /dev/null
+++ b/third_party/heimdal/lib/roken/vwarnx.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 1995 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+#include <err.h>
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+vwarnx(const char *fmt, va_list ap)
+{
+ rk_warnerr(0, fmt, ap);
+}
+
diff --git a/third_party/heimdal/lib/roken/warn.c b/third_party/heimdal/lib/roken/warn.c
new file mode 100644
index 0000000..e149c56
--- /dev/null
+++ b/third_party/heimdal/lib/roken/warn.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+#include "err.h"
+
+void
+warn(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vwarn(fmt, ap);
+ va_end(ap);
+}
diff --git a/third_party/heimdal/lib/roken/warnerr.c b/third_party/heimdal/lib/roken/warnerr.c
new file mode 100644
index 0000000..9e67023
--- /dev/null
+++ b/third_party/heimdal/lib/roken/warnerr.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1995 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+#include "err.h"
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rk_warnerr(int doerrno, const char *fmt, va_list ap)
+{
+ int sverrno = errno;
+ const char *progname = getprogname();
+
+ if(progname != NULL){
+ fprintf(stderr, "%s", progname);
+ if(fmt != NULL || doerrno)
+ fprintf(stderr, ": ");
+ }
+ if (fmt != NULL){
+ vfprintf(stderr, fmt, ap);
+ if(doerrno)
+ fprintf(stderr, ": ");
+ }
+ if(doerrno)
+ fprintf(stderr, "%s", strerror(sverrno));
+ fprintf(stderr, "\n");
+}
diff --git a/third_party/heimdal/lib/roken/warnx.c b/third_party/heimdal/lib/roken/warnx.c
new file mode 100644
index 0000000..cf33939
--- /dev/null
+++ b/third_party/heimdal/lib/roken/warnx.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "err.h"
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+warnx(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vwarnx(fmt, ap);
+ va_end(ap);
+}
diff --git a/third_party/heimdal/lib/roken/win32_alloc.c b/third_party/heimdal/lib/roken/win32_alloc.c
new file mode 100644
index 0000000..40fe0f4
--- /dev/null
+++ b/third_party/heimdal/lib/roken/win32_alloc.c
@@ -0,0 +1,76 @@
+/***********************************************************************
+ * Copyright (c) 2012, Secure Endpoints Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDER 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 <config.h>
+#include "roken.h"
+#undef calloc
+#undef malloc
+#undef free
+#undef strdup
+#undef wcsdup
+
+/*
+ * Windows executables and dlls suffer when memory is
+ * allocated with one allocator and deallocated with
+ * another because each allocator is backed by a separate
+ * heap. Reduce the exposure by ensuring that all
+ * binaries that are built using roken will build against
+ * same allocator.
+ */
+
+ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL
+rk_calloc(size_t elements, size_t size)
+{
+ return calloc( elements, size);
+}
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rk_free(void * ptr)
+{
+ free( ptr);
+}
+
+ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL
+rk_malloc(size_t size)
+{
+ return malloc( size);
+}
+
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+rk_strdup(const char *str)
+{
+ return strdup( str);
+}
+
+ROKEN_LIB_FUNCTION unsigned short * ROKEN_LIB_CALL
+rk_wcsdup(const unsigned short *str)
+{
+ return wcsdup( str);
+}
diff --git a/third_party/heimdal/lib/roken/win32_version.c b/third_party/heimdal/lib/roken/win32_version.c
new file mode 100644
index 0000000..faf05b8
--- /dev/null
+++ b/third_party/heimdal/lib/roken/win32_version.c
@@ -0,0 +1,128 @@
+#include <config.h>
+#include "roken.h"
+#include <psapi.h>
+
+static DWORD
+GetVersionInfo(CHAR *filename, CHAR *szOutput, DWORD dwOutput)
+{
+ DWORD dwVersionHandle;
+ LPVOID pVersionInfo = 0;
+ DWORD retval = 0;
+ LPDWORD pLangInfo = 0;
+ LPTSTR szVersion = 0;
+ UINT len = 0;
+ TCHAR szVerQ[] = TEXT("\\StringFileInfo\\12345678\\FileVersion");
+ DWORD size = GetFileVersionInfoSize(filename, &dwVersionHandle);
+
+ if (!size)
+ return GetLastError();
+
+ pVersionInfo = malloc(size);
+ if (!pVersionInfo)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ GetFileVersionInfo(filename, dwVersionHandle, size, pVersionInfo);
+ if (retval = GetLastError())
+ goto cleanup;
+
+ VerQueryValue(pVersionInfo, TEXT("\\VarFileInfo\\Translation"),
+ (LPVOID*)&pLangInfo, &len);
+ if (retval = GetLastError())
+ goto cleanup;
+
+ wsprintf(szVerQ,
+ TEXT("\\StringFileInfo\\%04x%04x\\FileVersion"),
+ LOWORD(*pLangInfo), HIWORD(*pLangInfo));
+
+ VerQueryValue(pVersionInfo, szVerQ, (LPVOID*)&szVersion, &len);
+ if (retval = GetLastError()) {
+ /* try again with language 409 since the old binaries were tagged wrong */
+ wsprintf(szVerQ,
+ TEXT("\\StringFileInfo\\0409%04x\\FileVersion"),
+ HIWORD(*pLangInfo));
+
+ VerQueryValue(pVersionInfo, szVerQ, (LPVOID*)&szVersion, &len);
+ if (retval = GetLastError())
+ goto cleanup;
+ }
+ snprintf(szOutput, dwOutput, TEXT("%s"), szVersion);
+ szOutput[dwOutput - 1] = 0;
+
+ cleanup:
+ free(pVersionInfo);
+
+ return retval;
+}
+
+ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
+win32_getLibraryVersion(const char *libname, char **outname, char **outversion)
+{
+ CHAR modVersion[128];
+ HMODULE hMods[1024];
+ HANDLE hProcess;
+ DWORD cbNeeded;
+ unsigned int i;
+ int success = -1;
+ HINSTANCE hPSAPI;
+ DWORD (WINAPI *pGetModuleFileNameExA)(HANDLE hProcess, HMODULE hModule, LPTSTR lpFilename, DWORD nSize);
+ BOOL (WINAPI *pEnumProcessModules)(HANDLE hProcess, HMODULE* lphModule, DWORD cb, LPDWORD lpcbNeeded);
+
+ if (outversion)
+ *outversion = NULL;
+ if (outname)
+ *outname = NULL;
+
+ hPSAPI = LoadLibrary("psapi");
+ if ( hPSAPI == NULL )
+ return -1;
+
+ if (((FARPROC) pGetModuleFileNameExA =
+ GetProcAddress( hPSAPI, "GetModuleFileNameExA" )) == NULL ||
+ ((FARPROC) pEnumProcessModules =
+ GetProcAddress( hPSAPI, "EnumProcessModules" )) == NULL)
+ {
+ goto out;
+ }
+
+ // Get a list of all the modules in this process.
+ hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
+ FALSE, GetCurrentProcessId());
+
+ if (pEnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
+ {
+ for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
+ {
+ char szModName[2048];
+
+ // Get the full path to the module's file.
+ if (pGetModuleFileNameExA(hProcess, hMods[i], szModName, sizeof(szModName)))
+ {
+ CHAR checkName[1024];
+ lstrcpy(checkName, szModName);
+ strlwr(checkName);
+
+ if (strstr(checkName, libname)) {
+ if (GetVersionInfo(szModName, modVersion, sizeof(modVersion)) == 0) {
+ success = 0;
+ if (outversion) {
+ *outversion = strdup(modVersion);
+ if (*outversion == NULL)
+ success = -1;
+ }
+ if (outname) {
+ *outname = strdup(szModName);
+ if (*outname == NULL)
+ success = -1;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ CloseHandle(hProcess);
+
+ out:
+ FreeLibrary(hPSAPI);
+ return success;
+}
diff --git a/third_party/heimdal/lib/roken/write_pid.c b/third_party/heimdal/lib/roken/write_pid.c
new file mode 100644
index 0000000..c010912
--- /dev/null
+++ b/third_party/heimdal/lib/roken/write_pid.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 1999 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+#ifdef HAVE_UTIL_H
+#include <util.h>
+#endif
+
+ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
+pid_file_write(const char *progname)
+{
+ const char *pidfile_dir = NULL;
+ const char *sep = "/";
+ size_t pidfile_dir_len;
+ char *ret = NULL;
+ FILE *fp;
+
+ /*
+ * Maybe we could have a version of this function (and pidfile())
+ * where we get a directory from the caller. That would allow us to
+ * have command-line options for the daemons for this.
+ *
+ * For now we use an environment variable.
+ */
+ pidfile_dir = secure_getenv("HEIM_PIDFILE_DIR");
+ if (pidfile_dir == NULL)
+ pidfile_dir = _PATH_VARRUN;
+
+ pidfile_dir_len = strlen(pidfile_dir);
+ if (pidfile_dir_len > 1 &&
+ pidfile_dir[pidfile_dir_len - 1] == '/')
+ sep = "";
+#ifdef WIN32
+ if (pidfile_dir_len > 1 &&
+ pidfile_dir[pidfile_dir_len - 1] == '\\')
+ sep = "";
+#endif
+
+ if (asprintf(&ret, "%s%s%s.pid", pidfile_dir, sep, progname) < 0 || ret == NULL)
+ return NULL;
+ fp = fopen(ret, "w");
+ if (fp == NULL) {
+ free(ret);
+ return NULL;
+ }
+ fprintf(fp, "%lu\n", (unsigned long)getpid());
+ fclose(fp);
+ return ret;
+}
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+pid_file_delete(char **filename)
+{
+ if (*filename != NULL) {
+ unlink(*filename);
+ free(*filename);
+ *filename = NULL;
+ }
+}
+
+static char *pidfile_path;
+static pid_t pidfile_pid;
+
+static void
+pidfile_cleanup(void)
+{
+ if (pidfile_path != NULL && pidfile_pid == getpid())
+ pid_file_delete(&pidfile_path);
+}
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+rk_pidfile(const char *bname)
+{
+ /*
+ * If the OS has a pidfile(), call that, but still call
+ * pid_file_write(). Even if both want to write the same file,
+ * writing it twice will still work.
+ */
+#ifdef HAVE_PIDFILE
+ pidfile(bname);
+#endif
+
+ if (pidfile_path != NULL)
+ return;
+ if (bname == NULL)
+ bname = getprogname();
+ pidfile_path = pid_file_write(bname);
+ pidfile_pid = getpid();
+#if defined(HAVE_ATEXIT)
+ if (pidfile_path != NULL)
+ atexit(pidfile_cleanup);
+#elif defined(HAVE_ON_EXIT)
+ if (pidfile_path != NULL)
+ on_exit(pidfile_cleanup);
+#endif
+}
diff --git a/third_party/heimdal/lib/roken/writev.c b/third_party/heimdal/lib/roken/writev.c
new file mode 100644
index 0000000..80945e9
--- /dev/null
+++ b/third_party/heimdal/lib/roken/writev.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+ROKEN_LIB_FUNCTION ssize_t ROKEN_LIB_CALL
+writev(int d, const struct iovec *iov, int iovcnt)
+{
+ ssize_t ret;
+ size_t tot = 0;
+ int i;
+ char *buf, *p;
+
+ for(i = 0; i < iovcnt; ++i)
+ tot += iov[i].iov_len;
+ buf = malloc(tot);
+ if (tot != 0 && buf == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+ p = buf;
+ for (i = 0; i < iovcnt; ++i) {
+ memcpy (p, iov[i].iov_base, iov[i].iov_len);
+ p += iov[i].iov_len;
+ }
+ ret = write (d, buf, tot);
+ free (buf);
+ return ret;
+}
diff --git a/third_party/heimdal/lib/roken/xdbm.h b/third_party/heimdal/lib/roken/xdbm.h
new file mode 100644
index 0000000..c2c6c28
--- /dev/null
+++ b/third_party/heimdal/lib/roken/xdbm.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1995 - 2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
+ */
+
+/* $Id$ */
+
+/* Generic *dbm include file */
+
+#ifndef __XDBM_H__
+#define __XDBM_H__
+
+#if HAVE_DB_NDBM
+#define DB_DBM_HSEARCH 1
+#include <db.h>
+#elif HAVE_NDBM
+#if defined(HAVE_GDBM_NDBM_H)
+#include <gdbm/ndbm.h>
+#elif defined(HAVE_NDBM_H)
+#include <ndbm.h>
+#endif
+#endif /* HAVE_NDBM */
+
+#endif /* __XDBM_H__ */
diff --git a/third_party/heimdal/lib/roken/xfree.c b/third_party/heimdal/lib/roken/xfree.c
new file mode 100644
index 0000000..c7e30da
--- /dev/null
+++ b/third_party/heimdal/lib/roken/xfree.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2008 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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 Institute 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 INSTITUTE 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 INSTITUTE 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 <config.h>
+
+#include "roken.h"
+
+void ROKEN_LIB_FUNCTION
+rk_xfree (void *buf)
+{
+ free(buf);
+}