1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-06-06 23:17:47 +02:00

Assuan server mode is now basically usable

This commit is contained in:
Werner Koch 2001-11-07 17:43:05 +00:00
parent 4fcb72b382
commit 7166bd6a5d
10 changed files with 426 additions and 59 deletions

View File

@ -33,6 +33,8 @@ libassuan_a_SOURCES = \
assuan-errors.c \
assuan-buffer.c \
assuan-handler.c \
assuan-listen.c \
assuan-connect.c \
assuan-pipe-server.c

View File

@ -21,24 +21,131 @@
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <assert.h>
#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;
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)
_assuan_write_line (ASSUAN_CONTEXT ctx, const char *line )
{
return -1;
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;
}

27
assuan/assuan-connect.c Normal file
View File

@ -0,0 +1,27 @@
/* 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 <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "assuan-defs.h"

View File

@ -23,6 +23,13 @@
#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;
@ -30,12 +37,25 @@ struct assuan_context_s {
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;
} outbound;
int pipe_mode; /* We are in pipe mode, i.e. we can handle just one
connection and must terminate then */
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 */
@ -47,6 +67,11 @@ struct assuan_context_s {
/*-- 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);
/*-- assuan-util.c --*/
void *_assuan_malloc (size_t n);
@ -59,8 +84,7 @@ void _assuan_free (void *p);
#define xtryrealloc(a,b) _assuan_realloc((a),(b))
#define xfree(a) _assuan_free ((a))
int _assuan_set_error (ASSUAN_CONTEXT ctx, int err, const char *text);
#define set_error(c,e,t) _assuan_set_error ((c), ASSUAN_ ## e, (t))
#define set_error(c,e,t) assuan_set_error ((c), ASSUAN_ ## e, (t))
#endif /*ASSUAN_DEFS_H*/

View File

@ -31,7 +31,6 @@
static int
dummy_handler (ASSUAN_CONTEXT ctx, char *line)
{
fprintf (stderr, "DBG-assuan: dummy handler called\n");
return set_error (ctx, Server_Fault, "no handler registered");
}
@ -39,42 +38,36 @@ dummy_handler (ASSUAN_CONTEXT ctx, char *line)
static int
std_handler_nop (ASSUAN_CONTEXT ctx, char *line)
{
fprintf (stderr, "DBG-assuan: processing a NOP `%s'\n", line);
return 0; /* okay */
}
static int
std_handler_cancel (ASSUAN_CONTEXT ctx, char *line)
{
fprintf (stderr, "DBG-assuan: processing a CANCEL `%s'\n", line);
return set_error (ctx, Not_Implemented, NULL);
}
static int
std_handler_bye (ASSUAN_CONTEXT ctx, char *line)
{
fprintf (stderr, "DBG-assuan: processing a BYE `%s'\n", line);
return set_error (ctx, Not_Implemented, NULL);
return -1; /* pretty simple :-) */
}
static int
std_handler_auth (ASSUAN_CONTEXT ctx, char *line)
{
fprintf (stderr, "DBG-assuan: processing a AUTH `%s'\n", line);
return set_error (ctx, Not_Implemented, NULL);
}
static int
std_handler_reset (ASSUAN_CONTEXT ctx, char *line)
{
fprintf (stderr, "DBG-assuan: processing a RESET `%s'\n", line);
return set_error (ctx, Not_Implemented, NULL);
}
static int
std_handler_end (ASSUAN_CONTEXT ctx, char *line)
{
fprintf (stderr, "DBG-assuan: processing a END `%s'\n", line);
return set_error (ctx, Not_Implemented, NULL);
}
@ -104,8 +97,6 @@ std_handler_input (ASSUAN_CONTEXT ctx, char *line)
{
int rc, fd;
fprintf (stderr, "DBG-assuan: processing a INPUT `%s'\n", line);
rc = parse_cmd_input_output (ctx, line, &fd);
if (rc)
return rc;
@ -152,20 +143,6 @@ static struct {
};
static const char *
std_cmd_name (int cmd_id)
{
int i;
for (i=0; std_cmd_table[i].name; i++)
if (std_cmd_table[i].cmd_id == cmd_id)
return std_cmd_table[i].name;
return NULL;
}
/**
* assuan_register_command:
* @ctx: the server context
@ -175,8 +152,8 @@ std_cmd_name (int cmd_id)
*
* Register a handler to be used for a given command.
*
* The @cmd_name must be %NULL for all @cmd_ids below
* %ASSUAN_CMD_USER becuase predefined values are used.
* 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:
**/
@ -185,17 +162,63 @@ assuan_register_command (ASSUAN_CONTEXT ctx,
int cmd_id, const char *cmd_name,
int (*handler)(ASSUAN_CONTEXT, char *))
{
if (cmd_name && cmd_id < ASSUAN_CMD_USER)
return ASSUAN_Invalid_Value;
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 (!cmd_name)
cmd_name = std_cmd_name (cmd_id);
if (!handler)
handler = dummy_handler;
if (!cmd_name)
return ASSUAN_Invalid_Value;
return ASSUAN_Invalid_Value;
fprintf (stderr, "DBG-assuan: registering %d as `%s'\n", cmd_id, cmd_name);
if (!ctx->cmdtbl)
{
ctx->cmdtbl_size = 10;
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;
fprintf (stderr, "DBG-assuan: enlarging cmdtbl\n");
x = xtryrealloc ( ctx->cmdtbl, (ctx->cmdtbl_size+10) * sizeof *x);
if (!x)
return ASSUAN_Out_Of_Core;
ctx->cmdtbl = x;
ctx->cmdtbl_size += 10;
}
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;
}
@ -209,8 +232,8 @@ _assuan_register_std_commands (ASSUAN_CONTEXT ctx)
{
if (std_cmd_table[i].always)
{
rc = assuan_register_command (ctx, std_cmd_table[i].cmd_id, NULL,
std_cmd_table[i].handler);
rc = assuan_register_command (ctx, std_cmd_table[i].cmd_id,
NULL, NULL);
if (rc)
return rc;
}
@ -223,7 +246,7 @@ _assuan_register_std_commands (ASSUAN_CONTEXT ctx)
/* 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)
handle_data_line (ASSUAN_CONTEXT ctx, char *line, int linelen)
{
return set_error (ctx, Not_Implemented, NULL);
}
@ -233,20 +256,102 @@ handle_data_line (ASSUAN_CONTEXT ctx, char *line)
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)
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);
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;
return set_error (ctx, Not_Implemented, NULL);
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);
/* dispatch comamnd and return reply */
rc = dispatch_command (ctx, ctx->inbound.line, ctx->inbound.linelen);
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;
}

86
assuan/assuan-listen.c Normal file
View File

@ -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 <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#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;
}

View File

@ -39,7 +39,9 @@ assuan_init_pipe_server (ASSUAN_CONTEXT *r_ctx, int filedes[2])
ctx->output_fd = -1;
ctx->inbound.fd = filedes[0];
ctx->outbound.fd = filedes[0];
ctx->outbound.fd = filedes[1];
ctx->pipe_mode = 1;
rc = _assuan_register_std_commands (ctx);
if (rc)

View File

@ -21,6 +21,7 @@
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "assuan-defs.h"
@ -72,11 +73,10 @@ _assuan_free (void *p)
/* Store the error in the context so that the error sending function
can take out a descriptive text. We wight also want to store a
standard text when TEXT is NULL. Use the macro set_error instead of
this 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)
assuan_set_error (ASSUAN_CONTEXT ctx, int err, const char *text)
{
ctx->err_no = err;
ctx->err_str = text;

View File

@ -33,15 +33,22 @@ typedef enum {
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_Unknown_Command = 100,
ASSUAN_Not_Implemented = 101,
ASSUAN_Server_Fault = 102,
ASSUAN_Syntax_Error = 103,
ASSUAN_Parameter_Error = 104,
ASSUAN_Parameter_Conflict = 105,
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,
@ -68,12 +75,18 @@ typedef enum {
struct assuan_context_s;
typedef struct assuan_context_s *ASSUAN_CONTEXT;
/*-- assuan-handler --*/
/*-- 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);
/*-- 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]);
@ -84,6 +97,7 @@ void assuan_deinit_pipe_server (ASSUAN_CONTEXT ctx);
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);
/*-- assuan-errors.c (built) --*/
const char *assuan_strerror (AssuanError err);

View File

@ -57,7 +57,7 @@ function print_code( s )
{
printf " case %s: s=\"", s ;
gsub(/_/, " ", s );
printf "%s\"; break;\n", substr(s,8);
printf "%s\"; break;\n", tolower(substr(s,8));
}
'