Updated Assuan to the current version

This commit is contained in:
Werner Koch 2001-12-13 15:04:36 +00:00
parent 70720764e1
commit 3de2384ea5
11 changed files with 945 additions and 86 deletions

View File

@ -1,3 +1,46 @@
2001-12-12 Werner Koch <wk@gnupg.org>
* assuan-connect.c (assuan_pipe_connect): Implemented the inital
handshake.
* assuan-client.c (read_from_server): Renamed to
(_assuan_read_from_server): this and made external.
* assuan-listen.c (assuan_set_hello_line): New.
(assuan_accept): Use a custom hello line is available.
* assuan-buffer.c (assuan_read_line): New.
(assuan_pending_line): New.
(_assuan_write_line): Renamed to ..
(assuan_write_line): this, made public and changed all callers.
2001-12-04 Werner Koch <wk@gnupg.org>
* assuan-connect.c (assuan_pipe_connect): Add more error reporting.
* assuan-client.c: New.
* assuan-inquire.c: New.
* assuan-handler.c (process_request): Check for nested invocations.
2001-11-27 Werner Koch <wk@gnupg.org>
* assuan-handler.c (assuan_register_input_notify): New.
(assuan_register_output_notify): New.
2001-11-26 Werner Koch <wk@gnupg.org>
* assuan.h: Added more status codes.
2001-11-25 Werner Koch <wk@gnupg.org>
* assuan-handler.c (assuan_register_bye_notify)
(assuan_register_reset_notify)
(assuan_register_cancel_notify): New and call them from the
standard handlers.
(assuan_process): Moved bulk of function to ..
(process_request): .. new.
(assuan_process_next): One shot version of above.
(assuan_get_active_fds): New.
2001-11-24 Werner Koch <wk@gnupg.org> 2001-11-24 Werner Koch <wk@gnupg.org>
* assuan-connect.c (assuan_get_pid): New. * assuan-connect.c (assuan_get_pid): New.

View File

@ -34,8 +34,10 @@ libassuan_a_SOURCES = \
assuan-errors.c \ assuan-errors.c \
assuan-buffer.c \ assuan-buffer.c \
assuan-handler.c \ assuan-handler.c \
assuan-inquire.c \
assuan-listen.c \ assuan-listen.c \
assuan-connect.c \ assuan-connect.c \
assuan-client.c \
assuan-pipe-server.c assuan-pipe-server.c

View File

