1/* $Id: plog.c,v 1.6.10.1 2005/12/07 10:19:51 vanhu Exp $ */
2
3/*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include "config.h"
33
34#include <sys/types.h>
35#include <sys/param.h>
36
37#include <stdlib.h>
38#include <fcntl.h>
39#include <stdio.h>
40#include <string.h>
41#include <errno.h>
42#ifdef HAVE_STDARG_H
43#include <stdarg.h>
44#else
45#include <varargs.h>
46#endif
47#if TIME_WITH_SYS_TIME
48# include <sys/time.h>
49# include <time.h>
50#else
51# if HAVE_SYS_TIME_H
52#  include <sys/time.h>
53# else
54#  include <time.h>
55# endif
56#endif
57#include <ctype.h>
58#include <err.h>
59#include <pthread.h>
60#include <unistd.h>
61#include <asl.h>
62#include <syslog.h>
63#include <asl_private.h>
64
65#include "var.h"
66#include "misc.h"
67#include "plog.h"
68#include "debug.h"
69#include "gcmalloc.h"
70#include "preferences.h"
71
72#ifndef VA_COPY
73# define VA_COPY(dst,src) memcpy(&(dst), (src), sizeof(va_list))
74#endif
75
76const char *plog_facility = "com.apple.racoon";
77const char *plog_session_id = "com.apple.racoon.sessionid";
78const char *plog_session_type = "com.apple.racoon.sessiontype";
79const char *plog_session_ver = "com.apple.racoon.sessionversion";
80
81extern int print_pid;
82
83char *pname = NULL;
84u_int32_t loglevel = ASL_LEVEL_NOTICE;
85//u_int32_t loglevel = ASL_LEVEL_DEBUG;
86int f_foreground = 0;
87
88int print_location = 0;
89
90char *logfile = NULL;
91int logfile_fd = -1;
92char  logFileStr[MAXPATHLEN+1];
93char *gSessId = NULL;
94char *gSessType = NULL;
95char *gSessVer = NULL;
96aslclient logRef = NULL;
97
98void
99plogdump_asl (aslmsg msg, int pri, const char *fmt, ...)
100{
101	caddr_t buf;
102	size_t buflen = 512;
103    va_list	args;
104	char   *level;
105
106	switch (pri) {
107	case ASL_LEVEL_INFO:
108		level = ASL_STRING_INFO;
109		break;
110
111	case ASL_LEVEL_NOTICE:
112		level = ASL_STRING_NOTICE;
113		break;
114
115	case ASL_LEVEL_WARNING:
116		level = ASL_STRING_WARNING;
117		break;
118
119	case ASL_LEVEL_ERR:
120		level = ASL_STRING_ERR;
121		break;
122
123	case ASL_LEVEL_DEBUG:
124		level = ASL_STRING_DEBUG;
125		break;
126
127	default:
128		return;
129	}
130
131	asl_set(msg, ASL_KEY_LEVEL, level);
132
133	buf = racoon_malloc(buflen);
134	if (buf) {
135		buf[0] = '\0';
136		va_start(args, fmt);
137		vsnprintf(buf, buflen, fmt, args);
138//		asl_set(msg, ASL_KEY_MESSAGE, buf);
139		va_end(args);
140		racoon_free(buf);
141	}
142}
143
144void
145plogdump_func(int pri, void *data, size_t len, const char *fmt, ...)
146{
147	caddr_t buf;
148	size_t buflen;
149	int i, j;
150    va_list	args;
151	char fmt_buf[512];
152
153	/*
154	 * 2 words a bytes + 1 space 4 bytes + 1 newline 32 bytes
155	 * + 2 newline + '\0'
156	 */
157	buflen = (len * 2) + (len / 4) + (len / 32) + 3;
158	buf = racoon_malloc(buflen);
159
160	i = 0;
161	j = 0;
162	while (j < len) {
163		if (j % 32 == 0)
164			buf[i++] = '\n';
165		else
166		if (j % 4 == 0)
167			buf[i++] = ' ';
168		snprintf(&buf[i], buflen - i, "%02x",
169			((unsigned char *)data)[j] & 0xff);
170		i += 2;
171		j++;
172	}
173	if (buflen - i >= 2) {
174		buf[i++] = '\n';
175		buf[i] = '\0';
176	}
177
178	fmt_buf[0] = '\n';
179	va_start(args, fmt);
180	vsnprintf(fmt_buf, sizeof(fmt_buf), fmt, args);
181	va_end(args);
182
183	plog(pri, "%s %s", fmt_buf, buf);
184
185	racoon_free(buf);
186}
187
188void
189clog_func (clog_err_t *cerr, clog_err_op_t cerr_op, int pri, const char *function, const char *line, const char *fmt, ...)
190{
191	clog_err_t *new, *p;
192    va_list	args;
193
194	if (!cerr) {
195		return;
196	}
197
198	if (!(new = racoon_calloc(1, sizeof(*cerr)))) {
199		return;
200	}
201	// fill in new
202	cerr->clog_err_level = pri; /* will be used for filtering */
203	/* TODO */
204	//cerr->clog_err_code;
205	//cerr->client_id;
206	//cerr->client_type;
207	va_start(args, fmt);
208	cerr->description_len = vasprintf(&cerr->description, fmt, args);
209	va_end(args);
210	cerr->function = function;
211	cerr->line = line;
212
213	// add new to the tail
214	TAILQ_FOREACH(p, &cerr->chain_head, chain) {
215		if (TAILQ_NEXT(p, chain) == NULL) {
216			TAILQ_NEXT(p, chain) = new;
217			new->chain.tqe_prev = &TAILQ_NEXT(p, chain);
218			break;
219		}
220	}
221
222	if (cerr_op == CLOG_ERR_DUMP) {
223		char *prev = NULL, *backtrace = NULL;
224
225		TAILQ_FOREACH(p, &cerr->chain_head, chain) {
226			// collapse list into backtrace
227			if (cerr->description) {
228				if (backtrace) {
229					prev = backtrace;
230					backtrace = NULL;
231					asprintf(&backtrace, "%s\n\t\t-> %s", prev, cerr->description);
232					free(prev);
233				} else {
234					asprintf(&backtrace, "%s", cerr->description);
235				}
236			}
237		}
238
239		if (backtrace) {
240			// use plog to dump event.
241			plog(pri, "%s", backtrace);
242		}
243	}
244}
245
246void
247plogsetfile(file)
248	char *file;
249{
250	syslog(LOG_NOTICE, "%s: about to add racoon log file: %s\n", __FUNCTION__, file? file:"bad file path");
251	if (logfile != NULL) {
252		racoon_free(logfile);
253		if (logfile_fd != -1) {
254			asl_remove_log_file(logRef, logfile_fd);
255			asl_close_auxiliary_file(logfile_fd);
256			logfile_fd = -1;
257		}
258	}
259	logfile = racoon_strdup(file);
260	STRDUP_FATAL(logfile);
261	if ((logfile_fd = open(logfile, O_CREAT | O_WRONLY | O_APPEND | O_NOFOLLOW, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) >= 0) {
262		asl_add_log_file(logRef, logfile_fd);
263	} else {
264		syslog(LOG_NOTICE, "%s: failed to add racoon log file: %s. error %d\n", __FUNCTION__, file? file:"bad file path", errno);
265	}
266}
267
268void
269plogresetfile(file)
270	char *file;
271{
272	/* if log paths equal - do nothing */
273	if (logfile == NULL && file == NULL) {
274		return;
275	}
276	if (logfile != NULL && file != NULL) {
277		if (!strcmp(logfile, file)) {
278			return;
279		}
280		if (logfile_fd != -1) {
281			asl_remove_log_file(logRef, logfile_fd);
282			close(logfile_fd);
283			logfile_fd = -1;
284		}
285	}
286
287	if (logfile) {
288			racoon_free(logfile);
289			logfile = NULL;
290	}
291
292	if (file)
293		plogsetfile(file);
294}
295
296int
297ploggetlevel(void)
298{
299    return loglevel;
300}
301
302void
303plogsetlevel(int level)
304{
305	int mask;
306
307	if (level && level >= ASL_LEVEL_EMERG && level <= ASL_LEVEL_DEBUG) {
308		loglevel = level;
309	}
310	if (loglevel >= ASL_LEVEL_INFO) {
311		mask = ASL_FILTER_MASK_TUNNEL;
312	} else {
313		mask = 0;
314	}
315	mask |= ASL_FILTER_MASK_UPTO(loglevel);
316	syslog(LOG_DEBUG, "%s: about to set racoon's log level %d, mask %x\n", __FUNCTION__, level, mask);
317	asl_set_filter(NULL, mask);
318}
319
320void
321plogsetlevelstr(char *levelstr)
322{
323	if (!levelstr) {
324		return;
325	}
326
327	if (strncmp(levelstr, ASL_STRING_EMERG, sizeof(ASL_STRING_EMERG) - 1) == 0) {
328		plogsetlevel(ASL_LEVEL_EMERG);
329	} else if (strncmp(levelstr, ASL_STRING_ALERT, sizeof(ASL_STRING_ALERT) - 1) == 0) {
330		plogsetlevel(ASL_LEVEL_ALERT);
331	} else if (strncmp(levelstr, ASL_STRING_CRIT, sizeof(ASL_STRING_CRIT) - 1) == 0) {
332		plogsetlevel(ASL_LEVEL_CRIT);
333	} else if (strncmp(levelstr, ASL_STRING_ERR, sizeof(ASL_STRING_ERR) - 1) == 0) {
334		plogsetlevel(ASL_LEVEL_ERR);
335	} else if (strncmp(levelstr, ASL_STRING_WARNING, sizeof(ASL_STRING_NOTICE) - 1) == 0) {
336		plogsetlevel(ASL_LEVEL_WARNING);
337	} else if (strncmp(levelstr, ASL_STRING_NOTICE, sizeof(ASL_STRING_NOTICE) - 1) == 0) {
338		plogsetlevel(ASL_LEVEL_NOTICE);
339	} else if (strncmp(levelstr, ASL_STRING_INFO, sizeof(ASL_STRING_INFO) - 1) == 0) {
340		plogsetlevel(ASL_LEVEL_INFO);
341	} else if (strncmp(levelstr, ASL_STRING_DEBUG, sizeof(ASL_STRING_DEBUG) - 1) == 0) {
342		plogsetlevel(ASL_LEVEL_DEBUG);
343	}
344}
345
346void
347plogsetlevelquotedstr (char *levelquotedstr)
348{
349	int len;
350
351	if (!levelquotedstr) {
352		plog(ASL_LEVEL_ERR, "Null log level (quoted string)");
353		return;
354	}
355
356	len = strlen(levelquotedstr);
357	if (len < 3 ||
358		levelquotedstr[0] != '"' ||
359		levelquotedstr[len - 1] != '"') {
360		plog(ASL_LEVEL_ERR, "Invalid log level (quoted string): %s", levelquotedstr);
361		return;
362	}
363	// skip quotes
364	levelquotedstr[len - 1] = '\0';
365	plogsetlevelstr(&levelquotedstr[1]);
366}
367
368void
369plogreadprefs (void)
370{
371	CFPropertyListRef	globals;
372	CFStringRef			logFileRef;
373	CFNumberRef			debugLevelRef;
374	CFStringRef			debugLevelStringRef;
375	char                logLevelStr[16];
376	int					level = 0;
377
378	logLevelStr[0] = 0;
379
380    SCPreferencesSynchronize(gPrefs);
381
382    globals = SCPreferencesGetValue(gPrefs, CFSTR("Global"));
383    if (!globals || (CFGetTypeID(globals) != CFDictionaryGetTypeID())) {
384        return;
385    }
386    debugLevelRef = CFDictionaryGetValue(globals, CFSTR("DebugLevel"));
387    if (debugLevelRef && (CFGetTypeID(debugLevelRef) == CFNumberGetTypeID())) {
388        CFNumberGetValue(debugLevelRef, kCFNumberSInt32Type, &level);
389        plogsetlevel(level);
390    } else {
391        debugLevelStringRef = CFDictionaryGetValue(globals, CFSTR("DebugLevelString"));
392        if (debugLevelStringRef && (CFGetTypeID(debugLevelStringRef) == CFStringGetTypeID())) {
393            CFStringGetCString(debugLevelStringRef, logLevelStr, sizeof(logLevelStr), kCFStringEncodingMacRoman);
394            plogsetlevelstr(logLevelStr);
395        }
396    }
397
398    logFileRef = CFDictionaryGetValue(globals, CFSTR("DebugLogfile"));
399    if (!logFileRef	|| (CFGetTypeID(logFileRef) != CFStringGetTypeID())) {
400        return;
401    }
402    CFStringGetCString(logFileRef, logFileStr, MAXPATHLEN, kCFStringEncodingMacRoman);
403    plogsetfile(logFileStr);
404}
405
406void
407ploginit(void)
408{
409	logFileStr[0] = 0;
410	logRef = NULL;//asl_open(NULL, plog_facility, 0);
411	plogsetlevel(ASL_LEVEL_NOTICE);
412	//plogsetlevel(ASL_LEVEL_DEBUG);
413	plogreadprefs();
414}
415
416void
417plogsetsessioninfo (const char *session_id,
418					const char *session_type,
419					const char *session_ver)
420{
421	if (gSessId) {
422		free(gSessId);
423	}
424	if (!session_id) {
425		gSessId = NULL;
426	} else {
427		gSessId = strdup(session_id);
428	}
429	if (gSessId) {
430		free(gSessId);
431	}
432	if (!session_type) {
433		gSessType = NULL;
434	} else {
435		gSessType = strdup(session_id);
436	}
437	if (gSessVer) {
438		free(gSessVer);
439	}
440	if (!session_ver) {
441		gSessVer = NULL;
442	} else {
443		gSessVer = strdup(session_ver);
444	}
445}
446
447char *
448createCStringFromCFString(CFAllocatorRef allocator, CFStringRef cfstr)
449{
450    CFIndex cstr_len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr), kCFStringEncodingUTF8) + 1;
451    char *cstr = (char *)CFAllocatorAllocate(allocator, cstr_len, 0);
452    CFStringGetCString(cfstr, cstr, cstr_len, kCFStringEncodingUTF8);
453    return cstr;
454}
455
456void
457plogcf(int priority, CFStringRef fmt, ...)
458{
459    va_list         args;
460    CFStringRef     cfstr;
461    char            *cstr;
462
463    va_start(args, fmt);
464    cfstr = CFStringCreateWithFormatAndArguments(kCFAllocatorDefault, NULL, fmt, args);
465    va_end(args);
466
467    cstr = createCStringFromCFString(kCFAllocatorDefault, cfstr);
468    plog(priority, "%s", cstr);
469
470    CFAllocatorDeallocate(kCFAllocatorDefault, cstr);
471    CFRelease(cfstr);
472}
473
474
475