summaryrefslogtreecommitdiffstats
path: root/lib/util/regress
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--lib/util/regress/closefrom/closefrom_test.c121
-rw-r--r--lib/util/regress/corpus/seed/sudo_conf/sudo.conf.1116
-rw-r--r--lib/util/regress/corpus/seed/sudo_conf/sudo.conf.2116
-rw-r--r--lib/util/regress/corpus/seed/sudo_conf/sudo.conf.3126
-rw-r--r--lib/util/regress/digest/digest_test.c1179
-rw-r--r--lib/util/regress/fnmatch/fnm_test.c92
-rw-r--r--lib/util/regress/fnmatch/fnm_test.in6
-rw-r--r--lib/util/regress/fuzz/fuzz_sudo_conf.c149
-rw-r--r--lib/util/regress/fuzz/fuzz_sudo_conf.dict18
-rw-r--r--lib/util/regress/getdelim/getdelim_test.c186
-rw-r--r--lib/util/regress/getgrouplist/getgids.c91
-rw-r--r--lib/util/regress/getgrouplist/getgrouplist_test.c117
-rw-r--r--lib/util/regress/glob/files47
-rw-r--r--lib/util/regress/glob/globtest.c224
-rw-r--r--lib/util/regress/glob/globtest.in64
-rwxr-xr-xlib/util/regress/harness.in109
-rw-r--r--lib/util/regress/hexchar/hexchar_test.c81
-rw-r--r--lib/util/regress/json/json_test.c235
-rw-r--r--lib/util/regress/mktemp/mktemp_test.c205
-rw-r--r--lib/util/regress/multiarch/multiarch_test.c184
-rw-r--r--lib/util/regress/open_parent_dir/open_parent_dir_test.c166
-rw-r--r--lib/util/regress/parse_gids/parse_gids_test.c124
-rw-r--r--lib/util/regress/progname/progname_test.c67
-rw-r--r--lib/util/regress/regex/regex_test.c126
-rw-r--r--lib/util/regress/strsig/strsig_test.c319
-rw-r--r--lib/util/regress/strsplit/strsplit_test.c117
-rw-r--r--lib/util/regress/strtofoo/strtobool_test.c98
-rw-r--r--lib/util/regress/strtofoo/strtoid_test.c118
-rw-r--r--lib/util/regress/strtofoo/strtomode_test.c91
-rw-r--r--lib/util/regress/strtofoo/strtonum_test.c135
-rw-r--r--lib/util/regress/sudo_conf/conf_test.c126
-rw-r--r--lib/util/regress/sudo_conf/test1.in73
-rw-r--r--lib/util/regress/sudo_conf/test1.out.ok8
-rw-r--r--lib/util/regress/sudo_conf/test2.in0
-rw-r--r--lib/util/regress/sudo_conf/test2.out.ok4
-rw-r--r--lib/util/regress/sudo_conf/test3.in2
-rw-r--r--lib/util/regress/sudo_conf/test3.out.ok6
-rw-r--r--lib/util/regress/sudo_conf/test4.err.ok1
-rw-r--r--lib/util/regress/sudo_conf/test4.in1
-rw-r--r--lib/util/regress/sudo_conf/test4.out.ok4
-rw-r--r--lib/util/regress/sudo_conf/test5.err.ok1
-rw-r--r--lib/util/regress/sudo_conf/test5.in1
-rw-r--r--lib/util/regress/sudo_conf/test5.out.ok4
-rw-r--r--lib/util/regress/sudo_conf/test6.in1
-rw-r--r--lib/util/regress/sudo_conf/test6.out.ok4
-rw-r--r--lib/util/regress/sudo_conf/test7.in4
-rw-r--r--lib/util/regress/sudo_conf/test7.out.ok8
-rw-r--r--lib/util/regress/sudo_parseln/parseln_test.c64
-rw-r--r--lib/util/regress/sudo_parseln/test1.in72
-rw-r--r--lib/util/regress/sudo_parseln/test1.out.ok72
-rw-r--r--lib/util/regress/sudo_parseln/test2.in8
-rw-r--r--lib/util/regress/sudo_parseln/test2.out.ok3
-rw-r--r--lib/util/regress/sudo_parseln/test3.in1
-rw-r--r--lib/util/regress/sudo_parseln/test3.out.ok1
-rw-r--r--lib/util/regress/sudo_parseln/test4.in4
-rw-r--r--lib/util/regress/sudo_parseln/test4.out.ok2
-rw-r--r--lib/util/regress/sudo_parseln/test5.in1
-rw-r--r--lib/util/regress/sudo_parseln/test5.out.ok0
-rw-r--r--lib/util/regress/sudo_parseln/test6.in3
-rw-r--r--lib/util/regress/sudo_parseln/test6.out.ok2
-rw-r--r--lib/util/regress/tailq/hltq_test.c205
-rw-r--r--lib/util/regress/uuid/uuid_test.c105
62 files changed, 5618 insertions, 0 deletions
diff --git a/lib/util/regress/closefrom/closefrom_test.c b/lib/util/regress/closefrom/closefrom_test.c
new file mode 100644
index 0000000..750c951
--- /dev/null
+++ b/lib/util/regress/closefrom/closefrom_test.c
@@ -0,0 +1,121 @@
+/*
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2022 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define SUDO_ERROR_WRAP 0
+
+#include <sudo_compat.h>
+#include <sudo_fatal.h>
+#include <sudo_util.h>
+
+sudo_dso_public int main(int argc, char *argv[]);
+
+/*
+ * Test that sudo_closefrom() works as expected.
+ */
+
+int
+main(int argc, char *argv[])
+{
+ int ch, fds[2], flag, maxfd, minfd, errors = 0, ntests = 0;
+ initprogname(argc > 0 ? argv[0] : "closefrom_test");
+
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch (ch) {
+ case 'v':
+ /* ignore */
+ break;
+ default:
+ fprintf(stderr, "usage: %s [-v]\n", getprogname());
+ return EXIT_FAILURE;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* We use pipe() because it doesn't rely on the filesystem. */
+ ntests++;
+ if (pipe(fds) == -1) {
+ sudo_warn("%s", "pipe");
+ errors++;
+ goto done;
+ }
+ maxfd = MAX(fds[0], fds[1]);
+ minfd = MIN(fds[0], fds[1]);
+
+ /* Close any fds greater than fds[0] and fds[1]. */
+ sudo_closefrom(maxfd + 1);
+
+ /* Verify that sudo_closefrom() didn't close fds[0] or fds[1]. */
+ ntests++;
+ if (fcntl(fds[0], F_GETFL, 0) == -1) {
+ sudo_warnx("fd %d closed prematurely", fds[0]);
+ errors++;
+ goto done;
+ }
+ ntests++;
+ if (fcntl(fds[1], F_GETFL, 0) == -1) {
+ sudo_warnx("fd %d closed prematurely", fds[1]);
+ errors++;
+ goto done;
+ }
+
+ /* Close fds[0], fds[1] and above. */
+ sudo_closefrom(minfd);
+
+ /* Verify that sudo_closefrom() closed both fds. */
+ ntests++;
+ flag = fcntl(fds[0], F_GETFD, 0);
+#ifdef __APPLE__
+ /* We only set the close-on-exec flag on macOS. */
+ if (flag == 1)
+ flag = -1;
+#endif
+ if (flag != -1) {
+ sudo_warnx("fd %d still open", fds[0]);
+ errors++;
+ goto done;
+ }
+ ntests++;
+ flag = fcntl(fds[1], F_GETFD, 0);
+#ifdef __APPLE__
+ /* We only set the close-on-exec flag on macOS. */
+ if (flag == 1)
+ flag = -1;
+#endif
+ if (flag != -1) {
+ sudo_warnx("fd %d still open", fds[1]);
+ errors++;
+ goto done;
+ }
+
+done:
+ if (ntests != 0) {
+ printf("%s: %d tests run, %d errors, %d%% success rate\n",
+ getprogname(), ntests, errors, (ntests - errors) * 100 / ntests);
+ }
+ return errors;
+}
diff --git a/lib/util/regress/corpus/seed/sudo_conf/sudo.conf.1 b/lib/util/regress/corpus/seed/sudo_conf/sudo.conf.1
new file mode 100644
index 0000000..1a58c87
--- /dev/null
+++ b/lib/util/regress/corpus/seed/sudo_conf/sudo.conf.1
@@ -0,0 +1,116 @@
+#
+# Default /etc/sudo.conf file
+#
+# Sudo plugins:
+# Plugin plugin_name plugin_path plugin_options ...
+#
+# The plugin_path is relative to /usr/local/libexec/sudo unless
+# fully qualified.
+# The plugin_name corresponds to a global symbol in the plugin
+# that contains the plugin interface structure.
+# The plugin_options are optional.
+#
+# The sudoers plugin is used by default if no Plugin lines are present.
+#Plugin sudoers_policy sudoers.so
+#Plugin sudoers_io sudoers.so
+#Plugin sudoers_audit sudoers.so
+
+#
+# Sudo askpass:
+# Path askpass /path/to/askpass
+#
+# An askpass helper program may be specified to provide a graphical
+# password prompt for "sudo -A" support. Sudo does not ship with its
+# own askpass program but can use the OpenSSH askpass.
+#
+# Use the OpenSSH askpass
+#Path askpass /usr/X11R6/bin/ssh-askpass
+#
+# Use the Gnome OpenSSH askpass
+#Path askpass /usr/libexec/openssh/gnome-ssh-askpass
+
+#
+# Sudo device search path:
+# Path devsearch /dev/path1:/dev/path2:/dev
+#
+# A colon-separated list of paths to check when searching for a user's
+# terminal device.
+#
+#Path devsearch /dev/pts:/dev/vt:/dev/term:/dev/zcons:/dev/pty:/dev
+
+#
+# Sudo noexec:
+# Path noexec /path/to/sudo_noexec.so
+#
+# Path to a shared library containing replacements for the execv(),
+# execve() and fexecve() library functions that just return an error.
+# This is used to implement the "noexec" functionality on systems that
+# support LD_PRELOAD or its equivalent.
+#
+# The compiled-in value is usually sufficient and should only be changed
+# if you rename or move the sudo_noexec.so file.
+#
+#Path noexec /usr/local/libexec/sudo/sudo_noexec.so
+
+#
+# Sudo plugin directory:
+# Path plugin_dir /path/to/plugins
+#
+# The default directory to use when searching for plugins that are
+# specified without a fully qualified path name.
+#
+#Path plugin_dir /usr/local/libexec/sudo
+
+#
+# Core dumps:
+# Set disable_coredump true|false
+#
+# By default, sudo disables core dumps while it is executing (they
+# are re-enabled for the command that is run).
+# To aid in debugging sudo problems, you may wish to enable core
+# dumps by setting "disable_coredump" to false.
+#
+#Set disable_coredump false
+
+#
+# User groups:
+# Set group_source static|dynamic|adaptive
+#
+# Sudo passes the user's group list to the policy plugin.
+# If the user is a member of the maximum number of groups (usually 16),
+# sudo will query the group database directly to be sure to include
+# the full list of groups.
+#
+# On some systems, this can be expensive so the behavior is configurable.
+# The "group_source" setting has three possible values:
+# static - use the user's list of groups returned by the kernel.
+# dynamic - query the group database to find the list of groups.
+# adaptive - if user is in less than the maximum number of groups.
+# use the kernel list, else query the group database.
+#
+#Set group_source static
+
+#
+# Sudo interface probing:
+# Set probe_interfaces true|false
+#
+# By default, sudo will probe the system's network interfaces and
+# pass the IP address of each enabled interface to the policy plugin.
+# On systems with a large number of virtual interfaces this may take
+# a noticeable amount of time.
+#
+#Set probe_interfaces false
+
+#
+# Sudo debug files:
+# Debug program /path/to/debug_log subsystem@priority[,subsyste@priority]
+#
+# Sudo and related programs support logging debug information to a file.
+# The program is typically sudo, sudoers.so, sudoreplay or visudo.
+#
+# Subsystems vary based on the program; "all" matches all subsystems.
+# Priority may be crit, err, warn, notice, diag, info, trace or debug.
+# Multiple subsystem@priority may be specified, separated by a comma.
+#
+#Debug sudo /var/log/sudo_debug all@debug
+#Debug sudoers.so /var/log/sudoers_debug all@debug
diff --git a/lib/util/regress/corpus/seed/sudo_conf/sudo.conf.2 b/lib/util/regress/corpus/seed/sudo_conf/sudo.conf.2
new file mode 100644
index 0000000..05039a5
--- /dev/null
+++ b/lib/util/regress/corpus/seed/sudo_conf/sudo.conf.2
@@ -0,0 +1,116 @@
+#
+# Default /etc/sudo.conf file
+#
+# Sudo plugins:
+# Plugin plugin_name plugin_path plugin_options ...
+#
+# The plugin_path is relative to /usr/local/libexec/sudo unless
+# fully qualified.
+# The plugin_name corresponds to a global symbol in the plugin
+# that contains the plugin interface structure.
+# The plugin_options are optional.
+#
+# The sudoers plugin is used by default if no Plugin lines are present.
+Plugin sudoers_policy sudoers.so
+Plugin sudoers_io sudoers.so
+Plugin sudoers_audit sudoers.so
+
+#
+# Sudo askpass:
+# Path askpass /path/to/askpass
+#
+# An askpass helper program may be specified to provide a graphical
+# password prompt for "sudo -A" support. Sudo does not ship with its
+# own askpass program but can use the OpenSSH askpass.
+#
+# Use the OpenSSH askpass
+Path askpass /usr/X11R6/bin/ssh-askpass
+#
+# Use the Gnome OpenSSH askpass
+Path askpass /usr/libexec/openssh/gnome-ssh-askpass
+
+#
+# Sudo device search path:
+# Path devsearch /dev/path1:/dev/path2:/dev
+#
+# A colon-separated list of paths to check when searching for a user's
+# terminal device.
+#
+Path devsearch /dev/pts:/dev/vt:/dev/term:/dev/zcons:/dev/pty:/dev
+
+#
+# Sudo noexec:
+# Path noexec /path/to/sudo_noexec.so
+#
+# Path to a shared library containing replacements for the execv(),
+# execve() and fexecve() library functions that just return an error.
+# This is used to implement the "noexec" functionality on systems that
+# support LD_PRELOAD or its equivalent.
+#
+# The compiled-in value is usually sufficient and should only be changed
+# if you rename or move the sudo_noexec.so file.
+#
+Path noexec /usr/local/libexec/sudo/sudo_noexec.so
+
+#
+# Sudo plugin directory:
+# Path plugin_dir /path/to/plugins
+#
+# The default directory to use when searching for plugins that are
+# specified without a fully qualified path name.
+#
+Path plugin_dir /usr/local/libexec/sudo
+
+#
+# Core dumps:
+# Set disable_coredump true|false
+#
+# By default, sudo disables core dumps while it is executing (they
+# are re-enabled for the command that is run).
+# To aid in debugging sudo problems, you may wish to enable core
+# dumps by setting "disable_coredump" to false.
+#
+Set disable_coredump false
+
+#
+# User groups:
+# Set group_source static|dynamic|adaptive
+#
+# Sudo passes the user's group list to the policy plugin.
+# If the user is a member of the maximum number of groups (usually 16),
+# sudo will query the group database directly to be sure to include
+# the full list of groups.
+#
+# On some systems, this can be expensive so the behavior is configurable.
+# The "group_source" setting has three possible values:
+# static - use the user's list of groups returned by the kernel.
+# dynamic - query the group database to find the list of groups.
+# adaptive - if user is in less than the maximum number of groups.
+# use the kernel list, else query the group database.
+#
+Set group_source static
+
+#
+# Sudo interface probing:
+# Set probe_interfaces true|false
+#
+# By default, sudo will probe the system's network interfaces and
+# pass the IP address of each enabled interface to the policy plugin.
+# On systems with a large number of virtual interfaces this may take
+# a noticeable amount of time.
+#
+Set probe_interfaces false
+
+#
+# Sudo debug files:
+# Debug program /path/to/debug_log subsystem@priority[,subsyste@priority]
+#
+# Sudo and related programs support logging debug information to a file.
+# The program is typically sudo, sudoers.so, sudoreplay or visudo.
+#
+# Subsystems vary based on the program; "all" matches all subsystems.
+# Priority may be crit, err, warn, notice, diag, info, trace or debug.
+# Multiple subsystem@priority may be specified, separated by a comma.
+#
+Debug sudo /var/log/sudo_debug all@debug
+Debug sudoers.so /var/log/sudoers_debug all@debug
diff --git a/lib/util/regress/corpus/seed/sudo_conf/sudo.conf.3 b/lib/util/regress/corpus/seed/sudo_conf/sudo.conf.3
new file mode 100644
index 0000000..bcfafb2
--- /dev/null
+++ b/lib/util/regress/corpus/seed/sudo_conf/sudo.conf.3
@@ -0,0 +1,126 @@
+#
+# Default /etc/sudo.conf file
+#
+# Sudo plugins:
+# Plugin plugin_name plugin_path plugin_options ...
+#
+# The plugin_path is relative to /usr/local/libexec/sudo unless
+# fully qualified.
+# The plugin_name corresponds to a global symbol in the plugin
+# that contains the plugin interface structure.
+# The plugin_options are optional.
+#
+# The sudoers plugin is used by default if no Plugin lines are present.
+Plugin sudoers_policy sudoers.so
+Plugin sudoers_io sudoers.so
+Plugin sudoers_audit sudoers.so
+
+#
+# Sudo askpass:
+# Path askpass /path/to/askpass
+#
+# An askpass helper program may be specified to provide a graphical
+# password prompt for "sudo -A" support. Sudo does not ship with its
+# own askpass program but can use the OpenSSH askpass.
+#
+# Use the OpenSSH askpass
+Path askpass /usr/X11R6/bin/ssh-askpass
+#
+# Use the Gnome OpenSSH askpass
+Path askpass /usr/libexec/openssh/gnome-ssh-askpass
+
+#
+# Sudo device search path:
+# Path devsearch /dev/path1:/dev/path2:/dev
+#
+# A colon-separated list of paths to check when searching for a user's
+# terminal device.
+#
+Path devsearch /dev/pts:/dev/vt:/dev/term:/dev/zcons:/dev/pty:/dev
+
+#
+# Sudo noexec:
+# Path noexec /path/to/sudo_noexec.so
+#
+# Path to a shared library containing replacements for the execv(),
+# execve() and fexecve() library functions that just return an error.
+# This is used to implement the "noexec" functionality on systems that
+# support LD_PRELOAD or its equivalent.
+#
+# The compiled-in value is usually sufficient and should only be changed
+# if you rename or move the sudo_noexec.so file.
+#
+Path noexec /usr/local/libexec/sudo/sudo_noexec.so
+
+#
+# Sudo plugin directory:
+# Path plugin_dir /path/to/plugins
+#
+# The default directory to use when searching for plugins that are
+# specified without a fully qualified path name.
+#
+Path plugin_dir /usr/local/libexec/sudo
+
+#
+# Path to the sesh binary for SELinux support
+#
+Path sesh /usr/local/libexec/sudo/sesh
+
+#
+# Core dumps:
+# Set disable_coredump true|false
+#
+# By default, sudo disables core dumps while it is executing (they
+# are re-enabled for the command that is run).
+# To aid in debugging sudo problems, you may wish to enable core
+# dumps by setting "disable_coredump" to false.
+#
+Set disable_coredump true
+
+#
+# User groups:
+# Set group_source static|dynamic|adaptive
+#
+# Sudo passes the user's group list to the policy plugin.
+# If the user is a member of the maximum number of groups (usually 16),
+# sudo will query the group database directly to be sure to include
+# the full list of groups.
+#
+# On some systems, this can be expensive so the behavior is configurable.
+# The "group_source" setting has three possible values:
+# static - use the user's list of groups returned by the kernel.
+# dynamic - query the group database to find the list of groups.
+# adaptive - if user is in less than the maximum number of groups.
+# use the kernel list, else query the group database.
+#
+Set group_source dynamic
+
+#
+# Maximum number of groups to use
+#
+Set max_groups 8
+
+#
+# Sudo interface probing:
+# Set probe_interfaces true|false
+#
+# By default, sudo will probe the system's network interfaces and
+# pass the IP address of each enabled interface to the policy plugin.
+# On systems with a large number of virtual interfaces this may take
+# a noticeable amount of time.
+#
+Set probe_interfaces true
+
+#
+# Sudo debug files:
+# Debug program /path/to/debug_log subsystem@priority[,subsyste@priority]
+#
+# Sudo and related programs support logging debug information to a file.
+# The program is typically sudo, sudoers.so, sudoreplay or visudo.
+#
+# Subsystems vary based on the program; "all" matches all subsystems.
+# Priority may be crit, err, warn, notice, diag, info, trace or debug.
+# Multiple subsystem@priority may be specified, separated by a comma.
+#
+Debug sudo /var/log/sudo_debug all@debug
+Debug sudoers.so /var/log/sudoers_debug all@debug
diff --git a/lib/util/regress/digest/digest_test.c b/lib/util/regress/digest/digest_test.c
new file mode 100644
index 0000000..69740a9
--- /dev/null
+++ b/lib/util/regress/digest/digest_test.c
@@ -0,0 +1,1179 @@
+/*
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2023 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define SUDO_ERROR_WRAP 0
+
+#include <sudo_compat.h>
+#include <sudo_digest.h>
+#include <sudo_util.h>
+#include <sudo_fatal.h>
+
+sudo_dso_public int main(int argc, char *argv[]);
+
+static int errors, ntests;
+static const char hex[] = "0123456789abcdef";
+
+struct test_vector {
+ size_t len; /* length in bytes */
+ const char *str; /* input string (hex bytes) */
+ const char *md; /* message digest */
+};
+
+/* SHA224 short messages test vectors. */
+static struct test_vector sha224_vectors[] = {
+ {
+ 0,
+ "",
+ "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f"
+ }, {
+ 1,
+ "\x84",
+ "3cd36921df5d6963e73739cf4d20211e2d8877c19cff087ade9d0e3a"
+ }, {
+ 2,
+ "\x5c\x7b",
+ "daff9bce685eb831f97fc1225b03c275a6c112e2d6e76f5faf7a36e6"
+ }, {
+ 3,
+ "\x51\xca\x3d",
+ "2c8959023515476e38388abb43599a29876b4b33d56adc06032de3a2"
+ }, {
+ 4,
+ "\x60\x84\x34\x7e",
+ "ae57c0a6d49739ba338adfa53bdae063e5c09122b77604780a8eeaa3"
+ }, {
+ 5,
+ "\x49\x3e\x14\x62\x3c",
+ "7f631f295e024e74552083245ca8f988a3fb65680ae97c3040d2e65c"
+ }, {
+ 6,
+ "\xd7\x29\xd8\xcd\x16\x31",
+ "342e8e6b23c1c6a54910631f098e08e836259c57e49c1b1d023d166d"
+ }, {
+ 7,
+ "\xcb\xf2\x06\x1e\x10\xfa\xa5",
+ "3aa702b1b66dc57d7aec3ccdbdfbd88592d7520f843ba5d0fa481168"
+ }, {
+ 8,
+ "\x5f\x77\xb3\x66\x48\x23\xc3\x3e",
+ "bdf21ff325f754157ccf417f4855360a72e8fd117d28c8fe7da3ea38"
+ }, {
+ 9,
+ "\x10\x71\x3b\x89\x4d\xe4\xa7\x34\xc0",
+ "03842600c86f5cd60c3a2147a067cb962a05303c3488b05cb45327bd"
+ }, {
+ 10,
+ "\x00\x64\x70\xd5\x7d\xad\x98\x93\xdc\x03",
+ "c90026cda5ad24115059c62ae9add57793ade445d4742273288bbce7"
+ }, {
+ 11,
+ "\x6f\x29\xca\x27\x41\x90\x40\x07\x20\xbb\xa2",
+ "ac53157947aa4b2a19089182382a4363d182dd8e4ca79cd8571390be"
+ }, {
+ 12,
+ "\x17\xe8\x55\x61\x76\xfc\xca\x2a\xdd\xbd\xde\x29",
+ "cc6ad0488db0222066f740557b5758a19b30372b302332295d8c3aff"
+ }, {
+ 13,
+ "\xdb\xf1\x63\x60\x1d\xb9\xa1\x22\xa4\x02\x68\x24\xde",
+ "9849845f4e47e1ece9a1c1e01a0d896ffea61c6c8894a75a11ce5f49"
+ }, {
+ 14,
+ "\x5e\x1e\xf2\xad\x86\xce\xaf\x54\x39\xfe\x87\xd2\xec\x9b",
+ "223c5d5d4a0116b32cea044f9af0fe44babea1c5ab201502591bcd5f"
+ }, {
+ 15,
+ "\x65\xf3\xb9\x86\x6f\xb8\x00\x2b\x53\xcf\xaf\x80\x6f\x70\x2f",
+ "b1e0806a218d593821fde8e9eacc44ab5287c32209a94f011ab66b75"
+ }, {
+ 16,
+ "\xb7\x76\x70\x8f\xfb\x91\xb3\x51\x5a\xc4\x65\x98\xab\x9f\xa7\x96",
+ "427311b1d7ab2488791c4deeb4251d783fe5f9806bfdfb5188c5443d"
+ }, {
+ 17,
+ "\xa4\xbc\x10\xb1\xa6\x2c\x96\xd4\x59\xfb\xaf\x3a\x5a\xa3\xfa\xce\x73",
+ "d7e6634723ac25cb1879bdb1508da05313530419013fe255967a39e1"
+ }, {
+ 18,
+ "\x9e\x8f\x3c\x66\x45\xc1\x74\x9b\x55\xc5\x0d\x20\x18\xce\x40\xdc\x24\x27",
+ "2f5a583bf588c8988a572d128a95bea5ef1b66780a7d4be9c29efc31"
+ }, {
+ 19,
+ "\x2d\xb6\xd2\x07\xc0\xb7\xd9\x11\x7f\x24\xd7\x8e\xe5\x9a\xbf\x2f\x31\x69\x78",
+ "35681fce28307cae19522c23cbd4a77969347f7d8ee4a3088ba90ada"
+ }, {
+ 20,
+ "\x3d\xf5\xe7\xf3\x99\xf6\xdd\x61\xa1\x2a\x9d\x4e\x94\x64\xfc\x49\x97\xc1\xf3\x7b",
+ "a3e68076e30751085a843a6cbfbf0f3dee63d9c4219c914372e50b28"
+ }, {
+ 21,
+ "\x65\x78\x1d\x01\x8f\x27\xca\x0c\x72\xa9\xfa\x9a\xb4\x64\x8e\xd3\x69\x64\x6d\xd3\xce",
+ "d15ef0d872d02da6427b8d0349dea2f204e67133b7365b4b150efc3c"
+ }, {
+ 22,
+ "\xaf\x48\xee\xdd\xd9\x3f\xee\x69\xd1\xbd\x7d\xe4\x28\xa6\x39\x86\x01\x1d\x10\x94\x5e\xaf",
+ "b89d428ee42e397cf11029ecbb27baddd036c8938f51c8ab56b875ac"
+ }, {
+ 23,
+ "\xdf\x2b\xf0\xd5\xf9\xc9\x94\xac\x69\xd7\x8b\xaa\x0d\x51\x2e\xce\xb7\x4d\x8a\x04\x75\x31\xc1",
+ "db8e1ce68c8c6b84d6db755c2b8bf54f3c4b081a881efcddaf303294"
+ }, {
+ 24,
+ "\x48\xd2\xf2\x09\x55\xea\x2d\x13\x43\x3c\x20\xbc\x04\x04\xeb\x2e\x6a\xd7\x9e\xd2\x8f\x7c\xb4\xc0",
+ "3617cc3179f8b59adce181eebeed5e2763f62650949224a67e53694b"
+ }, {
+ 25,
+ "\x21\x8f\x74\xa4\x2d\x3a\x47\xef\x3b\x80\x66\x01\xfb\xa0\x24\xb0\x78\xcb\xff\x4e\x4b\x85\x77\x2e\x0e",
+ "b5f40b95dcc363b97e9d00b67c5d7c37f17ab563297d2d67a4df20c9"
+ }, {
+ 26,
+ "\xef\x55\xb1\xe7\x97\x00\x0b\x04\xfc\xdb\x9b\x30\x21\xb0\x93\x27\xe3\xb4\xe2\x69\xd2\x0c\xab\xdf\x41\x8f",
+ "827b223d51240c2e3271c534c19c5637b6fe10083e85bcf06761ef21"
+ }, {
+ 27,
+ "\x96\xdf\x43\x87\xdc\x2c\x40\x29\x70\x43\xbe\xa3\x64\x83\xf6\x5e\x4e\xb1\xe0\x7e\x93\x35\x9c\xb7\xe6\x86\x10",
+ "98e430a63fcdedafc9419010f7f59a4d816a45b4f973beb62530ff8c"
+ }, {
+ 28,
+ "\x3e\xc0\xaa\x8d\x30\xd5\xed\x82\x5b\x77\xdc\x70\x95\xf4\x21\xb1\xe6\x08\x15\x87\x97\xa3\x77\xff\x8b\xed\x64\x1b",
+ "3108321eb7ff857f6aae69101b937f32a51ea279a6c14ba5232ac8c1"
+ }, {
+ 29,
+ "\x8b\x02\x39\x71\x20\x39\xf0\x77\xce\x32\x3b\x35\xf4\xe3\x06\x78\x7b\x9b\x35\x27\x00\x96\xe5\x77\x35\xcf\xf4\x5d\x84",
+ "a5c740d3ce46bb2e0a048488f2b0605c6d0ca0ea2f382d043d13db97"
+ }, {
+ 30,
+ "\x04\x4b\xe3\x01\x67\xa9\x75\x8c\x46\xc7\x27\x92\x1d\xc4\xeb\x4e\x0d\xcb\x96\x56\x23\x42\x3e\x6f\xdd\x44\xe7\xa4\xea\x52",
+ "6eb78313c743ea8769d8340f284dda6ded64a1db64392f21abb82c5c"
+ }, {
+ 31,
+ "\x57\xf6\x11\x8b\xac\xce\x47\xec\xc3\x1c\xe8\xb0\xc0\x83\xd3\xc9\x21\x9e\x0d\xbe\x9e\x4f\xbe\xa1\x54\x53\x7c\x41\x23\x1a\xcc",
+ "0dbb53c866d63af44c222c76c825df0e379dcedfb958db03b6fd29a5"
+ }, {
+ 32,
+ "\xfe\x1f\x0f\xb0\x2c\x90\x11\xf4\xc8\xc5\x90\x59\x34\xed\x15\x13\x67\x71\x73\x7c\xe3\x1c\x58\x59\xe6\x7f\x23\x5f\xe5\x94\xf5\xf6",
+ "bbeaacc632c2a3db2a9b47f157ab54aa27776c6e74cf0bcaa91b06d5"
+ }, {
+ 33,
+ "\x14\xfb\x01\xae\x9d\x60\x15\xec\xb3\xe5\x6d\x6e\xcd\xfa\x4b\xc0\x53\x31\x86\xad\xf8\x45\x7f\x5e\x4a\x5c\x57\xc6\x87\x89\x5f\x3d\xb3",
+ "178272c7d7cc71b15074c27e3b7997d4a3ba99626986a1a16cf30030"
+ }, {
+ 34,
+ "\xff\x6c\x49\x71\x2f\x04\x4f\x40\x63\xc1\x41\x25\xc0\xcd\xfb\xa1\x8e\xd8\xb7\x13\x84\x53\x76\x8a\x45\xdf\xa2\xd8\x2a\x05\xf1\xe8\x42\x27",
+ "403284c888a7280bc8bfc25f0c34182cd378306a21a1404d4e1c40cf"
+ }, {
+ 35,
+ "\xf9\x00\xbd\x7e\x01\x17\x24\x7f\x97\xc8\xfc\x7a\x66\x5c\x76\xa3\x5f\x57\x1c\x33\x66\x57\x1d\x6c\x4a\x3e\xe5\xd7\xfb\x93\xf1\xd1\xf7\x26\xe2",
+ "48235b9820d66d8885faabf6a9ede63ba2a21b6177e987a33242373e"
+ }, {
+ 36,
+ "\x42\xd3\x81\x88\xac\x49\x44\x0c\xfe\xfb\x77\xdb\x97\x5e\x08\x3e\x6b\x22\x34\x8c\x4c\x67\xf0\xf8\x69\x2e\x88\xad\x14\x0d\x86\x1d\xc8\x28\xd5\x95",
+ "615344f890e5bcf71b5efe39de1fc942ba1fe30dd9e9146adb6a41bf"
+ }, {
+ 37,
+ "\x74\xfd\xd7\xd9\x58\xb8\xae\x7c\x2c\x3c\x5c\xff\x42\x66\xdf\xb2\xb3\xb8\x42\xc9\xf5\x9e\xcb\xbc\xaf\xf5\x75\xed\xcb\xcd\xa0\x8c\xcd\x6e\x08\xb7\x64",
+ "66d7d6c54fc7775a0ba845ba3e11719fa535b9289f20b098c5f7a342"
+ }, {
+ 38,
+ "\x93\x44\x16\xdd\x05\x81\xe2\x2f\x2b\xfb\xec\xe7\xbb\x64\xaf\xe8\x20\x45\x1f\xa2\x13\x42\xdf\x7e\x6f\x9f\xb3\x7c\x41\x03\x38\x1a\x1f\x7c\xd3\x79\xbc\xc4",
+ "fae8f1aa22def4dbaa814c5b0babdec43394951792c937050d2963a6"
+ }, {
+ 39,
+ "\x10\x24\x01\xc8\x4a\x71\x6a\xe7\x25\x79\xc6\xae\x79\xc3\x59\xea\x30\x9f\xfd\x95\xab\xff\xae\x4c\x61\x88\x4c\x03\xc9\xe9\x9d\xf7\x7b\x6c\x92\xe4\x92\xca\xcb",
+ "8f34812d57a16ef8a51ad987660c5f8623e0fa9d89846e28d46d14d9"
+ }, {
+ 40,
+ "\x79\xbc\x8f\xb6\x0f\x85\xd1\x5a\x23\x86\x56\x6e\x3e\x73\x14\xdf\x28\x45\x33\x08\x5a\xdd\x1c\x7b\xb6\xea\xd3\xff\x76\x0c\x86\xd5\x63\x3a\x66\x40\x47\x61\xb5\x44",
+ "65c54014cfa30f0bc27d1c6efa96ae8481f4c2505bff272956eab0df"
+ }, {
+ 41,
+ "\xdb\x31\x21\xea\x71\x29\x49\x83\xb1\x85\x20\x7a\x9d\x8d\xe3\xe4\x84\xa6\x6c\x04\x31\xbf\x07\xc9\x62\xeb\x82\x97\x7c\x4f\x83\x4b\x7c\x3f\x1e\x79\x31\xa4\xa7\xf7\xa9",
+ "9316d2f021c2913d63a7e66924c87c161c3cfde0ea7ba07f54772862"
+ }, {
+ 42,
+ "\x0d\xd5\x1a\xa6\x60\xc5\xcb\x4b\x7f\x78\xc4\x68\x52\xc1\xdb\x87\x07\xab\x45\x1c\x13\x67\xb6\x18\x73\x88\xc8\xbb\x38\x73\xa1\xaa\x42\x10\xd0\x41\x4c\xc6\x79\x2a\x29\xa7",
+ "31989e7a62a5132a5070d77250d8904bb82d457dc63469d06b50185e"
+ }, {
+ 43,
+ "\x48\x7f\xd2\xe5\xb6\x94\xb7\x07\x1d\x37\x89\xa2\x58\xa5\x1e\x86\x04\xdc\x0d\x3e\x8f\x5d\x62\xf3\x91\x31\x96\x8e\x60\x2a\xbe\x1d\xdf\x6b\x02\x78\x96\x2a\x51\x24\x08\xb5\x53",
+ "e798683438284626d710877d9eea3a0e02f349fc43acb7f9f8f9e81c"
+ }, {
+ 44,
+ "\x11\x18\x3b\xde\xbf\xef\x58\xe4\xda\x5b\x1c\xb7\x3b\xe0\xd3\x0b\x20\xda\x30\x4d\x86\x59\xd9\x21\xda\x2e\x27\x0f\xd1\x46\x26\x79\x95\x37\xe4\xd1\x21\x19\xe8\x09\xee\x97\x00\x4a",
+ "96870657d6cb668be3995aa8bd31df77840d1d1915d72482e83b6b2c"
+ }, {
+ 45,
+ "\xa2\x39\xde\x5c\x8e\x26\x44\xe8\xf0\x30\xd9\x4d\x98\xf1\xa3\x06\x64\xe6\xfd\x96\x1d\xc2\x97\x7a\x9c\x08\xbe\x5c\x31\xd8\xde\x89\x45\x09\x45\xa5\x3d\x79\x29\x9e\xa2\xa1\xed\xde\x7f",
+ "e99743d4fd26c8800c36a67b6762247c29da6b62794123c59de06dc0"
+ }, {
+ 46,
+ "\x91\x7c\x45\x77\xaa\x6b\x0f\x9d\xf4\x99\x99\xfc\x1c\x95\x8c\xb0\x9b\x7f\xd5\xfc\x80\xbe\x94\x96\x70\xf0\x35\x45\xeb\x27\xdc\xae\xd0\x52\x07\x6b\x24\xf9\x6f\x5e\x0f\x2e\x2f\x45\x27\xc0",
+ "7ecd693d4d9cf43929464698efa0bac33c2e1424f816edc769260978"
+ }, {
+ 47,
+ "\xc3\xf1\xe7\x35\xa6\x74\x1a\xa4\x81\xad\x57\x7a\x98\xdb\xac\x1f\x03\xcc\x80\xea\x0d\xae\x1b\x94\xdb\x23\x69\xed\x4e\x93\xfa\xcd\x29\xc6\x4e\x4e\x77\xb2\x50\x38\x27\x91\x20\xbd\xfa\x37\x15",
+ "86f0d89d8e14fd8b6606412d71a7a54a347b304ea5d49c208f2266ab"
+ }, {
+ 48,
+ "\xde\x4f\xbf\xd5\x53\xcd\xf3\x70\x19\xf2\x5a\xfa\x82\xdc\x6b\x99\x70\xf4\xbb\x1e\xbb\xc3\x7f\x80\xd3\x08\x4c\x88\xa7\x07\x22\xcd\xc5\x23\xa9\xe3\xc2\xaf\xba\xd0\xdc\x02\x21\xbf\xde\xc9\xa2\xf9",
+ "4c5262acb4a2a44eaa9bc6757024fb202ef4d5a7a16fa37252a422b5"
+ }, {
+ 49,
+ "\xdb\x2e\x2e\xb6\x36\x61\x0c\xf4\x2e\x9b\x33\x43\x3a\xcc\xe1\xb3\xb9\x25\x94\x9f\x29\x7d\xd8\x31\x99\xf4\x5d\x28\x61\xd6\x4c\xd9\x10\xc2\xdb\x74\xa6\x0b\x20\x89\x04\x5e\x22\xcb\xa0\xa5\x36\x13\x7d",
+ "16bf4e45bcdc60447c68dcb30e6b08f55ce9f4124a29cf1f9a9d065d"
+ }, {
+ 50,
+ "\xa8\xe7\x29\xd3\x36\xd5\xd6\xac\x50\xe1\xe2\x2f\x0b\x19\x3b\x66\xe2\x60\x42\xfc\x64\x59\x21\x41\x29\x87\x5e\x74\x0a\xb2\xb1\x42\x91\x8c\x13\x8a\xaf\x94\x18\x63\xad\x3b\x7e\x60\x65\x45\x06\x13\xb2\x73",
+ "452bf2e5ebfc4e451cc434bc09e2a10032eed0b7627cf55e7e5ed0e2"
+ }, {
+ 51,
+ "\xd0\x53\x17\xd4\xb5\x35\xf9\xd1\x0f\x73\x9d\x0c\x2d\xed\xf3\xff\xb0\x90\xc1\xad\x9d\x20\x50\x89\xb1\x34\x66\x93\xf5\x82\x73\xc4\x92\x5c\x0f\xac\xe5\x7b\xa4\x5a\xd6\xfc\x68\x7c\x66\xa8\x8f\xc7\x88\x78\xbe",
+ "4f03c439e097b51b00e314f675937c4d911505859fb7ab16adc65e44"
+ }, {
+ 52,
+ "\x26\xbb\x4e\xd4\xf0\x42\x4c\x60\xfe\x42\x12\xff\x8c\x95\x5e\x89\xe2\xf5\x53\xa7\xd7\x70\x1b\xe5\x94\x16\xd2\x08\x9a\xf5\x9f\xa1\x07\x47\x24\xe2\x14\xe9\x19\xb1\xe3\x0f\x33\xfb\x78\x37\x4b\x4b\x05\x5b\xbc\x9b",
+ "e7c899e27009d4dc77c2d300f191b757e52c9e7eac4b023bfab2b52a"
+ }, {
+ 53,
+ "\xf0\x15\xec\x83\x94\x4f\x03\x29\x24\x63\xc4\x34\x5f\xdb\x1c\x26\xd1\xea\x07\x64\x5f\xac\xbc\x95\x20\xae\x24\x4b\x6e\xb1\x91\xe5\x3d\xab\xad\xb4\xac\x0f\xb1\x5c\xda\x4e\xd7\x7d\xfb\x9e\x11\x93\xab\xfa\xfb\x1b\x81",
+ "459e40b3fbd612912f0217c60099379ce077cd02505871b0c9c14e7a"
+ }, {
+ 54,
+ "\x07\x86\x70\x6f\x68\x0c\x27\xb7\x92\xd0\x54\xfa\xa6\x3f\x49\x9a\x8e\x6b\x5d\xdb\x90\x50\x29\x46\x23\x5b\xf7\x4c\x02\x2d\x77\x2c\x80\x9c\xb4\x17\x1b\xfa\x47\x91\x53\x9a\xca\x1a\xbd\x91\x90\x0e\x53\xba\x93\xca\x0e\xfd",
+ "fadebab7c3d0fb8e97e429b79083087735e4ab385a789521260ef3ad"
+ }, {
+ 55,
+ "\x44\x5e\x86\x98\xee\xb8\xac\xcb\xaa\xc4\xff\xa7\xd9\x34\xff\xfd\x16\x01\x4a\x43\x0e\xf7\x0f\x3a\x91\x74\xc6\xcf\xe9\x6d\x1e\x3f\x6a\xb1\x37\x7f\x4a\x72\x12\xdb\xb3\x01\x46\xdd\x17\xd9\xf4\x70\xc4\xdf\xfc\x45\xb8\xe8\x71",
+ "4c7ae028c0fe61f2a9cada61fae30685b77f04c6442576e912af9fa6"
+ }, {
+ 56,
+ "\x52\x83\x9f\x2f\x08\x53\xa3\x0d\xf1\x4e\xc8\x97\xa1\x91\x4c\x68\x5c\x1a\xc2\x14\x70\xd0\x06\x54\xc8\xc3\x76\x63\xbf\xb6\x5f\xa7\x32\xdb\xb6\x94\xd9\xdd\x09\xce\xd7\x23\xb4\x8d\x8f\x54\x58\x46\xba\x16\x89\x88\xb6\x1c\xc7\x24",
+ "2f755a57674b49d5c25cb37348f35b6fd2de2552c749f2645ba63d20"
+ }, {
+ 57,
+ "\x5f\xe8\xc2\x07\x2d\x89\x00\x28\x7c\xca\xf0\x7f\x3f\x66\xb0\xc2\x2a\xcd\x3e\x0b\xb9\x1d\x95\x73\x75\x4e\x19\xe3\x73\xac\x35\x27\x1d\x8b\x43\x44\x34\x36\xac\x0c\x16\x28\x50\xef\x3d\x7f\x28\x14\x09\xad\x29\xa9\xbf\x71\x6c\x77\xd1",
+ "42909757f6e229f69f04cc7a863c4e70e48c7c3575057b455c959775"
+ }, {
+ 58,
+ "\xe8\x06\x4d\x83\xf3\xd6\x43\xaf\x87\x18\xc8\x7e\x3c\xcd\x6a\x97\x33\x68\x5e\xac\x61\xd5\x72\xa2\x2a\xb9\x43\xf2\x32\xfc\xb0\x4f\x70\x85\x8e\x89\x84\x44\x9d\xb1\x4a\x76\xbb\x7e\xaf\x24\x58\xef\xc3\xed\x2a\x32\x10\x06\x22\xc5\x2b\x7f",
+ "1a1d8ed54cb45c97bc970754b43eb93d9eabde4c7b07f76ad82d8ede"
+ }, {
+ 59,
+ "\x87\xc9\xa5\x17\xe2\x8d\x1b\xb5\x4a\xd2\x0f\xca\x76\x46\x0e\xfd\x89\x4d\x77\x86\xe6\x8e\xe8\xd7\x46\xb2\xf6\x82\x08\x68\x21\x57\xc8\xad\x06\xcc\x32\x4a\xd7\xa3\x18\x9e\x09\xc6\xc3\x9d\x4c\x76\x87\x19\xc0\xa4\x9a\x41\x66\x9f\x27\x67\xd5",
+ "605977cf87b9b309bbddaaa64e528ace66b04df9f72c0e7ec88be1da"
+ }, {
+ 60,
+ "\x59\xfd\xac\x3b\x6b\x32\x03\x92\x91\x80\x1c\x7d\x6f\x46\xed\xe8\xd2\x6d\xc5\xb7\xa1\x92\xe0\x07\x11\x67\x39\xb6\x17\x56\x9f\x25\x23\x68\x0b\x3c\x0b\x66\x31\xaf\x45\x3e\x55\x80\x5a\xa7\x60\xc6\x97\x08\x33\xac\x06\x96\x3b\xbc\x9d\xbd\x45\x5e",
+ "e9f0cb1dc8337e906385892f2348a8ba4412318ecad9b96e3711531f"
+ }, {
+ 61,
+ "\x30\x35\x0a\x4d\xf0\xb5\x8f\xf4\x9c\x0f\xa0\x9e\x42\x6f\xcd\x70\x07\xb2\x90\xc7\x60\xc8\x25\xc1\x85\x5d\x9b\x00\x23\xb8\x2c\xaa\x51\xe3\xca\xb4\xc6\x0c\xfa\x61\x49\x2b\xe5\x05\x68\xe5\xac\x0f\x6d\xb0\xfd\x46\x8e\x39\xe4\x53\x64\x03\xe3\x80\x9f",
+ "776cc6636c02408fbf65ace73ae80017108b917c16c5a912fd860241"
+ }, {
+ 62,
+ "\xef\x79\x7a\x0d\x43\xc3\x0b\x4f\xe1\x01\x4b\xdb\x94\x20\x87\x9c\x2f\xf8\x45\xd2\x7e\x73\xd5\x5a\x7d\xf2\x29\x30\xc8\xec\xe7\x32\x53\xd8\xbb\x26\x5b\x4e\xf2\xff\x9c\x69\x45\x5c\xc5\x6f\xf2\x52\x29\xb4\x12\x6b\xb7\xbb\x26\xee\x2c\x9f\xf3\x61\x87\xb1",
+ "f5b9ffb102affac352a4a535a00f89b06c268cf4881d712668906025"
+ }, {
+ 63,
+ "\x71\x69\x44\xde\x41\x71\x0c\x29\xb6\x59\xbe\x10\x48\x0b\xb2\x5a\x35\x1a\x39\xe5\x77\xee\x30\xe8\xf4\x22\xd5\x7c\xf6\x2a\xd9\x5b\xda\x39\xb6\xe7\x0c\x61\x42\x6e\x33\xfd\x84\xac\xa8\x4c\xc7\x91\x2d\x5e\xee\x45\xdc\x34\x07\x6a\x5d\x23\x23\xa1\x5c\x79\x64",
+ "61645ac748db567ac862796b8d06a47afebfa2e1783d5c5f3bcd81e2"
+ }, {
+ 64,
+ "\xa3\x31\x0b\xa0\x64\xbe\x2e\x14\xad\x32\x27\x6e\x18\xcd\x03\x10\xc9\x33\xa6\xe6\x50\xc3\xc7\x54\xd0\x24\x3c\x6c\x61\x20\x78\x65\xb4\xb6\x52\x48\xf6\x6a\x08\xed\xf6\xe0\x83\x26\x89\xa9\xdc\x3a\x2e\x5d\x20\x95\xee\xea\x50\xbd\x86\x2b\xac\x88\xc8\xbd\x31\x8d",
+ "b2a5586d9cbf0baa999157b4af06d88ae08d7c9faab4bc1a96829d65"
+ }, {
+ 0,
+ NULL,
+ NULL
+ }
+};
+
+/* SHA256 short messages test vectors. */
+static struct test_vector sha256_vectors[] = {
+ {
+ 0,
+ "",
+ "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ }, {
+ 1,
+ "\xd3",
+ "28969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c1"
+ }, {
+ 2,
+ "\x11\xaf",
+ "5ca7133fa735326081558ac312c620eeca9970d1e70a4b95533d956f072d1f98"
+ }, {
+ 3,
+ "\xb4\x19\x0e",
+ "dff2e73091f6c05e528896c4c831b9448653dc2ff043528f6769437bc7b975c2"
+ }, {
+ 4,
+ "\x74\xba\x25\x21",
+ "b16aa56be3880d18cd41e68384cf1ec8c17680c45a02b1575dc1518923ae8b0e"
+ }, {
+ 5,
+ "\xc2\x99\x20\x96\x82",
+ "f0887fe961c9cd3beab957e8222494abb969b1ce4c6557976df8b0f6d20e9166"
+ }, {
+ 6,
+ "\xe1\xdc\x72\x4d\x56\x21",
+ "eca0a060b489636225b4fa64d267dabbe44273067ac679f20820bddc6b6a90ac"
+ }, {
+ 7,
+ "\x06\xe0\x76\xf5\xa4\x42\xd5",
+ "3fd877e27450e6bbd5d74bb82f9870c64c66e109418baa8e6bbcff355e287926"
+ }, {
+ 8,
+ "\x57\x38\xc9\x29\xc4\xf4\xcc\xb6",
+ "963bb88f27f512777aab6c8b1a02c70ec0ad651d428f870036e1917120fb48bf"
+ }, {
+ 9,
+ "\x33\x34\xc5\x80\x75\xd3\xf4\x13\x9e",
+ "078da3d77ed43bd3037a433fd0341855023793f9afd08b4b08ea1e5597ceef20"
+ }, {
+ 10,
+ "\x74\xcb\x93\x81\xd8\x9f\x5a\xa7\x33\x68",
+ "73d6fad1caaa75b43b21733561fd3958bdc555194a037c2addec19dc2d7a52bd"
+ }, {
+ 11,
+ "\x76\xed\x24\xa0\xf4\x0a\x41\x22\x1e\xbf\xcf",
+ "044cef802901932e46dc46b2545e6c99c0fc323a0ed99b081bda4216857f38ac"
+ }, {
+ 12,
+ "\x9b\xaf\x69\xcb\xa3\x17\xf4\x22\xfe\x26\xa9\xa0",
+ "fe56287cd657e4afc50dba7a3a54c2a6324b886becdcd1fae473b769e551a09b"
+ }, {
+ 13,
+ "\x68\x51\x1c\xdb\x2d\xbb\xf3\x53\x0d\x7f\xb6\x1c\xbc",
+ "af53430466715e99a602fc9f5945719b04dd24267e6a98471f7a7869bd3b4313"
+ }, {
+ 14,
+ "\xaf\x39\x7a\x8b\x8d\xd7\x3a\xb7\x02\xce\x8e\x53\xaa\x9f",
+ "d189498a3463b18e846b8ab1b41583b0b7efc789dad8a7fb885bbf8fb5b45c5c"
+ }, {
+ 15,
+ "\x29\x4a\xf4\x80\x2e\x5e\x92\x5e\xb1\xc6\xcc\x9c\x72\x4f\x09",
+ "dcbaf335360de853b9cddfdafb90fa75567d0d3d58af8db9d764113aef570125"
+ }, {
+ 16,
+ "\x0a\x27\x84\x7c\xdc\x98\xbd\x6f\x62\x22\x0b\x04\x6e\xdd\x76\x2b",
+ "80c25ec1600587e7f28b18b1b18e3cdc89928e39cab3bc25e4d4a4c139bcedc4"
+ }, {
+ 17,
+ "\x1b\x50\x3f\xb9\xa7\x3b\x16\xad\xa3\xfc\xf1\x04\x26\x23\xae\x76\x10",
+ "d5c30315f72ed05fe519a1bf75ab5fd0ffec5ac1acb0daf66b6b769598594509"
+ }, {
+ 18,
+ "\x59\xeb\x45\xbb\xbe\xb0\x54\xb0\xb9\x73\x34\xd5\x35\x80\xce\x03\xf6\x99",
+ "32c38c54189f2357e96bd77eb00c2b9c341ebebacc2945f97804f59a93238288"
+ }, {
+ 19,
+ "\x58\xe5\xa3\x25\x9c\xb0\xb6\xd1\x2c\x83\xf7\x23\x37\x9e\x35\xfd\x29\x8b\x60",
+ "9b5b37816de8fcdf3ec10b745428708df8f391c550ea6746b2cafe019c2b6ace"
+ }, {
+ 20,
+ "\xc1\xef\x39\xce\xe5\x8e\x78\xf6\xfc\xdc\x12\xe0\x58\xb7\xf9\x02\xac\xd1\xa9\x3b",
+ "6dd52b0d8b48cc8146cebd0216fbf5f6ef7eeafc0ff2ff9d1422d6345555a142"
+ }, {
+ 21,
+ "\x9c\xab\x7d\x7d\xca\xec\x98\xcb\x3a\xc6\xc6\x4d\xd5\xd4\x47\x0d\x0b\x10\x3a\x81\x0c",
+ "44d34809fc60d1fcafa7f37b794d1d3a765dd0d23194ebbe340f013f0c39b613"
+ }, {
+ 22,
+ "\xea\x15\x7c\x02\xeb\xaf\x1b\x22\xde\x22\x1b\x53\xf2\x35\x39\x36\xd2\x35\x9d\x1e\x1c\x97",
+ "9df5c16a3f580406f07d96149303d8c408869b32053b726cf3defd241e484957"
+ }, {
+ 23,
+ "\xda\x99\x9b\xc1\xf9\xc7\xac\xff\x32\x82\x8a\x73\xe6\x72\xd0\xa4\x92\xf6\xee\x89\x5c\x68\x67",
+ "672b54e43f41ee77584bdf8bf854d97b6252c918f7ea2d26bc4097ea53a88f10"
+ }, {
+ 24,
+ "\x47\x99\x13\x01\x15\x6d\x1d\x97\x7c\x03\x38\xef\xbc\xad\x41\x00\x41\x33\xae\xfb\xca\x6b\xcf\x7e",
+ "feeb4b2b59fec8fdb1e55194a493d8c871757b5723675e93d3ac034b380b7fc9"
+ }, {
+ 25,
+ "\x2e\x7e\xa8\x4d\xa4\xbc\x4d\x7c\xfb\x46\x3e\x3f\x2c\x86\x47\x05\x7a\xff\xf3\xfb\xec\xec\xa1\xd2\x00",
+ "76e3acbc718836f2df8ad2d0d2d76f0cfa5fea0986be918f10bcee730df441b9"
+ }, {
+ 26,
+ "\x47\xc7\x70\xeb\x45\x49\xb6\xef\xf6\x38\x1d\x62\xe9\xbe\xb4\x64\xcd\x98\xd3\x41\xcc\x1c\x09\x98\x1a\x7a",
+ "6733809c73e53666c735b3bd3daf87ebc77c72756150a616a194108d71231272"
+ }, {
+ 27,
+ "\xac\x4c\x26\xd8\xb4\x3b\x85\x79\xd8\xf6\x1c\x98\x07\x02\x6e\x83\xe9\xb5\x86\xe1\x15\x9b\xd4\x3b\x85\x19\x37",
+ "0e6e3c143c3a5f7f38505ed6adc9b48c18edf6dedf11635f6e8f9ac73c39fe9e"
+ }, {
+ 28,
+ "\x07\x77\xfc\x1e\x1c\xa4\x73\x04\xc2\xe2\x65\x69\x28\x38\x10\x9e\x26\xaa\xb9\xe5\xc4\xae\x4e\x86\x00\xdf\x4b\x1f",
+ "ffb4fc03e054f8ecbc31470fc023bedcd4a406b9dd56c71da1b660dcc4842c65"
+ }, {
+ 29,
+ "\x1a\x57\x25\x1c\x43\x1d\x4e\x6c\x2e\x06\xd6\x52\x46\xa2\x96\x91\x50\x71\xa5\x31\x42\x5e\xcf\x25\x59\x89\x42\x2a\x66",
+ "c644612cd326b38b1c6813b1daded34448805aef317c35f548dfb4a0d74b8106"
+ }, {
+ 30,
+ "\x9b\x24\x5f\xda\xd9\xba\xeb\x89\x0d\x9c\x0d\x0e\xff\x81\x6e\xfb\x4c\xa1\x38\x61\x0b\xc7\xd7\x8c\xb1\xa8\x01\xed\x32\x73",
+ "c0e29eeeb0d3a7707947e623cdc7d1899adc70dd7861205ea5e5813954fb7957"
+ }, {
+ 31,
+ "\x95\xa7\x65\x80\x9c\xaf\x30\xad\xa9\x0a\xd6\xd6\x1c\x2b\x4b\x30\x25\x0d\xf0\xa7\xce\x23\xb7\x75\x3c\x91\x87\xf4\x31\x9c\xe2",
+ "a4139b74b102cf1e2fce229a6cd84c87501f50afa4c80feacf7d8cf5ed94f042"
+ }, {
+ 32,
+ "\x09\xfc\x1a\xcc\xc2\x30\xa2\x05\xe4\xa2\x08\xe6\x4a\x8f\x20\x42\x91\xf5\x81\xa1\x27\x56\x39\x2d\xa4\xb8\xc0\xcf\x5e\xf0\x2b\x95",
+ "4f44c1c7fbebb6f9601829f3897bfd650c56fa07844be76489076356ac1886a4"
+ }, {
+ 33,
+ "\x05\x46\xf7\xb8\x68\x2b\x5b\x95\xfd\x32\x38\x5f\xaf\x25\x85\x4c\xb3\xf7\xb4\x0c\xc8\xfa\x22\x9f\xbd\x52\xb1\x69\x34\xaa\xb3\x88\xa7",
+ "b31ad3cd02b10db282b3576c059b746fb24ca6f09fef69402dc90ece7421cbb7"
+ }, {
+ 34,
+ "\xb1\x2d\xb4\xa1\x02\x55\x29\xb3\xb7\xb1\xe4\x5c\x6d\xbc\x7b\xaa\x88\x97\xa0\x57\x6e\x66\xf6\x4b\xf3\xf8\x23\x61\x13\xa6\x27\x6e\xe7\x7d",
+ "1c38bf6bbfd32292d67d1d651fd9d5b623b6ec1e854406223f51d0df46968712"
+ }, {
+ 35,
+ "\xe6\x8c\xb6\xd8\xc1\x86\x6c\x0a\x71\xe7\x31\x3f\x83\xdc\x11\xa5\x80\x9c\xf5\xcf\xbe\xed\x1a\x58\x7c\xe9\xc2\xc9\x2e\x02\x2a\xbc\x16\x44\xbb",
+ "c2684c0dbb85c232b6da4fb5147dd0624429ec7e657991edd95eda37a587269e"
+ }, {
+ 36,
+ "\x4e\x3d\x8a\xc3\x6d\x61\xd9\xe5\x14\x80\x83\x11\x55\xb2\x53\xb3\x79\x69\xfe\x7e\xf4\x9d\xb3\xb3\x99\x26\xf3\xa0\x0b\x69\xa3\x67\x74\x36\x60\x00",
+ "bf9d5e5b5393053f055b380baed7e792ae85ad37c0ada5fd4519542ccc461cf3"
+ }, {
+ 37,
+ "\x03\xb2\x64\xbe\x51\xe4\xb9\x41\x86\x4f\x9b\x70\xb4\xc9\x58\xf5\x35\x5a\xac\x29\x4b\x4b\x87\xcb\x03\x7f\x11\xf8\x5f\x07\xeb\x57\xb3\xf0\xb8\x95\x50",
+ "d1f8bd684001ac5a4b67bbf79f87de524d2da99ac014dec3e4187728f4557471"
+ }, {
+ 38,
+ "\xd0\xfe\xfd\x96\x78\x7c\x65\xff\xa7\xf9\x10\xd6\xd0\xad\xa6\x3d\x64\xd5\xc4\x67\x99\x60\xe7\xf0\x6a\xeb\x8c\x70\xdf\xef\x95\x4f\x8e\x39\xef\xdb\x62\x9b",
+ "49ba38db85c2796f85ffd57dd5ec337007414528ae33935b102d16a6b91ba6c1"
+ }, {
+ 39,
+ "\xb7\xc7\x9d\x7e\x5f\x1e\xec\xcd\xfe\xdf\x0e\x7b\xf4\x3e\x73\x0d\x44\x7e\x60\x7d\x8d\x14\x89\x82\x3d\x09\xe1\x12\x01\xa0\xb1\x25\x80\x39\xe7\xbd\x48\x75\xb1",
+ "725e6f8d888ebaf908b7692259ab8839c3248edd22ca115bb13e025808654700"
+ }, {
+ 40,
+ "\x64\xcd\x36\x3e\xcc\xe0\x5f\xdf\xda\x24\x86\xd0\x11\xa3\xdb\x95\xb5\x20\x6a\x19\xd3\x05\x40\x46\x81\x9d\xd0\xd3\x67\x83\x95\x5d\x7e\x5b\xf8\xba\x18\xbf\x73\x8a",
+ "32caef024f84e97c30b4a7b9d04b678b3d8a6eb2259dff5b7f7c011f090845f8"
+ }, {
+ 41,
+ "\x6a\xc6\xc6\x3d\x61\x8e\xaf\x00\xd9\x1c\x5e\x28\x07\xe8\x3c\x09\x39\x12\xb8\xe2\x02\xf7\x8e\x13\x97\x03\x49\x8a\x79\xc6\x06\x7f\x54\x49\x7c\x61\x27\xa2\x39\x10\xa6",
+ "4bb33e7c6916e08a9b3ed6bcef790aaaee0dcf2e7a01afb056182dea2dad7d63"
+ }, {
+ 42,
+ "\xd2\x68\x26\xdb\x9b\xae\xaa\x89\x26\x91\xb6\x89\x00\xb9\x61\x63\x20\x8e\x80\x6a\x1d\xa0\x77\x42\x9e\x45\x4f\xa0\x11\x84\x09\x51\xa0\x31\x32\x7e\x60\x5a\xb8\x2e\xcc\xe2",
+ "3ac7ac6bed82fdc8cd15b746f0ee7489158192c238f371c1883c9fe90b3e2831"
+ }, {
+ 43,
+ "\x3f\x7a\x05\x9b\x65\xd6\xcb\x02\x49\x20\x4a\xac\x10\xb9\xf1\xa4\xac\x9e\x58\x68\xad\xeb\xbe\x93\x5a\x9e\xb5\xb9\x01\x9e\x1c\x93\x8b\xfc\x4e\x5c\x53\x78\x99\x7a\x39\x47\xf2",
+ "bfce809534eefe871273964d32f091fe756c71a7f512ef5f2300bcd57f699e74"
+ }, {
+ 44,
+ "\x60\xff\xcb\x23\xd6\xb8\x8e\x48\x5b\x92\x0a\xf8\x1d\x10\x83\xf6\x29\x1d\x06\xac\x8c\xa3\xa9\x65\xb8\x59\x14\xbc\x2a\xdd\x40\x54\x4a\x02\x7f\xca\x93\x6b\xbd\xe8\xf3\x59\x05\x1c",
+ "1d26f3e04f89b4eaa9dbed9231bb051eef2e8311ad26fe53d0bf0b821eaf7567"
+ }, {
+ 45,
+ "\x9e\xcd\x07\xb6\x84\xbb\x9e\x0e\x66\x92\xe3\x20\xce\xc4\x51\x0c\xa7\x9f\xcd\xb3\xa2\x21\x2c\x26\xd9\x0d\xf6\x5d\xb3\x3e\x69\x2d\x07\x3c\xc1\x74\x84\x0d\xb7\x97\x50\x4e\x48\x2e\xef",
+ "0ffeb644a49e787ccc6970fe29705a4f4c2bfcfe7d19741c158333ff6982cc9c"
+ }, {
+ 46,
+ "\x9d\x64\xde\x71\x61\x89\x58\x84\xe7\xfa\x3d\x6e\x9e\xb9\x96\xe7\xeb\xe5\x11\xb0\x1f\xe1\x9c\xd4\xa6\xb3\x32\x2e\x80\xaa\xf5\x2b\xf6\x44\x7e\xd1\x85\x4e\x71\x00\x1f\x4d\x54\xf8\x93\x1d",
+ "d048ee1524014adf9a56e60a388277de194c694cc787fc5a1b554ea9f07abfdf"
+ }, {
+ 47,
+ "\xc4\xad\x3c\x5e\x78\xd9\x17\xec\xb0\xcb\xbc\xd1\xc4\x81\xfc\x2a\xaf\x23\x2f\x7e\x28\x97\x79\xf4\x0e\x50\x4c\xc3\x09\x66\x2e\xe9\x6f\xec\xbd\x20\x64\x7e\xf0\x0e\x46\x19\x9f\xbc\x48\x2f\x46",
+ "50dbf40066f8d270484ee2ef6632282dfa300a85a8530eceeb0e04275e1c1efd"
+ }, {
+ 48,
+ "\x4e\xef\x51\x07\x45\x9b\xdd\xf8\xf2\x4f\xc7\x65\x6f\xd4\x89\x6d\xa8\x71\x1d\xb5\x04\x00\xc0\x16\x48\x47\xf6\x92\xb8\x86\xce\x8d\x7f\x4d\x67\x39\x50\x90\xb3\x53\x4e\xfd\x7b\x0d\x29\x8d\xa3\x4b",
+ "7c5d14ed83dab875ac25ce7feed6ef837d58e79dc601fb3c1fca48d4464e8b83"
+ }, {
+ 49,
+ "\x04\x7d\x27\x58\xe7\xc2\xc9\x62\x3f\x9b\xdb\x93\xb6\x59\x7c\x5e\x84\xa0\xcd\x34\xe6\x10\x01\x4b\xcb\x25\xb4\x9e\xd0\x5c\x7e\x35\x6e\x98\xc7\xa6\x72\xc3\xdd\xdc\xae\xb8\x43\x17\xef\x61\x4d\x34\x2f",
+ "7d53eccd03da37bf58c1962a8f0f708a5c5c447f6a7e9e26137c169d5bdd82e4"
+ }, {
+ 50,
+ "\x3d\x83\xdf\x37\x17\x2c\x81\xaf\xd0\xde\x11\x51\x39\xfb\xf4\x39\x0c\x22\xe0\x98\xc5\xaf\x4c\x5a\xb4\x85\x24\x06\x51\x0b\xc0\xe6\xcf\x74\x17\x69\xf4\x44\x30\xc5\x27\x0f\xda\xe0\xcb\x84\x9d\x71\xcb\xab",
+ "99dc772e91ea02d9e421d552d61901016b9fd4ad2df4a8212c1ec5ba13893ab2"
+ }, {
+ 51,
+ "\x33\xfd\x9b\xc1\x7e\x2b\x27\x1f\xa0\x4c\x6b\x93\xc0\xbd\xea\xe9\x86\x54\xa7\x68\x2d\x31\xd9\xb4\xda\xb7\xe6\xf3\x2c\xd5\x8f\x2f\x14\x8a\x68\xfb\xe7\xa8\x8c\x5a\xb1\xd8\x8e\xdc\xcd\xde\xb3\x0a\xb2\x1e\x5e",
+ "cefdae1a3d75e792e8698d5e71f177cc761314e9ad5df9602c6e60ae65c4c267"
+ }, {
+ 52,
+ "\x77\xa8\x79\xcf\xa1\x1d\x7f\xca\xc7\xa8\x28\x2c\xc3\x8a\x43\xdc\xf3\x76\x43\xcc\x90\x98\x37\x21\x3b\xd6\xfd\x95\xd9\x56\xb2\x19\xa1\x40\x6c\xbe\x73\xc5\x2c\xd5\x6c\x60\x0e\x55\xb7\x5b\xc3\x7e\xa6\x96\x41\xbc",
+ "c99d64fa4dadd4bc8a389531c68b4590c6df0b9099c4d583bc00889fb7b98008"
+ }, {
+ 53,
+ "\x45\xa3\xe6\xb8\x65\x27\xf2\x0b\x45\x37\xf5\xaf\x96\xcf\xc5\xad\x87\x77\xa2\xdd\xe6\xcf\x75\x11\x88\x6c\x55\x90\xec\xe2\x4f\xc6\x1b\x22\x67\x39\xd2\x07\xda\xbf\xe3\x2b\xa6\xef\xd9\xff\x4c\xd5\xdb\x1b\xd5\xea\xd3",
+ "4d12a849047c6acd4b2eee6be35fa9051b02d21d50d419543008c1d82c427072"
+ }, {
+ 54,
+ "\x25\x36\x2a\x4b\x9d\x74\xbd\xe6\x12\x8c\x4f\xdc\x67\x23\x05\x90\x09\x47\xbc\x3a\xda\x9d\x9d\x31\x6e\xbc\xf1\x66\x7a\xd4\x36\x31\x89\x93\x72\x51\xf1\x49\xc7\x2e\x06\x4a\x48\x60\x8d\x94\x0b\x75\x74\xb1\x7f\xef\xc0\xdf",
+ "f8e4ccab6c979229f6066cc0cb0cfa81bb21447c16c68773be7e558e9f9d798d"
+ }, {
+ 55,
+ "\x3e\xbf\xb0\x6d\xb8\xc3\x8d\x5b\xa0\x37\xf1\x36\x3e\x11\x85\x50\xaa\xd9\x46\x06\xe2\x68\x35\xa0\x1a\xf0\x50\x78\x53\x3c\xc2\x5f\x2f\x39\x57\x3c\x04\xb6\x32\xf6\x2f\x68\xc2\x94\xab\x31\xf2\xa3\xe2\xa1\xa0\xd8\xc2\xbe\x51",
+ "6595a2ef537a69ba8583dfbf7f5bec0ab1f93ce4c8ee1916eff44a93af5749c4"
+ }, {
+ 56,
+ "\x2d\x52\x44\x7d\x12\x44\xd2\xeb\xc2\x86\x50\xe7\xb0\x56\x54\xba\xd3\x5b\x3a\x68\xee\xdc\x7f\x85\x15\x30\x6b\x49\x6d\x75\xf3\xe7\x33\x85\xdd\x1b\x00\x26\x25\x02\x4b\x81\xa0\x2f\x2f\xd6\xdf\xfb\x6e\x6d\x56\x1c\xb7\xd0\xbd\x7a",
+ "cfb88d6faf2de3a69d36195acec2e255e2af2b7d933997f348e09f6ce5758360"
+ }, {
+ 57,
+ "\x4c\xac\xe4\x22\xe4\xa0\x15\xa7\x54\x92\xb3\xb3\xbb\xfb\xdf\x37\x58\xea\xff\x4f\xe5\x04\xb4\x6a\x26\xc9\x0d\xac\xc1\x19\xfa\x90\x50\xf6\x03\xd2\xb5\x8b\x39\x8c\xad\x6d\x6d\x9f\xa9\x22\xa1\x54\xd9\xe0\xbc\x43\x89\x96\x82\x74\xb0",
+ "4d54b2d284a6794581224e08f675541c8feab6eefa3ac1cfe5da4e03e62f72e4"
+ }, {
+ 58,
+ "\x86\x20\xb8\x6f\xbc\xaa\xce\x4f\xf3\xc2\x92\x1b\x84\x66\xdd\xd7\xba\xca\xe0\x7e\xef\xef\x69\x3c\xf1\x77\x62\xdc\xab\xb8\x9a\x84\x01\x0f\xc9\xa0\xfb\x76\xce\x1c\x26\x59\x3a\xd6\x37\xa6\x12\x53\xf2\x24\xd1\xb1\x4a\x05\xad\xdc\xca\xbe",
+ "dba490256c9720c54c612a5bd1ef573cd51dc12b3e7bd8c6db2eabe0aacb846b"
+ }, {
+ 59,
+ "\xd1\xbe\x3f\x13\xfe\xba\xfe\xfc\x14\x41\x4d\x9f\xb7\xf6\x93\xdb\x16\xdc\x1a\xe2\x70\xc5\xb6\x47\xd8\x0d\xa8\x58\x35\x87\xc1\xad\x8c\xb8\xcb\x01\x82\x43\x24\x41\x1c\xa5\xac\xe3\xca\x22\xe1\x79\xa4\xff\x49\x86\xf3\xf2\x11\x90\xf3\xd7\xf3",
+ "02804978eba6e1de65afdbc6a6091ed6b1ecee51e8bff40646a251de6678b7ef"
+ }, {
+ 60,
+ "\xf4\x99\xcc\x3f\x6e\x3c\xf7\xc3\x12\xff\xdf\xba\x61\xb1\x26\x0c\x37\x12\x9c\x1a\xfb\x39\x10\x47\x19\x33\x67\xb7\xb2\xed\xeb\x57\x92\x53\xe5\x1d\x62\xba\x6d\x91\x1e\x7b\x81\x8c\xca\xe1\x55\x3f\x61\x46\xea\x78\x0f\x78\xe2\x21\x9f\x62\x93\x09",
+ "0b66c8b4fefebc8dc7da0bbedc1114f228aa63c37d5c30e91ab500f3eadfcec5"
+ }, {
+ 61,
+ "\x6d\xd6\xef\xd6\xf6\xca\xa6\x3b\x72\x9a\xa8\x18\x6e\x30\x8b\xc1\xbd\xa0\x63\x07\xc0\x5a\x2c\x0a\xe5\xa3\x68\x4e\x6e\x46\x08\x11\x74\x86\x90\xdc\x2b\x58\x77\x59\x67\xcf\xcc\x64\x5f\xd8\x20\x64\xb1\x27\x9f\xdc\xa7\x71\x80\x3d\xb9\xdc\xa0\xff\x53",
+ "c464a7bf6d180de4f744bb2fe5dc27a3f681334ffd54a9814650e60260a478e3"
+ }, {
+ 62,
+ "\x65\x11\xa2\x24\x2d\xdb\x27\x31\x78\xe1\x9a\x82\xc5\x7c\x85\xcb\x05\xa6\x88\x7f\xf2\x01\x4c\xf1\xa3\x1c\xb9\xba\x5d\xf1\x69\x5a\xad\xb2\x5c\x22\xb3\xc5\xed\x51\xc1\x0d\x04\x7d\x25\x6b\x8e\x34\x42\x84\x2a\xe4\xe6\xc5\x25\xf8\xd7\xa5\xa9\x44\xaf\x2a",
+ "d6859c0b5a0b66376a24f56b2ab104286ed0078634ba19112ace0d6d60a9c1ae"
+ }, {
+ 63,
+ "\xe2\xf7\x6e\x97\x60\x6a\x87\x2e\x31\x74\x39\xf1\xa0\x3f\xcd\x92\xe6\x32\xe5\xbd\x4e\x7c\xbc\x4e\x97\xf1\xaf\xc1\x9a\x16\xfd\xe9\x2d\x77\xcb\xe5\x46\x41\x6b\x51\x64\x0c\xdd\xb9\x2a\xf9\x96\x53\x4d\xfd\x81\xed\xb1\x7c\x44\x24\xcf\x1a\xc4\xd7\x5a\xce\xeb",
+ "18041bd4665083001fba8c5411d2d748e8abbfdcdfd9218cb02b68a78e7d4c23"
+ }, {
+ 64,
+ "\x5a\x86\xb7\x37\xea\xea\x8e\xe9\x76\xa0\xa2\x4d\xa6\x3e\x7e\xd7\xee\xfa\xd1\x8a\x10\x1c\x12\x11\xe2\xb3\x65\x0c\x51\x87\xc2\xa8\xa6\x50\x54\x72\x08\x25\x1f\x6d\x42\x37\xe6\x61\xc7\xbf\x4c\x77\xf3\x35\x39\x03\x94\xc3\x7f\xa1\xa9\xf9\xbe\x83\x6a\xc2\x85\x09",
+ "42e61e174fbb3897d6dd6cef3dd2802fe67b331953b06114a65c772859dfc1aa"
+ }, {
+ 0,
+ NULL,
+ NULL
+ }
+};
+
+/* SHA512 short messages test vectors. */
+static struct test_vector sha512_vectors[] = {
+ {
+ 0,
+ "",
+ "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"
+ }, {
+ 1,
+ "\x21",
+ "3831a6a6155e509dee59a7f451eb35324d8f8f2df6e3708894740f98fdee23889f4de5adb0c5010dfb555cda77c8ab5dc902094c52de3278f35a75ebc25f093a"
+ }, {
+ 2,
+ "\x90\x83",
+ "55586ebba48768aeb323655ab6f4298fc9f670964fc2e5f2731e34dfa4b0c09e6e1e12e3d7286b3145c61c2047fb1a2a1297f36da64160b31fa4c8c2cddd2fb4"
+ }, {
+ 3,
+ "\x0a\x55\xdb",
+ "7952585e5330cb247d72bae696fc8a6b0f7d0804577e347d99bc1b11e52f384985a428449382306a89261ae143c2f3fb613804ab20b42dc097e5bf4a96ef919b"
+ }, {
+ 4,
+ "\x23\xbe\x86\xd5",
+ "76d42c8eadea35a69990c63a762f330614a4699977f058adb988f406fb0be8f2ea3dce3a2bbd1d827b70b9b299ae6f9e5058ee97b50bd4922d6d37ddc761f8eb"
+ }, {
+ 5,
+ "\xeb\x0c\xa9\x46\xc1",
+ "d39ecedfe6e705a821aee4f58bfc489c3d9433eb4ac1b03a97e321a2586b40dd0522f40fa5aef36afff591a78c916bfc6d1ca515c4983dd8695b1ec7951d723e"
+ }, {
+ 6,
+ "\x38\x66\x7f\x39\x27\x7b",
+ "85708b8ff05d974d6af0801c152b95f5fa5c06af9a35230c5bea2752f031f9bd84bd844717b3add308a70dc777f90813c20b47b16385664eefc88449f04f2131"
+ }, {
+ 7,
+ "\xb3\x9f\x71\xaa\xa8\xa1\x08",
+ "258b8efa05b4a06b1e63c7a3f925c5ef11fa03e3d47d631bf4d474983783d8c0b09449009e842fc9fa15de586c67cf8955a17d790b20f41dadf67ee8cdcdfce6"
+ }, {
+ 8,
+ "\x6f\x8d\x58\xb7\xca\xb1\x88\x8c",
+ "a3941def2803c8dfc08f20c06ba7e9a332ae0c67e47ae57365c243ef40059b11be22c91da6a80c2cff0742a8f4bcd941bdee0b861ec872b215433ce8dcf3c031"
+ }, {
+ 9,
+ "\x16\x2b\x0c\xf9\xb3\x75\x0f\x94\x38",
+ "ade217305dc34392aa4b8e57f64f5a3afdd27f1fa969a9a2608353f82b95cfb4ae84598d01575a578a1068a59b34b5045ff6d5299c5cb7ee17180701b2d1d695"
+ }, {
+ 10,
+ "\xba\xd7\xc6\x18\xf4\x5b\xe2\x07\x97\x5e",
+ "5886828959d1f82254068be0bd14b6a88f59f534061fb20376a0541052dd3635edf3c6f0ca3d08775e13525df9333a2113c0b2af76515887529910b6c793c8a5"
+ }, {
+ 11,
+ "\x62\x13\xe1\x0a\x44\x20\xe0\xd9\xb7\x70\x37",
+ "9982dc2a04dff165567f276fd463efef2b369fa2fbca8cee31ce0de8a79a2eb0b53e437f7d9d1f41c71d725cabb949b513075bad1740c9eefbf6a5c6633400c7"
+ }, {
+ 12,
+ "\x63\x32\xc3\xc2\xa0\xa6\x25\xa6\x1d\xf7\x18\x58",
+ "9d60375d9858d9f2416fb86fa0a2189ee4213e8710314fd1ebed0fd158b043e6e7c9a76d62c6ba1e1d411a730902309ec676dd491433c6ef66c8f116233d6ce7"
+ }, {
+ 13,
+ "\xf4\x7b\xe3\xa2\xb0\x19\xd1\xbe\xed\xed\xf5\xb8\x0c",
+ "b94292625caa28c7be24a0997eb7328062a76d9b529c0f1d568f850df6d569b5e84df07e9e246be232033ffac3adf2d18f92ab9dacfc0ecf08aff7145f0b833b"
+ }, {
+ 14,
+ "\xb1\x71\x5f\x78\x2f\xf0\x2c\x6b\x88\x93\x7f\x05\x41\x16",
+ "ee1a56ee78182ec41d2c3ab33d4c41871d437c5c1ca060ee9e219cb83689b4e5a4174dfdab5d1d1096a31a7c8d3abda75c1b5e6da97e1814901c505b0bc07f25"
+ }, {
+ 15,
+ "\x9b\xcd\x52\x62\x86\x8c\xd9\xc8\xa9\x6c\x9e\x82\x98\x7f\x03",
+ "2e07662a001b9755ae922c8e8a95756db5341dc0f2e62ae1cf827038f33ce055f63ad5c00b65391428434ddc01e5535e7fecbf53db66d93099b8e0b7e44e4b25"
+ }, {
+ 16,
+ "\xcd\x67\xbd\x40\x54\xaa\xa3\xba\xa0\xdb\x17\x8c\xe2\x32\xfd\x5a",
+ "0d8521f8f2f3900332d1a1a55c60ba81d04d28dfe8c504b6328ae787925fe0188f2ba91c3a9f0c1653c4bf0ada356455ea36fd31f8e73e3951cad4ebba8c6e04"
+ }, {
+ 17,
+ "\x6b\xa0\x04\xfd\x17\x67\x91\xef\xb3\x81\xb8\x62\xe2\x98\xc6\x7b\x08",
+ "112e19144a9c51a223a002b977459920e38afd4ca610bd1c532349e9fa7c0d503215c01ad70e1b2ac5133cf2d10c9e8c1a4c9405f291da2dc45f706761c5e8fe"
+ }, {
+ 18,
+ "\xc6\xa1\x70\x93\x65\x68\x65\x10\x20\xed\xfe\x15\xdf\x80\x12\xac\xda\x8d",
+ "c36c100cdb6c8c45b072f18256d63a66c9843acb4d07de62e0600711d4fbe64c8cf314ec3457c90308147cb7ac7e4d073ba10f0ced78ea724a474b32dae71231"
+ }, {
+ 19,
+ "\x61\xbe\x0c\x9f\x5c\xf6\x27\x45\xc7\xda\x47\xc1\x04\x59\x71\x94\xdb\x24\x5c",
+ "b379249a3ca5f14c29456710114ba6f6136b34c3fc9f6fb91b59d491af782d6b237eb71aaffdd38079461cf690a46d9a4ddd602d19808ab6235d1d8aa01e8200"
+ }, {
+ 20,
+ "\xe0\x70\x56\xd4\xf7\x27\x7b\xc5\x48\x09\x95\x77\x72\x0a\x58\x1e\xec\x94\x14\x1d",
+ "59f1856303ff165e2ab5683dddeb6e8ad81f15bb578579b999eb5746680f22cfec6dba741e591ca4d9e53904837701b374be74bbc0847a92179ac2b67496d807"
+ }, {
+ 21,
+ "\x67\xeb\xda\x0a\x35\x73\xa9\xa5\x87\x51\xd4\x16\x9e\x10\xc7\xe8\x66\x3f\xeb\xb3\xa8",
+ "13963f81cfabfca71de4739fd24a10ce3897bba1d716907fc0a28490c192a7fc3ccb8db1f91af7a2d250d6617f0dfd1519d221d618a02e3e3fa9041cf35ed1ea"
+ }, {
+ 22,
+ "\x63\xe0\x9d\xb9\x9e\xb4\xcd\x62\x38\x67\x78\x59\xa5\x67\xdf\x31\x3c\x85\x20\xd8\x45\xb4",
+ "9083e5348b08eb9810b2d15781d8265845410de54fe61750d4b93853690649adc6e72490bc2b7c365e2390573d9414becc0939719e0cb78eca6b2c80c2fda920"
+ }, {
+ 23,
+ "\xf3\xe0\x6b\x4b\xd7\x9e\x38\x0a\x65\xcb\x67\x9a\x98\xcc\xd7\x32\x56\x3c\xc5\xeb\xe8\x92\xe2",
+ "6b315f106b07c59eedc5ab1df813b3c0b903060e7217cc010e9070278512a885008dac8b2472a521e77835a7f4deadc1d591aa23b624b69948a99bb60121c54e"
+ }, {
+ 24,
+ "\x16\xb1\x70\x74\xd3\xe3\xd9\x75\x57\xf9\xed\x77\xd9\x20\xb4\xb1\xbf\xf4\xe8\x45\xb3\x45\xa9\x22",
+ "6884134582a760046433abcbd53db8ff1a89995862f305b887020f6da6c7b903a314721e972bf438483f452a8b09596298a576c903c91df4a414c7bd20fd1d07"
+ }, {
+ 25,
+ "\x3e\xdf\x93\x25\x13\x49\xd2\x28\x06\xbe\xd2\x53\x45\xfd\x5c\x19\x0a\xac\x96\xd6\xcd\xb2\xd7\x58\xb8",
+ "299e0daf6605e5b0c30e1ec8bb98e7a3bd7b33b388bdb457452dab509594406c8e7b841e6f4e75c8d6fbd614d5eb9e56c359bfafb4285754787ab72b46dd33f0"
+ }, {
+ 26,
+ "\xb2\xd5\xa1\x4f\x01\xe6\xb7\x78\x88\x8c\x56\x2a\x05\x9e\xc8\x19\xad\x89\x99\x2d\x16\xa0\x9f\x7a\x54\xb4",
+ "ab2e7d745d8ad393439af2a3fbc9cdc25510d4a04e78b526e12b1c0be3b22966872ebe652e2f46ed5c5acecd2f233a9175dd295ebeb3a0706fc66fa1b137042b"
+ }, {
+ 27,
+ "\x84\x4b\x66\xf1\x2b\xa0\xc5\xf9\xe9\x27\x31\xf5\x71\x53\x9d\x1e\xef\x33\x2e\x15\x49\xa4\x9d\xbf\xa4\xc6\xde",
+ "c3f9c5781925774783ae9d839772d7513dfcea8c5af8da262c196f9fe80135b2b0c8c6ca0a1604e0a3460247620de20b299f2db7871982d27c2176ae5fa7ad65"
+ }, {
+ 28,
+ "\x6b\x6c\xc6\x92\xd3\x98\x60\xb1\xf3\x02\x03\x65\x3e\x25\xd0\x9c\x01\xe6\xa8\x04\x3c\x1a\x9c\xb8\xb2\x49\xa4\x1e",
+ "2e5263d9a4f21b210e0e161ed39df44102864325788647261a6e70ea4b1ee0abb57b57499bc82158d82336dd53f1ef4464c6a08126e138b2cc0892f765f6af85"
+ }, {
+ 29,
+ "\xab\x1f\xc9\xee\x84\x5e\xeb\x20\x5e\xc1\x37\x25\xda\xf1\xfb\x1f\x5d\x50\x62\x9b\x14\xea\x9a\x22\x35\xa9\x35\x0a\x88",
+ "72d188a9df5f3b00057bca22c92c0f8228422d974302d22d4b322e7a6c8fc3b2b50ec74c6842781f29f7075c3d4bd065878648846c39bb3e4e2692c0f053f7ed"
+ }, {
+ 30,
+ "\x59\x4e\xd8\x2a\xcf\xc0\x3c\x0e\x35\x9c\xc5\x60\xb8\xe4\xb8\x5f\x6e\xe7\x7e\xe5\x9a\x70\x02\x3c\x2b\x3d\x5b\x32\x85\xb2",
+ "5ef322cb4014ecbb713a13659612a222225984d31c187debc4459ba7901f03dac775400acfe3510b306b79894fb0e8437b412150c9193ee5a2164306ebb78301"
+ }, {
+ 31,
+ "\xf2\xc6\x6e\xfb\xf2\xa7\x6c\x5b\x04\x18\x60\xea\x57\x61\x03\xcd\x8c\x6b\x25\xe5\x0e\xca\x9f\xf6\xa2\xfa\x88\x08\x3f\xe9\xac",
+ "7978f93ef7ed02c4a24abecba124d14dd214e1492ff1e168304c0eab89637da0f7a569c43dc4562bdb9404a018b6314fe0eebaccfb25ba76506aa7e9dcd956a7"
+ }, {
+ 32,
+ "\x8c\xcb\x08\xd2\xa1\xa2\x82\xaa\x8c\xc9\x99\x02\xec\xaf\x0f\x67\xa9\xf2\x1c\xff\xe2\x80\x05\xcb\x27\xfc\xf1\x29\xe9\x63\xf9\x9d",
+ "4551def2f9127386eea8d4dae1ea8d8e49b2add0509f27ccbce7d9e950ac7db01d5bca579c271b9f2d806730d88f58252fd0c2587851c3ac8a0e72b4e1dc0da6"
+ }, {
+ 33,
+ "\x9f\x8c\x49\x32\x0a\xf9\x37\x0c\xd3\xdb\x20\xe9\xb5\x0d\x3e\xaa\x59\xa6\x23\x2d\x7a\x86\xfb\x7d\x47\x2f\x12\x45\x08\xd7\x96\x8b\x05",
+ "81b002f15c4d48be8517f7ed89df302fb1435c9435efefed58f3eb8ea11910623f1eb9028a66e02121a7f08a7c604226f2324f483e91548dbbd2c441ab704ce5"
+ }, {
+ 34,
+ "\x4a\xb9\xaa\x06\x94\x75\xe5\x4b\x25\xe5\x68\x8a\x52\xdd\x4a\xcd\x13\x41\x69\xc8\x58\x10\x5f\x01\xa0\xa1\xb1\x34\xc7\x2d\x4a\xf5\x1f\x8e",
+ "48ba5a63aba7e7bd8e420475331125a947928c67fdb00f65c4080d9a0b99c0672424e76a1ba6bd76dfe492c730f6f9adccaee7bb11571aadb31f6bb628cfa933"
+ }, {
+ 35,
+ "\xf0\xc1\xd3\x40\x7d\xe9\x2e\xf7\x42\x1e\x42\xdf\x5c\x9a\xb3\x1d\x2e\xc0\xa7\x50\xa9\x52\x28\x69\xcb\xe4\xca\xbd\x66\x90\x8d\x58\x23\xec\x04",
+ "9e75c5bca2c2af1d7739787f46e1d981c4f98e493d0724b5252c2fbae3c526719f1d27e6ccd0d705240281e8fbf3db75b9b3205c1413436d3b5d140004b8cca1"
+ }, {
+ 36,
+ "\xae\x8c\x9f\x8f\xb4\x1b\x51\x9b\x6d\x94\x38\x33\xfe\x1c\x32\xd1\xc4\x29\x2f\xb1\xdd\xf1\xdb\xe2\xeb\x22\x7d\x9e\x14\xd3\x1e\xd7\x4e\xba\xef\x12",
+ "042f9fd0a4ed3d9fec3655ae11011c6f2bc7e457e8812b6d8be2cd45fc6c432a94558c88f22c01439618865e8e49e509c448b342ca914b120344aaf7bcbdca18"
+ }, {
+ 37,
+ "\xda\x39\xfb\x86\x23\x7f\x00\x30\x38\x44\xe6\x1f\xc6\xcf\xe7\x79\xe4\x2a\xf5\x33\x49\x83\x95\x90\xbc\xd2\xf0\xe4\xcb\xbc\x27\x9e\xc0\xb7\xe8\x85\xd1",
+ "ecb43de8c233a731b38e30c5696f8876761b7ea72efe283fd07bedf20029f47c6d2a4427823e100fb087abaf22d7eff42a951c97c3dd05f48a20163fa4367cba"
+ }, {
+ 38,
+ "\x3e\x72\x71\xd2\x07\x0e\xf0\x95\x39\x46\x20\xc4\xb0\x16\x57\x6c\x15\x0f\x34\xbe\xa6\x07\x84\x61\x3a\x0f\x66\x0d\x7f\xa5\xae\x56\x87\x2b\x88\xc5\x83\x98",
+ "8154d0da634ab2266061acc123acb407650ffe9164a22de3fe29bf05393b2aece92cf4db00ea5b4341c31ddb7de151683c8a71b5a44d5c3175790feac67d18ee"
+ }, {
+ 39,
+ "\x31\x1f\xb6\x7f\x6a\x07\x84\xbb\x01\xa2\xd5\xa3\xf3\x09\x2c\x40\x7a\x9d\x33\x22\x31\x9d\xff\x9a\x79\xf8\x94\x29\x1c\x5f\xac\x37\x31\x9f\xb4\x08\x40\x2e\x18",
+ "1870fe913abb0a4b4f53b6581ae18322cd05328514556607f3f4d7b6a2ac8e9185d94d947d8b9c88e0efa66d89b59f7439c75fdadd1816f7412306ab2b59d664"
+ }, {
+ 40,
+ "\x76\x51\xab\x49\x1b\x8f\xa8\x6f\x96\x9d\x42\x97\x7d\x09\xdf\x5f\x8b\xee\x3e\x58\x99\x18\x0b\x52\xc9\x68\xb0\xdb\x05\x7a\x6f\x02\xa8\x86\xad\x61\x7a\x84\x91\x5a",
+ "f35e50e2e02b8781345f8ceb2198f068ba103476f715cfb487a452882c9f0de0c720b2a088a39d06a8a6b64ce4d6470dfeadc4f65ae06672c057e29f14c4daf9"
+ }, {
+ 41,
+ "\xdb\xe5\xdb\x68\x5e\xd7\xcb\x84\x8c\x09\x45\x24\xc1\x72\x35\x19\xd4\x9d\xc6\x6e\xf9\xfe\x6d\x57\xe6\x86\x2a\x64\x35\x75\x0b\xfa\x0a\x70\xf1\x04\xf5\xd3\x96\xe6\x1a",
+ "2fa6e5b2c443a68050f093e7fb713bd6b18f6274c061ed61d79bf0688a61dba1940bcc30998276860943ab038902896d0fbf59b88b07c80de927037097150c40"
+ }, {
+ 42,
+ "\x9f\xa8\x3e\x96\xb2\xa6\xdf\x23\xfb\x37\x28\x95\x01\x56\x78\xe0\xb2\xc9\xcd\x18\xa8\x54\x2c\x3e\xaa\x2c\x43\x5a\x76\xae\x4d\xc9\xbd\x51\x36\xd9\x70\xda\xff\x93\x3a\xcf",
+ "3a2c0ec88a3e5347cf0ea9c078838300ef7356f9a6c342063277c106b880a00ed2be205c13064097bd372fde38007bc306561eb4e74bba2bb20bd354aa690ca6"
+ }, {
+ 43,
+ "\x8a\x5a\x45\xe3\x98\xba\xc1\xd9\xb8\x96\xb5\xa2\xb4\xe3\x56\x6b\x91\xd8\x0a\xd2\x0c\x97\x7e\xa7\x45\x0f\xf2\xef\xb5\x21\xd8\x2f\x65\x01\x9e\xe7\x62\xe0\xc8\x5c\x6c\xc8\x41",
+ "3c704620f4066d79c1ff67752980f39ef3d9c1023fa5a213a5265376b14a15166ffe069b51df7710d8907fef9406bf375d502ce086ac82aff17229aaa7a5a334"
+ }, {
+ 44,
+ "\x49\xcf\xff\xda\xf4\xd0\x31\xe3\x3b\x1d\x28\xa4\x47\x45\x05\x45\xf6\xc4\x29\x3b\x38\xd5\xaf\xbc\xb9\x88\x39\x76\xc0\x14\xf0\x80\x57\x6e\xc6\x91\xac\x1b\xff\x70\xb7\x42\xef\xab",
+ "8bcc4f1ea2b7862ef1591bfa73916665de8faf65439ddf5cc1be43cebfd5f60f205e835a2b186b675b041258c5cff42669316ce25b46a2f4d4218e102f0f5d6f"
+ }, {
+ 45,
+ "\x2f\xf8\x45\xd8\x5e\xfb\xc4\xfa\x56\x37\xe9\x44\x8d\x95\x04\x96\xf1\x9d\x8d\x57\xda\x99\xb7\xbd\x3d\xf7\x47\x48\x22\xf0\xa7\x90\x58\x67\x36\x41\x67\x14\xe3\x64\xc6\xe1\xfa\xe0\x4e",
+ "236f6f4ed6e858c02d51787e60c578f731f694f8e52b5df4ecd5b04dff14c78e56bad1028d6f626c29d85aeee151a2a2846d3eed5cfafa9854a69fea8af6d04a"
+ }, {
+ 46,
+ "\xcf\xca\x05\xfd\x89\x3c\x0f\x00\x5f\x5f\xf7\x96\xf4\xda\x19\xba\x27\xa1\xe7\x29\x95\x6b\x8b\x71\x5e\x67\xce\x4b\x2d\x2a\x38\x2a\x72\xec\x78\x14\xf2\xf5\x07\xb1\x82\x52\x09\xa2\x0f\xcc",
+ "d80969284a4565add4dad6ab9b3bdf53446142f84aaf92d4b23dd22ee7241e6c81489ac8b246edcb6df9bd7b23d91a0c517f546feba4ed5790a2be6e165c1709"
+ }, {
+ 47,
+ "\xcf\xc4\x25\x75\x9a\x9c\x36\xbb\x9f\x4b\x32\xee\xd7\x76\x7a\xf6\x56\x6f\x68\xde\xd0\xad\xea\xe2\x5c\x7a\x70\xca\x78\xec\x09\x77\x4d\x16\xc8\xbc\x35\x7f\x6d\x6f\x7b\xd4\x41\xbf\x62\xd9\x42",
+ "b587a785cdf455cc9c544e756c1e306300aa3c59f8725012e68ab4d54020b6d227a164d9f83c905e86f8cebeef708a69f976d6e7b18b9bf78e9b98cc4a5cd1b6"
+ }, {
+ 48,
+ "\x09\x7c\x9d\xb9\x19\x51\x52\x42\xc9\x9d\x97\x3a\xcb\x1d\xc4\xed\x48\x27\x68\xf9\x74\xeb\x83\xb4\x65\xf9\xf6\xc8\x25\x03\x37\x20\x06\xe4\x49\x08\x35\xe2\xec\x8f\x92\x30\x11\x30\xbf\xb7\x90\xb2",
+ "ff5a376f938e73014caef7fe3962944a7230d020b7087869ebe7ec70302721cd06fcdc981c893a425d05e2f99fe198e4db50a088aee2bf1263212110efed422c"
+ }, {
+ 49,
+ "\x77\xe7\x3d\x38\x7e\x7b\xc8\x04\x19\xeb\xf5\x48\x2b\x61\xd5\x25\x5c\xaf\x81\x9f\xb5\x92\x51\xff\x6a\x38\x4e\x75\xf6\x01\xea\x02\x6d\x83\xef\x95\x0e\xd0\xb6\x75\x18\xfb\x99\xde\xe0\xd8\xaa\xef\x1f",
+ "c4c89cd882ec945cc888fb9a0127d35e585ecc14a75e4b5b3d8330538d22da28cf6af1ebec96dc247f109cd2aaab9756e6946a3d80db8363a4da3e6ddbb510a1"
+ }, {
+ 50,
+ "\x31\x7e\x5d\x9a\xc7\x3e\xd0\x63\x3f\xa1\x8e\xbe\xbb\xca\x79\x09\xec\x3a\x5e\xf7\x90\x47\x8f\x9c\x38\xca\xce\xc4\x4f\x19\x6d\x89\x58\x35\xb4\x25\x77\x44\x83\x04\x33\x41\x38\x1e\x7a\xf2\xd3\x83\xe5\x1a",
+ "b10bb04491b9c0c334709b407cda1d503efb6b63ee944f2d366b6855e6e63e5b80115be4be7ff63edecdfb5923792e68123976d79212b3884dec2179d1fcf382"
+ }, {
+ 51,
+ "\x20\x94\x61\xf2\x06\x66\xa3\x46\xfe\xdf\x4a\x53\x0f\x41\xa6\xfa\x28\x0c\x43\x66\x57\x67\xbe\x92\x3b\xc1\xd8\x0b\xbc\xb8\xc9\xf8\xf9\x3a\xd7\x57\x82\xea\x26\x89\xc8\xc5\xd2\x11\xd2\x05\x3b\x99\x31\x45\xa0",
+ "67b7a328d9444056a52ca2f695c5d3f3baafb625a14fb32eee8ff26a40ccb296bec1771a826b55f7ddb6170d4caf7795b612448e66a0f19356fe505927149b47"
+ }, {
+ 52,
+ "\x5d\x61\xaa\x45\xc4\x46\xf3\xbf\x93\x60\x4b\x05\x11\x31\x3b\x4e\x2f\x30\x6d\x6b\x04\x6f\xbd\x94\x79\x7b\x92\x67\x46\x83\x6f\x2e\x1d\xbd\xc5\x61\x24\x06\x0c\x6c\xa9\xc9\x11\xb1\x12\x21\x92\xd1\x12\x42\x08\x27",
+ "d3931bde2bde8271ed18ca0b9148b12f6f16161e637e376fc961f65bc33bcacf2f6addf26a3eaa81b196653cc37e8a739ec5b3df870d8c38c8f28691c22a39bb"
+ }, {
+ 53,
+ "\x92\x88\xc7\x95\xbb\x0b\x86\xc0\x41\x9d\x9c\x56\x37\xdc\xc3\x7b\x39\xbf\xa1\x8d\x44\x1e\x3f\xbf\xca\x75\xbc\x03\x06\xe5\x43\x2e\x8e\x7b\x3a\x56\x27\xb5\xbc\x7f\xdc\x42\x4a\x77\x52\x0a\xbd\xff\x56\x6e\x7f\x2b\xb8",
+ "e363d0e95d8cd18c384016ebeed6d99c4fa2768e2bd58fca019c5108b9cde1cb46f3f884028a55ce282ec310a10037faa1b16b4a6a669957f0b00f350bbd63d0"
+ }, {
+ 54,
+ "\x78\x04\x27\xdc\x16\x4b\x2f\x69\xb8\xc7\xd5\x69\x26\x6f\x46\x1e\x2d\x30\xc8\x8c\x4c\xd6\x05\x7f\xb0\x30\xa6\xcf\x63\x6f\x24\xe3\xc0\xd0\xdb\x74\x2a\x7b\x61\x93\xfd\xaa\x15\xee\xc5\x0d\xfb\x4f\xae\x6e\xc7\x65\x3c\x91",
+ "2964b009fb1bf996de12e030b9d6e0608ae8b9dbf2acfb9beb76fc5361cc104ee85c2a46fb7b4cee90848312da302de49afe61c546477e2b25d223d5e3d33560"
+ }, {
+ 55,
+ "\xec\x2a\x92\xe4\x7f\x69\x2b\x53\xc1\x35\x54\x75\xc7\x1c\xef\xf0\xb0\x95\x2a\x8b\x35\x41\xb2\x93\x82\x70\x24\x7d\x44\xe7\xc5\xcc\x04\xe1\x72\x36\xb3\x53\xda\x02\x86\x74\xea\xb4\x04\x7d\x89\xec\x5d\xad\x86\x8c\xfd\x91\xce",
+ "c83aca6147bfcbbc72c377efa8d53654ba0830c5a6a89e1d2a19b713e68fb534640deb833ca512247166dd273b5897e57d526f88eef58f6ff97baee0b4ee5644"
+ }, {
+ 56,
+ "\xc9\x9e\x31\xad\x4e\x23\xac\x68\xe1\x5e\x60\x5d\x0b\x02\x43\x7f\x81\x47\xc4\x4f\x54\x45\xa5\x5b\x68\xa1\x09\x05\x27\x6c\xce\x86\x76\x48\x1c\x33\xe8\xcd\x3e\xfe\x32\x2b\xb1\x3f\xe0\x10\x7b\xb5\x46\xcc\xbe\xc7\xb8\xb3\x8d\x10",
+ "52992d45a88221d972958e9f2854adaa9a21d2bf7051e1f1019ae78004da50c5b55c144a02afffe539d753949a2b056534f5b4c21f248a05baa52a6c38c7f5dd"
+ }, {
+ 57,
+ "\x9a\xa3\xe8\xad\x92\x77\x7d\xfe\xb1\x21\xa6\x46\xce\x2e\x91\x8d\x1e\x12\xb3\x07\x54\xbc\x09\x47\x0d\x6d\xa4\xaf\x6c\xc9\x64\x2b\x01\x2f\x04\x1f\xf0\x46\x56\x9d\x4f\xd8\xd0\xdc\xcf\xe4\x48\xe5\x9f\xee\xfc\x90\x8d\x9a\xd5\xaf\x6f",
+ "994d1cda4de40aff4713237cf9f78f7033af83369ac9c64e504091ea2f1caff6c5152d6a0c5608f82886c0093b3d7fbadd49dfd1f9e0f85accf23bc7dad48904"
+ }, {
+ 58,
+ "\x58\x42\x51\x2c\x37\x31\x25\x11\xa3\xd8\xae\x41\xf5\x80\x1d\xf6\x0c\xd6\x82\xd5\x8b\x4a\x99\x73\x42\xb6\xe7\x17\xe9\x40\x06\xc2\x14\x81\x3e\x6c\x63\xe7\x55\x91\xf9\x57\xa7\xec\x30\x17\x79\x83\x8b\xec\x8a\xe3\xed\x7f\xeb\xad\x08\x05",
+ "9763c43331ad0eb279d704c5f6e97e02da8724115026827f889e9fcda21f60fd230894ab35abb719890f3afa51afd31bc6852183b9c51059910af460abd2474d"
+ }, {
+ 59,
+ "\xca\x14\xe2\xea\x2f\x37\xc7\x8f\x78\xef\x28\x0f\x58\x70\x7e\xc5\x49\xa3\x1a\x94\x36\x10\x73\xe3\x77\x01\xbf\xe5\x03\xe4\xc0\x1e\xe1\xf2\xe1\x23\xe0\x0e\x81\xa1\x88\xf0\x8f\xa0\x50\x82\x57\x09\x12\x8a\x9b\x66\xbb\x8a\xe6\xea\x47\xe4\x1d",
+ "4600e022a02258739f67fdd367cc1e662631fb087918768352062b9b3c8de8dbca0e9ec751b91f284694fbddb8d325c0637bccb21dd2efa92e48dbab2e5e9c26"
+ }, {
+ 60,
+ "\x64\x76\x29\xc7\x79\xb2\x4c\x1e\x76\xf4\x17\x44\xab\xa1\x71\x59\x48\x75\x32\xa0\x15\x6a\x7d\x82\x64\xdb\x50\xd6\x45\xe9\x59\x5f\xf8\x1e\x0c\x96\xa8\x50\xf2\xaa\x56\xc8\x44\xc6\x13\xa4\xb8\x92\x72\x7a\x9b\xfc\x3d\x3e\x20\x38\x67\x66\xf8\x05",
+ "5bc842fc2d3b7eb31d2d3044df3ec32af114feaa7cfc27ebc8630f46ab6f0c543f59b812e776e5303861d17da3f1f16097641f3b808d4d5cb3e483946409746c"
+ }, {
+ 61,
+ "\x1c\x5d\xc0\xd1\xdd\x2e\x4c\x71\x76\x35\xff\x3e\x9b\x67\xca\xf9\x57\xae\xc0\xf8\xf6\x3c\x1b\x1e\x22\x1e\x80\x0a\x4c\x14\x84\x8f\x4e\xa0\x6e\x64\x4e\x5d\x3e\x1d\xe5\x92\xef\x5a\x80\x07\xfa\x3f\x07\x17\x1b\x24\xbd\x07\x57\x8d\x68\x96\x3e\x5c\xb1",
+ "cbf1ea86fa5b3dbf67be82fac41e84cccd0d296c757169b37837d273ccc015eecd102b9ce1cff68fdc7f05d22f2b774734f62ded54c8ee0bf57a5a82010d74f5"
+ }, {
+ 62,
+ "\x8a\x55\x5e\x75\x47\x7d\x06\x5b\x3a\xf7\xe6\x15\x47\x5f\x37\xc0\xa6\x67\xf7\x3a\x4c\x7a\xf5\xe4\xa6\x9f\x28\xa6\x8d\x9f\x44\x34\x77\x6a\x8f\x90\xea\xb7\xf1\xd1\x37\xeb\x4b\x22\x64\x3c\x0a\x0d\x6a\x16\xfc\xfa\xa1\xbd\x62\xf2\x78\x35\x46\xa9\x69\x5f",
+ "c088e4a3d7da2f6f99a8f3f717361108872b8ffef921b383c24b8061d4e7c27fc56f4f20dc8f952a14043c5650b5a9e777c49c41cfeb3f2de97ee2e16b2c3924"
+ }, {
+ 63,
+ "\xeb\xb3\xe2\xad\x78\x03\x50\x8b\xa4\x6e\x81\xe2\x20\xb1\xcf\xf3\x3e\xa8\x38\x15\x04\x11\x0e\x9f\x80\x92\xef\x08\x5a\xfe\xf8\x4d\xb0\xd4\x36\x93\x1d\x08\x5d\x0e\x1b\x06\xbd\x21\x8c\xf5\x71\xc7\x93\x38\xda\x31\xa8\x3b\x4c\xb1\xec\x6c\x06\xd6\xb9\x87\x68",
+ "f33428d8fc67aa2cc1adcb2822f37f29cbd72abff68190483e415824f0bcecd447cb4f05a9c47031b9c50e0411c552f31cd04c30cea2bc64bcf825a5f8a66028"
+ }, {
+ 64,
+ "\xc1\xca\x70\xae\x12\x79\xba\x0b\x91\x81\x57\x55\x8b\x49\x20\xd6\xb7\xfb\xa8\xa0\x6b\xe5\x15\x17\x0f\x20\x2f\xaf\xd3\x6f\xb7\xf7\x9d\x69\xfa\xd7\x45\xdb\xa6\x15\x05\x68\xdb\x1e\x2b\x72\x85\x04\x11\x3e\xea\xc3\x4f\x52\x7f\xc8\x2f\x22\x00\xb4\x62\xec\xbf\x5d",
+ "046e46623912b3932b8d662ab42583423843206301b58bf20ab6d76fd47f1cbbcf421df536ecd7e56db5354e7e0f98822d2129c197f6f0f222b8ec5231f3967d"
+ }, {
+ 65,
+ "\xd3\xdd\xdd\xf8\x05\xb1\x67\x8a\x02\xe3\x92\x00\xf6\x44\x00\x47\xac\xbb\x06\x2e\x4a\x2f\x04\x6a\x3c\xa7\xf1\xdd\x6e\xb0\x3a\x18\xbe\x00\xcd\x1e\xb1\x58\x70\x6a\x64\xaf\x58\x34\xc6\x8c\xf7\xf1\x05\xb4\x15\x19\x46\x05\x22\x2c\x99\xa2\xcb\xf7\x2c\x50\xcb\x14\xbf",
+ "bae7c5d590bf25a493d8f48b8b4638ccb10541c67996e47287b984322009d27d1348f3ef2999f5ee0d38e112cd5a807a57830cdc318a1181e6c4653cdb8cf122"
+ }, {
+ 66,
+ "\x8e\x8e\xf8\xaa\x33\x6b\x3b\x98\x89\x4c\x31\x26\xc7\x18\x78\x91\x06\x18\x83\x8c\x00\xac\x85\x90\x17\x3c\x91\x74\x99\x72\xff\x3d\x42\xa6\x11\x37\x02\x9a\xd7\x45\x01\x68\x4f\x75\xe1\xb8\xd1\xd7\x43\x36\xaa\x90\x8c\x44\x08\x2a\xe9\xeb\x16\x2e\x90\x18\x67\xf5\x49\x05",
+ "41672931558a93762522b1d55389ecf1b8c0feb8b88f4587fbd417ca809055b0cb630d8bea133ab7f6cf1f21c6b35e2e25c0d19583258808e6c23e1a75336103"
+ }, {
+ 67,
+ "\x52\x76\x1e\x1d\xac\x0e\xae\xa8\x98\xe0\xb0\x7c\xd2\x4f\x4b\x2e\x6b\xb7\xbc\x20\x0e\xa4\xb0\x52\x88\x42\xf1\x7b\x87\x15\x45\x59\xa2\xea\x94\x45\x9a\x0e\x48\x0a\xe0\xbd\xf9\xf7\x57\xdd\x4a\x33\x5a\xed\x0e\x51\x01\x38\xb0\x24\xa0\x4e\xd1\xd5\x91\xb4\x32\x32\x34\xdb\xd5",
+ "b826fe80494e19c51b42f2582b2d080ba6b90512f35f2db67dd7fd5ee532eaa16498afba08b4996cbcfdf8d1a2df6b1da939e8265115a48aefa42f38205db436"
+ }, {
+ 68,
+ "\x38\x04\xeb\xc4\x3c\xbe\xa8\x0c\x2b\xd7\xe4\xfd\xa5\xc5\x51\x55\x00\xcd\x2d\x2b\x84\x6a\x13\x78\xdb\xf2\x18\xd5\xc3\x77\x13\x86\x06\xeb\x3c\xb8\xac\x88\xf9\x07\x6f\x6f\xf4\x43\x6f\x90\x71\x74\x27\xc9\xdf\x1b\xa0\x52\xac\xbb\xe4\x58\x5e\x98\xb6\xe8\xe0\xbf\x80\x0f\x19\x46",
+ "17dd6d87bc6773051e52047fd444996afa8124b0483fe121877f98553448772bd0e7751fc655e9cc2d29830211015d310f191474ca6adc0477a187c03b8fe252"
+ }, {
+ 69,
+ "\x22\x49\xd6\x98\xc4\xd8\x07\xa8\xe7\xb4\xde\x21\xc4\x85\x73\x89\x59\xa0\xd6\x7e\x5d\x2c\xa6\xf7\x79\x83\xdf\xcc\xb5\xdb\xf4\x79\x31\x26\x1e\x1f\x15\x37\xf3\xcb\xca\x25\x3a\xfb\x6b\xf4\xfe\x5e\x76\x72\xe1\xdc\xc8\x60\xb3\xd6\xc8\xd2\x43\xaf\xe2\xd9\x75\x8b\x37\x5e\x95\x56\x92",
+ "6af44563fc468d51182f6c3be58d45932af1d985c6f283976c91a9ff421f383fe21dc7322f397ccead583e26b3e3fda067976a7f34665df25a2ced7b4b09cdec"
+ }, {
+ 70,
+ "\x32\xa9\xc1\x70\x33\x65\x8c\x54\xf2\x2c\x71\x35\xdd\xfc\x87\x9d\xe9\x4d\x79\x59\x3e\xf2\xdc\x7d\x30\x41\xbf\xa8\x72\x73\x83\x89\x86\x4e\xed\xa2\x78\x01\x79\x4c\xcc\x4f\xf1\xfc\xb5\xef\x3f\xc4\x88\x33\x80\x1d\x6f\xe9\x59\xe3\x62\x7f\x8e\xa1\x53\x6a\xd0\x0f\xa9\xc7\xd7\xd9\xf0\x43",
+ "6a47699dd3ada2f11bc4ea42072b06cc20857bf164497df1285400c250f5848b6f71957dbdc845f5daeab913036661f69387893fc2d61c25fa59b9d85b19f401"
+ }, {
+ 71,
+ "\x3d\x65\xf6\x9a\x59\x0a\x5b\xaa\xab\xcd\x27\x4f\xe3\xef\x9e\x88\x92\x0f\xfc\x7a\xdf\x05\xc1\x6d\x7b\x0f\x4d\x18\xd7\x2b\xac\x1e\x94\xc3\xb3\xd8\x3b\x8f\x4c\x55\x2e\xb8\x0e\x9f\xde\x39\x11\x40\x3f\x8b\x00\x05\x79\x81\x6f\x02\xe1\x71\x6f\xd6\x27\x94\x60\x31\xd0\xaf\x07\x93\xe7\xf3\xe1",
+ "ffb2d9450943c24b5933c24812459b75d3d9f380344c9bc06fa3e17ee448eca2f98ff79f7e2235ccd9f9a8176f68a2254bbc9b834d6ac8d2bfdbc1597c432c9f"
+ }, {
+ 72,
+ "\x76\xff\x8b\x20\xa1\x8c\xf1\x04\xf6\xcd\xb6\x5e\x2b\xa8\xf6\x6e\xcf\x84\x4a\xf7\xe8\x5e\x8e\xf2\xda\x19\xe8\x84\x8a\x16\x05\x2e\xc4\x05\xa6\x44\xda\xfb\x5c\xa0\x8e\xc4\x8f\x97\x32\x7a\xc5\x2c\x0e\x56\x21\x84\x02\xc7\x2a\x9a\x6d\xc1\xcf\x34\x4d\x58\xa7\x16\xa7\x8d\x7d\x75\x29\x68\x0b\xae",
+ "f8858144c6d709dd0689a526a548a43f17494950ba2ac20544799e8ea27201d78bce5b921e29a7b4029278e68341ef2a0ca4ba3894566b3c8f8950e3e545a689"
+ }, {
+ 73,
+ "\xca\x88\xdd\xdf\xc8\x76\xa1\x2f\x45\xf1\x95\x62\xbc\x9c\xa2\x50\xf4\x32\x67\xab\x25\x1a\x7f\x34\x5c\x3c\x02\x2e\x20\x14\x4e\x13\x56\x04\x07\x87\x62\xef\x5c\x8a\x8f\x03\x8c\xf1\xb1\xd6\xa9\x17\x09\xb5\x9d\xd0\x68\x39\x6a\x9e\x97\x1a\xb6\x28\xf7\x48\x86\xe7\x65\x38\x4a\x23\x60\x7c\x1a\x1e\x6e",
+ "4f3d9eeef349ca51a7e419af1686f42795abde58a85335ce68d496e81e4436a80a61dc143a4300008c23a3e71f4ba98743195a3694a8d02fee11bd314569abc0"
+ }, {
+ 74,
+ "\x0a\x78\xb1\x6b\x40\x26\xf7\xec\x06\x3d\xb4\xe7\xb7\x7c\x42\xa2\x98\xe5\x24\xe2\x68\x09\x3c\x50\x38\x85\x3e\x21\x7d\xcd\x65\xf6\x64\x28\x65\x01\x65\xfc\xa0\x6a\x1b\x4c\x9c\xf1\x53\x7f\xb5\xd4\x63\x63\x0f\xf3\xbd\x71\xcf\x32\xc3\x53\x8b\x1f\xdd\xa3\xfe\xd5\xc9\xf6\x01\x20\x33\x19\xb7\xe1\x86\x9a",
+ "6095c3df5b9db7ce524d76123f77421ce888b86a477ae8c6db1d0be8d326d22c852915ab03c0c81a5b7ac71e2c14e74bda17a78d2b10585fa214f6546eb710a0"
+ }, {
+ 75,
+ "\x20\xf1\x0e\xf9\xa0\xe6\x12\x86\x75\x34\x01\x71\xcd\x24\x8d\xf3\x0b\x58\x65\x57\x62\x0b\x61\x5c\xa3\x9a\x00\xdb\x53\x43\x15\xa9\x01\x2d\xbd\xbf\xd6\xa9\x94\x98\x6e\xb8\x29\xdb\xe6\xcd\xaf\x3a\x37\xd4\xf5\x9a\xc2\x72\x98\x74\x2c\x8f\x77\x7b\x6b\x12\x67\x7f\x21\xeb\x28\x91\x29\x57\x98\x68\x70\x5f\x27",
+ "b4ead3f860eabbd36c770d66c7356f8107acd1485c7c94178c2eaabd50266d7645d009972586ef83ed43ed92882137df5117b88f35231b894ec1741ae7501145"
+ }, {
+ 76,
+ "\x99\x5c\x8f\x74\x7e\xa4\x18\xf7\xd6\x3a\xba\x22\x60\xb3\x4a\xc3\xc7\xdc\xee\xbb\x78\x43\x8c\xa4\xb1\xf9\x82\xb7\xdb\x97\x98\xec\x1a\x7f\x32\x62\x22\x64\xcb\x02\x4c\x0d\x9e\x60\xe9\x55\xa6\xe1\xd6\x77\xc9\x23\x51\x88\x51\x99\x0a\x45\x9b\x76\x7d\x0f\x13\xcd\x80\x34\x60\xf6\x18\x70\xdb\x33\x91\xb4\x46\x93",
+ "a00a601edeaca83041dc452d438a8de549594e25d843c2cf60a0e009fb92d87abe28a72690ab657c8d35b43cd02d22ec0755de229d1f922fa6ca18a6d6c2aaae"
+ }, {
+ 77,
+ "\x0f\xeb\x23\xc7\xe4\xa1\x9b\xcb\xd7\x0b\xd3\x00\xd7\x6e\xc9\x04\x5d\x69\x6f\x8c\x96\x87\xf4\x9e\xc4\x15\x44\x00\xe2\x31\xd2\xf0\x86\x24\x95\x15\x0c\xf2\x50\xb6\xf1\x2f\x17\x2a\x7d\x13\x0f\x8f\xa5\xd1\x75\xbf\x2f\x25\xe2\x80\x17\x2c\xcd\xfb\x32\x79\x51\x70\x11\x65\x30\x27\x28\xa6\x19\xaa\x2f\x24\x26\x31\xc9",
+ "eeb6dee30c119fb1e1eb5c15ff2b32d8b9c7464a4e4cc6815cd251a6bae29b49961dd5c2fa9c44a9b142ca062c7072cbf3db04299b767789040196bf0c06aa76"
+ }, {
+ 78,
+ "\xac\x59\xa1\x10\x62\x3f\x1a\x64\x66\x6f\x16\x0e\xd3\x29\x26\x67\x6c\xb5\xbe\x25\xdd\x9d\x96\x2f\x44\x19\x51\xb0\xef\xcb\x5d\x6a\x67\xac\x1a\x4e\xae\x47\x3e\x49\xc6\x25\x78\x60\x72\x88\x53\xff\x41\x5c\x5e\x8e\xc7\x6a\x8a\x46\x2e\xcf\xd3\x43\xee\xac\x22\xda\xd8\x20\x72\x2c\x59\x73\x32\xfb\xfd\x94\xeb\xbd\x32\xc6",
+ "f65ea942ae0a47e73b02b1442e5b26083db79307f64dd34a039c476faf18d5c514bb77a2c412a6074a7afc326ea66c74e5705fe2abbabf274333325a15b61fd9"
+ }, {
+ 79,
+ "\x9e\x3e\x10\x77\xe1\x33\x3a\x1f\xb1\xaa\x63\x3c\xcf\x2f\x74\x65\x88\xad\x42\x64\x89\xea\x08\xdf\xf5\x51\x14\x38\xb5\xf4\xc0\xb1\x10\xd1\xa4\xd4\x7b\x54\x0a\x12\xb2\x1e\xa2\xaa\x07\x05\x78\xcc\xfa\x5c\x22\xfe\x0b\x74\x3e\xc0\xcc\x62\x1c\x6b\x3a\x03\xb7\x5f\x4d\x3e\xea\x5d\xce\x89\xe0\x32\x69\xaf\xcd\x96\x03\xd0\xdb",
+ "4b5c5df80c344c12388c723856cd06965b2190af652480476747dc2195ea3716f87c1762359583a5f31522f83f7833bec30f1f47d14540417dd463f5d258cd4a"
+ }, {
+ 80,
+ "\xe8\x81\xe3\x28\x4c\x79\xd8\xf5\x23\x7e\x69\x9e\x4f\xbc\xa8\x40\x90\xc6\x64\xbb\x53\x22\x9f\x58\xcb\x08\x42\xb0\x43\x67\x10\xc9\xb3\x29\xd9\x81\x91\xb8\xf0\x30\xe9\xc1\xdf\x89\xb0\x38\x58\xc1\x56\x9c\x6f\xf4\x9a\x7c\x07\xc4\xa2\x3a\x8a\x43\x4b\x0f\xde\x13\xbe\x4f\x94\xcb\x44\xee\x62\x9d\x5b\x44\xd3\x36\x09\x0d\x3d\xe6",
+ "147d8071c7871ef9256cff32aa63ea031404fa5ee4ec09c56afdd5da919b0cc84a9d35d142c417715203316011cc620cd6855bb117063a5e52867facc680d5f4"
+ }, {
+ 81,
+ "\xe5\x85\x21\x09\x89\x11\x50\x3d\xe8\x43\x11\x38\x7d\x37\x5c\x25\x92\x9e\x6e\x55\x07\x6e\xb6\x93\x4f\xd8\xf2\xb1\xbb\x7b\x96\x67\xfb\xd7\x6d\x5e\xe2\x04\x82\x87\x69\xa3\x41\xb1\xf7\x16\xda\x5b\xdf\xec\xe6\xc6\x2a\x9f\x4d\x4f\x98\x82\x67\xfc\xe1\xf5\x61\x55\x40\xdb\xe3\x75\x32\x4e\xef\x60\x7c\x91\x0d\x97\x6b\x45\xa5\xea\x5f",
+ "f97ba056fa41f43b8e1987072a09e828c71c5ff6ad4e37f9ab6b89e2a078933dd23052fa72c6615b613904259e9ff9b55ef7b923b89bc8752f6babddd256e117"
+ }, {
+ 82,
+ "\x37\x96\xcf\x51\xb8\x72\x66\x52\xa4\x20\x47\x33\xb8\xfb\xb0\x47\xcf\x00\xfb\x91\xa9\x83\x7e\x22\xec\x22\xb1\xa2\x68\xf8\x8e\x2c\x9f\x13\x3e\x5f\x85\x27\xf1\xb1\x84\x83\x0e\x07\xc3\x45\x8c\x83\xa8\xca\x9f\x9d\x9c\x69\x98\x76\x0e\x61\x06\x68\xba\x0f\x22\xe2\x2b\x65\x6a\x73\x7e\x97\x8b\x24\x6a\x17\x84\x0b\x7d\xc4\x09\x1d\xa8\x5f",
+ "c8a466199acbcbc93f2ce042968508c046901631e3118a2d0bf39a9b42b4197a379b3a86cdeca9df2de1a3eb71b79ae9bf2d6575eadf1878029c4093133f54d3"
+ }, {
+ 83,
+ "\x9a\xf6\x08\xd0\x31\xcc\xf3\x09\xd7\x27\x3c\x60\x7a\x8e\x5e\x36\x84\x0d\x44\x9b\x55\xdb\x5b\x13\xf0\x3a\xeb\x9a\xf4\x9f\xa7\xe7\xcf\x13\x83\xee\x2e\xd9\xc5\xa8\xb7\x51\x5f\x16\xfb\x1c\x7c\x84\xa6\x81\x59\x0b\xf9\x0f\x56\x59\x7b\x84\x4d\xb5\xeb\xee\x22\x3d\x78\x10\x9b\x72\x35\x07\x72\xf7\xc7\x2e\xa9\x96\x60\x3e\x1e\x84\xf2\xba\x5f",
+ "f0ded9495b4f64cac585be8a737cfa14247a4a81cdf7f01ebcb134ace71f5a83df2cd72e7773fea1e82beae17e13857372792c8231e2ab9fbeb633e399d5f0ae"
+ }, {
+ 84,
+ "\xd0\xdf\x1b\xdf\x1d\xf6\x20\x32\x41\x72\x2f\xb9\xc9\xc1\xcf\x74\x05\x01\x74\x97\xae\x15\x45\x38\xcc\xf9\x22\x4a\xd7\x52\xe6\xce\x1d\x4a\xe9\x48\x63\x9a\xca\x70\xcf\xe8\x6b\x2b\x06\x54\x3c\xb9\x91\x4e\xbd\x30\x85\xaa\x3e\x29\x63\xf6\xe9\xb9\x3d\x0b\x03\xa3\x1a\xe2\x6f\xcb\x9c\xa9\x74\xee\xe0\x16\xc0\x91\xa6\xfc\xac\x37\xb2\x1c\xc1\xd7",
+ "c2da3ea3c8a3fd88a5bc5dea2bc076f861abedefae5a5fbd941ddfd1c41cc3312eb2dc826c2c0f65414fe72ebee447d2f9b1a6a56302660d1f86632ee80a175f"
+ }, {
+ 85,
+ "\x8c\xbc\x94\x80\x55\x3a\xce\xf7\xbc\xdb\xa9\x71\x6e\xa8\xd6\x6b\x41\x31\x78\x09\x17\xde\x2b\x0b\x04\x80\x45\xfc\xb3\x2b\x5c\xac\x05\x48\x08\xe1\xfc\xe6\xe9\x4a\xd8\x51\xec\xb4\x7f\xe6\xcb\x80\x22\x25\xd3\x55\x1e\x08\xea\x12\x20\x93\xd0\x07\x8d\xad\xa5\x64\x21\x2e\xac\xf1\xd6\x39\x4e\x00\x07\xcc\x62\xa1\xd5\x95\xab\x14\xca\x08\xa2\x84\xbc",
+ "63b39b88ceb848188b37316e04560e75a5340ab8d417932d231c997e892b41daa69d9fe3e9a14dd19ccfbbfa01488c208e7b946cfaf16ca2b1bf7c8d8da4e6b2"
+ }, {
+ 86,
+ "\x38\xf1\x84\x44\x8f\x3c\xf8\x2a\x54\xca\xfc\x55\x6a\xff\x33\x6f\x23\xf9\x14\x9e\x61\x21\x34\xb3\xfc\x00\xc8\xa5\x64\x55\x65\x3d\x88\x64\x0b\x12\xf6\x90\x62\xb8\x43\x2c\x43\x35\xad\x8f\x7a\xb4\xff\x66\xcb\x7e\xb5\x4f\x33\x25\x61\xa3\x6f\x02\x4d\x92\xc3\xe2\x62\x76\xf4\xfd\x48\x61\x96\x28\xcf\xf8\x8e\x4b\x8e\x85\xcf\x14\xca\x47\x67\xed\x99\x0d",
+ "9a49265fc641c59f1a91872cdae490d3da73c0c60fd59648e1d17dba1a647a5b95629392bb4ff5163d1a3cb45427c1437a3b2e1d9f030c0a8bcc5ed22da9e2ed"
+ }, {
+ 87,
+ "\x70\x90\x06\x18\xb1\xe9\xe9\xdb\x62\x29\x6f\xb6\xc6\x59\x0c\x9f\x10\xb0\xa6\x32\x76\x5c\x48\x9c\x88\x7f\x1a\xb7\xc0\x77\x91\x76\x5a\x62\xe3\x84\x65\xe1\xbe\x28\x1b\x1d\x39\x6c\x6e\x08\x0b\x7e\xe3\xe6\xfa\x56\xa3\x0b\x97\x99\xd0\xe6\x29\xbe\x15\x3e\xe7\x6f\x81\xbc\x6a\x32\x95\xaa\x61\x48\x9b\xfa\x87\xd5\x3a\x8a\xd2\x42\x48\xa6\xed\xe0\xdf\xcf\xe9",
+ "1c8c3357ff1f8d6ac4defb3af462a73e09159e3a20c6506edd8cd3052df941c81f68c5fbb893912619e28640977fe8eaae8e9d5d4e7d5f132552cefab4540bac"
+ }, {
+ 88,
+ "\x4e\x6d\xda\xe0\xd8\x05\xaf\xcd\x10\xa0\x55\xbc\xe5\x84\xc8\x48\xd0\x50\xfb\x29\xfe\x8f\x1c\x64\xb1\x8e\x1a\xbf\xe4\x6b\x65\x78\x2e\x6f\xf5\x36\xe8\x9d\x8d\x40\x92\x8b\x41\xed\x73\x71\x36\x5c\x80\x80\xa9\x64\x7f\x75\x32\xce\x6c\x6d\x4a\xc2\x1c\xfb\x0c\x80\x20\x78\x38\x51\xec\x9a\x7d\xbc\x39\x48\xf8\xfc\xa7\xad\xf8\xb2\xa7\x8c\x04\xd8\x98\xd3\x1f\xf6",
+ "5c2f996c779b91b3c4639311f54fabbdde7e2212b53dbae4828c8399588fc00d3b2ae60918aaaf6bb48bc757e52b2bcea84f5d15bf4ec25d5519fb54f6f26e1b"
+ }, {
+ 89,
+ "\x69\x68\x25\xf6\xd6\xea\x81\x73\xec\x47\xd0\x95\x9a\x40\x1c\x4d\xdf\x69\xf8\xf0\x8d\xdd\x67\x8a\x4d\x2f\xf9\x76\xe3\xa4\x37\x2b\xb3\x9f\x41\x59\x84\x5c\xb6\x35\x85\xe1\xd4\x10\x8d\x32\xe1\x2f\xa7\xc5\xc9\xd7\xce\x35\x08\xa7\xf5\x3a\xca\x2b\x4b\xd9\x51\xad\xbc\xd8\x98\x4e\xbb\x75\x36\x56\x3f\x58\x84\xc9\x0b\xc5\x02\x3b\x33\x16\xf7\xe4\xdc\x69\x58\xf7\x43",
+ "3ce940ca96b00011375daa95c65f66907d69b3eb3b8d779e6fc971afcc05e990bc4c541f434590f6b18b68c080d0f24475a3e764e9cb85343301314ee2fb661e"
+ }, {
+ 90,
+ "\x79\xec\xdf\xd4\x7a\x29\xa7\x42\x20\xa5\x28\x19\xce\x45\x89\x74\x7f\x2b\x30\xb3\x64\xd0\x85\x2c\xce\x52\xf9\x1e\x4f\x0f\x48\xe6\x1c\x72\xfa\x76\xb6\x0d\x30\x02\xca\xe8\x9d\xfc\x55\x19\xd3\x43\x0b\x95\xc0\x98\xfa\x46\x78\x51\x6b\x5e\x35\x51\x09\xea\x9b\x37\x45\xaa\x41\xd6\xf8\x20\x6e\xe6\x4a\xe7\x20\xf8\xd4\x46\x53\xb0\x01\x05\x7f\x2e\xba\x7f\x63\xcd\x42\xf9",
+ "ba3d0fe04470f4cf8f08c46d82ae3afd1caea8c13bebbe026b5c1777aa59860af2e3da7751844e0be24072af48bc8a6fd77678aaee04e08f63395f5c8a465763"
+ }, {
+ 91,
+ "\x92\x63\xfe\x75\xe8\xf6\xc7\xd5\xd6\x42\xe2\xca\x6a\x6e\xea\x4f\x44\xe9\xa0\xf2\x49\x51\x3e\xd7\x9c\x94\x09\xff\xca\x55\x26\xca\x44\x91\xae\xbb\x13\x82\x05\x7c\xc7\xc3\x67\x22\xb0\xb6\xc3\xb1\x51\x23\xcd\xe3\x12\x21\x4f\x25\x35\x3a\xbf\xe3\x0b\xca\x17\x05\x68\xa8\xe1\xba\x54\x08\x91\x74\x03\xa0\x18\x34\x08\x0a\xb6\x07\xc5\x6a\x10\xd0\x26\x50\x82\x49\x8f\xe0\xb6",
+ "7736d7a7fc1eb05857ce7d88abfffa87f58c670bfdfc0a8031f60f379e4b6ad94ac8f13ffe28c697809b5cfac7f13be01e7496a85237c4025539051fb2e32fb6"
+ }, {
+ 92,
+ "\x78\xc1\x7b\xfe\x0e\x02\xeb\x52\x6d\x1a\x44\xa1\xac\x12\x7b\xe0\x82\x18\x14\x52\xb6\x25\x39\x4b\xd6\xdc\x09\x3a\x2c\xb4\x32\xe6\xee\x59\xc2\xf8\xb5\x50\x3a\xba\x30\xda\xe4\x1e\x1a\x1c\x67\x02\x69\x7c\x99\xb2\xc9\x4e\x94\xaf\x48\xb0\x0c\xaf\x53\xb2\xe0\xe4\xe1\xbb\xee\x81\xee\x28\x2c\x7b\x2b\x35\xf5\x8c\xf4\x21\xa0\x7e\x82\x8d\x57\xa6\x62\x26\x26\xaf\x25\x83\x53\x99",
+ "b56b6e343166328523e0d1693e5174da643ae83cf69c85a7b3c3bee247b77b84702069d9e6b4cab03bf17fe612009bf4239683ca78ca7e876aca7d07603ba714"
+ }, {
+ 93,
+ "\x29\x8b\xb3\x04\xa9\x20\xf9\x60\x44\x7d\x8f\xd3\x8b\x06\x1b\xf8\xfe\x4a\xc1\xf8\x71\xd8\xa0\xfe\xb4\x54\x9f\xeb\x72\xca\x69\x4a\x5a\x41\xb6\x86\x7d\x94\xcd\x5a\xf7\x7d\x46\x8a\xd2\xf3\x15\xd1\x27\xb6\xc4\x1a\x86\x28\x00\xf3\x98\x5e\x57\x3e\x03\x77\x40\x29\x8e\x2c\x5c\x61\x86\xa9\xfb\x83\x60\x9b\xe2\xd4\x9f\x8b\x4c\x31\xf9\x6a\x2e\x49\xb5\x6d\xbf\x09\x57\x1b\x38\x58\x7f",
+ "34e3878627904ffbbbd85266cc973c34f931e3cab5d4c31f841c553dd69f84838206067df4f9f3b9102001be19267151e673f5c2d4c2f8438a6999a0a325487d"
+ }, {
+ 94,
+ "\xa3\xcf\x71\x4b\xf1\x12\x64\x7e\x72\x7e\x8c\xfd\x46\x49\x9a\xcd\x35\xa6\x40\xdd\x39\x3d\xdd\x26\x3c\xd8\x5c\xf6\x22\x5f\x59\x89\x0a\x06\x86\xda\xd1\xc5\x4e\xb8\xd8\x09\xb8\x1c\x08\xa9\x8d\xba\x13\x1b\xbd\xd6\xfc\xe8\xff\x59\xd9\x5d\xb8\x24\xd8\x83\x1e\xa4\x80\x52\x9d\xa7\x39\x22\x7a\x6e\x0f\x62\xb6\x03\xb3\x8c\x35\xcd\xc2\x58\x1f\x61\x4a\x31\x87\x9b\x8b\xe5\x4a\xee\xfa\xa0",
+ "6f230ae4903ddbef0ba384c2e3506eab318bfd1a46ea76099f65a3fd529c91bc2865b9fd943e346de64626b8529f9db1377bf2c5e0129c66b50c6a5cfb364b3a"
+ }, {
+ 95,
+ "\x0a\x42\x7a\xe5\x5e\xf3\xa7\xe6\x04\x4a\x08\xcf\x61\x28\xcb\xaa\xab\xfd\x77\x6c\x4e\x93\x74\x70\x8f\x2e\xce\x24\x6f\xd7\x36\x03\xd2\xf5\x4a\xc3\xe0\x1d\x16\xcf\xac\x2b\xda\xf7\x13\x92\x0d\x66\xe8\xf0\xa3\xd5\x4e\xe6\x8c\xff\x64\x26\x7d\x55\x28\xcd\xf2\xf2\x95\xf4\x74\xd1\x0f\x81\x17\x3e\x01\x43\x48\x8a\xc5\x3f\xc5\x03\xc4\x44\xed\x23\xde\xc6\x3a\x08\x0c\xe9\x0c\x24\x43\xdb\xa8",
+ "f6bbe5d0cf13ddf41c1436748a5d1ccae2948547b452c2171c7c8e8b66c6ae4de3c0e8b2962bcb60d3de3608479f80e455c9024d9716c38f6f1206861ab1eaac"
+ }, {
+ 96,
+ "\x2c\xbb\xb8\x75\x11\xf4\x94\x8e\xfe\xc3\xa6\x1b\x51\x1e\xde\xdb\x1d\xda\x8b\x6e\xcf\xc0\x21\x0c\x11\xe4\x3a\x77\xee\x32\xdc\x2e\x37\x4a\xfa\xe4\x26\x8e\x3d\x30\x42\x78\x04\x86\x82\x32\xa9\x66\xb5\x60\x06\xd3\x21\x40\x37\x07\x6b\xf6\xa2\x65\xb7\x21\x35\xaf\x0f\xb2\xef\x79\x09\xfe\xa2\xde\xa4\x12\xf7\x71\x74\x46\xb2\x76\xff\x15\x37\x53\x66\x2b\x4d\x41\x48\xc0\x23\x47\xe3\x25\x91\x69",
+ "76897b87a8a1cf835c434f6d391c9e5227351af9d3e20a3389c796b98b424281a59068d9c8d567ec2bebc435b0126b059e2d86394a9854d6611e1c922f385496"
+ }, {
+ 97,
+ "\x2b\x23\x32\x4c\x99\x92\xf6\x0a\x7f\xc0\x10\x15\x9a\x03\xcb\x9a\x2b\x29\x0d\xf4\xfa\x6a\x82\x35\x9b\x9a\xf6\x02\xf0\xa4\x03\xa5\xef\x33\xed\x5d\xa5\xb2\xca\xf8\x7b\x77\xe6\xa4\xb9\x3b\x65\x03\x48\xce\x2a\x7d\xbc\x08\xf8\xda\x92\x03\xd7\x10\xb5\x87\xba\x59\x47\xc6\x5e\x89\x9f\x4a\x75\x9f\x8e\x2b\x04\x9a\xe7\x85\x0a\x8e\x3e\x29\x62\xf6\xef\x93\xea\x4c\x63\x1d\xe5\xd7\x8e\x72\x9e\xc5\xbc",
+ "3beea0b373ed09cf1c919c51d86d642c9125e0ee81698dc4cbadf02e9e6925efb562fd9b87301a6377ca192be79c4118deabc450b54639000c2e312945451fb5"
+ }, {
+ 98,
+ "\x40\x22\xf9\x30\xc7\x03\x3b\x00\xd9\x86\xc6\x5f\xf6\xbb\xbd\xf9\xeb\xd0\xe5\x8c\x52\x84\x4f\xf6\x58\xdf\x38\x93\xc3\x20\x2d\xc5\x33\xf8\x73\xd4\xa7\xf5\xa5\xf9\x44\x41\x9f\xb5\x52\x8c\x9b\x67\x88\x47\x9a\x1e\x89\x13\x06\xac\xae\x79\x95\xfc\x06\xdb\x70\xa5\x9b\xaa\x95\xbe\xf7\xda\x79\xf5\xe7\x93\xf2\xdb\x7f\x2a\x55\x82\x5e\x4f\xdb\x4a\x34\x88\x4a\xf8\x81\xde\xd1\x08\x9f\xd5\x33\x45\x02\xa2",
+ "0358775bbb733ccc49e78f544aeee512370d480d0e13c7e8d5c444c423e592146b45fdb91a1b694d35e36b60e4bc8397fca8bb9790e619339778b9cd1abe3fe9"
+ }, {
+ 99,
+ "\x1c\xb7\x7b\xa4\x3c\xe7\x7e\x23\x6b\x9f\xc9\x25\xf5\x89\xb1\xc0\x70\x78\x0a\x84\xf9\x9e\x8f\x50\xc1\xff\x84\x6a\xc9\x25\x99\xcf\xe9\x16\x12\xc8\x17\x83\x25\xbe\xe6\x42\xa3\x4f\x4d\xff\xdb\xa2\xaa\x2e\xbc\xf7\x06\x43\x39\x82\x9b\x26\xf2\x79\x93\xe1\x10\x6c\x13\x9c\x70\xd5\x78\xcc\x05\xf0\xe1\xa7\x77\xcc\xed\xdb\x10\xa2\xc6\x7f\xd9\x67\x5e\x4a\x00\x9d\xf8\x03\x7d\x6e\xeb\x38\xf5\xfb\xa2\x33\xdf",
+ "6502f46551a3fab3a96428fb97801d7a4aa2f17fef6603238df84e17c74309ed3d9489c8b16a9384ee634a3f86d0b3ba9a4dbc9c51ec8bd4bf8d61de6d3d87d7"
+ }, {
+ 100,
+ "\x52\x16\x7d\xe2\xd6\xc5\x02\xd9\x9f\xa1\x0c\x27\xb2\xab\x62\x03\xbd\xeb\xc2\xca\xfb\xbf\xde\xf1\x58\x72\xa4\x3d\xd6\x10\xc2\x36\x2f\x79\x6a\xd9\xbc\xb5\x52\x8d\x95\x87\x00\x58\xfa\x45\x44\x53\xf1\xe6\x06\x5b\x31\x5d\x41\x0a\x3f\x26\x50\xe5\xd7\x1e\x69\xd7\x8d\x97\x67\xdf\xb4\xac\xcc\x05\x7f\xd2\x06\x92\x66\xb0\xf1\x80\xcb\x31\x9e\x30\xde\xd7\x53\x5b\xbe\x52\xd2\x4b\xe1\x51\xde\x4b\xb5\x98\xfc\x5c",
+ "25cb3ed3983a91b4cf37a65193916c5e3e211b63e943e2f7b50a85d349a463b941aad33eff16561bdfdc92fda06a4e1d94b162de48f06d3c626940b31020925f"
+ }, {
+ 101,
+ "\xce\xde\x66\x97\xd4\x22\xdd\xaa\x78\xe2\xd5\x5a\xe0\x80\xb8\xb9\xe9\x35\x6c\x69\xbc\x55\x82\x01\xa2\xd4\xb0\xb3\x19\x0a\x81\x2c\x27\xb3\x4b\xbc\xee\x3a\x62\xb7\x81\x37\x8b\x1b\xf6\x36\xb3\x72\xbc\xba\xe1\xfa\x2f\x81\x6a\x04\x6a\x0a\x64\x9a\x5c\x55\x5c\x64\x1f\xea\x4c\xcd\x84\x1c\xc7\x61\xf3\x8f\x77\x79\x72\xf8\xc9\x1b\x03\x24\xe7\x1c\x33\x3c\xe7\x87\xf0\x47\x41\x43\x9b\xf0\x87\xef\x5e\x89\x50\x11\xc0",
+ "0be42a25d77ac6ad995c6be48e783380bad25a61732f87cefb0cce1a769cd69081f494a1a12d657664ef2b4d9c41f2ee83f6e9a84327d8756af9f985595e7d3b"
+ }, {
+ 102,
+ "\x56\xd1\x8d\x3e\x2e\x49\x64\x40\xd0\xa5\xc9\xe1\xbc\xb4\x64\xfa\xf5\xbc\x70\xa8\xb5\x62\x12\x4f\x5f\xc9\xe9\xde\xb5\xfe\xe6\x54\x4b\x94\x5e\x83\x3b\x8b\x5d\x13\x1b\x77\x3e\xcb\x2c\xdd\x78\x0c\xd4\xe1\xbb\x9e\x4f\x1e\x3c\xb0\xa1\xd6\x4d\x19\xcf\x4b\x30\xe4\x4e\x6c\x2d\x0c\xbc\xb4\xe2\x84\xce\x50\xdb\x7a\x8a\x80\x62\xdd\xb6\x3f\x98\x1d\x90\x26\xc5\x32\xbf\x8e\xed\xdf\x8a\xf5\xa4\x38\x48\xa3\x22\x62\x17\x8c",
+ "982dc61c91a93770582eee8025aa55da8e9edb966bf5cf70d4a6534c0d53a2789a8c4fb65b7fed478cda02ed1e0d198d85c5c735b2417c5fab5d34e969fc8e7e"
+ }, {
+ 103,
+ "\x25\xa7\x32\x0d\xfa\xec\x5a\xf6\x5d\xa4\xd0\xf8\x68\x8e\x29\xe8\xe9\x55\x32\xec\xc1\x66\x79\xea\x8a\xff\x0f\x40\x7d\x89\x8d\xb6\x92\x28\x55\xb0\xe8\x90\x1a\xa9\x68\x1a\xa3\xdc\xa6\x17\xcb\x44\x07\x64\xcd\xc7\x29\x3f\xbe\xaf\x7f\x58\x5b\x59\x3c\x2b\x05\x31\x73\x8e\x0a\xde\x7c\x86\x26\xb9\x99\x5f\x4a\x84\xd9\xfc\x9b\x59\x3d\x6b\xbe\xe0\x1a\xbc\x53\xc5\xbe\x14\xbf\x69\x56\xfd\x2f\xd8\x10\x00\xda\xfc\x7c\x76\x86",
+ "749c928c3d5510925bfe98659025b0ed7c01acd4d59a9bf1c54863a088091771dc9d407bdbf83b0f44b0902e10349ba79c84d0981d5e8c4f5c733a117fed0790"
+ }, {
+ 104,
+ "\x3d\x71\x77\xb2\x8f\xfd\x91\x6e\x7e\x06\x34\x89\x58\x33\xba\x0b\xd9\xe0\x65\x3d\xf2\xcc\x42\x02\xc8\x11\x53\x6a\x00\x5a\xec\x85\x3a\x50\x5e\x75\xdb\x55\xd3\xc7\x10\x75\x79\x04\x10\x99\xe3\x82\xa1\xfe\xac\x80\xdd\xe6\x5d\x72\x36\x8e\x90\x9a\xb8\x5f\x56\xd8\x8e\x68\xd7\xc3\xc8\x0c\x38\xf8\x5b\xf8\xc2\xb3\x69\x59\x40\x9c\xc3\x4b\xa8\xe3\xad\x94\xfe\x8e\xe1\x92\x76\x12\xd6\x72\xd9\x21\x41\xa3\x29\xc4\xdd\x8a\x88\xa9",
+ "14a331508cd7d94fcce56a66bf65f20870a281c8442f8dbd4c2371454a2b66f8d0994a0b67692e771efc6a5e0b887acae7d6f4ec7338e1aa89f2abc7034c4e4c"
+ }, {
+ 105,
+ "\xc0\x33\xe4\xa5\x12\x29\x7c\xae\xcd\xbe\xad\x89\x2b\x11\xa9\xf7\x00\x7a\xf9\xa7\x4b\xca\xb8\x9e\x0b\xd4\xff\xdd\x54\x2c\xa0\x3e\xa1\x2e\x17\xa0\x6c\x42\xbd\x43\xfc\x5f\x3f\x75\x7f\xce\x4f\x6f\x58\x31\x99\x7a\xba\xc3\xf9\x56\x76\xe1\xeb\xdb\x11\xca\x43\xe1\x1a\xa3\x1e\x5e\xba\xbe\x18\xce\x8d\x1b\xbf\xd8\xb0\x2f\x48\x2e\x1c\xe5\x81\xb5\x32\xe3\x07\xe6\x96\x0e\xb9\x74\x41\x50\x6c\x2e\xd2\x99\xe1\x28\x25\x23\xf4\x15\x27",
+ "95ac9b7d22aa458921874c4b4331e7d64761853217c3f83c601abcbccd7e2eaa6ca6ce9a22ebcfe5046d52f8a09097f043ab8bc59243fd770090bb432c3155e9"
+ }, {
+ 106,
+ "\x69\xff\xf0\xf1\xa3\xdb\xfb\x36\xe3\x2f\x02\x58\x19\xfa\x99\xea\x9a\x0e\xda\xef\x73\x14\x5b\xf7\xfc\xd0\x5d\x8b\xb0\xa6\x46\xcb\x3b\x5d\x52\x56\xd5\x24\x85\x6a\xcf\xd2\xe4\x4d\x6b\x72\xe4\xeb\xf1\xff\x23\xc0\xff\x6c\x56\xf8\x21\xe7\x82\xd5\xa1\x5f\x70\x52\xa1\x44\x5b\x06\x66\x8e\xeb\x4a\xf7\x00\x67\x9e\xe7\xae\x26\x49\x6f\xbd\x46\x40\xc0\x6a\xa1\x49\x96\x4d\xfd\x60\x11\xdf\x83\x5a\xc1\x3b\x73\xc8\xff\x21\x15\x1e\x84\x40",
+ "45d4daa652558d1c12beb0f5662c712f325b4c802fc6eb9ee039c949d002bb786f1a732712be941f9c5c79b3e5c43064d63a38578e5a54ee526acb735b9ad45f"
+ }, {
+ 107,
+ "\xb2\xc4\x39\xc9\x7a\xb7\xc6\x37\x36\xb3\x79\x63\x24\xd6\x8e\xeb\x7a\x47\x1e\xd1\x42\xbd\x96\x22\x68\x41\x67\xd6\x12\x34\xff\xf8\x2f\x93\xf9\x07\x53\x7a\x90\x9b\xc2\xe7\x5a\x4b\xcb\xc1\x33\xcf\x57\x19\x76\x62\xc1\xaf\x74\x6a\xe8\xb8\x1e\x5b\x83\xde\x05\xd9\xb5\x89\x85\x1d\xe2\x5d\x3c\x99\xc0\x04\xc1\xdf\xb1\x2d\x93\xbf\x50\xd4\x50\xaf\x49\xc4\x28\x71\x6f\x5b\x90\xef\x08\x8e\x3b\x6a\x6b\x2c\x46\xd3\xce\x67\xb3\x79\x59\x90\x18",
+ "c48ec83be5fa669e6ec8db90aca9676cfe2ec0d5e8e7a2431687bb953c0a300be3db4075cca3bac4dfa4d971baf0fa1aff46639db4b238856ff36d1dfcd520f1"
+ }, {
+ 108,
+ "\xc0\x16\xf5\x22\xf2\x6b\x74\x70\xe9\x22\xb9\xa2\x87\xe6\xd4\x5f\x6c\x28\x81\x3b\x68\xc1\x45\x7e\x36\xd9\xba\x26\x67\x08\x27\x2f\x9c\xbc\x54\x11\xf8\xdb\x9d\x8b\xd5\xa9\x44\x9f\xb6\xeb\x0c\xde\x7d\x4d\x03\xe5\xdf\x01\x9f\x28\x14\xa9\x0c\xee\xd3\x77\xc5\x9d\x7d\x92\x62\x38\x99\xbc\xb0\x26\x80\x33\x07\x35\x59\xd4\xd8\xde\x48\x86\x86\xcb\xe3\xd6\x77\x96\xe6\xdf\x6a\xd4\x27\x6d\x0b\x52\xcc\x62\xc4\x9e\xbb\x58\xd7\xc9\x52\x87\xaa\x6c",
+ "7402f1a99b47e102b3b73140c6771b07ee6c33b3715e9c4027c441bee40511b735d95e508baea78da26fded9b7038e9a53defa58448aba40dc1e62d7ec592107"
+ }, {
+ 109,
+ "\xa7\x66\xb2\xa7\xef\x91\x67\x21\xf4\x67\x7b\x67\xdb\xc6\x5e\xf9\xb4\xd1\xbd\xa1\xad\x4e\x53\xfc\x85\x4b\x02\x36\x44\x08\x22\x15\x2a\x11\x19\x39\xe5\xab\x2b\xa2\x07\x71\x94\x72\xb6\x3f\xd4\xf4\xa5\x4f\x4b\xde\x44\xa2\x05\xd3\x34\xa2\xd7\x2c\xfe\x05\xab\xf8\x04\xf4\x18\x41\xb8\x6d\x36\x92\x0b\xe6\xb0\xb5\x29\x33\x1a\xc1\x63\xa9\x85\x55\x6c\x84\x51\x1e\xc9\x86\x43\x9f\x83\xe1\xd7\x31\x1f\x57\xd8\x48\xcf\xa0\x2d\xf9\xea\x0c\xf6\xb9\x9a",
+ "ddd60f93a3babc78299cf763e7919d45ac6f479700e1adb05ab137acdf89c1521ecb9dfeacd091e58ca57a1db964a9c3cd1fa39192cc1e9f734caa1c5fa62975"
+ }, {
+ 110,
+ "\x10\xf2\xbe\x77\xa4\x05\x57\x71\xa6\x70\x07\xcd\x86\x30\xe3\x23\x0e\x38\x28\x84\x99\xcb\x16\x03\x80\x29\x01\x74\xd6\x6d\xa5\x74\x55\xb6\xba\xaa\x97\x85\xc8\x4c\x8a\x66\x3d\xe4\x1e\xd3\xbd\x54\x40\x55\xb9\x17\x0c\xec\x43\xcb\x3e\xb1\x20\xec\xea\xba\x1f\xe3\x6e\x3e\xaa\x3f\xa4\xf9\x9b\x42\x5c\xd2\x51\x9f\x09\xbc\x02\x82\xba\xda\x52\xd1\x4c\xe6\x25\xb1\xde\xd3\xb2\x4d\x86\xb1\xda\xd3\x42\xd2\xb7\xbe\x32\x2b\x77\x5b\x04\xfc\x6b\x86\xaf\xb4",
+ "a872fa33d463b3343cec57c20c66979c33e1ad067bfc703454696aab5dd0003bc194318f4a8ebbc74503feb7211a472dadee991efe3e38f21a1310f8a76eac80"
+ }, {
+ 111,
+ "\x32\x45\x33\xe6\x85\xf1\x85\x2e\x35\x8e\xea\x8e\xa8\xb8\x1c\x28\x8b\x3f\x3b\xeb\x1f\x2b\xc2\xb8\xd3\xfd\xba\xc3\x18\x38\x2e\x3d\x71\x20\xde\x30\xc9\xc2\x37\xaa\x0a\x34\x83\x1d\xeb\x1e\x5e\x06\x0a\x79\x69\xcd\x3a\x97\x42\xec\x1e\x64\xb3\x54\xf7\xeb\x29\x0c\xba\x1c\x68\x1c\x66\xcc\x7e\xa9\x94\xfd\xf5\x61\x4f\x60\x4d\x1a\x27\x18\xaa\xb5\x81\xc1\xc9\x49\x31\xb1\x38\x7e\x4b\x7d\xc7\x36\x35\xbf\x3a\x73\x01\x17\x40\x75\xfa\x70\xa9\x22\x7d\x85\xd3",
+ "3b26c5170729d0814153becb95f1b65cd42f9a6d0649d914e4f69d938b5e9dc041cd0f5c8da0b484d7c7bc7b1bdefb08fe8b1bfedc81109345bc9e9a399feedf"
+ }, {
+ 112,
+ "\x51\x89\x85\x97\x7e\xe2\x1d\x2b\xf6\x22\xa2\x05\x67\x12\x4f\xcb\xf1\x1c\x72\xdf\x80\x53\x65\x83\x5a\xb3\xc0\x41\xf4\xa9\xcd\x8a\x0a\xd6\x3c\x9d\xee\x10\x18\xaa\x21\xa9\xfa\x37\x20\xf4\x7d\xc4\x80\x06\xf1\xaa\x3d\xba\x54\x49\x50\xf8\x7e\x62\x7f\x36\x9b\xc2\x79\x3e\xde\x21\x22\x32\x74\x49\x2c\xce\xb7\x7b\xe7\xee\xa5\x0e\x5a\x50\x90\x59\x92\x9a\x16\xd3\x3a\x9f\x54\x79\x6c\xde\x57\x70\xc7\x4b\xd3\xec\xc2\x53\x18\x50\x3f\x1a\x41\x97\x64\x07\xaf\xf2",
+ "c00926a374cde55b8fbd77f50da1363da19744d3f464e07ce31794c5a61b6f9c85689fa1cfe136553527fd876be91673c2cac2dd157b2defea360851b6d92cf4"
+ }, {
+ 113,
+ "\x91\x59\x76\x72\x75\xba\x6f\x79\xcb\xb3\xd5\x8c\x01\x08\x33\x9d\x8c\x6a\x41\x13\x89\x91\xab\x7a\xa5\x8b\x14\x79\x3b\x54\x5b\x04\xbd\xa6\x1d\xd2\x55\x12\x7b\x12\xcc\x50\x1d\x5a\xaa\xd4\x76\xe0\x9f\xa1\x4a\xec\x21\x62\x6e\x8d\x57\xb7\xd0\x8c\x36\xcd\xb7\x9e\xea\x31\x4b\xdd\x77\xe6\x57\x79\xa0\xb5\x4e\xab\x08\xc4\x8c\xeb\x97\x6a\xdf\x63\x1f\x42\x46\xa3\x3f\x7e\xf8\x96\x88\x7e\xa8\xb5\xdf\xa2\x08\x7a\x22\x5c\x8c\x18\x0f\x89\x70\x69\x61\x01\xfc\x28\x3b",
+ "3cd3380a90868de17dee4bd4d7f90d7512696f0a92b2d089240d61a9d20cd3af094c78bf466c2d404dd2f662ec5f4a299be2adeadf627b98e50e1c072b769d62"
+ }, {
+ 114,
+ "\xfe\x2d\x8a\xe2\x00\xe6\x65\x7f\xdc\x74\x94\xaf\x5a\x12\xb2\xae\x94\x03\x48\xf1\xf9\x83\xf0\xba\x98\xfe\xbb\xe9\x9c\x80\xd1\x15\x12\x6d\x57\xdb\xf3\x72\x96\x76\x5e\xbb\x59\x90\x25\x66\x96\x58\x8b\x38\x51\xd5\x4c\x8f\xbe\x7a\xde\x98\xa6\xfa\xf7\xc2\x0b\x5e\x4f\x73\x0f\x54\xa7\xf9\x12\xca\x0a\xc3\x1b\xbb\x53\xd1\x79\x49\xef\x69\xaa\x0d\xe4\x0c\x7b\xab\x12\xa8\x71\xa9\xb9\x0f\x68\x81\x3c\xa8\x7a\xf4\x25\x64\x22\xa2\x68\xf4\xa1\xd8\xec\x3a\xa1\xa9\x47\xfd",
+ "8025a8608df0f6a01c34cdec012d4cb25852e1b100b68172fc4e86ac8b7126b64859cb9e767a7e59060989cedbd925afc475ca7369bd43f85ae590e224e036dd"
+ }, {
+ 115,
+ "\xdc\x28\x48\x4e\xbf\xd2\x93\xd6\x2a\xc7\x59\xd5\x75\x4b\xdf\x50\x24\x23\xe4\xd4\x19\xfa\x79\x02\x08\x05\x13\x4b\x2c\xe3\xdf\xf7\x38\xc7\x55\x6c\x91\xd8\x10\xad\xba\xd8\xdd\x21\x0f\x04\x12\x96\xb7\x3c\x21\x85\xd4\x64\x6c\x97\xfc\x0a\x5b\x69\xed\x49\xac\x8c\x7c\xed\x0b\xd1\xcf\xd7\xe3\xc3\xcc\xa4\x73\x74\xd1\x89\x24\x7d\xa6\x81\x1a\x40\xb0\xab\x09\x70\x67\xed\x4a\xd4\x0a\xde\x2e\x47\x91\xe3\x92\x04\xe3\x98\xb3\x20\x49\x71\x44\x58\x22\xa1\xbe\x0d\xd9\x3a\xf8",
+ "615115d2e8b62e345adaa4bdb95395a3b4fe27d71c4a111b86c1841463c5f03d6b20d164a39948ab08ae060720d05c10f6022e5c8caf2fa3bca2e04d9c539ded"
+ }, {
+ 116,
+ "\x5a\xf8\xc0\xf2\x6d\xb4\xe9\x9b\x47\xec\x2e\x4a\x01\xa7\x86\xe7\x78\x99\xe4\x6d\x46\x4a\xc3\x37\xf1\x75\x02\x7b\x61\xae\xf3\x14\x98\x48\xaf\x84\x9d\x76\xac\x39\xb9\xb0\x91\x0f\xe6\x59\x48\x17\x85\x9e\x55\x97\x4f\xa1\x67\x51\x8e\xd7\x2d\x08\x8d\xae\x6b\x41\x4d\x74\x4d\x47\x79\x74\xfb\x71\x9c\x62\x6d\xa7\x92\xf9\x81\x23\x3d\xe2\x4b\x75\x79\xd8\xac\xca\x51\x0a\x26\x6d\x73\xc0\xee\x8e\xe1\x42\x43\x43\xea\xf6\xff\xcc\x59\xc8\x6c\x1b\xec\xce\x58\x94\x07\x2c\x6c\x11",
+ "09da284d5b6556508be54c8ab6c97bbd472995c6bbd585917ecdb54ea9167208daaa070a7b2b7d8e93ce1315f0d1ef8d69667429c44dc5ee1499de57b229a398"
+ }, {
+ 117,
+ "\x49\xcd\x0b\xa0\xdf\x5b\xb3\xf4\x3f\x68\x46\x4e\x3e\x83\xe9\xcb\xd5\xd5\xee\x07\x7f\xfa\x55\x91\xe3\x0f\x93\x9c\xb3\x0c\x93\xf7\xd4\x54\xfb\x3f\xbf\x8b\xb0\x53\x27\xa8\x9c\x08\xdc\x4b\xaf\x1e\xef\x50\x23\x73\x17\xa4\x05\x77\x53\x57\xf1\xe0\xd1\xf3\x1d\x9f\x0f\x0d\x98\x12\x40\x19\xd4\x7b\xf1\x83\x63\xb1\xec\xfb\xfe\x15\x5c\x10\xcb\xc8\x33\x00\xe0\x1b\xc9\xce\x03\x47\xc5\x96\xb3\x5f\x41\x1e\x6d\x82\x29\xad\x28\x55\xe4\x20\x22\xb0\x37\x3a\xde\x98\x66\x3c\x6d\x6e\x9c",
+ "30cbf0679a97c871574d2fc05d7aa760c6bc8a864b7d246c39b9e812f9b7ff7b4ef5197dd5b69493306688b8564de1ad47d75505c913ba6a78788f8caf5788bd"
+ }, {
+ 118,
+ "\xa8\xa3\x7d\xfc\x08\x3a\xd2\xf4\x7f\xff\x46\x87\x38\xbf\x8b\x72\x8e\xb7\xf1\x90\x7e\x42\x7f\xa1\x5c\xb4\x42\x4b\xc6\x85\xe5\x5e\xd7\xb2\x82\x5c\x9c\x60\xb8\x39\xcc\xc2\xfe\x5f\xb3\x3e\x36\xf5\x70\xcb\x86\x61\x60\x9e\x63\x0b\xda\x05\xee\x64\x1d\x93\x84\x28\x86\x7d\x90\xe0\x07\x44\xa4\xaa\xd4\x94\xc9\x3c\x5f\x6d\x13\x27\x87\x80\x78\x59\x0c\xdc\xe1\xe6\x47\xc9\x82\x08\x18\xf4\x67\x64\x1f\xcd\x50\x8e\x2f\x2e\xbf\xd0\xff\x3d\x4f\x27\x23\x93\x47\x8f\x3b\x9e\x6f\x80\x6b\x43",
+ "8e1c91729be8eb40226f6c58a029380ef7edb9dc166a5c3cdbcefe90bd30d85cb7c4b248e66abf0a3a4c842281299bef6db88858d9e5ab5244f70b7969e1c072"
+ }, {
+ 119,
+ "\x36\xaf\x17\x59\x54\x94\xef\x79\x3c\x42\xf4\x84\x10\x24\x6d\xf0\x7d\x05\x93\x6a\x91\x8a\xfe\x74\xcd\x00\x5e\x53\x7c\x58\x6b\x28\x43\x70\x1f\x5d\xf8\x95\x22\x42\xb7\x45\x86\xf8\x33\x39\xb4\x8f\x4b\xa3\xa6\x6b\xde\xb4\x57\xec\xdf\x61\x78\x4e\xac\x67\x65\xcd\x9b\x8c\x57\x0d\xd6\x28\xdb\xba\x6a\xe5\x83\x6b\x9a\xc3\xdb\xcd\x79\x5f\x9e\xfd\xb8\x74\x2a\x35\xbc\xa2\x32\xab\xf3\x6e\xb3\xb6\x69\x8b\x29\x33\x96\x58\x02\x27\x7b\xa9\x53\xa6\xed\xca\xca\xf3\x30\xc1\xe4\xe8\xc7\xd4\x5f",
+ "158bfc348a30b4fabbe355a7d44bdc2122a4c850444c03f289003ce01bfc1ebf3ecc0febb6a8ff523d25db7681b05bdce048d11943ab476c1967cf6556c4a120"
+ }, {
+ 120,
+ "\x42\xd6\x6e\xdc\x5f\x22\xe0\xc1\x3c\x25\x50\x4c\x51\x01\xa5\xd1\x72\xd2\xdb\x72\x09\xe4\x61\xef\xa3\x23\xc0\xbf\xae\xd2\x7e\x5f\x80\x80\x42\xea\x9c\x38\x38\xea\x31\xf9\xb7\x6d\xe4\x65\x22\x5c\xcf\xbd\x0c\x09\xca\x0d\x9f\x07\xe9\xa4\x3e\x3e\x46\xc7\x69\x3e\x00\xa7\xe1\xd4\x83\x90\x0d\xdb\x0a\x62\x9d\x55\x63\x45\x6d\xbb\xf2\x99\xac\x91\xf9\x2c\x3d\x3c\x17\xb0\x5d\x18\x0e\x6c\x87\xc6\xc9\x31\x94\xc3\x9d\x90\x27\x3f\xcf\x4a\x48\x2c\x56\x08\x4f\x95\xe3\x4c\x04\x31\x1f\xa8\x04\x38",
+ "061afb119a3c60876e04c10f12ad0f4b977593dc5a2d21096a57e7d3f7d4d44fdef934b2c17d7530674e4f4a1c176dbdcc54811a22e1b8712e4192fc2d4bf8e8"
+ }, {
+ 121,
+ "\xf9\x1b\xb2\xe1\xa9\xc4\xcd\x96\xbf\x25\x04\x26\xb3\xa6\xaf\xd9\xb8\x7a\xc5\x1e\x93\x25\x4d\x2d\xae\x3b\x16\xec\x68\x6b\xa8\x0f\xb0\xbd\x7a\x84\xd2\x18\x66\x0e\x90\x07\x59\x30\x75\xbc\x4f\x4c\x66\x56\x7f\x0c\x7a\x5f\xd2\x01\x0c\x99\x9a\x8a\x0e\xfa\x81\xf8\x9f\xf5\xbf\xef\xe0\xfb\x91\x0f\x04\x42\xe6\xd4\xa7\xc5\x5b\xbb\x61\x8c\x69\xa7\x9a\x2d\xdd\x82\xa0\x93\x89\x27\xf6\xfe\x3a\x80\xf0\x4b\xea\xeb\x7c\x76\x36\xe3\x43\x5d\x12\xdc\xf1\xc6\xbb\x6e\xd0\xa4\xed\xb6\x9c\x96\x57\xfa\x93",
+ "6e692c8c694ee0a3565f37a299e0006b85ab4a821b20e76798220229f656efc6a20211a4e7e4ed77facde0d70e4d5d95bc8ed1d7a56d8df1446d562f044b344c"
+ }, {
+ 122,
+ "\xd1\xeb\x96\x1c\xa6\xa8\xf6\x7c\x49\xb6\x1e\x4d\x3c\xea\xa2\xa1\xde\x6f\x0e\xa9\x27\xb1\x32\xbf\x98\x7a\xbd\xaa\x72\x5b\x0e\x1e\x27\x4e\x46\x83\x0e\x99\xa2\xf7\x5a\xf6\x08\x96\x4d\xf0\xdf\xf9\xa9\x90\x24\xfc\x68\x39\xba\xc5\xac\xd1\x02\x02\xf9\x21\xac\x71\xa2\x7f\xcd\xa6\x81\xaa\x31\x09\xeb\xf5\xf2\x1e\xe3\xa8\x49\x09\x8e\xa3\xa5\x51\xe8\x44\xfa\xe4\xb4\x8b\x5c\x5b\xb9\x7c\xcc\x80\x2b\xc5\x52\x0d\x68\xa1\x4c\xb7\xe5\xfc\x05\x6b\x67\xd8\x89\xd8\x76\xef\xb8\x2d\x0e\x9a\x9a\x24\x99\xf1",
+ "39b2c76ec207120de4b320c7fe069e602c9c38f257596da7369395e87eb64b3acff988c1839ac269d5012c093f9edd4b7cabf13bdea7d42e969ab108269c6ab0"
+ }, {
+ 123,
+ "\xad\xf2\x26\x32\x00\xf3\x76\x88\x6b\xa7\xb6\xf5\xe4\x41\x1d\x5f\x07\xf7\xd9\xd1\x01\x59\x0c\x73\xac\xe1\x14\xba\xfb\xcb\x0f\xdc\x99\x26\x9e\x87\xcd\x2c\xea\xd2\xa1\xcf\xe5\x74\x43\x94\xd3\x33\xab\xa4\x08\xa0\x7e\x21\xf3\x02\x33\xb6\x5b\x90\x74\x72\xe9\xe3\xc7\xd6\xe7\xaa\x6d\x2c\x47\xa0\x8a\x1b\xe7\xbb\x87\x79\x13\xa6\xb5\x60\x4c\x72\x33\x84\x47\x89\x11\xc3\x39\xe3\xb5\xfe\x52\x7c\x7e\x28\x87\x05\xa8\x9c\x95\xd9\x70\xb4\x43\x34\x78\x97\xe7\x9f\x6c\x52\x2b\xaf\xe6\x2b\x11\xef\x8f\x31\x35",
+ "3c23d2d8cf4db6ac6a42e27208180f37668bef5ee0a3f879483c8e604e7f42583f202037b8d242c04a87345b8be6dc8b121d6484b9edad0d73c894c1288f5cae"
+ }, {
+ 124,
+ "\x18\xe7\x5b\x47\xd8\x98\xac\x62\x9c\x48\xe8\x0d\xbf\xb7\x5d\xae\x1e\x17\x00\xb7\x71\x16\x5e\xcc\xdb\x18\xd6\x28\xbf\xc4\x06\x3d\xd6\xc3\x83\x9a\x7e\xc4\xcd\x12\x55\xc4\x82\x1b\x07\x8c\xd1\x74\x64\x7b\x32\x0b\xb6\x85\x54\x1d\x51\x7c\x57\x9f\x6b\x8e\x3c\xdd\x2e\x10\x9a\x61\x0c\x7a\x92\x16\x53\xb2\x04\xad\x01\x8d\x03\x40\xd9\x93\x87\x35\xb6\x02\x62\x66\x20\x16\x76\x7e\x1d\x88\x24\xa6\x49\x54\x08\x62\x29\xc0\xe3\xb5\xbd\x9a\xd8\x8c\x54\xc1\xdc\x5a\xa4\xe7\x68\xff\x1a\x94\x70\xee\x6f\x6e\x99\x8f",
+ "01c756b7c20b5f95fd2b079ab6a50f28b946fb16266b07c6060945dc4fe9e0d279c5b1505b9ec7d8f8f3c9ebf0c5ee9365aec08cf278d65b64daeccc19d3cbf4"
+ }, {
+ 125,
+ "\xc2\x96\x33\x42\xcf\xaa\x88\xcc\xd1\x02\xa2\x58\xe6\xd6\x29\xf6\xb0\xd3\x67\xdd\x55\x11\x65\x02\xca\x44\x51\xea\x52\x36\x23\xbc\x41\x75\x81\x9a\x06\x48\xdf\x31\x68\xe8\xea\x8f\x10\xed\x27\x35\x48\x07\xd7\x6e\x02\xee\x1f\xdf\x1c\x9c\x65\x5e\xe2\xb9\xfd\x08\xd5\x57\x05\x8d\xab\xdf\x8d\xcf\x96\x4b\xfc\xac\xc9\x96\xae\x17\x39\x71\xe2\x6e\xa0\x38\xd4\x07\xc8\x24\x26\x0d\x06\xc2\x84\x8a\x04\xa4\x88\xc4\xc4\x56\xdb\xcd\xe2\x93\x9e\x56\x1a\xb9\x08\xc4\x09\x7b\x50\x86\x38\xd6\xcd\xa5\x56\x46\x5c\x9c\xc5",
+ "a4d2f59393a5fea612c3c745f4bb9f41aaf3a3ce1679aa8afc1a62baa4ed452819418c8ae1a1e658757976692390fc43d4decf7d855cd8b498b6dc60cae05a90"
+ }, {
+ 126,
+ "\x85\x36\x0c\x3d\x42\x57\xd9\x87\x8e\x2f\x5c\x16\xd3\xcd\x7d\x07\x47\xdf\x3d\x23\x1e\x1a\x8f\x63\xfd\xdc\x69\xb3\xb1\x10\x1a\xf7\x21\x53\xde\x4c\x81\x54\xb0\x90\xc9\x81\x5f\x24\x66\xe0\xe4\xf0\x2f\x3a\xf3\xa8\x9a\x7f\xd0\x4e\x30\x66\x64\xf9\x3e\x54\x90\xd4\xce\x7f\xc1\x69\xd5\x53\xc5\x20\xae\x15\xdd\x02\xc7\xc6\x13\xc3\x9b\x4a\xcd\x00\xe0\xc9\xa3\xc5\x01\x56\x6e\x52\xce\xce\xa1\x1f\x73\x03\xdd\x1d\xa6\x1a\xbf\x3f\x25\x32\xfd\x39\x60\x47\xb1\x88\x72\x55\xf4\xb2\x56\xc0\xaf\xcf\x58\xf3\xae\x48\xc9\x47",
+ "e8352ddcac59e377ea0f9c32bbb43dfd1b6c829fad1954240c41b7c45b0b09db11064b64e2442a96f6530aac2c4abf3beb1eae77f2bce4efe88fee1a70cf5423"
+ }, {
+ 127,
+ "\xc1\x3e\x6c\xa3\xab\xb8\x93\xaa\x5f\x82\xc4\xa8\xef\x75\x44\x60\x62\x8a\xf6\xb7\x5a\xf0\x21\x68\xf4\x5b\x72\xf8\xf0\x9e\x45\xed\x12\x7c\x20\x3b\xc7\xbb\x80\xff\x0c\x7b\xd9\x6f\x8c\xc6\xd8\x11\x08\x68\xeb\x2c\xfc\x01\x03\x7d\x80\x58\x99\x2a\x6c\xf2\xef\xfc\xbf\xe4\x98\xc8\x42\xe5\x3a\x2e\x68\xa7\x93\x86\x79\x68\xba\x18\xef\xc4\xa7\x8b\x21\xcd\xf6\xa1\x1e\x5d\xe8\x21\xdc\xab\xab\x14\x92\x1d\xdb\x33\x62\x5d\x48\xa1\x3b\xaf\xfa\xd6\xfe\x82\x72\xdb\xdf\x44\x33\xbd\x0f\x7b\x81\x3c\x98\x12\x69\xc3\x88\xf0\x01",
+ "6e56f77f6883d0bd4face8b8d557f144661989f66d51b1fe4b8fc7124d66d9d20218616fea1bcf86c08d63bf8f2f21845a3e519083b937e70aa7c358310b5a7c"
+ }, {
+ 128,
+ "\xfd\x22\x03\xe4\x67\x57\x4e\x83\x4a\xb0\x7c\x90\x97\xae\x16\x45\x32\xf2\x4b\xe1\xeb\x5d\x88\xf1\xaf\x77\x48\xce\xff\x0d\x2c\x67\xa2\x1f\x4e\x40\x97\xf9\xd3\xbb\x4e\x9f\xbf\x97\x18\x6e\x0d\xb6\xdb\x01\x00\x23\x0a\x52\xb4\x53\xd4\x21\xf8\xab\x9c\x9a\x60\x43\xaa\x32\x95\xea\x20\xd2\xf0\x6a\x2f\x37\x47\x0d\x8a\x99\x07\x5f\x1b\x8a\x83\x36\xf6\x22\x8c\xf0\x8b\x59\x42\xfc\x1f\xb4\x29\x9c\x7d\x24\x80\xe8\xe8\x2b\xce\x17\x55\x40\xbd\xfa\xd7\x75\x2b\xc9\x5b\x57\x7f\x22\x95\x15\x39\x4f\x3a\xe5\xce\xc8\x70\xa4\xb2\xf8",
+ "a21b1077d52b27ac545af63b32746c6e3c51cb0cb9f281eb9f3580a6d4996d5c9917d2a6e484627a9d5a06fa1b25327a9d710e027387fc3e07d7c4d14c6086cc"
+ }, {
+ 0,
+ NULL,
+ NULL
+ }
+};
+
+static void
+run_tests(unsigned int digest_type, struct test_vector *test_vectors)
+{
+ struct sudo_digest *ctx;
+ unsigned char md[64]; /* SHA512_DIGEST_LENGTH */
+ char mdhex[128 + 1]; /* SHA512_DIGEST_LENGTH * 2 + 1 */
+ size_t i, j, digest_len;
+
+ digest_len = sudo_digest_getlen(digest_type);
+ if (digest_len == 0)
+ sudo_fatalx("unable to get digest length for type %d", digest_type);
+ if (digest_len > ssizeof(md))
+ sudo_fatalx("digest length too big for type %d", digest_type);
+
+ ctx = sudo_digest_alloc(digest_type);
+ if (ctx == NULL)
+ sudo_fatal(NULL);
+
+ for (i = 0; test_vectors[i].str != NULL; i++) {
+ ntests++;
+ sudo_digest_update(ctx, test_vectors[i].str, test_vectors[i].len);
+ sudo_digest_final(ctx, md);
+
+ /* Convert md to a hex string. */
+ for (j = 0; j < digest_len; j++) {
+ mdhex[j * 2] = hex[md[j] >> 4];
+ mdhex[(j * 2) + 1] = hex[md[j] & 0x0f];
+ }
+ mdhex[j * 2] = '\0';
+
+ if (strcmp(test_vectors[i].md, mdhex) != 0) {
+ sudo_warnx("test %u:%zu: expected %s, got %s", digest_type, i,
+ mdhex, test_vectors[i].md);
+ errors++;
+ }
+ sudo_digest_reset(ctx);
+ }
+ sudo_digest_free(ctx);
+
+ return;
+}
+
+/*
+ * Verify SHA2 functions using NIST byte-oriented short message test vectors.
+ */
+int
+main(int argc, char *argv[])
+{
+ int ch;
+
+ initprogname(argc > 0 ? argv[0] : "digest_test");
+
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch (ch) {
+ case 'v':
+ /* ignore */
+ break;
+ default:
+ fprintf(stderr, "usage: %s [-v]\n", getprogname());
+ return EXIT_FAILURE;
+ }
+ }
+
+ run_tests(SUDO_DIGEST_SHA224, sha224_vectors);
+ run_tests(SUDO_DIGEST_SHA256, sha256_vectors);
+ run_tests(SUDO_DIGEST_SHA512, sha512_vectors);
+
+ if (ntests != 0) {
+ printf("%s: %d tests run, %d errors, %d%% success rate\n",
+ getprogname(), ntests, errors, (ntests - errors) * 100 / ntests);
+ }
+
+ return errors;
+}
diff --git a/lib/util/regress/fnmatch/fnm_test.c b/lib/util/regress/fnmatch/fnm_test.c
new file mode 100644
index 0000000..e4689c8
--- /dev/null
+++ b/lib/util/regress/fnmatch/fnm_test.c
@@ -0,0 +1,92 @@
+/* $OpenBSD: fnm_test.c,v 1.1 2008/10/01 23:04:58 millert Exp $ */
+
+/*
+ * Public domain, 2008, Todd C. Miller <Todd.Miller@sudo.ws>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef HAVE_FNMATCH
+# include <fnmatch.h>
+#else
+# include <compat/fnmatch.h>
+#endif
+
+#include <sudo_compat.h>
+#include <sudo_util.h>
+
+sudo_dso_public int main(int argc, char *argv[]);
+
+int
+main(int argc, char *argv[])
+{
+ FILE *fp = stdin;
+ char pattern[1024], string[1024], flagstr[1024];
+ int ch, errors = 0, ntests = 0, flags, got, want;
+
+ initprogname(argc > 0 ? argv[0] : "fnm_test");
+
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch (ch) {
+ case 'v':
+ /* ignore */
+ break;
+ default:
+ fprintf(stderr, "usage: %s [-v]\n", getprogname());
+ return EXIT_FAILURE;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 0) {
+ if ((fp = fopen(argv[0], "r")) == NULL) {
+ perror(argv[0]);
+ return EXIT_FAILURE;
+ }
+ }
+
+ /*
+ * Read in test file, which is formatted thusly:
+ *
+ * pattern string flags expected_result
+ *
+ */
+ for (;;) {
+ got = fscanf(fp, "%s %s %s %d\n", pattern, string, flagstr,
+ &want);
+ if (got == EOF)
+ break;
+ if (got == 4) {
+ flags = 0;
+ if (strcmp(flagstr, "FNM_NOESCAPE") == 0)
+ flags |= FNM_NOESCAPE;
+ else if (strcmp(flagstr, "FNM_PATHNAME") == 0)
+ flags |= FNM_PATHNAME;
+ else if (strcmp(flagstr, "FNM_PERIOD") == 0)
+ flags |= FNM_PERIOD;
+ else if (strcmp(flagstr, "FNM_LEADING_DIR") == 0)
+ flags |= FNM_LEADING_DIR;
+ else if (strcmp(flagstr, "FNM_CASEFOLD") == 0)
+ flags |= FNM_CASEFOLD;
+ got = fnmatch(pattern, string, flags);
+ if (got != want) {
+ fprintf(stderr,
+ "fnmatch: %s %s %d: want %d, got %d\n",
+ pattern, string, flags, want, got);
+ errors++;
+ }
+ ntests++;
+ }
+ }
+ if (ntests != 0) {
+ printf("fnmatch: %d test%s run, %d errors, %d%% success rate\n",
+ ntests, ntests == 1 ? "" : "s", errors,
+ (ntests - errors) * 100 / ntests);
+ }
+ return errors;
+}
diff --git a/lib/util/regress/fnmatch/fnm_test.in b/lib/util/regress/fnmatch/fnm_test.in
new file mode 100644
index 0000000..3f53f93
--- /dev/null
+++ b/lib/util/regress/fnmatch/fnm_test.in
@@ -0,0 +1,6 @@
+/bin/[[:alpha:][:alnum:]]* /bin/ls FNM_PATHNAME 0
+/bin/[[:alpha:][:alnum:]]* /bin/LS FNM_CASEFOLD 0
+/bin/[[:opper:][:alnum:]]* /bin/ls NONE 1
+[[:alpha:][:alnum:]]*.c foo1.c FNM_PERIOD 0
+[[:upper:]]* FOO NONE 0
+[![:space:]]* bar NONE 0
diff --git a/lib/util/regress/fuzz/fuzz_sudo_conf.c b/lib/util/regress/fuzz/fuzz_sudo_conf.c
new file mode 100644
index 0000000..e2e2723
--- /dev/null
+++ b/lib/util/regress/fuzz/fuzz_sudo_conf.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2021 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#if defined(HAVE_STDINT_H)
+# include <stdint.h>
+#elif defined(HAVE_INTTYPES_H)
+# include <inttypes.h>
+#endif
+
+#define SUDO_ERROR_WRAP 0
+
+#include <sudo_compat.h>
+#include <sudo_conf.h>
+#include <sudo_debug.h>
+#include <sudo_fatal.h>
+#include <sudo_plugin.h>
+#include <sudo_util.h>
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+static int
+fuzz_conversation(int num_msgs, const struct sudo_conv_message msgs[],
+ struct sudo_conv_reply replies[], struct sudo_conv_callback *callback)
+{
+ int n;
+
+ for (n = 0; n < num_msgs; n++) {
+ const struct sudo_conv_message *msg = &msgs[n];
+
+ switch (msg->msg_type & 0xff) {
+ case SUDO_CONV_PROMPT_ECHO_ON:
+ case SUDO_CONV_PROMPT_MASK:
+ case SUDO_CONV_PROMPT_ECHO_OFF:
+ /* input not supported */
+ return -1;
+ case SUDO_CONV_ERROR_MSG:
+ case SUDO_CONV_INFO_MSG:
+ /* no output for fuzzers */
+ break;
+ default:
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int
+LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ struct plugin_info_list *plugins = sudo_conf_plugins();
+ struct sudo_conf_debug_list *debug_list = sudo_conf_debugging();
+ struct sudo_conf_debug_file_list *debug_files;
+ char tempfile[] = "/tmp/sudo_conf.XXXXXX";
+ struct sudo_conf_debug *debug_spec;
+ struct sudo_debug_file *debug_file;
+ struct plugin_info *info;
+ ssize_t nwritten;
+ int fd;
+
+ initprogname("fuzz_sudo_conf");
+ if (getenv("SUDO_FUZZ_VERBOSE") == NULL)
+ sudo_warn_set_conversation(fuzz_conversation);
+
+ /* sudo_conf_read() uses a conf file path, not an open file. */
+ fd = mkstemp(tempfile);
+ if (fd == -1)
+ return 0;
+ nwritten = write(fd, data, size);
+ if (nwritten == -1) {
+ close(fd);
+ return 0;
+ }
+ close(fd);
+
+ /* sudo_conf_read() will re-init and free old data each time it runs. */
+ sudo_conf_clear_paths();
+ sudo_conf_read(tempfile, SUDO_CONF_ALL);
+
+ /* Path settings. */
+ if (sudo_conf_askpass_path() != NULL)
+ sudo_warnx("Path askpass %s", sudo_conf_askpass_path());
+ if (sudo_conf_sesh_path() != NULL)
+ sudo_warnx("Path sesh %s", sudo_conf_sesh_path());
+ if (sudo_conf_intercept_path() != NULL)
+ sudo_warnx("Path intercept %s", sudo_conf_intercept_path());
+ if (sudo_conf_noexec_path() != NULL)
+ sudo_warnx("Path noexec %s", sudo_conf_noexec_path());
+ if (sudo_conf_plugin_dir_path() != NULL)
+ sudo_warnx("Path plugin_dir %s", sudo_conf_plugin_dir_path());
+
+ /* Other settings. */
+ sudo_warnx("Set disable_coredump %s",
+ sudo_conf_disable_coredump() ? "true" : "false");
+ sudo_warnx("Set group_source %s",
+ sudo_conf_group_source() == GROUP_SOURCE_ADAPTIVE ? "adaptive" :
+ sudo_conf_group_source() == GROUP_SOURCE_STATIC ? "static" : "dynamic");
+ sudo_warnx("Set max_groups %d", sudo_conf_max_groups());
+ sudo_warnx("Set probe_interfaces %s",
+ sudo_conf_probe_interfaces() ? "true" : "false");
+
+ /* Plugins. */
+ plugins = sudo_conf_plugins();
+ TAILQ_FOREACH(info, plugins, entries) {
+ /* We don't bother with the plugin options. */
+ sudo_warnx("Plugin %s %s", info->symbol_name, info->path);
+ }
+
+ /* Debug settings. */
+ debug_list = sudo_conf_debugging();
+ TAILQ_FOREACH(debug_spec, debug_list, entries) {
+ TAILQ_FOREACH(debug_file, &debug_spec->debug_files, entries) {
+ sudo_warnx("Debug %s %s %s", debug_spec->progname,
+ debug_file->debug_file, debug_file->debug_flags);
+ }
+ }
+
+ debug_files = sudo_conf_debug_files(getprogname());
+ if (debug_files != NULL) {
+ TAILQ_FOREACH(debug_file, debug_files, entries) {
+ sudo_warnx("Debug %s %s %s", getprogname(),
+ debug_file->debug_file, debug_file->debug_flags);
+ }
+ }
+
+ unlink(tempfile);
+
+ fflush(stdout);
+
+ return 0;
+}
diff --git a/lib/util/regress/fuzz/fuzz_sudo_conf.dict b/lib/util/regress/fuzz/fuzz_sudo_conf.dict
new file mode 100644
index 0000000..4b26917
--- /dev/null
+++ b/lib/util/regress/fuzz/fuzz_sudo_conf.dict
@@ -0,0 +1,18 @@
+# sudo.conf keywords
+"Debug"
+"Path"
+"Plugin"
+"Set"
+
+# Paths
+"askpass"
+"sesh"
+"noexec"
+"plugin_dir"
+"devsearch"
+
+# Variables
+"disable_coredump"
+"group_source"
+"max_groups"
+"probe_interfaces"
diff --git a/lib/util/regress/getdelim/getdelim_test.c b/lib/util/regress/getdelim/getdelim_test.c
new file mode 100644
index 0000000..31548cc
--- /dev/null
+++ b/lib/util/regress/getdelim/getdelim_test.c
@@ -0,0 +1,186 @@
+/*
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2019-2020 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_STDBOOL_H
+# include <stdbool.h>
+#else
+# include <compat/stdbool.h>
+#endif
+#include <limits.h>
+#include <unistd.h>
+
+#include <sudo_compat.h>
+#include <sudo_fatal.h>
+#include <sudo_util.h>
+
+sudo_dso_public int main(int argc, char *argv[]);
+
+ssize_t sudo_getdelim(char ** restrict bufp, size_t * restrict bufsizep,
+ int delim, FILE * restrict fp);
+
+/*
+ * Test that sudo_getdelim() works as expected.
+ */
+
+struct getdelim_test {
+ const char *input;
+ const char *output[4];
+ int delim;
+};
+
+static char longstr[LINE_MAX * 4];
+static struct getdelim_test test_data[] = {
+ { "a\nb\nc\n", { "a\n", "b\n", "c\n", NULL }, '\n' },
+ { "a\nb\nc", { "a\n", "b\n", "c", NULL }, '\n' },
+ { "a\tb\tc\t", { "a\t", "b\t", "c\t", NULL }, '\t' },
+ { "a\tb\tc", { "a\t", "b\t", "c", NULL }, '\t' },
+ { longstr, { longstr, NULL }, '\n' },
+ { NULL, { NULL }, '\0' }
+};
+
+static int errors = 0, ntests = 0;
+
+static void
+runtests(char **buf, size_t *buflen)
+{
+ int i, j, sv[2];
+ pid_t pid;
+ FILE *fp;
+
+ /* Exercise realloc case by injecting an entry > LINE_MAX. */
+ memset(longstr, 'A', sizeof(longstr) - 2);
+ longstr[sizeof(longstr) - 2] = '\n';
+ longstr[sizeof(longstr) - 1] = '\0';
+
+ for (i = 0; test_data[i].input != NULL; i++) {
+ if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1)
+ sudo_fatal_nodebug("socketpair");
+
+ switch ((pid = fork())) {
+ case -1:
+ sudo_fatal_nodebug("fork");
+ case 0:
+ /* child */
+ close(sv[0]);
+ if (send(sv[1], test_data[i].input, strlen(test_data[i].input), 0) == -1) {
+ sudo_warn_nodebug("send");
+ _exit(127);
+ }
+ _exit(EXIT_SUCCESS);
+ break;
+ default:
+ /* parent */
+ break;
+ }
+
+ close(sv[1]);
+ if ((fp = fdopen(sv[0], "r")) == NULL)
+ sudo_fatal_nodebug("fdopen");
+
+ for (j = 0; test_data[i].output[j] != NULL; j++) {
+ ntests++;
+ alarm(10);
+ if (sudo_getdelim(buf, buflen, test_data[i].delim, fp) == -1)
+ sudo_fatal_nodebug("sudo_getdelim");
+ alarm(0);
+ if (strcmp(*buf, test_data[i].output[j]) != 0) {
+ sudo_warnx_nodebug("failed test #%d: expected %s, got %s",
+ ntests, test_data[i].output[j], *buf);
+ errors++;
+ }
+ }
+
+ /* test EOF */
+ ntests++;
+ alarm(30);
+ if (sudo_getdelim(buf, buflen, test_data[i].delim, fp) != -1) {
+ sudo_warnx_nodebug("failed test #%d: expected EOF, got %s",
+ ntests, *buf);
+ errors++;
+ } else {
+ if (!feof(fp)) {
+ sudo_warn_nodebug("failed test #%d: expected EOF, got error",
+ ntests);
+ errors++;
+ }
+ }
+
+ /* test error by closing the underlying fd. */
+ clearerr(fp);
+ close(fileno(fp));
+ ntests++;
+ alarm(30);
+ if (sudo_getdelim(buf, buflen, test_data[i].delim, fp) != -1) {
+ sudo_warnx_nodebug("failed test #%d: expected error, got %s",
+ ntests, *buf);
+ errors++;
+ } else {
+ /* Use feof(3), not ferror(3) so we can detect out of memory. */
+ if (feof(fp)) {
+ sudo_warn_nodebug("failed test #%d: expected error, got EOF",
+ ntests);
+ errors++;
+ }
+ }
+
+ fclose(fp);
+ waitpid(pid, NULL, 0);
+ alarm(0);
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ size_t buflen = 0;
+ char *buf = NULL;
+ int ch;
+
+ initprogname(argc > 0 ? argv[0] : "getdelim_test");
+
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch (ch) {
+ case 'v':
+ /* ignore */
+ break;
+ default:
+ fprintf(stderr, "usage: %s [-v]\n", getprogname());
+ return EXIT_FAILURE;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ runtests(&buf, &buflen);
+ free(buf);
+
+ /* XXX - redo tests with preallocated buffer filled with junk */
+ if (ntests != 0) {
+ printf("%s: %d tests run, %d errors, %d%% success rate\n",
+ getprogname(), ntests, errors, (ntests - errors) * 100 / ntests);
+ }
+ return errors;
+}
diff --git a/lib/util/regress/getgrouplist/getgids.c b/lib/util/regress/getgrouplist/getgids.c
new file mode 100644
index 0000000..83518f3
--- /dev/null
+++ b/lib/util/regress/getgrouplist/getgids.c
@@ -0,0 +1,91 @@
+/*
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2021 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_STDBOOL_H
+# include <stdbool.h>
+#else
+# include <compat/stdbool.h>
+#endif
+#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
+
+#define SUDO_ERROR_WRAP 0
+
+#include <sudo_compat.h>
+#include <sudo_fatal.h>
+#include <sudo_util.h>
+
+sudo_dso_public int main(int argc, char *argv[]);
+
+/*
+ * Implement "id -G" using sudo_getgrouplist2().
+ */
+
+int
+main(int argc, char *argv[])
+{
+ char *username = NULL;
+ GETGROUPS_T *groups = NULL;
+ struct passwd *pw;
+ int ch, i, ngroups;
+ gid_t basegid;
+
+ initprogname(argc > 0 ? argv[0] : "getgids");
+
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch (ch) {
+ case 'v':
+ /* ignore */
+ break;
+ default:
+ fprintf(stderr, "usage: %s [-v] [user]\n", getprogname());
+ return EXIT_FAILURE;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 0)
+ username = argv[0];
+
+ if (username != NULL) {
+ if ((pw = getpwnam(username)) == NULL)
+ sudo_fatalx("unknown user name %s", username);
+ } else {
+ if ((pw = getpwuid(getuid())) == NULL)
+ sudo_fatalx("unknown user ID %u", (unsigned int)getuid());
+ }
+ basegid = pw->pw_gid;
+ if ((username = strdup(pw->pw_name)) == NULL)
+ sudo_fatal(NULL);
+
+ if (sudo_getgrouplist2(username, basegid, &groups, &ngroups) == -1)
+ sudo_fatal("sudo_getgroulist2");
+
+ for (i = 0; i < ngroups; i++) {
+ printf("%s%u", i ? " " : "", (unsigned int)groups[i]);
+ }
+ putchar('\n');
+ return EXIT_SUCCESS;
+}
diff --git a/lib/util/regress/getgrouplist/getgrouplist_test.c b/lib/util/regress/getgrouplist/getgrouplist_test.c
new file mode 100644
index 0000000..e400e60
--- /dev/null
+++ b/lib/util/regress/getgrouplist/getgrouplist_test.c
@@ -0,0 +1,117 @@
+/*
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2018 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_STDBOOL_H
+# include <stdbool.h>
+#else
+# include <compat/stdbool.h>
+#endif
+#include <pwd.h>
+#include <grp.h>
+#include <unistd.h>
+
+#include <sudo_compat.h>
+#include <sudo_fatal.h>
+#include <sudo_util.h>
+
+sudo_dso_public int main(int argc, char *argv[]);
+
+/*
+ * Test that sudo_getgrouplist2() works as expected.
+ */
+
+int
+main(int argc, char *argv[])
+{
+ int errors = 0;
+#ifndef HAVE_GETGROUPLIST_2
+ GETGROUPS_T *groups = NULL;
+ struct passwd *pw;
+ struct group *grp;
+ char *username;
+ int ch, i, j, ntests = 0;
+ int ngroups;
+ gid_t basegid;
+
+ initprogname(argc > 0 ? argv[0] : "getgrouplist_test");
+
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch (ch) {
+ case 'v':
+ /* ignore */
+ break;
+ default:
+ fprintf(stderr, "usage: %s [-v]\n", getprogname());
+ return EXIT_FAILURE;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if ((pw = getpwuid(0)) == NULL)
+ sudo_fatal_nodebug("getpwuid(0)");
+ basegid = pw->pw_gid;
+ if ((username = strdup(pw->pw_name)) == NULL)
+ sudo_fatal_nodebug(NULL);
+
+ if (sudo_getgrouplist2(username, basegid, &groups, &ngroups) == -1)
+ sudo_fatal_nodebug("sudo_getgroulist2");
+
+ for (i = 0; i < ngroups; i++) {
+ ntests++;
+
+ /* Verify group ID exists. */
+ if ((grp = getgrgid(groups[i])) == NULL) {
+ sudo_warnx_nodebug("unable to look up group ID %u",
+ (unsigned int)groups[i]);
+ errors++;
+ continue;
+ }
+
+ /* Check user's primary gid from the passwd file. */
+ if (grp->gr_gid == basegid)
+ continue;
+
+ /* Verify group membership. */
+ for (j = 0; grp->gr_mem[j] != NULL; j++) {
+ if (strcmp(username, grp->gr_mem[j]) == 0) {
+ /* match */
+ break;
+ }
+ }
+ if (grp->gr_mem[j] == NULL) {
+ sudo_warnx_nodebug("unable to find %s in group %s",
+ username, grp->gr_name);
+ errors++;
+ continue;
+ }
+ }
+ if (ntests != 0) {
+ printf("%s: %d tests run, %d errors, %d%% success rate\n",
+ getprogname(), ntests, errors, (ntests - errors) * 100 / ntests);
+ }
+ free(username);
+ free(groups);
+#endif /* HAVE_GETGROUPLIST_2 */
+ return errors;
+}
diff --git a/lib/util/regress/glob/files b/lib/util/regress/glob/files
new file mode 100644
index 0000000..c5e92aa
--- /dev/null
+++ b/lib/util/regress/glob/files
@@ -0,0 +1,47 @@
+fake/bin/[
+fake/bin/cat
+fake/bin/chgrp
+fake/bin/chio
+fake/bin/chmod
+fake/bin/cksum
+fake/bin/cp
+fake/bin/cpio
+fake/bin/csh
+fake/bin/date
+fake/bin/dd
+fake/bin/df
+fake/bin/domainname
+fake/bin/echo
+fake/bin/ed
+fake/bin/eject
+fake/bin/expr
+fake/bin/hostname
+fake/bin/kill
+fake/bin/ksh
+fake/bin/ln
+fake/bin/ls
+fake/bin/md5
+fake/bin/mkdir
+fake/bin/mt
+fake/bin/mv
+fake/bin/pax
+fake/bin/ps
+fake/bin/pwd
+fake/bin/rcp
+fake/bin/rksh
+fake/bin/rm
+fake/bin/rmail
+fake/bin/rmd160
+fake/bin/rmdir
+fake/bin/sh
+fake/bin/sha1
+fake/bin/sha256
+fake/bin/sha384
+fake/bin/sha512
+fake/bin/sleep
+fake/bin/stty
+fake/bin/sum
+fake/bin/sync
+fake/bin/systrace
+fake/bin/tar
+fake/bin/test
diff --git a/lib/util/regress/glob/globtest.c b/lib/util/regress/glob/globtest.c
new file mode 100644
index 0000000..f3623a7
--- /dev/null
+++ b/lib/util/regress/glob/globtest.c
@@ -0,0 +1,224 @@
+/* $OpenBSD: globtest.c,v 1.1 2008/10/01 23:04:36 millert Exp $ */
+
+/*
+ * Public domain, 2008, Todd C. Miller <Todd.Miller@sudo.ws>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_GLOB
+# include <glob.h>
+#else
+# include <compat/glob.h>
+#endif
+#include <errno.h>
+#include <unistd.h>
+
+#include <sudo_compat.h>
+#include <sudo_util.h>
+
+#define MAX_RESULTS 256
+
+struct gl_entry {
+ int flags;
+ int nresults;
+ char pattern[1024];
+ char *results[MAX_RESULTS];
+};
+
+int test_glob(struct gl_entry *);
+sudo_dso_public int main(int argc, char *argv[]);
+
+int
+main(int argc, char **argv)
+{
+ FILE *fp = stdin;
+ char buf[2048], *cp, *ep;
+ int ch, errors = 0, ntests = 0, lineno;
+ struct gl_entry entry;
+ size_t len;
+
+ initprogname(argc > 0 ? argv[0] : "globtest");
+
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch (ch) {
+ case 'v':
+ /* ignore */
+ break;
+ default:
+ fprintf(stderr, "usage: %s [-v]\n", getprogname());
+ return EXIT_FAILURE;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 0) {
+ if ((fp = fopen(argv[0], "r")) == NULL) {
+ perror(argv[0]);
+ return EXIT_FAILURE;
+ }
+ }
+
+ /*
+ * Read in test file, which is formatted thusly:
+ *
+ * [pattern] <flags>
+ * result1
+ * result2
+ * result3
+ * ...
+ *
+ */
+ lineno = 0;
+ memset(&entry, 0, sizeof(entry));
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ lineno++;
+ len = strlen(buf);
+ if (len > 0) {
+ if (buf[len - 1] != '\n') {
+ fputs("globtest: missing newline at EOF\n", stderr);
+ return EXIT_FAILURE;
+ }
+ buf[--len] = '\0';
+ }
+ if (len == 0)
+ continue; /* blank line */
+
+ if (buf[0] == '[') {
+ /* check previous pattern */
+ if (entry.pattern[0]) {
+ errors += test_glob(&entry);
+ ntests++;
+ }
+
+ /* start new entry */
+ if ((cp = strrchr(buf + 1, ']')) == NULL) {
+ fprintf(stderr,
+ "globtest: invalid entry on line %d\n",
+ lineno);
+ return EXIT_FAILURE;
+ }
+ len = cp - buf - 1;
+ if (len >= sizeof(entry.pattern)) {
+ fprintf(stderr,
+ "globtest: pattern too big on line %d\n",
+ lineno);
+ return EXIT_FAILURE;
+ }
+ memcpy(entry.pattern, buf + 1, len);
+ entry.pattern[len] = '\0';
+
+ cp += 2;
+ if (*cp++ != '<') {
+ fprintf(stderr,
+ "globtest: invalid entry on line %d\n",
+ lineno);
+ return EXIT_FAILURE;
+ }
+ ep = strchr(cp, '>');
+ if (ep == NULL) {
+ fprintf(stderr,
+ "globtest: invalid entry on line %d\n",
+ lineno);
+ return EXIT_FAILURE;
+ }
+ *ep = '\0';
+ entry.flags = 0;
+ for ((cp = strtok_r(cp, "|", &ep)); cp != NULL; (cp = strtok_r(NULL, "|", &ep))) {
+ if (strcmp(cp, "GLOB_APPEND") == 0)
+ entry.flags |= GLOB_APPEND;
+ else if (strcmp(cp, "GLOB_DOOFFS") == 0)
+ entry.flags |= GLOB_DOOFFS;
+ else if (strcmp(cp, "GLOB_ERR") == 0)
+ entry.flags |= GLOB_ERR;
+ else if (strcmp(cp, "GLOB_MARK") == 0)
+ entry.flags |= GLOB_MARK;
+ else if (strcmp(cp, "GLOB_NOCHECK") == 0)
+ entry.flags |= GLOB_NOCHECK;
+ else if (strcmp(cp, "GLOB_NOSORT") == 0)
+ entry.flags |= GLOB_NOSORT;
+ else if (strcmp(cp, "GLOB_NOESCAPE") == 0)
+ entry.flags |= GLOB_NOESCAPE;
+ else if (strcmp(cp, "GLOB_BRACE") == 0)
+ entry.flags |= GLOB_BRACE;
+ else if (strcmp(cp, "GLOB_TILDE") == 0)
+ entry.flags |= GLOB_TILDE;
+ else if (strcmp(cp, "NONE") != 0) {
+ fprintf(stderr,
+ "globtest: invalid flags on line %d\n",
+ lineno);
+ return EXIT_FAILURE;
+ }
+ }
+ entry.nresults = 0;
+ continue;
+ }
+ if (!entry.pattern[0]) {
+ fprintf(stderr, "globtest: missing entry on line %d\n",
+ lineno);
+ return EXIT_FAILURE;
+ }
+
+ if (entry.nresults + 1 > MAX_RESULTS) {
+ fprintf(stderr,
+ "globtest: too many results for %s, max %d\n",
+ entry.pattern, MAX_RESULTS);
+ return EXIT_FAILURE;
+ }
+ entry.results[entry.nresults++] = strdup(buf);
+ }
+ if (entry.pattern[0]) {
+ errors += test_glob(&entry); /* test last pattern */
+ ntests++;
+ }
+ if (ntests != 0) {
+ printf("glob: %d test%s run, %d errors, %d%% success rate\n",
+ ntests, ntests == 1 ? "" : "s", errors,
+ (ntests - errors) * 100 / ntests);
+ }
+ return errors;
+}
+
+static int
+test_glob(struct gl_entry *entry)
+{
+ glob_t gl;
+ char **ap;
+ int nmatches = 0, i = 0;
+
+ if (glob(entry->pattern, entry->flags, NULL, &gl) != 0) {
+ fprintf(stderr, "glob failed: %s: %s\n", entry->pattern,
+ strerror(errno));
+ return 1;
+ }
+
+ for (ap = gl.gl_pathv; *ap != NULL; ap++)
+ nmatches++;
+
+ if (nmatches != entry->nresults)
+ goto mismatch;
+
+ for (i = 0; i < entry->nresults; i++) {
+ if (strcmp(gl.gl_pathv[i], entry->results[i]) != 0)
+ goto mismatch;
+ free(entry->results[i]);
+ }
+ return 0;
+ mismatch:
+ if (nmatches != entry->nresults) {
+ fprintf(stderr,
+ "globtest: mismatch in number of results (found %d, expected %d) for pattern %s\n",
+ nmatches, entry->nresults, entry->pattern);
+ } else {
+ fprintf(stderr, "globtest: mismatch for pattern %s, flags 0x%x "
+ "(found \"%s\", expected \"%s\")\n", entry->pattern, entry->flags,
+ gl.gl_pathv[i], entry->results[i]);
+ while (i < entry->nresults)
+ free(entry->results[i++]);
+ }
+ return 1;
+}
diff --git a/lib/util/regress/glob/globtest.in b/lib/util/regress/glob/globtest.in
new file mode 100644
index 0000000..20a86c1
--- /dev/null
+++ b/lib/util/regress/glob/globtest.in
@@ -0,0 +1,64 @@
+[fake/bin/[[:alpha:]]*] <NONE>
+fake/bin/cat
+fake/bin/chgrp
+fake/bin/chio
+fake/bin/chmod
+fake/bin/cksum
+fake/bin/cp
+fake/bin/cpio
+fake/bin/csh
+fake/bin/date
+fake/bin/dd
+fake/bin/df
+fake/bin/domainname
+fake/bin/echo
+fake/bin/ed
+fake/bin/eject
+fake/bin/expr
+fake/bin/hostname
+fake/bin/kill
+fake/bin/ksh
+fake/bin/ln
+fake/bin/ls
+fake/bin/md5
+fake/bin/mkdir
+fake/bin/mt
+fake/bin/mv
+fake/bin/pax
+fake/bin/ps
+fake/bin/pwd
+fake/bin/rcp
+fake/bin/rksh
+fake/bin/rm
+fake/bin/rmail
+fake/bin/rmd160
+fake/bin/rmdir
+fake/bin/sh
+fake/bin/sha1
+fake/bin/sha256
+fake/bin/sha384
+fake/bin/sha512
+fake/bin/sleep
+fake/bin/stty
+fake/bin/sum
+fake/bin/sync
+fake/bin/systrace
+fake/bin/tar
+fake/bin/test
+
+[fake/bin/rm{,dir,ail}] <GLOB_BRACE>
+fake/bin/rm
+fake/bin/rmdir
+fake/bin/rmail
+
+[fake/bin/sha[[:digit:]]] <NONE>
+fake/bin/sha1
+
+[fake/bin/sha[[:digit:]]*] <NONE>
+fake/bin/sha1
+fake/bin/sha256
+fake/bin/sha384
+fake/bin/sha512
+
+[fake/bin/ca[a-z]] <NONE>
+fake/bin/cat
diff --git a/lib/util/regress/harness.in b/lib/util/regress/harness.in
new file mode 100755
index 0000000..05fd298
--- /dev/null
+++ b/lib/util/regress/harness.in
@@ -0,0 +1,109 @@
+#!/bin/sh
+#
+# Copyright (c) 2022 Todd C. Miller <Todd.Miller@sudo.ws>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+# Simple test harness for libsudo_util tests.
+# usage: harness [-v] test_group [test_name ...]
+#
+srcdir="@abs_srcdir@"
+builddir="@abs_builddir@"
+SHELL=@SHELL@
+verbose=0
+rval=0
+ntests=0
+errors=0
+
+umask 022
+
+if [ "$1" = "-v" ]; then
+ verbose=1
+ shift
+fi
+
+if [ $# -eq 0 ]; then
+ echo "usage: harness test_group [test_name ...]" >&2
+ exit 1
+fi
+group="$1"
+shift
+srcdir=${srcdir%"/regress"}
+builddir=${builddir%"/regress"}
+
+cd $srcdir || exit 1
+
+if [ ! -d "regress/$group" ]; then
+ echo "missing test group: regress/$group" >&2
+ exit 1
+fi
+
+mkdir -p "$builddir/regress/$group"
+if [ $# -eq 0 ]; then
+ tests=
+ for t in regress/$group/*.in; do
+ tests="$tests `basename $t .in`"
+ done
+ set -- $tests
+fi
+
+
+while [ $# -ne 0 ]; do
+ test="$1"
+ shift
+ in="regress/$group/${test}.in"
+ out="$builddir/regress/$group/${test}.out"
+ out_ok="regress/$group/${test}.out.ok"
+ err="$builddir/regress/$group/${test}.err"
+ err_ok="regress/$group/${test}.err.ok"
+
+ if [ "$group" = "sudo_conf" ]; then
+ $builddir/conf_test $in >$out 2>$err
+ else
+ $builddir/parseln_test <$in >$out 2>$err
+ fi
+
+ ntests=`expr $ntests + 1`
+ if cmp $out $out_ok >/dev/null; then
+ if [ $verbose -eq 1 ]; then
+ echo "$group/$test: OK"
+ fi
+ else
+ errors=`expr $errors + 1`
+ echo "$group/$test: FAIL"
+ diff $out $out_ok || true
+ fi
+
+ ntests=`expr $ntests + 1`
+ if test -s $err_ok; then
+ if cmp $err $err_ok >/dev/null; then
+ if [ $verbose -eq 1 ]; then
+ echo "$group/$test (stderr): OK"
+ fi
+ else
+ errors=`expr $errors + 1`
+ echo "$group/$test (stderr): FAIL"
+ diff $err $err_ok || true
+ fi
+ elif test -s $err; then
+ errors=`expr $errors + 1`
+ echo "$group/$test (stderr): FAIL"
+ fi
+done
+${AWK-awk} -v group=$group -v ntests=$ntests -v errors=$errors \
+ 'END {printf("%s: %d tests run, %d errors, %d%% success rate\n", group, ntests, errors, (ntests - errors) * 100 / ntests)}' < /dev/null
+if test $errors -ne 0; then
+ rval=`expr $rval + $errors`
+fi
+
+exit $rval
diff --git a/lib/util/regress/hexchar/hexchar_test.c b/lib/util/regress/hexchar/hexchar_test.c
new file mode 100644
index 0000000..097cbcd
--- /dev/null
+++ b/lib/util/regress/hexchar/hexchar_test.c
@@ -0,0 +1,81 @@
+/*
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2014-2015, 2023 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define SUDO_ERROR_WRAP 0
+
+#include <sudo_compat.h>
+#include <sudo_util.h>
+
+sudo_dso_public int main(int argc, char *argv[]);
+
+struct hexchar_test {
+ char hex[3];
+ int value;
+};
+
+int
+main(int argc, char *argv[])
+{
+ struct hexchar_test *test_data;
+ int i, ntests, result, errors = 0;
+ static const char xdigs_lower[] = "0123456789abcdef";
+ static const char xdigs_upper[] = "0123456789ABCDEF";
+
+ initprogname(argc > 0 ? argv[0] : "hexchar_test");
+
+ /* Build up test data. */
+ ntests = 256 + 256 + 3;
+ test_data = calloc((size_t)ntests, sizeof(*test_data));
+ for (i = 0; i < 256; i++) {
+ /* lower case */
+ test_data[i].value = i;
+ test_data[i].hex[1] = xdigs_lower[ (i & 0x0f)];
+ test_data[i].hex[0] = xdigs_lower[((i & 0xf0) >> 4)];
+ /* upper case */
+ test_data[i + 256].value = i;
+ test_data[i + 256].hex[1] = xdigs_upper[ (i & 0x0f)];
+ test_data[i + 256].hex[0] = xdigs_upper[((i & 0xf0) >> 4)];
+ }
+ /* Also test invalid data */
+ test_data[ntests - 3].hex[0] = '\0';
+ test_data[ntests - 3].value = -1;
+ strlcpy(test_data[ntests - 2].hex, "AG", sizeof(test_data[ntests - 2].hex));
+ test_data[ntests - 2].value = -1;
+ strlcpy(test_data[ntests - 1].hex, "-1", sizeof(test_data[ntests - 1].hex));
+ test_data[ntests - 1].value = -1;
+
+ for (i = 0; i < ntests; i++) {
+ result = sudo_hexchar(test_data[i].hex);
+ if (result != test_data[i].value) {
+ fprintf(stderr, "%s: expected %d, got %d\n", getprogname(),
+ test_data[i].value, result);
+ errors++;
+ }
+ }
+ if (ntests != 0) {
+ printf("%s: %d tests run, %d errors, %d%% success rate\n",
+ getprogname(), ntests, errors, (ntests - errors) * 100 / ntests);
+ }
+ return errors;
+}
diff --git a/lib/util/regress/json/json_test.c b/lib/util/regress/json/json_test.c
new file mode 100644
index 0000000..5acaeb5
--- /dev/null
+++ b/lib/util/regress/json/json_test.c
@@ -0,0 +1,235 @@
+/*
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2022 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <string.h>
+#include <unistd.h>
+
+#define SUDO_ERROR_WRAP 0
+
+#include <sudo_compat.h>
+#include <sudo_json.h>
+#include <sudo_util.h>
+#include <sudo_fatal.h>
+
+sudo_dso_public int main(int argc, char *argv[]);
+
+/* Expected JSON output */
+const char outbuf[] = "\n"
+ " \"test1\": {\n"
+ " \"string1\": \"test\\\\\\b\\f\\n\\r\\t string1\",\n"
+ " \"id1\": 4294967295,\n"
+ " \"number1\": -1,\n"
+ " \"bool1\": true,\n"
+ " \"bool2\": false,\n"
+ " \"null1\": null,\n"
+ " \"array1\": [\n"
+ " \"string2\": \"test\\f\\u0011string2\",\n"
+ " \"number2\": -9223372036854775808,\n"
+ " \"number3\": 9223372036854775807\n"
+ " ]\n"
+ " }";
+
+/*
+ * Simple tests for sudo json functions()
+ */
+int
+main(int argc, char *argv[])
+{
+ struct json_container jsonc;
+ struct json_value value;
+ int ch, errors = 0, ntests = 0;
+
+ initprogname(argc > 0 ? argv[0] : "json_test");
+
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch (ch) {
+ case 'v':
+ /* ignore */
+ break;
+ default:
+ fprintf(stderr, "usage: %s [-v]\n", getprogname());
+ return EXIT_FAILURE;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ ntests++;
+ if (!sudo_json_init(&jsonc, 4, false, true, true)) {
+ sudo_warnx("unable to initialize json");
+ errors++;
+ goto done;
+ }
+
+ /* Open main JSON object. */
+ ntests++;
+ if (!sudo_json_open_object(&jsonc, "test1")) {
+ sudo_warnx("unable to open json object");
+ errors++;
+ goto done;
+ }
+
+ /* Verify invalid value is detected. */
+ value.type = -1;
+ value.u.string = NULL;
+ ntests++;
+ if (sudo_json_add_value(&jsonc, "bogus1", &value)) {
+ /* should have failed, not a fatal error */
+ sudo_warnx("should not be able to add bogus type value");
+ errors++;
+ }
+
+ /* Verify that adding an array is not allowed. */
+ value.type = JSON_ARRAY;
+ value.u.string = NULL;
+ ntests++;
+ if (sudo_json_add_value(&jsonc, "bogus2", &value)) {
+ /* should have failed, not a fatal error */
+ sudo_warnx("should not be able to add array type value");
+ errors++;
+ }
+
+ /* Verify that adding an object is not allowed. */
+ value.type = JSON_OBJECT;
+ value.u.string = NULL;
+ ntests++;
+ if (sudo_json_add_value(&jsonc, "bogus3", &value)) {
+ /* should have failed, not a fatal error */
+ sudo_warnx("should not be able to add object type value");
+ errors++;
+ }
+
+ value.type = JSON_STRING;
+ value.u.string = "test\\\b\f\n\r\t string1";
+ ntests++;
+ if (!sudo_json_add_value(&jsonc, "string1", &value)) {
+ /* not a fatal error */
+ sudo_warnx("unable to add string value (string1)");
+ errors++;
+ }
+
+ value.type = JSON_ID;
+ value.u.id = 0xffffffff;
+ ntests++;
+ if (!sudo_json_add_value(&jsonc, "id1", &value)) {
+ /* not a fatal error */
+ sudo_warnx("unable to add ID value (0xffffffff)");
+ errors++;
+ }
+
+ value.type = JSON_NUMBER;
+ value.u.number = -1;
+ ntests++;
+ if (!sudo_json_add_value(&jsonc, "number1", &value)) {
+ /* not a fatal error */
+ sudo_warnx("unable to add number value (-1)");
+ errors++;
+ }
+
+ value.type = JSON_BOOL;
+ value.u.boolean = true;
+ ntests++;
+ if (!sudo_json_add_value(&jsonc, "bool1", &value)) {
+ /* not a fatal error */
+ sudo_warnx("unable to add bool value (true)");
+ errors++;
+ }
+ value.u.boolean = false;
+ ntests++;
+ if (!sudo_json_add_value(&jsonc, "bool2", &value)) {
+ /* not a fatal error */
+ sudo_warnx("unable to add bool value (false)");
+ errors++;
+ }
+
+ value.type = JSON_NULL;
+ ntests++;
+ if (!sudo_json_add_value(&jsonc, "null1", &value)) {
+ /* not a fatal error */
+ sudo_warnx("unable to add null value");
+ errors++;
+ }
+
+ /* Open JSON array. */
+ ntests++;
+ if (!sudo_json_open_array(&jsonc, "array1")) {
+ sudo_warnx("unable to open json array");
+ errors++;
+ goto done;
+ }
+
+ value.type = JSON_STRING;
+ value.u.string = "test\x0c\x11string2";
+ ntests++;
+ if (!sudo_json_add_value(&jsonc, "string2", &value)) {
+ /* not a fatal error */
+ sudo_warnx("unable to add string value (string2)");
+ errors++;
+ }
+
+ value.type = JSON_NUMBER;
+ value.u.number = LLONG_MIN;
+ ntests++;
+ if (!sudo_json_add_value(&jsonc, "number2", &value)) {
+ /* not a fatal error */
+ sudo_warnx("unable to add number value (LLONG_MIN)");
+ errors++;
+ }
+ value.u.number = LLONG_MAX;
+ ntests++;
+ if (!sudo_json_add_value(&jsonc, "number3", &value)) {
+ /* not a fatal error */
+ sudo_warnx("unable to add number value (LLONG_MAX)");
+ errors++;
+ }
+
+ /* Close JSON array. */
+ if (!sudo_json_close_array(&jsonc)) {
+ sudo_warnx("unable to close json array");
+ errors++;
+ goto done;
+ }
+
+ /* Close main JSON object. */
+ if (!sudo_json_close_object(&jsonc)) {
+ sudo_warnx("unable to close json object");
+ errors++;
+ goto done;
+ }
+
+ if (strcmp(outbuf, jsonc.buf) != 0) {
+ fprintf(stderr, "Expected:\n%s\n", outbuf);
+ fprintf(stderr, "Received:\n%s\n", jsonc.buf);
+ }
+
+done:
+ sudo_json_free(&jsonc);
+
+ if (ntests != 0) {
+ printf("%s: %d tests run, %d errors, %d%% success rate\n",
+ getprogname(), ntests, errors, (ntests - errors) * 100 / ntests);
+ }
+
+ return errors;
+}
diff --git a/lib/util/regress/mktemp/mktemp_test.c b/lib/util/regress/mktemp/mktemp_test.c
new file mode 100644
index 0000000..b441431
--- /dev/null
+++ b/lib/util/regress/mktemp/mktemp_test.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2010 Philip Guenther <guenther@openbsd.org>
+ *
+ * Public domain.
+ *
+ * Verify that mkdtemp() and mkstemps() doesn't overrun or underrun
+ * the template buffer and that it can generate names that don't
+ * contain any X's
+ */
+
+#include <config.h>
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#define SUDO_ERROR_WRAP 0
+
+#include <sudo_compat.h>
+#include <sudo_util.h>
+#include <sudo_fatal.h>
+
+#ifndef MAP_ANON
+# if defined(MAP_ANONYMOUS)
+# define MAP_ANON MAP_ANONYMOUS
+# endif
+#endif
+
+#ifndef MAP_FAILED
+# define MAP_FAILED ((void *) -1)
+#endif
+
+#define MAX_TEMPLATE_LEN 10
+#define MAX_TRIES 100
+#define MIN_Xs 6
+
+#define SUFFIX ".suff"
+#define SLEN (sizeof SUFFIX - 1)
+
+sudo_dso_public int main(int argc, char *argv[]);
+
+/*
+ * verify that a path generated by mkdtemp() or mkstemp() looks like a
+ * reasonable expansion of the template and matches the fd. Returns true
+ * if all the X's were replaced with non-X's
+ */
+static int
+check(int fd, char const *kind, char const *path, char const *prefix,
+ size_t plen, char const *suffix, size_t slen, size_t tlen)
+{
+ struct stat sb, fsb;
+ char const *p;
+
+ if (tlen < MIN_Xs) {
+ if (fd != -1)
+ sudo_fatalx("%s(%s) succeed with too few Xs", kind, path);
+ if (errno != EINVAL)
+ sudo_fatal("%s(%s) failed with wrong errno: %d", kind, path, errno);
+ return 1;
+ }
+ if (fd == -1)
+ sudo_fatal("%s(%s)", kind, path);
+ if (stat(path, &sb))
+ sudo_fatal("%s: stat(%s)", kind, path);
+ if (fd >= 0) {
+ if (fstat(fd, &fsb))
+ sudo_fatal("%s: fstat(%d==%s)", kind, fd, path);
+ if (sb.st_dev != fsb.st_dev || sb.st_ino != fsb.st_ino)
+ sudo_fatalx("%s: stat mismatch", kind);
+ }
+ if (memcmp(path, prefix, plen) != 0)
+ sudo_fatalx("%s: prefix changed! %s vs %s", kind, prefix, path);
+ if (memcmp(path + plen + tlen, suffix, slen + 1) != 0)
+ sudo_fatalx("%s: suffix changed! %s vs %s", kind, suffix, path);
+ for (p = path + plen; p < path + plen + tlen; p++)
+ if (*p == '\0')
+ sudo_fatalx("%s: unexpected truncation", kind);
+ else if (*p == 'X')
+ return 0;
+ return 1;
+}
+
+static void
+try_mkdtemp(char *p, char const *prefix, size_t len)
+{
+ size_t plen = strlen(prefix);
+ int fd, tries, ok;
+
+ for (tries = 0; tries < MAX_TRIES; tries++) {
+ memcpy(p, prefix, plen);
+ memset(p + plen, 'X', len);
+ p[plen + len] = '\0';
+ fd = mkdtemp(p) ? -2 : -1;
+ ok = check(fd, "mkdtemp", p, prefix, plen, "", 0, len);
+ rmdir(p);
+ if (ok)
+ return;
+ }
+ sudo_fatalx("mkdtemp: exceeded MAX_TRIES");
+}
+
+static void
+try_mkstemps(char *p, char const *prefix, size_t len, char const *suffix)
+{
+ size_t plen = strlen(prefix);
+ size_t slen = strlen(suffix);
+ int tries, fd, ok;
+
+ for (tries = 0; tries < MAX_TRIES; tries++) {
+ memcpy(p, prefix, plen);
+ memset(p + plen, 'X', len);
+ memcpy(p + plen + len, suffix, slen + 1);
+ fd = mkstemps(p, (int)slen);
+ ok = check(fd, "mkstemp", p, prefix, plen, suffix, slen, len);
+ close(fd);
+ unlink(p);
+ if (ok)
+ return;
+ }
+ sudo_fatalx("mkstemps: exceeded MAX_TRIES");
+}
+
+int
+main(int argc, char *argv[])
+{
+ char cwd[PATH_MAX + 1];
+ char *p;
+ size_t clen, i;
+ size_t pg;
+ int ch;
+
+ initprogname(argc > 0 ? argv[0] : "mktemp_test");
+
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch (ch) {
+ case 'v':
+ /* ignore */
+ break;
+ default:
+ fprintf(stderr, "usage: %s [-v]\n", getprogname());
+ return EXIT_FAILURE;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ pg = (size_t)sysconf(_SC_PAGESIZE);
+ if (getcwd(cwd, sizeof cwd - 1) == NULL)
+ sudo_fatal("getcwd");
+ clen = strlen(cwd);
+ cwd[clen++] = '/';
+ cwd[clen] = '\0';
+#ifdef MAP_ANON
+ p = mmap(NULL, pg * 3, PROT_READ | PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
+#else
+ ch = open("/dev/zero", O_RDWR);
+ if (ch == -1)
+ sudo_fatal("/dev/zero");
+ p = mmap(NULL, pg * 3, PROT_READ | PROT_WRITE, MAP_PRIVATE, ch, 0);
+#endif
+ if (p == MAP_FAILED)
+ sudo_fatal("mmap");
+ if (mprotect(p, pg, PROT_NONE) || mprotect(p + pg * 2, pg, PROT_NONE))
+ sudo_fatal("mprotect");
+ p += pg;
+
+ for (i = MAX_TEMPLATE_LEN; i != 0; i--) {
+ /* try first at the start of a page, no prefix */
+ try_mkdtemp(p, "", i);
+ /* now at the end of the page, no prefix */
+ try_mkdtemp(p + pg - i - 1, "", i);
+ /* start of the page, prefixed with the cwd */
+ try_mkdtemp(p, cwd, i);
+ /* how about at the end of the page, prefixed with cwd? */
+ try_mkdtemp(p + pg - clen - i - 1, cwd, i);
+
+ /* again, with mkstemps() and an empty suffix */
+ /* try first at the start of a page, no prefix */
+ try_mkstemps(p, "", i, "");
+ /* now at the end of the page, no prefix */
+ try_mkstemps(p + pg - i - 1, "", i, "");
+ /* start of the page, prefixed with the cwd */
+ try_mkstemps(p, cwd, i, "");
+ /* how about at the end of the page, prefixed with cwd? */
+ try_mkstemps(p + pg - clen - i - 1, cwd, i, "");
+
+ /* mkstemps() and a non-empty suffix */
+ /* try first at the start of a page, no prefix */
+ try_mkstemps(p, "", i, SUFFIX);
+ /* now at the end of the page, no prefix */
+ try_mkstemps(p + pg - i - SLEN - 1, "", i, SUFFIX);
+ /* start of the page, prefixed with the cwd */
+ try_mkstemps(p, cwd, i, SUFFIX);
+ /* how about at the end of the page, prefixed with cwd? */
+ try_mkstemps(p + pg - clen - i - SLEN - 1, cwd, i, SUFFIX);
+ }
+
+ return 0;
+}
diff --git a/lib/util/regress/multiarch/multiarch_test.c b/lib/util/regress/multiarch/multiarch_test.c
new file mode 100644
index 0000000..a6e70c1
--- /dev/null
+++ b/lib/util/regress/multiarch/multiarch_test.c
@@ -0,0 +1,184 @@
+/*
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2022 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define SUDO_ERROR_WRAP 0
+
+#include <sudo_compat.h>
+#include <sudo_fatal.h>
+#include <sudo_util.h>
+
+sudo_dso_public int main(int argc, char *argv[]);
+
+#ifdef __linux__
+# include <sys/utsname.h>
+
+# if defined(__ILP32__)
+# define ARCH_LIB "libx32"
+# elif defined(__LP64__)
+# define ARCH_LIB "lib64"
+# else
+# define ARCH_LIB "lib32"
+# endif
+
+struct multiarch_test {
+ const char *inpath;
+ char *outpath;
+};
+
+static struct multiarch_test *
+make_test_data(void)
+{
+ struct multiarch_test *test_data;
+ struct utsname unamebuf;
+ int i;
+
+ if (uname(&unamebuf) == -1)
+ return NULL;
+
+ test_data = calloc(7, sizeof(*test_data));
+ if (test_data == NULL)
+ return NULL;
+
+ test_data[0].inpath = "/usr/" ARCH_LIB "/libfoo.so";
+ i = asprintf(&test_data[0].outpath, "/usr/lib/%s-linux-gnu/libfoo.so",
+ unamebuf.machine);
+ if (i == -1) {
+ test_data[0].outpath = NULL;
+ goto bad;
+ }
+
+ test_data[1].inpath = "/usr/lib/something.so";
+ i = asprintf(&test_data[1].outpath, "/usr/lib/%s-linux-gnu/something.so",
+ unamebuf.machine);
+ if (i == -1) {
+ test_data[1].outpath = NULL;
+ goto bad;
+ }
+
+ test_data[2].inpath = "/usr/libexec/libbar.so";
+ i = asprintf(&test_data[2].outpath, "/usr/libexec/%s-linux-gnu/libbar.so",
+ unamebuf.machine);
+ if (i == -1) {
+ test_data[2].outpath = NULL;
+ goto bad;
+ }
+
+ test_data[3].inpath = "/usr/local/lib/sudo/libsudo_util.so";
+ i = asprintf(&test_data[3].outpath, "/usr/local/lib/%s-linux-gnu/sudo/libsudo_util.so",
+ unamebuf.machine);
+ if (i == -1) {
+ test_data[3].outpath = NULL;
+ goto bad;
+ }
+
+ test_data[4].inpath = "/opt/sudo/lib/sudoers.so";
+ i = asprintf(&test_data[4].outpath, "/opt/sudo/lib/%s-linux-gnu/sudoers.so",
+ unamebuf.machine);
+ if (i == -1) {
+ test_data[4].outpath = NULL;
+ goto bad;
+ }
+
+ i = asprintf(&test_data[5].outpath, "/usr/lib/%s-linux-gnu/something.so",
+ unamebuf.machine);
+ if (i == -1) {
+ test_data[5].outpath = NULL;
+ goto bad;
+ }
+ test_data[5].inpath = test_data[5].outpath;
+ test_data[5].outpath = NULL;
+
+ return test_data;
+bad:
+ for (i = 0; test_data[i].outpath != NULL; i++)
+ free(test_data[i].outpath);
+ free(test_data);
+ return NULL;
+}
+#endif /* __linux__ */
+
+int
+main(int argc, char *argv[])
+{
+ int ch, errors = 0;
+#ifdef __linux__
+ int ntests = 0;
+ struct multiarch_test *test_data;
+#endif
+
+ initprogname(argc > 0 ? argv[0] : "multiarch_test");
+
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch (ch) {
+ case 'v':
+ /* ignore */
+ break;
+ default:
+ fprintf(stderr, "usage: %s [-v]\n", getprogname());
+ return EXIT_FAILURE;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+#ifdef __linux__
+ test_data = make_test_data();
+ if (test_data == NULL) {
+ sudo_warnx("%s", "failed to generate test data");
+ return EXIT_FAILURE;
+ }
+
+ for (ch = 0; test_data[ch].inpath != NULL; ch++) {
+ char *outpath = sudo_stat_multiarch(test_data[ch].inpath, NULL);
+ ntests++;
+ if (outpath == NULL) {
+ if (test_data[ch].outpath != NULL) {
+ sudo_warnx("%s: sudo_stat_multiarch failed",
+ test_data[ch].inpath);
+ errors++;
+ }
+ } else if (strcmp(outpath, test_data[ch].outpath) != 0) {
+ sudo_warnx("%s: expected %s got %s", test_data[ch].inpath,
+ test_data[ch].outpath, outpath);
+ errors++;
+ }
+ /* For test_data[5], inpath is allocated and outpath is NULL. */
+ if (test_data[ch].outpath != NULL)
+ free(test_data[ch].outpath);
+ else
+ free((char *)test_data[ch].inpath);
+ free(outpath);
+ }
+ free(test_data);
+
+ if (ntests != 0) {
+ printf("%s: %d tests run, %d errors, %d%% success rate\n",
+ getprogname(), ntests, errors, (ntests - errors) * 100 / ntests);
+ }
+#endif /* __linux__ */
+ return errors;
+}
diff --git a/lib/util/regress/open_parent_dir/open_parent_dir_test.c b/lib/util/regress/open_parent_dir/open_parent_dir_test.c
new file mode 100644
index 0000000..0a4f252
--- /dev/null
+++ b/lib/util/regress/open_parent_dir/open_parent_dir_test.c
@@ -0,0 +1,166 @@
+/*
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2022 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define SUDO_ERROR_WRAP 0
+
+#include <sudo_compat.h>
+#include <sudo_fatal.h>
+#include <sudo_util.h>
+
+sudo_dso_public int main(int argc, char *argv[]);
+
+static int errors = 0, ntests = 0;
+
+static int
+run_test(const char *tdir, const char *path, uid_t uid, gid_t gid)
+{
+ char *cp, fullpath[PATH_MAX];
+ struct stat sb1, sb2;
+ int dfd, len;
+ int ret = -1;
+
+ /* Test creating full path. */
+ len = snprintf(fullpath, sizeof(fullpath), "%s/%s", tdir, path);
+ if (len < 0 || len >= ssizeof(fullpath)) {
+ errno = ENAMETOOLONG;
+ sudo_fatal("%s/%s", tdir, path);
+ }
+ ntests++;
+ dfd = sudo_open_parent_dir(fullpath, uid, gid, 0700, false);
+ if (dfd == -1) {
+ errors++;
+ goto done;
+ }
+
+ /* Verify that we only created the parent dir, not full path. */
+ ntests++;
+ if (stat(fullpath, &sb1) == 0) {
+ sudo_warnx("created full path \"%s\", not just parent dir",
+ fullpath);
+ errors++;
+ goto done;
+ }
+
+ /* Verify that dfd refers to the parent dir. */
+ ntests++;
+ cp = strrchr(fullpath, '/');
+ *cp = '\0';
+ if (stat(fullpath, &sb1) == -1) {
+ sudo_warn("%s", fullpath);
+ errors++;
+ goto done;
+ }
+ if (fstat(dfd, &sb2) == -1) {
+ sudo_warn("%s", fullpath);
+ errors++;
+ goto done;
+ }
+ if (sb1.st_dev != sb2.st_dev || sb1.st_ino != sb2.st_ino) {
+ sudo_warn("%s: sudo_open_parent_dir fd mismatch", fullpath);
+ errors++;
+ goto done;
+ }
+
+done:
+ if (dfd != -1)
+ close(dfd);
+ return ret;
+}
+
+int
+main(int argc, char *argv[])
+{
+ char tdir[] = "open_parent_dir.XXXXXXXX";
+ int ch, dfd, fd, len;
+ char cmd[1024];
+ uid_t uid;
+ gid_t gid;
+
+ initprogname(argc > 0 ? argv[0] : "open_parent_dir_test");
+
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch (ch) {
+ case 'v':
+ /* ignore */
+ break;
+ default:
+ fprintf(stderr, "usage: %s [-v]\n", getprogname());
+ return EXIT_FAILURE;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ uid = geteuid();
+ gid = getegid();
+
+ /* All tests relative to tdir. */
+ if (mkdtemp(tdir) == NULL)
+ sudo_fatal("%s", tdir);
+
+ /* Test creating new path. */
+ dfd = run_test(tdir, "level1/level2/level3", uid, gid);
+
+ /* Verify we can create a new file in the new parent dir. */
+ if (dfd != -1) {
+ ntests++;
+ fd = openat(dfd, "testfile", O_WRONLY|O_CREAT|O_EXCL, 0600);
+ if (fd == -1) {
+ errors++;
+ } else {
+ close(fd);
+ }
+ close(dfd);
+ dfd = -1;
+ }
+
+ /* Test exiting path when final component exists. */
+ dfd = run_test(tdir, "level1/level2/testfile", uid, gid);
+ if (dfd != -1) {
+ unlinkat(dfd, "testfile", 0);
+ close(dfd);
+ }
+
+ /* Test exiting path when final component doesn't exist. */
+ dfd = run_test(tdir, "level1/level2/testfile", uid, gid);
+ if (dfd != -1)
+ close(dfd);
+
+ /* Cleanup */
+ len = snprintf(cmd, sizeof(cmd), "rm -rf \"%s\"", tdir);
+ if (len < 0 || len >= ssizeof(cmd)) {
+ errno = ENAMETOOLONG;
+ sudo_fatalx("rm -rf %s", tdir);
+ }
+ ignore_result(system(cmd));
+
+ if (ntests != 0) {
+ printf("%s: %d tests run, %d errors, %d%% success rate\n",
+ getprogname(), ntests, errors, (ntests - errors) * 100 / ntests);
+ }
+ return errors;
+}
diff --git a/lib/util/regress/parse_gids/parse_gids_test.c b/lib/util/regress/parse_gids/parse_gids_test.c
new file mode 100644
index 0000000..3a94a72
--- /dev/null
+++ b/lib/util/regress/parse_gids/parse_gids_test.c
@@ -0,0 +1,124 @@
+/*
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2015 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sudo_compat.h>
+#include <sudo_fatal.h>
+#include <sudo_util.h>
+
+sudo_dso_public int main(int argc, char *argv[]);
+
+/*
+ * Test that sudo_parse_gids() works as expected.
+ */
+
+struct parse_gids_test {
+ const char *gids;
+ gid_t *baseptr;
+ gid_t basegid;
+ int ngids;
+ const GETGROUPS_T *gidlist;
+};
+
+static const GETGROUPS_T test1_out[] = { 0, 1, 2, 3, 4 };
+static const GETGROUPS_T test2_out[] = { 1, 2, 3, 4 };
+static const GETGROUPS_T test3_out[] = { 0, 1, (gid_t)-2, 3, 4 };
+
+/* XXX - test syntax errors too */
+static struct parse_gids_test test_data[] = {
+ { "1,2,3,4", &test_data[0].basegid, 0, 5, test1_out },
+ { "1,2,3,4", NULL, 0, 4, test2_out },
+ { "1,-2,3,4", &test_data[2].basegid, 0, 5, test3_out },
+ { NULL, false, 0, 0, NULL }
+};
+
+static void
+dump_gids(const char *prefix, int ngids, const GETGROUPS_T *gidlist)
+{
+ int i;
+
+ fprintf(stderr, "%s: %s: ", getprogname(), prefix);
+ for (i = 0; i < ngids; i++) {
+ fprintf(stderr, "%s%d", i ? ", " : "", (int)gidlist[i]);
+ }
+ fputc('\n', stderr);
+}
+
+int
+main(int argc, char *argv[])
+{
+ GETGROUPS_T *gidlist = NULL;
+ size_t i;
+ int j, errors = 0, ntests = 0;
+ int ch, ngids;
+
+ initprogname(argc > 0 ? argv[0] : "parse_gids_test");
+
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch (ch) {
+ case 'v':
+ /* ignore */
+ break;
+ default:
+ fprintf(stderr, "usage: %s [-v]\n", getprogname());
+ return EXIT_FAILURE;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ for (i = 0; test_data[i].gids != NULL; i++) {
+ free(gidlist);
+ gidlist = NULL;
+ ngids = sudo_parse_gids(test_data[i].gids, test_data[i].baseptr, &gidlist);
+ if (ngids == -1)
+ sudo_fatal_nodebug("sudo_parse_gids");
+ ntests++;
+ if (ngids != test_data[i].ngids) {
+ sudo_warnx_nodebug("test #%d: expected %d gids, got %d",
+ ntests, test_data[i].ngids, ngids);
+ dump_gids("expected", test_data[i].ngids, test_data[i].gidlist);
+ dump_gids("received", ngids, gidlist);
+ errors++;
+ continue;
+ }
+ ntests++;
+ for (j = 0; j < ngids; j++) {
+ if (test_data[i].gidlist[j] != gidlist[j]) {
+ sudo_warnx_nodebug("test #%d: gid mismatch", ntests);
+ dump_gids("expected", test_data[i].ngids, test_data[i].gidlist);
+ dump_gids("received", ngids, gidlist);
+ errors++;
+ break;
+ }
+ }
+ }
+ free(gidlist);
+
+ if (ntests != 0) {
+ printf("%s: %d tests run, %d errors, %d%% success rate\n",
+ getprogname(), ntests, errors, (ntests - errors) * 100 / ntests);
+ }
+ return errors;
+}
diff --git a/lib/util/regress/progname/progname_test.c b/lib/util/regress/progname/progname_test.c
new file mode 100644
index 0000000..330736c
--- /dev/null
+++ b/lib/util/regress/progname/progname_test.c
@@ -0,0 +1,67 @@
+/*
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2014 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sudo_compat.h>
+#include <sudo_util.h>
+
+sudo_dso_public int main(int argc, char *argv[]);
+
+/*
+ * Test that getprogname() returns the expected result.
+ * On some systems (AIX), we may have issues with symbolic links.
+ */
+
+int
+main(int argc, char *argv[])
+{
+ const char *progbase = "progname_test";
+ int ch;
+
+ if (argc > 0)
+ progbase = sudo_basename(argv[0]);
+ initprogname(progbase);
+
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch (ch) {
+ case 'v':
+ /* ignore */
+ break;
+ default:
+ fprintf(stderr, "usage: %s [-v]\n", progbase);
+ return EXIT_FAILURE;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* Make sure getprogname() matches basename of argv[0]. */
+ if (strcmp(getprogname(), progbase) != 0) {
+ printf("%s: FAIL: incorrect program name \"%s\"\n",
+ progbase, getprogname());
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/lib/util/regress/regex/regex_test.c b/lib/util/regress/regex/regex_test.c
new file mode 100644
index 0000000..ce629c6
--- /dev/null
+++ b/lib/util/regress/regex/regex_test.c
@@ -0,0 +1,126 @@
+/*
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2022 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_STDBOOL_H
+# include <stdbool.h>
+#else
+# include <compat/stdbool.h>
+#endif
+
+#define SUDO_ERROR_WRAP 0
+
+#include <sudo_compat.h>
+#include <sudo_fatal.h>
+#include <sudo_util.h>
+
+sudo_dso_public int main(int argc, char *argv[]);
+
+struct regex_test {
+ const char *pattern;
+ bool result;
+};
+
+static struct regex_test test_data[] = {
+ { "ab++", false },
+ { "ab\\++", true },
+ { "ab+\\+", true },
+ { "ab**", false },
+ { "ab\\**", true },
+ { "ab*\\*", true },
+ { "ab??", false },
+ { "ab\\??", true },
+ { "ab?\\?", true },
+ { "ab{1}{1}", false },
+ { "ab{1}{1,1}", false },
+ { "ab{1}{,1}", false },
+ { "ab{1}{1,}", false },
+ { "ab{1}\\{1}", true },
+ { "ab{1}\\{1,1}", true },
+ { "ab{1}\\{,1}", true },
+ { "ab{1}\\{1,}", true },
+ { "ab+*", false },
+ { "ab\\+*", true },
+ { "ab+\\*", true },
+ { "ab*+", false },
+ { "ab\\*+", true },
+ { "ab*\\+", true },
+ { "ab?*", false },
+ { "ab\\?*", true },
+ { "ab?\\*", true },
+ { "ab{1}*", false },
+ { "ab\\{1}*", true },
+ { "ab{1}\\*", true },
+ { "ab{256}", false },
+ { "ab{,256}", false },
+ { "ab{256,}", false },
+ { "ab{1,256}", false },
+ { "ab{1,\\256}", false },
+ { "ab{1,2\\56}", false },
+ { "ab{256,1}", false },
+ { "ab{\\256,1}", false },
+ { "ab{2\\56,1}", false },
+ { NULL }
+};
+
+int
+main(int argc, char *argv[])
+{
+ struct regex_test *td;
+ const char *errstr;
+ int errors = 0, ntests = 0;
+ bool result;
+ int ch;
+
+ initprogname(argc > 0 ? argv[0] : "regex_test");
+
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch (ch) {
+ case 'v':
+ /* ignore */
+ break;
+ default:
+ fprintf(stderr, "usage: %s [-v]\n", getprogname());
+ return EXIT_FAILURE;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ for (td = test_data; td->pattern != NULL; td++) {
+ ntests++;
+ result = sudo_regex_compile(NULL, td->pattern, &errstr);
+ if (result != td->result) {
+ sudo_warnx("%s: expected %d, got %d", td->pattern, (int)td->result,
+ (int)result);
+ errors++;
+ }
+ }
+
+ if (ntests != 0) {
+ printf("%s: %d tests run, %d errors, %d%% success rate\n",
+ getprogname(), ntests, errors, (ntests - errors) * 100 / ntests);
+ }
+ return errors;
+}
diff --git a/lib/util/regress/strsig/strsig_test.c b/lib/util/regress/strsig/strsig_test.c
new file mode 100644
index 0000000..79b40fa
--- /dev/null
+++ b/lib/util/regress/strsig/strsig_test.c
@@ -0,0 +1,319 @@
+/*
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2019-2020 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sudo_compat.h>
+#include <sudo_util.h>
+#include <sudo_fatal.h>
+
+sudo_dso_public int main(int argc, char *argv[]);
+
+/*
+ * Note: we do not test SIGUNUSED as it may not appear in sys_sigabbrev[]
+ * on Linux. FreeBSD is missing SIGLWP (aka SIGTHR) in sys_signame[].
+ */
+static struct signal_data {
+ int rval;
+ int signo;
+ const char *sigstr;
+ const char *altstr;
+} signal_data[] = {
+#ifdef SIGHUP
+ { 0, SIGHUP, "HUP", NULL },
+#endif
+#ifdef SIGINT
+ { 0, SIGINT, "INT", NULL },
+#endif
+#ifdef SIGQUIT
+ { 0, SIGQUIT, "QUIT", NULL },
+#endif
+#ifdef SIGILL
+ { 0, SIGILL, "ILL", NULL },
+#endif
+#ifdef SIGTRAP
+ { 0, SIGTRAP, "TRAP", NULL },
+#endif
+#ifdef SIGABRT
+ { 0, SIGABRT, "ABRT", "IOT" },
+#endif
+#ifdef SIGIOT
+ { 0, SIGIOT, "IOT", "ABRT" },
+#endif
+#ifdef SIGEMT
+ { 0, SIGEMT, "EMT", NULL },
+#endif
+#ifdef SIGFPE
+ { 0, SIGFPE, "FPE", NULL },
+#endif
+#ifdef SIGKILL
+ { 0, SIGKILL, "KILL", NULL },
+#endif
+#ifdef SIGBUS
+ { 0, SIGBUS, "BUS", NULL },
+#endif
+#ifdef SIGSEGV
+ { 0, SIGSEGV, "SEGV", NULL },
+#endif
+#ifdef SIGSYS
+ { 0, SIGSYS, "SYS", NULL },
+#endif
+#ifdef SIGPIPE
+ { 0, SIGPIPE, "PIPE", NULL },
+#endif
+#ifdef SIGALRM
+ { 0, SIGALRM, "ALRM", NULL },
+#endif
+#ifdef SIGTERM
+ { 0, SIGTERM, "TERM", NULL },
+#endif
+#ifdef SIGSTKFLT
+ { 0, SIGSTKFLT, "STKFLT", NULL },
+#endif
+#ifdef SIGIO
+ { 0, SIGIO, "IO", "POLL"},
+#endif
+#ifdef SIGXCPU
+ { 0, SIGXCPU, "XCPU", NULL },
+#endif
+#ifdef SIGXFSZ
+ { 0, SIGXFSZ, "XFSZ", NULL },
+#endif
+#ifdef SIGVTALRM
+ { 0, SIGVTALRM, "VTALRM", NULL },
+#endif
+#ifdef SIGPROF
+ { 0, SIGPROF, "PROF", NULL },
+#endif
+#ifdef SIGWINCH
+ { 0, SIGWINCH, "WINCH", NULL },
+#endif
+#ifdef SIGLOST
+ { 0, SIGLOST, "LOST", NULL },
+#endif
+#ifdef SIGUSR1
+ { 0, SIGUSR1, "USR1", NULL },
+#endif
+#ifdef SIGUSR2
+ { 0, SIGUSR2, "USR2", NULL },
+#endif
+#ifdef SIGPWR
+ { 0, SIGPWR, "PWR", NULL },
+#endif
+#ifdef SIGPOLL
+ { 0, SIGPOLL, "POLL", "IO" },
+#endif
+#ifdef SIGSTOP
+ { 0, SIGSTOP, "STOP", NULL },
+#endif
+#ifdef SIGTSTP
+ { 0, SIGTSTP, "TSTP", NULL },
+#endif
+#ifdef SIGCONT
+ { 0, SIGCONT, "CONT", NULL },
+#endif
+#ifdef SIGCHLD
+ { 0, SIGCHLD, "CHLD", "CLD" },
+#endif
+#ifdef SIGCLD
+ { 0, SIGCLD, "CLD", "CHLD" },
+#endif
+#ifdef SIGTTIN
+ { 0, SIGTTIN, "TTIN", NULL },
+#endif
+#ifdef SIGTTOU
+ { 0, SIGTTOU, "TTOU", NULL },
+#endif
+#ifdef SIGINFO
+ { 0, SIGINFO, "INFO", NULL },
+#endif
+#ifdef SIGURG
+ { 0, SIGURG, "URG", NULL },
+#endif
+#ifdef SIGWAITING
+ { 0, SIGWAITING, "WAITING", NULL },
+#endif
+#if defined(SIGLWP) && !defined(__FreeBSD__)
+ { 0, SIGLWP, "LWP", NULL },
+#endif
+#ifdef SIGFREEZE
+ { 0, SIGFREEZE, "FREEZE", NULL },
+#endif
+#ifdef SIGTHAW
+ { 0, SIGTHAW, "THAW", NULL },
+#endif
+#ifdef SIGCANCEL
+ { 0, SIGCANCEL, "CANCEL", NULL },
+#endif
+#if defined(SIGRTMIN) && defined(SIGRTMAX)
+ { 0, -1, "RTMIN", NULL },
+ { 0, -1, "RTMIN+1", NULL },
+ { 0, -1, "RTMIN+2", NULL },
+ { 0, -1, "RTMIN+3", NULL },
+ { 0, -1, "RTMAX-3", NULL },
+ { 0, -1, "RTMAX-2", NULL },
+ { 0, -1, "RTMAX-1", NULL },
+ { 0, -1, "RTMAX", NULL },
+#endif
+ { -1, 1024, "QWERT", NULL }, /* invalid */
+ { -1, 0, NULL, NULL }
+};
+
+#ifndef HAVE_SIG2STR
+static int
+test_sig2str(int *ntests)
+{
+ struct signal_data *d;
+ int rval, errors = 0;
+ char sigstr[SIG2STR_MAX];
+
+ for (d = signal_data; d->signo != 0; d++) {
+ (*ntests)++;
+ rval = sudo_sig2str(d->signo, sigstr);
+ if (rval != d->rval) {
+ sudo_warnx_nodebug("FAIL: sig2str(SIG%s): %d != %d",
+ d->sigstr, rval, d->rval);
+ errors++;
+ continue;
+ }
+ if (rval != 0)
+ continue;
+ if (strcmp(sigstr, d->sigstr) != 0 &&
+ (d->altstr != NULL && strcmp(sigstr, d->altstr) != 0)) {
+ sudo_warnx_nodebug("FAIL: signal %d: %s != %s", d->signo,
+ sigstr, d->sigstr);
+ errors++;
+ continue;
+ }
+ }
+
+ return errors;
+}
+#else
+static int
+test_sig2str(int *ntests)
+{
+ return 0;
+}
+#endif /* HAVE_SIG2STR */
+
+#ifndef HAVE_STR2SIG
+static int
+test_str2sig(int *ntests)
+{
+ struct signal_data *d;
+ int rval, errors = 0;
+ int signo;
+
+ for (d = signal_data; d->sigstr != NULL; d++) {
+ (*ntests)++;
+ rval = sudo_str2sig(d->sigstr, &signo);
+ if (rval != d->rval) {
+ sudo_warnx_nodebug("FAIL: str2sig(SIG%s): %d != %d",
+ d->sigstr, rval, d->rval);
+ errors++;
+ continue;
+ }
+ if (rval != 0)
+ continue;
+ if (signo != d->signo) {
+ sudo_warnx_nodebug("FAIL: signal SIG%s: %d != %d", d->sigstr,
+ signo, d->signo);
+ errors++;
+ continue;
+ }
+ }
+
+ return errors;
+}
+#else
+static int
+test_str2sig(int *ntests)
+{
+ return 0;
+}
+#endif /* HAVE_STR2SIG */
+
+#if defined(SIGRTMIN) && defined(SIGRTMAX)
+static
+void init_sigrt(void)
+{
+ int i;
+
+ /* Initialize real-time signal values. */
+ for (i = 0; signal_data[i].signo != -1; i++)
+ continue;
+ signal_data[i++].signo = SIGRTMIN;
+ signal_data[i++].signo = SIGRTMIN + 1;
+ signal_data[i++].signo = SIGRTMIN + 2;
+ signal_data[i++].signo = SIGRTMIN + 3;
+ signal_data[i++].signo = SIGRTMAX - 3;
+ signal_data[i++].signo = SIGRTMAX - 2;
+ signal_data[i++].signo = SIGRTMAX - 1;
+ signal_data[i++].signo = SIGRTMAX;
+
+}
+#else
+static
+void init_sigrt(void)
+{
+ /* No real-time signals. */
+ return;
+}
+#endif
+
+/*
+ * Simple tests for sig2str() and str2sig().
+ */
+int
+main(int argc, char *argv[])
+{
+ int ch, errors = 0, ntests = 0;
+
+ initprogname(argc > 0 ? argv[0] : "strsig_test");
+
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch (ch) {
+ case 'v':
+ /* ignore */
+ break;
+ default:
+ fprintf(stderr, "usage: %s [-v]\n", getprogname());
+ return EXIT_FAILURE;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ init_sigrt();
+ errors += test_sig2str(&ntests);
+ errors += test_str2sig(&ntests);
+
+ if (ntests != 0) {
+ printf("%s: %d tests run, %d errors, %d%% success rate\n",
+ getprogname(), ntests, errors, (ntests - errors) * 100 / ntests);
+ }
+
+ return errors;
+}
diff --git a/lib/util/regress/strsplit/strsplit_test.c b/lib/util/regress/strsplit/strsplit_test.c
new file mode 100644
index 0000000..fb868f4
--- /dev/null
+++ b/lib/util/regress/strsplit/strsplit_test.c
@@ -0,0 +1,117 @@
+/*
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2015 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sudo_compat.h>
+#include <sudo_fatal.h>
+#include <sudo_util.h>
+
+sudo_dso_public int main(int argc, char *argv[]);
+
+/*
+ * Test that sudo_strsplit() works as expected.
+ */
+
+struct strsplit_test {
+ const char *input;
+ size_t input_len;
+ const char **output;
+};
+
+static const char test1_in[] = " vi ";
+static const char *test1_out[] = { "vi", NULL };
+static const char test2_in[] = "vi -r ";
+static const char *test2_out[] = { "vi", "-r", NULL };
+static const char test3_in[] = "vi -r -R abc\tdef ";
+static const char *test3_out[] = { "vi", "-r", "-R", "abc", "def", NULL };
+static const char test4_in[] = "vi -r -R abc\tdef ";
+static const char *test4_out[] = { "vi", "-r", "-R", "abc", NULL };
+static const char test5_in[] = "";
+static const char *test5_out[] = { NULL };
+
+static struct strsplit_test test_data[] = {
+ { test1_in, sizeof(test1_in) - 1, test1_out },
+ { test2_in, sizeof(test2_in) - 1, test2_out },
+ { test3_in, sizeof(test3_in) - 1, test3_out },
+ { test4_in, sizeof(test4_in) - 5, test4_out },
+ { test5_in, sizeof(test5_in) - 1, test5_out },
+ { NULL, 0, NULL }
+};
+
+int
+main(int argc, char *argv[])
+{
+ const char *cp, *ep, *input_end;
+ int ch, i, j, errors = 0, ntests = 0;
+ size_t len;
+
+ initprogname(argc > 0 ? argv[0] : "strsplit_test");
+
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch (ch) {
+ case 'v':
+ /* ignore */
+ break;
+ default:
+ fprintf(stderr, "usage: %s [-v]\n", getprogname());
+ return EXIT_FAILURE;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ for (i = 0; test_data[i].input != NULL; i++) {
+ input_end = test_data[i].input + test_data[i].input_len;
+ cp = sudo_strsplit(test_data[i].input, input_end, " \t", &ep);
+ for (j = 0; test_data[i].output[j] != NULL; j++) {
+ ntests++;
+ len = strlen(test_data[i].output[j]);
+ if ((size_t)(ep - cp) != len) {
+ sudo_warnx_nodebug("failed test #%d: bad length, expected "
+ "%zu, got %zu", ntests, len, (size_t)(ep - cp));
+ errors++;
+ continue;
+ }
+ ntests++;
+ if (strncmp(cp, test_data[i].output[j], len) != 0) {
+ sudo_warnx_nodebug("failed test #%d: expected %s, got %.*s",
+ ntests, test_data[i].output[j], (int)(ep - cp), cp);
+ errors++;
+ continue;
+ }
+ cp = sudo_strsplit(NULL, input_end, " \t", &ep);
+ }
+ ntests++;
+ if (cp != NULL) {
+ sudo_warnx_nodebug("failed test #%d: extra tokens \"%.*s\"",
+ ntests, (int)(input_end - cp), cp);
+ errors++;
+ }
+ }
+ if (ntests != 0) {
+ printf("%s: %d tests run, %d errors, %d%% success rate\n",
+ getprogname(), ntests, errors, (ntests - errors) * 100 / ntests);
+ }
+ return errors;
+}
diff --git a/lib/util/regress/strtofoo/strtobool_test.c b/lib/util/regress/strtofoo/strtobool_test.c
new file mode 100644
index 0000000..8264d4f
--- /dev/null
+++ b/lib/util/regress/strtofoo/strtobool_test.c
@@ -0,0 +1,98 @@
+/*
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2014-2020 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_STDBOOL_H
+# include <stdbool.h>
+#else
+# include <compat/stdbool.h>
+#endif
+#include <unistd.h>
+
+#include <sudo_compat.h>
+#include <sudo_util.h>
+#include <sudo_fatal.h>
+
+sudo_dso_public int main(int argc, char *argv[]);
+
+/* sudo_strtobool() tests */
+static struct strtobool_data {
+ const char *bool_str;
+ int value;
+} strtobool_data[] = {
+ { "true", true },
+ { "false", false },
+ { "TrUe", true },
+ { "fAlSe", false },
+ { "1", true },
+ { "0", false },
+ { "on", true },
+ { "off", false },
+ { "yes", true },
+ { "no", false },
+ { "nope", -1 },
+ { "10", -1 },
+ { "one", -1 },
+ { "zero", -1 },
+ { NULL, 0 }
+};
+
+/*
+ * Simple tests for sudo_strtobool()
+ */
+int
+main(int argc, char *argv[])
+{
+ struct strtobool_data *d;
+ int errors = 0, ntests = 0;
+ int ch, value;
+
+ initprogname(argc > 0 ? argv[0] : "strtobool_test");
+
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch (ch) {
+ case 'v':
+ /* ignore */
+ break;
+ default:
+ fprintf(stderr, "usage: %s [-v]\n", getprogname());
+ return EXIT_FAILURE;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ for (d = strtobool_data; d->bool_str != NULL; d++) {
+ ntests++;
+ value = sudo_strtobool(d->bool_str);
+ if (value != d->value) {
+ sudo_warnx_nodebug("FAIL: %s != %d", d->bool_str, d->value);
+ errors++;
+ }
+ }
+
+ if (ntests != 0) {
+ printf("%s: %d tests run, %d errors, %d%% success rate\n",
+ getprogname(), ntests, errors, (ntests - errors) * 100 / ntests);
+ }
+
+ return errors;
+}
diff --git a/lib/util/regress/strtofoo/strtoid_test.c b/lib/util/regress/strtofoo/strtoid_test.c
new file mode 100644
index 0000000..6e5998f
--- /dev/null
+++ b/lib/util/regress/strtofoo/strtoid_test.c
@@ -0,0 +1,118 @@
+/*
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2014-2020 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <sudo_compat.h>
+#include <sudo_util.h>
+#include <sudo_fatal.h>
+
+sudo_dso_public int main(int argc, char *argv[]);
+
+/* sudo_strtoidx() tests */
+static struct strtoidx_data {
+ const char *idstr;
+ id_t id;
+ const char *sep;
+ const char *ep;
+ int errnum;
+} strtoidx_data[] = {
+ { "0,1", 0, ",", ",", 0 },
+ { "10", 10, NULL, NULL, 0 },
+ { "-1", 0, NULL, NULL, EINVAL },
+ { "4294967295", 0, NULL, NULL, EINVAL },
+ { "4294967296", 0, NULL, NULL, ERANGE },
+ { "-2147483649", 0, NULL, NULL, ERANGE },
+ { "-2", (id_t)-2, NULL, NULL, 0 },
+#if SIZEOF_ID_T != SIZEOF_LONG_LONG
+ { "-2", (id_t)4294967294U, NULL, NULL, 0 },
+#endif
+ { "4294967294", (id_t)4294967294U, NULL, NULL, 0 },
+ { NULL, 0, NULL, NULL, 0 }
+};
+
+/*
+ * Simple tests for sudo_strtoidx()
+ */
+int
+main(int argc, char *argv[])
+{
+ int ch, errors = 0, ntests = 0;
+ struct strtoidx_data *d;
+ const char *errstr;
+ char *ep;
+ id_t value;
+
+ initprogname(argc > 0 ? argv[0] : "strtoid_test");
+
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch (ch) {
+ case 'v':
+ /* ignore */
+ break;
+ default:
+ fprintf(stderr, "usage: %s [-v]\n", getprogname());
+ return EXIT_FAILURE;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ for (d = strtoidx_data; d->idstr != NULL; d++) {
+ ntests++;
+ errstr = "some error";
+ value = sudo_strtoidx(d->idstr, d->sep, &ep, &errstr);
+ if (d->errnum != 0) {
+ if (errstr == NULL) {
+ sudo_warnx_nodebug("FAIL: %s: missing errstr for errno %d",
+ d->idstr, d->errnum);
+ errors++;
+ } else if (value != 0) {
+ sudo_warnx_nodebug("FAIL: %s should return 0 on error",
+ d->idstr);
+ errors++;
+ } else if (errno != d->errnum) {
+ sudo_warnx_nodebug("FAIL: %s: errno mismatch, %d != %d",
+ d->idstr, errno, d->errnum);
+ errors++;
+ }
+ } else if (errstr != NULL) {
+ sudo_warnx_nodebug("FAIL: %s: %s", d->idstr, errstr);
+ errors++;
+ } else if (value != d->id) {
+ sudo_warnx_nodebug("FAIL: %s != %u", d->idstr, (unsigned int)d->id);
+ errors++;
+ } else if (d->ep != NULL && ep[0] != d->ep[0]) {
+ sudo_warnx_nodebug("FAIL: ep[0] %d != %d", (int)(unsigned char)ep[0],
+ (int)(unsigned char)d->ep[0]);
+ errors++;
+ }
+ }
+
+ if (ntests != 0) {
+ printf("%s: %d tests run, %d errors, %d%% success rate\n",
+ getprogname(), ntests, errors, (ntests - errors) * 100 / ntests);
+ }
+
+ return errors;
+}
diff --git a/lib/util/regress/strtofoo/strtomode_test.c b/lib/util/regress/strtofoo/strtomode_test.c
new file mode 100644
index 0000000..c7a31b0
--- /dev/null
+++ b/lib/util/regress/strtofoo/strtomode_test.c
@@ -0,0 +1,91 @@
+/*
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2014-2020 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <sudo_compat.h>
+#include <sudo_util.h>
+#include <sudo_fatal.h>
+
+sudo_dso_public int main(int argc, char *argv[]);
+
+/* sudo_strtomode() tests */
+static struct strtomode_data {
+ const char *mode_str;
+ mode_t mode;
+} strtomode_data[] = {
+ { "755", 0755 },
+ { "007", 007 },
+ { "7", 7 },
+ { "8", (mode_t)-1 },
+ { NULL, 0 }
+};
+
+/*
+ * Simple tests for sudo_strtomode().
+ */
+int
+main(int argc, char *argv[])
+{
+ struct strtomode_data *d;
+ const char *errstr;
+ int ch, errors = 0, ntests = 0;
+ mode_t mode;
+
+ initprogname(argc > 0 ? argv[0] : "strtomode_test");
+
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch (ch) {
+ case 'v':
+ /* ignore */
+ break;
+ default:
+ fprintf(stderr, "usage: %s [-v]\n", getprogname());
+ return EXIT_FAILURE;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ for (d = strtomode_data; d->mode_str != NULL; d++) {
+ ntests++;
+ errstr = "some error";
+ mode = sudo_strtomode(d->mode_str, &errstr);
+ if (errstr != NULL) {
+ if (d->mode != (mode_t)-1) {
+ sudo_warnx_nodebug("FAIL: %s: %s", d->mode_str, errstr);
+ errors++;
+ }
+ } else if (mode != d->mode) {
+ sudo_warnx_nodebug("FAIL: %s != 0%o", d->mode_str,
+ (unsigned int) d->mode);
+ errors++;
+ }
+ }
+
+ if (ntests != 0) {
+ printf("%s: %d tests run, %d errors, %d%% success rate\n",
+ getprogname(), ntests, errors, (ntests - errors) * 100 / ntests);
+ }
+
+ return errors;
+}
diff --git a/lib/util/regress/strtofoo/strtonum_test.c b/lib/util/regress/strtofoo/strtonum_test.c
new file mode 100644
index 0000000..a90ed02
--- /dev/null
+++ b/lib/util/regress/strtofoo/strtonum_test.c
@@ -0,0 +1,135 @@
+/*
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2019-2020 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <sudo_compat.h>
+#include <sudo_util.h>
+#include <sudo_fatal.h>
+
+sudo_dso_public int main(int argc, char *argv[]);
+
+/* sudo_strtonum() tests */
+static struct strtonum_data {
+ const char *str;
+ long long minval;
+ long long maxval;
+ long long retval;
+ int errnum;
+} strtonum_data[] = {
+ { "0,1", LLONG_MIN, LLONG_MAX, 0, EINVAL },
+ { "0", INT_MAX, INT_MIN, 0, EINVAL },
+ { "", 0, UINT_MAX, 0, EINVAL },
+ { " ", 0, UINT_MAX, 0, EINVAL },
+ { "-1 ", 0, UINT_MAX, 0, EINVAL },
+ { "9223372036854775808X", LLONG_MIN, LLONG_MAX, 0, EINVAL },
+ { "-9223372036854775809X", LLONG_MIN, LLONG_MAX, 0, EINVAL },
+
+ { "10", 0, 255, 10, 0 },
+ { "-1", 0, UINT_MAX, 0, ERANGE },
+
+ { "-40", -100, -50, 0, ERANGE },
+ { "-60", -100, -50, -60, 0 },
+ { "-200", -100, -50, 0, ERANGE },
+
+ { "42", 42, 42, 42, 0 },
+ { "-42", -42, -42, -42, 0 },
+
+ { "4294967295", 0, UINT_MAX, UINT_MAX, 0 },
+ { "4294967295", INT_MIN, INT_MAX, 0, ERANGE },
+ { "4294967296", 0, UINT_MAX, 0, ERANGE },
+
+ { "2147483647", INT_MIN, INT_MAX, INT_MAX, 0 },
+ { "-2147483648", INT_MIN, INT_MAX, INT_MIN, 0 },
+ { "2147483648", INT_MIN, INT_MAX, 0, ERANGE },
+ { "-2147483649", INT_MIN, INT_MAX, 0, ERANGE },
+
+ { "9223372036854775807", LLONG_MIN, LLONG_MAX, LLONG_MAX, 0 },
+ { "-9223372036854775808", LLONG_MIN, LLONG_MAX, LLONG_MIN, 0 },
+ { "9223372036854775808", LLONG_MIN, LLONG_MAX, 0, ERANGE },
+ { "-9223372036854775809", LLONG_MIN, LLONG_MAX, 0, ERANGE },
+
+ { NULL, 0, 0, 0, 0 }
+};
+
+/*
+ * Simple tests for sudo_strtonum()
+ */
+int
+main(int argc, char *argv[])
+{
+ int ch, errors = 0, ntests = 0;
+ struct strtonum_data *d;
+ const char *errstr;
+ long long value;
+
+ initprogname(argc > 0 ? argv[0] : "strtonum_test");
+
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch (ch) {
+ case 'v':
+ /* ignore */
+ break;
+ default:
+ fprintf(stderr, "usage: %s [-v]\n", getprogname());
+ return EXIT_FAILURE;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ for (d = strtonum_data; d->str != NULL; d++) {
+ ntests++;
+ errstr = "some error";
+ value = sudo_strtonum(d->str, d->minval, d->maxval, &errstr);
+ if (d->errnum != 0) {
+ if (errstr == NULL) {
+ sudo_warnx_nodebug("FAIL: \"%s\": missing errstr for errno %d",
+ d->str, d->errnum);
+ errors++;
+ } else if (value != 0) {
+ sudo_warnx_nodebug("FAIL: %s should return 0 on error",
+ d->str);
+ errors++;
+ } else if (errno != d->errnum) {
+ sudo_warnx_nodebug("FAIL: \"%s\": errno mismatch, %d != %d",
+ d->str, errno, d->errnum);
+ errors++;
+ }
+ } else if (errstr != NULL) {
+ sudo_warnx_nodebug("FAIL: \"%s\": %s", d->str, errstr);
+ errors++;
+ } else if (value != d->retval) {
+ sudo_warnx_nodebug("FAIL: %s != %lld", d->str, d->retval);
+ errors++;
+ }
+ }
+
+ if (ntests != 0) {
+ printf("%s: %d tests run, %d errors, %d%% success rate\n",
+ getprogname(), ntests, errors, (ntests - errors) * 100 / ntests);
+ }
+
+ return errors;
+}
diff --git a/lib/util/regress/sudo_conf/conf_test.c b/lib/util/regress/sudo_conf/conf_test.c
new file mode 100644
index 0000000..dc65bc3
--- /dev/null
+++ b/lib/util/regress/sudo_conf/conf_test.c
@@ -0,0 +1,126 @@
+/*
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2013-2022 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sudo_compat.h>
+#include <sudo_conf.h>
+#include <sudo_debug.h>
+#include <sudo_util.h>
+
+static void sudo_conf_dump(void);
+
+sudo_dso_public int main(int argc, char *argv[]);
+
+/* Awful hack for macOS where the default group source is dynamic. */
+#ifdef __APPLE__
+# undef GROUP_SOURCE_ADAPTIVE
+# define GROUP_SOURCE_ADAPTIVE GROUP_SOURCE_DYNAMIC
+#endif
+
+sudo_noreturn static void
+usage(void)
+{
+ fprintf(stderr, "usage: %s [-v] conf_file\n", getprogname());
+ exit(EXIT_FAILURE);
+}
+
+/*
+ * Simple test driver for sudo_conf().
+ * Parses the given configuration file and dumps the resulting
+ * sudo_conf_data struct to the standard output.
+ */
+int
+main(int argc, char *argv[])
+{
+ int ch;
+
+ initprogname(argc > 0 ? argv[0] : "conf_test");
+
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch (ch) {
+ case 'v':
+ /* ignore */
+ break;
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 1)
+ usage();
+
+ sudo_conf_clear_paths();
+ if (sudo_conf_read(argv[0], SUDO_CONF_ALL) == -1)
+ return EXIT_FAILURE;
+ sudo_conf_dump();
+
+ return EXIT_SUCCESS;
+}
+
+static void
+sudo_conf_dump(void)
+{
+ struct plugin_info_list *plugins = sudo_conf_plugins();
+ struct sudo_conf_debug_list *debug_list = sudo_conf_debugging();
+ struct sudo_conf_debug *debug_spec;
+ struct sudo_debug_file *debug_file;
+ struct plugin_info *info;
+
+ printf("Set disable_coredump %s\n",
+ sudo_conf_disable_coredump() ? "true" : "false");
+ printf("Set group_source %s\n",
+ sudo_conf_group_source() == GROUP_SOURCE_ADAPTIVE ? "adaptive" :
+ sudo_conf_group_source() == GROUP_SOURCE_STATIC ? "static" : "dynamic");
+ printf("Set max_groups %d\n", sudo_conf_max_groups());
+ printf("Set probe_interfaces %s\n",
+ sudo_conf_probe_interfaces() ? "true" : "false");
+ if (sudo_conf_askpass_path() != NULL)
+ printf("Path askpass %s\n", sudo_conf_askpass_path());
+ if (sudo_conf_sesh_path() != NULL)
+ printf("Path sesh %s\n", sudo_conf_sesh_path());
+ if (sudo_conf_intercept_path() != NULL)
+ printf("Path intercept %s\n", sudo_conf_intercept_path());
+ if (sudo_conf_noexec_path() != NULL)
+ printf("Path noexec %s\n", sudo_conf_noexec_path());
+ if (sudo_conf_plugin_dir_path() != NULL)
+ printf("Path plugin_dir %s\n", sudo_conf_plugin_dir_path());
+ TAILQ_FOREACH(info, plugins, entries) {
+ printf("Plugin %s %s", info->symbol_name, info->path);
+ if (info->options) {
+ char * const * op;
+ for (op = info->options; *op != NULL; op++)
+ printf(" %s", *op);
+ }
+ putchar('\n');
+ }
+ TAILQ_FOREACH(debug_spec, debug_list, entries) {
+ TAILQ_FOREACH(debug_file, &debug_spec->debug_files, entries) {
+ printf("Debug %s %s %s\n", debug_spec->progname,
+ debug_file->debug_file, debug_file->debug_flags);
+ }
+ }
+}
diff --git a/lib/util/regress/sudo_conf/test1.in b/lib/util/regress/sudo_conf/test1.in
new file mode 100644
index 0000000..bc9f626
--- /dev/null
+++ b/lib/util/regress/sudo_conf/test1.in
@@ -0,0 +1,73 @@
+#
+# Sample /etc/sudo.conf file
+#
+# Format:
+# Plugin plugin_name plugin_path plugin_options ...
+# Path askpass /path/to/askpass
+# Path noexec /path/to/sudo_noexec.so
+# Debug sudo /var/log/sudo_debug all@warn
+# Set disable_coredump true
+#
+# Sudo plugins:
+#
+# The plugin_path is relative to ${prefix}/libexec unless fully qualified.
+# The plugin_name corresponds to a global symbol in the plugin
+# that contains the plugin interface structure.
+# The plugin_options are optional.
+#
+# The sudoers plugin is used by default if no Plugin lines are present.
+Plugin sudoers_policy sudoers.so
+Plugin sudoers_io sudoers.so
+
+#
+# Sudo askpass:
+#
+# An askpass helper program may be specified to provide a graphical
+# password prompt for "sudo -A" support. Sudo does not ship with its
+# own askpass program but can use the OpenSSH askpass.
+#
+# Use the OpenSSH askpass
+Path askpass /usr/X11R6/bin/ssh-askpass
+#
+# Use the Gnome OpenSSH askpass
+#Path askpass /usr/libexec/openssh/gnome-ssh-askpass
+
+#
+# Sudo noexec:
+#
+# Path to a shared library containing replacements for the execv(),
+# execve() and fexecve() library functions that just return an error.
+# This is used to implement the "noexec" functionality on systems that
+# support LD_PRELOAD or its equivalent.
+# The compiled-in value is usually sufficient and should only be changed
+# if you rename or move the sudo_noexec.so file.
+#
+Path noexec /usr/local/libexec/sudo_noexec.so
+Path noexec /usr/libexec/sudo_noexec.so
+
+#
+# Core dumps:
+#
+# By default, sudo disables core dumps while it is executing (they
+# are re-enabled for the command that is run).
+# To aid in debugging sudo problems, you may wish to enable core
+# dumps by setting "disable_coredump" to false.
+#
+Set disable_coredump false
+
+#
+# User groups:
+#
+# Sudo passes the user's group list to the policy plugin.
+# If the user is a member of the maximum number of groups (usually 16),
+# sudo will query the group database directly to be sure to include
+# the full list of groups.
+#
+# On some systems, this can be expensive so the behavior is configurable.
+# The "group_source" setting has three possible values:
+# static - use the user's list of groups returned by the kernel.
+# dynamic - query the group database to find the list of groups.
+# adaptive - if user is in less than the maximum number of groups.
+# use the kernel list, else query the group database.
+#
+Set group_source static
diff --git a/lib/util/regress/sudo_conf/test1.out.ok b/lib/util/regress/sudo_conf/test1.out.ok
new file mode 100644
index 0000000..d5b784c
--- /dev/null
+++ b/lib/util/regress/sudo_conf/test1.out.ok
@@ -0,0 +1,8 @@
+Set disable_coredump false
+Set group_source static
+Set max_groups -1
+Set probe_interfaces true
+Path askpass /usr/X11R6/bin/ssh-askpass
+Path noexec /usr/libexec/sudo_noexec.so
+Plugin sudoers_policy sudoers.so
+Plugin sudoers_io sudoers.so
diff --git a/lib/util/regress/sudo_conf/test2.in b/lib/util/regress/sudo_conf/test2.in
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lib/util/regress/sudo_conf/test2.in
diff --git a/lib/util/regress/sudo_conf/test2.out.ok b/lib/util/regress/sudo_conf/test2.out.ok
new file mode 100644
index 0000000..cfd8a08
--- /dev/null
+++ b/lib/util/regress/sudo_conf/test2.out.ok
@@ -0,0 +1,4 @@
+Set disable_coredump true
+Set group_source adaptive
+Set max_groups -1
+Set probe_interfaces true
diff --git a/lib/util/regress/sudo_conf/test3.in b/lib/util/regress/sudo_conf/test3.in
new file mode 100644
index 0000000..b111a23
--- /dev/null
+++ b/lib/util/regress/sudo_conf/test3.in
@@ -0,0 +1,2 @@
+Plugin sudoers_policy sudoers.so sudoers_file=/etc/sudoers sudoers_mode=0400 sudoers_gid=0 sudoers_uid=0
+Plugin sudoers_io sudoers.so
diff --git a/lib/util/regress/sudo_conf/test3.out.ok b/lib/util/regress/sudo_conf/test3.out.ok
new file mode 100644
index 0000000..3ff2284
--- /dev/null
+++ b/lib/util/regress/sudo_conf/test3.out.ok
@@ -0,0 +1,6 @@
+Set disable_coredump true
+Set group_source adaptive
+Set max_groups -1
+Set probe_interfaces true
+Plugin sudoers_policy sudoers.so sudoers_file=/etc/sudoers sudoers_mode=0400 sudoers_gid=0 sudoers_uid=0
+Plugin sudoers_io sudoers.so
diff --git a/lib/util/regress/sudo_conf/test4.err.ok b/lib/util/regress/sudo_conf/test4.err.ok
new file mode 100644
index 0000000..2d68831
--- /dev/null
+++ b/lib/util/regress/sudo_conf/test4.err.ok
@@ -0,0 +1 @@
+conf_test: invalid value for disable_coredump "foo" in regress/sudo_conf/test4.in, line 1
diff --git a/lib/util/regress/sudo_conf/test4.in b/lib/util/regress/sudo_conf/test4.in
new file mode 100644
index 0000000..a60236a
--- /dev/null
+++ b/lib/util/regress/sudo_conf/test4.in
@@ -0,0 +1 @@
+Set disable_coredump foo
diff --git a/lib/util/regress/sudo_conf/test4.out.ok b/lib/util/regress/sudo_conf/test4.out.ok
new file mode 100644
index 0000000..cfd8a08
--- /dev/null
+++ b/lib/util/regress/sudo_conf/test4.out.ok
@@ -0,0 +1,4 @@
+Set disable_coredump true
+Set group_source adaptive
+Set max_groups -1
+Set probe_interfaces true
diff --git a/lib/util/regress/sudo_conf/test5.err.ok b/lib/util/regress/sudo_conf/test5.err.ok
new file mode 100644
index 0000000..85ef46b
--- /dev/null
+++ b/lib/util/regress/sudo_conf/test5.err.ok
@@ -0,0 +1 @@
+conf_test: invalid max groups "0" in regress/sudo_conf/test5.in, line 1
diff --git a/lib/util/regress/sudo_conf/test5.in b/lib/util/regress/sudo_conf/test5.in
new file mode 100644
index 0000000..3a20495
--- /dev/null
+++ b/lib/util/regress/sudo_conf/test5.in
@@ -0,0 +1 @@
+Set max_groups 0
diff --git a/lib/util/regress/sudo_conf/test5.out.ok b/lib/util/regress/sudo_conf/test5.out.ok
new file mode 100644
index 0000000..cfd8a08
--- /dev/null
+++ b/lib/util/regress/sudo_conf/test5.out.ok
@@ -0,0 +1,4 @@
+Set disable_coredump true
+Set group_source adaptive
+Set max_groups -1
+Set probe_interfaces true
diff --git a/lib/util/regress/sudo_conf/test6.in b/lib/util/regress/sudo_conf/test6.in
new file mode 100644
index 0000000..537fa57
--- /dev/null
+++ b/lib/util/regress/sudo_conf/test6.in
@@ -0,0 +1 @@
+Set max_groups 16
diff --git a/lib/util/regress/sudo_conf/test6.out.ok b/lib/util/regress/sudo_conf/test6.out.ok
new file mode 100644
index 0000000..674ae38
--- /dev/null
+++ b/lib/util/regress/sudo_conf/test6.out.ok
@@ -0,0 +1,4 @@
+Set disable_coredump true
+Set group_source adaptive
+Set max_groups 16
+Set probe_interfaces true
diff --git a/lib/util/regress/sudo_conf/test7.in b/lib/util/regress/sudo_conf/test7.in
new file mode 100644
index 0000000..7438131
--- /dev/null
+++ b/lib/util/regress/sudo_conf/test7.in
@@ -0,0 +1,4 @@
+Debug sudo /var/log/sudo_debug all@info
+Debug sudo /var/log/sudo_debug util@debug
+Debug visudo /var/log/sudo_debug match@debug
+Debug sudoers.so /var/log/sudoers_debug match@debug,nss@info
diff --git a/lib/util/regress/sudo_conf/test7.out.ok b/lib/util/regress/sudo_conf/test7.out.ok
new file mode 100644
index 0000000..7ec856d
--- /dev/null
+++ b/lib/util/regress/sudo_conf/test7.out.ok
@@ -0,0 +1,8 @@
+Set disable_coredump true
+Set group_source adaptive
+Set max_groups -1
+Set probe_interfaces true
+Debug sudo /var/log/sudo_debug all@info
+Debug sudo /var/log/sudo_debug util@debug
+Debug visudo /var/log/sudo_debug match@debug
+Debug sudoers.so /var/log/sudoers_debug match@debug,nss@info
diff --git a/lib/util/regress/sudo_parseln/parseln_test.c b/lib/util/regress/sudo_parseln/parseln_test.c
new file mode 100644
index 0000000..9463767
--- /dev/null
+++ b/lib/util/regress/sudo_parseln/parseln_test.c
@@ -0,0 +1,64 @@
+/*
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2013 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sudo_compat.h>
+#include <sudo_util.h>
+
+sudo_dso_public int main(int argc, char *argv[]);
+
+/*
+ * Simple test driver for sudo_parseln().
+ * Behaves similarly to "cat -n" but with comment removal
+ * and line continuation.
+ */
+
+int
+main(int argc, char *argv[])
+{
+ unsigned int lineno = 0;
+ size_t linesize = 0;
+ char *line = NULL;
+ int ch;
+
+ initprogname(argc > 0 ? argv[0] : "parseln_test");
+
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch (ch) {
+ case 'v':
+ /* ignore */
+ break;
+ default:
+ fprintf(stderr, "usage: %s [-v]\n", getprogname());
+ return EXIT_FAILURE;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ while (sudo_parseln(&line, &linesize, &lineno, stdin, 0) != -1)
+ printf("%6u\t%s\n", lineno, line);
+ free(line);
+ return EXIT_SUCCESS;
+}
diff --git a/lib/util/regress/sudo_parseln/test1.in b/lib/util/regress/sudo_parseln/test1.in
new file mode 100644
index 0000000..8f417dd
--- /dev/null
+++ b/lib/util/regress/sudo_parseln/test1.in
@@ -0,0 +1,72 @@
+#
+# Sample /etc/sudo.conf file
+#
+# Format:
+# Plugin plugin_name plugin_path plugin_options ...
+# Path askpass /path/to/askpass
+# Path noexec /path/to/sudo_noexec.so
+# Debug sudo /var/log/sudo_debug all@warn
+# Set disable_coredump true
+#
+# Sudo plugins:
+#
+# The plugin_path is relative to ${prefix}/libexec unless fully qualified.
+# The plugin_name corresponds to a global symbol in the plugin
+# that contains the plugin interface structure.
+# The plugin_options are optional.
+#
+# The sudoers plugin is used by default if no Plugin lines are present.
+Plugin sudoers_policy sudoers.so
+Plugin sudoers_io sudoers.so
+
+#
+# Sudo askpass:
+#
+# An askpass helper program may be specified to provide a graphical
+# password prompt for "sudo -A" support. Sudo does not ship with its
+# own askpass program but can use the OpenSSH askpass.
+#
+# Use the OpenSSH askpass
+#Path askpass /usr/X11R6/bin/ssh-askpass
+#
+# Use the Gnome OpenSSH askpass
+#Path askpass /usr/libexec/openssh/gnome-ssh-askpass
+
+#
+# Sudo noexec:
+#
+# Path to a shared library containing replacements for the execv(),
+# execve() and fexecve() library functions that just return an error.
+# This is used to implement the "noexec" functionality on systems that
+# support LD_PRELOAD or its equivalent.
+# The compiled-in value is usually sufficient and should only be changed
+# if you rename or move the sudo_noexec.so file.
+#
+#Path noexec /usr/libexec/sudo_noexec.so
+
+#
+# Core dumps:
+#
+# By default, sudo disables core dumps while it is executing (they
+# are re-enabled for the command that is run).
+# To aid in debugging sudo problems, you may wish to enable core
+# dumps by setting "disable_coredump" to false.
+#
+#Set disable_coredump false
+
+#
+# User groups:
+#
+# Sudo passes the user's group list to the policy plugin.
+# If the user is a member of the maximum number of groups (usually 16),
+# sudo will query the group database directly to be sure to include
+# the full list of groups.
+#
+# On some systems, this can be expensive so the behavior is configurable.
+# The "group_source" setting has three possible values:
+# static - use the user's list of groups returned by the kernel.
+# dynamic - query the group database to find the list of groups.
+# adaptive - if user is in less than the maximum number of groups.
+# use the kernel list, else query the group database.
+#
+#Set group_source static
diff --git a/lib/util/regress/sudo_parseln/test1.out.ok b/lib/util/regress/sudo_parseln/test1.out.ok
new file mode 100644
index 0000000..c98ca77
--- /dev/null
+++ b/lib/util/regress/sudo_parseln/test1.out.ok
@@ -0,0 +1,72 @@
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19 Plugin sudoers_policy sudoers.so
+ 20 Plugin sudoers_io sudoers.so
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
diff --git a/lib/util/regress/sudo_parseln/test2.in b/lib/util/regress/sudo_parseln/test2.in
new file mode 100644
index 0000000..49166ee
--- /dev/null
+++ b/lib/util/regress/sudo_parseln/test2.in
@@ -0,0 +1,8 @@
+this \
+is all \
+one line
+# this is a comment, and does not get continued\
+trim the \
+ leading \
+ white \
+space
diff --git a/lib/util/regress/sudo_parseln/test2.out.ok b/lib/util/regress/sudo_parseln/test2.out.ok
new file mode 100644
index 0000000..d921968
--- /dev/null
+++ b/lib/util/regress/sudo_parseln/test2.out.ok
@@ -0,0 +1,3 @@
+ 3 this is all one line
+ 4
+ 8 trim the leading white space
diff --git a/lib/util/regress/sudo_parseln/test3.in b/lib/util/regress/sudo_parseln/test3.in
new file mode 100644
index 0000000..e372c07
--- /dev/null
+++ b/lib/util/regress/sudo_parseln/test3.in
@@ -0,0 +1 @@
+line continuation at EOF \
diff --git a/lib/util/regress/sudo_parseln/test3.out.ok b/lib/util/regress/sudo_parseln/test3.out.ok
new file mode 100644
index 0000000..2e8d16d
--- /dev/null
+++ b/lib/util/regress/sudo_parseln/test3.out.ok
@@ -0,0 +1 @@
+ 1 line continuation at EOF
diff --git a/lib/util/regress/sudo_parseln/test4.in b/lib/util/regress/sudo_parseln/test4.in
new file mode 100644
index 0000000..3583f3b
--- /dev/null
+++ b/lib/util/regress/sudo_parseln/test4.in
@@ -0,0 +1,4 @@
+line contin\
+uation raw
+line contin\
+ uation indented
diff --git a/lib/util/regress/sudo_parseln/test4.out.ok b/lib/util/regress/sudo_parseln/test4.out.ok
new file mode 100644
index 0000000..38afbeb
--- /dev/null
+++ b/lib/util/regress/sudo_parseln/test4.out.ok
@@ -0,0 +1,2 @@
+ 2 line continuation raw
+ 4 line continuation indented
diff --git a/lib/util/regress/sudo_parseln/test5.in b/lib/util/regress/sudo_parseln/test5.in
new file mode 100644
index 0000000..57ddad2
--- /dev/null
+++ b/lib/util/regress/sudo_parseln/test5.in
@@ -0,0 +1 @@
+\
diff --git a/lib/util/regress/sudo_parseln/test5.out.ok b/lib/util/regress/sudo_parseln/test5.out.ok
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lib/util/regress/sudo_parseln/test5.out.ok
diff --git a/lib/util/regress/sudo_parseln/test6.in b/lib/util/regress/sudo_parseln/test6.in
new file mode 100644
index 0000000..95cac84
--- /dev/null
+++ b/lib/util/regress/sudo_parseln/test6.in
@@ -0,0 +1,3 @@
+ leading and trailing white space
+ # a comment
+\
diff --git a/lib/util/regress/sudo_parseln/test6.out.ok b/lib/util/regress/sudo_parseln/test6.out.ok
new file mode 100644
index 0000000..340765e
--- /dev/null
+++ b/lib/util/regress/sudo_parseln/test6.out.ok
@@ -0,0 +1,2 @@
+ 1 leading and trailing white space
+ 2
diff --git a/lib/util/regress/tailq/hltq_test.c b/lib/util/regress/tailq/hltq_test.c
new file mode 100644
index 0000000..412d7a9
--- /dev/null
+++ b/lib/util/regress/tailq/hltq_test.c
@@ -0,0 +1,205 @@
+/*
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2013 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sudo_compat.h>
+#include <sudo_fatal.h>
+#include <sudo_queue.h>
+#include <sudo_util.h>
+
+sudo_dso_public int main(int argc, char *argv[]);
+
+/*
+ * Note: HLTQ_ENTRY is intentionally in the middle of the struct
+ * to catch bad assumptions in the PREV/NEXT macros.
+ */
+struct test_data {
+ int a;
+ HLTQ_ENTRY(test_data) entries;
+ char b;
+};
+
+TAILQ_HEAD(test_data_list, test_data);
+
+/*
+ * Simple tests for headless tail queue macros.
+ */
+int
+main(int argc, char *argv[])
+{
+ struct test_data d1, d2, d3;
+ struct test_data *hltq;
+ struct test_data_list tq;
+ int ch, errors = 0, ntests = 0;
+
+ initprogname(argc > 0 ? argv[0] : "hltq_test");
+
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch (ch) {
+ case 'v':
+ /* ignore */
+ break;
+ default:
+ fprintf(stderr, "usage: %s [-v]\n", getprogname());
+ return EXIT_FAILURE;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /*
+ * Initialize three data elements and concatenate them in order.
+ */
+ HLTQ_INIT(&d1, entries);
+ d1.a = 1;
+ d1.b = 'a';
+ if (HLTQ_FIRST(&d1) != &d1) {
+ sudo_warnx_nodebug("FAIL: HLTQ_FIRST(1 entry) doesn't return first element: got %p, expected %p", HLTQ_FIRST(&d1), &d1);
+ errors++;
+ }
+ ntests++;
+ if (HLTQ_LAST(&d1, test_data, entries) != &d1) {
+ sudo_warnx_nodebug("FAIL: HLTQ_LAST(1 entry) doesn't return first element: got %p, expected %p", HLTQ_LAST(&d1, test_data, entries), &d1);
+ errors++;
+ }
+ ntests++;
+ if (HLTQ_PREV(&d1, test_data, entries) != NULL) {
+ sudo_warnx_nodebug("FAIL: HLTQ_PREV(1 entry) doesn't return NULL: got %p", HLTQ_PREV(&d1, test_data, entries));
+ errors++;
+ }
+ ntests++;
+
+ HLTQ_INIT(&d2, entries);
+ d2.a = 2;
+ d2.b = 'b';
+
+ HLTQ_INIT(&d3, entries);
+ d3.a = 3;
+ d3.b = 'c';
+
+ HLTQ_CONCAT(&d1, &d2, entries);
+ HLTQ_CONCAT(&d1, &d3, entries);
+ hltq = &d1;
+
+ /*
+ * Verify that HLTQ_FIRST, HLTQ_LAST, HLTQ_NEXT, HLTQ_PREV
+ * work as expected.
+ */
+ if (HLTQ_FIRST(hltq) != &d1) {
+ sudo_warnx_nodebug("FAIL: HLTQ_FIRST(3 entries) doesn't return first element: got %p, expected %p", HLTQ_FIRST(hltq), &d1);
+ errors++;
+ }
+ ntests++;
+ if (HLTQ_LAST(hltq, test_data, entries) != &d3) {
+ sudo_warnx_nodebug("FAIL: HLTQ_LAST(3 entries) doesn't return third element: got %p, expected %p", HLTQ_LAST(hltq, test_data, entries), &d3);
+ errors++;
+ }
+ ntests++;
+
+ if (HLTQ_NEXT(&d1, entries) != &d2) {
+ sudo_warnx_nodebug("FAIL: HLTQ_NEXT(&d1) doesn't return &d2: got %p, expected %p", HLTQ_NEXT(&d1, entries), &d2);
+ errors++;
+ }
+ ntests++;
+ if (HLTQ_NEXT(&d2, entries) != &d3) {
+ sudo_warnx_nodebug("FAIL: HLTQ_NEXT(&d2) doesn't return &d3: got %p, expected %p", HLTQ_NEXT(&d2, entries), &d3);
+ errors++;
+ }
+ ntests++;
+ if (HLTQ_NEXT(&d3, entries) != NULL) {
+ sudo_warnx_nodebug("FAIL: HLTQ_NEXT(&d3) doesn't return NULL: got %p", HLTQ_NEXT(&d3, entries));
+ errors++;
+ }
+ ntests++;
+
+ if (HLTQ_PREV(&d1, test_data, entries) != NULL) {
+ sudo_warnx_nodebug("FAIL: HLTQ_PREV(&d1) doesn't return NULL: got %p", HLTQ_PREV(&d1, test_data, entries));
+ errors++;
+ }
+ ntests++;
+ if (HLTQ_PREV(&d2, test_data, entries) != &d1) {
+ sudo_warnx_nodebug("FAIL: HLTQ_PREV(&d2) doesn't return &d1: got %p, expected %p", HLTQ_PREV(&d2, test_data, entries), &d1);
+ errors++;
+ }
+ ntests++;
+ if (HLTQ_PREV(&d3, test_data, entries) != &d2) {
+ sudo_warnx_nodebug("FAIL: HLTQ_PREV(&d3) doesn't return &d2: got %p, expected %p", HLTQ_PREV(&d3, test_data, entries), &d2);
+ errors++;
+ }
+ ntests++;
+
+ /* Test conversion to TAILQ. */
+ HLTQ_TO_TAILQ(&tq, hltq, entries);
+
+ if (TAILQ_FIRST(&tq) != &d1) {
+ sudo_warnx_nodebug("FAIL: TAILQ_FIRST(&tq) doesn't return first element: got %p, expected %p", TAILQ_FIRST(&tq), &d1);
+ errors++;
+ }
+ ntests++;
+ if (TAILQ_LAST(&tq, test_data_list) != &d3) {
+ sudo_warnx_nodebug("FAIL: TAILQ_LAST(&tq) doesn't return third element: got %p, expected %p", TAILQ_LAST(&tq, test_data_list), &d3);
+ errors++;
+ }
+ ntests++;
+
+ if (TAILQ_NEXT(&d1, entries) != &d2) {
+ sudo_warnx_nodebug("FAIL: TAILQ_NEXT(&d1) doesn't return &d2: got %p, expected %p", TAILQ_NEXT(&d1, entries), &d2);
+ errors++;
+ }
+ ntests++;
+ if (TAILQ_NEXT(&d2, entries) != &d3) {
+ sudo_warnx_nodebug("FAIL: TAILQ_NEXT(&d2) doesn't return &d3: got %p, expected %p", TAILQ_NEXT(&d2, entries), &d3);
+ errors++;
+ }
+ ntests++;
+ if (TAILQ_NEXT(&d3, entries) != NULL) {
+ sudo_warnx_nodebug("FAIL: TAILQ_NEXT(&d3) doesn't return NULL: got %p", TAILQ_NEXT(&d3, entries));
+ errors++;
+ }
+ ntests++;
+
+ if (TAILQ_PREV(&d1, test_data_list, entries) != NULL) {
+ sudo_warnx_nodebug("FAIL: TAILQ_PREV(&d1) doesn't return NULL: got %p", TAILQ_PREV(&d1, test_data_list, entries));
+ errors++;
+ }
+ ntests++;
+ if (TAILQ_PREV(&d2, test_data_list, entries) != &d1) {
+ sudo_warnx_nodebug("FAIL: TAILQ_PREV(&d2) doesn't return &d1: got %p, expected %p", TAILQ_PREV(&d2, test_data_list, entries), &d1);
+ errors++;
+ }
+ ntests++;
+ if (TAILQ_PREV(&d3, test_data_list, entries) != &d2) {
+ sudo_warnx_nodebug("FAIL: TAILQ_PREV(&d3) doesn't return &d2: got %p, expected %p", TAILQ_PREV(&d3, test_data_list, entries), &d2);
+ errors++;
+ }
+ ntests++;
+
+ if (ntests != 0) {
+ printf("%s: %d tests run, %d errors, %d%% success rate\n",
+ getprogname(), ntests, errors, (ntests - errors) * 100 / ntests);
+ }
+
+ return errors;
+}
diff --git a/lib/util/regress/uuid/uuid_test.c b/lib/util/regress/uuid/uuid_test.c
new file mode 100644
index 0000000..411266c
--- /dev/null
+++ b/lib/util/regress/uuid/uuid_test.c
@@ -0,0 +1,105 @@
+/*
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2021 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#if defined(HAVE_STDINT_H)
+# include <stdint.h>
+#elif defined(HAVE_INTTYPES_H)
+# include <inttypes.h>
+#endif
+#include <string.h>
+#include <unistd.h>
+
+#define SUDO_ERROR_WRAP 0
+
+#include <sudo_compat.h>
+#include <sudo_fatal.h>
+#include <sudo_util.h>
+
+sudo_dso_public int main(int argc, char *argv[]);
+
+/*
+ * Test that sudo_uuid_create() generates a variant 1, version 4 uuid.
+ */
+
+/* From RFC 4122. */
+struct uuid {
+ uint32_t time_low;
+ uint16_t time_mid;
+ uint16_t time_hi_and_version;
+ uint8_t clock_seq_hi_and_reserved;
+ uint8_t clock_seq_low;
+ uint8_t node[6];
+};
+
+int
+main(int argc, char *argv[])
+{
+ int ch, errors = 0, ntests = 0;
+ union {
+ struct uuid id;
+ unsigned char u8[16];
+ } uuid;
+
+ initprogname(argc > 0 ? argv[0] : "uuid_test");
+
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch (ch) {
+ case 'v':
+ /* ignore */
+ break;
+ default:
+ fprintf(stderr, "usage: %s [-v]\n", getprogname());
+ return EXIT_FAILURE;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* Do 16 passes. */
+ for (ntests = 0; ntests < 16; ntests++) {
+ sudo_uuid_create(uuid.u8);
+
+ /* Variant: two most significant bits (6 and 7) are 0 and 1. */
+ if (ISSET(uuid.id.clock_seq_hi_and_reserved, (1 << 6))) {
+ sudo_warnx("uuid bit 6 set, should be clear");
+ errors++;
+ continue;
+ }
+ if (!ISSET(uuid.id.clock_seq_hi_and_reserved, (1 << 7))) {
+ sudo_warnx("uuid bit 7 clear, should be set");
+ errors++;
+ continue;
+ }
+
+ /* Version: bits 12-15 are 0010. */
+ if ((uuid.id.time_hi_and_version & 0xf000) != 0x4000) {
+ sudo_warnx("bad version: 0x%x", uuid.id.time_hi_and_version & 0xf000);
+ errors++;
+ continue;
+ }
+ }
+
+ if (ntests != 0) {
+ printf("%s: %d tests run, %d errors, %d%% success rate\n",
+ getprogname(), ntests, errors, (ntests - errors) * 100 / ntests);
+ }
+ return errors;
+}