]> granicus.if.org Git - sudo/commitdiff
Move the file digest code out of match.c and into filedigest.c.
authorTodd C. Miller <Todd.Miller@courtesan.com>
Mon, 20 Feb 2017 23:44:12 +0000 (16:44 -0700)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Mon, 20 Feb 2017 23:44:12 +0000 (16:44 -0700)
Inspired by RedHat changes that used libgcrypt.
Also add digest_type_to_name() to map a sudo digest type (int)
to a name (string) and use it.

MANIFEST
plugins/sudoers/Makefile.in
plugins/sudoers/digestname.c [new file with mode: 0644]
plugins/sudoers/filedigest.c [new file with mode: 0644]
plugins/sudoers/ldap.c
plugins/sudoers/match.c
plugins/sudoers/parse.h
plugins/sudoers/sssd.c
plugins/sudoers/visudo_json.c

index bba1c5c4320ca158039252e9c0c86397d46bc9a4..f57694395eda360b5fc2cf7c211d92c536e654e9 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -260,8 +260,10 @@ plugins/sudoers/def_data.h
 plugins/sudoers/def_data.in
 plugins/sudoers/defaults.c
 plugins/sudoers/defaults.h
+plugins/sudoers/digestname.c
 plugins/sudoers/editor.c
 plugins/sudoers/env.c
+plugins/sudoers/filedigest.c
 plugins/sudoers/find_path.c
 plugins/sudoers/gc.c
 plugins/sudoers/gentime.c
index f8f90b6195eea54ff4a6ea149a9b9a801a0ecf1f..f60361a370471d48152fec01c122ff9f3a0490ec 100644 (file)
@@ -150,11 +150,11 @@ TEST_PROGS = check_iolog_path check_fill check_wrap check_addr check_digest \
 
 AUTH_OBJS = sudo_auth.lo @AUTH_OBJS@
 
-LIBPARSESUDOERS_OBJS = alias.lo audit.lo base64.lo defaults.lo gentime.lo \
-                      hexchar.lo gmtoff.lo gram.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
+LIBPARSESUDOERS_OBJS = alias.lo audit.lo base64.lo defaults.lo digestname.lo \
+                      filedigest.lo 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
 
 SUDOERS_OBJS = $(AUTH_OBJS) boottime.lo check.lo editor.lo env.lo find_path.lo \
               gc.lo goodpath.lo group_plugin.lo interfaces.lo iolog.lo \
@@ -656,6 +656,11 @@ defaults.lo: $(srcdir)/defaults.c $(devdir)/def_data.c $(devdir)/def_data.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)/defaults.c
+digestname.lo: $(srcdir)/digestname.c $(incdir)/compat/stdbool.h \
+               $(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \
+               $(incdir)/sudo_queue.h $(srcdir)/parse.h \
+               $(srcdir)/sudoers_debug.h $(top_builddir)/config.h
+       $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/digestname.c
 editor.lo: $(srcdir)/editor.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 \
@@ -674,6 +679,17 @@ env.lo: $(srcdir)/env.c $(devdir)/def_data.h $(incdir)/compat/stdbool.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)/env.c
+filedigest.lo: $(srcdir)/filedigest.c $(devdir)/def_data.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 $(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
 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 \
diff --git a/plugins/sudoers/digestname.c b/plugins/sudoers/digestname.c
new file mode 100644 (file)
index 0000000..e7b8373
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2017 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <stdio.h>
+
+#include "sudo_compat.h"
+#include "sudoers_debug.h"
+#include "parse.h"
+
+const char *
+digest_type_to_name(int digest_type)
+{
+    const char *digest_name;
+    debug_decl(digest_type_to_name, SUDOERS_DEBUG_UTIL)
+
+    switch (digest_type) {
+    case SUDO_DIGEST_SHA224:
+       digest_name = "sha224";
+       break;
+    case SUDO_DIGEST_SHA256:
+       digest_name = "sha256";
+       break;
+    case SUDO_DIGEST_SHA384:
+       digest_name = "sha384";
+       break;
+    case SUDO_DIGEST_SHA512:
+       digest_name = "sha512";
+       break;
+    default:
+       digest_name = "unknown digest";
+       break;
+    }
+    debug_return_const_str(digest_name);
+}
diff --git a/plugins/sudoers/filedigest.c b/plugins/sudoers/filedigest.c
new file mode 100644 (file)
index 0000000..d100059
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2017 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#if defined(HAVE_STDINT_H)
+# include <stdint.h>
+#elif defined(HAVE_INTTYPES_H)
+# include <inttypes.h>
+#endif
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "sudoers.h"
+#include "parse.h"
+
+#ifdef HAVE_SHA224UPDATE
+# include <sha2.h>
+#else
+# include "compat/sha2.h"
+#endif
+
+static struct digest_function {
+    const unsigned int digest_len;
+    void (*init)(SHA2_CTX *);
+#ifdef SHA2_VOID_PTR
+    void (*update)(SHA2_CTX *, const void *, size_t);
+    void (*final)(void *, SHA2_CTX *);
+#else
+    void (*update)(SHA2_CTX *, const unsigned char *, size_t);
+    void (*final)(unsigned char *, SHA2_CTX *);
+#endif
+} digest_functions[] = {
+    {
+       SHA224_DIGEST_LENGTH,
+       SHA224Init,
+       SHA224Update,
+       SHA224Final
+    }, {
+       SHA256_DIGEST_LENGTH,
+       SHA256Init,
+       SHA256Update,
+       SHA256Final
+    }, {
+       SHA384_DIGEST_LENGTH,
+       SHA384Init,
+       SHA384Update,
+       SHA384Final
+    }, {
+       SHA512_DIGEST_LENGTH,
+       SHA512Init,
+       SHA512Update,
+       SHA512Final
+    }, {
+       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;
+    SHA2_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);
+}
index 1fa74d0864b849a966b4f261413a243bf0877408..9b866ad5ee806b5ef3aabe1c44954689e0690274 100644 (file)
@@ -968,10 +968,8 @@ sudo_ldap_extract_digest(char **cmnd, struct sudo_digest *digest)
                        cp++;
                    *cmnd = cp;
                    DPRINTF1("%s digest %s for %s",
-                       digest_type == SUDO_DIGEST_SHA224 ? "sha224" :
-                       digest_type == SUDO_DIGEST_SHA256 ? "sha256" :
-                       digest_type == SUDO_DIGEST_SHA384 ? "sha384" :
-                       "sha512", digest->digest_str, cp);
+                       digest_type_to_name(digest_type),
+                       digest->digest_str, cp);
                    debug_return_ptr(digest);
                }
            }
