diff options
-rw-r--r-- | THANKS | 1 | ||||
-rw-r--r-- | dirmngr/ChangeLog | 10 | ||||
-rw-r--r-- | dirmngr/dirmngr.c | 295 | ||||
-rw-r--r-- | dirmngr/ldap-wrapper.c | 11 | ||||
-rw-r--r-- | po/remove-potcdate.sed | 11 | ||||
-rw-r--r-- | scd/ChangeLog | 20 | ||||
-rw-r--r-- | scd/apdu.c | 20 | ||||
-rw-r--r-- | scd/apdu.h | 4 | ||||
-rw-r--r-- | scd/command.c | 35 | ||||
-rw-r--r-- | scd/sc-copykeys.c | 2 |
10 files changed, 273 insertions, 136 deletions
@@ -92,6 +92,7 @@ Geoff Keating geoffk at ozemail.com.au Georg Schwarz georg.schwarz at iname.com Giampaolo Tomassoni g.tomassoni at libero.it Gilbert Fernandes gilbert_fernandes at hotmail.com +Grant Olson kgo at grant-olson net Greg Louis glouis at dynamicro.on.ca Greg Troxel gdt at ir.bbn.com Gregory Steuck steuck at iname.com diff --git a/dirmngr/ChangeLog b/dirmngr/ChangeLog index 39df05d0b..02defce7e 100644 --- a/dirmngr/ChangeLog +++ b/dirmngr/ChangeLog @@ -1,3 +1,13 @@ +2011-01-25 Werner Koch <[email protected]> + + * dirmngr.c (handle_connections): Rewrite loop to use pth-select + so to sync timeouts to the full second. + (pth_thread_id): New. + (main) [W32CE]: Fix setting of default homedir. + + * ldap-wrapper.c (ldap_wrapper_thread): Sync to the full second. + Increate pth_wait timeout from 1 to 2 seconds. + 2011-01-20 Werner Koch <[email protected]> * server.c (release_ctrl_keyservers): New. diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c index ae922fa31..e1bae7ea3 100644 --- a/dirmngr/dirmngr.c +++ b/dirmngr/dirmngr.c @@ -1,6 +1,6 @@ /* dirmngr.c - LDAP access * Copyright (C) 2002 Klarälvdalens Datakonsult AB - * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2010 g10 Code GmbH + * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2010, 2011 g10 Code GmbH * * This file is part of DirMngr. * @@ -47,7 +47,7 @@ #define JNLIB_NEED_AFLOCAL #include "dirmngr.h" -#include <assuan.h> +#include <assuan.h> #include "certcache.h" #include "crlcache.h" @@ -74,7 +74,7 @@ enum cmd_and_opt_values { oSh = 's', oVerbose = 'v', oNoVerbose = 500, - + aServer, aDaemon, aService, @@ -128,7 +128,7 @@ enum cmd_and_opt_values { static ARGPARSE_OPTS opts[] = { - + ARGPARSE_group (300, N_("@Commands:\n ")), ARGPARSE_c (aServer, "server", N_("run in server mode (foreground)") ), @@ -185,13 +185,13 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_s (oOCSPResponder, "ocsp-responder", N_("|URL|use OCSP responder at URL")), - ARGPARSE_s_s (oOCSPSigner, "ocsp-signer", - N_("|FPR|OCSP response signed by FPR")), + ARGPARSE_s_s (oOCSPSigner, "ocsp-signer", + N_("|FPR|OCSP response signed by FPR")), ARGPARSE_s_i (oOCSPMaxClockSkew, "ocsp-max-clock-skew", "@"), ARGPARSE_s_i (oOCSPMaxPeriod, "ocsp-max-period", "@"), ARGPARSE_s_i (oOCSPCurrentPeriod, "ocsp-current-period", "@"), - ARGPARSE_s_i (oMaxReplies, "max-replies", + ARGPARSE_s_i (oMaxReplies, "max-replies", N_("|N|do not return more than N items in one query")), ARGPARSE_s_s (oSocketName, "socket-name", "@"), /* Only for debugging. */ @@ -201,7 +201,7 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_n (oDebugAll, "debug-all", "@"), ARGPARSE_s_i (oDebugWait, "debug-wait", "@"), ARGPARSE_s_n (oNoGreeting, "no-greeting", "@"), - ARGPARSE_s_s (oHomedir, "homedir", "@"), + ARGPARSE_s_s (oHomedir, "homedir", "@"), ARGPARSE_s_s (oLDAPWrapperProgram, "ldap-wrapper-program", "@"), ARGPARSE_s_s (oHTTPWrapperProgram, "http-wrapper-program", "@"), ARGPARSE_s_n (oHonorHTTPProxy, "honor-http-proxy", "@"), @@ -286,11 +286,18 @@ static int fixed_gcry_pth_init (void) return pth_self ()? 0 : (pth_init () == FALSE) ? errno : 0; } +#ifndef PTH_HAVE_PTH_THREAD_ID +static unsigned long pth_thread_id (void) +{ + return (unsigned long)pth_self (); +} +#endif + static const char * my_strusage( int level ) { const char *p; - switch ( level ) + switch ( level ) { case 11: p = "dirmngr (GnuPG)"; break; @@ -307,7 +314,7 @@ my_strusage( int level ) case 41: p = _("Syntax: dirmngr [options] [command [args]]\n" "LDAP and OCSP access for GnuPG\n"); break; - + default: p = NULL; } return p; @@ -318,18 +325,18 @@ my_strusage( int level ) implementation does only allow SHA-1 for hashing. This may be extended by mapping the name, testing for algorithm availibility and adjust the length checks accordingly. */ -static gpg_error_t +static gpg_error_t my_ksba_hash_buffer (void *arg, const char *oid, const void *buffer, size_t length, size_t resultsize, unsigned char *result, size_t *resultlen) { (void)arg; - if (oid && strcmp (oid, "1.3.14.3.2.26")) - return gpg_error (GPG_ERR_NOT_SUPPORTED); + if (oid && strcmp (oid, "1.3.14.3.2.26")) + return gpg_error (GPG_ERR_NOT_SUPPORTED); if (resultsize < 20) return gpg_error (GPG_ERR_BUFFER_TOO_SHORT); - gcry_md_hash_buffer (2, result, buffer, length); + gcry_md_hash_buffer (2, result, buffer, length); *resultlen = 20; return 0; } @@ -362,7 +369,7 @@ set_debug (void) /* Unless the "guru" string has been used we don't want to allow hashing debugging. The rationale is that people tend to select the highest debug value and would then clutter their - disk with debug files which may reveal confidential data. */ + disk with debug files which may reveal confidential data. */ if (numok) opt.debug &= ~(DBG_HASHING_VALUE); } @@ -387,7 +394,7 @@ set_debug (void) if (opt.debug & DBG_CRYPTO_VALUE ) gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1); } - + static void wrong_args (const char *text) @@ -422,10 +429,10 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread) opt.debug = 0; opt.ldap_wrapper_program = NULL; opt.disable_http = 0; - opt.disable_ldap = 0; - opt.honor_http_proxy = 0; - opt.http_proxy = NULL; - opt.ldap_proxy = NULL; + opt.disable_ldap = 0; + opt.honor_http_proxy = 0; + opt.http_proxy = NULL; + opt.ldap_proxy = NULL; opt.only_ldap_proxy = 0; opt.ignore_http_dp = 0; opt.ignore_ldap_dp = 0; @@ -485,7 +492,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread) case oAllowOCSP: opt.allow_ocsp = 1; break; case oOCSPResponder: opt.ocsp_responder = pargs->r.ret_str; break; - case oOCSPSigner: + case oOCSPSigner: opt.ocsp_signer = parse_ocsp_signer (pargs->r.ret_str); break; case oOCSPMaxClockSkew: opt.ocsp_max_clock_skew = pargs->r.ret_int; break; @@ -521,13 +528,13 @@ w32_service_control (DWORD control, DWORD event_type, LPVOID event_data, case SERVICE_CONTROL_SHUTDOWN: /* For shutdown we will try to force termination. */ service_status.dwCurrentState = SERVICE_STOP_PENDING; - SetServiceStatus (service_handle, &service_status); + SetServiceStatus (service_handle, &service_status); shutdown_pending = 3; break; case SERVICE_CONTROL_STOP: service_status.dwCurrentState = SERVICE_STOP_PENDING; - SetServiceStatus (service_handle, &service_status); + SetServiceStatus (service_handle, &service_status); shutdown_pending = 1; break; @@ -600,12 +607,12 @@ main (int argc, char **argv) service_status.dwServiceSpecificExitCode = NO_ERROR; service_status.dwCheckPoint = 0; service_status.dwWaitHint = 10000; /* 10 seconds timeout. */ - SetServiceStatus (service_handle, &service_status); + SetServiceStatus (service_handle, &service_status); } #endif /*USE_W32_SERVICE*/ set_strusage (my_strusage); - log_set_prefix ("dirmngr", 1|4); + log_set_prefix ("dirmngr", 1|4); /* Make sure that our subsystems are ready. */ i18n_init (); @@ -621,7 +628,7 @@ main (int argc, char **argv) gpg_strerror (rc)); } gcry_control (GCRYCTL_DISABLE_SECMEM, 0); - + /* Check that the libraries are suitable. Do it here because the option parsing may need services of the libraries. */ @@ -664,9 +671,9 @@ main (int argc, char **argv) if (pth_key_setdata (my_tlskey_current_fd, NULL)) log_set_pid_suffix_cb (pid_suffix_callback); #endif /*!HAVE_W32_SYSTEM*/ - + /* Reset rereadable options to default values. */ - parse_rereadable_options (NULL, 0); + parse_rereadable_options (NULL, 0); /* LDAP defaults. */ opt.add_new_ldapservers = 0; @@ -722,7 +729,7 @@ main (int argc, char **argv) if (opt.system_daemon && !homedir_seen) { #ifdef HAVE_W32CE_SYSTEM - opt.homedir == DIRSEP_S "gnupg"; + opt.homedir = DIRSEP_S "gnupg"; #else opt.homedir = gnupg_sysconfdir (); #endif @@ -732,7 +739,7 @@ main (int argc, char **argv) if (default_config) configname = make_filename (opt.homedir, "dirmngr.conf", NULL ); - + argc = orig_argc; argv = orig_argv; pargs.argc = &argc; @@ -757,7 +764,7 @@ main (int argc, char **argv) configname, strerror(errno) ); exit(2); } - xfree (configname); + xfree (configname); configname = NULL; } if (parse_debug && configname ) @@ -771,13 +778,13 @@ main (int argc, char **argv) continue; /* Already handled */ switch (pargs.r_opt) { - case aServer: + case aServer: case aDaemon: case aService: - case aShutdown: - case aFlush: - case aListCRLs: - case aLoadCRL: + case aShutdown: + case aFlush: + case aListCRLs: + case aLoadCRL: case aFetchCRL: case aGPGConfList: case aGPGConfTest: @@ -812,8 +819,8 @@ main (int argc, char **argv) case oSh: csh_style = 0; break; case oLDAPFile: ldapfile = pargs.r.ret_str; break; case oLDAPAddServers: opt.add_new_ldapservers = 1; break; - case oLDAPTimeout: - opt.ldaptimeout = pargs.r.ret_int; + case oLDAPTimeout: + opt.ldaptimeout = pargs.r.ret_int; break; case oFakedSystemTime: @@ -860,12 +867,12 @@ main (int argc, char **argv) #endif if (!access ("/etc/dirmngr", F_OK) && !strncmp (opt.homedir, "/etc/", 5)) - log_info + log_info ("NOTE: DirMngr is now a proper part of GnuPG. The configuration and" " other directory names changed. Please check that no other version" " of dirmngr is still installed. To disable this warning, remove the" " directory `/etc/dirmngr'.\n"); - + if (gnupg_faked_time_p ()) { gnupg_isotime_t tbuf; @@ -879,7 +886,7 @@ main (int argc, char **argv) set_debug (); /* Get LDAP server list from file. */ - if (!ldapfile) + if (!ldapfile) { ldapfile = make_filename (opt.homedir, opt.system_daemon? @@ -917,7 +924,7 @@ main (int argc, char **argv) log_set_file (logfile); log_set_prefix (NULL, 2|4); } - + if (debug_wait) { log_debug ("waiting for debugger - my pid is %u .....\n", @@ -941,7 +948,7 @@ main (int argc, char **argv) if (argc) wrong_args ("--daemon"); - + /* Now start with logging to a file if this is desired. */ if (logfile) { @@ -959,12 +966,12 @@ main (int argc, char **argv) dirmngr_exit (1); } #endif - if (strlen (socket_name)+1 >= sizeof serv_addr.sun_path ) + if (strlen (socket_name)+1 >= sizeof serv_addr.sun_path ) { log_error (_("name of socket too long\n")); dirmngr_exit (1); } - + fd = assuan_sock_new (AF_UNIX, SOCK_STREAM, 0); if (fd == ASSUAN_INVALID_FD) { @@ -979,7 +986,7 @@ main (int argc, char **argv) len = SUN_LEN (&serv_addr); rc = assuan_sock_bind (fd, (struct sockaddr*) &serv_addr, len); - if (rc == -1 + if (rc == -1 && (errno == EADDRINUSE #ifdef HAVE_W32_SYSTEM || errno == EEXIST @@ -990,7 +997,7 @@ main (int argc, char **argv) gnupg_remove (socket_name); rc = assuan_sock_bind (fd, (struct sockaddr*) &serv_addr, len); } - if (rc != -1 + if (rc != -1 && (rc = assuan_sock_get_nonce ((struct sockaddr*) &serv_addr, len, &socket_nonce))) log_error (_("error getting nonce for the socket\n")); if (rc == -1) @@ -1001,7 +1008,7 @@ main (int argc, char **argv) dirmngr_exit (1); } cleanup_socket = 1; - + if (listen (FD2INT (fd), 5) == -1) { log_error (_("listen() failed: %s\n"), strerror (errno)); @@ -1022,22 +1029,22 @@ main (int argc, char **argv) es_printf ("set DIRMNGR_INFO=%s;%lu;1\n", socket_name, (ulong) pid); #else pid = pth_fork (); - if (pid == (pid_t)-1) + if (pid == (pid_t)-1) { log_fatal (_("error forking process: %s\n"), strerror (errno)); dirmngr_exit (1); } - if (pid) + if (pid) { /* We are the parent */ char *infostr; - + /* Don't let cleanup() remove the socket - the child is responsible for doing that. */ cleanup_socket = 0; close (fd); - + /* Create the info string: <name>:<pid>:<protocol_version> */ if (asprintf (&infostr, "DIRMNGR_INFO=%s:%lu:1", socket_name, (ulong)pid ) < 0) @@ -1058,18 +1065,18 @@ main (int argc, char **argv) es_printf ( "%s; export DIRMNGR_INFO;\n", infostr); } free (infostr); - exit (0); + exit (0); /*NEVER REACHED*/ } /* end parent */ - - - /* + + + /* This is the child */ /* Detach from tty and put process into a new session */ if (!nodetach ) - { + { int i; unsigned int oldflags; @@ -1165,7 +1172,7 @@ main (int argc, char **argv) argv[0], gpg_strerror (rc)); else { - rc = crl_cache_insert (&ctrlbuf, argv[0], reader); + rc = crl_cache_insert (&ctrlbuf, argv[0], reader); if (rc) log_error (_("processing CRL from `%s' failed: %s\n"), argv[0], gpg_strerror (rc)); @@ -1236,7 +1243,7 @@ main (int argc, char **argv) and having both of them is thus problematic. --no-detach is also only usable on the command line. --batch is unused. */ - filename = make_filename (opt.homedir, + filename = make_filename (opt.homedir, opt.system_daemon? "ldapservers.conf":"dirmngr_ldapservers.conf", NULL); @@ -1327,7 +1334,7 @@ cleanup (void) } -void +void dirmngr_exit (int rc) { cleanup (); @@ -1345,7 +1352,7 @@ dirmngr_init_default_ctrl (ctrl_t ctrl) /* Create a list of LDAP servers from the file FILENAME. Returns the - list or NULL in case of errors. + list or NULL in case of errors. The format fo such a file is line oriented where empty lines and lines starting with a hash mark are ignored. All other lines are @@ -1353,7 +1360,7 @@ dirmngr_init_default_ctrl (ctrl_t ctrl) 1. field: Hostname 2. field: Portnumber - 3. field: Username + 3. field: Username 4. field: Password 5. field: Base DN @@ -1406,8 +1413,8 @@ parse_ldapserver_file (const char* filename) *serverend = server; serverend = &server->next; } - } - + } + if (es_ferror (fp)) log_error (_("error reading `%s': %s\n"), filename, strerror (errno)); es_fclose (fp); @@ -1441,14 +1448,14 @@ parse_ocsp_signer (const char *string) item->hexfpr[j] = 0; if (j != 40 || !(spacep (string+i) || !string[i])) { - log_error (_("%s:%u: invalid fingerprint detected\n"), + log_error (_("%s:%u: invalid fingerprint detected\n"), "--ocsp-signer", 0); xfree (item); return NULL; } return item; } - + /* Well, it is a filename. */ if (*string == '/' || (*string == '~' && string[1] == '/')) fname = make_filename (string, NULL); @@ -1503,7 +1510,7 @@ parse_ocsp_signer (const char *string) ; err = gpg_error (*line? GPG_ERR_LINE_TOO_LONG /* */: GPG_ERR_INCOMPLETE_LINE); - log_error (_("%s:%u: read error: %s\n"), + log_error (_("%s:%u: read error: %s\n"), fname, lnr, gpg_strerror (err)); errflag = 1; continue; @@ -1541,14 +1548,14 @@ parse_ocsp_signer (const char *string) /* - Stuff used in daemon mode. + Stuff used in daemon mode. */ /* Reread parts of the configuration. Note, that this function is obviously not thread-safe and should only be called from the PTH - signal handler. + signal handler. Fixme: Due to the way the argument parsing works, we create a memory leak here for all string type arguments. There is currently @@ -1619,11 +1626,11 @@ handle_signal (int signo) case SIGHUP: dirmngr_sighup_action (); break; - + case SIGUSR1: cert_cache_print_stats (); break; - + case SIGUSR2: log_info (_("SIGUSR2 received - no action defined\n")); break; @@ -1643,7 +1650,7 @@ handle_signal (int signo) dirmngr_exit (0); } break; - + case SIGINT: log_info (_("SIGINT received - immediate shutdown\n")); log_info( "%s %s stopped\n", strusage(11), strusage(13)); @@ -1681,12 +1688,12 @@ handle_tick (void) /* Check the nonce on a new connection. This is a NOP unless we we are using our Unix domain socket emulation under Windows. */ -static int +static int check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce) { if (assuan_sock_check_nonce (fd, nonce)) { - log_info (_("error reading nonce on fd %d: %s\n"), + log_info (_("error reading nonce on fd %d: %s\n"), FD2INT (fd), strerror (errno)); assuan_sock_close (fd); return -1; @@ -1701,13 +1708,16 @@ static void * start_connection_thread (void *arg) { union int_and_ptr_u argval; - assuan_fd_t fd; + gnupg_fd_t fd; argval.aptr = arg; fd = argval.afd; if (check_nonce (fd, &socket_nonce)) - return NULL; + { + log_error ("handler 0x%lx nonce check FAILED\n", pth_thread_id ()); + return NULL; + } #ifndef HAVE_W32_SYSTEM pth_key_setdata (my_tlskey_current_fd, argval.aptr); @@ -1727,7 +1737,7 @@ start_connection_thread (void *arg) argval.afd = ASSUAN_INVALID_FD; pth_key_setdata (my_tlskey_current_fd, argval.aptr); #endif - + return NULL; } @@ -1738,11 +1748,13 @@ handle_connections (assuan_fd_t listen_fd) { pth_attr_t tattr; pth_event_t ev, time_ev; - sigset_t sigs, oldsigs; + sigset_t sigs; int signo; struct sockaddr_un paddr; socklen_t plen = sizeof( paddr ); - assuan_fd_t fd; + gnupg_fd_t fd; + int nfd, ret; + fd_set fdset, read_fdset; tattr = pth_attr_new(); pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0); @@ -1750,46 +1762,89 @@ handle_connections (assuan_fd_t listen_fd) pth_attr_set (tattr, PTH_ATTR_NAME, "dirmngr"); #ifndef HAVE_W32_SYSTEM /* FIXME */ + /* Make sure that the signals we are going to handle are not blocked + and create an event object for them. We also set the default + action to ignore because we use an Pth event to get notified + about signals. This avoids that the default action is taken in + case soemthing goes wrong within Pth. The problem might also be + a Pth bug. */ sigemptyset (&sigs ); - sigaddset (&sigs, SIGHUP); - sigaddset (&sigs, SIGUSR1); - sigaddset (&sigs, SIGUSR2); - sigaddset (&sigs, SIGINT); - sigaddset (&sigs, SIGTERM); + { + static const int mysigs[] = { SIGHUP, SIGUSR1, SIGUSR2, SIGINT, SIGTERM }; + struct sigaction sa; + int i; + + for (i=0; i < DIM (mysigs); i++) + { + sigemptyset (&sa.sa_mask); + sa.sa_handler = SIG_IGN; + sa.sa_flags = 0; + sigaction (mysigs[i], &sa, NULL); + + sigaddset (&sigs, mysigs[i]); + } + } + + pth_sigmask (SIG_UNBLOCK, &sigs, NULL); ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo); #else + /* Use a dummy event. */ sigs = 0; ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo); #endif time_ev = NULL; + /* Setup the fdset. It has only one member. This is because we use + pth_select instead of pth_accept to properly sync timeouts with + to full second. */ + FD_ZERO (&fdset); + FD_SET (FD2INT (listen_fd), &fdset); + nfd = FD2INT (listen_fd); + + /* Main loop. */ for (;;) { + /* Make sure that our signals are not blocked. */ + pth_sigmask (SIG_UNBLOCK, &sigs, NULL); + + /* Shutdown test. */ if (shutdown_pending) { if (!active_connections) break; /* ready */ - /* Do not accept anymore connections but wait for existing - connections to terminate. */ - signo = 0; - pth_wait (ev); - if (pth_event_occurred (ev) && signo) - handle_signal (signo); - continue; + /* Do not accept new connections but keep on running the + loop to cope with the timer events. */ + FD_ZERO (&fdset); } + /* Create a timeout event if needed. To help with power saving + we syncronize the ticks to the next full second. */ if (!time_ev) - time_ev = pth_event (PTH_EVENT_TIME, - pth_timeout (TIMERTICK_INTERVAL, 0)); + { + pth_time_t nexttick; + + nexttick = pth_timeout (TIMERTICK_INTERVAL, 0); + if (nexttick.tv_usec > 10) /* Use a 10 usec threshhold. */ + { + nexttick.tv_sec++; + nexttick.tv_usec = 0; + } + time_ev = pth_event (PTH_EVENT_TIME, nexttick); + } + + /* Take a copy of the fdset. */ + read_fdset = fdset; if (time_ev) pth_event_concat (ev, time_ev, NULL); - fd = (assuan_fd_t) pth_accept_ev (FD2INT (listen_fd), (struct sockaddr *)&paddr, &plen, ev); + + ret = pth_select_ev (nfd+1, &read_fdset, NULL, NULL, NULL, ev); + if (time_ev) pth_event_isolate (time_ev); - if (fd == ASSUAN_INVALID_FD) + if (ret == -1) { if (pth_event_occurred (ev) || (time_ev && pth_event_occurred (time_ev)) ) @@ -1804,7 +1859,8 @@ handle_connections (assuan_fd_t listen_fd) } continue; } - log_error (_("accept failed: %s - waiting 1s\n"), strerror (errno)); + log_error (_("pth_select failed: %s - waiting 1s\n"), + strerror (errno)); pth_sleep (1); continue; } @@ -1825,25 +1881,38 @@ handle_connections (assuan_fd_t listen_fd) /* We now might create a new thread and because we don't want any signals (as we are handling them here) to be delivered to a new thread we need to block those signals. */ - pth_sigmask (SIG_BLOCK, &sigs, &oldsigs); - - /* Create thread to handle this connection. */ - { - union int_and_ptr_u argval; - - argval.afd = fd; - if (!pth_spawn (tattr, start_connection_thread, argval.aptr)) - { - log_error (_("error spawning connection handler: %s\n"), - strerror (errno) ); - assuan_sock_close (fd); - } - } + pth_sigmask (SIG_BLOCK, &sigs, NULL); - /* Restore the signal mask. */ - pth_sigmask (SIG_SETMASK, &oldsigs, NULL); + if (!shutdown_pending && FD_ISSET (FD2INT (listen_fd), &read_fdset)) + { + plen = sizeof paddr; + fd = INT2FD (pth_accept (FD2INT(listen_fd), + (struct sockaddr *)&paddr, &plen)); + if (fd == GNUPG_INVALID_FD) + { + log_error ("accept failed: %s\n", strerror (errno)); + } + else + { + char threadname[50]; + union int_and_ptr_u argval; + + argval.afd = fd; + snprintf (threadname, sizeof threadname-1, + "conn fd=%d", FD2INT(fd)); + threadname[sizeof threadname -1] = 0; + pth_attr_set (tattr, PTH_ATTR_NAME, threadname); + if (!pth_spawn (tattr, start_connection_thread, argval.aptr)) + { + log_error ("error spawning connection handler: %s\n", + strerror (errno) ); + assuan_sock_close (fd); + } + } + fd = GNUPG_INVALID_FD; + } } - + pth_event_free (ev, PTH_FREE_ALL); if (time_ev) pth_event_free (time_ev, PTH_FREE_ALL); diff --git a/dirmngr/ldap-wrapper.c b/dirmngr/ldap-wrapper.c index 25ec15513..fa5bf3c6b 100644 --- a/dirmngr/ldap-wrapper.c +++ b/dirmngr/ldap-wrapper.c @@ -269,8 +269,17 @@ ldap_wrapper_thread (void *dummy) { pth_event_t timeout_ev; int any_action = 0; + pth_time_t nexttick; - timeout_ev = pth_event (PTH_EVENT_TIME, pth_timeout (1, 0)); + /* We timeout the pth_wait every 2 seconds. To help with power + saving we syncronize the timeouts to the next full second. */ + nexttick = pth_timeout (2, 0); + if (nexttick.tv_usec > 10) /* Use a 10 usec threshhold. */ + { + nexttick.tv_sec++; + nexttick.tv_usec = 0; + } + timeout_ev = pth_event (PTH_EVENT_TIME, nexttick); if (! timeout_ev) { log_error (_("pth_event failed: %s\n"), strerror (errno)); diff --git a/po/remove-potcdate.sed b/po/remove-potcdate.sed deleted file mode 100644 index edb38d704..000000000 --- a/po/remove-potcdate.sed +++ /dev/null @@ -1,11 +0,0 @@ -/^"POT-Creation-Date: .*"$/{ -x -s/P/P/ -ta -g -d -bb -:a -x -:b -} diff --git a/scd/ChangeLog b/scd/ChangeLog index 41a0f76e1..c9f92b428 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,23 @@ +2011-01-25 NIIBE Yutaka <[email protected]>, + Grant Olson <[email protected]> (wk) + + * command.c (do_reset, get_reader_slot) + (update_reader_status_file): Fix handling of the VALID flag for + unplugged readers. + +2011-01-25 Werner Koch <[email protected]> + + From 2.0 branch, 2010-03-17: + + * command.c (open_card): Return GPG_ERR_NOT_OPERATIONAL if no + card services are available. + (get_reader_slot): Detect no services status. + (cmd_serialno): No reset if there are no services. + (scd_command_handler): Stop scdaemon in that case. + * apdu.c (pcsc_no_service): New. + (open_pcsc_reader_direct): Set it. + (apdu_open_reader): Add arg R_NO_SERVICE. + 2011-01-05 Werner Koch <[email protected]> * ccid-driver.c (ccid_transceive_secure): Support the gnuk token. diff --git a/scd/apdu.c b/scd/apdu.c index 80c933e59..dcb0e23bb 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -304,6 +304,9 @@ long (* DLSTDCALL pcsc_transmit) (unsigned long card, long (* DLSTDCALL pcsc_set_timeout) (unsigned long context, unsigned long timeout); +/* Flag set if PC/SC returned the no-service error. */ +static int pcsc_no_service; + /* Prototypes. */ static int pcsc_get_status (int slot, unsigned int *status); @@ -1504,8 +1507,11 @@ open_pcsc_reader_direct (const char *portstr) log_error ("pcsc_establish_context failed: %s (0x%lx)\n", pcsc_error_string (err), err); reader_table[slot].used = 0; + if (err == 0x8010001d) + pcsc_no_service = 1; return -1; } + pcsc_no_service = 0; err = pcsc_list_readers (reader_table[slot].pcsc.context, NULL, NULL, &nreader); @@ -2338,14 +2344,18 @@ unlock_slot (int slot) error. If PORTSTR is NULL we default to a suitable port (for ctAPI: the first USB reader. For PC/SC the first listed reader). */ int -apdu_open_reader (const char *portstr) +apdu_open_reader (const char *portstr, int *r_no_service) { static int pcsc_api_loaded, ct_api_loaded; + int slot; + + if (r_no_service) + *r_no_service = 0; #ifdef HAVE_LIBUSB if (!opt.disable_ccid) { - int slot, i; + int i; const char *s; slot = open_ccid_reader (portstr); @@ -2475,7 +2485,11 @@ apdu_open_reader (const char *portstr) pcsc_api_loaded = 1; } - return open_pcsc_reader (portstr); + slot = open_pcsc_reader (portstr); + if (slot == -1 && r_no_service && pcsc_no_service) + *r_no_service = 1; + + return slot; } diff --git a/scd/apdu.h b/scd/apdu.h index c47dea882..d79f8b48f 100644 --- a/scd/apdu.h +++ b/scd/apdu.h @@ -80,8 +80,8 @@ enum { #define APDU_CARD_ACTIVE (4) /* Card is active. */ -/* Note , that apdu_open_reader returns no status word but -1 on error. */ -int apdu_open_reader (const char *portstr); +/* Note, that apdu_open_reader returns no status word but -1 on error. */ +int apdu_open_reader (const char *portstr, int *r_no_service); int apdu_open_remote_reader (const char *portstr, const unsigned char *cookie, size_t length, int (*readfnc) (void *opaque, diff --git a/scd/command.c b/scd/command.c index fa1d46ce1..a44378d43 100644 --- a/scd/command.c +++ b/scd/command.c @@ -70,6 +70,10 @@ && (c)->reader_slot == locked_session->ctrl_backlink->reader_slot) +/* Flag indicating that the reader has been disabled. */ +static int reader_disabled; + + /* This structure is used to keep track of open readers (slots). */ struct slot_status_s { @@ -305,7 +309,7 @@ do_reset (ctrl_t ctrl, int send_reset) { if (apdu_reset (slot)) { - slot_table[slot].reset_failed = 1; + slot_table[slot].valid = 0; } application_notify_card_reset (slot); } @@ -394,7 +398,23 @@ get_reader_slot (void) /* Try to open the reader. */ if (ss->slot == -1) - ss->slot = apdu_open_reader (opt.reader_port); + { + int no_service_flag; + ss->slot = apdu_open_reader (opt.reader_port, &no_service_flag); + + /* If we still don't have a slot, we have no readers. + Invalidate for now until a reader is attached. */ + if(ss->slot == -1) + { + ss->valid = 0; + } + + if (no_service_flag) + { + log_info ("no card services - disabling scdaemon\n"); + reader_disabled = 1; + } + } /* Return the slot_table index. */ return 0; @@ -409,6 +429,9 @@ open_card (ctrl_t ctrl, const char *apptype) gpg_error_t err; int slot; + if (reader_disabled) + return gpg_error (GPG_ERR_NOT_OPERATIONAL); + /* If we ever got a card not present error code, return that. Only the SERIALNO command and a reset are able to clear from that state. */ @@ -441,7 +464,7 @@ open_card (ctrl_t ctrl, const char *apptype) slot = get_reader_slot (); ctrl->reader_slot = slot; if (slot == -1) - err = gpg_error (GPG_ERR_CARD); + err = gpg_error (reader_disabled? GPG_ERR_NOT_OPERATIONAL: GPG_ERR_CARD); else { /* Fixme: We should move the apdu_connect call to @@ -495,7 +518,7 @@ cmd_serialno (assuan_context_t ctx, char *line) time_t stamp; /* Clear the remove flag so that the open_card is able to reread it. */ - if (ctrl->server_local->card_removed) + if (!reader_disabled && ctrl->server_local->card_removed) { if ( IS_LOCKED (ctrl) ) return gpg_error (GPG_ERR_LOCKED); @@ -1993,7 +2016,7 @@ scd_command_handler (ctrl_t ctrl, int fd) BUG (); sl->next_session = ctrl->server_local->next_session; } - stopme = ctrl->server_local->stopme; + stopme = ctrl->server_local->stopme || reader_disabled; xfree (ctrl->server_local); ctrl->server_local = NULL; @@ -2175,6 +2198,8 @@ update_reader_status_file (int set_card_removed_flag) if (sw_apdu == SW_HOST_NO_READER) { /* Most likely the _reader_ has been unplugged. */ + apdu_close_reader(ss->slot); + ss->valid = 0; status = 0; changed = ss->changed; } diff --git a/scd/sc-copykeys.c b/scd/sc-copykeys.c index 615e4b28a..b863b01b3 100644 --- a/scd/sc-copykeys.c +++ b/scd/sc-copykeys.c @@ -139,7 +139,7 @@ main (int argc, char **argv ) if (argc != 1) usage (1); - slot = apdu_open_reader (reader_port); + slot = apdu_open_reader (reader_port, NULL); if (slot == -1) exit (1); if (apdu_connect (slot)) |