+2002-04-04 Werner Koch <wk@gnupg.org>
+
+ * assuan-buffer.c (my_log_prefix): New. Use it for all i/o debug
+ output.
+
+2002-03-06 Werner Koch <wk@gnupg.org>
+
+ * assuan-client.c (_assuan_read_from_server): Detect END.
+ (assuan_transact): Pass it to the data callback.
+
+2002-02-27 Werner Koch <wk@gnupg.org>
+
+ * 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 <wk@gnupg.org>
+
+ * 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 <wk@gnupg.org>
+
+ * 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 <wk@gnupg.org>
+
+ * 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 <marcus@g10code.de>
* Makefile.am (MOSTLYCLEANFILES): New variable.
#include <errno.h>
#include <unistd.h>
#include <assert.h>
-
+#ifdef USE_GNU_PTH
+# include <pth.h>
+#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)
{
*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)
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;
}
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
}
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;
/* 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
{
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
{
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
*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] == ' '))
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;
* @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
*
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;
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;
}
+
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);
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 */
#endif /*ASSUAN_DEFS_H*/
-
-
-
-
-
-
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)
{
{
char errline[256];
- if (rc < 100)
+ if (rc < 100)
sprintf (errline, "ERR %d server fault (%.50s)",
ASSUAN_Server_Fault, assuan_strerror (rc));
else
* @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
**/
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;
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);
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;
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;
}
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;
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
+#ifdef USE_GNU_PTH
+# include <pth.h>
+#endif
#include "assuan-defs.h"
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;
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,
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 */
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 --*/
+2002-04-04 Werner Koch <wk@gnupg.org>
+
+ * logging.c (log_get_prefix): New.
+
+2002-03-15 Werner Koch <wk@gnupg.org>
+
+ * argparse.c (optfile_parse): Fixed missing argument handling.
+
+2002-02-25 Werner Koch <wk@gnupg.org>
+
+ * stringhelp.c (ascii_memcasemem): New.
+
+2002-02-14 Werner Koch <wk@gnupg.org>
+
+ * Makefile.am (INCLUDES): Add cflags for libgcrypt.
+
+2002-02-07 Werner Koch <wk@gnupg.org>
+
+ * logging.c (log_set_fd): New.
+
+ * stringhelp.c (print_sanitized_buffer): New.
+ (print_sanitized_string): New.
+
+2002-01-24 Werner Koch <wk@gnupg.org>
+
+ * 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 <marcus@g10code.de>
* logging.c (log_printf): Do not initialize ARG_PTR with 0, we
(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
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 */
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"
}
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)
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()
{
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);
#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 ********
}
+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 *********
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);
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