#include "config.h"
#ifndef WIN32
#include <syslog.h>
#endif
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <assert.h>
#include <sys/types.h>
#include "wintypes.h"
#include "pcsclite.h"
#include "debuglog.h"
#include "sys_generic.h"
#define DEBUG_BUF_SIZE 2048
static char LogSuppress = DEBUGLOG_LOG_ENTRIES;
static char LogMsgType = DEBUGLOG_NO_DEBUG;
static char LogCategory = DEBUG_CATEGORY_NOTHING;
static char LogLevel = PCSC_LOG_INFO;
static signed char LogDoColor = 0;
void log_msg(const int priority, const char *fmt, ...)
{
char DebugBuffer[DEBUG_BUF_SIZE];
va_list argptr;
if ((LogSuppress != DEBUGLOG_LOG_ENTRIES)
|| (priority < LogLevel)
|| (DEBUGLOG_NO_DEBUG == LogMsgType))
return;
va_start(argptr, fmt);
#ifndef WIN32
vsnprintf(DebugBuffer, DEBUG_BUF_SIZE, fmt, argptr);
#else
#if HAVE_VSNPRINTF
vsnprintf(DebugBuffer, DEBUG_BUF_SIZE, fmt, argptr);
#else
vsprintf(DebugBuffer, fmt, argptr);
#endif
#endif
va_end(argptr);
#ifndef WIN32
if (DEBUGLOG_SYSLOG_DEBUG == LogMsgType)
syslog(LOG_INFO, "%s", DebugBuffer);
else
{
if (LogDoColor)
{
const char *color_pfx = "", *color_sfx = "\33[0m";
switch (priority)
{
case PCSC_LOG_CRITICAL:
color_pfx = "\33[01;31m";
break;
case PCSC_LOG_ERROR:
color_pfx = "\33[35m";
break;
case PCSC_LOG_INFO:
color_pfx = "\33[34m";
break;
case PCSC_LOG_DEBUG:
color_pfx = "";
color_sfx = "";
break;
}
fprintf(stderr, "%s%s%s\n", color_pfx, DebugBuffer, color_sfx);
}
else
fprintf(stderr, "%s\n", DebugBuffer);
}
#else
fprintf(stderr, "%s\n", DebugBuffer);
#endif
}
void log_xxd(const int priority, const char *msg, const unsigned char *buffer,
const int len)
{
char DebugBuffer[DEBUG_BUF_SIZE];
int i;
char *c;
char *debug_buf_end;
if ((LogSuppress != DEBUGLOG_LOG_ENTRIES)
|| (priority < LogLevel)
|| (DEBUGLOG_NO_DEBUG == LogMsgType))
return;
debug_buf_end = DebugBuffer + DEBUG_BUF_SIZE - 5;
strlcpy(DebugBuffer, msg, sizeof(DebugBuffer));
c = DebugBuffer + strlen(DebugBuffer);
for (i = 0; (i < len) && (c < debug_buf_end); ++i)
{
sprintf(c, "%02X ", buffer[i]);
c += 3;
}
if ((c >= debug_buf_end) && (i < len))
c[-3] = c[-2] = c[-1] = '.';
#ifndef WIN32
if (DEBUGLOG_SYSLOG_DEBUG == LogMsgType)
syslog(LOG_INFO, "%s", DebugBuffer);
else
#endif
fprintf(stderr, "%s\n", DebugBuffer);
}
#ifdef PCSCD
void DebugLogSuppress(const int lSType)
{
LogSuppress = lSType;
}
#endif
void DebugLogSetLogType(const int dbgtype)
{
switch (dbgtype)
{
case DEBUGLOG_NO_DEBUG:
case DEBUGLOG_SYSLOG_DEBUG:
case DEBUGLOG_STDERR_DEBUG:
LogMsgType = dbgtype;
break;
default:
Log2(PCSC_LOG_CRITICAL, "unknown log type (%d), using stderr",
dbgtype);
LogMsgType = DEBUGLOG_STDERR_DEBUG;
}
#ifndef WIN32
if (DEBUGLOG_STDERR_DEBUG == LogMsgType && isatty(fileno(stderr)))
{
const char *terms[] = { "linux", "xterm", "xterm-color", "Eterm", "rxvt", "rxvt-unicode" };
char *term;
term = getenv("TERM");
if (term)
{
unsigned int i;
for (i = 0; i < sizeof(terms) / sizeof(terms[0]); i++)
{
if (0 == strcmp(terms[i], term))
{
LogDoColor = 1;
break;
}
}
}
}
#endif
}
void DebugLogSetLevel(const int level)
{
LogLevel = level;
switch (level)
{
case PCSC_LOG_CRITICAL:
case PCSC_LOG_ERROR:
break;
case PCSC_LOG_INFO:
Log1(PCSC_LOG_INFO, "debug level=notice");
break;
case PCSC_LOG_DEBUG:
Log1(PCSC_LOG_DEBUG, "debug level=debug");
break;
default:
LogLevel = PCSC_LOG_INFO;
Log2(PCSC_LOG_CRITICAL, "unknown level (%d), using level=notice",
level);
}
}
INTERNAL int DebugLogSetCategory(const int dbginfo)
{
#define DEBUG_INFO_LENGTH 80
char text[DEBUG_INFO_LENGTH];
if (dbginfo < 0)
LogCategory &= dbginfo;
else
LogCategory |= dbginfo;
text[0] = '\0';
if (LogCategory & DEBUG_CATEGORY_APDU)
strlcat(text, " APDU", sizeof(text));
Log2(PCSC_LOG_INFO, "Debug options:%s", text);
return LogCategory;
}
INTERNAL void DebugLogCategory(const int category, const unsigned char *buffer,
const int len)
{
if ((category & DEBUG_CATEGORY_APDU)
&& (LogCategory & DEBUG_CATEGORY_APDU))
log_xxd(PCSC_LOG_INFO, "APDU: ", (const unsigned char *)buffer, len);
if ((category & DEBUG_CATEGORY_SW)
&& (LogCategory & DEBUG_CATEGORY_APDU))
log_xxd(PCSC_LOG_INFO, "SW: ", (const unsigned char *)buffer, len);
}
#ifdef PCSCD
void debug_msg(const char *fmt, ...)
{
char DebugBuffer[DEBUG_BUF_SIZE];
va_list argptr;
if ((LogSuppress != DEBUGLOG_LOG_ENTRIES)
|| (DEBUGLOG_NO_DEBUG == LogMsgType))
return;
va_start(argptr, fmt);
#ifndef WIN32
vsnprintf(DebugBuffer, DEBUG_BUF_SIZE, fmt, argptr);
#else
#if HAVE_VSNPRINTF
vsnprintf(DebugBuffer, DEBUG_BUF_SIZE, fmt, argptr);
#else
vsprintf(DebugBuffer, fmt, argptr);
#endif
#endif
va_end(argptr);
#ifndef WIN32
if (DEBUGLOG_SYSLOG_DEBUG == LogMsgType)
syslog(LOG_INFO, "%s", DebugBuffer);
else
#endif
fprintf(stderr, "%s\n", DebugBuffer);
}
void debug_xxd(const char *msg, const unsigned char *buffer, const int len)
{
log_xxd(PCSC_LOG_ERROR, msg, buffer, len);
}
#endif
char *pcsc_stringify_error(const int32_t Error)
{
static char strError[75];
switch (Error)
{
case SCARD_S_SUCCESS:
strcpy(strError, "Command successful.");
break;
case SCARD_E_CANCELLED:
strcpy(strError, "Command cancelled.");
break;
case SCARD_E_CANT_DISPOSE:
strcpy(strError, "Cannot dispose handle.");
break;
case SCARD_E_INSUFFICIENT_BUFFER:
strcpy(strError, "Insufficient buffer.");
break;
case SCARD_E_INVALID_ATR:
strcpy(strError, "Invalid ATR.");
break;
case SCARD_E_INVALID_HANDLE:
strcpy(strError, "Invalid handle.");
break;
case SCARD_E_INVALID_PARAMETER:
strcpy(strError, "Invalid parameter given.");
break;
case SCARD_E_INVALID_TARGET:
strcpy(strError, "Invalid target given.");
break;
case SCARD_E_INVALID_VALUE:
strcpy(strError, "Invalid value given.");
break;
case SCARD_E_NO_MEMORY:
strcpy(strError, "Not enough memory.");
break;
case SCARD_F_COMM_ERROR:
strcpy(strError, "RPC transport error.");
break;
case SCARD_F_INTERNAL_ERROR:
strcpy(strError, "Unknown internal error.");
break;
case SCARD_F_UNKNOWN_ERROR:
strcpy(strError, "Unknown internal error.");
break;
case SCARD_F_WAITED_TOO_LONG:
strcpy(strError, "Waited too long.");
break;
case SCARD_E_UNKNOWN_READER:
strcpy(strError, "Unknown reader specified.");
break;
case SCARD_E_TIMEOUT:
strcpy(strError, "Command timeout.");
break;
case SCARD_E_SHARING_VIOLATION:
strcpy(strError, "Sharing violation.");
break;
case SCARD_E_NO_SMARTCARD:
strcpy(strError, "No smartcard inserted.");
break;
case SCARD_E_UNKNOWN_CARD:
strcpy(strError, "Unknown card.");
break;
case SCARD_E_PROTO_MISMATCH:
strcpy(strError, "Card protocol mismatch.");
break;
case SCARD_E_NOT_READY:
strcpy(strError, "Subsystem not ready.");
break;
case SCARD_E_SYSTEM_CANCELLED:
strcpy(strError, "System cancelled.");
break;
case SCARD_E_NOT_TRANSACTED:
strcpy(strError, "Transaction failed.");
break;
case SCARD_E_READER_UNAVAILABLE:
strcpy(strError, "Reader/s is unavailable.");
break;
case SCARD_W_UNSUPPORTED_CARD:
strcpy(strError, "Card is not supported.");
break;
case SCARD_W_UNRESPONSIVE_CARD:
strcpy(strError, "Card is unresponsive.");
break;
case SCARD_W_UNPOWERED_CARD:
strcpy(strError, "Card is unpowered.");
break;
case SCARD_W_RESET_CARD:
strcpy(strError, "Card was reset.");
break;
case SCARD_W_REMOVED_CARD:
strcpy(strError, "Card was removed.");
break;
case SCARD_W_INSERTED_CARD:
strcpy(strError, "Card was inserted.");
break;
case SCARD_E_UNSUPPORTED_FEATURE:
strcpy(strError, "Feature not supported.");
break;
case SCARD_E_PCI_TOO_SMALL:
strcpy(strError, "PCI struct too small.");
break;
case SCARD_E_READER_UNSUPPORTED:
strcpy(strError, "Reader is unsupported.");
break;
case SCARD_E_DUPLICATE_READER:
strcpy(strError, "Reader already exists.");
break;
case SCARD_E_CARD_UNSUPPORTED:
strcpy(strError, "Card is unsupported.");
break;
case SCARD_E_NO_SERVICE:
strcpy(strError, "Service not available.");
break;
case SCARD_E_SERVICE_STOPPED:
strcpy(strError, "Service was stopped.");
break;
default:
sprintf(strError, "Unknown PCSC error: %d [0x%08X]", Error, Error);
break;
};
return strError;
}