pcsc-lite  2.2.3
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-2024
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 
51 #include "pcsclite.h"
52 #include "misc.h"
53 #include "debuglog.h"
54 #include "sys_generic.h"
55 
56 #ifdef NO_LOG
57 
58 void log_msg(const int priority, const char *fmt, ...)
59 {
60  (void)priority;
61  (void)fmt;
62 }
63 
64 void log_xxd(const int priority, const char *msg, const unsigned char *buffer,
65  const int len)
66 {
67  (void)priority;
68  (void)msg;
69  (void)buffer;
70  (void)len;
71 }
72 
73 void DebugLogSetLogType(const int dbgtype)
74 {
75  (void)dbgtype;
76 }
77 
78 void DebugLogSetLevel(const int level)
79 {
80  (void)level;
81 }
82 
83 INTERNAL void DebugLogSetCategory(const int dbginfo)
84 {
85  (void)dbginfo;
86 }
87 
88 INTERNAL void DebugLogCategory(const int category, const unsigned char *buffer,
89  const int len)
90 {
91  (void)category;
92  (void)buffer;
93  (void)len;
94 }
95 
96 #else
97 
101 #define DEBUG_BUF_SIZE 2048
102 
103 static char LogMsgType = DEBUGLOG_NO_DEBUG;
104 static char LogCategory = DEBUG_CATEGORY_NOTHING;
105 
107 static char LogLevel = PCSC_LOG_ERROR;
108 
109 static signed char LogDoColor = 0;
111 static pthread_mutex_t LastTimeMutex = PTHREAD_MUTEX_INITIALIZER;
112 
113 static void log_line(const int priority, const char *DebugBuffer,
114  unsigned int rv);
115 
116 /*
117  * log a message with the RV value returned by the daemon
118  */
119 void log_msg_rv(const int priority, unsigned int rv, const char *fmt, ...)
120 {
121  char DebugBuffer[DEBUG_BUF_SIZE];
122  va_list argptr;
123 
124  if ((priority < LogLevel) /* log priority lower than threshold? */
125  || (DEBUGLOG_NO_DEBUG == LogMsgType))
126  return;
127 
128  va_start(argptr, fmt);
129  vsnprintf(DebugBuffer, sizeof DebugBuffer, fmt, argptr);
130  va_end(argptr);
131 
132  log_line(priority, DebugBuffer, rv);
133 }
134 
135 void log_msg(const int priority, const char *fmt, ...)
136 {
137  char DebugBuffer[DEBUG_BUF_SIZE];
138  va_list argptr;
139 
140  if ((priority < LogLevel) /* log priority lower than threshold? */
141  || (DEBUGLOG_NO_DEBUG == LogMsgType))
142  return;
143 
144  va_start(argptr, fmt);
145  vsnprintf(DebugBuffer, sizeof DebugBuffer, fmt, argptr);
146  va_end(argptr);
147 
148  log_line(priority, DebugBuffer, -1);
149 } /* log_msg */
150 
151 /* convert from integer rv value to a string value
152  * SCARD_S_SUCCESS -> "SCARD_S_SUCCESS"
153  */
154 const char * rv2text(unsigned int rv)
155 {
156  const char *rv_text = NULL;
157  static __thread char strError[30];
158 
159 #define CASE(x) \
160  case x: \
161  rv_text = "rv=" #x; \
162  break
163 
164  if (rv != (unsigned int)-1)
165  {
166  switch (rv)
167  {
168  CASE(SCARD_S_SUCCESS);
169  CASE(SCARD_E_CANCELLED);
173  CASE(SCARD_E_INVALID_VALUE);
174  CASE(SCARD_E_NO_MEMORY);
175  CASE(SCARD_E_NO_SERVICE);
176  CASE(SCARD_E_NO_SMARTCARD);
181  CASE(SCARD_E_TIMEOUT);
184  CASE(SCARD_F_COMM_ERROR);
186  CASE(SCARD_W_REMOVED_CARD);
187  CASE(SCARD_W_RESET_CARD);
191 
192  default:
193  (void)snprintf(strError, sizeof(strError)-1,
194  "Unknown error: 0x%08X", rv);
195  rv_text = strError;
196  }
197  }
198 
199  return rv_text;
200 }
201 
202 static void log_line(const int priority, const char *DebugBuffer,
203  unsigned int rv)
204 {
205  if (DEBUGLOG_SYSLOG_DEBUG == LogMsgType)
206  syslog(LOG_INFO, "%s", DebugBuffer);
207  else
208  {
209  static struct timeval last_time = { 0, 0 };
210  struct timeval new_time = { 0, 0 };
211  struct timeval tmp;
212  int delta;
213  pthread_t thread_id;
214  const char *rv_text = NULL;
215 
216  (void)pthread_mutex_lock(&LastTimeMutex);
217  gettimeofday(&new_time, NULL);
218  if (0 == last_time.tv_sec)
219  last_time = new_time;
220 
221  tmp.tv_sec = new_time.tv_sec - last_time.tv_sec;
222  tmp.tv_usec = new_time.tv_usec - last_time.tv_usec;
223  if (tmp.tv_usec < 0)
224  {
225  tmp.tv_sec--;
226  tmp.tv_usec += 1000000;
227  }
228  if (tmp.tv_sec < 100)
229  delta = tmp.tv_sec * 1000000 + tmp.tv_usec;
230  else
231  delta = 99999999;
232 
233  last_time = new_time;
234  (void)pthread_mutex_unlock(&LastTimeMutex);
235 
236  thread_id = pthread_self();
237 
238  rv_text = rv2text(rv);
239 
240  if (LogDoColor)
241  {
242  const char *color_pfx = "", *color_sfx = "\33[0m";
243  const char *time_pfx = "\33[36m", *time_sfx = color_sfx;
244 
245  switch (priority)
246  {
247  case PCSC_LOG_CRITICAL:
248  color_pfx = "\33[01;31m"; /* bright + Red */
249  break;
250 
251  case PCSC_LOG_ERROR:
252  color_pfx = "\33[35m"; /* Magenta */
253  break;
254 
255  case PCSC_LOG_INFO:
256  color_pfx = "\33[34m"; /* Blue */
257  break;
258 
259  case PCSC_LOG_DEBUG:
260  color_pfx = ""; /* normal (black) */
261  color_sfx = "";
262  break;
263  }
264 
265 #ifdef __APPLE__
266 #define THREAD_FORMAT "%p"
267 #else
268 #define THREAD_FORMAT "%lu"
269 #endif
270  if (rv_text)
271  {
272  const char * rv_pfx = "", * rv_sfx = "";
273  if (rv != SCARD_S_SUCCESS)
274  {
275  rv_pfx = "\33[31m"; /* Red */
276  rv_sfx = "\33[0m";
277  }
278 
279  printf("%s%.8d%s [" THREAD_FORMAT "] %s%s%s, %s%s%s\n",
280  time_pfx, delta, time_sfx, thread_id,
281  color_pfx, DebugBuffer, color_sfx,
282  rv_pfx, rv_text, rv_sfx);
283  }
284  else
285  printf("%s%.8d%s [" THREAD_FORMAT "] %s%s%s\n",
286  time_pfx, delta, time_sfx, thread_id,
287  color_pfx, DebugBuffer, color_sfx);
288  }
289  else
290  {
291  if (rv_text)
292  printf("%.8d %s, %s\n", delta, DebugBuffer, rv_text);
293  else
294  printf("%.8d %s\n", delta, DebugBuffer);
295  }
296  fflush(stdout);
297  }
298 } /* log_line */
299 
300 static void log_xxd_always(const int priority, const char *msg,
301  const unsigned char *buffer, const int len)
302 {
303  char DebugBuffer[len*3 + strlen(msg) +1];
304  int i;
305  char *c;
306 
307  /* DebugBuffer is always big enough for msg */
308  strcpy(DebugBuffer, msg);
309  c = DebugBuffer + strlen(DebugBuffer);
310 
311  for (i = 0; (i < len); ++i)
312  {
313  /* 2 hex characters, 1 space, 1 NUL : total 4 characters */
314  snprintf(c, 4, "%02X ", buffer[i]);
315  c += 3;
316  }
317 
318  log_line(priority, DebugBuffer, -1);
319 } /* log_xxd_always */
320 
321 void log_xxd(const int priority, const char *msg, const unsigned char *buffer,
322  const int len)
323 {
324  if ((priority < LogLevel) /* log priority lower than threshold? */
325  || (DEBUGLOG_NO_DEBUG == LogMsgType))
326  return;
327 
328  /* len is an error value? */
329  if (len < 0)
330  return;
331 
332  log_xxd_always(priority, msg, buffer, len);
333 } /* log_xxd */
334 
335 void DebugLogSetLogType(const int dbgtype)
336 {
337  switch (dbgtype)
338  {
339  case DEBUGLOG_NO_DEBUG:
340  case DEBUGLOG_SYSLOG_DEBUG:
341  case DEBUGLOG_STDOUT_DEBUG:
342  case DEBUGLOG_STDOUT_COLOR_DEBUG:
343  LogMsgType = dbgtype;
344  break;
345  default:
346  Log2(PCSC_LOG_CRITICAL, "unknown log type (%d), using stdout",
347  dbgtype);
348  LogMsgType = DEBUGLOG_STDOUT_DEBUG;
349  }
350 
351  /* log to stdout and stdout is a tty? */
352  if ((DEBUGLOG_STDOUT_DEBUG == LogMsgType && isatty(fileno(stdout)))
353  || (DEBUGLOG_STDOUT_COLOR_DEBUG == LogMsgType))
354  {
355  const char *term;
356 
357  term = SYS_GetEnv("TERM");
358  if (term)
359  {
360  const char *terms[] = { "linux", "xterm", "xterm-color", "Eterm", "rxvt", "rxvt-unicode", "xterm-256color" };
361  unsigned int i;
362 
363  /* for each known color terminal */
364  for (i = 0; i < COUNT_OF(terms); i++)
365  {
366  /* we found a supported term? */
367  if (0 == strcmp(terms[i], term))
368  {
369  LogDoColor = 1;
370  break;
371  }
372  }
373  }
374  }
375 }
376 
377 void DebugLogSetLevel(const int level)
378 {
379  LogLevel = level;
380  switch (level)
381  {
382  case PCSC_LOG_CRITICAL:
383  case PCSC_LOG_ERROR:
384  /* do not log anything */
385  break;
386 
387  case PCSC_LOG_INFO:
388  Log1(PCSC_LOG_INFO, "debug level=info");
389  break;
390 
391  case PCSC_LOG_DEBUG:
392  Log1(PCSC_LOG_DEBUG, "debug level=debug");
393  break;
394 
395  default:
396  LogLevel = PCSC_LOG_INFO;
397  Log2(PCSC_LOG_CRITICAL, "unknown level (%d), using level=info",
398  level);
399  }
400 }
401 
402 INTERNAL void DebugLogSetCategory(const int dbginfo)
403 {
404  /* use a negative number to UNset
405  * typically use ~DEBUG_CATEGORY_APDU
406  */
407  if (dbginfo < 0)
408  LogCategory &= dbginfo;
409  else
410  LogCategory |= dbginfo;
411 
412  if (LogCategory & DEBUG_CATEGORY_APDU)
413  Log1(PCSC_LOG_INFO, "Debug options: APDU");
414 }
415 
416 INTERNAL void DebugLogCategory(const int category, const unsigned char *buffer,
417  const int len)
418 {
419  if ((category & DEBUG_CATEGORY_APDU)
420  && (LogCategory & DEBUG_CATEGORY_APDU))
421  log_xxd_always(PCSC_LOG_INFO, "APDU: ", buffer, len);
422 
423  if ((category & DEBUG_CATEGORY_SW)
424  && (LogCategory & DEBUG_CATEGORY_APDU))
425  log_xxd_always(PCSC_LOG_INFO, "SW: ", buffer, len);
426 }
427 
428 /*
429  * old function supported for backward object code compatibility
430  * defined only for pcscd
431  */
432 #ifdef PCSCD
433 void debug_msg(const char *fmt, ...);
434 void debug_msg(const char *fmt, ...)
435 {
436  char DebugBuffer[DEBUG_BUF_SIZE];
437  va_list argptr;
438 
439  if (DEBUGLOG_NO_DEBUG == LogMsgType)
440  return;
441 
442  va_start(argptr, fmt);
443  vsnprintf(DebugBuffer, sizeof DebugBuffer, fmt, argptr);
444  va_end(argptr);
445 
446  if (DEBUGLOG_SYSLOG_DEBUG == LogMsgType)
447  syslog(LOG_INFO, "%s", DebugBuffer);
448  else
449  puts(DebugBuffer);
450 } /* debug_msg */
451 
452 void debug_xxd(const char *msg, const unsigned char *buffer, const int len);
453 void debug_xxd(const char *msg, const unsigned char *buffer, const int len)
454 {
455  log_xxd(PCSC_LOG_ERROR, msg, buffer, len);
456 } /* debug_xxd */
457 #endif
458 
459 #endif /* NO_LOG */
460 
debuglog.h
This handles debugging.
SCARD_E_INVALID_PARAMETER
#define SCARD_E_INVALID_PARAMETER
One or more of the supplied parameters could not be properly interpreted.
Definition: pcsclite.h:115
SCARD_S_SUCCESS
#define SCARD_S_SUCCESS
No error was encountered.
Definition: pcsclite.h:107
SCARD_W_REMOVED_CARD
#define SCARD_W_REMOVED_CARD
The smart card has been removed, so further communication is not possible.
Definition: pcsclite.h:219
SYS_GetEnv
const char * SYS_GetEnv(const char *name)
(More) secure version of getenv(3)
Definition: sys_unix.c:168
sys_generic.h
This handles abstract system level calls.
SCARD_E_SHARING_VIOLATION
#define SCARD_E_SHARING_VIOLATION
The smart card cannot be accessed because of other connections outstanding.
Definition: pcsclite.h:129
SCARD_W_UNPOWERED_CARD
#define SCARD_W_UNPOWERED_CARD
Power has been removed from the smart card, so that further communication is not possible.
Definition: pcsclite.h:215
LogLevel
static char LogLevel
default level
Definition: debuglog.c:107
SCARD_E_READER_UNAVAILABLE
#define SCARD_E_READER_UNAVAILABLE
The specified reader is not currently available for use.
Definition: pcsclite.h:153
SCARD_E_CANCELLED
#define SCARD_E_CANCELLED
The action was cancelled by an SCardCancel request.
Definition: pcsclite.h:111
DEBUG_BUF_SIZE
#define DEBUG_BUF_SIZE
Max string size dumping a maximum of 2 lines of 80 characters.
Definition: debuglog.c:101
SCARD_E_INSUFFICIENT_BUFFER
#define SCARD_E_INSUFFICIENT_BUFFER
The data buffer to receive returned data is too small for the returned data.
Definition: pcsclite.h:123
SCARD_E_PROTO_MISMATCH
#define SCARD_E_PROTO_MISMATCH
The requested protocols are incompatible with the protocol currently in use with the smart card.
Definition: pcsclite.h:137
SCARD_W_RESET_CARD
#define SCARD_W_RESET_CARD
The smart card has been reset, so any shared state information is invalid.
Definition: pcsclite.h:217
SCARD_E_NO_READERS_AVAILABLE
#define SCARD_E_NO_READERS_AVAILABLE
Cannot find a smart card reader.
Definition: pcsclite.h:202
SCARD_W_UNRESPONSIVE_CARD
#define SCARD_W_UNRESPONSIVE_CARD
The smart card is not responding to a reset.
Definition: pcsclite.h:213
SCARD_E_NO_SMARTCARD
#define SCARD_E_NO_SMARTCARD
The operation requires a Smart Card, but no Smart Card is currently in the device.
Definition: pcsclite.h:131
SCARD_E_NO_MEMORY
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
Definition: pcsclite.h:119
SCARD_E_TIMEOUT
#define SCARD_E_TIMEOUT
The user-specified timeout value has expired.
Definition: pcsclite.h:127
SCARD_E_INVALID_VALUE
#define SCARD_E_INVALID_VALUE
One or more of the supplied parameters values could not be properly interpreted.
Definition: pcsclite.h:141
LogDoColor
static signed char LogDoColor
no color by default
Definition: debuglog.c:109
SCARD_F_COMM_ERROR
#define SCARD_F_COMM_ERROR
An internal communications error has been detected.
Definition: pcsclite.h:145
SCARD_F_INTERNAL_ERROR
#define SCARD_F_INTERNAL_ERROR
An internal consistency check failed.
Definition: pcsclite.h:109
SCARD_E_INVALID_HANDLE
#define SCARD_E_INVALID_HANDLE
The supplied handle was invalid.
Definition: pcsclite.h:113
pcsclite.h
This keeps a list of defines for pcsc-lite.
SCARD_E_UNSUPPORTED_FEATURE
#define SCARD_E_UNSUPPORTED_FEATURE
This smart card does not support the requested feature.
Definition: pcsclite.h:171
SCARD_E_NOT_TRANSACTED
#define SCARD_E_NOT_TRANSACTED
An attempt was made to end a non-existent transaction.
Definition: pcsclite.h:151
SCARD_E_UNKNOWN_READER
#define SCARD_E_UNKNOWN_READER
The specified reader name is not recognized.
Definition: pcsclite.h:125
SCARD_E_NO_SERVICE
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
Definition: pcsclite.h:165