From a441158cc77391ba8857928f01fd20ac1569ad85 Mon Sep 17 00:00:00 2001 From: Marcus Brinkmann Date: Tue, 20 Nov 2001 05:27:46 +0000 Subject: [PATCH] 2001-11-20 Marcus Brinkmann * Makefile.am (SUBDIRS): Support building the assuan library (currently if GPGSM_PATH is set).. * configure.ac: Support building the assuan library. * assuan: New directory, populated with the Assuan library (copied from the newpg repository). gpgme/ 2001-11-20 Marcus Brinkmann * Makefile.am (libgpgme_la_INCLUDES): Remove obsolete directive. (AM_CPPFLAGS): New directive [BUILD_ASSUAN]. (libgpgme_la_LIBADD): Likewise. --- ChangeLog | 8 + Makefile.am | 8 +- assuan/Makefile.am | 43 ++++ assuan/assuan-buffer.c | 247 +++++++++++++++++++++ assuan/assuan-connect.c | 129 +++++++++++ assuan/assuan-defs.h | 110 +++++++++ assuan/assuan-handler.c | 431 ++++++++++++++++++++++++++++++++++++ assuan/assuan-listen.c | 86 +++++++ assuan/assuan-pipe-server.c | 69 ++++++ assuan/assuan-util.c | 98 ++++++++ assuan/assuan.h | 120 ++++++++++ assuan/mkerrors | 71 ++++++ configure.ac | 8 +- gpgme/ChangeLog | 7 + gpgme/Makefile.am | 5 +- 15 files changed, 1436 insertions(+), 4 deletions(-) create mode 100644 assuan/Makefile.am create mode 100644 assuan/assuan-buffer.c create mode 100644 assuan/assuan-connect.c create mode 100644 assuan/assuan-defs.h create mode 100644 assuan/assuan-handler.c create mode 100644 assuan/assuan-listen.c create mode 100644 assuan/assuan-pipe-server.c create mode 100644 assuan/assuan-util.c create mode 100644 assuan/assuan.h create mode 100755 assuan/mkerrors diff --git a/ChangeLog b/ChangeLog index de92d63b..d448e5f8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2001-11-20 Marcus Brinkmann + + * Makefile.am (SUBDIRS): Support building the assuan library + (currently if GPGSM_PATH is set).. + * configure.ac: Support building the assuan library. + * assuan: New directory, populated with the Assuan library + (copied from the newpg repository). + 2001-11-20 Marcus Brinkmann * configure.ac (NEED_GPGSM_VERSION): New variable. Treat it diff --git a/Makefile.am b/Makefile.am index efe8c9ce..d9ef9645 100644 --- a/Makefile.am +++ b/Makefile.am @@ -21,6 +21,12 @@ EXTRA_DIST = README-alpha autogen.sh +if BUILD_ASSUAN +assuan = assuan +else +assuan = +endif + if BUILD_BONOBO bonobo = bonobo else @@ -39,4 +45,4 @@ else tests = endif -SUBDIRS = jnlib gpgme ${tests} doc ${bonobo} ${complus} +SUBDIRS = ${assuan} jnlib gpgme ${tests} doc ${bonobo} ${complus} diff --git a/assuan/Makefile.am b/assuan/Makefile.am new file mode 100644 index 00000000..3c576900 --- /dev/null +++ b/assuan/Makefile.am @@ -0,0 +1,43 @@ +# Assuan Makefile for test purposes +# 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 + +## Process this file with automake to produce Makefile.in + +EXTRA_DIST = mkerrors +INCLUDES = -I.. -I$(top_srcdir)/include +BUILT_SOURCES = assuan-errors.c + +noinst_LIBRARIES = libassuan.a + + +#libassuan_a_LDFLAGS = +libassuan_a_SOURCES = \ + assuan.h \ + assuan-defs.h \ + assuan-util.c \ + assuan-errors.c \ + assuan-buffer.c \ + assuan-handler.c \ + assuan-listen.c \ + assuan-connect.c \ + assuan-pipe-server.c + + +assuan-errors.c : assuan.h + $(srcdir)/mkerrors < $(srcdir)/assuan.h > assuan-errors.c diff --git a/assuan/assuan-buffer.c b/assuan/assuan-buffer.c new file mode 100644 index 00000000..912272f1 --- /dev/null +++ b/assuan/assuan-buffer.c @@ -0,0 +1,247 @@ +/* assuan-buffer.c - read and send data + * 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 "assuan-defs.h" + + +static int +writen ( int fd, const char *buffer, size_t length ) +{ + while (length) + { + int nwritten = write (fd, buffer, length); + + if (nwritten < 0) + { + if (errno == EINTR) + continue; + return -1; /* write error */ + } + length -= nwritten; + buffer += nwritten; + } + return 0; /* okay */ +} + +/* read an entire line */ +static int +readline (int fd, char *buf, size_t buflen, int *r_nread, int *eof) +{ + size_t nleft = buflen; + char *p; + + *eof = 0; + *r_nread = 0; + while (nleft > 0) + { + int n = read (fd, buf, nleft); + if (n < 0) + { + if (errno == EINTR) + continue; + return -1; /* read error */ + } + else if (!n) + { + *eof = 1; + break; /* allow incomplete lines */ + } + p = buf; + nleft -= n; + buf += n; + *r_nread += n; + + for (; n && *p != '\n'; n--, p++) + ; + if (n) + break; + } + + return 0; +} + + +int +_assuan_read_line (ASSUAN_CONTEXT ctx) +{ + char *line = ctx->inbound.line; + int n, nread; + int rc; + + if (ctx->inbound.eof) + return -1; + + rc = readline (ctx->inbound.fd, line, LINELENGTH, &nread, &ctx->inbound.eof); + if (rc) + return ASSUAN_Read_Error; + if (!nread) + { + assert (ctx->inbound.eof); + return -1; + } + + for (n=nread-1; n>=0 ; n--) + { + if (line[n] == '\n') + { + if (n != nread-1) + { + fprintf (stderr, "DBG-assuan: %d bytes left over after read\n", + nread-1 - n); + /* fixme: store them for the next read */ + } + if (n && line[n-1] == '\r') + n--; + line[n] = 0; + ctx->inbound.linelen = n; + return 0; + } + } + + *line = 0; + ctx->inbound.linelen = 0; + return ctx->inbound.eof? ASSUAN_Line_Not_Terminated : ASSUAN_Line_Too_Long; +} + + + + +int +_assuan_write_line (ASSUAN_CONTEXT ctx, const char *line ) +{ + int rc; + + /* fixme: we should do some kind of line buffering */ + rc = writen (ctx->outbound.fd, line, strlen(line)); + if (rc) + rc = ASSUAN_Write_Error; + if (!rc) + { + rc = writen (ctx->outbound.fd, "\n", 1); + if (rc) + rc = ASSUAN_Write_Error; + } + + return rc; +} + + + +/* Write out the data in buffer as datalines with line wrapping and + percent escaping. This fucntion is used for GNU's custom streams */ +int +_assuan_cookie_write_data (void *cookie, const char *buffer, size_t size) +{ + ASSUAN_CONTEXT ctx = cookie; + char *line; + size_t linelen; + + if (ctx->outbound.data.error) + return 0; + + line = ctx->outbound.data.line; + linelen = ctx->outbound.data.linelen; + line += linelen; + while (size) + { + /* insert data line header */ + if (!linelen) + { + *line++ = 'D'; + *line++ = ' '; + linelen += 2; + } + + /* copy data, keep some space for the CRLF and to escape one character */ + while (size && linelen < LINELENGTH-2-2) + { + if (*buffer == '%' || *buffer == '\r' || *buffer == '\n') + { + sprintf (line, "%%%02X", *(unsigned char*)buffer); + line += 3; + linelen += 3; + buffer++; + } + else + { + *line++ = *buffer++; + linelen++; + } + size--; + } + + if (linelen >= LINELENGTH-2-2) + { + *line++ = '\n'; + linelen++; + if (writen (ctx->outbound.fd, ctx->outbound.data.line, linelen)) + { + ctx->outbound.data.error = ASSUAN_Write_Error; + return 0; + } + line = ctx->outbound.data.line; + linelen = 0; + } + } + + ctx->outbound.data.linelen = linelen; + return 0; +} + + +/* Write out any buffered data + This fucntion is used for GNU's custom streams */ +int +_assuan_cookie_write_flush (void *cookie) +{ + ASSUAN_CONTEXT ctx = cookie; + char *line; + size_t linelen; + + if (ctx->outbound.data.error) + return 0; + + line = ctx->outbound.data.line; + linelen = ctx->outbound.data.linelen; + line += linelen; + if (linelen) + { + *line++ = '\n'; + linelen++; + if (writen (ctx->outbound.fd, ctx->outbound.data.line, linelen)) + { + ctx->outbound.data.error = ASSUAN_Write_Error; + return 0; + } + ctx->outbound.data.linelen = 0; + } + return 0; +} + + + + diff --git a/assuan/assuan-connect.c b/assuan/assuan-connect.c new file mode 100644 index 00000000..778b3a77 --- /dev/null +++ b/assuan/assuan-connect.c @@ -0,0 +1,129 @@ +/* assuan-connect.c - Establish a connection (client) + * 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 "assuan-defs.h" + +/* Connect to a server over a pipe, creating the assuan context and + returning it in CTX. The server filename is NAME, the argument + vector in ARGV. */ +AssuanError +assuan_pipe_connect (ASSUAN_CONTEXT *ctx, const char *name, char *const argv[]) +{ + static int fixed_signals = 0; + AssuanError err; + int rp[2]; + int wp[2]; + int fd[2]; + + if (!name || !argv || !argv[0]) + return ASSUAN_General_Error; + + if (!fixed_signals) + { + struct sigaction act; + + sigaction (SIGPIPE, NULL, &act); + if (act.sa_handler == SIG_DFL) + { + act.sa_handler = SIG_IGN; + sigemptyset (&act.sa_mask); + act.sa_flags = 0; + sigaction (SIGPIPE, &act, NULL); + } + fixed_signals = 1; + /* FIXME: This is not MT safe */ + } + + if (pipe (rp) < 0) + return ASSUAN_General_Error; + + if (pipe (wp) < 0) + { + close (rp[0]); + close (rp[1]); + return ASSUAN_General_Error; + } + + fd[0] = rp[0]; /* Our inbound is read end of read pipe. */ + fd[1] = wp[1]; /* Our outbound is write end of write pipe. */ + + err = assuan_init_pipe_server (ctx, fd); /* FIXME: Common code should be factored out. */ + if (err) + { + close (rp[0]); + close (rp[1]); + close (wp[0]); + close (wp[1]); + return err; + } + + (*ctx)->pid = fork (); + if ((*ctx)->pid < 0) + { + close (rp[0]); + close (rp[1]); + close (wp[0]); + close (wp[1]); + assuan_deinit_pipe_server (*ctx); /* FIXME: Common code should be factored out. */ + return ASSUAN_General_Error; + } + + if ((*ctx)->pid == 0) + { + close (rp[0]); + close (wp[1]); + if (rp[1] != STDOUT_FILENO) + { + dup2 (rp[1], STDOUT_FILENO); /* Child's outbound is write end of read pipe. */ + close (rp[1]); + } + if (wp[0] != STDIN_FILENO) + { + dup2 (wp[0], STDIN_FILENO); /* Child's inbound is read end of write pipe. */ + close (wp[0]); + } + execv (name, argv); + _exit (1); + } + + close (rp[1]); + close (wp[0]); + _assuan_read_line (*ctx); /* FIXME: Handshake. */ + return 0; +} + +void +assuan_pipe_disconnect (ASSUAN_CONTEXT ctx) +{ + _assuan_write_line (ctx, "BYE"); + close (ctx->inbound.fd); + close (ctx->outbound.fd); + waitpid (ctx->pid, NULL, 0); /* FIXME Check return value. */ + assuan_deinit_pipe_server (ctx); +} diff --git a/assuan/assuan-defs.h b/assuan/assuan-defs.h new file mode 100644 index 00000000..8723fd31 --- /dev/null +++ b/assuan/assuan-defs.h @@ -0,0 +1,110 @@ +/* assuan-defs.c - Internal definitions to Assuan + * 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 + */ + +#ifndef ASSUAN_DEFS_H +#define ASSUAN_DEFS_H + +#include +#include "assuan.h" + +#define LINELENGTH 1002 /* 1000 + [CR,]LF */ + +struct cmdtbl_s { + const char *name; + int cmd_id; + int (*handler)(ASSUAN_CONTEXT, char *line); +}; + +struct assuan_context_s { + AssuanError err_no; + const char *err_str; + + void *user_pointer; /* for assuan_[gs]et_pointer () */ + + struct { + int fd; + int eof; + char line[LINELENGTH]; + int linelen; /* w/o CR, LF - might not be the same as + strlen(line) due to embedded nuls. However a nul + is always written at this pos */ + } inbound; + + struct { + int fd; + struct { + FILE *fp; + char line[LINELENGTH]; + int linelen; + int error; + } data; + } outbound; + + int pipe_mode; /* We are in pipe mode, i.e. we can handle just one + connection and must terminate then */ + pid_t pid; /* In pipe mode, the pid of the child server process. */ + + struct cmdtbl_s *cmdtbl; + size_t cmdtbl_used; /* used entries */ + size_t cmdtbl_size; /* allocated size of table */ + + + int input_fd; /* set by INPUT command */ + int output_fd; /* set by OUTPUT command */ + + + +}; + + +/*-- assuan-handler.c --*/ +int _assuan_register_std_commands (ASSUAN_CONTEXT ctx); + +/*-- assuan-buffer.c --*/ +int _assuan_write_line (ASSUAN_CONTEXT ctx, const char *line); +int _assuan_read_line (ASSUAN_CONTEXT ctx); +int _assuan_cookie_write_data (void *cookie, const char *buffer, size_t size); +int _assuan_cookie_write_flush (void *cookie); + + + + +/*-- assuan-util.c --*/ +void *_assuan_malloc (size_t n); +void *_assuan_calloc (size_t n, size_t m); +void *_assuan_realloc (void *p, size_t n); +void _assuan_free (void *p); + +#define xtrymalloc(a) _assuan_malloc ((a)) +#define xtrycalloc(a,b) _assuan_calloc ((a),(b)) +#define xtryrealloc(a,b) _assuan_realloc((a),(b)) +#define xfree(a) _assuan_free ((a)) + +#define set_error(c,e,t) assuan_set_error ((c), ASSUAN_ ## e, (t)) + + +#endif /*ASSUAN_DEFS_H*/ + + + + + + + diff --git a/assuan/assuan-handler.c b/assuan/assuan-handler.c new file mode 100644 index 00000000..472206b0 --- /dev/null +++ b/assuan/assuan-handler.c @@ -0,0 +1,431 @@ +/* assuan-handler.c - dispatch commands + * 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 "assuan-defs.h" + +#define digitp(a) ((a) >= '0' && (a) <= '9') + + +static int +dummy_handler (ASSUAN_CONTEXT ctx, char *line) +{ + return set_error (ctx, Server_Fault, "no handler registered"); +} + + +static int +std_handler_nop (ASSUAN_CONTEXT ctx, char *line) +{ + return 0; /* okay */ +} + +static int +std_handler_cancel (ASSUAN_CONTEXT ctx, char *line) +{ + return set_error (ctx, Not_Implemented, NULL); +} + +static int +std_handler_bye (ASSUAN_CONTEXT ctx, char *line) +{ + return -1; /* pretty simple :-) */ +} + +static int +std_handler_auth (ASSUAN_CONTEXT ctx, char *line) +{ + return set_error (ctx, Not_Implemented, NULL); +} + +static int +std_handler_reset (ASSUAN_CONTEXT ctx, char *line) +{ + return set_error (ctx, Not_Implemented, NULL); +} + +static int +std_handler_end (ASSUAN_CONTEXT ctx, char *line) +{ + return set_error (ctx, Not_Implemented, NULL); +} + +static int +parse_cmd_input_output (ASSUAN_CONTEXT ctx, char *line, int *rfd) +{ + char *endp; + + if (strncmp (line, "FD=", 3)) + return set_error (ctx, Syntax_Error, "FD= expected"); + line += 3; + if (!digitp (*line)) + return set_error (ctx, Syntax_Error, "number required"); + *rfd = strtoul (line, &endp, 10); + if (*endp) + return set_error (ctx, Syntax_Error, "garbage found"); + if (*rfd == ctx->inbound.fd) + return set_error (ctx, Parameter_Conflict, "fd same as inbound fd"); + if (*rfd == ctx->outbound.fd) + return set_error (ctx, Parameter_Conflict, "fd same as outbound fd"); + return 0; +} + +/* Format is INPUT FD= */ +static int +std_handler_input (ASSUAN_CONTEXT ctx, char *line) +{ + int rc, fd; + + rc = parse_cmd_input_output (ctx, line, &fd); + if (rc) + return rc; + ctx->input_fd = fd; + return 0; +} + +/* Format is OUTPUT FD= */ +static int +std_handler_output (ASSUAN_CONTEXT ctx, char *line) +{ + int rc, fd; + + rc = parse_cmd_input_output (ctx, line, &fd); + if (rc) + return rc; + ctx->output_fd = fd; + return 0; +} + + + + + +/* This is a table with the standard commands and handler for them. + The table is used to initialize a new context and assuciate strings + and handlers with cmd_ids */ +static struct { + const char *name; + int cmd_id; + int (*handler)(ASSUAN_CONTEXT, char *line); + int always; /* always initializethis command */ +} std_cmd_table[] = { + { "NOP", ASSUAN_CMD_NOP, std_handler_nop, 1 }, + { "CANCEL", ASSUAN_CMD_CANCEL, std_handler_cancel, 1 }, + { "BYE", ASSUAN_CMD_BYE, std_handler_bye, 1 }, + { "AUTH", ASSUAN_CMD_AUTH, std_handler_auth, 1 }, + { "RESET", ASSUAN_CMD_RESET, std_handler_reset, 1 }, + { "END", ASSUAN_CMD_END, std_handler_end, 1 }, + + { "INPUT", ASSUAN_CMD_INPUT, std_handler_input }, + { "OUTPUT", ASSUAN_CMD_OUTPUT, std_handler_output }, + { NULL } +}; + + +/** + * assuan_register_command: + * @ctx: the server context + * @cmd_id: An ID value for the command + * @cmd_name: A string with the command name + * @handler: The handler function to be called + * + * Register a handler to be used for a given command. + * + * The @cmd_name must be %NULL or an empty string for all @cmd_ids + * below %ASSUAN_CMD_USER because predefined values are used. + * + * Return value: + **/ +int +assuan_register_command (ASSUAN_CONTEXT ctx, + int cmd_id, const char *cmd_name, + int (*handler)(ASSUAN_CONTEXT, char *)) +{ + int i; + + if (cmd_name && !*cmd_name) + cmd_name = NULL; + + if (cmd_id < ASSUAN_CMD_USER) + { + if (cmd_name) + return ASSUAN_Invalid_Value; /* must be NULL for these values*/ + + for (i=0; std_cmd_table[i].name; i++) + { + if (std_cmd_table[i].cmd_id == cmd_id) + { + cmd_name = std_cmd_table[i].name; + if (!handler) + handler = std_cmd_table[i].handler; + break; + } + } + if (!std_cmd_table[i].name) + return ASSUAN_Invalid_Value; /* not a pre-registered one */ + } + + if (!handler) + handler = dummy_handler; + + if (!cmd_name) + return ASSUAN_Invalid_Value; + +/* fprintf (stderr, "DBG-assuan: registering %d as `%s'\n", cmd_id, cmd_name); */ + + if (!ctx->cmdtbl) + { + ctx->cmdtbl_size = 50; + ctx->cmdtbl = xtrycalloc ( ctx->cmdtbl_size, sizeof *ctx->cmdtbl); + if (!ctx->cmdtbl) + return ASSUAN_Out_Of_Core; + ctx->cmdtbl_used = 0; + } + else if (ctx->cmdtbl_used >= ctx->cmdtbl_size) + { + struct cmdtbl_s *x; + + x = xtryrealloc ( ctx->cmdtbl, (ctx->cmdtbl_size+10) * sizeof *x); + if (!x) + return ASSUAN_Out_Of_Core; + ctx->cmdtbl = x; + ctx->cmdtbl_size += 50; + } + + ctx->cmdtbl[ctx->cmdtbl_used].name = cmd_name; + ctx->cmdtbl[ctx->cmdtbl_used].cmd_id = cmd_id; + ctx->cmdtbl[ctx->cmdtbl_used].handler = handler; + ctx->cmdtbl_used++; + return 0; +} + +/* Helper to register the standards commands */ +int +_assuan_register_std_commands (ASSUAN_CONTEXT ctx) +{ + int i, rc; + + for (i=0; std_cmd_table[i].name; i++) + { + if (std_cmd_table[i].always) + { + rc = assuan_register_command (ctx, std_cmd_table[i].cmd_id, + NULL, NULL); + if (rc) + return rc; + } + } + return 0; +} + + + +/* Process the special data lines. The "D " has already been removed + from the line. As all handlers this function may modify the line. */ +static int +handle_data_line (ASSUAN_CONTEXT ctx, char *line, int linelen) +{ + return set_error (ctx, Not_Implemented, NULL); +} + + +/* Parse the line, break out the command, find it in the command + table, remove leading and white spaces from the arguments, all the + handler with the argument line and return the error */ +static int +dispatch_command (ASSUAN_CONTEXT ctx, char *line, int linelen) +{ + char *p; + const char *s; + int shift, i; + + if (*line == 'D' && line[1] == ' ') /* divert to special handler */ + return handle_data_line (ctx, line+2, linelen-2); + + for (p=line; *p && *p != ' ' && *p != '\t'; p++) + ; + if (p==line) + return set_error (ctx, Invalid_Command, "leading white-space"); + if (*p) + { /* Skip over leading WS after the keyword */ + *p++ = 0; + while ( *p == ' ' || *p == '\t') + p++; + } + shift = p - line; + + for (i=0; (s=ctx->cmdtbl[i].name); i++) + if (!strcmp (line, s)) + break; + if (!s) + return set_error (ctx, Unknown_Command, NULL); + line += shift; + linelen -= shift; + +/* fprintf (stderr, "DBG-assuan: processing %s `%s'\n", s, line); */ + return ctx->cmdtbl[i].handler (ctx, line); +} + + + + +/** + * assuan_process: + * @ctx: assuan context + * + * This fucntion is used to handle the assuan protocol after a + * connection has been established using assuan_accept(). This is the + * main protocol handler. + * + * Return value: 0 on success or an error code if the assuan operation + * failed. Note, that no error is returned for operational errors. + **/ +int +assuan_process (ASSUAN_CONTEXT ctx) +{ + int rc; + + do { + /* Read the line but skip comments */ + do + { + rc = _assuan_read_line (ctx); + if (rc) + return rc; + +/* fprintf (stderr, "DBG-assuan: got %d bytes `%s'\n", */ +/* ctx->inbound.linelen, ctx->inbound.line); */ + } + while ( *ctx->inbound.line == '#' || !ctx->inbound.linelen); + + ctx->outbound.data.error = 0; + ctx->outbound.data.linelen = 0; + /* dispatch command and return reply */ + rc = dispatch_command (ctx, ctx->inbound.line, ctx->inbound.linelen); + /* check from data write errors */ + if (ctx->outbound.data.fp) + { /* Flush the data lines */ + fclose (ctx->outbound.data.fp); + ctx->outbound.data.fp = NULL; + if (!rc && ctx->outbound.data.error) + rc = ctx->outbound.data.error; + } + /* Error handling */ + if (!rc) + { + rc = _assuan_write_line (ctx, "OK"); + } + else if (rc == -1) + { /* No error checking because the peer may have already disconnect */ + _assuan_write_line (ctx, "OK Bye, bye - hope to meet you again"); + } + else + { + char errline[256]; + + if (rc < 100) + sprintf (errline, "ERR %d server fault (%.50s)", + ASSUAN_Server_Fault, assuan_strerror (rc)); + else + { + const char *text = ctx->err_no == rc? ctx->err_str:NULL; + + sprintf (errline, "ERR %d %.50s%s%.100s", + rc, assuan_strerror (rc), text? " - ":"", text?text:""); + } + rc = _assuan_write_line (ctx, errline); + } + } while (!rc); + + if (rc == -1) + rc = 0; + + return rc; +} + + +/* Return a FP to be used for data output. The FILE pointer is valid + until the end of a handler. So a close is not needed. Assuan does + all the buffering needed to insert the status line as well as the + required line wappping and quoting for data lines. + + We use GNU's custom streams here. There should be an alternative + implementaion for systems w/o a glibc, a simple implementation + could use a child process */ +FILE * +assuan_get_data_fp (ASSUAN_CONTEXT ctx) +{ + cookie_io_functions_t cookie_fnc; + + if (ctx->outbound.data.fp) + return ctx->outbound.data.fp; + + cookie_fnc.read = NULL; + cookie_fnc.write = _assuan_cookie_write_data; + cookie_fnc.seek = NULL; + cookie_fnc.close = _assuan_cookie_write_flush; + + ctx->outbound.data.fp = fopencookie (ctx, "wb", cookie_fnc); + ctx->outbound.data.error = 0; + return ctx->outbound.data.fp; +} + + +void +assuan_write_status (ASSUAN_CONTEXT ctx, const char *keyword, const char *text) +{ + char buffer[256]; + char *helpbuf; + size_t n; + + if ( !ctx || !keyword) + return; + if (!text) + text = ""; + + n = 2 + strlen (keyword) + 1 + strlen (text) + 1; + if (n < sizeof (buffer)) + { + strcpy (buffer, "S "); + strcat (buffer, keyword); + if (*text) + { + strcat (buffer, " "); + strcat (buffer, text); + } + _assuan_write_line (ctx, buffer); + } + else if ( (helpbuf = xtrymalloc (n)) ) + { + strcpy (helpbuf, "S "); + strcat (helpbuf, keyword); + if (*text) + { + strcat (helpbuf, " "); + strcat (helpbuf, text); + } + _assuan_write_line (ctx, helpbuf); + xfree (helpbuf); + } +} diff --git a/assuan/assuan-listen.c b/assuan/assuan-listen.c new file mode 100644 index 00000000..f8ccb270 --- /dev/null +++ b/assuan/assuan-listen.c @@ -0,0 +1,86 @@ +/* assuan-listen.c - Wait for a connection (server) + * 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 "assuan-defs.h" + + + +/** + * assuan_accept: + * @ctx: context + * + * Cancel any existing connectiion and wait for a connection from a + * client. The initial handshake is performed which may include an + * initial authentication or encryption negotiation. + * + * Return value: 0 on success or an error if the connection could for + * some reason not be established. + **/ +int +assuan_accept (ASSUAN_CONTEXT ctx) +{ + int rc; + + if (!ctx) + return ASSUAN_Invalid_Value; + + /* fixme: cancel existing connection */ + if (ctx->pipe_mode > 1) + return -1; /* second invocation for pipemode -> terminate */ + + if (!ctx->pipe_mode) + { + + /* fixme: wait for request */ + } + + /* send the hello */ + + rc = _assuan_write_line (ctx, + "OK Hello dear client - what can I do for you?"); + if (rc) + return rc; + + if (ctx->pipe_mode) + ctx->pipe_mode = 2; + + return 0; +} + + +int +assuan_get_input_fd (ASSUAN_CONTEXT ctx) +{ + return ctx? ctx->input_fd : -1; +} + + +int +assuan_get_output_fd (ASSUAN_CONTEXT ctx) +{ + return ctx? ctx->output_fd : -1; +} + + diff --git a/assuan/assuan-pipe-server.c b/assuan/assuan-pipe-server.c new file mode 100644 index 00000000..018d05df --- /dev/null +++ b/assuan/assuan-pipe-server.c @@ -0,0 +1,69 @@ +/* assuan-pipe-server.c - Assuan server working over a pipe + * 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 "assuan-defs.h" + + +int +assuan_init_pipe_server (ASSUAN_CONTEXT *r_ctx, int filedes[2]) +{ + ASSUAN_CONTEXT ctx; + int rc; + + *r_ctx = NULL; + ctx = xtrycalloc (1, sizeof *ctx); + if (!ctx) + return ASSUAN_Out_Of_Core; + ctx->input_fd = -1; + ctx->output_fd = -1; + + ctx->inbound.fd = filedes[0]; + ctx->outbound.fd = filedes[1]; + + ctx->pipe_mode = 1; + + rc = _assuan_register_std_commands (ctx); + if (rc) + xfree (ctx); + else + *r_ctx = ctx; + return rc; +} + +void +assuan_deinit_pipe_server (ASSUAN_CONTEXT ctx) +{ + xfree (ctx); +} + + + + + + + + + + + diff --git a/assuan/assuan-util.c b/assuan/assuan-util.c new file mode 100644 index 00000000..3eeee9ab --- /dev/null +++ b/assuan/assuan-util.c @@ -0,0 +1,98 @@ +/* assuan-util.c - Utility functions for Assuan + * 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 "assuan-defs.h" + + +static void *(*alloc_func)(size_t n) = malloc; +static void *(*realloc_func)(void *p, size_t n) = realloc; +static void (*free_func)(void*) = free; + + + +void +assuan_set_malloc_hooks ( void *(*new_alloc_func)(size_t n), + void *(*new_realloc_func)(void *p, size_t n), + void (*new_free_func)(void*) ) +{ + alloc_func = new_alloc_func; + realloc_func = new_realloc_func; + free_func = new_free_func; +} + +void * +_assuan_malloc (size_t n) +{ + return alloc_func (n); +} + +void * +_assuan_realloc (void *a, size_t n) +{ + return realloc_func (a, n); +} + +void * +_assuan_calloc (size_t n, size_t m) +{ + void *p = _assuan_malloc (n*m); + if (p) + memset (p, 0, n* m); + return p; +} + +void +_assuan_free (void *p) +{ + if (p) + free_func (p); +} + + + +/* Store the error in the context so that the error sending function + can take out a descriptive text. Inside the assuan code, use the + macro set_error instead of this function. */ +int +assuan_set_error (ASSUAN_CONTEXT ctx, int err, const char *text) +{ + ctx->err_no = err; + ctx->err_str = text; + return err; +} + +void +assuan_set_pointer (ASSUAN_CONTEXT ctx, void *pointer) +{ + if (ctx) + ctx->user_pointer = pointer; +} + +void * +assuan_get_pointer (ASSUAN_CONTEXT ctx) +{ + return ctx? ctx->user_pointer : NULL; +} + diff --git a/assuan/assuan.h b/assuan/assuan.h new file mode 100644 index 00000000..97462fb9 --- /dev/null +++ b/assuan/assuan.h @@ -0,0 +1,120 @@ +/* assuan.c - Definitions for the Assuna protocol + * 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 + */ + +#ifndef ASSUAN_H +#define ASSUAN_H + +#ifdef __cplusplus +extern "C" { +#if 0 + } +#endif +#endif + +typedef enum { + ASSUAN_No_Error = 0, + ASSUAN_General_Error = 1, + ASSUAN_Out_Of_Core = 2, + ASSUAN_Invalid_Value = 3, + ASSUAN_Timeout = 4, + ASSUAN_Read_Error = 5, + ASSUAN_Write_Error = 6, + + /* error codes above 99 are meant as status codes */ + ASSUAN_Not_Implemented = 100, + ASSUAN_Server_Fault = 101, + ASSUAN_Invalid_Command = 102, + ASSUAN_Unknown_Command = 103, + ASSUAN_Syntax_Error = 104, + ASSUAN_Parameter_Error = 105, + ASSUAN_Parameter_Conflict = 106, + ASSUAN_Line_Too_Long = 107, + ASSUAN_Line_Not_Terminated = 108, + ASSUAN_No_Input = 109, + ASSUAN_No_Output = 110, + + ASSUAN_Cert_Revoked = 301, + ASSUAN_No_CRL_For_Cert = 302, + ASSUNA_CRL_Too_Old = 303, + +} AssuanError; + +/* This is a list of pre-registered ASSUAN commands */ +typedef enum { + ASSUAN_CMD_NOP = 0, + ASSUAN_CMD_CANCEL, /* cancel the current request */ + ASSUAN_CMD_BYE, + ASSUAN_CMD_AUTH, + ASSUAN_CMD_RESET, + ASSUAN_CMD_DATA, + ASSUAN_CMD_END, + ASSUAN_CMD_INPUT, + ASSUAN_CMD_OUTPUT, + + ASSUAN_CMD_USER = 256 /* Other commands should be used with this offset*/ +} AssuanCommand; + + +struct assuan_context_s; +typedef struct assuan_context_s *ASSUAN_CONTEXT; + +/*-- assuan-handler.c --*/ +int assuan_register_command (ASSUAN_CONTEXT ctx, + int cmd_id, const char *cmd_string, + int (*handler)(ASSUAN_CONTEXT, char *)); +int assuan_process (ASSUAN_CONTEXT ctx); +FILE *assuan_get_data_fp (ASSUAN_CONTEXT ctx); +void assuan_write_status (ASSUAN_CONTEXT ctx, + const char *keyword, const char *text); + + +/*-- assuan-listen.c --*/ +int assuan_accept (ASSUAN_CONTEXT ctx); +int assuan_get_input_fd (ASSUAN_CONTEXT ctx); +int assuan_get_output_fd (ASSUAN_CONTEXT ctx); + + +/*-- assuan-pipe-server.c --*/ +int assuan_init_pipe_server (ASSUAN_CONTEXT *r_ctx, int filedes[2]); +void assuan_deinit_pipe_server (ASSUAN_CONTEXT ctx); + + +/*-- assuan-connect.c --*/ +AssuanError assuan_pipe_connect (ASSUAN_CONTEXT *ctx, const char *name, + char *const argv[]); +void assuan_pipe_disconnect (ASSUAN_CONTEXT ctx); + +/*-- assuan-util.c --*/ +void assuan_set_malloc_hooks ( void *(*new_alloc_func)(size_t n), + void *(*new_realloc_func)(void *p, size_t n), + void (*new_free_func)(void*) ); +int assuan_set_error (ASSUAN_CONTEXT ctx, int err, const char *text); +void assuan_set_pointer (ASSUAN_CONTEXT ctx, void *pointer); +void *assuan_get_pointer (ASSUAN_CONTEXT ctx); + + +/*-- assuan-errors.c (built) --*/ +const char *assuan_strerror (AssuanError err); + + +#ifdef __cplusplus +} +#endif +#endif /*ASSUAN_H*/ diff --git a/assuan/mkerrors b/assuan/mkerrors new file mode 100755 index 00000000..13eabde7 --- /dev/null +++ b/assuan/mkerrors @@ -0,0 +1,71 @@ +#!/bin/sh +# mkerrors - Extract error strings from assuan.h +# and create C source for assuan_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 "assuan.h" + +/** + * assuan_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 * +assuan_strerror (AssuanError err) +{ + const char *s; + static char buf[25]; + + switch (err) + { +EOF + +awk ' +/ASSUAN_No_Error/ { okay=1 } +!okay {next} +/}/ { exit 0 } +/ASSUAN_[A-Za-z_]*/ { print_code($1) } + + +function print_code( s ) +{ +printf " case %s: s=\"", s ; +gsub(/_/, " ", s ); +printf "%s\"; break;\n", tolower(substr(s,8)); +} +' + +cat < + + * Makefile.am (libgpgme_la_INCLUDES): Remove obsolete directive. + (AM_CPPFLAGS): New directive [BUILD_ASSUAN]. + (libgpgme_la_LIBADD): Likewise. + 2001-11-20 Marcus Brinkmann * version.c: Remove global variables lineno and @@ -9,6 +15,7 @@ * ops.h (_gpgme_get_program_version): Add prototype for _gpgme_get_program_version (we expect to use it elsewhere soon). +>>>>>>> 1.44 2001-11-18 Marcus Brinkmann * version.c (get_engine_info): If GnuPG is not available, return diff --git a/gpgme/Makefile.am b/gpgme/Makefile.am index 41b513cb..79155e3b 100644 --- a/gpgme/Makefile.am +++ b/gpgme/Makefile.am @@ -29,7 +29,10 @@ lib_LTLIBRARIES = libgpgme.la libgpgme_la_LDFLAGS = -version-info \ @LIBGPGME_LT_CURRENT@:@LIBGPGME_LT_REVISION@:@LIBGPGME_LT_AGE@ -libgpgme_la_INCLUDES = -I$(top_srcdir)/lib +if BUILD_ASSUAN +AM_CPPFLAGS = -I$(top_srcdir)/assuan +libgpgme_la_LIBADD = -L../assuan -lassuan +endif libgpgme_la_SOURCES = \ gpgme.h types.h \