diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2007-08-19 22:43:22 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2007-08-19 22:43:22 +0000 |
commit | 39a9fb6ab567b48ac8c38b98143d6089e9d16709 (patch) | |
tree | 7fa248d8ed2c38ec84a9496de4c2f420ddae5504 /src/gpg.c | |
parent | 32d5cff1b7c2266779b63fb97eb6b91cab34e7ad (diff) | |
download | wydawca-39a9fb6ab567b48ac8c38b98143d6089e9d16709.tar.gz wydawca-39a9fb6ab567b48ac8c38b98143d6089e9d16709.tar.bz2 |
* jabberd/jabberd.h (getmaxfd): moved to gsc.h
* jabberd/main.c (stderr_printer): Minor fix
* wydawca/triplet.c (triplet_processor): Minor fix
* wydawca/verify.c (verify_triplet): Save owner gid in reg.
Call verify_detached_signature
* wydawca/wydawca.h (struct file_register): New member gid.
(verify_detached_signature): New function
* wydawca/gpg.c (verify_detached_signature): New function
* lib/Makefile.am: Add userprivs.c
* lib/userprivs.c: New file
git-svn-id: file:///svnroot/wydawca/trunk@280 6bb4bd81-ecc2-4fd4-a2d4-9571d19c0d33
Diffstat (limited to 'src/gpg.c')
-rw-r--r-- | src/gpg.c | 230 |
1 files changed, 204 insertions, 26 deletions
@@ -17,6 +17,9 @@ #include "wydawca.h" #include "save-cwd.h" #include <gpgme.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <signal.h> #define fail_if_err(expr) \ do \ @@ -138,51 +141,226 @@ wydawca_gpg_homedir () setenv ("GNUPGHOME", homedir, 1); } +/* FIXME: dpair currently unused */ int -verify_signature (struct file_register *reg, struct directory_pair *dpair, - const char *pubkey) +verify_directive_signature (struct file_register *reg, + struct directory_pair *dpair, const char *pubkey) { gpgme_ctx_t ctx; gpgme_data_t key_data, directive_data, plain; off_t size; - size_t dcount, i; - char *p; - + gpgme_error_t ec; + int rc; + wydawca_gpg_homedir (); fail_if_err (gpgme_new (&ctx)); - fail_if_err (gpgme_data_new_from_mem (&key_data, pubkey, strlen (pubkey), 0)); + fail_if_err (gpgme_data_new_from_mem (&key_data, pubkey, strlen (pubkey), + 0)); fail_if_err (gpgme_op_import (ctx, key_data)); fail_if_err (gpgme_data_new_from_file (&directive_data, reg->file[file_directive].name, 1)); gpgme_data_new (&plain); - fail_if_err (gpgme_op_verify (ctx, directive_data, NULL, plain)); + ec = gpgme_op_verify (ctx, directive_data, NULL, plain); + if (ec == GPG_ERR_NO_ERROR) + { + size_t dcount, i; + char *p; + + rc = 0; + + size = gpgme_data_seek (plain, 0, SEEK_END); + gpgme_data_seek (plain, 0, SEEK_SET); + reg->blurb = xmalloc (size + 1); + gpgme_data_read (plain, reg->blurb, size); + reg->blurb[size] = 0; + gpgme_data_release (plain); + + dcount = 1; + for (p = reg->blurb; *p; p++) + if (*p == '\n') + dcount++; + + reg->directive = xcalloc (dcount, sizeof reg->directive[0]); + p = reg->blurb; + for (i = 0; i < dcount; i++) + { + reg->directive[i] = p; + p = strchr (p, '\n'); + if (!p) + break; + *p++ = 0; + } + reg->directive[i] = NULL; + } + else + { + rc = 1; + logmsg (LOG_ERR, "%s: directive verification failed: %s", + reg->name, gpgme_strerror (ec)); + /* FIXME: Send mail to the project maintainer */ + } gpgme_data_release (directive_data); gpgme_data_release (key_data); - size = gpgme_data_seek (plain, 0, SEEK_END); - gpgme_data_seek (plain, 0, SEEK_SET); - reg->blurb = xmalloc (size + 1); - gpgme_data_read (plain, reg->blurb, size); - reg->blurb[size] = 0; + return rc; +} - dcount = 1; - for (p = reg->blurb; *p; p++) - if (*p == '\n') - dcount++; +FILE * +start_prog (int argc, char **argv, pid_t *ppid) +{ + int p[2]; + FILE *fp; + pid_t pid; + int i; - reg->directive = xcalloc (dcount, sizeof reg->directive[0]); - p = reg->blurb; - for (i = 0; i < dcount; i++) + pipe (p); + switch (pid = fork ()) { - reg->directive[i] = p; - p = strchr (p, '\n'); - if (!p) - break; - *p++ = 0; + case 0: + /* Child process */ + + if (p[1] != 1) + dup2 (p[1], 1); + if (p[1] != 1) + dup2 (p[1], 2); + close (p[0]); + + /* Close unneded descripitors */ + for (i = getmaxfd (); i > 2; i--) + close (i); + + execv (argv[0], argv); + logmsg (LOG_CRIT, "cannot run %s: %s", argv[0], strerror (errno)); + exit (1); + + case -1: + logmsg (LOG_CRIT, "cannot run `%s': fork failed: %s", + argv[0], strerror (errno)); + return NULL; + + default: + /* Master process */ + close (p[1]); + fp = fdopen (p[0], "r"); + if (!fp) + logmsg (LOG_ERR, "cannot fdopen: %s", strerror (errno)); + *ppid = pid; } - reg->directive[i] = NULL; + return fp; +} - return 0; +static void +log_output (int prio, const char *prog, FILE *fp) +{ + size_t size = 0; + char *buf = NULL; + + logmsg (prio, "%s output follows:", prog); + while (getline (&buf, &size, fp) > 0) + logmsg (prio, "%s", buf); + logmsg (prio, "end of %s output", prog); + free (buf); +} + +int +verify_detached_signature (struct file_register *reg, + struct directory_pair *dpair) +{ + gpgme_engine_info_t info; + const char *gpg_prog; + char *argv[5]; + FILE *fp; + pid_t pid, npid; + int status; + int i; + int rc; + + fail_if_err (gpgme_get_engine_info (&info)); + while (info && info->protocol != GPGME_PROTOCOL_OpenPGP) + info = info->next; + if (!info) + { + logmsg (LOG_CRIT, + "cannot find path to gpg binary (attempting to verify " + "the detached signature for %s", reg->name); + return 1; + } + + wydawca_gpg_homedir (); + argv[0] = info->file_name; + argv[1] = "--verify"; + argv[2] = reg->file[file_signature].name; + argv[3] = reg->file[file_dist].name; + argv[4] = NULL; + + fp = start_prog (5, argv, &pid); + if (!fp) + { + logmsg (LOG_CRIT, + "cannot verify detached signature for %s", reg->name); + return 1; + } + + for (i = 0; i < 5 && (npid = waitpid (pid, &status, WNOHANG)) == 0; i++) + sleep (1); + + switch (npid) + { + case -1: + logmsg (LOG_CRIT, + "cannot verify detached signature for %s: " + "waitpid failed: %s", reg->name, strerror (errno)); + return 1; + + case 0: + logmsg (LOG_CRIT, + "cannot verify detached signature for %s: " + "process %s did not respond within 5 seconds: %s", + reg->name, argv[0], strerror (errno)); + kill (pid, SIGKILL); + return 1; + + default: + break; + } + + if (WIFEXITED (status)) + { + rc = WEXITSTATUS (status); + if (rc) + { + size_t size = 0; + char *buf = NULL; + + logmsg (LOG_ERR, "bad detached signature for %s", reg->name); + log_output (LOG_ERR, argv[0], fp); + /* FIXME: email? */ + } + else if (debug_level > 1) + log_output (LOG_DEBUG, argv[0], fp); + } + else + { + rc = 1; + if (WIFSIGNALED (status)) + logmsg (LOG_ERR, + "cannot verify detached signature for %s: " + "%s terminated on signal %d", + reg->name, argv[0], WTERMSIG (status)); + else if (WIFSTOPPED (status)) + logmsg (LOG_ERR, + "cannot verify detached signature for %s: " + "%s stopped on signal %d", + reg->name, argv[0], WTERMSIG (status)); + else + logmsg (LOG_ERR, + "cannot verify detached signature for %s: " + "%s terminated with unrecognized status", + reg->name, argv[0]); + } + fclose (fp); + + return rc; } |