diff options
| author | Marcus Brinkmann <[email protected]> | 2001-11-20 05:27:46 +0000 | 
|---|---|---|
| committer | Marcus Brinkmann <[email protected]> | 2001-11-20 05:27:46 +0000 | 
| commit | a441158cc77391ba8857928f01fd20ac1569ad85 (patch) | |
| tree | 34be0da9e61f66ea17990768062017e68e01e39f /assuan/assuan-handler.c | |
| parent | 2001-11-20 Marcus Brinkmann <[email protected]> (diff) | |
| download | gpgme-a441158cc77391ba8857928f01fd20ac1569ad85.tar.gz gpgme-a441158cc77391ba8857928f01fd20ac1569ad85.zip | |
2001-11-20  Marcus Brinkmann  <[email protected]>
	* 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  <[email protected]>
	* Makefile.am (libgpgme_la_INCLUDES): Remove obsolete directive.
	(AM_CPPFLAGS): New directive [BUILD_ASSUAN].
	(libgpgme_la_LIBADD): Likewise.
Diffstat (limited to '')
| -rw-r--r-- | assuan/assuan-handler.c | 431 | 
1 files changed, 431 insertions, 0 deletions
| 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 <config.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#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=<n> 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=<n> */ +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=<n> */ +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); +    } +} | 
