From 7c708298d2829b4adf4128be143ada91764ca26e Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 7 Nov 2001 17:44:22 +0000 Subject: [PATCH] Implemented server main loop and started with import command. --- sm/Makefile.am | 11 ++- sm/gpgsm.c | 2 +- sm/gpgsm.h | 16 ++++ sm/import.c | 213 +++++++++++++++++++++++++++++++++++++++++++++++++ sm/misc.c | 41 ++++++++++ sm/mkerrors | 72 +++++++++++++++++ sm/server.c | 182 ++++++++++++++++++++++++++++++++++++++++++ sm/util.h | 4 + 8 files changed, 537 insertions(+), 4 deletions(-) create mode 100644 sm/import.c create mode 100644 sm/misc.c create mode 100755 sm/mkerrors diff --git a/sm/Makefile.am b/sm/Makefile.am index 82a5e483a..47de0a8e3 100644 --- a/sm/Makefile.am +++ b/sm/Makefile.am @@ -22,12 +22,17 @@ bin_PROGRAMS = gpgsm INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl LDFLAGS = @LDFLAGS@ $(LIBGCRYPT_LIBS) +BUILT_SOURCES = errors.c gpgsm_SOURCES = \ gpgsm.c gpgsm.h \ - util.h \ - server.c + util.h misc.c errors.c \ + server.c \ + import.c -gpgsm_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a +gpgsm_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a \ + ../../libksba/src/.libs/libksba.a +errors.c : gpgsm.h mkerrors + $(srcdir)/mkerrors < $(srcdir)/gpgsm.h > errors.c diff --git a/sm/gpgsm.c b/sm/gpgsm.c index 8b715f40a..972ce080c 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -477,7 +477,7 @@ main ( int argc, char **argv) int orig_argc; char **orig_argv; const char *fname; - char *username; + /* char *username;*/ int may_coredump; STRLIST sl, remusr= NULL, locusr=NULL; STRLIST nrings=NULL; diff --git a/sm/gpgsm.h b/sm/gpgsm.h index ac169336a..1c66e1032 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -23,6 +23,19 @@ #include "util.h" +/* Error numbers */ +enum { + GPGSM_EOF = -1, + GPGSM_No_Error = 0, + GPGSM_General_Error = 1, + GPGSM_Out_Of_Core = 2, + GPGSM_Invalid_Value = 3, + GPGSM_IO_Error = 4, + + +}; + + /* A large struct name "opt" to keep global flags */ struct { unsigned int debug; /* debug flags (DBG_foo_VALUE) */ @@ -83,4 +96,7 @@ void gpgsm_exit (int rc); void gpgsm_server (void); +/*-- import.c --*/ +int gpgsm_import (int in_fd); + #endif /*GPGSM_H*/ diff --git a/sm/import.c b/sm/import.c new file mode 100644 index 000000000..b3827e222 --- /dev/null +++ b/sm/import.c @@ -0,0 +1,213 @@ +/* import.c - Import certificates + * Copyright (C) 2001 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG 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. + * + * GnuPG 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "gpgsm.h" + +struct reader_cb_parm_s { + FILE *fp; +}; + + +static int +reader_cb (void *cb_value, unsigned char *buffer, size_t count, size_t *nread) +{ + struct reader_cb_parm_s *parm = cb_value; + size_t n; + int c = 0; + + *nread = 0; + if (!buffer) + return -1; /* not supported */ + + for (n=0; n < count; n++) + { + c = getc (parm->fp); + if (c == EOF) + { + if ( ferror (parm->fp) ) + return -1; + if (n) + break; /* return what we have beofre an EOF */ + return -1; + } + *buffer++ = c; + } + + *nread = n; + return 0; +} + + +static void +print_integer (unsigned char *p) +{ + unsigned long len; + + if (!p) + fputs ("none", stdout); + else + { + len = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + for (p+=4; len; len--, p++) + printf ("%02X", *p); + } +} + +static void +print_time (time_t t) +{ + + if (!t) + fputs ("none", stdout); + else if ( t == (time_t)(-1) ) + fputs ("error", stdout); + else + { + struct tm *tp; + + tp = gmtime (&t); + printf ("%04d-%02d-%02d %02d:%02d:%02d", + 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday, + tp->tm_hour, tp->tm_min, tp->tm_sec); + assert (!tp->tm_isdst); + } +} + +static void +print_dn (char *p) +{ + + if (!p) + fputs ("error", stdout); + else + printf ("`%s'", p); +} + + + + +int +gpgsm_import (int in_fd) +{ + int rc; + KsbaReader reader = NULL; + KsbaCert cert = NULL; + struct reader_cb_parm_s rparm; + + memset (&rparm, 0, sizeof rparm); + + rparm.fp = fdopen ( dup (in_fd), "rb"); + if (!rparm.fp) + { + log_error ("fdopen() failed: %s\n", strerror (errno)); + rc = seterr (IO_Error); + goto leave; + } + + /* setup a skaba reader which uses a callback function so that we can + strip off a base64 encoding when necessary */ + reader = ksba_reader_new (); + if (!reader) + { + rc = seterr (Out_Of_Core); + goto leave; + } + + rc = ksba_reader_set_cb (reader, reader_cb, &rparm ); + if (rc) + { + ksba_reader_release (reader); + rc = map_ksba_err (rc); + goto leave; + } + + cert = ksba_cert_new (); + if (!cert) + { + rc = seterr (Out_Of_Core); + goto leave; + } + + rc = ksba_cert_read_der (cert, reader); + if (rc) + { + rc = map_ksba_err (rc); + goto leave; + } + + { + unsigned char *p; + char *dn; + time_t t; + + p = ksba_cert_get_serial (cert); + fputs ("serial: ", stdout); + print_integer (p); + ksba_free (p); + putchar ('\n'); + + t = ksba_cert_get_validity (cert, 0); + fputs ("notBefore: ", stdout); + print_time (t); + putchar ('\n'); + t = ksba_cert_get_validity (cert, 1); + fputs ("notAfter: ", stdout); + print_time (t); + putchar ('\n'); + + dn = ksba_cert_get_issuer (cert); + fputs ("issuer: ", stdout); + print_dn (dn); + ksba_free (dn); + putchar ('\n'); + + dn = ksba_cert_get_subject (cert); + fputs ("subject: ", stdout); + print_dn (dn); + ksba_free (dn); + putchar ('\n'); + + printf ("hash algo: %d\n", ksba_cert_get_digest_algo (cert)); + + ksba_cert_hash (cert, NULL, NULL); + } + + leave: + ksba_cert_release (cert); + ksba_reader_release (reader); + if (rparm.fp) + fclose (rparm.fp); + return rc; +} + + + + diff --git a/sm/misc.c b/sm/misc.c new file mode 100644 index 000000000..c1bc346d1 --- /dev/null +++ b/sm/misc.c @@ -0,0 +1,41 @@ +/* misc.c - Miscellaneous fucntions + * Copyright (C) 2001 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG 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. + * + * GnuPG 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 +#include +#include +#include +#include +#include +#include + +#include + +#include "util.h" + + +/* Note: we might want to wrap this in a macro to get our hands on + the line and file wehre the error occired */ +int +map_ksba_err (int err) +{ + return -1; +} + diff --git a/sm/mkerrors b/sm/mkerrors new file mode 100755 index 000000000..46c28e8c9 --- /dev/null +++ b/sm/mkerrors @@ -0,0 +1,72 @@ +#!/bin/sh +# mkerrors - Extract error strings from gpgsm.h +# and create C source for gpgsm_strerror +# Copyright (C) 2001 Free Software Foundation, Inc. +# +# This file is part of GnuPG. +# +# GnuPG 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. +# +# GnuPG 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 + +cat < +#include +#include "gpgsm.h" + +/** + * gpgsm_strerror: + * @err: Error code + * + * This function returns a textual representaion of the given + * errorcode. If this is an unknown value, a string with the value + * is returned (Beware: it is hold in a static buffer). + * + * Return value: String with the error description. + **/ +const char * +gpgsm_strerror (int err) +{ + const char *s; + static char buf[25]; + + switch (err) + { +EOF + +awk ' +/GPGSM_No_Error/ { okay=1 } +!okay {next} +/}/ { exit 0 } +/GPGSM_[A-Za-z_]*/ { print_code($1) } + + +function print_code( s ) +{ +printf " case %s: s=\"", s ; +gsub(/_/, " ", s ); +printf "%s\"; break;\n", tolower(substr(s,7)); +} +' + +cat < + + Set the recipient for the encryption. should be the + internal representation of the key; the server may accept any other + way of specification [we will support this]. If this is a valid and + trusted recipient the server does respond with OK, otherwise the + return is an ERR with the reason why the recipient can't be used, + the encryption will then not be done for this recipient. IF the + policy is not to encrypt at all if not all recipients are valid, the + client has to take care of this. All RECIPIENT commands are + cumulative until a RESET or ENCRYPT command. */ +static int +cmd_recipient (ASSUAN_CONTEXT ctx, char *line) +{ + + + return set_error (Not_Implemented, "fixme"); +} + + +/* ENCRYPT [armor] + + Do the actual encryption process. Takes the plaintext from the INPUT + command, writes to the ciphertext to the file descriptor set with + the OUTPUT command, take the recipients form all the recipients set + so far. If this command fails the clients should try to delete all + output currently done or otherwise mark it as invalid. GPGSM does + ensure that there won't be any security problem with leftover data + on the output in this case. + + This command should in general not fail, as all necessary checks + have been done while setting the recipients. The input and output + pipes are closed. + + The optional armor parameter may be used to request base64 encoded + output. */ +static int +cmd_encrypt (ASSUAN_CONTEXT ctx, char *line) +{ + + + return set_error (Not_Implemented, "fixme"); +} + +/* DECRYPT + + This performs the decrypt operation after doing some check on the + internal state. (e.g. that only needed data has been set). Because + it utilises the GPG-Agent for the session key decryption, there is + no need to ask the client for a protecting passphrase - GpgAgent + does take care of this but requesting this from the user. */ +static int +cmd_decrypt (ASSUAN_CONTEXT ctx, char *line) +{ + + + return set_error (Not_Implemented, "fixme"); +} + + +/* VERIFY + + This does a verify operation on the message send to the input-FD. + The result is written out using status lines. If an output FD was + given, the signed text will be written to that. + + The behavior for detached signatures has not yet been specified. */ +static int +cmd_verify (ASSUAN_CONTEXT ctx, char *line) +{ + + + return set_error (Not_Implemented, "fixme"); +} + + +/* SIGN + + FIXME */ +static int +cmd_sign (ASSUAN_CONTEXT ctx, char *line) +{ + + + return set_error (Not_Implemented, "fixme"); +} + + +/* IMPORT + + Import the certificates read form the input-fd, return status + message for each imported one. The import checks the validity of + the certificate but not of the path. It is possible to import + expired certificates. */ +static int +cmd_import (ASSUAN_CONTEXT ctx, char *line) +{ + int fd = assuan_get_input_fd (ctx); + + if (fd == -1) + return set_error (No_Input, NULL); + + gpgsm_import (fd); + + return 0; +} + + + + +/* Tell the assuan library about our commands */ +static int +register_commands (ASSUAN_CONTEXT ctx) +{ + static struct { + const char *name; + int cmd_id; + int (*handler)(ASSUAN_CONTEXT, char *line); + } table[] = { + { "RECIPIENT", 0, cmd_recipient }, + { "ENCRYPT", 0, cmd_encrypt }, + { "DECRYPT", 0, cmd_decrypt }, + { "VERIFY", 0, cmd_verify }, + { "SIGN", 0, cmd_sign }, + { "IMPORT", 0, cmd_import }, + { "", ASSUAN_CMD_INPUT, NULL }, + { "", ASSUAN_CMD_OUTPUT, NULL }, + { NULL } + }; + int i, j, rc; + + for (i=j=0; table[i].name; i++) + { + rc = assuan_register_command (ctx, + table[i].cmd_id? table[i].cmd_id + : (ASSUAN_CMD_USER + j++), + table[i].name, table[i].handler); + if (rc) + return rc; + } + return 0; +} + +/* Startup the server */ void gpgsm_server (void) { @@ -50,7 +195,44 @@ gpgsm_server (void) assuan_strerror(rc)); gpgsm_exit (2); } + rc = register_commands (ctx); + if (rc) + { + log_error ("failed to the register commands with Assuan: %s\n", + assuan_strerror(rc)); + gpgsm_exit (2); + } + + log_info ("Assuan started\n"); + for (;;) + { + rc = assuan_accept (ctx); + if (rc == -1) + { + log_info ("Assuan terminated\n"); + break; + } + else if (rc) + { + log_info ("Assuan accept problem: %s\n", assuan_strerror (rc)); + break; + } + + rc = assuan_process (ctx); + if (rc) + { + log_info ("Assuan processing failed: %s\n", assuan_strerror (rc)); + continue; + } + } assuan_deinit_pipe_server (ctx); } + + + + + + + diff --git a/sm/util.h b/sm/util.h index d2ac4c18c..f3b4ab7b5 100644 --- a/sm/util.h +++ b/sm/util.h @@ -42,5 +42,9 @@ #define xstrdup(a) gcry_xstrdup ((a)) +#define seterr(a) (GPGSM_ ## a) + +/*-- misc.c --*/ +int map_ksba_err (int err); #endif /*UTIL_H*/