mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
Let scdaemon call a script on status changes
This commit is contained in:
parent
44393f2ce7
commit
6374763c98
2
NEWS
2
NEWS
@ -12,6 +12,8 @@ Noteworthy changes in version 1.9.23
|
||||
* 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)
|
||||
-------------------------------------------------
|
||||
|
5
TODO
5
TODO
@ -80,9 +80,6 @@ might want to have an agent context for each service request
|
||||
* 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
|
||||
@ -91,8 +88,6 @@ might want to have an agent context for each service request
|
||||
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).
|
||||
|
@ -193,7 +193,7 @@ atfork_cb (void *opaque, int where)
|
||||
|
||||
/* 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
|
||||
|
@ -1,3 +1,10 @@
|
||||
2006-09-07 Werner Koch <wk@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@g10code.com>
|
||||
|
||||
* maperror.c: Removed.
|
||||
|
@ -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,6 +160,67 @@ create_inheritable_pipe (int filedes[2])
|
||||
#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
|
||||
@ -325,47 +387,10 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
|
||||
|
||||
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 @@ 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. 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*/
|
||||
}
|
||||
|
@ -43,4 +43,16 @@ gpg_error_t gnupg_spawn_process (const char *pgmname, const char *argv[],
|
||||
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*/
|
||||
|
@ -1,3 +1,10 @@
|
||||
2006-09-07 Werner Koch <wk@g10code.com>
|
||||
|
||||
* scdaemon.texi (Scdaemon Configuration): New.
|
||||
|
||||
* examples/scd-event: Event handler for sdaemon.
|
||||
* examples/: New directory
|
||||
|
||||
2006-08-22 Werner Koch <wk@g10code.com>
|
||||
|
||||
* yat2m.c (parse_file): Added code to skip a line after @mansect.
|
||||
|
@ -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
|
||||
|
102
doc/examples/scd-event
Executable file
102
doc/examples/scd-event
Executable file
@ -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
|
||||
|
@ -48,6 +48,7 @@ options.
|
||||
* 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,6 +321,41 @@ This is common fraqmework for smart card applications. It is used by
|
||||
@command{gpgsm}.
|
||||
|
||||
|
||||
@c *******************************************
|
||||
@c *************** ****************
|
||||
@c *************** FILES ****************
|
||||
@c *************** ****************
|
||||
@c *******************************************
|
||||
@mansect files
|
||||
@node Scdaemon Configuration
|
||||
@section Configuration files
|
||||
|
||||
There are a few configuration files to control certain aspects of
|
||||
@command{scdaemons}'s operation. Unless noted, they are expected in the
|
||||
current home directory (@pxref{option --homedir}).
|
||||
|
||||
@table @file
|
||||
|
||||
@item scdaemon.conf
|
||||
@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}).
|
||||
|
||||
@item scd-event
|
||||
@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
|
||||
|
||||
@item reader_@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
|
||||
@file{scd-event}.
|
||||
|
||||
@end table
|
||||
|
||||
|
||||
@c
|
||||
@c Examples
|
||||
@ -339,7 +375,7 @@ $ scdaemon --server -v
|
||||
@c
|
||||
@c Assuan Protocol
|
||||
@c
|
||||
@mansect assuan
|
||||
@manpause
|
||||
@node Scdaemon Protocol
|
||||
@section Scdaemon's Assuan Protocol
|
||||
|
||||
@ -621,3 +657,11 @@ Using the option @code{--more} handles the card status word MORE_DATA
|
||||
|
||||
|
||||
|
||||
@mansect see also
|
||||
@ifset isman
|
||||
@command{gpg-agent}(1),
|
||||
@command{gpgsm}(1),
|
||||
@command{gpg2}(1)
|
||||
@end ifset
|
||||
@include see-also-note.texi
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
2006-09-07 Werner Koch <wk@g10code.com>
|
||||
|
||||
* command.c (update_reader_status_file): Execute an event handler
|
||||
if available.
|
||||
|
||||
2006-09-06 Werner Koch <wk@g10code.com>
|
||||
|
||||
* apdu.c (pcsc_end_transaction):
|
||||
|
@ -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 @@ update_reader_status_file (void)
|
||||
}
|
||||
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 @@ update_reader_status_file (void)
|
||||
kill (pid, signo);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user