diff options
author | Werner Koch <wk@gnupg.org> | 2001-11-07 18:43:05 +0100 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2001-11-07 18:43:05 +0100 |
commit | 7166bd6a5d4e6dd850062c12362f33240b9b2124 (patch) | |
tree | 6df0ef5633d00f18ca6b513acff5d2792362e890 /assuan | |
parent | gpgsm does now build and a dummy server can be started. (diff) | |
download | gnupg2-7166bd6a5d4e6dd850062c12362f33240b9b2124.tar.xz gnupg2-7166bd6a5d4e6dd850062c12362f33240b9b2124.zip |
Assuan server mode is now basically usable
Diffstat (limited to 'assuan')
-rw-r--r-- | assuan/Makefile.am | 2 | ||||
-rw-r--r-- | assuan/assuan-buffer.c | 113 | ||||
-rw-r--r-- | assuan/assuan-connect.c | 27 | ||||
-rw-r--r-- | assuan/assuan-defs.h | 28 | ||||
-rw-r--r-- | assuan/assuan-handler.c | 189 | ||||
-rw-r--r-- | assuan/assuan-listen.c | 86 | ||||
-rw-r--r-- | assuan/assuan-pipe-server.c | 4 | ||||
-rw-r--r-- | assuan/assuan-util.c | 8 | ||||
-rw-r--r-- | assuan/assuan.h | 30 | ||||
-rwxr-xr-x | assuan/mkerrors | 2 |
10 files changed, 428 insertions, 61 deletions
diff --git a/assuan/Makefile.am b/assuan/Makefile.am index ad415afe5..b7a1a85cb 100644 --- a/assuan/Makefile.am +++ b/assuan/Makefile.am @@ -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 diff --git a/assuan/assuan-buffer.c b/assuan/assuan-buffer.c index c767a0e61..73786b631 100644 --- a/assuan/assuan-buffer.c +++ b/assuan/assuan-buffer.c @@ -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; + + 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; + } - 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; } diff --git a/assuan/assuan-connect.c b/assuan/assuan-connect.c new file mode 100644 index 000000000..d1c87fc2b --- /dev/null +++ b/assuan/assuan-connect.c @@ -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" + diff --git a/assuan/assuan-defs.h b/assuan/assuan-defs.h index 3402a91cb..d3e0439dc 100644 --- a/assuan/assuan-defs.h +++ b/assuan/assuan-defs.h @@ -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*/ diff --git a/assuan/assuan-handler.c b/assuan/assuan-handler.c index aeeb336e3..cebb78643 100644 --- a/assuan/assuan-handler.c +++ b/assuan/assuan-handler.c @@ -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) { - if (*line == 'D' && line[1] == ' ') /* divert to special handler */ - return handle_data_line (ctx, line+2); + char *p; + const char *s; + int shift, i; - - return set_error (ctx, Not_Implemented, NULL); + 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); + + /* 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; +} diff --git a/assuan/assuan-listen.c b/assuan/assuan-listen.c new file mode 100644 index 000000000..f8ccb2708 --- /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 <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; +} + + diff --git a/assuan/assuan-pipe-server.c b/assuan/assuan-pipe-server.c index 3dd0ab052..018d05df4 100644 --- a/assuan/assuan-pipe-server.c +++ b/assuan/assuan-pipe-server.c @@ -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) diff --git a/assuan/assuan-util.c b/assuan/assuan-util.c index 849cd3f36..3a9496e41 100644 --- a/assuan/assuan-util.c +++ b/assuan/assuan-util.c @@ -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; diff --git a/assuan/assuan.h b/assuan/assuan.h index b70b1613d..3806d5d40 100644 --- a/assuan/assuan.h +++ b/assuan/assuan.h @@ -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,11 +75,17 @@ 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 --*/ @@ -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); diff --git a/assuan/mkerrors b/assuan/mkerrors index 0906cdae1..13eabde7b 100755 --- a/assuan/mkerrors +++ b/assuan/mkerrors @@ -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)); } ' |