1
0
mirror of git://git.gnupg.org/gnupg.git synced 2025-01-21 14:47:03 +01:00

Changes to make use of code taken from libassuan. This replaces the

old ad-hoc connection code to gpg-agent.  We do need this for the
forthcoming diversion of card code to an already running gpg-agent
with card-support.
This commit is contained in:
Werner Koch 2005-04-05 17:09:13 +00:00
parent 727cda9758
commit 80f4424658
23 changed files with 2432 additions and 619 deletions

View File

@ -1,3 +1,14 @@
2005-03-31 Werner Koch <wk@g10code.com>
* configure.ac: New option --disable-agent-support. Define
ENABLE_AGENT_SUPPORT as AC_DEFINE and AM_CONDITIONAL.
Disable support for card and agent with --enable-minimal.
(AC_REPLACE_FUNCS): Add isascii.
(g10defs.h): Define PATHSEP_C and PATHSEP_S.
* README: Changed the instruction on how to verify a signature to
show a .sig extension and not the .asc we used to use ages ago.
2005-03-16 David Shaw <dshaw@jabberwocky.com>
* configure.ac: Move the LDAP detecting code to m4/ldap.m4.

18
README
View File

@ -81,10 +81,10 @@
a) If you already have a trusted Version of GnuPG installed, you
can simply check the supplied signature:
$ gpg --verify gnupg-x.y.z.tar.gz.asc
$ gpg --verify gnupg-x.y.z.tar.gz.sig
This checks that the detached signature gnupg-x.y.z.tar.gz.asc
is indeed a a signature of gnupg-x.y.z.tar.gz. The key used to
This checks that the detached signature gnupg-x.y.z.tar.gz.sig
is indeed a signature of gnupg-x.y.z.tar.gz. The key used to
create this signature is:
"pub 1024D/57548DCD 1998-07-07 Werner Koch (gnupg sig) <dd9jn@gnu.org>"
@ -584,9 +584,11 @@
--disable-cast5, --disable-blowfish,
--disable-aes, --disable-twofish,
--disable-sha256, --disable-sha512,
--without-bzip2, and --disable-exec. Configure
command lines are read from left to right, so if
you want to have an "almost minimal"
--without-bzip2, --disable-exec,
--disable-card-support and
--disable-agent-support.
Configure command lines are read from left to
right, so if you want to have an "almost minimal"
configuration, you can do (for example)
"--enable-minimal --enable-rsa" to have RSA added
to the minimal build.
@ -603,6 +605,10 @@
to include support if all required libraries are
available.
--disable-agent-support
Do not include support for the gpg-agent. The
default is to include support.
--enable-selinux-support
This prevents access to certain files and won't
allow import or export of secret keys.

1
THANKS
View File

@ -181,6 +181,7 @@ Russell Coker russell@coker.com.au
Ryan Malayter rmalayter@bai.org
Sam Roberts sam@cogent.ca
Sami Tolvanen sami@tolvanen.com
Sascha Kiefer sk@intertivity.com
Sean MacLennan seanm@netwinder.org
Sebastian Klemke packet@convergence.de
Serge Munhoven munhoven@mema.ucl.ac.be

View File