@ -123,16 +123,25 @@ _assuan_read_line (ASSUAN_CONTEXT ctx)
return -1; return -1;
} }
ctx->inbound.attic.pending = 0;
for (n=0; n < nread; n++) for (n=0; n < nread; n++)
{ {
if (line[n] == '\n') if (line[n] == '\n')
{ {
if (n+1 < nread) if (n+1 < nread)
{ {
char *s, *d;
int i;
n++; n++;
/* we have to copy the rest because the handlers are /* we have to copy the rest because the handlers are
allowed to modify the passed buffer */ allowed to modify the passed buffer */
memcpy (ctx->inbound.attic.line, line+n, nread-n); for (d=ctx->inbound.attic.line, s=line+n, i=nread-n; i; i--)
{
if (*s=='\n')
ctx->inbound.attic.pending = 1;
*d++ = *s++;
}
ctx->inbound.attic.linelen = nread-n; ctx->inbound.attic.linelen = nread-n;
n--; n--;
} }
@ -150,13 +159,44 @@ _assuan_read_line (ASSUAN_CONTEXT ctx)
} }
/* Read the next line from the client or server and return a pointer
to a buffer with holding that line. linelen returns the length of
the line. This buffer is valid until another read operation is
done on this buffer. The caller is allowed to modify this buffer.
He should only use the buffer if the function returns without an
error.
Returns: 0 on success or an assuan error code
See also: assuan_pending_line().
*/
AssuanError
assuan_read_line (ASSUAN_CONTEXT ctx, char **line, size_t *linelen)
{
if (!ctx)
return ASSUAN_Invalid_Value;
*line = ctx->inbound.line;
*linelen = ctx->inbound.linelen;
return _assuan_read_line (ctx);
}
/* Return true when a full line is pending for a read, without the need
for actual IO */
int int
_assuan_write_line (ASSUAN_CONTEXT ctx, const char *line ) assuan_pending_line (ASSUAN_CONTEXT ctx)
{
return ctx && ctx->inbound.attic.pending;
}
AssuanError
assuan_write_line (ASSUAN_CONTEXT ctx, const char *line )
{ {
int rc; int rc;
if (!ctx)
return ASSUAN_Invalid_Value;
/* fixme: we should do some kind of line buffering */ /* fixme: we should do some kind of line buffering */
rc = writen (ctx->outbound.fd, line, strlen(line)); rc = writen (ctx->outbound.fd, line, strlen(line));
if (rc) if (rc)
@ -265,5 +305,50 @@ _assuan_cookie_write_flush (void *cookie)
} }
/**
* assuan_send_data:
* @ctx: An assuan context
* @buffer: Data to send or NULL to flush
* @length: length of the data to send/
*
* This function may be used by the server or the client to send data
* lines. The data will be escaped as required by the Assuan protocol
* and may get buffered until a line is full. To force sending the
* data out @buffer may be passed as NULL (in which case @length must
* also be 0); however when used by a client this flush operation does
* also send the terminating "END" command to terminate the reponse on
* a INQUIRE response. However, when assuan_transact() is used, this
* function takes care of sending END itself.
*
* Return value: 0 on success or an error code
**/
AssuanError
assuan_send_data (ASSUAN_CONTEXT ctx, const void *buffer, size_t length)
{
if (!ctx)
return ASSUAN_Invalid_Value;
if (!buffer && length)
return ASSUAN_Invalid_Value;
if (!buffer)
{ /* flush what we have */
_assuan_cookie_write_flush (ctx);
if (ctx->outbound.data.error)
return ctx->outbound.data.error;
if (!ctx->is_server)
return assuan_write_line (ctx, "END");
}
else
{
_assuan_cookie_write_data (ctx, buffer, length);
if (ctx->outbound.data.error)
return ctx->outbound.data.error;
}
return 0;
}

180
assuan/assuan-client.c Normal file
View File

@ -0,0 +1,180 @@
/* assuan-client.c - client functions
* 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 <errno.h>
#include <unistd.h>
#include <assert.h>
#include "assuan-defs.h"
#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
*(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
AssuanError
_assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off)
{
char *line;
int linelen;
AssuanError rc;
*okay = 0;
*off = 0;
do
{
rc = _assuan_read_line (ctx);
if (rc)
return rc;
line = ctx->inbound.line;
linelen = ctx->inbound.linelen;
}
while (*line == '#' || !linelen);
if (linelen >= 1
&& line[0] == 'D' && line[1] == ' ')
{
*okay = 2; /* data line */
*off = 2;
}
else if (linelen >= 2
&& line[0] == 'O' && line[1] == 'K'
&& (line[2] == '\0' || line[2] == ' '))
{
*okay = 1;
*off = 2;
}
else if (linelen >= 3
&& line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
&& (line[3] == '\0' || line[3] == ' '))
{
*okay = 0;
*off = 3;
}
else if (linelen >= 7
&& line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
&& line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
&& line[6] == 'E'
&& (line[7] == '\0' || line[7] == ' '))
{
*okay = 3;
*off = 7;
}
else
rc = ASSUAN_Invalid_Response;
return rc;
}
/**
* assuan_transact:
* @ctx: The Assuan context
* @command: Coimmand line to be send to server
* @data_cb: Callback function for data lines
* @data_cb_arg: first argument passed to @data_cb
* @inquire_cb: Callback function for a inquire response
* @inquire_cb_arg: first argument passed to @inquire_cb
*
* FIXME: Write documentation
*
* Return value: 0 on success or error code. The error code may be
* the one one returned by the server in error lines or from the
* callback functions.
**/
AssuanError
assuan_transact (ASSUAN_CONTEXT ctx,
const char *command,
AssuanError (*data_cb)(void *, const void *, size_t),
void *data_cb_arg,
AssuanError (*inquire_cb)(void*, const char *),
void *inquire_cb_arg)
{
int rc, okay, off;
unsigned char *line;
int linelen;
rc = assuan_write_line (ctx, command);
if (rc)
return rc;
again:
rc = _assuan_read_from_server (ctx, &okay, &off);
if (rc)
return rc; /* error reading from server */
line = ctx->inbound.line + off;
linelen = ctx->inbound.linelen - off;
if (!okay)
{
rc = atoi (line);
if (rc < 100)
rc = ASSUAN_Server_Fault;
}
else if (okay == 2)
{
if (!data_cb)
rc = ASSUAN_No_Data_Callback;
else
{
unsigned char *s, *d;
for (s=d=line; linelen; linelen--)
{
if (*s == '%' && linelen > 2)
{ /* handle escaping */
s++;
*d++ = xtoi_2 (s);
s += 2;
linelen -= 2;
}
else
*d++ = *s++;
}
*d = 0; /* add a hidden string terminator */
rc = data_cb (data_cb_arg, line, d - line);
if (!rc)
goto again;
}
}
else if (okay == 3)
{
if (!inquire_cb)
{
assuan_write_line (ctx, "END"); /* get out of inquire mode */
_assuan_read_from_server (ctx, &okay, &off); /* dummy read */
rc = ASSUAN_No_Inquire_Callback;
}
else
{
rc = inquire_cb (inquire_cb_arg, line);
if (!rc)
rc = assuan_send_data (ctx, NULL, 0); /* flush and send END */
if (!rc)
goto again;
}
}
return rc;
}

View File

