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