diff options
Diffstat (limited to '')
-rw-r--r-- | ChangeLog | 11 | ||||
-rw-r--r-- | README | 18 | ||||
-rw-r--r-- | THANKS | 1 | ||||
-rw-r--r-- | configure.ac | 44 | ||||
-rw-r--r-- | g10/ChangeLog | 23 | ||||
-rw-r--r-- | g10/g10.c | 8 | ||||
-rw-r--r-- | g10/passphrase.c | 769 | ||||
-rw-r--r-- | include/ChangeLog | 10 | ||||
-rw-r--r-- | include/assuan.h | 261 | ||||
-rw-r--r-- | include/memory.h | 6 | ||||
-rw-r--r-- | util/ChangeLog | 19 | ||||
-rw-r--r-- | util/Makefile.am | 18 | ||||
-rw-r--r-- | util/assuan-buffer.c | 480 | ||||
-rw-r--r-- | util/assuan-client.c | 280 | ||||
-rw-r--r-- | util/assuan-connect.c | 95 | ||||
-rw-r--r-- | util/assuan-defs.h | 243 | ||||
-rw-r--r-- | util/assuan-errors.c | 104 | ||||
-rw-r--r-- | util/assuan-logging.c | 115 | ||||
-rw-r--r-- | util/assuan-socket-connect.c | 190 | ||||
-rw-r--r-- | util/assuan-socket.c | 96 | ||||
-rw-r--r-- | util/assuan-util.c | 170 | ||||
-rw-r--r-- | util/isascii.c | 29 | ||||
-rw-r--r-- | util/memory.c | 53 |
23 files changed, 2428 insertions, 615 deletions
@@ -1,3 +1,14 @@ +2005-03-31 Werner Koch <[email protected]> + + * 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 <[email protected]> * configure.ac: Move the LDAP detecting code to m4/ldap.m4. @@ -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) <[email protected]>" @@ -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. @@ -181,6 +181,7 @@ Russell Coker [email protected] Ryan Malayter [email protected] Sam Roberts [email protected] Sami Tolvanen [email protected] +Sascha Kiefer [email protected] Sean MacLennan [email protected] Sebastian Klemke [email protected] Serge Munhoven [email protected] diff --git a/configure.ac b/configure.ac index 7c91ddcce..fd2d271de 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/g10/ChangeLog b/g10/ChangeLog index f5a6a436a..0501c69b5 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,8 @@ +2005-04-01 Werner Koch <[email protected]> + + * keygen.c (keygen_set_std_prefs): Explain the chosen order of + AES key sizes. + 2005-04-01 David Shaw <[email protected]> * mainproc.c (proc_plaintext): Properly handle SIG+LITERAL @@ -11,6 +16,24 @@ 2005-03-31 Werner Koch <[email protected]> + * 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. @@ -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 ) diff --git a/g10/passphrase.c b/g10/passphrase.c index da2820b17..c309904b1 100644 --- a/g10/passphrase.c +++ b/g10/passphrase.c @@ -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; } -static int -writen (int fd, const void *buf, size_t nbytes) -{ -#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 */ +#ifdef ENABLE_AGENT_SUPPORT +/* Send one option to the gpg-agent. */ static int -agent_send_option (int fd, const char *name, const char *value) +agent_send_option (assuan_context_t ctx, const char *name, const char *value) { - char buf[200]; - int nread; char *line; - int i; - - 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; + int rc; - /* 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 */ - - return -1; + if (!value || !*value) + return 0; /* Avoid sending empty option values. */ + + 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]; - - *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; + int rc; + assuan_context_t ctx; + char *infostr, *p; + int prot; + int pid; - 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 ); - } - - 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; - } - *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; + infostr = xstrdup ( infostr ); } - - 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; + + 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; } - m_free (infostr); - - if (!prot) { - if ( writen ( fd, "GPGA\0\0\0\x01", 8 ) ) { - close (fd); - fd = -1; - } + + 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; } - 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; - } + xfree (infostr); - if (agent_send_all_options (fd)) { - log_error (_("problem with the agent - disabling agent use\n")); - close (fd); - 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; } -#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++) + + /* 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) { - 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); + 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*/ } diff --git a/include/ChangeLog b/include/ChangeLog index d922d6eb8..ae62bcf2b 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,11 @@ +2005-04-04 Werner Koch <[email protected]> + + * memory.h (xcalloc, xcalloc_secure): Replaced macros by functions. + +2005-03-31 Werner Koch <[email protected]> + + * assuan.h: New. Taken from libassuan 0.6.9. + 2005-03-18 David Shaw <[email protected]> * ttyio.h: Prototype tty_enable_completion(), and @@ -506,7 +514,7 @@ Tue Mar 3 15:11:21 1998 Werner Koch ([email protected]) 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 diff --git a/include/assuan.h b/include/assuan.h new file mode 100644 index 000000000..d39b774cf --- /dev/null +++ b/include/assuan.h @@ -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 */ diff --git a/include/memory.h b/include/memory.h index 377c2b702..4ab5cc470 100644 --- a/include/memory.h +++ b/include/memory.h @@ -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) diff --git a/util/ChangeLog b/util/ChangeLog index 52b9c317b..b6f35d3f4 100644 --- a/util/ChangeLog +++ b/util/ChangeLog @@ -1,3 +1,22 @@ +2005-04-04 Werner Koch <[email protected]> + + * 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 <[email protected]> + + * 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 <[email protected]> * ttyio.c (tty_enable_completion, tty_disable_completion): Enable diff --git a/util/Makefile.am b/util/Makefile.am index 973f36c10..cb241da3f 100644 --- a/util/Makefile.am +++ b/util/Makefile.am @@ -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 diff --git a/util/assuan-buffer.c b/util/assuan-buffer.c new file mode 100644 index 000000000..47f4e189e --- /dev/null +++ b/util/assuan-buffer.c @@ -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; +} + diff --git a/util/assuan-client.c b/util/assuan-client.c new file mode 100644 index 000000000..08ea0f6cc --- /dev/null +++ b/util/assuan-client.c @@ -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; +} + diff --git a/util/assuan-connect.c b/util/assuan-connect.c new file mode 100644 index 000000000..52c9aa00f --- /dev/null +++ b/util/assuan-connect.c @@ -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; +} + diff --git a/util/assuan-defs.h b/util/assuan-defs.h new file mode 100644 index 000000000..06400d836 --- /dev/null +++ b/util/assuan-defs.h @@ -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*/ + diff --git a/util/assuan-errors.c b/util/assuan-errors.c new file mode 100644 index 000000000..01f718ca9 --- /dev/null +++ b/util/assuan-errors.c @@ -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; +} + diff --git a/util/assuan-logging.c b/util/assuan-logging.c new file mode 100644 index 000000000..6663e8114 --- /dev/null +++ b/util/assuan-logging.c @@ -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*/ diff --git a/util/assuan-socket-connect.c b/util/assuan-socket-connect.c new file mode 100644 index 000000000..003859147 --- /dev/null +++ b/util/assuan-socket-connect.c @@ -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; +} diff --git a/util/assuan-socket.c b/util/assuan-socket.c new file mode 100644 index 000000000..080eff243 --- /dev/null +++ b/util/assuan-socket.c @@ -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 +} + + diff --git a/util/assuan-util.c b/util/assuan-util.c new file mode 100644 index 000000000..a5ee0b290 --- /dev/null +++ b/util/assuan-util.c @@ -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); + } + } +} + diff --git a/util/isascii.c b/util/isascii.c new file mode 100644 index 000000000..565c71664 --- /dev/null +++ b/util/isascii.c @@ -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); +} diff --git a/util/memory.c b/util/memory.c index c062bdd5f..f84e507dc 100644 --- a/util/memory.c +++ b/util/memory.c @@ -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); +} + |