@ -18,17 +18,57 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/ */
#ifdef HAVE_CONFIG_H
#include <config.h> #include <config.h>
#endif
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <signal.h> #include <signal.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include "assuan-defs.h" #include "assuan-defs.h"
#ifdef _POSIX_OPEN_MAX
#define MAX_OPEN_FDS _POSIX_OPEN_MAX
#else
#define MAX_OPEN_FDS 20
#endif
#ifdef HAVE_JNLIB_LOGGING
#include "../jnlib/logging.h"
#define LOGERROR1(a,b) log_error ((a), (b))
#else
#define LOGERROR1(a,b) fprintf (stderr, (a), (b))
#endif
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 */
}
/* Connect to a server over a pipe, creating the assuan context and /* Connect to a server over a pipe, creating the assuan context and
returning it in CTX. The server filename is NAME, the argument returning it in CTX. The server filename is NAME, the argument
vector in ARGV. */ vector in ARGV. */
@ -41,8 +81,8 @@ assuan_pipe_connect (ASSUAN_CONTEXT *ctx, const char *name, char *const argv[])
int wp[2]; int wp[2];
int fd[2]; int fd[2];
if (!name || !argv || !argv[0]) if (!ctx || !name || !argv || !argv[0])
return ASSUAN_General_Error; return ASSUAN_Invalid_Value;
if (!fixed_signals) if (!fixed_signals)
{ {
@ -82,6 +122,7 @@ assuan_pipe_connect (ASSUAN_CONTEXT *ctx, const char *name, char *const argv[])
close (wp[1]); close (wp[1]);
return err; return err;
} }
(*ctx)->is_server = 0;
(*ctx)->pid = fork (); (*ctx)->pid = fork ();
if ((*ctx)->pid < 0) if ((*ctx)->pid < 0)
@ -96,32 +137,89 @@ assuan_pipe_connect (ASSUAN_CONTEXT *ctx, const char *name, char *const argv[])
if ((*ctx)->pid == 0) if ((*ctx)->pid == 0)
{ {
close (rp[0]); int i, n;
close (wp[1]); char errbuf[512];
#ifdef HAVE_JNLIB_LOGGING
int log_fd = log_get_fd ();
#endif
/* close all files which will not be duped but keep stderr
and log_stream for now */
n = sysconf (_SC_OPEN_MAX);
if (n < 0)
n = MAX_OPEN_FDS;
for (i=0; i < n; i++)
{
if (i != fileno (stderr)
#ifdef HAVE_JNLIB_LOGGING
&& i != log_fd
#endif
&& i != rp[1] && i != wp[0])
close(i);
}
errno = 0;
/* Dup handles and to stdin/stdout and exec */
if (rp[1] != STDOUT_FILENO) if (rp[1] != STDOUT_FILENO)
{ {
dup2 (rp[1], STDOUT_FILENO); /* Child's outbound is write end of read pipe. */ if (dup2 (rp[1], STDOUT_FILENO) == -1)
close (rp[1]); {
} LOGERROR1 ("dup2 failed in child: %s\n", strerror (errno));
_exit (4);
}
close (rp[1]);
}
if (wp[0] != STDIN_FILENO) if (wp[0] != STDIN_FILENO)
{ {
dup2 (wp[0], STDIN_FILENO); /* Child's inbound is read end of write pipe. */ if (dup2 (wp[0], STDIN_FILENO) == -1)
close (wp[0]); {
} LOGERROR1 ("dup2 failed in child: %s\n", strerror (errno));
_exit (4);
}
close (wp[0]);
}
execv (name, argv); execv (name, argv);
_exit (1); /* oops - use the pipe to tell the parent about it */
snprintf (errbuf, sizeof(errbuf)-1, "ERR %d can't exec `%s': %.50s\n",
ASSUAN_Problem_Starting_Server, name, strerror (errno));
errbuf[sizeof(errbuf)-1] = 0;
writen (1, errbuf, strlen (errbuf));
_exit (4);
} }
close (rp[1]); close (rp[1]);
close (wp[0]); close (wp[0]);
_assuan_read_line (*ctx); /* FIXME: Handshake. */
return 0; /* initial handshake */
{
int okay, off;
err = _assuan_read_from_server (*ctx, &okay, &off);
if (err)
{
LOGERROR1 ("can't connect server: %s\n", assuan_strerror (err));
}
else if (okay != 1)
{
LOGERROR1 ("can't connect server: `%s'\n", (*ctx)->inbound.line);
err = ASSUAN_Connect_Failed;
}
}
if (err)
{
if ((*ctx)->pid != -1)
waitpid ((*ctx)->pid, NULL, 0); /* FIXME Check return value. */
assuan_deinit_pipe_server (*ctx); /* FIXME: Common code should be factored out. */
}
return err;
} }
void void
assuan_pipe_disconnect (ASSUAN_CONTEXT ctx) assuan_pipe_disconnect (ASSUAN_CONTEXT ctx)
{ {
_assuan_write_line (ctx, "BYE"); assuan_write_line (ctx, "BYE");
close (ctx->inbound.fd); close (ctx->inbound.fd);
close (ctx->outbound.fd); close (ctx->outbound.fd);
waitpid (ctx->pid, NULL, 0); /* FIXME Check return value. */ waitpid (ctx->pid, NULL, 0); /* FIXME Check return value. */
@ -133,3 +231,5 @@ assuan_get_pid (ASSUAN_CONTEXT ctx)
{ {
return ctx ? ctx->pid : -1; return ctx ? ctx->pid : -1;
} }

View File

@ -36,6 +36,10 @@ struct assuan_context_s {
AssuanError err_no; AssuanError err_no;
const char *err_str; const char *err_str;
int is_server; /* set if this is context belongs to a server */
int in_inquire;
char *hello_line;
void *user_pointer; /* for assuan_[gs]et_pointer () */ void *user_pointer; /* for assuan_[gs]et_pointer () */
struct { struct {
@ -48,6 +52,7 @@ struct assuan_context_s {
struct { struct {
char line[LINELENGTH]; char line[LINELENGTH];
int linelen ; int linelen ;
int pending; /* i.e. at least one line is available in the attic */
} attic; } attic;
} inbound; } inbound;
@ -69,6 +74,12 @@ struct assuan_context_s {
size_t cmdtbl_used; /* used entries */ size_t cmdtbl_used; /* used entries */
size_t cmdtbl_size; /* allocated size of table */ size_t cmdtbl_size; /* allocated size of table */
void (*bye_notify_fnc)(ASSUAN_CONTEXT);
void (*reset_notify_fnc)(ASSUAN_CONTEXT);
void (*cancel_notify_fnc)(ASSUAN_CONTEXT);
void (*input_notify_fnc)(ASSUAN_CONTEXT, const char *);
void (*output_notify_fnc)(ASSUAN_CONTEXT, const char *);
int input_fd; /* set by INPUT command */ int input_fd; /* set by INPUT command */
int output_fd; /* set by OUTPUT command */ int output_fd; /* set by OUTPUT command */
@ -82,12 +93,12 @@ struct assuan_context_s {
int _assuan_register_std_commands (ASSUAN_CONTEXT ctx); int _assuan_register_std_commands (ASSUAN_CONTEXT ctx);
/*-- assuan-buffer.c --*/ /*-- assuan-buffer.c --*/
int _assuan_write_line (ASSUAN_CONTEXT ctx, const char *line);
int _assuan_read_line (ASSUAN_CONTEXT ctx); int _assuan_read_line (ASSUAN_CONTEXT ctx);
int _assuan_cookie_write_data (void *cookie, const char *buffer, size_t size); int _assuan_cookie_write_data (void *cookie, const char *buffer, size_t size);
int _assuan_cookie_write_flush (void *cookie); int _assuan_cookie_write_flush (void *cookie);
/*-- assuan-client.c --*/
AssuanError _assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off);
/*-- assuan-util.c --*/ /*-- assuan-util.c --*/

View File

@ -44,12 +44,16 @@ std_handler_nop (ASSUAN_CONTEXT ctx, char *line)
static int static int
std_handler_cancel (ASSUAN_CONTEXT ctx, char *line) std_handler_cancel (ASSUAN_CONTEXT ctx, char *line)
{ {
if (ctx->cancel_notify_fnc)
ctx->cancel_notify_fnc (ctx);
return set_error (ctx, Not_Implemented, NULL); return set_error (ctx, Not_Implemented, NULL);
} }
static int static int
std_handler_bye (ASSUAN_CONTEXT ctx, char *line) std_handler_bye (ASSUAN_CONTEXT ctx, char *line)
{ {
if (ctx->bye_notify_fnc)
ctx->bye_notify_fnc (ctx);
return -1; /* pretty simple :-) */ return -1; /* pretty simple :-) */
} }
@ -62,7 +66,9 @@ std_handler_auth (ASSUAN_CONTEXT ctx, char *line)
static int static int
std_handler_reset (ASSUAN_CONTEXT ctx, char *line) std_handler_reset (ASSUAN_CONTEXT ctx, char *line)
{ {
return set_error (ctx, Not_Implemented, NULL); if (ctx->reset_notify_fnc)
ctx->reset_notify_fnc (ctx);
return 0;
} }
static int static int
@ -82,8 +88,9 @@ parse_cmd_input_output (ASSUAN_CONTEXT ctx, char *line, int *rfd)
if (!digitp (*line)) if (!digitp (*line))
return set_error (ctx, Syntax_Error, "number required"); return set_error (ctx, Syntax_Error, "number required");
*rfd = strtoul (line, &endp, 10); *rfd = strtoul (line, &endp, 10);
if (*endp) /* remove that argument so that a notify handler won't see it */
return set_error (ctx, Syntax_Error, "garbage found"); memset (line, ' ', endp? (endp-line):strlen(line));
if (*rfd == ctx->inbound.fd) if (*rfd == ctx->inbound.fd)
return set_error (ctx, Parameter_Conflict, "fd same as inbound fd"); return set_error (ctx, Parameter_Conflict, "fd same as inbound fd");
if (*rfd == ctx->outbound.fd) if (*rfd == ctx->outbound.fd)
@ -101,6 +108,8 @@ std_handler_input (ASSUAN_CONTEXT ctx, char *line)
if (rc) if (rc)
return rc; return rc;
ctx->input_fd = fd; ctx->input_fd = fd;
if (ctx->input_notify_fnc)
ctx->input_notify_fnc (ctx, line);
return 0; return 0;
} }
@ -114,6 +123,8 @@ std_handler_output (ASSUAN_CONTEXT ctx, char *line)
if (rc) if (rc)
return rc; return rc;
ctx->output_fd = fd; ctx->output_fd = fd;
if (ctx->output_notify_fnc)
ctx->output_notify_fnc (ctx, line);
return 0; return 0;
} }
@ -128,7 +139,7 @@ static struct {
const char *name; const char *name;
int cmd_id; int cmd_id;
int (*handler)(ASSUAN_CONTEXT, char *line); int (*handler)(ASSUAN_CONTEXT, char *line);
int always; /* always initializethis command */ int always; /* always initialize this command */
} std_cmd_table[] = { } std_cmd_table[] = {
{ "NOP", ASSUAN_CMD_NOP, std_handler_nop, 1 }, { "NOP", ASSUAN_CMD_NOP, std_handler_nop, 1 },
{ "CANCEL", ASSUAN_CMD_CANCEL, std_handler_cancel, 1 }, { "CANCEL", ASSUAN_CMD_CANCEL, std_handler_cancel, 1 },
@ -220,6 +231,54 @@ assuan_register_command (ASSUAN_CONTEXT ctx,
return 0; return 0;
} }
int
assuan_register_bye_notify (ASSUAN_CONTEXT ctx, void (*fnc)(ASSUAN_CONTEXT))
{
if (!ctx)
return ASSUAN_Invalid_Value;
ctx->bye_notify_fnc = fnc;
return 0;
}
int
assuan_register_reset_notify (ASSUAN_CONTEXT ctx, void (*fnc)(ASSUAN_CONTEXT))
{
if (!ctx)
return ASSUAN_Invalid_Value;
ctx->reset_notify_fnc = fnc;
return 0;
}
int
assuan_register_cancel_notify (ASSUAN_CONTEXT ctx, void (*fnc)(ASSUAN_CONTEXT))
{
if (!ctx)
return ASSUAN_Invalid_Value;
ctx->cancel_notify_fnc = fnc;
return 0;
}
int
assuan_register_input_notify (ASSUAN_CONTEXT ctx,
void (*fnc)(ASSUAN_CONTEXT, const char *))
{
if (!ctx)
return ASSUAN_Invalid_Value;
ctx->input_notify_fnc = fnc;
return 0;
}
int
assuan_register_output_notify (ASSUAN_CONTEXT ctx,
void (*fnc)(ASSUAN_CONTEXT, const char *))
{
if (!ctx)
return ASSUAN_Invalid_Value;
ctx->output_notify_fnc = fnc;
return 0;
}
/* Helper to register the standards commands */ /* Helper to register the standards commands */
int int
_assuan_register_std_commands (ASSUAN_CONTEXT ctx) _assuan_register_std_commands (ASSUAN_CONTEXT ctx)
@ -289,6 +348,61 @@ dispatch_command (ASSUAN_CONTEXT ctx, char *line, int linelen)
static int
process_request (ASSUAN_CONTEXT ctx)
{
int rc;
if (ctx->in_inquire)
return ASSUAN_Nested_Commands;
rc = _assuan_read_line (ctx);
if (rc)
return rc;
if (*ctx->inbound.line == '#' || !ctx->inbound.linelen)
return 0; /* comment line - ignore */
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 closing connection");
}
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);
}
return rc;
}
/** /**
* assuan_process: * assuan_process:
@ -307,55 +421,7 @@ assuan_process (ASSUAN_CONTEXT ctx)
int rc; int rc;
do { do {
/* Read the line but skip comments */ rc = process_request (ctx);
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); } while (!rc);
if (rc == -1) if (rc == -1)
@ -365,6 +431,65 @@ assuan_process (ASSUAN_CONTEXT ctx)
} }
/**
* assuan_process_next:
* @ctx: Assuan context
*
* Same as assuan_process() but the user has to provide the outer
* loop. He should loop as long as the return code is zero and stop
* otherwise; -1 is regular end.
*
* See also: assuan_get_active_fds()
* Return value: -1 for end of server, 0 on success or an error code
**/
int
assuan_process_next (ASSUAN_CONTEXT ctx)
{
return process_request (ctx);
}
/**
* assuan_get_active_fds:
* @ctx: Assuan context
* @what: 0 for read fds, 1 for write fds
* @fdarray: Caller supplied array to store the FDs
* @fdarraysize: size of that array
*
* Return all active filedescriptors for the given context. This
* function can be used to select on the fds and call
* assuan_process_next() if there is an active one.
*
* Note, that write FDs are not yet supported.
*
* Return value: number of FDs active and put into @fdarray or -1 on
* error which is most likely a too small fdarray.
**/
int
assuan_get_active_fds (ASSUAN_CONTEXT ctx, int what,
int *fdarray, int fdarraysize)
{
int n = 0;
if (ctx || fdarraysize < 2 || what < 0 || what > 1)
return -1;
if (!what)
{
if (ctx->inbound.fd != -1)
fdarray[n++] = ctx->inbound.fd;
}
else
{
if (ctx->outbound.fd != -1)
fdarray[n++] = ctx->outbound.fd;
if (ctx->outbound.data.fp)
fdarray[n++] = fileno (ctx->outbound.data.fp);
}
return n;
}
/* Return a FP to be used for data output. The FILE pointer is valid /* 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 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 all the buffering needed to insert the status line as well as the
@ -414,7 +539,7 @@ assuan_write_status (ASSUAN_CONTEXT ctx, const char *keyword, const char *text)
strcat (buffer, " "); strcat (buffer, " ");
strcat (buffer, text); strcat (buffer, text);
} }
_assuan_write_line (ctx, buffer); assuan_write_line (ctx, buffer);
} }
else if ( (helpbuf = xtrymalloc (n)) ) else if ( (helpbuf = xtrymalloc (n)) )
{ {
@ -425,7 +550,7 @@ assuan_write_status (ASSUAN_CONTEXT ctx, const char *keyword, const char *text)
strcat (helpbuf, " "); strcat (helpbuf, " ");
strcat (helpbuf, text); strcat (helpbuf, text);
} }
_assuan_write_line (ctx, helpbuf); assuan_write_line (ctx, helpbuf);
xfree (helpbuf); xfree (helpbuf);
} }
} }

220
assuan/assuan-inquire.c Normal file
View File

@ -0,0 +1,220 @@
/* assuan-inquire.c - handle inquire stuff
* 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')
#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
*(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
struct membuf {
size_t len;
size_t size;
char *buf;
int out_of_core;
int too_large;
size_t maxlen;
};
/* A simple implemnation of a dynamic buffer. Use init_membuf() to
create a buffer, put_membuf to append bytes and get_membuf to
release and return the buffer. Allocation errors are detected but
only returned at the final get_membuf(), this helps not to clutter
the code with out of core checks. */
static void
init_membuf (struct membuf *mb, int initiallen, size_t maxlen)
{
mb->len = 0;
mb->size = initiallen;
mb->out_of_core = 0;
mb->too_large = 0;
mb->maxlen = maxlen;
mb->buf = xtrymalloc (initiallen);
if (!mb->buf)
mb->out_of_core = 1;
}
static void
put_membuf (struct membuf *mb, const void *buf, size_t len)
{
if (mb->out_of_core || mb->too_large)
return;
if (mb->maxlen && mb->len + len > mb->maxlen)
{
mb->too_large = 1;
return;
}
if (mb->len + len >= mb->size)
{
char *p;
mb->size += len + 1024;
p = xtryrealloc (mb->buf, mb->size);
if (!p)
{
mb->out_of_core = 1;
return;
}
mb->buf = p;
}
memcpy (mb->buf + mb->len, buf, len);
mb->len += len;
}
static void *
get_membuf (struct membuf *mb, size_t *len)
{
char *p;
if (mb->out_of_core || mb->too_large)
{
xfree (mb->buf);
mb->buf = NULL;
return NULL;
}
p = mb->buf;
*len = mb->len;
mb->buf = NULL;
mb->out_of_core = 1; /* don't allow a reuse */
return p;
}
static void
free_membuf (struct membuf *mb)
{
xfree (mb->buf);
mb->buf = NULL;
}
/**
* assuan_inquire:
* @ctx: An assuan context
* @keyword: The keyword used for the inquire
* @r_buffer: Returns an allocated buffer
* @r_length: Returns the length of this buffer
* @maxlen: If no 0, the size limit of the inquired data.
*
* A Server may use this to Send an inquire
*
* Return value: 0 on success or an ASSUAN error code
**/
AssuanError
assuan_inquire (ASSUAN_CONTEXT ctx, const char *keyword,
char **r_buffer, size_t *r_length, size_t maxlen)
{
AssuanError rc;
struct membuf mb;
char cmdbuf[100];
unsigned char *line, *p;
int linelen;
if (!ctx || !keyword || (10 + strlen (keyword) >= sizeof (cmdbuf))
|| !r_buffer || !r_length )
return ASSUAN_Invalid_Value;
if (!ctx->is_server)
return ASSUAN_Not_A_Server;
if (ctx->in_inquire)
return ASSUAN_Nested_Commands;
ctx->in_inquire = 1;
init_membuf (&mb, maxlen? maxlen:1024, maxlen);
strcpy (stpcpy (cmdbuf, "INQUIRE "), keyword);
rc = assuan_write_line (ctx, cmdbuf);
if (rc)
goto leave;
for (;;)
{
do
{
rc = _assuan_read_line (ctx);
if (rc)
goto leave;
line = ctx->inbound.line;
linelen = ctx->inbound.linelen;
}
while (*line == '#' || !linelen);
if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
&& (!line[3] || line[3] == ' '))
break; /* END command received*/
if (line[0] != 'D' || line[1] != ' ')
{
rc = ASSUAN_Unexpected_Command;
goto leave;
}
if (linelen < 3)
continue;
line += 2;
linelen -= 2;
p = line;
while (linelen)
{
for (;linelen && *p != '%'; linelen--, p++)
;
put_membuf (&mb, line, p-line);
if (linelen > 2)
{ /* handle escaping */
unsigned char tmp[1];
p++;
*tmp = xtoi_2 (p);
p += 2;
linelen -= 3;
put_membuf (&mb, tmp, 1);
}
line = p;
}
if (mb.too_large)
{
rc = ASSUAN_Too_Much_Data;
goto leave;
}
}
*r_buffer = get_membuf (&mb, r_length);
if (!*r_buffer)
rc = ASSUAN_Out_Of_Core;
leave:
free_membuf (&mb);
ctx->in_inquire = 0;
return rc;
}

