mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
tools: Add gpgsum tool
* Makefile.am: Add option for building gpgsum * autogen.rc: Add option for building gpgsum * configure.ac: Add option for building gpgsum * tools/Makefile.am: Add sources for gpgsum * tools/gpgsum-w32info.rc: Add new file * tools/gpgsum.c: Add gpsum tool * tools/gpgsum.w32-manifest.in: Add new file
This commit is contained in:
parent
98dd6f7af6
commit
3e0d1c229b
@ -35,7 +35,8 @@ ACLOCAL_AMFLAGS = -I m4
|
|||||||
AM_DISTCHECK_DVI_TARGET = pdf
|
AM_DISTCHECK_DVI_TARGET = pdf
|
||||||
AM_DISTCHECK_CONFIGURE_FLAGS = --enable-gnupg-builddir-envvar \
|
AM_DISTCHECK_CONFIGURE_FLAGS = --enable-gnupg-builddir-envvar \
|
||||||
--enable-all-tests --enable-g13 \
|
--enable-all-tests --enable-g13 \
|
||||||
--enable-gpgtar --enable-wks-tools --disable-ntbtls
|
--enable-gpgtar --enable-wks-tools --disable-ntbtls \
|
||||||
|
--enable-gpgsum
|
||||||
|
|
||||||
GITLOG_TO_CHANGELOG=gitlog-to-changelog
|
GITLOG_TO_CHANGELOG=gitlog-to-changelog
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ case "$myhost:$myhostsub" in
|
|||||||
extraoptions="$extraoptions --disable-zip"
|
extraoptions="$extraoptions --disable-zip"
|
||||||
;;
|
;;
|
||||||
w32:)
|
w32:)
|
||||||
extraoptions="--enable-gpgtar"
|
extraoptions="--enable-gpgtar --enable-gpgsum"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
@ -136,6 +136,7 @@ GNUPG_BUILD_PROGRAM(gpgtar, yes)
|
|||||||
# We also install the gpg-wks-server tool by default but disable it
|
# We also install the gpg-wks-server tool by default but disable it
|
||||||
# later for platforms where it can't be build.
|
# later for platforms where it can't be build.
|
||||||
GNUPG_BUILD_PROGRAM(wks-tools, yes)
|
GNUPG_BUILD_PROGRAM(wks-tools, yes)
|
||||||
|
GNUPG_BUILD_PROGRAM(gpgsum, yes)
|
||||||
|
|
||||||
|
|
||||||
AC_SUBST(PACKAGE)
|
AC_SUBST(PACKAGE)
|
||||||
@ -1849,6 +1850,7 @@ AM_CONDITIONAL(BUILD_TPM2D, test "$build_tpm2d" = "yes")
|
|||||||
AM_CONDITIONAL(BUILD_DOC, test "$build_doc" = "yes")
|
AM_CONDITIONAL(BUILD_DOC, test "$build_doc" = "yes")
|
||||||
AM_CONDITIONAL(BUILD_GPGTAR, test "$build_gpgtar" = "yes")
|
AM_CONDITIONAL(BUILD_GPGTAR, test "$build_gpgtar" = "yes")
|
||||||
AM_CONDITIONAL(BUILD_WKS_TOOLS, test "$build_wks_tools" = "yes")
|
AM_CONDITIONAL(BUILD_WKS_TOOLS, test "$build_wks_tools" = "yes")
|
||||||
|
AM_CONDITIONAL(BUILD_GPGSUM, test "$build_gpgsum" = "yes")
|
||||||
|
|
||||||
AM_CONDITIONAL(DISABLE_TESTS, test "$run_tests" != yes)
|
AM_CONDITIONAL(DISABLE_TESTS, test "$run_tests" != yes)
|
||||||
AM_CONDITIONAL(ENABLE_CARD_SUPPORT, test "$card_support" = yes)
|
AM_CONDITIONAL(ENABLE_CARD_SUPPORT, test "$card_support" = yes)
|
||||||
@ -1923,6 +1925,7 @@ AC_DEFINE_UNQUOTED(GPGCONF_DISP_NAME, "GPGConf",
|
|||||||
[The displayed name of gpgconf])
|
[The displayed name of gpgconf])
|
||||||
|
|
||||||
AC_DEFINE_UNQUOTED(GPGTAR_NAME, "gpgtar", [The name of the gpgtar tool])
|
AC_DEFINE_UNQUOTED(GPGTAR_NAME, "gpgtar", [The name of the gpgtar tool])
|
||||||
|
AC_DEFINE_UNQUOTED(GPGSUM_NAME, "gpgsum", [The name of the gpgsum tool])
|
||||||
|
|
||||||
AC_DEFINE_UNQUOTED(GPG_AGENT_SOCK_NAME, "S.gpg-agent",
|
AC_DEFINE_UNQUOTED(GPG_AGENT_SOCK_NAME, "S.gpg-agent",
|
||||||
[The name of the agent socket])
|
[The name of the agent socket])
|
||||||
@ -2118,6 +2121,7 @@ tools/gpgtar.w32-manifest
|
|||||||
tools/gpg-check-pattern.w32-manifest
|
tools/gpg-check-pattern.w32-manifest
|
||||||
tools/gpg-wks-client.w32-manifest
|
tools/gpg-wks-client.w32-manifest
|
||||||
tools/gpg-card.w32-manifest
|
tools/gpg-card.w32-manifest
|
||||||
|
tools/gpgsum.w32-manifest
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
@ -2144,6 +2148,7 @@ echo "
|
|||||||
Keyboxd: $build_keyboxd
|
Keyboxd: $build_keyboxd
|
||||||
Gpgtar: $build_gpgtar
|
Gpgtar: $build_gpgtar
|
||||||
WKS tools: $build_wks_tools
|
WKS tools: $build_wks_tools
|
||||||
|
Gpgsum: $build_gpgsum
|
||||||
|
|
||||||
Protect tool: $show_gnupg_protect_tool_pgm
|
Protect tool: $show_gnupg_protect_tool_pgm
|
||||||
LDAP wrapper: $show_gnupg_dirmngr_ldap_pgm
|
LDAP wrapper: $show_gnupg_dirmngr_ldap_pgm
|
||||||
|
@ -26,7 +26,8 @@ EXTRA_DIST = \
|
|||||||
gpgtar-w32info.rc gpgtar.w32-manifest.in \
|
gpgtar-w32info.rc gpgtar.w32-manifest.in \
|
||||||
gpg-check-pattern-w32info.rc gpg-check-pattern.w32-manifest.in \
|
gpg-check-pattern-w32info.rc gpg-check-pattern.w32-manifest.in \
|
||||||
gpg-wks-client-w32info.rc gpg-wks-client.w32-manifest.in \
|
gpg-wks-client-w32info.rc gpg-wks-client.w32-manifest.in \
|
||||||
gpg-card-w32info.rc gpg-card.w32-manifest.in
|
gpg-card-w32info.rc gpg-card.w32-manifest.in \
|
||||||
|
gpgsum-w32info.rc gpgsum.w32-manifest.in
|
||||||
|
|
||||||
AM_CPPFLAGS =
|
AM_CPPFLAGS =
|
||||||
include $(top_srcdir)/am/cmacros.am
|
include $(top_srcdir)/am/cmacros.am
|
||||||
@ -38,6 +39,7 @@ gpg_card_rc_objs = gpg-card-w32info.o
|
|||||||
gpgtar_rc_objs = gpgtar-w32info.o
|
gpgtar_rc_objs = gpgtar-w32info.o
|
||||||
gpg_check_pattern_rc_objs = gpg-check-pattern-w32info.o
|
gpg_check_pattern_rc_objs = gpg-check-pattern-w32info.o
|
||||||
gpg_wks_client_rc_objs = gpg-wks-client-w32info.o
|
gpg_wks_client_rc_objs = gpg-wks-client-w32info.o
|
||||||
|
gpgsum_rc_objs = gpgsum-w32info.o
|
||||||
|
|
||||||
gpg-connect-agent-w32info.o : gpg-connect-agent.w32-manifest \
|
gpg-connect-agent-w32info.o : gpg-connect-agent.w32-manifest \
|
||||||
../common/w32info-rc.h
|
../common/w32info-rc.h
|
||||||
@ -48,6 +50,7 @@ gpg-check-pattern-w32info.o : gpg-check-pattern.w32-manifest \
|
|||||||
../common/w32info-rc.h
|
../common/w32info-rc.h
|
||||||
gpg-wks-client-w32info.o : gpg-wks-client.w32-manifest \
|
gpg-wks-client-w32info.o : gpg-wks-client.w32-manifest \
|
||||||
../common/w32info-rc.h
|
../common/w32info-rc.h
|
||||||
|
gpgsum-w32info.o : gpgsum.w32-manifest ../common/w32info-rc.h
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@ -82,6 +85,12 @@ else
|
|||||||
noinst_PROGRAMS += gpgtar
|
noinst_PROGRAMS += gpgtar
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if BUILD_GPGSUM
|
||||||
|
bin_PROGRAMS += gpgsum
|
||||||
|
else
|
||||||
|
noinst_PROGRAMS += gpgsum
|
||||||
|
endif
|
||||||
|
|
||||||
common_libs = $(libcommon)
|
common_libs = $(libcommon)
|
||||||
commonpth_libs = $(libcommonpth)
|
commonpth_libs = $(libcommonpth)
|
||||||
|
|
||||||
@ -157,6 +166,14 @@ gpgtar_LDADD = $(libcommon) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
|
|||||||
$(LIBINTL) $(NETLIBS) $(LIBICONV) $(W32SOCKLIBS) \
|
$(LIBINTL) $(NETLIBS) $(LIBICONV) $(W32SOCKLIBS) \
|
||||||
$(gpgtar_rc_objs)
|
$(gpgtar_rc_objs)
|
||||||
|
|
||||||
|
gpgsum_SOURCES = \
|
||||||
|
gpgsum.c
|
||||||
|
|
||||||
|
gpgsum_CFLAGS = $(LIBGCRYPT_CFLAGS) $(GPG_ERROR_CFLAGS)
|
||||||
|
gpgsum_LDADD = $(libcommon) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
|
||||||
|
$(LIBINTL) $(NETLIBS) \
|
||||||
|
$(gpgsum_rc_objs)
|
||||||
|
|
||||||
gpg_wks_server_SOURCES = \
|
gpg_wks_server_SOURCES = \
|
||||||
gpg-wks-server.c \
|
gpg-wks-server.c \
|
||||||
gpg-wks.h \
|
gpg-wks.h \
|
||||||
|
52
tools/gpgsum-w32info.rc
Normal file
52
tools/gpgsum-w32info.rc
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/* gpgsum-w32info.rc -*- c -*-
|
||||||
|
* Copyright (C) 2020-2023 g10 Code GmbH
|
||||||
|
*
|
||||||
|
* This file is free software; as a special exception the author gives
|
||||||
|
* unlimited permission to copy and/or distribute it, with or without
|
||||||
|
* modifications, as long as this notice is preserved.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||||
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "afxres.h"
|
||||||
|
#include "../common/w32info-rc.h"
|
||||||
|
|
||||||
|
1 ICON "../common/gnupg.ico"
|
||||||
|
|
||||||
|
1 VERSIONINFO
|
||||||
|
FILEVERSION W32INFO_VI_FILEVERSION
|
||||||
|
PRODUCTVERSION W32INFO_VI_PRODUCTVERSION
|
||||||
|
FILEFLAGSMASK 0x3fL
|
||||||
|
#ifdef _DEBUG
|
||||||
|
FILEFLAGS 0x01L /* VS_FF_DEBUG (0x1)*/
|
||||||
|
#else
|
||||||
|
FILEFLAGS 0x00L
|
||||||
|
#endif
|
||||||
|
FILEOS 0x40004L /* VOS_NT (0x40000) | VOS__WINDOWS32 (0x4) */
|
||||||
|
FILETYPE 0x1L /* VFT_APP (0x1) */
|
||||||
|
FILESUBTYPE 0x0L /* VFT2_UNKNOWN */
|
||||||
|
BEGIN
|
||||||
|
BLOCK "StringFileInfo"
|
||||||
|
BEGIN
|
||||||
|
BLOCK "040904b0" /* US English (0409), Unicode (04b0) */
|
||||||
|
BEGIN
|
||||||
|
VALUE "FileDescription", L"GnuPG\x2019s hashsum tool\0"
|
||||||
|
VALUE "InternalName", "gpgsum\0"
|
||||||
|
VALUE "OriginalFilename", "gpgsum.exe\0"
|
||||||
|
VALUE "ProductName", W32INFO_PRODUCTNAME
|
||||||
|
VALUE "ProductVersion", W32INFO_PRODUCTVERSION
|
||||||
|
VALUE "CompanyName", W32INFO_COMPANYNAME
|
||||||
|
VALUE "FileVersion", W32INFO_FILEVERSION
|
||||||
|
VALUE "LegalCopyright", W32INFO_LEGALCOPYRIGHT
|
||||||
|
VALUE "Comments", W32INFO_COMMENTS
|
||||||
|
END
|
||||||
|
END
|
||||||
|
BLOCK "VarFileInfo"
|
||||||
|
BEGIN
|
||||||
|
VALUE "Translation", 0x409, 0x4b0
|
||||||
|
END
|
||||||
|
END
|
||||||
|
|
||||||
|
1 RT_MANIFEST "gpgsum.w32-manifest"
|
528
tools/gpgsum.c
Normal file
528
tools/gpgsum.c
Normal file
@ -0,0 +1,528 @@
|
|||||||
|
/* gpgsum.c - A simple hash sum tool mainly useful for Windows.
|
||||||
|
* Copyright (C) 2023 g10 Code GmbH
|
||||||
|
*
|
||||||
|
* This file is part of GnuPG.
|
||||||
|
*
|
||||||
|
* GnuPG is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* GnuPG is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <gpg-error.h>
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#ifdef _WIN32
|
||||||
|
# include <fcntl.h>
|
||||||
|
# include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define INCLUDED_BY_MAIN_MODULE 1
|
||||||
|
#include "../common/util.h"
|
||||||
|
#include "../common/init.h"
|
||||||
|
#include "../common/i18n.h"
|
||||||
|
#include "../common/sysutils.h"
|
||||||
|
|
||||||
|
#include <gcrypt.h>
|
||||||
|
|
||||||
|
static unsigned int filecount;
|
||||||
|
static unsigned int readerrors;
|
||||||
|
static unsigned int checkcount;
|
||||||
|
static unsigned int matcherrors;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
int algo;
|
||||||
|
int check;
|
||||||
|
int filenames;
|
||||||
|
} opt;
|
||||||
|
|
||||||
|
enum cmd_and_opt_values
|
||||||
|
{
|
||||||
|
aNull = 0,
|
||||||
|
aCheck = 'c',
|
||||||
|
oFileNamesFromStdIn = '0',
|
||||||
|
};
|
||||||
|
|
||||||
|
static gpgrt_opt_t opts[] = {
|
||||||
|
ARGPARSE_group (300, N_("@Commands:\n ")),
|
||||||
|
|
||||||
|
ARGPARSE_c (aCheck, "check",
|
||||||
|
N_("Read checksums from files and check them")),
|
||||||
|
ARGPARSE_group (301, N_("@\nOptions:\n ")),
|
||||||
|
ARGPARSE_s_n (oFileNamesFromStdIn, "filenames",
|
||||||
|
N_("Read file names from stdin")),
|
||||||
|
ARGPARSE_end ()
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
parse_arguments (gpgrt_argparse_t *pargs, gpgrt_opt_t *popts)
|
||||||
|
{
|
||||||
|
while (gpgrt_argparse (NULL, pargs, popts))
|
||||||
|
{
|
||||||
|
switch (pargs->r_opt)
|
||||||
|
{
|
||||||
|
case aCheck:
|
||||||
|
opt.check = 1;
|
||||||
|
break;
|
||||||
|
case oFileNamesFromStdIn:
|
||||||
|
opt.filenames = 1;
|
||||||
|
break;
|
||||||
|
default: pargs->err = 2; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
my_strusage( int level )
|
||||||
|
{
|
||||||
|
const char *p;
|
||||||
|
|
||||||
|
switch (level)
|
||||||
|
{
|
||||||
|
case 9: p = "GPL-3.0-or-later"; break;
|
||||||
|
case 11: p = "gpgsum (@GNUPG@)";
|
||||||
|
break;
|
||||||
|
case 13: p = VERSION; break;
|
||||||
|
//case 14: p = GNUPG_DEF_COPYRIGHT_LINE; break;
|
||||||
|
//case 17: p = PRINTABLE_OS_NAME; break;
|
||||||
|
case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
case 40:
|
||||||
|
p = _("Usage: gpgsum [-c|-0] [--] FILENAMES|-");
|
||||||
|
break;
|
||||||
|
case 41:
|
||||||
|
p = _("Syntax: gpgsum [-c|-0] [--] FILENAMES|-\n"
|
||||||
|
"Create or verify hash sums for files.\n"
|
||||||
|
"The executable must be named for the desired hash algorithm "
|
||||||
|
"(i.e., \"sha2sum\").");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: p = NULL; break;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We need to escape the fname so that included linefeeds etc don't
|
||||||
|
mess up the the output file. On windows we also turn backslashes
|
||||||
|
into slashes so that we don't get into conflicts with the escape
|
||||||
|
character. Note that the GNU version escapes the backslash and the
|
||||||
|
LF but we also escape the CR. */
|
||||||
|
static char *
|
||||||
|
escapefname (const char *fname, int *escaped)
|
||||||
|
{
|
||||||
|
const char *s;
|
||||||
|
char *buffer;
|
||||||
|
char *d;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
*escaped = 0;
|
||||||
|
for (n = 0, s = fname; *s; s++)
|
||||||
|
{
|
||||||
|
if (*s == '\n' || *s == '\r')
|
||||||
|
n += 2;
|
||||||
|
else if (*s == '\\')
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
n++;
|
||||||
|
#else
|
||||||
|
n += 2;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
n++;
|
||||||
|
buffer = xmalloc (n);
|
||||||
|
d = buffer;
|
||||||
|
for (s = fname; *s; s++)
|
||||||
|
{
|
||||||
|
if (*s == '\n')
|
||||||
|
{
|
||||||
|
*d++ = '\\';
|
||||||
|
*d++ = 'n' ;
|
||||||
|
*escaped = 1;
|
||||||
|
}
|
||||||
|
else if (*s == '\r')
|
||||||
|
{
|
||||||
|
*d++ = '\\';
|
||||||
|
*d++ = 'r' ;
|
||||||
|
*escaped = 1;
|
||||||
|
}
|
||||||
|
else if (*s == '\\')
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
*d++ = '/';
|
||||||
|
#else
|
||||||
|
*d++ = '\\';
|
||||||
|
*d++ = '\\' ;
|
||||||
|
*escaped = 1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*d++ = *s;
|
||||||
|
}
|
||||||
|
*d = 0;
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Revert the escaping in-place. We handle some more of the standard
|
||||||
|
escaping characters but not all. */
|
||||||
|
static void
|
||||||
|
unescapefname (char *fname)
|
||||||
|
{
|
||||||
|
char *s, *d;
|
||||||
|
|
||||||
|
for (s=d=fname; *s; s++)
|
||||||
|
{
|
||||||
|
if (*s == '\\' && s[1])
|
||||||
|
{
|
||||||
|
s++;
|
||||||
|
switch (*s)
|
||||||
|
{
|
||||||
|
case '\\': *d++ = '\\'; break;
|
||||||
|
case 'n': *d++ = '\n'; break;
|
||||||
|
case 'r': *d++ = '\r'; break;
|
||||||
|
case 'f': *d++ = '\f'; break;
|
||||||
|
case 'v': *d++ = '\v'; break;
|
||||||
|
case 'b': *d++ = '\b'; break;
|
||||||
|
default: *d++ = '\\'; *d++ = *s; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*d++ = *s;
|
||||||
|
}
|
||||||
|
*d = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gpg_error_t
|
||||||
|
hash_file (const char *fname, const char *expected)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
estream_t fp;
|
||||||
|
char buffer[4096];
|
||||||
|
size_t n;
|
||||||
|
char *p;
|
||||||
|
char *fnamebuf;
|
||||||
|
int escaped;
|
||||||
|
gcry_md_hd_t hd;
|
||||||
|
unsigned char *result;
|
||||||
|
unsigned int digest_length;
|
||||||
|
|
||||||
|
|
||||||
|
digest_length = gcry_md_get_algo_dlen(opt.algo);
|
||||||
|
|
||||||
|
filecount++;
|
||||||
|
if (!expected && *fname == '-' && !fname[1])
|
||||||
|
{
|
||||||
|
/* Not in check mode and asked to read from stdin. */
|
||||||
|
fp = es_stdin;
|
||||||
|
es_set_binary (es_stdin);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fp = es_fopen (fname, "rb");
|
||||||
|
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
log_error ("Can't open '%s': %s\n",
|
||||||
|
fname, gpg_strerror (err));
|
||||||
|
if (expected)
|
||||||
|
log_error ("%s: FAILED open\n", fname);
|
||||||
|
readerrors++;
|
||||||
|
return gpg_error(GPG_ERR_GENERAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = gcry_md_open(&hd, opt.algo, 0);
|
||||||
|
if (err) {
|
||||||
|
log_error("Failed to open md: %s\n", gcry_strerror(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
while ( (n = es_fread (buffer, 1, sizeof buffer, fp)))
|
||||||
|
gcry_md_write(hd, buffer, n);
|
||||||
|
if (es_ferror (fp))
|
||||||
|
{
|
||||||
|
log_error ("Error reading `%s': %s\n",
|
||||||
|
fname, strerror (errno));
|
||||||
|
if (fp != es_stdin)
|
||||||
|
es_fclose (fp);
|
||||||
|
if (expected)
|
||||||
|
es_printf ("%s: FAILED read\n", fname);
|
||||||
|
readerrors++;
|
||||||
|
return gpg_error(GPG_ERR_GENERAL);
|
||||||
|
}
|
||||||
|
if (fp != es_stdin)
|
||||||
|
es_fclose (fp);
|
||||||
|
|
||||||
|
fnamebuf = escapefname (fname, &escaped);
|
||||||
|
fname = fnamebuf;
|
||||||
|
|
||||||
|
result = gcry_md_read(hd, opt.algo);
|
||||||
|
if (!result) {
|
||||||
|
log_error("Failed to read digest\n");
|
||||||
|
return gpg_error(GPG_ERR_GENERAL);
|
||||||
|
}
|
||||||
|
checkcount++;
|
||||||
|
bin2hex(result, digest_length, buffer);
|
||||||
|
if (expected)
|
||||||
|
{
|
||||||
|
/* Lowercase the checksum. */
|
||||||
|
buffer[strlen(expected)] = 0;
|
||||||
|
for (p=buffer; *p; p++)
|
||||||
|
if (*p >= 'A' && *p <= 'Z')
|
||||||
|
*p |= 0x20;
|
||||||
|
if (strcmp (buffer, expected))
|
||||||
|
{
|
||||||
|
es_printf ("%s: FAILED\n", fname);
|
||||||
|
matcherrors++;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
es_printf ("%s: OK\n", fname);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
es_printf ("%s%s %s\n", escaped? "\\":"", buffer, fname);
|
||||||
|
xfree (fnamebuf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gpg_error_t
|
||||||
|
check_file (const char *fname)
|
||||||
|
{
|
||||||
|
estream_t fp;
|
||||||
|
char *linebuf = NULL;
|
||||||
|
char *line;
|
||||||
|
char *p;
|
||||||
|
size_t n;
|
||||||
|
int rc = 0;
|
||||||
|
int escaped;
|
||||||
|
unsigned int digest_length;
|
||||||
|
unsigned int name_offset;
|
||||||
|
size_t line_length;
|
||||||
|
size_t max_length;
|
||||||
|
|
||||||
|
digest_length = gcry_md_get_algo_dlen(opt.algo);
|
||||||
|
name_offset = digest_length * 2 + 2;
|
||||||
|
|
||||||
|
if (*fname == '-' && !fname[1])
|
||||||
|
fp = es_stdin;
|
||||||
|
else
|
||||||
|
fp = es_fopen (fname, "r");
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
log_error ("Can't open '%s': %s\n", fname, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
max_length = 4096;
|
||||||
|
while ( es_read_line (fp, &linebuf, &line_length, &max_length) )
|
||||||
|
{
|
||||||
|
escaped = (*linebuf == '\\');
|
||||||
|
line = linebuf + escaped;
|
||||||
|
n = strlen(line);
|
||||||
|
if (!n || line[n-1] != '\n')
|
||||||
|
{
|
||||||
|
log_error ("Error reading '%s': %s\n", fname,
|
||||||
|
es_feof (fp)? "last linefeed missing":"line too long");
|
||||||
|
rc = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
line[--n] = 0;
|
||||||
|
if (n && line[n-1] == '\r')
|
||||||
|
line[--n] = 0;
|
||||||
|
if (!*line)
|
||||||
|
continue; /* Ignore empty lines. */
|
||||||
|
if (n < name_offset || line[name_offset-2] != ' ')
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Error parsing `%s': %s\n", fname,
|
||||||
|
"invalid line");
|
||||||
|
rc = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note that we ignore the binary flag ('*') used by GNU
|
||||||
|
versions of this tool: It does not make sense to compute a
|
||||||
|
digest over some transformation of a file - we always want a
|
||||||
|
reliable checksum. The flag does not work: On Unix a
|
||||||
|
checksum file is created without the flag because it is the
|
||||||
|
default there. When checking it on Windows the missing flag
|
||||||
|
would indicate that it has been created in text mode and thus
|
||||||
|
the checksums will differ. */
|
||||||
|
|
||||||
|
/* Lowercase the checksum. */
|
||||||
|
line[name_offset-2] = 0;
|
||||||
|
for (p=line; *p; p++)
|
||||||
|
if (*p >= 'A' && *p <= 'Z')
|
||||||
|
*p |= 0x20;
|
||||||
|
/* Unescape the fname. */
|
||||||
|
if (escaped)
|
||||||
|
unescapefname (line+name_offset);
|
||||||
|
/* Hash the file. */
|
||||||
|
if (hash_file (line+name_offset, line))
|
||||||
|
rc = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (es_ferror (fp))
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Error reading `%s': %s\n",
|
||||||
|
fname, strerror (errno));
|
||||||
|
rc = -1;
|
||||||
|
}
|
||||||
|
if (fp != stdin)
|
||||||
|
es_fclose (fp);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gpg_error_t
|
||||||
|
hash_list (void)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
int ready = 0;
|
||||||
|
int c;
|
||||||
|
char namebuf[4096];
|
||||||
|
size_t n = 0;
|
||||||
|
unsigned long lastoff = 0;
|
||||||
|
unsigned long off = 0;
|
||||||
|
|
||||||
|
es_set_binary(es_stdin);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if ((c = es_getc (es_stdin)) == EOF)
|
||||||
|
{
|
||||||
|
if (es_ferror (es_stdin))
|
||||||
|
{
|
||||||
|
log_error ("Error reading '%s' at offset %lu: %s\n",
|
||||||
|
"[stdin]", off, strerror (errno));
|
||||||
|
rc = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Note: The Nul is a delimiter and not a terminator. */
|
||||||
|
c = 0;
|
||||||
|
ready = 1;
|
||||||
|
}
|
||||||
|
if (n >= sizeof namebuf)
|
||||||
|
{
|
||||||
|
log_error ("Error reading '%s': "
|
||||||
|
"filename at offset %lu too long\n",
|
||||||
|
"[stdin]", lastoff);
|
||||||
|
rc = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
namebuf[n++] = c;
|
||||||
|
off++;
|
||||||
|
if (!c)
|
||||||
|
{
|
||||||
|
if (*namebuf && hash_file (namebuf, NULL))
|
||||||
|
rc = -1;
|
||||||
|
n = 0;
|
||||||
|
lastoff = off;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (!ready);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char **argv)
|
||||||
|
{
|
||||||
|
gpgrt_argparse_t pargs;
|
||||||
|
char *executable = argv[0];
|
||||||
|
char *maybe_executable;
|
||||||
|
char *algo_str;
|
||||||
|
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
gnupg_reopen_std ("gpgsum");
|
||||||
|
i18n_init();
|
||||||
|
init_common_subsystems(&argc, &argv);
|
||||||
|
|
||||||
|
gpgrt_set_strusage (my_strusage);
|
||||||
|
pargs.argc = &argc;
|
||||||
|
pargs.argv = &argv;
|
||||||
|
pargs.flags = ARGPARSE_FLAG_KEEP;
|
||||||
|
parse_arguments (&pargs, opts);
|
||||||
|
gpgrt_argparse (NULL, &pargs, NULL);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
maybe_executable = strrchr(executable, '\\');
|
||||||
|
#else
|
||||||
|
maybe_executable = strrchr(executable, '/');
|
||||||
|
#endif
|
||||||
|
if (maybe_executable)
|
||||||
|
{
|
||||||
|
executable = ++maybe_executable;
|
||||||
|
}
|
||||||
|
|
||||||
|
algo_str = executable;
|
||||||
|
if (strlen(executable) > 3)
|
||||||
|
{
|
||||||
|
algo_str = gpgrt_strdup(executable);
|
||||||
|
if (strstr(algo_str, ".exe") != NULL)
|
||||||
|
algo_str[strlen(algo_str) - 7] = 0;
|
||||||
|
else
|
||||||
|
algo_str[strlen(algo_str) - 3] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
opt.algo = gcry_md_map_name(algo_str);
|
||||||
|
|
||||||
|
if (!opt.algo)
|
||||||
|
{
|
||||||
|
//unknown algo
|
||||||
|
gpgrt_usage (1);
|
||||||
|
}
|
||||||
|
gpgrt_free(algo_str);
|
||||||
|
if (opt.filenames && opt.check) {
|
||||||
|
gpgrt_usage (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt.filenames)
|
||||||
|
{
|
||||||
|
/* With option -0 a dash must be given as filename. */
|
||||||
|
if (argc != 1 || strcmp (argv[0], "-"))
|
||||||
|
gpgrt_usage (1);
|
||||||
|
if (hash_list ())
|
||||||
|
rc = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (; argc; argv++, argc--)
|
||||||
|
{
|
||||||
|
if (opt.check)
|
||||||
|
{
|
||||||
|
if (check_file (*argv))
|
||||||
|
rc = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (hash_file (*argv, NULL))
|
||||||
|
rc = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt.check && readerrors)
|
||||||
|
log_error ("WARNING: %u of %u listed files could not be read\n",
|
||||||
|
readerrors, filecount);
|
||||||
|
if (opt.check && matcherrors)
|
||||||
|
log_error ("WARNING: %u of %u computed checksums did NOT match\n",
|
||||||
|
matcherrors, checkcount);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
25
tools/gpgsum.w32-manifest.in
Normal file
25
tools/gpgsum.w32-manifest.in
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||||
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||||
|
<description>GNU Privacy Guard (Hashsum tool)</description>
|
||||||
|
<assemblyIdentity
|
||||||
|
type="win32"
|
||||||
|
name="GnuPG.gpgsum"
|
||||||
|
version="@BUILD_VERSION@"
|
||||||
|
/>
|
||||||
|
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||||
|
<application>
|
||||||
|
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/><!-- 10 -->
|
||||||
|
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/><!-- 8.1 -->
|
||||||
|
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/><!-- 8 -->
|
||||||
|
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/><!-- 7 -->
|
||||||
|
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/><!-- Vista -->
|
||||||
|
</application>
|
||||||
|
</compatibility>
|
||||||
|
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||||
|
<security>
|
||||||
|
<requestedPrivileges>
|
||||||
|
<requestedExecutionLevel level="asInvoker"/>
|
||||||
|
</requestedPrivileges>
|
||||||
|
</security>
|
||||||
|
</trustInfo>
|
||||||
|
</assembly>
|
Loading…
x
Reference in New Issue
Block a user