index b51eff4bb1d7cc4fc2e2af8c3b03007a76211e6c..bb68285ec6122e9b2d7a62104e67f6898dd1f7b0 100644 (file)
 #else
 # include "compat/fnmatch.h"
 #endif /* HAVE_FNMATCH */
-#ifdef HAVE_SHA224UPDATE
-# include <sha2.h>
-#else
-# include "compat/sha2.h"
-#endif
 
 #if !defined(O_SEARCH) && defined(O_PATH)
 # define O_SEARCH O_PATH
@@ -723,127 +718,62 @@ command_matches_normal(const char *sudoers_cmnd, const char *sudoers_args, const
 }
 #else /* !SUDOERS_NAME_MATCH */
 
-static struct digest_function {
-    const char *digest_name;
-    const unsigned int digest_len;
-    void (*init)(SHA2_CTX *);
-#ifdef SHA2_VOID_PTR
-    void (*update)(SHA2_CTX *, const void *, size_t);
-    void (*final)(void *, SHA2_CTX *);
-#else
-    void (*update)(SHA2_CTX *, const unsigned char *, size_t);
-    void (*final)(unsigned char *, SHA2_CTX *);
-#endif
-} digest_functions[] = {
-    {
-       "SHA224",
-       SHA224_DIGEST_LENGTH,
-       SHA224Init,
-       SHA224Update,
-       SHA224Final
-    }, {
-       "SHA256",
-       SHA256_DIGEST_LENGTH,
-       SHA256Init,
-       SHA256Update,
-       SHA256Final
-    }, {
-       "SHA384",
-       SHA384_DIGEST_LENGTH,
-       SHA384Init,
-       SHA384Update,
-       SHA384Final
-    }, {
-       "SHA512",
-       SHA512_DIGEST_LENGTH,
-       SHA512Init,
-       SHA512Update,
-       SHA512Final
-    }, {
-       NULL
-    }
-};
-
 static bool
 digest_matches(int fd, const char *file, const struct sudo_digest *sd)
 {
-    unsigned char file_digest[SHA512_DIGEST_LENGTH];
-    unsigned char sudoers_digest[SHA512_DIGEST_LENGTH];
-    unsigned char buf[32 * 1024];
-    struct digest_function *func = NULL;
-    size_t nread;
-    SHA2_CTX ctx;
-    FILE *fp;
-    int fd2;
-    unsigned int i;
+    unsigned char *file_digest = NULL;
+    unsigned char *sudoers_digest = NULL;
+    bool matched = false;
+    size_t digest_len;
     debug_decl(digest_matches, SUDOERS_DEBUG_MATCH)
 
-    for (i = 0; digest_functions[i].digest_name != NULL; i++) {
-       if (sd->digest_type == i) {
-           func = &digest_functions[i];
-           break;
-       }
+    file_digest = sudo_filedigest(fd, file, sd->digest_type, &digest_len);
+    if (file_digest == NULL) {
+       /* Warning (if any) printed by sudo_filedigest() */
+       goto done;
     }
-    if (func == NULL) {
-       sudo_warnx(U_("unsupported digest type %d for %s"), sd->digest_type, file);
-       debug_return_bool(false);
+
+    /* Convert the command digest from ascii to binary. */
+    if ((sudoers_digest = malloc(digest_len)) == NULL) {
+       sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
+       goto done;
     }
-    if (strlen(sd->digest_str) == func->digest_len * 2) {
-       /* Convert the command digest from ascii hex to binary. */
-       for (i = 0; i < func->digest_len; i++) {
+    if (strlen(sd->digest_str) == digest_len * 2) {
+       /* Convert ascii hex to binary. */
+       unsigned int i;
+       for (i = 0; i < digest_len; i++) {
            const int h = hexchar(&sd->digest_str[i + i]);
            if (h == -1)
                goto bad_format;
            sudoers_digest[i] = (unsigned char)h;
        }
     } else {
-       size_t len = base64_decode(sd->digest_str, sudoers_digest,
-           sizeof(sudoers_digest));
-       if (len != func->digest_len) {
+       /* Convert base64 to binary. */
+       size_t len = base64_decode(sd->digest_str, sudoers_digest, digest_len);
+       if (len != digest_len) {
            sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
-               "incorrect length for digest, expected %u, got %zu",
-               func->digest_len, len);
+               "incorrect length for digest, expected %zu, got %zu",
+               digest_len, len);
            goto bad_format;
        }
     }
 
-    if ((fd2 = dup(fd)) == -1) {
-       sudo_debug_printf(SUDO_DEBUG_INFO, "unable to dup %s: %s",
-           file, strerror(errno));
-       debug_return_bool(false);
-    }
-    if ((fp = fdopen(fd2, "r")) == NULL) {
-       sudo_debug_printf(SUDO_DEBUG_INFO, "unable to open %s: %s",
-           file, strerror(errno));
-       close(fd2);
-       debug_return_bool(false);
-    }
-
-    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);
-       fclose(fp);
-       debug_return_bool(false);
-    }
-    func->final(file_digest, &ctx);
-
-    if (memcmp(file_digest, sudoers_digest, func->digest_len) != 0) {
-       fclose(fp);
+    if (memcmp(file_digest, sudoers_digest, digest_len) == 0) {
+       matched = true;
+    } else {
        sudo_debug_printf(SUDO_DEBUG_DIAG|SUDO_DEBUG_LINENO,
            "%s digest mismatch for %s, expecting %s",
-           func->digest_name, file, sd->digest_str);
-       debug_return_bool(false);
+           digest_type_to_name(sd->digest_type), file, sd->digest_str);
     }
+    goto done;
 
-    fclose(fp);
-    debug_return_bool(true);
 bad_format:
     sudo_warnx(U_("digest for %s (%s) is not in %s form"), file,
-       sd->digest_str, func->digest_name);
-    debug_return_bool(false);
+       sd->digest_str, digest_type_to_name(sd->digest_type));
+done:
+    free(sudoers_digest);
+    free(file_digest);
+    debug_return_bool(matched);
 }
 
 static bool
