You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
435 lines
14 KiB
435 lines
14 KiB
From c8a6eecf768d8102a9a77f5fdb5b516e571d462e Mon Sep 17 00:00:00 2001 |
|
From: Radovan Sroka <rsroka@redhat.com> |
|
Date: Tue, 23 Aug 2016 13:43:08 +0200 |
|
Subject: [PATCH] Using libgcrypt |
|
|
|
Using libgcrypt and not sudo implementation of SHA... |
|
|
|
Rebased patch of digest backport. |
|
Added option --with-gcrypt |
|
|
|
Rebased from: |
|
Patch35: sudo-1.8.6p7-digest-backport.patch |
|
|
|
Resolves: |
|
rhbz#1183818 |
|
--- |
|
configure.ac | 16 +++++++ |
|
plugins/sudoers/Makefile.in | 9 +++- |
|
plugins/sudoers/filedigest.c | 104 +++++++++++++++++++++++++++++++++++++++++++ |
|
plugins/sudoers/filedigest.h | 17 +++++++ |
|
plugins/sudoers/match.c | 94 ++++++++++++++++++++++++++++++-------- |
|
5 files changed, 219 insertions(+), 21 deletions(-) |
|
create mode 100644 plugins/sudoers/filedigest.c |
|
create mode 100644 plugins/sudoers/filedigest.h |
|
|
|
diff --git a/configure.ac b/configure.ac |
|
index 13c3c1b..54929b2 100644 |
|
--- a/configure.ac |
|
+++ b/configure.ac |
|
@@ -35,6 +35,7 @@ AC_SUBST([SUDO_OBJS]) |
|
AC_SUBST([LIBS]) |
|
AC_SUBST([SUDO_LIBS]) |
|
AC_SUBST([SUDOERS_LIBS]) |
|
+AC_SUBST([LIBPARSESUDOERS_LIBS]) |
|
AC_SUBST([STATIC_SUDOERS]) |
|
AC_SUBST([NET_LIBS]) |
|
AC_SUBST([AFS_LIBS]) |
|
@@ -1517,6 +1518,19 @@ AC_ARG_WITH(selinux, [AS_HELP_STRING([--with-selinux], [enable SELinux support]) |
|
;; |
|
esac], [with_selinux=no]) |
|
|
|
+AC_ARG_WITH(gcrypt, [AS_HELP_STRING([--with-gcrypt], [enable libgcrypt support])], |
|
+[case $with_gcrypt in |
|
+ yes) |
|
+ AC_DEFINE(HAVE_LIBGCRYPT) |
|
+ LIBPARSESUDOERS_LIBS="${LIBPARSESUDOERS_LIBS} -lgcrypt" |
|
+ AC_CHECK_LIB([gcrypt], [gcry_md_open], |
|
+ [AC_DEFINE(HAVE_GCRY_MD_OPEN)]) |
|
+ ;; |
|
+ no) ;; |
|
+ *) AC_MSG_ERROR(["--with-gcrypt does not take an argument."]) |
|
+ ;; |
|
+esac]) |
|
+ |
|
dnl |
|
dnl gss_krb5_ccache_name() may not work on Heimdal so we don't use it by default |
|
dnl |
|
@@ -4344,6 +4358,8 @@ AH_TEMPLATE(HAVE_PROJECT_H, [Define to 1 if you have the <project.h> header file |
|
AH_TEMPLATE(HAVE_SECURID, [Define to 1 if you use SecurID for authentication.]) |
|
AH_TEMPLATE(HAVE_SELINUX, [Define to 1 to enable SELinux RBAC support.]) |
|
AH_TEMPLATE(HAVE_SETKEYCREATECON, [Define to 1 if you have the `setkeycreatecon' function.]) |
|
+AH_TEMPLATE(HAVE_LIBGCRYPT, [Define to 1 to enable libgcrypt support.]) |
|
+AH_TEMPLATE(HAVE_GCRY_MD_OPEN, [Define to 1 if you have the `gcry_md_open' function.]) |
|
AH_TEMPLATE(HAVE_SHL_LOAD, [Define to 1 if you have the `shl_load' function.]) |
|
AH_TEMPLATE(HAVE_SKEY, [Define to 1 if you use S/Key.]) |
|
AH_TEMPLATE(HAVE_SKEYACCESS, [Define to 1 if your S/Key library has skeyaccess().]) |
|
diff --git a/plugins/sudoers/Makefile.in b/plugins/sudoers/Makefile.in |
|
index f36f9ef..32c0ed0 100644 |
|
--- a/plugins/sudoers/Makefile.in |
|
+++ b/plugins/sudoers/Makefile.in |
|
@@ -55,6 +55,7 @@ LT_LIBS = $(top_builddir)/lib/util/libsudo_util.la |
|
LIBS = $(LT_LIBS) |
|
NET_LIBS = @NET_LIBS@ |
|
SUDOERS_LIBS = @SUDOERS_LIBS@ @AFS_LIBS@ @GETGROUPS_LIB@ $(LIBS) $(NET_LIBS) @ZLIB@ @LIBMD@ |
|
+LIBPARSESUDOERS_LIBS = @LIBPARSESUDOERS_LIBS@ |
|
REPLAY_LIBS = @REPLAY_LIBS@ @ZLIB@ |
|
VISUDO_LIBS = $(NET_LIBS) @LIBMD@ |
|
TESTSUDOERS_LIBS = $(NET_LIBS) @LIBMD@ |
|
@@ -153,7 +154,7 @@ AUTH_OBJS = sudo_auth.lo @AUTH_OBJS@ |
|
LIBPARSESUDOERS_OBJS = alias.lo audit.lo base64.lo defaults.lo hexchar.lo \ |
|
gram.lo match.lo match_addr.lo pwutil.lo pwutil_impl.lo \ |
|
rcstr.lo redblack.lo sudoers_debug.lo timestr.lo \ |
|
- toke.lo toke_util.lo |
|
+ toke.lo toke_util.lo filedigest.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 \ |
|
@@ -217,7 +218,7 @@ Makefile: $(srcdir)/Makefile.in |
|
(cd $(top_builddir) && ./config.status --file plugins/sudoers/Makefile) |
|
|
|
libparsesudoers.la: $(LIBPARSESUDOERS_OBJS) |
|
- $(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(LIBPARSESUDOERS_OBJS) -no-install |
|
+ $(LIBTOOL) --mode=link $(CC) -o $@ $(LIBPARSESUDOERS_OBJS) $(LIBPARSESUDOERS_LIBS) -no-install |
|
|
|
sudoers.la: $(SUDOERS_OBJS) $(LT_LIBS) libparsesudoers.la @LT_LDDEP@ |
|
case "$(LT_LDFLAGS)" in \ |
|
@@ -656,6 +657,10 @@ 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 $(top_builddir)/config.h \ |
|
+ $(incdir)/sudo_debug.h |
|
+ $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/filedigest.c |
|
+filedigest.o: filedigest.lo |
|
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/filedigest.c b/plugins/sudoers/filedigest.c |
|
new file mode 100644 |
|
index 0000000..c173741 |
|
--- /dev/null |
|
+++ b/plugins/sudoers/filedigest.c |
|
@@ -0,0 +1,104 @@ |
|
+#include <config.h> |
|
+#include <errno.h> |
|
+#include <stddef.h> |
|
+#include <sys/types.h> |
|
+#include <sys/stat.h> |
|
+#include <fcntl.h> |
|
+#include <unistd.h> |
|
+#include "filedigest.h" |
|
+#include "sudo_compat.h" |
|
+#include "sudo_debug.h" |
|
+ |
|
+#if defined(HAVE_LIBGCRYPT) |
|
+#include <gcrypt.h> |
|
+ |
|
+static int sudo_filedigest_gcrypt(int fd, int algo, unsigned char **dvalue, size_t *dvalue_size) |
|
+{ |
|
+ char buffer[4096]; |
|
+ gcry_md_hd_t ctx; |
|
+ int gcry_algo; |
|
+ debug_decl(sudo_filedigest_gcrypt, SUDO_DEBUG_UTIL); |
|
+ |
|
+ switch(algo) { |
|
+ case SUDO_DIGEST_SHA224: |
|
+ gcry_algo = GCRY_MD_SHA224; break; |
|
+ case SUDO_DIGEST_SHA256: |
|
+ gcry_algo = GCRY_MD_SHA256; break; |
|
+ case SUDO_DIGEST_SHA384: |
|
+ gcry_algo = GCRY_MD_SHA384; break; |
|
+ case SUDO_DIGEST_SHA512: |
|
+ gcry_algo = GCRY_MD_SHA512; break; |
|
+ default: |
|
+ debug_return_int(-1); |
|
+ } |
|
+ |
|
+ gcry_md_open(&ctx, gcry_algo, 0); |
|
+ |
|
+ /* Read block of data from fd and digest them */ |
|
+ while (1) { |
|
+ const ssize_t read_bytes = read(fd, buffer, sizeof buffer); |
|
+ |
|
+ if (read_bytes < 0) { |
|
+ /* Error */ |
|
+ gcry_md_close(ctx); |
|
+ debug_return_int(-1); |
|
+ } |
|
+ else if (read_bytes > 0) { |
|
+ /* Some data read -- update the digest */ |
|
+ gcry_md_write(ctx, buffer, (size_t)read_bytes); |
|
+ } |
|
+ else { |
|
+ /* EOF */ |
|
+ break; |
|
+ } |
|
+ } |
|
+ |
|
+ /* |
|
+ * All data digested. Finalize the digest value. |
|
+ */ |
|
+ const unsigned char *value = gcry_md_read(ctx, gcry_algo); |
|
+ |
|
+ if (value == NULL) { |
|
+ debug_return_int(-1); |
|
+ } |
|
+ |
|
+ /* |
|
+ * Make a copy of the digest value. The pointer |
|
+ * returned from gcry_md_read cannot be used after |
|
+ * gcry_md_close was called |
|
+ */ |
|
+ (*dvalue_size) = gcry_md_get_algo_dlen(gcry_algo); |
|
+ (*dvalue) = malloc(*dvalue_size); |
|
+ |
|
+ if (*dvalue == NULL) { |
|
+ debug_return_int(-1); |
|
+ } |
|
+ |
|
+ memcpy(*dvalue, value, *dvalue_size); |
|
+ gcry_md_close(ctx); |
|
+ |
|
+ debug_return_int(0); |
|
+} |
|
+#endif |
|
+ |
|
+#include <stdio.h> |
|
+ |
|
+int sudo_filedigest(const char *path, int algo, unsigned char **dvalue, size_t *dvalue_size) |
|
+{ |
|
+ int rc = -1; |
|
+ int fd = -1; |
|
+ debug_decl(sudo_filedigest, SUDO_DEBUG_UTIL); |
|
+ |
|
+ if ((fd = open(path, O_RDONLY)) < 0) { |
|
+ debug_return_int(rc); |
|
+ } |
|
+ |
|
+#if defined(HAVE_LIBGCRYPT) |
|
+ rc = sudo_filedigest_gcrypt(fd, algo, dvalue, dvalue_size); |
|
+ close(fd); |
|
+#else |
|
+ rc = -1; |
|
+ errno = ENOTSUP; |
|
+#endif |
|
+ debug_return_int(rc); |
|
+} |
|
diff --git a/plugins/sudoers/filedigest.h b/plugins/sudoers/filedigest.h |
|
new file mode 100644 |
|
index 0000000..437f02f |
|
--- /dev/null |
|
+++ b/plugins/sudoers/filedigest.h |
|
@@ -0,0 +1,17 @@ |
|
+#include <stddef.h> |
|
+ |
|
+#define SUDO_DIGEST_SHA224 0 |
|
+#define SUDO_DIGEST_SHA256 1 |
|
+#define SUDO_DIGEST_SHA384 2 |
|
+#define SUDO_DIGEST_SHA512 3 |
|
+#define SUDO_DIGEST_INVALID 4 |
|
+ |
|
+#define SUDO_SHA224_DIGEST_LENGTH 28 |
|
+#define SUDO_SHA256_DIGEST_LENGTH 32 |
|
+#define SUDO_SHA384_DIGEST_LENGTH 48 |
|
+#define SUDO_SHA512_DIGEST_LENGTH 64 |
|
+ |
|
+/* |
|
+ * Compute a digest of a given file. Returns 0 on success, -1 otherwise. |
|
+ */ |
|
+int sudo_filedigest(const char *path, int algo, unsigned char **dvalue, size_t *dvalue_size); |
|
diff --git a/plugins/sudoers/match.c b/plugins/sudoers/match.c |
|
index 1916bde..2a9ea4b 100644 |
|
--- a/plugins/sudoers/match.c |
|
+++ b/plugins/sudoers/match.c |
|
@@ -62,6 +62,7 @@ |
|
|
|
#include "sudoers.h" |
|
#include "parse.h" |
|
+#include "filedigest.h" |
|
#include <gram.h> |
|
|
|
#ifdef HAVE_FNMATCH |
|
@@ -576,6 +577,7 @@ command_matches_normal(const char *sudoers_cmnd, const char *sudoers_args, const |
|
} |
|
#else /* !SUDOERS_NAME_MATCH */ |
|
|
|
+#ifndef HAVE_LIBGCRYPT /* !!! */ |
|
static struct digest_function { |
|
const char *digest_name; |
|
const unsigned int digest_len; |
|
@@ -616,24 +618,43 @@ static struct digest_function { |
|
NULL |
|
} |
|
}; |
|
+#endif /* !HAVE_LIBGCRYPT */ |
|
+ |
|
+static const char *digesttype2str(int digest_type) |
|
+{ |
|
+ switch(digest_type) { |
|
+ case SUDO_DIGEST_SHA224: |
|
+ return "SHA224"; |
|
+ case SUDO_DIGEST_SHA256: |
|
+ return "SHA256"; |
|
+ case SUDO_DIGEST_SHA384: |
|
+ return "SHA384"; |
|
+ case SUDO_DIGEST_SHA512: |
|
+ return "SHA512"; |
|
+ } |
|
+ return "<INVALID>"; |
|
+} |
|
|
|
static bool |
|
digest_matches(const char *file, const struct sudo_digest *sd, int *fd) |
|
{ |
|
- unsigned char file_digest[SHA512_DIGEST_LENGTH]; |
|
- unsigned char sudoers_digest[SHA512_DIGEST_LENGTH]; |
|
+ unsigned char * file_digest = NULL; |
|
+ unsigned char * sudoers_digest = NULL; |
|
+ size_t digest_size; |
|
unsigned char buf[32 * 1024]; |
|
- struct digest_function *func = NULL; |
|
#ifdef HAVE_FEXECVE |
|
bool first = true; |
|
bool is_script = false; |
|
#endif /* HAVE_FEXECVE */ |
|
size_t nread; |
|
- SHA2_CTX ctx; |
|
FILE *fp; |
|
unsigned int i; |
|
debug_decl(digest_matches, SUDOERS_DEBUG_MATCH) |
|
|
|
+#ifndef HAVE_LIBGCRYPT /* !!! */ |
|
+ |
|
+ SHA2_CTX ctx; |
|
+ struct digest_function *func = NULL; |
|
for (i = 0; digest_functions[i].digest_name != NULL; i++) { |
|
if (sd->digest_type == i) { |
|
func = &digest_functions[i]; |
|
@@ -644,9 +665,33 @@ digest_matches(const char *file, const struct sudo_digest *sd, int *fd) |
|
sudo_warnx(U_("unsupported digest type %d for %s"), sd->digest_type, file); |
|
debug_return_bool(false); |
|
} |
|
- if (strlen(sd->digest_str) == func->digest_len * 2) { |
|
+ |
|
+ digest_size = func->digest_len; |
|
+ |
|
+ file_digest = malloc(digest_size); |
|
+ if (file_digest == NULL) { |
|
+ debug_return_bool(false); |
|
+ } |
|
+ |
|
+#elif HAVE_LIBGCRYPT |
|
+ |
|
+ if (sudo_filedigest(file, sd->digest_type, |
|
+ &file_digest, &digest_size) != 0) { |
|
+ sudo_warnx(U_("Cannot compute digest type %d for %s"), sd->digest_type, file); |
|
+ goto clean_up; |
|
+ } |
|
+ |
|
+#endif /* !HAVE_LIBGCRYPT */ |
|
+ |
|
+ sudoers_digest = malloc(digest_size); |
|
+ if (sudoers_digest == NULL) { |
|
+ free(file_digest); |
|
+ debug_return_bool(false); |
|
+ } |
|
+ |
|
+ if (strlen(sd->digest_str) == digest_size * 2) { |
|
/* Convert the command digest from ascii hex to binary. */ |
|
- for (i = 0; i < func->digest_len; i++) { |
|
+ for (i = 0; i < digest_size ; i++) { |
|
const int h = hexchar(&sd->digest_str[i + i]); |
|
if (h == -1) |
|
goto bad_format; |
|
@@ -654,11 +699,11 @@ digest_matches(const char *file, const struct sudo_digest *sd, int *fd) |
|
} |
|
} else { |
|
size_t len = base64_decode(sd->digest_str, sudoers_digest, |
|
- sizeof(sudoers_digest)); |
|
- if (len != func->digest_len) { |
|
+ digest_size); |
|
+ if (len != digest_size) { |
|
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_size, len); |
|
goto bad_format; |
|
} |
|
} |
|
@@ -666,10 +711,11 @@ digest_matches(const char *file, const struct sudo_digest *sd, int *fd) |
|
if ((fp = fopen(file, "r")) == NULL) { |
|
sudo_debug_printf(SUDO_DEBUG_INFO, "unable to open %s: %s", |
|
file, strerror(errno)); |
|
- debug_return_bool(false); |
|
+ goto clean_up; |
|
} |
|
- |
|
+#ifndef HAVE_LIBGCRYPT |
|
func->init(&ctx); |
|
+#endif /* !HAVE_LIBGCRYPT */ |
|
while ((nread = fread(buf, 1, sizeof(buf), fp)) != 0) { |
|
#ifdef HAVE_FEXECVE |
|
/* Check for #! cookie and set is_script. */ |
|
@@ -679,21 +725,24 @@ digest_matches(const char *file, const struct sudo_digest *sd, int *fd) |
|
is_script = true; |
|
} |
|
#endif /* HAVE_FEXECVE */ |
|
+#ifndef HAVE_LIBGCRYPT |
|
func->update(&ctx, buf, nread); |
|
+#endif /* !HAVE_LIBGCRYPT */ |
|
} |
|
if (ferror(fp)) { |
|
sudo_warnx(U_("%s: read error"), file); |
|
fclose(fp); |
|
- debug_return_bool(false); |
|
+ goto clean_up; |
|
} |
|
+#ifndef HAVE_LIBGCRYPT |
|
func->final(file_digest, &ctx); |
|
- |
|
- if (memcmp(file_digest, sudoers_digest, func->digest_len) != 0) { |
|
+#endif /* !HAVE_LIBGCRYPT */ |
|
+ if (memcmp(file_digest, sudoers_digest, digest_size) != 0) { |
|
fclose(fp); |
|
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); |
|
+ digesttype2str(sd->digest_type), file, sd->digest_str); |
|
+ goto clean_up; |
|
} |
|
|
|
#ifdef HAVE_FEXECVE |
|
@@ -705,7 +754,7 @@ digest_matches(const char *file, const struct sudo_digest *sd, int *fd) |
|
sudo_debug_printf(SUDO_DEBUG_INFO, "unable to dup %s: %s", |
|
file, strerror(errno)); |
|
fclose(fp); |
|
- debug_return_bool(false); |
|
+ goto clean_up; |
|
} |
|
/* |
|
* Shell scripts go through namei twice and so we can't set the close |
|
@@ -715,10 +764,17 @@ digest_matches(const char *file, const struct sudo_digest *sd, int *fd) |
|
(void)fcntl(*fd, F_SETFD, FD_CLOEXEC); |
|
#endif /* HAVE_FEXECVE */ |
|
fclose(fp); |
|
+ free(file_digest); |
|
+ free(sudoers_digest); |
|
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); |
|
+ sd->digest_str, digesttype2str(sd->digest_type)); |
|
+clean_up: |
|
+ if (file_digest) |
|
+ free(file_digest); |
|
+ if (sudoers_digest) |
|
+ free(sudoers_digest); |
|
debug_return_bool(false); |
|
} |
|
|
|
-- |
|
2.7.4 |
|
|
|
|