pcsc-lite  2.5.0
debuglog.c
Go to the documentation of this file.
1 /*
2  * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
3  *
4  * Copyright (C) 1999-2002
5  * David Corcoran <corcoran@musclecard.com>
6  * Copyright (C) 2002-2025
7  * Ludovic Rousseau <ludovic.rousseau@free.fr>
8  *
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions
11 are met:
12 
13 1. Redistributions of source code must retain the above copyright
14  notice, this list of conditions and the following disclaimer.
15 2. Redistributions in binary form must reproduce the above copyright
16  notice, this list of conditions and the following disclaimer in the
17  documentation and/or other materials provided with the distribution.
18 3. The name of the author may not be used to endorse or promote products
19  derived from this software without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
38 #include "config.h"
39 #include <syslog.h>
40 #include <unistd.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <stdarg.h>
45 #include <assert.h>
46 #include <sys/types.h>
47 #include <sys/time.h>
48 #include <time.h>
49 #include <pthread.h>
50 #include <stdbool.h>
51 
52 #include "pcsclite.h"
53 #include "misc.h"
54 #include "debuglog.h"
55 #include "sys_generic.h"
56 
57 #ifdef NO_LOG
58 
59 void log_msg(const int priority, const char *fmt, ...)
60 {
61  (void)priority;
62  (void)fmt;
63 }
64 
65 void log_xxd(const int priority, const char *msg, const unsigned char *buffer,
66  const int len)
67 {
68  (void)priority;
69  (void)msg;
70  (void)buffer;
71  (void)len;
72 }
73 
74 void DebugLogSetLogType(const int dbgtype)
75 {
76  (void)dbgtype;
77 }
78 
79 void DebugLogSetLevel(const int level)
80 {
81  (void)level;
82 }
83 
84 INTERNAL void DebugLogSetCategory(const int dbginfo)
85 {
86  (void)dbginfo;
87 }
88 
89 INTERNAL void DebugLogCategory(const int category, const unsigned char *buffer,
90  const int len)
91 {
92  (void)category;
93  (void)buffer;
94  (void)len;
95 }
96 
97 #else
98 
102 #define DEBUG_BUF_SIZE 2048
103 
104 static char LogMsgType = DEBUGLOG_NO_DEBUG;
105 static char LogCategory = DEBUG_CATEGORY_NOTHING;
106 
108 static char LogLevel = PCSC_LOG_ERROR;
109 
110 static bool LogDoColor = false;
112 static pthread_mutex_t LastTimeMutex = PTHREAD_MUTEX_INITIALIZER;
113 
114 static void log_line(const int priority, const char *DebugBuffer,
115  unsigned int rv);
116 
117 /*
118  * log a message with the RV value returned by the daemon
119  */
120 void log_msg_rv(const int priority, unsigned int rv, const char *fmt, ...)
121 {
122  char DebugBuffer[DEBUG_BUF_SIZE];
123  va_list argptr;
124 
125  if ((priority < LogLevel) /* log priority lower than threshold? */
126  || (DEBUGLOG_NO_DEBUG == LogMsgType))
127  return;
128 
129  va_start(argptr, fmt);
130  vsnprintf(DebugBuffer, sizeof DebugBuffer, fmt, argptr);
131  va_end(argptr);
132 
133  log_line(priority, DebugBuffer, rv);
134 }
135 
136 void log_msg(const int priority, const char *fmt, ...)
137 {
138  char DebugBuffer[DEBUG_BUF_SIZE];
139  va_list argptr;
140  // boolean not to do openlog several times
141  static int syslog_opened = 0;
142 
143  if ((priority < LogLevel) /* log priority lower than threshold? */
144  || (DEBUGLOG_NO_DEBUG == LogMsgType))
145  return;
146 
147  va_start(argptr, fmt);
148  vsnprintf(DebugBuffer, sizeof DebugBuffer, fmt, argptr);
149  va_end(argptr);
150 
151  if (DEBUGLOG_SYSLOG_DEBUG == LogMsgType && !syslog_opened) {
152  openlog(NULL, LOG_PID, LOG_DAEMON);
153  syslog_opened = 1;
154  }
155 
156  log_line(priority, DebugBuffer, -1);
157 } /* log_msg */
158 
159 /* convert from integer rv value to a string value
160  * SCARD_S_SUCCESS -> "SCARD_S_SUCCESS"
161  */
162 const char * rv2text(unsigned int rv)
163 {
164  const char *rv_text = NULL;
165  static __thread char strError[30];
166 
167 #define CASE(x) \
168  case x: \
169  rv_text = "rv=" #x; \
170  break
171 
172  if (rv != (unsigned int)-1)
173  {
174  switch (rv)
175  {
176  CASE(SCARD_S_SUCCESS);
177  CASE(SCARD_E_CANCELLED);
181  CASE(SCARD_E_INVALID_VALUE);
182  CASE(SCARD_E_NO_MEMORY);
184  CASE(SCARD_E_NO_SERVICE);
185  CASE(SCARD_E_NO_SMARTCARD);
191  CASE(SCARD_E_TIMEOUT);
194  CASE(SCARD_F_COMM_ERROR);
196  CASE(SCARD_W_REMOVED_CARD);
197  CASE(SCARD_W_RESET_CARD);
200 
201  default:
202  (void)snprintf(strError, sizeof(strError)-1,
203  "Unknown error: 0x%08X", rv);
204  rv_text = strError;
205  }
206  }
207 
208  return rv_text;
209 }
210 
211 static void log_line(const int priority, const char *DebugBuffer,
212  unsigned int rv)
213 {
214  if (DEBUGLOG_SYSLOG_DEBUG == LogMsgType)
215  syslog(LOG_DEBUG, "%s", DebugBuffer);
216  else
217  {
218  static struct timeval last_time = { 0, 0 };
219  struct timeval new_time = { 0, 0 };
220  struct timeval tmp;
221  int delta;
222  pthread_t thread_id;
223  const char *rv_text = NULL;
224 
225  (void)pthread_mutex_lock(&LastTimeMutex);
226  gettimeofday(&new_time, NULL);
227  if (0 == last_time.tv_sec)
228  last_time = new_time;
229 
230  tmp.tv_sec = new_time.tv_sec - last_time.tv_sec;
231  tmp.tv_usec = new_time.tv_usec - last_time.tv_usec;
232  if (tmp.tv_usec < 0)
233  {
234  tmp.tv_sec--;
235  tmp.tv_usec += 1000000;
236  }
237  if (tmp.tv_sec < 100)
238  delta = tmp.tv_sec * 1000000 + tmp.tv_usec;
239  else
240  delta = 99999999;
241 
242  last_time = new_time;
243  (void)pthread_mutex_unlock(&LastTimeMutex);
244 
245  thread_id = pthread_self();
246 
247  rv_text = rv2text(rv);
248 
249  if (LogDoColor)
250  {
251  const char *color_pfx = "", *color_sfx = "\33[0m";
252  const char *time_pfx = "\33[36m", *time_sfx = color_sfx;
253 
254  switch (priority)
255  {
256  case PCSC_LOG_CRITICAL:
257  color_pfx = "\33[01;31m"; /* bright + Red */
258  break;
259 
260  case PCSC_LOG_ERROR:
261  color_pfx = "\33[35m"; /* Magenta */
262  break;
263 
264  case PCSC_LOG_INFO:
265  color_pfx = "\33[34m"; /* Blue */
266  break;
267 
268  case PCSC_LOG_DEBUG:
269  color_pfx = ""; /* normal (black) */
270  color_sfx = "";
271  break;
272  }
273 
274 #ifdef __GLIBC__
275 #define THREAD_FORMAT "%lu"
276 #else
277 #define THREAD_FORMAT "%p"
278 #endif
279  if (rv_text)
280  {
281  const char * rv_pfx = "", * rv_sfx = "";
282  if (rv != SCARD_S_SUCCESS)
283  {
284  rv_pfx = "\33[31m"; /* Red */
285  rv_sfx = "\33[0m";
286  }
287 
288  printf("%s%.8d%s [" THREAD_FORMAT "] %s%s%s, %s%s%s\n",
289  time_pfx, delta, time_sfx, thread_id,
290  color_pfx, DebugBuffer, color_sfx,
291  rv_pfx, rv_text, rv_sfx);
292  }
293  else
294  printf("%s%.8d%s [" THREAD_FORMAT "] %s%s%s\n",
295  time_pfx, delta, time_sfx, thread_id,
296  color_pfx, DebugBuffer, color_sfx);
297  }
298  else
299  {
300  if (rv_text)
301  printf("%.8d %s, %s\n", delta, DebugBuffer, rv_text);
302  else
303  printf("%.8d %s\n", delta, DebugBuffer);
304  }
305  fflush(stdout);
306  }
307 } /* log_line */
308 
309 static void log_xxd_always(const int priority, const char *msg,
310  const unsigned char *buffer, const int len)
311 {
312  char DebugBuffer[len*3 + strlen(msg) +1];
313  int i;
314  char *c;
315 
316  /* DebugBuffer is always big enough for msg */
317  strcpy(DebugBuffer, msg);
318  c = DebugBuffer + strlen(DebugBuffer);
319 
320  for (i = 0; (i < len); ++i)
321  {
322  /* 2 hex characters, 1 space, 1 NUL : total 4 characters */
323  snprintf(c, 4, "%02X ", buffer[i]);
324  c += 3;
325  }
326 
327  log_line(priority, DebugBuffer, -1);
328 } /* log_xxd_always */
329 
330 void log_xxd(const int priority, const char *msg, const unsigned char *buffer,
331  const int len)
332 {
333  if ((priority < LogLevel) /* log priority lower than threshold? */
334  || (DEBUGLOG_NO_DEBUG == LogMsgType))
335  return;
336 
337  /* len is an error value? */
338  if (len < 0)
339  return;
340 
341  log_xxd_always(priority, msg, buffer, len);
342 } /* log_xxd */
343 
344 void DebugLogSetLogType(const int dbgtype)
345 {
346  switch (dbgtype)
347  {
348  case DEBUGLOG_NO_DEBUG:
349  case DEBUGLOG_SYSLOG_DEBUG:
350  case DEBUGLOG_STDOUT_DEBUG:
351  LogMsgType = dbgtype;
352  break;
353  case DEBUGLOG_STDOUT_COLOR_DEBUG:
354  LogMsgType = dbgtype;
355  LogDoColor = true;
356  break;
357  default:
358  Log2(PCSC_LOG_CRITICAL, "unknown log type (%d), using stdout",
359  dbgtype);
360  LogMsgType = DEBUGLOG_STDOUT_DEBUG;
361  }
362 
363  /* log to stdout and stdout is a tty? */
364  if (DEBUGLOG_STDOUT_DEBUG == LogMsgType && isatty(fileno(stdout)))
365  {
366  const char *term;
367 
368  term = SYS_GetEnv("TERM");
369  if (term)
370  {
371  const char *terms[] = { "linux", "xterm", "xterm-color", "Eterm", "rxvt", "rxvt-unicode", "xterm-256color" };
372  unsigned int i;
373 
374  /* for each known color terminal */
375  for (i = 0; i < COUNT_OF(terms); i++)
376  {
377  /* we found a supported term? */
378  if (0 == strcmp(terms[i], term))
379  {
380  LogDoColor = true;
381  break;
382  }
383  }
384  }
385  }
386 }
387 
388 void DebugLogSetLevel(const int level)
389 {
390  LogLevel = level;
391  switch (level)
392  {
393  case PCSC_LOG_CRITICAL:
394  case PCSC_LOG_ERROR:
395  /* do not log anything */
396  break;
397 
398  case PCSC_LOG_INFO:
399  Log1(PCSC_LOG_INFO, "debug level=info");
400  break;
401 
402  case PCSC_LOG_DEBUG:
403  Log1(PCSC_LOG_DEBUG, "debug level=debug");
404  break;
405 
406  default:
407  LogLevel = PCSC_LOG_INFO;
408  Log2(PCSC_LOG_CRITICAL, "unknown level (%d), using level=info",
409  level);
410  }
411 }
412 
413 INTERNAL void DebugLogSetCategory(const int dbginfo)
414 {
415  /* use a negative number to UNset
416  * typically use ~DEBUG_CATEGORY_APDU
417  */
418  if (dbginfo < 0)
419  LogCategory &= dbginfo;
420  else
421  LogCategory |= dbginfo;
422 
423  if (LogCategory & DEBUG_CATEGORY_APDU)
424  Log1(PCSC_LOG_INFO, "Debug options: APDU");
425 }
426 
427 INTERNAL void DebugLogCategory(const int category, const unsigned char *buffer,
428  const int len)
429 {
430  if ((category & DEBUG_CATEGORY_APDU)
431  && (LogCategory & DEBUG_CATEGORY_APDU))
432  log_xxd_always(PCSC_LOG_INFO, "APDU: ", buffer, len);
433 
434  if ((category & DEBUG_CATEGORY_SW)
435  && (LogCategory & DEBUG_CATEGORY_APDU))
436  log_xxd_always(PCSC_LOG_INFO, "SW: ", buffer, len);
437 }
438 
439 /*
440  * old function supported for backward object code compatibility
441  * defined only for pcscd
442  */
443 #ifdef PCSCD
444 void debug_msg(const char *fmt, ...);
445 void debug_msg(const char *fmt, ...)
446 {
447  char DebugBuffer[DEBUG_BUF_SIZE];
448  va_list argptr;
449 
450  if (DEBUGLOG_NO_DEBUG == LogMsgType)
451  return;
452 
453  va_start(argptr, fmt);
454  vsnprintf(DebugBuffer, sizeof DebugBuffer, fmt, argptr);
455  va_end(argptr);
456 
457  if (DEBUGLOG_SYSLOG_DEBUG == LogMsgType)
458  syslog(LOG_INFO, "%s", DebugBuffer);
459  else
460  puts(DebugBuffer);
461 } /* debug_msg */
462 
463 void debug_xxd(const char *msg, const unsigned char *buffer, const int len);
464 void debug_xxd(const char *msg, const unsigned char *buffer, const int len)
465 {
466  log_xxd(PCSC_LOG_ERROR, msg, buffer, len);
467 } /* debug_xxd */
468 #endif
469 
470 #endif /* NO_LOG */
471 
#define SCARD_E_INVALID_VALUE
One or more of the supplied parameters values could not be properly interpreted.
Definition: pcsclite.h:141
#define SCARD_S_SUCCESS
No error was encountered.
Definition: pcsclite.h:107
#define SCARD_E_TIMEOUT
The user-specified timeout value has expired.
Definition: pcsclite.h:127
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
Definition: pcsclite.h:165
static bool LogDoColor
no color by default
Definition: debuglog.c:110
#define SCARD_E_INVALID_PARAMETER
One or more of the supplied parameters could not be properly interpreted.
Definition: pcsclite.h:115
#define SCARD_E_NO_READERS_AVAILABLE
Cannot find a smart card reader.
Definition: pcsclite.h:202
This handles abstract system level calls.
const char * SYS_GetEnv(const char *name)
(More) secure version of getenv(3)
Definition: sys_unix.c:168
#define SCARD_E_NO_SMARTCARD
The operation requires a Smart Card, but no Smart Card is currently in the device.
Definition: pcsclite.h:131
#define SCARD_W_UNRESPONSIVE_CARD
The smart card is not responding to a reset.
Definition: pcsclite.h:213
#define SCARD_E_NOT_TRANSACTED
An attempt was made to end a non-existent transaction.
Definition: pcsclite.h:151
#define DEBUG_BUF_SIZE
Max string size dumping a maximum of 2 lines of 80 characters.
Definition: debuglog.c:102
#define SCARD_E_PROTO_MISMATCH
The requested protocols are incompatible with the protocol currently in use with the smart card...
Definition: pcsclite.h:137
static char LogLevel
default level
Definition: debuglog.c:108
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
Definition: pcsclite.h:119
#define SCARD_E_READER_UNAVAILABLE
The specified reader is not currently available for use.
Definition: pcsclite.h:153
#define SCARD_W_RESET_CARD
The smart card has been reset, so any shared state information is invalid.
Definition: pcsclite.h:217
This keeps a list of defines for pcsc-lite.
#define SCARD_F_COMM_ERROR
An internal communications error has been detected.
Definition: pcsclite.h:145
#define SCARD_W_REMOVED_CARD
The smart card has been removed, so further communication is not possible.
Definition: pcsclite.h:219
#define SCARD_E_INSUFFICIENT_BUFFER
The data buffer to receive returned data is too small for the returned data.
Definition: pcsclite.h:123
#define SCARD_E_CANCELLED
The action was cancelled by an SCardCancel request.
Definition: pcsclite.h:111
#define SCARD_E_SHARING_VIOLATION
The smart card cannot be accessed because of other connections outstanding.
Definition: pcsclite.h:129
#define SCARD_E_UNKNOWN_READER
The specified reader name is not recognized.
Definition: pcsclite.h:125
#define SCARD_F_INTERNAL_ERROR
An internal consistency check failed.
Definition: pcsclite.h:109
#define SCARD_E_UNSUPPORTED_FEATURE
This smart card does not support the requested feature.
Definition: pcsclite.h:171
#define SCARD_E_SERVICE_STOPPED
The Smart card resource manager has shut down.
Definition: pcsclite.h:167
#define SCARD_E_INVALID_HANDLE
The supplied handle was invalid.
Definition: pcsclite.h:113
This handles debugging.
#define SCARD_W_UNPOWERED_CARD
Power has been removed from the smart card, so that further communication is not possible.
Definition: pcsclite.h:215