From 33c20b87d1624f9ce40d1474ab765052decf7811 Mon Sep 17 00:00:00 2001 From: Marcus Brinkmann Date: Tue, 22 Jan 2002 16:29:12 +0000 Subject: [PATCH] Update to current version in newpg module. --- trunk/assuan/ChangeLog | 68 ++++++- trunk/assuan/Makefile.am | 5 +- trunk/assuan/assuan-buffer.c | 56 +++++- trunk/assuan/assuan-client.c | 6 + trunk/assuan/assuan-connect.c | 210 +-------------------- trunk/assuan/assuan-defs.h | 22 ++- trunk/assuan/assuan-handler.c | 129 ++++++++++++- trunk/assuan/assuan-inquire.c | 9 +- trunk/assuan/assuan-listen.c | 10 +- trunk/assuan/assuan-pipe-connect.c | 269 +++++++++++++++++++++++++++ trunk/assuan/assuan-pipe-server.c | 80 ++++++-- trunk/assuan/assuan-socket-connect.c | 150 +++++++++++++++ trunk/assuan/assuan-socket-server.c | 121 ++++++++++++ trunk/assuan/assuan-util.c | 98 ++++++++++ trunk/assuan/assuan.h | 31 ++- trunk/jnlib/ChangeLog | 16 ++ trunk/jnlib/Makefile.am | 17 +- trunk/jnlib/argparse.c | 2 +- trunk/jnlib/libjnlib-config.h | 16 +- trunk/jnlib/logging.c | 163 ++++++++++------ trunk/jnlib/logging.h | 27 +++ trunk/jnlib/strlist.c | 133 +++++++++++++ trunk/jnlib/strlist.h | 43 +++++ 23 files changed, 1372 insertions(+), 309 deletions(-) create mode 100644 trunk/assuan/assuan-pipe-connect.c create mode 100644 trunk/assuan/assuan-socket-connect.c create mode 100644 trunk/assuan/assuan-socket-server.c create mode 100644 trunk/jnlib/strlist.c create mode 100644 trunk/jnlib/strlist.h diff --git a/trunk/assuan/ChangeLog b/trunk/assuan/ChangeLog index dbf5f43..76cd68e 100644 --- a/trunk/assuan/ChangeLog +++ b/trunk/assuan/ChangeLog @@ -1,3 +1,69 @@ +2002-01-22 Marcus Brinkmann + + * assuan-socket-connect.c (LOGERRORX): Reverse arguments to fputs. + +2002-01-21 Werner Koch + + * assuan-connect.c: Move all except assuan_get_pid to... + * assuan-pipe-connect.c: this. + (assuan_pipe_disconnect): Removed. + (do_finish, do_deinit): New + (assuan_pipe_connect): and set them into the context. + * assuan-socket-connect.c: New. + + * assuan-util.c (_assuan_log_sanitized_string): New. + + * assuan-pipe-server.c (assuan_init_pipe_server): Factored most + code out to ... + (_assuan_new_context): new func. + (_assuan_release_context): New + * assuan-connect.c (assuan_pipe_connect): Use the new functions. + +2002-01-20 Werner Koch + + * assuan.h: Added Invalid Option error code. + + * assuan-handler.c (std_handler_option): New. + (std_cmd_tbl): Add OPTION as standard command. + (assuan_register_option_handler): New. + (dispatch_command): Use case insensitive matching as a fallback. + (my_strcasecmp): New. + +2002-01-19 Werner Koch + + * assuan-buffer.c (_assuan_read_line): Add output logging. + (assuan_write_line): Ditto. + (_assuan_cookie_write_data): Ditto. + (_assuan_cookie_write_flush): Ditto. + * assuan-util.c (_assuan_log_print_buffer): New. + (assuan_set_log_stream): New. + (assuan_begin_confidential): New. + (assuan_end_confidential): New. + + * assuan-defs.h: Add a few handler variables. + * assuan-pipe-server.c (assuan_deinit_pipe_server): Removed. + (deinit_pipe_server): New. + (assuan_deinit_server): New. Changed all callers to use this. + * assuan-listen.c (assuan_accept): Use the accept handler. + * assuan-handler.c (process_request): Use the close Handler. + * assuan-socket-server.c: New. + +2002-01-14 Werner Koch + + * assuan-client.c (_assuan_read_from_server): Skip spaces after + the keyword. + +2002-01-03 Werner Koch + + * assuan-handler.c (assuan_set_okay_line): New. + (process_request): And use it here. + +2002-01-02 Werner Koch + + * assuan-inquire.c (init_membuf,put_membuf,get_membuf): Apply a + hidden 0 behind the buffer so that the buffer can be used as a + string in certain contexts. + 2001-12-14 Marcus Brinkmann * assuan-connect.c (assuan_pipe_connect): New argument @@ -90,7 +156,7 @@ * You may find it source-copied in other packages. * *********************************************************** - Copyright 2001 Free Software Foundation, Inc. + Copyright 2001, 2002 Free Software Foundation, Inc. This file is free software; as a special exception the author gives unlimited permission to copy and/or distribute it, with or without diff --git a/trunk/assuan/Makefile.am b/trunk/assuan/Makefile.am index bc14e8f..7508dce 100644 --- a/trunk/assuan/Makefile.am +++ b/trunk/assuan/Makefile.am @@ -38,7 +38,10 @@ libassuan_a_SOURCES = \ assuan-listen.c \ assuan-connect.c \ assuan-client.c \ - assuan-pipe-server.c + assuan-pipe-server.c \ + assuan-socket-server.c \ + assuan-pipe-connect.c \ + assuan-socket-connect.c assuan-errors.c : assuan.h diff --git a/trunk/assuan/assuan-buffer.c b/trunk/assuan/assuan-buffer.c index 399d11d..bd08817 100644 --- a/trunk/assuan/assuan-buffer.c +++ b/trunk/assuan/assuan-buffer.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -119,10 +120,17 @@ _assuan_read_line (ASSUAN_CONTEXT ctx) rc = readline (ctx->inbound.fd, line, LINELENGTH, &nread, &ctx->inbound.eof); if (rc) - return ASSUAN_Read_Error; + { + if (ctx->log_fp) + fprintf (ctx->log_fp, "%p <- [Error: %s]\n", + ctx, strerror (errno)); + return ASSUAN_Read_Error; + } if (!nread) { assert (ctx->inbound.eof); + if (ctx->log_fp) + fprintf (ctx->log_fp, "%p <- [EOF]\n", ctx); return -1; } @@ -153,10 +161,23 @@ _assuan_read_line (ASSUAN_CONTEXT ctx) n--; line[n] = 0; ctx->inbound.linelen = n; + if (ctx->log_fp) + { + fprintf (ctx->log_fp, "%p <- ", ctx); + if (ctx->confidential) + fputs ("[Confidential data not shown]", ctx->log_fp); + else + _assuan_log_print_buffer (ctx->log_fp, + ctx->inbound.line, + ctx->inbound.linelen); + putc ('\n', ctx->log_fp); + } return 0; } } + if (ctx->log_fp) + fprintf (ctx->log_fp, "%p <- [Invalid line]\n", ctx); *line = 0; ctx->inbound.linelen = 0; return ctx->inbound.eof? ASSUAN_Line_Not_Terminated : ASSUAN_Line_Too_Long; @@ -206,6 +227,17 @@ assuan_write_line (ASSUAN_CONTEXT ctx, const char *line ) return ASSUAN_Invalid_Value; /* fixme: we should do some kind of line buffering */ + if (ctx->log_fp) + { + fprintf (ctx->log_fp, "%p -> ", ctx); + if (ctx->confidential) + fputs ("[Confidential data not shown]", ctx->log_fp); + else + _assuan_log_print_buffer (ctx->log_fp, + line, strlen (line)); + putc ('\n', ctx->log_fp); + } + rc = writen (ctx->outbound.fd, line, strlen(line)); if (rc) rc = ASSUAN_Write_Error; @@ -266,6 +298,17 @@ _assuan_cookie_write_data (void *cookie, const char *buffer, size_t size) if (linelen >= LINELENGTH-2-2) { + if (ctx->log_fp) + { + fprintf (ctx->log_fp, "%p -> ", ctx); + if (ctx->confidential) + fputs ("[Confidential data not shown]", ctx->log_fp); + else + _assuan_log_print_buffer (ctx->log_fp, + ctx->outbound.data.line, + linelen); + putc ('\n', ctx->log_fp); + } *line++ = '\n'; linelen++; if (writen (ctx->outbound.fd, ctx->outbound.data.line, linelen)) @@ -300,6 +343,17 @@ _assuan_cookie_write_flush (void *cookie) line += linelen; if (linelen) { + if (ctx->log_fp) + { + fprintf (ctx->log_fp, "%p -> ", ctx); + if (ctx->confidential) + fputs ("[Confidential data not shown]", ctx->log_fp); + else + _assuan_log_print_buffer (ctx->log_fp, + ctx->outbound.data.line, + linelen); + putc ('\n', ctx->log_fp); + } *line++ = '\n'; linelen++; if (writen (ctx->outbound.fd, ctx->outbound.data.line, linelen)) diff --git a/trunk/assuan/assuan-client.c b/trunk/assuan/assuan-client.c index a555cf3..d56357d 100644 --- a/trunk/assuan/assuan-client.c +++ b/trunk/assuan/assuan-client.c @@ -63,6 +63,8 @@ _assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off) { *okay = 1; *off = 2; + while (line[*off] == ' ') + ++*off; } else if (linelen >= 3 && line[0] == 'E' && line[1] == 'R' && line[2] == 'R' @@ -70,6 +72,8 @@ _assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off) { *okay = 0; *off = 3; + while (line[*off] == ' ') + ++*off; } else if (linelen >= 7 && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q' @@ -79,6 +83,8 @@ _assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off) { *okay = 3; *off = 7; + while (line[*off] == ' ') + ++*off; } else rc = ASSUAN_Invalid_Response; diff --git a/trunk/assuan/assuan-connect.c b/trunk/assuan/assuan-connect.c index 613b54a..49d4aac 100644 --- a/trunk/assuan/assuan-connect.c +++ b/trunk/assuan/assuan-connect.c @@ -33,208 +33,18 @@ #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 ) +/* Disconnect and release the context CTX. */ +void +assuan_disconnect (ASSUAN_CONTEXT ctx) { - while (length) + if (ctx) { - int nwritten = write (fd, buffer, length); - - if (nwritten < 0) - { - if (errno == EINTR) - continue; - return -1; /* write error */ - } - length -= nwritten; - buffer += nwritten; + assuan_write_line (ctx, "BYE"); + ctx->finish_handler (ctx); + ctx->deinit_handler (ctx); + ctx->deinit_handler = NULL; + _assuan_release_context (ctx); } - return 0; /* okay */ -} - - - -/* 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. FD_CHILD_LIST is a -1 terminated list of file - descriptors not to close in the child. */ -AssuanError -assuan_pipe_connect (ASSUAN_CONTEXT *ctx, const char *name, char *const argv[], - int *fd_child_list) -{ - static int fixed_signals = 0; - AssuanError err; - int rp[2]; - int wp[2]; - int fd[2]; - - if (!ctx || !name || !argv || !argv[0]) - return ASSUAN_Invalid_Value; - - 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)->is_server = 0; - - (*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) - { - int i, n; - 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++) - { - int *fdp = fd_child_list; - - if (fdp) - { - while (*fdp != -1 && *fdp != i) - fdp++; - } - - if (!(fdp && *fdp != -1) - && 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 (dup2 (rp[1], STDOUT_FILENO) == -1) - { - LOGERROR1 ("dup2 failed in child: %s\n", strerror (errno)); - _exit (4); - } - close (rp[1]); - } - if (wp[0] != STDIN_FILENO) - { - if (dup2 (wp[0], STDIN_FILENO) == -1) - { - LOGERROR1 ("dup2 failed in child: %s\n", strerror (errno)); - _exit (4); - } - close (wp[0]); - } - - execv (name, argv); - /* 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 (wp[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 -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); } pid_t @@ -242,5 +52,3 @@ assuan_get_pid (ASSUAN_CONTEXT ctx) { return ctx ? ctx->pid : -1; } - - diff --git a/trunk/assuan/assuan-defs.h b/trunk/assuan/assuan-defs.h index ecabd38..7d55aab 100644 --- a/trunk/assuan/assuan-defs.h +++ b/trunk/assuan/assuan-defs.h @@ -35,13 +35,18 @@ struct cmdtbl_s { struct assuan_context_s { AssuanError err_no; const char *err_str; + int os_errno; /* last system error number used with certain error codes*/ + int confidential; int is_server; /* set if this is context belongs to a server */ int in_inquire; char *hello_line; + char *okay_line; /* see assan_set_okay_line() */ void *user_pointer; /* for assuan_[gs]et_pointer () */ + FILE *log_fp; + struct { int fd; int eof; @@ -68,7 +73,13 @@ struct assuan_context_s { 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. */ + pid_t pid; /* In pipe mode, the pid of the child server process. + In socket mode, the pid of the server */ + int listen_fd; /* The fd we are listening on (used by socket servers) */ + + void (*deinit_handler)(ASSUAN_CONTEXT); + int (*accept_handler)(ASSUAN_CONTEXT); + int (*finish_handler)(ASSUAN_CONTEXT); struct cmdtbl_s *cmdtbl; size_t cmdtbl_used; /* used entries */ @@ -77,6 +88,7 @@ struct assuan_context_s { void (*bye_notify_fnc)(ASSUAN_CONTEXT); void (*reset_notify_fnc)(ASSUAN_CONTEXT); void (*cancel_notify_fnc)(ASSUAN_CONTEXT); + int (*option_handler_fnc)(ASSUAN_CONTEXT,const char*, const char*); void (*input_notify_fnc)(ASSUAN_CONTEXT, const char *); void (*output_notify_fnc)(ASSUAN_CONTEXT, const char *); @@ -84,9 +96,12 @@ struct assuan_context_s { int input_fd; /* set by INPUT command */ int output_fd; /* set by OUTPUT command */ +}; -}; +/*-- assuan-pipe-server.c --*/ +int _assuan_new_context (ASSUAN_CONTEXT *r_ctx); +void _assuan_release_context (ASSUAN_CONTEXT ctx); /*-- assuan-handler.c --*/ @@ -114,6 +129,9 @@ void _assuan_free (void *p); #define set_error(c,e,t) assuan_set_error ((c), ASSUAN_ ## e, (t)) +void _assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length); +void _assuan_log_sanitized_string (const char *string); + #endif /*ASSUAN_DEFS_H*/ diff --git a/trunk/assuan/assuan-handler.c b/trunk/assuan/assuan-handler.c index a82bd53..1c8aded 100644 --- a/trunk/assuan/assuan-handler.c +++ b/trunk/assuan/assuan-handler.c @@ -25,6 +25,7 @@ #include "assuan-defs.h" +#define spacep(p) (*(p) == ' ' || *(p) == '\t') #define digitp(a) ((a) >= '0' && (a) <= '9') @@ -48,6 +49,53 @@ std_handler_cancel (ASSUAN_CONTEXT ctx, char *line) ctx->cancel_notify_fnc (ctx); return set_error (ctx, Not_Implemented, NULL); } + +static int +std_handler_option (ASSUAN_CONTEXT ctx, char *line) +{ + char *key, *value, *p; + + for (key=line; spacep (key); key++) + ; + if (!*key) + return set_error (ctx, Syntax_Error, "argument required"); + if (*key == '=') + return set_error (ctx, Syntax_Error, "no option name given"); + for (value=key; *value && !spacep (value) && *value != '='; value++) + ; + if (*value) + { + if (spacep (value)) + *value++ = 0; /* terminate key */ + for (; spacep (value); value++) + ; + if (*value == '=') + { + *value++ = 0; /* terminate key */ + for (; spacep (value); value++) + ; + if (!*value) + return set_error (ctx, Syntax_Error, "option argument expected"); + } + if (*value) + { + for (p = value + strlen(value) - 1; p > value && spacep (p); p--) + ; + if (p > value) + *++p = 0; /* strip trailing spaces */ + } + } + + if (*key == '-' && key[1] == '-' && key[2]) + key += 2; /* the double dashes are optional */ + if (*key == '-') + return set_error (ctx, Syntax_Error, + "option should not begin with one dash"); + + if (ctx->option_handler_fnc) + return ctx->option_handler_fnc (ctx, key, value); + return 0; +} static int std_handler_bye (ASSUAN_CONTEXT ctx, char *line) @@ -147,6 +195,7 @@ static struct { } std_cmd_table[] = { { "NOP", ASSUAN_CMD_NOP, std_handler_nop, 1 }, { "CANCEL", ASSUAN_CMD_CANCEL, std_handler_cancel, 1 }, + { "OPTION", ASSUAN_CMD_OPTION, std_handler_option, 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 }, @@ -154,6 +203,7 @@ static struct { { "INPUT", ASSUAN_CMD_INPUT, std_handler_input }, { "OUTPUT", ASSUAN_CMD_OUTPUT, std_handler_output }, + { "OPTION", ASSUAN_CMD_OPTION, std_handler_option, 1 }, { NULL } }; @@ -262,6 +312,17 @@ assuan_register_cancel_notify (ASSUAN_CONTEXT ctx, void (*fnc)(ASSUAN_CONTEXT)) return 0; } +int +assuan_register_option_handler (ASSUAN_CONTEXT ctx, + int (*fnc)(ASSUAN_CONTEXT, + const char*, const char*)) +{ + if (!ctx) + return ASSUAN_Invalid_Value; + ctx->option_handler_fnc = fnc; + return 0; +} + int assuan_register_input_notify (ASSUAN_CONTEXT ctx, void (*fnc)(ASSUAN_CONTEXT, const char *)) @@ -312,6 +373,20 @@ handle_data_line (ASSUAN_CONTEXT ctx, char *line, int linelen) return set_error (ctx, Not_Implemented, NULL); } +/* like ascii_strcasecmp but assume that B is already uppercase */ +static int +my_strcasecmp (const char *a, const char *b) +{ + if (a == b) + return 0; + + for (; *a && *b; a++, b++) + { + if (((*a >= 'a' && *a <= 'z')? (*a&~0x20):*a) != *b) + break; + } + return *a == *b? 0 : (((*a >= 'a' && *a <= 'z')? (*a&~0x20):*a) - *b); +} /* Parse the line, break out the command, find it in the command table, remove leading and white spaces from the arguments, all the @@ -339,8 +414,18 @@ dispatch_command (ASSUAN_CONTEXT ctx, char *line, int linelen) shift = p - line; for (i=0; (s=ctx->cmdtbl[i].name); i++) - if (!strcmp (line, s)) - break; + { + if (!strcmp (line, s)) + break; + } + if (!s) + { /* and try case insensitive */ + for (i=0; (s=ctx->cmdtbl[i].name); i++) + { + if (!my_strcasecmp (line, s)) + break; + } + } if (!s) return set_error (ctx, Unknown_Command, NULL); line += shift; @@ -382,17 +467,18 @@ process_request (ASSUAN_CONTEXT ctx) /* Error handling */ if (!rc) { - rc = assuan_write_line (ctx, "OK"); + rc = assuan_write_line (ctx, ctx->okay_line? ctx->okay_line : "OK"); } else if (rc == -1) { /* No error checking because the peer may have already disconnect */ assuan_write_line (ctx, "OK closing connection"); + ctx->finish_handler (ctx); } else { char errline[256]; - if (rc < 100) + if (rc < 100) sprintf (errline, "ERR %d server fault (%.50s)", ASSUAN_Server_Fault, assuan_strerror (rc)); else @@ -405,6 +491,12 @@ process_request (ASSUAN_CONTEXT ctx) rc = assuan_write_line (ctx, errline); } + ctx->confidential = 0; + if (ctx->okay_line) + { + xfree (ctx->okay_line); + ctx->okay_line = NULL; + } return rc; } @@ -522,6 +614,35 @@ assuan_get_data_fp (ASSUAN_CONTEXT ctx) } +/* Set the text used for the next OK reponse. This string is + automatically reset to NULL after the next command. */ +AssuanError +assuan_set_okay_line (ASSUAN_CONTEXT ctx, const char *line) +{ + if (!ctx) + return ASSUAN_Invalid_Value; + if (!line) + { + xfree (ctx->okay_line); + ctx->okay_line = NULL; + } + else + { + /* FIXME: we need to use gcry_is_secure() to test whether + we should allocate the entire line in secure memory */ + char *buf = xtrymalloc (3+strlen(line)+1); + if (!buf) + return ASSUAN_Out_Of_Core; + strcpy (buf, "OK "); + strcpy (buf+3, line); + xfree (ctx->okay_line); + ctx->okay_line = buf; + } + return 0; +} + + + void assuan_write_status (ASSUAN_CONTEXT ctx, const char *keyword, const char *text) { diff --git a/trunk/assuan/assuan-inquire.c b/trunk/assuan/assuan-inquire.c index 8fec77e..933091e 100644 --- a/trunk/assuan/assuan-inquire.c +++ b/trunk/assuan/assuan-inquire.c @@ -1,5 +1,5 @@ /* assuan-inquire.c - handle inquire stuff - * Copyright (C) 2001 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -56,7 +56,8 @@ init_membuf (struct membuf *mb, int initiallen, size_t maxlen) mb->out_of_core = 0; mb->too_large = 0; mb->maxlen = maxlen; - mb->buf = xtrymalloc (initiallen); + /* we need to allocate one byte more for get_membuf */ + mb->buf = xtrymalloc (initiallen+1); if (!mb->buf) mb->out_of_core = 1; } @@ -78,7 +79,8 @@ put_membuf (struct membuf *mb, const void *buf, size_t len) char *p; mb->size += len + 1024; - p = xtryrealloc (mb->buf, mb->size); + /* we need to allocate one byte more for get_membuf */ + p = xtryrealloc (mb->buf, mb->size+1); if (!p) { mb->out_of_core = 1; @@ -102,6 +104,7 @@ get_membuf (struct membuf *mb, size_t *len) return NULL; } + mb->buf[mb->len] = 0; /* there is enough space for the hidden eos */ p = mb->buf; *len = mb->len; mb->buf = NULL; diff --git a/trunk/assuan/assuan-listen.c b/trunk/assuan/assuan-listen.c index 57fe4b6..db63ad2 100644 --- a/trunk/assuan/assuan-listen.c +++ b/trunk/assuan/assuan-listen.c @@ -69,15 +69,13 @@ assuan_accept (ASSUAN_CONTEXT ctx) if (!ctx) return ASSUAN_Invalid_Value; - /* fixme: cancel existing connection */ if (ctx->pipe_mode > 1) return -1; /* second invocation for pipemode -> terminate */ + ctx->finish_handler (ctx); - if (!ctx->pipe_mode) - { - - /* fixme: wait for request */ - } + rc = ctx->accept_handler (ctx); + if (rc) + return rc; /* send the hello */ rc = assuan_write_line (ctx, ctx->hello_line? ctx->hello_line diff --git a/trunk/assuan/assuan-pipe-connect.c b/trunk/assuan/assuan-pipe-connect.c new file mode 100644 index 0000000..ccfc1f0 --- /dev/null +++ b/trunk/assuan/assuan-pipe-connect.c @@ -0,0 +1,269 @@ +/* assuan-pipe-connect.c - Establish a pipe 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 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 */ +} + + +static int +do_finish (ASSUAN_CONTEXT ctx) +{ + if (ctx->inbound.fd != -1) + { + close (ctx->inbound.fd); + ctx->inbound.fd = -1; + } + if (ctx->outbound.fd != -1) + { + close (ctx->outbound.fd); + ctx->outbound.fd = -1; + } + if (ctx->pid != -1) + { + waitpid (ctx->pid, NULL, 0); /* FIXME Check return value. */ + ctx->pid = -1; + } + return 0; +} + +static void +do_deinit (ASSUAN_CONTEXT ctx) +{ + do_finish (ctx); +} + + + +/* 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. FD_CHILD_LIST is a -1 terminated list of file + descriptors not to close in the child. */ +AssuanError +assuan_pipe_connect (ASSUAN_CONTEXT *ctx, const char *name, char *const argv[], + int *fd_child_list) +{ + static int fixed_signals = 0; + AssuanError err; + int rp[2]; + int wp[2]; + + if (!ctx || !name || !argv || !argv[0]) + return ASSUAN_Invalid_Value; + + 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; + } + + err = _assuan_new_context (ctx); + if (err) + { + close (rp[0]); + close (rp[1]); + close (wp[0]); + close (wp[1]); + return err; + } + (*ctx)->pipe_mode = 1; + (*ctx)->inbound.fd = rp[0]; /* Our inbound is read end of read pipe. */ + (*ctx)->outbound.fd = wp[1]; /* Our outbound is write end of write pipe. */ + (*ctx)->deinit_handler = do_deinit; + (*ctx)->finish_handler = do_finish; + + (*ctx)->pid = fork (); + if ((*ctx)->pid < 0) + { + close (rp[0]); + close (rp[1]); + close (wp[0]); + close (wp[1]); + _assuan_release_context (*ctx); + return ASSUAN_General_Error; + } + + if ((*ctx)->pid == 0) + { + int i, n; + 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++) + { + int *fdp = fd_child_list; + + if (fdp) + { + while (*fdp != -1 && *fdp != i) + fdp++; + } + + if (!(fdp && *fdp != -1) + && 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 (dup2 (rp[1], STDOUT_FILENO) == -1) + { + LOGERROR1 ("dup2 failed in child: %s\n", strerror (errno)); + _exit (4); + } + close (rp[1]); + } + if (wp[0] != STDIN_FILENO) + { + if (dup2 (wp[0], STDIN_FILENO) == -1) + { + LOGERROR1 ("dup2 failed in child: %s\n", strerror (errno)); + _exit (4); + } + close (wp[0]); + } + + execv (name, argv); + /* 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 (wp[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) + { + assuan_disconnect (*ctx); + *ctx = NULL; + } + + return err; +} + + + + + + + + + + + + + + diff --git a/trunk/assuan/assuan-pipe-server.c b/trunk/assuan/assuan-pipe-server.c index 2a9b829..d15f54f 100644 --- a/trunk/assuan/assuan-pipe-server.c +++ b/trunk/assuan/assuan-pipe-server.c @@ -24,9 +24,31 @@ #include "assuan-defs.h" +static void +deinit_pipe_server (ASSUAN_CONTEXT ctx) +{ + /* nothing to do for this simple server */ +} + +static int +accept_connection (ASSUAN_CONTEXT ctx) +{ + /* This is a NOP for a pipe server */ + return 0; +} +static int +finish_connection (ASSUAN_CONTEXT ctx) +{ + /* This is a NOP for a pipe server */ + return 0; +} + + +/* Create a new context. Note that the handlers are set up for a pipe + server/client - this wau we don't need extra dummy functions */ int -assuan_init_pipe_server (ASSUAN_CONTEXT *r_ctx, int filedes[2]) +_assuan_new_context (ASSUAN_CONTEXT *r_ctx) { ASSUAN_CONTEXT ctx; int rc; @@ -35,14 +57,17 @@ assuan_init_pipe_server (ASSUAN_CONTEXT *r_ctx, int filedes[2]) ctx = xtrycalloc (1, sizeof *ctx); if (!ctx) return ASSUAN_Out_Of_Core; - ctx->is_server = 1; ctx->input_fd = -1; ctx->output_fd = -1; - ctx->inbound.fd = filedes[0]; - ctx->outbound.fd = filedes[1]; + ctx->inbound.fd = -1; + ctx->outbound.fd = -1; - ctx->pipe_mode = 1; + ctx->listen_fd = -1; + /* use the pipe server handler as a default */ + ctx->deinit_handler = deinit_pipe_server; + ctx->accept_handler = accept_connection; + ctx->finish_handler = finish_connection; rc = _assuan_register_std_commands (ctx); if (rc) @@ -52,22 +77,47 @@ assuan_init_pipe_server (ASSUAN_CONTEXT *r_ctx, int filedes[2]) return rc; } + + +int +assuan_init_pipe_server (ASSUAN_CONTEXT *r_ctx, int filedes[2]) +{ + int rc; + + rc = _assuan_new_context (r_ctx); + if (!rc) + { + ASSUAN_CONTEXT ctx = *r_ctx; + + ctx->is_server = 1; + ctx->inbound.fd = filedes[0]; + ctx->outbound.fd = filedes[1]; + ctx->pipe_mode = 1; + } + return rc; +} + + void -assuan_deinit_pipe_server (ASSUAN_CONTEXT ctx) +_assuan_release_context (ASSUAN_CONTEXT ctx) { if (ctx) { xfree (ctx->hello_line); + xfree (ctx->okay_line); xfree (ctx); } } - - - - - - - - - +void +assuan_deinit_server (ASSUAN_CONTEXT ctx) +{ + if (ctx) + { + /* We use this function pointer to avoid linking other server + when not needed but still allow for a generic deinit function */ + ctx->deinit_handler (ctx); + ctx->deinit_handler = NULL; + _assuan_release_context (ctx); + } +} diff --git a/trunk/assuan/assuan-socket-connect.c b/trunk/assuan/assuan-socket-connect.c new file mode 100644 index 0000000..6602b82 --- /dev/null +++ b/trunk/assuan/assuan-socket-connect.c @@ -0,0 +1,150 @@ +/* assuan-socket-connect.c - Assuan socket based client + * Copyright (C) 2002 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" + +#ifdef HAVE_JNLIB_LOGGING +#include "../jnlib/logging.h" +#define LOGERROR(a) log_error ((a)) +#define LOGERROR1(a,b) log_error ((a), (b)) +#define LOGERROR2(a,b,c) log_error ((a), (b), (c)) +#define LOGERRORX(a) log_printf ((a)) +#else +#define LOGERROR(a) fprintf (stderr, (a)) +#define LOGERROR1(a,b) fprintf (stderr, (a), (b)) +#define LOGERROR2(a,b,c) fprintf (stderr, (a), (b), (c)) +#define LOGERRORX(a) fputs ((a), stderror) +#endif + + + +static int +do_finish (ASSUAN_CONTEXT ctx) +{ + if (ctx->inbound.fd != -1) + { + close (ctx->inbound.fd); + } + ctx->inbound.fd = -1; + ctx->outbound.fd = -1; + return 0; +} + +static void +do_deinit (ASSUAN_CONTEXT ctx) +{ + do_finish (ctx); +} + + + +/* Make a connection to the Unix domain socket NAME and return a new + Assuan context in CTX. SERVER_PID is currently not used but may + becode handy in future. */ +AssuanError +assuan_socket_connect (ASSUAN_CONTEXT *r_ctx, + const char *name, pid_t server_pid) +{ + AssuanError err; + ASSUAN_CONTEXT ctx; + int fd; + struct sockaddr_un srvr_addr; + size_t len; + + if (!r_ctx || !name) + return ASSUAN_Invalid_Value; + *r_ctx = NULL; + + /* we require that the name starts with a slash, so that we can + alter reuse this function for other socket types */ + if (*name != '/') + return ASSUAN_Invalid_Value; + if (strlen (name)+1 >= sizeof srvr_addr.sun_path) + return ASSUAN_Invalid_Value; + + err = _assuan_new_context (&ctx); + if (err) + return err; + ctx->pid = server_pid; /* save it in case we need it later */ + ctx->deinit_handler = do_deinit; + ctx->finish_handler = do_finish; + + fd = socket (AF_UNIX, SOCK_STREAM, 0); + if (fd == -1) + { + LOGERROR1 ("can't create socket: %s\n", strerror (errno)); + _assuan_release_context (ctx); + return ASSUAN_General_Error; + } + + memset (&srvr_addr, 0, sizeof srvr_addr ); + srvr_addr.sun_family = AF_UNIX; + strcpy (srvr_addr.sun_path, name); + len = (offsetof (struct sockaddr_un, sun_path) + + strlen (srvr_addr.sun_path) + 1); + + if (connect (fd, (struct sockaddr*)&srvr_addr, len) == -1) + { + LOGERROR2 ("can't connect to `%s': %s\n", name, strerror (errno)); + _assuan_release_context (ctx); + close (fd ); + return ASSUAN_Connect_Failed; + } + + ctx->inbound.fd = fd; + ctx->outbound.fd = fd; + + /* 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) + { + LOGERROR ("can't connect server: `"); + _assuan_log_sanitized_string (ctx->inbound.line); + LOGERRORX ("'\n"); + err = ASSUAN_Connect_Failed; + } + } + + if (err) + { + assuan_disconnect (ctx); + } + else + *r_ctx = ctx; + return 0; +} + + diff --git a/trunk/assuan/assuan-socket-server.c b/trunk/assuan/assuan-socket-server.c new file mode 100644 index 0000000..6ad6455 --- /dev/null +++ b/trunk/assuan/assuan-socket-server.c @@ -0,0 +1,121 @@ +/* assuan-socket-server.c - Assuan socket based server + * Copyright (C) 2002 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 "assuan-defs.h" + +static int +accept_connection (ASSUAN_CONTEXT ctx) +{ + int fd; + struct sockaddr_un clnt_addr; + size_t len = sizeof clnt_addr; + + fd = accept (ctx->listen_fd, (struct sockaddr*)&clnt_addr, &len ); + if (fd == -1) + { + ctx->os_errno = errno; + return ASSUAN_Accept_Failed; + } + + ctx->inbound.fd = fd; + ctx->inbound.eof = 0; + ctx->inbound.linelen = 0; + ctx->inbound.attic.linelen = 0; + ctx->inbound.attic.pending = 0; + + ctx->outbound.fd = fd; + ctx->outbound.data.linelen = 0; + ctx->outbound.data.error = 0; + + ctx->confidential = 0; + + return 0; +} + +static int +finish_connection (ASSUAN_CONTEXT ctx) +{ + if (ctx->inbound.fd != -1) + { + close (ctx->inbound.fd); + } + ctx->inbound.fd = -1; + ctx->outbound.fd = -1; + return 0; +} + + +static void +deinit_socket_server (ASSUAN_CONTEXT ctx) +{ + finish_connection (ctx); +} + + + +/* Initialize a server for the socket LISTEN_FD which has already be + put into listen mode */ +int +assuan_init_socket_server (ASSUAN_CONTEXT *r_ctx, int listen_fd) +{ + ASSUAN_CONTEXT ctx; + int rc; + + *r_ctx = NULL; + ctx = xtrycalloc (1, sizeof *ctx); + if (!ctx) + return ASSUAN_Out_Of_Core; + ctx->is_server = 1; + ctx->input_fd = -1; + ctx->output_fd = -1; + + ctx->inbound.fd = -1; + ctx->outbound.fd = -1; + + ctx->listen_fd = listen_fd; + ctx->deinit_handler = deinit_socket_server; + ctx->accept_handler = accept_connection; + ctx->finish_handler = finish_connection; + + rc = _assuan_register_std_commands (ctx); + if (rc) + xfree (ctx); + else + *r_ctx = ctx; + return rc; +} + + + + + + + + + + diff --git a/trunk/assuan/assuan-util.c b/trunk/assuan/assuan-util.c index 3eeee9a..4153ef8 100644 --- a/trunk/assuan/assuan-util.c +++ b/trunk/assuan/assuan-util.c @@ -25,6 +25,10 @@ #include "assuan-defs.h" +#ifdef HAVE_JNLIB_LOGGING +#include "../jnlib/logging.h" +#endif + static void *(*alloc_func)(size_t n) = malloc; static void *(*realloc_func)(void *p, size_t n) = realloc; @@ -96,3 +100,97 @@ assuan_get_pointer (ASSUAN_CONTEXT ctx) return ctx? ctx->user_pointer : NULL; } + +void +assuan_set_log_stream (ASSUAN_CONTEXT ctx, FILE *fp) +{ + if (ctx) + { + if (ctx->log_fp) + fflush (ctx->log_fp); + ctx->log_fp = fp; + } +} + + +void +assuan_begin_confidential (ASSUAN_CONTEXT ctx) +{ + if (ctx) + { + ctx->confidential = 1; + } +} + +void +assuan_end_confidential (ASSUAN_CONTEXT ctx) +{ + if (ctx) + { + ctx->confidential = 0; + } +} + +void +_assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length) +{ + const unsigned char *s; + int n; + + for (n=length,s=buffer; n; n--, s++) + { + if (*s < ' ' || (*s >= 0x7f && *s <= 0xa0)) + break; + } + s = buffer; + if (!n && *s != '[') + fwrite (buffer, length, 1, fp); + else + { + putc ('[', fp); + for (n=0; n < length; n++, s++) + fprintf (fp, " %02x", *s); + putc (' ', fp); + putc (']', fp); + } +} + + +/* print a user supplied string after filtering out potential bad + characters*/ +void +_assuan_log_sanitized_string (const char *string) +{ + const unsigned char *s = string; +#ifdef HAVE_JNLIB_LOGGING + FILE *fp = log_get_stream (); +#else + FILE *fp = stderr; +#endif + + for (; *s; s++) + { + if (*s < 0x20 || (*s >= 0x7f && *s <= 0xa0)) + { + putc ('\\', fp); + if (*s == '\n') + putc ('n', fp); + else if (*s == '\r') + putc ('r', fp); + else if (*s == '\f') + putc ('f', fp); + else if (*s == '\v') + putc ('v', fp); + else if (*s == '\b') + putc ('b', fp); + else if (!*s) + putc ('0', fp); + else + fprintf (fp, "x%02x", *s ); + } + else + putc (*s, fp); + } +} + + diff --git a/trunk/assuan/assuan.h b/trunk/assuan/assuan.h index cddc98c..5971d81 100644 --- a/trunk/assuan/assuan.h +++ b/trunk/assuan/assuan.h @@ -1,5 +1,5 @@ /* assuan.c - Definitions for the Assuna protocol - * Copyright (C) 2001 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -47,6 +47,7 @@ typedef enum { ASSUAN_No_Data_Callback = 12, ASSUAN_No_Inquire_Callback = 13, ASSUAN_Connect_Failed = 14, + ASSUAN_Accept_Failed = 15, /* error codes above 99 are meant as status codes */ ASSUAN_Not_Implemented = 100, @@ -69,6 +70,9 @@ typedef enum { ASSUAN_Invalid_Data = 117, ASSUAN_Unexpected_Command = 118, ASSUAN_Too_Much_Data = 119, + ASSUAN_Inquire_Unknown = 120, + ASSUAN_Inquire_Error = 121, + ASSUAN_Invalid_Option = 122, ASSUAN_Bad_Certificate = 201, ASSUAN_Bad_Certificate_Path = 202, @@ -83,6 +87,7 @@ typedef enum { ASSUAN_Cert_Revoked = 301, ASSUAN_No_CRL_For_Cert = 302, ASSUAN_CRL_Too_Old = 303, + ASSUAN_Not_Trusted = 304, } AssuanError; @@ -93,6 +98,7 @@ typedef enum { ASSUAN_CMD_BYE, ASSUAN_CMD_AUTH, ASSUAN_CMD_RESET, + ASSUAN_CMD_OPTION, ASSUAN_CMD_DATA, ASSUAN_CMD_END, ASSUAN_CMD_INPUT, @@ -120,6 +126,11 @@ 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_register_option_handler (ASSUAN_CONTEXT ctx, + int (*fnc)(ASSUAN_CONTEXT, + const char*, const char*)); + int assuan_process (ASSUAN_CONTEXT ctx); int assuan_process_next (ASSUAN_CONTEXT ctx); int assuan_get_active_fds (ASSUAN_CONTEXT ctx, int what, @@ -127,6 +138,7 @@ int assuan_get_active_fds (ASSUAN_CONTEXT ctx, int what, FILE *assuan_get_data_fp (ASSUAN_CONTEXT ctx); +AssuanError assuan_set_okay_line (ASSUAN_CONTEXT ctx, const char *line); void assuan_write_status (ASSUAN_CONTEXT ctx, const char *keyword, const char *text); @@ -142,13 +154,21 @@ AssuanError assuan_close_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); +void assuan_deinit_server (ASSUAN_CONTEXT ctx); +/*-- assuan-socket-server.c --*/ +int assuan_init_socket_server (ASSUAN_CONTEXT *r_ctx, int listen_fd); -/*-- assuan-connect.c --*/ + +/*-- assuan-pipe-connect.c --*/ AssuanError assuan_pipe_connect (ASSUAN_CONTEXT *ctx, const char *name, char *const argv[], int *fd_child_list); -void assuan_pipe_disconnect (ASSUAN_CONTEXT ctx); +/*-- assuan-socket-connect.c --*/ +AssuanError assuan_socket_connect (ASSUAN_CONTEXT *ctx, const char *name, + pid_t server_pid); + +/*-- assuan-connect.c --*/ +void assuan_disconnect (ASSUAN_CONTEXT ctx); pid_t assuan_get_pid (ASSUAN_CONTEXT ctx); /*-- assuan-client.c --*/ @@ -178,10 +198,13 @@ AssuanError assuan_send_data (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*) ); +void assuan_set_log_stream (ASSUAN_CONTEXT ctx, FILE *fp); 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); +void assuan_begin_confidential (ASSUAN_CONTEXT ctx); +void assuan_end_confidential (ASSUAN_CONTEXT ctx); /*-- assuan-errors.c (built) --*/ const char *assuan_strerror (AssuanError err); diff --git a/trunk/jnlib/ChangeLog b/trunk/jnlib/ChangeLog index 1d750bf..b5f723c 100644 --- a/trunk/jnlib/ChangeLog +++ b/trunk/jnlib/ChangeLog @@ -5,6 +5,22 @@ unconditionally. Reported by Jose Carlos Garcia Sogo . +2002-01-19 Werner Koch + + * logging.c (log_get_stream): New. + +2001-12-05 Werner Koch + + * logging.c (log_set_prefix): New. + (do_logv): Include prefix and pid only if enabled. Print time only + when explicitly enabled. + (log_logv): New. + * logging.h: Include log_logv() only when requested. + +2001-11-06 Werner Koch + + * strlist.c, strlist.h: New. Taken from pgnupg/util/strgutil.c + 2001-08-30 Werner Koch * logging.c (log_printf): Don't pass NULL instead of arg_ptr. diff --git a/trunk/jnlib/Makefile.am b/trunk/jnlib/Makefile.am index 1049f3c..515a49a 100644 --- a/trunk/jnlib/Makefile.am +++ b/trunk/jnlib/Makefile.am @@ -26,11 +26,14 @@ noinst_LIBRARIES = libjnlib.a #libjnlib_a_LDFLAGS = -libjnlib_a_SOURCES = libjnlib-config.h \ - xmalloc.c xmalloc.h \ - stringhelp.c stringhelp.h \ - argparse.c argparse.h \ - logging.c logging.h \ - types.h mischelp.h - +libjnlib_a_SOURCES = \ + libjnlib-config.h \ + stringhelp.c stringhelp.h \ + strlist.c strlist.h \ + argparse.c argparse.h \ + logging.c logging.h \ + dotlock.c dotlock.h \ + types.h mischelp.h + +# xmalloc.c xmalloc.h diff --git a/trunk/jnlib/argparse.c b/trunk/jnlib/argparse.c index ba63558..0e353e4 100644 --- a/trunk/jnlib/argparse.c +++ b/trunk/jnlib/argparse.c @@ -900,7 +900,7 @@ strusage( int level ) switch( level ) { case 11: p = "foo"; break; case 13: p = "0.0"; break; - case 14: p = "Copyright (C) 2000 Free Software Foundation, Inc."; break; + case 14: p = "Copyright (C) 2001 Free Software Foundation, Inc."; break; case 15: p = "This program comes with ABSOLUTELY NO WARRANTY.\n" "This is free software, and you are welcome to redistribute it\n" diff --git a/trunk/jnlib/libjnlib-config.h b/trunk/jnlib/libjnlib-config.h index de8e6a4..ec31d35 100644 --- a/trunk/jnlib/libjnlib-config.h +++ b/trunk/jnlib/libjnlib-config.h @@ -26,11 +26,9 @@ #ifndef LIBJNLIB_CONFIG_H #define LIBJNLIB_CONFIG_H -#include "xmalloc.h" +#include /* gcry_malloc & Cie. */ #include "logging.h" - - #ifdef USE_SIMPLE_GETTEXT int set_gettext_file( const char *filename ); const char *gettext( const char *msgid ); @@ -58,11 +56,11 @@ #endif /* !USE_SIMPLE_GETTEXT */ -#define jnlib_xmalloc(a) xmalloc( (a) ) -#define jnlib_xcalloc(a,b) xcalloc( (a), (b) ) -#define jnlib_xrealloc(a,n) xrealloc( (a), (n) ) -#define jnlib_xstrdup(a) xstrdup( (a) ) -#define jnlib_free(a) free( (a) ) +#define jnlib_xmalloc(a) gcry_xmalloc( (a) ) +#define jnlib_xcalloc(a,b) gcry_xcalloc( (a), (b) ) +#define jnlib_xrealloc(a,n) gcry_xrealloc( (a), (n) ) +#define jnlib_xstrdup(a) gcry_xstrdup( (a) ) +#define jnlib_free(a) gcry_free( (a) ) #define jnlib_log_debug log_debug #define jnlib_log_info log_info @@ -73,3 +71,5 @@ #endif /*LIBJNUTIL_CONFIG_H*/ + + diff --git a/trunk/jnlib/logging.c b/trunk/jnlib/logging.c index 69b94b1..2e0d53a 100644 --- a/trunk/jnlib/logging.c +++ b/trunk/jnlib/logging.c @@ -31,26 +31,23 @@ #include #include #include +#include +#include #ifdef __MINGW32__ #include #endif +#define JNLIB_NEED_LOG_LOGV 1 #include "libjnlib-config.h" #include "logging.h" -enum my_log_levels { - MY_LOG_BEGIN, /* only print the timestamp if configured */ - MY_LOG_CONT, - MY_LOG_INFO, - MY_LOG_WARN, - MY_LOG_ERROR, - MY_LOG_FATAL, - MY_LOG_BUG, - MY_LOG_DEBUG -}; static FILE *logstream; -static int use_time; +static char prefix_buffer[80]; +static int with_time; +static int with_prefix; +static int with_pid; + static int missing_lf; static int errorcount; @@ -95,61 +92,93 @@ log_set_file( const char *name ) if( logstream && logstream != stderr ) fclose( logstream ); logstream = fp; - use_time = fp != stderr; missing_lf = 0; } +void +log_set_prefix (const char *text, unsigned int flags) +{ + if (text) + { + strncpy (prefix_buffer, text, sizeof (prefix_buffer)-1); + prefix_buffer[sizeof (prefix_buffer)-1] = 0; + } + + with_prefix = (flags & 1); + with_time = (flags & 2); + with_pid = (flags & 4); +} + int log_get_fd() { return fileno(logstream?logstream:stderr); } -static void -do_logv( int level, const char *fmt, va_list arg_ptr ) +FILE * +log_get_stream () { - if( !logstream ) - logstream = stderr; - - if( missing_lf && level != MY_LOG_CONT ) - putc('\n', logstream ); - missing_lf = 0; + return logstream?logstream:stderr; +} - if( use_time && level != MY_LOG_CONT ) { - /* Note this does not work for multiple line logging as we would - * need to print to a buffer first */ - struct tm *tp; - time_t atime = time(NULL); - tp = localtime( &atime ); - fprintf( logstream, "%04d-%02d-%02d %02d:%02d:%02d ", - 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday, - tp->tm_hour, tp->tm_min, tp->tm_sec ); +static void +do_logv( int level, const char *fmt, va_list arg_ptr ) +{ + if (!logstream) + logstream = stderr; + + if (missing_lf && level != JNLIB_LOG_CONT) + putc('\n', logstream ); + missing_lf = 0; + + if (level != JNLIB_LOG_CONT) + { /* Note this does not work for multiple line logging as we would + * need to print to a buffer first */ + if (with_time) + { + struct tm *tp; + time_t atime = time (NULL); + + tp = localtime (&atime); + fprintf (logstream, "%04d-%02d-%02d %02d:%02d:%02d ", + 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday, + tp->tm_hour, tp->tm_min, tp->tm_sec ); + } + if (with_prefix) + fputs (prefix_buffer, logstream); + if (with_pid) + fprintf (logstream, "[%u]", (unsigned int)getpid ()); + if (!with_time) + putc (':', logstream); + putc (' ', logstream); } - switch ( level ) { - case MY_LOG_BEGIN: break; - case MY_LOG_CONT: break; - case MY_LOG_INFO: break; - case MY_LOG_WARN: break; - case MY_LOG_ERROR: break; - case MY_LOG_FATAL: fputs("Fatal: ",logstream ); break; - case MY_LOG_BUG: fputs("Ohhhh jeeee: ", logstream); break; - case MY_LOG_DEBUG: fputs("DBG: ", logstream ); break; - default: fprintf(logstream,"[Unknown log level %d]: ", level ); break; + switch (level) + { + case JNLIB_LOG_BEGIN: break; + case JNLIB_LOG_CONT: break; + case JNLIB_LOG_INFO: break; + case JNLIB_LOG_WARN: break; + case JNLIB_LOG_ERROR: break; + case JNLIB_LOG_FATAL: fputs("Fatal: ",logstream ); break; + case JNLIB_LOG_BUG: fputs("Ohhhh jeeee: ", logstream); break; + case JNLIB_LOG_DEBUG: fputs("DBG: ", logstream ); break; + default: fprintf(logstream,"[Unknown log level %d]: ", level ); break; } - if( fmt ) { - vfprintf(logstream,fmt,arg_ptr) ; - if( *fmt && fmt[strlen(fmt)-1] != '\n' ) - missing_lf = 1; + if (fmt) + { + vfprintf(logstream,fmt,arg_ptr) ; + if (*fmt && fmt[strlen(fmt)-1] != '\n') + missing_lf = 1; } - if( level == MY_LOG_FATAL ) - exit(2); - if( level == MY_LOG_BUG ) - abort(); + if (level == JNLIB_LOG_FATAL) + exit(2); + if (level == JNLIB_LOG_BUG) + abort(); } static void @@ -163,6 +192,11 @@ do_log( int level, const char *fmt, ... ) } +void +log_logv (int level, const char *fmt, va_list arg_ptr) +{ + do_logv (level, fmt, arg_ptr); +} void log_info( const char *fmt, ... ) @@ -170,7 +204,7 @@ log_info( const char *fmt, ... ) va_list arg_ptr ; va_start( arg_ptr, fmt ) ; - do_logv( MY_LOG_INFO, fmt, arg_ptr ); + do_logv( JNLIB_LOG_INFO, fmt, arg_ptr ); va_end(arg_ptr); } @@ -180,7 +214,7 @@ log_error( const char *fmt, ... ) va_list arg_ptr ; va_start( arg_ptr, fmt ) ; - do_logv( MY_LOG_ERROR, fmt, arg_ptr ); + do_logv( JNLIB_LOG_ERROR, fmt, arg_ptr ); va_end(arg_ptr); /* protect against counter overflow */ if( errorcount < 30000 ) @@ -194,7 +228,7 @@ log_fatal( const char *fmt, ... ) va_list arg_ptr ; va_start( arg_ptr, fmt ) ; - do_logv( MY_LOG_FATAL, fmt, arg_ptr ); + do_logv( JNLIB_LOG_FATAL, fmt, arg_ptr ); va_end(arg_ptr); abort(); /* never called, bugs it makes the compiler happy */ } @@ -205,7 +239,7 @@ log_bug( const char *fmt, ... ) va_list arg_ptr ; va_start( arg_ptr, fmt ) ; - do_logv( MY_LOG_BUG, fmt, arg_ptr ); + do_logv( JNLIB_LOG_BUG, fmt, arg_ptr ); va_end(arg_ptr); abort(); /* never called, but it makes the compiler happy */ } @@ -216,7 +250,7 @@ log_debug( const char *fmt, ... ) va_list arg_ptr ; va_start( arg_ptr, fmt ) ; - do_logv( MY_LOG_DEBUG, fmt, arg_ptr ); + do_logv( JNLIB_LOG_DEBUG, fmt, arg_ptr ); va_end(arg_ptr); } @@ -227,16 +261,35 @@ log_printf (const char *fmt, ...) va_list arg_ptr; va_start (arg_ptr, fmt); - do_logv (fmt ? MY_LOG_CONT : MY_LOG_BEGIN, fmt, arg_ptr); + do_logv (fmt ? JNLIB_LOG_CONT : JNLIB_LOG_BEGIN, fmt, arg_ptr); va_end (arg_ptr); } +/* Print a hexdump of BUFFER. With TEXT of NULL print just the raw + dump, with TEXT just an empty string, print a trailing linefeed, + otherwise print an entire debug line. */ +void +log_printhex (const char *text, const void *buffer, size_t length) +{ + if (text && *text) + log_debug ("%s ", text); + if (length) + { + const unsigned char *p = buffer; + log_printf ("%02X", *p); + for (length--, p++; length--; p++) + log_printf (" %02X", *p); + } + if (text) + log_printf ("\n"); +} + #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ) void bug_at( const char *file, int line, const char *func ) { - do_log( MY_LOG_BUG, + do_log( JNLIB_LOG_BUG, ("... this is a bug (%s:%d:%s)\n"), file, line, func ); abort(); /* never called, but it makes the compiler happy */ } @@ -244,7 +297,7 @@ bug_at( const char *file, int line, const char *func ) void bug_at( const char *file, int line ) { - do_log( MY_LOG_BUG, + do_log( JNLIB_LOG_BUG, _("you found a bug ... (%s:%d)\n"), file, line); abort(); /* never called, but it makes the compiler happy */ } diff --git a/trunk/jnlib/logging.h b/trunk/jnlib/logging.h index 83158f0..7b7b8c8 100644 --- a/trunk/jnlib/logging.h +++ b/trunk/jnlib/logging.h @@ -24,9 +24,12 @@ #include #include "mischelp.h" + int log_get_errorcount (int clear); void log_set_file( const char *name ); +void log_set_prefix (const char *text, unsigned int flags); int log_get_fd(void); +FILE *log_get_stream (void); #ifdef JNLIB_GCC_M_FUNCTION void bug_at( const char *file, int line, const char *func ) JNLIB_GCC_A_NR; @@ -36,12 +39,36 @@ int log_get_fd(void); # define BUG() bug_at( __FILE__ , __LINE__ ) #endif +/* To avoid mandatory inclusion of stdarg and other stuff, do it only + if explicitly requested to do so. */ +#ifdef JNLIB_NEED_LOG_LOGV +#include +enum jnlib_log_levels { + JNLIB_LOG_BEGIN, + JNLIB_LOG_CONT, + JNLIB_LOG_INFO, + JNLIB_LOG_WARN, + JNLIB_LOG_ERROR, + JNLIB_LOG_FATAL, + JNLIB_LOG_BUG, + JNLIB_LOG_DEBUG +}; +void log_logv (int level, const char *fmt, va_list arg_ptr); +#endif /*JNLIB_NEED_LOG_LOGV*/ + + void log_bug( const char *fmt, ... ) JNLIB_GCC_A_NR_PRINTF(1,2); void log_fatal( const char *fmt, ... ) JNLIB_GCC_A_NR_PRINTF(1,2); void log_error( const char *fmt, ... ) JNLIB_GCC_A_PRINTF(1,2); void log_info( const char *fmt, ... ) JNLIB_GCC_A_PRINTF(1,2); void log_debug( const char *fmt, ... ) JNLIB_GCC_A_PRINTF(1,2); void log_printf( const char *fmt, ... ) JNLIB_GCC_A_PRINTF(1,2); +void log_printhex (const char *text, const void *buffer, size_t length); #endif /*LIBJNLIB_LOGGING_H*/ + + + + + diff --git a/trunk/jnlib/strlist.c b/trunk/jnlib/strlist.c new file mode 100644 index 0000000..7cbaf5e --- /dev/null +++ b/trunk/jnlib/strlist.c @@ -0,0 +1,133 @@ +/* strlist.c - string helpers + * Copyright (C) 1998, 2000, 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 "libjnlib-config.h" +#include "strlist.h" + + +void +free_strlist( STRLIST sl ) +{ + STRLIST sl2; + + for(; sl; sl = sl2 ) { + sl2 = sl->next; + jnlib_free(sl); + } +} + + +STRLIST +add_to_strlist( STRLIST *list, const char *string ) +{ + STRLIST sl; + + sl = jnlib_xmalloc( sizeof *sl + strlen(string)); + sl->flags = 0; + strcpy(sl->d, string); + sl->next = *list; + *list = sl; + return sl; +} + +#if 0 +/**************** + * same as add_to_strlist() but if is_utf8 is *not* set a conversion + * to UTF8 is done + */ +STRLIST +add_to_strlist2( STRLIST *list, const char *string, int is_utf8 ) +{ + STRLIST sl; + + if( is_utf8 ) + sl = add_to_strlist( list, string ); + else { + char *p = native_to_utf8( string ); + sl = add_to_strlist( list, p ); + m_free( p ); + } + return sl; +} +#endif + +STRLIST +append_to_strlist( STRLIST *list, const char *string ) +{ + STRLIST r, sl; + + sl = jnlib_xmalloc( sizeof *sl + strlen(string)); + sl->flags = 0; + strcpy(sl->d, string); + sl->next = NULL; + if( !*list ) + *list = sl; + else { + for( r = *list; r->next; r = r->next ) + ; + r->next = sl; + } + return sl; +} + +#if 0 +STRLIST +append_to_strlist2( STRLIST *list, const char *string, int is_utf8 ) +{ + STRLIST sl; + + if( is_utf8 ) + sl = append_to_strlist( list, string ); + else { + char *p = native_to_utf8( string ); + sl = append_to_strlist( list, p ); + m_free( p ); + } + return sl; +} +#endif + +STRLIST +strlist_prev( STRLIST head, STRLIST node ) +{ + STRLIST n; + + for(n=NULL; head && head != node; head = head->next ) + n = head; + return n; +} + +STRLIST +strlist_last( STRLIST node ) +{ + if( node ) + for( ; node->next ; node = node->next ) + ; + return node; +} + + + diff --git a/trunk/jnlib/strlist.h b/trunk/jnlib/strlist.h new file mode 100644 index 0000000..53c0bc7 --- /dev/null +++ b/trunk/jnlib/strlist.h @@ -0,0 +1,43 @@ +/* strlist.h + * Copyright (C) 1998, 2000, 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 LIBJNLIB_STRLIST_H +#define LIBJNLIB_STRLIST_H + +struct string_list { + struct string_list *next; + unsigned int flags; + char d[1]; +}; +typedef struct string_list *STRLIST; + + +void free_strlist( STRLIST sl ); +STRLIST add_to_strlist( STRLIST *list, const char *string ); +STRLIST add_to_strlist2( STRLIST *list, const char *string, int is_utf8 ); +STRLIST append_to_strlist( STRLIST *list, const char *string ); +STRLIST append_to_strlist2( STRLIST *list, const char *string, int is_utf8 ); +STRLIST strlist_prev( STRLIST head, STRLIST node ); +STRLIST strlist_last( STRLIST node ); + +#define FREE_STRLIST(a) do { free_strlist((a)); (a) = NULL ; } while(0) + + +#endif /*LIBJNLIB_STRLIST_H*/ -- 2.26.2