[svn] GnuPG - r4246 - in trunk: . agent common doc doc/examples scd

svn author wk cvs at cvs.gnupg.org
Thu Sep 7 17:13:35 CEST 2006


Author: wk
Date: 2006-09-07 17:13:33 +0200 (Thu, 07 Sep 2006)
New Revision: 4246

Added:
   trunk/doc/examples/
   trunk/doc/examples/scd-event
Modified:
   trunk/NEWS
   trunk/TODO
   trunk/agent/call-scd.c
   trunk/common/ChangeLog
   trunk/common/exechelp.c
   trunk/common/exechelp.h
   trunk/doc/ChangeLog
   trunk/doc/Makefile.am
   trunk/doc/scdaemon.texi
   trunk/scd/ChangeLog
   trunk/scd/command.c
Log:
Let scdaemon call a script on status changes


Modified: trunk/NEWS
===================================================================
--- trunk/NEWS	2006-09-07 06:42:55 UTC (rev 4245)
+++ trunk/NEWS	2006-09-07 15:13:33 UTC (rev 4246)
@@ -12,7 +12,9 @@
  * API change in gpg-agent's pkdecrypt command.  Thus an older gpgsm
    may not be used with the current gpg-agent.
 
+ * The scdaemon will now call a script on reader status changes.
 
+
 Noteworthy changes in version 1.9.22 (2006-07-27)
 -------------------------------------------------
 

Modified: trunk/TODO
===================================================================
--- trunk/TODO	2006-09-07 06:42:55 UTC (rev 4245)
+++ trunk/TODO	2006-09-07 15:13:33 UTC (rev 4246)
@@ -80,10 +80,7 @@
 * doc/
 ** Explain how to setup a root CA key as trusted
 ** Explain how trustlist.txt might be managed.
-** Write a script to generate man pages from texi.
-   In progress (yatm)
 
-
 * Windows port
 ** gpgsm's LISTKEYS does not yet work
     Fix is to change everything to libestream
@@ -91,8 +88,6 @@
     This means we can't reread a configuration
 ** No card status notifications.
 
-
-
 * sm/
 ** check that we issue NO_SECKEY xxx if a -u key was not found
    We don't. The messages retruned are also wrong (recipient vs. signer).

Modified: trunk/agent/call-scd.c
===================================================================
--- trunk/agent/call-scd.c	2006-09-07 06:42:55 UTC (rev 4245)
+++ trunk/agent/call-scd.c	2006-09-07 15:13:33 UTC (rev 4246)
@@ -193,7 +193,7 @@
 
 /* Fork off the SCdaemon if this has not already been done.  Lock the
    daemon and make sure that a proper context has been setup in CTRL.
-   Thsi fucntion might also lock the daemon, which means that the
+   This function might also lock the daemon, which means that the
    caller must call unlock_scd after this fucntion has returned
    success and the actual Assuan transaction been done. */
 static int

Modified: trunk/common/ChangeLog
===================================================================
--- trunk/common/ChangeLog	2006-09-07 06:42:55 UTC (rev 4245)
+++ trunk/common/ChangeLog	2006-09-07 15:13:33 UTC (rev 4246)
@@ -1,3 +1,10 @@
+2006-09-07  Werner Koch  <wk at g10code.com>
+
+	* exechelp.c (gnupg_spawn_process): Factor out post fork code to ..
+	(do_exec): .. new function.  Allow passing of -1 for the fds.
+	(gnupg_spawn_process): Terminate gcrypt's secure memory in the child.
+	(gnupg_spawn_process_detached): New.
+
 2006-09-06  Werner Koch  <wk at g10code.com>
 
 	* maperror.c: Removed.

Modified: trunk/common/exechelp.c
===================================================================
--- trunk/common/exechelp.c	2006-09-07 06:42:55 UTC (rev 4245)
+++ trunk/common/exechelp.c	2006-09-07 15:13:33 UTC (rev 4246)
@@ -28,6 +28,7 @@
 #include <assert.h>
 #include <signal.h>
 #include <unistd.h> 
+#include <fcntl.h>
 #ifdef USE_GNU_PTH      
 #include <pth.h>
 #endif
@@ -159,7 +160,68 @@
 #endif /*HAVE_W32_SYSTEM*/
 
 