View File

@ -25,6 +25,28 @@
#include "assuan-defs.h" #include "assuan-defs.h"
AssuanError
assuan_set_hello_line (ASSUAN_CONTEXT ctx, const char *line)
{
if (!ctx)
return ASSUAN_Invalid_Value;
if (!line)
{
xfree (ctx->hello_line);
ctx->hello_line = NULL;
}
else
{
char *buf = xtrymalloc (3+strlen(line)+1);
if (!buf)
return ASSUAN_Out_Of_Core;
strcpy (buf, "OK ");
strcpy (buf+3, line);
xfree (ctx->hello_line);
ctx->hello_line = buf;
}
return 0;
}
/** /**
@ -38,7 +60,7 @@
* Return value: 0 on success or an error if the connection could for * Return value: 0 on success or an error if the connection could for
* some reason not be established. * some reason not be established.
**/ **/
int AssuanError
assuan_accept (ASSUAN_CONTEXT ctx) assuan_accept (ASSUAN_CONTEXT ctx)
{ {
int rc; int rc;
@ -57,9 +79,8 @@ assuan_accept (ASSUAN_CONTEXT ctx)
} }
/* send the hello */ /* send the hello */
rc = assuan_write_line (ctx, ctx->hello_line? ctx->hello_line
rc = _assuan_write_line (ctx, : "OK Your orders please");
"OK Hello dear client - what can I do for you?");
if (rc) if (rc)
return rc; return rc;
@ -70,6 +91,7 @@ assuan_accept (ASSUAN_CONTEXT ctx)
} }
int int
assuan_get_input_fd (ASSUAN_CONTEXT ctx) assuan_get_input_fd (ASSUAN_CONTEXT ctx)
{ {

View File

@ -35,6 +35,7 @@ assuan_init_pipe_server (ASSUAN_CONTEXT *r_ctx, int filedes[2])
ctx = xtrycalloc (1, sizeof *ctx); ctx = xtrycalloc (1, sizeof *ctx);
if (!ctx) if (!ctx)
return ASSUAN_Out_Of_Core; return ASSUAN_Out_Of_Core;
ctx->is_server = 1;
ctx->input_fd = -1; ctx->input_fd = -1;
ctx->output_fd = -1; ctx->output_fd = -1;
@ -54,7 +55,11 @@ assuan_init_pipe_server (ASSUAN_CONTEXT *r_ctx, int filedes[2])
void void
assuan_deinit_pipe_server (ASSUAN_CONTEXT ctx) assuan_deinit_pipe_server (ASSUAN_CONTEXT ctx)
{ {
xfree (ctx); if (ctx)
{
xfree (ctx->hello_line);
xfree (ctx);
}
} }
@ -66,4 +71,3 @@ assuan_deinit_pipe_server (ASSUAN_CONTEXT ctx)

View File

@ -39,6 +39,14 @@ typedef enum {
ASSUAN_Timeout = 4, ASSUAN_Timeout = 4,
ASSUAN_Read_Error = 5, ASSUAN_Read_Error = 5,
ASSUAN_Write_Error = 6, ASSUAN_Write_Error = 6,
ASSUAN_Problem_Starting_Server = 7,
ASSUAN_Not_A_Server = 8,
ASSUAN_Not_A_Client = 9,
ASSUAN_Nested_Commands = 10,
ASSUAN_Invalid_Response = 11,
ASSUAN_No_Data_Callback = 12,
ASSUAN_No_Inquire_Callback = 13,
ASSUAN_Connect_Failed = 14,
/* error codes above 99 are meant as status codes */ /* error codes above 99 are meant as status codes */
ASSUAN_Not_Implemented = 100, ASSUAN_Not_Implemented = 100,
@ -53,10 +61,28 @@ typedef enum {
ASSUAN_No_Input = 109, ASSUAN_No_Input = 109,
ASSUAN_No_Output = 110, ASSUAN_No_Output = 110,
ASSUAN_Canceled = 111, ASSUAN_Canceled = 111,
ASSUAN_Unsupported_Algorithm = 112,
ASSUAN_Server_Resource_Problem = 113,
ASSUAN_Server_IO_Error = 114,
ASSUAN_Server_Bug = 115,
ASSUAN_No_Data_Available = 116,
ASSUAN_Invalid_Data = 117,
ASSUAN_Unexpected_Command = 118,
ASSUAN_Too_Much_Data = 119,
ASSUAN_Bad_Certificate = 201,
ASSUAN_Bad_Certificate_Path = 202,
ASSUAN_Missing_Certificate = 203,
ASSUAN_Bad_Signature = 204,
ASSUAN_No_Agent = 205,
ASSUAN_Agent_Error = 206,
ASSUAN_No_Public_Key = 207,
ASSUAN_No_Secret_Key = 208,
ASSUAN_Invalid_Name = 209,
ASSUAN_Cert_Revoked = 301, ASSUAN_Cert_Revoked = 301,
ASSUAN_No_CRL_For_Cert = 302, ASSUAN_No_CRL_For_Cert = 302,
ASSUNA_CRL_Too_Old = 303, ASSUAN_CRL_Too_Old = 303,
} AssuanError; } AssuanError;
@ -83,14 +109,30 @@ typedef struct assuan_context_s *ASSUAN_CONTEXT;
int assuan_register_command (ASSUAN_CONTEXT ctx, int assuan_register_command (ASSUAN_CONTEXT ctx,
int cmd_id, const char *cmd_string, int cmd_id, const char *cmd_string,
int (*handler)(ASSUAN_CONTEXT, char *)); int (*handler)(ASSUAN_CONTEXT, char *));
int assuan_register_bye_notify (ASSUAN_CONTEXT ctx,
void (*fnc)(ASSUAN_CONTEXT));
int assuan_register_reset_notify (ASSUAN_CONTEXT ctx,
void (*fnc)(ASSUAN_CONTEXT));
int assuan_register_cancel_notify (ASSUAN_CONTEXT ctx,
void (*fnc)(ASSUAN_CONTEXT));
int assuan_register_input_notify (ASSUAN_CONTEXT ctx,
void (*fnc)(ASSUAN_CONTEXT, const char *));
int assuan_register_output_notify (ASSUAN_CONTEXT ctx,
void (*fnc)(ASSUAN_CONTEXT, const char *));
int assuan_process (ASSUAN_CONTEXT ctx); int assuan_process (ASSUAN_CONTEXT ctx);
int assuan_process_next (ASSUAN_CONTEXT ctx);
int assuan_get_active_fds (ASSUAN_CONTEXT ctx, int what,
int *fdarray, int fdarraysize);
FILE *assuan_get_data_fp (ASSUAN_CONTEXT ctx); FILE *assuan_get_data_fp (ASSUAN_CONTEXT ctx);
void assuan_write_status (ASSUAN_CONTEXT ctx, void assuan_write_status (ASSUAN_CONTEXT ctx,
const char *keyword, const char *text); const char *keyword, const char *text);
/*-- assuan-listen.c --*/ /*-- assuan-listen.c --*/
int assuan_accept (ASSUAN_CONTEXT ctx); AssuanError assuan_set_hello_line (ASSUAN_CONTEXT ctx, const char *line);
AssuanError assuan_accept (ASSUAN_CONTEXT ctx);
int assuan_get_input_fd (ASSUAN_CONTEXT ctx); int assuan_get_input_fd (ASSUAN_CONTEXT ctx);
int assuan_get_output_fd (ASSUAN_CONTEXT ctx); int assuan_get_output_fd (ASSUAN_CONTEXT ctx);
@ -106,6 +148,29 @@ AssuanError assuan_pipe_connect (ASSUAN_CONTEXT *ctx, const char *name,
void assuan_pipe_disconnect (ASSUAN_CONTEXT ctx); void assuan_pipe_disconnect (ASSUAN_CONTEXT ctx);
pid_t assuan_get_pid (ASSUAN_CONTEXT ctx); pid_t assuan_get_pid (ASSUAN_CONTEXT ctx);
/*-- assuan-client.c --*/
AssuanError
assuan_transact (ASSUAN_CONTEXT ctx,
const char *command,
AssuanError (*data_cb)(void *, const void *, size_t),
void *data_cb_arg,
AssuanError (*inquire_cb)(void*, const char *),
void *inquire_cb_arg);
/*-- assuan-inquire.c --*/
AssuanError assuan_inquire (ASSUAN_CONTEXT ctx, const char *keyword,
char **r_buffer, size_t *r_length, size_t maxlen);
/*-- assuan-buffer.c --*/
AssuanError assuan_read_line (ASSUAN_CONTEXT ctx,
char **line, size_t *linelen);
int assuan_pending_line (ASSUAN_CONTEXT ctx);
AssuanError assuan_write_line (ASSUAN_CONTEXT ctx, const char *line );
AssuanError assuan_send_data (ASSUAN_CONTEXT ctx,
const void *buffer, size_t length);
/*-- assuan-util.c --*/ /*-- assuan-util.c --*/
void assuan_set_malloc_hooks ( void *(*new_alloc_func)(size_t n), void assuan_set_malloc_hooks ( void *(*new_alloc_func)(size_t n),
void *(*new_realloc_func)(void *p, size_t n), void *(*new_realloc_func)(void *p, size_t n),
@ -123,3 +188,5 @@ const char *assuan_strerror (AssuanError err);
} }
#endif #endif
#endif /*ASSUAN_H*/ #endif /*ASSUAN_H*/