From cvs at cvs.gnupg.org Tue Jun 1 14:13:32 2010 From: cvs at cvs.gnupg.org (svn author wk) Date: Tue, 01 Jun 2010 14:13:32 +0200 Subject: [svn] GnuPG - r5344 - in branches/STABLE-BRANCH-1-4: . g10 Message-ID: Author: wk Date: 2010-06-01 14:13:31 +0200 (Tue, 01 Jun 2010) New Revision: 5344 Modified: branches/STABLE-BRANCH-1-4/NEWS branches/STABLE-BRANCH-1-4/g10/ChangeLog branches/STABLE-BRANCH-1-4/g10/gpg.c Log: Ignore some GnuPG-2 only options. Modified: branches/STABLE-BRANCH-1-4/g10/ChangeLog =================================================================== --- branches/STABLE-BRANCH-1-4/g10/ChangeLog 2010-05-30 12:06:38 UTC (rev 5343) +++ branches/STABLE-BRANCH-1-4/g10/ChangeLog 2010-06-01 12:13:31 UTC (rev 5344) @@ -1,3 +1,8 @@ +2010-06-01 Werner Koch + + * gpg.c (main): Add dummy option --debug-level and ignore + --log-file if a socket prefix is given. + 2010-05-12 Werner Koch * armor.c (radix64_read): Change fix 2006-04-08 to fix bug#1179. Modified: branches/STABLE-BRANCH-1-4/NEWS =================================================================== --- branches/STABLE-BRANCH-1-4/NEWS 2010-05-30 12:06:38 UTC (rev 5343) +++ branches/STABLE-BRANCH-1-4/NEWS 2010-06-01 12:13:31 UTC (rev 5344) @@ -3,6 +3,7 @@ * Bug fixes. + Noteworthy changes in version 1.4.10 (2009-09-02) ------------------------------------------------- Modified: branches/STABLE-BRANCH-1-4/g10/gpg.c =================================================================== --- branches/STABLE-BRANCH-1-4/g10/gpg.c 2010-05-30 12:06:38 UTC (rev 5343) +++ branches/STABLE-BRANCH-1-4/g10/gpg.c 2010-06-01 12:13:31 UTC (rev 5344) @@ -188,6 +188,7 @@ oOptions, oDebug, oDebugAll, + oDebugLevel, oDebugCCIDDriver, oStatusFD, oStatusFile, @@ -513,6 +514,7 @@ { oOptions, "options", 2, "@"}, { oDebug, "debug" ,4|16, "@"}, { oDebugAll, "debug-all" ,0, "@"}, + { oDebugLevel, "debug-level" ,0, "@"}, { oStatusFD, "status-fd" ,1, "@"}, { oStatusFile, "status-file" ,2, "@"}, { oAttributeFD, "attribute-fd" ,1, "@" }, @@ -2202,6 +2204,7 @@ break; case oDebug: opt.debug |= pargs.r.ret_ulong; break; case oDebugAll: opt.debug = ~0; break; + case oDebugLevel: break; /* Not supported. */ case oDebugCCIDDriver: #if defined(ENABLE_CARD_SUPPORT) && defined(HAVE_LIBUSB) ccid_set_debug_level (ccid_set_debug_level (1)+1); @@ -2224,7 +2227,11 @@ iobuf_translate_file_handle (pargs.r.ret_int, 1)); break; case oLoggerFile: - log_set_logfile( NULL, open_info_file (pargs.r.ret_str, 1) ); + /* Our log code does not support the socket feature. Thus + we ignore such log files to avoid problems with + gpg.conf files which are also used by gpg2. */ + if (strncmp (pargs.r.ret_str, "socket://", 9)) + log_set_logfile( NULL, open_info_file (pargs.r.ret_str, 1) ); break; case oWithFingerprint: From cvs at cvs.gnupg.org Tue Jun 1 14:42:40 2010 From: cvs at cvs.gnupg.org (svn author wk) Date: Tue, 01 Jun 2010 14:42:40 +0200 Subject: [svn] GnuPG - r5345 - in branches/STABLE-BRANCH-1-4: doc mpi Message-ID: Author: wk Date: 2010-06-01 14:42:39 +0200 (Tue, 01 Jun 2010) New Revision: 5345 Modified: branches/STABLE-BRANCH-1-4/doc/gpg.texi branches/STABLE-BRANCH-1-4/mpi/ChangeLog branches/STABLE-BRANCH-1-4/mpi/longlong.h Log: Fix bug 1231. Minor doc improvement. Modified: branches/STABLE-BRANCH-1-4/mpi/ChangeLog =================================================================== --- branches/STABLE-BRANCH-1-4/mpi/ChangeLog 2010-06-01 12:13:31 UTC (rev 5344) +++ branches/STABLE-BRANCH-1-4/mpi/ChangeLog 2010-06-01 12:42:39 UTC (rev 5345) @@ -1,3 +1,8 @@ +2010-06-01 Werner Koch + + * longlong.h (umul_ppmm) <__mips__>: Add code for gcc 4.4. This + fixes bug#1231. + 2009-12-09 Werner Koch * config.links: Remove asm modules for all sparc64. This is Modified: branches/STABLE-BRANCH-1-4/doc/gpg.texi =================================================================== --- branches/STABLE-BRANCH-1-4/doc/gpg.texi 2010-06-01 12:13:31 UTC (rev 5344) +++ branches/STABLE-BRANCH-1-4/doc/gpg.texi 2010-06-01 12:42:39 UTC (rev 5345) @@ -845,7 +845,8 @@ @c man:.RS The listing shows you the key with its secondary keys and all user -ids. Selected keys or user ids are indicated by an asterisk. The trust +ids. The primary user id is indicated by a dot, and selected keys or +user ids are indicated by an asterisk. The trust value is displayed with the primary key: the first is the assigned owner trust and the second is the calculated trust value. Letters are used for the values: Modified: branches/STABLE-BRANCH-1-4/mpi/longlong.h =================================================================== --- branches/STABLE-BRANCH-1-4/mpi/longlong.h 2010-06-01 12:13:31 UTC (rev 5344) +++ branches/STABLE-BRANCH-1-4/mpi/longlong.h 2010-06-01 12:42:39 UTC (rev 5345) @@ -710,8 +710,15 @@ ************** MIPS ***************** ***************************************/ #if defined (__mips__) && W_TYPE_SIZE == 32 -#if __GNUC__ > 2 || __GNUC_MINOR__ >= 7 -#define umul_ppmm(w1, w0, u, v) \ +#if __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR >= 4 ) +#define umul_ppmm(w1, w0, u, v) \ + do { \ + UDItype __ll = (UDItype)(u) * (v); \ + w1 = __ll >> 32; \ + w0 = __ll; \ + } while (0) +#elif __GNUC__ > 2 || __GNUC_MINOR__ >= 7 +#define umul_ppmm(w1, w0, u, v) \ __asm__ ("multu %2,%3" \ : "=l" ((USItype)(w0)), \ "=h" ((USItype)(w1)) \ From cvs at cvs.gnupg.org Mon Jun 7 15:33:03 2010 From: cvs at cvs.gnupg.org (svn author wk) Date: Mon, 07 Jun 2010 15:33:03 +0200 Subject: [svn] GnuPG - r5346 - in trunk: . agent common doc g10 g13 tests/openpgp tools Message-ID: Author: wk Date: 2010-06-07 15:33:02 +0200 (Mon, 07 Jun 2010) New Revision: 5346 Added: trunk/tools/gpgtar-create.c trunk/tools/gpgtar-extract.c trunk/tools/gpgtar-list.c trunk/tools/gpgtar.c trunk/tools/gpgtar.h Modified: trunk/ChangeLog trunk/agent/ChangeLog trunk/agent/preset-passphrase.c trunk/common/ChangeLog trunk/common/estream.c trunk/common/estream.h trunk/common/exechelp-posix.c trunk/common/exechelp-w32.c trunk/common/exechelp-w32ce.c trunk/common/exechelp.h trunk/common/logging.c trunk/configure.ac trunk/doc/gpg.texi trunk/g10/ChangeLog trunk/g10/armor.c trunk/g10/card-util.c trunk/g10/plaintext.c trunk/g13/runner.c trunk/tests/openpgp/ChangeLog trunk/tests/openpgp/armor.test trunk/tools/ChangeLog trunk/tools/Makefile.am Log: Add unfinished gpgtar. Collected changes and ports of bug fixes from stable. [The diff below has been truncated] Modified: trunk/ChangeLog =================================================================== --- trunk/ChangeLog 2010-06-01 12:42:39 UTC (rev 5345) +++ trunk/ChangeLog 2010-06-07 13:33:02 UTC (rev 5346) @@ -1,3 +1,11 @@ +2010-06-07 Werner Koch + + * configure.ac: Add option --enable-gpgtar. + +2010-05-31 Werner Koch + + * configure.ac (AC_CHECK_FUNCS): Check for lstat. + 2010-04-30 Werner Koch * configure.ac: Add option --enable-standard-socket. Modified: trunk/agent/ChangeLog =================================================================== --- trunk/agent/ChangeLog 2010-06-01 12:42:39 UTC (rev 5345) +++ trunk/agent/ChangeLog 2010-06-07 13:33:02 UTC (rev 5346) @@ -1,3 +1,8 @@ +2010-05-12 Werner Koch + + * preset-passphrase.c (forget_passphrase): Actually implement + this. Fixes bug#1198. + 2010-05-11 Werner Koch * agent.h (opt): Add field USE_STANDARD_SOCKET. Modified: trunk/common/ChangeLog =================================================================== --- trunk/common/ChangeLog 2010-06-01 12:42:39 UTC (rev 5345) +++ trunk/common/ChangeLog 2010-06-07 13:33:02 UTC (rev 5346) @@ -1,3 +1,22 @@ +2010-06-07 Werner Koch + + * estream.c (es_fname_get, es_fname_set): New. + (fname_set_internal): New. + (struct estream_internal): Add fields printable_fname and + printable_fname_inuse. + (_es_get_std_stream): Set stream name. + (es_fopen, es_freopen, es_deinitialize): Set fname. + + * exechelp-posix.c (gnupg_spawn_process): Allow passing INFILE or + OUTFILE as NULL. + * exechelp-w32.c (gnupg_spawn_process): Ditto. + * exechelp-w32ce.c (gnupg_spawn_process): Return an error for + INFILE or OUTFILE passed as NULL. + +2010-06-01 Werner Koch + + * logging.c (log_get_stream): Make sture a log stream is available. + 2010-05-30 Werner Koch * init.c (writestring_via_estream): New. @@ -15,7 +34,7 @@ (es_func_fd_destroy): Implement a dummy stream. * exechelp-w32ce.c (build_w32_commandline): Add args FD0_ISNULL - and FD1_ISNULL. Remove arg PGMNAME. Change callers. + and FD1_ISNULL. Remove arg PGMNAME. Change callers. (gnupg_spawn_process_detached): Implement. (gnupg_spawn_process_fd): Implement one special case for now. Modified: trunk/g10/ChangeLog =================================================================== --- trunk/g10/ChangeLog 2010-06-01 12:42:39 UTC (rev 5345) +++ trunk/g10/ChangeLog 2010-06-07 13:33:02 UTC (rev 5346) @@ -1,3 +1,10 @@ +2010-05-12 Werner Koch + + * armor.c (radix64_read): Extended 2006-04-28 fix to fix bug#1179. + + * plaintext.c (handle_plaintext): Check return code of fflush. + Fixes bug#1207. + 2010-05-07 Werner Koch * import.c (fix_bad_direct_key_sigs): New. Modified: trunk/tests/openpgp/ChangeLog =================================================================== --- trunk/tests/openpgp/ChangeLog 2010-06-01 12:42:39 UTC (rev 5345) +++ trunk/tests/openpgp/ChangeLog 2010-06-07 13:33:02 UTC (rev 5346) @@ -1,3 +1,7 @@ +2010-05-12 Werner Koch + + * armor.test (Version): Add test for bug#1179. + 2010-05-11 Werner Koch * genkey1024.test: Use GPG macro. Modified: trunk/tools/ChangeLog =================================================================== --- trunk/tools/ChangeLog 2010-06-01 12:42:39 UTC (rev 5345) +++ trunk/tools/ChangeLog 2010-06-07 13:33:02 UTC (rev 5346) @@ -1,3 +1,11 @@ +2010-06-07 Werner Koch + + * gpgtar.c, gpgtar.h, gpgtar-list.c, gpgtar-create.c + * gpgtar-extract.c: New. + * Makefile.am (commonpth_libs): New. + (gpgtar_SOURCES, gpgtar_CFLAGS, gpgtar_LDADD): New. + (bin_PROGRAMS) [!W32CE]: Add gpgtar. + 2010-04-20 Marcus Brinkmann * gpgconf-comp.c (option_check_validity): Use dummy variables to @@ -1104,7 +1112,7 @@ Copyright 2003, 2004, 2005, 2006, 2007, 2008, - 2009 Free Software Foundation, Inc. + 2009, 2010 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 Modified: trunk/agent/preset-passphrase.c =================================================================== --- trunk/agent/preset-passphrase.c 2010-06-01 12:42:39 UTC (rev 5345) +++ trunk/agent/preset-passphrase.c 2010-06-07 13:33:02 UTC (rev 5346) @@ -189,11 +189,15 @@ rc = asprintf (&line, "CLEAR_PASSPHRASE %s\n", keygrip); if (rc < 0) + rc = gpg_error_from_syserror (); + else + rc = map_spwq_error (simple_query (line)); + if (rc) { - log_error ("clearing passphrase failed: %s\n", - gpg_strerror (gpg_error_from_syserror ())); + log_error ("clearing passphrase failed: %s\n", gpg_strerror (rc)); return; } + xfree (line); } Modified: trunk/common/estream.c =================================================================== --- trunk/common/estream.c 2010-06-01 12:42:39 UTC (rev 5345) +++ trunk/common/estream.c 2010-06-07 13:33:02 UTC (rev 5346) @@ -211,6 +211,7 @@ void *cookie; /* Cookie. */ void *opaque; /* Opaque data. */ unsigned int modeflags; /* Flags for the backend. */ + char *printable_fname; /* Malloced filename for es_fname_get. */ off_t offset; es_cookie_read_function_t func_read; es_cookie_write_function_t func_write; @@ -227,6 +228,7 @@ unsigned int is_stdstream:1; /* This is a standard stream. */ unsigned int stdstream_fd:2; /* 0, 1 or 2 for a standard stream. */ unsigned int print_err: 1; /* Error in print_fun_writer. */ + unsigned int printable_fname_inuse: 1; /* es_fname_get has been used. */ int print_errno; /* Errno from print_fun_writer. */ size_t print_ntotal; /* Bytes written from in print_fun_writer. */ FILE *print_fp; /* Stdio stream used by print_fun_writer. */ @@ -266,8 +268,12 @@ #endif +/* Local prototypes. */ +static void fname_set_internal (estream_t stream, const char *fname, int quote); + + + - /* Macros. */ /* Calculate array dimension. */ @@ -1275,6 +1281,8 @@ stream->intern->is_stdstream = 0; stream->intern->stdstream_fd = 0; stream->intern->deallocate_buffer = 0; + stream->intern->printable_fname = NULL; + stream->intern->printable_fname_inuse = 0; stream->data_len = 0; stream->data_offset = 0; @@ -1314,7 +1322,10 @@ if (func_close) SET_UNLESS_NONZERO (err, tmp_err, (*func_close) (stream->intern->cookie)); - + mem_free (stream->intern->printable_fname); + stream->intern->printable_fname = NULL; + stream->intern->printable_fname_inuse = 0; + return err; } @@ -2190,6 +2201,9 @@ if (err) goto out; + if (stream && path) + fname_set_internal (stream, path, 1); + out: if (err && create_called) @@ -2467,6 +2481,9 @@ stream->intern->stdstream_fd = fd; if (fd == 2) es_set_buffering (stream, NULL, _IOLBF, 0); + fname_set_internal (stream, + fd == 0? "[stdin]" : + fd == 1? "[stdout]" : "[stderr]", 0); } ESTREAM_LIST_UNLOCK; return stream; @@ -2515,7 +2532,11 @@ stream = NULL; } else - ESTREAM_UNLOCK (stream); + { + if (stream && path) + fname_set_internal (stream, path, 1); + ESTREAM_UNLOCK (stream); + } } else { @@ -3407,6 +3428,68 @@ return opaque; } + +static void +fname_set_internal (estream_t stream, const char *fname, int quote) +{ + if (stream->intern->printable_fname + && !stream->intern->printable_fname_inuse) + { + mem_free (stream->intern->printable_fname); + stream->intern->printable_fname = NULL; + } + if (stream->intern->printable_fname) + return; /* Can't change because it is in use. */ + + if (*fname != '[') + quote = 0; + else + quote = !!quote; + + stream->intern->printable_fname = mem_alloc (strlen (fname) + quote + 1); + if (fname) + { + if (quote) + stream->intern->printable_fname[0] = '\\'; + strcpy (stream->intern->printable_fname+quote, fname); + } +} + + +/* Set the filename attribute of STREAM. There is no error return. + as long as STREAM is valid. This function is called internally by + functions which open a filename. */ +void +es_fname_set (estream_t stream, const char *fname) +{ + if (fname) + { + ESTREAM_LOCK (stream); + fname_set_internal (stream, fname, 1); + ESTREAM_UNLOCK (stream); + } +} + + +/* Return the filename attribute of STREAM. In case no filename has + been set, "[?]" will be returned. The returned file name is valid + as long as STREAM is valid. */ +const char * +es_fname_get (estream_t stream) +{ + const char *fname; + + ESTREAM_LOCK (stream); + fname = stream->intern->printable_fname; + if (fname) + stream->intern->printable_fname_inuse = 1; + ESTREAM_UNLOCK (stream); + if (!fname) + fname = "[?]"; + return fname; +} + + /* Print a BUFFER to STREAM while replacing all control characters and the characters in DELIMITERS by standard C escape sequences. Returns 0 on success or -1 on error. If BYTES_WRITTEN is not NULL Modified: trunk/common/estream.h =================================================================== --- trunk/common/estream.h 2010-06-01 12:42:39 UTC (rev 5345) +++ trunk/common/estream.h 2010-06-07 13:33:02 UTC (rev 5346) @@ -128,6 +128,8 @@ #define es_tmpfile _ESTREAM_PREFIX(es_tmpfile) #define es_opaque_set _ESTREAM_PREFIX(es_opaque_set) #define es_opaque_get _ESTREAM_PREFIX(es_opaque_get) +#define es_fname_set _ESTREAM_PREFIX(es_fname_set) +#define es_fname_get _ESTREAM_PREFIX(es_fname_get) #define es_write_sanitized_utf8_buffer \ _ESTREAM_PREFIX(es_write_sanitized_utf8_buffer) #endif /*_ESTREAM_EXT_SYM_PREFIX*/ @@ -358,7 +360,10 @@ void es_opaque_set (estream_t ES__RESTRICT stream, void *ES__RESTRICT opaque); void *es_opaque_get (estream_t stream); +void es_fname_set (estream_t stream, const char *fname); +const char *es_fname_get (estream_t stream); + #ifdef GNUPG_MAJOR_VERSION int es_write_sanitized_utf8_buffer (estream_t stream, const void *buffer, size_t length, Modified: trunk/common/exechelp-posix.c =================================================================== --- trunk/common/exechelp-posix.c 2010-06-01 12:42:39 UTC (rev 5345) +++ trunk/common/exechelp-posix.c 2010-06-07 13:33:02 UTC (rev 5346) @@ -313,11 +313,22 @@ *statusfile = NULL; *pid = (pid_t)(-1); - es_fflush (infile); - es_rewind (infile); - fd = es_fileno (infile); - fdout = es_fileno (outfile); - if (fd == -1 || fdout == -1) + + if (infile) + { + es_fflush (infile); + es_rewind (infile); + fd = es_fileno (infile); + } + else + fd = -1; + + if (outfile) + fdout = es_fileno (outfile); + else + fdout = -1; + + if ((infile && fd == -1) || (outfile && fdout == -1)) log_fatal ("no file descriptor for file passed to gnupg_spawn_process\n"); if (pipe (rp) == -1) Modified: trunk/common/exechelp-w32.c =================================================================== --- trunk/common/exechelp-w32.c 2010-06-01 12:42:39 UTC (rev 5345) +++ trunk/common/exechelp-w32.c 2010-06-07 13:33:02 UTC (rev 5346) @@ -382,17 +382,30 @@ int cr_flags; char *cmdline; int fd, fdout, rp[2]; + HANDLE nullhd[]; + int i; (void)preexec; /* Setup return values. */ *statusfile = NULL; *pid = (pid_t)(-1); - es_fflush (infile); - es_rewind (infile); - fd = _get_osfhandle (es_fileno (infile)); - fdout = _get_osfhandle (es_fileno (outfile)); - if (fd == -1 || fdout == -1) + + if (infile) + { + es_fflush (infile); + es_rewind (infile); + fd = _get_osfhandle (es_fileno (infile)); + } + else + fd = -1; + + if (outfile) + fdout = _get_osfhandle (es_fileno (outfile)); + else + fdout = -1; + + if ( (infile && fd == -1) || (outfile && fdout == -1)) log_fatal ("no file descriptor for file passed to gnupg_spawn_process\n"); /* Prepare security attributes. */ @@ -414,14 +427,17 @@ return err; } + nullhd[0] = fd == -1? w32_open_null (0) : INVALID_HANDLE_VALUE; + nullhd[1] = outfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE; + /* Start the process. Note that we can't run the PREEXEC function because this would change our own environment. */ memset (&si, 0, sizeof si); si.cb = sizeof (si); si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE; - si.hStdInput = fd_to_handle (fd); - si.hStdOutput = fd_to_handle (fdout); + si.hStdInput = fd == -1? nullhd[0] : fd_to_handle (fd); + si.hStdOutput = outfd == -1? nullhd[1] : fd_to_handle (fdout); si.hStdError = fd_to_handle (rp[1]); cr_flags = (CREATE_DEFAULT_ERROR_MODE @@ -450,6 +466,11 @@ xfree (cmdline); cmdline = NULL; + /* Close the inherited handles to /dev/null. */ + for (i=0; i < DIM (nullhd); i++) + if (nullhd[i] != INVALID_HANDLE_VALUE) + CloseHandle (nullhd[i]); + /* Close the other end of the pipe. */ CloseHandle (fd_to_handle (rp[1])); Modified: trunk/common/exechelp-w32ce.c =================================================================== --- trunk/common/exechelp-w32ce.c 2010-06-01 12:42:39 UTC (rev 5345) +++ trunk/common/exechelp-w32ce.c 2010-06-07 13:33:02 UTC (rev 5346) @@ -501,6 +501,11 @@ *statusfile = NULL; *pid = (pid_t)(-1); + /* A NULL INFILE or OUTFILE is only used by gpgtar thus we don't + need to implement this for CE. */ + if (!infile || !outfile) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + es_fflush (infile); es_rewind (infile); Modified: trunk/common/exechelp.h =================================================================== --- trunk/common/exechelp.h 2010-06-01 12:42:39 UTC (rev 5345) +++ trunk/common/exechelp.h 2010-06-07 13:33:02 UTC (rev 5346) @@ -53,13 +53,14 @@ /* Fork and exec the PGMNAME, connect the file descriptor of INFILE to - stdin, write the output to OUTFILE, return a new stream in - STATUSFILE for stderr and the pid of the process in PID. The - arguments for the process are expected in the NULL terminated array - ARGV. The program name itself should not be included there. If - PREEXEC is not NULL, that function will be called right before the - exec. Calling gnupg_wait_process is required. Returns 0 on - success or an error code. + stdin, write the output to OUTFILE. INFILE or PUTFILE may be NULL + to connect thenm to /dev/null. Returns a new stream in STATUSFILE + for stderr and the pid of the process in PID. The arguments for the + process are expected in the NULL terminated array ARGV. The + program name itself should not be included there. If PREEXEC is + not NULL, that function will be called right before the exec. + Calling gnupg_wait_process is required. Returns 0 on success or an + error code. FLAGS is a bit vector: Modified: trunk/common/logging.c =================================================================== --- trunk/common/logging.c 2010-06-01 12:42:39 UTC (rev 5345) +++ trunk/common/logging.c 2010-06-07 13:33:02 UTC (rev 5346) @@ -402,7 +402,11 @@ estream_t log_get_stream () { - assert (logstream); + if (!logstream) + { + log_set_file (NULL); /* Make sure a log stream has been set. */ + assert (logstream); + } return logstream; } Modified: trunk/configure.ac =================================================================== --- trunk/configure.ac 2010-06-01 12:42:39 UTC (rev 5345) +++ trunk/configure.ac 2010-06-07 13:33:02 UTC (rev 5346) @@ -89,6 +89,7 @@ GNUPG_BUILD_PROGRAM(tools, yes) GNUPG_BUILD_PROGRAM(doc, yes) GNUPG_BUILD_PROGRAM(symcryptrun, no) +GNUPG_BUILD_PROGRAM(gpgtar, no) AC_SUBST(PACKAGE) AC_SUBST(PACKAGE_GT) @@ -1156,8 +1157,8 @@ AC_CHECK_FUNCS([unsetenv fcntl ftruncate]) AC_CHECK_FUNCS([gettimeofday getrusage getrlimit setrlimit clock_gettime]) AC_CHECK_FUNCS([atexit raise getpagesize strftime nl_langinfo setlocale]) -AC_CHECK_FUNCS([waitpid wait4 sigaction sigprocmask pipe stat getaddrinfo]) -AC_CHECK_FUNCS([ttyname rand ftello fsync]) +AC_CHECK_FUNCS([waitpid wait4 sigaction sigprocmask pipe getaddrinfo]) +AC_CHECK_FUNCS([ttyname rand ftello fsync stat lstat]) AC_CHECK_TYPES([struct sigaction, sigset_t],,,[#include ]) @@ -1473,6 +1474,7 @@ AM_CONDITIONAL(BUILD_TOOLS, test "$build_tools" = "yes") AM_CONDITIONAL(BUILD_DOC, test "$build_doc" = "yes") AM_CONDITIONAL(BUILD_SYMCRYPTRUN, test "$build_symcryptrun" = "yes") +AM_CONDITIONAL(BUILD_GPGTAR,test "$build_gpgtar" = "yes") AM_CONDITIONAL(RUN_GPG_TESTS, test x$cross_compiling = xno -a "$build_gpg" = yes ) @@ -1583,6 +1585,7 @@ Agent: $build_agent $build_agent_threaded Smartcard: $build_scdaemon $build_scdaemon_extra G13: $build_g13 + Gpgtar: $build_gpgtar Protect tool: $show_gnupg_protect_tool_pgm Default agent: $show_gnupg_agent_pgm Modified: trunk/doc/gpg.texi =================================================================== --- trunk/doc/gpg.texi 2010-06-01 12:42:39 UTC (rev 5345) +++ trunk/doc/gpg.texi 2010-06-07 13:33:02 UTC (rev 5346) @@ -845,7 +845,8 @@ @c man:.RS The listing shows you the key with its secondary keys and all user -ids. Selected keys or user ids are indicated by an asterisk. The trust +ids. The primary user id is indicated by a dot, and selected keys or +user ids are indicated by an asterisk. The trust value is displayed with the primary key: the first is the assigned owner trust and the second is the calculated trust value. Letters are used for the values: Modified: trunk/g10/armor.c =================================================================== --- trunk/g10/armor.c 2010-06-01 12:42:39 UTC (rev 5345) +++ trunk/g10/armor.c 2010-06-07 13:33:02 UTC (rev 5346) @@ -798,9 +798,10 @@ goto again; } } - else if(n==0) - onlypad=1; + if (!n) + onlypad = 1; + if( idx == 1 ) buf[n++] = val; checkcrc++; Modified: trunk/g10/card-util.c =================================================================== --- trunk/g10/card-util.c 2010-06-01 12:42:39 UTC (rev 5345) +++ trunk/g10/card-util.c 2010-06-07 13:33:02 UTC (rev 5346) @@ -1360,6 +1360,8 @@ { char *answer; + /* FIXME: Should be something like cpr_get_bool so that a status + GET_BOOL will be emitted. */ answer = cpr_get ("cardedit.genkeys.backup_enc", _("Make off-card backup of encryption key? (Y/n) ")); Modified: trunk/g10/plaintext.c =================================================================== --- trunk/g10/plaintext.c 2010-06-01 12:42:39 UTC (rev 5345) +++ trunk/g10/plaintext.c 2010-06-07 13:33:02 UTC (rev 5346) @@ -448,7 +448,15 @@ /* Make sure that stdout gets flushed after the plaintext has been handled. This is for extra security as we do a flush anyway before checking the signature. */ - fflush (stdout); + if (fflush (stdout)) + { + /* We need to check the return code to detect errors like disk + full for short plaintexts. See bug#1207. Checking return + values is a good idea in any case. */ + if (!rc) + rc = gpg_error_from_syserror (); + log_error ("error flushing `%s': %s\n", "[stdout]", strerror (errno)); + } if (fp && fp != stdout && fp != opt.outfp) fclose (fp); Modified: trunk/g13/runner.c =================================================================== --- trunk/g13/runner.c 2010-06-01 12:42:39 UTC (rev 5345) +++ trunk/g13/runner.c 2010-06-07 13:33:02 UTC (rev 5346) @@ -48,7 +48,7 @@ /* We use a reference counter to know when it is safe to remove the - object. Lackiong an explicit ref fucntion this counter will take + object. Lacking an explicit ref function this counter will take only these two values: 1 = Thread not running or only the thread is still running. Modified: trunk/tests/openpgp/armor.test =================================================================== --- trunk/tests/openpgp/armor.test 2010-06-01 12:42:39 UTC (rev 5345) +++ trunk/tests/openpgp/armor.test 2010-06-07 13:33:02 UTC (rev 5346) @@ -185,4 +185,579 @@ +nopad_armored_msg='-----BEGIN PGP MESSAGE----- +Version: GnuPG v1.4.11-svn5139 (GNU/Linux) +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 +jnOKMUrdbDkbYM+ojXZ18/4WPKtaxf6lTLrh3m5CJ1V8slRJp0Jes74aDQf/OXqo +QgqVrI2wnl1klGwn06bhVaymdk0hMkxAfeHBGZIQ4BMMZ3aLuVWjAcBH/HP1tVQ4 +IG7MHRnm81yVNgA6yAuZZIPQwxDWVko7rRm/DnsJcpKfL0nZHoF+bJ6q4Rd6Dey1 +S96L4PDmXseFkVZOH/7dNWyKuvSA/MmthkN14lWJiYJebaXb7oZG3XDC70o7bG6Y +mtGOrOwVthFereg1Ii98ZA4nKgqeu2paMju/t03hQXHY5iqyV9ax0A3B0rdivz4U +VbqCcO7pGNb/Ki3gGc3hfVw9YXnR7E+tra19eE7UM7o+YlunKF1Q5dJaLKY1z3L9 +3UAJmXG/sZcLqrDn9zHfb/YxqbyIkM7VIU2kKztWCCNiNKgLQsIoVzK4sbS2LVDI +grmvZg+Q7EkwxZ1FXeBGJmsiyjKYPU3PI8ZBU1MXjwTjtnQRuBSxh+Ok9glPeE+1 +rUDdlVoogUGgPAvLV3BM43E/Q5VE+X04KvPNKINvvS1nZpGKyyy1MayOfstc7Hsw +W/RgllTEd7VW5jgZKg7YyA8r8cUjMqE7zewrq6MtkoFk6ZVslWxfoADBW3ivwdwe +I4XwNboOgBx77qxf95aHRRdqWZa0JF8zvK5BH6EpBI29hlJU4leax696ACA7QIIM +Rpc+ulkvHsNxsUlrUut9AXoob0MqDJRmZvU4gSVivHjvKLEIlymJw4pLbMWhcrNa +v94TExP21Fy/zYcWiZT2nCX6qZVXTcUcQGIrBTWDbR8bxKll4FNo/2zmelyFmeXt +iH+Zp2EwFAUELsrxx9plNd5WceyU9VnZoeucNFd2QFl7lV9KL8AlQaaMdsYOt27m +8j7iNBID4HtCYM0xLwE/5uqVQPxX6qzPPZc66MSRIi8ZHZPFvVilFVzFyZSrq5Lo +ojQQmAycQGOzx7dwx7vi9SeTrBRY2PK3WVurcLiRxM+2u9vjlxigwimpnK3VU1dh +GDoPghB3O34bfiV5GndcnPDLJxsSGWz2z2WiyCFgCkVp3shHUN5c2PLWDIOf/Ejz +LzNJXFKjO6/6ZGpMmGf6bZCa9MBnvXMNic9/k0lmtbgj8SS+2//gko1EDa/Gpaqo +J2xgEuHLvp9KQABWt9VRI+tNUJQCS/Jq10ZiT1TzhczyJEqbtVDOo0l5A5sMV0PO +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 +=3akT +-----END PGP MESSAGE----- + +' + +alpha_seckey='-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1.4.8 (GNU/Linux) + +lQHhBDbjjp4RBAC2ZbFDX0wmJI8yLDYQdIiZeAuHLmfyHsqXaLGUMZtWiAvn/hNp +ctwahmzKm5oXinHUvUkLOQ0s8rOlu15nhw4azc30rTP1LsIkn5zORNnFdgYC6RKy +hOeim/63+/yGtdnTm49lVfaCqwsEmBCEkXaeWDGq+ie1b89J89T6n/JquwCgoQkj +VeVGG+B/SzJ6+yifdHWQVkcD/RXDyLXX4+WHGP2aet51XlKojWGwsZmc9LPPYhwU +/RcUO7ce1QQb0XFlUVFBhY0JQpM/ty/kNi+aGWFzigbQ+HAWZkUvA8+VIAVneN+p ++SHhGIyLTXKpAYTq46AwvllZ5Cpvf02Cp/+W1aVyA0qnBWMyeIxXmR9HOi6lxxn5 +cjajA/9VZufOXWqCXkBvz4Oy3Q5FbjQQ0/+ty8rDn8OTaiPi41FyUnEi6LO+qyBS +09FjnZj++PkcRcXW99SNxmEJRY7MuNHt5wIvEH2jNEOJ9lszzZFBDbuwsjXHK35+ +lPbGEy69xCP26iEafysKKbRXJhE1C+tk8SnK+Gm62sivmK/5av4CAwKcF1Qep+Pf +ssOqtJhr+klruUBf55onBJi4vkk0gK3m32p/05YB2bbMURGz8R4JxUZfUxjdDk73 +LaNYRbQpQWxwaGEgVGVzdCAoZGVtbyBrZXkpIDxhbHBoYUBleGFtcGxlLm5ldD6I +VQQTEQIAFQUCNuOOngMLCgMDFQMCAxYCAQIXgAAKCRAtcnzHaGl3NDl4AJ4rouHB ++LpCkNi5C59jHEa1kbANzACgmddtrNSj1yPyTCwUwRghPUomECS0EEFsaWNlIChk +ZW1vIGtleSmIVQQTEQIAFQUCNuO2qwMLCgMDFQMCAxYCAQIXgAAKCRAtcnzHaGl3 +NCeMAJ9MeUVrago5Jc6PdwdeN5OMwby37QCghW65cZTQlD1bBlIq/QM8bz9AN4G0 +J0FsZmEgVGVzdCAoZGVtbyBrZXkpIDxhbGZhQGV4YW1wbGUubmV0PohVBBMRAgAV +BQI247hYAwsKAwMVAwIDFgIBAheAAAoJEC1yfMdoaXc0t8IAoJPwa6j+Vm5Vi3Nv +uo8JZri4PJ/DAJ9dqbmaJdB8FdJnHfGh1rXK3y/Jcp0BuAQ2448PEAQAnI3XH1f0 +uyN9fZnw72zsHMw706g7EW29nD4UDQG4OzRZViSrUa5n39eI7QrfTO+1meVvs0y8 +F/PvFst5jH68rPLnGSrXz4sTl1T4cop1FBkquvCAKwPLy0lE7jjtCyItOSwIOo8x +oTfY4JEEXmcqsbm+KHv9yYSF/YK4Cf7bIzcAAwcD/Rnl5jKxoucDA96pD2829TKs +LFQSau+Xiy8bvOSSDdlyABsOkNBSaeKO3eAQEKgDM7dzjVNTnAlpQ0EQ8Y9Z8pxO +WYEQYlaMrnRBC4DZ2IadzEhLlIOz5BVp/jfhrr8oVVBwKZXsrz9PZLz+e4Yn+siU +Uvlei9boD9L2ZgSOHakP/gIDApwXVB6n49+yw6e5k2VJBGTFDkQbxpgi4oslePpT +7Tc2qjAke4zO8JHkgKSokEgnMpMz412q9otFX/3qC5MpPG5P8f4r00Kfy9Am/thk +ri01WTIUqF8L/VZXJxLKVoRAabSXudG0eavfah14fN5/+Bw5i8vSHhc/xmQEKTya +2X8Nt1F5zMrE1LAGVVCL9i/DUygnJYOZzAd1Ct0RJ4kFj7lOBICF2IWWiEYEGBEC +AAYFAjbjjw8ACgkQLXJ8x2hpdzQgqQCgn81AaW8W/lyVwMh/UBeMuVMUb24An2uz +wg7Md81a5RI3F2FG8747t9gX +=VM1e +-----END PGP PRIVATE KEY BLOCK----- +' + +# Bug 1179 solved 2010-05-12: +# It occured for messages of a multiple of the iobuf block size where +# the last line had no pad character. Due to premature poppng of thea +# rmor filter gpg swalled the CRC line and passed the '-----END...' +# line on to the decryption layer. + +i=alpha_seckey +info "importing: $i" +eval "(IFS=; echo \"\$$i\")" >x +$GPG --import x || true + +i=nopad_armored_msg +info "checking: $i" +eval "(IFS=; echo \"\$$i\")" >x +if $GPG -o - x > /dev/null ; then + : +else + error "bug#1179 is back in town" +fi + Modified: trunk/tools/Makefile.am =================================================================== --- trunk/tools/Makefile.am 2010-06-01 12:42:39 UTC (rev 5345) +++ trunk/tools/Makefile.am 2010-06-07 13:33:02 UTC (rev 5346) @@ -42,13 +42,19 @@ symcryptrun = endif +if BUILD_GPGTAR + gpgtar = gpgtar +else + gpgtar = +endif + # Fixme: We should remove the gpgkey2ssh tool. bin_PROGRAMS = gpgconf gpg-connect-agent ${symcryptrun} if !HAVE_W32_SYSTEM bin_PROGRAMS += watchgnupg gpgparsemail endif if !HAVE_W32CE_SYSTEM -bin_PROGRAMS += gpgkey2ssh +bin_PROGRAMS += gpgkey2ssh ${gpgtar} endif if !DISABLE_REGEX @@ -60,6 +66,7 @@ endif common_libs = $(libcommon) ../gl/libgnu.a +commonpth_libs = $(libcommonpth) ../gl/libgnu.a if HAVE_W32CE_SYSTEM pwquery_libs = else @@ -114,15 +121,16 @@ $(LIBINTL) $(LIBICONV) $(W32SOCKLIBS) endif -#gpgtar_SOURCES = \ -# gpgtar.c gpgtar.h \ -# gpgtar-create.c \ -# gpgtar-extract.c \ -# gpgtar-list.c \ -# no-libgcrypt.c -#gpgtar_LDADD = $(common_libs) -# +gpgtar_SOURCES = \ + gpgtar.c gpgtar.h \ + gpgtar-create.c \ + gpgtar-extract.c \ + gpgtar-list.c \ + no-libgcrypt.c +gpgtar_CFLAGS = $(GPG_ERROR_CFLAGS) $(PTH_CFLAGS) +gpgtar_LDADD = $(commonpth_libs) $(PTH_LIBS) $(GPG_ERROR_LIBS) + # Make sure that all libs are build before we use them. This is # important for things like make -j2. $(PROGRAMS): $(common_libs) $(pwquery_libs) ../common/libgpgrl.a Added: trunk/tools/gpgtar-create.c =================================================================== --- trunk/tools/gpgtar-create.c (rev 0) +++ trunk/tools/gpgtar-create.c 2010-06-07 13:33:02 UTC (rev 5346) @@ -0,0 +1,643 @@ +/* gpgtar-create.c - Create a TAR archive + * Copyright (C) 2010 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 3 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, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +/* #ifdef HAVE_W32_SYSTEM */ +/* # define WIN32_LEAN_AND_MEAN */ +/* # include */ +/* #else /\*!HAVE_W32_SYSTEM*\/ */ +# include +# include +# include +/* #endif /\*!HAVE_W32_SYSTEM*\/ */ +#include + +#include "i18n.h" +#include "../common/sysutils.h" +#include "gpgtar.h" + +#ifndef HAVE_LSTAT +#define lstat(a,b) stat ((a), (b)) +#endif + + +/* Object to control the file scanning. */ +struct scanctrl_s; +typedef struct scanctrl_s *scanctrl_t; +struct scanctrl_s +{ + tar_header_t flist; + tar_header_t *flist_tail; + int nestlevel; +}; + + + + +/* Given a fresh header object HDR with only the name field set, try + to gather all available info. */ +static gpg_error_t +fillup_entry (tar_header_t hdr) +{ + gpg_error_t err; + struct stat sbuf; + + if (lstat (hdr->name, &sbuf)) + { + err = gpg_error_from_syserror (); + log_error ("error stat-ing `%s': %s\n", hdr->name, gpg_strerror (err)); + return err; + } + + if (S_ISREG (sbuf.st_mode)) + hdr->typeflag = TF_REGULAR; + else if (S_ISDIR (sbuf.st_mode)) + hdr->typeflag = TF_DIRECTORY; + else if (S_ISCHR (sbuf.st_mode)) + hdr->typeflag = TF_CHARDEV; + else if (S_ISBLK (sbuf.st_mode)) + hdr->typeflag = TF_BLOCKDEV; + else if (S_ISFIFO (sbuf.st_mode)) + hdr->typeflag = TF_FIFO; + else if (S_ISLNK (sbuf.st_mode)) + hdr->typeflag = TF_SYMLINK; + else + hdr->typeflag = TF_NOTSUP; + + /* FIXME: Save DEV and INO? */ + + /* Set the USTAR defined mode bits using the system macros. */ + if (sbuf.st_mode & S_IRUSR) + hdr->mode |= 0400; + if (sbuf.st_mode & S_IWUSR) + hdr->mode |= 0200; + if (sbuf.st_mode & S_IXUSR) + hdr->mode |= 0100; + if (sbuf.st_mode & S_IRGRP) + hdr->mode |= 0040; + if (sbuf.st_mode & S_IWGRP) + hdr->mode |= 0020; + if (sbuf.st_mode & S_IXGRP) + hdr->mode |= 0010; + if (sbuf.st_mode & S_IROTH) + hdr->mode |= 0004; + if (sbuf.st_mode & S_IWOTH) + hdr->mode |= 0002; + if (sbuf.st_mode & S_IXOTH) + hdr->mode |= 0001; +#ifdef S_IXUID + if (sbuf.st_mode & S_IXUID) + hdr->mode |= 04000; +#endif +#ifdef S_IXGID + if (sbuf.st_mode & S_IXGID) + hdr->mode |= 02000; +#endif +#ifdef S_ISVTX + if (sbuf.st_mode & S_ISVTX) + hdr->mode |= 01000; +#endif + + hdr->nlink = sbuf.st_nlink; + + hdr->uid = sbuf.st_uid; + hdr->gid = sbuf.st_gid; + + /* Only set the size for a regular file. */ + if (hdr->typeflag == TF_REGULAR) + hdr->size = sbuf.st_size; + + hdr->mtime = sbuf.st_mtime; + + + return 0; +} + + + +static gpg_error_t +add_entry (const char *dname, size_t dnamelen, struct dirent *de, + scanctrl_t scanctrl) +{ + gpg_error_t err; + tar_header_t hdr; + char *p; + + assert (dnamelen); + + hdr = xtrycalloc (1, sizeof *hdr + dnamelen + 1 + + (de? strlen (de->d_name) : 0)); + if (!hdr) + { + err = gpg_error_from_syserror (); + log_error (_("error reading directory `%s': %s\n"), + dname, gpg_strerror (err)); + return err; + } + + p = stpcpy (hdr->name, dname); + if (de) + { + if (dname[dnamelen-1] != '/') + *p++ = '/'; + strcpy (p, de->d_name); + } + else + { + if (hdr->name[dnamelen-1] == '/') + hdr->name[dnamelen-1] = 0; + } +#ifdef HAVE_DOSISH_SYSTEM + for (p=hdr->name; *p; p++) + if (*p == '\\') + *p = '/'; +#endif + err = fillup_entry (hdr); + if (err) + xfree (hdr); + else + { + if (opt.verbose) + gpgtar_print_header (hdr, log_get_stream ()); + *scanctrl->flist_tail = hdr; + scanctrl->flist_tail = &hdr->next; + } + + return 0; +} + + +static gpg_error_t +scan_directory (const char *dname, scanctrl_t scanctrl) +{ + gpg_error_t err = 0; + size_t dnamelen; + DIR *dir; + struct dirent *de; + + dnamelen = strlen (dname); + if (!dnamelen) + return 0; /* An empty directory name has no entries. */ + + dir = opendir (dname); + if (!dir) + { + err = gpg_error_from_syserror (); + log_error (_("error reading directory `%s': %s\n"), + dname, gpg_strerror (err)); + return err; + } + + while ((de = readdir (dir))) + { + if (!strcmp (de->d_name, "." ) || !strcmp (de->d_name, "..")) + continue; /* Skip self and parent dir entry. */ + + err = add_entry (dname, dnamelen, de, scanctrl); + if (err) + goto leave; + } + + leave: + closedir (dir); + return err; +} + + +static gpg_error_t +scan_recursive (const char *dname, scanctrl_t scanctrl) +{ + gpg_error_t err = 0; + tar_header_t hdr, *start_tail, *stop_tail; + + if (scanctrl->nestlevel > 200) + { + log_error ("directories too deeply nested\n"); + return gpg_error (GPG_ERR_RESOURCE_LIMIT); + } + scanctrl->nestlevel++; + + assert (scanctrl->flist_tail); + start_tail = scanctrl->flist_tail; + scan_directory (dname, scanctrl); + stop_tail = scanctrl->flist_tail; + hdr = *start_tail; + for (; hdr && hdr != *stop_tail; hdr = hdr->next) + if (hdr->typeflag == TF_DIRECTORY) + { + if (opt.verbose > 1) + log_info ("scanning directory `%s'\n", hdr->name); + scan_recursive (hdr->name, scanctrl); + } + + scanctrl->nestlevel--; + return err; +} + + +/* Returns true if PATTERN is acceptable. */ +static int +pattern_valid_p (const char *pattern) +{ + if (!*pattern) + return 0; + if (*pattern == '.' && pattern[1] == '.') + return 0; + if (*pattern == '/' || *pattern == DIRSEP_C) + return 0; /* Absolute filenames are not supported. */ +#ifdef HAVE_DRIVE_LETTERS + if (((*pattern >= 'a' && *pattern <= 'z') + || (*pattern >= 'A' && *pattern <= 'Z')) + && pattern[1] == ':') + return 0; /* Drive letter are not allowed either. */ +#endif /*HAVE_DRIVE_LETTERS*/ + + return 1; /* Okay. */ +} + + + +static void +store_xoctal (char *buffer, size_t length, unsigned long long value) +{ + char *p, *pend; + size_t n; + unsigned long long v; + + assert (length > 1); + + v = value; + n = length; + p = pend = buffer + length; + *--p = 0; /* Nul byte. */ + n--; + do + { + *--p = '0' + (v % 8); + v /= 8; + n--; + } + while (v && n); + if (!v) + { + /* Pad. */ + for ( ; n; n--) + *--p = '0'; + } + else /* Does not fit into the field. Store as binary number. */ + { + v = value; + n = length; + p = pend = buffer + length; + do + { + *--p = v; + v /= 256; + n--; + } + while (v && n); + if (!v) + { + /* Pad. */ + for ( ; n; n--) + *--p = 0; + if (*p & 0x80) + BUG (); + *p |= 0x80; /* Set binary flag. */ + } + else + BUG (); + } +} + + +static void +store_uname (char *buffer, size_t length, unsigned long uid) +{ + static int initialized; + static unsigned long lastuid; + static char lastuname[32]; + + if (!initialized || uid != lastuid) + { + struct passwd *pw = getpwuid (uid); + + lastuid = uid; + initialized = 1; + if (pw) + mem2str (lastuname, pw->pw_name, sizeof lastuname); + else + { + log_info ("failed to get name for uid %lu\n", uid); From cvs at cvs.gnupg.org Mon Jun 7 17:11:35 2010 From: cvs at cvs.gnupg.org (svn author wk) Date: Mon, 07 Jun 2010 17:11:35 +0200 Subject: [svn] GnuPG - r5347 - in trunk: common tests/openpgp Message-ID: Author: wk Date: 2010-06-07 17:11:35 +0200 (Mon, 07 Jun 2010) New Revision: 5347 Modified: trunk/common/ChangeLog trunk/common/sysutils.c trunk/tests/openpgp/ChangeLog trunk/tests/openpgp/Makefile.am trunk/tests/openpgp/decrypt.test trunk/tests/openpgp/defs.inc trunk/tests/openpgp/genkey1024.test trunk/tests/openpgp/gpg-agent.conf.tmpl Log: Change OpenPGP test framework to run under the control of the agent. Modified: trunk/common/ChangeLog =================================================================== --- trunk/common/ChangeLog 2010-06-07 13:33:02 UTC (rev 5346) +++ trunk/common/ChangeLog 2010-06-07 15:11:35 UTC (rev 5347) @@ -1,5 +1,7 @@ 2010-06-07 Werner Koch + * sysutils.c [W32CE]: Finish pipe creation. + * estream.c (es_fname_get, es_fname_set): New. (fname_set_internal): New. (struct estream_internal): Add fields printable_fname and Modified: trunk/tests/openpgp/ChangeLog =================================================================== --- trunk/tests/openpgp/ChangeLog 2010-06-07 13:33:02 UTC (rev 5346) +++ trunk/tests/openpgp/ChangeLog 2010-06-07 15:11:35 UTC (rev 5347) @@ -1,3 +1,12 @@ +2010-06-07 Werner Koch + + * Makefile.am (TESTS_ENVIRONMENT): New. Start all scripts under + the control of the gpg-agent. + (prepared.stamp): Create gpg-agent.conf. + * defs.inc: Do not create gpg-agent.conf + (GNUPGHOME): Check that it is set properly. + (GPG_AGENT_INFO): Do not change. + 2010-05-12 Werner Koch * armor.test (Version): Add test for bug#1179. Modified: trunk/common/sysutils.c =================================================================== --- trunk/common/sysutils.c 2010-06-07 13:33:02 UTC (rev 5346) +++ trunk/common/sysutils.c 2010-06-07 15:11:35 UTC (rev 5347) @@ -299,11 +299,16 @@ } /* This is the same as translate_sys2libc_fd but takes an integer - which is assumed to be such an system handle. */ + which is assumed to be such an system handle. On WindowsCE the + passed FD is a rendezvous ID and the function finishes the pipe + creation. */ int translate_sys2libc_fd_int (int fd, int for_write) { -#ifdef HAVE_W32_SYSTEM +#if HAVE_W32CE_SYSTEM + fd = _assuan_w32ce_finish_pipe fd, for_write); + return translate_sys2libc_fd ((void*)fd, for_write); +#elif HAVE_W32_SYSTEM if (fd <= 2) return fd; /* Do not do this for error, stdin, stdout, stderr. */ Modified: trunk/tests/openpgp/Makefile.am =================================================================== --- trunk/tests/openpgp/Makefile.am 2010-06-07 13:33:02 UTC (rev 5346) +++ trunk/tests/openpgp/Makefile.am 2010-06-07 15:11:35 UTC (rev 5347) @@ -23,6 +23,9 @@ required_pgms = ../../g10/gpg2 ../../agent/gpg-agent \ ../../tools/gpg-connect-agent +TESTS_ENVIRONMENT = GNUPGHOME=$(abs_builddir) GPG_AGENT_INFO= LC_ALL=C \ + ../../agent/gpg-agent --quiet --daemon sh + TESTS = version.test mds.test \ decrypt.test decrypt-dsa.test \ sigs.test sigs-dsa.test \ @@ -49,8 +52,6 @@ EXTRA_DIST = defs.inc $(TESTS) $(TEST_FILES) \ mkdemodirs signdemokey -# Note that removing S.gpg-agent forces a running gpg-agent to -# terminate after some time. CLEANFILES = prepared.stamp x y yy z out err $(DATA_FILES) \ plain-1 plain-2 plain-3 trustdb.gpg *.lock .\#lk* \ *.test.log gpg_dearmor gpg.conf gpg-agent.conf S.gpg-agent \ @@ -67,6 +68,7 @@ prepared.stamp: ./pubring.gpg ./secring.gpg ./plain-1 ./plain-2 ./plain-3 \ ./pubring.pkr ./secring.skr ./gpg_dearmor $(DATA_FILES) $(GPG_IMPORT) $(srcdir)/pubdemo.asc + cat $(srcdir)/gpg-agent.conf.tmpl > gpg-agent.conf echo timestamp >./prepared.stamp # We need to depend on a couple of programs so that the tests don't Modified: trunk/tests/openpgp/decrypt.test =================================================================== --- trunk/tests/openpgp/decrypt.test 2010-06-07 13:33:02 UTC (rev 5346) +++ trunk/tests/openpgp/decrypt.test 2010-06-07 15:11:35 UTC (rev 5347) @@ -12,7 +12,7 @@ #info Checking decryption of supplied files for i in $plain_files ; do - echo "$usrpass1" | $GPG --passphrase-fd 0 -o y --yes $srcdir/$i.asc + echo "$usrpass1" | $GPG --passphrase-fd 0 -o y --yes $srcdir/$i.asc cmp $i y || error "$i: mismatch" done Modified: trunk/tests/openpgp/defs.inc =================================================================== --- trunk/tests/openpgp/defs.inc 2010-06-07 13:33:02 UTC (rev 5346) +++ trunk/tests/openpgp/defs.inc 2010-06-07 15:11:35 UTC (rev 5347) @@ -162,7 +162,7 @@ [ -z "$srcdir" ] && fatal "not called from make" # Make sure we have a valid option files even with VPATH builds. -for f in gpg.conf gpg-agent.conf; do +for f in gpg.conf ; do if [ -f ./$f ]; then : elif [ -f $srcdir/$f.tmpl ]; then @@ -170,19 +170,23 @@ fi done -# Always work in the current directory -GNUPGHOME=`pwd` -export GNUPGHOME +# Always work in the current directory. We set GNUPGHOME only if it +# has not been set already. Usually it is set through the Makefile's +# TESTS_ENVIRONMENT macro. +if [ -z "$GNUPGHOME" ]; then + GNUPGHOME=`pwd` + export GNUPGHOME +elif [ "$GNUPGHOME" != `pwd` ]; then + echo "$pgmname: GNUPGHOME not set to the cwd" $* >&2 + exit 1 +fi -# We do not use an external info variable for gpg-agent because we use -# a standard socket in the home directory. This way gpg-agent will be -# started as soon as needed. It is terminated indirectly using a -# Makefile rule. -GPG_AGENT_INFO= - GPG="../../g10/gpg2 --no-permission-warning " -exec 5>&2 2>${pgmname}.log +echo "Test: $pgmname" > ${pgmname}.log +echo "GNUPGHOME=$GNUPGHOME" >> ${pgmname}.log +echo "GPG_AGENT_INFO=$GPG_AGENT_INFO" >> ${pgmname}.log +exec 5>&2 2>>${pgmname}.log : # end Modified: trunk/tests/openpgp/genkey1024.test =================================================================== --- trunk/tests/openpgp/genkey1024.test 2010-06-07 13:33:02 UTC (rev 5346) +++ trunk/tests/openpgp/genkey1024.test 2010-06-07 15:11:35 UTC (rev 5347) @@ -10,6 +10,9 @@ . $srcdir/defs.inc || exit 3 +# FIXME: Skip this test for now +exit 77 + $GPG --quiet --batch --debug-quick-random --gen-key < Author: marcus Date: 2010-06-07 17:14:52 +0200 (Mon, 07 Jun 2010) New Revision: 374 Modified: trunk/src/ChangeLog trunk/src/gpgcedev.c Log: 2010-06-07 Marcus Brinkmann * gpgcedev.c: This rewrite does away with troublesome race conditions (close vs everything else, for example) by simplifying the locking model. It also handles EOF, EPIPE, but still assumes that there is always only ever one reader and writer. Also, no need to treat ERROR_PIPE_NOT_CONNECTED and ERROR_BUSY as EAGAIN anymore. (struct pipeimpl_s, pipeimpl_t): New types. (PIPE_FLAG_NO_READER, PIPE_FLAG, NO_WRITER): New macros. (struct opnctx_s): Remove everything that's now in struct pipeimpl_s. Remove also assoc and locked. Add pipeimpl field. (pipeimpl_new, pipeimpl_unref, allocate_opnctx, verify_opnctx, access_opnctx): New functions. (get_new_opnctx, find_and_lock_opnctx, validate_and_lock_opnctx, unlock_opnctx): Removed. (GPG_Init, GPG_Deinit): Improve debugging output. (GPG_Open): Improve debugging output, use allocate_opnctx instead of get_new_opnctx. (GPG_Close): Improve debugging output. Rewrite to use reference counting. Also check if reader or writer is closed and set flags for triggering EOF or EPIPE. (GPG_Read): Improve debugging output. Rewrite using pipeimpl. Check for EOF. (GPG_Write): Improve debugging output. Rewrite using pipeimpl. Check for EPIPE. (make_pipe): Rewrite using pipeimpl. (GPG_IOControl): Improve debugging output. Modified: trunk/src/ChangeLog =================================================================== --- trunk/src/ChangeLog 2010-04-22 15:51:01 UTC (rev 373) +++ trunk/src/ChangeLog 2010-06-07 15:14:52 UTC (rev 374) @@ -1,3 +1,32 @@ +2010-06-07 Marcus Brinkmann + + * gpgcedev.c: This rewrite does away with troublesome race + conditions (close vs everything else, for example) by simplifying + the locking model. It also handles EOF, EPIPE, but still assumes + that there is always only ever one reader and writer. Also, no + need to treat ERROR_PIPE_NOT_CONNECTED and ERROR_BUSY as EAGAIN + anymore. + (struct pipeimpl_s, pipeimpl_t): New types. + (PIPE_FLAG_NO_READER, PIPE_FLAG, NO_WRITER): New macros. + (struct opnctx_s): Remove everything that's now in struct + pipeimpl_s. Remove also assoc and locked. Add pipeimpl field. + (pipeimpl_new, pipeimpl_unref, allocate_opnctx, verify_opnctx, + access_opnctx): New functions. + (get_new_opnctx, find_and_lock_opnctx, validate_and_lock_opnctx, + unlock_opnctx): Removed. + (GPG_Init, GPG_Deinit): Improve debugging output. + (GPG_Open): Improve debugging output, use allocate_opnctx instead + of get_new_opnctx. + (GPG_Close): Improve debugging output. Rewrite to use reference + counting. Also check if reader or writer is closed and set flags + for triggering EOF or EPIPE. + (GPG_Read): Improve debugging output. Rewrite using pipeimpl. + Check for EOF. + (GPG_Write): Improve debugging output. Rewrite using pipeimpl. + Check for EPIPE. + (make_pipe): Rewrite using pipeimpl. + (GPG_IOControl): Improve debugging output. + 2010-04-22 Werner Koch * assuan-listen.c (assuan_accept): Show the PID with the default Modified: trunk/src/gpgcedev.c =================================================================== --- trunk/src/gpgcedev.c 2010-04-22 15:51:01 UTC (rev 373) +++ trunk/src/gpgcedev.c 2010-06-07 15:14:52 UTC (rev 374) @@ -54,34 +54,38 @@ #define GPGCEDEV_IOCTL_MAKE_PIPE \ CTL_CODE (FILE_DEVICE_STREAMS, 2049, METHOD_BUFFERED, FILE_ANY_ACCESS) +struct pipeimpl_s +{ + CRITICAL_SECTION critsect; /* Lock for all members. */ + int refcnt; + char *buffer; + size_t buffer_size; + size_t buffer_len; /* The valid length of the bufer. */ + size_t buffer_pos; /* The actual read position. */ + +#define PIPE_FLAG_NO_READER 1 +#define PIPE_FLAG_NO_WRITER 2 + int flags; + + HANDLE space_available; /* Set if space is available. */ + HANDLE data_available; /* Set if data is available. */ +}; +typedef struct pipeimpl_s *pipeimpl_t; + + /* An object to store information pertaining to an open-context. */ struct opnctx_s; typedef struct opnctx_s *opnctx_t; struct opnctx_s { int inuse; /* True if this object has valid data. */ - opnctx_t assoc; /* This context has been associated with this - other context; i.e. a pipe has been - established. */ - int is_write; /* True if this is the write end of the pipe. */ LONG rvid; /* The unique rendezvous identifier. */ DWORD access_code;/* Value from OpenFile. */ DWORD share_mode; /* Value from OpenFile. */ - CRITICAL_SECTION critsect; /* Lock for all operations. */ - int locked; /* True if we are in a critical section. */ - /* The malloced buffer and its size. We use a buffer for each - handle which allows us eventually implement a system to - distribute data to several handles. Not sure whether this is - really needed but as a side effect it makes the code easier. */ - char *buffer; - size_t buffer_size; - size_t buffer_len; /* The valid length of the bufer. */ - size_t buffer_pos; /* The actual read or write position. */ - - HANDLE space_available; /* Set if space is available. */ - HANDLE data_available; /* Set if data is available. */ + /* The state shared by all users. */ + pipeimpl_t pipeimpl; }; /* A malloced table of open-context and the number of allocated slots. */ @@ -136,18 +140,78 @@ +pipeimpl_t +pipeimpl_new (void) +{ + pipeimpl_t pimpl; + + pimpl = malloc (sizeof (*pimpl)); + if (!pimpl) + return NULL; + + InitializeCriticalSection (&pimpl->critsect); + pimpl->refcnt = 1; + pimpl->buffer_size = 512; + pimpl->buffer = malloc (pimpl->buffer_size); + pimpl->buffer_len = 0; + pimpl->buffer_pos = 0; + pimpl->flags = 0; + pimpl->space_available = CreateEvent (NULL, FALSE, FALSE, NULL); + pimpl->data_available = CreateEvent (NULL, FALSE, FALSE, NULL); + + return pimpl; +} + + +/* PIMPL must be locked. It is unlocked at exit. */ +void +pipeimpl_unref (pipeimpl_t pimpl) +{ + int release = 0; + + log_debug ("pipeimpl_unref (%p): dereference\n", pimpl); + + if (--pimpl->refcnt == 0) + release = 1; + LeaveCriticalSection (&pimpl->critsect); + + if (! release) + return; + + log_debug ("pipeimpl_unref (%p): release\n", pimpl); + + DeleteCriticalSection (&pimpl->critsect); + if (pimpl->buffer) + { + free (pimpl->buffer); + pimpl->buffer = NULL; + pimpl->buffer_size = 0; + } + if (pimpl->space_available != INVALID_HANDLE_VALUE) + { + CloseHandle (pimpl->space_available); + pimpl->space_available = INVALID_HANDLE_VALUE; + } + if (pimpl->data_available != INVALID_HANDLE_VALUE) + { + CloseHandle (pimpl->data_available); + pimpl->data_available = INVALID_HANDLE_VALUE; + } +} + + + /* Return a new opnctx handle and mark it as used. Returns NULL and - sets LastError on memory failure etc. On success the context is - locked. */ + sets LastError on memory failure etc. opnctx_table_cs must be + locked on entry and is locked on exit. */ static opnctx_t -get_new_opnctx (void) +allocate_opnctx (void) { opnctx_t opnctx = NULL; int idx; - EnterCriticalSection (&opnctx_table_cs); - for (idx=0; idx < opnctx_table_size; idx++) - if (!opnctx_table[idx].inuse) + for (idx = 0; idx < opnctx_table_size; idx++) + if (! opnctx_table[idx].inuse) break; if (idx == opnctx_table_size) { @@ -159,129 +223,91 @@ newtbl = calloc (newsize, sizeof *newtbl); if (!newtbl) goto leave; - for (idx=0; idx < opnctx_table_size; idx++) - newtbl[idx] = opnctx_table[idx]; + memcpy (newtbl, opnctx_table, opnctx_table_size * sizeof (*newtbl)); free (opnctx_table); opnctx_table = newtbl; idx = opnctx_table_size; opnctx_table_size = newsize; } - opnctx = opnctx_table + idx; - opnctx->assoc = NULL; - opnctx->rvid = create_rendezvous_id (); - opnctx->is_write = 0; + opnctx = &opnctx_table[idx]; + opnctx->inuse = 1; + opnctx->rvid = 0; opnctx->access_code = 0; opnctx->share_mode = 0; - InitializeCriticalSection (&opnctx->critsect); - opnctx->locked = 0; - opnctx->buffer_size = 512; - opnctx->buffer = malloc (opnctx->buffer_size); - if (!opnctx->buffer) - { - opnctx = NULL; - goto leave; - } - opnctx->buffer_len = 0; - opnctx->buffer_pos = 0; - opnctx->data_available = INVALID_HANDLE_VALUE; - opnctx->space_available = INVALID_HANDLE_VALUE; + opnctx->pipeimpl = 0; - opnctx->inuse = 1; - EnterCriticalSection (&opnctx->critsect); - opnctx->locked = 1; - leave: - LeaveCriticalSection (&opnctx_table_cs); - if (opnctx) - log_debug ("get_new_opnctx -> %p (rvid=%ld)\n", opnctx, opnctx->rvid); - else - log_debug ("get_new_opnctx -> failed\n"); return opnctx; } -/* Find the OPNCTX object with the rendezvous id RVID. */ -static opnctx_t -find_and_lock_opnctx (LONG rvid) +/* Verify context CTX, returns NULL if not valid and the pointer to + the context if valid. opnctx_table_cs must be locked on entry and + is locked on exit. */ +opnctx_t +verify_opnctx (opnctx_t ctx) { - opnctx_t result = NULL; - int idx; - - EnterCriticalSection (&opnctx_table_cs); - for (idx=0; idx < opnctx_table_size; idx++) - if (opnctx_table[idx].inuse && opnctx_table[idx].rvid == rvid) - { - result = opnctx_table + idx; - break; - } - LeaveCriticalSection (&opnctx_table_cs); - if (!result) + int idx = ctx - opnctx_table; + if (idx < 0 || idx >= opnctx_table_size) { SetLastError (ERROR_INVALID_HANDLE); - log_debug ("find_opnctx -> invalid rendezvous id\n"); + return NULL; } - else if (TryEnterCriticalSection (&result->critsect)) + if (! opnctx_table[idx].inuse) { - result->locked++; - log_debug ("find_opnctx -> %p (rvid=%ld)\n", result, result->rvid); + SetLastError (ERROR_INVALID_HANDLE); + return NULL; } - else - { - SetLastError (ERROR_BUSY); - result = NULL; - log_debug ("find_opnctx -> busy\n"); - } - return result; + return &opnctx_table[idx]; } -/* Check that OPNCTX is valid. Returns TRUE if it is valid or FALSE - if it is a bad or closed contect. In the latter case SetLastError - is called. In the former case a lock is taken and unlock_opnctx - needs to be called. If WAIT is false the fucntion only tries to - acquire a lock. */ -static BOOL -validate_and_lock_opnctx (opnctx_t opnctx, int wait) +/* Verify access CODE for context CTX, returning a reference to the + locked pipe implementation. opnctx_table_cs must be locked on + entry and is locked on exit. */ +pipeimpl_t +access_opnctx (opnctx_t ctx, DWORD code) { - BOOL result = FALSE; int idx; EnterCriticalSection (&opnctx_table_cs); - for (idx=0; idx < opnctx_table_size; idx++) - if (opnctx_table[idx].inuse && (opnctx_table + idx) == opnctx) - { - result = TRUE; - break; - } - LeaveCriticalSection (&opnctx_table_cs); + idx = ctx - opnctx_table; + if (idx < 0 || idx >= opnctx_table_size || ! opnctx_table[idx].inuse) + { + SetLastError (ERROR_INVALID_HANDLE); + LeaveCriticalSection (&opnctx_table_cs); + return NULL; + } + ctx = &opnctx_table[idx]; - if (!result) - SetLastError (ERROR_INVALID_HANDLE); - else if (wait) + if (!(ctx->access_code & code)) { - EnterCriticalSection (&opnctx->critsect); - opnctx->locked++; + SetLastError (ERROR_INVALID_ACCESS); + LeaveCriticalSection (&opnctx_table_cs); + return NULL; } - else if (TryEnterCriticalSection (&opnctx->critsect)) - opnctx->locked++; - else + + if (! ctx->pipeimpl) { - SetLastError (ERROR_BUSY); - result = FALSE; + ctx->pipeimpl = pipeimpl_new (); + if (! ctx->pipeimpl) + { + log_debug (" access_opnctx (ctx=0x%p): error: can't create pipe\n", + ctx); + LeaveCriticalSection (&opnctx_table_cs); + return NULL; + } + log_debug (" access_opnctx (ctx=0x%p): created pipe 0x%p\n", + ctx, ctx->pipeimpl); } - return result; + + EnterCriticalSection (&ctx->pipeimpl->critsect); + ctx->pipeimpl->refcnt++; + LeaveCriticalSection (&opnctx_table_cs); + return ctx->pipeimpl; } -static void -unlock_opnctx (opnctx_t opnctx) -{ - opnctx->locked--; - LeaveCriticalSection (&opnctx->critsect); -} - - - static char * wchar_to_utf8 (const wchar_t *string) @@ -314,7 +340,7 @@ (void)bus_context; tmpbuf = wchar_to_utf8 (active_key); - log_debug ("GPG_Init (%s)\n", tmpbuf); + log_debug ("GPG_Init (devctx=0x%p, %s)\n", DEVCTX_VALUE, tmpbuf); free (tmpbuf); /* We don't need any global data. However, we need to return @@ -328,7 +354,7 @@ BOOL GPG_Deinit (DWORD devctx) { - log_debug ("GPG_Deinit (%p)\n", (void*)devctx); + log_debug ("GPG_Deinit (devctx=0x%p)\n", (void*)devctx); if (devctx != DEVCTX_VALUE) { SetLastError (ERROR_INVALID_PARAMETER); @@ -349,20 +375,32 @@ { opnctx_t opnctx; - log_debug ("GPG_Open(devctx=%p)\n", (void*)devctx); + log_debug ("GPG_Open (devctx=%p)\n", (void*)devctx); if (devctx != DEVCTX_VALUE) { + log_debug ("GPG_Open (devctx=%p): error: devctx mismatch (expected 0x%p)\n", + (void*) devctx); SetLastError (ERROR_INVALID_PARAMETER); return 0; /* Error. */ } - opnctx = get_new_opnctx (); + EnterCriticalSection (&opnctx_table_cs); + opnctx = allocate_opnctx (); if (!opnctx) - return 0; + { + log_debug ("GPG_Open (devctx=%p): error: could not allocate context\n", + (void*) devctx); + goto leave; + } + opnctx->access_code = access_code; opnctx->share_mode = share_mode; - unlock_opnctx (opnctx); + log_debug ("GPG_Open (devctx=%p): success: created context 0x%p\n", + (void*) devctx, opnctx); + + leave: + LeaveCriticalSection (&opnctx_table_cs); return (DWORD)opnctx; } @@ -373,50 +411,45 @@ { opnctx_t opnctx = (opnctx_t)opnctx_arg; BOOL result = FALSE; - int idx; - log_debug ("GPG_Close(%p)\n", (void*)opnctx); + log_debug ("GPG_Close (ctx=0x%p)\n", (void*)opnctx); EnterCriticalSection (&opnctx_table_cs); - for (idx=0; idx < opnctx_table_size; idx++) - if (opnctx_table[idx].inuse && (opnctx_table + idx) == opnctx) - { - if (opnctx->assoc) - { - opnctx->assoc->assoc = NULL; - opnctx->assoc = NULL; - } - if (opnctx->locked) - { - /* FIXME: Check earlier or use close only in locked state - or use PReClose. */ - log_debug ("GPG_Close while still locked\n"); - } - DeleteCriticalSection (&opnctx->critsect); - if (opnctx->buffer) - { - free (opnctx->buffer); - opnctx->buffer = NULL; - opnctx->buffer_size = 0; - } - if (opnctx->space_available != INVALID_HANDLE_VALUE) - { - CloseHandle (opnctx->space_available); - opnctx->space_available = INVALID_HANDLE_VALUE; - } - if (opnctx->data_available != INVALID_HANDLE_VALUE) - { - CloseHandle (opnctx->data_available); - opnctx->data_available = INVALID_HANDLE_VALUE; - } - opnctx->inuse = 0; - result = TRUE; - break; - } + opnctx = verify_opnctx (opnctx); + if (!opnctx) + { + log_debug ("GPG_Close (ctx=0x%p): could not find context\n", (void*)opnctx); + goto leave; + } + + if (opnctx->pipeimpl) + { + pipeimpl_t pimpl = opnctx->pipeimpl; + EnterCriticalSection (&pimpl->critsect); + /* This needs to be adjusted if there can be multiple + reader/writers. */ + if (opnctx->access_code & GENERIC_READ) + { + pimpl->flags |= PIPE_FLAG_NO_READER; + SetEvent (pimpl->space_available); + } + else if (opnctx->access_code & GENERIC_WRITE) + { + pimpl->flags |= PIPE_FLAG_NO_WRITER; + SetEvent (pimpl->data_available); + } + pipeimpl_unref (pimpl); + opnctx->pipeimpl = 0; + } + opnctx->access_code = 0; + opnctx->share_mode = 0; + opnctx->rvid = 0; + opnctx->inuse = 0; + result = TRUE; + log_debug ("GPG_Close (ctx=0x%p): success\n", (void*)opnctx); + + leave: LeaveCriticalSection (&opnctx_table_cs); - - if (!result) - SetLastError (ERROR_INVALID_HANDLE); return result; } @@ -425,72 +458,67 @@ DWORD GPG_Read (DWORD opnctx_arg, void *buffer, DWORD count) { - opnctx_t rctx = (opnctx_t)opnctx_arg; - opnctx_t wctx; - int result = -1; + opnctx_t ctx = (opnctx_t)opnctx_arg; + pipeimpl_t pimpl; const char *src; char *dst; + int result = -1; - log_debug ("GPG_Read(%p, count=%d)\n", (void*)rctx, count); + log_debug ("GPG_Read (ctx=0x%p, buffer=0x%p, count=%d)\n", + (void*)ctx, buffer, count); - /* We use the write end's buffer, thus there is no need to wait for - our (read end) lock. */ - if (!validate_and_lock_opnctx (rctx, LOCK_TRY)) - return -1; /* Error. */ - - if (rctx->is_write) + pimpl = access_opnctx (ctx, GENERIC_READ); + if (!pimpl) { - SetLastError (ERROR_INVALID_ACCESS); - log_debug ("GPG_Read(%p) -> invalid access\n", (void*)rctx); - goto leave; + log_debug ("GPG_Read (ctx=0x%p): error: could not access context\n", + (void*)ctx); + return -1; } - if (!rctx->assoc) - { - SetLastError (ERROR_PIPE_NOT_CONNECTED); - goto leave; - } - /* Read from the corresponding write buffer. */ retry: - wctx = rctx->assoc; - if (!validate_and_lock_opnctx (wctx, LOCK_WAIT)) - goto leave; + if (pimpl->buffer_pos == pimpl->buffer_len) + { + HANDLE data_available = pimpl->data_available; - if (wctx->buffer_pos == wctx->buffer_len) - { - unlock_opnctx (wctx); - log_debug ("%s:%d: WFSO(data_available)\n", __func__, __LINE__); - WaitForSingleObject (wctx->data_available, INFINITE); - log_debug ("%s:%d: WFSO ... woke up\n", __func__, __LINE__); + /* Check for end of file. */ + if (pimpl->flags & PIPE_FLAG_NO_WRITER) + { + log_debug ("GPG_Read (ctx=0x%p): success: EOF\n", (void*)ctx); + result = 0; + goto leave; + } + + LeaveCriticalSection (&pimpl->critsect); + log_debug ("GPG_Read (ctx=0x%p): waiting: data_available\n", (void*)ctx); + WaitForSingleObject (data_available, INFINITE); + log_debug ("GPG_Read (ctx=0x%p): resuming: data_available\n", (void*)ctx); + EnterCriticalSection (&pimpl->critsect); goto retry; } dst = buffer; - src = wctx->buffer + wctx->buffer_pos; - while (count > 0 && wctx->buffer_pos < wctx->buffer_len) + src = pimpl->buffer + pimpl->buffer_pos; + while (count > 0 && pimpl->buffer_pos < pimpl->buffer_len) { *dst++ = *src++; count--; - wctx->buffer_pos++; + pimpl->buffer_pos++; } result = (dst - (char*)buffer); - if (wctx->buffer_pos == wctx->buffer_len) - wctx->buffer_pos = wctx->buffer_len = 0; + if (pimpl->buffer_pos == pimpl->buffer_len) + pimpl->buffer_pos = pimpl->buffer_len = 0; /* Now there should be some space available. Signal the write end. Even if COUNT was passed as NULL and no space is available, signaling must be done. */ - if (!SetEvent (wctx->space_available)) - { - log_debug ("%s:%d: SetEvent(space_available) failed: rc=%d\n", - __func__, __LINE__, (int)GetLastError ()); - unlock_opnctx (wctx); - goto leave; - } - unlock_opnctx (wctx); + if (!SetEvent (pimpl->space_available)) + log_debug ("GPG_Read (ctx=0x%p): warning: SetEvent(space_available) failed: rc=%d\n", + (void*) ctx, (int)GetLastError ()); + log_debug ("GPG_Read (ctx=0x%p): success: result=%d\n", (void*)ctx, result); + leave: - unlock_opnctx (rctx); + pipeimpl_unref (pimpl); return result; } @@ -499,64 +527,72 @@ DWORD GPG_Write (DWORD opnctx_arg, const void *buffer, DWORD count) { - opnctx_t wctx = (opnctx_t)opnctx_arg; + opnctx_t ctx = (opnctx_t)opnctx_arg; + pipeimpl_t pimpl; int result = -1; const char *src; char *dst; size_t nwritten = 0; - log_debug ("GPG_Write(%p, count=%d)\n", (void*)wctx, count); - retry: - if (!validate_and_lock_opnctx (wctx, LOCK_WAIT)) - return -1; /* Error. */ + log_debug ("GPG_Write (ctx=0x%p, buffer=0x%p, count=%d)\n", (void*)ctx, + buffer, count); - if (!wctx->is_write) + pimpl = access_opnctx (ctx, GENERIC_WRITE); + if (!pimpl) { - SetLastError (ERROR_INVALID_ACCESS); - log_debug ("GPG_Write(%p) -> invalid access\n", (void*)wctx); - goto leave; + log_debug ("GPG_Write (ctx=0x%p): error: could not access context\n", + (void*)ctx); + return -1; } - if (!wctx->assoc) + + if (!count) { - SetLastError (ERROR_PIPE_NOT_CONNECTED); + log_debug ("GPG_Write (ctx=0x%p): success\n", (void*)ctx); + result = 0; goto leave; } - if (!count) + + retry: + /* Check for broken pipe. */ + if (pimpl->flags & PIPE_FLAG_NO_READER) { - result = 0; + log_debug ("GPG_Write (ctx=0x%p): error: broken pipe\n", (void*)ctx); + SetLastError (ERROR_BROKEN_PIPE); goto leave; } /* Write to our buffer. */ - if (wctx->buffer_len == wctx->buffer_size) + if (pimpl->buffer_len == pimpl->buffer_size) { /* Buffer is full. */ - unlock_opnctx (wctx); - log_debug ("%s:%d: WFSO(space_available)\n", __func__, __LINE__); - WaitForSingleObject (wctx->space_available, INFINITE); - log_debug ("%s:%d: WFSO ... woke up\n", __func__, __LINE__); + HANDLE space_available = pimpl->space_available; + LeaveCriticalSection (&pimpl->critsect); + log_debug ("GPG_Write (ctx=0x%p): waiting: space_available\n", (void*)ctx); + WaitForSingleObject (space_available, INFINITE); + log_debug ("GPG_Write (ctx=0x%p): resuming: space_available\n", (void*)ctx); + EnterCriticalSection (&pimpl->critsect); goto retry; } src = buffer; - dst = wctx->buffer + wctx->buffer_len; - while (count > 0 && wctx->buffer_len < wctx->buffer_size) + dst = pimpl->buffer + pimpl->buffer_len; + while (count > 0 && pimpl->buffer_len < pimpl->buffer_size) { *dst++ = *src++; count--; - wctx->buffer_len++; + pimpl->buffer_len++; nwritten++; } - if (!SetEvent (wctx->data_available)) - { - log_debug ("%s:%d: SetEvent(data_available) failed: rc=%d\n", - __func__, __LINE__, (int)GetLastError ()); - goto leave; - } result = nwritten; + if (!SetEvent (pimpl->data_available)) + log_debug ("GPG_Write (ctx=0x%p): warning: SetEvent(data_available) failed: rc=%d\n", + (void*) ctx, (int)GetLastError ()); + + log_debug ("GPG_Write (ctx=0x%p): success: result=%d\n", (void*)ctx, result); + leave: - unlock_opnctx (wctx); + pipeimpl_unref (pimpl); return result; } @@ -571,35 +607,41 @@ +/* opnctx_table_s is locked on entering and on exit. */ static BOOL make_pipe (opnctx_t ctx, LONG rvid) { - BOOL result = FALSE; opnctx_t peerctx = NULL; + int idx; - log_debug (" make_pipe(%p, rvid=%ld)\n", ctx, rvid); - if (ctx->assoc) + log_debug (" make_pipe (ctx=0x%p, rvid=%08lx)\n", ctx, rvid); + + if (ctx->pipeimpl) { + log_debug (" make_pipe (ctx=0x%p): error: already assigned\n", ctx); SetLastError (ERROR_ALREADY_ASSIGNED); - goto leave; + return FALSE; } - peerctx = find_and_lock_opnctx (rvid); - if (!peerctx) + for (idx = 0; idx < opnctx_table_size; idx++) + if (opnctx_table[idx].inuse && opnctx_table[idx].rvid == rvid) + { + peerctx = &opnctx_table[idx]; + break; + } + if (! peerctx) { + log_debug (" make_pipe (ctx=0x%p): error: not found\n", ctx); SetLastError (ERROR_NOT_FOUND); - goto leave; + return FALSE; } + if (peerctx == ctx) { + log_debug (" make_pipe (ctx=0x%p): error: target and source identical\n", ctx); SetLastError (ERROR_INVALID_TARGET_HANDLE); - goto leave; + return FALSE; } - if (peerctx->assoc) - { - SetLastError (ERROR_ALREADY_ASSIGNED); - goto leave; - } if ((ctx->access_code & GENERIC_READ)) { @@ -607,17 +649,9 @@ if (!(peerctx->access_code & GENERIC_WRITE)) { SetLastError (ERROR_INVALID_ACCESS); - log_debug (" make_pipe(%p) write end -> invalid access\n", ctx); - goto leave; + log_debug (" make_pipe (ctx=0x%p): error: peer is not writer\n", ctx); + return FALSE; } - peerctx->space_available = CreateEvent (NULL, FALSE, FALSE, NULL); - peerctx->data_available = CreateEvent (NULL, FALSE, FALSE, NULL); - - ctx->assoc = peerctx; - peerctx->assoc = ctx; - ctx->is_write = 0; - peerctx->is_write = 1; - result = TRUE; } else if ((ctx->access_code & GENERIC_WRITE)) { @@ -625,29 +659,39 @@ if (!(peerctx->access_code & GENERIC_READ)) { SetLastError (ERROR_INVALID_ACCESS); - log_debug (" make_pipe(%p) read_end -> invalid access\n", ctx); - goto leave; + log_debug (" make_pipe (ctx=0x%p): error: peer is not reader\n", ctx); + return FALSE; } - ctx->space_available = CreateEvent (NULL, FALSE, FALSE, NULL); - ctx->data_available = CreateEvent (NULL, FALSE, FALSE, NULL); - - ctx->assoc = peerctx; - peerctx->assoc = ctx; - ctx->is_write = 1; - peerctx->is_write = 0; - result = TRUE; } else { SetLastError (ERROR_INVALID_ACCESS); - log_debug (" make_pipe(%p) no_access -> invalid access\n", ctx); - goto leave; + log_debug (" make_pipe (ctx=0x%p): error: invalid access\n", ctx); + return FALSE; } - leave: - if (peerctx) - unlock_opnctx (peerctx); - return result; + /* Make sure the peer has a pipe implementation to be shared. If + not yet, create one. */ + if (! peerctx->pipeimpl) + { + peerctx->pipeimpl = pipeimpl_new (); + if (! peerctx->pipeimpl) + { + log_debug (" make_pipe (ctx=0x%p): error: can't create pipe\n", + ctx); + return FALSE; + } + log_debug (" make_pipe (ctx=0x%p): created pipe 0x%p\n", + ctx, peerctx->pipeimpl); + } + EnterCriticalSection (&peerctx->pipeimpl->critsect); + peerctx->pipeimpl->refcnt++; + ctx->pipeimpl = peerctx->pipeimpl; + LeaveCriticalSection (&peerctx->pipeimpl->critsect); + log_debug (" make_pipe (ctx=0x%p): success: combined with peer ctx=0x%p (pipe 0x%p)\n", + ctx, peerctx, peerctx->pipeimpl); + + return TRUE; } @@ -659,19 +703,34 @@ BOOL result = FALSE; LONG rvid; - log_debug ("GPG_IOControl(%p, %d)\n", (void*)opnctx, code); - if (!validate_and_lock_opnctx (opnctx, LOCK_TRY)) - return FALSE; + log_debug ("GPG_IOControl (ctx=0x%p, %08x)\n", (void*)opnctx, code); + EnterCriticalSection (&opnctx_table_cs); + opnctx = verify_opnctx (opnctx); + if (!opnctx) + { + log_debug ("GPG_IOControl (ctx=0x%p): error: could not access context\n", + (void*)opnctx); + goto leave; + } + switch (code) { case GPGCEDEV_IOCTL_GET_RVID: - if (!opnctx || inbuf || inbuflen - || !outbuf || outbuflen < sizeof (LONG)) + log_debug ("GPG_IOControl (ctx=0x%p): code: GET_RVID\n", (void*)opnctx); + if (inbuf || inbuflen || !outbuf || outbuflen < sizeof (LONG)) { + log_debug ("GPG_IOControl (ctx=0x%p): error: invalid parameter\n", + (void*)opnctx); SetLastError (ERROR_INVALID_PARAMETER); goto leave; } + + if (! opnctx->rvid) + opnctx->rvid = create_rendezvous_id (); + log_debug ("GPG_IOControl (ctx=0x%p): returning rvid: %08lx\n", + (void*)opnctx, opnctx->rvid); + memcpy (outbuf, &opnctx->rvid, sizeof (LONG)); if (actualoutlen) *actualoutlen = sizeof (LONG); @@ -679,28 +738,38 @@ break; case GPGCEDEV_IOCTL_MAKE_PIPE: - if (!opnctx || !inbuf || inbuflen < sizeof (LONG) - || outbuf || outbuflen || actualoutlen ) + log_debug ("GPG_IOControl (ctx=0x%p): code: MAKE_PIPE\n", (void*)opnctx); + if (!inbuf || inbuflen < sizeof (LONG) + || outbuf || outbuflen || actualoutlen) { + log_debug ("GPG_IOControl (ctx=0x%p): error: invalid parameter\n", + (void*)opnctx); SetLastError (ERROR_INVALID_PARAMETER); goto leave; } memcpy (&rvid, inbuf, sizeof (LONG)); + log_debug ("GPG_IOControl (ctx=0x%p): requesting to finish pipe for rvid: %08lx\n", + (void*)opnctx, rvid); if (make_pipe (opnctx, rvid)) result = TRUE; break; case IOCTL_PSL_NOTIFY: + log_debug ("GPG_IOControl (ctx=0x%p): code: NOTIFY\n", (void*)opnctx); /* Unexpected process termination. */ break; default: + log_debug ("GPG_IOControl (ctx=0x%p): code: (unknown)\n", (void*)opnctx); SetLastError (ERROR_INVALID_PARAMETER); break; } + log_debug ("GPG_IOControl (ctx=0x%p): success: result=%d\n", (void*)opnctx, + result); + leave: - unlock_opnctx (opnctx); + LeaveCriticalSection (&opnctx_table_cs); return result; } From cvs at cvs.gnupg.org Mon Jun 7 19:04:50 2010 From: cvs at cvs.gnupg.org (svn author wk) Date: Mon, 07 Jun 2010 19:04:50 +0200 Subject: [svn] GnuPG - r5348 - trunk/g10 Message-ID: Author: wk Date: 2010-06-07 19:04:50 +0200 (Mon, 07 Jun 2010) New Revision: 5348 Modified: trunk/g10/ChangeLog trunk/g10/cpr.c Log: use estream for status output. Modified: trunk/g10/ChangeLog =================================================================== --- trunk/g10/ChangeLog 2010-06-07 15:11:35 UTC (rev 5347) +++ trunk/g10/ChangeLog 2010-06-07 17:04:50 UTC (rev 5348) @@ -1,3 +1,7 @@ +2010-06-07 Werner Koch + + * cpr.c: Use estream for status output. + 2010-05-12 Werner Koch * armor.c (radix64_read): Extended 2006-04-28 fix to fix bug#1179. Modified: trunk/g10/cpr.c =================================================================== --- trunk/g10/cpr.c 2010-06-07 15:11:35 UTC (rev 5347) +++ trunk/g10/cpr.c 2010-06-07 17:04:50 UTC (rev 5348) @@ -40,10 +40,11 @@ #define CONTROL_D ('D' - 'A' + 1) +/* The stream to output the status information. Output is disabled if + this is NULL. */ +static estream_t statusfp; -static FILE *statusfp; - static void progress_cb (void *ctx, const char *what, int printchar, int current, int total) @@ -94,68 +95,74 @@ void -set_status_fd ( int fd ) +set_status_fd (int fd) { - static int last_fd = -1; + static int last_fd = -1; + + if (fd != -1 && last_fd == fd) + return; - if ( fd != -1 && last_fd == fd ) - return; - - if ( statusfp && statusfp != stdout && statusfp != stderr ) - fclose (statusfp); - statusfp = NULL; - if ( fd == -1 ) - return; - - if( fd == 1 ) - statusfp = stdout; - else if( fd == 2 ) - statusfp = stderr; - else - statusfp = fdopen( fd, "w" ); - if( !statusfp ) { - log_fatal("can't open fd %d for status output: %s\n", - fd, strerror(errno)); + if (statusfp && statusfp != es_stdout && statusfp != es_stderr ) + es_fclose (statusfp); + statusfp = NULL; + if (fd == -1) + return; + + if (fd == 1) + statusfp = es_stdout; + else if (fd == 2) + statusfp = es_stderr; + else + statusfp = es_fdopen (fd, "w"); + if (!statusfp) + { + log_fatal ("can't open fd %d for status output: %s\n", + fd, strerror (errno)); } - last_fd = fd; + last_fd = fd; - gcry_set_progress_handler ( progress_cb, NULL ); + gcry_set_progress_handler (progress_cb, NULL); } + int -is_status_enabled() +is_status_enabled () { - return !!statusfp; + return !!statusfp; } + void write_status ( int no ) { write_status_text( no, NULL ); } + void -write_status_text ( int no, const char *text) +write_status_text (int no, const char *text) { - if( !statusfp || !status_currently_allowed (no) ) - return; /* Not enabled or allowed. */ + if (!statusfp || !status_currently_allowed (no) ) + return; /* Not enabled or allowed. */ - fputs ( "[GNUPG:] ", statusfp ); - fputs ( get_status_string (no), statusfp ); - if( text ) { - putc ( ' ', statusfp ); - for (; *text; text++) { - if (*text == '\n') - fputs ( "\\n", statusfp ); - else if (*text == '\r') - fputs ( "\\r", statusfp ); - else - putc ( *(const byte *)text, statusfp ); + es_fputs ("[GNUPG:] ", statusfp); + es_fputs (get_status_string (no), statusfp); + if ( text ) + { + es_putc ( ' ', statusfp); + for (; *text; text++) + { + if (*text == '\n') + es_fputs ("\\n", statusfp); + else if (*text == '\r') + es_fputs ("\\r", statusfp); + else + es_fputc ( *(const byte *)text, statusfp); } } - putc ('\n',statusfp); - if ( fflush (statusfp) && opt.exit_on_status_write_error ) - g10_exit (0); + es_putc ('\n', statusfp); + if (es_fflush (statusfp) && opt.exit_on_status_write_error) + g10_exit (0); } @@ -166,23 +173,23 @@ if (!statusfp || !status_currently_allowed (STATUS_ERROR)) return; /* Not enabled or allowed. */ - fprintf (statusfp, "[GNUPG:] %s %s %u\n", - get_status_string (STATUS_ERROR), where, err); - if (fflush (statusfp) && opt.exit_on_status_write_error) + es_fprintf (statusfp, "[GNUPG:] %s %s %u\n", + get_status_string (STATUS_ERROR), where, err); + if (es_fflush (statusfp) && opt.exit_on_status_write_error) g10_exit (0); } -/* Same as above but only putputs the error code. */ +/* Same as above but outputs the error code only. */ void write_status_errcode (const char *where, int errcode) { if (!statusfp || !status_currently_allowed (STATUS_ERROR)) return; /* Not enabled or allowed. */ - fprintf (statusfp, "[GNUPG:] %s %s %u\n", - get_status_string (STATUS_ERROR), where, gpg_err_code (errcode)); - if (fflush (statusfp) && opt.exit_on_status_write_error) + es_fprintf (statusfp, "[GNUPG:] %s %s %u\n", + get_status_string (STATUS_ERROR), where, gpg_err_code (errcode)); + if (es_fflush (statusfp) && opt.exit_on_status_write_error) g10_exit (0); } @@ -194,73 +201,83 @@ * A wrap of -1 forces spaces not to be encoded as %20. */ void -write_status_text_and_buffer ( int no, const char *string, - const char *buffer, size_t len, int wrap ) +write_status_text_and_buffer (int no, const char *string, + const char *buffer, size_t len, int wrap) { - const char *s, *text; - int esc, first; - int lower_limit = ' '; - size_t n, count, dowrap; + const char *s, *text; + int esc, first; + int lower_limit = ' '; + size_t n, count, dowrap; - if( !statusfp || !status_currently_allowed (no) ) - return; /* Not enabled or allowed. */ + if (!statusfp || !status_currently_allowed (no)) + return; /* Not enabled or allowed. */ - if (wrap == -1) { - lower_limit--; - wrap = 0; + if (wrap == -1) + { + lower_limit--; + wrap = 0; } - text = get_status_string (no); - count = dowrap = first = 1; - do { - if (dowrap) { - fprintf (statusfp, "[GNUPG:] %s ", text ); - count = dowrap = 0; - if (first && string) { - fputs (string, statusfp); - count += strlen (string); - /* Make sure that there is space after the string. */ - if (*string && string[strlen (string)-1] != ' ') - { - putc (' ', statusfp); - count++; - } + text = get_status_string (no); + count = dowrap = first = 1; + do + { + if (dowrap) + { + es_fprintf (statusfp, "[GNUPG:] %s ", text); + count = dowrap = 0; + if (first && string) + { + es_fputs (string, statusfp); + count += strlen (string); + /* Make sure that there is a space after the string. */ + if (*string && string[strlen (string)-1] != ' ') + { + es_putc (' ', statusfp); + count++; + } } - first = 0; + first = 0; } - for (esc=0, s=buffer, n=len; n && !esc; s++, n-- ) { - if ( *s == '%' || *(const byte*)s <= lower_limit - || *(const byte*)s == 127 ) - esc = 1; - if ( wrap && ++count > wrap ) { - dowrap=1; - break; + for (esc=0, s=buffer, n=len; n && !esc; s++, n--) + { + if (*s == '%' || *(const byte*)s <= lower_limit + || *(const byte*)s == 127 ) + esc = 1; + if (wrap && ++count > wrap) + { + dowrap=1; + break; } } - if (esc) { - s--; n++; + if (esc) + { + s--; n++; } - if (s != buffer) - fwrite (buffer, s-buffer, 1, statusfp ); - if ( esc ) { - fprintf (statusfp, "%%%02X", *(const byte*)s ); - s++; n--; + if (s != buffer) + es_fwrite (buffer, s-buffer, 1, statusfp); + if ( esc ) + { + es_fprintf (statusfp, "%%%02X", *(const byte*)s ); + s++; n--; } - buffer = s; - len = n; - if ( dowrap && len ) - putc ( '\n', statusfp ); - } while ( len ); + buffer = s; + len = n; + if (dowrap && len) + es_putc ('\n', statusfp); + } + while (len); - putc ('\n',statusfp); - if ( fflush (statusfp) && opt.exit_on_status_write_error ) - g10_exit (0); + es_putc ('\n',statusfp); + if (es_fflush (statusfp) && opt.exit_on_status_write_error) + g10_exit (0); } + void -write_status_buffer ( int no, const char *buffer, size_t len, int wrap ) +write_status_buffer (int no, const char *buffer, size_t len, int wrap) { - write_status_text_and_buffer (no, NULL, buffer, len, wrap); + write_status_text_and_buffer (no, NULL, buffer, len, wrap); } @@ -285,13 +302,13 @@ buflen = 0; for (i=1; i <= 11; i++) if (i < 4 || i > 7) - if ( gcry_md_is_enabled (md, i) && buflen < DIM(buf) ) + if (gcry_md_is_enabled (md, i) && buflen < DIM(buf)) { snprintf (buf+buflen, DIM(buf) - buflen - 1, "%sH%d", buflen? " ":"",i); buflen += strlen (buf+buflen); } - write_status_text ( STATUS_BEGIN_SIGNING, buf ); + write_status_text (STATUS_BEGIN_SIGNING, buf); } else write_status ( STATUS_BEGIN_SIGNING ); @@ -301,28 +318,34 @@ static int myread(int fd, void *buf, size_t count) { - int rc; - do { - rc = read( fd, buf, count ); - } while ( rc == -1 && errno == EINTR ); - if ( !rc && count ) { - static int eof_emmited=0; - if ( eof_emmited < 3 ) { - *(char*)buf = CONTROL_D; - rc = 1; - eof_emmited++; + int rc; + do + { + rc = read( fd, buf, count ); + } + while (rc == -1 && errno == EINTR); + + if (!rc && count) + { + static int eof_emmited=0; + if ( eof_emmited < 3 ) + { + *(char*)buf = CONTROL_D; + rc = 1; + eof_emmited++; } - else { /* Ctrl-D not caught - do something reasonable */ + else /* Ctrl-D not caught - do something reasonable */ + { #ifdef HAVE_DOSISH_SYSTEM #ifndef HAVE_W32CE_SYSTEM - raise (SIGINT); /* nothing to hangup under DOS */ + raise (SIGINT); /* Nothing to hangup under DOS. */ #endif #else - raise (SIGHUP); /* no more input data */ + raise (SIGHUP); /* No more input data. */ #endif } } - return rc; + return rc; } @@ -336,8 +359,8 @@ int i, len; char *string; - if (statusfp != stdout) - fflush (stdout); + if (statusfp != es_stdout) + es_fflush (es_stdout); write_status_text (getbool? STATUS_GET_BOOL : hidden? STATUS_GET_HIDDEN : STATUS_GET_LINE, keyword); From cvs at cvs.gnupg.org Tue Jun 8 17:40:50 2010 From: cvs at cvs.gnupg.org (svn author wk) Date: Tue, 08 Jun 2010 17:40:50 +0200 Subject: [svn] pinentry - r234 - in trunk: . qt qt4 Message-ID: Author: wk Date: 2010-06-08 17:40:49 +0200 (Tue, 08 Jun 2010) New Revision: 234 Modified: trunk/ChangeLog trunk/qt/pinentrydialog.cpp trunk/qt4/pinentrydialog.cpp Log: Add StaysOnTopHint. Modified: trunk/ChangeLog =================================================================== --- trunk/ChangeLog 2010-05-12 17:13:29 UTC (rev 233) +++ trunk/ChangeLog 2010-06-08 15:40:49 UTC (rev 234) @@ -1,3 +1,9 @@ +2010-06-08 Marc Mutz (wk) + + * qt4/pinentrydialog.cpp (PinEntryDialog): Add WindowStaysOnTopHint. + + * qt/pinentrydialog.cpp (PinEntryDialog): Add WStyle_StaysOnTop. + 2010-05-12 Guido G?nther (wk) * gtk+-2/gtksecentry.c: Make -DSEAL safe. Modified: trunk/qt/pinentrydialog.cpp =================================================================== --- trunk/qt/pinentrydialog.cpp 2010-05-12 17:13:29 UTC (rev 233) +++ trunk/qt/pinentrydialog.cpp 2010-06-08 15:40:49 UTC (rev 234) @@ -33,7 +33,7 @@ PinEntryDialog::PinEntryDialog( QWidget* parent, const char* name, bool modal, bool enable_quality_bar ) - : QDialog( parent, name, modal ), _grabbed( false ) + : QDialog( parent, name, modal, Qt::WStyle_StaysOnTop ), _grabbed( false ) { QBoxLayout* top = new QVBoxLayout( this, 6 ); QBoxLayout* upperLayout = new QHBoxLayout( top ); Modified: trunk/qt4/pinentrydialog.cpp =================================================================== --- trunk/qt4/pinentrydialog.cpp 2010-05-12 17:13:29 UTC (rev 233) +++ trunk/qt4/pinentrydialog.cpp 2010-06-08 15:40:49 UTC (rev 234) @@ -83,7 +83,7 @@ PinEntryDialog::PinEntryDialog( QWidget* parent, const char* name, bool modal, bool enable_quality_bar ) - : QDialog( parent ), _grabbed( false ) + : QDialog( parent, Qt::WindowStaysOnTopHint ), _grabbed( false ) { setWindowFlags( windowFlags() & ~Qt::WindowContextHelpButtonHint ); From cvs at cvs.gnupg.org Tue Jun 8 18:59:20 2010 From: cvs at cvs.gnupg.org (svn author wk) Date: Tue, 08 Jun 2010 18:59:20 +0200 Subject: [svn] GnuPG - r5349 - trunk/common Message-ID: Author: wk Date: 2010-06-08 18:59:19 +0200 (Tue, 08 Jun 2010) New Revision: 5349 Modified: trunk/common/ChangeLog trunk/common/gettime.c trunk/common/iobuf.c trunk/common/sexputil.c Log: W32CE fix. Typo fixes Modified: trunk/common/ChangeLog =================================================================== --- trunk/common/ChangeLog 2010-06-07 17:04:50 UTC (rev 5348) +++ trunk/common/ChangeLog 2010-06-08 16:59:19 UTC (rev 5349) @@ -1,3 +1,7 @@ +2010-06-08 Werner Koch + + * iobuf.c (translate_file_handle) [W32CE]: Handle rendezvous ids. + 2010-06-07 Werner Koch * sysutils.c [W32CE]: Finish pipe creation. Modified: trunk/common/gettime.c =================================================================== --- trunk/common/gettime.c 2010-06-07 17:04:50 UTC (rev 5348) +++ trunk/common/gettime.c 2010-06-08 16:59:19 UTC (rev 5349) @@ -497,6 +497,7 @@ } +/* Dump the ISO time T to the log stream without a LF. */ void dump_isotime (const gnupg_isotime_t t) { Modified: trunk/common/iobuf.c =================================================================== --- trunk/common/iobuf.c 2010-06-07 17:04:50 UTC (rev 5348) +++ trunk/common/iobuf.c 2010-06-08 16:59:19 UTC (rev 5349) @@ -2366,7 +2366,12 @@ static int translate_file_handle (int fd, int for_write) { -#if defined(HAVE_W32_SYSTEM) && !defined (HAVE_W32CE_SYSTEM) +#if defined (HAVE_W32CE_SYSTEM) + /* This is called only with one of the special filenames. Under + W32CE the FD here is not a file descriptor but a rendezvous id, + thus we need to finish the pipe first. */ + fd = _assuan_w32ce_finish_pipe fd, for_write); +#elif defined(HAVE_W32_SYSTEM) { int x; Modified: trunk/common/sexputil.c =================================================================== --- trunk/common/sexputil.c 2010-06-07 17:04:50 UTC (rev 5348) +++ trunk/common/sexputil.c 2010-06-08 16:59:19 UTC (rev 5349) @@ -99,7 +99,7 @@ /* Compare two simple S-expressions like "(3:foo)". Returns 0 if they - are identical or !0 if they are not. Not that this function can't + are identical or !0 if they are not. Note that this function can't be used for sorting. */ int cmp_simple_canon_sexp (const unsigned char *a_orig, From cvs at cvs.gnupg.org Tue Jun 8 20:33:22 2010 From: cvs at cvs.gnupg.org (svn author marcus) Date: Tue, 08 Jun 2010 20:33:22 +0200 Subject: [svn] GnuPG - r5350 - trunk/common Message-ID: Author: marcus Date: 2010-06-08 20:33:21 +0200 (Tue, 08 Jun 2010) New Revision: 5350 Modified: trunk/common/ChangeLog trunk/common/Makefile.am trunk/common/iobuf.c trunk/common/sysutils.c Log: 2010-06-08 Marcus Brinkmann * Makefile.am (AM_CFLAGS): Add $(LIBASSUAN_CFLAGS). (t_common_ldadd): Add $(LIBASSUAN_LIBS). * sysutils.c: Include . (translate_sys2libc_fd_int): Cast to silence gcc warning. * iobuf.c: Include (translate_file_handle): Fix syntax error. Modified: trunk/common/ChangeLog =================================================================== --- trunk/common/ChangeLog 2010-06-08 16:59:19 UTC (rev 5349) +++ trunk/common/ChangeLog 2010-06-08 18:33:21 UTC (rev 5350) @@ -1,3 +1,12 @@ +2010-06-08 Marcus Brinkmann + + * Makefile.am (AM_CFLAGS): Add $(LIBASSUAN_CFLAGS). + (t_common_ldadd): Add $(LIBASSUAN_LIBS). + * sysutils.c: Include . + (translate_sys2libc_fd_int): Cast to silence gcc warning. + * iobuf.c: Include + (translate_file_handle): Fix syntax error. + 2010-06-08 Werner Koch * iobuf.c (translate_file_handle) [W32CE]: Handle rendezvous ids. Modified: trunk/common/Makefile.am =================================================================== --- trunk/common/Makefile.am 2010-06-08 16:59:19 UTC (rev 5349) +++ trunk/common/Makefile.am 2010-06-08 18:33:21 UTC (rev 5350) @@ -34,7 +34,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/gl -I$(top_srcdir)/intl -AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(KSBA_CFLAGS) +AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(LIBASSUAN_CFLAGS) $(KSBA_CFLAGS) include $(top_srcdir)/am/cmacros.am @@ -168,7 +168,7 @@ t_common_ldadd = libcommon.a ../gl/libgnu.a \ - $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) $(LIBINTL) $(LIBICONV) + $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) $(LIBINTL) $(LIBICONV) # jnlib tests t_stringhelp_SOURCES = t-stringhelp.c $(t_jnlib_src) Modified: trunk/common/iobuf.c =================================================================== --- trunk/common/iobuf.c 2010-06-08 16:59:19 UTC (rev 5349) +++ trunk/common/iobuf.c 2010-06-08 18:33:21 UTC (rev 5350) @@ -37,6 +37,8 @@ # include #endif /* __riscos__ */ +#include + #include "util.h" #include "sysutils.h" #include "iobuf.h" @@ -2366,11 +2368,11 @@ static int translate_file_handle (int fd, int for_write) { -#if defined (HAVE_W32CE_SYSTEM) +#if defined(HAVE_W32CE_SYSTEM) /* This is called only with one of the special filenames. Under W32CE the FD here is not a file descriptor but a rendezvous id, thus we need to finish the pipe first. */ - fd = _assuan_w32ce_finish_pipe fd, for_write); + fd = _assuan_w32ce_finish_pipe (fd, for_write); #elif defined(HAVE_W32_SYSTEM) { int x; Modified: trunk/common/sysutils.c =================================================================== --- trunk/common/sysutils.c 2010-06-08 16:59:19 UTC (rev 5349) +++ trunk/common/sysutils.c 2010-06-08 18:33:21 UTC (rev 5350) @@ -51,6 +51,8 @@ #endif #include +#include + #include "setenv.h" /* Gnulib replacement. */ #include "util.h" @@ -306,7 +308,7 @@ translate_sys2libc_fd_int (int fd, int for_write) { #if HAVE_W32CE_SYSTEM - fd = _assuan_w32ce_finish_pipe fd, for_write); + fd = (int) _assuan_w32ce_finish_pipe (fd, for_write); return translate_sys2libc_fd ((void*)fd, for_write); #elif HAVE_W32_SYSTEM if (fd <= 2) From cvs at cvs.gnupg.org Wed Jun 9 15:12:32 2010 From: cvs at cvs.gnupg.org (svn author marcus) Date: Wed, 09 Jun 2010 15:12:32 +0200 Subject: [svn] assuan - r375 - trunk/src Message-ID: Author: marcus Date: 2010-06-09 15:12:31 +0200 (Wed, 09 Jun 2010) New Revision: 375 Modified: trunk/src/ChangeLog trunk/src/gpgcedev.c Log: 2010-06-09 Marcus Brinkmann * gpgcedev.c (GPGCEDEV_IOCTL_UNBLOCK): New ioctl. (PIPE_FLAG_UNBLOCK_READER, PIPE_FLAG_UNBLOCK_WRITER): New flags. (GPG_Read): Check if PIPE_FLAG_UNBLOCK_READER is set and return ERROR_BUSY in that case. (GPG_Write): Likewise for PIPE_FLAG_UNBLOCK_WRITER. (unblock_call): New function. (GPG_IOControl): Implement GPGCEDEV_IOCTL_UNBLOCK. Modified: trunk/src/ChangeLog =================================================================== --- trunk/src/ChangeLog 2010-06-07 15:14:52 UTC (rev 374) +++ trunk/src/ChangeLog 2010-06-09 13:12:31 UTC (rev 375) @@ -1,3 +1,13 @@ +2010-06-09 Marcus Brinkmann + + * gpgcedev.c (GPGCEDEV_IOCTL_UNBLOCK): New ioctl. + (PIPE_FLAG_UNBLOCK_READER, PIPE_FLAG_UNBLOCK_WRITER): New flags. + (GPG_Read): Check if PIPE_FLAG_UNBLOCK_READER is set and return + ERROR_BUSY in that case. + (GPG_Write): Likewise for PIPE_FLAG_UNBLOCK_WRITER. + (unblock_call): New function. + (GPG_IOControl): Implement GPGCEDEV_IOCTL_UNBLOCK. + 2010-06-07 Marcus Brinkmann * gpgcedev.c: This rewrite does away with troublesome race Modified: trunk/src/gpgcedev.c =================================================================== --- trunk/src/gpgcedev.c 2010-06-07 15:14:52 UTC (rev 374) +++ trunk/src/gpgcedev.c 2010-06-09 13:12:31 UTC (rev 375) @@ -54,6 +54,17 @@ #define GPGCEDEV_IOCTL_MAKE_PIPE \ CTL_CODE (FILE_DEVICE_STREAMS, 2049, METHOD_BUFFERED, FILE_ANY_ACCESS) +/* The IOCTL used to unblock a blocking thread. + + The caller sends this IOCTL to the read or the write handle. No + parameter is required. The effect is that a reader or writer + blocked on the same handle is unblocked (and will return + ERROR_BUSY). Note that the operation can be repeated, if so + desired. The state of the pipe itself will not be affected in any + way. */ +#define GPGCEDEV_IOCTL_UNBLOCK \ + CTL_CODE (FILE_DEVICE_STREAMS, 2050, METHOD_BUFFERED, FILE_ANY_ACCESS) + struct pipeimpl_s { CRITICAL_SECTION critsect; /* Lock for all members. */ @@ -66,6 +77,8 @@ #define PIPE_FLAG_NO_READER 1 #define PIPE_FLAG_NO_WRITER 2 +#define PIPE_FLAG_UNBLOCK_READER 4 +#define PIPE_FLAG_UNBLOCK_WRITER 8 int flags; HANDLE space_available; /* Set if space is available. */ @@ -488,6 +501,16 @@ goto leave; } + /* Check for request to unblock once. */ + if (pimpl->flags & PIPE_FLAG_UNBLOCK_READER) + { + log_debug ("GPG_Read (ctx=0x%p): success: EBUSY (due to unblock request)\n", (void*)ctx); + pimpl->flags &= ~PIPE_FLAG_UNBLOCK_READER; + SetLastError (ERROR_BUSY); + result = -1; + goto leave; + } + LeaveCriticalSection (&pimpl->critsect); log_debug ("GPG_Read (ctx=0x%p): waiting: data_available\n", (void*)ctx); WaitForSingleObject (data_available, INFINITE); @@ -561,6 +584,16 @@ goto leave; } + /* Check for request to unblock once. */ + if (pimpl->flags & PIPE_FLAG_UNBLOCK_WRITER) + { + log_debug ("GPG_Write (ctx=0x%p): success: EBUSY (due to unblock request)\n", (void*)ctx); + pimpl->flags &= ~PIPE_FLAG_UNBLOCK_WRITER; + SetLastError (ERROR_BUSY); + result = -1; + goto leave; + } + /* Write to our buffer. */ if (pimpl->buffer_len == pimpl->buffer_size) { @@ -695,6 +728,30 @@ } +/* opnctx_table_s is locked on entering and on exit. */ +static BOOL +unblock_call (opnctx_t ctx) +{ + /* If there is no pipe object, no thread can be blocked. */ + if (!ctx->pipeimpl) + return TRUE; + + EnterCriticalSection (&ctx->pipeimpl->critsect); + if (ctx->access_code & GENERIC_READ) + { + ctx->pipeimpl->flags |= PIPE_FLAG_UNBLOCK_READER; + SetEvent (ctx->pipeimpl->data_available); + } + else if (ctx->access_code & GENERIC_WRITE) + { + ctx->pipeimpl->flags |= PIPE_FLAG_UNBLOCK_WRITER; + SetEvent (ctx->pipeimpl->space_available); + } + LeaveCriticalSection (&ctx->pipeimpl->critsect); + + return TRUE; +} + BOOL GPG_IOControl (DWORD opnctx_arg, DWORD code, void *inbuf, DWORD inbuflen, void *outbuf, DWORD outbuflen, DWORD *actualoutlen) @@ -754,6 +811,20 @@ result = TRUE; break; + case GPGCEDEV_IOCTL_UNBLOCK: + log_debug ("GPG_IOControl (ctx=0x%p): code: UNBLOCK\n", (void*)opnctx); + if (inbuf || inbuflen || outbuf || outbuflen || actualoutlen) + { + log_debug ("GPG_IOControl (ctx=0x%p): error: invalid parameter\n", + (void*)opnctx); + SetLastError (ERROR_INVALID_PARAMETER); + goto leave; + } + + if (unblock_call (opnctx)) + result = TRUE; + break; + case IOCTL_PSL_NOTIFY: log_debug ("GPG_IOControl (ctx=0x%p): code: NOTIFY\n", (void*)opnctx); /* Unexpected process termination. */ From cvs at cvs.gnupg.org Wed Jun 9 15:14:45 2010 From: cvs at cvs.gnupg.org (svn author marcus) Date: Wed, 09 Jun 2010 15:14:45 +0200 Subject: [svn] gpgme - r1474 - trunk/src Message-ID: Author: marcus Date: 2010-06-09 15:14:44 +0200 (Wed, 09 Jun 2010) New Revision: 1474 Modified: trunk/src/ChangeLog trunk/src/genkey.c Log: 2010-06-09 Marcus Brinkmann * genkey.c (gpgme_op_genkey): Return err with TRACE_ERR. Modified: trunk/src/ChangeLog =================================================================== --- trunk/src/ChangeLog 2010-05-12 18:20:36 UTC (rev 1473) +++ trunk/src/ChangeLog 2010-06-09 13:14:44 UTC (rev 1474) @@ -1,3 +1,7 @@ +2010-06-09 Marcus Brinkmann + + * genkey.c (gpgme_op_genkey): Return err with TRACE_ERR. + 2010-05-12 Marcus Brinkmann * conversion.c (_gpgme_timegm) [HAVE_W32_SYSTEM]: New static Modified: trunk/src/genkey.c =================================================================== --- trunk/src/genkey.c 2010-05-12 18:20:36 UTC (rev 1473) +++ trunk/src/genkey.c 2010-06-09 13:14:44 UTC (rev 1474) @@ -223,5 +223,5 @@ err = genkey_start (ctx, 1, parms, pubkey, seckey); if (!err) err = _gpgme_wait_one (ctx); - return err; + return TRACE_ERR (err); } From cvs at cvs.gnupg.org Wed Jun 9 15:23:30 2010 From: cvs at cvs.gnupg.org (svn author marcus) Date: Wed, 09 Jun 2010 15:23:30 +0200 Subject: [svn] gpgme - r1475 - trunk/src Message-ID: Author: marcus Date: 2010-06-09 15:23:30 +0200 (Wed, 09 Jun 2010) New Revision: 1475 Modified: trunk/src/ChangeLog trunk/src/gpgme-tool.c Log: 2010-06-09 Marcus Brinkmann * gpgme-tool.c (result_add_timestamp): Add missing NULL argument. (result_sign_to_xml): Protect against NULL fingerprint. (struct server): New members input_fd, input_filename, input_stream output_fd, output_filename, output_stream, message_filename, message_stream. (server_reset_fds): Deallocate those. (server_parse_fd): New function. (server_data_obj): Take optional filename argument and direction argument. Also take new argument to return a filestream that needs to be closed after destroying the data object. Change all callers, too. (input_notify, output_notify): Removed. (cmd_input, cmd_output): New functions. (gpgme_server): Do not register input and output notifier. (register_commands): Use cmd_input and cmd_output. (cmd_message): Rewritten to use server_parse_fd. (cmd_delete, cmd_keylist): Fix inverted option check. (main) [HAVE_W32CE_SYSTEM]: Sleep a bit to work around bug in ssh. Modified: trunk/src/ChangeLog =================================================================== --- trunk/src/ChangeLog 2010-06-09 13:14:44 UTC (rev 1474) +++ trunk/src/ChangeLog 2010-06-09 13:23:30 UTC (rev 1475) @@ -1,5 +1,24 @@ 2010-06-09 Marcus Brinkmann + * gpgme-tool.c (result_add_timestamp): Add missing NULL argument. + (result_sign_to_xml): Protect against NULL fingerprint. + (struct server): New members input_fd, input_filename, + input_stream output_fd, output_filename, output_stream, + message_filename, message_stream. + (server_reset_fds): Deallocate those. + (server_parse_fd): New function. + (server_data_obj): Take optional filename argument and direction + argument. Also take new argument to return a filestream that + needs to be closed after destroying the data object. + Change all callers, too. + (input_notify, output_notify): Removed. + (cmd_input, cmd_output): New functions. + (gpgme_server): Do not register input and output notifier. + (register_commands): Use cmd_input and cmd_output. + (cmd_message): Rewritten to use server_parse_fd. + (cmd_delete, cmd_keylist): Fix inverted option check. + (main) [HAVE_W32CE_SYSTEM]: Sleep a bit to work around bug in ssh. + * genkey.c (gpgme_op_genkey): Return err with TRACE_ERR. 2010-05-12 Marcus Brinkmann Modified: trunk/src/gpgme-tool.c =================================================================== --- trunk/src/gpgme-tool.c 2010-06-09 13:14:44 UTC (rev 1474) +++ trunk/src/gpgme-tool.c 2010-06-09 13:23:30 UTC (rev 1475) @@ -746,7 +746,7 @@ char code[20]; snprintf (code, sizeof (code) - 1, "%ui", timestamp); - result_xml_tag_start (state, name, "unix", code); + result_xml_tag_start (state, name, "unix", code, NULL); result_xml_tag_end (state); return 0; } @@ -937,7 +937,8 @@ result_add_pubkey_algo (&state, "pubkey-algo", new_sig->pubkey_algo); result_add_hash_algo (&state, "hash-algo", new_sig->hash_algo); result_add_timestamp (&state, "timestamp", new_sig->timestamp); - result_add_fpr (&state, "fpr", new_sig->fpr); + if (new_sig->fpr) + result_add_fpr (&state, "fpr", new_sig->fpr); result_add_value (&state, "sig-class", new_sig->sig_class); result_xml_tag_end (&state); @@ -1835,7 +1836,15 @@ gpgme_data_encoding_t input_enc; gpgme_data_encoding_t output_enc; + assuan_fd_t input_fd; + char *input_filename; + FILE *input_stream; + assuan_fd_t output_fd; + char *output_filename; + FILE *output_stream; assuan_fd_t message_fd; + char *message_filename; + FILE *message_stream; gpgme_data_encoding_t message_enc; }; @@ -1856,6 +1865,30 @@ } + +static gpg_error_t +server_parse_fd (assuan_context_t ctx, char *line, assuan_fd_t *rfd, + char **filename) +{ + *rfd = ASSUAN_INVALID_FD; + *filename = NULL; + + if (! strncasecmp (line, "file=", 5)) + { + char *term; + *filename = strdup (line + 5); + if (!*filename) + return gpg_error_from_syserror(); + term = strchr (*filename, ' '); + if (term) + *term = '\0'; + return 0; + } + else + return assuan_command_parse_fd (ctx, line, rfd); +} + + static gpgme_data_encoding_t server_data_encoding (const char *line) { @@ -1876,13 +1909,24 @@ static gpgme_error_t -server_data_obj (assuan_fd_t fd, gpgme_data_encoding_t encoding, - gpgme_data_t *data) +server_data_obj (assuan_fd_t fd, char *fn, int out, + gpgme_data_encoding_t encoding, + gpgme_data_t *data, FILE **fs) { gpgme_error_t err; - /* For now... */ - err = gpgme_data_new_from_fd (data, (int) fd); + *fs = NULL; + if (fn) + { + *fs = fopen (fn, out ? "wb" : "rb"); + if (!*fs) + return gpg_error_from_syserror (); + + err = gpgme_data_new_from_stream (data, *fs); + } + else + err = gpgme_data_new_from_fd (data, (int) fd); + if (err) return err; return gpgme_data_set_encoding (*data, encoding); @@ -1907,6 +1951,37 @@ #endif server->message_fd = ASSUAN_INVALID_FD; } + if (server->input_filename) + { + free (server->input_filename); + server->input_filename = NULL; + } + if (server->output_filename) + { + free (server->output_filename); + server->output_filename = NULL; + } + if (server->message_filename) + { + free (server->message_filename); + server->message_filename = NULL; + } + if (server->input_stream) + { + fclose (server->input_stream); + server->input_stream = NULL; + } + if (server->output_stream) + { + fclose (server->output_stream); + server->output_stream = NULL; + } + if (server->message_stream) + { + fclose (server->message_stream); + server->message_stream = NULL; + } + server->input_enc = GPGME_DATA_ENCODING_NONE; server->output_enc = GPGME_DATA_ENCODING_NONE; server->message_enc = GPGME_DATA_ENCODING_NONE; @@ -1922,6 +1997,7 @@ return 0; } + static const char hlp_version[] = "VERSION []\n" "\n" @@ -2065,18 +2141,36 @@ static gpg_error_t -input_notify (assuan_context_t ctx, char *line) +cmd_input (assuan_context_t ctx, char *line) { struct server *server = assuan_get_pointer (ctx); + gpg_error_t err; + assuan_fd_t sysfd; + char *filename; + + err = server_parse_fd (ctx, line, &sysfd, &filename); + if (err) + return err; + server->input_fd = sysfd; + server->input_filename = filename; server->input_enc = server_data_encoding (line); return 0; } static gpg_error_t -output_notify (assuan_context_t ctx, char *line) +cmd_output (assuan_context_t ctx, char *line) { struct server *server = assuan_get_pointer (ctx); + gpg_error_t err; + assuan_fd_t sysfd; + char *filename; + + err = server_parse_fd (ctx, line, &sysfd, &filename); + if (err) + return err; + server->output_fd = sysfd; + server->output_filename = filename; server->output_enc = server_data_encoding (line); return 0; } @@ -2088,11 +2182,13 @@ struct server *server = assuan_get_pointer (ctx); gpg_error_t err; assuan_fd_t sysfd; + char *filename; - err = assuan_command_parse_fd (ctx, line, &sysfd); + err = server_parse_fd (ctx, line, &sysfd, &filename); if (err) return err; server->message_fd = sysfd; + server->message_filename = filename; server->message_enc = server_data_encoding (line); return 0; } @@ -2131,21 +2227,27 @@ struct server *server = assuan_get_pointer (ctx); gpg_error_t err; assuan_fd_t inp_fd; + char *inp_fn; assuan_fd_t out_fd; + char *out_fn; gpgme_data_t inp_data; gpgme_data_t out_data; inp_fd = assuan_get_input_fd (ctx); - if (inp_fd == ASSUAN_INVALID_FD) + inp_fn = server->input_filename; + if (inp_fd == ASSUAN_INVALID_FD && !inp_fn) return GPG_ERR_ASS_NO_INPUT; out_fd = assuan_get_output_fd (ctx); - if (out_fd == ASSUAN_INVALID_FD) + out_fn = server->output_filename; + if (out_fd == ASSUAN_INVALID_FD && !out_fn) return GPG_ERR_ASS_NO_OUTPUT; - err = server_data_obj (inp_fd, server->input_enc, &inp_data); + err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data, + &server->input_stream); if (err) return err; - err = server_data_obj (out_fd, server->output_enc, &out_data); + err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data, + &server->output_stream); if (err) { gpgme_data_release (inp_data); @@ -2183,7 +2285,9 @@ struct server *server = assuan_get_pointer (ctx); gpg_error_t err; assuan_fd_t inp_fd; + char *inp_fn; assuan_fd_t out_fd; + char *out_fn; gpgme_data_t inp_data = NULL; gpgme_data_t out_data = NULL; gpgme_encrypt_flags_t flags = 0; @@ -2198,16 +2302,20 @@ flags |= GPGME_ENCRYPT_EXPECT_SIGN; inp_fd = assuan_get_input_fd (ctx); + inp_fn = server->input_filename; out_fd = assuan_get_output_fd (ctx); - if (inp_fd != ASSUAN_INVALID_FD) + out_fn = server->output_filename; + if (inp_fd != ASSUAN_INVALID_FD || inp_fn) { - err = server_data_obj (inp_fd, server->input_enc, &inp_data); + err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data, + &server->input_stream); if (err) return err; } - if (out_fd != ASSUAN_INVALID_FD) + if (out_fd != ASSUAN_INVALID_FD || out_fn) { - err = server_data_obj (out_fd, server->output_enc, &out_data); + err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data, + &server->output_stream); if (err) { gpgme_data_release (inp_data); @@ -2246,7 +2354,9 @@ struct server *server = assuan_get_pointer (ctx); gpg_error_t err; assuan_fd_t inp_fd; + char *inp_fn; assuan_fd_t out_fd; + char *out_fn; gpgme_data_t inp_data; gpgme_data_t out_data; gpgme_sig_mode_t mode = GPGME_SIG_MODE_NORMAL; @@ -2257,16 +2367,20 @@ mode = GPGME_SIG_MODE_DETACH; inp_fd = assuan_get_input_fd (ctx); - if (inp_fd == ASSUAN_INVALID_FD) + inp_fn = server->input_filename; + if (inp_fd == ASSUAN_INVALID_FD && !inp_fn) return GPG_ERR_ASS_NO_INPUT; out_fd = assuan_get_output_fd (ctx); - if (out_fd == ASSUAN_INVALID_FD) + out_fn = server->output_filename; + if (out_fd == ASSUAN_INVALID_FD && !out_fn) return GPG_ERR_ASS_NO_OUTPUT; - err = server_data_obj (inp_fd, server->input_enc, &inp_data); + err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data, + &server->input_stream); if (err) return err; - err = server_data_obj (out_fd, server->output_enc, &out_data); + err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data, + &server->output_stream); if (err) { gpgme_data_release (inp_data); @@ -2291,31 +2405,40 @@ assuan_fd_t inp_fd; assuan_fd_t msg_fd; assuan_fd_t out_fd; + char *inp_fn; + char *msg_fn; + char *out_fn; gpgme_data_t inp_data; gpgme_data_t msg_data = NULL; gpgme_data_t out_data = NULL; inp_fd = assuan_get_input_fd (ctx); - if (inp_fd == ASSUAN_INVALID_FD) + inp_fn = server->input_filename; + if (inp_fd == ASSUAN_INVALID_FD && !inp_fn) return GPG_ERR_ASS_NO_INPUT; msg_fd = server->message_fd; + msg_fn = server->message_filename; out_fd = assuan_get_output_fd (ctx); - - err = server_data_obj (inp_fd, server->input_enc, &inp_data); + out_fn = server->output_filename; + + err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data, + &server->input_stream); if (err) return err; - if (msg_fd != ASSUAN_INVALID_FD) + if (msg_fd != ASSUAN_INVALID_FD || msg_fn) { - err = server_data_obj (msg_fd, server->message_enc, &msg_data); + err = server_data_obj (msg_fd, msg_fn, 0, server->message_enc, &msg_data, + &server->message_stream); if (err) { gpgme_data_release (inp_data); return err; } } - if (out_fd != ASSUAN_INVALID_FD) + if (out_fd != ASSUAN_INVALID_FD || out_fn) { - err = server_data_obj (out_fd, server->output_enc, &out_data); + err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data, + &server->output_stream); if (err) { gpgme_data_release (inp_data); @@ -2353,13 +2476,16 @@ { gpg_error_t err; assuan_fd_t inp_fd; + char *inp_fn; gpgme_data_t inp_data; inp_fd = assuan_get_input_fd (ctx); - if (inp_fd == ASSUAN_INVALID_FD) + inp_fn = server->input_filename; + if (inp_fd == ASSUAN_INVALID_FD && !inp_fn) return GPG_ERR_ASS_NO_INPUT; - err = server_data_obj (inp_fd, server->input_enc, &inp_data); + err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data, + &server->input_stream); if (err) return err; @@ -2384,14 +2510,17 @@ struct server *server = assuan_get_pointer (ctx); gpg_error_t err; assuan_fd_t out_fd; + char *out_fn; gpgme_data_t out_data; gpgme_export_mode_t mode = 0; const char *pattern[2]; out_fd = assuan_get_output_fd (ctx); - if (out_fd == ASSUAN_INVALID_FD) + out_fn = server->output_filename; + if (out_fd == ASSUAN_INVALID_FD && !out_fn) return GPG_ERR_ASS_NO_OUTPUT; - err = server_data_obj (out_fd, server->output_enc, &out_data); + err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data, + &server->output_stream); if (err) return err; @@ -2438,23 +2567,29 @@ struct server *server = assuan_get_pointer (ctx); gpg_error_t err; assuan_fd_t inp_fd; + char *inp_fn; assuan_fd_t out_fd; + char *out_fn; gpgme_data_t inp_data; gpgme_data_t out_data = NULL; gpgme_data_t parms_data = NULL; const char *parms; inp_fd = assuan_get_input_fd (ctx); - if (inp_fd == ASSUAN_INVALID_FD) + inp_fn = server->input_filename; + if (inp_fd == ASSUAN_INVALID_FD && !inp_fn) return GPG_ERR_ASS_NO_INPUT; out_fd = assuan_get_output_fd (ctx); + out_fn = server->output_filename; - err = server_data_obj (inp_fd, server->input_enc, &inp_data); + err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data, + &server->input_stream); if (err) return err; - if (out_fd != ASSUAN_INVALID_FD) + if (out_fd != ASSUAN_INVALID_FD || out_fn) { - err = server_data_obj (out_fd, server->output_enc, &out_data); + err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data, + &server->output_stream); if (err) { gpgme_data_release (inp_data); @@ -2514,12 +2649,14 @@ { struct server *server = assuan_get_pointer (ctx); int allow_secret = 0; - const char optstr[] = "--allow-secret "; + const char optstr[] = "--allow-secret"; - if (strncasecmp (line, optstr, strlen (optstr))) + if (!strncasecmp (line, optstr, strlen (optstr))) { allow_secret = 1; line += strlen (optstr); + while (*line && !spacep (line)) + line++; } return gt_delete (server->gt, line, allow_secret); } @@ -2532,12 +2669,14 @@ gpg_error_t err; int secret_only = 0; const char *pattern[2]; - const char optstr[] = "--secret-only "; + const char optstr[] = "--secret-only"; - if (strncasecmp (line, optstr, strlen (optstr))) + if (!strncasecmp (line, optstr, strlen (optstr))) { secret_only = 1; line += strlen (optstr); + while (*line && !spacep (line)) + line++; } pattern[0] = line; pattern[1] = NULL; @@ -2580,13 +2719,16 @@ struct server *server = assuan_get_pointer (ctx); gpg_error_t err; assuan_fd_t out_fd; + char *out_fn; gpgme_data_t out_data; unsigned int flags = 0; out_fd = assuan_get_output_fd (ctx); - if (out_fd == ASSUAN_INVALID_FD) + out_fn = server->output_filename; + if (out_fd == ASSUAN_INVALID_FD && !out_fn) return GPG_ERR_ASS_NO_OUTPUT; - err = server_data_obj (out_fd, server->output_enc, &out_data); + err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data, + &server->output_stream); if (err) return err; @@ -2722,8 +2864,8 @@ { "TEXTMODE", cmd_textmode }, { "INCLUDE_CERTS", cmd_include_certs }, { "KEYLIST_MODE", cmd_keylist_mode }, - { "INPUT", NULL }, - { "OUTPUT", NULL }, + { "INPUT", cmd_input }, + { "OUTPUT", cmd_output }, { "MESSAGE", cmd_message }, { "RECIPIENT", cmd_recipient }, { "SIGNER", cmd_signer }, @@ -2815,8 +2957,6 @@ assuan_set_hello_line (server.assuan_ctx, hello); assuan_register_reset_notify (server.assuan_ctx, reset_notify); - assuan_register_input_notify (server.assuan_ctx, input_notify); - assuan_register_output_notify (server.assuan_ctx, output_notify); #define DBG_ASSUAN 0 if (DBG_ASSUAN) @@ -2936,6 +3076,11 @@ gpgme_release (gt.ctx); +#ifdef HAVE_W32CE_SYSTEM + /* Give the buggy ssh server time to flush the output buffers. */ + Sleep (300); +#endif + return 0; } From cvs at cvs.gnupg.org Wed Jun 9 15:33:32 2010 From: cvs at cvs.gnupg.org (svn author marcus) Date: Wed, 09 Jun 2010 15:33:32 +0200 Subject: [svn] gpgme - r1476 - trunk/src Message-ID: Author: marcus Date: 2010-06-09 15:33:31 +0200 (Wed, 09 Jun 2010) New Revision: 1476 Modified: trunk/src/ChangeLog trunk/src/w32-io.c Log: 2010-06-09 Marcus Brinkmann * w32-io.c [HAVE_W32CE_SYSTEM]: Include assuan.h and winioctl.h. (GPGCEDEV_IOCTL_UNBLOCK) [HAVE_W32CE_SYSTEM]: Define. (set_synchronize) [HAVE_W32CE_SYSTEM]: Stub it out. (is_socket): Allow to return -1 for auto-detect (old behaviour). (is_socket) [HAVE_W32CE_SYSTEM]: Return -1. (reader): Handle auto-detect case. Handle ctx->stop_me before checking for EOF. (destroy_reader) [HAVE_W32CE_SYSTEM]: Unblock a pending reader. (writer): Handle auto-detect case. Handle ctx->stop_me with ERROR_BUSY. (destroy_writer) [HAVE_W32CE_SYSTEM]: Unblock a pending writer. (_gpgme_io_pipe) [HAVE_W32CE_SYSTEM]: Implement in terms of a half-pipe. (build_commandline) [HAVE_W32CE_SYSTEM]: New function. (_gpgme_io_spawn) [HAVE_W32CE_SYSTEM]: Implement it differently for this platform. (_gpgme_io_fd2str) [HAVE_W32CE_SYSTEM]: Implement it for RVIDs. (_gpgme_io_dup) [HAVE_W32CE_SYSTEM]: Stub it out. Modified: trunk/src/ChangeLog =================================================================== --- trunk/src/ChangeLog 2010-06-09 13:23:30 UTC (rev 1475) +++ trunk/src/ChangeLog 2010-06-09 13:33:31 UTC (rev 1476) @@ -1,5 +1,24 @@ 2010-06-09 Marcus Brinkmann + * w32-io.c [HAVE_W32CE_SYSTEM]: Include assuan.h and winioctl.h. + (GPGCEDEV_IOCTL_UNBLOCK) [HAVE_W32CE_SYSTEM]: Define. + (set_synchronize) [HAVE_W32CE_SYSTEM]: Stub it out. + (is_socket): Allow to return -1 for auto-detect (old behaviour). + (is_socket) [HAVE_W32CE_SYSTEM]: Return -1. + (reader): Handle auto-detect case. Handle ctx->stop_me before + checking for EOF. + (destroy_reader) [HAVE_W32CE_SYSTEM]: Unblock a pending reader. + (writer): Handle auto-detect case. Handle ctx->stop_me with + ERROR_BUSY. + (destroy_writer) [HAVE_W32CE_SYSTEM]: Unblock a pending writer. + (_gpgme_io_pipe) [HAVE_W32CE_SYSTEM]: Implement in terms of a + half-pipe. + (build_commandline) [HAVE_W32CE_SYSTEM]: New function. + (_gpgme_io_spawn) [HAVE_W32CE_SYSTEM]: Implement it differently + for this platform. + (_gpgme_io_fd2str) [HAVE_W32CE_SYSTEM]: Implement it for RVIDs. + (_gpgme_io_dup) [HAVE_W32CE_SYSTEM]: Stub it out. + * gpgme-tool.c (result_add_timestamp): Add missing NULL argument. (result_sign_to_xml): Protect against NULL fingerprint. (struct server): New members input_fd, input_filename, Modified: trunk/src/w32-io.c =================================================================== --- trunk/src/w32-io.c 2010-06-09 13:23:30 UTC (rev 1475) +++ trunk/src/w32-io.c 2010-06-09 13:33:31 UTC (rev 1476) @@ -33,6 +33,13 @@ #include #include +#ifdef HAVE_W32CE_SYSTEM +#include +#include +#define GPGCEDEV_IOCTL_UNBLOCK \ + CTL_CODE (FILE_DEVICE_STREAMS, 2050, METHOD_BUFFERED, FILE_ANY_ACCESS) +#endif + #include "util.h" #include "sema.h" #include "priv-io.h" @@ -154,6 +161,9 @@ static HANDLE set_synchronize (HANDLE hd) { +#ifdef HAVE_W32CE_SYSTEM + return hd; +#else HANDLE new_hd; /* For NT we have to set the sync flag. It seems that the only way @@ -171,13 +181,18 @@ CloseHandle (hd); return new_hd; +#endif } -/* Return true if HD refers to a socket. */ +/* Return 1 if HD refers to a socket, 0 if it does not refer to a + socket, and -1 for unknown (autodetect). */ static int is_socket (HANDLE hd) { +#ifdef HAVE_W32CE_SYSTEM + return -1; +#else /* We need to figure out whether we are working on a socket or on a handle. A trivial way would be to check for the return code of recv and see if it is WSAENOTSOCK. However the recv may block @@ -193,12 +208,14 @@ only if it is supported by the service provider. Tests on a stock XP using a local TCP socket show that it does not work. */ DWORD dummyflags, dummyoutsize, dummyinsize, dummyinst; + if (GetFileType (hd) == FILE_TYPE_PIPE && !GetNamedPipeInfo (hd, &dummyflags, &dummyoutsize, &dummyinsize, &dummyinst)) return 1; /* Function failed; thus we assume it is a socket. */ else return 0; /* Success; this is not a socket. */ +#endif } @@ -243,7 +260,7 @@ TRACE_LOG2 ("%s %d bytes", sock? "receiving":"reading", nbytes); - if (sock) + if (sock == -1 || sock == 1) { int n; @@ -251,6 +268,17 @@ ctx->buffer + ctx->writepos, nbytes, 0); if (n < 0) { + if (sock == -1) + { + if (WSAGetLastError () == WSAENOTSOCK) + { + sock = 0; + goto try_readfile; + } + else + sock = 1; + } + ctx->error_code = (int) WSAGetLastError (); if (ctx->error_code == ERROR_BROKEN_PIPE) { @@ -268,10 +296,13 @@ } else { + try_readfile: if (!ReadFile (ctx->file_hd, ctx->buffer + ctx->writepos, nbytes, &nread, NULL)) { ctx->error_code = (int) GetLastError (); + /* NOTE (W32CE): Do not ignore ERROR_BUSY! Check at + least stop_me if that happens. */ if (ctx->error_code == ERROR_BROKEN_PIPE) { ctx->eof = 1; @@ -285,20 +316,21 @@ break; } } + LOCK (ctx->mutex); + if (ctx->stop_me) + { + UNLOCK (ctx->mutex); + break; + } if (!nread) { ctx->eof = 1; TRACE_LOG ("got eof"); + UNLOCK (ctx->mutex); break; } TRACE_LOG1 ("got %u bytes", nread); - LOCK (ctx->mutex); - if (ctx->stop_me) - { - UNLOCK (ctx->mutex); - break; - } ctx->writepos = (ctx->writepos + nread) % READBUF_SIZE; if (!SetEvent (ctx->have_data_ev)) TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d", ctx->have_data_ev, @@ -403,6 +435,19 @@ SetEvent (ctx->have_space_ev); UNLOCK (ctx->mutex); +#ifdef HAVE_W32CE_SYSTEM + /* Scenario: We never create a full pipe, but already started + reading. Then we need to unblock the reader in the pipe driver + to make our reader thread notice that we want it to go away. */ + + if (!DeviceIoControl (ctx->file_hd, GPGCEDEV_IOCTL_UNBLOCK, + NULL, 0, NULL, 0, NULL, NULL)) + { + TRACE1 (DEBUG_SYSIO, "gpgme:destroy_reader", ctx->file_hd, + "unblock control call failed for thread %p", ctx->thread_hd); + } +#endif + TRACE1 (DEBUG_SYSIO, "gpgme:destroy_reader", ctx->file_hd, "waiting for termination of thread %p", ctx->thread_hd); WaitForSingleObject (ctx->stopped, INFINITE); @@ -603,16 +648,27 @@ /* Note that CTX->nbytes is not zero at this point, because _gpgme_io_write always writes at least 1 byte before waking us up, unless CTX->stop_me is true, which we catch above. */ - if (sock) + if (sock == -1 || sock == 1) { /* We need to try send first because a socket handle can't be used with WriteFile. */ int n; - + n = send (handle_to_socket (ctx->file_hd), ctx->buffer, ctx->nbytes, 0); if (n < 0) { + if (sock == -1) + { + if (WSAGetLastError () == WSAENOTSOCK) + { + sock = 0; + goto try_writefile; + } + else + sock = 1; + } + ctx->error_code = (int) WSAGetLastError (); ctx->error = 1; TRACE_LOG1 ("send error: ec=%d", ctx->error_code); @@ -622,9 +678,17 @@ } else { + try_writefile: if (!WriteFile (ctx->file_hd, ctx->buffer, ctx->nbytes, &nwritten, NULL)) { + if (GetLastError () == ERROR_BUSY) + { + /* Probably stop_me is set now. */ + TRACE_LOG ("pipe busy (unblocked?)"); + continue; + } + ctx->error_code = (int) GetLastError (); ctx->error = 1; TRACE_LOG1 ("write error: ec=%d", ctx->error_code); @@ -732,6 +796,19 @@ if (ctx->have_data) SetEvent (ctx->have_data); UNLOCK (ctx->mutex); + +#ifdef HAVE_W32CE_SYSTEM + /* Scenario: We never create a full pipe, but already started + reading. Then we need to unblock the reader in the pipe driver + to make our reader thread notice that we want it to go away. */ + + if (!DeviceIoControl (ctx->file_hd, GPGCEDEV_IOCTL_UNBLOCK, + NULL, 0, NULL, 0, NULL, NULL)) + { + TRACE1 (DEBUG_SYSIO, "gpgme:destroy_writer", ctx->file_hd, + "unblock control call failed for thread %p", ctx->thread_hd); + } +#endif TRACE1 (DEBUG_SYSIO, "gpgme:destroy_writer", ctx->file_hd, "waiting for termination of thread %p", ctx->thread_hd); @@ -894,11 +971,40 @@ { HANDLE rh; HANDLE wh; - SECURITY_ATTRIBUTES sec_attr; + +#ifdef HAVE_W32CE_SYSTEM + HANDLE hd; + int rvid; + TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes, "inherit_idx=%i (GPGME uses it for %s)", inherit_idx, inherit_idx ? "reading" : "writing"); + hd = _assuan_w32ce_prepare_pipe (&rvid, !inherit_idx); + if (hd == INVALID_HANDLE_VALUE) + { + TRACE_LOG1 ("_assuan_w32ce_prepare_pipe failed: ec=%d", + (int) GetLastError ()); + /* FIXME: Should translate the error code. */ + gpg_err_set_errno (EIO); + return TRACE_SYSRES (-1); + } + + if (inherit_idx == 0) + { + /* FIXME: For now. We need to detect them at close. */ + rh = (void*) ((rvid << 1) | 1); + wh = hd; + } + else + { + rh = hd; + /* FIXME: For now. We need to detect them at close. */ + wh = (void*) ((rvid << 1) | 1); + } +#else + SECURITY_ATTRIBUTES sec_attr; + memset (&sec_attr, 0, sizeof (sec_attr)); sec_attr.nLength = sizeof (sec_attr); sec_attr.bInheritHandle = FALSE; @@ -914,7 +1020,6 @@ /* Make one end inheritable. */ if (inherit_idx == 0) { - struct writer_context_s *ctx; HANDLE hd; if (!DuplicateHandle (GetCurrentProcess(), rh, GetCurrentProcess(), &hd, 0, @@ -930,22 +1035,9 @@ } CloseHandle (rh); rh = hd; - - ctx = find_writer (handle_to_fd (wh), 0); - assert (ctx == NULL); - ctx = find_writer (handle_to_fd (wh), 1); - if (!ctx) - { - CloseHandle (rh); - CloseHandle (wh); - /* FIXME: Should translate the error code. */ - gpg_err_set_errno (EIO); - return TRACE_SYSRES (-1); - } } else if (inherit_idx == 1) { - struct reader_context_s *ctx; HANDLE hd; if (!DuplicateHandle( GetCurrentProcess(), wh, GetCurrentProcess(), &hd, 0, @@ -961,14 +1053,38 @@ } CloseHandle (wh); wh = hd; + } +#endif + if (inherit_idx == 0) + { + struct writer_context_s *ctx; + ctx = find_writer (handle_to_fd (wh), 0); + assert (ctx == NULL); + ctx = find_writer (handle_to_fd (wh), 1); + if (!ctx) + { +#ifndef HAVE_W32CE_SYSTEM + CloseHandle (rh); +#endif + CloseHandle (wh); + /* FIXME: Should translate the error code. */ + gpg_err_set_errno (EIO); + return TRACE_SYSRES (-1); + } + } + else if (inherit_idx == 1) + { + struct reader_context_s *ctx; ctx = find_reader (handle_to_fd (rh), 0); assert (ctx == NULL); ctx = find_reader (handle_to_fd (rh), 1); if (!ctx) { CloseHandle (rh); +#ifndef HAVE_W32CE_SYSTEM CloseHandle (wh); +#endif /* FIXME: Should translate the error code. */ gpg_err_set_errno (EIO); return TRACE_SYSRES (-1); @@ -995,6 +1111,12 @@ return TRACE_SYSRES (-1); } +#ifdef HAVE_W32CE_SYSTEM + /* FIXME: For now: This is a rendezvous id. */ + if (fd & 1) + return TRACE_SYSRES (0); +#endif + kill_reader (fd); kill_writer (fd); LOCK (notify_table_lock); @@ -1066,7 +1188,105 @@ return 0; } +#ifdef HAVE_W32CE_SYSTEM +static char * +build_commandline (char **argv, int fd0, int fd0_isnull, + int fd1, int fd1_isnull, + int fd2, int fd2_isnull) +{ + int i, n; + const char *s; + char *buf, *p; + char fdbuf[3*30]; + p = fdbuf; + *p = 0; + + strcpy (p, "-&S0=null "); + p += strlen (p); + if (fd0 != -1) + { + /* FIXME */ + if (fd0 & 1) + fd0 = fd0 >> 1; + + if (fd0_isnull) + strcpy (p, "-&S0=null "); + else + snprintf (p, 25, "-&S0=%d ", (int)fd0); + p += strlen (p); + } + if (fd1 != -1) + { + /* FIXME */ + if (fd1 & 1) + fd1 = fd1 >> 1; + + if (fd1_isnull) + strcpy (p, "-&S1=null "); + else + snprintf (p, 25, "-&S1=%d ", (int)fd1); + p += strlen (p); + } + if (fd2 != -1) + { + /* FIXME */ + if (fd2 & 1) + fd2 = fd2 >> 1; + + if (fd2_isnull) + strcpy (p, "-&S2=null "); + else + snprintf (p, 25, "-&S2=%d ", (int)fd2); + p += strlen (p); + } + strcpy (p, "-&S2=null "); + p += strlen (p); + + n = strlen (fdbuf); + for (i=0; (s = argv[i]); i++) + { + if (!i) + continue; /* Ignore argv[0]. */ + n += strlen (s) + 1 + 2; /* (1 space, 2 quoting) */ + for (; *s; s++) + if (*s == '\"') + n++; /* Need to double inner quotes. */ + } + n++; + buf = p = malloc (n); + if (! buf) + return NULL; + + p = stpcpy (p, fdbuf); + for (i = 0; argv[i]; i++) + { + if (!i) + continue; /* Ignore argv[0]. */ + if (i > 1) + p = stpcpy (p, " "); + + if (! *argv[i]) /* Empty string. */ + p = stpcpy (p, "\"\""); + else if (strpbrk (argv[i], " \t\n\v\f\"")) + { + p = stpcpy (p, "\""); + for (s = argv[i]; *s; s++) + { + *p++ = *s; + if (*s == '\"') + *p++ = *s; + } + *p++ = '\"'; + *p = 0; + } + else + p = stpcpy (p, argv[i]); + } + + return buf; +} +#else static char * build_commandline (char **argv) { @@ -1120,6 +1340,7 @@ return buf; } +#endif int @@ -1128,7 +1349,6 @@ void (*atfork) (void *opaque, int reserved), void *atforkvalue, pid_t *r_pid) { - SECURITY_ATTRIBUTES sec_attr; PROCESS_INFORMATION pi = { NULL, /* returns process handle */ @@ -1136,10 +1356,85 @@ 0, /* returns pid */ 0 /* returns tid */ }; - STARTUPINFO si; - int cr_flags = (CREATE_DEFAULT_ERROR_MODE - | GetPriorityClass (GetCurrentProcess ())); int i; + +#ifdef HAVE_W32CE_SYSTEM + int fd_in = -1; + int fd_out = -1; + int fd_err = -1; + int fd_in_isnull = 1; + int fd_out_isnull = 1; + int fd_err_isnull = 1; + char *cmdline; + + TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path, + "path=%s", path); + i = 0; + while (argv[i]) + { + TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]); + i++; + } + + for (i = 0; fd_list[i].fd != -1; i++) + { + TRACE_LOG3 ("fd_list[%2i] = fd %i, dup_to %i", i, fd_list[i].fd, fd_list[i].dup_to); + if (fd_list[i].dup_to == 0) + { + fd_in = fd_list[i].fd; + fd_in_isnull = 0; + } + else if (fd_list[i].dup_to == 1) + { + fd_out = fd_list[i].fd; + fd_out_isnull = 0; + } + else if (fd_list[i].dup_to == 2) + { + fd_err = fd_list[i].fd; + fd_err_isnull = 0; + } + } + + cmdline = build_commandline (argv, fd_in, fd_in_isnull, + fd_out, fd_out_isnull, fd_err, fd_err_isnull); + if (!cmdline) + { + TRACE_LOG1 ("build_commandline failed: %s", strerror (errno)); + return TRACE_SYSRES (-1); + } + + fprintf (stderr, "SPAWNY: %s\n", cmdline); + + if (!CreateProcessA (path, /* Program to start. */ + cmdline, /* Command line arguments. */ + NULL, /* (not supported) */ + NULL, /* (not supported) */ + FALSE, /* (not supported) */ + (CREATE_SUSPENDED), /* Creation flags. */ + NULL, /* (not supported) */ + NULL, /* (not supported) */ + NULL, /* (not supported) */ + &pi /* Returns process information.*/ + )) + { + TRACE_LOG1 ("CreateProcess failed: ec=%d", (int) GetLastError ()); + free (cmdline); + gpg_err_set_errno (EIO); + return TRACE_SYSRES (-1); + } + + /* Insert the inherited handles. */ + for (i = 0; fd_list[i].fd != -1; i++) + { + /* Return the child name of this handle. */ + fd_list[i].peer_name = fd_list[i].fd; + } + +#else + SECURITY_ATTRIBUTES sec_attr; + STARTUPINFOA si; + int cr_flags = CREATE_DEFAULT_ERROR_MODE; char **args; char *arg_string; /* FIXME. */ @@ -1183,7 +1478,7 @@ if (!arg_string) { close (tmp_fd); - DeleteFile (tmp_name); + DeleteFileA (tmp_name); return TRACE_SYSRES (-1); } @@ -1196,7 +1491,10 @@ si.hStdError = INVALID_HANDLE_VALUE; cr_flags |= CREATE_SUSPENDED; +#ifndef HAVE_W32CE_SYSTEM cr_flags |= DETACHED_PROCESS; + cr_flags |= GetPriorityClass (GetCurrentProcess ()); +#endif if (!CreateProcessA (_gpgme_get_w32spawn_path (), arg_string, &sec_attr, /* process security attributes */ @@ -1211,7 +1509,7 @@ TRACE_LOG1 ("CreateProcess failed: ec=%d", (int) GetLastError ()); free (arg_string); close (tmp_fd); - DeleteFile (tmp_name); + DeleteFileA (tmp_name); /* FIXME: Should translate the error code. */ gpg_err_set_errno (EIO); @@ -1241,7 +1539,7 @@ CloseHandle (pi.hProcess); close (tmp_fd); - DeleteFile (tmp_name); + DeleteFileA (tmp_name); /* FIXME: Should translate the error code. */ gpg_err_set_errno (EIO); @@ -1294,7 +1592,9 @@ close (tmp_fd); /* The temporary file is deleted by the gpgme-w32spawn process (hopefully). */ +#endif + TRACE_LOG4 ("CreateProcess ready: hProcess=%p, hThread=%p, " "dwProcessID=%d, dwThreadId=%d", pi.hProcess, pi.hThread, @@ -1511,6 +1811,13 @@ int _gpgme_io_fd2str (char *buf, int buflen, int fd) { +#ifdef HAVE_W32CE_SYSTEM + /* FIXME: For now. See above. */ + if (fd & 1) + fd = fd >> 1; + /* FIXME: The real problems start if fd is not of this type! */ +#endif + return snprintf (buf, buflen, "%d", fd); } @@ -1518,6 +1825,10 @@ int _gpgme_io_dup (int fd) { +#ifdef HAVE_W32CE_SYSTEM + gpg_err_set_errno (EIO); + return -1; +#else HANDLE handle = fd_to_handle (fd); HANDLE new_handle = fd_to_handle (fd); int i; @@ -1575,6 +1886,7 @@ } return TRACE_SYSRES (handle_to_fd (new_handle)); +#endif } From cvs at cvs.gnupg.org Wed Jun 9 18:53:57 2010 From: cvs at cvs.gnupg.org (svn author wk) Date: Wed, 09 Jun 2010 18:53:57 +0200 Subject: [svn] GnuPG - r5351 - in trunk: . agent am common dirmngr g13 m4 scd sm tools Message-ID: Author: wk Date: 2010-06-09 18:53:51 +0200 (Wed, 09 Jun 2010) New Revision: 5351 Added: trunk/dirmngr/ trunk/dirmngr/ChangeLog trunk/dirmngr/ChangeLog.1 trunk/dirmngr/Makefile.am trunk/dirmngr/OAUTHORS trunk/dirmngr/ONEWS trunk/dirmngr/b64dec.c trunk/dirmngr/b64enc.c trunk/dirmngr/cdb.h trunk/dirmngr/cdblib.c trunk/dirmngr/certcache.c trunk/dirmngr/certcache.h trunk/dirmngr/crlcache.c trunk/dirmngr/crlcache.h trunk/dirmngr/crlfetch.c trunk/dirmngr/crlfetch.h trunk/dirmngr/dirmngr-client.c trunk/dirmngr/dirmngr.c trunk/dirmngr/dirmngr.h trunk/dirmngr/dirmngr_ldap.c trunk/dirmngr/get-path.c trunk/dirmngr/http.c trunk/dirmngr/http.h trunk/dirmngr/ldap-url.c trunk/dirmngr/ldap-url.h trunk/dirmngr/ldap.c trunk/dirmngr/ldapserver.c trunk/dirmngr/ldapserver.h trunk/dirmngr/misc.c trunk/dirmngr/misc.h trunk/dirmngr/no-libgcrypt.c trunk/dirmngr/ocsp.c trunk/dirmngr/ocsp.h trunk/dirmngr/server.c trunk/dirmngr/validate.c trunk/dirmngr/validate.h Modified: trunk/ChangeLog trunk/Makefile.am trunk/NEWS trunk/agent/genkey.c trunk/am/cmacros.am trunk/autogen.sh trunk/common/ChangeLog trunk/common/asshelp.c trunk/common/exechelp-posix.c trunk/common/exechelp-w32.c trunk/common/exechelp-w32ce.c trunk/common/exechelp.h trunk/common/homedir.c trunk/common/logging.c trunk/common/logging.h trunk/common/util.h trunk/configure.ac trunk/g13/be-encfs.c trunk/g13/runner.c trunk/m4/ChangeLog trunk/m4/ldap.m4 trunk/scd/ChangeLog trunk/scd/scdaemon.c trunk/sm/export.c trunk/sm/import.c trunk/tools/gpgconf-comp.c Log: Merged Dirmngr with GnuPG. A few code changes to support dirmngr. [The diff below has been truncated] Modified: trunk/ChangeLog =================================================================== --- trunk/ChangeLog 2010-06-08 18:33:21 UTC (rev 5350) +++ trunk/ChangeLog 2010-06-09 16:53:51 UTC (rev 5351) @@ -1,5 +1,23 @@ +2010-06-09 Werner Koch + + * configure.ac (GNUPG_DIRMNGR_LDAP_PGM): Add option + --with-dirmngr-ldap-pgm. + + * am/cmacros.am (-DGNUPG_LOCALSTATEDIR): New. + (GNUPG_DEFAULT_DIRMNGR_LDAP): New. + +2010-06-08 Werner Koch + + * configure.ac: Add build support for dirmngr. + (try_ldap): Rename to try_ks_ldap. + (GNUPG_CHECK_LDAP): Also test if dirmngr is to be build. + + * Makefile.am (SUBDIRS): Add dirmngr. + 2010-06-07 Werner Koch + * dirmngr/: New. + * configure.ac: Add option --enable-gpgtar. 2010-05-31 Werner Koch Modified: trunk/common/ChangeLog =================================================================== --- trunk/common/ChangeLog 2010-06-08 18:33:21 UTC (rev 5350) +++ trunk/common/ChangeLog 2010-06-09 16:53:51 UTC (rev 5351) @@ -1,3 +1,21 @@ +2010-06-09 Werner Koch + + * exechelp-posix.c, exechelp-w32.c + * exechelp-w32ce.c (gnupg_wait_process): Add new arg HANG. Change + all callers. + (gnupg_release_process): New. Use it after all calls to + gnupg_wait_process. + + * util.h (GNUPG_MODULE_NAME_DIRMNGR_LDAP): New. + * homedir.c (gnupg_cachedir): New. + (w32_try_mkdir): New. + (dirmngr_socket_name): Chanmge standard socket name. + (gnupg_module_name): Support GNUPG_MODULE_NAME_DIRMNGR_LDAP. + + * logging.c (log_set_get_tid_callback): Replace by ... + (log_set_pid_suffix_cb): .. new. + (do_logv): Change accordingly. + 2010-06-08 Marcus Brinkmann * Makefile.am (AM_CFLAGS): Add $(LIBASSUAN_CFLAGS). @@ -5,7 +23,7 @@ * sysutils.c: Include . (translate_sys2libc_fd_int): Cast to silence gcc warning. * iobuf.c: Include - (translate_file_handle): Fix syntax error. + (translate_file_handle): Fix syntax error. 2010-06-08 Werner Koch Modified: trunk/m4/ChangeLog =================================================================== --- trunk/m4/ChangeLog 2010-06-08 18:33:21 UTC (rev 5350) +++ trunk/m4/ChangeLog 2010-06-09 16:53:51 UTC (rev 5351) @@ -1,3 +1,7 @@ +2010-06-08 Werner Koch + + * ldap.m4 (gnupg_have_ldap): Set variable. + 2009-09-03 Werner Koch * estream.m4: Update for libestream. Modified: trunk/scd/ChangeLog =================================================================== --- trunk/scd/ChangeLog 2010-06-08 18:33:21 UTC (rev 5350) +++ trunk/scd/ChangeLog 2010-06-09 16:53:51 UTC (rev 5351) @@ -1,3 +1,8 @@ +2010-06-09 Werner Koch + + * scdaemon.c (main): s/log_set_get_tid_callback/log_set_pid_suffix_cb/. + (tid_log_callback): Adjust for this change. + 2010-03-11 Werner Koch * scdaemon.c: Include "asshelp.h". Modified: trunk/Makefile.am =================================================================== --- trunk/Makefile.am 2010-06-08 18:33:21 UTC (rev 5350) +++ trunk/Makefile.am 2010-06-09 16:53:51 UTC (rev 5351) @@ -61,6 +61,11 @@ else g13 = endif +if BUILD_DIRMNGR +dirmngr = dirmngr +else +dirmngr = +endif if BUILD_TOOLS tools = tools else @@ -79,7 +84,8 @@ endif SUBDIRS = m4 gl include common ${kbx} \ - ${gpg} ${keyserver} ${sm} ${agent} ${scd} ${g13} ${tools} po ${doc} ${tests} + ${gpg} ${keyserver} ${sm} ${agent} ${scd} ${g13} ${dirmngr} \ + ${tools} po ${doc} ${tests} dist_doc_DATA = README Modified: trunk/NEWS =================================================================== --- trunk/NEWS 2010-06-08 18:33:21 UTC (rev 5350) +++ trunk/NEWS 2010-06-09 16:53:51 UTC (rev 5351) @@ -29,7 +29,9 @@ option --use-standard-socket may now be used to use this feature by default. + * Dirmngr is now a part of this package. + Noteworthy changes in version 2.0.13 (2009-09-04) ------------------------------------------------- Modified: trunk/agent/genkey.c =================================================================== --- trunk/agent/genkey.c 2010-06-08 18:33:21 UTC (rev 5350) +++ trunk/agent/genkey.c 2010-06-09 16:53:51 UTC (rev 5351) @@ -129,10 +129,11 @@ if (gnupg_spawn_process_fd (pgmname, argv, fileno (infp), -1, -1, &pid)) result = 1; /* Execute error - assume password should no be used. */ - else if (gnupg_wait_process (pgmname, pid, NULL)) + else if (gnupg_wait_process (pgmname, pid, 0, NULL)) result = 1; /* Helper returned an error - probably a match. */ else result = 0; /* Success; i.e. no match. */ + gnupg_release_process (pid); /* Overwrite our temporary file. */ fseek (infp, 0, SEEK_SET); Modified: trunk/am/cmacros.am =================================================================== --- trunk/am/cmacros.am 2010-06-08 18:33:21 UTC (rev 5350) +++ trunk/am/cmacros.am 2010-06-09 16:53:51 UTC (rev 5351) @@ -25,7 +25,8 @@ -DGNUPG_LIBEXECDIR="\"$(libexecdir)\"" \ -DGNUPG_LIBDIR="\"$(libdir)/@PACKAGE@\"" \ -DGNUPG_DATADIR="\"$(datadir)/@PACKAGE@\"" \ - -DGNUPG_SYSCONFDIR="\"$(sysconfdir)/@PACKAGE@\"" + -DGNUPG_SYSCONFDIR="\"$(sysconfdir)/@PACKAGE@\"" \ + -DGNUPG_LOCALSTATEDIR="\"$(localstatedir)\"" endif @@ -47,6 +48,9 @@ if GNUPG_PROTECT_TOOL_PGM AM_CPPFLAGS += -DGNUPG_DEFAULT_PROTECT_TOOL="\"@GNUPG_PROTECT_TOOL_PGM@\"" endif +if GNUPG_DIRMNGR_LDAP_PGM +AM_CPPFLAGS += -DGNUPG_DEFAULT_DIRMNGR_LDAP="\"@GNUPG_DIRMNGR_LDAP_PGM@\"" +endif # Under Windows we use LockFileEx. WindowsCE provides this only on # the WindowsMobile 6 platform and thus we need to use the coredll6 Modified: trunk/autogen.sh =================================================================== --- trunk/autogen.sh 2010-06-08 18:33:21 UTC (rev 5350) +++ trunk/autogen.sh 2010-06-09 16:53:51 UTC (rev 5351) @@ -103,7 +103,7 @@ w32root="$w32ce_root" [ -z "$w32root" ] && w32root="$HOME/w32ce_root" toolprefixes="$w32ce_toolprefixes arm-mingw32ce" - extraoptions="--disable-scdaemon --disable-zip $w32ce_extraoptions" + extraoptions="--disable-scdaemon --disable-zip --disable-ldap --disable-dirmngr $w32ce_extraoptions" ;; *) [ -z "$w32root" ] && w32root="$HOME/w32root" Modified: trunk/common/asshelp.c =================================================================== --- trunk/common/asshelp.c 2010-06-08 18:33:21 UTC (rev 5350) +++ trunk/common/asshelp.c 2010-06-09 16:53:51 UTC (rev 5351) @@ -362,12 +362,13 @@ if (err) log_debug ("starting `%s' for testing failed: %s\n", agent_program, gpg_strerror (err)); - else if ((err = gnupg_wait_process (agent_program, pid, &excode))) + else if ((err = gnupg_wait_process (agent_program, pid, 0, &excode))) { if (excode == -1) log_debug ("running `%s' for testing failed: %s\n", agent_program, gpg_strerror (err)); } + gnupg_release_process (pid); if (!err && !excode) { Modified: trunk/common/exechelp-posix.c =================================================================== --- trunk/common/exechelp-posix.c 2010-06-08 18:33:21 UTC (rev 5350) +++ trunk/common/exechelp-posix.c 2010-06-09 16:53:51 UTC (rev 5351) @@ -416,38 +416,40 @@ } -/* Wait for the process identified by PID to terminate. PGMNAME should - be the same as supplied to the spawn function and is only used for - diagnostics. Returns 0 if the process succeeded, GPG_ERR_GENERAL - for any failures of the spawned program or other error codes. If - EXITCODE is not NULL the exit code of the process is stored at this - address or -1 if it could not be retrieved and no error message is - logged. */ +/* See exechelp.h for the description. */ gpg_error_t -gnupg_wait_process (const char *pgmname, pid_t pid, int *exitcode) +gnupg_wait_process (const char *pgmname, pid_t pid, int hang, int *r_exitcode) { gpg_err_code_t ec; - int i, status; - if (exitcode) - *exitcode = -1; + if (r_exitcode) + *r_exitcode = -1; if (pid == (pid_t)(-1)) return gpg_error (GPG_ERR_INV_VALUE); #ifdef USE_GNU_PTH - i = pth_waitpid ? pth_waitpid (pid, &status, 0) : waitpid (pid, &status, 0); -#else - while ( (i=waitpid (pid, &status, 0)) == -1 && errno == EINTR) - ; + if (pth_waitpid) + i = pth_waitpid (pid, &status, hang? 0:WNOHANG); + else #endif + { + while ((i=waitpid (pid, &status, hang? 0:WNOHANG)) == (pid_t)(-1) + && errno == EINTR) + ; + } + if (i == (pid_t)(-1)) { + ec = gpg_err_code_from_errno (errno); log_error (_("waiting for process %d to terminate failed: %s\n"), (int)pid, strerror (errno)); - ec = gpg_err_code_from_errno (errno); } + else if (!i) + { + ec = GPG_ERR_TIMEOUT; /* Still running. */ + } else if (WIFEXITED (status) && WEXITSTATUS (status) == 127) { log_error (_("error running `%s': probably not installed\n"), pgmname); @@ -455,11 +457,11 @@ } else if (WIFEXITED (status) && WEXITSTATUS (status)) { - if (!exitcode) + if (!r_exitcode) log_error (_("error running `%s': exit status %d\n"), pgmname, WEXITSTATUS (status)); else - *exitcode = WEXITSTATUS (status); + *r_exitcode = WEXITSTATUS (status); ec = GPG_ERR_GENERAL; } else if (!WIFEXITED (status)) @@ -469,8 +471,8 @@ } else { - if (exitcode) - *exitcode = 0; + if (r_exitcode) + *r_exitcode = 0; ec = 0; } @@ -478,7 +480,14 @@ } -/* Spawn a new process and immediatley detach from it. The name of +void +gnupg_release_process (pid_t pid) +{ + (void)pid; +} + + +/* Spawn a new process and immediately detach from it. The name of the program to exec is PGMNAME and its arguments are in ARGV (the programname is automatically passed as first argument). Environment strings in ENVP are set. An error is returned if Modified: trunk/common/exechelp-w32.c =================================================================== --- trunk/common/exechelp-w32.c 2010-06-08 18:33:21 UTC (rev 5350) +++ trunk/common/exechelp-w32.c 2010-06-09 16:53:51 UTC (rev 5351) @@ -382,7 +382,7 @@ int cr_flags; char *cmdline; int fd, fdout, rp[2]; - HANDLE nullhd[]; + HANDLE nullhd[2]; int i; (void)preexec; @@ -428,7 +428,7 @@ } nullhd[0] = fd == -1? w32_open_null (0) : INVALID_HANDLE_VALUE; - nullhd[1] = outfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE; + nullhd[1] = fdout == -1? w32_open_null (1) : INVALID_HANDLE_VALUE; /* Start the process. Note that we can't run the PREEXEC function because this would change our own environment. */ @@ -437,7 +437,7 @@ si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE; si.hStdInput = fd == -1? nullhd[0] : fd_to_handle (fd); - si.hStdOutput = outfd == -1? nullhd[1] : fd_to_handle (fdout); + si.hStdOutput = fdout == -1? nullhd[1] : fd_to_handle (fdout); si.hStdError = fd_to_handle (rp[1]); cr_flags = (CREATE_DEFAULT_ERROR_MODE @@ -599,22 +599,17 @@ } -/* Wait for the process identified by PID to terminate. PGMNAME should - be the same as supplied to the spawn function and is only used for - diagnostics. Returns 0 if the process succeeded, GPG_ERR_GENERAL - for any failures of the spawned program or other error codes. If - EXITCODE is not NULL the exit code of the process is stored at this - address or -1 if it could not be retrieved. */ +/* See exechelp.h for a description. */ gpg_error_t -gnupg_wait_process (const char *pgmname, pid_t pid, int *exitcode) +gnupg_wait_process (const char *pgmname, pid_t pid, int hang, int *r_exitcode) { gpg_err_code_t ec; HANDLE proc = fd_to_handle (pid); int code; DWORD exc; - if (exitcode) - *exitcode = -1; + if (r_exitcode) + *r_exitcode = -1; if (pid == (pid_t)(-1)) return gpg_error (GPG_ERR_INV_VALUE); @@ -622,50 +617,66 @@ /* FIXME: We should do a pth_waitpid here. However this has not yet been implemented. A special W32 pth system call would even be better. */ - code = WaitForSingleObject (proc, INFINITE); + code = WaitForSingleObject (proc, hang? INFINITE : 0); switch (code) { - case WAIT_FAILED: - log_error (_("waiting for process %d to terminate failed: %s\n"), - (int)pid, w32_strerror (-1)); - ec = GPG_ERR_GENERAL; - break; + case WAIT_TIMEOUT: + ec = GPG_ERR_TIMEOUT; + break; - case WAIT_OBJECT_0: - if (!GetExitCodeProcess (proc, &exc)) - { - log_error (_("error getting exit code of process %d: %s\n"), - (int)pid, w32_strerror (-1) ); - ec = GPG_ERR_GENERAL; - } - else if (exc) - { - log_error (_("error running `%s': exit status %d\n"), - pgmname, (int)exc ); - if (exitcode) - *exitcode = (int)exc; - ec = GPG_ERR_GENERAL; - } - else - { - if (exitcode) - *exitcode = 0; - ec = 0; - } - CloseHandle (proc); - break; + case WAIT_FAILED: + log_error (_("waiting for process %d to terminate failed: %s\n"), + (int)pid, w32_strerror (-1)); + ec = GPG_ERR_GENERAL; + break; - default: - log_error ("WaitForSingleObject returned unexpected " - "code %d for pid %d\n", code, (int)pid ); - ec = GPG_ERR_GENERAL; - break; + case WAIT_OBJECT_0: + if (!GetExitCodeProcess (proc, &exc)) + { + log_error (_("error getting exit code of process %d: %s\n"), + (int)pid, w32_strerror (-1) ); + ec = GPG_ERR_GENERAL; + } + else if (exc) + { + log_error (_("error running `%s': exit status %d\n"), + pgmname, (int)exc ); + if (r_exitcode) + *r_exitcode = (int)exc; + ec = GPG_ERR_GENERAL; + } + else + { + if (r_exitcode) + *r_exitcode = 0; + ec = 0; + } + break; + + default: + log_error ("WaitForSingleObject returned unexpected " + "code %d for pid %d\n", code, (int)pid ); + ec = GPG_ERR_GENERAL; + break; } - + return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec); } + +void +gnupg_release_process (pid_t pid) +{ + if (pid != (pid_t)INVALID_HANDLE_VALUE) + { + HANDLE process = (HANDLE)pid; + + CloseHandle (process); + } +} + + /* Spawn a new process and immediatley detach from it. The name of the program to exec is PGMNAME and its arguments are in ARGV (the programname is automatically passed as first argument). Modified: trunk/common/exechelp-w32ce.c =================================================================== --- trunk/common/exechelp-w32ce.c 2010-06-08 18:33:21 UTC (rev 5350) +++ trunk/common/exechelp-w32ce.c 2010-06-09 16:53:51 UTC (rev 5351) @@ -653,14 +653,10 @@ return 0; } -/* Wait for the process identified by PID to terminate. PGMNAME should - be the same as supplied to the spawn function and is only used for - diagnostics. Returns 0 if the process succeeded, GPG_ERR_GENERAL - for any failures of the spawned program or other error codes. If - EXITCODE is not NULL the exit code of the process is stored at this - address or -1 if it could not be retrieved. */ + +/* See exechelp.h for a description. */ gpg_error_t -gnupg_wait_process (const char *pgmname, pid_t pid, int *exitcode) +gnupg_wait_process (const char *pgmname, pid_t pid, int hang, int *exitcode) { gpg_err_code_t ec; HANDLE proc = fd_to_handle (pid); @@ -676,50 +672,65 @@ /* FIXME: We should do a pth_waitpid here. However this has not yet been implemented. A special W32 pth system call would even be better. */ - code = WaitForSingleObject (proc, INFINITE); + code = WaitForSingleObject (proc, hang? INFINITE : 0); switch (code) { - case WAIT_FAILED: - log_error (_("waiting for process %d to terminate failed: %s\n"), - (int)pid, w32_strerror (-1)); - ec = GPG_ERR_GENERAL; - break; + case WAIT_TIMEOUT: + ec = GPG_ERR_TIMEOUT; + break; + + case WAIT_FAILED: + log_error (_("waiting for process %d to terminate failed: %s\n"), + (int)pid, w32_strerror (-1)); + ec = GPG_ERR_GENERAL; + break; - case WAIT_OBJECT_0: - if (!GetExitCodeProcess (proc, &exc)) - { - log_error (_("error getting exit code of process %d: %s\n"), - (int)pid, w32_strerror (-1) ); - ec = GPG_ERR_GENERAL; + case WAIT_OBJECT_0: + if (!GetExitCodeProcess (proc, &exc)) + { + log_error (_("error getting exit code of process %d: %s\n"), + (int)pid, w32_strerror (-1) ); + ec = GPG_ERR_GENERAL; } - else if (exc) - { - log_error (_("error running `%s': exit status %d\n"), + else if (exc) + { + log_error (_("error running `%s': exit status %d\n"), pgmname, (int)exc ); - if (exitcode) - *exitcode = (int)exc; - ec = GPG_ERR_GENERAL; - } - else - { - if (exitcode) - *exitcode = 0; - ec = 0; - } - CloseHandle (proc); - break; - - default: - log_error ("WaitForSingleObject returned unexpected " - "code %d for pid %d\n", code, (int)pid ); - ec = GPG_ERR_GENERAL; - break; + if (exitcode) + *exitcode = (int)exc; + ec = GPG_ERR_GENERAL; + } + else + { + if (exitcode) + *exitcode = 0; + ec = 0; + } + break; + + default: + log_error ("WaitForSingleObject returned unexpected " + "code %d for pid %d\n", code, (int)pid ); + ec = GPG_ERR_GENERAL; + break; } return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec); } +void +gnupg_release_process (pid_t pid) +{ + if (pid != (pid_t)INVALID_HANDLE_VALUE) + { + HANDLE process = (HANDLE)pid; + + CloseHandle (process); + } +} + + /* Spawn a new process and immediatley detach from it. The name of the program to exec is PGMNAME and its arguments are in ARGV (the programname is automatically passed as first argument). Modified: trunk/common/exechelp.h =================================================================== --- trunk/common/exechelp.h 2010-06-08 18:33:21 UTC (rev 5350) +++ trunk/common/exechelp.h 2010-06-09 16:53:51 UTC (rev 5351) @@ -59,8 +59,8 @@ process are expected in the NULL terminated array ARGV. The program name itself should not be included there. If PREEXEC is not NULL, that function will be called right before the exec. - Calling gnupg_wait_process is required. Returns 0 on success or an - error code. + Calling gnupg_wait_process and gnupg_release_process is required. + Returns 0 on success or an error code. FLAGS is a bit vector: @@ -85,29 +85,54 @@ and ERRFD to stderr (any of them may be -1 to connect them to /dev/null). The arguments for the process are expected in the NULL terminated array ARGV. The program name itself should not be - included there. Calling gnupg_wait_process is required. Returns 0 - on success or an error code. */ + included there. Calling gnupg_wait_process and + gnupg_release_process is required. Returns 0 on success or an + error code. */ gpg_error_t gnupg_spawn_process_fd (const char *pgmname, const char *argv[], int infd, int outfd, int errfd, pid_t *pid); -/* Wait for the process identified by PID to terminate. PGMNAME should - be the same as supplied to the spawn fucntion and is only used for - diagnostics. Returns 0 if the process succeded, GPG_ERR_GENERAL - for any failures of the spawned program or other error codes. If - EXITCODE is not NULL the exit code of the process is stored at this - address or -1 if it could not be retrieved. */ -gpg_error_t gnupg_wait_process (const char *pgmname, pid_t pid, int *exitcode); +/* If HANG is true, waits for the process identified by PID to exit; + if HANG is false, checks whether the process has terminated. + PGMNAME should be the same as supplied to the spawn function and is + only used for diagnostics. Return values: + 0 + The process exited successful. 0 is stored at R_EXITCODE. + GPG_ERR_GENERAL + The process exited without success. The exit code of process + is then stored at R_EXITCODE. An exit code of -1 indicates + that the process terminated abnormally (e.g. due to a signal). + + GPG_ERR_TIMEOUT + The process is still running (returned only if HANG is false). + + GPG_ERR_INV_VALUE + An invalid PID has been specified. + + Other error codes may be returned as well. Unless otherwise noted, + -1 will be stored at R_EXITCODE. R_EXITCODE may be passed as NULL + if the exit code is not required (in that case an error messge will + be printed). Note that under Windows PID is not the process id but + the handle of the process. */ +gpg_error_t gnupg_wait_process (const char *pgmname, pid_t pid, int hang, + int *r_exitcode); + + /* Kill a process; that is send an appropriate signal to the process. gnupg_wait_process must be called to actually remove the process from the system. An invalid PID is ignored. */ void gnupg_kill_process (pid_t pid); +/* Release the process identified by PID. This function is actually + only required for Windows but it does not harm to always call it. + It is a nop if PID is invalid. */ +void gnupg_release_process (pid_t pid); + /* Spawn a new process and immediatley detach from it. The name of the program to exec is PGMNAME and its arguments are in ARGV (the programname is automatically passed as first argument). Modified: trunk/common/homedir.c =================================================================== --- trunk/common/homedir.c 2010-06-08 18:33:21 UTC (rev 5350) +++ trunk/common/homedir.c 2010-06-09 16:53:51 UTC (rev 5351) @@ -44,6 +44,24 @@ #include "sysutils.h" +#ifdef HAVE_W32_SYSTEM +static void +w32_try_mkdir (const char *dir) +{ +#ifdef HAVE_W32CE_SYSTEM + wchar_t *wdir = utf8_to_wchar (dir); + if (wdir) + { + CreateDirectory (wdir, NULL); + xfree (wdir); + } +#else + CreateDirectory (dir, NULL); +#endif +} +#endif + + /* This is a helper function to load a Windows function from either of one DLLs. */ #ifdef HAVE_W32_SYSTEM @@ -114,18 +132,7 @@ /* Try to create the directory if it does not yet exists. */ if (access (dir, F_OK)) - { -#ifdef HAVE_W32CE_SYSTEM - wchar_t *wdir = utf8_to_wchar (dir); - if (wdir) - { - CreateDirectory (wdir, NULL); - xfree (wdir); - } -#else - CreateDirectory (dir, NULL); -#endif - } + w32_try_mkdir (dir); } else dir = GNUPG_DEFAULT_HOMEDIR; @@ -366,6 +373,54 @@ } +/* Return the name of the cache directory. The name is allocated in a + static area on the first use. Windows only: If the directory does + not exist it is created. */ +const char * +gnupg_cachedir (void) +{ +#ifdef HAVE_W32_SYSTEM + static const char *dir; + + if (!dir) + { + char path[MAX_PATH]; + const char *s1[] = { "GNU", "cache", "gnupg", NULL }; + int s1_len; + const char **comp; + + s1_len = 0; + for (comp = s1; *comp; comp++) + s1_len += 1 + strlen (*comp); + + if (w32_shgetfolderpath (NULL, CSIDL_LOCAL_APPDATA|CSIDL_FLAG_CREATE, + NULL, 0, path) >= 0) + { + char *tmp = xmalloc (strlen (path) + s1_len + 1); + char *p; + + p = stpcpy (tmp, path); + for (comp = s1; *comp; comp++) + { + p = stpcpy (p, "\\"); + p = stpcpy (p, *comp); + + if (access (tmp, F_OK)) + w32_try_mkdir (tmp); + } + + dir = tmp; + } + else + dir = "c:\\temp\\cache\\dirmngr"; + } + return dir; +#else /*!HAVE_W32_SYSTEM*/ + return GNUPG_LOCALSTATEDIR "/cache/" PACKAGE_NAME; +#endif /*!HAVE_W32_SYSTEM*/ +} + + /* Return the default socket name used by DirMngr. */ const char * dirmngr_socket_name (void) @@ -379,7 +434,10 @@ const char *s2; /* We need something akin CSIDL_COMMON_PROGRAMS, but local - (non-roaming). */ + (non-roaming). This is becuase the file needs to be on the + local machine and makes only sense on that machine. + CSIDL_WINDOWS seems to be the only location which guarantees + that. */ if (w32_shgetfolderpath (NULL, CSIDL_WINDOWS, NULL, 0, s1) < 0) strcpy (s1, "C:\\WINDOWS"); s2 = DIRSEP_S "S.dirmngr"; @@ -388,7 +446,7 @@ } return name; #else /*!HAVE_W32_SYSTEM*/ - return "/var/run/dirmngr/socket"; + return GNUPG_LOCALSTATEDIR "/run/" PACKAGE_NAME "/S.dirmngr"; #endif /*!HAVE_W32_SYSTEM*/ } @@ -450,6 +508,13 @@ X(libexecdir, "gpg-protect-tool"); #endif + case GNUPG_MODULE_NAME_DIRMNGR_LDAP: +#ifdef GNUPG_DEFAULT_DIRMNGR_LDAP + return GNUPG_DEFAULT_DIRMNGR_LDAP; +#else + X(libexecdir, "dirmngr_ldap"); +#endif + case GNUPG_MODULE_NAME_CHECK_PATTERN: X(libexecdir, "gpg-check-pattern"); Modified: trunk/common/logging.c =================================================================== --- trunk/common/logging.c 2010-06-08 18:33:21 UTC (rev 5350) +++ trunk/common/logging.c 2010-06-09 16:53:51 UTC (rev 5351) @@ -63,7 +63,7 @@ static int with_time; static int with_prefix; static int with_pid; -static unsigned long (*get_tid_callback)(void); +static int (*get_pid_suffix_cb)(unsigned long *r_value); static int running_detached; static int force_prefixes; @@ -336,9 +336,9 @@ void -log_set_get_tid_callback (unsigned long (*cb)(void)) +log_set_pid_suffix_cb (int (*cb)(unsigned long *r_value)) { - get_tid_callback = cb; + get_pid_suffix_cb = cb; } @@ -441,9 +441,12 @@ es_fputs_unlocked (prefix_buffer, logstream); if (with_pid || force_prefixes) { - if (get_tid_callback) - es_fprintf_unlocked (logstream, "[%u.%lx]", - (unsigned int)getpid (), get_tid_callback ()); + unsigned long pidsuf; + int pidfmt; + + if (get_pid_suffix_cb && (pidfmt=get_pid_suffix_cb (&pidsuf))) + es_fprintf_unlocked (logstream, pidfmt == 1? "[%u.%lu]":"[%u.%lx]", + (unsigned int)getpid (), pidsuf); else es_fprintf_unlocked (logstream, "[%u]", (unsigned int)getpid ()); } Modified: trunk/common/logging.h =================================================================== --- trunk/common/logging.h 2010-06-08 18:33:21 UTC (rev 5350) +++ trunk/common/logging.h 2010-06-09 16:53:51 UTC (rev 5351) @@ -35,7 +35,7 @@ void log_inc_errorcount (void); void log_set_file( const char *name ); void log_set_fd (int fd); -void log_set_get_tid_callback (unsigned long (*cb)(void)); +void log_set_pid_suffix_cb (int (*cb)(unsigned long *r_value)); void log_set_prefix (const char *text, unsigned int flags); const char *log_get_prefix (unsigned int *flags); int log_test_fd (int fd); Modified: trunk/common/util.h =================================================================== --- trunk/common/util.h 2010-06-08 18:33:21 UTC (rev 5350) +++ trunk/common/util.h 2010-06-09 16:53:51 UTC (rev 5351) @@ -192,6 +192,7 @@ const char *gnupg_libdir (void); const char *gnupg_datadir (void); const char *gnupg_localedir (void); +const char *gnupg_cachedir (void); const char *dirmngr_socket_name (void); /* All module names. We also include gpg and gpgsm for the sake for @@ -206,6 +207,7 @@ #define GNUPG_MODULE_NAME_GPG 8 #define GNUPG_MODULE_NAME_CONNECT_AGENT 9 #define GNUPG_MODULE_NAME_GPGCONF 10 +#define GNUPG_MODULE_NAME_DIRMNGR_LDAP 11 const char *gnupg_module_name (int which); Modified: trunk/configure.ac =================================================================== --- trunk/configure.ac 2010-06-08 18:33:21 UTC (rev 5350) +++ trunk/configure.ac 2010-06-09 16:53:51 UTC (rev 5351) @@ -1,6 +1,6 @@ # configure.ac - for GnuPG 2.1 # Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, -# 2006, 2007, 2008, 2009 Free Software Foundation, Inc. +# 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. # # This file is part of GnuPG. # @@ -81,11 +81,14 @@ use_ccid_driver=yes use_standard_socket=no +try_ks_ldap=no + GNUPG_BUILD_PROGRAM(gpg, yes) GNUPG_BUILD_PROGRAM(gpgsm, yes) GNUPG_BUILD_PROGRAM(agent, yes) GNUPG_BUILD_PROGRAM(scdaemon, yes) GNUPG_BUILD_PROGRAM(g13, yes) +GNUPG_BUILD_PROGRAM(dirmngr, yes) GNUPG_BUILD_PROGRAM(tools, yes) GNUPG_BUILD_PROGRAM(doc, yes) GNUPG_BUILD_PROGRAM(symcryptrun, no) @@ -155,7 +158,16 @@ test -n "$GNUPG_PROTECT_TOOL_PGM" \ && show_gnupg_protect_tool_pgm="$GNUPG_PROTECT_TOOL_PGM" +AC_ARG_WITH(dirmngr-ldap-pgm, + [ --with-dirmngr-ldap-pgm=PATH Use PATH as the default for the dirmnge ldap wrapper)], + GNUPG_DIRMNGR_LDAP_PGM="$withval", GNUPG_DIRMNGR_LDAP_PGM="" ) +AC_SUBST(GNUPG_DIRMNGR_LDAP_PGM) +AM_CONDITIONAL(GNUPG_DIRMNGR_LDAP_PGM, test -n "$GNUPG_DIRMNGR_LDAP_PGM") +show_gnupg_dirmngr_ldap_pgm="(default)" +test -n "$GNUPG_DIRMNGR_LDAP_PGM" \ + && show_gnupg_dirmngr_ldap_pgm="$GNUPG_DIRMNGR_LDAP_PGM" + # Some folks want to use only the agent from this packet. Make it # easier for them by providing the configure option # --enable-only-agent. @@ -239,8 +251,8 @@ AC_MSG_CHECKING([whether LDAP keyserver support is requested]) AC_ARG_ENABLE(ldap, AC_HELP_STRING([--disable-ldap],[disable LDAP keyserver interface only]), - try_ldap=$enableval, try_ldap=yes) - AC_MSG_RESULT($try_ldap) + try_ks_ldap=$enableval, try_ks_ldap=yes) + AC_MSG_RESULT($try_ks_ldap) AC_MSG_CHECKING([whether HKP keyserver support is requested]) AC_ARG_ENABLE(hkp, @@ -528,6 +540,7 @@ have_w32_system=no have_w32ce_system=no use_simple_gettext=no +mmap_needed=yes case "${host}" in *-mingw32*) # special stuff for Windoze NT @@ -552,6 +565,7 @@ esac try_gettext="no" use_simple_gettext=yes + mmap_needed=no ;; i?86-emx-os2 | i?86-*-os2*emx ) # OS/2 with the EMX environment @@ -738,6 +752,10 @@ AC_DEFINE_UNQUOTED(FUSERMOUNT, "${FUSERMOUNT}", [defines the filename of the fusermount program]) + +# Checks for dirmngr + + # # Checks for symcryptrun: # @@ -943,7 +961,7 @@ # # Check for LDAP # -if test "$try_ldap" = yes ; then +if test "$try_ks_ldap" = yes || test "$build_dirmngr" = "yes" ; then GNUPG_CHECK_LDAP($NETLIBS) fi @@ -1152,9 +1170,9 @@ AC_FUNC_FSEEKO AC_FUNC_VPRINTF AC_FUNC_FORK -AC_CHECK_FUNCS([strerror strlwr tcgetattr mmap]) -AC_CHECK_FUNCS([strcasecmp strncasecmp ctermid times gmtime_r]) -AC_CHECK_FUNCS([unsetenv fcntl ftruncate]) +AC_CHECK_FUNCS([strerror strlwr tcgetattr mmap canonicalize_file_name]) +AC_CHECK_FUNCS([strcasecmp strncasecmp ctermid times gmtime_r strtoull]) +AC_CHECK_FUNCS([unsetenv fcntl ftruncate canonicalize_file_name]) AC_CHECK_FUNCS([gettimeofday getrusage getrlimit setrlimit clock_gettime]) AC_CHECK_FUNCS([atexit raise getpagesize strftime nl_langinfo setlocale]) AC_CHECK_FUNCS([waitpid wait4 sigaction sigprocmask pipe getaddrinfo]) @@ -1162,6 +1180,11 @@ AC_CHECK_TYPES([struct sigaction, sigset_t],,,[#include ]) +# Dirmngr requires mmap on Unix systems. +if test $ac_cv_func_mmap != yes -a $mmap_needed = yes; then + AC_MSG_ERROR([[Sorry, the current implemenation requires mmap.]]) +fi + # # These are needed by the jnlib parts in common. # Note: We already checked pwd.h. @@ -1170,7 +1193,10 @@ memrchr isascii timegm getrusage setrlimit stat setlocale \ flockfile funlockfile fopencookie funopen getpwnam getpwuid \ getenv ]) +# end jnlib checks. + + # # gnulib checks # @@ -1466,18 +1492,19 @@ fi -AM_CONDITIONAL(BUILD_GPG, test "$build_gpg" = "yes") -AM_CONDITIONAL(BUILD_GPGSM, test "$build_gpgsm" = "yes") -AM_CONDITIONAL(BUILD_AGENT, test "$build_agent" = "yes") -AM_CONDITIONAL(BUILD_SCDAEMON, test "$build_scdaemon" = "yes") -AM_CONDITIONAL(BUILD_G13, test "$build_g13" = "yes") -AM_CONDITIONAL(BUILD_TOOLS, test "$build_tools" = "yes") -AM_CONDITIONAL(BUILD_DOC, test "$build_doc" = "yes") +AM_CONDITIONAL(BUILD_GPG, test "$build_gpg" = "yes") +AM_CONDITIONAL(BUILD_GPGSM, test "$build_gpgsm" = "yes") +AM_CONDITIONAL(BUILD_AGENT, test "$build_agent" = "yes") +AM_CONDITIONAL(BUILD_SCDAEMON, test "$build_scdaemon" = "yes") +AM_CONDITIONAL(BUILD_G13, test "$build_g13" = "yes") +AM_CONDITIONAL(BUILD_DIRMNGR, test "$build_dirmngr" = "yes") +AM_CONDITIONAL(BUILD_TOOLS, test "$build_tools" = "yes") +AM_CONDITIONAL(BUILD_DOC, test "$build_doc" = "yes") AM_CONDITIONAL(BUILD_SYMCRYPTRUN, test "$build_symcryptrun" = "yes") -AM_CONDITIONAL(BUILD_GPGTAR,test "$build_gpgtar" = "yes") +AM_CONDITIONAL(BUILD_GPGTAR, test "$build_gpgtar" = "yes") AM_CONDITIONAL(RUN_GPG_TESTS, - test x$cross_compiling = xno -a "$build_gpg" = yes ) + test x$cross_compiling = xno -a "$build_gpg" = yes ) # @@ -1524,6 +1551,16 @@ *** (at least version $NEED_KSBA_VERSION using API $NEED_KSBA_API is required). ***]]) fi +if test "$gnupg_have_ldap" = "no"; then + die=yes + AC_MSG_NOTICE([[ +*** +*** You need a LDAP library to build this program. +*** Check out +*** http://www.openldap.org +*** for a suitable implementation. +***]]) +fi if test "$missing_pth" = "yes"; then AC_MSG_NOTICE([[ *** @@ -1562,6 +1599,7 @@ agent/Makefile scd/Makefile g13/Makefile +dirmngr/Makefile keyserver/Makefile keyserver/gpg2keys_mailto keyserver/gpg2keys_test @@ -1585,9 +1623,11 @@ Agent: $build_agent $build_agent_threaded Smartcard: $build_scdaemon $build_scdaemon_extra G13: $build_g13 + Dirmngr: $build_dirmngr Gpgtar: $build_gpgtar Protect tool: $show_gnupg_protect_tool_pgm + LDAP wrapper: $show_gnupg_dirmngr_ldap_pgm Default agent: $show_gnupg_agent_pgm Default pinentry: $show_gnupg_pinentry_pgm Default scdaemon: $show_gnupg_scdaemon_pgm Added: trunk/dirmngr/ChangeLog =================================================================== --- trunk/dirmngr/ChangeLog (rev 0) +++ trunk/dirmngr/ChangeLog 2010-06-09 16:53:51 UTC (rev 5351) @@ -0,0 +1,1345 @@ +2010-06-09 Werner Koch + + * i18n.h: Remove. + + * Makefile.am (no-libgcrypt.c): New rule. + + * exechelp.h: Remove. + * exechelp.c: Remove. + (dirmngr_release_process): Change callers to use the gnupg func. + (dirmngr_wait_process): Likewise. + (dirmngr_kill_process): Likewise. This actually implements it for + W32. + * ldap.c (ldap_wrapper): s/get_dirmngr_ldap_path/gnupg_module_name/. + (ldap_wrapper_thread): Use gnupg_wait_process and adjust for + changed semantics. + (ldap_wrapper): Replace xcalloc by xtrycalloc. Replace spawn + mechanism. + + * server.c (start_command_handler): Remove assuan_set_log_stream. + + * validate.c: Remove gcrypt.h and ksba.h. + + * ldapserver.c: s/util.h/dirmngr.h/. + + * dirmngr.c (sleep) [W32]: Remove macro. + (main): s/sleep/gnupg_sleep/. + (pid_suffix_callback): Change arg type. + (my_gcry_logger): Remove. + (fixed_gcry_pth_init): New. + (main): Use it. + (FD2INT): Remove. + +2010-06-08 Werner Koch + + * misc.h (copy_time): Remove and replace by gnupg_copy_time which + allows to set a null date. + * misc.c (dump_isotime, get_time, get_isotime, set_time) + (check_isotime, add_isotime): Remove and replace all calls by the + versions from common/gettime.c. + + * crlcache.c, misc.c, misc.h: s/dirmngr_isotime_t/gnupg_isotime_t/. + * server.c, ldap.c: Reorder include directives. + * crlcache.h, misc.h: Remove all include directives. + + * certcache.c (cmp_simple_canon_sexp): Remove. + (compare_serialno): Rewrite using cmp_simple_canon_sexp from + common/sexputil.c + + * error.h: Remove. + + * dirmngr.c: Remove transitional option "--ignore-ocsp-servic-url". + (opts): Use ARGPARSE macros. + (i18n_init): Remove. + (main): Use GnuPG init functions. + + * dirmngr.h: Remove duplicated stuff now taken from ../common. + + * get-path.c, util.h: Remove. + + * Makefile.am: Adjust to GnuPG system. + * estream.c, estream.h, estream-printf.c, estream-printf.h: Remove. + +2010-06-07 Werner Koch + + * OAUTHORS, ONEWS, ChangeLog.1: New. + + * ChangeLog, Makefile.am, b64dec.c, b64enc.c, cdb.h, cdblib.c + * certcache.c, certcache.h, crlcache.c, crlcache.h, crlfetch.c + * crlfetch.h, dirmngr-client.c, dirmngr.c, dirmngr.h + * dirmngr_ldap.c, error.h, estream-printf.c, estream-printf.h + * estream.c, estream.h, exechelp.c, exechelp.h, get-path.c, http.c + * http.h, i18n.h, ldap-url.c, ldap-url.h, ldap.c, ldapserver.c + * ldapserver.h, misc.c, misc.h, ocsp.c, ocsp.h, server.c, util.h + * validate.c, validate.h: Imported from the current SVN of the + dirmngr package (only src/). + +2010-03-13 Werner Koch + + * dirmngr.c (int_and_ptr_u): New. + (pid_suffix_callback): Trick out compiler. + (start_connection_thread): Ditto. + (handle_connections): Ditto. + +2010-03-09 Werner Koch + + * dirmngr.c (set_debug): Allow numerical values. + +2009-12-15 Werner Koch + + * dirmngr.c: Add option --ignore-cert-extension. + (parse_rereadable_options): Implement. + * dirmngr.h (opt): Add IGNORED_CERT_EXTENSIONS. + * validate.c (unknown_criticals): Handle ignored extensions. + +2009-12-08 Marcus Brinkmann + + * dirmngr-client.c (start_dirmngr): Convert posix FDs to assuan fds. + +2009-11-25 Marcus Brinkmann + + * server.c (start_command_handler): Use assuan_fd_t and + assuan_fdopen on fds. + +2009-11-05 Marcus Brinkmann + + * server.c (start_command_handler): Update use of + assuan_init_socket_server. + * dirmngr-client.c (start_dirmngr): Update use of + assuan_pipe_connect and assuan_socket_connect. + +2009-11-04 Werner Koch + + * server.c (register_commands): Add help arg to + assuan_register_command. Change all command comments to strings. + +2009-11-02 Marcus Brinkmann + + * server.c (reset_notify): Take LINE argument, return gpg_error_t. + +2009-10-16 Marcus Brinkmann + + * Makefile.am: (dirmngr_LDADD): Link to $(LIBASSUAN_LIBS) instead + of $(LIBASSUAN_PTH_LIBS). + * dirmngr.c: Invoke ASSUAN_SYSTEM_PTH_IMPL. + (main): Call assuan_set_system_hooks and assuan_sock_init. + +2009-09-22 Marcus Brinkmann + + * dirmngr.c (main): Update to new Assuan interface. + * server.c (option_handler, cmd_ldapserver, cmd_isvalid) + (cmd_checkcrl, cmd_checkocsp, cmd_lookup, cmd_loadcrl) + (cmd_listcrls, cmd_cachecert, cmd_validate): Return gpg_error_t + instead int. + (register_commands): Likewise for member HANDLER. + (start_command_handler): Allocate context with assuan_new before + starting server. Release on error. + * dirmngr-client.c (main): Update to new Assuan interface. + (start_dirmngr): Allocate context with assuan_new before + connecting to server. Release on error. + +2009-08-12 Werner Koch + + * dirmngr-client.c (squid_loop_body): Flush stdout. Suggested by + Philip Shin. + +2009-08-07 Werner Koch + + * crlfetch.c (my_es_read): Add explicit check for EOF. + + * http.c (struct http_context_s): Turn IN_DATA and IS_HTTP_0_9 to + bit fields. + (struct cookie_s): Add CONTENT_LENGTH_VALID and CONTENT_LENGTH. + (parse_response): Parse the Content-Length header. + (cookie_read): Handle content length. + (http_open): Make NEED_HEADER the semi-default. + + * http.h (HTTP_FLAG_IGNORE_CL): New. + +2009-08-04 Werner Koch + + * ldap.c (ldap_wrapper_thread): Factor some code out to ... + (read_log_data): ... new. Close the log fd on error. + (ldap_wrapper_thread): Delay cleanup until the log fd is closed. + (SAFE_PTH_CLOSE): New. Use it instead of pth_close. + +2009-07-31 Werner Koch + + * server.c (cmd_loadcrl): Add option --url. + * dirmngr-client.c (do_loadcrl): Make use of --url. + + * crlfetch.c (crl_fetch): Remove HTTP_FLAG_NO_SHUTDOWN. Add + flag HTTP_FLAG_LOG_RESP with active DBG_LOOKUP. + + * http.c: Require estream. Remove P_ES macro. + (write_server): Remove. + (my_read_line): Remove. Replace all callers by es_read_line. + (send_request): Use es_asprintf. Always store the cookie. + (http_wait_response): Remove the need to dup the socket. USe new + shutdown flag. + * http.h (HTTP_FLAG_NO_SHUTDOWN): Rename to HTTP_FLAG_SHUTDOWN. + + * estream.c, estream.h, estream-printf.c, estream-printf.h: Update + from current libestream. This is provide es_asprintf. + +2009-07-20 Werner Koch + + * dirmngr.c (pid_suffix_callback): New. + (main): Use log_set_pid_suffix_cb. + (start_connection_thread): Put the fd into the tls. + + * ldap.c (ldap_wrapper_thread): Print ldap worker stati. + (ldap_wrapper_release_context): Print a debug info. + (end_cert_fetch_ldap): Release the reader. Might fix bug#999. + +2009-06-17 Werner Koch + + * util.h: Remove unused dotlock.h. + +2009-05-26 Werner Koch + + * ldap.c (ldap_wrapper): Show reader object in diagnostics. + * crlcache.c (crl_cache_reload_crl): Ditto. Change debug messages + to regular diagnostics. + * dirmngr_ldap.c (print_ldap_entries): Add extra diagnostics. + +2009-04-03 Werner Koch + + * dirmngr.h (struct server_local_s): Move back to ... + * server.c (struct server_local_s): ... here. + (get_ldapservers_from_ctrl): New. + * ldapserver.h (ldapserver_iter_begin): Use it. + +2008-10-29 Marcus Brinkmann + + * estream.c (es_getline): Add explicit cast to silence gcc -W + warning. + * crlcache.c (finish_sig_check): Likewise. + + * dirmngr.c (opts): Add missing initializer to silence gcc + -W warning. + * server.c (register_commands): Likewise. + * dirmngr-client.c (opts): Likewise. + * dirmngr_ldap.c (opts): Likewise. + + * dirmngr-client.c (status_cb, inq_cert, data_cb): Change return + type to gpg_error_t to silence gcc warning. + +2008-10-21 Werner Koch + + * certcache.c (load_certs_from_dir): Accept ".der" files. + + * server.c (get_istrusted_from_client): New. + * validate.c (validate_cert_chain): Add new optional arg + R_TRUST_ANCHOR. Adjust all callers + * crlcache.c (crl_cache_entry_s): Add fields USER_TRUST_REQ + and CHECK_TRUST_ANCHOR. + (release_one_cache_entry): Release CHECK_TRUST_ANCHOR. + (list_one_crl_entry): Print info about the new fields. + (open_dir, write_dir_line_crl): Support the new U-flag. + (crl_parse_insert): Add arg R_TRUST_ANCHOR and set it accordingly. + (crl_cache_insert): Store trust anchor in entry object. + (cache_isvalid): Ask client for trust is needed. + + * crlcache.c (open_dir): Replace xcalloc by xtrycalloc. + (next_line_from_file): Ditt. Add arg to return the gpg error. + Change all callers. + (update_dir): Replace sprintf and malloc by estream_asprintf. + (crl_cache_insert): Ditto. + (crl_cache_isvalid): Replace xmalloc by xtrymalloc. + (get_auth_key_id): Ditto. + (crl_cache_insert): Ditto. + + * crlcache.c (start_sig_check): Remove HAVE_GCRY_MD_DEBUG test. + * validate.c (check_cert_sig): Ditto. Remove workaround for bug + in libgcrypt 1.2. + + * estream.c, estream.h, estream-printf.c, estream-printf.h: Update + from current libestream (svn rev 61). + +2008-09-30 Marcus Brinkmann + + * get-path.c (get_dirmngr_ldap_path): Revert last change. + Instead, use dirmngr_libexecdir(). + (find_program_at_standard_place): Don't define for now. + +2008-09-30 Marcus Brinkmann + + * get-path.c (dirmngr_cachedir): Make COMP a pointer to const to + silence gcc warning. + (get_dirmngr_ldap_path): Look for dirmngr_ldap in the installation + directory. + +2008-08-06 Marcus Brinkmann + + * dirmngr.c (main): Mark the ldapserverlist-file option as + read-only. + +2008-07-31 Werner Koch + + * crlcache.c (start_sig_check) [!HAVE_GCRY_MD_DEBUG]: Use + gcry_md_start_debug + +2008-06-16 Werner Koch + + * get-path.c (w32_commondir): New. + (dirmngr_sysconfdir): Use it here. + (dirmngr_datadir): Ditto. + +2008-06-12 Marcus Brinkmann + + * Makefile.am (dirmngr_SOURCES): Add ldapserver.h and ldapserver.c. + * ldapserver.h, ldapserver.c: New files. + * ldap.c: Include "ldapserver.h". + (url_fetch_ldap): Use iterator to get session servers as well. + (attr_fetch_ldap, start_default_fetch_ldap): Likewise. + * dirmngr.c: Include "ldapserver.h". + (free_ldapservers_list): Removed. Change callers to + ldapserver_list_free. + (parse_ldapserver_file): Use ldapserver_parse_one. + * server.c: Include "ldapserver.h". + (cmd_ldapserver): New command. + (register_commands): Add new command LDAPSERVER. + (reset_notify): New function. + (start_command_handler): Register reset notify handler. + Deallocate session server list. + (lookup_cert_by_pattern): Use iterator to get session servers as well. + (struct server_local_s): Move to ... + * dirmngr.h (struct server_local_s): ... here. Add new member + ldapservers. + +2008-06-10 Werner Koch + + Support PEM encoded CRLs. Fixes bug#927. + + * crlfetch.c (struct reader_cb_context_s): New. + (struct file_reader_map_s): Replace FP by new context. + (register_file_reader, get_file_reader): Adjust accordingly. + (my_es_read): Detect Base64 encoded CRL and decode if needed. + (crl_fetch): Pass new context to the callback. + (crl_close_reader): Cleanup the new context. + * b64dec.c: New. Taken from GnuPG. + * util.h (struct b64state): Add new fields STOP_SEEN and + INVALID_ENCODING. + +2008-05-26 Marcus Brinkmann + + * dirmngr.c (main) [HAVE_W32_SYSTEM]: Switch to system + configuration on gpgconf related commands, and make all options + unchangeable. + +2008-03-25 Marcus Brinkmann + + * dirmngr_ldap.c (print_ldap_entries): Add code alternative for + W32 console stdout (unused at this point). + +2008-03-21 Marcus Brinkmann + + * estream.c (ESTREAM_MUTEX_DESTROY): New macro. + (es_create, es_destroy): Use it. + +2008-02-21 Werner Koch + + * validate.c (check_cert_sig) [HAVE_GCRY_MD_DEBUG]: Use new debug + function if available. + + * crlcache.c (abort_sig_check): Mark unused arg. + + * exechelp.c (dirmngr_release_process) [!W32]: Mark unsed arg. + + * validate.c (is_root_cert): New. Taken from GnuPG. + (validate_cert_chain): Use it in place of the simple DN compare. + +2008-02-15 Marcus Brinkmann + + * dirmngr.c (main): Reinitialize assuan log stream if necessary. + + * crlcache.c (update_dir) [HAVE_W32_SYSTEM]: Remove destination + file before rename. + (crl_cache_insert) [HAVE_W32_SYSTEM]: Remove destination file + before rename. + +2008-02-14 Marcus Brinkmann + + * validate.c (check_cert_policy): Use ksba_free instead of xfree. + (validate_cert_chain): Likewise. Free SUBJECT on error. + (cert_usage_p): Likewise. + + * crlcache.c (finish_sig_check): Undo last change. + (finish_sig_check): Close md. + (abort_sig_check): New function. + (crl_parse_insert): Use abort_sig_check to clean up. + + * crlcache.c (crl_cache_insert): Clean up CDB on error. + +2008-02-13 Marcus Brinkmann + + * crlcache.c (finish_sig_check): Call gcry_md_stop_debug. + * exechelp.h (dirmngr_release_process): New prototype. + * exechelp.c (dirmngr_release_process): New function. + * ldap.c (ldap_wrapper_thread): Release pid. + (destroy_wrapper): Likewise. + + * dirmngr.c (launch_reaper_thread): Destroy tattr. + (handle_connections): Likewise. + +2008-02-12 Marcus Brinkmann + + * ldap.c (pth_close) [! HAVE_W32_SYSTEM]: New macro. + (struct wrapper_context_s): New member log_ev. + (destroy_wrapper): Check FDs for != -1 rather than != 0. Use + pth_close instead of close. Free CTX->log_ev. + (ldap_wrapper_thread): Rewritten to use pth_wait instead of + select. Also use pth_read instead of read and pth_close instead + of close. + (ldap_wrapper): Initialize CTX->log_ev. + (reader_callback): Use pth_close instead of close. + * exechelp.c (create_inheritable_pipe) [HAVE_W32_SYSTEM]: Removed. + (dirmngr_spawn_process) [HAVE_W32_SYSTEM]: Use pth_pipe instead. + * dirmngr_ldap.c [HAVE_W32_SYSTEM]: Include . + (main) [HAVE_W32_SYSTEM]: Set mode of stdout to binary. + +2008-02-01 Werner Koch + + * ldap.c: Remove all ldap headers as they are unused. + + * dirmngr_ldap.c (LDAP_DEPRECATED): New, to have OpenLDAP use the + old standard API. + +2008-01-10 Werner Koch + + * dirmngr-client.c: New option --local. + (do_lookup): Use it. + + * server.c (lookup_cert_by_pattern): Implement local lookup. + (return_one_cert): New. + * certcache.c (hexsn_to_sexp): New. + (classify_pattern, get_certs_bypattern): New. + + * misc.c (unhexify): Allow passing NULL for RESULT. + (cert_log_subject): Do not call ksba_free on an unused variable. + +2008-01-02 Marcus Brinkmann + + * Makefile.am (dirmngr_LDADD, dirmngr_ldap_LDADD) + (dirmngr_client_LDADD): Add $(LIBICONV). Reported by Michael + Nottebrock. + +2007-12-11 Werner Koch + + * server.c (option_handler): New option audit-events. + * dirmngr.h (struct server_control_s): Add member AUDIT_EVENTS. + +2007-11-26 Marcus Brinkmann + + * get-path.c (dirmngr_cachedir): Create intermediate directories. + (default_socket_name): Use CSIDL_WINDOWS. + +2007-11-21 Werner Koch + + * server.c (lookup_cert_by_pattern): Add args SINGLE and CACHE_ONLY. + (cmd_lookup): Add options --single and --cache-only. + +2007-11-16 Werner Koch + + * certcache.c (load_certs_from_dir): Also log the subject DN. + * misc.c (cert_log_subject): New. + +2007-11-14 Werner Koch + + * dirmngr-client.c: Replace --lookup-url by --url. + (main): Remove extra code for --lookup-url. + (do_lookup): Remove LOOKUP_URL arg and use the + global option OPT.URL. + + * server.c (has_leading_option): New. + (cmd_lookup): Use it. + + * crlfetch.c (fetch_cert_by_url): Use GPG_ERR_INV_CERT_OBJ. + (fetch_cert_by_url): Use gpg_error_from_syserror. + +2007-11-14 Moritz (wk) + + * dirmngr-client.c: New command: --lookup-url . + (do_lookup): New parameter: lookup_url. If TRUE, include "--url" + switch in LOOKUP transaction. + (enum): New entry: oLookupUrl. + (opts): Likewise. + (main): Handle oLookupUrl. New variable: cmd_lookup_url, set + during option parsing, pass to do_lookup() and substitute some + occurences of "cmd_lookup" with "cmd_lookup OR cmd_lookup_url". + * crlfetch.c (fetch_cert_by_url): New function, uses + url_fetch_ldap() to create a reader object and libksba functions + to read a single cert from that reader. + * server.c (lookup_cert_by_url, lookup_cert_by_pattern): New + functions. + (cmd_lookup): Moved almost complete code ... + (lookup_cert_by_pattern): ... here. + (cmd_lookup): Support new optional argument: --url. Depending on + the presence of that switch, call lookup_cert_by_url() or + lookup_cert_by_pattern(). + (lookup_cert_by_url): Heavily stripped down version of + lookup_cert_by_pattern(), using fetch_cert_by_url. + +2007-10-24 Marcus Brinkmann + + * exechelp.c (dirmngr_spawn_process): Fix child handles. + +2007-10-05 Marcus Brinkmann + + * dirmngr.h: Include assuan.h. + (start_command_handler): Change type of FD to assuan_fd_t. + * dirmngr.c: Do not include w32-afunix.h. + (socket_nonce): New global variable. + (create_server_socket): Use assuan socket wrappers. Remove W32 + specific stuff. Save the server nonce. + (check_nonce): New function. + (start_connection_thread): Call it. + (handle_connections): Change args to assuan_fd_t. + * server.c (start_command_handler): Change type of FD to assuan_fd_t. From cvs at cvs.gnupg.org Thu Jun 10 11:05:43 2010 From: cvs at cvs.gnupg.org (svn author wk) Date: Thu, 10 Jun 2010 11:05:43 +0200 Subject: [svn] gcry - r1433 - in trunk: cipher doc tests Message-ID: Author: wk Date: 2010-06-10 11:05:42 +0200 (Thu, 10 Jun 2010) New Revision: 1433 Modified: trunk/cipher/ChangeLog trunk/cipher/ecc.c trunk/doc/gcrypt.texi trunk/tests/ChangeLog trunk/tests/t-mpi-bit.c Log: Allow transient-key for ecdsa. Fix a bug in a test. Modified: trunk/cipher/ChangeLog =================================================================== --- trunk/cipher/ChangeLog 2010-04-27 03:04:56 UTC (rev 1432) +++ trunk/cipher/ChangeLog 2010-06-10 09:05:42 UTC (rev 1433) @@ -1,3 +1,9 @@ +2010-06-10 Jeff Johnson (wk) + + * ecc.c (ecc_generate_ext): Parse transient-key flag. + (generate_key): Add arg TRANSIENT_KEY and use it to set the random + level. + 2010-04-12 Brad Hards (wk) Spelling fixes. Modified: trunk/tests/ChangeLog =================================================================== --- trunk/tests/ChangeLog 2010-04-27 03:04:56 UTC (rev 1432) +++ trunk/tests/ChangeLog 2010-06-10 09:05:42 UTC (rev 1433) @@ -1,3 +1,7 @@ +2010-06-10 Werner Koch + + * t-mpi-bit.c (mpi2bitstr_nlz): Handle case for LENGTH==0. + 2010-04-12 Brad Hards (wk) * basic.c (check_cbc_mac_cipher): Print more info. Modified: trunk/cipher/ecc.c =================================================================== --- trunk/cipher/ecc.c 2010-04-27 03:04:56 UTC (rev 1432) +++ trunk/cipher/ecc.c 2010-06-10 09:05:42 UTC (rev 1433) @@ -1,5 +1,5 @@ /* ecc.c - Elliptic Curve Cryptography - Copyright (C) 2007, 2008 Free Software Foundation, Inc. + Copyright (C) 2007, 2008, 2010 Free Software Foundation, Inc. This file is part of Libgcrypt. @@ -504,6 +504,7 @@ */ static gpg_err_code_t generate_key (ECC_secret_key *sk, unsigned int nbits, const char *name, + int transient_key, gcry_mpi_t g_x, gcry_mpi_t g_y, gcry_mpi_t q_x, gcry_mpi_t q_y) { @@ -512,6 +513,7 @@ gcry_mpi_t d; mpi_point_t Q; mpi_ec_t ctx; + gcry_random_level_t random_level; err = generate_curve (nbits, name, &E, &nbits); if (err) @@ -528,9 +530,11 @@ log_mpidump ("ecc generation Gz", E.G.z); } + random_level = transient_key ? GCRY_STRONG_RANDOM : GCRY_VERY_STRONG_RANDOM; if (DBG_CIPHER) - log_debug ("choosing a random x of size %u\n", nbits); - d = gen_k (E.n, GCRY_VERY_STRONG_RANDOM); + log_debug ("choosing a random x of size %u%s\n", nbits, + transient_key? " (transient-key)":""); + d = gen_k (E.n, random_level); /* Compute Q. */ point_init (&Q); @@ -962,6 +966,7 @@ gcry_mpi_t g_x, g_y, q_x, q_y; char *curve_name = NULL; gcry_sexp_t l1; + int transient_key = 0; (void)algo; (void)evalue; @@ -978,6 +983,14 @@ if (!curve_name) return GPG_ERR_INV_OBJ; /* No curve name or value too large. */ } + + /* Parse the optional transient-key flag. */ + l1 = gcry_sexp_find_token (genparms, "transient-key", 0); + if (l1) + { + transient_key = 1; + gcry_sexp_release (l1); + } } /* NBITS is required if no curve name has been given. */ @@ -988,7 +1001,7 @@ g_y = mpi_new (0); q_x = mpi_new (0); q_y = mpi_new (0); - ec = generate_key (&sk, nbits, curve_name, g_x, g_y, q_x, q_y); + ec = generate_key (&sk, nbits, curve_name, transient_key, g_x, g_y, q_x, q_y); gcry_free (curve_name); if (ec) return ec; Modified: trunk/doc/gcrypt.texi =================================================================== --- trunk/doc/gcrypt.texi 2010-04-27 03:04:56 UTC (rev 1432) +++ trunk/doc/gcrypt.texi 2010-06-10 09:05:42 UTC (rev 1433) @@ -2736,10 +2736,10 @@ 15680 are valid as long as they are multiples of 8. @item transient-key -This is only meaningful for RSA and DSA keys. This is a flag with no -value. If given the RSA or DSA key is created using a faster and a -somewhat less secure random number generator. This flag may be used -for keys which are only used for a short time and do not require full +This is only meaningful for RSA, DSA and ECDSA keys. This is a flag +with no value. If given the key is created using a faster and a +somewhat less secure random number generator. This flag may be used for +keys which are only used for a short time and do not require full cryptographic strength. @item domain Modified: trunk/tests/t-mpi-bit.c =================================================================== --- trunk/tests/t-mpi-bit.c 2010-04-27 03:04:56 UTC (rev 1432) +++ trunk/tests/t-mpi-bit.c 2010-06-10 09:05:42 UTC (rev 1433) @@ -108,13 +108,20 @@ { char *p, *buf; size_t length = gcry_mpi_get_nbits (a); - - buf = p = xmalloc (length + 1); - while (length-- > 1) - *p++ = gcry_mpi_test_bit (a, length) ? '1':'0'; - *p++ = gcry_mpi_test_bit (a, 0) ? '1':'0'; + + if (!length) + { + buf = p = xmalloc (2); + *p++ = '0'; + } + else + { + buf = p = xmalloc (length + 1); + while (length-- > 1) + *p++ = gcry_mpi_test_bit (a, length) ? '1':'0'; + *p++ = gcry_mpi_test_bit (a, 0) ? '1':'0'; + } *p = 0; - return buf; } @@ -190,7 +197,7 @@ gcry_mpi_release (a); } -/* Check that the shifting actually works for an amount larger than +/* Check that right shifting actually works for an amount larger than the number of bits per limb. */ static void test_rshift (int pass) @@ -249,7 +256,7 @@ gcry_mpi_release (a); } -/* Check that the left shifting. */ +/* Check that left shifting works correctly. */ static void test_lshift (int pass) { From cvs at cvs.gnupg.org Thu Jun 10 11:06:47 2010 From: cvs at cvs.gnupg.org (svn author wk) Date: Thu, 10 Jun 2010 11:06:47 +0200 Subject: [svn] gcry - r1434 - branches/LIBGCRYPT-1-4-BRANCH/tests Message-ID: Author: wk Date: 2010-06-10 11:06:46 +0200 (Thu, 10 Jun 2010) New Revision: 1434 Modified: branches/LIBGCRYPT-1-4-BRANCH/tests/ChangeLog branches/LIBGCRYPT-1-4-BRANCH/tests/t-mpi-bit.c Log: Fix a test. Reported by Jeff Johnson. Modified: branches/LIBGCRYPT-1-4-BRANCH/tests/ChangeLog =================================================================== --- branches/LIBGCRYPT-1-4-BRANCH/tests/ChangeLog 2010-06-10 09:05:42 UTC (rev 1433) +++ branches/LIBGCRYPT-1-4-BRANCH/tests/ChangeLog 2010-06-10 09:06:46 UTC (rev 1434) @@ -1,3 +1,7 @@ +2010-06-10 Werner Koch + + * t-mpi-bit.c (mpi2bitstr_nlz): Handle case for LENGTH==0. + 2009-01-22 Werner Koch * cavs_tests.sh: Pass option -D to driver if required. Modified: branches/LIBGCRYPT-1-4-BRANCH/tests/t-mpi-bit.c =================================================================== --- branches/LIBGCRYPT-1-4-BRANCH/tests/t-mpi-bit.c 2010-06-10 09:05:42 UTC (rev 1433) +++ branches/LIBGCRYPT-1-4-BRANCH/tests/t-mpi-bit.c 2010-06-10 09:06:46 UTC (rev 1434) @@ -108,13 +108,20 @@ { char *p, *buf; size_t length = gcry_mpi_get_nbits (a); - - buf = p = xmalloc (length + 1); - while (length-- > 1) - *p++ = gcry_mpi_test_bit (a, length) ? '1':'0'; - *p++ = gcry_mpi_test_bit (a, 0) ? '1':'0'; + + if (!length) + { + buf = p = xmalloc (2); + *p++ = '0'; + } + else + { + buf = p = xmalloc (length + 1); + while (length-- > 1) + *p++ = gcry_mpi_test_bit (a, length) ? '1':'0'; + *p++ = gcry_mpi_test_bit (a, 0) ? '1':'0'; + } *p = 0; - return buf; } @@ -190,7 +197,7 @@ gcry_mpi_release (a); } -/* Check that the shifting actually works for an amount larger than +/* Check that right shifting actually works for an amount larger than the number of bits per limb. */ static void test_rshift (int pass) @@ -249,7 +256,7 @@ gcry_mpi_release (a); } -/* Check that the left shifting. */ +/* Check that left shifting works correctly. */ static void test_lshift (int pass) { From cvs at cvs.gnupg.org Thu Jun 10 12:39:45 2010 From: cvs at cvs.gnupg.org (svn author wk) Date: Thu, 10 Jun 2010 12:39:45 +0200 Subject: [svn] GnuPG - r5352 - trunk/doc Message-ID: Author: wk Date: 2010-06-10 12:39:44 +0200 (Thu, 10 Jun 2010) New Revision: 5352 Added: trunk/doc/dirmngr.texi Modified: trunk/doc/ChangeLog trunk/doc/Makefile.am trunk/doc/contrib.texi trunk/doc/gnupg.texi trunk/doc/gnupg7.texi trunk/doc/gpg-agent.texi trunk/doc/instguide.texi trunk/doc/tools.texi Log: Include dirmngr manual Modified: trunk/doc/ChangeLog =================================================================== --- trunk/doc/ChangeLog 2010-06-09 16:53:51 UTC (rev 5351) +++ trunk/doc/ChangeLog 2010-06-10 10:39:44 UTC (rev 5352) @@ -1,3 +1,16 @@ +2010-06-10 Werner Koch + + * Makefile.am (gnupg_TEXINFOS): Add dirmngr.texi. + (myman_sources): Ditto. + (myman_pages): Add dirmngr and dirmngr-client pages. + (noinst_MANS): Move gnupg.7 to man_MANS. + + * gnupg.texi: Include dirmngr.texi and add a menu entry. + * dirmngr.texi: New. Taken from the current SVN of the dirmngr + package and adjusted to fit into the GnuPG manual. Moved + dirmngr-cleint stuff to ... + * tools.texi (dirmngr-client): ... new. + 2009-11-18 Werner Koch * gpg.texi (GPG Key related Options): Describe Modified: trunk/doc/Makefile.am =================================================================== --- trunk/doc/Makefile.am 2010-06-09 16:53:51 UTC (rev 5351) +++ trunk/doc/Makefile.am 2010-06-10 10:39:44 UTC (rev 5352) @@ -52,7 +52,7 @@ gnupg_TEXINFOS = \ gpg.texi gpgsm.texi gpg-agent.texi scdaemon.texi instguide.texi \ tools.texi debugging.texi glossary.texi contrib.texi gpl.texi \ - sysnotes.texi gnupg-card-architecture.fig \ + sysnotes.texi gnupg-card-architecture.fig dirmngr.texi \ howtos.texi howto-create-a-server-cert.texi DVIPS = TEXINPUTS="$(srcdir)$(PATH_SEPARATOR)$$TEXINPUTS" dvips @@ -63,14 +63,14 @@ --release "GnuPG @PACKAGE_VERSION@" --source "GNU Privacy Guard" myman_sources = gnupg7.texi gpg.texi gpgsm.texi gpg-agent.texi \ - scdaemon.texi tools.texi -myman_pages = gpg2.1 gpgsm.1 gpg-agent.1 scdaemon.1 gpgv2.1 \ + dirmngr.texi scdaemon.texi tools.texi +myman_pages = gpg2.1 gpgsm.1 gpg-agent.1 dirmngr.8 scdaemon.1 gpgv2.1 \ watchgnupg.1 gpgconf.1 addgnupghome.8 gpg-preset-passphrase.1 \ gpg-connect-agent.1 gpgparsemail.1 symcryptrun.1 \ - gpgsm-gencert.sh.1 applygnupgdefaults.8 gpg-zip.1 + gpgsm-gencert.sh.1 applygnupgdefaults.8 gpg-zip.1 \ + dirmngr-client.1 -man_MANS = $(myman_pages) -noinst_MANS = gnupg.7 +man_MANS = $(myman_pages) gnupg.7 watchgnupg_SOURCE = gnupg.texi Modified: trunk/doc/contrib.texi =================================================================== --- trunk/doc/contrib.texi 2010-06-09 16:53:51 UTC (rev 5351) +++ trunk/doc/contrib.texi 2010-06-10 10:39:44 UTC (rev 5352) @@ -97,7 +97,7 @@ This software has been made possible by the previous work of Chris Wedgwood, Jean-loup Gailly, Jon Callas, Mark Adler, Martin Hellmann Paul Kendall, Philip R. Zimmermann, Peter Gutmann, Philip A. Nelson, -Taher ElGamal, Torbjorn Granlund, Whitfield Diffie, some unknown NSA +Taher Elgamal, Torbjorn Granlund, Whitfield Diffie, some unknown NSA mathematicians and all the folks who have worked hard to create complete and free operating systems. Added: trunk/doc/dirmngr.texi =================================================================== --- trunk/doc/dirmngr.texi (rev 0) +++ trunk/doc/dirmngr.texi 2010-06-10 10:39:44 UTC (rev 5352) @@ -0,0 +1,788 @@ + at c Copyright (C) 2002 Klar"alvdalens Datakonsult AB + at c Copyright (C) 2004, 2005, 2006, 2007 g10 Code GmbH + at c This is part of the GnuPG manual. + at c For copying conditions, see the file gnupg.texi. + + at node Invoking DIRMNGR + at chapter Invoking DIRMNGR + at cindex DIRMNGR command options + at cindex command options + at cindex options, DIRMNGR command + + at manpage dirmngr.8 + at ifset manverb +.B dirmngr +\- CRL and OCSP daemon + at end ifset + + at mansect synopsis + at ifset manverb +.B dirmngr +.RI [ options ] +.I command +.RI [ args ] + at end ifset + + at mansect description +Dirmngr is a server for managing and downloading certificate revocation +lists (CRLs) for X.509 certificates and for downloading the certificates +themselves. Dirmngr also handles OCSP requests as an alternative to +CRLs. Dirmngr is either invoked internally by gpgsm or when running as a +system daemon through the @command{dirmngr-client} tool. + +If @command{dirmngr} is started in system daemon mode, it uses a +directory layout as common for system daemons and does not make use of +the default @file{~/.gnupg} directory. + + + at manpause + at noindent + at xref{Option Index},for an index to @command{DIRMNGR}'s commands and +options. + at mancont + + at menu +* Dirmngr Commands:: List of all commands. +* Dirmngr Options:: List of all options. +* Dirmngr Configuration:: Configuration files. +* Dirmngr Signals:: Use of signals. +* Dirmngr Examples:: Some usage examples. +* Dirmngr Protocol:: The protocol dirmngr uses. + at end menu + + + at node Dirmngr Commands + at section Commands + at mansect commands + +Commands are not distinguished from options except for the fact that +only one command is allowed. + + at table @gnupgtabopt + at item --version + at opindex version +Print the program version and licensing information. Note that you cannot +abbreviate this command. + + at item --help, -h + at opindex help +Print a usage message summarizing the most useful command-line options. +Not that you cannot abbreviate this command. + + at item --dump-options + at opindex dump-options +Print a list of all available options and commands. Note that you cannot +abbreviate this command. + + at item --server + at opindex server +Run in server mode and wait for commands on the @code{stdin}. The +default mode is to create a socket and listen for commands there. + + at item --daemon + at opindex daemon +Run in background daemon mode and listen for commands on a socket. +Note that this also changes the default home directory and enables the +internal certificate validation code. + + at item --list-crls + at opindex list-crls +List the contents of the CRL cache on @code{stdout}. This is probably +only useful for debugging purposes. + + at item --load-crl @var{file} + at opindex load-crl +This command requires a filename as additional argument, and it will +make Dirmngr try to import the CRL in @var{file} into it's cache. +Note, that this is only possible if Dirmngr is able to retrieve the +CA's certificate directly by its own means. In general it is better +to use @code{gpgsm}'s @code{--call-dirmngr loadcrl filename} command +so that @code{gpgsm} can help dirmngr. + + at item --fetch-crl @var{url} + at opindex fetch-crl +This command requires an URL as additional argument, and it will make +dirmngr try to retrieve an import the CRL from that @var{url} into +it's cache. This is mainly useful for debugging purposes. The + at command{dirmngr-client} provides the same feature for a running dirmngr. + + at item --shutdown + at opindex shutdown +This commands shuts down an running instance of Dirmngr. This command +has currently no effect. + + at item --flush + at opindex flush +This command removes all CRLs from Dirmngr's cache. Client requests +will thus trigger reading of fresh CRLs. + + at end table + + + at mansect options + at node Dirmngr Options + at section Option Summary + + at table @gnupgtabopt + + at item --options @var{file} + at opindex options +Reads configuration from @var{file} instead of from the default +per-user configuration file. The default configuration file is named + at file{dirmngr.conf} and expected in the home directory. + + at item --homedir @var{dir} + at opindex options +Set the name of the home directory to @var{dir}. This option is only +effective when used on the command line. The default depends on the +running mode: + + at table @asis + + at item With @code{--daemon} given on the commandline +the directory named @file{/etc/gnupg} for configuration files, + at file{/var/lib/gnupg/} for extra data and @file{/var/cache/gnupg} +for cached CRLs. + + at item Without @code{--daemon} given on the commandline +the directory named @file{.gnupg} directly below the home directory +of the user unless the environment variable @code{GNUPGHOME} has been set +in which case its value will be used. All kind of data is stored below +this directory. + at end table + + + at item -v + at item --verbose + at opindex v + at opindex verbose +Outputs additional information while running. +You can increase the verbosity by giving several +verbose commands to @sc{dirmngr}, such as @option{-vv}. + + + at item --log-file @var{file} + at opindex log-file +Append all logging output to @var{file}. This is very helpful in +seeing what the agent actually does. + + at item --debug-level @var{level} + at opindex debug-level +Select the debug level for investigating problems. @var{level} may be a +numeric value or by a keyword: + + at table @code + at item none +No debugging at all. A value of less than 1 may be used instead of +the keyword. + at item basic +Some basic debug messages. A value between 1 and 2 may be used +instead of the keyword. + at item advanced +More verbose debug messages. A value between 3 and 5 may be used +instead of the keyword. + at item expert +Even more detailed messages. A value between 6 and 8 may be used +instead of the keyword. + at item guru +All of the debug messages you can get. A value greater than 8 may be +used instead of the keyword. The creation of hash tracing files is +only enabled if the keyword is used. + at end table + +How these messages are mapped to the actual debugging flags is not +specified and may change with newer releases of this program. They are +however carefully selected to best aid in debugging. + + at item --debug @var{flags} + at opindex debug +This option is only useful for debugging and the behaviour may change at +any time without notice. FLAGS are bit encoded and may be given in +usual C-Syntax. + + at item --debug-all + at opindex debug-all +Same as @code{--debug=0xffffffff} + + at item --debug-wait @var{n} + at opindex debug-wait +When running in server mode, wait @var{n} seconds before entering the +actual processing loop and print the pid. This gives time to attach a +debugger. + + at item -s + at itemx --sh + at itemx -c + at itemx --csh + at opindex s + at opindex sh + at opindex c + at opindex csh +Format the info output in daemon mode for use with the standard Bourne +shell respective the C-shell . The default ist to guess it based on the +environment variable @code{SHELL} which is in almost all cases +sufficient. + + at item --force + at opindex force +Enabling this option forces loading of expired CRLs; this is only +useful for debugging. + + at item --disable-ldap + at opindex disable-ldap +Entirely disables the use of LDAP. + + at item --disable-http + at opindex disable-http +Entirely disables the use of HTTP. + + at item --ignore-http-dp + at opindex ignore-http-dp +When looking for the location of a CRL, the to be tested certificate +usually contains so called @dfn{CRL Distribution Point} (DP) entries +which are URLs describing the way to access the CRL. The first found DP +entry is used. With this option all entries using the @acronym{HTTP} +scheme are ignored when looking for a suitable DP. + + at item --ignore-ldap-dp + at opindex ignore-ldap-dp +This is similar to @option{--ignore-http-dp} but ignores entries using +the @acronym{LDAP} scheme. Both options may be combined resulting in +ignoring DPs entirely. + + at item --ignore-ocsp-service-url + at opindex ignore-ocsp-service-url +Ignore all OCSP URLs contained in the certificate. The effect is to +force the use of the default responder. + + at item --honor-http-proxy + at opindex honor-http-proxy +If the environment variable @env{http_proxy} has been set, use its +value to access HTTP servers. + + at item --http-proxy @var{host}[:@var{port}] + at opindex http-proxy +Use @var{host} and @var{port} to access HTTP servers. The use of this +options overrides the environment variable @env{http_proxy} regardless +whether @option{--honor-http-proxy} has been set. + + + at item --ldap-proxy @var{host}[:@var{port}] + at opindex ldap-proxy +Use @var{host} and @var{port} to connect to LDAP servers. If @var{port} +is ommitted, port 389 (standard LDAP port) is used. This overrides any +specified host and port part in a LDAP URL and will also be used if host +and port have been ommitted from the URL. + + at item --only-ldap-proxy + at opindex only-ldap-proxy +Never use anything else but the LDAP "proxy" as configured with + at option{--ldap-proxy}. Usually @command{dirmngr} tries to use other +configured LDAP server if the connection using the "proxy" failed. + + + at item --ldapserverlist-file @var{file} + at opindex ldapserverlist-file +Read the list of LDAP servers to consult for CRLs and certificates from +file instead of the default per-user ldap server list file. The default +value for @var{file} is @file{dirmngr_ldapservers.conf} or + at file{ldapservers.conf} when running in @option{--daemon} mode. + +This server list file contains one LDAP server per line in the format + + at sc{hostname:port:username:password:base_dn} + +Lines starting with a @samp{#} are comments. + +Note that as usual all strings entered are expected to be UTF-8 encoded. +Obviously this will lead to problems if the password has orginally been +encoded as Latin-1. There is no other solution here than to put such a +password in the binary encoding into the file (i.e. non-ascii characters +won't show up readable). at footnote{The @command{gpgconf} tool might be +helpful for frontends as it allows to edit this configuration file using +percent escaped strings.} + + + at item --ldaptimeout @var{secs} + at opindex ldaptimeout +Specify the number of seconds to wait for an LDAP query before timing +out. The default is currently 100 seconds. 0 will never timeout. + + + at item --add-servers + at opindex add-servers +This options makes dirmngr add any servers it discovers when validating +certificates against CRLs to the internal list of servers to consult for +certificates and CRLs. + +This options is useful when trying to validate a certificate that has +a CRL distribution point that points to a server that is not already +listed in the ldapserverlist. Dirmngr will always go to this server and +try to download the CRL, but chances are high that the certificate used +to sign the CRL is located on the same server. So if dirmngr doesn't add +that new server to list, it will often not be able to verify the +signature of the CRL unless the @code{--add-servers} option is used. + +Note: The current version of dirmngr has this option disabled by default. + + + at item --allow-ocsp + at opindex allow-ocsp +This option enables OCSP support if requested by the client. + +OCSP requests are rejected by default because they may violate the +privacy of the user; for example it is possible to track the time when +a user is reading a mail. + + + at item --ocsp-responder @var{url} + at opindex ocsp-responder +Use @var{url} as the default OCSP Responder if the certificate does +not contain information about an assigned responder. Note, that + at code{--ocsp-signer} must also be set to a valid certificate. + + at item --ocsp-signer @var{fpr}|@var{file} + at opindex ocsp-signer +Use the certificate with the fingerprint @var{fpr} to check the +responses of the default OCSP Responder. Alternativly a filename can be +given in which case the respinse is expected to be signed by one of the +certificates described in that file. Any argument which contains a +slash, dot or tilde is considered a filename. Usual filename expansion +takes place: A tilde at the start followed by a slash is replaced by the +content of @env{HOME}, no slash at start describes a relative filename +which will be searched at the home directory. To make sure that the + at var{file} is searched in the home directory, either prepend the name +with "./" or use a name which contains a dot. + +If a response has been signed by a certificate described by these +fingerprints no further check upon the validity of this certificate is +done. + +The format of the @var{FILE} is a list of SHA-1 fingerprint, one per +line with optional colons between the bytes. Empty lines and lines +prefix with a hash mark are ignored. + + + at item --ocsp-max-clock-skew @var{n} + at opindex ocsp-max-clock-skew +The number of seconds a skew between the OCSP responder and them local +clock is accepted. Default is 600 (20 minutes). + + at item --ocsp-max-period @var{n} + at opindex ocsp-max-period +Seconds a response is at maximum considered valid after the time given +in the thisUpdate field. Default is 7776000 (90 days). + + at item --ocsp-current-period @var{n} + at opindex ocsp-current-period +The number of seconds an OCSP response is considered valid after the +time given in the NEXT_UPDATE datum. Default is 10800 (3 hours). + + + at item --max-replies @var{n} + at opindex max-replies +Do not return more that @var{n} items in one query. The default is +10. + + at item --ignore-cert-extension @var{oid} + at opindex ignore-cert-extension +Add @var{oid} to the list of ignored certificate extensions. The + at var{oid} is expected to be in dotted decimal form, like + at code{2.5.29.3}. This option may be used more than once. Critical +flagged certificate extensions matching one of the OIDs in the list +are treated as if they are actually handled and thus the certificate +won't be rejected due to an unknown critical extension. Use this +option with care because extensions are usually flagged as critical +for a reason. + + at end table + + + at c + at c Dirmngr Configuration + at c + at mansect files + at node Dirmngr Configuration + at section Configuration + +Dirmngr makes use of several directories when running in daemon mode: + + at table @file + + at item /etc/gnupg +This is where all the configuration files are expected by default. + + at item /etc/gnupg/trusted-certs +This directory should be filled with certificates of Root CAs you are +trusting in checking the CRLS and signing OCSP Reponses. Usually +these are the same certificates you use with the applications making +use of dirmngr. It is expected that each of these certificate files +contain exactly one @acronym{DER} encoded certificate in a file with +the suffix @file{.crt} or @file{.der}. @command{dirmngr} reads those +certificates on startup and when given a SIGHUP. Certificates which +are not readable or do not make up a proper X.509 certificate are +ignored; see the log file for details. + +Note that for OCSP responses the certificate specified using the option + at option{--ocsp-signer} is always considered valid to sign OCSP requests. + + + at item /var/lib/gnupg/extra-certs +This directory may contain extra certificates which are preloaded into +the interal cache on startup. This is convenient in cases you have a +couple intermediate CA certificates or certificates ususally used to +sign OCSP reponses. These certificates are first tried before going out +to the net to look for them. These certificates must also be + at acronym{DER} encoded and suffixed with @file{.crt} or @file{.der}. + + at item /var/run/gnupg +This directory keeps the socket file for accsing @command{dirmngr} services. +The name of the socket file will be @file{S.dirmngr}. Make sure that this +directory has the proper permissions to let @command{dirmngr} create the +socket file and that eligible users may read and write to that socket. + + at item /var/cache/gnupg/crls.d +This directory is used to store cached CRLs. The @file{crls.d} part +will be created by dirmngr if it does not exists but you need to make +sure that the upper directory exists. + + at end table + at manpause + +To be able to see what's going on you should create the configure file + at file{/etc/dirmngr/dirmngr.conf} with at least one line: + + at example +log-file /var/log/gnupg/dirmngr.log + at end example + +To be able to perform OCSP requests you probably want to add the line: + + at example +allow-ocsp + at end example + +Now you may start dirmngr as a system daemon using: + + at example +dirmngr --daemon + at end example + +Please ignore the output; it is not needed anymore. Check the log file +to see whether all trusted root certificates have benn loaded correctly. + + + at c + at c Dirmngr Signals + at c + at mansect signals + at node Dirmngr Signals + at section Use of signals. + +A running @command{dirmngr} may be controlled by signals, i.e. using +the @command{kill} command to send a signal to the process. + +Here is a list of supported signals: + + at table @gnupgtabopt + + at item SIGHUP + at cpindex SIGHUP +This signals flushes all internally cached CRLs as well as any cached +certificates. Then the certificate cache is reinitialized as on +startup. Options are re-read from the configuration file. + + at item SIGTERM + at cpindex SIGTERM +Shuts down the process but waits until all current requests are +fulfilled. If the process has received 3 of these signals and requests +are still pending, a shutdown is forced. + + at item SIGINT + at cpindex SIGINT +Shuts down the process immediately. + + + at item SIGUSR1 + at cpindex SIGUSR1 +This prints some caching statistics to the log file. + + at end table + + + + at c + at c Examples + at c + at mansect examples + at node Dirmngr Examples + at section Examples + + +The way to start the dirmngr in the foreground (as done by tools if no +dirmngr is running in the background) is to use: + + at example + dirmngr --server -v + at end example + +If a dirmngr is supposed to be used as a system wide daemon, it should +be started like: + + at example + dirmngr --daemon + at end example + +This will force it to go into the backround, read the default +certificates (including the trusted root certificates) and listen on a +socket for client requests. It does also print information about the +socket used but they are only for compatibilty reasons with old GnuPG +versions and may be ignored. + + + at c + at c Assuan Protocol + at c + at manpause + at node Dirmngr Protocol + at section Dirmngr's Assuan Protocol + +Assuan is the IPC protocol used to access dirmngr. This is a +description of the commands implemented by dirmngr. + + at menu +* Dirmngr LOOKUP:: Look up a certificate via LDAP +* Dirmngr ISVALID:: Validate a certificate using a CRL or OCSP. +* Dirmngr CHECKCRL:: Validate a certificate using a CRL. +* Dirmngr CHECKOCSP:: Validate a certificate using OCSP. +* Dirmngr CACHECERT:: Put a certificate into the internal cache. +* Dirmngr VALIDATE:: Validate a certificate for debugging. + at end menu + + at node Dirmngr LOOKUP + at subsection Return the certificate(s) found + +Lookup certificate. To allow multiple patterns (which are ORed) +quoting is required: Spaces are to be translated into "+" or into +"%20"; obviously this requires that the usual escape quoting rules +are applied. The server responds with: + + at example + S: D + S: END + S: D + S: END + S: OK + at end example + +In this example 2 certificates are returned. The server may return +any number of certificates; OK will also be returned when no +certificates were found. The dirmngr might return a status line + + at example + S: S TRUNCATED + at end example + + +To indicate that the output was truncated to N items due to a +limitation of the server or by an arbitrary set limit. + +The option @option{--url} may be used if instead of a search pattern a +complete URL to the certificate is known: + + at example + C: LOOKUP --url CN%3DWerner%20Koch,o%3DIntevation%20GmbH,c%3DDE?userCertificate + at end example + +If the option @option{--cache-only} is given, no external lookup is done +so that only certificates from the cache are returned. + +With the option @option{--single}, the first and only the first match +will be returned. Unless option @option{--cache-only} is also used, no +local lookup will be done in this case. + + + + at node Dirmngr ISVALID + at subsection Validate a certificate using a CRL or OCSP + + at example + ISVALID [--only-ocsp] [--force-default-responder] @var{certid}|@var{certfpr} + at end example + +Check whether the certificate described by the @var{certid} has been +revoked. Due to caching, the Dirmngr is able to answer immediately in +most cases. + +The @var{certid} is a hex encoded string consisting of two parts, +delimited by a single dot. The first part is the SHA-1 hash of the +issuer name and the second part the serial number. + +Alternatively the certificate's SHA-1 fingerprint @var{certfpr} may be +given in which case an OCSP request is done before consulting the CRL. +If the option @option{--only-ocsp} is given, no fallback to a CRL check +will be used. If the option @option{--force-default-responder} is +given, only the default OCSP responder will be used and any other +methods of obtaining an OCSP responder URL won't be used. + + at noindent +Common return values are: + + at table @code + at item GPG_ERR_NO_ERROR (0) +This is the positive answer: The certificate is not revoked and we have +an up-to-date revocation list for that certificate. If OCSP was used +the responder confirmed that the certificate has not been revoked. + + at item GPG_ERR_CERT_REVOKED +This is the negative answer: The certificate has been revoked. Either +it is in a CRL and that list is up to date or an OCSP responder informed +us that it has been revoked. + + at item GPG_ERR_NO_CRL_KNOWN +No CRL is known for this certificate or the CRL is not valid or out of +date. + + at item GPG_ERR_NO_DATA +The OCSP responder returned an ``unknown'' status. This means that it +is not aware of the certificate's status. + + at item GPG_ERR_NOT_SUPPORTED +This is commonly seen if OCSP support has not been enabled in the +configuration. + at end table + +If DirMngr has not enough information about the given certificate (which +is the case for not yet cached certificates), it will will inquire the +missing data: + + at example + S: INQUIRE SENDCERT + C: D + C: END + at end example + +A client should be aware that DirMngr may ask for more than one +certificate. + +If Dirmngr has a certificate but the signature of the certificate +could not been validated because the root certificate is not known to +dirmngr as trusted, it may ask back to see whether the client trusts +this the root certificate: + + at example + S: INQUIRE ISTRUSTED + C: D 1 + C: END + at end example + +Only this answer will let Dirmngr consider the CRL as valid. + + + at node Dirmngr CHECKCRL + at subsection Validate a certificate using a CRL + +Check whether the certificate with FINGERPRINT (SHA-1 hash of the +entire X.509 certificate blob) is valid or not by consulting the CRL +responsible for this certificate. If the fingerprint has not been +given or the certificate is not know, the function inquires the +certificate using: + + at example + S: INQUIRE TARGETCERT + C: D + C: END + at end example + +Thus the caller is expected to return the certificate for the request +(which should match FINGERPRINT) as a binary blob. Processing then +takes place without further interaction; in particular dirmngr tries +to locate other required certificate by its own mechanism which +includes a local certificate store as well as a list of trusted root +certificates. + + at noindent +The return code is 0 for success; i.e. the certificate has not been +revoked or one of the usual error codes from libgpg-error. + + at node Dirmngr CHECKOCSP + at subsection Validate a certificate using OCSP + + at example + CHECKOCSP [--force-default-responder] [@var{fingerprint}] + at end example + +Check whether the certificate with @var{fingerprint} (the SHA-1 hash of +the entire X.509 certificate blob) is valid by consulting the appropiate +OCSP responder. If the fingerprint has not been given or the +certificate is not known by Dirmngr, the function inquires the +certificate using: + + at example + S: INQUIRE TARGETCERT + C: D + C: END + at end example + +Thus the caller is expected to return the certificate for the request +(which should match @var{fingerprint}) as a binary blob. Processing +then takes place without further interaction; in particular dirmngr +tries to locate other required certificates by its own mechanism which +includes a local certificate store as well as a list of trusted root +certificates. + +If the option @option{--force-default-responder} is given, only the +default OCSP responder is used. This option is the per-command variant +of the global option @option{--ignore-ocsp-service-url}. + + + at noindent +The return code is 0 for success; i.e. the certificate has not been +revoked or one of the usual error codes from libgpg-error. + + at node Dirmngr CACHECERT + at subsection Put a certificate into the internal cache + +Put a certificate into the internal cache. This command might be +useful if a client knows in advance certificates required for a test and +wnats to make sure they get added to the internal cache. It is also +helpful for debugging. To get the actual certificate, this command +immediately inquires it using + + at example + S: INQUIRE TARGETCERT + C: D + C: END + at end example + +Thus the caller is expected to return the certificate for the request +as a binary blob. + + at noindent +The return code is 0 for success; i.e. the certificate has not been +succesfully cached or one of the usual error codes from libgpg-error. + + at node Dirmngr VALIDATE + at subsection Validate a certificate for debugging + +Validate a certificate using the certificate validation function used +internally by dirmngr. This command is only useful for debugging. To +get the actual certificate, this command immediately inquires it using + + at example + S: INQUIRE TARGETCERT + C: D + C: END + at end example + +Thus the caller is expected to return the certificate for the request +as a binary blob. + + + at mansect see also + at ifset isman + at command{gpgsm}(1), + at command{dirmngr-client}(1) + at end ifset + at include see-also-note.texi + Modified: trunk/doc/gnupg.texi =================================================================== --- trunk/doc/gnupg.texi 2010-06-09 16:53:51 UTC (rev 5351) +++ trunk/doc/gnupg.texi 2010-06-10 10:39:44 UTC (rev 5352) @@ -50,6 +50,9 @@ @direntry * gpg2: (gnupg). OpenPGP encryption and signing tool. * gpgsm: (gnupg). S/MIME encryption and signing tool. +* gpg-agent: (gnupg). The secret key daemon. +* dirmngr: (gnupg). X.509 CRL and OCSP server. +* dirmngr-client: (gnupg). X.509 CRL and OCSP client. @end direntry @@ -121,6 +124,7 @@ * Installation:: A short installation guide. * Invoking GPG-AGENT:: How to launch the secret key daemon. +* Invoking DIRMNGR:: How to launch the CRL and OCSP daemon. * Invoking GPG:: Using the OpenPGP protocol. * Invoking GPGSM:: Using the S/MIME protocol. * Invoking SCDAEMON:: How to handle Smartcards. @@ -152,6 +156,7 @@ @include instguide.texi @include gpg-agent.texi + at include dirmngr.texi @include gpg.texi @include gpgsm.texi @include scdaemon.texi @@ -194,6 +199,18 @@ @c Epilogue @c --------------------------------------------------------------------- + at c @node History + at c @unnumbered History + at c + at c Here are the notices from the old dirmngr manual: + at c + at c @itemize + at c @item Using DirMngr, 2002, Steffen Hansen, Klar"alvdalens Datakonsult AB. + at c @item Using DirMngr, 2004, 2005, 2006, 2008 Werner Koch, g10 Code GmbH. + at c @end itemize + at c + + @bye Modified: trunk/doc/gnupg7.texi =================================================================== --- trunk/doc/gnupg7.texi 2010-06-09 16:53:51 UTC (rev 5351) +++ trunk/doc/gnupg7.texi 2010-06-10 10:39:44 UTC (rev 5352) @@ -23,6 +23,7 @@ @command{gpgv}(1), @command{gpgsm}(1), @command{gpg-agent}(1), + at command{dirmngr}(8), @command{scdaemon}(1) @include see-also-note.texi @end ifset Modified: trunk/doc/gpg-agent.texi =================================================================== --- trunk/doc/gpg-agent.texi 2010-06-09 16:53:51 UTC (rev 5351) +++ trunk/doc/gpg-agent.texi 2010-06-10 10:39:44 UTC (rev 5352) @@ -136,18 +136,18 @@ @table @gnupgtabopt @item --version @opindex version -Print the program version and licensing information. Not that you can +Print the program version and licensing information. Note that you cannot abbreviate this command. @item --help @itemx -h @opindex help Print a usage message summarizing the most useful command-line options. -Not that you can abbreviate this command. +Note that you cannot abbreviate this command. @item --dump-options @opindex dump-options -Print a list of all available options and commands. Not that you can +Print a list of all available options and commands. Note that you cannot abbreviate this command. @item --server Modified: trunk/doc/instguide.texi =================================================================== --- trunk/doc/instguide.texi 2010-06-09 16:53:51 UTC (rev 5351) +++ trunk/doc/instguide.texi 2010-06-10 10:39:44 UTC (rev 5352) @@ -6,7 +6,6 @@ @node Installation @chapter A short installation guide. - Unfortunately the installation guide has not been finished in time. Instead of delaying the release of GnuPG 2.0 even further, I decided to release without that guide. The chapter on gpg-agent and gpgsm do @@ -16,6 +15,31 @@ gnupg-users mailing listsfor advise on how to solve problems or how to get that whole thing up and running. +** Building the software + +Building the software is decribed in the file @file{INSTALL}. Given +that you are already reading this documentation we can only give some +extra hints + +To comply with the rules on GNU systems you should have build time +configured @command{dirmngr} using: + + at example +./configure --sysconfdir=/etc --localstatedir=/var + at end example + +This is to make sure that system wide configuration files are searched +in the directory @file{/etc/gnupg} and variable data below @file{/var}; +the default would be to also install them below @file{/usr/local} where +the binaries get installed. If you selected to use the + at option{--prefix=/} you obviously don't need those option as they are +the default then. + + + +** Explain how to setup a root CA key as trusted + + Such questions may also help to write a proper installation guide. [to be written] Modified: trunk/doc/tools.texi =================================================================== --- trunk/doc/tools.texi 2010-06-09 16:53:51 UTC (rev 5351) +++ trunk/doc/tools.texi 2010-06-10 10:39:44 UTC (rev 5352) @@ -16,6 +16,7 @@ * gpgsm-gencert.sh:: Generate an X.509 certificate request. * gpg-preset-passphrase:: Put a passphrase into the cache. * gpg-connect-agent:: Communicate with a running agent. +* dirmngr-client:: How to use the Dirmngr client tool. * gpgparsemail:: Parse a mail message into an annotated format * symcryptrun:: Call a simple symmetric encryption tool. * gpg-zip:: Encrypt or sign files into an archive. @@ -1381,7 +1382,168 @@ @include see-also-note.texi @end ifset + at c + at c DIRMNGR-CLIENT + at c + at node dirmngr-client + at section The Dirmngr Client Tool + at manpage dirmngr-client.1 + at ifset manverb +.B dirmngr-client +\- Tool to access the Dirmngr services + at end ifset + + at mansect synopsis + at ifset manverb +.B dirmngr-client +.RI [ options ] +.RI [ certfile | pattern ] + at end ifset + + at mansect description +The @command{dirmngr-client} is a simple tool to contact a running +dirmngr and test whether a certificate has been revoked --- either by +being listed in the corresponding CRL or by running the OCSP protocol. +If no dirmngr is running, a new instances will be started but this is +in general not a good idea due to the huge performance overhead. + + at noindent +The usual way to run this tool is either: + + at example +dirmngr-client @var{acert} + at end example + + at noindent +or + + at example +dirmngr-client <@var{acert} + at end example + +Where @var{acert} is one DER encoded (binary) X.509 certificates to be +tested. + at ifclear isman +The return value of this command is + at end ifclear + + at mansect return value + at ifset isman + at command{dirmngr-client} returns these values: + at end ifset + at table @code + + at item 0 +The certificate under question is valid; i.e. there is a valid CRL +available and it is not listed tehre or teh OCSP request returned that +that certificate is valid. + + at item 1 +The certificate has been revoked + + at item 2 (and other values) +There was a problem checking the revocation state of the certificate. +A message to stderr has given more detailed information. Most likely +this is due to a missing or expired CRL or due to a network problem. + + at end table + + at mansect options + at noindent + at command{dirmngr-client} may be called with the following options: + + + at table @gnupgtabopt + at item --version + at opindex version +Print the program version and licensing information. Note that you cannot +abbreviate this command. + + at item --help, -h + at opindex help +Print a usage message summarizing the most useful command-line options. +Note that you cannot abbreviate this command. + + at item --quiet, -q + at opindex quiet +Make the output extra brief by suppressing any informational messages. + + at item -v + at item --verbose + at opindex v + at opindex verbose +Outputs additional information while running. +You can increase the verbosity by giving several +verbose commands to @sc{dirmngr}, such as @samp{-vv}. + + at item --pem + at opindex pem +Assume that the given certificate is in PEM (armored) format. + + at item --ocsp + at opindex ocsp +Do the check using the OCSP protocol and ignore any CRLs. + + at item --force-default-responder + at opindex force-default-responder +When checking using the OCSP protocl, force the use of the default OCSP +responder. That is not to use the Reponder as given by the certificate. + + at item --ping + at opindex ping +Check whether the dirmngr daemon is up and running. + + at item --cache-cert + at opindex cache-cert +Put the given certificate into the cache of a running dirmngr. This is +mainly useful for debugging. + + at item --validate + at opindex validate +Validate the given certificate using dirmngr's internal validation code. +This is mainly useful for debugging. + + at item --load-crl + at opindex load-crl +This command expects a list of filenames with DER encoded CRL files. +With the option @option{--url} URLs are expected in place of filenames +and they are loaded directly from the given location. All CRLs will be +validated and then loaded into dirmngr's cache. + + at item --lookup + at opindex lookup +Take the remaining arguments and run a lookup command on each of them. +The results are Base-64 encoded outputs (without header lines). This +may be used to retrieve certificates from a server. However the output +format is not very well suited if more than one certificate is returned. + + at item --url + at itemx -u + at opindex url +Modify the @command{lookup} and @command{load-crl} commands to take an URL. + + at item --local + at itemx -l + at opindex url +Let the @command{lookup} command only search the local cache. + + at item --squid-mode + at opindex squid-mode +Run @sc{dirmngr-client} in a mode suitable as a helper program for +Squid's @option{external_acl_type} option. + + + at end table + + at ifset isman + at mansect see also + at command{dirmngr}(8), + at command{gpgsm}(1) + at include see-also-note.texi + at end ifset + + @c @c GPGPARSEMAIL @c From cvs at cvs.gnupg.org Thu Jun 10 15:41:12 2010 From: cvs at cvs.gnupg.org (svn author marcus) Date: Thu, 10 Jun 2010 15:41:12 +0200 Subject: [svn] gpgme - r1477 - trunk/src Message-ID: Author: marcus Date: 2010-06-10 15:41:12 +0200 (Thu, 10 Jun 2010) New Revision: 1477 Modified: trunk/src/w32-glib-io.c Log: * debug.h (TRACE_SUC6): New macro. Modified: trunk/src/w32-glib-io.c =================================================================== --- trunk/src/w32-glib-io.c 2010-06-09 13:33:31 UTC (rev 1476) +++ trunk/src/w32-glib-io.c 2010-06-10 13:41:12 UTC (rev 1477) @@ -110,7 +110,7 @@ static GIOChannel * find_channel (int fd) { - if (fd < 0 || fd >= MAX_SLAFD) + if (fd < 0 || fd >= MAX_SLAFD || !giochannel_table[fd].used) return NULL; return giochannel_table[fd].chan; From cvs at cvs.gnupg.org Thu Jun 10 15:49:20 2010 From: cvs at cvs.gnupg.org (svn author marcus) Date: Thu, 10 Jun 2010 15:49:20 +0200 Subject: [svn] gpgme - r1478 - trunk/src Message-ID: Author: marcus Date: 2010-06-10 15:49:19 +0200 (Thu, 10 Jun 2010) New Revision: 1478 Modified: trunk/src/ChangeLog trunk/src/debug.h trunk/src/w32-io.c Log: 2010-06-10 Marcus Brinkmann * debug.h (TRACE_SUC6): New macro. * w32-io.c (MAX_SLAFD): New macro. (fd_table): New static variable. (new_fd, release_fd): New functions. (fd_to_handle, handle_to_fd, handle_to_socket): Remove macros. (MAX_READERS, MAX_WRITERS): Increase to 64. (notify_table): Increase to MAX_SLAFD. (struct reader_context_s, struct writer_context_s): Add member file_sock. (reader, writer): Use file_hd vs file_sock to decide if socket operations to use. Remove auto-detect mode. (create_reader, create_writer): Set file_sock. Unblock pending thread only if this is a pipe fd. (_gpgme_io_pipe): Allocate fds from table and return slot indices instead of windows handles. This allows to properly handle RVIDs. (_gpgme_io_close): Handle dup'ed file descriptors. (build_commandline) [HAVE_W32_SYSTEM]: Use RVID from fd table now. (_gpgme_io_spawn): Use fd table now. (_gpgme_io_fd2str): Use RVID from fd table now. (_gpgme_io_dup): Implement using fd table. (_gpgme_io_socket): Allocate fds from table. (_gpgme_io_connect): Use fd from table. Modified: trunk/src/ChangeLog =================================================================== --- trunk/src/ChangeLog 2010-06-10 13:41:12 UTC (rev 1477) +++ trunk/src/ChangeLog 2010-06-10 13:49:19 UTC (rev 1478) @@ -1,3 +1,30 @@ +2010-06-10 Marcus Brinkmann + + * debug.h (TRACE_SUC6): New macro. + * w32-io.c (MAX_SLAFD): New macro. + (fd_table): New static variable. + (new_fd, release_fd): New functions. + (fd_to_handle, handle_to_fd, handle_to_socket): Remove macros. + (MAX_READERS, MAX_WRITERS): Increase to 64. + (notify_table): Increase to MAX_SLAFD. + (struct reader_context_s, struct writer_context_s): Add member + file_sock. + (reader, writer): Use file_hd vs file_sock to decide if socket + operations to use. Remove auto-detect mode. + (create_reader, create_writer): Set file_sock. Unblock pending + thread only if this is a pipe fd. + (_gpgme_io_pipe): Allocate fds from table and return slot indices + instead of windows handles. This allows to properly handle RVIDs. + (_gpgme_io_close): Handle dup'ed file descriptors. + (build_commandline) [HAVE_W32_SYSTEM]: Use RVID from fd table now. + (_gpgme_io_spawn): Use fd table now. + (_gpgme_io_fd2str): Use RVID from fd table now. + (_gpgme_io_dup): Implement using fd table. + (_gpgme_io_socket): Allocate fds from table. + (_gpgme_io_connect): Use fd from table. + + * w32-glib-io.c (find_channel): Check that the slot is used. + 2010-06-09 Marcus Brinkmann * w32-io.c [HAVE_W32CE_SYSTEM]: Include assuan.h and winioctl.h. Modified: trunk/src/debug.h =================================================================== --- trunk/src/debug.h 2010-06-10 13:41:12 UTC (rev 1477) +++ trunk/src/debug.h 2010-06-10 13:49:19 UTC (rev 1478) @@ -204,6 +204,10 @@ _gpgme_debug (_gpgme_trace_level, "%s: leave: " fmt "\n", \ _gpgme_trace_func, arg1, arg2, arg3, arg4, arg5), \ _gpgme_debug_frame_end (), 0 +#define TRACE_SUC6(fmt, arg1, arg2, arg3, arg4, arg5, arg6) \ + _gpgme_debug (_gpgme_trace_level, "%s: leave: " fmt "\n", \ + _gpgme_trace_func, arg1, arg2, arg3, arg4, arg5, arg6), \ + _gpgme_debug_frame_end (), 0 #define TRACE_LOG(fmt) \ _gpgme_debug (_gpgme_trace_level, "%s: check: %s=%p, " fmt "\n", \ Modified: trunk/src/w32-io.c =================================================================== --- trunk/src/w32-io.c 2010-06-10 13:41:12 UTC (rev 1477) +++ trunk/src/w32-io.c 2010-06-10 13:49:19 UTC (rev 1478) @@ -46,22 +46,87 @@ #include "debug.h" -/* We assume that a HANDLE can be represented by an int which should - be true for all i386 systems (HANDLE is defined as void *) and - these are the only systems for which Windows is available. Further - we assume that -1 denotes an invalid handle. */ +/* FIXME: Optimize. */ +#define MAX_SLAFD 512 -#define fd_to_handle(a) ((HANDLE)(a)) -#define handle_to_fd(a) ((int)(a)) +static struct +{ + int used; + + /* If this is not INVALID_HANDLE_VALUE, then it's a handle. */ + HANDLE handle; + + /* If this is not INVALID_SOCKET, then it's a Windows socket. */ + int socket; + + /* If this is not 0, then it's a rendezvous ID for the pipe server. */ + int rvid; + + /* DUP_FROM is -1 if this file descriptor was allocated by pipe or + socket functions. Only then should the handle or socket be + destroyed when this FD is closed. This, together with the fact + that dup'ed file descriptors are closed before the file + descriptors from which they are dup'ed are closed, ensures that + the handle or socket is always valid, and shared among all file + descriptors refering to the same underlying object. + + The logic behind this is that there is only one reason for us to + dup file descriptors anyway: to allow simpler book-keeping of + file descriptors shared between GPGME and libassuan, which both + want to close something. Using the same handle for these + duplicates works just fine. */ + int dup_from; +} fd_table[MAX_SLAFD]; + + +/* Returns the FD or -1 on resource limit. */ +int +new_fd (void) +{ + int idx; + + for (idx = 0; idx < MAX_SLAFD; idx++) + if (! fd_table[idx].used) + break; + + if (idx == MAX_SLAFD) + { + gpg_err_set_errno (EIO); + return -1; + } + + fd_table[idx].used = 1; + fd_table[idx].handle = INVALID_HANDLE_VALUE; + fd_table[idx].socket = INVALID_SOCKET; + fd_table[idx].rvid = 0; + fd_table[idx].dup_from = -1; + + return idx; +} + + +void +release_fd (int fd) +{ + if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used) + return; + + fd_table[fd].used = 0; + fd_table[fd].handle = INVALID_HANDLE_VALUE; + fd_table[fd].socket = INVALID_SOCKET; + fd_table[fd].rvid = 0; + fd_table[fd].dup_from = -1; +} + + #define pid_to_handle(a) ((HANDLE)(a)) #define handle_to_pid(a) ((int)(a)) -#define handle_to_socket(a) ((unsigned int)(a)) #define READBUF_SIZE 4096 #define WRITEBUF_SIZE 4096 #define PIPEBUF_SIZE 4096 -#define MAX_READERS 40 -#define MAX_WRITERS 40 +#define MAX_READERS 64 +#define MAX_WRITERS 64 static struct { @@ -69,13 +134,14 @@ int fd; _gpgme_close_notify_handler_t handler; void *value; -} notify_table[256]; +} notify_table[MAX_SLAFD]; DEFINE_STATIC_LOCK (notify_table_lock); struct reader_context_s { HANDLE file_hd; + int file_sock; HANDLE thread_hd; int refcount; @@ -110,6 +176,7 @@ struct writer_context_s { HANDLE file_hd; + int file_sock; HANDLE thread_hd; int refcount; @@ -229,7 +296,10 @@ TRACE_BEG1 (DEBUG_SYSIO, "gpgme:reader", ctx->file_hd, "thread=%p", ctx->thread_hd); - sock = is_socket (ctx->file_hd); + if (ctx->file_hd != INVALID_HANDLE_VALUE) + sock = 0; + else + sock = 1; for (;;) { @@ -260,25 +330,13 @@ TRACE_LOG2 ("%s %d bytes", sock? "receiving":"reading", nbytes); - if (sock == -1 || sock == 1) + if (sock) { int n; - n = recv (handle_to_socket (ctx->file_hd), - ctx->buffer + ctx->writepos, nbytes, 0); + n = recv (ctx->file_sock, ctx->buffer + ctx->writepos, nbytes, 0); if (n < 0) { - if (sock == -1) - { - if (WSAGetLastError () == WSAENOTSOCK) - { - sock = 0; - goto try_readfile; - } - else - sock = 1; - } - ctx->error_code = (int) WSAGetLastError (); if (ctx->error_code == ERROR_BROKEN_PIPE) { @@ -296,7 +354,6 @@ } else { - try_readfile: if (!ReadFile (ctx->file_hd, ctx->buffer + ctx->writepos, nbytes, &nread, NULL)) { @@ -348,7 +405,7 @@ static struct reader_context_s * -create_reader (HANDLE fd) +create_reader (int fd) { struct reader_context_s *ctx; SECURITY_ATTRIBUTES sec_attr; @@ -367,7 +424,14 @@ return NULL; } - ctx->file_hd = fd; + if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used) + { + TRACE_SYSERR (EIO); + return NULL; + } + ctx->file_hd = fd_table[fd].handle; + ctx->file_sock = fd_table[fd].socket; + ctx->refcount = 1; ctx->have_data_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL); if (ctx->have_data_ev) @@ -440,11 +504,14 @@ reading. Then we need to unblock the reader in the pipe driver to make our reader thread notice that we want it to go away. */ - if (!DeviceIoControl (ctx->file_hd, GPGCEDEV_IOCTL_UNBLOCK, + if (ctx->file_hd != INVALID_HANDLE_VALUE) + { + if (!DeviceIoControl (ctx->file_hd, GPGCEDEV_IOCTL_UNBLOCK, NULL, 0, NULL, 0, NULL, NULL)) - { - TRACE1 (DEBUG_SYSIO, "gpgme:destroy_reader", ctx->file_hd, - "unblock control call failed for thread %p", ctx->thread_hd); + { + TRACE1 (DEBUG_SYSIO, "gpgme:destroy_reader", ctx->file_hd, + "unblock control call failed for thread %p", ctx->thread_hd); + } } #endif @@ -491,7 +558,7 @@ if (i != reader_table_size) { - rd = create_reader (fd_to_handle (fd)); + rd = create_reader (fd); if (rd) { reader_table[i].fd = fd; @@ -614,7 +681,10 @@ TRACE_BEG1 (DEBUG_SYSIO, "gpgme:writer", ctx->file_hd, "thread=%p", ctx->thread_hd); - sock = is_socket (ctx->file_hd); + if (ctx->file_hd != INVALID_HANDLE_VALUE) + sock = 0; + else + sock = 1; for (;;) { @@ -648,27 +718,15 @@ /* Note that CTX->nbytes is not zero at this point, because _gpgme_io_write always writes at least 1 byte before waking us up, unless CTX->stop_me is true, which we catch above. */ - if (sock == -1 || sock == 1) + if (sock) { /* We need to try send first because a socket handle can't be used with WriteFile. */ int n; - n = send (handle_to_socket (ctx->file_hd), - ctx->buffer, ctx->nbytes, 0); + n = send (ctx->file_sock, ctx->buffer, ctx->nbytes, 0); if (n < 0) { - if (sock == -1) - { - if (WSAGetLastError () == WSAENOTSOCK) - { - sock = 0; - goto try_writefile; - } - else - sock = 1; - } - ctx->error_code = (int) WSAGetLastError (); ctx->error = 1; TRACE_LOG1 ("send error: ec=%d", ctx->error_code); @@ -678,7 +736,6 @@ } else { - try_writefile: if (!WriteFile (ctx->file_hd, ctx->buffer, ctx->nbytes, &nwritten, NULL)) { @@ -711,7 +768,7 @@ static struct writer_context_s * -create_writer (HANDLE fd) +create_writer (int fd) { struct writer_context_s *ctx; SECURITY_ATTRIBUTES sec_attr; @@ -730,7 +787,14 @@ return NULL; } - ctx->file_hd = fd; + if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used) + { + TRACE_SYSERR (EIO); + return NULL; + } + ctx->file_hd = fd_table[fd].handle; + ctx->file_sock = fd_table[fd].socket; + ctx->refcount = 1; ctx->have_data = CreateEvent (&sec_attr, TRUE, FALSE, NULL); if (ctx->have_data) @@ -853,7 +917,7 @@ if (i != writer_table_size) { - wt = create_writer (fd_to_handle (fd)); + wt = create_writer (fd); if (wt) { writer_table[i].fd = fd; @@ -969,22 +1033,39 @@ int _gpgme_io_pipe (int filedes[2], int inherit_idx) { - HANDLE rh; - HANDLE wh; - + int rfd; + int wfd; #ifdef HAVE_W32CE_SYSTEM HANDLE hd; int rvid; +#else + HANDLE rh; + HANDLE wh; + SECURITY_ATTRIBUTES sec_attr; +#endif TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes, "inherit_idx=%i (GPGME uses it for %s)", inherit_idx, inherit_idx ? "reading" : "writing"); + rfd = new_fd (); + if (rfd == -1) + return TRACE_SYSRES (-1); + wfd = new_fd (); + if (wfd == -1) + { + release_fd (rfd); + return TRACE_SYSRES (-1); + } + +#ifdef HAVE_W32CE_SYSTEM hd = _assuan_w32ce_prepare_pipe (&rvid, !inherit_idx); if (hd == INVALID_HANDLE_VALUE) { TRACE_LOG1 ("_assuan_w32ce_prepare_pipe failed: ec=%d", (int) GetLastError ()); + release_fd (rfd); + release_fd (wfd); /* FIXME: Should translate the error code. */ gpg_err_set_errno (EIO); return TRACE_SYSRES (-1); @@ -992,18 +1073,16 @@ if (inherit_idx == 0) { - /* FIXME: For now. We need to detect them at close. */ - rh = (void*) ((rvid << 1) | 1); - wh = hd; + fd_table[rfd].rvid = rvid; + fd_table[wfd].handle = hd; } else { - rh = hd; - /* FIXME: For now. We need to detect them at close. */ - wh = (void*) ((rvid << 1) | 1); + fd_table[rfd].handle = hd; + fd_table[wfd].rvid = rvid; } + #else - SECURITY_ATTRIBUTES sec_attr; memset (&sec_attr, 0, sizeof (sec_attr)); sec_attr.nLength = sizeof (sec_attr); @@ -1012,6 +1091,8 @@ if (!CreatePipe (&rh, &wh, &sec_attr, PIPEBUF_SIZE)) { TRACE_LOG1 ("CreatePipe failed: ec=%d", (int) GetLastError ()); + release_fd (rfd); + release_fd (wfd); /* FIXME: Should translate the error code. */ gpg_err_set_errno (EIO); return TRACE_SYSRES (-1); @@ -1027,6 +1108,8 @@ { TRACE_LOG1 ("DuplicateHandle failed: ec=%d", (int) GetLastError ()); + release_fd (rfd); + release_fd (wfd); CloseHandle (rh); CloseHandle (wh); /* FIXME: Should translate the error code. */ @@ -1045,6 +1128,8 @@ { TRACE_LOG1 ("DuplicateHandle failed: ec=%d", (int) GetLastError ()); + release_fd (rfd); + release_fd (wfd); CloseHandle (rh); CloseHandle (wh); /* FIXME: Should translate the error code. */ @@ -1054,20 +1139,25 @@ CloseHandle (wh); wh = hd; } + fd_table[rfd].handle = rh; + fd_table[wfd].handle = wh; #endif if (inherit_idx == 0) { struct writer_context_s *ctx; - ctx = find_writer (handle_to_fd (wh), 0); + ctx = find_writer (wfd, 0); assert (ctx == NULL); - ctx = find_writer (handle_to_fd (wh), 1); + ctx = find_writer (wfd, 1); if (!ctx) { -#ifndef HAVE_W32CE_SYSTEM - CloseHandle (rh); -#endif - CloseHandle (wh); + /* No way/need to close RVIDs on Windows CE. */ + if (fd_table[rfd].handle) + CloseHandle (fd_table[rfd].handle); + if (fd_table[wfd].handle) + CloseHandle (fd_table[wfd].handle); + release_fd (rfd); + release_fd (wfd); /* FIXME: Should translate the error code. */ gpg_err_set_errno (EIO); return TRACE_SYSRES (-1); @@ -1076,24 +1166,29 @@ else if (inherit_idx == 1) { struct reader_context_s *ctx; - ctx = find_reader (handle_to_fd (rh), 0); + ctx = find_reader (rfd, 0); assert (ctx == NULL); - ctx = find_reader (handle_to_fd (rh), 1); + ctx = find_reader (rfd, 1); if (!ctx) { - CloseHandle (rh); -#ifndef HAVE_W32CE_SYSTEM - CloseHandle (wh); -#endif + if (fd_table[rfd].handle) + CloseHandle (fd_table[rfd].handle); + /* No way/need to close RVIDs on Windows CE. */ + if (fd_table[wfd].handle) + CloseHandle (fd_table[wfd].handle); + release_fd (rfd); + release_fd (wfd); /* FIXME: Should translate the error code. */ gpg_err_set_errno (EIO); return TRACE_SYSRES (-1); } } - filedes[0] = handle_to_fd (rh); - filedes[1] = handle_to_fd (wh); - return TRACE_SUC2 ("read=%p, write=%p", rh, wh); + filedes[0] = rfd; + filedes[1] = wfd; + return TRACE_SUC6 ("read=0x%x (%p/0x%x), write=0x%x (%p/0x%x)", + rfd, fd_table[rfd].handle, fd_table[rfd].rvid, + wfd, fd_table[wfd].handle, fd_table[wfd].rvid); } @@ -1103,6 +1198,7 @@ int i; _gpgme_close_notify_handler_t handler = NULL; void *value = NULL; + TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd); if (fd == -1) @@ -1110,13 +1206,12 @@ gpg_err_set_errno (EBADF); return TRACE_SYSRES (-1); } + if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used) + { + gpg_err_set_errno (EBADF); + return TRACE_SYSRES (-1); + } -#ifdef HAVE_W32CE_SYSTEM - /* FIXME: For now: This is a rendezvous id. */ - if (fd & 1) - return TRACE_SYSRES (0); -#endif - kill_reader (fd); kill_writer (fd); LOCK (notify_table_lock); @@ -1136,14 +1231,33 @@ if (handler) handler (fd, value); - if (!CloseHandle (fd_to_handle (fd))) - { - TRACE_LOG1 ("CloseHandle failed: ec=%d", (int) GetLastError ()); - /* FIXME: Should translate the error code. */ - gpg_err_set_errno (EIO); - return TRACE_SYSRES (-1); + if (fd_table[fd].dup_from == -1) + { + if (fd_table[fd].handle != INVALID_HANDLE_VALUE) + { + if (!CloseHandle (fd_table[fd].handle)) + { + TRACE_LOG1 ("CloseHandle failed: ec=%d", (int) GetLastError ()); + /* FIXME: Should translate the error code. */ + gpg_err_set_errno (EIO); + return TRACE_SYSRES (-1); + } + } + else if (fd_table[fd].socket != INVALID_SOCKET) + { + if (closesocket (fd_table[fd].socket)) + { + TRACE_LOG1 ("closesocket failed: ec=%d", (int) WSAGetLastError ()); + /* FIXME: Should translate the error code. */ + gpg_err_set_errno (EIO); + return TRACE_SYSRES (-1); + } + } + /* Nothing to do for RVIDs. */ } + release_fd (fd); + return TRACE_SYSRES (0); } @@ -1188,6 +1302,7 @@ return 0; } + #ifdef HAVE_W32CE_SYSTEM static char * build_commandline (char **argv, int fd0, int fd0_isnull, @@ -1202,42 +1317,28 @@ p = fdbuf; *p = 0; - strcpy (p, "-&S0=null "); - p += strlen (p); if (fd0 != -1) { - /* FIXME */ - if (fd0 & 1) - fd0 = fd0 >> 1; - if (fd0_isnull) strcpy (p, "-&S0=null "); else - snprintf (p, 25, "-&S0=%d ", (int)fd0); + snprintf (p, 25, "-&S0=%d ", fd_table[fd0].rvid); p += strlen (p); } if (fd1 != -1) { - /* FIXME */ - if (fd1 & 1) - fd1 = fd1 >> 1; - if (fd1_isnull) strcpy (p, "-&S1=null "); else - snprintf (p, 25, "-&S1=%d ", (int)fd1); + snprintf (p, 25, "-&S1=%d ", fd_table[fd1].rvid); p += strlen (p); } if (fd2 != -1) { - /* FIXME */ - if (fd2 & 1) - fd2 = fd2 >> 1; - if (fd2_isnull) strcpy (p, "-&S2=null "); else - snprintf (p, 25, "-&S2=%d ", (int)fd2); + snprintf (p, 25, "-&S2=%d ", fd_table[fd2].rvid); p += strlen (p); } strcpy (p, "-&S2=null "); @@ -1378,7 +1479,22 @@ for (i = 0; fd_list[i].fd != -1; i++) { - TRACE_LOG3 ("fd_list[%2i] = fd %i, dup_to %i", i, fd_list[i].fd, fd_list[i].dup_to); + int fd = fd_list[i].fd; + + TRACE_LOG3 ("fd_list[%2i] = fd %i, dup_to %i", i, fd, fd_list[i].dup_to); + if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used) + { + TRACE_LOG1 ("invalid fd 0x%x", fd); + gpg_err_set_errno (EBADF); + return TRACE_SYSRES (-1); + } + if (fd_table[fd].rvid == 0) + { + TRACE_LOG1 ("fd 0x%x not inheritable (not an RVID)", fd); + gpg_err_set_errno (EBADF); + return TRACE_SYSRES (-1); + } + if (fd_list[i].dup_to == 0) { fd_in = fd_list[i].fd; @@ -1428,7 +1544,7 @@ for (i = 0; fd_list[i].fd != -1; i++) { /* Return the child name of this handle. */ - fd_list[i].peer_name = fd_list[i].fd; + fd_list[i].peer_name = fd_table[fd_list[i].fd].rvid; } #else @@ -1749,6 +1865,7 @@ else if (code == WAIT_FAILED) { int le = (int) GetLastError (); +#if 0 if (le == ERROR_INVALID_HANDLE) { int k; @@ -1765,6 +1882,7 @@ } TRACE_LOG (" oops, or not???"); } +#endif TRACE_LOG1 ("WFMO failed: %d", le); count = -1; } @@ -1813,9 +1931,11 @@ { #ifdef HAVE_W32CE_SYSTEM /* FIXME: For now. See above. */ - if (fd & 1) - fd = fd >> 1; - /* FIXME: The real problems start if fd is not of this type! */ + if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used + || fd_table[fd].rvid == 0) + fd = -1; + else + fd = fd_table[fd].rvid; #endif return snprintf (buf, buflen, "%d", fd); @@ -1825,28 +1945,28 @@ int _gpgme_io_dup (int fd) { -#ifdef HAVE_W32CE_SYSTEM - gpg_err_set_errno (EIO); - return -1; -#else - HANDLE handle = fd_to_handle (fd); - HANDLE new_handle = fd_to_handle (fd); - int i; + int newfd; struct reader_context_s *rd_ctx; struct writer_context_s *wt_ctx; + int i; TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_dup", fd); - if (!DuplicateHandle (GetCurrentProcess(), handle, - GetCurrentProcess(), &new_handle, - 0, FALSE, DUPLICATE_SAME_ACCESS)) + if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used) { - TRACE_LOG1 ("DuplicateHandle failed: ec=%d\n", (int) GetLastError ()); - /* FIXME: Translate error code. */ - gpg_err_set_errno (EIO); + gpg_err_set_errno (EINVAL); return TRACE_SYSRES (-1); } + newfd = new_fd(); + if (newfd == -1) + return TRACE_SYSRES (-1); + + fd_table[newfd].handle = fd_table[fd].handle; + fd_table[newfd].socket = fd_table[fd].socket; + fd_table[newfd].rvid = fd_table[fd].rvid; + fd_table[newfd].dup_from = fd; + rd_ctx = find_reader (fd, 0); if (rd_ctx) { @@ -1860,7 +1980,7 @@ break; /* FIXME. */ assert (i != reader_table_size); - reader_table[i].fd = handle_to_fd (new_handle); + reader_table[i].fd = newfd; reader_table[i].context = rd_ctx; reader_table[i].used = 1; UNLOCK (reader_table_lock); @@ -1879,14 +1999,13 @@ break; /* FIXME. */ assert (i != writer_table_size); - writer_table[i].fd = handle_to_fd (new_handle); + writer_table[i].fd = newfd; writer_table[i].context = wt_ctx; writer_table[i].used = 1; UNLOCK (writer_table_lock); } - return TRACE_SYSRES (handle_to_fd (new_handle)); -#endif + return TRACE_SYSRES (newfd); } @@ -1931,18 +2050,25 @@ _gpgme_io_socket (int domain, int type, int proto) { int res; + int fd; TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_socket", domain, "type=%i, protp=%i", type, proto); + fd = new_fd(); + if (fd == -1) + return TRACE_SYSRES (-1); + res = socket (domain, type, proto); if (res == INVALID_SOCKET) { + release_fd (fd); gpg_err_set_errno (wsa2errno (WSAGetLastError ())); return TRACE_SYSRES (-1); } + fd_table[fd].socket = res; - TRACE_SUC1 ("socket=0x%x", res); + TRACE_SUC2 ("socket=0x%x (0x%x)", fd, fd_table[fd].socket); return res; } @@ -1956,7 +2082,13 @@ TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd, "addr=%p, addrlen=%i", addr, addrlen); - res = connect (fd, addr, addrlen); + if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used) + { + gpg_err_set_errno (EBADF); + return TRACE_SYSRES (-1); + } + + res = connect (fd_table[fd].socket, addr, addrlen); if (res) { gpg_err_set_errno (wsa2errno (WSAGetLastError ())); From cvs at cvs.gnupg.org Thu Jun 10 17:08:29 2010 From: cvs at cvs.gnupg.org (svn author marcus) Date: Thu, 10 Jun 2010 17:08:29 +0200 Subject: [svn] GnuPG - r5353 - trunk/sm Message-ID: Author: marcus Date: 2010-06-10 17:08:29 +0200 (Thu, 10 Jun 2010) New Revision: 5353 Modified: trunk/sm/server.c Log: common/ 2010-06-10 Marcus Brinkmann * estream.c (_es_get_std_stream): Fix cut&paste bug. sm/ 2010-06-10 Marcus Brinkmann * server.c (SERVER_STDIN, SERVER_STDOUT): New macros. (gpgsm_server): Use them with assuan_fdopen. Modified: trunk/sm/server.c =================================================================== --- trunk/sm/server.c 2010-06-10 10:39:44 UTC (rev 5352) +++ trunk/sm/server.c 2010-06-10 15:08:29 UTC (rev 5353) @@ -1249,8 +1249,15 @@ /* We use a pipe based server so that we can work from scripts. assuan_init_pipe_server will automagically detect when we are called with a socketpair and ignore FILEDES in this case. */ - filedes[0] = assuan_fdopen (0); - filedes[1] = assuan_fdopen (1); +#ifdef HAVE_W32CE_SYSTEM + #define SERVER_STDIN es_fileno(es_stdin) + #define SERVER_STDOUT es_fileno(es_stdout) +#else +#define SERVER_STDIN 0 +#define SERVER_STDOUT 1 +#endif + filedes[0] = assuan_fdopen (SERVER_STDIN); + filedes[1] = assuan_fdopen (SERVER_STDOUT); rc = assuan_new (&ctx); if (rc) { From cvs at cvs.gnupg.org Thu Jun 10 17:26:04 2010 From: cvs at cvs.gnupg.org (svn author marcus) Date: Thu, 10 Jun 2010 17:26:04 +0200 Subject: [svn] GnuPG - r5354 - in trunk: common sm Message-ID: Author: marcus Date: 2010-06-10 17:26:03 +0200 (Thu, 10 Jun 2010) New Revision: 5354 Modified: trunk/common/ChangeLog trunk/common/estream.c trunk/sm/ChangeLog Log: 2010-06-10 Marcus Brinkmann * server.c (SERVER_STDIN, SERVER_STDOUT): New macros. (gpgsm_server): Use them with assuan_fdopen. Modified: trunk/common/ChangeLog =================================================================== --- trunk/common/ChangeLog 2010-06-10 15:08:29 UTC (rev 5353) +++ trunk/common/ChangeLog 2010-06-10 15:26:03 UTC (rev 5354) @@ -1,3 +1,7 @@ +2010-06-10 Marcus Brinkmann + + * estream.c (_es_get_std_stream): Fix cut&paste bug. + 2010-06-09 Werner Koch * exechelp-posix.c, exechelp-w32.c Modified: trunk/sm/ChangeLog =================================================================== --- trunk/sm/ChangeLog 2010-06-10 15:08:29 UTC (rev 5353) +++ trunk/sm/ChangeLog 2010-06-10 15:26:03 UTC (rev 5354) @@ -1,3 +1,8 @@ +2010-06-10 Marcus Brinkmann + + * server.c (SERVER_STDIN, SERVER_STDOUT): New macros. + (gpgsm_server): Use them with assuan_fdopen. + 2010-04-23 Marcus Brinkmann * certreqgen.c (read_parameters): Use ascii_isspace instead of Modified: trunk/common/estream.c =================================================================== --- trunk/common/estream.c 2010-06-10 15:08:29 UTC (rev 5353) +++ trunk/common/estream.c 2010-06-10 15:26:03 UTC (rev 5354) @@ -2452,7 +2452,7 @@ else if (fd == 1 && custom_std_fds_valid[1]) stream = do_fdopen (custom_std_fds[1], "a", 1, 1); else if (custom_std_fds_valid[2]) - stream = do_fdopen (custom_std_fds[1], "a", 1, 1); + stream = do_fdopen (custom_std_fds[2], "a", 1, 1); if (!stream) { From cvs at cvs.gnupg.org Thu Jun 10 18:13:15 2010 From: cvs at cvs.gnupg.org (svn author marcus) Date: Thu, 10 Jun 2010 18:13:15 +0200 Subject: [svn] gpgme - r1479 - trunk/src Message-ID: Author: marcus Date: 2010-06-10 18:13:14 +0200 (Thu, 10 Jun 2010) New Revision: 1479 Modified: trunk/src/ChangeLog trunk/src/engine-gpgsm.c Log: 2010-06-10 Marcus Brinkmann * engine-gpgsm.c (gpgsm_new): Translate returned achild_fds back to child_fds. Modified: trunk/src/ChangeLog =================================================================== --- trunk/src/ChangeLog 2010-06-10 13:49:19 UTC (rev 1478) +++ trunk/src/ChangeLog 2010-06-10 16:13:14 UTC (rev 1479) @@ -1,5 +1,8 @@ 2010-06-10 Marcus Brinkmann + * engine-gpgsm.c (gpgsm_new): Translate returned achild_fds back + to child_fds. + * debug.h (TRACE_SUC6): New macro. * w32-io.c (MAX_SLAFD): New macro. (fd_table): New static variable. Modified: trunk/src/engine-gpgsm.c =================================================================== --- trunk/src/engine-gpgsm.c 2010-06-10 13:49:19 UTC (rev 1478) +++ trunk/src/engine-gpgsm.c 2010-06-10 16:13:14 UTC (rev 1479) @@ -351,6 +351,10 @@ err = assuan_pipe_connect (gpgsm->assuan_ctx, file_name ? file_name : _gpgme_get_gpgsm_path (), argv, achild_fds, NULL, NULL, 0); + + /* For now... */ + for (i = 0; i < 4; i++) + child_fds[i] = (int) achild_fds[i]; } /* On Windows, handles are inserted in the spawned process with From cvs at cvs.gnupg.org Thu Jun 10 19:27:25 2010 From: cvs at cvs.gnupg.org (svn author marcus) Date: Thu, 10 Jun 2010 19:27:25 +0200 Subject: [svn] assuan - r376 - trunk/src Message-ID: Author: marcus Date: 2010-06-10 19:27:24 +0200 (Thu, 10 Jun 2010) New Revision: 376 Modified: trunk/src/ChangeLog trunk/src/system-w32ce.c trunk/src/w32ce-add.h Log: 2010-06-10 Marcus Brinkmann * w32ce-add.h (ASSUAN_STDIN, ASSUAN_STDOUT): Define magic handle values. * system-w32ce.c (__assuan_read, __assuan_write): Handle magic handle values differently. * system-w32ce.c (_assuan_w32ce_finish_pipe): Return error on RVID 0. Modified: trunk/src/ChangeLog =================================================================== --- trunk/src/ChangeLog 2010-06-09 13:12:31 UTC (rev 375) +++ trunk/src/ChangeLog 2010-06-10 17:27:24 UTC (rev 376) @@ -1,3 +1,11 @@ +2010-06-10 Marcus Brinkmann + + * w32ce-add.h (ASSUAN_STDIN, ASSUAN_STDOUT): Define magic handle values. + * system-w32ce.c (__assuan_read, __assuan_write): Handle magic + handle values differently. + + * system-w32ce.c (_assuan_w32ce_finish_pipe): Return error on RVID 0. + 2010-06-09 Marcus Brinkmann * gpgcedev.c (GPGCEDEV_IOCTL_UNBLOCK): New ioctl. Modified: trunk/src/system-w32ce.c =================================================================== --- trunk/src/system-w32ce.c 2010-06-09 13:12:31 UTC (rev 375) +++ trunk/src/system-w32ce.c 2010-06-10 17:27:24 UTC (rev 376) @@ -158,6 +158,9 @@ { HANDLE hd; + if (!rvid) + return INVALID_HANDLE_VALUE; + hd = CreateFile (L"GPG1:", write_end? GENERIC_WRITE : GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,NULL); @@ -281,6 +284,28 @@ TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "__assuan_read", ctx, "fd=0x%x, buffer=%p, size=%i", fd, buffer, size); +#ifdef HAVE_W32CE_SYSTEM + /* This is a bit of a hack to support stdin over ssh. Note that + fread buffers fully while getchar is line buffered. Weird, but + that's the way it is. ASSUAN_STDIN and ASSUAN_STDOUT are + special handle values that shouldn't occur in the wild. */ + if (fd == ASSUAN_STDIN) + { + int i = 0; + int chr; + while (i < size) + { + chr = getchar(); + if (chr == EOF) + break; + ((char*)buffer)[i++] = (char) chr; + if (chr == '\n') + break; + } + return TRACE_SYSRES (i); + } +#endif + res = recv (HANDLE2SOCKET (fd), buffer, size, 0); if (res == -1) { @@ -346,6 +371,18 @@ TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "__assuan_write", ctx, "fd=0x%x, buffer=%p, size=%i", fd, buffer, size); +#ifdef HAVE_W32CE_SYSTEM + /* This is a bit of a hack to support stdout over ssh. Note that + fread buffers fully while getchar is line buffered. Weird, but + that's the way it is. ASSUAN_STDIN and ASSUAN_STDOUT are + special handle values that shouldn't occur in the wild. */ + if (fd == ASSUAN_STDOUT) + { + res = fwrite (buffer, 1, size, stdout); + return TRACE_SYSRES (res); + } +#endif + res = send ((int)fd, buffer, size, 0); if (res == -1 && WSAGetLastError () == WSAENOTSOCK) { Modified: trunk/src/w32ce-add.h =================================================================== --- trunk/src/w32ce-add.h 2010-06-09 13:12:31 UTC (rev 375) +++ trunk/src/w32ce-add.h 2010-06-10 17:27:24 UTC (rev 376) @@ -26,3 +26,8 @@ LPSECURITY_ATTRIBUTES sec_attr, DWORD size); #define CreatePipe(a,b,c,d) _assuan_w32ce_create_pipe ((a),(b),(c),(d)) +/* Magic handle values. Let's hope those never occur legitimately as + handles or sockets. (Sockets are numbered sequentially from 0, + while handles seem aligned to wordsize. */ +#define ASSUAN_STDIN (void*)0x7ffffffd +#define ASSUAN_STDOUT (void*)0x7fffffff From cvs at cvs.gnupg.org Thu Jun 10 19:29:44 2010 From: cvs at cvs.gnupg.org (svn author marcus) Date: Thu, 10 Jun 2010 19:29:44 +0200 Subject: [svn] gpgme - r1480 - trunk/src Message-ID: Author: marcus Date: 2010-06-10 19:29:43 +0200 (Thu, 10 Jun 2010) New Revision: 1480 Modified: trunk/src/ChangeLog trunk/src/gpgme-tool.c Log: 2010-06-10 Marcus Brinkmann * gpgme-tool.c (gpgme_server): Use special hack for Windows CE to get at stdin and stdout. Modified: trunk/src/ChangeLog =================================================================== --- trunk/src/ChangeLog 2010-06-10 16:13:14 UTC (rev 1479) +++ trunk/src/ChangeLog 2010-06-10 17:29:43 UTC (rev 1480) @@ -1,5 +1,8 @@ 2010-06-10 Marcus Brinkmann + * gpgme-tool.c (gpgme_server): Use special hack for Windows CE to + get at stdin and stdout. + * engine-gpgsm.c (gpgsm_new): Translate returned achild_fds back to child_fds. Modified: trunk/src/gpgme-tool.c =================================================================== --- trunk/src/gpgme-tool.c 2010-06-10 16:13:14 UTC (rev 1479) +++ trunk/src/gpgme-tool.c 2010-06-10 17:29:43 UTC (rev 1480) @@ -2940,8 +2940,13 @@ /* We use a pipe based server so that we can work from scripts. assuan_init_pipe_server will automagically detect when we are called with a socketpair and ignore FIELDES in this case. */ +#ifdef HAVE_W32CE_SYSTEM + filedes[0] = ASSUAN_STDIN; + filedes[1] = ASSUAN_STDOUT; +#else filedes[0] = assuan_fdopen (0); filedes[1] = assuan_fdopen (1); +#endif err = assuan_new (&server.assuan_ctx); if (err) log_error (1, err, "can't create assuan context"); From cvs at cvs.gnupg.org Thu Jun 10 19:55:23 2010 From: cvs at cvs.gnupg.org (svn author marcus) Date: Thu, 10 Jun 2010 19:55:23 +0200 Subject: [svn] GnuPG - r5355 - trunk/common Message-ID: Author: marcus Date: 2010-06-10 19:55:22 +0200 (Thu, 10 Jun 2010) New Revision: 5355 Modified: trunk/common/ChangeLog trunk/common/sysutils.c Log: 2010-06-10 Marcus Brinkmann * sysutils.c (translate_sys2libc_fd) [HAVE_W32CE_SYSTEM]: Implement. (translate_sys2libc_fd_int) [HAVE_W32CE_SYSTEM]: Don't call translate_sys2libc_fd. Modified: trunk/common/ChangeLog =================================================================== --- trunk/common/ChangeLog 2010-06-10 15:26:03 UTC (rev 5354) +++ trunk/common/ChangeLog 2010-06-10 17:55:22 UTC (rev 5355) @@ -1,5 +1,10 @@ 2010-06-10 Marcus Brinkmann + * sysutils.c (translate_sys2libc_fd) [HAVE_W32CE_SYSTEM]: + Implement. + (translate_sys2libc_fd_int) [HAVE_W32CE_SYSTEM]: Don't call + translate_sys2libc_fd. + * estream.c (_es_get_std_stream): Fix cut&paste bug. 2010-06-09 Werner Koch Modified: trunk/common/sysutils.c =================================================================== --- trunk/common/sysutils.c 2010-06-10 15:26:03 UTC (rev 5354) +++ trunk/common/sysutils.c 2010-06-10 17:55:22 UTC (rev 5355) @@ -280,8 +280,7 @@ translate_sys2libc_fd (gnupg_fd_t fd, int for_write) { #if defined(HAVE_W32CE_SYSTEM) - (void)for_write; - return (int)fd; + return (int) _assuan_w32ce_finish_pipe ((int)fd, for_write); #elif defined(HAVE_W32_SYSTEM) int x; @@ -308,8 +307,7 @@ translate_sys2libc_fd_int (int fd, int for_write) { #if HAVE_W32CE_SYSTEM - fd = (int) _assuan_w32ce_finish_pipe (fd, for_write); - return translate_sys2libc_fd ((void*)fd, for_write); + return (int) _assuan_w32ce_finish_pipe (fd, for_write); #elif HAVE_W32_SYSTEM if (fd <= 2) return fd; /* Do not do this for error, stdin, stdout, stderr. */ From cvs at cvs.gnupg.org Fri Jun 11 01:09:33 2010 From: cvs at cvs.gnupg.org (svn author marcus) Date: Fri, 11 Jun 2010 01:09:33 +0200 Subject: [svn] assuan - r377 - trunk/src Message-ID: Author: marcus Date: 2010-06-11 01:09:32 +0200 (Fri, 11 Jun 2010) New Revision: 377 Modified: trunk/src/ChangeLog trunk/src/assuan-handler.c trunk/src/system-w32ce.c Log: 2010-06-11 Marcus Brinkmann * assuan-handler.c (std_handler_input, std_handler_output) [HAVE_W32CE_SYSTEM]: Finish the pipe. We must do this here, because otherwise assuan_close_input_fd() and assuan_close_output_fd() can't work. * system-w32ce.c (_assuan_w32ce_finish_pipe): Call SetLastError in error case. (__assuan_close): Save WSAGetLastError before trashing it! Otherwise handle is never closed and GPGME hangs. Modified: trunk/src/ChangeLog =================================================================== --- trunk/src/ChangeLog 2010-06-10 17:27:24 UTC (rev 376) +++ trunk/src/ChangeLog 2010-06-10 23:09:32 UTC (rev 377) @@ -1,3 +1,14 @@ +2010-06-11 Marcus Brinkmann + + * assuan-handler.c (std_handler_input, + std_handler_output) [HAVE_W32CE_SYSTEM]: Finish the pipe. We must + do this here, because otherwise assuan_close_input_fd() and + assuan_close_output_fd() can't work. + * system-w32ce.c (_assuan_w32ce_finish_pipe): Call SetLastError in + error case. + (__assuan_close): Save WSAGetLastError before trashing it! + Otherwise handle is never closed and GPGME hangs. + 2010-06-10 Marcus Brinkmann * w32ce-add.h (ASSUAN_STDIN, ASSUAN_STDOUT): Define magic handle values. Modified: trunk/src/assuan-handler.c =================================================================== --- trunk/src/assuan-handler.c 2010-06-10 17:27:24 UTC (rev 376) +++ trunk/src/assuan-handler.c 2010-06-10 23:09:32 UTC (rev 377) @@ -264,6 +264,17 @@ rc = assuan_command_parse_fd (ctx, line, &fd); if (rc) return PROCESS_DONE (ctx, rc); + +#ifdef HAVE_W32CE_SYSTEM + oldfd = fd; + fd = _assuan_w32ce_finish_pipe ((int)fd, 0); + if (fd == INVALID_HANDLE_VALUE) + return PROCESS_DONE (ctx, set_error (ctx, GPG_ERR_ASS_PARAMETER, + "rvid conversion failed")); + TRACE2 (ctx, ASSUAN_LOG_SYSIO, "std_handler_input", ctx, + "turned RVID 0x%x into handle 0x%x", oldfd, fd); +#endif + if (ctx->input_notify_fnc) { oldfd = ctx->input_fd; @@ -284,10 +295,21 @@ { gpg_error_t rc; assuan_fd_t fd, oldfd; - + rc = assuan_command_parse_fd (ctx, line, &fd); if (rc) return PROCESS_DONE (ctx, rc); + +#ifdef HAVE_W32CE_SYSTEM + oldfd = fd; + fd = _assuan_w32ce_finish_pipe ((int)fd, 1); + if (fd == INVALID_HANDLE_VALUE) + return PROCESS_DONE (ctx, set_error (ctx, gpg_err_code_from_syserror (), + "rvid conversion failed")); + TRACE2 (ctx, ASSUAN_LOG_SYSIO, "std_handler_output", ctx, + "turned RVID 0x%x into handle 0x%x", oldfd, fd); +#endif + if (ctx->output_notify_fnc) { oldfd = ctx->output_fd; Modified: trunk/src/system-w32ce.c =================================================================== --- trunk/src/system-w32ce.c 2010-06-10 17:27:24 UTC (rev 376) +++ trunk/src/system-w32ce.c 2010-06-10 23:09:32 UTC (rev 377) @@ -159,7 +159,10 @@ HANDLE hd; if (!rvid) - return INVALID_HANDLE_VALUE; + { + SetLastError (ERROR_INVALID_HANDLE); + return INVALID_HANDLE_VALUE; + } hd = CreateFile (L"GPG1:", write_end? GENERIC_WRITE : GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, @@ -259,9 +262,13 @@ __assuan_close (assuan_context_t ctx, assuan_fd_t fd) { int rc = closesocket (HANDLE2SOCKET(fd)); + int err = WSAGetLastError (); + + /* Note that gpg_err_set_errno on Windows CE overwrites + WSAGetLastError() (via SetLastError()). */ if (rc) - gpg_err_set_errno ( _assuan_sock_wsa2errno (WSAGetLastError ()) ); - if (rc && WSAGetLastError () == WSAENOTSOCK) + gpg_err_set_errno (_assuan_sock_wsa2errno (err)); + if (rc && err == WSAENOTSOCK) { rc = CloseHandle (fd); if (rc) From cvs at cvs.gnupg.org Fri Jun 11 01:17:33 2010 From: cvs at cvs.gnupg.org (svn author marcus) Date: Fri, 11 Jun 2010 01:17:33 +0200 Subject: [svn] GnuPG - r5356 - in trunk: common sm Message-ID: Author: marcus Date: 2010-06-11 01:17:33 +0200 (Fri, 11 Jun 2010) New Revision: 5356 Modified: trunk/common/ChangeLog trunk/common/sysutils.c trunk/sm/ChangeLog trunk/sm/server.c Log: common/ 2010-06-11 Marcus Brinkmann * sysutils.c (translate_sys2libc_fd): Revert last change. (translate_sys2libc_fd_int): Revert last change. sm/ 2010-06-11 Marcus Brinkmann * server.c (cmd_message) [HAVE_W32CE_SYSTEM]: Finish pipe. Modified: trunk/common/ChangeLog =================================================================== --- trunk/common/ChangeLog 2010-06-10 17:55:22 UTC (rev 5355) +++ trunk/common/ChangeLog 2010-06-10 23:17:33 UTC (rev 5356) @@ -1,3 +1,8 @@ +2010-06-11 Marcus Brinkmann + + * sysutils.c (translate_sys2libc_fd): Revert last change. + (translate_sys2libc_fd_int): Revert last change. + 2010-06-10 Marcus Brinkmann * sysutils.c (translate_sys2libc_fd) [HAVE_W32CE_SYSTEM]: Modified: trunk/sm/ChangeLog =================================================================== --- trunk/sm/ChangeLog 2010-06-10 17:55:22 UTC (rev 5355) +++ trunk/sm/ChangeLog 2010-06-10 23:17:33 UTC (rev 5356) @@ -1,3 +1,7 @@ +2010-06-11 Marcus Brinkmann + + * server.c (cmd_message) [HAVE_W32CE_SYSTEM]: Finish pipe. + 2010-06-10 Marcus Brinkmann * server.c (SERVER_STDIN, SERVER_STDOUT): New macros. Modified: trunk/common/sysutils.c =================================================================== --- trunk/common/sysutils.c 2010-06-10 17:55:22 UTC (rev 5355) +++ trunk/common/sysutils.c 2010-06-10 23:17:33 UTC (rev 5356) @@ -280,7 +280,8 @@ translate_sys2libc_fd (gnupg_fd_t fd, int for_write) { #if defined(HAVE_W32CE_SYSTEM) - return (int) _assuan_w32ce_finish_pipe ((int)fd, for_write); + (void)for_write; + return (int) fd; #elif defined(HAVE_W32_SYSTEM) int x; @@ -307,7 +308,8 @@ translate_sys2libc_fd_int (int fd, int for_write) { #if HAVE_W32CE_SYSTEM - return (int) _assuan_w32ce_finish_pipe (fd, for_write); + fd = (int) _assuan_w32ce_finish_pipe (fd, for_write); + return translate_sys2libc_fd ((void*)fd, for_write); #elif HAVE_W32_SYSTEM if (fd <= 2) return fd; /* Do not do this for error, stdin, stdout, stderr. */ Modified: trunk/sm/server.c =================================================================== --- trunk/sm/server.c 2010-06-10 17:55:22 UTC (rev 5355) +++ trunk/sm/server.c 2010-06-10 23:17:33 UTC (rev 5356) @@ -163,6 +163,7 @@ { if (ctrl->server_local->message_fd != -1) { +#warning Is this correct for W32/W32CE? close (ctrl->server_local->message_fd); ctrl->server_local->message_fd = -1; } @@ -839,6 +840,14 @@ rc = assuan_command_parse_fd (ctx, line, &sysfd); if (rc) return rc; + +#ifdef HAVE_W32CE_SYSTEM + sysfd = _assuan_w32ce_finish_pipe ((int)sysfd, 0); + if (sysfd == INVALID_HANDLE_VALUE) + return set_error (gpg_err_code_from_syserror (), + "rvid conversion failed"); +#endif + fd = translate_sys2libc_fd (sysfd, 0); if (fd == -1) return set_error (GPG_ERR_ASS_NO_INPUT, NULL); From cvs at cvs.gnupg.org Fri Jun 11 01:29:07 2010 From: cvs at cvs.gnupg.org (svn author marcus) Date: Fri, 11 Jun 2010 01:29:07 +0200 Subject: [svn] gpgme - r1481 - trunk/src Message-ID: Author: marcus Date: 2010-06-11 01:29:06 +0200 (Fri, 11 Jun 2010) New Revision: 1481 Modified: trunk/src/ChangeLog trunk/src/w32-io.c Log: 2010-06-11 Marcus Brinkmann * w32-io.c (_gpgme_io_spawn): Remove debug printf. Modified: trunk/src/ChangeLog =================================================================== --- trunk/src/ChangeLog 2010-06-10 17:29:43 UTC (rev 1480) +++ trunk/src/ChangeLog 2010-06-10 23:29:06 UTC (rev 1481) @@ -1,3 +1,7 @@ +2010-06-11 Marcus Brinkmann + + * w32-io.c (_gpgme_io_spawn): Remove debug printf. + 2010-06-10 Marcus Brinkmann * gpgme-tool.c (gpgme_server): Use special hack for Windows CE to Modified: trunk/src/w32-io.c =================================================================== --- trunk/src/w32-io.c 2010-06-10 17:29:43 UTC (rev 1480) +++ trunk/src/w32-io.c 2010-06-10 23:29:06 UTC (rev 1481) @@ -1520,8 +1520,6 @@ return TRACE_SYSRES (-1); } - fprintf (stderr, "SPAWNY: %s\n", cmdline); - if (!CreateProcessA (path, /* Program to start. */ cmdline, /* Command line arguments. */ NULL, /* (not supported) */ From cvs at cvs.gnupg.org Fri Jun 11 15:51:12 2010 From: cvs at cvs.gnupg.org (svn author wk) Date: Fri, 11 Jun 2010 15:51:12 +0200 Subject: [svn] GnuPG - r5357 - in trunk/scripts: . gpg-w32-dev Message-ID: Author: wk Date: 2010-06-11 15:51:11 +0200 (Fri, 11 Jun 2010) New Revision: 5357 Added: trunk/scripts/gpg-w32-dev/ trunk/scripts/gpg-w32-dev/GNUmakefile trunk/scripts/gpg-w32-dev/README trunk/scripts/gpg-w32-dev/speedo.mk Log: Add makefiles to build a w32 development package. From cvs at cvs.gnupg.org Mon Jun 14 09:43:50 2010 From: cvs at cvs.gnupg.org (svn author wk) Date: Mon, 14 Jun 2010 09:43:50 +0200 Subject: [svn] dirmngr - r342 - in trunk: . po src Message-ID: Author: wk Date: 2010-06-14 09:43:49 +0200 (Mon, 14 Jun 2010) New Revision: 342 Modified: trunk/ChangeLog trunk/NEWS trunk/configure.ac trunk/po/de.po trunk/po/dirmngr.pot trunk/src/ChangeLog trunk/src/exechelp.c Log: prepare a release Modified: trunk/ChangeLog =================================================================== --- trunk/ChangeLog 2010-03-13 09:12:28 UTC (rev 341) +++ trunk/ChangeLog 2010-06-14 07:43:49 UTC (rev 342) @@ -1,3 +1,7 @@ +2010-06-14 Werner Koch + + Release 1.1.0. + 2010-03-09 Werner Koch Release 1.1.0rc1. Modified: trunk/src/ChangeLog =================================================================== --- trunk/src/ChangeLog 2010-03-13 09:12:28 UTC (rev 341) +++ trunk/src/ChangeLog 2010-06-14 07:43:49 UTC (rev 342) @@ -1,3 +1,7 @@ +2010-06-07 Werner Koch + + * vasprintf.c: Remove. + 2010-03-13 Werner Koch * dirmngr.c (int_and_ptr_u): New. Modified: trunk/NEWS =================================================================== --- trunk/NEWS 2010-03-13 09:12:28 UTC (rev 341) +++ trunk/NEWS 2010-06-14 07:43:49 UTC (rev 342) @@ -1,4 +1,4 @@ -Noteworthy changes in version 1.1.0 (unreleased) +Noteworthy changes in version 1.1.0 (2010-06-14) ------------------------------------------------ * Fixed a resource problem with LDAP CRLs. Modified: trunk/configure.ac =================================================================== --- trunk/configure.ac 2010-03-13 09:12:28 UTC (rev 341) +++ trunk/configure.ac 2010-06-14 07:43:49 UTC (rev 342) @@ -28,7 +28,7 @@ # Set my_issvn to "yes" for non-released code. Remember to run an # "svn up" and "autogen.sh" right before creating a distribution. m4_define([my_version], [1.1.0]) -m4_define([my_issvn], [yes]) +m4_define([my_issvn], [no]) m4_define([svn_revision], m4_esyscmd([printf "%d" $( (svn info 2>/dev/null \ || echo 'Revision: 0')|sed -n '/^Revision:/ {s/[^0-9]//gp;q;}')])) Modified: trunk/po/de.po [not shown] Modified: trunk/po/dirmngr.pot =================================================================== --- trunk/po/dirmngr.pot 2010-03-13 09:12:28 UTC (rev 341) +++ trunk/po/dirmngr.pot 2010-06-14 07:43:49 UTC (rev 342) @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: gpa-dev at gnupg.org\n" -"POT-Creation-Date: 2010-03-09 13:14+0100\n" +"POT-Creation-Date: 2010-03-13 08:35+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -51,7 +51,7 @@ msgid "can't access directory `%s': %s\n" msgstr "" -#: src/certcache.c:390 src/crlcache.c:2367 src/dirmngr.c:1479 +#: src/certcache.c:390 src/crlcache.c:2367 src/dirmngr.c:1493 #, c-format msgid "can't open `%s': %s\n" msgstr "" @@ -245,7 +245,7 @@ msgstr "" #: src/crlcache.c:649 src/crlcache.c:654 src/crlcache.c:908 src/crlcache.c:914 -#: src/dirmngr.c:1425 +#: src/dirmngr.c:1439 #, c-format msgid "error reading `%s': %s\n" msgstr "" @@ -822,201 +822,201 @@ #. TRANSLATORS: @EMAIL@ will get replaced by the actual bug #. reporting address. This is so that we can change the #. reporting address without breaking the translations. -#: src/dirmngr.c:275 src/dirmngr-client.c:149 src/dirmngr_ldap.c:148 +#: src/dirmngr.c:286 src/dirmngr-client.c:149 src/dirmngr_ldap.c:148 msgid "Please report bugs to <@EMAIL@>.\n" msgstr "" -#: src/dirmngr.c:278 +#: src/dirmngr.c:289 msgid "Usage: dirmngr [options] (-h for help)" msgstr "" -#: src/dirmngr.c:280 +#: src/dirmngr.c:291 msgid "" "Syntax: dirmngr [options] [command [args]]\n" "LDAP and OCSP access for GnuPG\n" msgstr "" -#: src/dirmngr.c:366 +#: src/dirmngr.c:377 #, c-format msgid "invalid debug-level `%s' given\n" msgstr "" -#: src/dirmngr.c:367 +#: src/dirmngr.c:378 #, c-format msgid "valid debug levels are: %s\n" msgstr "" -#: src/dirmngr.c:405 +#: src/dirmngr.c:416 msgid "usage: dirmngr [options] " msgstr "" -#: src/dirmngr.c:430 +#: src/dirmngr.c:441 #, c-format msgid "error spawning ldap wrapper reaper thread: %s\n" msgstr "" -#: src/dirmngr.c:657 src/dirmngr.c:667 +#: src/dirmngr.c:671 src/dirmngr.c:681 #, c-format msgid "%s is too old (need %s, have %s)\n" msgstr "" -#: src/dirmngr.c:783 +#: src/dirmngr.c:797 #, c-format msgid "NOTE: no default option file `%s'\n" msgstr "" -#: src/dirmngr.c:788 src/dirmngr.c:1585 +#: src/dirmngr.c:802 src/dirmngr.c:1599 #, c-format msgid "option file `%s': %s\n" msgstr "" -#: src/dirmngr.c:796 +#: src/dirmngr.c:810 #, c-format msgid "reading options from `%s'\n" msgstr "" -#: src/dirmngr.c:898 +#: src/dirmngr.c:912 #, c-format msgid "WARNING: running with faked system time %s\n" msgstr "" -#: src/dirmngr.c:979 +#: src/dirmngr.c:993 msgid "colons are not allowed in the socket name\n" msgstr "" -#: src/dirmngr.c:985 +#: src/dirmngr.c:999 msgid "name of socket too long\n" msgstr "" -#: src/dirmngr.c:992 +#: src/dirmngr.c:1006 #, c-format msgid "can't create socket: %s\n" msgstr "" -#: src/dirmngr.c:1011 +#: src/dirmngr.c:1025 msgid "error getting nonce for the socket\n" msgstr "" -#: src/dirmngr.c:1014 +#: src/dirmngr.c:1028 #, c-format msgid "error binding socket to `%s': %s\n" msgstr "" -#: src/dirmngr.c:1023 +#: src/dirmngr.c:1037 #, c-format msgid "listen() failed: %s\n" msgstr "" -#: src/dirmngr.c:1029 +#: src/dirmngr.c:1043 #, c-format msgid "listening on socket `%s'\n" msgstr "" -#: src/dirmngr.c:1040 +#: src/dirmngr.c:1054 #, c-format msgid "fork failed: %s\n" msgstr "" -#: src/dirmngr.c:1058 +#: src/dirmngr.c:1072 msgid "out of core\n" msgstr "" -#: src/dirmngr.c:1097 +#: src/dirmngr.c:1111 #, c-format msgid "setsid() failed: %s\n" msgstr "" -#: src/dirmngr.c:1107 +#: src/dirmngr.c:1121 #, c-format msgid "chdir to / failed: %s\n" msgstr "" -#: src/dirmngr.c:1177 src/server.c:1103 +#: src/dirmngr.c:1191 src/server.c:1103 #, c-format msgid "fetching CRL from `%s' failed: %s\n" msgstr "" -#: src/dirmngr.c:1183 src/server.c:1109 +#: src/dirmngr.c:1197 src/server.c:1109 #, c-format msgid "processing CRL from `%s' failed: %s\n" msgstr "" -#: src/dirmngr.c:1387 +#: src/dirmngr.c:1401 #, c-format msgid "error opening `%s': %s\n" msgstr "" -#: src/dirmngr.c:1402 +#: src/dirmngr.c:1416 #, c-format msgid "%s:%u: line too long - skipped\n" msgstr "" -#: src/dirmngr.c:1457 src/dirmngr.c:1541 +#: src/dirmngr.c:1471 src/dirmngr.c:1555 #, c-format msgid "%s:%u: invalid fingerprint detected\n" msgstr "" -#: src/dirmngr.c:1493 src/dirmngr.c:1519 +#: src/dirmngr.c:1507 src/dirmngr.c:1533 #, c-format msgid "%s:%u: read error: %s\n" msgstr "" -#: src/dirmngr.c:1548 +#: src/dirmngr.c:1562 #, c-format msgid "%s:%u: garbage at end of line ignored\n" msgstr "" -#: src/dirmngr.c:1618 +#: src/dirmngr.c:1632 msgid "SIGHUP received - re-reading configuration and flushing caches\n" msgstr "" -#: src/dirmngr.c:1632 +#: src/dirmngr.c:1646 msgid "SIGUSR2 received - no action defined\n" msgstr "" -#: src/dirmngr.c:1637 src/dirmngr.c:1674 +#: src/dirmngr.c:1651 src/dirmngr.c:1688 msgid "SIGTERM received - shutting down ...\n" msgstr "" -#: src/dirmngr.c:1639 +#: src/dirmngr.c:1653 #, c-format msgid "SIGTERM received - still %d active connections\n" msgstr "" -#: src/dirmngr.c:1644 src/dirmngr.c:1677 +#: src/dirmngr.c:1658 src/dirmngr.c:1691 msgid "shutdown forced\n" msgstr "" -#: src/dirmngr.c:1652 +#: src/dirmngr.c:1666 msgid "SIGINT received - immediate shutdown\n" msgstr "" -#: src/dirmngr.c:1659 +#: src/dirmngr.c:1673 #, c-format msgid "signal %d received - no action defined\n" msgstr "" -#: src/dirmngr.c:1693 +#: src/dirmngr.c:1707 #, c-format msgid "error reading nonce on fd %d: %s\n" msgstr "" -#: src/dirmngr.c:1718 +#: src/dirmngr.c:1736 #, c-format msgid "handler for fd %d started\n" msgstr "" -#: src/dirmngr.c:1723 +#: src/dirmngr.c:1741 #, c-format msgid "handler for fd %d terminated\n" msgstr "" -#: src/dirmngr.c:1806 +#: src/dirmngr.c:1825 #, c-format msgid "accept failed: %s - waiting 1s\n" msgstr "" -#: src/dirmngr.c:1832 +#: src/dirmngr.c:1855 #, c-format msgid "error spawning connection handler: %s\n" msgstr "" Modified: trunk/src/exechelp.c =================================================================== --- trunk/src/exechelp.c 2010-03-13 09:12:28 UTC (rev 341) +++ trunk/src/exechelp.c 2010-06-14 07:43:49 UTC (rev 342) @@ -233,6 +233,8 @@ return err; /* Create a pipe. */ +#warning pth_pipe implementaion is not correct for W32CE. + /* FIXME: We better replace it by the assuan pipe. */ if (pth_pipe (rp_stdout, 1)) { err = gpg_error (GPG_ERR_GENERAL); From cvs at cvs.gnupg.org Mon Jun 14 09:44:53 2010 From: cvs at cvs.gnupg.org (svn author wk) Date: Mon, 14 Jun 2010 09:44:53 +0200 Subject: [svn] dirmngr - r343 - trunk/src Message-ID: Author: wk Date: 2010-06-14 09:44:53 +0200 (Mon, 14 Jun 2010) New Revision: 343 Modified: trunk/src/exechelp.c Log: Remove a warning directive Modified: trunk/src/exechelp.c =================================================================== --- trunk/src/exechelp.c 2010-06-14 07:43:49 UTC (rev 342) +++ trunk/src/exechelp.c 2010-06-14 07:44:53 UTC (rev 343) @@ -233,7 +233,6 @@ return err; /* Create a pipe. */ -#warning pth_pipe implementaion is not correct for W32CE. /* FIXME: We better replace it by the assuan pipe. */ if (pth_pipe (rp_stdout, 1)) { From cvs at cvs.gnupg.org Mon Jun 14 09:59:28 2010 From: cvs at cvs.gnupg.org (svn author wk) Date: Mon, 14 Jun 2010 09:59:28 +0200 Subject: [svn] dirmngr - r344 - tags Message-ID: Author: wk Date: 2010-06-14 09:59:28 +0200 (Mon, 14 Jun 2010) New Revision: 344 Added: tags/dirmngr-1.1.0/ Log: Release tag From cvs at cvs.gnupg.org Thu Jun 17 14:58:52 2010 From: cvs at cvs.gnupg.org (svn author wk) Date: Thu, 17 Jun 2010 14:58:52 +0200 Subject: [svn] GnuPG - r5358 - in branches/STABLE-BRANCH-2-0: doc g10 tests/openpgp Message-ID: Author: wk Date: 2010-06-17 14:58:51 +0200 (Thu, 17 Jun 2010) New Revision: 5358 Modified: branches/STABLE-BRANCH-2-0/doc/gpg.texi branches/STABLE-BRANCH-2-0/g10/ChangeLog branches/STABLE-BRANCH-2-0/g10/gpg.c branches/STABLE-BRANCH-2-0/tests/openpgp/ChangeLog Log: Make CAST5 the default s2k algo tomatch the doc and gpg 1.4. Modified: branches/STABLE-BRANCH-2-0/g10/ChangeLog =================================================================== --- branches/STABLE-BRANCH-2-0/g10/ChangeLog 2010-06-11 13:51:11 UTC (rev 5357) +++ branches/STABLE-BRANCH-2-0/g10/ChangeLog 2010-06-17 12:58:51 UTC (rev 5358) @@ -1,3 +1,8 @@ +2010-06-17 Werner Koch + + * gpg.c (main): Use CAST5 as default s2k algo. The macro + USE_CAST5 was only used with GnuPG 1.x. + 2010-05-12 Werner Koch * armor.c (radix64_read): Change fix 2006-04-28 to fix bug#1179. Modified: branches/STABLE-BRANCH-2-0/tests/openpgp/ChangeLog =================================================================== --- branches/STABLE-BRANCH-2-0/tests/openpgp/ChangeLog 2010-06-11 13:51:11 UTC (rev 5357) +++ branches/STABLE-BRANCH-2-0/tests/openpgp/ChangeLog 2010-06-17 12:58:51 UTC (rev 5358) @@ -2,7 +2,7 @@ * armor.test: Add test for bug#1179. - * Makefile.am (TESTS_ENVIRONMENT): New. Start all scripts udner + * Makefile.am (TESTS_ENVIRONMENT): New. Start all scripts under the control of the gpg-agent. (prepared.stamp): Create gpg-agent.conf. * defs.inc: Do not create gpg-agent.conf Modified: branches/STABLE-BRANCH-2-0/doc/gpg.texi =================================================================== --- branches/STABLE-BRANCH-2-0/doc/gpg.texi 2010-06-11 13:51:11 UTC (rev 5357) +++ branches/STABLE-BRANCH-2-0/doc/gpg.texi 2010-06-17 12:58:51 UTC (rev 5358) @@ -845,7 +845,8 @@ @c man:.RS The listing shows you the key with its secondary keys and all user -ids. Selected keys or user ids are indicated by an asterisk. The trust +ids. The primary user id is indicated by a dot, and selected keys or +user ids are indicated by an asterisk. The trust value is displayed with the primary key: the first is the assigned owner trust and the second is the calculated trust value. Letters are used for the values: Modified: branches/STABLE-BRANCH-2-0/g10/gpg.c =================================================================== --- branches/STABLE-BRANCH-2-0/g10/gpg.c 2010-06-11 13:51:11 UTC (rev 5357) +++ branches/STABLE-BRANCH-2-0/g10/gpg.c 2010-06-17 12:58:51 UTC (rev 5358) @@ -1973,11 +1973,7 @@ opt.compress_algo = -1; /* defaults to DEFAULT_COMPRESS_ALGO */ opt.s2k_mode = 3; /* iterated+salted */ opt.s2k_count = 0; /* Auto-calibrate when needed. */ -#ifdef USE_CAST5 opt.s2k_cipher_algo = CIPHER_ALGO_CAST5; -#else - opt.s2k_cipher_algo = CIPHER_ALGO_3DES; -#endif opt.completes_needed = 1; opt.marginals_needed = 3; opt.max_cert_depth = 5; From cvs at cvs.gnupg.org Thu Jun 17 17:44:47 2010 From: cvs at cvs.gnupg.org (svn author wk) Date: Thu, 17 Jun 2010 17:44:47 +0200 Subject: [svn] GnuPG - r5359 - in trunk: agent common dirmngr doc g10 sm Message-ID: Author: wk Date: 2010-06-17 17:44:44 +0200 (Thu, 17 Jun 2010) New Revision: 5359 Added: trunk/sm/minip12.c trunk/sm/minip12.h Removed: trunk/agent/minip12.c trunk/agent/minip12.h Modified: trunk/agent/ChangeLog trunk/agent/Makefile.am trunk/agent/agent.h trunk/agent/command.c trunk/agent/findkey.c trunk/agent/genkey.c trunk/agent/preset-passphrase.c trunk/agent/protect-tool.c trunk/agent/protect.c trunk/common/ChangeLog trunk/common/membuf.c trunk/common/sexputil.c trunk/common/util.h trunk/dirmngr/http.c trunk/doc/dirmngr.texi trunk/g10/ChangeLog trunk/g10/gpg.c trunk/sm/ChangeLog trunk/sm/Makefile.am trunk/sm/call-agent.c trunk/sm/gpgsm.h trunk/sm/import.c Log: Avoid using the protect-tool to import pkcs#12. [The diff below has been truncated] Modified: trunk/agent/ChangeLog =================================================================== --- trunk/agent/ChangeLog 2010-06-17 12:58:51 UTC (rev 5358) +++ trunk/agent/ChangeLog 2010-06-17 15:44:44 UTC (rev 5359) @@ -1,3 +1,29 @@ +2010-06-15 Werner Koch + + * command.c (cmd_keywrap_key, cmd_import_key): New. + + * genkey.c (agent_genkey, agent_protect_and_store): Factor common + code out to... + (agent_ask_new_passphrase): .. new. + + * findkey.c (agent_write_private_key): Return GPG_ERR_EEXIST + instead of GPG_ERR_GENERAL. + +2010-06-14 Werner Koch + + * protect-tool.c: Remove commands --p12-import and --p12-export. + * minip12.c, minip12.h: Move to ../sm. + * Makefile.am (gpg_protect_tool_SOURCES): Remove them. + * preset-passphrase.c: Remove unneeded minip12.h. + + * command.c (cmd_keywrap_key): New. + + * command.c (leave_cmd): New. + (cmd_istrusted, cmd_listtrusted, cmd_marktrusted, cmd_pksign) + (cmd_pkdecrypt, cmd_genkey, cmd_readkey, cmd_keyinfo) + (cmd_get_passphrase, cmd_get_confirmation, cmd_learn) + (cmd_passwd, cmd_preset_passphrase, cmd_getval, cmd_putval): Use it. + 2010-05-12 Werner Koch * preset-passphrase.c (forget_passphrase): Actually implement Modified: trunk/common/ChangeLog =================================================================== --- trunk/common/ChangeLog 2010-06-17 12:58:51 UTC (rev 5358) +++ trunk/common/ChangeLog 2010-06-17 15:44:44 UTC (rev 5359) @@ -1,3 +1,11 @@ +2010-06-17 Werner Koch + + * sexputil.c (make_canon_sexp_pad): New. + +2010-06-14 Werner Koch + + * membuf.c (put_membuf): Add shortcut for !LEN. + 2010-06-11 Marcus Brinkmann * sysutils.c (translate_sys2libc_fd): Revert last change. Modified: trunk/g10/ChangeLog =================================================================== --- trunk/g10/ChangeLog 2010-06-17 12:58:51 UTC (rev 5358) +++ trunk/g10/ChangeLog 2010-06-17 15:44:44 UTC (rev 5359) @@ -1,3 +1,8 @@ +2010-06-17 Werner Koch + + * gpg.c (main): Use CAST5 as default s2k algo. The macro + USE_CAST5 was only used with GnuPG 1.x. + 2010-06-07 Werner Koch * cpr.c: Use estream for status output. Modified: trunk/sm/ChangeLog =================================================================== --- trunk/sm/ChangeLog 2010-06-17 12:58:51 UTC (rev 5358) +++ trunk/sm/ChangeLog 2010-06-17 15:44:44 UTC (rev 5359) @@ -1,3 +1,19 @@ +2010-06-17 Werner Koch + + * import.c (parse_p12): Remove arg retfp. Use the agent's new + import command. + (import_one): Adjust call to pkcs12. + (store_cert_cb, rsa_key_check): New. + (popen_protect_tool): Remove. + * minip12.c (parse_bag_encrypted_data, p12_parse): Add arg + R_BADPASS. + * call-agent.c (gpgsm_agent_ask_passphrase): New. + (gpgsm_agent_keywrap_key): New. + (struct import_key_parm_s): New. + (gpgsm_agent_import_key): New. + * minip12.c, minip12.h: Move from ../agent/. + * Makefile.am (gpgsm_SOURCES): Add them. + 2010-06-11 Marcus Brinkmann * server.c (cmd_message) [HAVE_W32CE_SYSTEM]: Finish pipe. Modified: trunk/agent/Makefile.am =================================================================== --- trunk/agent/Makefile.am 2010-06-17 12:58:51 UTC (rev 5358) +++ trunk/agent/Makefile.am 2010-06-17 15:44:44 UTC (rev 5359) @@ -79,8 +79,7 @@ gpg_protect_tool_SOURCES = \ protect-tool.c \ - protect.c \ - minip12.c minip12.h + protect.c gpg_protect_tool_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS) gpg_protect_tool_LDADD = $(common_libs) $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) \ Modified: trunk/agent/agent.h =================================================================== --- trunk/agent/agent.h 2010-06-17 12:58:51 UTC (rev 5358) +++ trunk/agent/agent.h 2010-06-17 15:44:44 UTC (rev 5359) @@ -284,6 +284,8 @@ /*-- genkey.c --*/ int check_passphrase_constraints (ctrl_t ctrl, const char *pw, int silent); +gpg_error_t agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt, + char **r_passphrase); int agent_genkey (ctrl_t ctrl, const char *keyparam, size_t keyparmlen, membuf_t *outbuf); int agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey); Modified: trunk/agent/command.c =================================================================== --- trunk/agent/command.c 2010-06-17 12:58:51 UTC (rev 5358) +++ trunk/agent/command.c 2010-06-17 15:44:44 UTC (rev 5359) @@ -38,10 +38,14 @@ #include #include "i18n.h" -/* maximum allowed size of the inquired ciphertext */ +/* Maximum allowed size of the inquired ciphertext. */ #define MAXLEN_CIPHERTEXT 4096 -/* maximum allowed size of the key parameters */ +/* Maximum allowed size of the key parameters. */ #define MAXLEN_KEYPARAM 1024 +/* Maximum allowed size of key data as used in inquiries (bytes). */ +#define MAXLEN_KEYDATA 4096 +/* The size of the import/export KEK key (in bytes). */ +#define KEYWRAP_KEYSIZE (128/8) #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t)) @@ -63,6 +67,8 @@ the end of this session. */ int allow_pinentry_notify; /* Set if pinentry notifications should be done. */ + void *import_key; /* Malloced KEK for the import_key command. */ + void *export_key; /* Malloced KEK for the export_key command. */ }; @@ -340,6 +346,26 @@ } +/* Helper to print a message while leaving a command. */ +static gpg_error_t +leave_cmd (assuan_context_t ctx, gpg_error_t err) +{ + if (err) + { + const char *name = assuan_get_command_name (ctx); + if (!name) + name = "?"; + if (gpg_err_source (err) == GPG_ERR_SOURCE_DEFAULT) + log_error ("command '%s' failed: %s\n", name, + gpg_strerror (err)); + else + log_error ("command '%s' failed: %s <%s>\n", name, + gpg_strerror (err), gpg_strsource (err)); + } + return err; +} + + static const char hlp_geteventcounter[] = "GETEVENTCOUNTER\n" @@ -432,10 +458,7 @@ else if (rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF ) return gpg_error (GPG_ERR_NOT_TRUSTED); else - { - log_error ("command is_trusted failed: %s\n", gpg_strerror (rc)); - return rc; - } + return leave_cmd (ctx, rc); } @@ -451,9 +474,7 @@ (void)line; rc = agent_listtrusted (ctx); - if (rc) - log_error ("command listtrusted failed: %s\n", gpg_strerror (rc)); - return rc; + return leave_cmd (ctx, rc); } @@ -494,9 +515,7 @@ p++; rc = agent_marktrusted (ctrl, p, fpr, flag); - if (rc) - log_error ("command marktrusted failed: %s\n", gpg_strerror (rc)); - return rc; + return leave_cmd (ctx, rc); } @@ -695,11 +714,9 @@ clear_outbuf (&outbuf); else rc = write_and_clear_outbuf (ctx, &outbuf); - if (rc) - log_error ("command pksign failed: %s\n", gpg_strerror (rc)); xfree (ctrl->server_local->keydesc); ctrl->server_local->keydesc = NULL; - return rc; + return leave_cmd (ctx, rc); } @@ -734,11 +751,9 @@ clear_outbuf (&outbuf); else rc = write_and_clear_outbuf (ctx, &outbuf); - if (rc) - log_error ("command pkdecrypt failed: %s\n", gpg_strerror (rc)); xfree (ctrl->server_local->keydesc); ctrl->server_local->keydesc = NULL; - return rc; + return leave_cmd (ctx, rc); } @@ -780,9 +795,7 @@ clear_outbuf (&outbuf); else rc = write_and_clear_outbuf (ctx, &outbuf); - if (rc) - log_error ("command genkey failed: %s\n", gpg_strerror (rc)); - return rc; + return leave_cmd (ctx, rc); } @@ -825,9 +838,7 @@ gcry_sexp_release (s_pkey); } - if (rc) - log_error ("command readkey failed: %s\n", gpg_strerror (rc)); - return rc; + return leave_cmd (ctx, rc); } @@ -967,7 +978,7 @@ if (dir) closedir (dir); if (err && gpg_err_code (err) != GPG_ERR_NOT_FOUND) - log_error ("command keyinfo failed: %s\n", gpg_strerror (err)); + leave_cmd (ctx, err); return err; } @@ -1167,9 +1178,7 @@ } } - if (rc) - log_error ("command get_passphrase failed: %s\n", gpg_strerror (rc)); - return rc; + return leave_cmd (ctx, rc); } @@ -1240,9 +1249,7 @@ plus_to_blank (desc); rc = agent_get_confirmation (ctrl, desc, NULL, NULL, 0); - if (rc) - log_error ("command get_confirmation failed: %s\n", gpg_strerror (rc)); - return rc; + return leave_cmd (ctx, rc); } @@ -1259,9 +1266,7 @@ int rc; rc = agent_handle_learn (ctrl, has_option (line, "--send")? ctx : NULL); - if (rc) - log_error ("command learn failed: %s\n", gpg_strerror (rc)); - return rc; + return leave_cmd (ctx, rc); } @@ -1304,9 +1309,7 @@ leave: gcry_sexp_release (s_skey); xfree (shadow_info); - if (rc) - log_error ("command passwd failed: %s\n", gpg_strerror (rc)); - return rc; + return leave_cmd (ctx, rc); } @@ -1371,10 +1374,7 @@ if (!rc) rc = agent_put_cache (grip_clear, CACHE_MODE_ANY, passphrase, ttl); - if (rc) - log_error ("command preset_passphrase failed: %s\n", gpg_strerror (rc)); - - return rc; + return leave_cmd (ctx, rc); } @@ -1397,6 +1397,186 @@ +static const char hlp_keywrap_key[] = + "KEYWRAP_KEY [--clear] \n" + "\n" + "Return a key to wrap another key. For now the key is returned\n" + "verbatim and and thus makes not much sense because an eavesdropper on\n" + "the gpg-agent connection will see the key as well as the wrapped key.\n" + "However, this function may either be equipped with a public key\n" + "mechanism or not used at all if the key is a pre-shared key. In any\n" + "case wrapping the import and export of keys is a requirement for\n" + "certain cryptographic validations and thus useful. The key persists\n" + "a RESET command but may be cleared using the option --clear.\n" + "\n" + "Supported modes are:\n" + " --import - Return a key to import a key into gpg-agent\n" + " --export - Return a key to export a key from gpg-agent"; +static gpg_error_t +cmd_keywrap_key (assuan_context_t ctx, char *line) +{ + ctrl_t ctrl = assuan_get_pointer (ctx); + gpg_error_t err = 0; + int clearopt = has_option (line, "--clear"); + + + assuan_begin_confidential (ctx); + if (has_option (line, "--import")) + { + xfree (ctrl->server_local->import_key); + if (clearopt) + ctrl->server_local->import_key = NULL; + else if (!(ctrl->server_local->import_key = + gcry_random_bytes (KEYWRAP_KEYSIZE, GCRY_STRONG_RANDOM))) + err = gpg_error_from_syserror (); + else + err = assuan_send_data (ctx, ctrl->server_local->import_key, + KEYWRAP_KEYSIZE); + } + else if (has_option (line, "--export")) + { + xfree (ctrl->server_local->export_key); + if (clearopt) + ctrl->server_local->export_key = NULL; + else if (!(ctrl->server_local->export_key = + gcry_random_bytes (KEYWRAP_KEYSIZE, GCRY_STRONG_RANDOM))) + err = gpg_error_from_syserror (); + else + err = assuan_send_data (ctx, ctrl->server_local->export_key, + KEYWRAP_KEYSIZE); + } + else + err = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for MODE"); + assuan_end_confidential (ctx); + + return leave_cmd (ctx, err); +} + + + +static const char hlp_import_key[] = + "IMPORT_KEY\n" + "\n" + "Import a secret key into the key store. The key is expected to be\n" + "encrypted using the current session's key wrapping key (cf. command\n" + "KEYWRAP_KEY) using the AESWRAP-128 algorithm. This function takes\n" + "no arguments but uses the inquiry \"KEYDATA\" to ask for the actual\n" + "key data. The unwrapped key must be a canonical S-expression."; +static gpg_error_t +cmd_import_key (assuan_context_t ctx, char *line) +{ + ctrl_t ctrl = assuan_get_pointer (ctx); + gpg_error_t err; + unsigned char *wrappedkey = NULL; + size_t wrappedkeylen; + gcry_cipher_hd_t cipherhd = NULL; + unsigned char *key = NULL; + size_t keylen, realkeylen; + char *passphrase = NULL; + unsigned char *finalkey = NULL; + size_t finalkeylen; + unsigned char grip[20]; + + (void)line; + + if (!ctrl->server_local->import_key) + { + err = gpg_error (GPG_ERR_BAD_KEY); + goto leave; + } + + assuan_begin_confidential (ctx); + err = assuan_inquire (ctx, "KEYDATA", + &wrappedkey, &wrappedkeylen, MAXLEN_KEYDATA); + assuan_end_confidential (ctx); + if (err) + goto leave; + if (wrappedkeylen < 24) + { + err = gpg_error (GPG_ERR_INV_LENGTH); + goto leave; + } + keylen = wrappedkeylen - 8; + key = xtrymalloc_secure (keylen); + if (!key) + { + err = gpg_error_from_syserror (); + goto leave; + } + + err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128, + GCRY_CIPHER_MODE_AESWRAP, 0); + if (err) + goto leave; + err = gcry_cipher_setkey (cipherhd, + ctrl->server_local->import_key, KEYWRAP_KEYSIZE); + if (err) + goto leave; + err = gcry_cipher_decrypt (cipherhd, key, keylen, wrappedkey, wrappedkeylen); + if (err) + goto leave; + gcry_cipher_close (cipherhd); + cipherhd = NULL; + xfree (wrappedkey); + wrappedkey = NULL; + + realkeylen = gcry_sexp_canon_len (key, keylen, NULL, &err); + if (!realkeylen) + goto leave; /* Invalid canonical encoded S-expression. */ + + err = keygrip_from_canon_sexp (key, realkeylen, grip); + if (err) + goto leave; + + if (!agent_key_available (grip)) + { + err = gpg_error (GPG_ERR_EEXIST); + goto leave; + } + + err = agent_ask_new_passphrase + (ctrl, _("Please enter the passphrase to protect the " + "imported object within the GnuPG system."), + &passphrase); + if (err) + goto leave; + + if (passphrase) + { + err = agent_protect (key, passphrase, &finalkey, &finalkeylen); + if (!err) + err = agent_write_private_key (grip, finalkey, finalkeylen, 0); + } + else + err = agent_write_private_key (grip, key, realkeylen, 0); + + leave: + xfree (finalkey); + xfree (passphrase); + xfree (key); + gcry_cipher_close (cipherhd); + xfree (wrappedkey); + return leave_cmd (ctx, err); +} + + + +static const char hlp_export_key[] = + "EXPORT_KEY\n" + "\n"; +static gpg_error_t +cmd_export_key (assuan_context_t ctx, char *line) +{ + gpg_error_t err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + + /* leave: */ + return leave_cmd (ctx, err); +} + + + + static const char hlp_getval[] = "GETVAL \n" "\n" @@ -1435,9 +1615,7 @@ else return gpg_error (GPG_ERR_NO_DATA); - if (rc) - log_error ("command getval failed: %s\n", gpg_strerror (rc)); - return rc; + return leave_cmd (ctx, rc); } @@ -1520,9 +1698,7 @@ } } - if (rc) - log_error ("command putval failed: %s\n", gpg_strerror (rc)); - return rc; + return leave_cmd (ctx, rc); } @@ -1641,7 +1817,7 @@ " std_session_env - List the standard session environment.\n" " std_startup_env - List the standard startup environment.\n" " cmd_has_option\n" - " - Returns OK if the command CMD implements the option OPT."; + " - Returns OK if the command CMD implements the option OPT\n."; static gpg_error_t cmd_getinfo (assuan_context_t ctx, char *line) { @@ -1910,6 +2086,9 @@ { "INPUT", NULL }, { "OUTPUT", NULL }, { "SCD", cmd_scd, hlp_scd }, + { "KEYWRAP_KEY", cmd_keywrap_key, hlp_keywrap_key }, + { "IMPORT_KEY", cmd_import_key, hlp_import_key }, + { "EXPORT_KEY", cmd_export_key, hlp_export_key }, { "GETVAL", cmd_getval, hlp_getval }, { "PUTVAL", cmd_putval, hlp_putval }, { "UPDATESTARTUPTTY", cmd_updatestartuptty, hlp_updatestartuptty }, @@ -2021,6 +2200,9 @@ /* Cleanup. */ assuan_release (ctx); + xfree (ctrl->server_local->keydesc); + xfree (ctrl->server_local->import_key); + xfree (ctrl->server_local->export_key); if (ctrl->server_local->stopme) agent_exit (0); xfree (ctrl->server_local); Modified: trunk/agent/findkey.c =================================================================== --- trunk/agent/findkey.c 2010-06-17 12:58:51 UTC (rev 5358) +++ trunk/agent/findkey.c 2010-06-17 15:44:44 UTC (rev 5359) @@ -69,7 +69,7 @@ { log_error ("secret key file `%s' already exists\n", fname); xfree (fname); - return gpg_error (GPG_ERR_GENERAL); + return gpg_error (GPG_ERR_EEXIST); } /* FIXME: On POSIX systems we used include S_IRGRP as well. */ @@ -883,8 +883,8 @@ -/* Return the secret key as an S-Exp after locating it using the grip. - Returns NULL if key is not available. 0 = key is available */ +/* Check whether the the secret key identified by GRIP is available. + Returns 0 is the key is available. */ int agent_key_available (const unsigned char *grip) { Modified: trunk/agent/genkey.c =================================================================== --- trunk/agent/genkey.c 2010-06-17 12:58:51 UTC (rev 5358) +++ trunk/agent/genkey.c 2010-06-17 15:44:44 UTC (rev 5359) @@ -1,5 +1,5 @@ /* genkey.c - Generate a keypair - * Copyright (C) 2002, 2003, 2004, 2007 Free Software Foundation, Inc. + * Copyright (C) 2002, 2003, 2004, 2007, 2010 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -286,7 +286,70 @@ } +/* Ask the user for a new passphrase using PROMPT. On success the + function returns 0 and store the passphrase at R_PASSPHRASE; if the + user opted not to use a passphrase NULL will be stored there. The + user needs to free the returned string. In case of an error and + error code is returned and NULL stored at R_PASSPHRASE. */ +gpg_error_t +agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt, + char **r_passphrase) +{ + gpg_error_t err; + const char *text1 = prompt; + const char *text2 = _("Please re-enter this passphrase"); + const char *initial_errtext = NULL; + struct pin_entry_info_s *pi, *pi2; + + *r_passphrase = NULL; + pi = gcry_calloc_secure (2, sizeof (*pi) + 100); + pi2 = pi + (sizeof *pi + 100); + pi->max_length = 100; + pi->max_tries = 3; + pi->with_qualitybar = 1; + pi2->max_length = 100; + pi2->max_tries = 3; + pi2->check_cb = reenter_compare_cb; + pi2->check_cb_arg = pi->pin; + + next_try: + err = agent_askpin (ctrl, text1, NULL, initial_errtext, pi); + initial_errtext = NULL; + if (!err) + { + if (check_passphrase_constraints (ctrl, pi->pin, 0)) + { + pi->failed_tries = 0; + pi2->failed_tries = 0; + goto next_try; + } + /* Unless the passphrase is empty, ask to confirm it. */ + if (pi->pin && *pi->pin) + { + err = agent_askpin (ctrl, text2, NULL, NULL, pi2); + if (err == -1) + { /* The re-entered one did not match and the user did not + hit cancel. */ + initial_errtext = _("does not match - try again"); + goto next_try; + } + } + } + + if (!err && *pi->pin) + { + /* User wants a passphrase. */ + *r_passphrase = xtrystrdup (pi->pin); + if (!*r_passphrase) + err = gpg_error_from_syserror (); + } + xfree (pi); + return err; +} + + + /* Generate a new keypair according to the parameters given in KEYPARAM */ int @@ -294,7 +357,7 @@ membuf_t *outbuf) { gcry_sexp_t s_keyparam, s_key, s_private, s_public; - struct pin_entry_info_s *pi, *pi2; + char *passphrase = NULL; int rc; size_t len; char *buf; @@ -307,63 +370,19 @@ } /* Get the passphrase now, cause key generation may take a while. */ - { - const char *text1 = _("Please enter the passphrase to%0A" - "to protect your new key"); - const char *text2 = _("Please re-enter this passphrase"); - const char *initial_errtext = NULL; + rc = agent_ask_new_passphrase (ctrl, + _("Please enter the passphrase to%0A" + "to protect your new key"), + &passphrase); + if (rc) + return rc; - pi = gcry_calloc_secure (2, sizeof (*pi) + 100); - pi2 = pi + (sizeof *pi + 100); - pi->max_length = 100; - pi->max_tries = 3; - pi->with_qualitybar = 1; - pi2->max_length = 100; - pi2->max_tries = 3; - pi2->check_cb = reenter_compare_cb; - pi2->check_cb_arg = pi->pin; - - next_try: - rc = agent_askpin (ctrl, text1, NULL, initial_errtext, pi); - initial_errtext = NULL; - if (!rc) - { - if (check_passphrase_constraints (ctrl, pi->pin, 0)) - { - pi->failed_tries = 0; - pi2->failed_tries = 0; - goto next_try; - } - if (pi->pin && *pi->pin) - { - rc = agent_askpin (ctrl, text2, NULL, NULL, pi2); - if (rc == -1) - { /* The re-entered one did not match and the user did not - hit cancel. */ - initial_errtext = _("does not match - try again"); - goto next_try; - } - } - } - if (rc) - { - xfree (pi); - return rc; - } - - if (!*pi->pin) - { - xfree (pi); - pi = NULL; /* User does not want a passphrase. */ - } - } - rc = gcry_pk_genkey (&s_key, s_keyparam ); gcry_sexp_release (s_keyparam); if (rc) { log_error ("key generation failed: %s\n", gpg_strerror (rc)); - xfree (pi); + xfree (passphrase); return rc; } @@ -373,7 +392,7 @@ { log_error ("key generation failed: invalid return value\n"); gcry_sexp_release (s_key); - xfree (pi); + xfree (passphrase); return gpg_error (GPG_ERR_INV_DATA); } s_public = gcry_sexp_find_token (s_key, "public-key", 0); @@ -382,7 +401,7 @@ log_error ("key generation failed: invalid return value\n"); gcry_sexp_release (s_private); gcry_sexp_release (s_key); - xfree (pi); + xfree (passphrase); return gpg_error (GPG_ERR_INV_DATA); } gcry_sexp_release (s_key); s_key = NULL; @@ -390,8 +409,9 @@ /* store the secret key */ if (DBG_CRYPTO) log_debug ("storing private key\n"); - rc = store_key (s_private, pi? pi->pin:NULL, 0); - xfree (pi); pi = NULL; + rc = store_key (s_private, passphrase, 0); + xfree (passphrase); + passphrase = NULL; gcry_sexp_release (s_private); if (rc) { @@ -423,65 +443,20 @@ -/* Apply a new passpahrse to the key S_SKEY and store it. */ +/* Apply a new passphrase to the key S_SKEY and store it. */ int agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey) { - struct pin_entry_info_s *pi, *pi2; int rc; + char *passphrase; - { - const char *text1 = _("Please enter the new passphrase"); - const char *text2 = _("Please re-enter this passphrase"); - const char *initial_errtext = NULL; - - pi = gcry_calloc_secure (2, sizeof (*pi) + 100); - pi2 = pi + (sizeof *pi + 100); - pi->max_length = 100; - pi->max_tries = 3; - pi->with_qualitybar = 1; - pi2->max_length = 100; - pi2->max_tries = 3; - pi2->check_cb = reenter_compare_cb; - pi2->check_cb_arg = pi->pin; - - next_try: - rc = agent_askpin (ctrl, text1, NULL, initial_errtext, pi); - initial_errtext = NULL; - if (!rc) - { - if (check_passphrase_constraints (ctrl, pi->pin, 0)) - { - pi->failed_tries = 0; - pi2->failed_tries = 0; - goto next_try; - } - /* Unless the passphrase is empty, ask to confirm it. */ - if (pi->pin && *pi->pin) - { - rc = agent_askpin (ctrl, text2, NULL, NULL, pi2); - if (rc == -1) - { /* The re-entered one did not match and the user did not - hit cancel. */ - initial_errtext = _("does not match - try again"); - goto next_try; - } - } - } - if (rc) - { - xfree (pi); - return rc; - } - - if (!*pi->pin) - { - xfree (pi); - pi = NULL; /* User does not want a passphrase. */ - } - } - - rc = store_key (s_skey, pi? pi->pin:NULL, 1); - xfree (pi); + rc = agent_ask_new_passphrase (ctrl, + _("Please enter the new passphrase"), + &passphrase); + if (!rc) + { + rc = store_key (s_skey, passphrase, 1); + xfree (passphrase); + } return rc; } Modified: trunk/agent/preset-passphrase.c =================================================================== --- trunk/agent/preset-passphrase.c 2010-06-17 12:58:51 UTC (rev 5358) +++ trunk/agent/preset-passphrase.c 2010-06-17 15:44:44 UTC (rev 5359) @@ -43,7 +43,6 @@ #define JNLIB_NEED_LOG_LOGV #include "agent.h" -#include "minip12.h" #include "simple-pwquery.h" #include "i18n.h" #include "sysutils.h" Modified: trunk/agent/protect-tool.c =================================================================== --- trunk/agent/protect-tool.c 2010-06-17 12:58:51 UTC (rev 5358) +++ trunk/agent/protect-tool.c 2010-06-17 15:44:44 UTC (rev 5359) @@ -40,7 +40,6 @@ #define JNLIB_NEED_LOG_LOGV #include "agent.h" -#include "minip12.h" #include "i18n.h" #include "get-passphrase.h" #include "sysutils.h" @@ -63,8 +62,6 @@ oS2Kcalibration, oCanonical, - oP12Import, - oP12Export, oP12Charset, oStore, oForce, @@ -116,11 +113,6 @@ ARGPARSE_c (oShadow, "shadow", "create a shadow entry for a public key"), ARGPARSE_c (oShowShadowInfo, "show-shadow-info", "return the shadow info"), ARGPARSE_c (oShowKeygrip, "show-keygrip", "show the \"keygrip\""), - ARGPARSE_c (oP12Import, "p12-import", - "import a pkcs#12 encoded private key"), - ARGPARSE_c (oP12Export, "p12-export", - "export a private key pkcs#12 encoded"), - ARGPARSE_c (oS2Kcalibration, "s2k-calibration", "@"), ARGPARSE_group (301, N_("@\nOptions:\n ")), @@ -635,7 +627,7 @@ return err? -1:0; } - +#if 0 /* A callback used by p12_parse to return a certificate. */ static void import_p12_cert_cb (void *opaque, const unsigned char *cert, size_t certlen) @@ -793,6 +785,7 @@ xfree (result); } +#endif @@ -865,6 +858,7 @@ } +#if 0 static void export_p12_file (const char *fname) { @@ -1009,6 +1003,7 @@ fwrite (key, keylen, 1, stdout); xfree (key); } +#endif @@ -1059,8 +1054,6 @@ case oShadow: cmd = oShadow; break; case oShowShadowInfo: cmd = oShowShadowInfo; break; case oShowKeygrip: cmd = oShowKeygrip; break; - case oP12Import: cmd = oP12Import; break; - case oP12Export: cmd = oP12Export; break; case oP12Charset: opt_p12_charset = pargs.r.ret_str; break; case oS2Kcalibration: cmd = oS2Kcalibration; break; @@ -1105,10 +1098,6 @@ show_shadow_info (fname); else if (cmd == oShowKeygrip) show_keygrip (fname); - else if (cmd == oP12Import) - import_p12_file (fname); - else if (cmd == oP12Export) - export_p12_file (fname); else if (cmd == oS2Kcalibration) { if (!opt.verbose) Modified: trunk/agent/protect.c =================================================================== --- trunk/agent/protect.c 2010-06-17 12:58:51 UTC (rev 5358) +++ trunk/agent/protect.c 2010-06-17 15:44:44 UTC (rev 5359) @@ -415,7 +415,7 @@ unsigned char *p; gcry_md_hd_t md; - /* Create an S-expression with the procted-at timestamp. */ + /* Create an S-expression with the protected-at timestamp. */ memcpy (timestamp_exp, "(12:protected-at15:", 19); gnupg_get_isotime (timestamp_exp+19); timestamp_exp[19+15] = ')'; Modified: trunk/common/membuf.c =================================================================== --- trunk/common/membuf.c 2010-06-17 12:58:51 UTC (rev 5358) +++ trunk/common/membuf.c 2010-06-17 15:44:44 UTC (rev 5359) @@ -59,7 +59,7 @@ void put_membuf (membuf_t *mb, const void *buf, size_t len) { - if (mb->out_of_core) + if (mb->out_of_core || !len) return; if (mb->len + len >= mb->size) Modified: trunk/common/sexputil.c =================================================================== --- trunk/common/sexputil.c 2010-06-17 12:58:51 UTC (rev 5358) +++ trunk/common/sexputil.c 2010-06-17 15:44:44 UTC (rev 5359) @@ -36,7 +36,7 @@ #include "sexp-parse.h" -/* Helper function to create a a canonical encoded S-expression from a +/* Helper function to create a canonical encoded S-expression from a Libgcrypt S-expression object. The function returns 0 on success and the malloced canonical S-expression is stored at R_BUFFER and the allocated length at R_BUFLEN. On error an error code is @@ -71,6 +71,36 @@ } +/* Same as make_canon_sexp but pad the buffer to multiple of 64 + bits. */ +gpg_error_t +make_canon_sexp_pad (gcry_sexp_t sexp, + unsigned char **r_buffer, size_t *r_buflen) +{ + size_t len; + unsigned char *buf; + + *r_buffer = NULL; + if (r_buflen) + *r_buflen = 0;; + + len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, NULL, 0); + if (!len) + return gpg_error (GPG_ERR_BUG); + len += (8 - len % 8) % 8; + buf = xtrycalloc (1, len); + if (!buf) + return gpg_error_from_syserror (); + if (!gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, buf, len)) + return gpg_error (GPG_ERR_BUG); + + *r_buffer = buf; + if (r_buflen) + *r_buflen = len; + + return 0; +} + /* Return the so called "keygrip" which is the SHA-1 hash of the public key parameters expressed in a way depended on the algorithm. Modified: trunk/common/util.h =================================================================== --- trunk/common/util.h 2010-06-17 12:58:51 UTC (rev 5358) +++ trunk/common/util.h 2010-06-17 15:44:44 UTC (rev 5359) @@ -146,6 +146,8 @@ /*-- sexputil.c */ gpg_error_t make_canon_sexp (gcry_sexp_t sexp, unsigned char **r_buffer, size_t *r_buflen); +gpg_error_t make_canon_sexp_pad (gcry_sexp_t sexp, + unsigned char **r_buffer, size_t *r_buflen); gpg_error_t keygrip_from_canon_sexp (const unsigned char *key, size_t keylen, unsigned char *grip); int cmp_simple_canon_sexp (const unsigned char *a, const unsigned char *b); Modified: trunk/dirmngr/http.c =================================================================== --- trunk/dirmngr/http.c 2010-06-17 12:58:51 UTC (rev 5358) +++ trunk/dirmngr/http.c 2010-06-17 15:44:44 UTC (rev 5359) @@ -38,6 +38,8 @@ an exit handler to cleanup the socket layer. */ +#warning Duplicated code with common/http.c + #ifdef HAVE_CONFIG_H # include #endif Modified: trunk/doc/dirmngr.texi =================================================================== --- trunk/doc/dirmngr.texi 2010-06-17 12:58:51 UTC (rev 5358) +++ trunk/doc/dirmngr.texi 2010-06-17 15:44:44 UTC (rev 5359) @@ -786,3 +786,254 @@ @end ifset @include see-also-note.texi + at c + at c !!! UNDER CONSTRUCTION !!! + at c + at c + at c @section Verifying a Certificate + at c + at c There are several ways to request services from Dirmngr. Almost all of + at c them are done using the Assuan protocol. What we describe here is the + at c Assuan command CHECKCRL as used for example by the dirmnr-client tool if + at c invoked as + at c + at c @example + at c dirmngr-client foo.crt + at c @end example + at c + at c This command will send an Assuan request to an already running Dirmngr + at c instance. foo.crt is expected to be a standard X.509 certificate and + at c dirmngr will receive the Assuan command + at c + at c @example + at c CHECKCRL @var [{fingerprint}] + at c @end example + at c + at c @var{fingerprint} is optional and expected to be the SHA-1 has of the + at c DER encoding of the certificate under question. It is to be HEX + at c encoded. The rationale for sending the fingerprint is that it allows + at c dirmngr to reply immediatly if it has already cached such a request. If + at c this is not the case and no certificate has been found in dirmngr's + at c internal certificate storage, dirmngr will request the certificate using + at c the Assuan inquiry + at c + at c @example + at c INQUIRE TARGETCERT + at c @end example + at c + at c The caller (in our example dirmngr-client) is then expected to return + at c the certificate for the request (which should match @var{fingerprint}) + at c as a binary blob. + at c + at c Dirmngr now passes control to @code{crl_cache_cert_isvalid}. This + at c function checks whether a CRL item exists for target certificate. These + at c CRL items are kept in a database of already loaded and verified CRLs. + at c This mechanism is called the CRL cache. Obviously timestamps are kept + at c there with each item to cope with the expiration date of the CRL. The + at c possible return values are: @code{0} to indicate that a valid CRL is + at c available for the certificate and the certificate itself is not listed + at c in this CRL, @code{GPG_ERR_CERT_REVOKED} to indicate that the certificate is + at c listed in the CRL or @code{GPG_ERR_NO_CRL_KNOWN} in cases where no CRL or no + at c information is available. The first two codes are immediatly returned to + at c the caller and the processing of this request has been done. + at c + at c Only the @code{GPG_ERR_NO_CRL_KNOWN} needs more attention: Dirmngr now + at c calls @code{clr_cache_reload_crl} and if this succeeds calls + at c @code{crl_cache_cert_isvald) once more. All further errors are + at c immediately returned to the caller. + at c + at c @code{crl_cache_reload_crl} is the actual heart of the CRL management. + at c It locates the corresponding CRL for the target certificate, reads and + at c verifies this CRL and stores it in the CRL cache. It works like this: + at c + at c * Loop over all crlDPs in the target certificate. + at c * If the crlDP is invalid immediately terminate the loop. + at c * Loop over all names in the current crlDP. + at c * If the URL scheme is unknown or not enabled + at c (--ignore-http-dp, --ignore-ldap-dp) continues with + at c the next name. + at c * @code{crl_fetch} is called to actually retrieve the CRL. + at c In case of problems this name is ignore and we continue with + at c the next name. Note that @code{crl_fetch} does only return + at c a descriptor for the CRL for further reading so does the CRL + at c does not yet end up in memory. + at c * @code{crl_cache_insert} is called with that descriptor to + at c actually read the CRL into the cache. See below for a + at c description of this function. If there is any error (e.g. read + at c problem, CRL not correctly signed or verification of signature + at c not possible), this descriptor is rejected and we continue + at c with the next name. If the CRL has been successfully loaded, + at c the loop is terminated. + at c * If no crlDP has been found in the previous loop use a default CRL. + at c Note, that if any crlDP has been found but loading of the CRL failed, + at c this condition is not true. + at c * Try to load a CRL from all configured servers (ldapservers.conf) + at c in turn. The first server returning a CRL is used. + at c * @code(crl_cache_insert) is then used to actually insert the CRL + at c into the cache. If this failed we give up immediatley without + at c checking the rest of the servers from the first step. + at c * Ready. + at c + at c + at c The @code{crl_cache_insert} function takes care of reading the bulk of + at c the CRL, parsing it and checking the signature. It works like this: A + at c new database file is created using a temporary file name. The CRL + at c parsing machinery is started and all items of the CRL are put into + at c this database file. At the end the issuer certificate of the CRL + at c needs to be retrieved. Three cases are to be distinguished: + at c + at c a) An authorityKeyIdentifier with an issuer and serialno exits: The + at c certificate is retrieved using @code{find_cert_bysn}. If + at c the certificate is in the certificate cache, it is directly + at c returned. Then the requester (i.e. the client who requested the + at c CRL check) is asked via the Assuan inquiry ``SENDCERT'' whether + at c he can provide this certificate. If this succeed the returned + at c certificate gets cached and returned. Note, that dirmngr does not + at c verify in any way whether the expected certificate is returned. + at c It is in the interest of the client to return a useful certificate + at c as otherwise the service request will fail due to a bad signature. + at c The last way to get the certificate is by looking it up at + at c external resources. This is done using the @code{ca_cert_fetch} + at c and @code{fetch_next_ksba_cert} and comparing the returned + at c certificate to match the requested issuer and seriano (This is + at c needed because the LDAP layer may return several certificates as + at c LDAP as no standard way to retrieve by serial number). + at c + at c b) An authorityKeyIdentifier with a key ID exists: The certificate is + at c retrieved using @code{find_cert_bysubject}. If the certificate is + at c in the certificate cache, it is directly returned. Then the + at c requester is asked via the Assuan inquiry ``SENDCERT_SKI'' whether + at c he can provide this certificate. If this succeed the returned + at c certificate gets cached and returned. Note, that dirmngr does not + at c verify in any way whether the expected certificate is returned. + at c It is in the interest of the client to return a useful certificate + at c as otherwise the service request will fail due to a bad signature. + at c The last way to get the certificate is by looking it up at + at c external resources. This is done using the @code{ca_cert_fetch} + at c and @code{fetch_next_ksba_cert} and comparing the returned + at c certificate to match the requested subject and key ID. + at c + at c c) No authorityKeyIdentifier exits: The certificate is retrieved + at c using @code{find_cert_bysubject} without the key ID argument. If + at c the certificate is in the certificate cache the first one with a + at c matching subject is is directly returned. Then the requester is + at c asked via the Assuan inquiry ``SENDCERT'' and an exact + at c specification of the subject whether he can + at c provide this certificate. If this succeed the returned + at c certificate gets cached and returned. Note, that dirmngr does not + at c verify in any way whether the expected certificate is returned. + at c It is in the interest of the client to return a useful certificate + at c as otherwise the service request will fail due to a bad signature. + at c The last way to get the certificate is by looking it up at + at c external resources. This is done using the @code{ca_cert_fetch} + at c and @code{fetch_next_ksba_cert} and comparing the returned + at c certificate to match the requested subject; the first certificate + at c with a matching subject is then returned. + at c + at c If no certificate was found, the function returns with the error + at c GPG_ERR_MISSING_CERT. Now the signature is verified. If this fails, + at c the erro is returned. On success the @code{validate_cert_chain} is + at c used to verify that the certificate is actually valid. + at c + at c Here we may encounter a recursive situation: + at c @code{validate_cert_chain} needs to look at other certificates and + at c also at CRLs to check whether tehse other certificates and well, the + at c CRL issuer certificate itself are not revoked. FIXME: We need to make + at c sure that @code{validate_cert_chain} does not try to lookup the CRL we + at c are currently processing. This would be a catch-22 and may indicate a + at c broken PKI. However, due to overlapping expiring times and imprecise + at c clocks thsi may actually happen. + at c + at c For historical reasons the Assuan command ISVALID is a bit different + at c to CHECKCRL but this is mainly due to different calling conventions. + at c In the end the same fucntionality is used, albeit hidden by a couple + at c of indirection and argument and result code mangling. It furthere + at c ingetrages OCSP checking depending on options are the way it is + at c called. GPGSM still uses this command but might eventuall switch over + at c to CHECKCRL and CHECKOCSP so that ISVALID can be retired. + at c + at c + at c @section Validating a certificate + at c + at c We describe here how the internal function @code{validate_cert_chain} + at c works. Note that mainly testing purposes this functionality may be + at c called directly using @cmd{dirmngr-client --validate @file{foo.crt}}. + at c + at c For backward compatibility this function returns success if Dirmngr is + at c not used as a system daemon. Thus not validating the certicates at + at c all. FIXME: This is definitely not correct and should be fixed ASAP. + at c + at c The function takes the target certificate and a mode argument as + at c parameters and returns an error code and optionally the closes + at c expiration time of all certificates in the chain. + at c + at c We first check that the certificate may be used for the requested + at c purpose (i.e. OCSP or CRL signing). If this is not the case + at c GPG_ERR_WRONG_KEY_USAGE is returned. + at c + at c The next step is to find the trust anchor (root certificate) and to + at c assemble the chain in memory: Starting with the target certificate, + at c the expiration time is checked against the current date, unknown + at c critical extensions are detected and certificate policies are matched + at c (We only allow 2.289.9.9 but I have no clue about that OID and from + at c where I got it - it does not even seem to be assigned - debug cruft?). + at c + at c Now if this certificate is a self-signed one, we have reached the + at c trust anchor. In this case we check that the signature is good, the + at c certificate is allowed to act as a CA, that it is a trusted one (by + at c checking whether it is has been put into the trusted-certs + at c configuration directory) and finally prepend into to our list + at c representing the certificate chain. This steps ends then. + at c + at c If it is not a self-signed certificate, we check that the chain won't + at c get too long (current limit is 100), if this is the case we terminate + at c with the error GPG_ERR_BAD_CERT_CHAIN. + at c + at c Now the issuer's certificate is looked up: If an + at c authorityKeyIdentifier is available, this one is used to locate the + at c certificate either using issuer and serialnumber or subject DN + at c (i.e. the issuer's DN) and the keyID. The functions + at c @code{find_cert_bysn) and @code{find_cert_bysubject} are used + at c respectively. The have already been described above under the + at c description of @code{crl_cache_insert}. If no certificate was found + at c or with no authorityKeyIdentifier, only the cache is consulted using + at c @code{get_cert_bysubject}. The latter is is done under the assumption + at c that a matching certificate has explicitly been put into the + at c certificate cache. If the issuer's certificate could not be found, + at c the validation terminates with the error code @code{GPG_ERR_MISSING_CERT}. + at c + at c If the issuer's certificate has been found, the signature of the + at c actual certificate is checked and in case this fails the error + at c #code{GPG_ERR_BAD_CERT_CHAIN} is returned. If the signature checks out, the + at c maximum cahin length of the issueing certificate is checked as well as + at c the capiblity of the certificate (i.e. whether he may be used for + at c certificate signing). Then the certificate is prepended to our list + at c representing the certificate chain. Finally the loop is continued now + at c with the issuer's certificate as the current certificate. + at c + at c After the end of the loop and if no error as been encountered + at c (i.e. the certificate chain has been assempled correctly), a check is + at c done whether any certificate expired or a critical policy has not been + at c met. In any of these cases the validation terminates with an + at c appropriate error. + at c + at c Finally the function @code{check_revocations} is called to verify no + at c certificate in the assempled chain has been revoked: This is an + at c recursive process because a CRL has to be checked for each certificate + at c in the chain except for the root certificate, of which we already know + at c that it is trusted and we avoid checking a CRL here due to common + at c setup problems and the assumption that a revoked root certifcate has + at c been removed from the list of trusted certificates. + at c + at c + at c + at c + at c @section Looking up certificates through LDAP. + at c + at c This describes the LDAP layer to retrieve certificates. + at c the functions @code{ca_cert_fetch} and @code{fetch_next_ksba_cert} are + at c used for this. The first one starts a search and the second one is + at c used to retrieve certificate after certificate. + at c + + Modified: trunk/g10/gpg.c =================================================================== --- trunk/g10/gpg.c 2010-06-17 12:58:51 UTC (rev 5358) +++ trunk/g10/gpg.c 2010-06-17 15:44:44 UTC (rev 5359) @@ -1976,11 +1976,7 @@ opt.compress_algo = -1; /* defaults to DEFAULT_COMPRESS_ALGO */ opt.s2k_mode = 3; /* iterated+salted */ opt.s2k_count = 0; /* Auto-calibrate when needed. */ -#ifdef USE_CAST5 opt.s2k_cipher_algo = CIPHER_ALGO_CAST5; -#else - opt.s2k_cipher_algo = CIPHER_ALGO_3DES; -#endif opt.completes_needed = 1; opt.marginals_needed = 3; opt.max_cert_depth = 5; Modified: trunk/sm/Makefile.am =================================================================== --- trunk/sm/Makefile.am 2010-06-17 12:58:51 UTC (rev 5358) +++ trunk/sm/Makefile.am 2010-06-17 15:44:44 UTC (rev 5359) @@ -49,6 +49,7 @@ delete.c \ certreqgen.c \ certreqgen-ui.c \ + minip12.c minip12.h \ qualified.c Modified: trunk/sm/call-agent.c =================================================================== --- trunk/sm/call-agent.c 2010-06-17 12:58:51 UTC (rev 5358) +++ trunk/sm/call-agent.c 2010-06-17 15:44:44 UTC (rev 5359) @@ -1,6 +1,6 @@ /* call-agent.c - Divert GPGSM operations to the agent * Copyright (C) 2001, 2002, 2003, 2005, 2007, - * 2008, 2009 Free Software Foundation, Inc. + * 2008, 2009, 2010 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -66,7 +66,15 @@ membuf_t *data; }; +struct import_key_parm_s +{ + ctrl_t ctrl; + assuan_context_t ctx; + const void *key; + size_t keylen; +}; + /* Try to connect to the agent via socket or fork it off and work by pipes. Handle the server's initial greeting */ @@ -1066,3 +1074,130 @@ return err; } + + +/* Ask for the passphrase (this is used for pkcs#12 import/export. On + success the caller needs to free the string stored at R_PASSPHRASE. + On error NULL will be stored at R_PASSPHRASE and an appropriate + error code returned. */ +gpg_error_t +gpgsm_agent_ask_passphrase (ctrl_t ctrl, const char *desc_msg, + char **r_passphrase) +{ + gpg_error_t err; + char line[ASSUAN_LINELENGTH]; + char *arg4 = NULL; + membuf_t data; + + *r_passphrase = NULL; + + err = start_agent (ctrl); + if (err) + return err; + + if (desc_msg && *desc_msg && !(arg4 = percent_plus_escape (desc_msg))) + return gpg_error_from_syserror (); + + snprintf (line, DIM(line)-1, "GET_PASSPHRASE --data -- X X X %s", arg4); + xfree (arg4); + + init_membuf_secure (&data, 64); + err = assuan_transact (agent_ctx, line, + membuf_data_cb, &data, + default_inq_cb, NULL, NULL, NULL); + + if (err) + xfree (get_membuf (&data, NULL)); + else + { + put_membuf (&data, "", 1); + *r_passphrase = get_membuf (&data, NULL); + if (!*r_passphrase) + err = gpg_error_from_syserror (); + } + return err; +} + + + +/* Retrieve a key encryption key from the agent. With FOREXPORT true + the key shall be use for export, with false for import. On success + the new key is stored at R_KEY and its length at R_KEKLEN. */ +gpg_error_t +gpgsm_agent_keywrap_key (ctrl_t ctrl, int forexport, + void **r_kek, size_t *r_keklen) +{ + gpg_error_t err; + membuf_t data; + size_t len; + unsigned char *buf; + char line[ASSUAN_LINELENGTH]; + + *r_kek = NULL; + err = start_agent (ctrl); + if (err) + return err; + + snprintf (line, DIM(line)-1, "KEYWRAP_KEY %s", + forexport? "--export":"--import"); + + init_membuf_secure (&data, 64); + err = assuan_transact (agent_ctx, line, + membuf_data_cb, &data, + default_inq_cb, ctrl, NULL, NULL); + if (err) + { + xfree (get_membuf (&data, &len)); + return err; + } + buf = get_membuf (&data, &len); + if (!buf) + return gpg_error_from_syserror (); + *r_kek = buf; + *r_keklen = len; + return 0; +} + + + + +/* Handle the inquiry for an IMPORT_KEY command. */ +static gpg_error_t +inq_import_key_parms (void *opaque, const char *line) +{ + struct import_key_parm_s *parm = opaque; + gpg_error_t err; + + if (!strncmp (line, "KEYDATA", 7) && (line[7]==' '||!line[7])) + { + assuan_begin_confidential (parm->ctx); + err = assuan_send_data (parm->ctx, parm->key, parm->keylen); + assuan_end_confidential (parm->ctx); + } + else + err = default_inq_cb (parm->ctrl, line); + + return err; +} + + +/* Call the agent to import a key into the agent. */ +gpg_error_t +gpgsm_agent_import_key (ctrl_t ctrl, const void *key, size_t keylen) +{ + gpg_error_t err; + struct import_key_parm_s parm; + + err = start_agent (ctrl); + if (err) + return err; + + parm.ctrl = ctrl; + parm.ctx = agent_ctx; + parm.key = key; + parm.keylen = keylen; + + err = assuan_transact (agent_ctx, "IMPORT_KEY", + NULL, NULL, inq_import_key_parms, &parm, NULL, NULL); + return err; +} Modified: trunk/sm/gpgsm.h =================================================================== --- trunk/sm/gpgsm.h 2010-06-17 12:58:51 UTC (rev 5358) +++ trunk/sm/gpgsm.h 2010-06-17 15:44:44 UTC (rev 5359) @@ -405,6 +405,12 @@ gpg_error_t gpgsm_agent_send_nop (ctrl_t ctrl); gpg_error_t gpgsm_agent_keyinfo (ctrl_t ctrl, const char *hexkeygrip, char **r_serialno); +gpg_error_t gpgsm_agent_ask_passphrase (ctrl_t ctrl, const char *desc_msg, + char **r_passphrase); +gpg_error_t gpgsm_agent_keywrap_key (ctrl_t ctrl, int forexport, + void **r_kek, size_t *r_keklen); +gpg_error_t gpgsm_agent_import_key (ctrl_t ctrl, + const void *key, size_t keylen); /*-- call-dirmngr.c --*/ int gpgsm_dirmngr_isvalid (ctrl_t ctrl, Modified: trunk/sm/import.c =================================================================== --- trunk/sm/import.c 2010-06-17 12:58:51 UTC (rev 5358) +++ trunk/sm/import.c 2010-06-17 15:44:44 UTC (rev 5359) @@ -35,8 +35,13 @@ #include "i18n.h" #include "sysutils.h" #include "../kbx/keybox.h" /* for KEYBOX_FLAG_* */ +#include "../common/membuf.h" +#include "minip12.h" +/* The arbitrary limit of one PKCS#12 object. */ +#define MAX_P12OBJ_SIZE 128 /*kb*/ + struct stats_s { unsigned long count; unsigned long imported; @@ -48,8 +53,19 @@ }; +struct rsa_secret_key_s +{ + gcry_mpi_t n; /* public modulus */ + gcry_mpi_t e; /* public exponent */ + gcry_mpi_t d; /* exponent */ + gcry_mpi_t p; /* prime p. */ + gcry_mpi_t q; /* prime q. */ + gcry_mpi_t u; /* inverse of p mod q. */ +}; + + static gpg_error_t parse_p12 (ctrl_t ctrl, ksba_reader_t reader, - estream_t *retfp, struct stats_s *stats); + struct stats_s *stats); @@ -325,51 +341,11 @@ any = 1; } else if (ct == KSBA_CT_PKCS12) - { /* This seems to be a pkcs12 message. We use an external - tool to parse the message and to store the private keys. - We need to use a another reader here to parse the - certificate we included in the p12 file; then we continue - to look for other pkcs12 files (works only if they are in - PEM format. */ - estream_t certfp; - Base64Context b64p12rdr; - ksba_reader_t p12rdr; - - rc = parse_p12 (ctrl, reader, &certfp, stats); + { + /* This seems to be a pkcs12 message. */ + rc = parse_p12 (ctrl, reader, stats); if (!rc) - { From cvs at cvs.gnupg.org Fri Jun 18 10:08:22 2010 From: cvs at cvs.gnupg.org (svn author wk) Date: Fri, 18 Jun 2010 10:08:22 +0200 Subject: [svn] GnuPG - r5360 - branches/STABLE-BRANCH-1-4/g10 Message-ID: Author: wk Date: 2010-06-18 10:08:21 +0200 (Fri, 18 Jun 2010) New Revision: 5360 Modified: branches/STABLE-BRANCH-1-4/g10/ChangeLog branches/STABLE-BRANCH-1-4/g10/parse-packet.c Log: Backport bug fix. Fixes bug#1240. Modified: branches/STABLE-BRANCH-1-4/g10/ChangeLog =================================================================== --- branches/STABLE-BRANCH-1-4/g10/ChangeLog 2010-06-17 15:44:44 UTC (rev 5359) +++ branches/STABLE-BRANCH-1-4/g10/ChangeLog 2010-06-18 08:08:21 UTC (rev 5360) @@ -1,3 +1,8 @@ +2010-06-18 Werner Koch + + * parse-packet.c (skip_packet, parse_gpg_control): Take care of + premature EOFs. Backport from trunk. + 2010-06-01 Werner Koch * gpg.c (main): Add dummy option --debug-level and ignore Modified: branches/STABLE-BRANCH-1-4/g10/parse-packet.c =================================================================== --- branches/STABLE-BRANCH-1-4/g10/parse-packet.c 2010-06-17 15:44:44 UTC (rev 5359) +++ branches/STABLE-BRANCH-1-4/g10/parse-packet.c 2010-06-18 08:08:21 UTC (rev 5360) @@ -622,7 +622,11 @@ else { for( ; pktlen; pktlen-- ) - dump_hex_line(iobuf_get(inp), &i); + { + dump_hex_line ((c=iobuf_get(inp)), &i); + if (c==-1) + break; + } } putc ('\n', listfp); return; @@ -2441,7 +2445,11 @@ } else { for( ; pktlen; pktlen-- ) - dump_hex_line(iobuf_get(inp), &i); + { + dump_hex_line ((c=iobuf_get (inp)), &i); + if (c == -1) + break; + } } putc ('\n', listfp); } From cvs at cvs.gnupg.org Fri Jun 18 10:08:50 2010 From: cvs at cvs.gnupg.org (svn author wk) Date: Fri, 18 Jun 2010 10:08:50 +0200 Subject: [svn] GnuPG - r5361 - branches/STABLE-BRANCH-2-0/g10 Message-ID: Author: wk Date: 2010-06-18 10:08:49 +0200 (Fri, 18 Jun 2010) New Revision: 5361 Modified: branches/STABLE-BRANCH-2-0/g10/ChangeLog branches/STABLE-BRANCH-2-0/g10/parse-packet.c Log: Backport bug fix. Fixes bug#1240. Modified: branches/STABLE-BRANCH-2-0/g10/ChangeLog =================================================================== --- branches/STABLE-BRANCH-2-0/g10/ChangeLog 2010-06-18 08:08:21 UTC (rev 5360) +++ branches/STABLE-BRANCH-2-0/g10/ChangeLog 2010-06-18 08:08:49 UTC (rev 5361) @@ -1,3 +1,8 @@ +2010-06-18 Werner Koch + + * parse-packet.c (skip_packet, parse_gpg_control): Take care of + premature EOFs. Backport from trunk. + 2010-06-17 Werner Koch * gpg.c (main): Use CAST5 as default s2k algo. The macro Modified: branches/STABLE-BRANCH-2-0/g10/parse-packet.c =================================================================== --- branches/STABLE-BRANCH-2-0/g10/parse-packet.c 2010-06-18 08:08:21 UTC (rev 5360) +++ branches/STABLE-BRANCH-2-0/g10/parse-packet.c 2010-06-18 08:08:49 UTC (rev 5361) @@ -682,7 +682,11 @@ else { for( ; pktlen; pktlen-- ) - dump_hex_line(iobuf_get(inp), &i); + { + dump_hex_line ((c=iobuf_get(inp)), &i); + if (c == -1) + break; + } } putc ('\n', listfp); return; @@ -2529,7 +2533,11 @@ } else { for( ; pktlen; pktlen-- ) - dump_hex_line(iobuf_get(inp), &i); + { + dump_hex_line ((c=iobuf_get (inp)), &i); + if (c == -1) + break; + } } putc ('\n', listfp); } From cvs at cvs.gnupg.org Fri Jun 18 16:23:21 2010 From: cvs at cvs.gnupg.org (svn author wk) Date: Fri, 18 Jun 2010 16:23:21 +0200 Subject: [svn] gpg-error - r243 - in trunk: . po src Message-ID: Author: wk Date: 2010-06-18 16:23:20 +0200 (Fri, 18 Jun 2010) New Revision: 243 Modified: trunk/ChangeLog trunk/po/de.po trunk/src/err-codes.h.in Log: Add new error code. Convert de.po to utf8 Modified: trunk/ChangeLog =================================================================== --- trunk/ChangeLog 2010-05-06 15:02:04 UTC (rev 242) +++ trunk/ChangeLog 2010-06-18 14:23:20 UTC (rev 243) @@ -1,3 +1,7 @@ +2010-06-18 Werner Koch + + * src/err-codes.h.in (GPG_ERR_MISSING_KEY): New. + 2010-05-06 Werner Koch Release 1.8. Modified: trunk/po/de.po [not shown] Modified: trunk/src/err-codes.h.in =================================================================== --- trunk/src/err-codes.h.in 2010-05-06 15:02:04 UTC (rev 242) +++ trunk/src/err-codes.h.in 2010-06-18 14:23:20 UTC (rev 243) @@ -210,7 +210,8 @@ 178 GPG_ERR_NO_PIN No PIN given 179 GPG_ERR_NOT_ENABLED Not enabled 180 GPG_ERR_NO_ENGINE No crypto engine -# 181 to 198 are free to be used. +181 GPG_ERR_MISSING_KEY Missing key +# 182 to 198 are free to be used. 199 GPG_ERR_UNFINISHED Operation not yet finished 200 GPG_ERR_BUFFER_TOO_SHORT Buffer too short From cvs at cvs.gnupg.org Mon Jun 21 12:01:26 2010 From: cvs at cvs.gnupg.org (svn author wk) Date: Mon, 21 Jun 2010 12:01:26 +0200 Subject: [svn] GnuPG - r5362 - in trunk: . agent common sm Message-ID: Author: wk Date: 2010-06-21 12:01:24 +0200 (Mon, 21 Jun 2010) New Revision: 5362 Modified: trunk/agent/ChangeLog trunk/agent/command.c trunk/agent/protect-tool.c trunk/common/ChangeLog trunk/common/sexputil.c trunk/common/util.h trunk/configure.ac trunk/sm/ChangeLog trunk/sm/call-agent.c trunk/sm/export.c trunk/sm/gpgsm.c trunk/sm/gpgsm.h trunk/sm/import.c trunk/sm/minip12.c trunk/sm/minip12.h Log: Implement export of pkcs#12 objects using a direct agent connection. Modified: trunk/agent/ChangeLog =================================================================== --- trunk/agent/ChangeLog 2010-06-18 08:08:49 UTC (rev 5361) +++ trunk/agent/ChangeLog 2010-06-21 10:01:24 UTC (rev 5362) @@ -1,3 +1,9 @@ +2010-06-18 Werner Koch + + * protect-tool.c (store_private_key, rsa_key_check): + + * command.c (cmd_export_key): New. + 2010-06-15 Werner Koch * command.c (cmd_keywrap_key, cmd_import_key): New. @@ -2652,7 +2658,7 @@ Copyright 2001, 2002, 2003, 2004, 2005, - 2007, 2008, 2009 Free Software Foundation, Inc. + 2007, 2008, 2009, 2010 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 Modified: trunk/common/ChangeLog =================================================================== --- trunk/common/ChangeLog 2010-06-18 08:08:49 UTC (rev 5361) +++ trunk/common/ChangeLog 2010-06-21 10:01:24 UTC (rev 5362) @@ -1,3 +1,13 @@ +2010-06-21 Werner Koch + + * util.h (xfree_fnc): New. + +2010-06-18 Werner Koch + + * util.h (GPG_ERR_MISSING_KEY) [!GPG_ERR_MISSING_KEY]: New. + + * sexputil.c (make_canon_sexp_pad): Add arg SECURE. + 2010-06-17 Werner Koch * sexputil.c (make_canon_sexp_pad): New. Modified: trunk/sm/ChangeLog =================================================================== --- trunk/sm/ChangeLog 2010-06-18 08:08:49 UTC (rev 5361) +++ trunk/sm/ChangeLog 2010-06-21 10:01:24 UTC (rev 5362) @@ -1,3 +1,21 @@ +2010-06-21 Werner Koch + + * minip12.c (p12_build): Change arg CERT to const void ptr. + (build_cert_sequence): Change arg CERT to const ptr. + + * gpgsm.c (main) : Use to estream. + (open_fwrite): Removed. + + * export.c: Include minip12.h. + (popen_protect_tool): Remove. + (export_p12): Use gpg-agent directly. Change calling convention. + (gpgsm_p12_export): Adjust for that change. Change arg FP to an + estream_t. + (do_putc): Remove. Change callers to es_putc. + (do_fputs): Likewise. + (print_short_info): Remove arg FP. + * call-agent.c (gpgsm_agent_export_key): new. + 2010-06-17 Werner Koch * import.c (parse_p12): Remove arg retfp. Use the agent's new Modified: trunk/agent/command.c =================================================================== --- trunk/agent/command.c 2010-06-18 08:08:49 UTC (rev 5361) +++ trunk/agent/command.c 2010-06-21 10:01:24 UTC (rev 5362) @@ -1,6 +1,6 @@ /* command.c - gpg-agent command handler * Copyright (C) 2001, 2002, 2003, 2004, 2005, - * 2006, 2008, 2009 Free Software Foundation, Inc. + * 2006, 2008, 2009, 2010 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -38,6 +38,8 @@ #include #include "i18n.h" + + /* Maximum allowed size of the inquired ciphertext. */ #define MAXLEN_CIPHERTEXT 4096 /* Maximum allowed size of the key parameters. */ @@ -564,7 +566,7 @@ static const char hlp_setkeydesc[] = "SETKEYDESC plus_percent_escaped_string\n" "\n" - "Set a description to be used for the next PKSIGN or PKDECRYPT\n" + "Set a description to be used for the next PKSIGN, PKDECRYPT or EXPORT_KEY\n" "operation if this operation requires the entry of a passphrase. If\n" "this command is not used a default text will be used. Note, that\n" "this description implictly selects the label used for the entry\n" @@ -573,8 +575,8 @@ "\"passphrase\" is used. The description string should not contain\n" "blanks unless they are percent or '+' escaped.\n" "\n" - "The description is only valid for the next PKSIGN or PKDECRYPT\n" - "operation."; + "The description is only valid for the next PKSIGN, PKDECRYPT or\n" + "EXPORT_KEY operation."; static gpg_error_t cmd_setkeydesc (assuan_context_t ctx, char *line) { @@ -1481,7 +1483,7 @@ if (!ctrl->server_local->import_key) { - err = gpg_error (GPG_ERR_BAD_KEY); + err = gpg_error (GPG_ERR_MISSING_KEY); goto leave; } @@ -1562,15 +1564,97 @@ static const char hlp_export_key[] = - "EXPORT_KEY\n" - "\n"; + "EXPORT_KEY \n" + "\n" + "Export a secret key from the key store. The key will be encrypted\n" + "using the current session's key wrapping key (cf. command KEYWRAP_KEY)\n" + "using the AESWRAP-128 algorithm. The caller needs to retrieve that key\n" + "prior to using this command. The function takes the keygrip as argument.\n"; static gpg_error_t cmd_export_key (assuan_context_t ctx, char *line) { - gpg_error_t err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); + ctrl_t ctrl = assuan_get_pointer (ctx); + gpg_error_t err; + unsigned char grip[20]; + gcry_sexp_t s_skey = NULL; + unsigned char *key = NULL; + size_t keylen; + gcry_cipher_hd_t cipherhd = NULL; + unsigned char *wrappedkey = NULL; + size_t wrappedkeylen; + if (!ctrl->server_local->export_key) + { + err = gpg_error (GPG_ERR_MISSING_KEY); + goto leave; + } - /* leave: */ + err = parse_keygrip (ctx, line, grip); + if (err) + goto leave; + + if (agent_key_available (grip)) + { + err = gpg_error (GPG_ERR_NO_SECKEY); + goto leave; + } + + err = agent_key_from_file (ctrl, ctrl->server_local->keydesc, grip, + NULL, CACHE_MODE_IGNORE, NULL, &s_skey); + if (err) + goto leave; + if (!s_skey) + { + /* Key is on a smartcard. Actually we should not see this here + because we do not pass a shadow_info variable to the above + function, thus it will return this error directly. */ + err = gpg_error (GPG_ERR_UNUSABLE_SECKEY); + goto leave; + } + + err = make_canon_sexp_pad (s_skey, 1, &key, &keylen); + if (err) + goto leave; + gcry_sexp_release (s_skey); + s_skey = NULL; + + err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128, + GCRY_CIPHER_MODE_AESWRAP, 0); + if (err) + goto leave; + err = gcry_cipher_setkey (cipherhd, + ctrl->server_local->export_key, KEYWRAP_KEYSIZE); + if (err) + goto leave; + + wrappedkeylen = keylen + 8; + wrappedkey = xtrymalloc (wrappedkeylen); + if (!wrappedkey) + { + err = gpg_error_from_syserror (); + goto leave; + } + + err = gcry_cipher_encrypt (cipherhd, wrappedkey, wrappedkeylen, key, keylen); + if (err) + goto leave; + xfree (key); + key = NULL; + gcry_cipher_close (cipherhd); + cipherhd = NULL; + + assuan_begin_confidential (ctx); + err = assuan_send_data (ctx, wrappedkey, wrappedkeylen); + assuan_end_confidential (ctx); + + + leave: + xfree (wrappedkey); + gcry_cipher_close (cipherhd); + xfree (key); + gcry_sexp_release (s_skey); + xfree (ctrl->server_local->keydesc); + ctrl->server_local->keydesc = NULL; return leave_cmd (ctx, err); } Modified: trunk/agent/protect-tool.c =================================================================== --- trunk/agent/protect-tool.c 2010-06-18 08:08:49 UTC (rev 5361) +++ trunk/agent/protect-tool.c 2010-06-21 10:01:24 UTC (rev 5362) @@ -544,89 +544,7 @@ } -static int -rsa_key_check (struct rsa_secret_key_s *skey) -{ - int err = 0; - gcry_mpi_t t = gcry_mpi_snew (0); - gcry_mpi_t t1 = gcry_mpi_snew (0); - gcry_mpi_t t2 = gcry_mpi_snew (0); - gcry_mpi_t phi = gcry_mpi_snew (0); - /* check that n == p * q */ - gcry_mpi_mul (t, skey->p, skey->q); - if (gcry_mpi_cmp( t, skey->n) ) - { - log_error ("RSA oops: n != p * q\n"); - err++; - } - - /* check that p is less than q */ - if (gcry_mpi_cmp (skey->p, skey->q) > 0) - { - gcry_mpi_t tmp; - - log_info ("swapping secret primes\n"); - tmp = gcry_mpi_copy (skey->p); - gcry_mpi_set (skey->p, skey->q); - gcry_mpi_set (skey->q, tmp); - gcry_mpi_release (tmp); - /* and must recompute u of course */ - gcry_mpi_invm (skey->u, skey->p, skey->q); - } - - /* check that e divides neither p-1 nor q-1 */ - gcry_mpi_sub_ui (t, skey->p, 1 ); - gcry_mpi_div (NULL, t, t, skey->e, 0); - if (!gcry_mpi_cmp_ui( t, 0) ) - { - log_error ("RSA oops: e divides p-1\n"); - err++; - } - gcry_mpi_sub_ui (t, skey->q, 1); - gcry_mpi_div (NULL, t, t, skey->e, 0); - if (!gcry_mpi_cmp_ui( t, 0)) - { - log_info ( "RSA oops: e divides q-1\n" ); - err++; - } - - /* check that d is correct. */ - gcry_mpi_sub_ui (t1, skey->p, 1); - gcry_mpi_sub_ui (t2, skey->q, 1); - gcry_mpi_mul (phi, t1, t2); - gcry_mpi_invm (t, skey->e, phi); - if (gcry_mpi_cmp (t, skey->d)) - { /* no: try universal exponent. */ - gcry_mpi_gcd (t, t1, t2); - gcry_mpi_div (t, NULL, phi, t, 0); - gcry_mpi_invm (t, skey->e, t); - if (gcry_mpi_cmp (t, skey->d)) - { - log_error ("RSA oops: bad secret exponent\n"); - err++; - } - } - - /* check for correctness of u */ - gcry_mpi_invm (t, skey->p, skey->q); - if (gcry_mpi_cmp (t, skey->u)) - { - log_info ( "RSA oops: bad u parameter\n"); - err++; - } - - if (err) - log_info ("RSA secret key check failed\n"); - - gcry_mpi_release (t); - gcry_mpi_release (t1); - gcry_mpi_release (t2); - gcry_mpi_release (phi); - - return err? -1:0; -} - #if 0 /* A callback used by p12_parse to return a certificate. */ static void @@ -789,6 +707,7 @@ +#if 0 static gcry_mpi_t * sexp_to_kparms (gcry_sexp_t sexp) { @@ -842,20 +761,20 @@ gcry_sexp_release (list); return array; } +#endif - /* Check whether STRING is a KEYGRIP, i.e has the correct length and does only consist of uppercase hex characters. */ -static int -is_keygrip (const char *string) -{ - int i; +/* static int */ +/* is_keygrip (const char *string) */ +/* { */ +/* int i; */ - for(i=0; string[i] && i < 41; i++) - if (!strchr("01234567890ABCDEF", string[i])) - return 0; - return i == 40; -} +/* for(i=0; string[i] && i < 41; i++) */ +/* if (!strchr("01234567890ABCDEF", string[i])) */ +/* return 0; */ +/* return i == 40; */ +/* } */ #if 0 @@ -1195,6 +1114,7 @@ } } +#if 0 static int store_private_key (const unsigned char *grip, const void *buffer, size_t length, int force) @@ -1257,3 +1177,4 @@ xfree (fname); return 0; } +#endif Modified: trunk/common/sexputil.c =================================================================== --- trunk/common/sexputil.c 2010-06-18 08:08:49 UTC (rev 5361) +++ trunk/common/sexputil.c 2010-06-21 10:01:24 UTC (rev 5362) @@ -72,9 +72,9 @@ /* Same as make_canon_sexp but pad the buffer to multiple of 64 - bits. */ + bits. If SECURE is set, secure memory will be allocated. */ gpg_error_t -make_canon_sexp_pad (gcry_sexp_t sexp, +make_canon_sexp_pad (gcry_sexp_t sexp, int secure, unsigned char **r_buffer, size_t *r_buflen) { size_t len; @@ -88,7 +88,7 @@ if (!len) return gpg_error (GPG_ERR_BUG); len += (8 - len % 8) % 8; - buf = xtrycalloc (1, len); + buf = secure? xtrycalloc_secure (1, len) : xtrycalloc (1, len); if (!buf) return gpg_error_from_syserror (); if (!gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, buf, len)) Modified: trunk/common/util.h =================================================================== --- trunk/common/util.h 2010-06-18 08:08:49 UTC (rev 5361) +++ trunk/common/util.h 2010-06-21 10:01:24 UTC (rev 5362) @@ -23,6 +23,10 @@ #include /* We need this for the memory function protos. */ #include /* We need errno. */ #include /* We need gpg_error_t. */ +/* Add error codes available only in newer versions of libgpg-error. */ +#ifndef GPG_ERR_MISSING_KEY +#define GPG_ERR_MISSING_KEY 181 +#endif /* Hash function used with libksba. */ #define HASH_FNC ((void (*)(void *, const void*,size_t))gcry_md_write) @@ -77,6 +81,7 @@ #define xtryrealloc(a,b) gcry_realloc ((a),(b)) #define xtrystrdup(a) gcry_strdup ((a)) #define xfree(a) gcry_free ((a)) +#define xfree_fnc gcry_free #define xmalloc(a) gcry_xmalloc ((a)) #define xmalloc_secure(a) gcry_xmalloc_secure ((a)) @@ -146,7 +151,7 @@ /*-- sexputil.c */ gpg_error_t make_canon_sexp (gcry_sexp_t sexp, unsigned char **r_buffer, size_t *r_buflen); -gpg_error_t make_canon_sexp_pad (gcry_sexp_t sexp, +gpg_error_t make_canon_sexp_pad (gcry_sexp_t sexp, int secure, unsigned char **r_buffer, size_t *r_buflen); gpg_error_t keygrip_from_canon_sexp (const unsigned char *key, size_t keylen, unsigned char *grip); Modified: trunk/configure.ac =================================================================== --- trunk/configure.ac 2010-06-18 08:08:49 UTC (rev 5361) +++ trunk/configure.ac 2010-06-21 10:01:24 UTC (rev 5362) @@ -40,7 +40,7 @@ # sufficient. development_version=no -NEED_GPG_ERROR_VERSION=1.4 +NEED_GPG_ERROR_VERSION=1.8 NEED_LIBGCRYPT_API=1 NEED_LIBGCRYPT_VERSION=1.4.0 Modified: trunk/sm/call-agent.c =================================================================== --- trunk/sm/call-agent.c 2010-06-18 08:08:49 UTC (rev 5361) +++ trunk/sm/call-agent.c 2010-06-21 10:01:24 UTC (rev 5362) @@ -1079,9 +1079,10 @@ /* Ask for the passphrase (this is used for pkcs#12 import/export. On success the caller needs to free the string stored at R_PASSPHRASE. On error NULL will be stored at R_PASSPHRASE and an appropriate - error code returned. */ + error code returned. If REPEAT is true the agent tries to get a + new passphrase (i.e. asks the user to confirm it). */ gpg_error_t -gpgsm_agent_ask_passphrase (ctrl_t ctrl, const char *desc_msg, +gpgsm_agent_ask_passphrase (ctrl_t ctrl, const char *desc_msg, int repeat, char **r_passphrase) { gpg_error_t err; @@ -1098,7 +1099,9 @@ if (desc_msg && *desc_msg && !(arg4 = percent_plus_escape (desc_msg))) return gpg_error_from_syserror (); - snprintf (line, DIM(line)-1, "GET_PASSPHRASE --data -- X X X %s", arg4); + snprintf (line, DIM(line)-1, "GET_PASSPHRASE --data%s -- X X X %s", + repeat? " --repeat=1 --check --qualitybar":"", + arg4); xfree (arg4); init_membuf_secure (&data, 64); @@ -1201,3 +1204,55 @@ NULL, NULL, inq_import_key_parms, &parm, NULL, NULL); return err; } + + + +/* Receive a secret key from the agent. KEYGRIP is the hexified + keygrip, DESC a prompt to be displayed with the agent's passphrase + question (needs to be plus+percent escaped). On success the key is + stored as a canonical S-expression at R_RESULT and R_RESULTLEN. */ +gpg_error_t +gpgsm_agent_export_key (ctrl_t ctrl, const char *keygrip, const char *desc, + unsigned char **r_result, size_t *r_resultlen) +{ + gpg_error_t err; + membuf_t data; + size_t len; + unsigned char *buf; + char line[ASSUAN_LINELENGTH]; + + *r_result = NULL; + + err = start_agent (ctrl); + if (err) + return err; + + if (desc) + { + snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc); + err = assuan_transact (agent_ctx, line, + NULL, NULL, NULL, NULL, NULL, NULL); + if (err) + return err; + } + + snprintf (line, DIM(line)-1, "EXPORT_KEY %s", keygrip); + + init_membuf_secure (&data, 1024); + err = assuan_transact (agent_ctx, line, + membuf_data_cb, &data, + default_inq_cb, ctrl, NULL, NULL); + if (err) + { + xfree (get_membuf (&data, &len)); + return err; + } + buf = get_membuf (&data, &len); + if (!buf) + return gpg_error_from_syserror (); + *r_result = buf; + *r_resultlen = len; + return 0; +} + + Modified: trunk/sm/export.c =================================================================== --- trunk/sm/export.c 2010-06-18 08:08:49 UTC (rev 5361) +++ trunk/sm/export.c 2010-06-21 10:01:24 UTC (rev 5362) @@ -34,9 +34,8 @@ #include "exechelp.h" #include "i18n.h" #include "sysutils.h" +#include "minip12.h" - - /* A table to store a fingerprint as used in a duplicates table. We don't need to hash here because a fingerprint is already a perfect hash value. This we use the most significant bits to index the @@ -57,11 +56,11 @@ #define DUPTABLE_SIZE (1 << DUPTABLE_BITS) -static void print_short_info (ksba_cert_t cert, FILE *fp, estream_t stream); +static void print_short_info (ksba_cert_t cert, estream_t stream); static gpg_error_t export_p12 (ctrl_t ctrl, const unsigned char *certimg, size_t certimglen, const char *prompt, const char *keygrip, - estream_t *retfp); + void **r_result, size_t *r_resultlen); /* Create a table used to indetify duplicated certificates. */ @@ -255,7 +254,7 @@ { if (count) es_putc ('\n', stream); - print_short_info (cert, NULL, stream); + print_short_info (cert, stream); es_putc ('\n', stream); } count++; @@ -317,23 +316,22 @@ } -/* Export a certificates and its private key. */ +/* Export a certificate and its private key. */ void -gpgsm_p12_export (ctrl_t ctrl, const char *name, FILE *fp) +gpgsm_p12_export (ctrl_t ctrl, const char *name, estream_t stream) { + gpg_error_t err = 0; KEYDB_HANDLE hd; KEYDB_SEARCH_DESC *desc = NULL; Base64Context b64writer = NULL; ksba_writer_t writer; ksba_cert_t cert = NULL; - int rc=0; const unsigned char *image; size_t imagelen; char *keygrip = NULL; char *prompt; - char buffer[1024]; - int nread; - estream_t datafp = NULL; + void *data; + size_t datalen; hd = keydb_new (0); @@ -351,28 +349,28 @@ goto leave; } - rc = classify_user_id (name, desc); - if (rc) + err = classify_user_id (name, desc); + if (err) { log_error ("key `%s' not found: %s\n", - name, gpg_strerror (rc)); + name, gpg_strerror (err)); goto leave; } /* Lookup the certificate and make sure that it is unique. */ - rc = keydb_search (hd, desc, 1); - if (!rc) + err = keydb_search (hd, desc, 1); + if (!err) { - rc = keydb_get_cert (hd, &cert); - if (rc) + err = keydb_get_cert (hd, &cert); + if (err) { - log_error ("keydb_get_cert failed: %s\n", gpg_strerror (rc)); + log_error ("keydb_get_cert failed: %s\n", gpg_strerror (err)); goto leave; } next_ambiguous: - rc = keydb_search (hd, desc, 1); - if (!rc) + err = keydb_search (hd, desc, 1); + if (!err) { ksba_cert_t cert2 = NULL; @@ -385,14 +383,14 @@ } ksba_cert_release (cert2); } - rc = gpg_error (GPG_ERR_AMBIGUOUS_NAME); + err = gpg_error (GPG_ERR_AMBIGUOUS_NAME); } - else if (rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF) - rc = 0; - if (rc) + else if (err == -1 || gpg_err_code (err) == GPG_ERR_EOF) + err = 0; + if (err) { log_error ("key `%s' not found: %s\n", - name, gpg_strerror (rc)); + name, gpg_strerror (err)); goto leave; } } @@ -401,8 +399,8 @@ if (!keygrip || gpgsm_agent_havekey (ctrl, keygrip)) { /* Note, that the !keygrip case indicates a bad certificate. */ - rc = gpg_error (GPG_ERR_NO_SECKEY); - log_error ("can't export key `%s': %s\n", name, gpg_strerror (rc)); + err = gpg_error (GPG_ERR_NO_SECKEY); + log_error ("can't export key `%s': %s\n", name, gpg_strerror (err)); goto leave; } @@ -415,51 +413,44 @@ if (ctrl->create_pem) { - print_short_info (cert, fp, NULL); - putc ('\n', fp); + print_short_info (cert, stream); + es_putc ('\n', stream); } if (opt.p12_charset && ctrl->create_pem) { - fprintf (fp, "The passphrase is %s encoded.\n\n", - opt.p12_charset); + es_fprintf (stream, "The passphrase is %s encoded.\n\n", + opt.p12_charset); } ctrl->pem_name = "PKCS12"; - rc = gpgsm_create_writer (&b64writer, ctrl, fp, NULL, &writer); - if (rc) + err = gpgsm_create_writer (&b64writer, ctrl, NULL, stream, &writer); + if (err) { - log_error ("can't create writer: %s\n", gpg_strerror (rc)); + log_error ("can't create writer: %s\n", gpg_strerror (err)); goto leave; } - prompt = gpgsm_format_keydesc (cert); - rc = export_p12 (ctrl, image, imagelen, prompt, keygrip, &datafp); + err = export_p12 (ctrl, image, imagelen, prompt, keygrip, &data, &datalen); xfree (prompt); - if (rc) + if (err) goto leave; - es_rewind (datafp); - while ( (nread = es_fread (buffer, 1, sizeof buffer, datafp)) > 0 ) - if ((rc = ksba_writer_write (writer, buffer, nread))) - { - log_error ("write failed: %s\n", gpg_strerror (rc)); - goto leave; - } - if (es_ferror (datafp)) + err = ksba_writer_write (writer, data, datalen); + xfree (data); + if (err) { - rc = gpg_error_from_syserror (); - log_error ("error reading temporary file: %s\n", gpg_strerror (rc)); + log_error ("write failed: %s\n", gpg_strerror (err)); goto leave; } if (ctrl->create_pem) { /* We want one certificate per PEM block */ - rc = gpgsm_finish_writer (b64writer); - if (rc) + err = gpgsm_finish_writer (b64writer); + if (err) { - log_error ("write failed: %s\n", gpg_strerror (rc)); + log_error ("write failed: %s\n", gpg_strerror (err)); goto leave; } gpgsm_destroy_writer (b64writer); @@ -470,7 +461,6 @@ cert = NULL; leave: - es_fclose (datafp); gpgsm_destroy_writer (b64writer); ksba_cert_release (cert); xfree (desc); @@ -478,30 +468,9 @@ } -/* Call either es_putc or the plain putc. */ -static void -do_putc (int value, FILE *fp, estream_t stream) -{ - if (stream) - es_putc (value, stream); - else - putc (value, fp); -} - -/* Call either es_fputs or the plain fputs. */ -static void -do_fputs (const char *string, FILE *fp, estream_t stream) -{ - if (stream) - es_fputs (string, stream); - else - fputs (string, fp); -} - - /* Print some info about the certifciate CERT to FP or STREAM */ static void -print_short_info (ksba_cert_t cert, FILE *fp, estream_t stream) +print_short_info (ksba_cert_t cert, estream_t stream) { char *p; ksba_sexp_t sexp; @@ -509,18 +478,15 @@ for (idx=0; (p = ksba_cert_get_issuer (cert, idx)); idx++) { - do_fputs ((!idx + es_fputs ((!idx ? "Issuer ...: " - : "\n aka ...: "), fp, stream); - if (stream) - gpgsm_es_print_name (stream, p); - else - gpgsm_print_name (fp, p); + : "\n aka ...: "), stream); + gpgsm_es_print_name (stream, p); xfree (p); } - do_putc ('\n', fp, stream); + es_putc ('\n', stream); - do_fputs ("Serial ...: ", fp, stream); + es_fputs ("Serial ...: ", stream); sexp = ksba_cert_get_serial (cert); if (sexp) { @@ -533,199 +499,208 @@ for (len=0; *s && *s != ':' && digitp (s); s++) len = len*10 + atoi_1 (s); if (*s == ':') - { - if (stream) - es_write_hexstring (stream, s+1, len, 0, NULL); - else - print_hexstring (fp, s+1, len, 0); - } + es_write_hexstring (stream, s+1, len, 0, NULL); } xfree (sexp); } - do_putc ('\n', fp, stream); + es_putc ('\n', stream); for (idx=0; (p = ksba_cert_get_subject (cert, idx)); idx++) { - do_fputs ((!idx + es_fputs ((!idx ? "Subject ..: " - : "\n aka ..: "), fp, stream); - if (stream) - gpgsm_es_print_name (stream, p); - else - gpgsm_print_name (fp, p); + : "\n aka ..: "), stream); + gpgsm_es_print_name (stream, p); xfree (p); } - do_putc ('\n', fp, stream); + es_putc ('\n', stream); } -static gpg_error_t -popen_protect_tool (ctrl_t ctrl, const char *pgmname, - estream_t infile, estream_t outfile, - estream_t *statusfile, - const char *prompt, const char *keygrip, - pid_t *pid) + +/* Parse a private key S-expression and retutn a malloced array with + the RSA paramaters in pkcs#12 order. The caller needs to + deep-release this array. */ +static gcry_mpi_t * +sexp_to_kparms (gcry_sexp_t sexp) { - const char *argv[22]; - int i=0; + gcry_sexp_t list, l2; + const char *name; + const char *s; + size_t n; + int idx; + const char *elems; + gcry_mpi_t *array; - /* Make sure that the agent is running so that the protect tool is - able to ask for a passphrase. This has only an effect under W32 - where the agent is started on demand; sending a NOP does not harm - on other platforms. This is not really necessary anymore because - the protect tool does this now by itself; it does not harm either.*/ - gpgsm_agent_send_nop (ctrl); + list = gcry_sexp_find_token (sexp, "private-key", 0 ); + if(!list) + return NULL; + l2 = gcry_sexp_cadr (list); + gcry_sexp_release (list); + list = l2; + name = gcry_sexp_nth_data (list, 0, &n); + if(!name || n != 3 || memcmp (name, "rsa", 3)) + { + gcry_sexp_release (list); + return NULL; + } - argv[i++] = "--homedir"; - argv[i++] = opt.homedir; - argv[i++] = "--p12-export"; - argv[i++] = "--have-cert"; - argv[i++] = "--prompt"; - argv[i++] = prompt?prompt:""; - argv[i++] = "--enable-status-msg"; - if (opt.p12_charset) + /* Parameter names used with RSA in the pkcs#12 order. */ + elems = "nedqp--u"; + array = xtrycalloc (strlen(elems) + 1, sizeof *array); + if (!array) { - argv[i++] = "--p12-charset"; - argv[i++] = opt.p12_charset; + gcry_sexp_release (list); + return NULL; } - if (opt.agent_program) + for (idx=0, s=elems; *s; s++, idx++ ) { - argv[i++] = "--agent-program"; - argv[i++] = opt.agent_program; + if (*s == '-') + continue; /* Computed below */ + l2 = gcry_sexp_find_token (list, s, 1); + if (l2) + { + array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); + gcry_sexp_release (l2); + } + if (!array[idx]) /* Required parameter not found or invalid. */ + { + for (idx=0; array[idx]; idx++) + gcry_mpi_release (array[idx]); + xfree (array); + gcry_sexp_release (list); + return NULL; + } } - argv[i++] = "--", - argv[i++] = keygrip, - argv[i] = NULL; - assert (i < sizeof argv); + gcry_sexp_release (list); - return gnupg_spawn_process (pgmname, argv, infile, outfile, - setup_pinentry_env, (128|64), - statusfile, pid); + array[5] = gcry_mpi_snew (0); /* compute d mod (q-1) */ + gcry_mpi_sub_ui (array[5], array[3], 1); + gcry_mpi_mod (array[5], array[2], array[5]); + + array[6] = gcry_mpi_snew (0); /* compute d mod (p-1) */ + gcry_mpi_sub_ui (array[6], array[4], 1); + gcry_mpi_mod (array[6], array[3], array[6]); + + return array; } static gpg_error_t export_p12 (ctrl_t ctrl, const unsigned char *certimg, size_t certimglen, - const char *prompt, const char *keygrip, estream_t *retfp) + const char *prompt, const char *keygrip, + void **r_result, size_t *r_resultlen) { - const char *pgmname; - gpg_error_t err = 0, child_err = 0; - int c, cont_line; - unsigned int pos; - estream_t infp = NULL; - estream_t fp = NULL; - estream_t outfp = NULL; - char buffer[1024]; - pid_t pid = -1; - int bad_pass = 0; + gpg_error_t err = 0; + void *kek = NULL; + size_t keklen; + unsigned char *wrappedkey = NULL; + size_t wrappedkeylen; + gcry_cipher_hd_t cipherhd = NULL; + gcry_sexp_t s_skey = NULL; + gcry_mpi_t *kparms = NULL; + unsigned char *key = NULL; + size_t keylen; + char *passphrase = NULL; + unsigned char *result = NULL; + size_t resultlen; + int i; - if (!opt.protect_tool_program || !*opt.protect_tool_program) - pgmname = gnupg_module_name (GNUPG_MODULE_NAME_PROTECT_TOOL); - else - pgmname = opt.protect_tool_program; + *r_result = NULL; - infp = es_tmpfile (); - if (!infp) + /* Get the current KEK. */ + err = gpgsm_agent_keywrap_key (ctrl, 1, &kek, &keklen); + if (err) { - err = gpg_error_from_syserror (); - log_error (_("error creating temporary file: %s\n"), strerror (errno)); - goto cleanup; + log_error ("error getting the KEK: %s\n", gpg_strerror (err)); + goto leave; } - if (es_fwrite (certimg, certimglen, 1, infp) != 1) + /* Receive the wrapped key from the agent. */ + err = gpgsm_agent_export_key (ctrl, keygrip, prompt, + &wrappedkey, &wrappedkeylen); + if (err) + goto leave; + + + /* Unwrap the key. */ + err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128, + GCRY_CIPHER_MODE_AESWRAP, 0); + if (err) + goto leave; + err = gcry_cipher_setkey (cipherhd, kek, keklen); + if (err) + goto leave; + xfree (kek); + kek = NULL; + + if (wrappedkeylen < 24) { - err = gpg_error_from_syserror (); - log_error (_("error writing to temporary file: %s\n"), - strerror (errno)); - goto cleanup; + err = gpg_error (GPG_ERR_INV_LENGTH); + goto leave; } - - outfp = es_tmpfile (); - if (!outfp) + keylen = wrappedkeylen - 8; + key = xtrymalloc_secure (keylen); + if (!key) { err = gpg_error_from_syserror (); - log_error (_("error creating temporary file: %s\n"), strerror (errno)); - goto cleanup; + goto leave; } - - err = popen_protect_tool (ctrl, - pgmname, infp, outfp, &fp, prompt, keygrip, &pid); + err = gcry_cipher_decrypt (cipherhd, key, keylen, wrappedkey, wrappedkeylen); if (err) - { - pid = -1; - goto cleanup; - } - es_fclose (infp); - infp = NULL; + goto leave; + xfree (wrappedkey); + wrappedkey = NULL; + gcry_cipher_close (cipherhd); + cipherhd = NULL; - /* Read stderr of the protect tool. */ - pos = 0; - cont_line = 0; - while ((c=es_getc (fp)) != EOF) - { - /* fixme: We could here grep for status information of the - protect tool to figure out better error codes for - CHILD_ERR. */ - buffer[pos++] = c; - if (pos >= sizeof buffer - 5 || c == '\n') - { - buffer[pos - (c == '\n')] = 0; - if (cont_line) - log_printf ("%s", buffer); - else - { - if (!strncmp (buffer, "gpg-protect-tool: [PROTECT-TOOL:] ",34)) - { - char *p, *pend; - p = buffer + 34; - pend = strchr (p, ' '); - if (pend) - *pend = 0; - if ( !strcmp (p, "bad-passphrase")) - bad_pass++; - } - else - log_info ("%s", buffer); - } - pos = 0; - cont_line = (c != '\n'); - } - } + /* Convert to a gcrypt S-expression. */ + err = gcry_sexp_create (&s_skey, key, keylen, 0, xfree_fnc); + if (err) + goto leave; + key = NULL; /* Key is now owned by S_KEY. */ - if (pos) + /* Get the parameters from the S-expression. */ + kparms = sexp_to_kparms (s_skey); + gcry_sexp_release (s_skey); + s_skey = NULL; + if (!kparms) { - buffer[pos] = 0; - if (cont_line) - log_printf ("%s\n", buffer); - else - log_info ("%s\n", buffer); - } - else if (cont_line) - log_printf ("\n"); + log_error ("error converting key parameters\n"); + err = GPG_ERR_BAD_SECKEY; + goto leave; + } + + err = gpgsm_agent_ask_passphrase + (ctrl, + i18n_utf8 ("Please enter the passphrase to protect the " + "new PKCS#12 object."), + 1, &passphrase); + if (err) + goto leave; - /* If we found no error in the output of the child, setup a suitable - error code, which will later be reset if the exit status of the - child is 0. */ - if (!child_err) - child_err = gpg_error (GPG_ERR_DECRYPT_FAILED); - - cleanup: - es_fclose (infp); - es_fclose (fp); - if (pid != -1) + result = p12_build (kparms, certimg, certimglen, passphrase, + opt.p12_charset, &resultlen); + xfree (passphrase); + passphrase = NULL; + if (!result) + err = gpg_error (GPG_ERR_GENERAL); + + leave: + xfree (key); + gcry_sexp_release (s_skey); + if (kparms) { - if (!gnupg_wait_process (pgmname, pid, 0, NULL)) - child_err = 0; - gnupg_release_process (pid); + for (i=0; kparms[i]; i++) + gcry_mpi_release (kparms[i]); + xfree (kparms); } - if (!err) - err = child_err; - if (err) - es_fclose (outfp); - else - *retfp = outfp; - if (bad_pass) + gcry_cipher_close (cipherhd); + xfree (wrappedkey); + xfree (kek); + + if (gpg_err_code (err) == GPG_ERR_BAD_PASSPHRASE) { /* During export this is the passphrase used to unprotect the key and not the pkcs#12 thing as in export. Therefore we can @@ -733,6 +708,16 @@ zero keyid by a regular one. */ gpgsm_status (ctrl, STATUS_BAD_PASSPHRASE, "0000000000000000"); } + + if (err) + { + xfree (result); + } + else + { + *r_result = result; + *r_resultlen = resultlen; + } return err; } Modified: trunk/sm/gpgsm.c =================================================================== --- trunk/sm/gpgsm.c 2010-06-18 08:08:49 UTC (rev 5361) +++ trunk/sm/gpgsm.c 2010-06-21 10:01:24 UTC (rev 5362) @@ -435,7 +435,6 @@ static int check_special_filename (const char *fname, int for_write); static int open_read (const char *filename); static estream_t open_es_fread (const char *filename, const char *mode); -static FILE *open_fwrite (const char *filename); static estream_t open_es_fwrite (const char *filename); static void run_protect_tool (int argc, char **argv); @@ -1877,14 +1876,14 @@ case aExportSecretKeyP12: { - FILE *fp = open_fwrite (opt.outfile?opt.outfile:"-"); + estream_t fp = open_es_fwrite (opt.outfile?opt.outfile:"-"); if (argc == 1) gpgsm_p12_export (&ctrl, *argv, fp); else wrong_args ("--export-secret-key-p12 KEY-ID"); - if (fp != stdout) - fclose (fp); + if (fp != es_stdout) + es_fclose (fp); } break; @@ -2091,45 +2090,6 @@ } -/* Open FILENAME for fwrite and return the stream. Stop with an error - message in case of problems. "-" denotes stdout and if special - filenames are allowed the given fd is opened instead. Caller must - close the returned stream unless it is stdout. */ -static FILE * -open_fwrite (const char *filename) -{ - int fd; - FILE *fp; - - if (filename[0] == '-' && !filename[1]) - { - set_binary (stdout); - return stdout; - } - - fd = check_special_filename (filename, 1); - if (fd != -1) - { -#warning replace the line below - fp = NULL; /*fdopen (dup (fd), "wb"); */ - if (!fp) - { - log_error ("fdopen(%d) failed: %s\n", fd, strerror (errno)); - gpgsm_exit (2); - } - set_binary (fp); - return fp; - } - fp = fopen (filename, "wb"); - if (!fp) - { - log_error (_("can't open `%s': %s\n"), filename, strerror (errno)); - gpgsm_exit (2); - } - return fp; -} - - /* Open FILENAME for fwrite and return an extended stream. Stop with an error message in case of problems. "-" denotes stdout and if special filenames are allowed the given fd is opened instead. Modified: trunk/sm/gpgsm.h =================================================================== --- trunk/sm/gpgsm.h 2010-06-18 08:08:49 UTC (rev 5361) +++ trunk/sm/gpgsm.h 2010-06-21 10:01:24 UTC (rev 5362) @@ -344,7 +344,7 @@ /*-- export.c --*/ void gpgsm_export (ctrl_t ctrl, strlist_t names, estream_t stream); -void gpgsm_p12_export (ctrl_t ctrl, const char *name, FILE *fp); +void gpgsm_p12_export (ctrl_t ctrl, const char *name, estream_t stream); /*-- delete.c --*/ int gpgsm_delete (ctrl_t ctrl, strlist_t names); @@ -406,11 +406,15 @@ gpg_error_t gpgsm_agent_keyinfo (ctrl_t ctrl, const char *hexkeygrip, char **r_serialno); gpg_error_t gpgsm_agent_ask_passphrase (ctrl_t ctrl, const char *desc_msg, - char **r_passphrase); + int repeat, char **r_passphrase); gpg_error_t gpgsm_agent_keywrap_key (ctrl_t ctrl, int forexport, void **r_kek, size_t *r_keklen); gpg_error_t gpgsm_agent_import_key (ctrl_t ctrl, const void *key, size_t keylen); +gpg_error_t gpgsm_agent_export_key (ctrl_t ctrl, const char *keygrip, + const char *desc, + unsigned char **r_result, + size_t *r_resultlen); /*-- call-dirmngr.c --*/ int gpgsm_dirmngr_isvalid (ctrl_t ctrl, Modified: trunk/sm/import.c =================================================================== --- trunk/sm/import.c 2010-06-18 08:08:49 UTC (rev 5361) +++ trunk/sm/import.c 2010-06-21 10:01:24 UTC (rev 5362) @@ -759,8 +759,9 @@ err = gpgsm_agent_ask_passphrase - (ctrl, _("Please enter the passphrase to unprotect the PKCS#12 object."), - &passphrase); + (ctrl, + i18n_utf8 ("Please enter the passphrase to unprotect the PKCS#12 object."), + 0, &passphrase); if (err) goto leave; @@ -812,7 +813,7 @@ kparms = NULL; if (err) { - log_error ("failed to created S-expression from key: %s\n", + log_error ("failed to create S-expression from key: %s\n", gpg_strerror (err)); goto leave; } @@ -828,7 +829,7 @@ /* Convert to canonical encoding using a function which pads it to a multiple of 64 bits. We need this padding for AESWRAP. */ - err = make_canon_sexp_pad (s_key, &key, &keylen); + err = make_canon_sexp_pad (s_key, 1, &key, &keylen); if (err) { log_error ("error creating canonical S-expression\n"); Modified: trunk/sm/minip12.c =================================================================== --- trunk/sm/minip12.c 2010-06-18 08:08:49 UTC (rev 5361) +++ trunk/sm/minip12.c 2010-06-21 10:01:24 UTC (rev 5362) @@ -2024,7 +2024,7 @@ static unsigned char * -build_cert_sequence (unsigned char *buffer, size_t buflen, +build_cert_sequence (const unsigned char *buffer, size_t buflen, const unsigned char *sha1hash, const char *keyidstr, size_t *r_length) { @@ -2144,7 +2144,7 @@ in R_LENGTH; return NULL in case of an error. If CHARSET is not NULL, re-encode PW to that character set. */ unsigned char * -p12_build (gcry_mpi_t *kparms, unsigned char *cert, size_t certlen, +p12_build (gcry_mpi_t *kparms, const void *cert, size_t certlen, const char *pw, const char *charset, size_t *r_length) { unsigned char *buffer = NULL; @@ -2298,6 +2298,7 @@ unsigned char *buf; size_t buflen; gcry_mpi_t *result; + int badpass; if (argc != 3) { @@ -2330,7 +2331,7 @@ } fclose (fp); - result = p12_parse (buf, buflen, argv[2], cert_cb, NULL); + result = p12_parse (buf, buflen, argv[2], cert_cb, NULL, &badpass); if (result) { int i, rc; Modified: trunk/sm/minip12.h =================================================================== --- trunk/sm/minip12.h 2010-06-18 08:08:49 UTC (rev 5361) +++ trunk/sm/minip12.h 2010-06-21 10:01:24 UTC (rev 5362) @@ -28,7 +28,7 @@ void *certcbarg, int *r_badpass); unsigned char *p12_build (gcry_mpi_t *kparms, - unsigned char *cert, size_t certlen, + const void *cert, size_t certlen, const char *pw, const char *charset, size_t *r_length); From cvs at cvs.gnupg.org Mon Jun 21 12:04:37 2010 From: cvs at cvs.gnupg.org (svn author wk) Date: Mon, 21 Jun 2010 12:04:37 +0200 Subject: [svn] GnuPG - r5363 - trunk/agent Message-ID: Author: wk Date: 2010-06-21 12:04:36 +0200 (Mon, 21 Jun 2010) New Revision: 5363 Modified: trunk/agent/ChangeLog trunk/agent/protect-tool.c Log: Remove cruft. Modified: trunk/agent/ChangeLog =================================================================== --- trunk/agent/ChangeLog 2010-06-21 10:01:24 UTC (rev 5362) +++ trunk/agent/ChangeLog 2010-06-21 10:04:36 UTC (rev 5363) @@ -1,6 +1,12 @@ +2010-06-21 Werner Koch + + * protect-tool.c (export_p12_file, import_p12_cert_cb) + (import_p12_file, sexp_to_kparms, store_private_key): Remove + unused code. + 2010-06-18 Werner Koch - * protect-tool.c (store_private_key, rsa_key_check): + * protect-tool.c (store_private_key, rsa_key_check): Remove. * command.c (cmd_export_key): New. Modified: trunk/agent/protect-tool.c =================================================================== --- trunk/agent/protect-tool.c 2010-06-21 10:01:24 UTC (rev 5362) +++ trunk/agent/protect-tool.c 2010-06-21 10:04:36 UTC (rev 5363) @@ -62,7 +62,6 @@ oS2Kcalibration, oCanonical, - oP12Charset, oStore, oForce, oHaveCert, @@ -96,13 +95,10 @@ static const char *opt_passphrase; static char *opt_prompt; static int opt_status_msg; -static const char *opt_p12_charset; static const char *opt_agent_program; static char *get_passphrase (int promptno); static void release_passphrase (char *pw); -static int store_private_key (const unsigned char *grip, - const void *buffer, size_t length, int force); static ARGPARSE_OPTS opts[] = { @@ -122,8 +118,6 @@ ARGPARSE_s_n (oCanonical, "canonical", "write output in canonical format"), ARGPARSE_s_s (oPassphrase, "passphrase", "|STRING|use passphrase STRING"), - ARGPARSE_s_s (oP12Charset,"p12-charset", - "|NAME|set charset for a new PKCS#12 passphrase to NAME"), ARGPARSE_s_n (oHaveCert, "have-cert", "certificate to export provided on STDIN"), ARGPARSE_s_n (oStore, "store", @@ -545,387 +539,8 @@ -#if 0 -/* A callback used by p12_parse to return a certificate. */ -static void -import_p12_cert_cb (void *opaque, const unsigned char *cert, size_t certlen) -{ - struct b64state state; - gpg_error_t err, err2; - (void)opaque; - - err = b64enc_start (&state, stdout, "CERTIFICATE"); - if (!err) - err = b64enc_write (&state, cert, certlen); - err2 = b64enc_finish (&state); - if (!err) - err = err2; - if (err) - log_error ("error writing armored certificate: %s\n", gpg_strerror (err)); -} - -static void -import_p12_file (const char *fname) -{ - char *buf; - unsigned char *result; - size_t buflen, resultlen, buf_off; - int i; - int rc; - gcry_mpi_t *kparms; - struct rsa_secret_key_s sk; - gcry_sexp_t s_key; - unsigned char *key; - unsigned char grip[20]; - char *pw; - - /* fixme: we should release some stuff on error */ - - buf = read_file (fname, &buflen); - if (!buf) - return; - - /* GnuPG 2.0.4 accidently created binary P12 files with the string - "The passphrase is %s encoded.\n\n" prepended to the ASN.1 data. - We fix that here. */ - if (buflen > 29 && !memcmp (buf, "The passphrase is ", 18)) - { - for (buf_off=18; buf_off < buflen && buf[buf_off] != '\n'; buf_off++) - ; - buf_off++; - if (buf_off < buflen && buf[buf_off] == '\n') - buf_off++; - } - else - buf_off = 0; - - kparms = p12_parse ((unsigned char*)buf+buf_off, buflen-buf_off, - (pw=get_passphrase (2)), - import_p12_cert_cb, NULL); - release_passphrase (pw); - xfree (buf); - if (!kparms) - { - log_error ("error parsing or decrypting the PKCS-12 file\n"); - return; - } - for (i=0; kparms[i]; i++) - ; - if (i != 8) - { - log_error ("invalid structure of private key\n"); - return; - } - - -/* print_mpi (" n", kparms[0]); */ -/* print_mpi (" e", kparms[1]); */ -/* print_mpi (" d", kparms[2]); */ -/* print_mpi (" p", kparms[3]); */ -/* print_mpi (" q", kparms[4]); */ -/* print_mpi ("dmp1", kparms[5]); */ -/* print_mpi ("dmq1", kparms[6]); */ -/* print_mpi (" u", kparms[7]); */ - - sk.n = kparms[0]; - sk.e = kparms[1]; - sk.d = kparms[2]; - sk.q = kparms[3]; - sk.p = kparms[4]; - sk.u = kparms[7]; - if (rsa_key_check (&sk)) - return; -/* print_mpi (" n", sk.n); */ -/* print_mpi (" e", sk.e); */ -/* print_mpi (" d", sk.d); */ -/* print_mpi (" p", sk.p); */ -/* print_mpi (" q", sk.q); */ -/* print_mpi (" u", sk.u); */ - - /* Create an S-expresion from the parameters. */ - rc = gcry_sexp_build (&s_key, NULL, - "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))", - sk.n, sk.e, sk.d, sk.p, sk.q, sk.u, NULL); - for (i=0; i < 8; i++) - gcry_mpi_release (kparms[i]); - gcry_free (kparms); - if (rc) - { - log_error ("failed to created S-expression from key: %s\n", - gpg_strerror (rc)); - return; - } - - /* Compute the keygrip. */ - if (!gcry_pk_get_keygrip (s_key, grip)) - { - log_error ("can't calculate keygrip\n"); - return; - } - log_info ("keygrip: "); - for (i=0; i < 20; i++) - log_printf ("%02X", grip[i]); - log_printf ("\n"); - - /* Convert to canonical encoding. */ - buflen = gcry_sexp_sprint (s_key, GCRYSEXP_FMT_CANON, NULL, 0); - assert (buflen); - key = gcry_xmalloc_secure (buflen); - buflen = gcry_sexp_sprint (s_key, GCRYSEXP_FMT_CANON, key, buflen); - assert (buflen); - gcry_sexp_release (s_key); - - pw = get_passphrase (4); - rc = agent_protect (key, pw, &result, &resultlen); - release_passphrase (pw); - xfree (key); - if (rc) - { - log_error ("protecting the key failed: %s\n", gpg_strerror (rc)); - return; - } - - if (opt_armor) - { - char *p = make_advanced (result, resultlen); - xfree (result); - if (!p) - return; - result = (unsigned char*)p; - resultlen = strlen (p); - } - - if (opt_store) - store_private_key (grip, result, resultlen, opt_force); - else - fwrite (result, resultlen, 1, stdout); - - xfree (result); -} -#endif - - -#if 0 -static gcry_mpi_t * -sexp_to_kparms (gcry_sexp_t sexp) -{ - gcry_sexp_t list, l2; - const char *name; - const char *s; - size_t n; - int i, idx; - const char *elems; - gcry_mpi_t *array; - - list = gcry_sexp_find_token (sexp, "private-key", 0 ); - if(!list) - return NULL; - l2 = gcry_sexp_cadr (list); - gcry_sexp_release (list); - list = l2; - name = gcry_sexp_nth_data (list, 0, &n); - if(!name || n != 3 || memcmp (name, "rsa", 3)) - { - gcry_sexp_release (list); - return NULL; - } - - /* Parameter names used with RSA. */ - elems = "nedpqu"; - array = xcalloc (strlen(elems) + 1, sizeof *array); - for (idx=0, s=elems; *s; s++, idx++ ) - { - l2 = gcry_sexp_find_token (list, s, 1); - if (!l2) - { - for (i=0; i Author: wk Date: 2010-06-24 12:51:30 +0200 (Thu, 24 Jun 2010) New Revision: 5364 Modified: trunk/agent/ChangeLog trunk/agent/genkey.c trunk/common/ChangeLog trunk/common/asshelp.c trunk/g13/be-encfs.c trunk/g13/runner.c trunk/tools/ChangeLog trunk/tools/gpgconf-comp.c Log: Fix a regression from 2010-06-09. Modified: trunk/agent/ChangeLog =================================================================== --- trunk/agent/ChangeLog 2010-06-21 10:04:36 UTC (rev 5363) +++ trunk/agent/ChangeLog 2010-06-24 10:51:30 UTC (rev 5364) @@ -1,3 +1,8 @@ +2010-06-24 Werner Koch + + * genkey.c (check_passphrase_pattern): Use HANG option for + gnupg_wait_progress. Fixes regression from 2010-06-09. + 2010-06-21 Werner Koch * protect-tool.c (export_p12_file, import_p12_cert_cb) Modified: trunk/common/ChangeLog =================================================================== --- trunk/common/ChangeLog 2010-06-21 10:04:36 UTC (rev 5363) +++ trunk/common/ChangeLog 2010-06-24 10:51:30 UTC (rev 5364) @@ -1,3 +1,9 @@ +2010-06-24 Werner Koch + + * asshelp.c (lock_agent_spawning) [W32]: Use CreateMutexW. + (start_new_gpg_agent): Use HANG option for gnupg_wait_progress. + Fixes regression from 2010-06-09. + 2010-06-21 Werner Koch * util.h (xfree_fnc): New. @@ -41,7 +47,7 @@ * util.h (GNUPG_MODULE_NAME_DIRMNGR_LDAP): New. * homedir.c (gnupg_cachedir): New. (w32_try_mkdir): New. - (dirmngr_socket_name): Chanmge standard socket name. + (dirmngr_socket_name): Change standard socket name. (gnupg_module_name): Support GNUPG_MODULE_NAME_DIRMNGR_LDAP. * logging.c (log_set_get_tid_callback): Replace by ... Modified: trunk/tools/ChangeLog =================================================================== --- trunk/tools/ChangeLog 2010-06-21 10:04:36 UTC (rev 5363) +++ trunk/tools/ChangeLog 2010-06-24 10:51:30 UTC (rev 5364) @@ -1,3 +1,9 @@ +2010-06-24 Werner Koch + + * gpgconf-comp.c (gpg_agent_runtime_change) + (scdaemon_runtime_change, retrieve_options_from_program): Use HANG + option for gnupg_wait_progress. Fixes regression from 2010-06-09. + 2010-06-07 Werner Koch * gpgtar.c, gpgtar.h, gpgtar-list.c, gpgtar-create.c Modified: trunk/agent/genkey.c =================================================================== --- trunk/agent/genkey.c 2010-06-21 10:04:36 UTC (rev 5363) +++ trunk/agent/genkey.c 2010-06-24 10:51:30 UTC (rev 5364) @@ -129,7 +129,7 @@ if (gnupg_spawn_process_fd (pgmname, argv, fileno (infp), -1, -1, &pid)) result = 1; /* Execute error - assume password should no be used. */ - else if (gnupg_wait_process (pgmname, pid, 0, NULL)) + else if (gnupg_wait_process (pgmname, pid, 1, NULL)) result = 1; /* Helper returned an error - probably a match. */ else result = 0; /* Success; i.e. no match. */ Modified: trunk/common/asshelp.c =================================================================== --- trunk/common/asshelp.c 2010-06-21 10:04:36 UTC (rev 5363) +++ trunk/common/asshelp.c 2010-06-24 10:51:30 UTC (rev 5364) @@ -226,7 +226,7 @@ (void)homedir; /* Not required. */ - *lock = CreateMutex (NULL, FALSE, "GnuPG_spawn_agent_sentinel"); + *lock = CreateMutexW (NULL, FALSE, L"GnuPG_spawn_agent_sentinel"); if (!*lock) { log_error ("failed to create the spawn_agent mutex: %s\n", @@ -362,10 +362,10 @@ if (err) log_debug ("starting `%s' for testing failed: %s\n", agent_program, gpg_strerror (err)); - else if ((err = gnupg_wait_process (agent_program, pid, 0, &excode))) + else if ((err = gnupg_wait_process (agent_program, pid, 1, &excode))) { if (excode == -1) - log_debug ("running `%s' for testing failed: %s\n", + log_debug ("running `%s' for testing failed (wait): %s\n", agent_program, gpg_strerror (err)); } gnupg_release_process (pid); Modified: trunk/g13/be-encfs.c =================================================================== --- trunk/g13/be-encfs.c 2010-06-21 10:04:36 UTC (rev 5363) +++ trunk/g13/be-encfs.c 2010-06-24 10:51:30 UTC (rev 5364) @@ -304,7 +304,7 @@ close (outbound[1]); if (pid != (pid_t)(-1)) { - gnupg_wait_process (pgmname, pid, 0, NULL); + gnupg_wait_process (pgmname, pid, 1, NULL); gnupg_release_process (pid); } runner_release (runner); Modified: trunk/g13/runner.c =================================================================== --- trunk/g13/runner.c 2010-06-21 10:04:36 UTC (rev 5363) +++ trunk/g13/runner.c 2010-06-24 10:51:30 UTC (rev 5364) @@ -165,7 +165,7 @@ arbitrary NAME of the runner object. However it does not matter because that information is only used for diagnostics.) */ - gnupg_wait_process (runner->name, runner->pid, 0, NULL); + gnupg_wait_process (runner->name, runner->pid, 1, NULL); gnupg_release_process (runner->pid); } @@ -371,7 +371,7 @@ int exitcode; log_debug ("runner thread waiting ...\n"); - err = gnupg_wait_process (runner->name, runner->pid, 0, &exitcode); + err = gnupg_wait_process (runner->name, runner->pid, 1, &exitcode); gnupg_release_process (runner->pid); runner->pid = (pid_t)(-1); if (err) Modified: trunk/tools/gpgconf-comp.c =================================================================== --- trunk/tools/gpgconf-comp.c 2010-06-21 10:04:36 UTC (rev 5363) +++ trunk/tools/gpgconf-comp.c 2010-06-24 10:51:30 UTC (rev 5364) @@ -1051,7 +1051,7 @@ err = gnupg_spawn_process_fd (pgmname, argv, -1, -1, -1, &pid); if (!err) - err = gnupg_wait_process (pgmname, pid, 0, NULL); + err = gnupg_wait_process (pgmname, pid, 1, NULL); if (err) gc_error (0, 0, "error running `%s%s': %s", pgmname, " reloadagent", gpg_strerror (err)); @@ -1083,7 +1083,7 @@ err = gnupg_spawn_process_fd (pgmname, argv, -1, -1, -1, &pid); if (!err) - err = gnupg_wait_process (pgmname, pid, 0, NULL); + err = gnupg_wait_process (pgmname, pid, 1, NULL); if (err) gc_error (0, 0, "error running `%s%s': %s", pgmname, " scd killscd", gpg_strerror (err)); @@ -1503,7 +1503,7 @@ close (filedes[1]); errlines = collect_error_output (filedes[0], gc_component[component].name); - if (gnupg_wait_process (pgmname, pid, 0, &exitcode)) + if (gnupg_wait_process (pgmname, pid, 1, &exitcode)) { if (exitcode == -1) result |= 1; /* Program could not be run or it @@ -1922,7 +1922,7 @@ if (fclose (config) && ferror (config)) gc_error (1, errno, "error closing %s", pgmname); - err = gnupg_wait_process (pgmname, pid, 0, &exitcode); + err = gnupg_wait_process (pgmname, pid, 1, &exitcode); if (err) gc_error (1, 0, "running %s failed (exitcode=%d): %s", pgmname, exitcode, gpg_strerror (err)); From cvs at cvs.gnupg.org Fri Jun 25 15:51:50 2010 From: cvs at cvs.gnupg.org (cvs user werner) Date: Fri, 25 Jun 2010 15:51:50 +0200 Subject: oftpd (ChangeLog configure.ac) Message-ID: Date: Friday, June 25, 2010 @ 15:51:50 Author: werner Path: /cvs/wk/oftpd Modified: ChangeLog configure.ac Fix crash under Linux NPTL + From cvs at cvs.gnupg.org Mon Jun 28 15:37:45 2010 From: cvs at cvs.gnupg.org (svn author wk) Date: Mon, 28 Jun 2010 15:37:45 +0200 Subject: [svn] GnuPG - r5365 - trunk/dirmngr Message-ID: Author: wk Date: 2010-06-28 15:37:44 +0200 (Mon, 28 Jun 2010) New Revision: 5365 Modified: trunk/dirmngr/ChangeLog trunk/dirmngr/Makefile.am trunk/dirmngr/dirmngr-client.c trunk/dirmngr/dirmngr_ldap.c Log: Make it build on W32 again. Modified: trunk/dirmngr/ChangeLog =================================================================== --- trunk/dirmngr/ChangeLog 2010-06-24 10:51:30 UTC (rev 5364) +++ trunk/dirmngr/ChangeLog 2010-06-28 13:37:44 UTC (rev 5365) @@ -1,3 +1,14 @@ +2010-06-28 Werner Koch + + * dirmngr_ldap.c (my_i18n_init): Remove. + (main): Call i18n_init instead of above function. + + * dirmngr-client.c (my_i18n_init): Remove. + (main): Call i18n_init instead of above function. + + * Makefile.am (dirmngr_LDADD): Add ../gl/libgnu. + (dirmngr_ldap_LDADD, dirmngr_client_LDADD): Ditto. + 2010-06-09 Werner Koch * i18n.h: Remove. Modified: trunk/dirmngr/Makefile.am =================================================================== --- trunk/dirmngr/Makefile.am 2010-06-24 10:51:30 UTC (rev 5364) +++ trunk/dirmngr/Makefile.am 2010-06-28 13:37:44 UTC (rev 5365) @@ -41,7 +41,7 @@ b64dec.c cdb.h cdblib.c ldap.c http.c http.h misc.c \ ocsp.c ocsp.h validate.c validate.h -dirmngr_LDADD = $(libcommonpth) $(DNSLIBS) $(LIBASSUAN_LIBS) \ +dirmngr_LDADD = $(libcommonpth) ../gl/libgnu.a $(DNSLIBS) $(LIBASSUAN_LIBS) \ $(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(PTH_LIBS) $(LIBINTL) $(LIBICONV) if HAVE_W32_SYSTEM @@ -53,11 +53,11 @@ dirmngr_ldap_SOURCES = dirmngr_ldap.c $(ldap_url) no-libgcrypt.c dirmngr_ldap_CFLAGS = $(GPG_ERROR_CFLAGS) dirmngr_ldap_LDFLAGS = -dirmngr_ldap_LDADD = $(libcommon) $(DNSLIBS) \ +dirmngr_ldap_LDADD = $(libcommon) ../gl/libgnu.a $(DNSLIBS) \ $(GPG_ERROR_LIBS) $(LDAPLIBS) $(LIBINTL) $(LIBICONV) dirmngr_client_SOURCES = dirmngr-client.c b64enc.c no-libgcrypt.c -dirmngr_client_LDADD = $(libcommon) $(LIBASSUAN_LIBS) \ +dirmngr_client_LDADD = $(libcommon) ../gl/libgnu.a $(LIBASSUAN_LIBS) \ $(GPG_ERROR_LIBS) $(LIBINTL) $(LIBICONV) Modified: trunk/dirmngr/dirmngr-client.c =================================================================== --- trunk/dirmngr/dirmngr-client.c 2010-06-24 10:51:30 UTC (rev 5364) +++ trunk/dirmngr/dirmngr-client.c 2010-06-28 13:37:44 UTC (rev 5365) @@ -164,22 +164,7 @@ } -static void -my_i18n_init (void) -{ -#warning Better use common init functions -#ifdef USE_SIMPLE_GETTEXT - set_gettext_file (PACKAGE); -#else -# ifdef ENABLE_NLS - setlocale (LC_ALL, "" ); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); -# endif -#endif -} - int main (int argc, char **argv ) { @@ -214,7 +199,7 @@ assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT); /* Setup I18N. */ - my_i18n_init(); + i18n_init(); /* Parse the command line. */ pargs.argc = &argc; Modified: trunk/dirmngr/dirmngr_ldap.c =================================================================== --- trunk/dirmngr/dirmngr_ldap.c 2010-06-24 10:51:30 UTC (rev 5364) +++ trunk/dirmngr/dirmngr_ldap.c 2010-06-28 13:37:44 UTC (rev 5365) @@ -161,22 +161,6 @@ } -static void -my_i18n_init (void) -{ -#warning Better use common init functions -#ifdef USE_SIMPLE_GETTEXT - set_gettext_file (PACKAGE); -#else -# ifdef ENABLE_NLS - setlocale (LC_ALL, "" ); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); -# endif -#endif -} - - int main (int argc, char **argv ) { @@ -194,7 +178,7 @@ log_set_prefix ("dirmngr_ldap", JNLIB_LOG_WITH_PREFIX); /* Setup I18N. */ - my_i18n_init(); + i18n_init(); /* LDAP defaults */ opt.timeout.tv_sec = DEFAULT_LDAP_TIMEOUT; From cvs at cvs.gnupg.org Tue Jun 29 19:11:03 2010 From: cvs at cvs.gnupg.org (svn author wk) Date: Tue, 29 Jun 2010 19:11:03 +0200 Subject: [svn] assuan - r378 - trunk/src Message-ID: Author: wk Date: 2010-06-29 19:11:03 +0200 (Tue, 29 Jun 2010) New Revision: 378 Modified: trunk/src/ChangeLog trunk/src/gpgcedev.c trunk/src/gpgcemgr.c Log: Handle NOTIFY event. Modified: trunk/src/ChangeLog =================================================================== --- trunk/src/ChangeLog 2010-06-10 23:09:32 UTC (rev 377) +++ trunk/src/ChangeLog 2010-06-29 17:11:03 UTC (rev 378) @@ -1,3 +1,7 @@ +2010-06-28 Werner Koch + + * gpgcedev.c (GPG_IOControl) : Unblock threads. + 2010-06-11 Marcus Brinkmann * assuan-handler.c (std_handler_input, @@ -14,7 +18,7 @@ * w32ce-add.h (ASSUAN_STDIN, ASSUAN_STDOUT): Define magic handle values. * system-w32ce.c (__assuan_read, __assuan_write): Handle magic handle values differently. - + * system-w32ce.c (_assuan_w32ce_finish_pipe): Return error on RVID 0. 2010-06-09 Marcus Brinkmann Modified: trunk/src/gpgcedev.c =================================================================== --- trunk/src/gpgcedev.c 2010-06-10 23:09:32 UTC (rev 377) +++ trunk/src/gpgcedev.c 2010-06-29 17:11:03 UTC (rev 378) @@ -25,7 +25,7 @@ #include #define ENABLE_DEBUG -#warning Cancel and caller process termination not handled. +#warning Cancel not handled. /* Missing IOCTLs in the current mingw32ce. */ @@ -826,8 +826,15 @@ break; case IOCTL_PSL_NOTIFY: + /* This notification is received if the application's main + thread exits and the application has other threads running + and the application has open handles for this device. What + we do is to unblock them all simialr to an explicit unblock + call. */ log_debug ("GPG_IOControl (ctx=0x%p): code: NOTIFY\n", (void*)opnctx); - /* Unexpected process termination. */ + + if (unblock_call (opnctx)) + result = TRUE; break; default: Modified: trunk/src/gpgcemgr.c =================================================================== --- trunk/src/gpgcemgr.c 2010-06-10 23:09:32 UTC (rev 377) +++ trunk/src/gpgcemgr.c 2010-06-29 17:11:03 UTC (rev 378) @@ -102,7 +102,176 @@ } +/* Kudos to Scott Seligman for his work + on the reverse engineering. */ +struct htc_sensor_s +{ + SHORT tilt_x; // From -1000 to 1000 (about), 0 is flat + SHORT tilt_y; // From -1000 to 1000 (about), 0 is flat + SHORT tilt_z; // From -1000 to 1000 (about) + DWORD angle_x; // 0 .. 359 + DWORD angle_y; // From 0 to 359 + DWORD orientation; // 0.. 5? + DWORD unknown; // Handle? +}; +typedef struct htc_sensor_s *htc_sensor_t; +static HANDLE (WINAPI *HTCSensorOpen) (DWORD); +static void (WINAPI *HTCSensorClose) (HANDLE); +static DWORD (WINAPI *HTCSensorGetDataOutput) (HANDLE, htc_sensor_t); + +static int +load_sensor_api (void) +{ + static HMODULE dll_hd; + + if (dll_hd) + return 0; + + dll_hd = LoadLibrary (L"HTCSensorSDK.dll"); + if (!dll_hd) + { + fprintf (stderr, PGM": error loading sensor DLL: rc=%d\n", + (int)GetLastError ()); + return 1; + } + + HTCSensorOpen = (void*)GetProcAddress (dll_hd, L"HTCSensorOpen"); + if (HTCSensorOpen) + HTCSensorClose = (void*)GetProcAddress (dll_hd, L"HTCSensorClose"); + if (HTCSensorClose) + HTCSensorGetDataOutput = (void*) + GetProcAddress (dll_hd, L"HTCSensorGetDataOutput"); + if (!HTCSensorGetDataOutput) + { + fprintf (stderr, PGM": error loading function from sensor DLL: rc=%d\n", + (int)GetLastError ()); + CloseHandle (dll_hd); + return 1; + } + return 0; +} + + +static int +gravity (void) +{ + int rc; + HANDLE sensor; + struct htc_sensor_s lastdata; + struct htc_sensor_s data; + + rc = load_sensor_api (); + if (rc) + return rc; + + sensor = HTCSensorOpen (1 /* tilt sensor */); + if (!sensor || sensor == INVALID_HANDLE_VALUE) + { + fprintf (stderr, PGM": error opening gravity sensor: rc=%d\n", + (int)GetLastError ()); + HTCSensorClose (sensor); + return 1; + } + + memset (&lastdata, 0, sizeof lastdata); + while (HTCSensorGetDataOutput (sensor, &data)) + { + if (lastdata.tilt_x/10 != data.tilt_x/10 + || lastdata.tilt_y/10 != data.tilt_y/10 + || lastdata.tilt_z/10 != data.tilt_z/10 + || lastdata.angle_x/5 != data.angle_x/5 + || lastdata.angle_y/5 != data.angle_y/5 + || lastdata.orientation != data.orientation) + { + lastdata = data; + printf ("tilt: x=%-5d y=%-5d z=%-5d " + "angle: x=%-3d y=%-3d " + "ori: %d\n", + (int)data.tilt_x, (int)data.tilt_y, (int)data.tilt_z, + (int)data.angle_x, (int)data.angle_y, + (int)data.orientation); + } + Sleep (200); + } + fprintf (stderr, PGM": reading sensor data failed: rc=%d\n", + (int)GetLastError ()); + HTCSensorClose (sensor); + return 0; +} + + + +/* No GPD1 device on the HTC Touch Pro 2. */ +# if 0 +static int +gps_raw (void) +{ + HANDLE hd; + char buffer[1000]; + unsigned long nread; + int count; + + hd = CreateFile (L"GPD1:", GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (hd == INVALID_HANDLE_VALUE) + { + fprintf (stderr, PGM": can't open `GPD1': rc=%d\n", + (int)GetLastError ()); + return 1; + } + fprintf (stderr, PGM": GPS device successfully opened\n"); + + for (count=0; count < 100; count++) + { + if (!ReadFile (hd, buffer, sizeof buffer-1, &nread, NULL)) + { + fprintf (stderr, PGM": error reading `GPD1': rc=%d\n", + (int)GetLastError ()); + CloseHandle (hd); + return 1; + } + buffer[nread-1] = 0; + fputs (buffer, stdout); + } + + CloseHandle (hd); + return 0; +} +#endif + +/* Untested samples for CE6. */ +#if 0 +static int +gps (void) +{ + HANDLE hd; + GPS_POSITION pos; + + hd = GPSOpenDevice (NULL, NULL, NULL, 0); + if (hd == INVALID_HANDLE_VALUE) + { + fprintf (stderr, PGM": GPSOpenDevice failed: rc=%d\n", + (int)GetLastError ()); + return 1; + } + fprintf (stderr, PGM": GPS device successfully opened\n"); + + if (GPSGetPosition (hd, &pos, 2000, 0)) + { + fprintf (stderr, PGM": GPSGetPosition failed: rc=%d\n", + (int)GetLastError ()); + GPSCloseDevice (hd); + return 1; + } + + + GPSCloseDevice (hd); + return 0; +} +#endif + + int main (int argc, char **argv) { @@ -125,6 +294,10 @@ else fprintf (stderr, PGM": device activated\n"); } + else if (argc > 1 && !strcmp (argv[1], "--gravity")) + result = gravity (); + /* else if (argc > 1 && !strcmp (argv[1], "--gps")) */ + /* result = gps (); */ else { fprintf (stderr, "usage: " PGM " --register|--deactivate|--activate\n"); From cvs at cvs.gnupg.org Tue Jun 29 19:12:30 2010 From: cvs at cvs.gnupg.org (svn author wk) Date: Tue, 29 Jun 2010 19:12:30 +0200 Subject: [svn] gpg-error - r244 - trunk Message-ID: Author: wk Date: 2010-06-29 19:12:30 +0200 (Tue, 29 Jun 2010) New Revision: 244 Modified: trunk/NEWS Log: Update Modified: trunk/NEWS =================================================================== --- trunk/NEWS 2010-06-18 14:23:20 UTC (rev 243) +++ trunk/NEWS 2010-06-29 17:12:30 UTC (rev 244) @@ -2,6 +2,11 @@ ---------------------------------------------- + * Interface changes relative to the 1.8 release: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + GPG_ERR_MISSING_KEY NEW. + + Noteworthy changes in version 1.8 (2010-05-06) ---------------------------------------------- From cvs at cvs.gnupg.org Tue Jun 29 19:13:07 2010 From: cvs at cvs.gnupg.org (svn author wk) Date: Tue, 29 Jun 2010 19:13:07 +0200 Subject: [svn] gpgme - r1482 - in trunk: . src Message-ID: Author: wk Date: 2010-06-29 19:13:07 +0200 (Tue, 29 Jun 2010) New Revision: 1482 Modified: trunk/NEWS trunk/src/engine.c Log: comment typo fixes Modified: trunk/NEWS =================================================================== --- trunk/NEWS 2010-06-10 23:29:06 UTC (rev 1481) +++ trunk/NEWS 2010-06-29 17:13:07 UTC (rev 1482) @@ -23,7 +23,7 @@ * New engine GPGME_PROTOCOL_UISERVER to support UI Servers. - * New API to change the passpgrase of a key. + * New API to change the passphrase of a key. * Interface changes relative to the 1.2.0 release: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Modified: trunk/src/engine.c =================================================================== --- trunk/src/engine.c 2010-06-10 23:29:06 UTC (rev 1481) +++ trunk/src/engine.c 2010-06-29 17:13:07 UTC (rev 1482) @@ -66,7 +66,7 @@ NULL, #endif #ifdef ENABLE_UISERVER - &_gpgme_engine_ops_uiserver /* Crypto VFS. */ + &_gpgme_engine_ops_uiserver /* UI-Server. */ #else NULL #endif From cvs at cvs.gnupg.org Tue Jun 29 19:14:36 2010 From: cvs at cvs.gnupg.org (svn author wk) Date: Tue, 29 Jun 2010 19:14:36 +0200 Subject: [svn] gcry - r1435 - trunk/src Message-ID: Author: wk Date: 2010-06-29 19:14:35 +0200 (Tue, 29 Jun 2010) New Revision: 1435 Modified: trunk/src/ChangeLog trunk/src/gcrypt.h.in trunk/src/sexp.c Log: fixes for msvc compiler Modified: trunk/src/ChangeLog =================================================================== --- trunk/src/ChangeLog 2010-06-10 09:06:46 UTC (rev 1434) +++ trunk/src/ChangeLog 2010-06-29 17:14:35 UTC (rev 1435) @@ -1,3 +1,7 @@ +2010-06-24 Werner Koch + + * gcrypt.h.in [W32]: Include time.h and not sys/time.h. + 2010-04-19 Marcus Brinkmann * misc.c (write2stderr): Dummy variable to silence gcc warning. Modified: trunk/src/gcrypt.h.in =================================================================== --- trunk/src/gcrypt.h.in 2010-06-10 09:06:46 UTC (rev 1434) +++ trunk/src/gcrypt.h.in 2010-06-29 17:14:35 UTC (rev 1435) @@ -33,14 +33,15 @@ #if defined _WIN32 || defined __WIN32__ # include # include +# include + typedef long ssize_t; #else # include +# include #endif /*!_WIN32*/ @FALLBACK_SOCKLEN_T@ -#include - /* This is required for error code compatibility. */ #define _GCRY_ERR_SOURCE_DEFAULT GPG_ERR_SOURCE_GCRYPT Modified: trunk/src/sexp.c =================================================================== --- trunk/src/sexp.c 2010-06-10 09:06:46 UTC (rev 1434) +++ trunk/src/sexp.c 2010-06-29 17:14:35 UTC (rev 1435) @@ -1838,7 +1838,7 @@ } -/* Scan a cannocial encoded buffer with implicit length values and +/* Scan a canonical encoded buffer with implicit length values and return the actual length this S-expression uses. For a valid S-Exp it should never return 0. If LENGTH is not zero, the maximum length to scan is given - this can be used for syntax checks of