+#ifndef HAVE_W32_SYSTEM
+/* The exec core used right after the fork. This will never return. */
+static void
+do_exec (const char *pgmname, const char *argv[],
+         int fd_in, int fd_out, int fd_err,
+         void (*preexec)(void) )
+{
+  char **arg_list;
+  int n, i, j;
+  int fds[3];
 
+  fds[0] = fd_in;
+  fds[1] = fd_out;
+  fds[2] = fd_err;
+
+  /* Create the command line argument array.  */
+  i = 0;
+  if (argv)
+    while (argv[i])
+      i++;
+  arg_list = xcalloc (i+2, sizeof *arg_list);
+  arg_list[0] = strrchr (pgmname, '/');
+  if (arg_list[0])
+    arg_list[0]++;
+  else
+    arg_list[0] = xstrdup (pgmname);
+  if (argv)
+    for (i=0,j=1; argv[i]; i++, j++)
+      arg_list[j] = (char*)argv[i];
+
+  /* Connect the standard files. */
+  for (i=0; i <= 2; i++)
+    {
+      if (fds[i] == -1 )
+        {
+          fds[i] = open ("/dev/null", i? O_WRONLY : O_RDONLY);
+          if (fds[i] == -1)
+            log_fatal ("failed to open `%s': %s\n",
+                       "/dev/null", strerror (errno));
+        }
+      else if (fds[i] != i && dup2 (fds[i], i) == -1)
+        log_fatal ("dup2 std%s failed: %s\n",
+                   i==0?"in":i==1?"out":"err", strerror (errno));
+    }
+
+  /* Close all other files. */
+  n = sysconf (_SC_OPEN_MAX);
+  if (n < 0)
+    n = MAX_OPEN_FDS;
+  for (i=3; i < n; i++)
+    close(i);
+  errno = 0;
+  
+  if (preexec)
+    preexec ();
+  execv (pgmname, arg_list);
+  /* No way to print anything, as we have closed all streams. */
+  _exit (127);
+}
+#endif /*!HAVE_W32_SYSTEM*/
+
+
 /* Fork and exec the PGMNAME, connect the file descriptor of INFILE to
    stdin, write the output to OUTFILE, return a new stream in
    STATUSFILE for stderr and the pid of the process in PID. The
@@ -325,47 +387,10 @@
 
   if (!*pid)
     { 
-      /* Child. */
-      char **arg_list;
-      int n, i, j;
-
-      /* Create the command line argument array.  */
-      for (i=0; argv[i]; i++)
-        ;
-      arg_list = xcalloc (i+2, sizeof *arg_list);
-      arg_list[0] = strrchr (pgmname, '/');
-      if (arg_list[0])
-        arg_list[0]++;
-      else
-        arg_list[0] = xstrdup (pgmname);
-      for (i=0,j=1; argv[i]; i++, j++)
-        arg_list[j] = (char*)argv[i];
-
-      /* Connect the infile to stdin. */
-      if (fd != 0 && dup2 (fd, 0) == -1)
-        log_fatal ("dup2 stdin failed: %s\n", strerror (errno));
-
-      /* Connect the outfile to stdout. */
-      if (fdout != 1 && dup2 (fdout, 1) == -1)
-        log_fatal ("dup2 stdout failed: %s\n", strerror (errno));
-      
-      /* Connect stderr to our pipe. */
-      if (rp[1] != 2 && dup2 (rp[1], 2) == -1)
-        log_fatal ("dup2 stderr failed: %s\n", strerror (errno));
-
-      /* Close all other files. */
-      n = sysconf (_SC_OPEN_MAX);
-      if (n < 0)
-        n = MAX_OPEN_FDS;
-      for (i=3; i < n; i++)
-        close(i);
-      errno = 0;
-
-      if (preexec)
-        preexec ();
-      execv (pgmname, arg_list);
-      /* No way to print anything, as we have closed all streams. */
-      _exit (127);
+      gcry_control (GCRYCTL_TERM_SECMEM);
+      /* Run child. */
+      do_exec (pgmname, argv, fd, fdout, rp[1], preexec);
+      /*NOTREACHED*/
     }
 
   /* Parent. */
@@ -481,3 +506,64 @@
 
 }
 