index 407651c0c2b8017d586e7b2d27ce0e70447ec7e0..b16f9ce037f736aebc6e93b76165d6437e29787b 100644 (file)
@@ -290,4 +290,10 @@ long get_gmtoff(time_t *clock);
 /* gentime.c */
 time_t parse_gentime(const char *expstr);
 
+/* filedigest.c */
+unsigned char *sudo_filedigest(int fd, const char *file, int digest_type, size_t *digest_len);
+
+/* digestname.c */
+const char *digest_type_to_name(int digest_type);
+
 #endif /* SUDOERS_PARSE_H */
index 93d407c7d103c267ea3eb0c02c2f8332ab59aef5..c6725cfa8bd41e46ecb1b4499f67fcaa4cfd2563 100644 (file)
@@ -1059,10 +1059,8 @@ sudo_sss_extract_digest(char **cmnd, struct sudo_digest *digest)
                    *cmnd = cp;
                    sudo_debug_printf(SUDO_DEBUG_INFO,
                        "%s digest %s for %s",
-                       digest_type == SUDO_DIGEST_SHA224 ? "sha224" :
-                       digest_type == SUDO_DIGEST_SHA256 ? "sha256" :
-                       digest_type == SUDO_DIGEST_SHA384 ? "sha384" :
-                       "sha512", digest->digest_str, cp);
+                       digest_type_to_name(digest_type),
+                       digest->digest_str, cp);
                    debug_return_ptr(digest);
                }
            }
index bbea8d89109799fab950da22f40ad08b2b364792..f3c330f1daaa746da9a2fceb6c53a6c35d5922db 100644 (file)
@@ -254,23 +254,7 @@ print_command_json(FILE *fp, struct member *m, int indent, bool last_one)
     /* Optional digest. */
     if (c->digest != NULL) {
        fputs(",\n", fp);
-       switch (c->digest->digest_type) {
-       case SUDO_DIGEST_SHA224:
-           digest_name = "sha224";
-           break;
-       case SUDO_DIGEST_SHA256:
-           digest_name = "sha256";
-           break;
-       case SUDO_DIGEST_SHA384:
-           digest_name = "sha384";
-           break;
-       case SUDO_DIGEST_SHA512:
-           digest_name = "sha512";
-           break;
-       default:
-           digest_name = "invalid digest";
-           break;
-       }
+       digest_name = digest_type_to_name(c->digest->digest_type);
        value.type = JSON_STRING;
        value.u.string = c->digest->digest_str;
        print_pair_json(fp, NULL, digest_name, &value, NULL, indent);