scd: Don't limit to ST-2xxx for PC/SC.
[gnupg.git] / scd / scdaemon.c
index 2cabee8..064cae9 100644 (file)
@@ -15,7 +15,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
@@ -118,7 +118,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oSh,   "sh", N_("sh-style command output")),
   ARGPARSE_s_n (oCsh,  "csh", N_("csh-style command output")),
   ARGPARSE_s_s (oOptions, "options", N_("|FILE|read options from FILE")),
-  ARGPARSE_p_u (oDebug,        "debug", "@"),
+  ARGPARSE_s_s (oDebug,        "debug", "@"),
   ARGPARSE_s_n (oDebugAll, "debug-all", "@"),
   ARGPARSE_s_s (oDebugLevel, "debug-level" ,
                 N_("|LEVEL|set the debugging level to LEVEL")),
@@ -156,11 +156,29 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_s (oDisableApplication, "disable-application", "@"),
   ARGPARSE_s_n (oEnablePinpadVarlen, "enable-pinpad-varlen",
                 N_("use variable length input for pinpad")),
+  ARGPARSE_s_s (oHomedir,    "homedir",      "@"),
 
   ARGPARSE_end ()
 };
 
 
+/* The list of supported debug flags.  */
+static struct debug_flags_s debug_flags [] =
+  {
+    { DBG_COMMAND_VALUE, "command"  },
+    { DBG_MPI_VALUE    , "mpi"     },
+    { DBG_CRYPTO_VALUE , "crypto"  },
+    { DBG_MEMORY_VALUE , "memory"  },
+    { DBG_CACHE_VALUE  , "cache"   },
+    { DBG_MEMSTAT_VALUE, "memstat" },
+    { DBG_HASHING_VALUE, "hashing" },
+    { DBG_IPC_VALUE    , "ipc"     },
+    { DBG_CARD_IO_VALUE, "cardio"  },
+    { DBG_READER_VALUE , "reader"  },
+    { 0, NULL }
+  };
+
+
 /* The card driver we use by default for PC/SC.  */
 #if defined(HAVE_W32_SYSTEM) || defined(__CYGWIN__)
 #define DEFAULT_PCSC_DRIVER "winscard.dll"
@@ -343,17 +361,7 @@ set_debug (const char *level)
   gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
 
   if (opt.debug)
-    log_info ("enabled debug flags:%s%s%s%s%s%s%s%s%s%s\n",
-              (opt.debug & DBG_COMMAND_VALUE)? " command":"",
-              (opt.debug & DBG_MPI_VALUE    )? " mpi":"",
-              (opt.debug & DBG_CRYPTO_VALUE )? " crypto":"",
-              (opt.debug & DBG_MEMORY_VALUE )? " memory":"",
-              (opt.debug & DBG_CACHE_VALUE  )? " cache":"",
-              (opt.debug & DBG_MEMSTAT_VALUE)? " memstat":"",
-              (opt.debug & DBG_HASHING_VALUE)? " hashing":"",
-              (opt.debug & DBG_IPC_VALUE    )? " ipc":"",
-              (opt.debug & DBG_CARD_IO_VALUE)? " cardio":"",
-              (opt.debug & DBG_READER_VALUE )? " reader":"");
+    parse_debug_flag (NULL, &opt.debug, debug_flags);
 }
 
 
@@ -364,18 +372,10 @@ cleanup (void)
   if (socket_name && *socket_name)
     {
       char *name;
-      char *p;
 
       name = redir_socket_name? redir_socket_name : socket_name;
 
       gnupg_remove (name);
-      p = strrchr (name, '/');
-      if (p)
-        {
-          *p = 0;
-          rmdir (name);
-          *p = '/';
-        }
       *socket_name = 0;
     }
 }
@@ -416,22 +416,12 @@ main (int argc, char **argv )
   /* Please note that we may running SUID(ROOT), so be very CAREFUL
      when adding any stuff between here and the call to INIT_SECMEM()
      somewhere after the option parsing */