+
+/* Spawn a new process and immediatley detach from it.  The name of
+   the program to exec is PGMNAME and its arguments are in ARGV (the
+   programname is automatically passed as first argument).
+   Environment strings in ENVP are set.  An error is returned if
+   pgmname is not executable; to make this work it is necessary to
+   provide an absolute file name.  All standard file descriptors are
+   connected to /dev/null. */
+gpg_error_t
+gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
+                              const char *envp[] )
+{
+#ifdef HAVE_W32_SYSTEM
+  return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+#else
+  pid_t pid;
+  int i;
+
+  if (getuid() != geteuid())
+    return gpg_error (GPG_ERR_BUG);
+
+  if (access (pgmname, X_OK))
+    return gpg_error_from_errno (errno);
+
+#ifdef USE_GNU_PTH      
+  pid = pth_fork? pth_fork () : fork ();
+#else
+  pid = fork ();
+#endif
+  if (pid == (pid_t)(-1))
+    {
+      log_error (_("error forking process: %s\n"), strerror (errno));
+      return gpg_error_from_errno (errno);
+    }
+  if (!pid)
+    {
+      gcry_control (GCRYCTL_TERM_SECMEM);
+      if (setsid() == -1 || chdir ("/"))
+        _exit (1);
+      pid = fork (); /* Double fork to let init takes over the new child. */
+      if (pid == (pid_t)(-1))
+        _exit (1);
+      if (pid)
+        _exit (0);  /* Let the parent exit immediately. */
+
+      if (envp)
+        for (i=0; envp[i]; i++)
+          putenv (xstrdup (envp[i]));
+      
+      do_exec (pgmname, argv, -1, -1, -1, NULL);
+
+      /*NOTREACHED*/
+    }
+  
+  if (waitpid (pid, NULL, 0) == -1)
+    log_error ("waitpid failed in gnupg_spawn_process_detached: %s",
+               strerror (errno));
+
+  return 0;
+#endif /* !HAVE_W32_SYSTEM*/
+}

Modified: trunk/common/exechelp.h
===================================================================
--- trunk/common/exechelp.h	2006-09-07 06:42:55 UTC (rev 4245)
+++ trunk/common/exechelp.h	2006-09-07 15:13:33 UTC (rev 4246)
@@ -43,4 +43,16 @@
 gpg_error_t gnupg_wait_process (const char *pgmname, pid_t pid);
 
 
+/* Spawn a new process and immediatley detach from it.  The name of
+   the program to exec is PGMNAME and its arguments are in ARGV (the
+   programname is automatically passed as first argument).
+   Environment strings in ENVP are set.  An error is returned if
+   pgmname is not executable; to make this work it is necessary to
+   provide an absolute file name.  */
+gpg_error_t gnupg_spawn_process_detached (const char *pgmname,
+                                          const char *argv[],
+                                          const char *envp[] );
+
+
+
 #endif /*GNUPG_COMMON_EXECHELP_H*/

Modified: trunk/doc/ChangeLog
===================================================================
--- trunk/doc/ChangeLog	2006-09-07 06:42:55 UTC (rev 4245)
+++ trunk/doc/ChangeLog	2006-09-07 15:13:33 UTC (rev 4246)
@@ -1,3 +1,10 @@
+2006-09-07  Werner Koch  <wk at g10code.com>
+
+	* scdaemon.texi (Scdaemon Configuration): New.
+
+	* examples/scd-event: Event handler for sdaemon.
+	* examples/: New directory
+
 2006-08-22  Werner Koch  <wk at g10code.com>
 
 	* yat2m.c (parse_file): Added code to skip a line after @mansect.

Modified: trunk/doc/Makefile.am
===================================================================
--- trunk/doc/Makefile.am	2006-09-07 06:42:55 UTC (rev 4245)
+++ trunk/doc/Makefile.am	2006-09-07 15:13:33 UTC (rev 4246)
@@ -19,13 +19,16 @@
 
 ## Process this file with automake to produce Makefile.in
 
+examples=examples/scd-event
+
 EXTRA_DIST = DETAILS HACKING TRANSLATE OpenPGP KEYSERVER samplekeys.asc \
 	     gnupg-badge-openpgp.eps gnupg-badge-openpgp.jpg \
              gnupg-badge-openpgp.pdf \
              gnupg-card-architecture.eps gnupg-card-architecture.png \
              gnupg-card-architecture.pdf \
              faq.raw FAQ faq.html gnupg7.texi \
