LCOV - code coverage report
Current view: top level - dirmngr - dirmngr.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 799 0.0 %
Date: 2015-11-05 17:10:59 Functions: 0 31 0.0 %

          Line data    Source code
       1             : /* dirmngr.c - Keyserver and X.509 LDAP access
       2             :  * Copyright (C) 2002 Klarälvdalens Datakonsult AB
       3             :  * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2010, 2011 g10 Code GmbH
       4             :  * Copyright (C) 2014 Werner Koch
       5             :  *
       6             :  * This file is part of GnuPG.
       7             :  *
       8             :  * GnuPG is free software; you can redistribute it and/or modify
       9             :  * it under the terms of the GNU General Public License as published by
      10             :  * the Free Software Foundation; either version 3 of the License, or
      11             :  * (at your option) any later version.
      12             :  *
      13             :  * GnuPG is distributed in the hope that it will be useful,
      14             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :  * GNU General Public License for more details.
      17             :  *
      18             :  * You should have received a copy of the GNU General Public License
      19             :  * along with this program; if not, see <http://www.gnu.org/licenses/>.
      20             :  */
      21             : 
      22             : #include <config.h>
      23             : 
      24             : #include <stdio.h>
      25             : #include <stdlib.h>
      26             : #include <stddef.h>
      27             : #include <stdarg.h>
      28             : #include <string.h>
      29             : #include <errno.h>
      30             : #include <assert.h>
      31             : #include <time.h>
      32             : #include <fcntl.h>
      33             : #ifndef HAVE_W32_SYSTEM
      34             : #include <sys/socket.h>
      35             : #include <sys/un.h>
      36             : #endif
      37             : #include <sys/stat.h>
      38             : #include <unistd.h>
      39             : #ifdef HAVE_SIGNAL_H
      40             : # include <signal.h>
      41             : #endif
      42             : #include <npth.h>
      43             : 
      44             : #include "dirmngr-err.h"
      45             : 
      46             : #if  HTTP_USE_NTBTLS
      47             : # include <ntbtls.h>
      48             : #elif HTTP_USE_GNUTLS
      49             : # include <gnutls/gnutls.h>
      50             : #endif /*HTTP_USE_GNUTLS*/
      51             : 
      52             : 
      53             : #define GNUPG_COMMON_NEED_AFLOCAL
      54             : #include "dirmngr.h"
      55             : 
      56             : #include <assuan.h>
      57             : 
      58             : #include "certcache.h"
      59             : #include "crlcache.h"
      60             : #include "crlfetch.h"
      61             : #include "misc.h"
      62             : #if USE_LDAP
      63             : # include "ldapserver.h"
      64             : #endif
      65             : #include "asshelp.h"
      66             : #if USE_LDAP
      67             : # include "ldap-wrapper.h"
      68             : #endif
      69             : #include "../common/init.h"
      70             : #include "gc-opt-flags.h"
      71             : 
      72             : /* The plain Windows version uses the windows service system.  For
      73             :    example to start the service you may use "sc start dirmngr".
      74             :    WindowsCE does not support this; the service system over there is
      75             :    based on a single process with all services being DLLs - we can't
      76             :    support this easily.  */
      77             : #if defined(HAVE_W32_SYSTEM) && !defined(HAVE_W32CE_SYSTEM)
      78             : # define USE_W32_SERVICE 1
      79             : #endif
      80             : 
      81             : #ifndef ENAMETOOLONG
      82             : # define ENAMETOOLONG EINVAL
      83             : #endif
      84             : 
      85             : 
      86             : enum cmd_and_opt_values {
      87             :   aNull = 0,
      88             :   oCsh            = 'c',
      89             :   oQuiet          = 'q',
      90             :   oSh             = 's',
      91             :   oVerbose        = 'v',
      92             :   oNoVerbose = 500,
      93             : 
      94             :   aServer,
      95             :   aDaemon,
      96             :   aService,
      97             :   aListCRLs,
      98             :   aLoadCRL,
      99             :   aFetchCRL,
     100             :   aShutdown,
     101             :   aFlush,
     102             :   aGPGConfList,
     103             :   aGPGConfTest,
     104             : 
     105             :   oOptions,
     106             :   oDebug,
     107             :   oDebugAll,
     108             :   oDebugWait,
     109             :   oDebugLevel,
     110             :   oGnutlsDebug,
     111             :   oNoGreeting,
     112             :   oNoOptions,
     113             :   oHomedir,
     114             :   oNoDetach,
     115             :   oLogFile,
     116             :   oBatch,
     117             :   oDisableHTTP,
     118             :   oDisableLDAP,
     119             :   oIgnoreLDAPDP,
     120             :   oIgnoreHTTPDP,
     121             :   oIgnoreOCSPSvcUrl,
     122             :   oHonorHTTPProxy,
     123             :   oHTTPProxy,
     124             :   oLDAPProxy,
     125             :   oOnlyLDAPProxy,
     126             :   oLDAPFile,
     127             :   oLDAPTimeout,
     128             :   oLDAPAddServers,
     129             :   oOCSPResponder,
     130             :   oOCSPSigner,
     131             :   oOCSPMaxClockSkew,
     132             :   oOCSPMaxPeriod,
     133             :   oOCSPCurrentPeriod,
     134             :   oMaxReplies,
     135             :   oHkpCaCert,
     136             :   oFakedSystemTime,
     137             :   oForce,
     138             :   oAllowOCSP,
     139             :   oSocketName,
     140             :   oLDAPWrapperProgram,
     141             :   oHTTPWrapperProgram,
     142             :   oIgnoreCertExtension,
     143             :   oUseTor,
     144             :   oKeyServer,
     145             :   aTest
     146             : };
     147             : 
     148             : 
     149             : 
     150             : static ARGPARSE_OPTS opts[] = {
     151             : 
     152             :   ARGPARSE_group (300, N_("@Commands:\n ")),
     153             : 
     154             :   ARGPARSE_c (aServer,   "server",  N_("run in server mode (foreground)") ),
     155             :   ARGPARSE_c (aDaemon,   "daemon",  N_("run in daemon mode (background)") ),
     156             : #ifdef USE_W32_SERVICE
     157             :   ARGPARSE_c (aService,  "service", N_("run as windows service (background)")),
     158             : #endif
     159             :   ARGPARSE_c (aListCRLs, "list-crls", N_("list the contents of the CRL cache")),
     160             :   ARGPARSE_c (aLoadCRL,  "load-crl",  N_("|FILE|load CRL from FILE into cache")),
     161             :   ARGPARSE_c (aFetchCRL, "fetch-crl", N_("|URL|fetch a CRL from URL")),
     162             :   ARGPARSE_c (aShutdown, "shutdown",  N_("shutdown the dirmngr")),
     163             :   ARGPARSE_c (aFlush,    "flush",     N_("flush the cache")),
     164             :   ARGPARSE_c (aGPGConfList, "gpgconf-list", "@"),
     165             :   ARGPARSE_c (aGPGConfTest, "gpgconf-test", "@"),
     166             : 
     167             :   ARGPARSE_group (301, N_("@\nOptions:\n ")),
     168             : 
     169             :   ARGPARSE_s_n (oVerbose,  "verbose",   N_("verbose")),
     170             :   ARGPARSE_s_n (oQuiet,    "quiet",     N_("be somewhat more quiet")),
     171             :   ARGPARSE_s_n (oSh,       "sh",        N_("sh-style command output")),
     172             :   ARGPARSE_s_n (oCsh,      "csh",       N_("csh-style command output")),
     173             :   ARGPARSE_s_s (oOptions,  "options",   N_("|FILE|read options from FILE")),
     174             :   ARGPARSE_s_s (oDebugLevel, "debug-level",
     175             :                 N_("|LEVEL|set the debugging level to LEVEL")),
     176             :   ARGPARSE_s_n (oNoDetach, "no-detach", N_("do not detach from the console")),
     177             :   ARGPARSE_s_s (oLogFile,  "log-file",
     178             :                 N_("|FILE|write server mode logs to FILE")),
     179             :   ARGPARSE_s_n (oBatch,    "batch",       N_("run without asking a user")),
     180             :   ARGPARSE_s_n (oForce,    "force",       N_("force loading of outdated CRLs")),
     181             :   ARGPARSE_s_n (oAllowOCSP, "allow-ocsp", N_("allow sending OCSP requests")),
     182             :   ARGPARSE_s_n (oDisableHTTP, "disable-http", N_("inhibit the use of HTTP")),
     183             :   ARGPARSE_s_n (oDisableLDAP, "disable-ldap", N_("inhibit the use of LDAP")),
     184             :   ARGPARSE_s_n (oIgnoreHTTPDP,"ignore-http-dp",
     185             :                 N_("ignore HTTP CRL distribution points")),
     186             :   ARGPARSE_s_n (oIgnoreLDAPDP,"ignore-ldap-dp",
     187             :                 N_("ignore LDAP CRL distribution points")),
     188             :   ARGPARSE_s_n (oIgnoreOCSPSvcUrl, "ignore-ocsp-service-url",
     189             :                 N_("ignore certificate contained OCSP service URLs")),
     190             : 
     191             :   ARGPARSE_s_s (oHTTPProxy,  "http-proxy",
     192             :                 N_("|URL|redirect all HTTP requests to URL")),
     193             :   ARGPARSE_s_s (oLDAPProxy,  "ldap-proxy",
     194             :                 N_("|HOST|use HOST for LDAP queries")),
     195             :   ARGPARSE_s_n (oOnlyLDAPProxy, "only-ldap-proxy",
     196             :                 N_("do not use fallback hosts with --ldap-proxy")),
     197             : 
     198             :   ARGPARSE_s_s (oLDAPFile, "ldapserverlist-file",
     199             :                 N_("|FILE|read LDAP server list from FILE")),
     200             :   ARGPARSE_s_n (oLDAPAddServers, "add-servers",
     201             :                 N_("add new servers discovered in CRL distribution"
     202             :                    " points to serverlist")),
     203             :   ARGPARSE_s_i (oLDAPTimeout, "ldaptimeout",
     204             :                 N_("|N|set LDAP timeout to N seconds")),
     205             : 
     206             :   ARGPARSE_s_s (oOCSPResponder, "ocsp-responder",
     207             :                 N_("|URL|use OCSP responder at URL")),
     208             :   ARGPARSE_s_s (oOCSPSigner, "ocsp-signer",
     209             :                 N_("|FPR|OCSP response signed by FPR")),
     210             :   ARGPARSE_s_i (oOCSPMaxClockSkew, "ocsp-max-clock-skew", "@"),
     211             :   ARGPARSE_s_i (oOCSPMaxPeriod,    "ocsp-max-period", "@"),
     212             :   ARGPARSE_s_i (oOCSPCurrentPeriod, "ocsp-current-period", "@"),
     213             : 
     214             :   ARGPARSE_s_i (oMaxReplies, "max-replies",
     215             :                 N_("|N|do not return more than N items in one query")),
     216             : 
     217             :   ARGPARSE_s_s (oKeyServer, "keyserver", "@"),
     218             :   ARGPARSE_s_s (oHkpCaCert, "hkp-cacert",
     219             :                 N_("|FILE|use the CA certificates in FILE for HKP over TLS")),
     220             : 
     221             :   ARGPARSE_s_n (oUseTor, "use-tor", N_("route all network traffic via Tor")),
     222             : 
     223             :   ARGPARSE_s_s (oSocketName, "socket-name", "@"),  /* Only for debugging.  */
     224             : 
     225             :   ARGPARSE_s_u (oFakedSystemTime, "faked-system-time", "@"), /*(epoch time)*/
     226             :   ARGPARSE_s_s (oDebug,    "debug", "@"),
     227             :   ARGPARSE_s_n (oDebugAll, "debug-all", "@"),
     228             :   ARGPARSE_s_i (oGnutlsDebug, "gnutls-debug", "@"),
     229             :   ARGPARSE_s_i (oGnutlsDebug, "tls-debug", "@"),
     230             :   ARGPARSE_s_i (oDebugWait, "debug-wait", "@"),
     231             :   ARGPARSE_s_n (oNoGreeting, "no-greeting", "@"),
     232             :   ARGPARSE_s_s (oHomedir, "homedir", "@"),
     233             :   ARGPARSE_s_s (oLDAPWrapperProgram, "ldap-wrapper-program", "@"),
     234             :   ARGPARSE_s_s (oHTTPWrapperProgram, "http-wrapper-program", "@"),
     235             :   ARGPARSE_s_n (oHonorHTTPProxy, "honor-http-proxy", "@"),
     236             :   ARGPARSE_s_s (oIgnoreCertExtension,"ignore-cert-extension", "@"),
     237             : 
     238             :   ARGPARSE_group (302,N_("@\n(See the \"info\" manual for a complete listing "
     239             :                          "of all commands and options)\n")),
     240             : 
     241             :   ARGPARSE_end ()
     242             : };
     243             : 
     244             : /* The list of supported debug flags.  */
     245             : static struct debug_flags_s debug_flags [] =
     246             :   {
     247             :     { DBG_X509_VALUE   , "x509"    },
     248             :     { DBG_CRYPTO_VALUE , "crypto"  },
     249             :     { DBG_MEMORY_VALUE , "memory"  },
     250             :     { DBG_CACHE_VALUE  , "cache"   },
     251             :     { DBG_MEMSTAT_VALUE, "memstat" },
     252             :     { DBG_HASHING_VALUE, "hashing" },
     253             :     { DBG_IPC_VALUE    , "ipc"     },
     254             :     { DBG_LOOKUP_VALUE , "lookup"  },
     255             :     { 77, NULL } /* 77 := Do not exit on "help" or "?".  */
     256             :   };
     257             : 
     258             : #define DEFAULT_MAX_REPLIES 10
     259             : #define DEFAULT_LDAP_TIMEOUT 100 /* arbitrary large timeout */
     260             : 
     261             : /* For the cleanup handler we need to keep track of the socket's name.  */
     262             : static const char *socket_name;
     263             : /* If the socket has been redirected, this is the name of the
     264             :    redirected socket..  */
     265             : static const char *redir_socket_name;
     266             : 
     267             : /* We need to keep track of the server's nonces (these are dummies for
     268             :    POSIX systems). */
     269             : static assuan_sock_nonce_t socket_nonce;
     270             : 
     271             : /* Only if this flag has been set will we remove the socket file.  */
     272             : static int cleanup_socket;
     273             : 
     274             : /* Keep track of the current log file so that we can avoid updating
     275             :    the log file after a SIGHUP if it didn't changed. Malloced. */
     276             : static char *current_logfile;
     277             : 
     278             : /* Helper to implement --debug-level. */
     279             : static const char *debug_level;
     280             : 
     281             : /* Helper to set the NTBTLS or GNUTLS log level.  */
     282             : static int opt_gnutls_debug = -1;
     283             : 
     284             : /* Flag indicating that a shutdown has been requested.  */
     285             : static volatile int shutdown_pending;
     286             : 
     287             : /* Counter for the active connections.  */
     288             : static int active_connections;
     289             : 
     290             : /* The timer tick used for housekeeping stuff.  For Windows we use a
     291             :    longer period as the SetWaitableTimer seems to signal earlier than
     292             :    the 2 seconds.  All values are in seconds. */
     293             : #if defined(HAVE_W32CE_SYSTEM)
     294             : # define TIMERTICK_INTERVAL         (60)
     295             : #elif defined(HAVE_W32_SYSTEM)
     296             : # define TIMERTICK_INTERVAL          (4)
     297             : #else
     298             : # define TIMERTICK_INTERVAL          (2)
     299             : #endif
     300             : 
     301             : #define HOUSEKEEPING_INTERVAL      (600)
     302             : 
     303             : 
     304             : /* This union is used to avoid compiler warnings in case a pointer is
     305             :    64 bit and an int 32 bit.  We store an integer in a pointer and get
     306             :    it back later (npth_getspecific et al.).  */
     307             : union int_and_ptr_u
     308             : {
     309             :   int  aint;
     310             :   assuan_fd_t afd;
     311             :   void *aptr;
     312             : };
     313             : 
     314             : 
     315             : 
     316             : /* The key used to store the current file descriptor in the thread
     317             :    local storage.  We use this in conjunction with the
     318             :    log_set_pid_suffix_cb feature.  */
     319             : #ifndef HAVE_W32_SYSTEM
     320             : static int my_tlskey_current_fd;
     321             : #endif
     322             : 
     323             : /* Prototypes. */
     324             : static void cleanup (void);
     325             : #if USE_LDAP
     326             : static ldap_server_t parse_ldapserver_file (const char* filename);
     327             : #endif /*USE_LDAP*/
     328             : static fingerprint_list_t parse_ocsp_signer (const char *string);
     329             : static void handle_connections (assuan_fd_t listen_fd);
     330             : 
     331             : /* NPth wrapper function definitions. */
     332           0 : ASSUAN_SYSTEM_NPTH_IMPL;
     333             : 
     334             : static const char *
     335           0 : my_strusage( int level )
     336             : {
     337             :   const char *p;
     338           0 :   switch ( level )
     339             :     {
     340           0 :     case 11: p = "@DIRMNGR@ (@GNUPG@)";
     341           0 :       break;
     342           0 :     case 13: p = VERSION; break;
     343           0 :     case 17: p = PRINTABLE_OS_NAME; break;
     344             :       /* TRANSLATORS: @EMAIL@ will get replaced by the actual bug
     345             :          reporting address.  This is so that we can change the
     346             :          reporting address without breaking the translations.  */
     347           0 :     case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
     348           0 :     case 49: p = PACKAGE_BUGREPORT; break;
     349             :     case 1:
     350           0 :     case 40: p = _("Usage: @DIRMNGR@ [options] (-h for help)");
     351           0 :       break;
     352           0 :     case 41: p = _("Syntax: @DIRMNGR@ [options] [command [args]]\n"
     353             :                    "Keyserver, CRL, and OCSP access for @GNUPG@\n");
     354           0 :       break;
     355             : 
     356           0 :     default: p = NULL;
     357             :     }
     358           0 :   return p;
     359             : }
     360             : 
     361             : 
     362             : /* Callback from libksba to hash a provided buffer.  Our current
     363             :    implementation does only allow SHA-1 for hashing. This may be
     364             :    extended by mapping the name, testing for algorithm availibility
     365             :    and adjust the length checks accordingly. */
     366             : static gpg_error_t
     367           0 : my_ksba_hash_buffer (void *arg, const char *oid,
     368             :                      const void *buffer, size_t length, size_t resultsize,
     369             :                      unsigned char *result, size_t *resultlen)
     370             : {
     371             :   (void)arg;
     372             : 
     373           0 :   if (oid && strcmp (oid, "1.3.14.3.2.26"))
     374           0 :     return gpg_error (GPG_ERR_NOT_SUPPORTED);
     375           0 :   if (resultsize < 20)
     376           0 :     return gpg_error (GPG_ERR_BUFFER_TOO_SHORT);
     377           0 :   gcry_md_hash_buffer (2, result, buffer, length);
     378           0 :   *resultlen = 20;
     379           0 :   return 0;
     380             : }
     381             : 
     382             : 
     383             : /* GNUTLS log function callback.  */
     384             : #ifdef HTTP_USE_GNUTLS
     385             : static void
     386           0 : my_gnutls_log (int level, const char *text)
     387             : {
     388             :   int n;
     389             : 
     390           0 :   n = strlen (text);
     391           0 :   while (n && text[n-1] == '\n')
     392           0 :     n--;
     393             : 
     394           0 :   log_debug ("gnutls:L%d: %.*s\n", level, n, text);
     395           0 : }
     396             : #endif /*HTTP_USE_GNUTLS*/
     397             : 
     398             : /* Setup the debugging.  With a LEVEL of NULL only the active debug
     399             :    flags are propagated to the subsystems.  With LEVEL set, a specific
     400             :    set of debug flags is set; thus overriding all flags already
     401             :    set. */
     402             : static void
     403           0 : set_debug (void)
     404             : {
     405           0 :   int numok = (debug_level && digitp (debug_level));
     406           0 :   int numlvl = numok? atoi (debug_level) : 0;
     407             : 
     408           0 :   if (!debug_level)
     409             :     ;
     410           0 :   else if (!strcmp (debug_level, "none") || (numok && numlvl < 1))
     411           0 :     opt.debug = 0;
     412           0 :   else if (!strcmp (debug_level, "basic") || (numok && numlvl <= 2))
     413           0 :     opt.debug = DBG_IPC_VALUE;
     414           0 :   else if (!strcmp (debug_level, "advanced") || (numok && numlvl <= 5))
     415           0 :     opt.debug = (DBG_IPC_VALUE|DBG_X509_VALUE|DBG_LOOKUP_VALUE);
     416           0 :   else if (!strcmp (debug_level, "expert") || (numok && numlvl <= 8))
     417           0 :     opt.debug = (DBG_IPC_VALUE|DBG_X509_VALUE|DBG_LOOKUP_VALUE
     418             :                  |DBG_CACHE_VALUE|DBG_CRYPTO_VALUE);
     419           0 :   else if (!strcmp (debug_level, "guru") || numok)
     420             :     {
     421           0 :       opt.debug = ~0;
     422             :       /* Unless the "guru" string has been used we don't want to allow
     423             :          hashing debugging.  The rationale is that people tend to
     424             :          select the highest debug value and would then clutter their
     425             :          disk with debug files which may reveal confidential data.  */
     426           0 :       if (numok)
     427           0 :         opt.debug &= ~(DBG_HASHING_VALUE);
     428             :     }
     429             :   else
     430             :     {
     431           0 :       log_error (_("invalid debug-level '%s' given\n"), debug_level);
     432           0 :       log_info (_("valid debug levels are: %s\n"),
     433             :                 "none, basic, advanced, expert, guru");
     434           0 :       opt.debug = 0; /* Reset debugging, so that prior debug
     435             :                         statements won't have an undesired effect. */
     436             :     }
     437             : 
     438             : 
     439           0 :   if (opt.debug && !opt.verbose)
     440             :     {
     441           0 :       opt.verbose = 1;
     442           0 :       gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
     443             :     }
     444           0 :   if (opt.debug && opt.quiet)
     445           0 :     opt.quiet = 0;
     446             : 
     447           0 :   if (opt.debug & DBG_CRYPTO_VALUE )
     448           0 :     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1);
     449             : 
     450             : #if HTTP_USE_NTBTLS
     451             :   if (opt_gnutls_debug >= 0)
     452             :     {
     453             :       ntbtls_set_debug (opt_gnutls_debug, NULL, NULL);
     454             :     }
     455             : #elif HTTP_USE_GNUTLS
     456           0 :   if (opt_gnutls_debug >= 0)
     457             :     {
     458           0 :       gnutls_global_set_log_function (my_gnutls_log);
     459           0 :       gnutls_global_set_log_level (opt_gnutls_debug);
     460             :     }
     461             : #endif /*HTTP_USE_GNUTLS*/
     462             : 
     463           0 :   if (opt.debug)
     464           0 :     parse_debug_flag (NULL, &opt.debug, debug_flags);
     465           0 : }
     466             : 
     467             : 
     468             : static void
     469           0 : set_tor_mode (void)
     470             : {
     471           0 :   if (opt.use_tor)
     472             :     {
     473             : #if ASSUAN_VERSION_NUMBER >= 0x020300 /* >= 2.3.0 */
     474           0 :       if (assuan_sock_set_flag (ASSUAN_INVALID_FD, "tor-mode", 1))
     475             : #endif
     476             :         {
     477           0 :           log_error ("error enabling Tor mode: %s\n", strerror (errno));
     478           0 :           log_info ("(is your Libassuan recent enough?)\n");
     479             :         }
     480             :     }
     481           0 : }
     482             : 
     483             : 
     484             : static void
     485           0 : wrong_args (const char *text)
     486             : {
     487           0 :   es_fprintf (es_stderr, _("usage: %s [options] "), DIRMNGR_NAME);
     488           0 :   es_fputs (text, es_stderr);
     489           0 :   es_putc ('\n', es_stderr);
     490           0 :   dirmngr_exit (2);
     491           0 : }
     492             : 
     493             : 
     494             : /* Helper to stop the reaper thread for the ldap wrapper.  */
     495             : static void
     496           0 : shutdown_reaper (void)
     497             : {
     498             : #if USE_LDAP
     499           0 :   ldap_wrapper_wait_connections ();
     500             : #endif
     501           0 : }
     502             : 
     503             : 
     504             : /* Handle options which are allowed to be reset after program start.
     505             :    Return true if the current option in PARGS could be handled and
     506             :    false if not.  As a special feature, passing a value of NULL for
     507             :    PARGS, resets the options to the default.  REREAD should be set
     508             :    true if it is not the initial option parsing. */
     509             : static int
     510           0 : parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
     511             : {
     512           0 :   if (!pargs)
     513             :     { /* Reset mode. */
     514           0 :       opt.quiet = 0;
     515           0 :       opt.verbose = 0;
     516           0 :       opt.debug = 0;
     517           0 :       opt.ldap_wrapper_program = NULL;
     518           0 :       opt.disable_http = 0;
     519           0 :       opt.disable_ldap = 0;
     520           0 :       opt.honor_http_proxy = 0;
     521           0 :       opt.http_proxy = NULL;
     522           0 :       opt.ldap_proxy = NULL;
     523           0 :       opt.only_ldap_proxy = 0;
     524           0 :       opt.ignore_http_dp = 0;
     525           0 :       opt.ignore_ldap_dp = 0;
     526           0 :       opt.ignore_ocsp_service_url = 0;
     527           0 :       opt.allow_ocsp = 0;
     528           0 :       opt.ocsp_responder = NULL;
     529           0 :       opt.ocsp_max_clock_skew = 10 * 60;      /* 10 minutes.  */
     530           0 :       opt.ocsp_max_period = 90 * 86400;       /* 90 days.  */
     531           0 :       opt.ocsp_current_period = 3 * 60 * 60;  /* 3 hours. */
     532           0 :       opt.max_replies = DEFAULT_MAX_REPLIES;
     533           0 :       while (opt.ocsp_signer)
     534             :         {
     535           0 :           fingerprint_list_t tmp = opt.ocsp_signer->next;
     536           0 :           xfree (opt.ocsp_signer);
     537           0 :           opt.ocsp_signer = tmp;
     538             :         }
     539           0 :       FREE_STRLIST (opt.ignored_cert_extensions);
     540           0 :       http_register_tls_ca (NULL);
     541           0 :       xfree (opt.keyserver);
     542           0 :       opt.keyserver = NULL;
     543             :       /* Note: We do not allow resetting of opt.use_tor at runtime.  */
     544           0 :       return 1;
     545             :     }
     546             : 
     547           0 :   switch (pargs->r_opt)
     548             :     {
     549           0 :     case oQuiet:   opt.quiet = 1; break;
     550           0 :     case oVerbose: opt.verbose++; break;
     551             :     case oDebug:
     552           0 :       parse_debug_flag (pargs->r.ret_str, &opt.debug, debug_flags);
     553           0 :       break;
     554           0 :     case oDebugAll: opt.debug = ~0; break;
     555           0 :     case oDebugLevel: debug_level = pargs->r.ret_str; break;
     556           0 :     case oGnutlsDebug: opt_gnutls_debug = pargs->r.ret_int; break;
     557             : 
     558             :     case oLogFile:
     559           0 :       if (!reread)
     560           0 :         return 0; /* Not handled. */
     561           0 :       if (!current_logfile || !pargs->r.ret_str
     562           0 :           || strcmp (current_logfile, pargs->r.ret_str))
     563             :         {
     564           0 :           log_set_file (pargs->r.ret_str);
     565           0 :           xfree (current_logfile);
     566           0 :           current_logfile = xtrystrdup (pargs->r.ret_str);
     567             :         }
     568           0 :       break;
     569             : 
     570             :     case oLDAPWrapperProgram:
     571           0 :       opt.ldap_wrapper_program = pargs->r.ret_str;
     572           0 :       break;
     573             :     case oHTTPWrapperProgram:
     574           0 :       opt.http_wrapper_program = pargs->r.ret_str;
     575           0 :       break;
     576             : 
     577           0 :     case oDisableHTTP: opt.disable_http = 1; break;
     578           0 :     case oDisableLDAP: opt.disable_ldap = 1; break;
     579           0 :     case oHonorHTTPProxy: opt.honor_http_proxy = 1; break;
     580           0 :     case oHTTPProxy: opt.http_proxy = pargs->r.ret_str; break;
     581           0 :     case oLDAPProxy: opt.ldap_proxy = pargs->r.ret_str; break;
     582           0 :     case oOnlyLDAPProxy: opt.only_ldap_proxy = 1; break;
     583           0 :     case oIgnoreHTTPDP: opt.ignore_http_dp = 1; break;
     584           0 :     case oIgnoreLDAPDP: opt.ignore_ldap_dp = 1; break;
     585           0 :     case oIgnoreOCSPSvcUrl: opt.ignore_ocsp_service_url = 1; break;
     586             : 
     587           0 :     case oAllowOCSP: opt.allow_ocsp = 1; break;
     588           0 :     case oOCSPResponder: opt.ocsp_responder = pargs->r.ret_str; break;
     589             :     case oOCSPSigner:
     590           0 :       opt.ocsp_signer = parse_ocsp_signer (pargs->r.ret_str);
     591           0 :       break;
     592           0 :     case oOCSPMaxClockSkew: opt.ocsp_max_clock_skew = pargs->r.ret_int; break;
     593           0 :     case oOCSPMaxPeriod: opt.ocsp_max_period = pargs->r.ret_int; break;
     594           0 :     case oOCSPCurrentPeriod: opt.ocsp_current_period = pargs->r.ret_int; break;
     595             : 
     596           0 :     case oMaxReplies: opt.max_replies = pargs->r.ret_int; break;
     597             : 
     598             :     case oHkpCaCert:
     599             :       {
     600             :         char *tmpname;
     601             : 
     602             :         /* Do tilde expansion and print a warning if the file can't be
     603             :            accessed.  */
     604           0 :         tmpname = make_absfilename_try (pargs->r.ret_str, NULL);
     605           0 :         if (!tmpname || access (tmpname, F_OK))
     606           0 :           log_info (_("can't access '%s': %s\n"),
     607             :                     tmpname? tmpname : pargs->r.ret_str,
     608             :                     gpg_strerror (gpg_error_from_syserror()));
     609             :         else
     610           0 :           http_register_tls_ca (tmpname);
     611           0 :         xfree (tmpname);
     612             :       }
     613           0 :       break;
     614             : 
     615             :     case oIgnoreCertExtension:
     616           0 :       add_to_strlist (&opt.ignored_cert_extensions, pargs->r.ret_str);
     617           0 :       break;
     618             : 
     619           0 :     case oUseTor: opt.use_tor = 1; break;
     620             : 
     621             :     case oKeyServer:
     622           0 :       xfree (opt.keyserver);
     623           0 :       opt.keyserver = *pargs->r.ret_str? xtrystrdup (pargs->r.ret_str) : NULL;
     624           0 :       break;
     625             : 
     626             :     default:
     627           0 :       return 0; /* Not handled. */
     628             :     }
     629             : 
     630           0 :   return 1; /* Handled. */
     631             : }
     632             : 
     633             : 
     634             : #ifdef USE_W32_SERVICE
     635             : /* The global status of our service.  */
     636             : SERVICE_STATUS_HANDLE service_handle;
     637             : SERVICE_STATUS service_status;
     638             : 
     639             : DWORD WINAPI
     640             : w32_service_control (DWORD control, DWORD event_type, LPVOID event_data,
     641             :                      LPVOID context)
     642             : {
     643             :   (void)event_type;
     644             :   (void)event_data;
     645             :   (void)context;
     646             : 
     647             :   /* event_type and event_data are not used here.  */
     648             :   switch (control)
     649             :     {
     650             :     case SERVICE_CONTROL_SHUTDOWN:
     651             :       /* For shutdown we will try to force termination.  */
     652             :       service_status.dwCurrentState = SERVICE_STOP_PENDING;
     653             :       SetServiceStatus (service_handle, &service_status);
     654             :       shutdown_pending = 3;
     655             :       break;
     656             : 
     657             :     case SERVICE_CONTROL_STOP:
     658             :       service_status.dwCurrentState = SERVICE_STOP_PENDING;
     659             :       SetServiceStatus (service_handle, &service_status);
     660             :       shutdown_pending = 1;
     661             :       break;
     662             : 
     663             :     default:
     664             :       break;
     665             :     }
     666             :   return 0;
     667             : }
     668             : #endif /*USE_W32_SERVICE*/
     669             : 
     670             : #ifndef HAVE_W32_SYSTEM
     671             : static int
     672           0 : pid_suffix_callback (unsigned long *r_suffix)
     673             : {
     674             :   union int_and_ptr_u value;
     675             : 
     676           0 :   memset (&value, 0, sizeof value);
     677           0 :   value.aptr = npth_getspecific (my_tlskey_current_fd);
     678           0 :   *r_suffix = value.aint;
     679           0 :   return (*r_suffix != -1);  /* Use decimal representation.  */
     680             : }
     681             : #endif /*!HAVE_W32_SYSTEM*/
     682             : 
     683             : 
     684             : #ifdef USE_W32_SERVICE
     685             : # define main real_main
     686             : #endif
     687             : int
     688           0 : main (int argc, char **argv)
     689             : {
     690             : #ifdef USE_W32_SERVICE
     691             : # undef main
     692             : #endif
     693           0 :   enum cmd_and_opt_values cmd = 0;
     694             :   ARGPARSE_ARGS pargs;
     695             :   int orig_argc;
     696             :   char **orig_argv;
     697           0 :   FILE *configfp = NULL;
     698           0 :   char *configname = NULL;
     699             :   const char *shell;
     700             :   unsigned configlineno;
     701           0 :   int parse_debug = 0;
     702           0 :   int default_config =1;
     703           0 :   int greeting = 0;
     704           0 :   int nogreeting = 0;
     705           0 :   int nodetach = 0;
     706           0 :   int csh_style = 0;
     707           0 :   char *logfile = NULL;
     708             : #if USE_LDAP
     709           0 :   char *ldapfile = NULL;
     710             : #endif /*USE_LDAP*/
     711           0 :   int debug_wait = 0;
     712             :   int rc;
     713           0 :   int homedir_seen = 0;
     714             :   struct assuan_malloc_hooks malloc_hooks;
     715             : 
     716           0 :   early_system_init ();
     717             : 
     718             : #ifdef USE_W32_SERVICE
     719             :   /* The option will be set by main() below if we should run as a
     720             :      system daemon.  */
     721             :   if (opt.system_service)
     722             :     {
     723             :       service_handle
     724             :         = RegisterServiceCtrlHandlerEx ("DirMngr",
     725             :                                         &w32_service_control, NULL /*FIXME*/);
     726             :       if (service_handle == 0)
     727             :         log_error ("failed to register service control handler: ec=%d",
     728             :                    (int) GetLastError ());
     729             :       service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
     730             :       service_status.dwCurrentState = SERVICE_START_PENDING;
     731             :       service_status.dwControlsAccepted
     732             :         = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
     733             :       service_status.dwWin32ExitCode = NO_ERROR;
     734             :       service_status.dwServiceSpecificExitCode = NO_ERROR;
     735             :       service_status.dwCheckPoint = 0;
     736             :       service_status.dwWaitHint = 10000; /* 10 seconds timeout.  */
     737             :       SetServiceStatus (service_handle, &service_status);
     738             :     }
     739             : #endif /*USE_W32_SERVICE*/
     740             : 
     741           0 :   set_strusage (my_strusage);
     742           0 :   log_set_prefix (DIRMNGR_NAME, 1|4);
     743             : 
     744             :   /* Make sure that our subsystems are ready.  */
     745           0 :   i18n_init ();
     746           0 :   init_common_subsystems (&argc, &argv);
     747             : 
     748           0 :   npth_init ();
     749             : 
     750           0 :   gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
     751             : 
     752             :  /* Check that the libraries are suitable.  Do it here because
     753             :     the option parsing may need services of the libraries. */
     754             : 
     755           0 :   if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
     756           0 :     log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt",
     757             :                NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
     758           0 :   if (!ksba_check_version (NEED_KSBA_VERSION) )
     759           0 :     log_fatal( _("%s is too old (need %s, have %s)\n"), "libksba",
     760             :                NEED_KSBA_VERSION, ksba_check_version (NULL) );
     761             : 
     762           0 :   ksba_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free );
     763           0 :   ksba_set_hash_buffer_function (my_ksba_hash_buffer, NULL);
     764             : 
     765             :   /* Init TLS library.  */
     766             : #if HTTP_USE_NTBTLS
     767             :   if (!ntbtls_check_version (NEED_NTBTLS_VERSION) )
     768             :     log_fatal( _("%s is too old (need %s, have %s)\n"), "ntbtls",
     769             :                NEED_NTBTLS_VERSION, ntbtls_check_version (NULL) );
     770             : #elif HTTP_USE_GNUTLS
     771           0 :   rc = gnutls_global_init ();
     772           0 :   if (rc)
     773           0 :     log_fatal ("gnutls_global_init failed: %s\n", gnutls_strerror (rc));
     774             : #endif /*HTTP_USE_GNUTLS*/
     775             : 
     776             :   /* Init Assuan. */
     777           0 :   malloc_hooks.malloc = gcry_malloc;
     778           0 :   malloc_hooks.realloc = gcry_realloc;
     779           0 :   malloc_hooks.free = gcry_free;
     780           0 :   assuan_set_malloc_hooks (&malloc_hooks);
     781           0 :   assuan_set_assuan_log_prefix (log_get_prefix (NULL));
     782           0 :   assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
     783           0 :   assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);
     784           0 :   assuan_sock_init ();
     785           0 :   setup_libassuan_logging (&opt.debug);
     786             : 
     787           0 :   setup_libgcrypt_logging ();
     788             : 
     789             :   /* Setup defaults. */
     790           0 :   shell = getenv ("SHELL");
     791           0 :   if (shell && strlen (shell) >= 3 && !strcmp (shell+strlen (shell)-3, "csh") )
     792           0 :     csh_style = 1;
     793             : 
     794           0 :   opt.homedir = default_homedir ();
     795             : 
     796             :   /* Now with NPth running we can set the logging callback.  Our
     797             :      windows implementation does not yet feature the NPth TLS
     798             :      functions.  */
     799             : #ifndef HAVE_W32_SYSTEM
     800           0 :   if (npth_key_create (&my_tlskey_current_fd, NULL) == 0)
     801           0 :     if (npth_setspecific (my_tlskey_current_fd, NULL) == 0)
     802           0 :       log_set_pid_suffix_cb (pid_suffix_callback);
     803             : #endif /*!HAVE_W32_SYSTEM*/
     804             : 
     805             :   /* Reset rereadable options to default values. */
     806           0 :   parse_rereadable_options (NULL, 0);
     807             : 
     808             :   /* LDAP defaults.  */
     809           0 :   opt.add_new_ldapservers = 0;
     810           0 :   opt.ldaptimeout = DEFAULT_LDAP_TIMEOUT;
     811             : 
     812             :   /* Other defaults.  */
     813             : 
     814             :   /* Check whether we have a config file given on the commandline */
     815           0 :   orig_argc = argc;
     816           0 :   orig_argv = argv;
     817           0 :   pargs.argc = &argc;
     818           0 :   pargs.argv = &argv;
     819           0 :   pargs.flags= 1|(1<<6);  /* do not remove the args, ignore version */
     820           0 :   while (arg_parse( &pargs, opts))
     821             :     {
     822           0 :       if (pargs.r_opt == oDebug || pargs.r_opt == oDebugAll)
     823           0 :         parse_debug++;
     824           0 :       else if (pargs.r_opt == oOptions)
     825             :         { /* Yes there is one, so we do not try the default one, but
     826             :              read the option file when it is encountered at the
     827             :              commandline */
     828           0 :           default_config = 0;
     829             :         }
     830           0 :       else if (pargs.r_opt == oNoOptions)
     831           0 :         default_config = 0; /* --no-options */
     832           0 :       else if (pargs.r_opt == oHomedir)
     833             :         {
     834           0 :           opt.homedir = pargs.r.ret_str;
     835           0 :           homedir_seen = 1;
     836             :         }
     837           0 :       else if (pargs.r_opt == aDaemon)
     838           0 :         opt.system_daemon = 1;
     839           0 :       else if (pargs.r_opt == aService)
     840             :         {
     841             :           /* Redundant.  The main function takes care of it.  */
     842           0 :           opt.system_service = 1;
     843           0 :           opt.system_daemon = 1;
     844             :         }
     845             : #ifdef HAVE_W32_SYSTEM
     846             :       else if (pargs.r_opt == aGPGConfList || pargs.r_opt == aGPGConfTest)
     847             :         /* We set this so we switch to the system configuration
     848             :            directory below.  This is a crutch to solve the problem
     849             :            that the user configuration is never used on Windows.  Also
     850             :            see below at aGPGConfList.  */
     851             :         opt.system_daemon = 1;
     852             : #endif
     853             :     }
     854             : 
     855             :   /* If --daemon has been given on the command line but not --homedir,
     856             :      we switch to /etc/gnupg as default home directory.  Note, that
     857             :      this also overrides the GNUPGHOME environment variable.  */
     858           0 :   if (opt.system_daemon && !homedir_seen)
     859             :     {
     860             : #ifdef HAVE_W32CE_SYSTEM
     861             :       opt.homedir = DIRSEP_S "gnupg";
     862             : #else
     863           0 :       opt.homedir = gnupg_sysconfdir ();
     864             : #endif
     865           0 :       opt.homedir_cache = gnupg_cachedir ();
     866           0 :       socket_name = dirmngr_sys_socket_name ();
     867             :     }
     868           0 :   else if (dirmngr_user_socket_name ())
     869           0 :     socket_name = dirmngr_user_socket_name ();
     870             :   else
     871           0 :     socket_name = dirmngr_sys_socket_name ();
     872             : 
     873           0 :   if (default_config)
     874           0 :     configname = make_filename (opt.homedir, DIRMNGR_NAME".conf", NULL );
     875             : 
     876           0 :   argc = orig_argc;
     877           0 :   argv = orig_argv;
     878           0 :   pargs.argc = &argc;
     879           0 :   pargs.argv = &argv;
     880           0 :   pargs.flags= 1;  /* do not remove the args */
     881             :  next_pass:
     882           0 :   if (configname)
     883             :     {
     884           0 :       configlineno = 0;
     885           0 :       configfp = fopen (configname, "r");
     886           0 :       if (!configfp)
     887             :         {
     888           0 :           if (default_config)
     889             :             {
     890           0 :               if( parse_debug )
     891           0 :                 log_info (_("Note: no default option file '%s'\n"),
     892             :                           configname );
     893             :             }
     894             :           else
     895             :             {
     896           0 :               log_error (_("option file '%s': %s\n"),
     897           0 :                          configname, strerror(errno) );
     898           0 :               exit(2);
     899             :             }
     900           0 :           xfree (configname);
     901           0 :           configname = NULL;
     902             :         }
     903           0 :       if (parse_debug && configname )
     904           0 :         log_info (_("reading options from '%s'\n"), configname );
     905           0 :       default_config = 0;
     906             :     }
     907             : 
     908           0 :   while (optfile_parse( configfp, configname, &configlineno, &pargs, opts) )
     909             :     {
     910           0 :       if (parse_rereadable_options (&pargs, 0))
     911           0 :         continue; /* Already handled */
     912           0 :       switch (pargs.r_opt)
     913             :         {
     914             :         case aServer:
     915             :         case aDaemon:
     916             :         case aService:
     917             :         case aShutdown:
     918             :         case aFlush:
     919             :         case aListCRLs:
     920             :         case aLoadCRL:
     921             :         case aFetchCRL:
     922             :         case aGPGConfList:
     923             :         case aGPGConfTest:
     924           0 :           cmd = pargs.r_opt;
     925           0 :           break;
     926             : 
     927           0 :         case oQuiet: opt.quiet = 1; break;
     928           0 :         case oVerbose: opt.verbose++; break;
     929           0 :         case oBatch: opt.batch=1; break;
     930             : 
     931           0 :         case oDebugWait: debug_wait = pargs.r.ret_int; break;
     932             : 
     933             :         case oOptions:
     934             :           /* Config files may not be nested (silently ignore them) */
     935           0 :           if (!configfp)
     936             :             {
     937           0 :                 xfree(configname);
     938           0 :                 configname = xstrdup(pargs.r.ret_str);
     939           0 :                 goto next_pass;
     940             :             }
     941           0 :           break;
     942           0 :         case oNoGreeting: nogreeting = 1; break;
     943           0 :         case oNoVerbose: opt.verbose = 0; break;
     944           0 :         case oNoOptions: break; /* no-options */
     945           0 :         case oHomedir: /* Ignore this option here. */; break;
     946           0 :         case oNoDetach: nodetach = 1; break;
     947           0 :         case oLogFile: logfile = pargs.r.ret_str; break;
     948           0 :         case oCsh: csh_style = 1; break;
     949           0 :         case oSh: csh_style = 0; break;
     950             :         case oLDAPFile:
     951             : #        if USE_LDAP
     952           0 :           ldapfile = pargs.r.ret_str;
     953             : #        endif /*USE_LDAP*/
     954           0 :           break;
     955           0 :         case oLDAPAddServers: opt.add_new_ldapservers = 1; break;
     956             :         case oLDAPTimeout:
     957           0 :           opt.ldaptimeout = pargs.r.ret_int;
     958           0 :           break;
     959             : 
     960             :         case oFakedSystemTime:
     961           0 :           gnupg_set_time ((time_t)pargs.r.ret_ulong, 0);
     962           0 :           break;
     963             : 
     964           0 :         case oForce: opt.force = 1; break;
     965             : 
     966           0 :         case oSocketName: socket_name = pargs.r.ret_str; break;
     967             : 
     968           0 :         default : pargs.err = configfp? 1:2; break;
     969             :         }
     970             :     }
     971           0 :   if (configfp)
     972             :     {
     973           0 :       fclose (configfp);
     974           0 :       configfp = NULL;
     975             :       /* Keep a copy of the name so that it can be read on SIGHUP. */
     976           0 :       opt.config_filename = configname;
     977           0 :       configname = NULL;
     978           0 :       goto next_pass;
     979             :     }
     980           0 :   xfree (configname);
     981           0 :   configname = NULL;
     982           0 :   if (log_get_errorcount(0))
     983           0 :     exit(2);
     984           0 :   if (nogreeting )
     985           0 :     greeting = 0;
     986             : 
     987           0 :   if (!opt.homedir_cache)
     988           0 :     opt.homedir_cache = opt.homedir;
     989             : 
     990           0 :   if (greeting)
     991             :     {
     992           0 :       es_fprintf (es_stderr, "%s %s; %s\n",
     993             :                   strusage(11), strusage(13), strusage(14) );
     994           0 :       es_fprintf (es_stderr, "%s\n", strusage(15) );
     995             :     }
     996             : 
     997             : #ifdef IS_DEVELOPMENT_VERSION
     998             :   log_info ("NOTE: this is a development version!\n");
     999             : #endif
    1000             : 
    1001           0 :   if (opt.use_tor)
    1002             :     {
    1003           0 :       log_info ("WARNING: ***************************************\n");
    1004           0 :       log_info ("WARNING: Tor mode (--use-tor) MAY NOT FULLY WORK!\n");
    1005           0 :       log_info ("WARNING: ***************************************\n");
    1006             :     }
    1007             : 
    1008             :   /* Print a warning if an argument looks like an option.  */
    1009           0 :   if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
    1010             :     {
    1011             :       int i;
    1012             : 
    1013           0 :       for (i=0; i < argc; i++)
    1014           0 :         if (argv[i][0] == '-' && argv[i][1] == '-')
    1015           0 :           log_info (_("Note: '%s' is not considered an option\n"), argv[i]);
    1016             :     }
    1017             : 
    1018           0 :   if (!access ("/etc/"DIRMNGR_NAME, F_OK) && !strncmp (opt.homedir, "/etc/", 5))
    1019           0 :     log_info
    1020             :       ("NOTE: DirMngr is now a proper part of %s.  The configuration and"
    1021             :        " other directory names changed.  Please check that no other version"
    1022             :        " of dirmngr is still installed.  To disable this warning, remove the"
    1023             :        " directory '/etc/dirmngr'.\n", GNUPG_NAME);
    1024             : 
    1025           0 :   if (gnupg_faked_time_p ())
    1026             :     {
    1027             :       gnupg_isotime_t tbuf;
    1028             : 
    1029           0 :       log_info (_("WARNING: running with faked system time: "));
    1030           0 :       gnupg_get_isotime (tbuf);
    1031           0 :       dump_isotime (tbuf);
    1032           0 :       log_printf ("\n");
    1033             :     }
    1034             : 
    1035           0 :   set_debug ();
    1036           0 :   set_tor_mode ();
    1037             : 
    1038             :   /* Get LDAP server list from file. */
    1039             : #if USE_LDAP
    1040           0 :   if (!ldapfile)
    1041             :     {
    1042           0 :       ldapfile = make_filename (opt.homedir,
    1043           0 :                                 opt.system_daemon?
    1044             :                                 "ldapservers.conf":"dirmngr_ldapservers.conf",
    1045             :                                 NULL);
    1046           0 :       opt.ldapservers = parse_ldapserver_file (ldapfile);
    1047           0 :       xfree (ldapfile);
    1048             :     }
    1049             :   else
    1050           0 :       opt.ldapservers = parse_ldapserver_file (ldapfile);
    1051             : #endif /*USE_LDAP*/
    1052             : 
    1053             : #ifndef HAVE_W32_SYSTEM
    1054             :   /* We need to ignore the PIPE signal because the we might log to a
    1055             :      socket and that code handles EPIPE properly.  The ldap wrapper
    1056             :      also requires us to ignore this silly signal. Assuan would set
    1057             :      this signal to ignore anyway.*/
    1058           0 :   signal (SIGPIPE, SIG_IGN);
    1059             : #endif
    1060             : 
    1061             :   /* Ready.  Now to our duties. */
    1062           0 :   if (!cmd && opt.system_service)
    1063           0 :     cmd = aDaemon;
    1064           0 :   else if (!cmd)
    1065           0 :     cmd = aServer;
    1066           0 :   rc = 0;
    1067             : 
    1068           0 :   if (cmd == aServer)
    1069             :     {
    1070             :       /* Note that this server mode is mainly useful for debugging.  */
    1071           0 :       if (argc)
    1072           0 :         wrong_args ("--server");
    1073             : 
    1074           0 :       if (logfile)
    1075             :         {
    1076           0 :           log_set_file (logfile);
    1077           0 :           log_set_prefix (NULL, 2|4);
    1078             :         }
    1079             : 
    1080           0 :       if (debug_wait)
    1081             :         {
    1082           0 :           log_debug ("waiting for debugger - my pid is %u .....\n",
    1083           0 :                      (unsigned int)getpid());
    1084           0 :           gnupg_sleep (debug_wait);
    1085           0 :           log_debug ("... okay\n");
    1086             :         }
    1087             : 
    1088             : #if USE_LDAP
    1089           0 :       ldap_wrapper_launch_thread ();
    1090             : #endif /*USE_LDAP*/
    1091             : 
    1092           0 :       cert_cache_init ();
    1093           0 :       crl_cache_init ();
    1094           0 :       start_command_handler (ASSUAN_INVALID_FD);
    1095           0 :       shutdown_reaper ();
    1096             :     }
    1097           0 :   else if (cmd == aDaemon)
    1098             :     {
    1099             :       assuan_fd_t fd;
    1100             :       pid_t pid;
    1101             :       int len;
    1102             :       struct sockaddr_un serv_addr;
    1103             : 
    1104           0 :       if (argc)
    1105           0 :         wrong_args ("--daemon");
    1106             : 
    1107             :       /* Now start with logging to a file if this is desired. */
    1108           0 :       if (logfile)
    1109             :         {
    1110           0 :           log_set_file (logfile);
    1111           0 :           log_set_prefix (NULL, (GPGRT_LOG_WITH_PREFIX
    1112             :                                  |GPGRT_LOG_WITH_TIME
    1113             :                                  |GPGRT_LOG_WITH_PID));
    1114           0 :           current_logfile = xstrdup (logfile);
    1115             :         }
    1116             : 
    1117             : #ifndef HAVE_W32_SYSTEM
    1118           0 :       if (strchr (socket_name, ':'))
    1119             :         {
    1120           0 :           log_error (_("colons are not allowed in the socket name\n"));
    1121           0 :           dirmngr_exit (1);
    1122             :         }
    1123             : #endif
    1124           0 :       fd = assuan_sock_new (AF_UNIX, SOCK_STREAM, 0);
    1125           0 :       if (fd == ASSUAN_INVALID_FD)
    1126             :         {
    1127           0 :           log_error (_("can't create socket: %s\n"), strerror (errno));
    1128           0 :           cleanup ();
    1129           0 :           dirmngr_exit (1);
    1130             :         }
    1131             : 
    1132             : #if ASSUAN_VERSION_NUMBER >= 0x020104 /* >= 2.1.4 */
    1133             :       {
    1134             :         int redirected;
    1135             : 
    1136           0 :         if (assuan_sock_set_sockaddr_un (socket_name,
    1137             :                                          (struct sockaddr*)&serv_addr,
    1138             :                                          &redirected))
    1139             :           {
    1140           0 :             if (errno == ENAMETOOLONG)
    1141           0 :               log_error (_("socket name '%s' is too long\n"), socket_name);
    1142             :             else
    1143           0 :               log_error ("error preparing socket '%s': %s\n",
    1144             :                          socket_name,
    1145             :                          gpg_strerror (gpg_error_from_syserror ()));
    1146           0 :             dirmngr_exit (1);
    1147             :           }
    1148           0 :         if (redirected)
    1149             :           {
    1150           0 :             redir_socket_name = xstrdup (serv_addr.sun_path);
    1151           0 :             if (opt.verbose)
    1152           0 :               log_info ("redirecting socket '%s' to '%s'\n",
    1153             :                         socket_name, redir_socket_name);
    1154             :           }
    1155             :       }
    1156             : #else /* Assuan < 2.1.4 */
    1157             :       memset (&serv_addr, 0, sizeof serv_addr);
    1158             :       serv_addr.sun_family = AF_UNIX;
    1159             :       if (strlen (socket_name)+1 >= sizeof serv_addr.sun_path )
    1160             :         {
    1161             :           log_error (_("socket name '%s' is too long\n"), socket_name);
    1162             :           dirmngr_exit (1);
    1163             :         }
    1164             :       strcpy (serv_addr.sun_path, socket_name);
    1165             : #endif /* Assuan < 2.1.4 */
    1166             : 
    1167           0 :       len = SUN_LEN (&serv_addr);
    1168             : 
    1169           0 :       rc = assuan_sock_bind (fd, (struct sockaddr*) &serv_addr, len);
    1170           0 :       if (rc == -1
    1171           0 :           && (errno == EADDRINUSE
    1172             : #ifdef HAVE_W32_SYSTEM
    1173             :               || errno == EEXIST
    1174             : #endif
    1175             :               ))
    1176             :         {
    1177             :           /* Fixme: We should test whether a dirmngr is already running. */
    1178           0 :           gnupg_remove (redir_socket_name? redir_socket_name : socket_name);
    1179           0 :           rc = assuan_sock_bind (fd, (struct sockaddr*) &serv_addr, len);
    1180             :         }
    1181           0 :       if (rc != -1
    1182           0 :           && (rc = assuan_sock_get_nonce ((struct sockaddr*) &serv_addr, len, &socket_nonce)))
    1183           0 :         log_error (_("error getting nonce for the socket\n"));
    1184           0 :       if (rc == -1)
    1185             :         {
    1186           0 :           log_error (_("error binding socket to '%s': %s\n"),
    1187             :                      serv_addr.sun_path,
    1188           0 :                      gpg_strerror (gpg_error_from_errno (errno)));
    1189           0 :           assuan_sock_close (fd);
    1190           0 :           dirmngr_exit (1);
    1191             :         }
    1192           0 :       cleanup_socket = 1;
    1193             : 
    1194           0 :       if (listen (FD2INT (fd), 5) == -1)
    1195             :         {
    1196           0 :           log_error (_("listen() failed: %s\n"), strerror (errno));
    1197           0 :           assuan_sock_close (fd);
    1198           0 :           dirmngr_exit (1);
    1199             :         }
    1200             : 
    1201           0 :       if (opt.verbose)
    1202           0 :         log_info (_("listening on socket '%s'\n"), serv_addr.sun_path);
    1203             : 
    1204           0 :       es_fflush (NULL);
    1205             : 
    1206             :       /* Note: We keep the dirmngr_info output only for the sake of
    1207             :          existing scripts which might use this to detect a successful
    1208             :          start of the dirmngr.  */
    1209             : #ifdef HAVE_W32_SYSTEM
    1210             :       (void)csh_style;
    1211             :       (void)nodetach;
    1212             : 
    1213             :       pid = getpid ();
    1214             :       es_printf ("set %s=%s;%lu;1\n",
    1215             :                  DIRMNGR_INFO_NAME, socket_name, (ulong) pid);
    1216             : #else
    1217           0 :       pid = fork();
    1218           0 :       if (pid == (pid_t)-1)
    1219             :         {
    1220           0 :           log_fatal (_("error forking process: %s\n"), strerror (errno));
    1221             :           dirmngr_exit (1);
    1222             :         }
    1223             : 
    1224           0 :       if (pid)
    1225             :         { /* We are the parent */
    1226             :           char *infostr;
    1227             : 
    1228             :           /* Don't let cleanup() remove the socket - the child is
    1229             :              responsible for doing that.  */
    1230           0 :           cleanup_socket = 0;
    1231             : 
    1232           0 :           close (fd);
    1233             : 
    1234             :           /* Create the info string: <name>:<pid>:<protocol_version> */
    1235           0 :           if (asprintf (&infostr, "%s=%s:%lu:1",
    1236             :                         DIRMNGR_INFO_NAME, serv_addr.sun_path, (ulong)pid ) < 0)
    1237             :             {
    1238           0 :               log_error (_("out of core\n"));
    1239           0 :               kill (pid, SIGTERM);
    1240           0 :               dirmngr_exit (1);
    1241             :             }
    1242             :           /* Print the environment string, so that the caller can use
    1243             :              shell's eval to set it.  But see above.  */
    1244           0 :           if (csh_style)
    1245             :             {
    1246           0 :               *strchr (infostr, '=') = ' ';
    1247           0 :               es_printf ( "setenv %s;\n", infostr);
    1248             :             }
    1249             :           else
    1250             :             {
    1251           0 :               es_printf ( "%s; export %s;\n", infostr, DIRMNGR_INFO_NAME);
    1252             :             }
    1253           0 :           free (infostr);
    1254           0 :           exit (0);
    1255             :           /*NEVER REACHED*/
    1256             :         } /* end parent */
    1257             : 
    1258             : 
    1259             :       /*
    1260             :          This is the child
    1261             :        */
    1262             : 
    1263             :       /* Detach from tty and put process into a new session */
    1264           0 :       if (!nodetach )
    1265             :         {
    1266             :           int i;
    1267             :           unsigned int oldflags;
    1268             : 
    1269             :           /* Close stdin, stdout and stderr unless it is the log stream */
    1270           0 :           for (i=0; i <= 2; i++)
    1271             :             {
    1272           0 :               if (!log_test_fd (i) && i != fd )
    1273           0 :                 close (i);
    1274             :             }
    1275           0 :           if (setsid() == -1)
    1276             :             {
    1277           0 :               log_error ("setsid() failed: %s\n", strerror(errno) );
    1278           0 :               dirmngr_exit (1);
    1279             :             }
    1280             : 
    1281           0 :           log_get_prefix (&oldflags);
    1282           0 :           log_set_prefix (NULL, oldflags | GPGRT_LOG_RUN_DETACHED);
    1283           0 :           opt.running_detached = 1;
    1284             : 
    1285           0 :           if (chdir("/"))
    1286             :             {
    1287           0 :               log_error ("chdir to / failed: %s\n", strerror (errno));
    1288           0 :               dirmngr_exit (1);
    1289             :             }
    1290             :         }
    1291             : #endif
    1292             : 
    1293             : #if USE_LDAP
    1294           0 :       ldap_wrapper_launch_thread ();
    1295             : #endif /*USE_LDAP*/
    1296             : 
    1297           0 :       cert_cache_init ();
    1298           0 :       crl_cache_init ();
    1299             : #ifdef USE_W32_SERVICE
    1300             :       if (opt.system_service)
    1301             :         {
    1302             :           service_status.dwCurrentState = SERVICE_RUNNING;
    1303             :           SetServiceStatus (service_handle, &service_status);
    1304             :         }
    1305             : #endif
    1306           0 :       handle_connections (fd);
    1307           0 :       assuan_sock_close (fd);
    1308           0 :       shutdown_reaper ();
    1309             : #ifdef USE_W32_SERVICE
    1310             :       if (opt.system_service)
    1311             :         {
    1312             :           service_status.dwCurrentState = SERVICE_STOPPED;
    1313             :           SetServiceStatus (service_handle, &service_status);
    1314             :         }
    1315             : #endif
    1316             :     }
    1317           0 :   else if (cmd == aListCRLs)
    1318             :     {
    1319             :       /* Just list the CRL cache and exit. */
    1320           0 :       if (argc)
    1321           0 :         wrong_args ("--list-crls");
    1322             : #if USE_LDAP
    1323           0 :       ldap_wrapper_launch_thread ();
    1324             : #endif /*USE_LDAP*/
    1325           0 :       crl_cache_init ();
    1326           0 :       crl_cache_list (es_stdout);
    1327             :     }
    1328           0 :   else if (cmd == aLoadCRL)
    1329             :     {
    1330             :       struct server_control_s ctrlbuf;
    1331             : 
    1332           0 :       memset (&ctrlbuf, 0, sizeof ctrlbuf);
    1333           0 :       dirmngr_init_default_ctrl (&ctrlbuf);
    1334             : 
    1335             : #if USE_LDAP
    1336           0 :       ldap_wrapper_launch_thread ();
    1337             : #endif /*USE_LDAP*/
    1338           0 :       cert_cache_init ();
    1339           0 :       crl_cache_init ();
    1340           0 :       if (!argc)
    1341           0 :         rc = crl_cache_load (&ctrlbuf, NULL);
    1342             :       else
    1343             :         {
    1344           0 :           for (; !rc && argc; argc--, argv++)
    1345           0 :             rc = crl_cache_load (&ctrlbuf, *argv);
    1346             :         }
    1347           0 :       dirmngr_deinit_default_ctrl (&ctrlbuf);
    1348             :     }
    1349           0 :   else if (cmd == aFetchCRL)
    1350             :     {
    1351             :       ksba_reader_t reader;
    1352             :       struct server_control_s ctrlbuf;
    1353             : 
    1354           0 :       if (argc != 1)
    1355           0 :         wrong_args ("--fetch-crl URL");
    1356             : 
    1357           0 :       memset (&ctrlbuf, 0, sizeof ctrlbuf);
    1358           0 :       dirmngr_init_default_ctrl (&ctrlbuf);
    1359             : 
    1360             : #if USE_LDAP
    1361           0 :       ldap_wrapper_launch_thread ();
    1362             : #endif /*USE_LDAP*/
    1363           0 :       cert_cache_init ();
    1364           0 :       crl_cache_init ();
    1365           0 :       rc = crl_fetch (&ctrlbuf, argv[0], &reader);
    1366           0 :       if (rc)
    1367           0 :         log_error (_("fetching CRL from '%s' failed: %s\n"),
    1368             :                      argv[0], gpg_strerror (rc));
    1369             :       else
    1370             :         {
    1371           0 :           rc = crl_cache_insert (&ctrlbuf, argv[0], reader);
    1372           0 :           if (rc)
    1373           0 :             log_error (_("processing CRL from '%s' failed: %s\n"),
    1374             :                        argv[0], gpg_strerror (rc));
    1375           0 :           crl_close_reader (reader);
    1376             :         }
    1377           0 :       dirmngr_deinit_default_ctrl (&ctrlbuf);
    1378             :     }
    1379           0 :   else if (cmd == aFlush)
    1380             :     {
    1381             :       /* Delete cache and exit. */
    1382           0 :       if (argc)
    1383           0 :         wrong_args ("--flush");
    1384           0 :       rc = crl_cache_flush();
    1385             :     }
    1386           0 :   else if (cmd == aGPGConfTest)
    1387           0 :     dirmngr_exit (0);
    1388           0 :   else if (cmd == aGPGConfList)
    1389             :     {
    1390           0 :       unsigned long flags = 0;
    1391             :       char *filename;
    1392             :       char *filename_esc;
    1393             : 
    1394             : #ifdef HAVE_W32_SYSTEM
    1395             :       /* On Windows systems, dirmngr always runs as system daemon, and
    1396             :          the per-user configuration is never used.  So we short-cut
    1397             :          everything to use the global system configuration of dirmngr
    1398             :          above, and here we set the no change flag to make these
    1399             :          read-only.  */
    1400             :       flags |= GC_OPT_FLAG_NO_CHANGE;
    1401             : #endif
    1402             : 
    1403             :       /* First the configuration file.  This is not an option, but it
    1404             :          is vital information for GPG Conf.  */
    1405           0 :       if (!opt.config_filename)
    1406           0 :         opt.config_filename = make_filename (opt.homedir,
    1407             :                                              "dirmngr.conf", NULL );
    1408             : 
    1409           0 :       filename = percent_escape (opt.config_filename, NULL);
    1410           0 :       es_printf ("gpgconf-dirmngr.conf:%lu:\"%s\n",
    1411             :               GC_OPT_FLAG_DEFAULT, filename);
    1412           0 :       xfree (filename);
    1413             : 
    1414           0 :       es_printf ("verbose:%lu:\n", flags | GC_OPT_FLAG_NONE);
    1415           0 :       es_printf ("quiet:%lu:\n", flags | GC_OPT_FLAG_NONE);
    1416           0 :       es_printf ("debug-level:%lu:\"none\n", flags | GC_OPT_FLAG_DEFAULT);
    1417           0 :       es_printf ("log-file:%lu:\n", flags | GC_OPT_FLAG_NONE);
    1418           0 :       es_printf ("force:%lu:\n", flags | GC_OPT_FLAG_NONE);
    1419             : 
    1420             :       /* --csh and --sh are mutually exclusive, something we can not
    1421             :          express in GPG Conf.  --options is only usable from the
    1422             :          command line, really.  --debug-all interacts with --debug,
    1423             :          and having both of them is thus problematic.  --no-detach is
    1424             :          also only usable on the command line.  --batch is unused.  */
    1425             : 
    1426           0 :       filename = make_filename (opt.homedir,
    1427           0 :                                 opt.system_daemon?
    1428             :                                 "ldapservers.conf":"dirmngr_ldapservers.conf",
    1429             :                                 NULL);
    1430           0 :       filename_esc = percent_escape (filename, NULL);
    1431           0 :       es_printf ("ldapserverlist-file:%lu:\"%s\n", flags | GC_OPT_FLAG_DEFAULT,
    1432             :               filename_esc);
    1433           0 :       xfree (filename_esc);
    1434           0 :       xfree (filename);
    1435             : 
    1436           0 :       es_printf ("ldaptimeout:%lu:%u\n",
    1437             :               flags | GC_OPT_FLAG_DEFAULT, DEFAULT_LDAP_TIMEOUT);
    1438           0 :       es_printf ("max-replies:%lu:%u\n",
    1439             :               flags | GC_OPT_FLAG_DEFAULT, DEFAULT_MAX_REPLIES);
    1440           0 :       es_printf ("allow-ocsp:%lu:\n", flags | GC_OPT_FLAG_NONE);
    1441           0 :       es_printf ("ocsp-responder:%lu:\n", flags | GC_OPT_FLAG_NONE);
    1442           0 :       es_printf ("ocsp-signer:%lu:\n", flags | GC_OPT_FLAG_NONE);
    1443             : 
    1444           0 :       es_printf ("faked-system-time:%lu:\n", flags | GC_OPT_FLAG_NONE);
    1445           0 :       es_printf ("no-greeting:%lu:\n", flags | GC_OPT_FLAG_NONE);
    1446             : 
    1447           0 :       es_printf ("disable-http:%lu:\n", flags | GC_OPT_FLAG_NONE);
    1448           0 :       es_printf ("disable-ldap:%lu:\n", flags | GC_OPT_FLAG_NONE);
    1449           0 :       es_printf ("honor-http-proxy:%lu\n", flags | GC_OPT_FLAG_NONE);
    1450           0 :       es_printf ("http-proxy:%lu:\n", flags | GC_OPT_FLAG_NONE);
    1451           0 :       es_printf ("ldap-proxy:%lu:\n", flags | GC_OPT_FLAG_NONE);
    1452           0 :       es_printf ("only-ldap-proxy:%lu:\n", flags | GC_OPT_FLAG_NONE);
    1453           0 :       es_printf ("ignore-ldap-dp:%lu:\n", flags | GC_OPT_FLAG_NONE);
    1454           0 :       es_printf ("ignore-http-dp:%lu:\n", flags | GC_OPT_FLAG_NONE);
    1455           0 :       es_printf ("ignore-ocsp-service-url:%lu:\n", flags | GC_OPT_FLAG_NONE);
    1456             :       /* Note: The next one is to fix a typo in gpgconf - should be
    1457             :          removed eventually. */
    1458           0 :       es_printf ("ignore-ocsp-servic-url:%lu:\n", flags | GC_OPT_FLAG_NONE);
    1459             : 
    1460           0 :       es_printf ("use-tor:%lu:\n", flags | GC_OPT_FLAG_NONE);
    1461           0 :       es_printf ("keyserver:%lu:\n", flags | GC_OPT_FLAG_NONE);
    1462             :     }
    1463           0 :   cleanup ();
    1464           0 :   return !!rc;
    1465             : }
    1466             : 
    1467             : 
    1468             : #ifdef USE_W32_SERVICE
    1469             : static void WINAPI
    1470             : call_real_main (DWORD argc, LPSTR *argv)
    1471             : {
    1472             :   real_main (argc, argv);
    1473             : }
    1474             : 
    1475             : int
    1476             : main (int argc, char *argv[])
    1477             : {
    1478             :   int i;
    1479             : 
    1480             :   /* Find out if we run in daemon mode or on the command line.  */
    1481             :   for (i = 1; i < argc; i++)
    1482             :     if (!strcmp (argv[i], "--service"))
    1483             :       {
    1484             :         opt.system_service = 1;
    1485             :         opt.system_daemon = 1;
    1486             :         break;
    1487             :       }
    1488             : 
    1489             :   if (!opt.system_service)
    1490             :     return real_main (argc, argv);
    1491             :   else
    1492             :     {
    1493             :       SERVICE_TABLE_ENTRY DispatchTable [] =
    1494             :         {
    1495             :           { "DirMngr", &call_real_main },
    1496             :           { NULL, NULL }
    1497             :         };
    1498             : 
    1499             :       if (!StartServiceCtrlDispatcher (DispatchTable))
    1500             :         return 1;
    1501             :       return 0;
    1502             :     }
    1503             : }
    1504             : #endif /*USE_W32_SERVICE*/
    1505             : 
    1506             : 
    1507             : static void
    1508           0 : cleanup (void)
    1509             : {
    1510           0 :   crl_cache_deinit ();
    1511           0 :   cert_cache_deinit (1);
    1512             : 
    1513             : #if USE_LDAP
    1514           0 :   ldapserver_list_free (opt.ldapservers);
    1515             : #endif /*USE_LDAP*/
    1516           0 :   opt.ldapservers = NULL;
    1517             : 
    1518           0 :   if (cleanup_socket)
    1519             :     {
    1520           0 :       cleanup_socket = 0;
    1521           0 :       if (redir_socket_name)
    1522           0 :         gnupg_remove (redir_socket_name);
    1523           0 :       else if (socket_name && *socket_name)
    1524           0 :         gnupg_remove (socket_name);
    1525             :     }
    1526           0 : }
    1527             : 
    1528             : 
    1529             : void
    1530           0 : dirmngr_exit (int rc)
    1531             : {
    1532           0 :   cleanup ();
    1533           0 :   exit (rc);
    1534             : }
    1535             : 
    1536             : 
    1537             : void
    1538           0 : dirmngr_init_default_ctrl (ctrl_t ctrl)
    1539             : {
    1540           0 :   if (opt.http_proxy)
    1541           0 :     ctrl->http_proxy = xstrdup (opt.http_proxy);
    1542           0 : }
    1543             : 
    1544             : 
    1545             : void
    1546           0 : dirmngr_deinit_default_ctrl (ctrl_t ctrl)
    1547             : {
    1548           0 :   if (!ctrl)
    1549           0 :     return;
    1550           0 :   xfree (ctrl->http_proxy);
    1551           0 :   ctrl->http_proxy = NULL;
    1552             : }
    1553             : 
    1554             : 
    1555             : /* Create a list of LDAP servers from the file FILENAME. Returns the
    1556             :    list or NULL in case of errors.
    1557             : 
    1558             :    The format fo such a file is line oriented where empty lines and
    1559             :    lines starting with a hash mark are ignored.  All other lines are
    1560             :    assumed to be colon seprated with these fields:
    1561             : 
    1562             :    1. field: Hostname
    1563             :    2. field: Portnumber
    1564             :    3. field: Username
    1565             :    4. field: Password
    1566             :    5. field: Base DN
    1567             : 
    1568             : */
    1569             : #if USE_LDAP
    1570             : static ldap_server_t
    1571           0 : parse_ldapserver_file (const char* filename)
    1572             : {
    1573             :   char buffer[1024];
    1574             :   char *p;
    1575             :   ldap_server_t server, serverstart, *serverend;
    1576             :   int c;
    1577           0 :   unsigned int lineno = 0;
    1578             :   estream_t fp;
    1579             : 
    1580           0 :   fp = es_fopen (filename, "r");
    1581           0 :   if (!fp)
    1582             :     {
    1583           0 :       log_error (_("error opening '%s': %s\n"), filename, strerror (errno));
    1584           0 :       return NULL;
    1585             :     }
    1586             : 
    1587           0 :   serverstart = NULL;
    1588           0 :   serverend = &serverstart;
    1589           0 :   while (es_fgets (buffer, sizeof buffer, fp))
    1590             :     {
    1591           0 :       lineno++;
    1592           0 :       if (!*buffer || buffer[strlen(buffer)-1] != '\n')
    1593             :         {
    1594           0 :           if (*buffer && es_feof (fp))
    1595             :             ; /* Last line not terminated - continue. */
    1596             :           else
    1597             :             {
    1598           0 :               log_error (_("%s:%u: line too long - skipped\n"),
    1599             :                          filename, lineno);
    1600           0 :               while ( (c=es_fgetc (fp)) != EOF && c != '\n')
    1601             :                 ; /* Skip until end of line. */
    1602           0 :               continue;
    1603             :             }
    1604             :         }
    1605             :       /* Skip empty and comment lines.*/
    1606           0 :       for (p=buffer; spacep (p); p++)
    1607             :         ;
    1608           0 :       if (!*p || *p == '\n' || *p == '#')
    1609           0 :         continue;
    1610             : 
    1611             :       /* Parse the colon separated fields. */
    1612           0 :       server = ldapserver_parse_one (buffer, filename, lineno);
    1613           0 :       if (server)
    1614             :         {
    1615           0 :           *serverend = server;
    1616           0 :           serverend = &server->next;
    1617             :         }
    1618             :     }
    1619             : 
    1620           0 :   if (es_ferror (fp))
    1621           0 :     log_error (_("error reading '%s': %s\n"), filename, strerror (errno));
    1622           0 :   es_fclose (fp);
    1623             : 
    1624           0 :   return serverstart;
    1625             : }
    1626             : #endif /*USE_LDAP*/
    1627             : 
    1628             : static fingerprint_list_t
    1629           0 : parse_ocsp_signer (const char *string)
    1630             : {
    1631             :   gpg_error_t err;
    1632             :   char *fname;
    1633             :   estream_t fp;
    1634             :   char line[256];
    1635             :   char *p;
    1636             :   fingerprint_list_t list, *list_tail, item;
    1637           0 :   unsigned int lnr = 0;
    1638             :   int c, i, j;
    1639           0 :   int errflag = 0;
    1640             : 
    1641             : 
    1642             :   /* Check whether this is not a filename and treat it as a direct
    1643             :      fingerprint specification.  */
    1644           0 :   if (!strpbrk (string, "/.~\\"))
    1645             :     {
    1646           0 :       item = xcalloc (1, sizeof *item);
    1647           0 :       for (i=j=0; (string[i] == ':' || hexdigitp (string+i)) && j < 40; i++)
    1648           0 :         if ( string[i] != ':' )
    1649           0 :           item->hexfpr[j++] = string[i] >= 'a'? (string[i] & 0xdf): string[i];
    1650           0 :       item->hexfpr[j] = 0;
    1651           0 :       if (j != 40 || !(spacep (string+i) || !string[i]))
    1652             :         {
    1653           0 :           log_error (_("%s:%u: invalid fingerprint detected\n"),
    1654             :                      "--ocsp-signer", 0);
    1655           0 :           xfree (item);
    1656           0 :           return NULL;
    1657             :         }
    1658           0 :       return item;
    1659             :     }
    1660             : 
    1661             :   /* Well, it is a filename.  */
    1662           0 :   if (*string == '/' || (*string == '~' && string[1] == '/'))
    1663           0 :     fname = make_filename (string, NULL);
    1664             :   else
    1665             :     {
    1666           0 :       if (string[0] == '.' && string[1] == '/' )
    1667           0 :         string += 2;
    1668           0 :       fname = make_filename (opt.homedir, string, NULL);
    1669             :     }
    1670             : 
    1671           0 :   fp = es_fopen (fname, "r");
    1672           0 :   if (!fp)
    1673             :     {
    1674           0 :       err = gpg_error_from_syserror ();
    1675           0 :       log_error (_("can't open '%s': %s\n"), fname, gpg_strerror (err));
    1676           0 :       xfree (fname);
    1677           0 :       return NULL;
    1678             :     }
    1679             : 
    1680           0 :   list = NULL;
    1681           0 :   list_tail = &list;
    1682             :   for (;;)
    1683             :     {
    1684           0 :       if (!es_fgets (line, DIM(line)-1, fp) )
    1685             :         {
    1686           0 :           if (!es_feof (fp))
    1687             :             {
    1688           0 :               err = gpg_error_from_syserror ();
    1689           0 :               log_error (_("%s:%u: read error: %s\n"),
    1690             :                          fname, lnr, gpg_strerror (err));
    1691           0 :               errflag = 1;
    1692             :             }
    1693           0 :           es_fclose (fp);
    1694           0 :           if (errflag)
    1695             :             {
    1696           0 :               while (list)
    1697             :                 {
    1698           0 :                   fingerprint_list_t tmp = list->next;
    1699           0 :                   xfree (list);
    1700           0 :                   list = tmp;
    1701             :                 }
    1702             :             }
    1703           0 :           xfree (fname);
    1704           0 :           return list; /* Ready.  */
    1705             :         }
    1706             : 
    1707           0 :       lnr++;
    1708           0 :       if (!*line || line[strlen(line)-1] != '\n')
    1709             :         {
    1710             :           /* Eat until end of line. */
    1711           0 :           while ( (c=es_getc (fp)) != EOF && c != '\n')
    1712             :             ;
    1713           0 :           err = gpg_error (*line? GPG_ERR_LINE_TOO_LONG
    1714             :                            /* */: GPG_ERR_INCOMPLETE_LINE);
    1715           0 :           log_error (_("%s:%u: read error: %s\n"),
    1716             :                      fname, lnr, gpg_strerror (err));
    1717           0 :           errflag = 1;
    1718           0 :           continue;
    1719             :         }
    1720             : 
    1721             :       /* Allow for empty lines and spaces */
    1722           0 :       for (p=line; spacep (p); p++)
    1723             :         ;
    1724           0 :       if (!*p || *p == '\n' || *p == '#')
    1725           0 :         continue;
    1726             : 
    1727           0 :       item = xcalloc (1, sizeof *item);
    1728           0 :       *list_tail = item;
    1729           0 :       list_tail = &item->next;
    1730             : 
    1731           0 :       for (i=j=0; (p[i] == ':' || hexdigitp (p+i)) && j < 40; i++)
    1732           0 :         if ( p[i] != ':' )
    1733           0 :           item->hexfpr[j++] = p[i] >= 'a'? (p[i] & 0xdf): p[i];
    1734           0 :       item->hexfpr[j] = 0;
    1735           0 :       if (j != 40 || !(spacep (p+i) || p[i] == '\n'))
    1736             :         {
    1737           0 :           log_error (_("%s:%u: invalid fingerprint detected\n"), fname, lnr);
    1738           0 :           errflag = 1;
    1739             :         }
    1740           0 :       i++;
    1741           0 :       while (spacep (p+i))
    1742           0 :         i++;
    1743           0 :       if (p[i] && p[i] != '\n')
    1744           0 :         log_info (_("%s:%u: garbage at end of line ignored\n"), fname, lnr);
    1745           0 :     }
    1746             :   /*NOTREACHED*/
    1747             : }
    1748             : 
    1749             : 
    1750             : 
    1751             : 
    1752             : /*
    1753             :    Stuff used in daemon mode.
    1754             :  */
    1755             : 
    1756             : 
    1757             : 
    1758             : /* Reread parts of the configuration.  Note, that this function is
    1759             :    obviously not thread-safe and should only be called from the NPTH
    1760             :    signal handler.
    1761             : 
    1762             :    Fixme: Due to the way the argument parsing works, we create a
    1763             :    memory leak here for all string type arguments.  There is currently
    1764             :    no clean way to tell whether the memory for the argument has been
    1765             :    allocated or points into the process' original arguments.  Unless
    1766             :    we have a mechanism to tell this, we need to live on with this. */
    1767             : static void
    1768           0 : reread_configuration (void)
    1769             : {
    1770             :   ARGPARSE_ARGS pargs;
    1771             :   FILE *fp;
    1772           0 :   unsigned int configlineno = 0;
    1773             :   int dummy;
    1774             : 
    1775           0 :   if (!opt.config_filename)
    1776           0 :     return; /* No config file. */
    1777             : 
    1778           0 :   fp = fopen (opt.config_filename, "r");
    1779           0 :   if (!fp)
    1780             :     {
    1781           0 :       log_error (_("option file '%s': %s\n"),
    1782           0 :                  opt.config_filename, strerror(errno) );
    1783           0 :       return;
    1784             :     }
    1785             : 
    1786           0 :   parse_rereadable_options (NULL, 1); /* Start from the default values. */
    1787             : 
    1788           0 :   memset (&pargs, 0, sizeof pargs);
    1789           0 :   dummy = 0;
    1790           0 :   pargs.argc = &dummy;
    1791           0 :   pargs.flags = 1;  /* do not remove the args */
    1792           0 :   while (optfile_parse (fp, opt.config_filename, &configlineno, &pargs, opts) )
    1793             :     {
    1794           0 :       if (pargs.r_opt < -1)
    1795           0 :         pargs.err = 1; /* Print a warning. */
    1796             :       else /* Try to parse this option - ignore unchangeable ones. */
    1797           0 :         parse_rereadable_options (&pargs, 1);
    1798             :     }
    1799           0 :   fclose (fp);
    1800             : 
    1801           0 :   set_debug ();
    1802           0 :   set_tor_mode ();
    1803             : }
    1804             : 
    1805             : 
    1806             : /* A global function which allows us to trigger the reload stuff from
    1807             :    other places.  */
    1808             : void
    1809           0 : dirmngr_sighup_action (void)
    1810             : {
    1811           0 :   log_info (_("SIGHUP received - "
    1812             :               "re-reading configuration and flushing caches\n"));
    1813           0 :   reread_configuration ();
    1814           0 :   cert_cache_deinit (0);
    1815           0 :   crl_cache_deinit ();
    1816           0 :   cert_cache_init ();
    1817           0 :   crl_cache_init ();
    1818           0 : }
    1819             : 
    1820             : 
    1821             : 
    1822             : /* The signal handler. */
    1823             : #ifndef HAVE_W32_SYSTEM
    1824             : static void
    1825           0 : handle_signal (int signo)
    1826             : {
    1827           0 :   switch (signo)
    1828             :     {
    1829             :     case SIGHUP:
    1830           0 :       dirmngr_sighup_action ();
    1831           0 :       break;
    1832             : 
    1833             :     case SIGUSR1:
    1834           0 :       cert_cache_print_stats ();
    1835           0 :       break;
    1836             : 
    1837             :     case SIGUSR2:
    1838           0 :       log_info (_("SIGUSR2 received - no action defined\n"));
    1839           0 :       break;
    1840             : 
    1841             :     case SIGTERM:
    1842           0 :       if (!shutdown_pending)
    1843           0 :         log_info (_("SIGTERM received - shutting down ...\n"));
    1844             :       else
    1845           0 :         log_info (_("SIGTERM received - still %d active connections\n"),
    1846             :                   active_connections);
    1847           0 :       shutdown_pending++;
    1848           0 :       if (shutdown_pending > 2)
    1849             :         {
    1850           0 :           log_info (_("shutdown forced\n"));
    1851           0 :           log_info ("%s %s stopped\n", strusage(11), strusage(13) );
    1852           0 :           cleanup ();
    1853           0 :           dirmngr_exit (0);
    1854             :         }
    1855           0 :       break;
    1856             : 
    1857             :     case SIGINT:
    1858           0 :       log_info (_("SIGINT received - immediate shutdown\n"));
    1859           0 :       log_info( "%s %s stopped\n", strusage(11), strusage(13));
    1860           0 :       cleanup ();
    1861           0 :       dirmngr_exit (0);
    1862           0 :       break;
    1863             : 
    1864             :     default:
    1865           0 :       log_info (_("signal %d received - no action defined\n"), signo);
    1866             :     }
    1867           0 : }
    1868             : #endif /*!HAVE_W32_SYSTEM*/
    1869             : 
    1870             : 
    1871             : /* Thread to do the housekeeping.  */
    1872             : static void *
    1873           0 : housekeeping_thread (void *arg)
    1874             : {
    1875             :   static int sentinel;
    1876             :   time_t curtime;
    1877             : 
    1878             :   (void)arg;
    1879             : 
    1880           0 :   curtime = gnupg_get_time ();
    1881           0 :   if (sentinel)
    1882             :     {
    1883           0 :       log_info ("housekeeping is already going on\n");
    1884           0 :       return NULL;
    1885             :     }
    1886           0 :   sentinel++;
    1887           0 :   if (opt.verbose)
    1888           0 :     log_info ("starting housekeeping\n");
    1889             : 
    1890           0 :   ks_hkp_housekeeping (curtime);
    1891             : 
    1892           0 :   if (opt.verbose)
    1893           0 :     log_info ("ready with housekeeping\n");
    1894           0 :   sentinel--;
    1895           0 :   return NULL;
    1896             : 
    1897             : }
    1898             : 
    1899             : 
    1900             : #if GPGRT_GCC_HAVE_PUSH_PRAGMA
    1901             : # pragma GCC push_options
    1902             : # pragma GCC optimize ("no-strict-overflow")
    1903             : #endif
    1904             : static int
    1905           0 : time_for_housekeeping_p (time_t curtime)
    1906             : {
    1907             :   static time_t last_housekeeping;
    1908             : 
    1909           0 :   if (!last_housekeeping)
    1910           0 :     last_housekeeping = curtime;
    1911             : 
    1912           0 :   if (last_housekeeping + HOUSEKEEPING_INTERVAL <= curtime
    1913           0 :       || last_housekeeping > curtime /*(be prepared for y2038)*/)
    1914             :     {
    1915           0 :       last_housekeeping = curtime;
    1916           0 :       return 1;
    1917             :     }
    1918           0 :   return 0;
    1919             : }
    1920             : #if GPGRT_GCC_HAVE_PUSH_PRAGMA
    1921             : # pragma GCC pop_options
    1922             : #endif
    1923             : 
    1924             : 
    1925             : /* This is the worker for the ticker.  It is called every few seconds
    1926             :    and may only do fast operations. */
    1927             : static void
    1928           0 : handle_tick (void)
    1929             : {
    1930             :   /* Under Windows we don't use signals and need a way for the loop to
    1931             :      check for the shutdown flag.  */
    1932             : #ifdef HAVE_W32_SYSTEM
    1933             :   if (shutdown_pending)
    1934             :     log_info (_("SIGTERM received - shutting down ...\n"));
    1935             :   if (shutdown_pending > 2)
    1936             :     {
    1937             :       log_info (_("shutdown forced\n"));
    1938             :       log_info ("%s %s stopped\n", strusage(11), strusage(13) );
    1939             :       cleanup ();
    1940             :       dirmngr_exit (0);
    1941             :     }
    1942             : #endif /*HAVE_W32_SYSTEM*/
    1943             : 
    1944           0 :   if (time_for_housekeeping_p (gnupg_get_time ()))
    1945             :     {
    1946             :       npth_t thread;
    1947             :       npth_attr_t tattr;
    1948             :       int err;
    1949             : 
    1950           0 :       err = npth_attr_init (&tattr);
    1951           0 :       if (err)
    1952           0 :         log_error ("error preparing housekeeping thread: %s\n", strerror (err));
    1953             :       else
    1954             :         {
    1955           0 :           npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
    1956           0 :           err = npth_create (&thread, &tattr, housekeeping_thread, NULL);
    1957           0 :           if (err)
    1958           0 :             log_error ("error spawning housekeeping thread: %s\n",
    1959             :                        strerror (err));
    1960           0 :           npth_attr_destroy (&tattr);
    1961             :         }
    1962             :     }
    1963           0 : }
    1964             : 
    1965             : 
    1966             : /* Check the nonce on a new connection.  This is a NOP unless we are
    1967             :    using our Unix domain socket emulation under Windows.  */
    1968             : static int
    1969           0 : check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce)
    1970             : {
    1971           0 :   if (assuan_sock_check_nonce (fd, nonce))
    1972             :     {
    1973           0 :       log_info (_("error reading nonce on fd %d: %s\n"),
    1974           0 :                 FD2INT (fd), strerror (errno));
    1975           0 :       assuan_sock_close (fd);
    1976           0 :       return -1;
    1977             :     }
    1978             :   else
    1979           0 :     return 0;
    1980             : }
    1981             : 
    1982             : 
    1983             : /* Helper to call a connection's main fucntion. */
    1984             : static void *
    1985           0 : start_connection_thread (void *arg)
    1986             : {
    1987             :   union int_and_ptr_u argval;
    1988             :   gnupg_fd_t fd;
    1989             : 
    1990           0 :   memset (&argval, 0, sizeof argval);
    1991           0 :   argval.aptr = arg;
    1992           0 :   fd = argval.afd;
    1993             : 
    1994           0 :   if (check_nonce (fd, &socket_nonce))
    1995             :     {
    1996           0 :       log_error ("handler nonce check FAILED\n");
    1997           0 :       return NULL;
    1998             :     }
    1999             : 
    2000             : #ifndef HAVE_W32_SYSTEM
    2001           0 :   npth_setspecific (my_tlskey_current_fd, argval.aptr);
    2002             : #endif
    2003             : 
    2004           0 :   active_connections++;
    2005           0 :   if (opt.verbose)
    2006           0 :     log_info (_("handler for fd %d started\n"), FD2INT (fd));
    2007             : 
    2008           0 :   start_command_handler (fd);
    2009             : 
    2010           0 :   if (opt.verbose)
    2011           0 :     log_info (_("handler for fd %d terminated\n"), FD2INT (fd));
    2012           0 :   active_connections--;
    2013             : 
    2014             : #ifndef HAVE_W32_SYSTEM
    2015           0 :   argval.afd = ASSUAN_INVALID_FD;
    2016           0 :   npth_setspecific (my_tlskey_current_fd, argval.aptr);
    2017             : #endif
    2018             : 
    2019           0 :   return NULL;
    2020             : }
    2021             : 
    2022             : 
    2023             : /* Main loop in daemon mode. */
    2024             : static void
    2025           0 : handle_connections (assuan_fd_t listen_fd)
    2026             : {
    2027             :   npth_attr_t tattr;
    2028             : #ifndef HAVE_W32_SYSTEM
    2029             :   int signo;
    2030             : #endif
    2031             :   struct sockaddr_un paddr;
    2032           0 :   socklen_t plen = sizeof( paddr );
    2033             :   gnupg_fd_t fd;
    2034             :   int nfd, ret;
    2035             :   fd_set fdset, read_fdset;
    2036             :   struct timespec abstime;
    2037             :   struct timespec curtime;
    2038             :   struct timespec timeout;
    2039             :   int saved_errno;
    2040             : 
    2041           0 :   npth_attr_init (&tattr);
    2042           0 :   npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
    2043             : 
    2044             : #ifndef HAVE_W32_SYSTEM /* FIXME */
    2045           0 :   npth_sigev_init ();
    2046           0 :   npth_sigev_add (SIGHUP);
    2047           0 :   npth_sigev_add (SIGUSR1);
    2048           0 :   npth_sigev_add (SIGUSR2);
    2049           0 :   npth_sigev_add (SIGINT);
    2050           0 :   npth_sigev_add (SIGTERM);
    2051           0 :   npth_sigev_fini ();
    2052             : #endif
    2053             : 
    2054             :   /* Setup the fdset.  It has only one member.  This is because we use
    2055             :      pth_select instead of pth_accept to properly sync timeouts with
    2056             :      to full second.  */
    2057           0 :   FD_ZERO (&fdset);
    2058           0 :   FD_SET (FD2INT (listen_fd), &fdset);
    2059           0 :   nfd = FD2INT (listen_fd);
    2060             : 
    2061           0 :   npth_clock_gettime (&abstime);
    2062           0 :   abstime.tv_sec += TIMERTICK_INTERVAL;
    2063             : 
    2064             :   /* Main loop.  */
    2065             :   for (;;)
    2066             :     {
    2067             :       /* Shutdown test.  */
    2068           0 :       if (shutdown_pending)
    2069             :         {
    2070           0 :           if (!active_connections)
    2071           0 :             break; /* ready */
    2072             : 
    2073             :           /* Do not accept new connections but keep on running the
    2074             :              loop to cope with the timer events.  */
    2075           0 :           FD_ZERO (&fdset);
    2076             :         }
    2077             : 
    2078             :       /* Take a copy of the fdset.  */
    2079           0 :       read_fdset = fdset;
    2080             : 
    2081           0 :       npth_clock_gettime (&curtime);
    2082           0 :       if (!(npth_timercmp (&curtime, &abstime, <)))
    2083             :         {
    2084             :           /* Timeout.  */
    2085           0 :           handle_tick ();
    2086           0 :           npth_clock_gettime (&abstime);
    2087           0 :           abstime.tv_sec += TIMERTICK_INTERVAL;
    2088             :         }
    2089           0 :       npth_timersub (&abstime, &curtime, &timeout);
    2090             : 
    2091             : #ifndef HAVE_W32_SYSTEM
    2092           0 :       ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, &timeout, npth_sigev_sigmask());
    2093           0 :       saved_errno = errno;
    2094             : 
    2095           0 :       while (npth_sigev_get_pending(&signo))
    2096           0 :         handle_signal (signo);
    2097             : #else
    2098             :       ret = npth_eselect (nfd+1, &read_fdset, NULL, NULL, &timeout, NULL, NULL);
    2099             :       saved_errno = errno;
    2100             : #endif
    2101             : 
    2102           0 :       if (ret == -1 && saved_errno != EINTR)
    2103             :         {
    2104           0 :           log_error (_("npth_pselect failed: %s - waiting 1s\n"),
    2105             :                      strerror (saved_errno));
    2106           0 :           npth_sleep (1);
    2107           0 :           continue;
    2108             :         }
    2109             : 
    2110           0 :       if (ret <= 0)
    2111             :         /* Interrupt or timeout.  Will be handled when calculating the
    2112             :            next timeout.  */
    2113           0 :         continue;
    2114             : 
    2115           0 :       if (!shutdown_pending && FD_ISSET (FD2INT (listen_fd), &read_fdset))
    2116             :         {
    2117           0 :           plen = sizeof paddr;
    2118           0 :           fd = INT2FD (npth_accept (FD2INT(listen_fd),
    2119             :                                     (struct sockaddr *)&paddr, &plen));
    2120           0 :           if (fd == GNUPG_INVALID_FD)
    2121             :             {
    2122           0 :               log_error ("accept failed: %s\n", strerror (errno));
    2123             :             }
    2124             :           else
    2125             :             {
    2126             :               char threadname[50];
    2127             :               union int_and_ptr_u argval;
    2128             :               npth_t thread;
    2129             : 
    2130           0 :               memset (&argval, 0, sizeof argval);
    2131           0 :               argval.afd = fd;
    2132           0 :               snprintf (threadname, sizeof threadname-1,
    2133             :                         "conn fd=%d", FD2INT(fd));
    2134           0 :               threadname[sizeof threadname -1] = 0;
    2135             : 
    2136           0 :               ret = npth_create (&thread, &tattr,
    2137             :                                  start_connection_thread, argval.aptr);
    2138           0 :               if (ret)
    2139             :                 {
    2140           0 :                   log_error ("error spawning connection handler: %s\n",
    2141             :                              strerror (ret) );
    2142           0 :                   assuan_sock_close (fd);
    2143             :                 }
    2144           0 :               npth_setname_np (thread, threadname);
    2145             :             }
    2146           0 :           fd = GNUPG_INVALID_FD;
    2147             :         }
    2148           0 :     }
    2149             : 
    2150           0 :   npth_attr_destroy (&tattr);
    2151           0 :   cleanup ();
    2152           0 :   log_info ("%s %s stopped\n", strusage(11), strusage(13));
    2153           0 : }

Generated by: LCOV version 1.11