diff --git a/src/assuan-logging.c b/src/assuan-logging.c index ca87488..fd47582 100644 --- a/src/assuan-logging.c +++ b/src/assuan-logging.c @@ -1,304 +1,304 @@ /* assuan-logging.c - Default logging function. Copyright (C) 2002, 2003, 2004, 2007, 2009, 2010 Free Software Foundation, Inc. This file is part of Assuan. Assuan is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. Assuan 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #ifdef HAVE_W32_SYSTEM # ifdef HAVE_WINSOCK2_H # include # endif # include #endif /*HAVE_W32_SYSTEM*/ #include #include #include "assuan-defs.h" /* The default log handler is useful for global logging, but it should only be used by one user of libassuan at a time. Libraries that use libassuan can register their own log handler. */ /* A common prefix for all log messages. */ static char prefix_buffer[80]; /* A global flag read from the environment to check if to enable full logging of buffer data. This is also used by custom log handlers. */ static int full_logging; /* A bitfield that specifies the categories to log. */ static int log_cats; #define TEST_LOG_CAT(x) (!! (log_cats & (1 << (x - 1)))) static FILE *_assuan_log; void _assuan_init_log_envvars (void) { char *flagstr; full_logging = !!getenv ("ASSUAN_FULL_LOGGING"); flagstr = getenv ("ASSUAN_DEBUG"); if (flagstr) log_cats = atoi (flagstr); else /* Default to log the control channel. */ log_cats = (1 << (ASSUAN_LOG_CONTROL - 1)); _assuan_sysutils_blurb (); /* Make sure this code gets linked in. */ } void assuan_set_assuan_log_stream (FILE *fp) { _assuan_log = fp; _assuan_init_log_envvars (); } /* Set the per context log stream. Also enable the default log stream if it has not been set. */ void assuan_set_log_stream (assuan_context_t ctx, FILE *fp) { if (ctx) { if (ctx->log_fp) fflush (ctx->log_fp); ctx->log_fp = fp; if (! _assuan_log) assuan_set_assuan_log_stream (fp); } } /* Set the prefix to be used for logging to TEXT or resets it to the default if TEXT is NULL. */ void assuan_set_assuan_log_prefix (const char *text) { if (text) { strncpy (prefix_buffer, text, sizeof (prefix_buffer)-1); prefix_buffer[sizeof (prefix_buffer)-1] = 0; } else *prefix_buffer = 0; } /* Get the prefix to be used for logging. */ const char * assuan_get_assuan_log_prefix (void) { return prefix_buffer; } /* Default log handler. */ int _assuan_log_handler (assuan_context_t ctx, void *hook, unsigned int cat, const char *msg) { FILE *fp; const char *prf; int saved_errno = errno; /* For now. */ if (msg == NULL) return TEST_LOG_CAT (cat); if (! TEST_LOG_CAT (cat)) return 0; fp = ctx->log_fp ? ctx->log_fp : _assuan_log; if (!fp) return 0; prf = assuan_get_assuan_log_prefix (); if (*prf) fprintf (fp, "%s[%u]: ", prf, (unsigned int)getpid ()); fprintf (fp, "%s", msg); /* If the log stream is a file, the output would be buffered. This is bad for debugging, thus we flush the stream if FORMAT ends with a LF. */ if (msg && *msg && msg[strlen (msg) - 1] == '\n') fflush (fp); gpg_err_set_errno (saved_errno); return 0; } /* Log a control channel message. This is either a STRING with a diagnostic or actual data in (BUFFER1,LENGTH1) and (BUFFER2,LENGTH2). If OUTBOUND is true the data is intended for the peer. */ void _assuan_log_control_channel (assuan_context_t ctx, int outbound, const char *string, const void *buffer1, size_t length1, const void *buffer2, size_t length2) { int res; char *outbuf; int saved_errno; /* Check whether logging is enabled and do a quick check to see whether the callback supports our category. */ if (!ctx || !ctx->log_cb || ctx->flags.no_logging || !(*ctx->log_cb) (ctx, ctx->log_cb_data, ASSUAN_LOG_CONTROL, NULL)) return; saved_errno = errno; /* Note that we use the inbound channel fd as the printed channel number for both directions. */ #ifdef HAVE_W32_SYSTEM # define CHANNEL_FMT "%p" #else # define CHANNEL_FMT "%d" #endif #define TOHEX(val) (((val) < 10) ? ((val) + '0') : ((val) - 10 + 'a')) if (!buffer1 && buffer2) { buffer1 = buffer2; length1 = length2; buffer2 = NULL; length2 = 0; } if (ctx->flags.confidential && !string && buffer1) string = "[Confidential data not shown]"; if (string) { /* Print the diagnostic. */ res = gpgrt_asprintf (&outbuf, "chan_" CHANNEL_FMT " %s [%s]\n", ctx->inbound.fd, outbound? "->":"<-", string); } else if (buffer1) { /* Print the control channel data. */ const unsigned char *s; unsigned int n, x; for (n = length1, s = buffer1; n; n--, s++) if ((!isascii (*s) || iscntrl (*s) || !isprint (*s) || !*s) && !(*s >= 0x80)) break; if (!n && buffer2) { for (n = length2, s = buffer2; n; n--, s++) if ((!isascii (*s) || iscntrl (*s) || !isprint (*s) || !*s) && !(*s >= 0x80)) break; } if (!buffer2) length2 = 0; if (!n && (length1 && *(const char*)buffer1 != '[')) { /* No control characters and not starting with our error message indicator. Log it verbatim. */ res = gpgrt_asprintf (&outbuf, "chan_" CHANNEL_FMT " %s %.*s%.*s\n", ctx->inbound.fd, outbound? "->":"<-", (int)length1, (const char*)buffer1, (int)length2, buffer2? (const char*)buffer2:""); } else { /* The buffer contains control characters - do a hex dump. Even in full logging mode we limit the line length - however this is no real limit because the provided buffers will never be larger than the maximum assuan line length. */ char *hp; unsigned int nbytes; unsigned int maxbytes = full_logging? (2*LINELENGTH) : 16; nbytes = length1 + length2; if (nbytes > maxbytes) nbytes = maxbytes; if (!(outbuf = malloc (50 + 3*nbytes + 60 + 3 + 1))) res = -1; else { res = 0; hp = outbuf; snprintf (hp, 50, "chan_" CHANNEL_FMT " %s [", ctx->inbound.fd, outbound? "->":"<-"); hp += strlen (hp); n = 0; for (s = buffer1, x = 0; x < length1 && n < nbytes; x++, n++) { *hp++ = ' '; *hp++ = TOHEX (*s >> 4); *hp++ = TOHEX (*s & 0x0f); s++; } for (s = buffer2, x = 0; x < length2 && n < nbytes; x++, n++) { *hp++ = ' '; *hp++ = TOHEX (*s >> 4); *hp++ = TOHEX (*s & 0x0f); s++; } if (nbytes < length1 + length2) { snprintf (hp, 60, " ...(%u byte(s) skipped)", (unsigned int)((length1+length2) - nbytes)); hp += strlen (hp); } strcpy (hp, " ]\n"); } } } else { res = 0; outbuf = NULL; } if (res < 0) ctx->log_cb (ctx, ctx->log_cb_data, ASSUAN_LOG_CONTROL, "[libassuan failed to format the log message]"); else if (outbuf) { ctx->log_cb (ctx, ctx->log_cb_data, ASSUAN_LOG_CONTROL, outbuf); - free (outbuf); + gpgrt_free (outbuf); } #undef TOHEX #undef CHANNEL_FMT gpg_err_set_errno (saved_errno); } diff --git a/src/debug.c b/src/debug.c index 9ef6237..9fe9f20 100644 --- a/src/debug.c +++ b/src/debug.c @@ -1,189 +1,189 @@ /* debug.c - helpful output in desperate situations Copyright (C) 2000 Werner Koch (dd9jn) Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2009 g10 Code GmbH This file is part of Assuan. Assuan is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. Assuan 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #if HAVE_CONFIG_H #include #endif #include #include #include #include #ifdef HAVE_UNISTD_H # include #endif #include #include #ifndef HAVE_DOSISH_SYSTEM # include # include # include #endif #include #include "assuan-defs.h" #include "debug.h" /* Log the formatted string FORMAT at debug category CAT higher. */ void _assuan_debug (assuan_context_t ctx, unsigned int cat, const char *format, ...) { va_list arg_ptr; int saved_errno; char *msg; int res; /* vasprintf is an expensive operation thus we first check whether the callback has enabled CAT for logging. */ if (!ctx || !ctx->log_cb || !(*ctx->log_cb) (ctx, ctx->log_cb_data, cat, NULL)) return; saved_errno = errno; va_start (arg_ptr, format); res = gpgrt_vasprintf (&msg, format, arg_ptr); va_end (arg_ptr); if (res < 0) return; ctx->log_cb (ctx, ctx->log_cb_data, cat, msg); - free (msg); + gpgrt_free (msg); gpg_err_set_errno (saved_errno); } /* Start a new debug line in *LINE, logged at level LEVEL or higher, and starting with the formatted string FORMAT. */ void _assuan_debug_begin (assuan_context_t ctx, void **line, unsigned int cat, const char *format, ...) { va_list arg_ptr; int res; *line = NULL; /* Probe if this wants to be logged based on category. */ if (! ctx || ! ctx->log_cb || ! (*ctx->log_cb) (ctx, ctx->log_cb_data, cat, NULL)) return; va_start (arg_ptr, format); res = gpgrt_vasprintf ((char **) line, format, arg_ptr); va_end (arg_ptr); if (res < 0) *line = NULL; } /* Add the formatted string FORMAT to the debug line *LINE. */ void _assuan_debug_add (assuan_context_t ctx, void **line, const char *format, ...) { va_list arg_ptr; char *toadd; char *result; int res; if (!*line) return; va_start (arg_ptr, format); res = gpgrt_vasprintf (&toadd, format, arg_ptr); va_end (arg_ptr); if (res < 0) { - free (*line); + gpgrt_free (*line); *line = NULL; } res = gpgrt_asprintf (&result, "%s%s", *(char **) line, toadd); - free (toadd); - free (*line); + gpgrt_free (toadd); + gpgrt_free (*line); if (res < 0) *line = NULL; else *line = result; } /* Finish construction of *LINE and send it to the debug output stream. */ void _assuan_debug_end (assuan_context_t ctx, void **line, unsigned int cat) { if (!*line) return; /* Force logging here by using category ~0. */ _assuan_debug (ctx, ~0, "%s", *line); - free (*line); + gpgrt_free (*line); *line = NULL; } #define TOHEX(val) (((val) < 10) ? ((val) + '0') : ((val) - 10 + 'a')) void _assuan_debug_buffer (assuan_context_t ctx, unsigned int cat, const char *const fmt, const char *const func, const char *const tagname, void *tag, const char *const buffer, size_t len) { int idx = 0; int j; /* Probe if this wants to be logged based on category. */ if (!ctx || ! ctx->log_cb || ! (*ctx->log_cb) (ctx, ctx->log_cb_data, cat, NULL)) return; while (idx < len) { char str[51]; char *strp = str; char *strp2 = &str[34]; for (j = 0; j < 16; j++) { unsigned char val; if (idx < len) { val = buffer[idx++]; *(strp++) = TOHEX (val >> 4); *(strp++) = TOHEX (val % 16); *(strp2++) = isprint (val) ? val : '.'; } else { *(strp++) = ' '; *(strp++) = ' '; } if (j == 7) *(strp++) = ' '; } *(strp++) = ' '; *(strp2++) = '\n'; *(strp2) = '\0'; _assuan_debug (ctx, cat, fmt, func, tagname, tag, str); } }