-             opt-homedir.texi see-also-note.texi
+             opt-homedir.texi see-also-note.texi \
+	     $(examples)
 
 BUILT_SOURCES = gnupg-card-architecture.eps gnupg-card-architecture.png \
                 gnupg-card-architecture.pdf FAQ faq.html

Added: trunk/doc/examples/scd-event
===================================================================
--- trunk/doc/examples/scd-event	2006-09-07 06:42:55 UTC (rev 4245)
+++ trunk/doc/examples/scd-event	2006-09-07 15:13:33 UTC (rev 4246)
@@ -0,0 +1,102 @@
+#!/bin/sh
+# Sample script for scdaemon event mechanism.
+
+#exec >>/tmp/scd-event.log
+
+PGM=scd-event
+
+reader_port=
+old_code=0x0000
+new_code=0x0000
+status=
+
+tick='`'
+prev=
+while [ $# -gt 0 ]; do
+  arg="$1"
+  case $arg in
+      -*=*) optarg=$(echo "X$arg" | sed -e '1s/^X//' -e 's/[-_a-zA-Z0-9]*=//')
+            ;;
+         *) optarg=
+            ;;
+  esac
+  if [ -n "$prev" ]; then
+    eval "$prev=\$arg"
+    prev=
+    shift
+    continue
+  fi
+  case $arg in
+      --help|-h)
+          cat <<EOF
+Usage: $PGM [options]
+$PGM is called by scdaemon on card reader status changes
+
+Options:
+  --reader-port N        Reports change for port N
+  --old-code 0xNNNN      Previous status code
+  --old-code 0xNNNN      Current status code
+  --status USABLE|ACTIVE|PRESENT}NOCARD 
+                         Human readable status code
+
+Environment:
+
+GNUPGHOME=DIR            Set to the active hmedir
+
+EOF
+          exit 0
+          ;;
+    
+      --reader-port)  
+          prev=reader_port
+          ;;
+      --reader-port=*)
+          reader_port="$optarg"
+          ;;
+      --old-code)  
+          prev=old_code
+          ;;
+      --old-code=*)
+          old_code="$optarg"
+          ;;
+      --new-code)  
+          prev=new_code
+          ;;
+      --new-code=*)
+          new_code="$optarg"
+          ;;
+      --status)  
+          prev=status
+          ;;
+      --new-code=*)
+          status="$optarg"
+          ;;
+
+      -*)
+          echo "$PGM: invalid option $tick$arg'" >&2
+          exit 1
+          ;;
+
+      *)
+          break
+          ;;
+  esac
+  shift
+done
+if [ -n "$prev" ]; then
+  echo "$PGM: argument missing for option $tick$prev'" >&2
+  exit 1
+fi
+
+cat <<EOF
+========================
+port:     $reader_port
+old-code: $old_code
+new-code: $new_code
+status:   $status
+EOF
+
+if [ x$status = xUSABLE ]; then
+    gpg --batch --card-status 2>&1
+fi
+


Property changes on: trunk/doc/examples/scd-event
___________________________________________________________________
Name: svn:executable
   + *

Modified: trunk/doc/scdaemon.texi
===================================================================
--- trunk/doc/scdaemon.texi	2006-09-07 06:42:55 UTC (rev 4245)
+++ trunk/doc/scdaemon.texi	2006-09-07 15:13:33 UTC (rev 4246)
@@ -48,6 +48,7 @@
 * Scdaemon Commands::      List of all commands.
 * Scdaemon Options::       List of all options.
 * Card applications::      Description of card applications.
+* Scdaemon Configuration:: Configuration files.
 * Scdaemon Examples::      Some usage examples.
 * Scdaemon Protocol::      The protocol the daemon uses.
 @end menu
@@ -320,7 +321,42 @@
 @command{gpgsm}.
 
 
+ at c *******************************************
+ at c ***************            ****************
+ at c ***************   FILES    ****************
+ at c ***************            ****************
+ at c *******************************************
+ at mansect files
+ at node Scdaemon Configuration
+ at section Configuration files
 
