diff options
| author | Werner Koch <[email protected]> | 2000-11-09 16:35:35 +0000 | 
|---|---|---|
| committer | Werner Koch <[email protected]> | 2000-11-09 16:35:35 +0000 | 
| commit | 36966ea498fe145a81f284e21a66be54af4d30ad (patch) | |
| tree | be365cc282a24b7791b29950aaa175bf6de1cfbe | |
| parent | Just a backup for now (diff) | |
| download | gpgme-36966ea498fe145a81f284e21a66be54af4d30ad.tar.gz gpgme-36966ea498fe145a81f284e21a66be54af4d30ad.zip | |
Add verify function
| -rw-r--r-- | gpgme/Makefile.am | 1 | ||||
| -rw-r--r-- | gpgme/context.h | 22 | ||||
| -rw-r--r-- | gpgme/data.c | 84 | ||||
| -rw-r--r-- | gpgme/encrypt.c | 24 | ||||
| -rw-r--r-- | gpgme/gpgme.c | 22 | ||||
| -rw-r--r-- | gpgme/gpgme.h | 12 | ||||
| -rw-r--r-- | gpgme/ops.h | 8 | ||||
| -rw-r--r-- | gpgme/rungpg.c | 146 | ||||
| -rw-r--r-- | gpgme/types.h | 5 | ||||
| -rw-r--r-- | gpgme/verify.c | 198 | ||||
| -rw-r--r-- | gpgme/wait.c | 65 | ||||
| -rw-r--r-- | tests/Makefile.am | 2 | ||||
| -rw-r--r-- | tests/t-encrypt.c | 28 | ||||
| -rw-r--r-- | tests/t-verify.c | 85 | 
14 files changed, 645 insertions, 57 deletions
| diff --git a/gpgme/Makefile.am b/gpgme/Makefile.am index 87de1de1..b47169cb 100644 --- a/gpgme/Makefile.am +++ b/gpgme/Makefile.am @@ -18,6 +18,7 @@ libgpgme_la_SOURCES = \  	data.c recipient.c \          wait.c wait.h \  	encrypt.c \ +	verify.c \          rungpg.c rungpg.h status-table.h \  	gpgme.c errors.c diff --git a/gpgme/context.h b/gpgme/context.h index 504ec89c..c45d1bf6 100644 --- a/gpgme/context.h +++ b/gpgme/context.h @@ -25,16 +25,34 @@  #include "types.h"  #include "rungpg.h"  /* for GpgObject */ +typedef enum { +    RESULT_TYPE_NONE = 0, +    RESULT_TYPE_VERIFY, +} ResultType; + +  /* Currently we need it at several places, so we put the definition    * into this header file */  struct gpgme_context_s {      int initialized;      int pending;   /* a gpg request is still pending */ -     + +    /* at some points we need to allocate memory but we are not +     * able to handle a malloc problem at that point, so we set this +     * flag to indicate this condition */ +    int out_of_core;    +      GpgObject gpg; /* the running gpg process */      int verbosity;  /* level of verbosity to use */      int use_armor;  /* use armoring */ + +     + +    ResultType result_type; +    union { +        VerifyResult verify; +    } result;  }; @@ -44,6 +62,8 @@ struct gpgme_data_s {      GpgmeDataType type;      GpgmeDataMode mode;      size_t readpos; +    size_t writepos; +    size_t private_len;      char *private_buffer;  }; diff --git a/gpgme/data.c b/gpgme/data.c index 253e1011..8499069b 100644 --- a/gpgme/data.c +++ b/gpgme/data.c @@ -27,6 +27,9 @@  #include "context.h" +#define ALLOC_CHUNK 1024 + +  /**   * gpgme_new_data:   * @r_dh:   Returns a new data object. @@ -59,8 +62,10 @@ gpgme_new_data ( GpgmeData *r_dh, const char *buffer, size_t size, int copy )                  xfree (dh);                  return mk_error (Out_Of_Core);              } +            dh->private_len = size;              memcpy (dh->private_buffer, buffer, size );              dh->data = dh->private_buffer; +            dh->writepos = size;          }          else {              dh->data = buffer; @@ -113,24 +118,95 @@ _gpgme_query_data_mode ( GpgmeData dh )      return dh->mode;  } +GpgmeError +gpgme_rewind_data ( GpgmeData dh ) +{ +    if ( !dh ) +        return mk_error (Invalid_Value); +    /* Fixme: We should check whether rewinding does make sense for the +     * data type */ +    dh->readpos = 0; +    return 0; +} + +GpgmeError +gpgme_read_data ( GpgmeData dh, char *buffer, size_t length, size_t *nread ) +{ +    size_t nbytes; + +    if ( !dh ) +        return mk_error (Invalid_Value); +    nbytes = dh->len - dh->readpos; +    if ( !nbytes ) { +        *nread = 0; +        return mk_error(EOF); +    } +    if (nbytes > length) +        nbytes = length; +    memcpy ( buffer, dh->data + dh->readpos, nbytes ); +    *nread = nbytes; +    dh->readpos += nbytes; +    return 0; +}   GpgmeError -_gpgme_append_data ( GpgmeData dh, const char *buf, size_t length ) +_gpgme_append_data ( GpgmeData dh, const char *buffer, size_t length )  {      assert (dh);      if ( dh->type == GPGME_DATA_TYPE_NONE ) {          /* convert it to a mem data type */ +        assert (!dh->private_buffer); +        dh->type = GPGME_DATA_TYPE_MEM; +        dh->private_len = length < ALLOC_CHUNK? ALLOC_CHUNK : length; +        dh->private_buffer = xtrymalloc ( dh->private_len ); +        if (!dh->private_buffer) { +            dh->private_len = 0; +            return mk_error (Out_Of_Core); +        } +        dh->writepos = 0; +        dh->data = dh->private_buffer;      } -    else if ( dh->type != GPGME_DATA_TYPE_MEM ) { +    else if ( dh->type != GPGME_DATA_TYPE_MEM )           return mk_error (Invalid_Type); -    } - +          if ( dh->mode != GPGME_DATA_MODE_INOUT            && dh->mode != GPGME_DATA_MODE_IN  )          return mk_error (Invalid_Mode); +    if ( !dh->private_buffer ) { +        /* we have to copy it now */ +        assert (dh->data); +        dh->private_len = dh->len+length; +        if (dh->private_len < ALLOC_CHUNK) +            dh->private_len = ALLOC_CHUNK; +        dh->private_buffer = xtrymalloc ( dh->private_len ); +        if (!dh->private_buffer) { +            dh->private_len = 0; +            return mk_error (Out_Of_Core); +        } +        dh->writepos = 0; +        dh->data = dh->private_buffer; +    } + +    /* allocate more memory if needed */ +    if ( dh->writepos + length > dh->private_len ) { +        char *p; +        size_t newlen = dh->private_len +                        + (dh->len < ALLOC_CHUNK? ALLOC_CHUNK : length); +        p = xtryrealloc ( dh->private_buffer, newlen ); +        if ( !p )  +            return mk_error (Out_Of_Core); +        dh->private_buffer = p; +        dh->private_len = newlen; +        dh->data = dh->private_buffer; +        assert ( !(dh->writepos + length > dh->private_len) );       +    } + +    memcpy ( dh->private_buffer + dh->writepos, buffer, length ); +    dh->writepos += length; +    dh->len += length;      return 0;  } diff --git a/gpgme/encrypt.c b/gpgme/encrypt.c index eaf57429..501e65fd 100644 --- a/gpgme/encrypt.c +++ b/gpgme/encrypt.c @@ -39,7 +39,7 @@ encrypt_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args )  GpgmeError -gpgme_req_encrypt ( GpgmeCtx c, GpgmeRecipientSet recp, +gpgme_start_encrypt ( GpgmeCtx c, GpgmeRecipientSet recp,                      GpgmeData plain, GpgmeData ciph )  {      int rc = 0; @@ -87,7 +87,7 @@ gpgme_req_encrypt ( GpgmeCtx c, GpgmeRecipientSet recp,      _gpgme_gpg_add_arg ( c->gpg, "--output" );      _gpgme_gpg_add_arg ( c->gpg, "-" );      _gpgme_gpg_add_data ( c->gpg, ciph, 1 ); - +    _gpgme_gpg_add_arg ( c->gpg, "--" );      _gpgme_gpg_add_data ( c->gpg, plain, 0 );      /* and kick off the process */ @@ -102,18 +102,6 @@ gpgme_req_encrypt ( GpgmeCtx c, GpgmeRecipientSet recp,  } -GpgmeError -gpgme_wait_encrypt ( GpgmeCtx c, GpgmeData *r_out ) -{ -    wait_on_request_or_fail (c); - -    fprintf (stderr,"gpgme_wait_encrypt: main\n"); - -     -    return 0; -} - -  /**   * gpgme_encrypt:   * @c: The context @@ -131,9 +119,11 @@ GpgmeError  gpgme_encrypt ( GpgmeCtx c, GpgmeRecipientSet recp,                  GpgmeData in, GpgmeData out )  { -    int rc = gpgme_req_encrypt ( c, recp, in, out ); -    if ( !rc )  -        rc = gpgme_wait_encrypt ( c, NULL ); +    int rc = gpgme_start_encrypt ( c, recp, in, out ); +    if ( !rc ) { +        gpgme_wait (c, 1); +        c->pending = 0; +    }      return rc;  } diff --git a/gpgme/gpgme.c b/gpgme/gpgme.c index fd55c4b6..10df5080 100644 --- a/gpgme/gpgme.c +++ b/gpgme/gpgme.c @@ -24,7 +24,7 @@  #include "util.h"  #include "context.h" - +#include "ops.h"  /**   * gpgme_new_context: @@ -58,14 +58,26 @@ gpgme_new_context (GpgmeCtx *r_ctx)  void  gpgme_release_context ( GpgmeCtx c )  { +     +    _gpgme_gpg_release_object ( c->gpg );  +    _gpgme_release_result ( c );      xfree ( c );  } - - - - +void +_gpgme_release_result ( GpgmeCtx c ) +{ +    switch (c->result_type) { +      case RESULT_TYPE_NONE: +        break; +      case RESULT_TYPE_VERIFY: +        _gpgme_release_verify_result ( c->result.verify ); +        break; +    } +    c->result.verify = NULL; +    c->result_type = RESULT_TYPE_NONE; +} diff --git a/gpgme/gpgme.h b/gpgme/gpgme.h index f5ede58b..88a84348 100644 --- a/gpgme/gpgme.h +++ b/gpgme/gpgme.h @@ -38,6 +38,7 @@ typedef struct gpgme_recipient_set_s *GpgmeRecipientSet;  typedef enum { +    GPGME_EOF = -1,      GPGME_No_Error = 0,      GPGME_General_Error = 1,      GPGME_Out_Of_Core = 2, @@ -81,12 +82,16 @@ GpgmeError gpgme_new_data ( GpgmeData *r_dh,                                  const char *buffer, size_t size, int copy );  void gpgme_release_data ( GpgmeData dh );  GpgmeDataType gpgme_query_data_type ( GpgmeData dh ); +GpgmeError gpgme_rewind_data ( GpgmeData dh ); +GpgmeError gpgme_read_data ( GpgmeData dh, +                             char *buffer, size_t length, size_t *nread ); +  /* Basic GnuPG functions */ -GpgmeError gpgme_req_encrypt ( GpgmeCtx c, GpgmeRecipientSet recp, -                               GpgmeData in, GpgmeData out ); -GpgmeError gpgme_wait_encrypt ( GpgmeCtx c, GpgmeData *r_out ); +GpgmeError gpgme_start_encrypt ( GpgmeCtx c, GpgmeRecipientSet recp, +                                 GpgmeData in, GpgmeData out ); +GpgmeError gpgme_start_verify ( GpgmeCtx c,  GpgmeData sig, GpgmeData text );  /* Key management functions */ @@ -99,6 +104,7 @@ GpgmeError gpgme_wait_encrypt ( GpgmeCtx c, GpgmeData *r_out );  /* Convenience functions for syncronous usage */  GpgmeError gpgme_encrypt ( GpgmeCtx c, GpgmeRecipientSet recp,                             GpgmeData in, GpgmeData out ); +GpgmeError gpgme_verify ( GpgmeCtx c, GpgmeData sig, GpgmeData text );  /* miscellaneous functions */ diff --git a/gpgme/ops.h b/gpgme/ops.h index ca361ca5..59efeffc 100644 --- a/gpgme/ops.h +++ b/gpgme/ops.h @@ -23,6 +23,9 @@  #include "types.h" +/*-- gpgme.c --*/ +void _gpgme_release_result ( GpgmeCtx c ); +  /*-- recipient.c --*/  void _gpgme_append_gpg_args_from_recipients ( @@ -33,8 +36,11 @@ void _gpgme_append_gpg_args_from_recipients (  /*-- data.c --*/  GpgmeDataMode _gpgme_query_data_mode ( GpgmeData dh );  void          _gpgme_set_data_mode ( GpgmeData dh, GpgmeDataMode mode ); +GpgmeError    _gpgme_append_data ( GpgmeData dh, +                                   const char *buffer, size_t length ); - +/*-- verify.c --*/ +void _gpgme_release_verify_result ( VerifyResult res );  #endif /* OPS_H */ diff --git a/gpgme/rungpg.c b/gpgme/rungpg.c index 6353ad27..ac6ba114 100644 --- a/gpgme/rungpg.c +++ b/gpgme/rungpg.c @@ -29,6 +29,7 @@  #include <unistd.h>  #include <sys/wait.h>  #include <signal.h> +#include <fcntl.h>  #include "gpgme.h"  #include "util.h" @@ -84,6 +85,7 @@ struct gpg_object_s {  static void kill_gpg ( GpgObject gpg );  static void free_argv ( char **argv ); +static void free_fd_data_map ( struct fd_data_map_s *fd_data_map );  static int gpg_status_handler ( void *opaque, pid_t pid, int fd );  static int gpg_inbound_handler ( void *opaque, pid_t pid, int fd );  static int gpg_outbound_handler ( void *opaque, pid_t pid, int fd ); @@ -96,7 +98,6 @@ GpgmeError  _gpgme_gpg_new_object ( GpgObject *r_gpg )  {      GpgObject gpg; -    char buf[20];      int rc = 0;      gpg = xtrycalloc ( 1, sizeof *gpg ); @@ -109,9 +110,6 @@ _gpgme_gpg_new_object ( GpgObject *r_gpg )      gpg->status.fd[0] = -1;      gpg->status.fd[1] = -1; -    /* The name of the beast will be gpg - so put it into argv[0] */ -    _gpgme_gpg_add_arg ( gpg, "gpg" ); -      /* allocate the read buffer for the status pipe */      gpg->status.bufsize = 1024;      gpg->status.readpos = 0; @@ -128,8 +126,13 @@ _gpgme_gpg_new_object ( GpgObject *r_gpg )      }      gpg->status.eof = 0;      _gpgme_gpg_add_arg ( gpg, "--status-fd" ); -    sprintf ( buf, "%d", gpg->status.fd[1]); -    _gpgme_gpg_add_arg ( gpg, buf ); +    { +        char buf[25]; +        sprintf ( buf, "%d", gpg->status.fd[1]); +        _gpgme_gpg_add_arg ( gpg, buf ); +    } +    _gpgme_gpg_add_arg ( gpg, "--batch" ); +    _gpgme_gpg_add_arg ( gpg, "--no-tty" );   leave:      if (rc) { @@ -153,8 +156,7 @@ _gpgme_gpg_release_object ( GpgObject gpg )          close (gpg->status.fd[0]);      if (gpg->status.fd[1] != -1 )          close (gpg->status.fd[1]); -    /* fixme: walk over the data map and close all fds */ -    xfree (gpg->fd_data_map); +    free_fd_data_map (gpg->fd_data_map);      kill_gpg (gpg); /* fixme: should be done asyncronously */      xfree (gpg);  } @@ -162,6 +164,7 @@ _gpgme_gpg_release_object ( GpgObject gpg )  static void  kill_gpg ( GpgObject gpg )  { +  #if 0      if ( gpg->running ) {          /* still running? Must send a killer */          kill ( gpg->pid, SIGTERM); @@ -172,6 +175,7 @@ kill_gpg ( GpgObject gpg )          }          gpg->running = 0;      } +  #endif  } @@ -238,6 +242,21 @@ free_argv ( char **argv )      xfree (argv);  } +static void +free_fd_data_map ( struct fd_data_map_s *fd_data_map ) +{ +    int i; + +    for (i=0; fd_data_map[i].data; i++ ) { +        if ( fd_data_map[i].fd != -1 ) +            close (fd_data_map[i].fd); +        if ( fd_data_map[i].peer_fd != -1 ) +            close (fd_data_map[i].peer_fd); +        /* don't realease data because this is only a reference */ +    } +    xfree (fd_data_map); +} +  static GpgmeError  build_argv ( GpgObject gpg ) @@ -246,22 +265,32 @@ build_argv ( GpgObject gpg )      struct fd_data_map_s *fd_data_map;      size_t datac=0, argc=0;        char **argv; +    int need_special = 0;      if ( gpg->argv ) {          free_argv ( gpg->argv );          gpg->argv = NULL;      } -    /* fixme: release fd_data_map */ +    if (gpg->fd_data_map) { +        free_fd_data_map (gpg->fd_data_map); +        gpg->fd_data_map = NULL; +    } +    argc++; /* for argv[0] */      for ( a=gpg->arglist; a; a = a->next ) {          argc++;          if (a->data) { -            fprintf (stderr, "build_argv: data\n" ); +            /*fprintf (stderr, "build_argv: data\n" );*/              datac++; +            if ( a->dup_to == -1 ) +                need_special = 1; +        } +        else { +            /*   fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/          } -        else -            fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );      } +    if ( need_special ) +        argc++;      argv = xtrycalloc ( argc+1, sizeof *argv );      if (!argv) @@ -273,6 +302,22 @@ build_argv ( GpgObject gpg )      }      argc = datac = 0; +    argv[argc] = xtrystrdup ( "gpg" ); /* argv[0] */ +    if (!argv[argc]) { +        xfree (fd_data_map); +        free_argv (argv); +        return mk_error (Out_Of_Core); +    } +    argc++; +    if ( need_special ) { +        argv[argc] = xtrystrdup ( "--enable-special-filenames" ); +        if (!argv[argc]) { +            xfree (fd_data_map); +            free_argv (argv); +            return mk_error (Out_Of_Core); +        } +        argc++; +    }      for ( a=gpg->arglist; a; a = a->next ) {          if ( a->data ) {              switch ( _gpgme_query_data_mode (a->data) ) { @@ -328,6 +373,16 @@ build_argv ( GpgObject gpg )              }              fd_data_map[datac].data = a->data;              fd_data_map[datac].dup_to = a->dup_to; +            if ( a->dup_to == -1 ) { +                argv[argc] = xtrymalloc ( 25 ); +                if (!argv[argc]) { +                    xfree (fd_data_map); +                    free_argv (argv); +                    return mk_error (Out_Of_Core); +                } +                sprintf ( argv[argc], "-&%d", fd_data_map[datac].peer_fd ); +                argc++; +            }              datac++;          }          else { @@ -337,8 +392,8 @@ build_argv ( GpgObject gpg )                  free_argv (argv);                  return mk_error (Out_Of_Core);              } +            argc++;          } -        argc++;      }      gpg->argv = argv; @@ -372,6 +427,11 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque )      }      if ( !pid ) { /* child */ +        int duped_stdin = 0; +        int duped_stderr = 0; + +        close (gpg->status.fd[0]); +                      for (i=0; gpg->fd_data_map[i].data; i++ ) {              close (gpg->fd_data_map[i].fd);              gpg->fd_data_map[i].fd = -1; @@ -382,20 +442,49 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque )                               strerror (errno));                      _exit (8);                  } +                if ( gpg->fd_data_map[i].dup_to == 0 ) +                    duped_stdin=1; +                if ( gpg->fd_data_map[i].dup_to == 2 ) +                    duped_stderr=1;                  close ( gpg->fd_data_map[i].peer_fd );              }          } -         -        if ( gpg->status.fd[0] != -1 ) -            close (gpg->status.fd[0]); -        /* FIXME: dup /dev/null to stdin if nothing is connected to stdin */ -        execv ("/usr/local/bin/gpg", gpg->argv ); -        fprintf (stderr,"exec of gpg failed\n"); fflush (stderr); +        if( !duped_stdin || !duped_stderr ) { +            int fd = open ( "/dev/null", O_RDONLY ); +            if ( fd == -1 ) { +                fprintf (stderr,"can't open `/dev/null': %s\n", +                         strerror (errno) ); +                _exit (8); +            } +            /* Make sure that gpg has a connected stdin */ +            if ( !duped_stdin ) { +                if ( dup2 ( fd, 0 ) == -1 ) { +                    fprintf (stderr,"dup2(/dev/null, 0) failed: %s\n", +                             strerror (errno) ); +                    _exit (8); +                } +            } +            /* We normally don't want all the normal output */ +            if ( !duped_stderr ) { +                if ( dup2 ( fd, 2 ) == -1 ) { +                    fprintf (stderr,"dup2(dev/null, 2) failed: %s\n", +                             strerror (errno) ); +                    _exit (8); +                } +            } +            close (fd); +        } + +        execv ("./gpg", gpg->argv ); +        fprintf (stderr,"exec of gpg failed\n");          _exit (8);      } +    /* parent */      gpg->pid = pid; +    /*_gpgme_register_term_handler ( closure, closure_value, pid );*/ +      if ( gpg->status.fd[1] != -1 )          close (gpg->status.fd[1]);      if ( _gpgme_register_pipe_handler ( opaque, gpg_status_handler, @@ -424,7 +513,6 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque )      gpg->running = 1;      return 0; -  } @@ -432,6 +520,7 @@ static int  gpg_inbound_handler ( void *opaque, pid_t pid, int fd )  {      GpgmeData dh = opaque; +    GpgmeError err;      int nread;      char buf[200]; @@ -448,7 +537,19 @@ gpg_inbound_handler ( void *opaque, pid_t pid, int fd )      }      else if (!nread)          return 1; /* eof */ + +    /* We could improve this with a GpgmeData function which takes +     * the read function or provides a memory area for writing to it. +     */ +    err = _gpgme_append_data ( dh, buf, nread ); +    if ( err ) { +        fprintf (stderr, "_gpgme_append_data failed: %s\n", +                 gpgme_strerror(err)); +        /* Fixme: we should close the pipe or read it to /dev/null in +         * this case. Returnin EOF is not sufficient */ +        return 1; +    }      return 0;  } @@ -520,8 +621,11 @@ gpg_status_handler ( void *opaque, pid_t pid, int fd )  static int -status_cmp (const struct status_table_s *a, const struct status_table_s *b) +status_cmp (const void *ap, const void *bp)  { +    const struct status_table_s *a = ap; +    const struct status_table_s *b = bp; +      return strcmp (a->name, b->name);  } diff --git a/gpgme/types.h b/gpgme/types.h index c8b23023..82f6b79d 100644 --- a/gpgme/types.h +++ b/gpgme/types.h @@ -43,6 +43,11 @@ struct gpg_object_s;  typedef struct gpg_object_s *GpgObject; +/*-- verify.c --*/ +struct verify_result_s; +typedef struct verify_result_s *VerifyResult; + +  #endif /* TYPES_H */ diff --git a/gpgme/verify.c b/gpgme/verify.c new file mode 100644 index 00000000..e9844787 --- /dev/null +++ b/gpgme/verify.c @@ -0,0 +1,198 @@ +/* verify.c -  signature verification + *	Copyright (C) 2000 Werner Koch (dd9jn) + * + * This file is part of GPGME. + * + * GPGME is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GPGME is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "util.h" +#include "context.h" +#include "ops.h" + +typedef enum { +    VERIFY_STATUS_NONE = 0, +    VERIFY_STATUS_NOSIG, +    VERIFY_STATUS_NOKEY, +    VERIFY_STATUS_ERROR, +    VERIFY_STATUS_BAD, +    VERIFY_STATUS_GOOD +} VerifyStatus; + +struct verify_result_s { +    VerifyStatus status; + +}; + + +void +_gpgme_release_verify_result ( VerifyResult res ) +{ +    xfree (res); +} + + +static void +verify_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args ) +{ +    if ( ctx->out_of_core ) +        return; +    if ( ctx->result_type == RESULT_TYPE_NONE ) { +        assert ( !ctx->result.verify ); +        ctx->result.verify = xtrycalloc ( 1, sizeof *ctx->result.verify ); +        if ( !ctx->result.verify ) { +            ctx->out_of_core = 1; +            return; +        } +        ctx->result_type = RESULT_TYPE_VERIFY; +    } +    assert ( ctx->result_type == RESULT_TYPE_VERIFY ); + +    /* FIXME: For now we handle only one signature */ +    /* FIXME: Collect useful information */ +    switch (code) { +      case STATUS_GOODSIG: +        ctx->result.verify->status = VERIFY_STATUS_GOOD; +        break; +      case STATUS_BADSIG: +        ctx->result.verify->status = VERIFY_STATUS_BAD; +        break; +      case STATUS_ERRSIG: +        ctx->result.verify->status = VERIFY_STATUS_ERROR; +        /* FIXME: distinguish between a regular error and a missing key. +         * this is encoded in the args. */ +        break; +      default: +        /* ignore all other codes */ +        fprintf (stderr, "verify_status: code=%d not handled\n", code ); +        break; +    } +} + + + +GpgmeError +gpgme_start_verify ( GpgmeCtx c,  GpgmeData sig, GpgmeData text ) +{ +    int rc = 0; +    int i; + +    fail_on_pending_request( c ); +    c->pending = 1; + +    _gpgme_release_result (c); +    c->out_of_core = 0; + +    /* create a process object. +     * To optimize this, we should reuse an existing one and +     * run gpg in the new --pipemode (I started with this but it is +     * not yet finished) */ +    if ( c->gpg ) { +        _gpgme_gpg_release_object ( c->gpg );  +        c->gpg = NULL; +    } +    rc = _gpgme_gpg_new_object ( &c->gpg ); +    if (rc) +        goto leave; + +    _gpgme_gpg_set_status_handler ( c->gpg, verify_status_handler, c ); + +    /* build the commandline */ +    _gpgme_gpg_add_arg ( c->gpg, "--verify" ); +    for ( i=0; i < c->verbosity; i++ ) +        _gpgme_gpg_add_arg ( c->gpg, "--verbose" ); +     + +    /* Check the supplied data */ +    if ( gpgme_query_data_type (sig) == GPGME_DATA_TYPE_NONE ) { +        rc = mk_error (No_Data); +        goto leave; +    } +    if ( text && gpgme_query_data_type (text) == GPGME_DATA_TYPE_NONE ) { +        rc = mk_error (No_Data); +        goto leave; +    } +    _gpgme_set_data_mode (sig, GPGME_DATA_MODE_OUT ); +    if (text) /* detached signature */ +        _gpgme_set_data_mode (text, GPGME_DATA_MODE_OUT ); +    /* Tell the gpg object about the data */ +    _gpgme_gpg_add_arg ( c->gpg, "--" ); +    _gpgme_gpg_add_data ( c->gpg, sig, -1 ); +    if (text) +        _gpgme_gpg_add_data ( c->gpg, text, 0 ); + +    /* and kick off the process */ +    rc = _gpgme_gpg_spawn ( c->gpg, c ); + + leave: +    if (rc) { +        c->pending = 0;  +        _gpgme_gpg_release_object ( c->gpg ); c->gpg = NULL; +    } +    return rc; +} + + + +GpgmeError +gpgme_verify ( GpgmeCtx c, GpgmeData sig, GpgmeData text ) +{ +    int rc = gpgme_start_verify ( c, sig, text ); +    if ( !rc ) { +        gpgme_wait (c, 1); +        if ( c->result_type != RESULT_TYPE_VERIFY ) +            rc = mk_error (General_Error); +        else if ( c->out_of_core ) +            rc = mk_error (Out_Of_Core); +        else { +            assert ( c->result.verify ); +            switch ( c->result.verify->status ) { +              case VERIFY_STATUS_NONE: +                fputs ("Verification Status: None\n", stdout); +                break; +              case VERIFY_STATUS_NOSIG: +                fputs ("Verification Status: No Signature\n", stdout); +                break; +              case VERIFY_STATUS_GOOD: +                fputs ("Verification Status: Good\n", stdout); +                break; +              case VERIFY_STATUS_BAD: +                fputs ("Verification Status: Bad\n", stdout); +                break; +              case VERIFY_STATUS_NOKEY: +                fputs ("Verification Status: No Key\n", stdout); +                break; +              case VERIFY_STATUS_ERROR: +                fputs ("Verification Status: Error\n", stdout); +                break; +            } +        } +        c->pending = 0; +    } +    return rc; +} + + + + + + + diff --git a/gpgme/wait.c b/gpgme/wait.c index f8cadc00..a84c7465 100644 --- a/gpgme/wait.c +++ b/gpgme/wait.c @@ -98,6 +98,53 @@ queue_item_from_context ( GpgmeCtx ctx )  } +static void +propagate_term_results ( const struct wait_queue_item_s *first_q ) +{ +    struct wait_queue_item_s *q; +     +    for (q=wait_queue; q; q = q->next) { +        if ( q->used && q != first_q && !q->exited +             && q->pid == first_q->pid  ) { +            q->exited = first_q->exited; +            q->exit_status = first_q->exit_status; +            q->exit_signal = first_q->exit_signal; +        } +    } +} + +static int +count_active_fds ( pid_t pid ) +{ +    struct wait_queue_item_s *q; +    int count = 0; +     +    for (q=wait_queue; q; q = q->next) { +        if ( q->used && q->active && q->pid == pid  )  +            count++; +    } +    return count; +} + + +/* remove the given process from the queue */ +static void +remove_process ( pid_t pid ) +{ +    struct wait_queue_item_s *q; +     +    for (q=wait_queue; q; q = q->next) { +        if ( q->used ) { +            close (q->fd); +            q->handler = NULL; +            q->ctx = NULL; +            q->used = 0; +        } +    } +} + + +  /**   * gpgme_wait:   * @c:  @@ -127,7 +174,9 @@ gpgme_wait ( GpgmeCtx c, int hang )              q = queue_item_from_context ( c );              assert (q); -            if ( waitpid ( q->pid, &status, WNOHANG ) == q->pid ) { +            if (q->exited) +                ; +            else if ( waitpid ( q->pid, &status, WNOHANG ) == q->pid ) {                  q->exited = 1;                       if ( WIFSIGNALED (status) ) {                      q->exit_status = 4; /* Need some value here */ @@ -140,8 +189,18 @@ gpgme_wait ( GpgmeCtx c, int hang )                      q->exited++;                      q->exit_status = 4;                  } -                /* okay, the process has terminated - we are ready */ -                hang = 0; +                propagate_term_results (q); +            } + +            if ( q->exited ) { +                if ( !count_active_fds (q->pid) ) { +                    /* Hmmm, as long as we don't have a callback for +                     * the exit status, we have no use for these +                     * values and therefore we can remove this from +                     * the queue */ +                    remove_process (q->pid); +                    hang = 0; +                }              }          }      } while (hang); diff --git a/tests/Makefile.am b/tests/Makefile.am index eab4df3c..aced4007 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,6 +1,6 @@  ## Process this file with automake to create Makefile.in -TESTS = t-encrypt  +TESTS = t-encrypt t-verify  INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl diff --git a/tests/t-encrypt.c b/tests/t-encrypt.c index 8f6e5c5d..d99beff0 100644 --- a/tests/t-encrypt.c +++ b/tests/t-encrypt.c @@ -31,6 +31,23 @@                                  exit (1); }                               \                               } while(0) +static void +print_data ( GpgmeData dh ) +{ +    char buf[100]; +    size_t nread; +    GpgmeError err; + +    err = gpgme_rewind_data ( dh ); +    fail_if_err (err); +    while ( !(err = gpgme_read_data ( dh, buf, 100, &nread )) ) { +        fwrite ( buf, nread, 1, stdout ); +    } +    if (err != GPGME_EOF)  +        fail_if_err (err); +} + +  int   main (int argc, char **argv ) @@ -40,10 +57,11 @@ main (int argc, char **argv )      GpgmeData in, out;      GpgmeRecipientSet rset; +  do {      err = gpgme_new_context (&ctx);      fail_if_err (err); -    err = gpgme_new_data ( &in, "Hallo Leute", 11, 0 ); +    err = gpgme_new_data ( &in, "Hallo Leute\n", 12, 0 );      fail_if_err (err);      err = gpgme_new_data ( &out, NULL, 0,0 ); @@ -53,16 +71,24 @@ main (int argc, char **argv )      fail_if_err (err);      err = gpgme_add_recipient (rset, "Bob");      fail_if_err (err); +    err = gpgme_add_recipient (rset, "Alpha"); +    fail_if_err (err);      err = gpgme_encrypt (ctx, rset, in, out );      fail_if_err (err); +    fflush (NULL); +    fputs ("Begin Result:\n", stdout ); +    print_data (out); +    fputs ("End Result.\n", stdout );      gpgme_release_recipient_set (rset);      gpgme_release_data (in);      gpgme_release_data (out);      gpgme_release_context (ctx); +  } while ( argc > 1 && !strcmp( argv[1], "--loop" ) ); +         return 0;  } diff --git a/tests/t-verify.c b/tests/t-verify.c new file mode 100644 index 00000000..3a948afd --- /dev/null +++ b/tests/t-verify.c @@ -0,0 +1,85 @@ +/* t-verify.c  - regression test + *	Copyright (C) 2000 Werner Koch (dd9jn) + * + * This file is part of GPGME. + * + * GPGME is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GPGME is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "../gpgme/gpgme.h" + +static const char test_text1[] = "Just GNU it!\n"; +static const char test_text1f[]= "Just GNU it?\n"; +static const char test_sig1[] = +"-----BEGIN PGP SIGNATURE-----\n" +"\n" +"iEYEABECAAYFAjoKgjIACgkQLXJ8x2hpdzQMSwCeO/xUrhysZ7zJKPf/FyXA//u1\n" +"ZgIAn0204PBR7yxSdQx6CFxugstNqmRv\n" +"=yku6\n" +"-----END PGP SIGNATURE-----\n" +; + + +#define fail_if_err(a) do { if(a) {                                       \ +                               fprintf (stderr, "%s:%d: GpgmeError %s\n", \ +                                __FILE__, __LINE__, gpgme_strerror(a));   \ +                                exit (1); }                               \ +                             } while(0) + + +int  +main (int argc, char **argv ) +{ +    GpgmeCtx ctx; +    GpgmeError err; +    GpgmeData sig, text; + +    err = gpgme_new_context (&ctx); +    fail_if_err (err); + +  do { +    err = gpgme_new_data ( &text, test_text1, strlen (test_text1), 0 ); +    fail_if_err (err); +    err = gpgme_new_data ( &sig, test_sig1, strlen (test_sig1), 0 ); +    fail_if_err (err); + +    puts ("checking a valid message:\n"); +    err = gpgme_verify (ctx, sig, text ); +    fail_if_err (err); + +    puts ("checking a manipulated message:\n"); +    gpgme_release_data (text); +    err = gpgme_new_data ( &text, test_text1f, strlen (test_text1f), 0 ); +    fail_if_err (err); +    gpgme_rewind_data ( sig ); +    err = gpgme_verify (ctx, sig, text ); +    fail_if_err (err); + +    gpgme_release_data (sig); +    gpgme_release_data (text); +  +} while ( argc > 1 && !strcmp( argv[1], "--loop" ) ); +      gpgme_release_context (ctx); +     +    return 0; +} + + + | 
