/src/opensc/src/libopensc/log.c
Line | Count | Source |
1 | | /* |
2 | | * log.c: Miscellaneous logging functions |
3 | | * |
4 | | * Copyright (C) 2001, 2002 Juha Yrjölä <juha.yrjola@iki.fi> |
5 | | * Copyright (C) 2003 Antti Tapaninen <aet@cc.hut.fi> |
6 | | * |
7 | | * This library is free software; you can redistribute it and/or |
8 | | * modify it under the terms of the GNU Lesser General Public |
9 | | * License as published by the Free Software Foundation; either |
10 | | * version 2.1 of the License, or (at your option) any later version. |
11 | | * |
12 | | * This library is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | | * Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public |
18 | | * License along with this library; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | | */ |
21 | | |
22 | | #ifdef HAVE_CONFIG_H |
23 | | #include "config.h" |
24 | | #endif |
25 | | |
26 | | #include <stdarg.h> |
27 | | #include <stdlib.h> |
28 | | #include <assert.h> |
29 | | #include <ctype.h> |
30 | | #include <string.h> |
31 | | #include <time.h> |
32 | | #ifdef HAVE_UNISTD_H |
33 | | #include <unistd.h> |
34 | | #endif |
35 | | #ifdef HAVE_SYS_TIME_H |
36 | | #include <sys/time.h> |
37 | | #endif |
38 | | #ifdef HAVE_IO_H |
39 | | #include <io.h> |
40 | | #endif |
41 | | #ifdef HAVE_PTHREAD |
42 | | #include <pthread.h> |
43 | | #endif |
44 | | #ifdef _WIN32 |
45 | | #include <windows.h> |
46 | | #endif |
47 | | #ifdef ENABLE_OPENSSL |
48 | | #include <openssl/err.h> |
49 | | #endif /* ENABLE_OPENSSL */ |
50 | | #include "common/compat_strlcat.h" |
51 | | |
52 | | #include "internal.h" |
53 | | |
54 | | static void sc_do_log_va(sc_context_t *ctx, int level, const char *file, int line, const char *func, int color, const char *format, va_list args); |
55 | | static int sc_color_fprintf_va(int colors, struct sc_context *ctx, FILE * stream, const char *format, va_list args); |
56 | | |
57 | | void sc_do_log(sc_context_t *ctx, int level, const char *file, int line, const char *func, const char *format, ...) |
58 | 14.2M | { |
59 | 14.2M | va_list ap; |
60 | | |
61 | 14.2M | va_start(ap, format); |
62 | 14.2M | sc_do_log_va(ctx, level, file, line, func, 0, format, ap); |
63 | 14.2M | va_end(ap); |
64 | 14.2M | } |
65 | | |
66 | | void sc_do_log_color(sc_context_t *ctx, int level, const char *file, int line, const char *func, int color, const char *format, ...) |
67 | 4.20M | { |
68 | 4.20M | va_list ap; |
69 | | |
70 | 4.20M | va_start(ap, format); |
71 | 4.20M | sc_do_log_va(ctx, level, file, line, func, color, format, ap); |
72 | 4.20M | va_end(ap); |
73 | 4.20M | } |
74 | | |
75 | | #ifdef ENABLE_OPENSSL |
76 | | void sc_do_log_openssl(sc_context_t *ctx, int level, const char *file, int line, const char *func) |
77 | 4.60k | { |
78 | 4.60k | BIO *bio = NULL; |
79 | 4.60k | int length, rc; |
80 | 4.60k | char *buffer = NULL; |
81 | | |
82 | 4.60k | if ((bio = BIO_new(BIO_s_mem())) == NULL) { |
83 | 0 | sc_do_log(ctx, level, file, line, func, "Cannot log OpenSSL error"); |
84 | 0 | goto end; |
85 | 0 | } |
86 | 4.60k | ERR_print_errors(bio); |
87 | | |
88 | 4.60k | length = BIO_pending(bio); |
89 | 4.60k | if (length <= 0) { |
90 | | /* no error? */ |
91 | 4.60k | goto end; |
92 | 4.60k | } |
93 | | /* trailing null byte */ |
94 | 1 | buffer = malloc(length + 1); |
95 | 1 | if (buffer == NULL) { |
96 | 0 | sc_do_log(ctx, level, file, line, func, "No memory!"); |
97 | 0 | goto end; |
98 | 0 | } |
99 | 1 | rc = BIO_read(bio, buffer, length); |
100 | 1 | buffer[length] = '\0'; |
101 | 1 | if (rc <= 0) { |
102 | 0 | sc_do_log(ctx, level, file, line, func, "Cannot read OpenSSL error"); |
103 | 0 | goto end; |
104 | 0 | } |
105 | | |
106 | 1 | sc_do_log(ctx, level, file, line, func, "OpenSSL error\n%s", buffer); |
107 | 4.60k | end: |
108 | 4.60k | free(buffer); |
109 | 4.60k | BIO_free(bio); |
110 | 4.60k | } |
111 | | #else |
112 | | void sc_do_log_openssl(sc_context_t *ctx, int level, const char *file, int line, const char *func) |
113 | | { |
114 | | sc_do_log(ctx, level, file, line, func, "OpenSSL not enabled"); |
115 | | } |
116 | | #endif |
117 | | |
118 | | void sc_do_log_noframe(sc_context_t *ctx, int level, const char *format, va_list args) |
119 | 0 | { |
120 | 0 | sc_do_log_va(ctx, level, NULL, 0, NULL, 0, format, args); |
121 | 0 | } |
122 | | |
123 | | static void sc_do_log_va(sc_context_t *ctx, int level, const char *file, int line, const char *func, int color, const char *format, va_list args) |
124 | 18.4M | { |
125 | | #ifdef _WIN32 |
126 | | SYSTEMTIME st; |
127 | | #else |
128 | 18.4M | struct tm *tm; |
129 | 18.4M | struct timeval tv; |
130 | 18.4M | char time_string[40]; |
131 | 18.4M | #endif |
132 | | |
133 | 18.4M | if (!ctx || ctx->debug < level) |
134 | 18.4M | return; |
135 | | |
136 | | #ifdef _WIN32 |
137 | | /* In Windows, file handles can not be shared between DLL-s, each DLL has a |
138 | | * separate file handle table. Make sure we always have a valid file |
139 | | * descriptor. */ |
140 | | if (sc_ctx_log_to_file(ctx, ctx->debug_filename) < 0) |
141 | | return; |
142 | | #endif |
143 | 0 | if (ctx->debug_file == NULL) |
144 | 0 | return; |
145 | | |
146 | | #ifdef _WIN32 |
147 | | GetLocalTime(&st); |
148 | | sc_color_fprintf(SC_COLOR_FG_GREEN|SC_COLOR_BOLD, |
149 | | ctx, ctx->debug_file, |
150 | | "P:%lu; T:%lu", |
151 | | (unsigned long)GetCurrentProcessId(), |
152 | | (unsigned long)GetCurrentThreadId()); |
153 | | sc_color_fprintf(SC_COLOR_FG_GREEN, |
154 | | ctx, ctx->debug_file, |
155 | | " %i-%02i-%02i %02i:%02i:%02i.%03i", |
156 | | st.wYear, st.wMonth, st.wDay, |
157 | | st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); |
158 | | #else |
159 | 0 | sc_color_fprintf(SC_COLOR_FG_GREEN|SC_COLOR_BOLD, |
160 | 0 | ctx, ctx->debug_file, |
161 | 0 | "P:%lu; T:0x%lu", |
162 | 0 | (unsigned long)getpid(), |
163 | 0 | (unsigned long)pthread_self()); |
164 | 0 | gettimeofday (&tv, NULL); |
165 | 0 | tm = localtime (&tv.tv_sec); |
166 | 0 | strftime (time_string, sizeof(time_string), "%H:%M:%S", tm); |
167 | 0 | sc_color_fprintf(SC_COLOR_FG_GREEN, |
168 | 0 | ctx, ctx->debug_file, |
169 | 0 | " %s.%03ld", |
170 | 0 | time_string, |
171 | 0 | (long)tv.tv_usec / 1000); |
172 | 0 | #endif |
173 | |
|
174 | 0 | sc_color_fprintf(SC_COLOR_FG_YELLOW, |
175 | 0 | ctx, ctx->debug_file, |
176 | 0 | " ["); |
177 | 0 | sc_color_fprintf(SC_COLOR_FG_YELLOW|SC_COLOR_BOLD, |
178 | 0 | ctx, ctx->debug_file, |
179 | 0 | "%s", |
180 | 0 | ctx->app_name); |
181 | 0 | sc_color_fprintf(SC_COLOR_FG_YELLOW, |
182 | 0 | ctx, ctx->debug_file, |
183 | 0 | "] "); |
184 | |
|
185 | 0 | if (file != NULL) { |
186 | 0 | sc_color_fprintf(SC_COLOR_FG_YELLOW, |
187 | 0 | ctx, ctx->debug_file, |
188 | 0 | "%s:%d:%s: ", |
189 | 0 | file, line, func ? func : ""); |
190 | 0 | } |
191 | |
|
192 | 0 | sc_color_fprintf_va(color, ctx, ctx->debug_file, format, args); |
193 | 0 | if (strlen(format) == 0 || format[strlen(format) - 1] != '\n') |
194 | 0 | sc_color_fprintf(color, ctx, ctx->debug_file, "\n"); |
195 | 0 | fflush(ctx->debug_file); |
196 | |
|
197 | | #ifdef _WIN32 |
198 | | if (ctx->debug_file && (ctx->debug_file != stderr && ctx->debug_file != stdout)) |
199 | | fclose(ctx->debug_file); |
200 | | ctx->debug_file = NULL; |
201 | | #endif |
202 | 0 | } |
203 | | |
204 | | void _sc_debug(struct sc_context *ctx, int level, const char *format, ...) |
205 | 0 | { |
206 | 0 | va_list ap; |
207 | |
|
208 | 0 | va_start(ap, format); |
209 | 0 | sc_do_log_va(ctx, level, NULL, 0, NULL, 0, format, ap); |
210 | 0 | va_end(ap); |
211 | 0 | } |
212 | | |
213 | | void _sc_log(struct sc_context *ctx, const char *format, ...) |
214 | 0 | { |
215 | 0 | va_list ap; |
216 | |
|
217 | 0 | va_start(ap, format); |
218 | 0 | sc_do_log_va(ctx, SC_LOG_DEBUG_NORMAL, NULL, 0, NULL, 0, format, ap); |
219 | 0 | va_end(ap); |
220 | 0 | } |
221 | | |
222 | | void _sc_log_openssl(struct sc_context *ctx) |
223 | 0 | { |
224 | 0 | sc_do_log_openssl(ctx, SC_LOG_DEBUG_DEPS, NULL, 0, NULL); |
225 | 0 | } |
226 | | |
227 | | static int is_a_tty(FILE *fp) |
228 | 0 | { |
229 | 0 | if (fp != NULL) { |
230 | 0 | int fd = fileno(fp); |
231 | 0 | if (fd >= 0) { |
232 | | #ifdef _WIN32 |
233 | | HANDLE h = (HANDLE)_get_osfhandle(fd); |
234 | | if (h != INVALID_HANDLE_VALUE) { |
235 | | return GetFileType(h) == FILE_TYPE_CHAR; |
236 | | } |
237 | | #else |
238 | 0 | return isatty(fd); |
239 | 0 | #endif |
240 | 0 | } |
241 | 0 | } |
242 | 0 | return 0; |
243 | 0 | } |
244 | | |
245 | | #ifdef _WIN32 |
246 | | #define set_color(sc_color, win_color, vt100_color) \ |
247 | | do { if (colors & sc_color) { attr |= win_color; } } while (0) |
248 | | #else |
249 | | #define set_color(sc_color, win_color, vt100_color) \ |
250 | 0 | do { if (colors & sc_color) { fprintf(stream, vt100_color); } } while (0) |
251 | | #endif |
252 | | |
253 | | int sc_color_fprintf(int colors, struct sc_context *ctx, FILE * stream, const char * format, ...) |
254 | 0 | { |
255 | 0 | int r; |
256 | 0 | va_list ap; |
257 | |
|
258 | 0 | va_start(ap, format); |
259 | 0 | r = sc_color_fprintf_va(colors, ctx, stream, format, ap); |
260 | 0 | va_end(ap); |
261 | |
|
262 | 0 | return r; |
263 | 0 | } |
264 | | |
265 | | int sc_color_fprintf_va(int colors, struct sc_context *ctx, FILE * stream, const char *format, va_list args) |
266 | 0 | { |
267 | 0 | int r; |
268 | | #ifdef _WIN32 |
269 | | WORD old_attr = 0; |
270 | | int fd = stream ? fileno(stream) : -1; |
271 | | HANDLE handle = fd >= 0 ? (HANDLE) _get_osfhandle(fd) : INVALID_HANDLE_VALUE; |
272 | | #endif |
273 | |
|
274 | 0 | if (!is_a_tty(stream)) |
275 | 0 | colors = 0; |
276 | |
|
277 | 0 | if (colors && (!ctx || (!(ctx->flags & SC_CTX_FLAG_DISABLE_COLORS)))) { |
278 | | #ifdef _WIN32 |
279 | | WORD attr = 0; |
280 | | CONSOLE_SCREEN_BUFFER_INFO csbi; |
281 | | GetConsoleScreenBufferInfo(handle, &csbi); |
282 | | old_attr = csbi.wAttributes; |
283 | | #endif |
284 | 0 | set_color(SC_COLOR_FG_RED, |
285 | 0 | FOREGROUND_RED, |
286 | 0 | "\x1b[31m"); |
287 | 0 | set_color(SC_COLOR_FG_GREEN, |
288 | 0 | FOREGROUND_GREEN, |
289 | 0 | "\x1b[32m"); |
290 | 0 | set_color(SC_COLOR_FG_YELLOW, |
291 | 0 | FOREGROUND_GREEN|FOREGROUND_RED, |
292 | 0 | "\x1b[33m"); |
293 | 0 | set_color(SC_COLOR_FG_BLUE, |
294 | 0 | FOREGROUND_BLUE, |
295 | 0 | "\x1b[34m"); |
296 | 0 | set_color(SC_COLOR_FG_MAGENTA, |
297 | 0 | FOREGROUND_BLUE|FOREGROUND_RED, |
298 | 0 | "\x1b[35m"); |
299 | 0 | set_color(SC_COLOR_FG_CYAN, |
300 | 0 | FOREGROUND_BLUE|FOREGROUND_GREEN, |
301 | 0 | "\x1b[36m"); |
302 | 0 | set_color(SC_COLOR_BG_RED, |
303 | 0 | FOREGROUND_RED, |
304 | 0 | "\x1b[41m"); |
305 | 0 | set_color(SC_COLOR_BG_GREEN, |
306 | 0 | BACKGROUND_GREEN, |
307 | 0 | "\x1b[42m"); |
308 | 0 | set_color(SC_COLOR_BG_YELLOW, |
309 | 0 | BACKGROUND_GREEN|BACKGROUND_RED, |
310 | 0 | "\x1b[43m"); |
311 | 0 | set_color(SC_COLOR_BG_BLUE, |
312 | 0 | BACKGROUND_BLUE, |
313 | 0 | "\x1b[44m"); |
314 | 0 | set_color(SC_COLOR_BG_MAGENTA, |
315 | 0 | BACKGROUND_BLUE|BACKGROUND_RED, |
316 | 0 | "\x1b[45m"); |
317 | 0 | set_color(SC_COLOR_BG_CYAN, |
318 | 0 | BACKGROUND_BLUE|BACKGROUND_GREEN, |
319 | 0 | "\x1b[46m"); |
320 | 0 | set_color(SC_COLOR_BOLD, |
321 | 0 | FOREGROUND_INTENSITY, |
322 | 0 | "\x1b[1m"); |
323 | | #ifdef _WIN32 |
324 | | SetConsoleTextAttribute(handle, attr); |
325 | | #endif |
326 | 0 | } |
327 | |
|
328 | 0 | r = vfprintf(stream, format, args); |
329 | |
|
330 | 0 | if (colors && (!ctx || (!(ctx->flags & SC_CTX_FLAG_DISABLE_COLORS)))) { |
331 | | #ifdef _WIN32 |
332 | | SetConsoleTextAttribute(handle, old_attr); |
333 | | #else |
334 | 0 | fprintf(stream, "\x1b[0m"); |
335 | 0 | #endif |
336 | 0 | } |
337 | |
|
338 | 0 | return r; |
339 | 0 | } |
340 | | |
341 | | void _sc_debug_hex(sc_context_t *ctx, int type, const char *file, int line, |
342 | | const char *func, const char *label, const u8 *data, size_t len) |
343 | 422k | { |
344 | 422k | size_t blen = len * 5 + 128; |
345 | 422k | char *buf = malloc(blen); |
346 | 422k | if (buf == NULL) |
347 | 0 | return; |
348 | | |
349 | 422k | sc_hex_dump(data, len, buf, blen); |
350 | | |
351 | 422k | if (label) |
352 | 422k | sc_do_log(ctx, type, file, line, func, |
353 | 422k | "\n%s (%"SC_FORMAT_LEN_SIZE_T"u byte%s):\n%s", |
354 | 422k | label, len, len==1?"":"s", buf); |
355 | 0 | else |
356 | 0 | sc_do_log(ctx, type, file, line, func, |
357 | 0 | "%"SC_FORMAT_LEN_SIZE_T"u byte%s:\n%s", |
358 | 0 | len, len==1?"":"s", buf); |
359 | | |
360 | 422k | free(buf); |
361 | 422k | } |
362 | | |
363 | | void sc_hex_dump(const u8 * in, size_t count, char *buf, size_t len) |
364 | 422k | { |
365 | 422k | char *p = buf; |
366 | 422k | size_t p_len = len; |
367 | 422k | int lines = 0; |
368 | | |
369 | 422k | if (buf == NULL || (in == NULL && count != 0)) { |
370 | 0 | return; |
371 | 0 | } |
372 | 422k | buf[0] = 0; |
373 | 422k | if ((count * 5) > len) |
374 | 0 | return; |
375 | 2.50M | while (count) { |
376 | 2.07M | char ascbuf[17]; |
377 | 2.07M | size_t i; |
378 | | |
379 | 32.8M | for (i = 0; i < count && i < 16; i++) { |
380 | 30.8M | sprintf(p, "%02X ", *in); |
381 | 30.8M | if (isprint(*in)) |
382 | 14.0M | ascbuf[i] = *in; |
383 | 16.7M | else |
384 | 16.7M | ascbuf[i] = '.'; |
385 | 30.8M | p += 3; |
386 | 30.8M | p_len -= 3; |
387 | 30.8M | in++; |
388 | 30.8M | } |
389 | 2.07M | count -= i; |
390 | 2.07M | ascbuf[i] = 0; |
391 | 2.54M | for (; i < 16 && lines; i++) { |
392 | 461k | strlcat(p, " ", p_len); |
393 | 461k | p += 3; |
394 | 461k | p_len -= 3; |
395 | 461k | } |
396 | 2.07M | snprintf(p, p_len, "%s\n", ascbuf); |
397 | 2.07M | p += strlen(ascbuf) + 1; |
398 | 2.07M | p_len -= strlen(ascbuf) - 1; |
399 | 2.07M | lines++; |
400 | 2.07M | } |
401 | 422k | } |
402 | | |
403 | | const char * |
404 | | sc_dump_hex(const u8 * in, size_t count) |
405 | 178k | { |
406 | 178k | static char dump_buf[0x1000]; |
407 | 178k | size_t ii, size = sizeof(dump_buf) - 0x10; |
408 | 178k | size_t offs = 0; |
409 | | |
410 | 178k | memset(dump_buf, 0, sizeof(dump_buf)); |
411 | 178k | if (in == NULL) |
412 | 0 | return dump_buf; |
413 | | |
414 | 959k | for (ii=0; ii<count; ii++) { |
415 | 780k | if (ii && !(ii%16)) { |
416 | 14.4k | if (!(ii%48)) |
417 | 3.72k | snprintf(dump_buf + offs, size - offs, "\n"); |
418 | 10.7k | else |
419 | 10.7k | snprintf(dump_buf + offs, size - offs, " "); |
420 | 14.4k | offs = strlen(dump_buf); |
421 | 14.4k | } |
422 | | |
423 | 780k | snprintf(dump_buf + offs, size - offs, "%02X", *(in + ii)); |
424 | 780k | offs += 2; |
425 | | |
426 | 780k | if (offs > size) |
427 | 0 | break; |
428 | 780k | } |
429 | | |
430 | 178k | if (ii<count) |
431 | 0 | snprintf(dump_buf + offs, sizeof(dump_buf) - offs, "....\n"); |
432 | | |
433 | 178k | return dump_buf; |
434 | 178k | } |
435 | | |
436 | | const char * |
437 | | sc_dump_oid(const struct sc_object_id *oid) |
438 | 4.89k | { |
439 | 4.89k | static char dump_buf[SC_MAX_OBJECT_ID_OCTETS * 20]; |
440 | 4.89k | size_t ii; |
441 | | |
442 | 4.89k | memset(dump_buf, 0, sizeof(dump_buf)); |
443 | 4.89k | if (oid) |
444 | 37.3k | for (ii=0; ii<SC_MAX_OBJECT_ID_OCTETS && oid->value[ii] != -1; ii++) |
445 | 32.4k | snprintf(dump_buf + strlen(dump_buf), sizeof(dump_buf) - strlen(dump_buf), "%s%i", (ii ? "." : ""), oid->value[ii]); |
446 | | |
447 | 4.89k | return dump_buf; |
448 | 4.89k | } |