+There are a few configuration files to control certain aspects of
+ at command{scdaemons}'s operation. Unless noted, they are expected in the
+current home directory (@pxref{option --homedir}).
+
+ at table @file
+
+ at item scdaemon.conf
+ at cindex scdaemon.conf
+This is the standard configuration file read by @command{scdaemon} on
+startup.  It may contain any valid long option; the leading two dashes
+may not be entered and the option may not be abbreviated.  This default
+name may be changed on the command line (@pxref{option --options}).
+
+ at item scd-event
+ at cindex scd-event
+If this file is present and executable, it will be called on veyer card
+reader's status changed. An example of this script is provided with the
+distribution
+
+ at item reader_ at var{n}.status
+This file is created by @command{sdaemon} to let other applications now
+about reader status changes.  Its use is now deprecated in favor of
+ at file{scd-event}.
+
+ at end table
+
+
 @c 
 @c  Examples
 @c
@@ -339,7 +375,7 @@
 @c 
 @c  Assuan Protocol
 @c
- at mansect assuan
+ at manpause
 @node Scdaemon Protocol
 @section Scdaemon's Assuan Protocol
 
@@ -621,3 +657,11 @@
 
 
 
+ at mansect see also
+ at ifset isman
+ at command{gpg-agent}(1),
+ at command{gpgsm}(1), 
+ at command{gpg2}(1)
+ at end ifset
+ at include see-also-note.texi
+

Modified: trunk/scd/ChangeLog
===================================================================
--- trunk/scd/ChangeLog	2006-09-07 06:42:55 UTC (rev 4245)
+++ trunk/scd/ChangeLog	2006-09-07 15:13:33 UTC (rev 4246)
@@ -1,3 +1,8 @@
+2006-09-07  Werner Koch  <wk at g10code.com>
+
+	* command.c (update_reader_status_file): Execute an event handler
+	if available.
+
 2006-09-06  Werner Koch  <wk at g10code.com>
 
 	* apdu.c (pcsc_end_transaction): 

Modified: trunk/scd/command.c
===================================================================
--- trunk/scd/command.c	2006-09-07 06:42:55 UTC (rev 4245)
+++ trunk/scd/command.c	2006-09-07 15:13:33 UTC (rev 4246)
@@ -37,6 +37,7 @@
 #include <ksba.h>
 #include "app-common.h"
 #include "apdu.h" /* Required for apdu_*_reader (). */
+#include "exechelp.h"
 
 /* Maximum length allowed as a PIN; used for INQUIRE NEEDPIN */
 #define MAXLEN_PIN 100
@@ -1778,6 +1779,47 @@
             }
           xfree (fname);
             
+          /* If a status script is executable, run it. */
+          {
+            const char *args[9], *envs[2];
+            char numbuf1[30], numbuf2[3], numbuf3[30];
+            char *homestr, *envstr;
+            gpg_error_t err;
+            
+            homestr = make_filename (opt.homedir, NULL);
+            if (asprintf (&envstr, "GNUPGHOME=%s", homestr) < 0)
+              log_error ("out of core while building environment\n");
+            else
+              {
+                envs[0] = envstr;
+                envs[1] = NULL;
+
+                sprintf (numbuf1, "%d", ss->slot);
+                sprintf (numbuf2, "0x%04X", ss->status);
+                sprintf (numbuf3, "0x%04X", status);
+                args[0] = "--reader-port";
+                args[1] = numbuf1; 
+                args[2] = "--old-code";
+                args[3] = numbuf2;  
+                args[4] = "--new-code";
+                args[5] = numbuf3; 
+                args[6] = "--status";
+                args[7] = ((status & 1)? "USABLE":
+                           (status & 4)? "ACTIVE":
+                           (status & 2)? "PRESENT": "NOCARD");
+                args[8] = NULL;  
+
+                fname = make_filename (opt.homedir, "scd-event", NULL);
+                err = gnupg_spawn_process_detached (fname, args, envs);
+                if (err && gpg_err_code (err) != GPG_ERR_ENOENT)
+                  log_error ("failed to run event handler `%s': %s\n",
+                             fname, gpg_strerror (err));
+                xfree (fname);
+                free (envstr);
+              }
+            xfree (homestr);
+          }
+
           /* Set the card removed flag for all current sessions.  We
              will set this on any card change because a reset or
              SERIALNO request must be done in any case.  */
@@ -1802,6 +1844,7 @@
                   kill (pid, signo);
 #endif
               }
+
         }
     }
 }




More information about the Gnupg-commits mailing list