-  log_set_prefix ("scdaemon", 1|4);
+  log_set_prefix ("scdaemon", GPGRT_LOG_WITH_PREFIX | GPGRT_LOG_WITH_PID);
 
   /* Make sure that our subsystems are ready.  */
   i18n_init ();
   init_common_subsystems (&argc, &argv);
 
-  npth_init ();
-
-  /* Check that the libraries are suitable.  Do it here because
-     the option parsing may need services of the library */
-  if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
-    {
-      log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt",
-                 NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
-    }
-
   ksba_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free);
 
   malloc_hooks.malloc = gcry_malloc;
@@ -441,7 +431,7 @@ main (int argc, char **argv )
   assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
   assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);
   assuan_sock_init ();
-  setup_libassuan_logging (&opt.debug);
+  setup_libassuan_logging (&opt.debug, NULL);
 
   setup_libgcrypt_logging ();
   gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
@@ -456,8 +446,6 @@ main (int argc, char **argv )
   if (shell && strlen (shell) >= 3 && !strcmp (shell+strlen (shell)-3, "csh") )
     csh_style = 1;
 
-  opt.homedir = default_homedir ();
-
   /* Check whether we have a config file on the commandline */
   orig_argc = argc;
   orig_argv = argv;
@@ -477,7 +465,7 @@ main (int argc, char **argv )
        else if (pargs.r_opt == oNoOptions)
           default_config = 0; /* --no-options */
        else if (pargs.r_opt == oHomedir)
-          opt.homedir = pargs.r.ret_str;
+          gnupg_set_homedir (pargs.r.ret_str);
     }
 
   /* initialize the secure memory. */
@@ -490,7 +478,7 @@ main (int argc, char **argv )
 
 
   if (default_config)
