Blame src/debug.c

Packit d7e8d0
/* debug.c - helpful output in desperate situations
Packit Service 30b792
 * Copyright (C) 2000 Werner Koch (dd9jn)
Packit Service 30b792
 * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2009, 2019 g10 Code GmbH
Packit Service 30b792
 *
Packit Service 30b792
 * This file is part of GPGME.
Packit Service 30b792
 *
Packit Service 30b792
 * GPGME is free software; you can redistribute it and/or modify it
Packit Service 30b792
 * under the terms of the GNU Lesser General Public License as
Packit Service 30b792
 * published by the Free Software Foundation; either version 2.1 of
Packit Service 30b792
 * the License, or (at your option) any later version.
Packit Service 30b792
 *
Packit Service 30b792
 * GPGME is distributed in the hope that it will be useful, but
Packit Service 30b792
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 30b792
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 30b792
 * Lesser General Public License for more details.
Packit Service 30b792
 *
Packit Service 30b792
 * You should have received a copy of the GNU Lesser General Public
Packit Service 30b792
 * License along with this program; if not, see <https://gnu.org/licenses/>.
Packit Service 30b792
 * SPDX-License-Identifier: LGPL-2.1-or-later
Packit Service 30b792
 */
Packit d7e8d0
Packit d7e8d0
#if HAVE_CONFIG_H
Packit d7e8d0
#include <config.h>
Packit d7e8d0
#endif
Packit d7e8d0
#include <stdio.h>
Packit d7e8d0
#include <stdlib.h>
Packit d7e8d0
#include <string.h>
Packit d7e8d0
#include <stdarg.h>
Packit d7e8d0
#ifdef HAVE_UNISTD_H
Packit d7e8d0
# include <unistd.h>
Packit d7e8d0
#endif
Packit d7e8d0
#include <ctype.h>
Packit d7e8d0
#include <errno.h>
Packit d7e8d0
#include <time.h>
Packit d7e8d0
#ifndef HAVE_DOSISH_SYSTEM
Packit d7e8d0
# ifdef HAVE_SYS_TYPES_H
Packit d7e8d0
#  include <sys/types.h>
Packit d7e8d0
# endif
Packit d7e8d0
# ifdef HAVE_SYS_STAT_H
Packit d7e8d0
#  include <sys/stat.h>
Packit d7e8d0
# endif
Packit d7e8d0
# include <fcntl.h>
Packit d7e8d0
#endif
Packit d7e8d0
#include <assert.h>
Packit d7e8d0
Packit d7e8d0
#include "util.h"
Packit d7e8d0
#include "ath.h"
Packit d7e8d0
#include "sema.h"
Packit d7e8d0
#include "sys-util.h"
Packit d7e8d0
#include "debug.h"
Packit d7e8d0
Packit d7e8d0

Packit d7e8d0
/* The amount of detail requested by the user, per environment
Packit d7e8d0
   variable GPGME_DEBUG.  */
Packit d7e8d0
static int debug_level;
Packit d7e8d0
Packit d7e8d0
/* The output stream for the debug messages.  */
Packit d7e8d0
static FILE *errfp;
Packit d7e8d0
Packit d7e8d0
/* If not NULL, this malloced string is used instead of the
Packit d7e8d0
   GPGME_DEBUG envvar.  It must have been set before the debug
Packit d7e8d0
   subsystem has been initialized.  Using it later may or may not have
Packit d7e8d0
   any effect.  */
Packit d7e8d0
static char *envvar_override;
Packit d7e8d0
Packit d7e8d0

