A small step for GnuPG but a huge leap for error codes.

(Sorry, it does not build currently - I need to check it in to avoid
duplicate work.)
This commit is contained in:
Werner Koch 2003-06-05 07:14:21 +00:00
parent 7250331472
commit b7b07d36e8
11 changed files with 514 additions and 12 deletions

View File

@ -1,3 +1,7 @@
2003-06-04 Werner Koch <wk@gnupg.org>
* configure.ac, Makefile.am: Enable building of gpg.
2003-04-29 Werner Koch <wk@gnupg.org>
* configure.ac: Build a limited version of scdaemon if libopensc

View File

@ -23,6 +23,11 @@ ACLOCAL_AMFLAGS = -I m4
EXTRA_DIST = scripts/config.rpath autogen.sh
if BUILD_GPG
gpg = g10
else
gpg =
endif
if BUILD_GPGSM
sm = sm
else
@ -39,9 +44,10 @@ else
scd =
endif
SUBDIRS = m4 intl jnlib common kbx ${sm} ${agent} ${scd} po doc tests
SUBDIRS = m4 intl jnlib common kbx ${gpg} ${sm} ${agent} ${scd} po doc tests
dist-hook:
@set -e; echo "$(VERSION)" > $(distdir)/VERSION

View File

@ -44,7 +44,7 @@ have_ksba=no
have_opensc=no
have_pth=no
GNUPG_BUILD_PROGRAM(gpg, no)
GNUPG_BUILD_PROGRAM(gpg, yes)
GNUPG_BUILD_PROGRAM(gpgsm, yes)
GNUPG_BUILD_PROGRAM(agent, yes)
GNUPG_BUILD_PROGRAM(scdaemon, yes)
@ -363,6 +363,7 @@ if test "$build_scdaemon" = "yes"; then
fi
AM_CONDITIONAL(BUILD_GPG, test "$build_gpg" = "yes")
AM_CONDITIONAL(BUILD_GPGSM, test "$build_gpgsm" = "yes")
AM_CONDITIONAL(BUILD_AGENT, test "$build_agent" = "yes")
AM_CONDITIONAL(BUILD_SCDAEMON, test "$build_scdaemon" = "yes")
@ -375,6 +376,7 @@ intl/Makefile
jnlib/Makefile
common/Makefile
kbx/Makefile
g10/Makefile
sm/Makefile
agent/Makefile
scd/Makefile

View File

@ -1,3 +1,10 @@
2003-06-04 Werner Koch <wk@gnupg.org>
* Makefile.am: Add new files, link gpg with libgpg-error.
* g10.c, options.h: New option --agent-program.
* call-agent.c: New.
* gpg.h, call-agent.h: New.
2003-06-03 David Shaw <dshaw@jabberwocky.com>
* options.h, g10.c (main), keylist.c (list_keyblock_print): Add

View File

@ -24,16 +24,17 @@ EXTRA_DIST = options.skel
# it seems that we can't use this with automake 1.5
#OMIT_DEPENDENCIES = zlib.h zconf.h
libexecdir = @libexecdir@/@PACKAGE@
if ! HAVE_DOSISH_SYSTEM
AM_CFLAGS = -DGNUPG_LIBEXECDIR="\"$(libexecdir)\""
endif
# FIXME: Windows support currently not enabled
#if ! HAVE_DOSISH_SYSTEM
#AM_CFLAGS = -DGNUPG_LIBEXECDIR="\"$(libexecdir)\""
#endif
needed_libs = ../cipher/libcipher.a ../mpi/libmpi.a ../util/libutil.a
#noinst_PROGRAMS = gpgd
bin_PROGRAMS = gpg gpgv
common_source = \
global.h \
global.h gpg.h \
build-packet.c \
compress.c \
filter.h \
@ -93,6 +94,7 @@ gpg_SOURCES = g10.c \
keyserver.c \
keyserver-internal.h \
photoid.c photoid.h \
call-agent.c call-agent.h \
exec.c exec.h
gpgv_SOURCES = gpgv.c \
@ -107,8 +109,7 @@ gpgv_SOURCES = gpgv.c \
# $(common_source)
LDADD = $(needed_libs) @INTLLIBS@ @CAPLIBS@ @ZLIBS@
# gpg gets LIBOBJS to add in mkdtemp if the platform doesn't have it
gpg_LDADD = @LIBOBJS@ $(LDADD) @DLLIBS@ @EGDLIBS@
gpg_LDADD = $(LDADD) @DLLIBS@ @EGDLIBS@ -lgpg-error
$(PROGRAMS): $(needed_libs)

