* Makefile.am (pkglib_PROGRAMS): Put protect-tool there.

* findkey.c (agent_write_private_key,agent_key_from_file)
(agent_key_available): Use GNUPG_PRIVATE_KEYS_DIR constant.
* gpg-agent.c (main): Use GNUPG_DEFAULT_HOMEDIR constant.

* protect-tool.c (store_private_key): New.
(import_p12_file): Store the new file if requested.
(main): New options --force and --store.

* gpg-agent.c (main): Set a global flag when runing detached.
* query.c (start_pinentry): Pass the list of FD to keep in the
child when not running detached.
* call-scd.c (start_scd): Ditto.
This commit is contained in:
Werner Koch 2002-06-27 07:29:29 +00:00
parent 738e6d8212
commit 56b049686f
13 changed files with 769 additions and 41 deletions

View File

@ -1,3 +1,30 @@
2002-06-27 Werner Koch <wk@gnupg.org>
* Makefile.am (pkglib_PROGRAMS): Put protect-tool there.
* findkey.c (agent_write_private_key,agent_key_from_file)
(agent_key_available): Use GNUPG_PRIVATE_KEYS_DIR constant.
* gpg-agent.c (main): Use GNUPG_DEFAULT_HOMEDIR constant.
* protect-tool.c (store_private_key): New.
(import_p12_file): Store the new file if requested.
(main): New options --force and --store.
* gpg-agent.c (main): Set a global flag when runing detached.
* query.c (start_pinentry): Pass the list of FD to keep in the
child when not running detached.
* call-scd.c (start_scd): Ditto.
2002-06-26 Werner Koch <wk@gnupg.org>
* command.c (cmd_istrusted, cmd_listtrusted, cmd_marktrusted)
(cmd_pksign, cmd_pkdecrypt, cmd_genkey, cmd_get_passphrase)
(cmd_learn): Print an error message for a failed operation.
* simple-pwquery.c, simple-pwquery.h: New.
* protect-tool. (get_passphrase): New, used to ge a passphrase
from the agent if none was given on the command line.
2002-06-25 Werner Koch <wk@gnupg.org>
* protect-tool.c (rsa_key_check): New.

View File

@ -19,7 +19,7 @@
## Process this file with automake to produce Makefile.in
bin_PROGRAMS = gpg-agent
noinst_PROGRAMS = protect-tool
pkglib_PROGRAMS = protect-tool
AM_CPPFLAGS = -I$(top_srcdir)/common $(LIBGCRYPT_CFLAGS) $(PTH_CFLAGS)
LDFLAGS = @LDFLAGS@
@ -48,8 +48,8 @@ gpg_agent_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a \
protect_tool_SOURCES = \
protect-tool.c \
protect.c \
minip12.c minip12.h
minip12.c minip12.h \
simple-pwquery.c simple-pwquery.h
protect_tool_LDADD = ../jnlib/libjnlib.a \
../common/libcommon.a $(LIBGCRYPT_LIBS)

View File

@ -45,6 +45,8 @@ struct {
int no_grab; /* don't let the pinentry grab the keyboard */
unsigned long def_cache_ttl;
int running_detached; /* we are running detached from the tty. */
} opt;

View File

