diff options
Diffstat (limited to '')
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; +} |