407
g10/call-agent.c Normal file
View File

@ -0,0 +1,407 @@
/* call-agent.c - divert operations to the agent
* Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if 0 /* lety Emacs display a red warning */
#error fixme: this shares a lof of code with the file in ../sm
#endif
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#include <assert.h>
#include <gcrypt.h>
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
#include <assuan.h>
#include "gpg.h"
#include "i18n.h"
static ASSUAN_CONTEXT agent_ctx = NULL;
static int force_pipe_server = 0;
struct cipher_parm_s {
ASSUAN_CONTEXT ctx;
const char *ciphertext;
size_t ciphertextlen;
};
struct genkey_parm_s {
ASSUAN_CONTEXT ctx;
const char *sexp;
size_t sexplen;
};
struct learn_parm_s {
int error;
ASSUAN_CONTEXT ctx;
struct membuf *data;
};
/* Try to connect to the agent via socket or fork it off and work by
pipes. Handle the server's initial greeting */
static int
start_agent (void)
{
int rc = 0;
char *infostr, *p;
ASSUAN_CONTEXT ctx;
char *dft_display = NULL;
char *dft_ttyname = NULL;
char *dft_ttytype = NULL;
char *old_lc = NULL;
char *dft_lc = NULL;
if (agent_ctx)
return 0; /* fixme: We need a context for each thread or serialize
the access to the agent. */
infostr = force_pipe_server? NULL : getenv ("GPG_AGENT_INFO");
if (!infostr)
{
const char *pgmname;
const char *argv[3];
int no_close_list[3];
int i;
if (opt.verbose)
log_info (_("no running gpg-agent - starting one\n"));
if (fflush (NULL))
{
gpg_error_t tmperr = gpg_error_from_errno (errno);
log_error ("error flushing pending output: %s\n", strerror (errno));
return tmperr;
}
if (!opt.agent_program || !*opt.agent_program)
opt.agent_program = GNUPG_DEFAULT_AGENT;
if ( !(pgmname = strrchr (opt.agent_program, '/')))
pgmname = opt.agent_program;
else
pgmname++;
argv[0] = pgmname;
argv[1] = "--server";
argv[2] = NULL;
i=0;
if (log_get_fd () != -1)
no_close_list[i++] = log_get_fd ();
no_close_list[i++] = fileno (stderr);
no_close_list[i] = -1;
/* connect to the agent and perform initial handshaking */
rc = assuan_pipe_connect (&ctx, opt.agent_program, (char**)argv,
no_close_list);
}
else
{
int prot;
int pid;
infostr = xstrdup (infostr);
if ( !(p = strchr (infostr, ':')) || p == infostr)
{
log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
xfree (infostr);
force_pipe_server = 1;
return start_agent ();
}
*p++ = 0;
pid = atoi (p);
while (*p && *p != ':')
p++;
prot = *p? atoi (p+1) : 0;
if (prot != 1)
{
log_error (_("gpg-agent protocol version %d is not supported\n"),
prot);
xfree (infostr);
force_pipe_server = 1;
return start_agent ();
}
rc = assuan_socket_connect (&ctx, infostr, pid);
xfree (infostr);
if (rc == ASSUAN_Connect_Failed)
{
log_error (_("can't connect to the agent - trying fall back\n"));
force_pipe_server = 1;
return start_agent ();
}
}
if (rc)
{
log_error ("can't connect to the agent: %s\n", assuan_strerror (rc));
return gpg_error (GPG_ERR_NO_AGENT);
}
agent_ctx = ctx;
if (DBG_ASSUAN)
log_debug ("connection to agent established\n");
rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return map_assuan_err (rc);
dft_display = getenv ("DISPLAY");
if (opt.display || dft_display)
{
char *optstr;
if (asprintf (&optstr, "OPTION display=%s",
opt.display ? opt.display : dft_display) < 0)
return OUT_OF_CORE (errno);
rc = assuan_transact (agent_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
NULL);
free (optstr);
if (rc)
return map_assuan_err (rc);
}
if (!opt.ttyname)
{
dft_ttyname = getenv ("GPG_TTY");
if ((!dft_ttyname || !*dft_ttyname) && ttyname (0))
dft_ttyname = ttyname (0);
}
if (opt.ttyname || dft_ttyname)
{
char *optstr;
if (asprintf (&optstr, "OPTION ttyname=%s",
opt.ttyname ? opt.ttyname : dft_ttyname) < 0)
return OUT_OF_CORE (errno);
rc = assuan_transact (agent_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
NULL);
free (optstr);
if (rc)
return map_assuan_err (rc);
}
dft_ttytype = getenv ("TERM");
if (opt.ttytype || (dft_ttyname && dft_ttytype))
{
char *optstr;
if (asprintf (&optstr, "OPTION ttytype=%s",
opt.ttyname ? opt.ttytype : dft_ttytype) < 0)
return OUT_OF_CORE (errno);
rc = assuan_transact (agent_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
NULL);
free (optstr);
if (rc)
return map_assuan_err (rc);
}
#if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
old_lc = setlocale (LC_CTYPE, NULL);
if (old_lc)
{
old_lc = strdup (old_lc);
if (!old_lc)
return OUT_OF_CORE (errno);
}
dft_lc = setlocale (LC_CTYPE, "");
#endif
if (opt.lc_ctype || (dft_ttyname && dft_lc))
{
char *optstr;
if (asprintf (&optstr, "OPTION lc-ctype=%s",
opt.lc_ctype ? opt.lc_ctype : dft_lc) < 0)
rc = OUT_OF_CORE (errno);
else
{
rc = assuan_transact (agent_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
NULL);
free (optstr);
if (rc)
rc = map_assuan_err (rc);
}
}
#if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
if (old_lc)
{
setlocale (LC_CTYPE, old_lc);
free (old_lc);
}
#endif
if (rc)
return rc;
#if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
old_lc = setlocale (LC_MESSAGES, NULL);
if (old_lc)
{
old_lc = strdup (old_lc);
if (!old_lc)
return OUT_OF_CORE (errno);
}
dft_lc = setlocale (LC_MESSAGES, "");
#endif
if (opt.lc_messages || (dft_ttyname && dft_lc))
{
char *optstr;
if (asprintf (&optstr, "OPTION lc-messages=%s",
opt.lc_messages ? opt.lc_messages : dft_lc) < 0)
rc = OUT_OF_CORE (errno);
else
{
rc = assuan_transact (agent_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
NULL);
free (optstr);
if (rc)
rc = map_assuan_err (rc);
}
}
#if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
if (old_lc)
{
setlocale (LC_MESSAGES, old_lc);
free (old_lc);
}
#endif
return rc;
}
static AssuanError
membuf_data_cb (void *opaque, const void *buffer, size_t length)
{
membuf_t *data = opaque;
if (buffer)
put_membuf (data, buffer, length);
return 0;
}
#if 0
/* Handle a KEYPARMS inquiry. Note, we only send the data,
assuan_transact takes care of flushing and writing the end */
static AssuanError
inq_genkey_parms (void *opaque, const char *keyword)
{
struct genkey_parm_s *parm = opaque;
AssuanError rc;
rc = assuan_send_data (parm->ctx, parm->sexp, parm->sexplen);
return rc;
}
/* Call the agent to generate a new key */
int
agent_genkey (KsbaConstSexp keyparms, KsbaSexp *r_pubkey)
{
int rc;
struct genkey_parm_s gk_parm;
membuf_t data;
size_t len;
char *buf;
*r_pubkey = NULL;
rc = start_agent ();
if (rc)
return rc;
rc = assuan_transact (agent_ctx, "RESET", NULL, NULL,
NULL, NULL, NULL, NULL);
if (rc)
return map_assuan_err (rc);
init_membuf (&data, 1024);
gk_parm.ctx = agent_ctx;
gk_parm.sexp = keyparms;
gk_parm.sexplen = gcry_sexp_canon_len (keyparms, 0, NULL, NULL);
if (!gk_parm.sexplen)
return gpg_error (GPG_ERR_INV_VALUE);
rc = assuan_transact (agent_ctx, "GENKEY",
membuf_data_cb, &data,
inq_genkey_parms, &gk_parm, NULL, NULL);
if (rc)
{
xfree (get_membuf (&data, &len));
return map_assuan_err (rc);
}
buf = get_membuf (&data, &len);
if (!buf)
return gpg_error (GPG_ERR_ENOMEM);
if (!gcry_sexp_canon_len (buf, len, NULL, NULL))
{
xfree (buf);
return gpg_error (GPG_ERR_INV_SEXP);
}
*r_pubkey = buf;
return 0;
}
#endif /*0*/
/* Ask the agent whether the corresponding secret key is available for
the given keygrip. */
int
agent_havekey (const char *hexkeygrip)
{
int rc;
char line[ASSUAN_LINELENGTH];
rc = start_agent ();
if (rc)
return rc;
if (!hexkeygrip || strlen (hexkeygrip) != 40)
return gpg_error (GPG_ERR_INV_VALUE);
snprintf (line, DIM(line)-1, "HAVEKEY %s", hexkeygrip);
line[DIM(line)-1] = 0;
rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
return map_assuan_err (rc);
}
/* Ask the agent to change the passphrase of the key identified by
HEXKEYGRIP. */
int
agent_passwd (const char *hexkeygrip)
{
int rc;
char line[ASSUAN_LINELENGTH];
rc = start_agent ();
if (rc)
return rc;
if (!hexkeygrip || strlen (hexkeygrip) != 40)
return gpg_error (GPG_ERR_INV_VALUE);
snprintf (line, DIM(line)-1, "PASSWD %s", hexkeygrip);
line[DIM(line)-1] = 0;
rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
return map_assuan_err (rc);
}