Packit d7e8d0
#ifdef HAVE_TLS
Packit d7e8d0
#define FRAME_NR
Packit d7e8d0
static __thread int frame_nr = 0;
Packit d7e8d0
#endif
Packit d7e8d0
Packit d7e8d0
void
Packit d7e8d0
_gpgme_debug_frame_begin (void)
Packit d7e8d0
{
Packit d7e8d0
#ifdef FRAME_NR
Packit d7e8d0
  frame_nr++;
Packit d7e8d0
#endif
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
int _gpgme_debug_frame_end (void)
Packit d7e8d0
{
Packit d7e8d0
#ifdef FRAME_NR
Packit d7e8d0
  frame_nr--;
Packit d7e8d0
#endif
Packit d7e8d0
  return 0;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0

Packit d7e8d0
/* Remove leading and trailing white spaces.  */
Packit d7e8d0
static char *
Packit d7e8d0
trim_spaces (char *str)
Packit d7e8d0
{
Packit d7e8d0
  char *string, *p, *mark;
Packit d7e8d0
Packit d7e8d0
  string = str;
Packit d7e8d0
  /* Find first non space character.  */
Packit d7e8d0
  for (p = string; *p && isspace (*(unsigned char *) p); p++)
Packit d7e8d0
    ;
Packit d7e8d0
  /* Move characters.  */
Packit d7e8d0
  for (mark = NULL; (*string = *p); string++, p++)
Packit d7e8d0
    if (isspace (*(unsigned char *) p))
Packit d7e8d0
      {
Packit d7e8d0
	if (!mark)
Packit d7e8d0
	  mark = string;
Packit d7e8d0
      }
Packit d7e8d0
    else
Packit d7e8d0
      mark = NULL;
Packit d7e8d0
  if (mark)
Packit d7e8d0
    *mark = '\0';	/* Remove trailing spaces.  */
Packit d7e8d0
Packit d7e8d0
  return str;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* This is an internal function to set debug info.  The caller must
Packit d7e8d0
   assure that this function is called only by one thread at a time.
Packit d7e8d0
   The function may have no effect if called after the debug system
Packit d7e8d0
   has been initialized.  Returns 0 on success.  */
Packit d7e8d0
int
Packit d7e8d0
_gpgme_debug_set_debug_envvar (const char *value)
Packit d7e8d0
{
Packit d7e8d0
  free (envvar_override);
Packit d7e8d0
  envvar_override = strdup (value);
Packit d7e8d0
  return !envvar_override;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
static void
Packit d7e8d0
debug_init (void)
Packit d7e8d0
{
Packit d7e8d0
  static int initialized;
Packit d7e8d0
Packit d7e8d0
  if (!initialized)
Packit d7e8d0
    {
Packit d7e8d0
      gpgme_error_t err;
Packit d7e8d0
      char *e;
Packit d7e8d0
      const char *s1, *s2;;
Packit d7e8d0
Packit d7e8d0
      if (envvar_override)
Packit d7e8d0
        {
Packit d7e8d0
          e = strdup (envvar_override);
Packit d7e8d0
          free (envvar_override);
Packit d7e8d0
          envvar_override = NULL;
Packit d7e8d0
        }
Packit d7e8d0
      else
Packit d7e8d0
        {
Packit d7e8d0
          err = _gpgme_getenv ("GPGME_DEBUG", &e);
Packit d7e8d0
          if (err)
Packit Service 30b792
            return;
Packit d7e8d0
        }
Packit d7e8d0
Packit d7e8d0
      initialized = 1;
Packit d7e8d0
      errfp = stderr;
Packit d7e8d0
      if (e)
Packit d7e8d0
	{
Packit d7e8d0
	  debug_level = atoi (e);
Packit d7e8d0
	  s1 = strchr (e, PATHSEP_C);
Packit d7e8d0
	  if (s1)
Packit d7e8d0
	    {
Packit d7e8d0
#ifndef HAVE_DOSISH_SYSTEM
Packit d7e8d0
	      if (getuid () == geteuid ()
Packit d7e8d0
#if defined(HAVE_GETGID) && defined(HAVE_GETEGID)
Packit d7e8d0
                  && getgid () == getegid ()
Packit d7e8d0
#endif
Packit d7e8d0
                  )
Packit d7e8d0
		{
Packit d7e8d0
#endif
Packit d7e8d0
		  char *p;
Packit d7e8d0
		  FILE *fp;
Packit d7e8d0
Packit d7e8d0
		  s1++;
Packit d7e8d0
		  if (!(s2 = strchr (s1, PATHSEP_C)))
Packit d7e8d0
		    s2 = s1 + strlen (s1);
Packit d7e8d0
		  p = malloc (s2 - s1 + 1);
Packit d7e8d0
		  if (p)
Packit d7e8d0
		    {
Packit d7e8d0
		      memcpy (p, s1, s2 - s1);
Packit d7e8d0
		      p[s2-s1] = 0;
Packit d7e8d0
		      trim_spaces (p);
Packit d7e8d0
		      fp = fopen (p,"a");
Packit d7e8d0
		      if (fp)
Packit d7e8d0
			{
Packit d7e8d0
			  setvbuf (fp, NULL, _IOLBF, 0);
Packit d7e8d0
			  errfp = fp;
Packit d7e8d0
			}
Packit d7e8d0
		      free (p);
Packit d7e8d0
		    }
Packit d7e8d0
#ifndef HAVE_DOSISH_SYSTEM
Packit d7e8d0
		}
Packit d7e8d0
#endif
Packit d7e8d0
	    }
Packit d7e8d0
	  free (e);
Packit d7e8d0
        }
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  if (debug_level > 0)
Packit d7e8d0
    {
Packit Service 30b792
      _gpgme_debug (NULL, DEBUG_INIT, -1, NULL, NULL, NULL,
Packit Service 30b792
                    "gpgme_debug: level=%d\n", debug_level);
Packit d7e8d0
#ifdef HAVE_W32_SYSTEM
Packit d7e8d0
      {
Packit d7e8d0
        const char *name = _gpgme_get_inst_dir ();
Packit Service 30b792
        _gpgme_debug (NULL, DEBUG_INIT, -1, NULL, NULL, NULL,
Packit Service 30b792
                      "gpgme_debug: gpgme='%s'\n", name? name: "?");
Packit d7e8d0
      }
Packit d7e8d0
#endif
Packit d7e8d0
    }
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
Packit Service 30b792
/* This should be called as soon as possible.  It is required so that
Packit Service 30b792
 * the assuan logging gets connected to the gpgme log stream as early
Packit Service 30b792
 * as possible.  */
Packit d7e8d0
void
Packit d7e8d0
_gpgme_debug_subsystem_init (void)
Packit d7e8d0
{
Packit d7e8d0
  debug_init ();
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0

Packit Service 30b792
/* Log the formatted string FORMAT prefixed with additional info
Packit Service 30b792
 * depending on MODE:
Packit Service 30b792
 *
Packit Service 30b792
 * -1 = Do not print any additional args.
Packit Service 30b792
 *  0 = standalone (used by macro TRACE)
Packit Service 30b792
 *  1 = enter a function (used by macro TRACE_BEG)
Packit Service 30b792
 *  2 = debug a function (used by macro TRACE_LOG)
Packit Service 30b792
 *  3 = leave a function (used by macro TRACE_SUC)
Packit Service 30b792
 *
Packit Service 30b792
 * If LINE is not NULL the output will be stored in that variabale but
Packit Service 30b792
 * without a LF.  _gpgme_debug_add can be used to add more and
Packit Service 30b792
 * _gpgme_debug_end to finally output it.
Packit d7e8d0
 *
Packit d7e8d0
 * Returns: 0
Packit d7e8d0
 *
Packit d7e8d0
 * Note that we always return 0 because the old TRACE macro evaluated
Packit d7e8d0
 * to 0 which issues a warning with newer gcc version about an unused
Packit d7e8d0
 * values.  By using a return value of this function this can be
Packit d7e8d0
 * avoided.  Fixme: It might be useful to check whether the return
Packit d7e8d0
 * value from the TRACE macros are actually used somewhere.
Packit d7e8d0
 */
Packit d7e8d0
int
Packit Service 30b792
_gpgme_debug (void **line, int level, int mode,
Packit Service 30b792
              const char *func, const char *tagname,
Packit Service 30b792
              const char *tagvalue, const char *format, ...)
Packit d7e8d0
{
Packit d7e8d0
  va_list arg_ptr;
Packit d7e8d0
  int saved_errno;
Packit Service 30b792
  int need_lf;
Packit Service 30b792
  int indent;
Packit Service 30b792
  char *prefix, *stdinfo, *userinfo;
Packit Service 30b792
  const char *modestr;
Packit Service 30b792
  int no_userinfo = 0;
Packit d7e8d0
Packit d7e8d0
  if (debug_level < level)
Packit d7e8d0
    return 0;
Packit d7e8d0
Packit Service 30b792
#ifdef FRAME_NR
Packit Service 30b792
    indent = frame_nr > 0? (2 * (frame_nr - 1)):0;
Packit Service 30b792
#else
Packit Service 30b792
    indent = 0;
Packit Service 30b792
#endif
Packit Service 30b792
Packit Service 30b792
  saved_errno = errno;
Packit d7e8d0
  va_start (arg_ptr, format);
Packit d7e8d0
  {
Packit d7e8d0
    struct tm *tp;
Packit d7e8d0
    time_t atime = time (NULL);
Packit d7e8d0
Packit d7e8d0
    tp = localtime (&atime);
Packit Service 30b792
    prefix = gpgrt_bsprintf ("GPGME %04d%02d%02dT%02d%02d%02d %04llX  %*s",
Packit Service 30b792
                             1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
Packit Service 30b792
                             tp->tm_hour, tp->tm_min, tp->tm_sec,
Packit Service 30b792
                             (unsigned long long) ath_self (),
Packit Service 30b792
                             indent < 40? indent : 40, "");
Packit d7e8d0
  }
Packit d7e8d0
Packit Service 30b792
  switch (mode)
Packit Service 30b792
    {
Packit Service 30b792
    case -1: modestr = NULL; break; /* Do nothing.  */
Packit Service 30b792
    case 0: modestr = "call"; break;
Packit Service 30b792
    case 1: modestr = "enter"; break;
Packit Service 30b792
    case 2: modestr = "check"; break;
Packit Service 30b792
    case 3: modestr = "leave"; break;
Packit Service 30b792
    default: modestr = "mode?"; break;
Packit Service 30b792
    }
Packit d7e8d0
Packit Service 30b792
  if (!modestr)
Packit Service 30b792
    stdinfo = NULL;
Packit Service 30b792
  else if (tagname && strcmp (tagname, XSTRINGIFY (NULL)))
Packit Service 30b792
    stdinfo = gpgrt_bsprintf ("%s: %s: %s=%p ", func,modestr,tagname,tagvalue);
Packit Service 30b792
  else
Packit Service 30b792
    stdinfo = gpgrt_bsprintf ("%s: %s: ", func, modestr);
Packit d7e8d0
Packit Service 30b792
  if (format && *format)
Packit Service 30b792
    userinfo = gpgrt_vbsprintf (format, arg_ptr);
Packit Service 30b792
  else
Packit Service 30b792
    {
Packit Service 30b792
      userinfo = NULL;
Packit Service 30b792
      no_userinfo = 1;
Packit Service 30b792
    }
Packit Service 30b792
  va_end (arg_ptr);
Packit d7e8d0
Packit Service 30b792
  if (mode != -1 && (!format || !*format))
Packit Service 30b792
    need_lf = 1;
Packit Service 30b792
  else if (userinfo && *userinfo && userinfo[strlen (userinfo) - 1] != '\n')
Packit Service 30b792
    need_lf = 1;
Packit Service 30b792
  else
Packit Service 30b792
    need_lf = 0;
Packit Service 30b792
Packit Service 30b792
  if (line)
Packit Service 30b792
    *line = gpgrt_bsprintf ("%s%s%s",
Packit Service 30b792
                            prefix? prefix : "GPGME out-of-core ",
Packit Service 30b792
                            !modestr? "" : stdinfo? stdinfo :
Packit Service 30b792
                            (!format || !*format)? "" :"out-of-core ",
Packit Service 30b792
                            userinfo? userinfo : "out-of-core");
Packit Service 30b792
  else
Packit d7e8d0
    {
Packit Service 30b792
      fprintf (errfp, "%s%s%s%s",
Packit Service 30b792
               prefix? prefix : "GPGME out-of-core ",
Packit Service 30b792
               !modestr? "" : stdinfo? stdinfo :
Packit Service 30b792
               (!format || !*format)? "" :"out-of-core ",
Packit Service 30b792
               userinfo? userinfo : no_userinfo? "" : "out-of-core",
Packit Service 30b792
               need_lf? "\n":"");
Packit Service 30b792
      fflush (errfp);
Packit d7e8d0
    }
Packit d7e8d0
Packit Service 30b792
  gpgrt_free (userinfo);
Packit Service 30b792
  gpgrt_free (stdinfo);
Packit Service 30b792
  gpgrt_free (prefix);
Packit Service 30b792
  gpg_err_set_errno (saved_errno);
Packit Service 30b792
  return 0;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Add the formatted string FORMAT to the debug line *LINE.  */
Packit d7e8d0
void
Packit d7e8d0
_gpgme_debug_add (void **line, const char *format, ...)
Packit d7e8d0
{
Packit d7e8d0
  va_list arg_ptr;
Packit d7e8d0
  char *toadd;
Packit d7e8d0
  char *result;
Packit d7e8d0
  int res;
Packit d7e8d0
Packit d7e8d0
  if (!*line)
Packit d7e8d0
    return;
Packit d7e8d0
Packit d7e8d0
  va_start (arg_ptr, format);
Packit d7e8d0
  res = gpgrt_vasprintf (&toadd, format, arg_ptr);
Packit d7e8d0
  va_end (arg_ptr);
Packit d7e8d0
  if (res < 0)
Packit d7e8d0
    {
Packit d7e8d0
      gpgrt_free (*line);
Packit d7e8d0
      *line = NULL;
Packit d7e8d0
    }
Packit d7e8d0
  res = gpgrt_asprintf (&result, "%s%s", *(char **) line, toadd);
Packit d7e8d0
  gpgrt_free (toadd);
Packit d7e8d0
  gpgrt_free (*line);
Packit d7e8d0
  if (res < 0)
Packit d7e8d0
    *line = NULL;
Packit d7e8d0
  else
Packit d7e8d0
    *line = result;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Finish construction of *LINE and send it to the debug output
Packit d7e8d0
   stream.  */
Packit d7e8d0
void
Packit d7e8d0
_gpgme_debug_end (void **line)
Packit d7e8d0
{
Packit Service 30b792
  const char *string;
Packit Service 30b792
Packit d7e8d0
  if (!*line)
Packit d7e8d0
    return;
Packit Service 30b792
  string = *line;
Packit d7e8d0
Packit Service 30b792
  fprintf (errfp, "%s%s",
Packit Service 30b792
           string,
Packit Service 30b792
           (*string && string[strlen (string)-1] != '\n')? "\n":"");
Packit Service 30b792
  fflush (errfp);
Packit d7e8d0
  gpgrt_free (*line);
Packit d7e8d0
  *line = NULL;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
#define TOHEX(val) (((val) < 10) ? ((val) + '0') : ((val) - 10 + 'a'))
Packit d7e8d0
Packit d7e8d0
void
Packit d7e8d0
_gpgme_debug_buffer (int lvl, const char *const fmt,
Packit d7e8d0
		     const char *const func, const char *const buffer,
Packit d7e8d0
		     size_t len)
Packit d7e8d0
{
Packit d7e8d0
  int idx = 0;
Packit d7e8d0
  int j;
Packit d7e8d0
Packit d7e8d0
  if (!_gpgme_debug_trace ())
Packit d7e8d0
    return;
Packit d7e8d0
Packit Service 30b792
  if (!buffer)
Packit Service 30b792
    return;
Packit Service 30b792
Packit Service 30b792
  if (lvl > 9)
Packit d7e8d0
    {
Packit Service 30b792
      while (idx < len)
Packit Service 30b792
        {
Packit Service 30b792
          char str[51];
Packit Service 30b792
          char *strp = str;
Packit Service 30b792
          char *strp2 = &str[34];
Packit d7e8d0
Packit Service 30b792
          for (j = 0; j < 16; j++)
Packit Service 30b792
            {
Packit Service 30b792
              unsigned char val;
Packit Service 30b792
              if (idx < len)
Packit Service 30b792
                {
Packit Service 30b792
                  val = buffer[idx++];
Packit Service 30b792
                  *(strp++) = TOHEX (val >> 4);
Packit Service 30b792
                  *(strp++) = TOHEX (val % 16);
Packit Service 30b792
                  *(strp2++) = isprint (val)? val : '.';
Packit Service 30b792
                }
Packit Service 30b792
              else
Packit Service 30b792
                {
Packit Service 30b792
                  *(strp++) = ' ';
Packit Service 30b792
                  *(strp++) = ' ';
Packit Service 30b792
                }
Packit Service 30b792
              if (j == 7)
Packit Service 30b792
                *(strp++) = ' ';
Packit Service 30b792
            }
Packit Service 30b792
          *(strp++) = ' ';
Packit Service 30b792
          *(strp2) = '\0';
Packit d7e8d0
Packit Service 30b792
          _gpgme_debug (NULL, lvl, -1, NULL, NULL, NULL, fmt, func, str);
Packit Service 30b792
        }
Packit Service 30b792
    }
Packit Service 30b792
  else
Packit Service 30b792
    {
Packit Service 30b792
      while (idx < len)
Packit Service 30b792
        {
Packit Service 30b792
          char str[48+4+1];
Packit Service 30b792
          char *strp = str;
Packit Service 30b792
Packit Service 30b792
          for (j = 0; j < 48; j++)
Packit Service 30b792
            {
Packit Service 30b792
              unsigned char val;
Packit Service 30b792
              if (idx < len)
Packit Service 30b792
                {
Packit Service 30b792
                  val = buffer[idx++];
Packit Service 30b792
                  if (val == '\n')
Packit Service 30b792
                    {
Packit Service 30b792
                      *strp++ = '<';
Packit Service 30b792
                      *strp++ = 'L';
Packit Service 30b792
                      *strp++ = 'F';
Packit Service 30b792
                      *strp++ = '>';
Packit Service 30b792
                      break;
Packit Service 30b792
                    }
Packit Service 30b792
                  *strp++ = (val > 31 && val < 127)? val : '.';
Packit Service 30b792
                }
Packit Service 30b792
            }
Packit Service 30b792
          *strp = 0;
Packit Service 30b792
Packit Service 30b792
          _gpgme_debug (NULL, lvl, -1, NULL, NULL, NULL, fmt, func, str);
Packit Service 30b792
        }
Packit d7e8d0
    }
Packit d7e8d0
}