diff --git a/assuan/ChangeLog b/assuan/ChangeLog index 290fef58..2b95d56d 100644 --- a/assuan/ChangeLog +++ b/assuan/ChangeLog @@ -1,3 +1,39 @@ +2002-04-04 Werner Koch + + * assuan-buffer.c (my_log_prefix): New. Use it for all i/o debug + output. + +2002-03-06 Werner Koch + + * assuan-client.c (_assuan_read_from_server): Detect END. + (assuan_transact): Pass it to the data callback. + +2002-02-27 Werner Koch + + * assuan-client.c (assuan_transact): Add 2 more arguments to + support status lines. Passing NULL yields the old behaviour. + + * assuan-handler.c (process_request): Flush data lines send + without using the data fp. + +2002-02-14 Werner Koch + + * assuan-inquire.c (assuan_inquire): Check for a cancel command + and return ASSUAN_Canceled. Allow for non-data inquiry. + + * assuan.h: Add a few token specific error codes. + +2002-02-13 Werner Koch + + * assuan-defs.h (assuan_context_s): New var CLIENT_PID. + * assuan-pipe-server.c (_assuan_new_context): set default value. + * assuan-socket-server.c (accept_connection): get the actual pid. + +2002-02-12 Werner Koch + + * assuan-buffer.c (writen,readline) [USE_GNU_PT]: Use pth_read/write. + * assuan-socket-server.c (accept_connection) [USE_GNU_PTH]: Ditto. + 2002-02-01 Marcus Brinkmann * Makefile.am (MOSTLYCLEANFILES): New variable. diff --git a/assuan/assuan-buffer.c b/assuan/assuan-buffer.c index bd088174..29f94794 100644 --- a/assuan/assuan-buffer.c +++ b/assuan/assuan-buffer.c @@ -25,16 +25,37 @@ #include #include #include - +#ifdef USE_GNU_PTH +# include +#endif #include "assuan-defs.h" +#ifdef HAVE_JNLIB_LOGGING +#include "../jnlib/logging.h" +#endif + + +static const char * +my_log_prefix (void) +{ +#ifdef HAVE_JNLIB_LOGGING + return log_get_prefix (NULL); +#else + return ""; +#endif +} + static int writen ( int fd, const char *buffer, size_t length ) { while (length) { +#ifdef USE_GNU_PTH + int nwritten = pth_write (fd, buffer, length); +#else int nwritten = write (fd, buffer, length); +#endif if (nwritten < 0) { @@ -59,7 +80,11 @@ readline (int fd, char *buf, size_t buflen, int *r_nread, int *eof) *r_nread = 0; while (nleft > 0) { +#ifdef USE_GNU_PTH + int n = pth_read (fd, buf, nleft); +#else int n = read (fd, buf, nleft); +#endif if (n < 0) { if (errno == EINTR) @@ -122,15 +147,15 @@ _assuan_read_line (ASSUAN_CONTEXT ctx) if (rc) { if (ctx->log_fp) - fprintf (ctx->log_fp, "%p <- [Error: %s]\n", - ctx, strerror (errno)); + fprintf (ctx->log_fp, "%s[%p] <- [Error: %s]\n", + my_log_prefix (), 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); + fprintf (ctx->log_fp, "%s[%p] <- [EOF]\n", my_log_prefix (),ctx); return -1; } @@ -163,7 +188,7 @@ _assuan_read_line (ASSUAN_CONTEXT ctx) ctx->inbound.linelen = n; if (ctx->log_fp) { - fprintf (ctx->log_fp, "%p <- ", ctx); + fprintf (ctx->log_fp, "%s[%p] <- ", my_log_prefix (), ctx); if (ctx->confidential) fputs ("[Confidential data not shown]", ctx->log_fp); else @@ -177,7 +202,7 @@ _assuan_read_line (ASSUAN_CONTEXT ctx) } if (ctx->log_fp) - fprintf (ctx->log_fp, "%p <- [Invalid line]\n", ctx); + fprintf (ctx->log_fp, "%s[%p] <- [Invalid line]\n", my_log_prefix (), ctx); *line = 0; ctx->inbound.linelen = 0; return ctx->inbound.eof? ASSUAN_Line_Not_Terminated : ASSUAN_Line_Too_Long; @@ -229,7 +254,7 @@ assuan_write_line (ASSUAN_CONTEXT ctx, const char *line ) /* fixme: we should do some kind of line buffering */ if (ctx->log_fp) { - fprintf (ctx->log_fp, "%p -> ", ctx); + fprintf (ctx->log_fp, "%s[%p] -> ", my_log_prefix (), ctx); if (ctx->confidential) fputs ("[Confidential data not shown]", ctx->log_fp); else @@ -300,7 +325,7 @@ _assuan_cookie_write_data (void *cookie, const char *buffer, size_t size) { if (ctx->log_fp) { - fprintf (ctx->log_fp, "%p -> ", ctx); + fprintf (ctx->log_fp, "%s[%p] -> ", my_log_prefix (), ctx); if (ctx->confidential) fputs ("[Confidential data not shown]", ctx->log_fp); else @@ -345,7 +370,7 @@ _assuan_cookie_write_flush (void *cookie) { if (ctx->log_fp) { - fprintf (ctx->log_fp, "%p -> ", ctx); + fprintf (ctx->log_fp, "%s[%p] -> ", my_log_prefix (), ctx); if (ctx->confidential) fputs ("[Confidential data not shown]", ctx->log_fp); else diff --git a/assuan/assuan-client.c b/assuan/assuan-client.c index d56357dc..6c7a6e3e 100644 --- a/assuan/assuan-client.c +++ b/assuan/assuan-client.c @@ -57,6 +57,15 @@ _assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off) *okay = 2; /* data line */ *off = 2; } + else if (linelen >= 1 + && line[0] == 'S' + && (line[1] == '\0' || line[1] == ' ')) + { + *okay = 4; + *off = 1; + while (line[*off] == ' ') + ++*off; + } else if (linelen >= 2 && line[0] == 'O' && line[1] == 'K' && (line[2] == '\0' || line[2] == ' ')) @@ -86,6 +95,13 @@ _assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off) while (line[*off] == ' ') ++*off; } + else if (linelen >= 3 + && line[0] == 'E' && line[1] == 'N' && line[2] == 'D' + && (line[3] == '\0' || line[3] == ' ')) + { + *okay = 5; /* end line */ + *off = 3; + } else rc = ASSUAN_Invalid_Response; return rc; @@ -101,6 +117,8 @@ _assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off) * @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 + * @status_cb: Callback function for a status response + * @status_cb_arg: first argument passed to @status_cb * * FIXME: Write documentation * @@ -114,7 +132,9 @@ assuan_transact (ASSUAN_CONTEXT ctx, AssuanError (*data_cb)(void *, const void *, size_t), void *data_cb_arg, AssuanError (*inquire_cb)(void*, const char *), - void *inquire_cb_arg) + void *inquire_cb_arg, + AssuanError (*status_cb)(void*, const char *), + void *status_cb_arg) { int rc, okay, off; unsigned char *line; @@ -181,6 +201,25 @@ assuan_transact (ASSUAN_CONTEXT ctx, goto again; } } + else if (okay == 4) + { + if (status_cb) + rc = status_cb (status_cb_arg, line); + if (!rc) + goto again; + } + else if (okay == 5) + { + if (!data_cb) + rc = ASSUAN_No_Data_Callback; + else + { + rc = data_cb (data_cb_arg, NULL, 0); + if (!rc) + goto again; + } + } return rc; } + diff --git a/assuan/assuan-defs.h b/assuan/assuan-defs.h index 7d55aabd..6c502bf9 100644 --- a/assuan/assuan-defs.h +++ b/assuan/assuan-defs.h @@ -77,6 +77,9 @@ struct assuan_context_s { In socket mode, the pid of the server */ int listen_fd; /* The fd we are listening on (used by socket servers) */ + pid_t client_pid; /* for a socket server the PID of the client or -1 + if not available */ + void (*deinit_handler)(ASSUAN_CONTEXT); int (*accept_handler)(ASSUAN_CONTEXT); int (*finish_handler)(ASSUAN_CONTEXT); @@ -92,7 +95,6 @@ struct assuan_context_s { void (*input_notify_fnc)(ASSUAN_CONTEXT, const char *); void (*output_notify_fnc)(ASSUAN_CONTEXT, const char *); - int input_fd; /* set by INPUT command */ int output_fd; /* set by OUTPUT command */ @@ -135,9 +137,3 @@ void _assuan_log_sanitized_string (const char *string); #endif /*ASSUAN_DEFS_H*/ - - - - - - diff --git a/assuan/assuan-handler.c b/assuan/assuan-handler.c index 1c8aded7..69b34b4f 100644 --- a/assuan/assuan-handler.c +++ b/assuan/assuan-handler.c @@ -464,6 +464,12 @@ process_request (ASSUAN_CONTEXT ctx) if (!rc && ctx->outbound.data.error) rc = ctx->outbound.data.error; } + else /* flush any data send w/o using the data fp */ + { + assuan_send_data (ctx, NULL, 0); + if (!rc && ctx->outbound.data.error) + rc = ctx->outbound.data.error; + } /* Error handling */ if (!rc) { @@ -478,7 +484,7 @@ process_request (ASSUAN_CONTEXT ctx) { char errline[256]; - if (rc < 100) + if (rc < 100) sprintf (errline, "ERR %d server fault (%.50s)", ASSUAN_Server_Fault, assuan_strerror (rc)); else diff --git a/assuan/assuan-inquire.c b/assuan/assuan-inquire.c index 933091e1..2bac1303 100644 --- a/assuan/assuan-inquire.c +++ b/assuan/assuan-inquire.c @@ -126,9 +126,10 @@ free_membuf (struct membuf *mb) * @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. + * @maxlen: If not 0, the size limit of the inquired data. * - * A Server may use this to Send an inquire + * A Server may use this to Send an inquire. r_buffer, r_length and + * maxlen may all be NULL/0 to indicate that no real data is expected. * * Return value: 0 on success or an ASSUAN error code **/ @@ -141,9 +142,12 @@ assuan_inquire (ASSUAN_CONTEXT ctx, const char *keyword, char cmdbuf[100]; unsigned char *line, *p; int linelen; + int nodataexpected; - if (!ctx || !keyword || (10 + strlen (keyword) >= sizeof (cmdbuf)) - || !r_buffer || !r_length ) + if (!ctx || !keyword || (10 + strlen (keyword) >= sizeof (cmdbuf))) + return ASSUAN_Invalid_Value; + nodataexpected = !r_buffer && !r_length && !maxlen; + if (!nodataexpected && (!r_buffer || !r_length)) return ASSUAN_Invalid_Value; if (!ctx->is_server) return ASSUAN_Not_A_Server; @@ -151,7 +155,10 @@ assuan_inquire (ASSUAN_CONTEXT ctx, const char *keyword, return ASSUAN_Nested_Commands; ctx->in_inquire = 1; - init_membuf (&mb, maxlen? maxlen:1024, maxlen); + if (nodataexpected) + memset (&mb, 0, sizeof mb); /* avoid compiler warnings */ + else + init_membuf (&mb, maxlen? maxlen:1024, maxlen); strcpy (stpcpy (cmdbuf, "INQUIRE "), keyword); rc = assuan_write_line (ctx, cmdbuf); @@ -172,7 +179,12 @@ assuan_inquire (ASSUAN_CONTEXT ctx, const char *keyword, if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D' && (!line[3] || line[3] == ' ')) break; /* END command received*/ - if (line[0] != 'D' || line[1] != ' ') + if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N') + { + rc = ASSUAN_Canceled; + goto leave; + } + if (line[0] != 'D' || line[1] != ' ' || nodataexpected) { rc = ASSUAN_Unexpected_Command; goto leave; @@ -205,13 +217,17 @@ assuan_inquire (ASSUAN_CONTEXT ctx, const char *keyword, goto leave; } } - - *r_buffer = get_membuf (&mb, r_length); - if (!*r_buffer) - rc = ASSUAN_Out_Of_Core; + + if (!nodataexpected) + { + *r_buffer = get_membuf (&mb, r_length); + if (!*r_buffer) + rc = ASSUAN_Out_Of_Core; + } leave: - free_membuf (&mb); + if (!nodataexpected) + free_membuf (&mb); ctx->in_inquire = 0; return rc; } diff --git a/assuan/assuan-pipe-server.c b/assuan/assuan-pipe-server.c index d15f54f5..5c5d1248 100644 --- a/assuan/assuan-pipe-server.c +++ b/assuan/assuan-pipe-server.c @@ -64,6 +64,7 @@ _assuan_new_context (ASSUAN_CONTEXT *r_ctx) ctx->outbound.fd = -1; ctx->listen_fd = -1; + ctx->client_pid = (pid_t)-1; /* use the pipe server handler as a default */ ctx->deinit_handler = deinit_pipe_server; ctx->accept_handler = accept_connection; diff --git a/assuan/assuan-socket-server.c b/assuan/assuan-socket-server.c index 6ad6455e..39dd84a1 100644 --- a/assuan/assuan-socket-server.c +++ b/assuan/assuan-socket-server.c @@ -25,6 +25,9 @@ #include #include #include +#ifdef USE_GNU_PTH +# include +#endif #include "assuan-defs.h" @@ -35,13 +38,28 @@ accept_connection (ASSUAN_CONTEXT ctx) struct sockaddr_un clnt_addr; size_t len = sizeof clnt_addr; + ctx->client_pid = (pid_t)-1; +#ifdef USE_GNU_PTH + fd = pth_accept (ctx->listen_fd, (struct sockaddr*)&clnt_addr, &len ); +#else fd = accept (ctx->listen_fd, (struct sockaddr*)&clnt_addr, &len ); +#endif if (fd == -1) { ctx->os_errno = errno; return ASSUAN_Accept_Failed; } +#ifdef HAVE_SO_PEERCRED + { + struct ucred cr; + int cl = sizeof cr; + + if ( !getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &cr, &cl) ) + ctx->client_pid = cr.pid; + } +#endif + ctx->inbound.fd = fd; ctx->inbound.eof = 0; ctx->inbound.linelen = 0; diff --git a/assuan/assuan.h b/assuan/assuan.h index 5971d81b..a9340019 100644 --- a/assuan/assuan.h +++ b/assuan/assuan.h @@ -73,6 +73,12 @@ typedef enum { ASSUAN_Inquire_Unknown = 120, ASSUAN_Inquire_Error = 121, ASSUAN_Invalid_Option = 122, + ASSUAN_Invalid_Index = 123, + ASSUAN_Unexpected_Status = 124, + ASSUAN_Unexpected_Data = 125, + ASSUAN_Invalid_Status = 126, + + ASSUAN_Not_Confirmed = 128, ASSUAN_Bad_Certificate = 201, ASSUAN_Bad_Certificate_Path = 202, @@ -89,6 +95,12 @@ typedef enum { ASSUAN_CRL_Too_Old = 303, ASSUAN_Not_Trusted = 304, + ASSUAN_Card_Error = 401, + ASSUAN_Invalid_Card = 402, + ASSUAN_No_PKCS15_App = 403, + ASSUAN_Card_Not_Present = 404, + ASSUAN_Invalid_Id = 405 + } AssuanError; /* This is a list of pre-registered ASSUAN commands */ @@ -178,7 +190,9 @@ assuan_transact (ASSUAN_CONTEXT ctx, AssuanError (*data_cb)(void *, const void *, size_t), void *data_cb_arg, AssuanError (*inquire_cb)(void*, const char *), - void *inquire_cb_arg); + void *inquire_cb_arg, + AssuanError (*status_cb)(void*, const char *), + void *status_cb_arg); /*-- assuan-inquire.c --*/ diff --git a/jnlib/ChangeLog b/jnlib/ChangeLog index b5f723cf..bf5e6c7e 100644 --- a/jnlib/ChangeLog +++ b/jnlib/ChangeLog @@ -1,3 +1,33 @@ +2002-04-04 Werner Koch + + * logging.c (log_get_prefix): New. + +2002-03-15 Werner Koch + + * argparse.c (optfile_parse): Fixed missing argument handling. + +2002-02-25 Werner Koch + + * stringhelp.c (ascii_memcasemem): New. + +2002-02-14 Werner Koch + + * Makefile.am (INCLUDES): Add cflags for libgcrypt. + +2002-02-07 Werner Koch + + * logging.c (log_set_fd): New. + + * stringhelp.c (print_sanitized_buffer): New. + (print_sanitized_string): New. + +2002-01-24 Werner Koch + + * argparse.c (strusage): Set default copyright notice year to 2002. + + Fixed the copyright notice of this file, as it has always been + part of GnuPG and therefore belongs to the FSF. + 2001-11-01 Marcus Brinkmann * logging.c (log_printf): Do not initialize ARG_PTR with 0, we @@ -72,8 +102,12 @@ Mon Jan 24 13:04:28 CET 2000 Werner Koch (do_logv): Add kludge to insert LFs. - Copyright 2000 Werner Koch (dd9jn) - Copyright 2001 g10 Code GmbH + *********************************************************** + * Please note that Jnlib is maintained as part of GnuPG. * + * You may find it source-copied in other packages. * + *********************************************************** + + Copyright 2000, 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/jnlib/argparse.c b/jnlib/argparse.c index 0e353e4d..0eb99d45 100644 --- a/jnlib/argparse.c +++ b/jnlib/argparse.c @@ -276,10 +276,12 @@ optfile_parse( FILE *fp, const char *filename, unsigned *lineno, arg->r_opt = -arg->r_opt; if( !opts[idx].short_opt ) /* unknown command/option */ arg->r_opt = (opts[idx].flags & 256)? -7:-2; - else if( (opts[idx].flags & 8) ) /* no argument */ - arg->r_opt = -3; /* error */ - else /* no or optional argument */ + else if( !(opts[idx].flags & 7) ) /* does not take an arg */ arg->r_type = 0; /* okay */ + else if( (opts[idx].flags & 8) ) /* argument is optional */ + arg->r_type = 0; /* okay */ + else /* required argument */ + arg->r_opt = -3; /* error */ break; } else if( state == 3 ) { /* no argument found */ @@ -900,7 +902,7 @@ strusage( int level ) switch( level ) { case 11: p = "foo"; break; case 13: p = "0.0"; break; - case 14: p = "Copyright (C) 2001 Free Software Foundation, Inc."; break; + case 14: p = "Copyright (C) 2002 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/jnlib/logging.c b/jnlib/logging.c index 2e0d53ae..647e757c 100644 --- a/jnlib/logging.c +++ b/jnlib/logging.c @@ -89,12 +89,37 @@ log_set_file( const char *name ) } setvbuf( fp, NULL, _IOLBF, 0 ); - if( logstream && logstream != stderr ) - fclose( logstream ); + if (logstream && logstream != stderr && logstream != stdout) + fclose( logstream ); logstream = fp; missing_lf = 0; } +void +log_set_fd (int fd) +{ + FILE *fp; + + if (fd == 1) + fp = stdout; + else if (fd == 2) + fp = stderr; + else + fp = fdopen (fd, "a"); + if (!fp) + { + fprintf (stderr, "failed to fdopen log fd %d: %s\n", + fd, strerror(errno)); + return; + } + setvbuf (fp, NULL, _IOLBF, 0); + + if (logstream && logstream != stderr && logstream != stdout) + fclose( logstream); + logstream = fp; + missing_lf = 0; +} + void log_set_prefix (const char *text, unsigned int flags) @@ -110,6 +135,23 @@ log_set_prefix (const char *text, unsigned int flags) with_pid = (flags & 4); } + +const char * +log_get_prefix (unsigned int *flags) +{ + if (flags) + { + *flags = 0; + if (with_prefix) + *flags |= 1; + if (with_time) + *flags |= 2; + if (with_pid) + *flags |=4; + } + return prefix_buffer; +} + int log_get_fd() { diff --git a/jnlib/logging.h b/jnlib/logging.h index 7b7b8c8a..224db36e 100644 --- a/jnlib/logging.h +++ b/jnlib/logging.h @@ -27,7 +27,9 @@ int log_get_errorcount (int clear); void log_set_file( const char *name ); +void log_set_fd (int fd); void log_set_prefix (const char *text, unsigned int flags); +const char *log_get_prefix (unsigned int *flags); int log_get_fd(void); FILE *log_get_stream (void); diff --git a/jnlib/stringhelp.c b/jnlib/stringhelp.c index 0d3035e8..d6883e7d 100644 --- a/jnlib/stringhelp.c +++ b/jnlib/stringhelp.c @@ -263,6 +263,52 @@ compare_filenames( const char *a, const char *b ) #endif } +/* Print a BUFFER to stream FP while replacing all control characters + and the character DELIM with standard C eescape sequences. Returns + the number of characters printed. */ +size_t +print_sanitized_buffer (FILE *fp, const void *buffer, size_t length, int delim) +{ + const unsigned char *p = buffer; + size_t count = 0; + + for (; length; length--, p++, count++) + { + if (*p < 0x20 || (*p >= 0x7f && *p < 0xa0) || *p == delim) + { + putc ('\\', fp); + count++; + if (*p == '\n') + putc ('n', fp); + else if (*p == '\r') + putc ('r', fp); + else if (*p == '\f') + putc ('f', fp); + else if (*p == '\v') + putc ('v', fp); + else if (*p == '\b') + putc ('b', fp); + else if (!*p) + putc('0', fp); + else + { + fprintf (fp, "x%02x", *p); + count += 2; + } + } + else + putc (*p, fp); + } + + return count; +} + +size_t +print_sanitized_string (FILE *fp, const char *string, int delim) +{ + return string? print_sanitized_buffer (fp, string, strlen (string), delim):0; +} + /**************************************************** ******** locale insensitive ctype functions ******** @@ -336,6 +382,26 @@ ascii_strcmp( const char *a, const char *b ) } +void * +ascii_memcasemem (const void *haystack, size_t nhaystack, + const void *needle, size_t nneedle) +{ + + if (!nneedle) + return (void*)haystack; /* finding an empty needle is really easy */ + if (nneedle <= nhaystack) + { + const unsigned char *a = haystack; + const unsigned char *b = a + nhaystack - nneedle; + + for (; a <= b; a++) + { + if ( !ascii_memcasecmp (a, needle, nneedle) ) + return (void *)a; + } + } + return NULL; +} /********************************************* ********** missing string functions ********* diff --git a/jnlib/stringhelp.h b/jnlib/stringhelp.h index 17a6ad09..bfdb0d91 100644 --- a/jnlib/stringhelp.h +++ b/jnlib/stringhelp.h @@ -37,6 +37,11 @@ char *make_dirname(const char *filepath); char *make_filename( const char *first_part, ... ); int compare_filenames( const char *a, const char *b ); +size_t print_sanitized_buffer (FILE *fp, const void *buffer, size_t length, + int delim); +size_t print_sanitized_string (FILE *fp, const char *string, int delim); + + const char *ascii_memistr( const char *buf, size_t buflen, const char *sub ); int ascii_isupper (int c); int ascii_islower (int c); @@ -44,6 +49,8 @@ int ascii_toupper (int c); int ascii_tolower (int c); int ascii_strcasecmp( const char *a, const char *b ); int ascii_memcasecmp( const char *a, const char *b, size_t n ); +void *ascii_memcasemem (const void *haystack, size_t nhaystack, + const void *needle, size_t nneedle); #ifndef HAVE_MEMICMP