34
g10/call-agent.h Normal file
View File

@ -0,0 +1,34 @@
/* call-agent.h - Divert operations to the agent
* Copyright (C) 2003 Free Software Foundation, Inc.
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef GNUPG_G10_CALL_AGENT_H
#define GNUPG_G10_CALL_AGENT_H
/* Check whether the secret key for the key identified by HEXKEYGRIP
is available. Return 0 for yes or an error code. */
int agent_havekey (const char *hexkeygrip);
/* Ask the agent to let the user change the passphrase of the secret
key identified by HEXKEYGRIP. */
int agent_passwd (const char *hexkeygrip);
#endif /*GNUPG_G10_CALL_AGENT_H*/

View File

@ -303,6 +303,7 @@ enum cmd_and_opt_values { aNull = 0,
oPersonalDigestPreferences,
oPersonalCompressPreferences,
oEmuMDEncodeBug,
oAgentProgram,
oDisplay,
oTTYname,
oTTYtype,
@ -610,6 +611,7 @@ static ARGPARSE_OPTS opts[] = {
{ oPersonalDigestPreferences, "personal-digest-preferences", 2, "@"},
{ oPersonalCompressPreferences, "personal-compress-preferences", 2, "@"},
{ oEmuMDEncodeBug, "emulate-md-encode-bug", 0, "@"},
{ oAgentProgram, "agent-program", 2 , "@" },
{ oDisplay, "display", 2, "@" },
{ oTTYname, "ttyname", 2, "@" },
{ oTTYtype, "ttytype", 2, "@" },
@ -1876,6 +1878,7 @@ main( int argc, char **argv )
case oPersonalCompressPreferences:
pers_compress_list=pargs.r.ret_str;
break;
case oAgentProgram: opt.agent_program = pargs.r.ret_str; break;
case oDisplay: opt.display = pargs.r.ret_str; break;
case oTTYname: opt.ttyname = pargs.r.ret_str; break;
case oTTYtype: opt.ttytype = pargs.r.ret_str; break;

33
g10/gpg.h Normal file
View File

@ -0,0 +1,33 @@
/* gpg.h - top level include file for gpg etc.
* Copyright (C) 2003 Free Software Foundation, Inc.
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef GNUPG_G10_GPG_H
#define GNUPG_G10_GPG_H
#ifdef GPG_ERR_SOURCE_DEFAULT
#error GPG_ERR_SOURCE_DEFAULT already defined
#endif
#define GPG_ERR_SOURCE_DEFAULT GPG_ERR_SOURCE_GPG
#include <gpg-error.h>
/* FIXME: merge this with global.h */
#endif /*GNUPG_G10_GPG_H*/

View File

@ -79,7 +79,7 @@ struct {
int completes_needed;
int max_cert_depth;
const char *homedir;
const char *agent_program;
char *display; /* 5 options to be passed to the gpg-agent */
char *ttyname;
char *ttytype;

View File

@ -17,8 +17,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef G10_ERRORS_H
#define G10_ERRORS_H
#ifndef GNUPG_INCLUDE_ERRORS_H
#define GNUPG_INCLUDE_ERRORS_H
#if 0
#error Remove this file after replacing all error codes with those
#error from libgpg-error. The numerical values are identical, though.
#endif
#define G10ERR_GENERAL 1
#define G10ERR_UNKNOWN_PACKET 2
@ -81,4 +86,4 @@
char *strerror( int n );
#endif
#endif /*G10_ERRORS_H*/
#endif /*GNUPG_INCLUDE_ERRORS_H*/