-    configname = make_filename (opt.homedir, SCDAEMON_NAME EXTSEP_S "conf",
+    configname = make_filename (gnupg_homedir (), SCDAEMON_NAME EXTSEP_S "conf",
                                 NULL );
 
 
@@ -536,7 +524,13 @@ main (int argc, char **argv )
         case oVerbose: opt.verbose++; break;
         case oBatch: opt.batch=1; break;
 
-        case oDebug: opt.debug |= pargs.r.ret_ulong; break;
+        case oDebug:
+          if (parse_debug_flag (pargs.r.ret_str, &opt.debug, debug_flags))
+            {
+              pargs.r_opt = ARGPARSE_INVALID_ARG;
+              pargs.err = ARGPARSE_PRINT_ERROR;
+            }
+          break;
         case oDebugAll: opt.debug = ~0; break;
         case oDebugLevel: debug_level = pargs.r.ret_str; break;
         case oDebugWait: debug_wait = pargs.r.ret_int; break;
@@ -569,7 +563,7 @@ main (int argc, char **argv )
         case oNoGreeting: nogreeting = 1; break;
         case oNoVerbose: opt.verbose = 0; break;
         case oNoOptions: break; /* no-options */
-        case oHomedir: opt.homedir = pargs.r.ret_str; break;
+        case oHomedir: gnupg_set_homedir (pargs.r.ret_str); break;
         case oNoDetach: nodetach = 1; break;
         case oLogFile: logfile = pargs.r.ret_str; break;
         case oCsh: csh_style = 1; break;
@@ -661,8 +655,8 @@ main (int argc, char **argv )
       if (config_filename)
        filename = xstrdup (config_filename);
       else
-        filename = make_filename (opt.homedir, SCDAEMON_NAME EXTSEP_S "conf",
-                                  NULL);
+        filename = make_filename (gnupg_homedir (),
+                                  SCDAEMON_NAME EXTSEP_S "conf", NULL);
       filename_esc = percent_escape (filename, NULL);
 
       es_printf ("%s-%s.conf:%lu:\"%s\n",
@@ -699,7 +693,7 @@ main (int argc, char **argv )
   if (logfile)
     {
       log_set_file (logfile);
-      log_set_prefix (NULL, 1|2|4);
+      log_set_prefix (NULL, GPGRT_LOG_WITH_PREFIX | GPGRT_LOG_WITH_TIME | GPGRT_LOG_WITH_PID);
     }
 
   if (debug_wait && pipe_server)
@@ -728,6 +722,9 @@ main (int argc, char **argv )
       }
 #endif
 
+      npth_init ();
+      gpgrt_set_syscall_clamp (npth_unprotect, npth_protect);
+
       /* If --debug-allow-core-dump has been given we also need to
          switch the working directory to a place where we can actually
          write. */
@@ -865,15 +862,28 @@ main (int argc, char **argv )
 
       /* This is the child. */
 
+      npth_init ();
+      gpgrt_set_syscall_clamp (npth_unprotect, npth_protect);
+
       /* Detach from tty and put process into a new session. */
       if (!nodetach )
         {
           /* Close stdin, stdout and stderr unless it is the log stream. */
           for (i=0; i <= 2; i++)
             {
-              if ( log_test_fd (i) && i != fd)
-                close (i);
+              if (!log_test_fd (i) && i != fd )
+                {
+                  if ( !close (i)
+                       && open ("/dev/null", i? O_WRONLY : O_RDONLY) == -1)
+                    {
+                      log_error ("failed to open '%s': %s\n",
+                                 "/dev/null", strerror (errno));
+                      cleanup ();
+                      exit (1);
+                    }
+                }
             }
+
           if (setsid() == -1)
             {
               log_error ("setsid() failed: %s\n", strerror(errno) );
@@ -1031,7 +1041,7 @@ create_socket_name (char *standard_name)
 {
   char *name;
 
-  name = make_filename (opt.homedir, standard_name, NULL);
+  name = make_filename (gnupg_socketdir (), standard_name, NULL);
   if (strchr (name, PATHSEP_C))
     {
       log_error (("'%s' are not allowed in the socket name\n"), PATHSEP_S);
@@ -1069,7 +1079,6 @@ create_server_socket (const char *name, char **r_redir_name,
   unaddr = xmalloc (sizeof (*unaddr));
   addr = (struct sockaddr*)unaddr;
 
-#if ASSUAN_VERSION_NUMBER >= 0x020104 /* >= 2.1.4 */
   {
     int redirected;
 
@@ -1089,16 +1098,6 @@ create_server_socket (const char *name, char **r_redir_name,
           log_info ("redirecting socket '%s' to '%s'\n", name, *r_redir_name);
       }
   }
-#else /* Assuan < 2.1.4 */
-  memset (unaddr, 0, sizeof *unaddr);
-  unaddr->sun_family = AF_UNIX;
-  if (strlen (name) + 1 >= sizeof (unaddr->sun_path))
-    {
-      log_error (_("socket name '%s' is too long\n"), name);
-      scd_exit (2);
-    }
-  strcpy (unaddr->sun_path, name);
-#endif /* Assuan < 2.1.4 */
 
   len = SUN_LEN (unaddr);
 
@@ -1120,6 +1119,10 @@ create_server_socket (const char *name, char **r_redir_name,
       scd_exit (2);
     }
 
+  if (gnupg_chmod (unaddr->sun_path, "-rwx"))
+    log_error (_("can't set permissions of '%s': %s\n"),
+               unaddr->sun_path, strerror (errno));
+
   if (listen (FD2INT(fd), 5 ) == -1)
     {
       log_error (_("listen() failed: %s\n"),
@@ -1299,8 +1302,7 @@ handle_connections (int listen_fd)
               char threadname[50];
              npth_t thread;
 
-              snprintf (threadname, sizeof threadname-1, "conn fd=%d", fd);
-              threadname[sizeof threadname -1] = 0;
+              snprintf (threadname, sizeof threadname, "conn fd=%d", fd);
               ctrl->thread_startup.fd = INT2FD (fd);
               ret = npth_create (&thread, &tattr, start_connection_thread, ctrl);
              if (ret)