@ -122,13 +122,6 @@ AC_ARG_ENABLE(selinux-support,
AC_MSG_RESULT($selinux_support)
AC_MSG_CHECKING([whether OpenPGP card support is requested])
AC_ARG_ENABLE(card-support,
AC_HELP_STRING([--disable-card-support],
[disable OpenPGP card support]),
card_support=$enableval, card_support=yes)
AC_MSG_RESULT($card_support)
AC_MSG_CHECKING([whether the new iconv based code is requested])
AC_ARG_ENABLE(gnupg-iconv,
AC_HELP_STRING([--disable-gnupg-iconv],
@ -158,6 +151,8 @@ use_sha256=yes
use_sha512=yes
use_bzip2=yes
use_exec=yes
card_support=yes
agent_support=yes
AC_ARG_ENABLE(minimal,
AC_HELP_STRING([--enable-minimal],[build the smallest gpg binary possible]),
@ -170,7 +165,27 @@ AC_ARG_ENABLE(minimal,
use_sha256=no
use_sha512=no
use_bzip2=no
use_exec=no)
use_exec=no
card_support=no
agent_support=no)
AC_MSG_CHECKING([whether OpenPGP card support is requested])
AC_ARG_ENABLE(card-support,
AC_HELP_STRING([--disable-card-support],
[disable OpenPGP card support]),
card_support=$enableval)
AC_MSG_RESULT($card_support)
# Note that we may later disable the agent support based on the platform.
AC_MSG_CHECKING([whether gpg-agent support is requested])
AC_ARG_ENABLE(agent-support,
AC_HELP_STRING([--disable-agent-support],
[disable gpg-agent support]),
agent_support=$enableval)
AC_MSG_RESULT($agent_support)
AC_MSG_CHECKING([whether to enable the RSA public key algorithm])
AC_ARG_ENABLE(rsa,
@ -471,6 +486,7 @@ case "${host}" in
have_dosish_system=yes
need_dlopen=no
try_gettext="no"
agent_support=no
;;
i?86-emx-os2 | i?86-*-os2*emx )
# OS/2 with the EMX environment
@ -478,6 +494,7 @@ case "${host}" in
AC_DEFINE(HAVE_DRIVE_LETTERS)
have_dosish_system=yes
try_gettext="no"
agent_support=no
;;
i?86-*-msdosdjgpp*)
@ -486,6 +503,7 @@ case "${host}" in
AC_DEFINE(HAVE_DRIVE_LETTERS)
have_dosish_system=yes
try_gettext="no"
agent_support=no
;;
*-*-freebsd*)
@ -754,6 +772,10 @@ if test "$card_support" = yes ; then
AC_DEFINE(ENABLE_CARD_SUPPORT,1,[Define to include OpenPGP card support])
fi
if test "$agent_support" = yes ; then
AC_DEFINE(ENABLE_AGENT_SUPPORT,1,[Define to include gpg-agent support])
fi
if test "$try_extensions" = yes ; then
AC_DEFINE(USE_DYNAMIC_LINKING,1,[Define to enable the use of extensions])
fi
@ -771,6 +793,7 @@ if test "$do_backsigs" = yes ; then
fi
AM_CONDITIONAL(ENABLE_CARD_SUPPORT, test "$card_support" = yes)
AM_CONDITIONAL(ENABLE_AGENT_SUPPORT, test "$agent_support" = yes)
dnl Checks for header files.
AC_HEADER_STDC
@ -841,6 +864,7 @@ AC_CHECK_FUNCS(memmove gettimeofday getrusage setrlimit clock_gettime)
AC_CHECK_FUNCS(atexit raise getpagesize strftime nl_langinfo setlocale)
AC_CHECK_FUNCS(waitpid wait4 sigaction sigprocmask rand pipe stat getaddrinfo)
AC_REPLACE_FUNCS(mkdtemp timegm)
AC_REPLACE_FUNCS(isascii)
AC_CHECK_TYPES([struct sigaction, sigset_t],,,[#include <signal.h>])
@ -1260,11 +1284,15 @@ cat >g10defs.tmp <<G10EOF
#define EXTSEP_C '.'
#define DIRSEP_S "\\\\"
#define EXTSEP_S "."
#define PATHSEP_C ';'
#define PATHSEP_S ";"
#else
#define DIRSEP_C '/'
#define EXTSEP_C '.'
#define DIRSEP_S "/"
#define EXTSEP_S "."
#define PATHSEP_C ':'
#define PATHSEP_S ":"
#endif
/* This is the same as VERSION, but should be overridden if the
platform cannot handle things like dots'.' in filenames. Set

View File

@ -1,3 +1,8 @@
2005-04-01 Werner Koch <wk@g10code.com>
* keygen.c (keygen_set_std_prefs): Explain the chosen order of
AES key sizes.
2005-04-01 David Shaw <dshaw@jabberwocky.com>
* mainproc.c (proc_plaintext): Properly handle SIG+LITERAL
@ -11,6 +16,24 @@
2005-03-31 Werner Koch <wk@g10code.com>
* passphrase.c (agent_open): Dropped support for W32 - is was
never actually used. Removed support for the old non-assuan
protocol; there has never been a matured implementation and
gpg-agent is now arround for quite some time. Rewritten to make
use of the Assuan code from ../util.
(gpga_protocol_codes): Removed.
(readn): Removed.
(agent_close): Simplified for use with Assuan.
(agent_get_passphrase, passphrase_clear_cache): Removed support
for old protocol. Use only with ENABLE_CARD_SUPPORT defined.
(agent_send_all_options): Take assuan context instead of a file
descriptor.
(agent_send_option): Likewise. Use assuan_transact.
* passphrase.c (writen, readaline): Removed.
* g10.c (main): Print a warning if --use-agent has been used but
it has not been build with support for it.
* keydb.c (keydb_add_resource): Clarify meaning of flags. Add new
flag 4. Use log_info for errors registering the default secret key.
* g10.c (main): Flag the default keyrings.

View File

@ -2591,6 +2591,14 @@ main( int argc, char **argv )
"--no-literal" );
}
#ifndef ENABLE_AGENT_SUPPORT
if (opt.use_agent) {
log_info(_("NOTE: %s is not available in this version\n"),
"--use-agent");
opt.use_agent = 0;
}
#endif /*!ENABLE_AGENT_SUPPORT*/
if (opt.set_filesize)
log_info(_("NOTE: %s is not for normal use!\n"), "--set-filesize");
if( opt.batch )

View File

@ -50,32 +50,9 @@
#include "main.h"
#include "i18n.h"
#include "status.h"
enum gpga_protocol_codes {
/* Request codes */
GPGA_PROT_GET_VERSION = 1,
GPGA_PROT_GET_PASSPHRASE = 2,
GPGA_PROT_CLEAR_PASSPHRASE= 3,
GPGA_PROT_SHUTDOWN = 4,
GPGA_PROT_FLUSH = 5,
/* Reply codes */
GPGA_PROT_REPLY_BASE = 0x10000,
GPGA_PROT_OKAY = 0x10001,
GPGA_PROT_GOT_PASSPHRASE = 0x10002,
/* Error codes */
GPGA_PROT_ERROR_BASE = 0x20000,
GPGA_PROT_PROTOCOL_ERROR = 0x20001,
GPGA_PROT_INVALID_REQUEST= 0x20002,
GPGA_PROT_CANCELED = 0x20003,
GPGA_PROT_NO_PASSPHRASE = 0x20004,
GPGA_PROT_BAD_PASSPHRASE = 0x20005,
GPGA_PROT_INVALID_DATA = 0x20006,
GPGA_PROT_NOT_IMPLEMENTED= 0x20007,
GPGA_PROT_UI_PROBLEM = 0x20008
};
#ifdef ENABLE_AGENT_SUPPORT
#include "assuan.h"
#endif /*ENABLE_AGENT_SUPPORT*/
#define buftou32( p ) ((*(byte*)(p) << 24) | (*((byte*)(p)+1)<< 16) | \
@ -191,187 +168,29 @@ read_passphrase_from_fd( int fd )
fd_passwd = pw;
}
#ifdef ENABLE_AGENT_SUPPORT
/* Send one option to the gpg-agent. */
static int
writen (int fd, const void *buf, size_t nbytes)
agent_send_option (assuan_context_t ctx, const char *name, const char *value)
{
#if defined (_WIN32)
DWORD nwritten, nleft = nbytes;
while (nleft > 0)
{
if (!WriteFile ((HANDLE)write_fd, buf, nleft, &nwritten, NULL))
{
log_error ("write failed: %s\n", w32_strerror (0));
return -1;
}
/*log_info ("** WriteFile fd=%d nytes=%d nwritten=%d\n",
write_fd, nbytes, (int)nwritten);*/
Sleep (100);
nleft -= nwritten;
buf = (const BYTE *)buf + nwritten;
}
#elif defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
/* not implemented */
#else
size_t nleft = nbytes;
int nwritten;
while (nleft > 0)
{
nwritten = write (fd, buf, nleft);
if (nwritten < 0)
{
if (errno == EINTR)
nwritten = 0;
else
{
log_error ("write() failed: %s\n", strerror (errno));
return -1;
}
}
nleft -= nwritten;
buf = (const char*)buf + nwritten;
}
#endif
return 0;
}
static int
readn (int fd, void *buf, size_t buflen, size_t *ret_nread)
{
#if defined (_WIN32)
DWORD nread, nleft = buflen;
while (nleft > 0)
{
if (!ReadFile ((HANDLE)read_fd, buf, nleft, &nread, NULL))
{
log_error ("read() error: %s\n", w32_strerror (0));
return -1;
}
if (!nread || GetLastError() == ERROR_BROKEN_PIPE)
break;
/*log_info ("** ReadFile fd=%d buflen=%d nread=%d\n",
read_fd, buflen, (int)nread);*/
Sleep (100);
nleft -= nread;
buf = (BYTE *)buf + nread;
}
if (ret_nread)
*ret_nread = buflen - nleft;
#elif defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
/* not implemented */
#else
size_t nleft = buflen;
int nread;
char *p;
p = buf;
while( nleft > 0 )
{
nread = read ( fd, buf, nleft );
if( nread < 0 )
{
if (errno == EINTR)
nread = 0;
else
{
log_error ( "read() error: %s\n", strerror (errno) );
return -1;
}
}
else if (!nread)
break; /* EOF */
nleft -= nread;
buf = (char*)buf + nread;
}
if (ret_nread)
*ret_nread = buflen - nleft;
#endif
return 0;
}
/* read an entire line */
static int
readaline (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 -1; /* read error */
}
else if (!n)
{
return -1; /* 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 temporary hack until we use
the assuna lib in gpg. So it is okay to forget
about pending bytes */
}
}
return nread;
}
#if !defined (__riscos__)
#if !defined (_WIN32)
/* For the new Assuan protocol we may have to send options */
static int
agent_send_option (int fd, const char *name, const char *value)
{
char buf[200];
int nread;
char *line;
int i;
int rc;
line = m_alloc (7 + strlen (name) + 1 + strlen (value) + 2);
strcpy (stpcpy (stpcpy (stpcpy (
stpcpy (line, "OPTION "), name), "="), value), "\n");
i = writen (fd, line, strlen (line));
m_free (line);
if (i)
return -1;
/* get response */
nread = readaline (fd, buf, DIM(buf)-1);
if (nread < 3)
return -1;
if (buf[0] == 'O' && buf[1] == 'K' && (buf[2] == ' ' || buf[2] == '\n'))
return 0; /* okay */
if (!value || !*value)
return 0; /* Avoid sending empty option values. */
return -1;
line = xmalloc (7 + strlen (name) + 1 + strlen (value) + 1);
strcpy (stpcpy (stpcpy (stpcpy (line, "OPTION "), name), "="), value);
rc = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
xfree (line);
return rc? -1 : 0;
}
/* Send all required options to the gpg-agent. */
static int
agent_send_all_options (int fd)
agent_send_all_options (assuan_context_t ctx)
{
char *dft_display = NULL;
const char *dft_ttyname = NULL;
@ -383,7 +202,7 @@ agent_send_all_options (int fd)
dft_display = getenv ("DISPLAY");
if (opt.display || dft_display)
{
if (agent_send_option (fd, "display",
if (agent_send_option (ctx, "display",
opt.display ? opt.display : dft_display))
return -1;
}
@ -400,7 +219,7 @@ agent_send_all_options (int fd)
}
if (opt.ttyname || dft_ttyname)
{
if (agent_send_option (fd, "ttyname",
if (agent_send_option (ctx, "ttyname",
opt.ttyname ? opt.ttyname : dft_ttyname))
return -1;
}
@ -408,7 +227,7 @@ agent_send_all_options (int fd)
dft_ttytype = getenv ("TERM");
if (opt.ttytype || (dft_ttyname && dft_ttytype))
{
if (agent_send_option (fd, "ttytype",
if (agent_send_option (ctx, "ttytype",
opt.ttyname ? opt.ttytype : dft_ttytype))
return -1;
}
@ -421,7 +240,7 @@ agent_send_all_options (int fd)
#endif
if (opt.lc_ctype || (dft_ttyname && dft_lc))
{
rc = agent_send_option (fd, "lc-ctype",
rc = agent_send_option (ctx, "lc-ctype",
opt.lc_ctype ? opt.lc_ctype : dft_lc);
}
#if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
@ -442,7 +261,7 @@ agent_send_all_options (int fd)
#endif
if (opt.lc_messages || (dft_ttyname && dft_lc))
{
rc = agent_send_option (fd, "lc-messages",
rc = agent_send_option (ctx, "lc-messages",
opt.lc_messages ? opt.lc_messages : dft_lc);
}
#if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
@ -454,170 +273,147 @@ agent_send_all_options (int fd)
#endif
return rc;
}
#endif /*!_WIN32*/
#endif /*ENABLE_AGENT_SUPPORT*/
/*
* Open a connection to the agent and send the magic string
* Returns: -1 on error or an filedescriptor for urther processing
* Open a connection to the agent and initializes the connection.
* Returns: -1 on error; on success a file descriptor for that
* connection is returned.
*/
static int
agent_open (int *ret_prot)
#ifdef ENABLE_AGENT_SUPPORT
static assuan_context_t
agent_open (void)
{
#if defined (_WIN32)
int fd;
char *infostr, *p;
HANDLE h;
char pidstr[128];
int rc;
assuan_context_t ctx;
char *infostr, *p;
int prot;
int pid;
*ret_prot = 0;
if ( !(infostr = read_w32_registry_string(NULL, "Software\\GNU\\GnuPG",
"agentPID"))
|| *infostr == '0') {
log_error( _("gpg-agent is not available in this session\n"));
return -1;
}
free(infostr);
sprintf(pidstr, "%u", (unsigned int)GetCurrentProcessId());
if (write_w32_registry_string(NULL, "Software\\GNU\\GnuPG",
"agentCID", pidstr)) {
log_error( _("can't set client pid for the agent\n") );
return -1;
}
h = OpenEvent(EVENT_ALL_ACCESS, FALSE, "gpg_agent");
SetEvent(h);
Sleep(50); /* some time for the server */
if ( !(p = read_w32_registry_string(NULL, "Software\\GNU\\GnuPG",
"agentReadFD")) ) {
log_error( _("can't get server read FD for the agent\n") );
return -1;
}
read_fd = atol(p);
free(p);
if ( !(p = read_w32_registry_string(NULL, "Software\\GNU\\GnuPG",
"agentWriteFD")) ) {
log_error ( _("can't get server write FD for the agent\n") );
return -1;
}
write_fd = atol(p);
free(p);
fd = 0;
if ( writen ( fd, "GPGA\0\0\0\x01", 8 ) ) {
fd = -1;
}
#else /* Posix */
int fd;
char *infostr, *p;
struct sockaddr_un client_addr;
size_t len;
int prot;
if (opt.gpg_agent_info)
infostr = m_strdup (opt.gpg_agent_info);
else
{
infostr = getenv ( "GPG_AGENT_INFO" );
if ( !infostr ) {
if (opt.gpg_agent_info)
infostr = xstrdup (opt.gpg_agent_info);
else
{
infostr = getenv ( "GPG_AGENT_INFO" );
if (!infostr || !*infostr)
{
log_error (_("gpg-agent is not available in this session\n"));
opt.use_agent = 0;
return -1;
return NULL;
}
infostr = m_strdup ( infostr );
}
infostr = xstrdup ( infostr );
}
if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
{
log_error ( _("malformed GPG_AGENT_INFO environment variable\n"));
xfree (infostr);
opt.use_agent = 0;
return NULL;
}
*p++ = 0;
pid = atoi (p);
while (*p && *p != PATHSEP_C)
p++;
prot = *p? atoi (p+1) : 0;
if (prot != 1)
{
log_error (_("gpg-agent protocol version %d is not supported\n"), prot);
xfree (infostr);
opt.use_agent = 0;
return NULL;
}
rc = assuan_socket_connect (&ctx, infostr, pid);
if (rc)
{
log_error ( _("can't connect to `%s': %s\n"),
infostr, assuan_strerror (rc));
xfree (infostr );
opt.use_agent = 0;
return NULL;
}
xfree (infostr);
if ( !(p = strchr ( infostr, ':')) || p == infostr
|| (p-infostr)+1 >= sizeof client_addr.sun_path ) {
log_error( _("malformed GPG_AGENT_INFO environment variable\n"));
m_free (infostr );
opt.use_agent = 0;
return -1;
if (agent_send_all_options (ctx))
{
log_error (_("problem with the agent - disabling agent use\n"));
assuan_disconnect (ctx);
opt.use_agent = 0;
return NULL;
}
*p++ = 0;
/* See whether this is the new gpg-agent using the Assuna protocl.
This agent identifies itself by have an info string with a
version number in the 3rd field. */
while (*p && *p != ':')
p++;
prot = *p? atoi (p+1) : 0;
if ( prot < 0 || prot > 1) {
log_error (_("gpg-agent protocol version %d is not supported\n"),prot);
m_free (infostr );
opt.use_agent = 0;
return -1;
}
*ret_prot = prot;
if( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1 ) {
log_error ("can't create socket: %s\n", strerror(errno) );
m_free (infostr );
opt.use_agent = 0;
return -1;
}
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 ) {
log_error ( _("can't connect to `%s': %s\n"),
infostr, strerror (errno) );
m_free (infostr );
close (fd );
opt.use_agent = 0;
return -1;
}
m_free (infostr);
if (!prot) {
if ( writen ( fd, "GPGA\0\0\0\x01", 8 ) ) {
close (fd);
fd = -1;
}
}
else { /* assuan based gpg-agent */
char line[200];
int nread;
nread = readaline (fd, line, DIM(line));
if (nread < 3 || !(line[0] == 'O' && line[1] == 'K'
&& (line[2] == '\n' || line[2] == ' ')) ) {
log_error ( _("communication problem with gpg-agent\n"));
close (fd );
opt.use_agent = 0;
return -1;
}
if (agent_send_all_options (fd)) {
log_error (_("problem with the agent - disabling agent use\n"));
close (fd);
opt.use_agent = 0;
return -1;
}
}
#endif
return fd;
return ctx;
}
#endif/*ENABLE_AGENT_SUPPORT*/
#ifdef ENABLE_AGENT_SUPPORT
static void
agent_close ( int fd )
agent_close (assuan_context_t ctx)
{
#if defined (_WIN32)
HANDLE h = OpenEvent(EVENT_ALL_ACCESS, FALSE, "gpg_agent");
ResetEvent(h);
#else
close (fd);
#endif
assuan_disconnect (ctx);
}
#endif /* !__riscos__ */
#endif /*ENABLE_AGENT_SUPPORT*/
/* Copy the text ATEXT into the buffer P and do plus '+' and percent
escaping. Note that the provided buffer needs to be 3 times the
size of ATEXT plus 1. Returns a pointer to the leading Nul in P. */
#ifdef ENABLE_AGENT_SUPPORT
static char *
percent_plus_escape (char *p, const char *atext)
{
const unsigned char *s;
for (s=atext; *s; s++)
{
if (*s < ' ' || *s == '+')
{
sprintf (p, "%%%02X", *s);
p += 3;
}
else if (*s == ' ')
*p++ = '+';
else
*p++ = *s;
}
*p = 0;
return p;
}
#endif /*ENABLE_AGENT_SUPPORT*/
#ifdef ENABLE_AGENT_SUPPORT
/* Object for the agent_okay_cb function. */
struct agent_okay_cb_s {
char *pw;
};
/* A callback used to get the passphrase from the okay line. See
agent-get_passphrase for details. LINE is the rest of the OK
status line without leading white spaces. */
static assuan_error_t
agent_okay_cb (void *opaque, const char *line)
{
struct agent_okay_cb_s *parm = opaque;
int i;
/* Note: If the malloc below fails we won't be able to wipe the
memory at LINE given the current implementation of the Assuan
code. There is no easy ay around this w/o adding a lot of more
memory function code to allow wiping arbitrary stuff on memory
failure. */
parm->pw = xmalloc_secure (strlen (line)/2+2);
for (i=0; hexdigitp (line) && hexdigitp (line+1); line += 2)
parm->pw[i++] = xtoi_2 (line);
parm->pw[i] = 0;
return 0;
}
#endif /*ENABLE_AGENT_SUPPORT*/
@ -636,19 +432,13 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text,
const char *custom_description,
const char *custom_prompt, int *canceled)
{
#if defined(__riscos__)
return NULL;
#else
size_t n;
#ifdef ENABLE_AGENT_SUPPORT
char *atext = NULL;
char buf[50];
int fd = -1;
u32 reply;
assuan_context_t ctx = NULL;
char *pw = NULL;
PKT_public_key *pk = m_alloc_clear( sizeof *pk );
byte fpr[MAX_FINGERPRINT_LEN];
int have_fpr = 0;
int prot;
char *orig_codeset = NULL;
if (canceled)
@ -667,7 +457,7 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text,
}
#ifdef ENABLE_NLS
/* The Assuan agent protol requires us to transmit utf-8 strings */
/* The Assuan agent protocol requires us to transmit utf-8 strings */
orig_codeset = bind_textdomain_codeset (PACKAGE, NULL);
#ifdef HAVE_LANGINFO_CODESET
if (!orig_codeset)
@ -681,7 +471,7 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text,
}
#endif
if ( (fd = agent_open (&prot)) == -1 )
if ( !(ctx = agent_open ()) )
goto failure;
if (custom_description)
@ -740,100 +530,23 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text,
else
atext = m_strdup ( _("Enter passphrase\n") );
if (!prot)
{ /* old style protocol */
size_t nread;
n = 4 + 20 + strlen (atext);
u32tobuf (buf, n );
u32tobuf (buf+4, GPGA_PROT_GET_PASSPHRASE );
memcpy (buf+8, fpr, 20 );
if ( writen ( fd, buf, 28 ) || writen ( fd, atext, strlen (atext) ) )
goto failure;
m_free (atext); atext = NULL;
/* get response */
if ( readn ( fd, buf, 12, &nread ) )
goto failure;
if ( nread < 8 )
{
log_error ( "response from agent too short\n" );
goto failure;
}
n = buftou32 ( buf );
reply = buftou32 ( buf + 4 );
if ( reply == GPGA_PROT_GOT_PASSPHRASE )
{
size_t pwlen;
size_t nn;
if ( nread < 12 || n < 8 )
{
log_error ( "response from agent too short\n" );
goto failure;
}
pwlen = buftou32 ( buf + 8 );
nread -= 12;
n -= 8;
if ( pwlen > n || n > 1000 )
{
log_error (_("passphrase too long\n"));
/* or protocol error */
goto failure;
}
/* we read the whole block in one chunk to give no hints
* on how long the passhrase actually is - this wastes some bytes
* but because we already have this padding we should not loosen
* this by issuing 2 read calls */
pw = m_alloc_secure ( n+1 );
if ( readn ( fd, pw, n, &nn ) )
goto failure;
if ( n != nn )
{
log_error (_("invalid response from agent\n"));
goto failure;
}
pw[pwlen] = 0; /* make a C String */
agent_close (fd);
if (pk)
free_public_key( pk );
#ifdef ENABLE_NLS
if (orig_codeset)
bind_textdomain_codeset (PACKAGE, orig_codeset);
#endif
m_free (orig_codeset);
return pw;
}
else if ( reply == GPGA_PROT_CANCELED )
{
log_info ( _("cancelled by user\n") );
if (canceled)
*canceled = 1;
}
else
log_error ( _("problem with the agent: agent returns 0x%lx\n"),
(ulong)reply );
}
else
{ /* The new Assuan protocol */
int nread;
{
char *line, *p;
const unsigned char *s;
int i;
int i, rc;
struct agent_okay_cb_s okay_cb_parm;
if (!tryagain_text)
tryagain_text = "X";
else
tryagain_text = _(tryagain_text);
/* We allocate 2 time the needed space for atext so that there
is enough space for escaping */
line = m_alloc (15 + 46
+ 3*strlen (tryagain_text)
/* We allocate 23 times the needed space for thye texts so that
there is enough space for escaping. */
line = xmalloc (15 + 46
+ 3*strlen (atext)
+ 3*strlen (custom_prompt? custom_prompt:"")
+ 2);
+ 3*strlen (tryagain_text)
+ 1);
strcpy (line, "GET_PASSPHRASE ");
p = line+15;
if (!mode && have_fpr)
@ -842,92 +555,50 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text,
sprintf (p, "%02X", fpr[i]);
}
else
*p++ = 'X'; /* no caching */
*p++ = 'X'; /* No caching. */
*p++ = ' ';
for (i=0, s=tryagain_text; *s; s++)
{
if (*s < ' ' || *s == '+')
{
sprintf (p, "%%%02X", *s);
p += 3;
}
else if (*s == ' ')
*p++ = '+';
else
*p++ = *s;
}
p = percent_plus_escape (p, tryagain_text);
*p++ = ' ';
/* The prompt. */
if (custom_prompt)
{
char *tmp = native_to_utf8 (custom_prompt);
for (i=0, s=tmp; *s; s++)
{
if (*s < ' ' || *s == '+')
{
sprintf (p, "%%%02X", *s);
p += 3;
}
else if (*s == ' ')
*p++ = '+';
else
*p++ = *s;
}
p = percent_plus_escape (p, tmp);
xfree (tmp);
}
else
*p++ = 'X'; /* Use the standard prompt */
*p++ = 'X'; /* Use the standard prompt. */
*p++ = ' ';
/* copy description */
for (i=0, s= atext; *s; s++)
{
if (*s < ' ' || *s == '+')
{
sprintf (p, "%%%02X", *s);
p += 3;
}
else if (*s == ' ')
*p++ = '+';
else
*p++ = *s;
}
*p++ = '\n';
i = writen (fd, line, p - line);
m_free (line);
if (i)
goto failure;
m_free (atext); atext = NULL;
/* get response */
pw = m_alloc_secure (500);
nread = readaline (fd, pw, 499);
if (nread < 3)
goto failure;
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 */
agent_close (fd);
/* Copy description. */
percent_plus_escape (p, atext);
/* Call gpg-agent. */
memset (&okay_cb_parm, 0, sizeof okay_cb_parm);
rc = assuan_transact2 (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL,
agent_okay_cb, &okay_cb_parm);
xfree (line);
xfree (atext); atext = NULL;
if (!rc)
{
assert (okay_cb_parm.pw);
pw = okay_cb_parm.pw;
agent_close (ctx);
if (pk)
free_public_key( pk );
#ifdef ENABLE_NLS
if (orig_codeset)
bind_textdomain_codeset (PACKAGE, orig_codeset);
#endif
m_free (orig_codeset);
xfree (orig_codeset);
return pw;
}
else if (nread > 4 && !memcmp (pw, "ERR ", 4)
&& (0xffff & strtoul (&pw[4], NULL, 0)) == 99)
else if (rc && (rc & 0xffff) == 99)
{
/* 99 is GPG_ERR_CANCELED. FIXME: Check tail and overflow,
and use gpg-error. */
/* 99 is GPG_ERR_CANCELED. */
log_info (_("cancelled by user\n") );
if (canceled)
*canceled = 1;
@ -937,7 +608,7 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text,
log_error (_("problem with the agent - disabling agent use\n"));
opt.use_agent = 0;
}
}
}
failure:
@ -945,34 +616,28 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text,
if (orig_codeset)
bind_textdomain_codeset (PACKAGE, orig_codeset);
#endif
m_free (atext);
if ( fd != -1 )
agent_close (fd);
m_free (pw );
xfree (atext);
agent_close (ctx);
xfree (pw );
if (pk)
free_public_key( pk );
#endif /*ENABLE_AGENT_SUPPORT*/
return NULL;
#endif /* Posix or W32 */
}
/*
* Clear the cached passphrase
*/
void
passphrase_clear_cache ( u32 *keyid, int algo )
{
#if defined(__riscos__)
return ;
#else
size_t n;
char buf[200];
int fd = -1;
size_t nread;
u32 reply;
#ifdef ENABLE_AGENT_SUPPORT
assuan_context_t ctx = NULL;
PKT_public_key *pk;
byte fpr[MAX_FINGERPRINT_LEN];
int prot;
#if MAX_FINGERPRINT_LEN < 20
#error agent needs a 20 byte fingerprint
@ -981,7 +646,7 @@ passphrase_clear_cache ( u32 *keyid, int algo )
if (!opt.use_agent)
return;
pk = m_alloc_clear ( sizeof *pk );
pk = xcalloc (1, sizeof *pk);
memset (fpr, 0, MAX_FINGERPRINT_LEN );
if( !keyid || get_pubkey( pk, keyid ) )
{
@ -993,58 +658,23 @@ passphrase_clear_cache ( u32 *keyid, int algo )
fingerprint_from_pk( pk, fpr, &dummy );
}
if ( (fd = agent_open (&prot)) == -1 )
if ( !(ctx = agent_open ()) )
goto failure;
if (!prot)
{
n = 4 + 20;
u32tobuf (buf, n );
u32tobuf (buf+4, GPGA_PROT_CLEAR_PASSPHRASE );
memcpy (buf+8, fpr, 20 );
if ( writen ( fd, buf, 28 ) )
goto failure;
/* get response */
if ( readn ( fd, buf, 8, &nread ) )
goto failure;
if ( nread < 8 ) {
log_error ( "response from agent too short\n" );
goto failure;
}
reply = buftou32 ( buf + 4 );
if ( reply != GPGA_PROT_OKAY && reply != GPGA_PROT_NO_PASSPHRASE )
{
log_error ( _("problem with the agent: agent returns 0x%lx\n"),
(ulong)reply );
}
}
else
{ /* The assuan protocol */
{
char *line, *p;
int i;
int i, rc;
line = m_alloc (17 + 40 + 2);
line = xmalloc (17 + 40 + 2);
strcpy (line, "CLEAR_PASSPHRASE ");
p = line+17;
for (i=0; i < 20; i++, p +=2 )
sprintf (p, "%02X", fpr[i]);
*p++ = '\n';
i = writen (fd, line, p - line);
m_free (line);
if (i)
goto failure;
/* get response */
nread = readaline (fd, buf, DIM(buf)-1);
if (nread < 3)
goto failure;
if (buf[0] == 'O' && buf[1] == 'K' && (buf[2] == ' ' || buf[2] == '\n'))
;
else
*p = 0;
rc = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
xfree (line);
if (rc)
{
log_error (_("problem with the agent - disabling agent use\n"));
opt.use_agent = 0;
@ -1052,11 +682,10 @@ passphrase_clear_cache ( u32 *keyid, int algo )
}
failure:
if (fd != -1)
agent_close (fd);
agent_close (ctx);
if (pk)
free_public_key( pk );
#endif /* Posix or W32 */
#endif /*ENABLE_AGENT_SUPPORT*/
}

View File

@ -1,3 +1,11 @@
2005-04-04 Werner Koch <wk@g10code.com>
* memory.h (xcalloc, xcalloc_secure): Replaced macros by functions.
2005-03-31 Werner Koch <wk@g10code.com>
* assuan.h: New. Taken from libassuan 0.6.9.
2005-03-18 David Shaw <dshaw@jabberwocky.com>
* ttyio.h: Prototype tty_enable_completion(), and
@ -506,7 +514,7 @@ Tue Mar 3 15:11:21 1998 Werner Koch (wk@isil.d.shuttle.de)
Copyright 1998, 1999, 2000, 2001, 2002, 2003,
2004 Free Software Foundation, Inc.
2004, 2005 Free Software Foundation, Inc.
This file is free software; as a special exception the author gives
unlimited permission to copy and/or distribute it, with or without

261
include/assuan.h Normal file
View File

@ -0,0 +1,261 @@
/* assuan.c - Definitions for the Assuan protocol
* Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
* Copyright (C) 2005 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Assuan 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*/
/* Please note that this is a stripped down and modified version of
the orginal Assuan code from libassuan. For the standalone version
of gnupg we only need the ability to connect to a server, so we
dropped everything else and maintain this separate copy. */
#ifndef ASSUAN_H
#define ASSUAN_H
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
typedef enum
{
ASSUAN_No_Error = 0,
ASSUAN_General_Error = 1,
ASSUAN_Out_Of_Core = 2,
ASSUAN_Invalid_Value = 3,
ASSUAN_Timeout = 4,
ASSUAN_Read_Error = 5,
ASSUAN_Write_Error = 6,
ASSUAN_Problem_Starting_Server = 7,
ASSUAN_Not_A_Server = 8,
ASSUAN_Not_A_Client = 9,
ASSUAN_Nested_Commands = 10,
ASSUAN_Invalid_Response = 11,
ASSUAN_No_Data_Callback = 12,
ASSUAN_No_Inquire_Callback = 13,
ASSUAN_Connect_Failed = 14,
ASSUAN_Accept_Failed = 15,
/* Error codes above 99 are meant as status codes */
ASSUAN_Not_Implemented = 100,
ASSUAN_Server_Fault = 101,
ASSUAN_Invalid_Command = 102,
ASSUAN_Unknown_Command = 103,
ASSUAN_Syntax_Error = 104,
ASSUAN_Parameter_Error = 105,
ASSUAN_Parameter_Conflict = 106,
ASSUAN_Line_Too_Long = 107,
ASSUAN_Line_Not_Terminated = 108,
ASSUAN_No_Input = 109,
ASSUAN_No_Output = 110,
ASSUAN_Canceled = 111,
ASSUAN_Unsupported_Algorithm = 112,
ASSUAN_Server_Resource_Problem = 113,
ASSUAN_Server_IO_Error = 114,
ASSUAN_Server_Bug = 115,
ASSUAN_No_Data_Available = 116,
ASSUAN_Invalid_Data = 117,
ASSUAN_Unexpected_Command = 118,
ASSUAN_Too_Much_Data = 119,
ASSUAN_Inquire_Unknown = 120,
ASSUAN_Inquire_Error = 121,
ASSUAN_Invalid_Option = 122,
ASSUAN_Invalid_Index = 123,
ASSUAN_Unexpected_Status = 124,
ASSUAN_Unexpected_Data = 125,
ASSUAN_Invalid_Status = 126,
ASSUAN_Locale_Problem = 127,
ASSUAN_Not_Confirmed = 128,
/* Error codes in the range 1000 to 9999 may be used by applications
at their own discretion. */
ASSUAN_USER_ERROR_FIRST = 1000,
ASSUAN_USER_ERROR_LAST = 9999
} assuan_error_t;
#define ASSUAN_LINELENGTH 1002 /* 1000 + [CR,]LF */
struct assuan_context_s;
typedef struct assuan_context_s *assuan_context_t;
/*-- assuan-handler.c --*/
int assuan_register_command (assuan_context_t ctx,
const char *cmd_string,
int (*handler)(assuan_context_t, char *));
int assuan_register_bye_notify (assuan_context_t ctx,
void (*fnc)(assuan_context_t));
int assuan_register_reset_notify (assuan_context_t ctx,
void (*fnc)(assuan_context_t));
int assuan_register_cancel_notify (assuan_context_t ctx,
void (*fnc)(assuan_context_t));
int assuan_register_input_notify (assuan_context_t ctx,
void (*fnc)(assuan_context_t, const char *));
int assuan_register_output_notify (assuan_context_t ctx,
void (*fnc)(assuan_context_t, const char *));
int assuan_register_option_handler (assuan_context_t ctx,
int (*fnc)(assuan_context_t,
const char*, const char*));
int assuan_process (assuan_context_t ctx);
int assuan_process_next (assuan_context_t ctx);
int assuan_get_active_fds (assuan_context_t ctx, int what,
int *fdarray, int fdarraysize);
FILE *assuan_get_data_fp (assuan_context_t ctx);
assuan_error_t assuan_set_okay_line (assuan_context_t ctx, const char *line);
assuan_error_t assuan_write_status (assuan_context_t ctx,
const char *keyword, const char *text);
/* Negotiate a file descriptor. If LINE contains "FD=N", returns N
assuming a local file descriptor. If LINE contains "FD" reads a
file descriptor via CTX and stores it in *RDF (the CTX must be
capable of passing file descriptors). */
assuan_error_t assuan_command_parse_fd (assuan_context_t ctx, char *line,
int *rfd);
/*-- assuan-listen.c --*/
assuan_error_t assuan_set_hello_line (assuan_context_t ctx, const char *line);
assuan_error_t assuan_accept (assuan_context_t ctx);
int assuan_get_input_fd (assuan_context_t ctx);
int assuan_get_output_fd (assuan_context_t ctx);
assuan_error_t assuan_close_input_fd (assuan_context_t ctx);
assuan_error_t assuan_close_output_fd (assuan_context_t ctx);
/*-- assuan-pipe-server.c --*/
int assuan_init_pipe_server (assuan_context_t *r_ctx, int filedes[2]);
void assuan_deinit_server (assuan_context_t ctx);
/*-- assuan-socket-server.c --*/
int assuan_init_socket_server (assuan_context_t *r_ctx, int listen_fd);
int assuan_init_connected_socket_server (assuan_context_t *r_ctx, int fd);
/*-- assuan-pipe-connect.c --*/
assuan_error_t assuan_pipe_connect (assuan_context_t *ctx, const char *name,
char *const argv[], int *fd_child_list);
assuan_error_t assuan_pipe_connect2 (assuan_context_t *ctx, const char *name,
char *const argv[], int *fd_child_list,
void (*atfork) (void*, int),
void *atforkvalue);
/*-- assuan-socket-connect.c --*/
assuan_error_t assuan_socket_connect (assuan_context_t *ctx, const char *name,
pid_t server_pid);
/*-- assuan-domain-connect.c --*/
/* Connect to a Unix domain socket server. RENDEZVOUSFD is
bidirectional file descriptor (normally returned via socketpair)
which the client can use to rendezvous with the server. SERVER s
the server's pid. */
assuan_error_t assuan_domain_connect (assuan_context_t *r_ctx,
int rendezvousfd,
pid_t server);
/*-- assuan-domain-server.c --*/
/* RENDEZVOUSFD is a bidirectional file descriptor (normally returned
via socketpair) that the domain server can use to rendezvous with
the client. CLIENT is the client's pid. */
assuan_error_t assuan_init_domain_server (assuan_context_t *r_ctx,
int rendezvousfd,
pid_t client);
/*-- assuan-connect.c --*/
void assuan_disconnect (assuan_context_t ctx);
pid_t assuan_get_pid (assuan_context_t ctx);
/*-- assuan-client.c --*/
assuan_error_t
assuan_transact (assuan_context_t ctx,
const char *command,
assuan_error_t (*data_cb)(void *, const void *, size_t),
void *data_cb_arg,
assuan_error_t (*inquire_cb)(void*, const char *),
void *inquire_cb_arg,
assuan_error_t (*status_cb)(void*, const char *),
void *status_cb_arg);
assuan_error_t
assuan_transact2 (assuan_context_t ctx,
const char *command,
assuan_error_t (*data_cb)(void *, const void *, size_t),
void *data_cb_arg,
assuan_error_t (*inquire_cb)(void*, const char *),
void *inquire_cb_arg,
assuan_error_t (*status_cb)(void*, const char *),
void *status_cb_arg,
assuan_error_t (*okay_cb)(void*, const char *),
void *okay_cb_arg);
/*-- assuan-inquire.c --*/
assuan_error_t assuan_inquire (assuan_context_t ctx, const char *keyword,
unsigned char **r_buffer, size_t *r_length,
size_t maxlen);
/*-- assuan-buffer.c --*/
assuan_error_t assuan_read_line (assuan_context_t ctx,
char **line, size_t *linelen);
int assuan_pending_line (assuan_context_t ctx);
assuan_error_t assuan_write_line (assuan_context_t ctx, const char *line );
assuan_error_t assuan_send_data (assuan_context_t ctx,
const void *buffer, size_t length);
/*-- assuan-util.c --*/
void assuan_set_malloc_hooks ( void *(*new_alloc_func)(size_t n),
void *(*new_realloc_func)(void *p, size_t n),
void (*new_free_func)(void*) );
void assuan_set_log_stream (assuan_context_t ctx, FILE *fp);
int assuan_set_error (assuan_context_t ctx, int err, const char *text);
void assuan_set_pointer (assuan_context_t ctx, void *pointer);
void *assuan_get_pointer (assuan_context_t ctx);
void assuan_begin_confidential (assuan_context_t ctx);
void assuan_end_confidential (assuan_context_t ctx);
/*-- assuan-errors.c (built) --*/
const char *assuan_strerror (assuan_error_t err);
/*-- assuan-logging.c --*/
/* Set the stream to which assuan should log message not associated
with a context. By default, this is stderr. The default value
will be changed when the first log stream is associated with a
context. Note, that this function is not thread-safe and should
in general be used right at startup. */
extern void assuan_set_assuan_log_stream (FILE *fp);
/* Return the stream which is currently being using for global logging. */
extern FILE *assuan_get_assuan_log_stream (void);
/* Set the prefix to be used at the start of a line emitted by assuan
on the log stream. The default is the empty string. Note, that
this function is not thread-safe and should in general be used
right at startup. */
void assuan_set_assuan_log_prefix (const char *text);
/* Return a prefix to be used at the start of a line emitted by assuan
on the log stream. The default implementation returns the empty
string, i.e. "" */
const char *assuan_get_assuan_log_prefix (void);
#endif /* ASSUAN_H */

View File

@ -1,5 +1,5 @@
/* memory.h - memory allocation
* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
* Copyright (C) 1998, 1999, 2000, 2001, 2005 Free Software Foundation, Inc.
*
* This file is part of GNUPG.
*
@ -93,9 +93,9 @@ EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode;
/* To prepare a migration to the xmalloc suite of function as used in
1.9 we define a couple of macros. */
#define xmalloc(n) m_alloc ((n))
#define xcalloc(n,m) m_alloc_clear ((n)*(m))
void *xcalloc (size_t n, size_t m);
#define xmalloc_secure(n) m_alloc_secure (n)
#define xcalloc_secure(n) m_alloc_secure_clear ((n)*(m))
void *xcalloc_secure (size_t n, size_t m);
#define xrealloc(a,n) m_realloc ((a),(n))
#define xstrdup(a) m_strdup ((a))
#define xfree(a) m_free (a)

View File

@ -1,3 +1,22 @@
2005-04-04 Werner Koch <wk@g10code.com>
* memory.c (xcalloc, xcalloc_secure): New wrappers.
* assuan-client.c (assuan_transact): Factored all code out to ..
(assuan_transact2): .. new. Add arg OKAY_CB. Wipe the memory
processed though that callback.
2005-03-31 Werner Koch <wk@g10code.com>
* isascii.c: New. This is an autoconf replacement function.
* Makefile.am (assuan_source): New. Only used when agent support
has been requested.
* assuan-buffer.c, assuan-client.c, assuan-defs.h,
* assuan-errors.c, assuan-logging.c, assuan-socket-connect.c,
* assuan-socket.c, assuan-util.c, assuan-connect.c: New. Taken
from libassuan 0.6.9 and adjusted for our limited use of Assuan.
2005-03-18 David Shaw <dshaw@jabberwocky.com>
* ttyio.c (tty_enable_completion, tty_disable_completion): Enable

View File

@ -1,4 +1,4 @@
# Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
# Copyright (C) 1998, 1999, 2000, 2001, 2005 Free Software Foundation, Inc.
#
# This file is part of GnuPG.
#
@ -22,12 +22,24 @@ INCLUDES = -I.. -I$(top_srcdir)/include -I$(top_srcdir)/intl
noinst_LIBRARIES = libutil.a
EXTRA_libutil_a_SOURCES = regcomp.c regex.c regexec.c regex_internal.c regex_internal.h
EXTRA_libutil_a_SOURCES = regcomp.c regex.c regexec.c regex_internal.c \
regex_internal.h
# We build the assuan support only if it has been requested.
if ENABLE_AGENT_SUPPORT
assuan_source = assuan-buffer.c assuan-client.c assuan-defs.h \
assuan-errors.c assuan-logging.c assuan-socket-connect.c \
assuan-connect.c assuan-socket.c assuan-util.c
else
assuan_source =
endif
#libutil_a_LDFLAGS =
libutil_a_SOURCES = logger.c fileutil.c miscutil.c strgutil.c \
ttyio.c argparse.c memory.c secmem.c errors.c iobuf.c \
dotlock.c http.c srv.h srv.c simple-gettext.c w32reg.c
dotlock.c http.c srv.h srv.c simple-gettext.c \
w32reg.c $(assuan_source)
libutil_a_DEPENDENCIES = @LIBOBJS@ @REGEX_O@
# LIBOBJS is for the replacement functions

480
util/assuan-buffer.c Normal file
View File

@ -0,0 +1,480 @@
/* assuan-buffer.c - read and send data
* Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Assuan 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*/
/* Please note that this is a stripped down and modified version of
the orginal Assuan code from libassuan. */
#include <config.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <assert.h>
#ifdef HAVE_W32_SYSTEM
#include <process.h>
#endif
#include "assuan-defs.h"
static int
writen (assuan_context_t ctx, const char *buffer, size_t length)
{
while (length)
{
ssize_t nwritten = ctx->io->writefnc (ctx, buffer, length);
if (nwritten < 0)
{
if (errno == EINTR)
continue;
return -1; /* write error */
}
length -= nwritten;
buffer += nwritten;
}
return 0; /* okay */
}
/* Read an entire line. */
static int
readaline (assuan_context_t ctx, char *buf, size_t buflen,
int *r_nread, int *r_eof)
{
size_t nleft = buflen;
char *p;
*r_eof = 0;
*r_nread = 0;
while (nleft > 0)
{
ssize_t n = ctx->io->readfnc (ctx, buf, nleft);
if (n < 0)
{
if (errno == EINTR)
continue;
return -1; /* read error */
}
else if (!n)
{
*r_eof = 1;
break; /* allow incomplete lines */
}
p = buf;
nleft -= n;
buf += n;
*r_nread += n;
p = memrchr (p, '\n', n);
if (p)
break; /* at least one full line available - that's enough for now */
}
return 0;
}
int
_assuan_read_line (assuan_context_t ctx)
{
char *line = ctx->inbound.line;
int nread, atticlen;
int rc;
char *endp = 0;
if (ctx->inbound.eof)
return -1;
atticlen = ctx->inbound.attic.linelen;
if (atticlen)
{
memcpy (line, ctx->inbound.attic.line, atticlen);
ctx->inbound.attic.linelen = 0;
endp = memchr (line, '\n', atticlen);
if (endp)
/* Found another line in the attic. */
{
rc = 0;
nread = atticlen;
atticlen = 0;
}
else
/* There is pending data but not a full line. */
{
assert (atticlen < LINELENGTH);
rc = readaline (ctx, line + atticlen,
LINELENGTH - atticlen, &nread, &ctx->inbound.eof);
}
}
else
/* No pending data. */
rc = readaline (ctx, line, LINELENGTH,
&nread, &ctx->inbound.eof);
if (rc)
{
if (ctx->log_fp)
fprintf (ctx->log_fp, "%s[%u.%p] DBG: <- [Error: %s]\n",
assuan_get_assuan_log_prefix (),
(unsigned int)getpid (), ctx, strerror (errno));
return ASSUAN_Read_Error;
}
if (!nread)
{
assert (ctx->inbound.eof);
if (ctx->log_fp)
fprintf (ctx->log_fp, "%s[%u.%p] DBG: <- [EOF]\n",
assuan_get_assuan_log_prefix (),
(unsigned int)getpid (), ctx);
return -1;
}
ctx->inbound.attic.pending = 0;
nread += atticlen;
if (! endp)
endp = memchr (line, '\n', nread);
if (endp)
{
int n = endp - line + 1;
if (n < nread)
/* LINE contains more than one line. We copy it to the attic
now as handlers are allowed to modify the passed
buffer. */
{
int len = nread - n;
memcpy (ctx->inbound.attic.line, endp + 1, len);
ctx->inbound.attic.pending = memrchr (endp + 1, '\n', len) ? 1 : 0;
ctx->inbound.attic.linelen = len;
}
if (endp != line && endp[-1] == '\r')
endp --;
*endp = 0;
ctx->inbound.linelen = endp - line;
if (ctx->log_fp)
{
fprintf (ctx->log_fp, "%s[%u.%p] DBG: <- ",
assuan_get_assuan_log_prefix (),
(unsigned int)getpid (), ctx);
if (ctx->confidential)
fputs ("[Confidential data not shown]", ctx->log_fp);
else
_assuan_log_print_buffer (ctx->log_fp,
ctx->inbound.line,
ctx->inbound.linelen);
putc ('\n', ctx->log_fp);
}
return 0;
}
else
{
if (ctx->log_fp)
fprintf (ctx->log_fp, "%s[%u.%p] DBG: <- [Invalid line]\n",
assuan_get_assuan_log_prefix (),
(unsigned int)getpid (), ctx);
*line = 0;
ctx->inbound.linelen = 0;
return ctx->inbound.eof ? ASSUAN_Line_Not_Terminated
: ASSUAN_Line_Too_Long;
}
}
/* Read the next line from the client or server and return a pointer
in *LINE to a buffer holding the line. LINELEN is the length of
*LINE. The buffer is valid until the next read operation on it.
The caller may modify the buffer. The buffer is invalid (i.e. must
not be used) if an error is returned.
Returns 0 on success or an assuan error code.
See also: assuan_pending_line().
*/
assuan_error_t
assuan_read_line (assuan_context_t ctx, char **line, size_t *linelen)
{
assuan_error_t err;
if (!ctx)
return ASSUAN_Invalid_Value;
err = _assuan_read_line (ctx);
*line = ctx->inbound.line;
*linelen = ctx->inbound.linelen;
return err;
}
/* Return true if a full line is buffered (i.e. an entire line may be
read without any I/O). */
int
assuan_pending_line (assuan_context_t ctx)
{
return ctx && ctx->inbound.attic.pending;
}
assuan_error_t
_assuan_write_line (assuan_context_t ctx, const char *prefix,
const char *line, size_t len)
{
int rc = 0;
size_t prefixlen = prefix? strlen (prefix):0;
/* Make sure that the line is short enough. */
if (len + prefixlen + 2 > ASSUAN_LINELENGTH)
{
if (ctx->log_fp)
fprintf (ctx->log_fp, "%s[%u.%p] DBG: -> "
"[supplied line too long -truncated]\n",
assuan_get_assuan_log_prefix (),
(unsigned int)getpid (), ctx);
if (prefixlen > 5)
prefixlen = 5;
if (len > ASSUAN_LINELENGTH - prefixlen - 2)
len = ASSUAN_LINELENGTH - prefixlen - 2 - 1;
}
/* Fixme: we should do some kind of line buffering. */
if (ctx->log_fp)
{
fprintf (ctx->log_fp, "%s[%u.%p] DBG: -> ",
assuan_get_assuan_log_prefix (),
(unsigned int)getpid (), ctx);
if (ctx->confidential)
fputs ("[Confidential data not shown]", ctx->log_fp);
else
_assuan_log_print_buffer (ctx->log_fp, line, len);
putc ('\n', ctx->log_fp);
}
if (prefixlen)
{
rc = writen (ctx, prefix, prefixlen);
if (rc)
rc = ASSUAN_Write_Error;
}
if (!rc)
{
rc = writen (ctx, line, len);
if (rc)
rc = ASSUAN_Write_Error;
if (!rc)
{
rc = writen (ctx, "\n", 1);
if (rc)
rc = ASSUAN_Write_Error;
}
}
return rc;
}
assuan_error_t
assuan_write_line (assuan_context_t ctx, const char *line)
{
size_t len;
const char *s;
if (!ctx)
return ASSUAN_Invalid_Value;
/* Make sure that we never take a LF from the user - this might
violate the protocol. */
s = strchr (line, '\n');
len = s? (s-line) : strlen (line);
if (ctx->log_fp && s)
fprintf (ctx->log_fp, "%s[%u.%p] DBG: -> "
"[supplied line contained a LF -truncated]\n",
assuan_get_assuan_log_prefix (),
(unsigned int)getpid (), ctx);
return _assuan_write_line (ctx, NULL, line, len);
}
/* Write out the data in buffer as datalines with line wrapping and
percent escaping. This function is used for GNU's custom streams */
int
_assuan_cookie_write_data (void *cookie, const char *buffer, size_t orig_size)
{
assuan_context_t ctx = cookie;
size_t size = orig_size;
char *line;
size_t linelen;
if (ctx->outbound.data.error)
return 0;
line = ctx->outbound.data.line;
linelen = ctx->outbound.data.linelen;
line += linelen;
while (size)
{
/* insert data line header */
if (!linelen)
{
*line++ = 'D';
*line++ = ' ';
linelen += 2;
}
/* copy data, keep some space for the CRLF and to escape one character */
while (size && linelen < LINELENGTH-2-2)
{
if (*buffer == '%' || *buffer == '\r' || *buffer == '\n')
{
sprintf (line, "%%%02X", *(unsigned char*)buffer);
line += 3;
linelen += 3;
buffer++;
}
else
{
*line++ = *buffer++;
linelen++;
}
size--;
}
if (linelen >= LINELENGTH-2-2)
{
if (ctx->log_fp)
{
fprintf (ctx->log_fp, "%s[%u.%p] DBG: -> ",
assuan_get_assuan_log_prefix (),
(unsigned int)getpid (), ctx);
if (ctx->confidential)
fputs ("[Confidential data not shown]", ctx->log_fp);
else
_assuan_log_print_buffer (ctx->log_fp,
ctx->outbound.data.line,
linelen);
putc ('\n', ctx->log_fp);
}
*line++ = '\n';
linelen++;
if (writen (ctx, ctx->outbound.data.line, linelen))
{
ctx->outbound.data.error = ASSUAN_Write_Error;
return 0;
}
line = ctx->outbound.data.line;
linelen = 0;
}
}
ctx->outbound.data.linelen = linelen;
return (int)orig_size;
}
/* Write out any buffered data
This function is used for GNU's custom streams */
int
_assuan_cookie_write_flush (void *cookie)
{
assuan_context_t ctx = cookie;
char *line;
size_t linelen;
if (ctx->outbound.data.error)
return 0;
line = ctx->outbound.data.line;
linelen = ctx->outbound.data.linelen;
line += linelen;
if (linelen)
{
if (ctx->log_fp)
{
fprintf (ctx->log_fp, "%s[%u.%p] DBG: -> ",
assuan_get_assuan_log_prefix (),
(unsigned int)getpid (), ctx);
if (ctx->confidential)
fputs ("[Confidential data not shown]", ctx->log_fp);
else
_assuan_log_print_buffer (ctx->log_fp,
ctx->outbound.data.line, linelen);
putc ('\n', ctx->log_fp);
}
*line++ = '\n';
linelen++;
if (writen (ctx, ctx->outbound.data.line, linelen))
{
ctx->outbound.data.error = ASSUAN_Write_Error;
return 0;
}
ctx->outbound.data.linelen = 0;
}
return 0;
}
/**
* assuan_send_data:
* @ctx: An assuan context
* @buffer: Data to send or NULL to flush
* @length: length of the data to send/
*
* This function may be used by the server or the client to send data
* lines. The data will be escaped as required by the Assuan protocol
* and may get buffered until a line is full. To force sending the
* data out @buffer may be passed as NULL (in which case @length must
* also be 0); however when used by a client this flush operation does
* also send the terminating "END" command to terminate the reponse on
* a INQUIRE response. However, when assuan_transact() is used, this
* function takes care of sending END itself.
*
* Return value: 0 on success or an error code
**/
assuan_error_t
assuan_send_data (assuan_context_t ctx, const void *buffer, size_t length)
{
if (!ctx)
return ASSUAN_Invalid_Value;
if (!buffer && length)
return ASSUAN_Invalid_Value;
if (!buffer)
{ /* flush what we have */
_assuan_cookie_write_flush (ctx);
if (ctx->outbound.data.error)
return ctx->outbound.data.error;
if (!ctx->is_server)
return assuan_write_line (ctx, "END");
}
else
{
_assuan_cookie_write_data (ctx, buffer, length);
if (ctx->outbound.data.error)
return ctx->outbound.data.error;
}
return 0;
}

280
util/assuan-client.c Normal file
View File

@ -0,0 +1,280 @@
/* assuan-client.c - client functions
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
* Copyright (C) 2005 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Assuan 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*/
/* Please note that this is a stripped down and modified version of
the orginal Assuan code from libassuan. */
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <assert.h>
#include "assuan-defs.h"
#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))
assuan_error_t
_assuan_read_from_server (assuan_context_t ctx, int *okay, int *off)
{
char *line;
int linelen;
assuan_error_t rc;
*okay = 0;
*off = 0;
do
{
rc = _assuan_read_line (ctx);
if (rc)
return rc;
line = ctx->inbound.line;
linelen = ctx->inbound.linelen;
}
while (*line == '#' || !linelen);
if (linelen >= 1
&& line[0] == 'D' && line[1] == ' ')
{
*okay = 2; /* data line */
*off = 2;
}
else if (linelen >= 1
&& line[0] == 'S'
&& (line[1] == '\0' || line[1] == ' '))
{
*okay = 4;
*off = 1;
while (line[*off] == ' ')
++*off;
}
else if (linelen >= 2
&& line[0] == 'O' && line[1] == 'K'
&& (line[2] == '\0' || line[2] == ' '))
{
*okay = 1;
*off = 2;
while (line[*off] == ' ')
++*off;
}
else if (linelen >= 3
&& line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
&& (line[3] == '\0' || line[3] == ' '))
{
*okay = 0;
*off = 3;
while (line[*off] == ' ')
++*off;
}
else if (linelen >= 7
&& line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
&& line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
&& line[6] == 'E'
&& (line[7] == '\0' || line[7] == ' '))
{
*okay = 3;
*off = 7;
while (line[*off] == ' ')
++*off;
}
else if (linelen >= 3
&& line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
&& (line[3] == '\0' || line[3] == ' '))
{
*okay = 5; /* end line */
*off = 3;
}
else
rc = ASSUAN_Invalid_Response;
return rc;
}
assuan_error_t
assuan_transact (assuan_context_t ctx,
const char *command,
assuan_error_t (*data_cb)(void *, const void *, size_t),
void *data_cb_arg,
assuan_error_t (*inquire_cb)(void*, const char *),
void *inquire_cb_arg,
assuan_error_t (*status_cb)(void*, const char *),
void *status_cb_arg)
{
return assuan_transact2 (ctx, command,
data_cb, data_cb_arg,
inquire_cb, inquire_cb_arg,
status_cb, status_cb_arg,
NULL, NULL);
}
/**
* assuan_transact2:
* @ctx: The Assuan context
* @command: Coimmand line to be send to server
* @data_cb: Callback function for data lines
* @data_cb_arg: first argument passed to @data_cb
* @inquire_cb: Callback function for a inquire response
* @inquire_cb_arg: first argument passed to @inquire_cb
* @status_cb: Callback function for a status response
* @status_cb_arg: first argument passed to @status_cb
* @okay_cb: Callback function for the final OK response
* @okay_cb_arg: first argument passed to @okay_cb
*
* FIXME: Write documentation
*
* Return value: 0 on success or error code. The error code may be
* the one one returned by the server in error lines or from the
* callback functions.
**/
assuan_error_t
assuan_transact2 (assuan_context_t ctx,
const char *command,
assuan_error_t (*data_cb)(void *, const void *, size_t),
void *data_cb_arg,
assuan_error_t (*inquire_cb)(void*, const char *),
void *inquire_cb_arg,
assuan_error_t (*status_cb)(void*, const char *),
void *status_cb_arg,
assuan_error_t (*okay_cb)(void*, const char *),
void *okay_cb_arg)
{
int rc, okay, off;
unsigned char *line;
int linelen;
rc = assuan_write_line (ctx, command);
if (rc)
return rc;
if (*command == '#' || !*command)
return 0; /* Don't expect a response for a comment line. */
again:
rc = _assuan_read_from_server (ctx, &okay, &off);
if (rc)
return rc; /* error reading from server */
line = ctx->inbound.line + off;
linelen = ctx->inbound.linelen - off;
if (!okay)
{
rc = atoi (line);
if (rc < 100)
rc = ASSUAN_Server_Fault;
}
else if (okay == 1) /* Received OK. */
{
if (okay_cb)
{
rc = okay_cb (okay_cb_arg, line);
/* We better wipe out the buffer after processing it. This
is no real guarantee that it won't get swapped out but at
least for the standard cases we can make sure that a
passphrase returned with the OK line is rendered
unreadable. In fact the current Assuan interface suffers
from the problem that it is not possible to do assuan I/O
through secure memory. There is no easy solution given
the current implementation but we need to address it
sooner or later. The problem was introduced with
gpg-agent's GET_PASPHRASE command but it might also make
sense to have a way to convey sessions keys through
secured memory. Note that the old implementation in gpg
for accessing the passphrase in fact used secure memory
but had the drawback of using a limited and not fully
conforming Assuan implementation - given that pinentry
and gpg-agent neither use secured memory for Assuan I/O,
it is negligible to drop the old implementation in gpg's
passphrase.c and use the wipememory workaround here. */
memset (line, 0, strlen (line));
}
}
else if (okay == 2)
{
if (!data_cb)
rc = ASSUAN_No_Data_Callback;
else
{
unsigned char *s, *d;
for (s=d=line; linelen; linelen--)
{
if (*s == '%' && linelen > 2)
{ /* handle escaping */
s++;
*d++ = xtoi_2 (s);
s += 2;
linelen -= 2;
}
else
*d++ = *s++;
}
*d = 0; /* add a hidden string terminator */
rc = data_cb (data_cb_arg, line, d - line);
if (!rc)
goto again;
}
}
else if (okay == 3)
{
if (!inquire_cb)
{
assuan_write_line (ctx, "END"); /* get out of inquire mode */
_assuan_read_from_server (ctx, &okay, &off); /* dummy read */
rc = ASSUAN_No_Inquire_Callback;
}
else
{
rc = inquire_cb (inquire_cb_arg, line);
if (!rc)
rc = assuan_send_data (ctx, NULL, 0); /* flush and send END */
if (!rc)
goto again;
}
}
else if (okay == 4)
{
if (status_cb)
rc = status_cb (status_cb_arg, line);
if (!rc)
goto again;
}
else if (okay == 5)
{
if (!data_cb)
rc = ASSUAN_No_Data_Callback;
else
{
rc = data_cb (data_cb_arg, NULL, 0);
if (!rc)
goto again;
}
}
return rc;
}

95
util/assuan-connect.c Normal file
View File

@ -0,0 +1,95 @@
/* assuan-connect.c - Establish a connection (client)
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Assuan 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*/
/* Please note that this is a stripped down and modified version of
the orginal Assuan code from libassuan. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#ifndef HAVE_W32_SYSTEM
#include <sys/wait.h>
#endif
#include "assuan-defs.h"
/* Create a new context. */
int
_assuan_new_context (assuan_context_t *r_ctx)
{
assuan_context_t ctx;
*r_ctx = NULL;
ctx = xcalloc (1, sizeof *ctx);
ctx->input_fd = -1;
ctx->output_fd = -1;
ctx->inbound.fd = -1;
ctx->outbound.fd = -1;
ctx->io = NULL;
ctx->listen_fd = -1;
*r_ctx = ctx;
return 0;
}
void
_assuan_release_context (assuan_context_t ctx)
{
if (ctx)
{
xfree (ctx->hello_line);
xfree (ctx->okay_line);
xfree (ctx);
}
}
/* Disconnect and release the context CTX. */
void
assuan_disconnect (assuan_context_t ctx)
{
if (ctx)
{
assuan_write_line (ctx, "BYE");
ctx->finish_handler (ctx);
ctx->deinit_handler (ctx);
ctx->deinit_handler = NULL;
_assuan_release_context (ctx);
}
}
/* Return the PID of the peer or -1 if not known. */
pid_t
assuan_get_pid (assuan_context_t ctx)
{
return (ctx && ctx->pid)? ctx->pid : -1;
}

243
util/assuan-defs.h Normal file
View File

@ -0,0 +1,243 @@
/* assuan-defs.c - Internal definitions to Assuan
* Copyright (C) 2001, 2002, 2004 Free Software Foundation, Inc.
* Copyright (C) 2005 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Assuan 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*/
/* Please note that this is a stripped down and modified version of
the orginal Assuan code from libassuan. */
#ifndef ASSUAN_DEFS_H
#define ASSUAN_DEFS_H
#include <sys/types.h>
#ifndef HAVE_W32_SYSTEM
#include <sys/socket.h>
#include <sys/un.h>
#else
#include <windows.h>
#endif
#include <unistd.h>
#include "assuan.h"
#include "memory.h"
#ifndef HAVE_W32_SYSTEM
#define DIRSEP_C '/'
#else
#define DIRSEP_C '\\'
#endif
#ifdef HAVE_W32_SYSTEM
#define AF_LOCAL AF_UNIX
/* We need to prefix the structure with a sockaddr_in header so we can
use it later for sendto and recvfrom. */
struct sockaddr_un
{
short sun_family;
unsigned short sun_port;
struct in_addr sun_addr;
char sun_path[108-2-4]; /* Path name. */
};
/* Not needed anymore because the current mingw32 defines this in
sys/types.h */
/* typedef int ssize_t; */
/* Missing W32 functions */
int putc_unlocked (int c, FILE *stream);
void * memrchr (const void *block, int c, size_t size);
char * stpcpy (char *dest, const char *src);
#endif
#define LINELENGTH ASSUAN_LINELENGTH
struct cmdtbl_s
{
const char *name;
int (*handler)(assuan_context_t, char *line);
};
struct assuan_io
{
/* Routine to read from input_fd. */
ssize_t (*readfnc) (assuan_context_t, void *, size_t);
/* Routine to write to output_fd. */
ssize_t (*writefnc) (assuan_context_t, const void *, size_t);
/* Send a file descriptor. */
assuan_error_t (*sendfd) (assuan_context_t, int);
/* Receive a file descriptor. */
assuan_error_t (*receivefd) (assuan_context_t, int *);
};
struct assuan_context_s
{
assuan_error_t err_no;
const char *err_str;
int os_errno; /* last system error number used with certain error codes*/
int confidential;
int is_server; /* set if this is context belongs to a server */
int in_inquire;
char *hello_line;
char *okay_line; /* see assan_set_okay_line() */
void *user_pointer; /* for assuan_[gs]et_pointer () */
FILE *log_fp;
struct {
int fd;
int eof;
char line[LINELENGTH];
int linelen; /* w/o CR, LF - might not be the same as
strlen(line) due to embedded nuls. However a nul
is always written at this pos */
struct {
char line[LINELENGTH];
int linelen ;
int pending; /* i.e. at least one line is available in the attic */
} attic;
} inbound;
struct {
int fd;
struct {
FILE *fp;
char line[LINELENGTH];
int linelen;
int error;
} data;
} outbound;
int pipe_mode; /* We are in pipe mode, i.e. we can handle just one
connection and must terminate then */
pid_t pid; /* The the pid of the peer. */
int listen_fd; /* The fd we are listening on (used by socket servers) */
int connected_fd; /* helper */
/* Used for Unix domain sockets. */
struct sockaddr_un myaddr;
struct sockaddr_un serveraddr;
/* When reading from datagram sockets, we must read an entire
message at a time. This means that we have to do our own
buffering to be able to get the semantics of read. */
void *domainbuffer;
/* Offset of start of buffer. */
int domainbufferoffset;
/* Bytes buffered. */
int domainbuffersize;
/* Memory allocated. */
int domainbufferallocated;
int *pendingfds;
int pendingfdscount;
void (*deinit_handler)(assuan_context_t);
int (*accept_handler)(assuan_context_t);
int (*finish_handler)(assuan_context_t);
struct cmdtbl_s *cmdtbl;
size_t cmdtbl_used; /* used entries */
size_t cmdtbl_size; /* allocated size of table */
void (*bye_notify_fnc)(assuan_context_t);
void (*reset_notify_fnc)(assuan_context_t);
void (*cancel_notify_fnc)(assuan_context_t);
int (*option_handler_fnc)(assuan_context_t,const char*, const char*);
void (*input_notify_fnc)(assuan_context_t, const char *);
void (*output_notify_fnc)(assuan_context_t, const char *);
int input_fd; /* set by INPUT command */
int output_fd; /* set by OUTPUT command */
/* io routines. */
struct assuan_io *io;
};
/*-- assuan-pipe-server.c --*/
int _assuan_new_context (assuan_context_t *r_ctx);
void _assuan_release_context (assuan_context_t ctx);
/*-- assuan-domain-connect.c --*/
/* Make a connection to the Unix domain socket NAME and return a new
Assuan context in CTX. SERVER_PID is currently not used but may
become handy in the future. */
assuan_error_t _assuan_domain_init (assuan_context_t *r_ctx,
int rendezvousfd,
pid_t peer);
/*-- assuan-handler.c --*/
int _assuan_register_std_commands (assuan_context_t ctx);
/*-- assuan-buffer.c --*/
int _assuan_read_line (assuan_context_t ctx);
int _assuan_cookie_write_data (void *cookie, const char *buffer, size_t size);
int _assuan_cookie_write_flush (void *cookie);
assuan_error_t _assuan_write_line (assuan_context_t ctx, const char *prefix,
const char *line, size_t len);
/*-- assuan-client.c --*/
assuan_error_t _assuan_read_from_server (assuan_context_t ctx, int *okay, int *off);
/*-- assuan-util.c --*/
#define set_error(c,e,t) assuan_set_error ((c), ASSUAN_ ## e, (t))
void _assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length);
void _assuan_log_sanitized_string (const char *string);
#ifdef HAVE_W32_SYSTEM
const char *_assuan_w32_strerror (int ec);
#define w32_strerror(e) _assuan_w32_strerror ((e))
#endif /*HAVE_W32_SYSTEM*/
/*-- assuan-logging.c --*/
void _assuan_set_default_log_stream (FILE *fp);
void _assuan_log_printf (const char *format, ...)
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
__attribute__ ((format (printf,1,2)))
#endif
;
/*-- assuan-io.c --*/
ssize_t _assuan_simple_read (assuan_context_t ctx, void *buffer, size_t size);
ssize_t _assuan_simple_write (assuan_context_t ctx, const void *buffer,
size_t size);
/*-- assuan-socket.c --*/
int _assuan_close (int fd);
int _assuan_sock_new (int domain, int type, int proto);
int _assuan_sock_connect (int sockfd, struct sockaddr *addr, int addrlen);
#ifdef HAVE_FOPENCOOKIE
/* We have to implement funopen in terms of glibc's fopencookie. */
FILE *_assuan_funopen(void *cookie,
cookie_read_function_t *readfn,
cookie_write_function_t *writefn,
cookie_seek_function_t *seekfn,
cookie_close_function_t *closefn);
#define funopen(a,r,w,s,c) _assuan_funopen ((a), (r), (w), (s), (c))
#endif /*HAVE_FOPENCOOKIE*/
#endif /*ASSUAN_DEFS_H*/

104
util/assuan-errors.c Normal file
View File

@ -0,0 +1,104 @@
/* assuan-errors.c - error codes
* Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
* Copyright (C) 2005 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Assuan 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*/
/* Please note that this is a stripped down and modified version of
the orginal Assuan code from libassuan. */
#include <stdio.h>
#include "assuan.h"
/* This function returns a textual representaion of the given error
code. If this is an unknown value, a string with the value is
returned (Beware: it is hold in a static buffer). Return value:
String with the error description.
*/
const char *
assuan_strerror (assuan_error_t err)
{
const char *s;
static char buf[50];
switch (err)
{
case ASSUAN_No_Error: s="no error"; break;
case ASSUAN_General_Error: s="general error"; break;
case ASSUAN_Out_Of_Core: s="out of core"; break;
case ASSUAN_Invalid_Value: s="invalid value"; break;
case ASSUAN_Timeout: s="timeout"; break;
case ASSUAN_Read_Error: s="read error"; break;
case ASSUAN_Write_Error: s="write error"; break;
case ASSUAN_Problem_Starting_Server: s="problem starting server"; break;
case ASSUAN_Not_A_Server: s="not a server"; break;
case ASSUAN_Not_A_Client: s="not a client"; break;
case ASSUAN_Nested_Commands: s="nested commands"; break;
case ASSUAN_Invalid_Response: s="invalid response"; break;
case ASSUAN_No_Data_Callback: s="no data callback"; break;
case ASSUAN_No_Inquire_Callback: s="no inquire callback"; break;
case ASSUAN_Connect_Failed: s="connect failed"; break;
case ASSUAN_Accept_Failed: s="accept failed"; break;
case ASSUAN_Not_Implemented: s="not implemented"; break;
case ASSUAN_Server_Fault: s="server fault"; break;
case ASSUAN_Invalid_Command: s="invalid command"; break;
case ASSUAN_Unknown_Command: s="unknown command"; break;
case ASSUAN_Syntax_Error: s="syntax error"; break;
case ASSUAN_Parameter_Error: s="parameter error"; break;
case ASSUAN_Parameter_Conflict: s="parameter conflict"; break;
case ASSUAN_Line_Too_Long: s="line too long"; break;
case ASSUAN_Line_Not_Terminated: s="line not terminated"; break;
case ASSUAN_No_Input: s="no input"; break;
case ASSUAN_No_Output: s="no output"; break;
case ASSUAN_Canceled: s="canceled"; break;
case ASSUAN_Unsupported_Algorithm: s="unsupported algorithm"; break;
case ASSUAN_Server_Resource_Problem: s="server resource problem"; break;
case ASSUAN_Server_IO_Error: s="server io error"; break;
case ASSUAN_Server_Bug: s="server bug"; break;
case ASSUAN_No_Data_Available: s="no data available"; break;
case ASSUAN_Invalid_Data: s="invalid data"; break;
case ASSUAN_Unexpected_Command: s="unexpected command"; break;
case ASSUAN_Too_Much_Data: s="too much data"; break;
case ASSUAN_Inquire_Unknown: s="inquire unknown"; break;
case ASSUAN_Inquire_Error: s="inquire error"; break;
case ASSUAN_Invalid_Option: s="invalid option"; break;
case ASSUAN_Invalid_Index: s="invalid index"; break;
case ASSUAN_Unexpected_Status: s="unexpected status"; break;
case ASSUAN_Unexpected_Data: s="unexpected data"; break;
case ASSUAN_Invalid_Status: s="invalid status"; break;
case ASSUAN_Locale_Problem: s="locale problem"; break;
case ASSUAN_Not_Confirmed: s="not confirmed"; break;
case ASSUAN_USER_ERROR_FIRST: s="user error first"; break;
case ASSUAN_USER_ERROR_LAST: s="user error last"; break;
default:
{
unsigned int source, code;
source = ((err >> 24) & 0xff);
code = (err & 0x00ffffff);
if (source) /* Assume this is an libgpg-error. */
sprintf (buf, "ec=%u.%u", source, code );
else
sprintf (buf, "ec=%d", err );
s=buf; break;
}
}
return s;
}

115
util/assuan-logging.c Normal file
View File

@ -0,0 +1,115 @@
/* assuan-logging.c - Default logging function.
* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Assuan 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*/
/* Please note that this is a stripped down and modified version of
the orginal Assuan code from libassuan. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#ifdef HAVE_W32_SYSTEM
#include <windows.h>
#endif /*HAVE_W32_SYSTEM*/
#include "assuan-defs.h"
static char prefix_buffer[80];
static FILE *_assuan_log;
void
_assuan_set_default_log_stream (FILE *fp)
{
if (!_assuan_log)
_assuan_log = fp;
}
void
assuan_set_assuan_log_stream (FILE *fp)
{
_assuan_log = fp;
}
FILE *
assuan_get_assuan_log_stream (void)
{
return _assuan_log ? _assuan_log : stderr;
}
/* Set the prefix to be used for logging to TEXT or
resets it to the default if TEXT is NULL. */
void
assuan_set_assuan_log_prefix (const char *text)
{
if (text)
{
strncpy (prefix_buffer, text, sizeof (prefix_buffer)-1);
prefix_buffer[sizeof (prefix_buffer)-1] = 0;
}
else
*prefix_buffer = 0;
}
const char *
assuan_get_assuan_log_prefix (void)
{
return prefix_buffer;
}
void
_assuan_log_printf (const char *format, ...)
{
va_list arg_ptr;
FILE *fp;
const char *prf;
fp = assuan_get_assuan_log_stream ();
prf = assuan_get_assuan_log_prefix ();
if (*prf)
{
fputs (prf, fp);
fputs (": ", fp);
}
va_start (arg_ptr, format);
vfprintf (fp, format, arg_ptr );
va_end (arg_ptr);
}
#ifdef HAVE_W32_SYSTEM
const char *
_assuan_w32_strerror (int ec)
{
static char strerr[256];
if (ec == -1)
ec = (int)GetLastError ();
FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, ec,
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
strerr, sizeof (strerr)-1, NULL);
return strerr;
}
#endif /*HAVE_W32_SYSTEM*/

View File

@ -0,0 +1,190 @@
/* assuan-socket-connect.c - Assuan socket based client
* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Assuan 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*/
/* Please note that this is a stripped down and modified version of
the orginal Assuan code from libassuan. */
#include <config.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#ifndef HAVE_W32_SYSTEM
#include <sys/socket.h>
#include <sys/un.h>
#else
#include <windows.h>
#endif
#include "assuan-defs.h"
/* Hacks for Slowaris. */
#ifndef PF_LOCAL
# ifdef PF_UNIX
# define PF_LOCAL PF_UNIX
# else
# define PF_LOCAL AF_UNIX
# endif
#endif
#ifndef AF_LOCAL
# define AF_LOCAL AF_UNIX
#endif
#ifndef SUN_LEN
# define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
+ strlen ((ptr)->sun_path))
#endif
static int
do_finish (assuan_context_t ctx)
{
if (ctx->inbound.fd != -1)
{
_assuan_close (ctx->inbound.fd);
}
ctx->inbound.fd = -1;
ctx->outbound.fd = -1;
return 0;
}
static void
do_deinit (assuan_context_t ctx)
{
do_finish (ctx);
}
static ssize_t
simple_read (assuan_context_t ctx, void *buffer, size_t size)
{
#ifndef HAVE_W32_SYSTEM
return read (ctx->inbound.fd, buffer, size);
#else
return recv (ctx->inbound.fd, buffer, size, 0);
#endif
}
static ssize_t
simple_write (assuan_context_t ctx, const void *buffer, size_t size)
{
#ifndef HAVE_W32_SYSTEM
return write (ctx->outbound.fd, buffer, size);
#else
return send (ctx->outbound.fd, buffer, size, 0);
#endif
}
/* Make a connection to the Unix domain socket NAME and return a new
Assuan context in CTX. SERVER_PID is currently not used but may
become handy in the future. */
assuan_error_t
assuan_socket_connect (assuan_context_t *r_ctx,
const char *name, pid_t server_pid)
{
static struct assuan_io io = { simple_read, simple_write };
assuan_error_t err;
assuan_context_t ctx;
int fd;
struct sockaddr_un srvr_addr;
size_t len;
const char *s;
if (!r_ctx || !name)
return ASSUAN_Invalid_Value;
*r_ctx = NULL;
/* We require that the name starts with a slash, so that we can
alter reuse this function for other socket types. To make things
easier we allow an optional dirver prefix. */
s = name;
if (*s && s[1] == ':')
s += 2;
if (*s != DIRSEP_C && *s != '/')
return ASSUAN_Invalid_Value;
if (strlen (name)+1 >= sizeof srvr_addr.sun_path)
return ASSUAN_Invalid_Value;
err = _assuan_new_context (&ctx);
if (err)
return err;
ctx->deinit_handler = do_deinit;
ctx->finish_handler = do_finish;
fd = _assuan_sock_new (PF_LOCAL, SOCK_STREAM, 0);
if (fd == -1)
{
_assuan_log_printf ("can't create socket: %s\n", strerror (errno));
_assuan_release_context (ctx);
return ASSUAN_General_Error;
}
memset (&srvr_addr, 0, sizeof srvr_addr);
srvr_addr.sun_family = AF_LOCAL;
strncpy (srvr_addr.sun_path, name, sizeof (srvr_addr.sun_path) - 1);
srvr_addr.sun_path[sizeof (srvr_addr.sun_path) - 1] = 0;
len = SUN_LEN (&srvr_addr);
if (_assuan_sock_connect (fd, (struct sockaddr *) &srvr_addr, len) == -1)
{
_assuan_log_printf ("can't connect to `%s': %s\n",
name, strerror (errno));
_assuan_release_context (ctx);
_assuan_close (fd);
return ASSUAN_Connect_Failed;
}
ctx->inbound.fd = fd;
ctx->outbound.fd = fd;
ctx->io = &io;
/* initial handshake */
{
int okay, off;
err = _assuan_read_from_server (ctx, &okay, &off);
if (err)
_assuan_log_printf ("can't connect to server: %s\n",
assuan_strerror (err));
else if (okay != 1)
{
/*LOG ("can't connect to server: `");*/
_assuan_log_sanitized_string (ctx->inbound.line);
fprintf (assuan_get_assuan_log_stream (), "'\n");
err = ASSUAN_Connect_Failed;
}
}
if (err)
{
assuan_disconnect (ctx);
}
else
*r_ctx = ctx;
return 0;
}

96
util/assuan-socket.c Normal file
View File

@ -0,0 +1,96 @@
/* assuan-socket.c
* Copyright (C) 2004 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
*/
/* Please note that this is a stripped down and modified version of
the orginal Assuan code from libassuan. */
#include <config.h>
#include <stdio.h>
#ifdef HAVE_W32_SYSTEM
#include <windows.h>
#include <io.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#endif
#include "assuan-defs.h"
int
_assuan_close (int fd)
{
#ifndef HAVE_W32_SYSTEM
return close (fd);
#else
int rc = closesocket (fd);
if (rc && WSAGetLastError () == WSAENOTSOCK)
rc = close (fd);
return rc;
#endif
}
int
_assuan_sock_new (int domain, int type, int proto)
{
#ifndef HAVE_W32_SYSTEM
return socket (domain, type, proto);
#else
if (domain == AF_UNIX || domain == AF_LOCAL)
domain = AF_INET;
return socket (domain, type, proto);
#endif
}
int
_assuan_sock_connect (int sockfd, struct sockaddr * addr, int addrlen)
{
#ifndef HAVE_W32_SYSTEM
return connect (sockfd, addr, addrlen);
#else
struct sockaddr_in myaddr;
struct sockaddr_un * unaddr;
FILE * fp;
int port = 0;
unaddr = (struct sockaddr_un *)addr;
fp = fopen (unaddr->sun_path, "rb");
if (!fp)
return -1;
fscanf (fp, "%d", &port);
fclose (fp);
/* XXX: set errno in this case */
if (port < 0 || port > 65535)
return -1;
myaddr.sin_family = AF_INET;
myaddr.sin_port = port;
myaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
/* we need this later. */
unaddr->sun_family = myaddr.sin_family;
unaddr->sun_port = myaddr.sin_port;
unaddr->sun_addr.s_addr = myaddr.sin_addr.s_addr;
return connect (sockfd, (struct sockaddr *)&myaddr, sizeof myaddr);
#endif
}

170
util/assuan-util.c Normal file
View File

@ -0,0 +1,170 @@
/* assuan-util.c - Utility functions for Assuan
* Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
* Copyright (C) 2005 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Assuan 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
*/
/* Please note that this is a stripped down and modified version of
the orginal Assuan code from libassuan. */
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "assuan-defs.h"
/* Store the error in the context so that the error sending function
can take out a descriptive text. Inside the assuan code, use the
macro set_error instead of this function. */
int
assuan_set_error (assuan_context_t ctx, int err, const char *text)
{
ctx->err_no = err;
ctx->err_str = text;
return err;
}
void
assuan_set_pointer (assuan_context_t ctx, void *pointer)
{
if (ctx)
ctx->user_pointer = pointer;
}
void *
assuan_get_pointer (assuan_context_t ctx)
{
return ctx? ctx->user_pointer : NULL;
}
void
assuan_set_log_stream (assuan_context_t ctx, FILE *fp)
{
if (ctx)
{
if (ctx->log_fp)
fflush (ctx->log_fp);
ctx->log_fp = fp;
_assuan_set_default_log_stream (fp);
}
}
void
assuan_begin_confidential (assuan_context_t ctx)
{
if (ctx)
{
ctx->confidential = 1;
}
}
void
assuan_end_confidential (assuan_context_t ctx)
{
if (ctx)
{
ctx->confidential = 0;
}
}
/* Dump a possibly binary string (used for debugging). Distinguish
ascii text from binary and print it accordingly. */
void
_assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length)
{
const unsigned char *s;
int n;
for (n=length,s=buffer; n; n--, s++)
if ((!isascii (*s) || iscntrl (*s) || !isprint (*s)) && !(*s >= 0x80))
break;
s = buffer;
if (!n && *s != '[')
fwrite (buffer, length, 1, fp);
else
{
putc ('[', fp);
for (n=0; n < length; n++, s++)
fprintf (fp, " %02x", *s);
putc (' ', fp);
putc (']', fp);
}
}
/* Log a user supplied string. Escapes non-printable before
printing. */
void
_assuan_log_sanitized_string (const char *string)
{
const unsigned char *s = string;
FILE *fp = assuan_get_assuan_log_stream ();
if (! *s)
return;
for (; *s; s++)
{
int c = 0;
switch (*s)
{
case '\r':
c = 'r';
break;
case '\n':
c = 'n';
break;
case '\f':
c = 'f';
break;
case '\v':
c = 'v';
break;
case '\b':
c = 'b';
break;
default:
if ((isascii (*s) && isprint (*s)) || (*s >= 0x80))
putc (*s, fp);
else
{
putc ('\\', fp);
fprintf (fp, "x%02x", *s);
}
}
if (c)
{
putc ('\\', fp);
putc (c, fp);
}
}
}

29
util/isascii.c Normal file
View File

@ -0,0 +1,29 @@
/* isascii.c - Replacement for isascii.
* 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
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
int
isascii (int c)
{
return (((c) & ~0x7f) == 0);
}

View File

@ -1,5 +1,5 @@
/* memory.c - memory allocation
* Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc.
* Copyright (C) 1998, 1999, 2001, 2005 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -603,29 +603,6 @@ m_size( const void *a )
}
#if 0 /* not used */
/****************
* Make a copy of the memory block at a
*/
void *
FNAME(copy)( const void *a FNAMEPRT )
{
void *b;
size_t n;
if( !a )
return NULL;
n = m_size(a); Aiiiih woher nehmen
if( m_is_secure(a) )
b = FNAME(alloc_secure)(n FNAMEARG);
else
b = FNAME(alloc)(n FNAMEARG);
memcpy(b, a, n );
return b;
}
#endif
char *
FNAME(strdup)( const char *a FNAMEPRT )
{
@ -634,3 +611,31 @@ FNAME(strdup)( const char *a FNAMEPRT )
strcpy(p, a);
return p;
}
/* Wrapper around m_alloc_clear to take the usual 2 arguments of a
calloc style function. */
void *
xcalloc (size_t n, size_t m)
{
size_t nbytes;
nbytes = n * m;
if (m && nbytes / m != n)
out_of_core (nbytes, 0);
return m_alloc_clear (nbytes);
}
/* Wrapper around m_alloc_csecure_lear to take the usual 2 arguments
of a calloc style function. */
void *
xcalloc_secure (size_t n, size_t m)
{
size_t nbytes;
nbytes = n * m;
if (m && nbytes / m != n)
out_of_core (nbytes, 1);
return m_alloc_secure_clear (nbytes);
}