1/*
2 *  Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
3 *
4 *  @APPLE_LICENSE_HEADER_START@
5 *
6 *  This file contains Original Code and/or Modifications of Original Code
7 *  as defined in and that are subject to the Apple Public Source License
8 *  Version 2.0 (the 'License'). You may not use this file except in
9 *  compliance with the License. Please obtain a copy of the License at
10 *  http://www.opensource.apple.com/apsl/ and read it before using this
11 *  file.
12 *
13 *  The Original Code and all software distributed under the License are
14 *  distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 *  EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 *  INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 *  FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 *  Please see the License for the specific language governing rights and
19 *  limitations under the License.
20 *
21 *  @APPLE_LICENSE_HEADER_END@
22 */
23
24/*
25 *  debuglog.c
26 *  SmartCardServices
27 */
28
29/*
30 * MUSCLE SmartCard Development ( http://www.linuxnet.com )
31 *
32 * Copyright (C) 1999-2002
33 *  David Corcoran <corcoran@linuxnet.com>
34 * Copyright (C) 1999-2005
35 *  Ludovic Rousseau <ludovic.rousseau@free.fr>
36 *
37 * $Id: debuglog.c 123 2010-03-27 10:50:42Z ludovic.rousseau@gmail.com $
38 */
39
40/**
41 * @file
42 * @brief This handles debugging for pcscd.
43 */
44
45#include "config.h"
46#ifdef HAVE_SYSLOG_H
47#include <syslog.h>
48#endif
49#include <unistd.h>
50#include <stdio.h>
51#include <stdlib.h>
52#include <string.h>
53#include <stdarg.h>
54#include <assert.h>
55#include <sys/types.h>
56
57#include "wintypes.h"
58#include "pcsclite.h"
59#include "debuglog.h"
60#include "sys_generic.h"
61//#include "strlcpy.h"
62
63/**
64 * Max string size when dumping a 256 bytes longs APDU
65 * Should be bigger than 256*3+30
66 */
67#define DEBUG_BUF_SIZE 2048
68
69static char LogSuppress = DEBUGLOG_LOG_ENTRIES;
70static char LogMsgType = DEBUGLOG_NO_DEBUG;
71static char LogCategory = DEBUG_CATEGORY_NOTHING;
72
73/* default level is a bit verbose to be backward compatible */
74static char LogLevel = PCSC_LOG_INFO;
75
76static signed char LogDoColor = 0;	/* no color by default */
77
78void log_msg(const int priority, const char *fmt, ...)
79{
80	char DebugBuffer[DEBUG_BUF_SIZE];
81	va_list argptr;
82
83	if ((LogSuppress != DEBUGLOG_LOG_ENTRIES)
84		|| (priority < LogLevel) /* log priority lower than threshold? */
85		|| (DEBUGLOG_NO_DEBUG == LogMsgType))
86		return;
87
88	va_start(argptr, fmt);
89	vsnprintf(DebugBuffer, DEBUG_BUF_SIZE, fmt, argptr);
90	va_end(argptr);
91
92	if (DEBUGLOG_SYSLOG_DEBUG == LogMsgType)
93		syslog(LOG_INFO, "%s", DebugBuffer);
94	else
95	{
96		if (LogDoColor)
97		{
98			const char *color_pfx = "", *color_sfx = "\33[0m";
99
100			switch (priority)
101			{
102				case PCSC_LOG_CRITICAL:
103					color_pfx = "\33[01;31m"; /* bright + Red */
104					break;
105
106				case PCSC_LOG_ERROR:
107					color_pfx = "\33[35m"; /* Magenta */
108					break;
109
110				case PCSC_LOG_INFO:
111					color_pfx = "\33[34m"; /* Blue */
112					break;
113
114				case PCSC_LOG_DEBUG:
115					color_pfx = ""; /* normal (black) */
116					color_sfx = "";
117					break;
118			}
119			fprintf(stderr, "%s%s%s\n", color_pfx, DebugBuffer, color_sfx);
120		}
121		else
122			fprintf(stderr, "%s\n", DebugBuffer);
123	}
124} /* log_msg */
125
126void log_xxd(const int priority, const char *msg, const unsigned char *buffer,
127	const int len)
128{
129	char DebugBuffer[DEBUG_BUF_SIZE];
130	int i;
131	char *c;
132	char *debug_buf_end;
133
134	if ((LogSuppress != DEBUGLOG_LOG_ENTRIES)
135		|| (priority < LogLevel) /* log priority lower than threshold? */
136		|| (DEBUGLOG_NO_DEBUG == LogMsgType))
137		return;
138
139	debug_buf_end = DebugBuffer + DEBUG_BUF_SIZE - 5;
140
141	strlcpy(DebugBuffer, msg, sizeof(DebugBuffer));
142	c = DebugBuffer + strlen(DebugBuffer);
143
144	for (i = 0; (i < len) && (c < debug_buf_end); ++i)
145	{
146		sprintf(c, "%02X ", buffer[i]);
147		c += 3;
148	}
149
150	/* the buffer is too small so end it with "..." */
151	if ((c >= debug_buf_end) && (i < len))
152		c[-3] = c[-2] = c[-1] = '.';
153
154	if (DEBUGLOG_SYSLOG_DEBUG == LogMsgType)
155		syslog(LOG_INFO, "%s", DebugBuffer);
156	else
157		fprintf(stderr, "%s\n", DebugBuffer);
158} /* log_xxd */
159
160#ifdef PCSCD
161void DebugLogSuppress(const int lSType)
162{
163	LogSuppress = lSType;
164}
165#endif
166
167void DebugLogSetLogType(const int dbgtype)
168{
169	switch (dbgtype)
170	{
171		case DEBUGLOG_NO_DEBUG:
172		case DEBUGLOG_SYSLOG_DEBUG:
173		case DEBUGLOG_STDERR_DEBUG:
174			LogMsgType = dbgtype;
175			break;
176		default:
177			Log2(PCSC_LOG_CRITICAL, "unknown log type (%d), using stderr",
178				dbgtype);
179			LogMsgType = DEBUGLOG_STDERR_DEBUG;
180	}
181
182	/* log to stderr and stderr is a tty? */
183	if (DEBUGLOG_STDERR_DEBUG == LogMsgType && isatty(fileno(stderr)))
184	{
185		const char *terms[] = { "linux", "xterm", "xterm-color", "Eterm", "rxvt", "rxvt-unicode" };
186		char *term;
187
188		term = getenv("TERM");
189		if (term)
190		{
191			unsigned int i;
192
193			/* for each known color terminal */
194			for (i = 0; i < sizeof(terms) / sizeof(terms[0]); i++)
195			{
196				/* we found a supported term? */
197				if (0 == strcmp(terms[i], term))
198				{
199					LogDoColor = 1;
200					break;
201				}
202			}
203		}
204	}
205}
206
207void DebugLogSetLevel(const int level)
208{
209	LogLevel = level;
210	switch (level)
211	{
212		case PCSC_LOG_CRITICAL:
213		case PCSC_LOG_ERROR:
214			/* do not log anything */
215			break;
216
217		case PCSC_LOG_INFO:
218			Log1(PCSC_LOG_INFO, "debug level=notice");
219			break;
220
221		case PCSC_LOG_DEBUG:
222			Log1(PCSC_LOG_DEBUG, "debug level=debug");
223			break;
224
225		default:
226			LogLevel = PCSC_LOG_INFO;
227			Log2(PCSC_LOG_CRITICAL, "unknown level (%d), using level=notice",
228				level);
229	}
230}
231
232int DebugLogSetCategory(const int dbginfo)
233{
234#define DEBUG_INFO_LENGTH 80
235	char text[DEBUG_INFO_LENGTH];
236
237	/* use a negative number to UNset
238	 * typically use ~DEBUG_CATEGORY_APDU
239	 */
240	if (dbginfo < 0)
241		LogCategory &= dbginfo;
242	else
243		LogCategory |= dbginfo;
244
245	/* set to empty string */
246	text[0] = '\0';
247
248	if (LogCategory & DEBUG_CATEGORY_APDU)
249		strlcat(text, " APDU", sizeof(text));
250
251	Log2(PCSC_LOG_INFO, "Debug options:%s", text);
252
253	return LogCategory;
254}
255
256void DebugLogCategory(const int category, const unsigned char *buffer,
257	const int len)
258{
259	if ((category & DEBUG_CATEGORY_APDU)
260		&& (LogCategory & DEBUG_CATEGORY_APDU))
261		log_xxd(PCSC_LOG_INFO, "APDU: ", (const unsigned char *)buffer, len);
262
263	if ((category & DEBUG_CATEGORY_SW)
264		&& (LogCategory & DEBUG_CATEGORY_APDU))
265		log_xxd(PCSC_LOG_INFO, "SW: ", (const unsigned char *)buffer, len);
266}
267
268/*
269 * old function supported for backward object code compatibility
270 * defined only for pcscd
271 */
272#ifdef PCSCD
273void debug_msg(const char *fmt, ...);
274void debug_msg(const char *fmt, ...)
275{
276	char DebugBuffer[DEBUG_BUF_SIZE];
277	va_list argptr;
278
279	if ((LogSuppress != DEBUGLOG_LOG_ENTRIES)
280		|| (DEBUGLOG_NO_DEBUG == LogMsgType))
281		return;
282
283	va_start(argptr, fmt);
284	vsnprintf(DebugBuffer, DEBUG_BUF_SIZE, fmt, argptr);
285	va_end(argptr);
286
287	if (DEBUGLOG_SYSLOG_DEBUG == LogMsgType)
288		syslog(LOG_INFO, "%s", DebugBuffer);
289	else
290		fprintf(stderr, "%s\n", DebugBuffer);
291} /* debug_msg */
292
293void debug_xxd(const char *msg, const unsigned char *buffer, const int len);
294void debug_xxd(const char *msg, const unsigned char *buffer, const int len)
295{
296	log_xxd(PCSC_LOG_ERROR, msg, buffer, len);
297} /* debug_xxd */
298#endif
299
300