From 540f9164c01dbbd1f8fc9abcd2ee67dbf6e1ee10 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 19 Jun 2007 09:11:11 +0000 Subject: [PATCH] Made percent_escape more general. Added regression tests support to jnlib. W32 changes. --- AUTHORS | 3 + agent/ChangeLog | 6 +- agent/gpg-agent.c | 31 ++++++--- agent/w32main.c | 154 +++++++++++++++++++++++++++++++++++++++---- doc/gpg-agent.texi | 10 +-- g10/gpg.c | 2 +- jnlib/ChangeLog | 14 ++++ jnlib/Makefile.am | 19 ++++++ jnlib/stringhelp.c | 26 ++++++-- jnlib/stringhelp.h | 5 +- jnlib/t-stringhelp.c | 94 ++++++++++++++++++++++++++ jnlib/t-support.c | 111 +++++++++++++++++++++++++++++++ jnlib/t-support.h | 52 +++++++++++++++ jnlib/w32-afunix.c | 56 ++++++++++++---- scd/scdaemon.c | 2 +- sm/gpgsm.c | 2 +- tools/ChangeLog | 5 ++ tools/gpgconf-comp.c | 15 +++-- 18 files changed, 551 insertions(+), 56 deletions(-) create mode 100644 jnlib/t-stringhelp.c create mode 100644 jnlib/t-support.c create mode 100644 jnlib/t-support.h diff --git a/AUTHORS b/AUTHORS index 799a2aee6..548bc8a61 100644 --- a/AUTHORS +++ b/AUTHORS @@ -128,6 +128,9 @@ GnuPG. The RPM specs file scripts/gnupg.spec has been contributed by several people. +The function build_argv in agent/w32main.c is based on code from +Alexandre Julliard. + Copyright ========= diff --git a/agent/ChangeLog b/agent/ChangeLog index e23cd99a9..19564556e 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -5,10 +5,14 @@ 2007-06-18 Werner Koch + * w32main.c (build_argv): New. + (WinMain): Use it. + * command.c (cmd_killagent) [W32]: New. (cmd_getinfo): New. * gpg-agent.c (get_agent_ssh_socket_name): New. - + (no_force_standard_socket) New. + (create_server_socket): Use it. * Makefile.am (gpg_agent_res_ldflags): Pass windows option to ld. 2007-06-14 Werner Koch diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index 419f3769a..8907e9234 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -93,6 +93,7 @@ enum cmd_and_opt_values oMinPassphraseLen, oUseStandardSocket, oNoUseStandardSocket, + oNoReuseStandardSocket, oIgnoreCacheForSigning, oAllowMarkTrusted, @@ -130,6 +131,7 @@ static ARGPARSE_OPTS opts[] = { { oUseStandardSocket, "use-standard-socket", 0, N_("use a standard location for the socket")}, { oNoUseStandardSocket, "no-use-standard-socket", 0, "@"}, + { oNoReuseStandardSocket, "no-reuse-standard-socket", 0, "@"}, { oPinentryProgram, "pinentry-program", 2 , N_("|PGM|use PGM as the PIN-Entry program") }, @@ -186,6 +188,10 @@ static char *socket_name; /* Name of the communication socket used for ssh-agent-emulation. */ static char *socket_name_ssh; +/* If set to true and a standard socket is requested, we won't try to + bind to a socket which is already in use. */ +static int no_reuse_standard_socket; + /* Default values for options passed to the pinentry. */ static char *default_display; static char *default_ttyname; @@ -215,7 +221,7 @@ static pid_t parent_pid = (pid_t)(-1); static char *create_socket_name (int use_standard_socket, char *standard_name, char *template); -static int create_server_socket (int is_standard_name, const char *name); +static int create_server_socket (int is_standard_name, char *name); static void create_directories (void); static void agent_init_default_ctrl (ctrl_t ctrl); @@ -621,6 +627,7 @@ main (int argc, char **argv ) case oUseStandardSocket: standard_socket = 1; break; case oNoUseStandardSocket: standard_socket = 0; break; + case oNoReuseStandardSocket: no_reuse_standard_socket = 1; break; case oKeepTTY: opt.keep_tty = 1; break; case oKeepDISPLAY: opt.keep_display = 1; break; @@ -715,7 +722,7 @@ main (int argc, char **argv ) #define GC_OPT_FLAG_NO_ARG_DESC (1UL << 6) filename = make_filename (opt.homedir, "gpg-agent.conf", NULL ); - filename_esc = percent_escape (filename); + filename_esc = percent_escape (filename, NULL); printf ("gpgconf-gpg-agent.conf:%lu:\"%s\n", GC_OPT_FLAG_DEFAULT, filename_esc); @@ -1226,10 +1233,10 @@ create_socket_name (int use_standard_socket, /* Create a Unix domain socket with NAME. IS_STANDARD_NAME indicates - whether a non-random socket is used. Returns the filedescriptor or + whether a non-random socket is used. Returns the file descriptor or terminates the process in case of an error. */ static int -create_server_socket (int is_standard_name, const char *name) +create_server_socket (int is_standard_name, char *name) { struct sockaddr_un *serv_addr; socklen_t len; @@ -1257,14 +1264,16 @@ create_server_socket (int is_standard_name, const char *name) #ifdef HAVE_W32_SYSTEM rc = _w32_sock_bind (fd, (struct sockaddr*) serv_addr, len); - if (is_standard_name && rc == -1 ) + if (is_standard_name && rc == -1 && errno == WSAEADDRINUSE + && !no_reuse_standard_socket) { remove (name); - rc = bind (fd, (struct sockaddr*) serv_addr, len); + rc = _w32_sock_bind (fd, (struct sockaddr*) serv_addr, len); } #else rc = bind (fd, (struct sockaddr*) serv_addr, len); - if (is_standard_name && rc == -1 && errno == EADDRINUSE) + if (is_standard_name && rc == -1 && errno == EADDRINUSE + && !no_reuse_standard_socket) { remove (name); rc = bind (fd, (struct sockaddr*) serv_addr, len); @@ -1272,9 +1281,15 @@ create_server_socket (int is_standard_name, const char *name) #endif if (rc == -1) { + /* We use gpg_strerror here because it allows us to get strings + for some W32 socket error codes. */ log_error (_("error binding socket to `%s': %s\n"), - serv_addr->sun_path, strerror (errno)); + serv_addr->sun_path, + gpg_strerror (gpg_error_from_errno (errno))); + close (fd); + if (is_standard_name && no_reuse_standard_socket) + *name = 0; /* Inhibit removal of the socket by cleanup(). */ agent_exit (2); } diff --git a/agent/w32main.c b/agent/w32main.c index 5fccb7ea2..176050220 100644 --- a/agent/w32main.c +++ b/agent/w32main.c @@ -1,5 +1,6 @@ /* w32main.c - W32 main entry pint and taskbar support for the GnuPG Agent * Copyright (C) 2007 Free Software Foundation, Inc. + * Copyright 1996, 1998 Alexandre Julliard * * This file is part of GnuPG. * @@ -37,6 +38,136 @@ static HINSTANCE glob_hinst; static HWND glob_hwnd; +/* Build an argv array from the command in CMDLINE. RESERVED is the + number of args to reserve before the first one. This code is based + on Alexandre Julliard's LGPLed wine-0.9.34/dlls/kernel32/process.c + and modified to fit into our framework. The function returns NULL + on error; on success an arry with the argiments is returned. This + array has been allocaqted using a plain malloc (and not the usual + xtrymalloc). */ +static char ** +build_argv (char *cmdline_arg, int reserved) +{ + int argc; + char **argv; + char *cmdline, *s, *arg, *d; + int in_quotes, bs_count; + + cmdline = malloc (strlen (cmdline_arg) + 1); + if (!cmdline) + return NULL; + strcpy (cmdline, cmdline_arg); + + /* First determine the required size of the array. */ + argc = reserved + 1; + bs_count = 0; + in_quotes = 0; + s = cmdline; + for (;;) + { + if ( !*s || ((*s==' ' || *s=='\t') && !in_quotes)) /* A space. */ + { + argc++; + /* Skip the remaining spaces. */ + while (*s==' ' || *s=='\t') + s++; + if (!*s) + break; + bs_count = 0; + } + else if (*s=='\\') + { + bs_count++; + s++; + } + else if ( (*s == '\"') && !(bs_count & 1)) + { + /* Unescaped '\"' */ + in_quotes = !in_quotes; + bs_count=0; + s++; + } + else /* A regular character. */ + { + bs_count = 0; + s++; + } + } + + argv = malloc (argc * sizeof *argv); + if (!argv) + { + free (cmdline); + return NULL; + } + + /* Now actually parse the command line. */ + argc = reserved; + bs_count = 0; + in_quotes=0; + arg = d = s = cmdline; + while (*s) + { + if ((*s==' ' || *s=='\t') && !in_quotes) + { + /* Close the argument and copy it. */ + *d = 0; + argv[argc++] = arg; + + /* Skip the remaining spaces. */ + do + s++; + while (*s==' ' || *s=='\t'); + + /* Start with a new argument */ + arg = d = s; + bs_count = 0; + } + else if (*s=='\\') + { + *d++ = *s++; + bs_count++; + } + else if (*s=='\"') + { + if ( !(bs_count & 1) ) + { + /* Preceded by an even number of backslashes, this is + half that number of backslashes, plus a '\"' which we + discard. */ + d -= bs_count/2; + s++; + in_quotes = !in_quotes; + } + else + { + /* Preceded by an odd number of backslashes, this is + half that number of backslashes followed by a '\"'. */ + d = d - bs_count/2 - 1; + *d++ ='\"'; + s++; + } + bs_count=0; + } + else /* A regular character. */ + { + *d++ = *s++; + bs_count = 0; + } + } + + if (*arg) + { + *d = 0; + argv[argc++] = arg; + } + argv[argc] = NULL; + + return argv; +} + + + /* Our window message processing function. */ static LRESULT CALLBACK wndw_proc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) @@ -155,24 +286,23 @@ w32_setup_taskbar (void) /* The main entry point for the Windows version. We save away all GUI - related stuff, parse the commandline and finally call the real + related stuff, parse the command line and finally call the real main. */ int WINAPI WinMain (HINSTANCE hinst, HINSTANCE hprev, LPSTR cmdline, int showcmd) { - /* Fixme: We need a parser for the command line. Should be - available in some CRT code - need to see whether we can find a - GNU version. For nopw we call gpg-agent with a couple of fixed arguments - */ - char *argv[] = { "gpg-agent.exe", "--daemon", "-v", "--debug-all", NULL }; + char **argv; + int argc; + /* We use the GetCommandLine function because that also includes the + program name in contrast to the CMDLINE arg. */ + argv = build_argv (GetCommandLineA (), 0); + if (!argv) + return 2; /* Can't do much about a malloc failure. */ + for (argc=0; argv[argc]; argc++) + ; glob_hinst = hinst; - return w32_main (DIM(argv)-1, argv); + return w32_main (argc, argv); } - - - - - diff --git a/doc/gpg-agent.texi b/doc/gpg-agent.texi index 3f0412538..a079b3095 100644 --- a/doc/gpg-agent.texi +++ b/doc/gpg-agent.texi @@ -369,18 +369,20 @@ this option at runtime does not kill an already forked scdaemon. @item --use-standard-socket @itemx --no-use-standard-socket +@itemx --no-reuse-standard-socket @opindex use-standard-socket @opindex no-use-standard-socket +@opindex no-reuse-standard-socket By enabling this option @command{gpg-agent} will listen on the socket named @file{S.gpg-agent}, located in the home directory, and not create a random socket below a temporary directory. Tools connecting to @command{gpg-agent} should first try to connect to the socket given in environment variable @var{GPG_AGENT_INFO} and the fall back to this socket. This option may not be used if the home directory is mounted as -a remote file system. - -@noindent -Note, that as of now, W32 systems default to this option. +a remote file system. If @option{--no-reuse-standard-socket} is used, +@command{gpg-agent} will not try to reuse a socket which is already in +use. Note, that @option{--use-standard-socket} is the default on +Windows systems. @item --display @var{string} diff --git a/g10/gpg.c b/g10/gpg.c index 1e202f681..44ea8048e 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -1456,7 +1456,7 @@ list_config(char *items) static void gpgconf_list (const char *configfile) { - char *configfile_esc = percent_escape (configfile); + char *configfile_esc = percent_escape (configfile, NULL); /* The following definitions are taken from gnupg/tools/gpgconf-comp.c. */ #define GC_OPT_FLAG_NONE 0UL diff --git a/jnlib/ChangeLog b/jnlib/ChangeLog index f98b1a282..4826ce4cd 100644 --- a/jnlib/ChangeLog +++ b/jnlib/ChangeLog @@ -1,3 +1,17 @@ +2007-06-19 Werner Koch + + * Makefile.am: Add support for regression tests. + * t-support.h, t-support.c: New. + * t-stringhelp.c: New. + + * stringhelp.c (percent_escape): Add arg EXTRA to make it a more + general function. Changed all callers. + +2007-06-18 Werner Koch + + * w32-afunix.c (_w32_sock_bind): Changed to properly detect an + already used socket. + 2007-06-18 Marcus Brinkmann * stringhelp.h (percent_escape): New prototype. diff --git a/jnlib/Makefile.am b/jnlib/Makefile.am index 0f593bb3f..eb447b592 100644 --- a/jnlib/Makefile.am +++ b/jnlib/Makefile.am @@ -23,6 +23,8 @@ ## Process this file with automake to produce Makefile.in EXTRA_DIST = README +noinst_PROGRAMS = $(module_tests) +TESTS = $(module_tests) AM_CPPFLAGS = -I$(top_srcdir)/intl @@ -51,3 +53,20 @@ endif # For GnuPG we don't need the xmalloc stuff. # xmalloc.c xmalloc.h + +# +# Module tests. +# +# These tests should only be used at the canonical location of jnlib +# which is the GnuPG package. The reason for this is that t-support.c +# defines replacements for the actual used memory allocation functions +# so that there is no dependency on libgcrypt. +# +module_tests = t-stringhelp + +t_jnlib_src = t-support.c t-support.h +t_jnlib_ldadd = libjnlib.a $(LIBINTL) $(LIBICONV) + +t_stringhelp_SOURCES = t-stringhelp.c $(t_jnlib_src) +t_stringhelp_LDADD = $(t_jnlib_ldadd) + diff --git a/jnlib/stringhelp.c b/jnlib/stringhelp.c index 49d91c075..2050cddb3 100644 --- a/jnlib/stringhelp.c +++ b/jnlib/stringhelp.c @@ -34,6 +34,8 @@ #include "stringhelp.h" +#define tohex_lower(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'a')) + /* * Look for the substring SUB in buffer and return a pointer to that * substring in BUFFER or NULL if not found. @@ -827,19 +829,19 @@ memrchr (const void *buffer, int c, size_t n) #endif /*HAVE_MEMRCHR*/ -/* Percent-escape the string STR by replacing colons with '%3a'. */ +/* Percent-escape the string STR by replacing colons with '%3a'. If + EXTRA is not NULL all characters in it are also escaped. */ char * -percent_escape (const char *str) +percent_escape (const char *str, const char *extra) { - int i = 0; - int j = 0; + int i, j; char *ptr; if (!str) return NULL; - while (str[i]) - if (str[i++] == ':') + for (i=j=0; str[i]; i++) + if (str[i] == ':' || str[i] == '%' || (extra && strchr (extra, str[i]))) j++; ptr = jnlib_xmalloc (i + 2 * j + 1); i = 0; @@ -851,6 +853,18 @@ percent_escape (const char *str) ptr[i++] = '3'; ptr[i++] = 'a'; } + else if (*str == '%') + { + ptr[i++] = '%'; + ptr[i++] = '2'; + ptr[i++] = '5'; + } + else if (extra && strchr (extra, *str)) + { + ptr[i++] = '%'; + ptr[i++] = tohex_lower ((*str>>4)&15); + ptr[i++] = tohex_lower (*str&15); + } else ptr[i++] = *str; str++; diff --git a/jnlib/stringhelp.h b/jnlib/stringhelp.h index fdd887bf2..5f08745cb 100644 --- a/jnlib/stringhelp.h +++ b/jnlib/stringhelp.h @@ -117,8 +117,9 @@ isascii (int c) #endif #define STR2(v) STR(v) -/* Percent-escape the string STR by replacing colons with '%3a'. */ -char *percent_escape (const char *str); +/* Percent-escape the string STR by replacing colons with '%3a'. If + EXTRA is not NULL, also replace all characters given in EXTRA. */ +char *percent_escape (const char *str, const char *extra); #endif /*LIBJNLIB_STRINGHELP_H*/ diff --git a/jnlib/t-stringhelp.c b/jnlib/t-stringhelp.c new file mode 100644 index 000000000..27bea8940 --- /dev/null +++ b/jnlib/t-stringhelp.c @@ -0,0 +1,94 @@ +/* t-stringhelp.c - Regression tests for stringhelp.c + * Copyright (C) 2007 Free Software Foundation, Inc. + * + * This file is part of JNLIB. + * + * JNLIB 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. + * + * JNLIB 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include +#include +#include +#include + +#include "stringhelp.h" + +#include "t-support.h" + + + +static void +test_percent_escape (void) +{ + char *result; + static struct { + const char *extra; + const char *value; + const char *expected; + } tests[] = + { + { NULL, "", "" }, + { NULL, "%", "%25" }, + { NULL, "%%", "%25%25" }, + { NULL, " %", " %25" }, + { NULL, ":", "%3a" }, + { NULL, " :", " %3a" }, + { NULL, ": ", "%3a " }, + { NULL, " : ", " %3a " }, + { NULL, "::", "%3a%3a" }, + { NULL, ": :", "%3a %3a" }, + { NULL, "%:", "%25%3a" }, + { NULL, ":%", "%3a%25" }, + { "\\\n:", ":%", "%3a%25" }, + { "\\\n:", "\\:%", "%5c%3a%25" }, + { "\\\n:", "\n:%", "%0a%3a%25" }, + { "\\\n:", "\xff:%", "\xff%3a%25" }, + { "\\\n:", "\xfe:%", "\xfe%3a%25" }, + { "\\\n:", "\x01:%", "\x01%3a%25" }, + { "\x01", "\x01:%", "%01%3a%25" }, + { "\xfe", "\xfe:%", "%fe%3a%25" }, + { "\xfe", "\xff:%", "\xff%3a%25" }, + + { NULL, NULL, NULL } + }; + int testno; + + result = percent_escape (NULL, NULL); + if (result) + fail (0); + for (testno=0; tests[testno].value; testno++) + { + result = percent_escape (tests[testno].value, tests[testno].extra); + if (!result) + fail (testno); + if (strcmp (result, tests[testno].expected)) + fail (testno); + xfree (result); + } + +} + + + + +int +main (int argc, char **argv) +{ + test_percent_escape (); + + return 0; +} + diff --git a/jnlib/t-support.c b/jnlib/t-support.c new file mode 100644 index 000000000..d9d50e9a4 --- /dev/null +++ b/jnlib/t-support.c @@ -0,0 +1,111 @@ +/* t-support.c - helper functions for the regression tests. + * Copyright (C) 2007 Free Software Foundation, Inc. + * + * This file is part of JNLIB. + * + * JNLIB 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. + * + * JNLIB 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include +#include +#include +#include +#include + +#include "t-support.h" + +/* Replacements for the malloc functions as used here. */ + +static void +out_of_memory (void) +{ + fprintf (stderr,"error: out of core in regression tests: %s\n", + strerror (errno)); + exit (2); +} + + +void * +gcry_malloc (size_t n) +{ + return malloc (n); +} + +void * +gcry_xmalloc (size_t n) +{ + void *p = malloc (n); + if (!p) + out_of_memory (); + return p; +} + +char * +gcry_strdup (const char *string) +{ + return malloc (strlen (string)+1); +} + + +void * +gcry_realloc (void *a, size_t n) +{ + return realloc (a, n); +} + +void * +gcry_xrealloc (void *a, size_t n) +{ + void *p = realloc (a, n); + if (!p) + out_of_memory (); + return p; +} + + + +void * +gcry_calloc (size_t n, size_t m) +{ + return calloc (n, m); +} + +void * +gcry_xcalloc (size_t n, size_t m) +{ + void *p = calloc (n, m); + if (!p) + out_of_memory (); + return p; +} + + +char * +gcry_xstrdup (const char *string) +{ + void *p = malloc (strlen (string)+1); + if (!p) + out_of_memory (); + strcpy (p, string); + return p; +} + +void +gcry_free (void *a) +{ + if (a) + free (a); +} diff --git a/jnlib/t-support.h b/jnlib/t-support.h new file mode 100644 index 000000000..661dfb46e --- /dev/null +++ b/jnlib/t-support.h @@ -0,0 +1,52 @@ +/* t-support.h - Helper for the regression tests + * Copyright (C) 2007 Free Software Foundation, Inc. + * + * This file is part of JNLIB. + * + * JNLIB 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. + * + * JNLIB 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef LIBJNLIB_T_SUPPORT_H +#define LIBJNLIB_T_SUPPORT_H 1 + +#ifdef GCRYPT_VERSION +#error The regression tests should not include with gcrypt.h +#endif + +/* Repalcement prototypes. */ +void *gcry_xmalloc (size_t n); +void *gcry_xcalloc (size_t n, size_t m); +void *gcry_xrealloc (void *a, size_t n); +char *gcry_xstrdup (const char * a); +void gcry_free (void *a); + +/* Map the used xmalloc functions to those implemented by t-support.c */ +#define xmalloc(a) gcry_xmalloc ( (a) ) +#define xcalloc(a,b) gcry_xcalloc ( (a), (b) ) +#define xrealloc(a,n) gcry_xrealloc ( (a), (n) ) +#define xstrdup(a) gcry_xstrdup ( (a) ) +#define xfree(a) gcry_free ( (a) ) + + +/* Macros to print the result of a test. */ +#define pass() do { ; } while(0) +#define fail(a) do { fprintf (stderr, "%s:%d: test %d failed\n",\ + __FILE__,__LINE__, (a)); \ + exit (1); \ + } while(0) + + +#endif /*LIBJNLIB_T_SUPPORT_H*/ diff --git a/jnlib/w32-afunix.c b/jnlib/w32-afunix.c index dcce423c7..16132a230 100644 --- a/jnlib/w32-afunix.c +++ b/jnlib/w32-afunix.c @@ -22,11 +22,19 @@ #ifdef _WIN32 #include #include +#include +#include #include #include #include "w32-afunix.h" +#ifndef S_IRGRP +# define S_IRGRP 0 +# define S_IWGRP 0 +#endif + + int _w32_close (int fd) { @@ -81,34 +89,56 @@ _w32_sock_connect (int sockfd, struct sockaddr * addr, int addrlen) int -_w32_sock_bind (int sockfd, struct sockaddr * addr, int addrlen) +_w32_sock_bind (int sockfd, struct sockaddr *addr, int addrlen) { if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX) { struct sockaddr_in myaddr; - struct sockaddr_un * unaddr; - FILE * fp; + struct sockaddr_un *unaddr; + int filefd; + FILE *fp; int len = sizeof myaddr; int rc; + unaddr = (struct sockaddr_un *)addr; + myaddr.sin_port = 0; myaddr.sin_family = AF_INET; myaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); - rc = bind (sockfd, (struct sockaddr *)&myaddr, len); - if (rc) - return rc; - rc = getsockname (sockfd, (struct sockaddr *)&myaddr, &len); - if (rc) - return rc; - unaddr = (struct sockaddr_un *)addr; - fp = fopen (unaddr->sun_path, "wb"); + filefd = open (unaddr->sun_path, + (O_WRONLY|O_CREAT|O_EXCL|O_BINARY), + (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)); + if (filefd == -1) + { + if (errno == EEXIST) + errno = WSAEADDRINUSE; + return -1; + } + fp = fdopen (filefd, "wb"); if (!fp) - return -1; + { + int save_e = errno; + close (filefd); + errno = save_e; + return -1; + } + + rc = bind (sockfd, (struct sockaddr *)&myaddr, len); + if (!rc) + rc = getsockname (sockfd, (struct sockaddr *)&myaddr, &len); + if (rc) + { + int save_e = errno; + fclose (fp); + remove (unaddr->sun_path); + errno = save_e; + return rc; + } fprintf (fp, "%d", myaddr.sin_port); fclose (fp); - /* we need this later. */ + /* The caller expects these values. */ unaddr->sun_family = myaddr.sin_family; unaddr->sun_port = myaddr.sin_port; unaddr->sun_addr.s_addr = myaddr.sin_addr.s_addr; diff --git a/scd/scdaemon.c b/scd/scdaemon.c index 4e45907db..f9a99922f 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -551,7 +551,7 @@ main (int argc, char **argv ) #define GC_OPT_FLAG_NO_ARG_DESC (1UL << 6) if (!config_filename) filename = make_filename (opt.homedir, "scdaemon.conf", NULL ); - filename_esc = percent_escape (filename); + filename_esc = percent_escape (filename, NULL); printf ("gpgconf-scdaemon.conf:%lu:\"%s\n", GC_OPT_FLAG_DEFAULT, filename_esc); diff --git a/sm/gpgsm.c b/sm/gpgsm.c index 11b759b65..f6d2b8444 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -1393,7 +1393,7 @@ main ( int argc, char **argv) a default, which is described by the value of the ARGDEF field. */ #define GC_OPT_FLAG_NO_ARG_DESC (1UL << 6) - char *config_filename_esc = percent_escape (opt.config_filename); + char *config_filename_esc = percent_escape (opt.config_filename, NULL); printf ("gpgconf-gpgsm.conf:%lu:\"%s\n", GC_OPT_FLAG_DEFAULT, config_filename_esc); diff --git a/tools/ChangeLog b/tools/ChangeLog index c30ef7954..f36c33a40 100644 --- a/tools/ChangeLog +++ b/tools/ChangeLog @@ -1,3 +1,8 @@ +2007-06-19 Werner Koch + + * gpgconf-comp.c (percent_escape): Rename to my_percent_escape. + Changed all callers. + 2007-06-18 Marcus Brinkmann * gpgconf-comp.c (retrieve_options_from_file): Close LIST_FILE. diff --git a/tools/gpgconf-comp.c b/tools/gpgconf-comp.c index 368d4988d..caf09d342 100644 --- a/tools/gpgconf-comp.c +++ b/tools/gpgconf-comp.c @@ -984,7 +984,7 @@ my_dgettext (const char *domain, const char *msgid) /* Percent-Escape special characters. The string is valid until the next invocation of the function. */ static char * -percent_escape (const char *src) +my_percent_escape (const char *src) { static char *esc_str; static int esc_str_len; @@ -1083,7 +1083,8 @@ gc_component_list_components (FILE *out) { const char *desc = gc_component[idx].desc; desc = my_dgettext (gc_component[idx].desc_domain, desc); - fprintf (out, "%s:%s\n", gc_component[idx].name, percent_escape (desc)); + fprintf (out, "%s:%s\n", + gc_component[idx].name, my_percent_escape (desc)); } } @@ -1174,7 +1175,7 @@ list_one_option (const gc_option_t *option, FILE *out) fprintf (out, " %s", gc_level[option->level].name); /* The description field. */ - fprintf (out, ":%s", desc ? percent_escape (desc) : ""); + fprintf (out, ":%s", desc ? my_percent_escape (desc) : ""); /* The type field. */ fprintf (out, ":%u", option->arg_type); @@ -1188,7 +1189,7 @@ list_one_option (const gc_option_t *option, FILE *out) gc_arg_type[gc_arg_type[option->arg_type].fallback].name); /* The argument name field. */ - fprintf (out, ":%s", arg_name ? percent_escape (arg_name) : ""); + fprintf (out, ":%s", arg_name ? my_percent_escape (arg_name) : ""); if (arg_name) xfree (arg_name); @@ -1458,7 +1459,7 @@ retrieve_options_from_program (gc_component_t component, gc_backend_t backend) } else if (gc_arg_type[option->arg_type].fallback == GC_ARG_TYPE_STRING) - opt_value = xasprintf ("\"%s", percent_escape (value)); + opt_value = xasprintf ("\"%s", my_percent_escape (value)); else { /* FIXME: Verify that the number is sane. */ @@ -1549,12 +1550,12 @@ retrieve_options_from_file (gc_component_t component, gc_backend_t backend) really append. */ if (list) { - new_list = xasprintf ("%s,\"%s", list, percent_escape (start)); + new_list = xasprintf ("%s,\"%s", list, my_percent_escape (start)); xfree (list); list = new_list; } else - list = xasprintf ("\"%s", percent_escape (start)); + list = xasprintf ("\"%s", my_percent_escape (start)); } if (length < 0 || ferror (list_file)) gc_error (1, errno, "can not read list file %s", list_pathname);