@ -156,6 +156,8 @@ start_scd (void)
const char *pgmname;
ASSUAN_CONTEXT ctx;
const char *argv[3];
int no_close_list[3];
int i;
#ifdef USE_GNU_PTH
if (!pth_mutex_acquire (&scd_lock, 0, NULL))
@ -191,8 +193,18 @@ start_scd (void)
argv[1] = "--server";
argv[2] = NULL;
i=0;
if (!opt.running_detached)
{
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 pinentry and perform initial handshaking */
rc = assuan_pipe_connect (&ctx, opt.scdaemon_program, (char**)argv, 0);
rc = assuan_pipe_connect (&ctx, opt.scdaemon_program, (char**)argv,
no_close_list);
if (rc)
{
log_error ("can't connect to the SCdaemon: %s\n",

View File

@ -110,7 +110,10 @@ cmd_istrusted (ASSUAN_CONTEXT ctx, char *line)
else if (rc == -1)
return ASSUAN_Not_Trusted;
else
return map_to_assuan_status (rc);
{
log_error ("command is_trusted failed: %s\n", gnupg_strerror (rc));
return map_to_assuan_status (rc);
}
}
/* LISTTRUSTED
@ -119,7 +122,10 @@ cmd_istrusted (ASSUAN_CONTEXT ctx, char *line)
static int
cmd_listtrusted (ASSUAN_CONTEXT ctx, char *line)
{
return map_to_assuan_status (agent_listtrusted (ctx));
int rc = agent_listtrusted (ctx);
if (rc)
log_error ("command listtrusted failed: %s\n", gnupg_strerror (rc));
return map_to_assuan_status (rc);
}
@ -158,6 +164,8 @@ cmd_marktrusted (ASSUAN_CONTEXT ctx, char *line)
p++;
rc = agent_marktrusted (p, fpr, flag);
if (rc)
log_error ("command marktrusted failed: %s\n", gnupg_strerror (rc));
return map_to_assuan_status (rc);
}
@ -281,6 +289,8 @@ cmd_pksign (ASSUAN_CONTEXT ctx, char *line)
CTRL ctrl = assuan_get_pointer (ctx);
rc = agent_pksign (ctrl, assuan_get_data_fp (ctx));
if (rc)
log_error ("command pksign failed: %s\n", gnupg_strerror (rc));
return map_to_assuan_status (rc);
}
@ -304,6 +314,8 @@ cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line)
rc = agent_pkdecrypt (ctrl, value, valuelen, assuan_get_data_fp (ctx));
xfree (value);
if (rc)
log_error ("command pkdecrypt failed: %s\n", gnupg_strerror (rc));
return map_to_assuan_status (rc);
}
@ -337,6 +349,8 @@ cmd_genkey (ASSUAN_CONTEXT ctx, char *line)
rc = agent_genkey (ctrl, value, valuelen, assuan_get_data_fp (ctx));
xfree (value);
if (rc)
log_error ("command genkey failed: %s\n", gnupg_strerror (rc));
return map_to_assuan_status (rc);
}
@ -449,6 +463,8 @@ cmd_get_passphrase (ASSUAN_CONTEXT ctx, char *line)
}
}
if (rc)
log_error ("command get_passphrase failed: %s\n", gnupg_strerror (rc));
return map_to_assuan_status (rc);
}
@ -491,7 +507,7 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line)
rc = agent_handle_learn (has_option (line, "--send")? ctx : NULL);
if (rc)
log_error ("agent_handle_learn failed: %s\n", gnupg_strerror (rc));
log_error ("command learn failed: %s\n", gnupg_strerror (rc));
return map_to_assuan_status (rc);
}

View File

@ -173,7 +173,6 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
{
struct pin_entry_info_s *pi;
int rc;
int tries = 0;
assert (!opaque);

View File

@ -52,7 +52,7 @@ agent_write_private_key (const unsigned char *grip,
sprintf (hexgrip+2*i, "%02X", grip[i]);
strcpy (hexgrip+40, ".key");
fname = make_filename (opt.homedir, "private-keys-v1.d", hexgrip, NULL);
fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
if (force)
fp = fopen (fname, "wb");
else
@ -194,7 +194,7 @@ agent_key_from_file (const unsigned char *grip, unsigned char **shadow_info)
sprintf (hexgrip+2*i, "%02X", grip[i]);
strcpy (hexgrip+40, ".key");
fname = make_filename (opt.homedir, "private-keys-v1.d", hexgrip, NULL);
fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
fp = fopen (fname, "rb");
if (!fp)
{
@ -318,7 +318,7 @@ agent_key_available (const unsigned char *grip)
sprintf (hexgrip+2*i, "%02X", grip[i]);
strcpy (hexgrip+40, ".key");
fname = make_filename (opt.homedir, "private-keys-v1.d", hexgrip, NULL);
fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
i = !access (fname, R_OK)? 0 : -1;
xfree (fname);
return i;

View File

@ -295,13 +295,7 @@ main (int argc, char **argv )
opt.homedir = getenv("GNUPGHOME");
if (!opt.homedir || !*opt.homedir)
{
#ifdef HAVE_DRIVE_LETTERS
opt.homedir = "c:/gnupg-test";
#else
opt.homedir = "~/.gnupg-test";
#endif
}
opt.homedir = GNUPG_DEFAULT_HOMEDIR;
opt.def_cache_ttl = 10*60; /* default to 10 minutes */
@ -473,7 +467,6 @@ main (int argc, char **argv )
{ /* regular server mode */
int fd;
pid_t pid;
int i;
int len;
struct sockaddr_un serv_addr;
char *p;
@ -599,7 +592,10 @@ main (int argc, char **argv )
/* detach from tty and put process into a new session */
if (!nodetach )
{ /* close stdin, stdout and stderr unless it is the log stream */
{
int i;
/* close stdin, stdout and stderr unless it is the log stream */
for (i=0; i <= 2; i++)
{
if ( log_get_fd () != i)
@ -611,6 +607,7 @@ main (int argc, char **argv )
cleanup ();
exit (1);
}
opt.running_detached = 1;
}
if (chdir("/"))

View File

@ -660,7 +660,7 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw)
bagseqlength = ti.length;
while (bagseqlength)
{
log_error ( "at offset %u\n", (p - buffer));
/*log_debug ( "at offset %u\n", (p - buffer));*/
where = "bag-sequence";
if (parse_tag (&p, &n, &ti))
goto bailout;

View File

@ -35,6 +35,7 @@
#define JNLIB_NEED_LOG_LOGV
#include "agent.h"
#include "minip12.h"
#include "simple-pwquery.h"
#define N_(a) a
#define _(a) a
@ -55,6 +56,8 @@ enum cmd_and_opt_values
oShowKeygrip,
oP12Import,
oStore,
oForce,
aTest };
@ -70,7 +73,14 @@ struct rsa_secret_key_s
static int opt_armor;
static const char *passphrase = "abc";
static int opt_store;
static int opt_force;
static const char *passphrase;
static const char *get_passphrase (void);
static int store_private_key (const unsigned char *grip,
const void *buffer, size_t length, int force);
static ARGPARSE_OPTS opts[] = {
@ -86,6 +96,8 @@ static ARGPARSE_OPTS opts[] = {
{ oShowKeygrip, "show-keygrip", 256, "show the \"keygrip\""},
{ oP12Import, "p12-import", 256, "import a PKCS-12 encoded private key"},
{ oStore, "store", 0, "store the created key in the appropriate place"},
{ oForce, "force", 0, "force overwriting"},
{0}
};
@ -283,7 +295,7 @@ read_and_protect (const char *fname)
if (!key)
return;
rc = agent_protect (key, passphrase, &result, &resultlen);
rc = agent_protect (key, get_passphrase (), &result, &resultlen);
xfree (key);
if (rc)
{
@ -318,7 +330,7 @@ read_and_unprotect (const char *fname)
if (!key)
return;
rc = agent_unprotect (key, passphrase, &result, &resultlen);
rc = agent_unprotect (key, get_passphrase (), &result, &resultlen);
xfree (key);
if (rc)
{
@ -564,6 +576,7 @@ import_p12_file (const char *fname)
struct rsa_secret_key_s sk;
GcrySexp s_key;
unsigned char *key;
unsigned char grip[20];
/* fixme: we should release some stuff on error */
@ -571,7 +584,7 @@ import_p12_file (const char *fname)
if (!buf)
return;
kparms = p12_parse (buf, buflen, passphrase);
kparms = p12_parse (buf, buflen, get_passphrase ());
xfree (buf);
if (!kparms)
{
@ -626,18 +639,15 @@ import_p12_file (const char *fname)
}
/* Compute the keygrip. */
{
unsigned char grip[20];
if (!gcry_pk_get_keygrip (s_key, grip))
{
log_error ("can't calculate keygrip\n");
return;
}
log_info ("keygrip: ");
for (i=0; i < 20; i++)
log_printf ("%02X", grip[i]);
log_printf ("\n");
}
if (!gcry_pk_get_keygrip (s_key, grip))
{
log_error ("can't calculate keygrip\n");
return;
}
log_info ("keygrip: ");
for (i=0; i < 20; i++)
log_printf ("%02X", grip[i]);
log_printf ("\n");
/* convert to canonical encoding */
buflen = gcry_sexp_sprint (s_key, GCRYSEXP_FMT_CANON, NULL, 0);
@ -648,7 +658,7 @@ import_p12_file (const char *fname)
gcry_sexp_release (s_key);
rc = agent_protect (key, passphrase, &result, &resultlen);
rc = agent_protect (key, get_passphrase (), &result, &resultlen);
xfree (key);
if (rc)
{
@ -666,7 +676,11 @@ import_p12_file (const char *fname)
resultlen = strlen (p);
}
fwrite (result, resultlen, 1, stdout);
if (opt_store)
store_private_key (grip, result, resultlen, opt_force);
else
fwrite (result, resultlen, 1, stdout);
xfree (result);
}
@ -711,6 +725,8 @@ main (int argc, char **argv )
case oP12Import: cmd = oP12Import; break;
case oPassphrase: passphrase = pargs.r.ret_str; break;
case oStore: opt_store = 1; break;
case oForce: opt_force = 1; break;
default : pargs.err = 2; break;
}
@ -736,7 +752,8 @@ main (int argc, char **argv )
else
show_file (*argv);
return 0;
agent_exit (0);
return 8; /*NOTREACHED*/
}
void
@ -745,3 +762,95 @@ agent_exit (int rc)
rc = rc? rc : log_get_errorcount(0)? 2 : 0;
exit (rc);
}
/* Return the passphrase string and ask the agent if it has not been
set from the command line. */
static const char *
get_passphrase (void)
{
char *pw;
int err;
if (passphrase)
return passphrase;
pw = simple_pwquery (NULL,NULL,
_("Enter passphrase:"),
_("Please enter the passphrase or the PIN\n"
"needed to complete this operation."),
&err);
if (!pw)
{
if (err)
log_error ("error while asking for the passphrase\n");
else
log_info ("cancelled\n");
agent_exit (0);
}
passphrase = pw;
return passphrase;
}
static int
store_private_key (const unsigned char *grip,
const void *buffer, size_t length, int force)
{
int i;
const char *homedir;
char *fname;
FILE *fp;
char hexgrip[40+4+1];
for (i=0; i < 20; i++)
sprintf (hexgrip+2*i, "%02X", grip[i]);
strcpy (hexgrip+40, ".key");
homedir = getenv("GNUPGHOME");
if (!homedir || !*homedir)
homedir = GNUPG_DEFAULT_HOMEDIR;
fname = make_filename (homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
if (force)
fp = fopen (fname, "wb");
else
{
if (!access (fname, F_OK))
{
log_error ("secret key file `%s' already exists\n", fname);
xfree (fname);
return -1;
}
fp = fopen (fname, "wbx"); /* FIXME: the x is a GNU extension - let
configure check whether this actually
works */
}
if (!fp)
{
log_error ("can't create `%s': %s\n", fname, strerror (errno));
xfree (fname);
return -1;
}
if (fwrite (buffer, length, 1, fp) != 1)
{
log_error ("error writing `%s': %s\n", fname, strerror (errno));
fclose (fp);
remove (fname);
xfree (fname);
return -1;
}
if ( fclose (fp) )
{
log_error ("error closing `%s': %s\n", fname, strerror (errno));
remove (fname);
xfree (fname);
return -1;
}
log_info ("secret key stored as `%s'\n", fname);
xfree (fname);
return 0;
}

View File

@ -80,6 +80,8 @@ start_pinentry (void)
const char *pgmname;
ASSUAN_CONTEXT ctx;
const char *argv[5];
int no_close_list[3];
int i;
#ifdef USE_GNU_PTH
if (!pth_mutex_acquire (&entry_lock, 0, NULL))
@ -119,9 +121,19 @@ start_pinentry (void)
}
else
argv[1] = NULL;
i=0;
if (!opt.running_detached)
{
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 pinentry and perform initial handshaking */
rc = assuan_pipe_connect (&ctx, opt.pinentry_program, (char**)argv, 0);
rc = assuan_pipe_connect (&ctx, opt.pinentry_program, (char**)argv,
no_close_list);
if (rc)
{
log_error ("can't connect to the PIN entry module: %s\n",

485
agent/simple-pwquery.c Normal file
View File

@ -0,0 +1,485 @@
/* simple-pwquery.c - A simple password query cleint for gpg-agent
* Copyright (C) 2002 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
*/
/* This module is intended as a standalone client implementation to
gpg-agent's GET_PASSPHRASE command. In particular it does not use
the Assuan library and can only cope with an already running
gpg-agent. Some stuff is configurable in the header file. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
#define SIMPLE_PWQUERY_IMPLEMENTATION 1
#include "simple-pwquery.h"
#if defined(SPWQ_USE_LOGGING) && !defined(HAVE_JNLIB_LOGGING)
# undef SPWQ_USE_LOGGING
#endif
#ifndef _
#define _(a) (a)
#endif
#if !defined (hexdigitp) && !defined (xtoi_2)
#define digitp(p) (*(p) >= '0' && *(p) <= '9')
#define hexdigitp(a) (digitp (a) \
|| (*(a) >= 'A' && *(a) <= 'F') \
|| (*(a) >= 'a' && *(a) <= 'f'))
#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
*(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
#endif
/* Write NBYTES of BUF to file descriptor FD. */
static int
writen (int fd, const void *buf, size_t nbytes)
{
size_t nleft = nbytes;
int nwritten;
while (nleft > 0)
{
nwritten = write( fd, buf, nleft );
if (nwritten < 0)
{
if (errno == EINTR)
nwritten = 0;
else {
#ifdef SPWQ_USE_LOGGING
log_error ("write failed: %s\n", strerror (errno));
#endif
return SPWQ_IO_ERROR;
}
}
nleft -= nwritten;
buf = (const char*)buf + nwritten;
}
return 0;
}
/* Read an entire line and return number of bytes read. */
static int
readline (int fd, char *buf, size_t buflen)
{
size_t nleft = buflen;
char *p;
int nread = 0;
while (nleft > 0)
{
int n = read (fd, buf, nleft);
if (n < 0)
{
if (errno == EINTR)
continue;
return -(SPWQ_IO_ERROR);
}
else if (!n)
{
return -(SPWQ_PROTOCOL_ERROR); /* incomplete line */
}
p = buf;
nleft -= n;
buf += n;
nread += n;
for (; n && *p != '\n'; n--, p++)
;
if (n)
{
break; /* at least one full line available - that's enough.
This function is just a simple implementation, so
it is okay to forget about pending bytes */
}
}
return nread;
}
/* Send an option to the agent */
static int
agent_send_option (int fd, const char *name, const char *value)
{
char buf[200];
int nread;
char *line;
int i;
line = spwq_malloc (7 + strlen (name) + 1 + strlen (value) + 2);
if (!line)
return SPWQ_OUT_OF_CORE;
strcpy (stpcpy (stpcpy (stpcpy (
stpcpy (line, "OPTION "), name), "="), value), "\n");
i = writen (fd, line, strlen (line));
spwq_free (line);
if (i)
return i;
/* get response */
nread = readline (fd, buf, DIM(buf)-1);
if (nread < 0)
return -nread;
if (nread < 3)
return SPWQ_PROTOCOL_ERROR;
if (buf[0] == 'O' && buf[1] == 'K' && (buf[2] == ' ' || buf[2] == '\n'))
return 0; /* okay */
return SPWQ_ERR_RESPONSE;
}
/* Send all available options to the agent. */
static int
agent_send_all_options (int fd)
{
char *dft_display = NULL;
char *dft_ttyname = NULL;
char *dft_ttytype = NULL;
int rc = 0;
dft_display = getenv ("DISPLAY");
if (dft_display)
{
if ((rc = agent_send_option (fd, "display", dft_display)))
return rc;
}
if (ttyname (1))
dft_ttyname = ttyname (1);
if (dft_ttyname)
{
if ((rc=agent_send_option (fd, "ttyname", dft_ttyname)))
return rc;
}
dft_ttytype = getenv ("TERM");
if (dft_ttyname && dft_ttytype)
{
if ((rc = agent_send_option (fd, "ttytype", dft_ttytype)))
return rc;
}
#if defined(HAVE_SETLOCALE)
{
char *old_lc = NULL;
char *dft_lc = NULL;
#if defined(LC_CTYPE)
old_lc = setlocale (LC_CTYPE, NULL);
if (old_lc)
{
char *p = spwq_malloc (strlen (old_lc)+1);
if (!p)
return SPWQ_OUT_OF_CORE;
strcpy (p, old_lc);
old_lc = p;
}
dft_lc = setlocale (LC_CTYPE, "");
if (dft_ttyname && dft_lc)
rc = agent_send_option (fd, "lc-ctype", dft_lc);
if (old_lc)
{
setlocale (LC_CTYPE, old_lc);
spwq_free (old_lc);
}
if (rc)
return rc;
#endif
#if defined(LC_MESSAGES)
old_lc = setlocale (LC_MESSAGES, NULL);
if (old_lc)
{
char *p = spwq_malloc (strlen (old_lc)+1);
if (!p)
return SPWQ_OUT_OF_CORE;
strcpy (p, old_lc);
old_lc = p;
}
dft_lc = setlocale (LC_MESSAGES, "");
if (dft_ttyname && dft_lc)
rc = agent_send_option (fd, "lc-messages", dft_lc);
if (old_lc)
{
setlocale (LC_MESSAGES, old_lc);
spwq_free (old_lc);
}
if (rc)
return rc;
#endif
}
#endif /*HAVE_SETLOCALE*/
return 0;
}
/* Try to open a connection to the agent, send all options and return
the file descriptor for the connection. Return -1 in case of
error. */
static int
agent_open (int *rfd)
{
int rc;
int fd;
char *infostr, *p;
struct sockaddr_un client_addr;
size_t len;
int prot;
char line[200];
int nread;
*rfd = -1;
infostr = getenv ( "GPG_AGENT_INFO" );
if ( !infostr )
{
#ifdef SPWQ_USE_LOGGING
log_error (_("gpg-agent is not available in this session\n"));
#endif
return SPWQ_NO_AGENT;
}
if ( !(p = strchr ( infostr, ':')) || p == infostr
|| (p-infostr)+1 >= sizeof client_addr.sun_path )
{
#ifdef SPWQ_USE_LOGGING
log_error ( _("malformed GPG_AGENT_INFO environment variable\n"));
#endif
return SPWQ_NO_AGENT;
}
*p++ = 0;
while (*p && *p != ':')
p++;
prot = *p? atoi (p+1) : 0;
if ( prot != 1)
{
#ifdef SPWQ_USE_LOGGING
log_error (_("gpg-agent protocol version %d is not supported\n"),prot);
#endif
return SPWQ_PROTOCOL_ERROR;
}
if( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1 )
{
#ifdef SPWQ_USE_LOGGING
log_error ("can't create socket: %s\n", strerror(errno) );
#endif
return SPWQ_SYS_ERROR;
}
memset (&client_addr, 0, sizeof client_addr);
client_addr.sun_family = AF_UNIX;
strcpy (client_addr.sun_path, infostr);
len = (offsetof (struct sockaddr_un, sun_path)
+ strlen(client_addr.sun_path) + 1);
if (connect (fd, (struct sockaddr*)&client_addr, len ) == -1)
{
#ifdef SPWQ_USE_LOGGING
log_error ( _("can't connect to `%s': %s\n"), infostr, strerror (errno));
#endif
close (fd );
return SPWQ_IO_ERROR;
}
nread = readline (fd, line, DIM(line));
if (nread < 3 || !(line[0] == 'O' && line[1] == 'K'
&& (line[2] == '\n' || line[2] == ' ')) )
{
#ifdef SPWQ_USE_LOGGING
log_error ( _("communication problem with gpg-agent\n"));
#endif
close (fd );
return SPWQ_PROTOCOL_ERROR;
}
rc = agent_send_all_options (fd);
if (rc)
{
#ifdef SPWQ_USE_LOGGING
log_error (_("problem setting the gpg-agent options\n"));
#endif
close (fd);
return rc;
}
*rfd = fd;
return 0;
}
/* Copy text to BUFFER and escape as required. Return a poiinter to
the end of the new buffer. NOte that BUFFER must be large enough
to keep the entire text; allocataing it 3 times the size of TEXT
is sufficient. */
static char *
copy_and_escape (char *buffer, const char *text)
{
int i;
char *p = buffer;
for (i=0; text[i]; i++)
{
if (text[i] < ' ' || text[i] == '+')
{
sprintf (p, "%%%02X", text[i]);
p += 3;
}
else if (text[i] == ' ')
*p++ = '+';
else
*p++ = text[i];
}
return p;
}
/* Ask the gpg-agent for a passphrase and present the user with a
DESCRIPTION, a PROMPT and optiaonlly with a TRYAGAIN extra text.
If a CACHEID is not NULL it is used to locate the passphrase in in
the cache and store it under this ID. If ERRORCODE is not NULL it
should point a variable receiving an errorcode; thsi errocode might
be 0 if the user canceled the operation. The function returns NULL
to indicate an error. */
char *
simple_pwquery (const char *cacheid,
const char *tryagain,
const char *prompt,
const char *description,
int *errorcode)
{
int fd = -1;
int nread;
char *result = NULL;
char *pw = NULL;
char *p;
int rc, i;
rc = agent_open (&fd);
if (rc)
goto leave;
if (!cacheid)
cacheid = "X";
if (!tryagain)
tryagain = "X";
if (!prompt)
prompt = "X";
if (!description)
description = "X";
{
char *line;
/* We allocate 3 times the needed space so that there is enough
space for escaping. */
line = spwq_malloc (15
+ 3*strlen (cacheid) + 1
+ 3*strlen (tryagain) + 1
+ 3*strlen (prompt) + 1
+ 3*strlen (description) + 1
+ 2);
if (!line)
{
rc = SPWQ_OUT_OF_CORE;
goto leave;
}
strcpy (line, "GET_PASSPHRASE ");
p = line+15;
p = copy_and_escape (p, cacheid);
*p++ = ' ';
p = copy_and_escape (p, tryagain);
*p++ = ' ';
p = copy_and_escape (p, prompt);
*p++ = ' ';
p = copy_and_escape (p, description);
*p++ = '\n';
rc = writen (fd, line, p - line);
spwq_free (line);
if (rc)
goto leave;
}
/* get response */
pw = spwq_secure_malloc (500);
nread = readline (fd, pw, 499);
if (nread < 0)
{
rc = -nread;
goto leave;
}
if (nread < 3)
{
rc = SPWQ_PROTOCOL_ERROR;
goto leave;
}
if (pw[0] == 'O' && pw[1] == 'K' && pw[2] == ' ')
{ /* we got a passphrase - convert it back from hex */
size_t pwlen = 0;
for (i=3; i < nread && hexdigitp (pw+i); i+=2)
pw[pwlen++] = xtoi_2 (pw+i);
pw[pwlen] = 0; /* make a C String */
result = pw;
pw = NULL;
}
else if (nread > 7 && !memcmp (pw, "ERR 111", 7)
&& (pw[7] == ' ' || pw[7] == '\n') )
{
#ifdef SPWQ_USE_LOGGING
log_info (_("canceled by user\n") );
#endif
*errorcode = 0; /* canceled */
}
else
{
#ifdef SPWQ_USE_LOGGING
log_error (_("problem with the agent\n"));
#endif
rc = SPWQ_ERR_RESPONSE;
}
leave:
if (errorcode)
*errorcode = rc;
if (fd != -1)
close (fd);
if (pw)
spwq_free (pw);
return result;
}

69
agent/simple-pwquery.h Normal file
View File

@ -0,0 +1,69 @@
/* simple-pwquery.c - A simple password query cleint for gpg-agent
* Copyright (C) 2002 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 SIMPLE_PWQUERY_H
#define SIMPLE_PWQUERY_H
#ifdef SIMPLE_PWQUERY_IMPLEMENTATION /* Begin configuration stuff. */
/* Include whatever files you need. */
#include <gcrypt.h>
#include "../jnlib/logging.h"
/* Try to write error message using the standard log mechanism. The
current implementation requires that the HAVE_JNLIB_LOGGING is also
defined. */
#define SPWQ_USE_LOGGING 1
/* Memory allocation functions used by the implementation. Note, that
the returned value is expected to be freed with
spwq_secure_free. */
#define spwq_malloc(a) gcry_malloc (a)
#define spwq_free(a) gcry_free (a)
#define spwq_secure_malloc(a) gcry_malloc_secure (a)
#define spwq_secure_free(a) gcry_free (a)
#endif /*SIMPLE_PWQUERY_IMPLEMENTATION*/ /* End configuration stuff. */
/* Ask the gpg-agent for a passphrase and present the user with a
DESCRIPTION, a PROMPT and optiaonlly with a TRYAGAIN extra text.
If a CACHEID is not NULL it is used to locate the passphrase in in
the cache and store it under this ID. If ERRORCODE is not NULL it
should point a variable receiving an errorcode; thsi errocode might
be 0 if the user canceled the operation. The function returns NULL
to indicate an error. */
char *simple_pwquery (const char *cacheid,
const char *tryagain,
const char *prompt,
const char *description,
int *errorcode);
#define SPWQ_OUT_OF_CORE 1
#define SPWQ_IO_ERROR 2
#define SPWQ_PROTOCOL_ERROR 3
#define SPWQ_ERR_RESPONSE 4
#define SPWQ_NO_AGENT 5
#define SPWQ_SYS_ERROR 6
#define SPWQ_GENERAL_ERROR 7
#endif /*SIMPLE_PWQUERY_H*/