From 199a594f43e804379c05dfeba27fee6854193fad Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Mon, 20 Feb 2017 16:44:12 -0700 Subject: [PATCH] Add support for using the message digest functions in OpenSSL instead of sudo's own SHA2 implementation. --- INSTALL | 6 ++ MANIFEST | 1 + configure | 150 ++++++++++++++++++++++++--- configure.ac | 52 +++++++--- mkdep.pl | 1 + plugins/sudoers/Makefile.in | 41 +++++--- plugins/sudoers/filedigest_openssl.c | 133 ++++++++++++++++++++++++ 7 files changed, 341 insertions(+), 43 deletions(-) create mode 100644 plugins/sudoers/filedigest_openssl.c diff --git a/INSTALL b/INSTALL index fc24ca873..b2fbebf63 100644 --- a/INSTALL +++ b/INSTALL @@ -515,6 +515,12 @@ Authentication options: gss_krb5_ccache_name() provides a better API to do this it is not supported by all Kerberos V and SASL combinations. + --enable-openssl[=DIR] + Use OpenSSL's SHA-2 message digest functions instead of the + ones bundled with sudo (or in the system's C library). + If specified, DIR should contain include and lib directories + with openssl/sha.h and libcrypto respectively. + Development options: --enable-env-debug Enable debugging of the environment setting functions. This diff --git a/MANIFEST b/MANIFEST index f57694395..d2a026075 100644 --- a/MANIFEST +++ b/MANIFEST @@ -264,6 +264,7 @@ plugins/sudoers/digestname.c plugins/sudoers/editor.c plugins/sudoers/env.c plugins/sudoers/filedigest.c +plugins/sudoers/filedigest_openssl.c plugins/sudoers/find_path.c plugins/sudoers/gc.c plugins/sudoers/gentime.c diff --git a/configure b/configure index 13330a720..d20a4a173 100755 --- a/configure +++ b/configure @@ -722,6 +722,7 @@ timeout vardir rundir iolog_dir +FILEDIGEST exampledir TMPFILES_D COMPAT_EXP @@ -946,6 +947,7 @@ enable_zlib enable_env_reset enable_warnings enable_werror +enable_openssl enable_hardening enable_pie enable_asan @@ -1621,6 +1623,8 @@ Optional Features: --enable-env-reset Whether to enable environment resetting by default. --enable-warnings Whether to enable compiler warnings --enable-werror Whether to enable the -Werror compiler option + --enable-openssl Use OpenSSL's message digest functions instead of + sudo's --disable-hardening Do not use compiler/linker exploit mitigation options --enable-pie Build sudo as a position independent executable. @@ -3043,6 +3047,7 @@ $as_echo "$as_me: Configuring Sudo version $PACKAGE_VERSION" >&6;} + # @@ -3089,6 +3094,7 @@ secure_path="not set" pam_session=on pam_login_service=sudo PLUGINDIR=/usr/local/libexec/sudo +FILEDIGEST=filedigest.lo # # End initial values for man page substitution # @@ -6338,6 +6344,120 @@ $as_echo "$as_me: WARNING: Ignoring unknown argument to --enable-werror: $enable fi +# Check whether --enable-openssl was given. +if test "${enable_openssl+set}" = set; then : + enableval=$enable_openssl; case $enableval in + no) ;; + *) LIBMD="-lcrypto" + FILEDIGEST=filedigest_openssl.lo + if test "$enableval" != "yes"; then + +if ${CPPFLAGS+:} false; then : + + case " $CPPFLAGS " in #( + *" -I${enableval}/include "*) : + { { $as_echo "$as_me:${as_lineno-$LINENO}: : CPPFLAGS already contains -I\${enableval}/include"; } >&5 + (: CPPFLAGS already contains -I${enableval}/include) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } ;; #( + *) : + + as_fn_append CPPFLAGS " -I${enableval}/include" + { { $as_echo "$as_me:${as_lineno-$LINENO}: : CPPFLAGS=\"\$CPPFLAGS\""; } >&5 + (: CPPFLAGS="$CPPFLAGS") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + ;; +esac + +else + + CPPFLAGS=-I${enableval}/include + { { $as_echo "$as_me:${as_lineno-$LINENO}: : CPPFLAGS=\"\$CPPFLAGS\""; } >&5 + (: CPPFLAGS="$CPPFLAGS") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + +fi + + + +if ${SUDOERS_LDFLAGS+:} false; then : + + case " $SUDOERS_LDFLAGS " in #( + *" -L${enableval}/lib "*) : + { { $as_echo "$as_me:${as_lineno-$LINENO}: : SUDOERS_LDFLAGS already contains -L\${enableval}/lib"; } >&5 + (: SUDOERS_LDFLAGS already contains -L${enableval}/lib) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } ;; #( + *) : + + as_fn_append SUDOERS_LDFLAGS " -L${enableval}/lib" + { { $as_echo "$as_me:${as_lineno-$LINENO}: : SUDOERS_LDFLAGS=\"\$SUDOERS_LDFLAGS\""; } >&5 + (: SUDOERS_LDFLAGS="$SUDOERS_LDFLAGS") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + ;; +esac + +else + + SUDOERS_LDFLAGS=-L${enableval}/lib + { { $as_echo "$as_me:${as_lineno-$LINENO}: : SUDOERS_LDFLAGS=\"\$SUDOERS_LDFLAGS\""; } >&5 + (: SUDOERS_LDFLAGS="$SUDOERS_LDFLAGS") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + +fi + + if test X"$enable_rpath" = X"yes"; then + +if ${SUDOERS_LDFLAGS_R+:} false; then : + + case " $SUDOERS_LDFLAGS_R " in #( + *" -R${enableval}/lib "*) : + { { $as_echo "$as_me:${as_lineno-$LINENO}: : SUDOERS_LDFLAGS_R already contains -R\${enableval}/lib"; } >&5 + (: SUDOERS_LDFLAGS_R already contains -R${enableval}/lib) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } ;; #( + *) : + + as_fn_append SUDOERS_LDFLAGS_R " -R${enableval}/lib" + { { $as_echo "$as_me:${as_lineno-$LINENO}: : SUDOERS_LDFLAGS_R=\"\$SUDOERS_LDFLAGS_R\""; } >&5 + (: SUDOERS_LDFLAGS_R="$SUDOERS_LDFLAGS_R") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + ;; +esac + +else + + SUDOERS_LDFLAGS_R=-R${enableval}/lib + { { $as_echo "$as_me:${as_lineno-$LINENO}: : SUDOERS_LDFLAGS_R=\"\$SUDOERS_LDFLAGS_R\""; } >&5 + (: SUDOERS_LDFLAGS_R="$SUDOERS_LDFLAGS_R") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + +fi + + fi + + fi + ;; + esac + +fi + + # Check whether --enable-hardening was given. if test "${enable_hardening+set}" = set; then : enableval=$enable_hardening; @@ -20419,12 +20539,14 @@ fi fi -FOUND_SHA2=no -ac_fn_c_check_header_mongrel "$LINENO" "sha2.h" "ac_cv_header_sha2_h" "$ac_includes_default" +# Look for sha2 functions if not using openssl +if test "$FILEDIGEST" = "filedigest.lo"; then + FOUND_SHA2=no + ac_fn_c_check_header_mongrel "$LINENO" "sha2.h" "ac_cv_header_sha2_h" "$ac_includes_default" if test "x$ac_cv_header_sha2_h" = xyes; then : - FOUND_SHA2=yes - for ac_func in SHA224Update + FOUND_SHA2=yes + for ac_func in SHA224Update do : ac_fn_c_check_func "$LINENO" "SHA224Update" "ac_cv_func_SHA224Update" if test "x$ac_cv_func_SHA224Update" = xyes; then : @@ -20467,8 +20589,8 @@ $as_echo "#define SHA2_VOID_PTR 1" >>confdefs.h else - # On some systems, SHA224Update is in libmd - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SHA224Update in -lmd" >&5 + # On some systems, SHA224Update is in libmd + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SHA224Update in -lmd" >&5 $as_echo_n "checking for SHA224Update in -lmd... " >&6; } if ${ac_cv_lib_md_SHA224Update+:} false; then : $as_echo_n "(cached) " >&6 @@ -20506,9 +20628,9 @@ fi $as_echo "$ac_cv_lib_md_SHA224Update" >&6; } if test "x$ac_cv_lib_md_SHA224Update" = xyes; then : - $as_echo "#define HAVE_SHA224UPDATE 1" >>confdefs.h + $as_echo "#define HAVE_SHA224UPDATE 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the data argument of SHA224Update() is void *" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the data argument of SHA224Update() is void *" >&5 $as_echo_n "checking whether the data argument of SHA224Update() is void *... " >&6; } if ${sudo_cv_func_sha2_void_ptr+:} false; then : $as_echo_n "(cached) " >&6 @@ -20542,12 +20664,12 @@ $as_echo "#define SHA2_VOID_PTR 1" >>confdefs.h fi - LIBMD="-lmd" + LIBMD="-lmd" else - # Does not have SHA224Update - FOUND_SHA2=no + # Does not have SHA224Update + FOUND_SHA2=no fi @@ -20559,8 +20681,8 @@ done fi -if test X"$FOUND_SHA2" = X"no"; then - case " $LIBOBJS " in + if test X"$FOUND_SHA2" = X"no"; then + case " $LIBOBJS " in *" sha2.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS sha2.$ac_objext" ;; @@ -20572,6 +20694,8 @@ esac " done + SUDOERS_TEST_PROGS="${SUDOERS_TEST_PROGS}${SUDOERS_TEST_PROGS+ }check_digest" + fi fi for ac_func in vsyslog do : diff --git a/configure.ac b/configure.ac index 763419473..2b3904244 100644 --- a/configure.ac +++ b/configure.ac @@ -96,6 +96,7 @@ AC_SUBST([RC_LINK]) AC_SUBST([COMPAT_EXP]) AC_SUBST([TMPFILES_D]) AC_SUBST([exampledir]) +AC_SUBST([FILEDIGEST]) dnl dnl Variables that get substituted in docs (not overridden by environment) dnl @@ -183,6 +184,7 @@ secure_path="not set" pam_session=on pam_login_service=sudo PLUGINDIR=/usr/local/libexec/sudo +FILEDIGEST=filedigest.lo # # End initial values for man page substitution # @@ -1449,6 +1451,20 @@ AC_ARG_ENABLE(werror, esac ]) +AC_ARG_ENABLE(openssl, +[AS_HELP_STRING([--enable-openssl], [Use OpenSSL's message digest functions instead of sudo's])], +[ case $enableval in + no) ;; + *) LIBMD="-lcrypto" + FILEDIGEST=filedigest_openssl.lo + if test "$enableval" != "yes"; then + AX_APPEND_FLAG([-I${enableval}/include], [CPPFLAGS]) + SUDO_APPEND_LIBPATH(SUDOERS_LDFLAGS, [${enableval}/lib]) + fi + ;; + esac +]) + AC_ARG_ENABLE(hardening, [AS_HELP_STRING([--disable-hardening], [Do not use compiler/linker exploit mitigation options])], [], [enable_hardening=yes]) @@ -2673,24 +2689,28 @@ AC_INCLUDES_DEFAULT AC_CHECK_MEMBER([struct stat.st_mtim], [AC_DEFINE(HAVE_ST_MTIM)] [AC_CHECK_MEMBER([struct stat.st_mtim.st__tim], AC_DEFINE(HAVE_ST__TIM))], [AC_CHECK_MEMBER([struct stat.st_mtimespec], AC_DEFINE([HAVE_ST_MTIMESPEC]))]) -FOUND_SHA2=no -AC_CHECK_HEADER([sha2.h], [ - FOUND_SHA2=yes - AC_CHECK_FUNCS([SHA224Update], [SUDO_FUNC_SHA2_VOID_PTR], [ - # On some systems, SHA224Update is in libmd - AC_CHECK_LIB(md, SHA224Update, [ - AC_DEFINE(HAVE_SHA224UPDATE) - SUDO_FUNC_SHA2_VOID_PTR - LIBMD="-lmd" - ], [ - # Does not have SHA224Update - FOUND_SHA2=no +# Look for sha2 functions if not using openssl +if test "$FILEDIGEST" = "filedigest.lo"; then + FOUND_SHA2=no + AC_CHECK_HEADER([sha2.h], [ + FOUND_SHA2=yes + AC_CHECK_FUNCS([SHA224Update], [SUDO_FUNC_SHA2_VOID_PTR], [ + # On some systems, SHA224Update is in libmd + AC_CHECK_LIB(md, SHA224Update, [ + AC_DEFINE(HAVE_SHA224UPDATE) + SUDO_FUNC_SHA2_VOID_PTR + LIBMD="-lmd" + ], [ + # Does not have SHA224Update + FOUND_SHA2=no + ]) ]) ]) -]) -if test X"$FOUND_SHA2" = X"no"; then - AC_LIBOBJ(sha2) - SUDO_APPEND_COMPAT_EXP(sudo_SHA224Final sudo_SHA224Init sudo_SHA224Pad sudo_SHA224Transform sudo_SHA224Update sudo_SHA256Final sudo_SHA256Init sudo_SHA256Pad sudo_SHA256Transform sudo_SHA256Update sudo_SHA384Final sudo_SHA384Init sudo_SHA384Pad sudo_SHA384Transform sudo_SHA384Update sudo_SHA512Final sudo_SHA512Init sudo_SHA512Pad sudo_SHA512Transform sudo_SHA512Update) + if test X"$FOUND_SHA2" = X"no"; then + AC_LIBOBJ(sha2) + SUDO_APPEND_COMPAT_EXP(sudo_SHA224Final sudo_SHA224Init sudo_SHA224Pad sudo_SHA224Transform sudo_SHA224Update sudo_SHA256Final sudo_SHA256Init sudo_SHA256Pad sudo_SHA256Transform sudo_SHA256Update sudo_SHA384Final sudo_SHA384Init sudo_SHA384Pad sudo_SHA384Transform sudo_SHA384Update sudo_SHA512Final sudo_SHA512Init sudo_SHA512Pad sudo_SHA512Transform sudo_SHA512Update) + SUDOERS_TEST_PROGS="${SUDOERS_TEST_PROGS}${SUDOERS_TEST_PROGS+ }check_digest" + fi fi AC_CHECK_FUNCS([vsyslog], [], [ AC_LIBOBJ(vsyslog) diff --git a/mkdep.pl b/mkdep.pl index 5a83c7f92..26f0ba602 100755 --- a/mkdep.pl +++ b/mkdep.pl @@ -70,6 +70,7 @@ sub mkdep { $makefile =~ s:\@SUDOERS_OBJS\@:bsm_audit.lo linux_audit.lo ldap.lo solaris_audit.lo sssd.lo:; # XXX - fill in AUTH_OBJS from contents of the auth dir instead $makefile =~ s:\@AUTH_OBJS\@:afs.lo aix_auth.lo bsdauth.lo dce.lo fwtk.lo getspwuid.lo kerb5.lo pam.lo passwd.lo rfc1938.lo secureware.lo securid5.lo sia.lo:; + $makefile =~ s:\@FILEDIGEST\@:filedigest.lo filedigest_openssl.lo:; $makefile =~ s:\@LTLIBOBJS\@:closefrom.lo fnmatch.lo getaddrinfo.lo getcwd.lo getgrouplist.lo getline.lo getopt_long.lo glob.lo inet_ntop_lo inet_pton.lo isblank.lo memrchr.lo memset_s.lo mksiglist.lo mksigname.lo mktemp.lo nanosleep.lo pw_dup.lo reallocarray.lo sha2.lo sig2str.lo siglist.lo signame.lo snprintf.lo strlcat.lo strlcpy.lo strndup.lo strnlen.lo strsignal.lo strtonum.lo utimens.lo vsyslog.lo:; # Parse OBJS lines diff --git a/plugins/sudoers/Makefile.in b/plugins/sudoers/Makefile.in index f60361a37..6413c09e3 100644 --- a/plugins/sudoers/Makefile.in +++ b/plugins/sudoers/Makefile.in @@ -145,13 +145,13 @@ SHELL = @SHELL@ PROGS = sudoers.la visudo sudoreplay testsudoers -TEST_PROGS = check_iolog_path check_fill check_wrap check_addr check_digest \ - check_base64 check_gentime check_hexchar @SUDOERS_TEST_PROGS@ +TEST_PROGS = check_iolog_path check_fill check_wrap check_addr check_base64 \ + check_gentime check_hexchar @SUDOERS_TEST_PROGS@ AUTH_OBJS = sudo_auth.lo @AUTH_OBJS@ LIBPARSESUDOERS_OBJS = alias.lo audit.lo base64.lo defaults.lo digestname.lo \ - filedigest.lo gentime.lo gmtoff.lo gram.lo hexchar.lo \ + @FILEDIGEST@ gentime.lo gmtoff.lo gram.lo hexchar.lo \ match.lo match_addr.lo pwutil.lo pwutil_impl.lo \ rcstr.lo redblack.lo sudoers_debug.lo timeout.lo \ timestr.lo toke.lo toke_util.lo @@ -377,15 +377,17 @@ check: $(TEST_PROGS) visudo testsudoers mkdir -p regress/parser; \ ./check_addr $(srcdir)/regress/parser/check_addr.in || rval=`expr $$rval + $$?`; \ ./check_base64 || rval=`expr $$rval + $$?`; \ - ./check_digest > regress/parser/check_digest.out; \ - diff regress/parser/check_digest.out $(srcdir)/regress/parser/check_digest.out.ok || rval=`expr $$rval + $$?`; \ + if test -f check_digest; then \ + ./check_digest > regress/parser/check_digest.out; \ + diff regress/parser/check_digest.out $(srcdir)/regress/parser/check_digest.out.ok || rval=`expr $$rval + $$?`; \ + fi; \ ./check_fill || rval=`expr $$rval + $$?`; \ ./check_gentime || rval=`expr $$rval + $$?`; \ ./check_hexchar || rval=`expr $$rval + $$?`; \ ./check_iolog_path $(srcdir)/regress/iolog_path/data || rval=`expr $$rval + $$?`; \ - case "$(TEST_PROGS)" in \ - *check_symbols*) ./check_symbols .libs/sudoers.so $(shlib_exp) || rval=`expr $$rval + $$?`;; \ - esac; \ + if test -f check_symbols; then \ + ./check_symbols .libs/sudoers.so $(shlib_exp) || rval=`expr $$rval + $$?`; \ + fi; \ mkdir -p regress/logging; \ ./check_wrap $(srcdir)/regress/logging/check_wrap.in > regress/logging/check_wrap.out; \ diff regress/logging/check_wrap.out $(srcdir)/regress/logging/check_wrap.out.ok || rval=`expr $$rval + $$?`; \ @@ -690,6 +692,17 @@ filedigest.lo: $(srcdir)/filedigest.c $(devdir)/def_data.h \ $(srcdir)/sudoers_debug.h $(top_builddir)/config.h \ $(top_builddir)/pathnames.h $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/filedigest.c +filedigest_openssl.lo: $(srcdir)/filedigest_openssl.c $(devdir)/def_data.h \ + $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \ + $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \ + $(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h \ + $(incdir)/sudo_util.h $(srcdir)/defaults.h \ + $(srcdir)/logging.h $(srcdir)/parse.h \ + $(srcdir)/sudo_nss.h $(srcdir)/sudoers.h \ + $(srcdir)/sudoers_debug.h $(top_builddir)/config.h \ + $(top_builddir)/pathnames.h + $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/filedigest_openssl.c find_path.lo: $(srcdir)/find_path.c $(devdir)/def_data.h \ $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \ $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \ @@ -867,12 +880,12 @@ logwrap.lo: $(srcdir)/logwrap.c $(devdir)/def_data.h \ logwrap.o: logwrap.lo match.lo: $(srcdir)/match.c $(devdir)/def_data.h $(devdir)/gram.h \ $(incdir)/compat/fnmatch.h $(incdir)/compat/glob.h \ - $(incdir)/compat/sha2.h $(incdir)/compat/stdbool.h \ - $(incdir)/sudo_compat.h $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \ - $(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \ - $(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \ - $(srcdir)/defaults.h $(srcdir)/logging.h $(srcdir)/parse.h \ - $(srcdir)/sudo_nss.h $(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \ + $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \ + $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h $(incdir)/sudo_fatal.h \ + $(incdir)/sudo_gettext.h $(incdir)/sudo_plugin.h \ + $(incdir)/sudo_queue.h $(incdir)/sudo_util.h $(srcdir)/defaults.h \ + $(srcdir)/logging.h $(srcdir)/parse.h $(srcdir)/sudo_nss.h \ + $(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \ $(top_builddir)/config.h $(top_builddir)/pathnames.h $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/match.c match_addr.lo: $(srcdir)/match_addr.c $(devdir)/def_data.h \ diff --git a/plugins/sudoers/filedigest_openssl.c b/plugins/sudoers/filedigest_openssl.c new file mode 100644 index 000000000..5c4ae9cfa --- /dev/null +++ b/plugins/sudoers/filedigest_openssl.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2017 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include + +#include +#include +#ifdef HAVE_STRING_H +# include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +# include +#endif /* HAVE_STRINGS_H */ +#include +#include +#include + +#include + +#include "sudoers.h" +#include "parse.h" + +union ANY_CTX { + SHA256_CTX sha256; + SHA512_CTX sha512; +}; + +static struct digest_function { + const unsigned int digest_len; + int (*init)(union ANY_CTX *); + int (*update)(union ANY_CTX *, const void *, size_t); + int (*final)(unsigned char *, union ANY_CTX *); +} digest_functions[] = { + { + SHA224_DIGEST_LENGTH, + (int (*)(union ANY_CTX *))SHA224_Init, + (int (*)(union ANY_CTX *, const void *, size_t))SHA224_Update, + (int (*)(unsigned char *, union ANY_CTX *))SHA224_Final + }, { + SHA256_DIGEST_LENGTH, + (int (*)(union ANY_CTX *))SHA256_Init, + (int (*)(union ANY_CTX *, const void *, size_t))SHA256_Update, + (int (*)(unsigned char *, union ANY_CTX *))SHA256_Final + }, { + SHA384_DIGEST_LENGTH, + (int (*)(union ANY_CTX *))SHA384_Init, + (int (*)(union ANY_CTX *, const void *, size_t))SHA384_Update, + (int (*)(unsigned char *, union ANY_CTX *))SHA384_Final + }, { + SHA512_DIGEST_LENGTH, + (int (*)(union ANY_CTX *))SHA512_Init, + (int (*)(union ANY_CTX *, const void *, size_t))SHA512_Update, + (int (*)(unsigned char *, union ANY_CTX *))SHA512_Final + }, { + 0 + } +}; + +unsigned char * +sudo_filedigest(int fd, const char *file, int digest_type, size_t *digest_len) +{ + struct digest_function *func = NULL; + unsigned char *file_digest = NULL; + unsigned char buf[32 * 1024]; + size_t nread; + union ANY_CTX ctx; + int i, fd2; + FILE *fp = NULL; + debug_decl(sudo_filedigest, SUDOERS_DEBUG_UTIL) + + for (i = 0; digest_functions[i].digest_len != 0; i++) { + if (digest_type == i) { + func = &digest_functions[i]; + break; + } + } + if (func == NULL) { + sudo_warnx(U_("unsupported digest type %d for %s"), digest_type, file); + goto bad; + } + + if ((fd2 = dup(fd)) == -1) { + sudo_debug_printf(SUDO_DEBUG_INFO, "unable to dup %s: %s", + file, strerror(errno)); + goto bad; + } + if ((fp = fdopen(fd2, "r")) == NULL) { + sudo_debug_printf(SUDO_DEBUG_INFO, "unable to fdopen %s: %s", + file, strerror(errno)); + close(fd2); + goto bad; + } + if ((file_digest = malloc(func->digest_len)) == NULL) { + sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + goto bad; + } + + func->init(&ctx); + while ((nread = fread(buf, 1, sizeof(buf), fp)) != 0) { + func->update(&ctx, buf, nread); + } + if (ferror(fp)) { + sudo_warnx(U_("%s: read error"), file); + goto bad; + } + func->final(file_digest, &ctx); + fclose(fp); + + *digest_len = func->digest_len; + debug_return_ptr(file_digest); +bad: + free(file_digest); + if (fp != NULL) + fclose(fp); + debug_return_ptr(NULL); +} -- 2.40.0