LCOV - code coverage report
Current view: top level - src - assuan-logging.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 67 108 62.0 %
Date: 2016-11-29 14:54:18 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /* assuan-logging.c - Default logging function.
       2             :    Copyright (C) 2002, 2003, 2004, 2007, 2009,
       3             :                  2010 Free Software Foundation, Inc.
       4             : 
       5             :    This file is part of Assuan.
       6             : 
       7             :    Assuan is free software; you can redistribute it and/or modify it
       8             :    under the terms of the GNU Lesser General Public License as
       9             :    published by the Free Software Foundation; either version 2.1 of
      10             :    the License, or (at your option) any later version.
      11             : 
      12             :    Assuan is distributed in the hope that it will be useful, but
      13             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             :    Lesser General Public License for more details.
      16             : 
      17             :    You should have received a copy of the GNU Lesser General Public
      18             :    License along with this program; if not, see <http://www.gnu.org/licenses/>.
      19             :  */
      20             : 
      21             : #ifdef HAVE_CONFIG_H
      22             : #include <config.h>
      23             : #endif
      24             : #include <stdio.h>
      25             : #include <stdlib.h>
      26             : #include <string.h>
      27             : #include <stdarg.h>
      28             : #ifdef HAVE_W32_SYSTEM
      29             : # ifdef HAVE_WINSOCK2_H
      30             : #  include <winsock2.h>
      31             : # endif
      32             : # include <windows.h>
      33             : #endif /*HAVE_W32_SYSTEM*/
      34             : #include <errno.h>
      35             : #include <ctype.h>
      36             : 
      37             : #include "assuan-defs.h"
      38             : 
      39             : 
      40             : /* The default log handler is useful for global logging, but it should
      41             :    only be used by one user of libassuan at a time.  Libraries that
      42             :    use libassuan can register their own log handler.  */
      43             : 
      44             : /* A common prefix for all log messages.  */
      45             : static char prefix_buffer[80];
      46             : 
      47             : /* A global flag read from the environment to check if to enable full
      48             :    logging of buffer data.  This is also used by custom log
      49             :    handlers.  */
      50             : static int full_logging;
      51             : 
      52             : /* A bitfield that specifies the categories to log.  */
      53             : static int log_cats;
      54             : #define TEST_LOG_CAT(x) (!! (log_cats & (1 << (x - 1))))
      55             : 
      56             : static FILE *_assuan_log;
      57             : 
      58             : 
      59             : void
      60           1 : _assuan_init_log_envvars (void)
      61             : {
      62             :   char *flagstr;
      63             : 
      64           1 :   full_logging = !!getenv ("ASSUAN_FULL_LOGGING");
      65           1 :   flagstr = getenv ("ASSUAN_DEBUG");
      66           1 :   if (flagstr)
      67           0 :     log_cats = atoi (flagstr);
      68             :   else /* Default to log the control channel.  */
      69           1 :     log_cats = (1 << (ASSUAN_LOG_CONTROL - 1));
      70             : 
      71           1 :   _assuan_sysutils_blurb (); /* Make sure this code gets linked in.  */
      72           1 : }
      73             : 
      74             : 
      75             : void
      76           1 : assuan_set_assuan_log_stream (FILE *fp)
      77             : {
      78           1 :   _assuan_log = fp;
      79             : 
      80           1 :   _assuan_init_log_envvars ();
      81           1 : }
      82             : 
      83             : 
      84             : /* Set the per context log stream.  Also enable the default log stream
      85             :    if it has not been set.  */
      86             : void
      87           1 : assuan_set_log_stream (assuan_context_t ctx, FILE *fp)
      88             : {
      89           1 :   if (ctx)
      90             :     {
      91           1 :       if (ctx->log_fp)
      92           0 :         fflush (ctx->log_fp);
      93           1 :       ctx->log_fp = fp;
      94           1 :       if (! _assuan_log)
      95           1 :         assuan_set_assuan_log_stream (fp);
      96             :     }
      97           1 : }
      98             : 
      99             : 
     100             : /* Set the prefix to be used for logging to TEXT or resets it to the
     101             :    default if TEXT is NULL. */
     102             : void
     103           4 : assuan_set_assuan_log_prefix (const char *text)
     104             : {
     105           4 :   if (text)
     106             :     {
     107           4 :       strncpy (prefix_buffer, text, sizeof (prefix_buffer)-1);
     108           4 :       prefix_buffer[sizeof (prefix_buffer)-1] = 0;
     109             :     }
     110             :   else
     111           0 :     *prefix_buffer = 0;
     112           4 : }
     113             : 
     114             : 
     115             : /* Get the prefix to be used for logging.  */
     116             : const char *
     117          33 : assuan_get_assuan_log_prefix (void)
     118             : {
     119          33 :   return prefix_buffer;
     120             : }
     121             : 
     122             : 
     123             : /* Default log handler.  */
     124             : int
     125         167 : _assuan_log_handler (assuan_context_t ctx, void *hook, unsigned int cat,
     126             :                      const char *msg)
     127             : {
     128             :   FILE *fp;
     129             :   const char *prf;
     130         167 :   int saved_errno = errno;
     131             : 
     132             :   /* For now.  */
     133         167 :   if (msg == NULL)
     134         134 :     return TEST_LOG_CAT (cat);
     135             : 
     136          33 :   if (! TEST_LOG_CAT (cat))
     137           0 :     return 0;
     138             : 
     139          33 :   fp = ctx->log_fp ? ctx->log_fp : _assuan_log;
     140          33 :   if (!fp)
     141           0 :     return 0;
     142             : 
     143          33 :   prf = assuan_get_assuan_log_prefix ();
     144          33 :   if (*prf)
     145          33 :     fprintf (fp, "%s[%u]: ", prf, (unsigned int)getpid ());
     146             : 
     147          33 :   fprintf (fp, "%s", msg);
     148             :   /* If the log stream is a file, the output would be buffered.  This
     149             :      is bad for debugging, thus we flush the stream if FORMAT ends
     150             :      with a LF.  */
     151          33 :   if (msg && *msg && msg[strlen (msg) - 1] == '\n')
     152          33 :     fflush (fp);
     153          33 :   gpg_err_set_errno (saved_errno);
     154             : 
     155          33 :   return 0;
     156             : }
     157             : 
     158             : 
     159             : 
     160             : /* Log a control channel message.  This is either a STRING with a
     161             :    diagnostic or actual data in (BUFFER1,LENGTH1) and
     162             :    (BUFFER2,LENGTH2).  If OUTBOUND is true the data is intended for
     163             :    the peer.  */
     164             : void
     165          72 : _assuan_log_control_channel (assuan_context_t ctx, int outbound,
     166             :                              const char *string,
     167             :                              const void *buffer1, size_t length1,
     168             :                              const void *buffer2, size_t length2)
     169             : {
     170             :   int res;
     171             :   char *outbuf;
     172             :   int saved_errno;
     173             : 
     174             :   /* Check whether logging is enabled and do a quick check to see
     175             :      whether the callback supports our category.  */
     176          72 :   if (!ctx
     177          72 :       || !ctx->log_cb
     178          72 :       || ctx->flags.no_logging
     179          72 :       || !(*ctx->log_cb) (ctx, ctx->log_cb_data, ASSUAN_LOG_CONTROL, NULL))
     180         111 :     return;
     181             : 
     182          33 :   saved_errno = errno;
     183             : 
     184             :   /* Note that we use the inbound channel fd as the printed channel
     185             :      number for both directions.  */
     186             : #ifdef HAVE_W32_SYSTEM
     187             : # define CHANNEL_FMT "%p"
     188             : #else
     189             : # define CHANNEL_FMT "%d"
     190             : #endif
     191             : #define TOHEX(val) (((val) < 10) ? ((val) + '0') : ((val) - 10 + 'a'))
     192             : 
     193          33 :   if (!buffer1 && buffer2)
     194             :     {
     195          14 :       buffer1 = buffer2;
     196          14 :       length1 = length2;
     197          14 :       buffer2 = NULL;
     198          14 :       length2 = 0;
     199             :     }
     200             : 
     201          33 :   if (ctx->flags.confidential && !string && buffer1)
     202           0 :     string = "[Confidential data not shown]";
     203             : 
     204          33 :   if (string)
     205             :     {
     206             :       /* Print the diagnostic.  */
     207           0 :       res = gpgrt_asprintf (&outbuf, "chan_" CHANNEL_FMT " %s [%s]\n",
     208             :                             ctx->inbound.fd, outbound? "->":"<-", string);
     209             :     }
     210          33 :   else if (buffer1)
     211             :     {
     212             :       /* Print the control channel data.  */
     213             :       const unsigned char *s;
     214             :       unsigned int n, x;
     215             : 
     216         351 :       for (n = length1, s = buffer1; n; n--, s++)
     217         318 :         if ((!isascii (*s) || iscntrl (*s) || !isprint (*s) || !*s)
     218           0 :             && !(*s >= 0x80))
     219           0 :           break;
     220          33 :       if (!n && buffer2)
     221             :         {
     222           0 :           for (n = length2, s = buffer2; n; n--, s++)
     223           0 :             if ((!isascii (*s) || iscntrl (*s) || !isprint (*s) || !*s)
     224           0 :                 && !(*s >= 0x80))
     225           0 :               break;
     226             :         }
     227          33 :       if (!buffer2)
     228          33 :         length2 = 0;
     229             : 
     230          33 :       if (!n && (length1 && *(const char*)buffer1 != '['))
     231             :         {
     232             :           /* No control characters and not starting with our error
     233             :              message indicator.  Log it verbatim.  */
     234          33 :           res = gpgrt_asprintf (&outbuf, "chan_" CHANNEL_FMT " %s %.*s%.*s\n",
     235             :                           ctx->inbound.fd, outbound? "->":"<-",
     236             :                           (int)length1, (const char*)buffer1,
     237             :                           (int)length2, buffer2? (const char*)buffer2:"");
     238             :         }
     239             :       else
     240             :         {
     241             :           /* The buffer contains control characters - do a hex dump.
     242             :              Even in full logging mode we limit the line length -
     243             :              however this is no real limit because the provided
     244             :              buffers will never be larger than the maximum assuan line
     245             :              length. */
     246             :           char *hp;
     247             :           unsigned int nbytes;
     248           0 :           unsigned int maxbytes = full_logging? (2*LINELENGTH) : 16;
     249             : 
     250           0 :           nbytes = length1 + length2;
     251           0 :           if (nbytes > maxbytes)
     252           0 :             nbytes = maxbytes;
     253             : 
     254           0 :           if (!(outbuf = malloc (50 + 3*nbytes + 60 + 3 + 1)))
     255           0 :             res = -1;
     256             :           else
     257             :             {
     258           0 :               res = 0;
     259           0 :               hp = outbuf;
     260           0 :               snprintf (hp, 50, "chan_" CHANNEL_FMT " %s [",
     261             :                         ctx->inbound.fd, outbound? "->":"<-");
     262           0 :               hp += strlen (hp);
     263           0 :               n = 0;
     264           0 :               for (s = buffer1, x = 0; x < length1 && n < nbytes; x++, n++)
     265             :                 {
     266           0 :                   *hp++ = ' ';
     267           0 :                   *hp++ = TOHEX (*s >> 4);
     268           0 :                   *hp++ = TOHEX (*s & 0x0f);
     269           0 :                   s++;
     270             :                 }
     271           0 :               for (s = buffer2, x = 0; x < length2 && n < nbytes; x++, n++)
     272             :                 {
     273           0 :                   *hp++ = ' ';
     274           0 :                   *hp++ = TOHEX (*s >> 4);
     275           0 :                   *hp++ = TOHEX (*s & 0x0f);
     276           0 :                   s++;
     277             :                 }
     278           0 :               if (nbytes < length1 + length2)
     279             :                 {
     280           0 :                   snprintf (hp, 60, " ...(%u byte(s) skipped)",
     281             :                             (unsigned int)((length1+length2) - nbytes));
     282           0 :                   hp += strlen (hp);
     283             :                 }
     284           0 :               strcpy (hp, " ]\n");
     285             :             }
     286             :         }
     287             :     }
     288             :   else
     289             :     {
     290           0 :       res = 0;
     291           0 :       outbuf = NULL;
     292             :     }
     293          33 :   if (res < 0)
     294           0 :     ctx->log_cb (ctx, ctx->log_cb_data, ASSUAN_LOG_CONTROL,
     295             :                  "[libassuan failed to format the log message]");
     296          33 :   else if (outbuf)
     297             :     {
     298          33 :       ctx->log_cb (ctx, ctx->log_cb_data, ASSUAN_LOG_CONTROL, outbuf);
     299          33 :       free (outbuf);
     300             :     }
     301             : #undef TOHEX
     302             : #undef CHANNEL_FMT
     303          33 :   gpg_err_set_errno (saved_errno);
     304             : }

Generated by: LCOV version 1.11