1/* 2 * Copyright (c) 2004-2012 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#include <TargetConditionals.h> 25 26#include <sys/types.h> 27#include <sys/socket.h> 28#include <sys/un.h> 29#include <sys/ucred.h> 30#include <stdio.h> 31#include <stdlib.h> 32#include <string.h> 33#include <unistd.h> 34#include <netinet/in.h> 35#include <arpa/inet.h> 36#define SYSLOG_NAMES 37#include <syslog.h> 38#include <sys/fslog.h> 39#include <vproc.h> 40#include <pthread.h> 41#include <vproc_priv.h> 42#include <mach/mach.h> 43#include <assert.h> 44#include <libkern/OSAtomic.h> 45#include <libproc.h> 46#include <uuid/uuid.h> 47#include "daemon.h" 48 49#define LIST_SIZE_DELTA 256 50 51#define streq(A,B) (strcmp(A,B)==0) 52#define forever for(;;) 53 54#define ASL_MSG_TYPE_MASK 0x0000000f 55#define ASL_TYPE_ERROR 2 56 57#define ASL_KEY_FACILITY "Facility" 58 59#define FACILITY_USER "user" 60#define FACILITY_CONSOLE "com.apple.console" 61#define SYSTEM_RESERVED "com.apple.system" 62#define SYSTEM_RESERVED_LEN 16 63 64#define VERIFY_STATUS_OK 0 65#define VERIFY_STATUS_INVALID_MESSAGE 1 66#define VERIFY_STATUS_EXCEEDED_QUOTA 2 67 68extern void disaster_message(aslmsg m); 69extern int asl_action_reset(void); 70extern int asl_action_control_set_param(const char *s); 71 72static char myname[MAXHOSTNAMELEN + 1] = {0}; 73static int name_change_token = -1; 74 75static OSSpinLock count_lock = 0; 76 77#if !TARGET_OS_EMBEDDED 78static vproc_transaction_t vproc_trans = {0}; 79#endif 80 81#define QUOTA_KERN_EXCEEDED_MESSAGE "*** kernel exceeded %d log message per second limit - remaining messages this second discarded ***" 82 83#define DEFAULT_DB_FILE_MAX 25600000 84#define DEFAULT_DB_MEMORY_MAX 8192 85#define DEFAULT_DB_MINI_MAX 256 86#define DEFAULT_MPS_LIMIT 500 87#define DEFAULT_REMOTE_DELAY 5000 88#define DEFAULT_BSD_MAX_DUP_SEC 30 89#define DEFAULT_MARK_SEC 0 90#define DEFAULT_UTMP_TTL_SEC 31622400 91 92static time_t quota_time = 0; 93static int32_t kern_quota; 94static int32_t kern_level; 95 96static const char *kern_notify_key[] = 97{ 98 "com.apple.system.log.kernel.emergency", 99 "com.apple.system.log.kernel.alert", 100 "com.apple.system.log.kernel.critical", 101 "com.apple.system.log.kernel.error", 102 "com.apple.system.log.kernel.warning", 103 "com.apple.system.log.kernel.notice", 104 "com.apple.system.log.kernel.info", 105 "com.apple.system.log.kernel.debug" 106}; 107 108static int kern_notify_token[8] = {-1, -1, -1, -1, -1, -1, -1, -1 }; 109 110static uint32_t 111kern_quota_check(time_t now, aslmsg msg, uint32_t level) 112{ 113 char *str, lstr[2]; 114 115 if (msg == NULL) return VERIFY_STATUS_INVALID_MESSAGE; 116 if (global.mps_limit == 0) return VERIFY_STATUS_OK; 117 118 if (quota_time != now) 119 { 120 kern_quota = global.mps_limit; 121 kern_level = 7; 122 quota_time = now; 123 } 124 125 if (level < kern_level) kern_level = level; 126 if (kern_quota > 0) kern_quota--; 127 128 if (kern_quota > 0) return VERIFY_STATUS_OK; 129 if (kern_quota < 0) return VERIFY_STATUS_EXCEEDED_QUOTA; 130 131 kern_quota = -1; 132 133 str = NULL; 134 asprintf(&str, QUOTA_KERN_EXCEEDED_MESSAGE, global.mps_limit); 135 if (str != NULL) 136 { 137 asl_set(msg, ASL_KEY_MSG, str); 138 free(str); 139 lstr[0] = kern_level + '0'; 140 lstr[1] = 0; 141 asl_set(msg, ASL_KEY_LEVEL, lstr); 142 } 143 144 return VERIFY_STATUS_OK; 145} 146 147static const char * 148whatsmyhostname() 149{ 150 static dispatch_once_t once; 151 int check, status; 152 153 dispatch_once(&once, ^{ 154 snprintf(myname, sizeof(myname), "%s", "localhost"); 155 notify_register_check(kNotifySCHostNameChange, &name_change_token); 156 }); 157 158 check = 1; 159 status = 0; 160 161 if (name_change_token >= 0) status = notify_check(name_change_token, &check); 162 163 if ((status == 0) && (check == 0)) return (const char *)myname; 164 165 if (gethostname(myname, MAXHOSTNAMELEN) < 0) 166 { 167 snprintf(myname, sizeof(myname), "%s", "localhost"); 168 } 169 else 170 { 171 char *dot; 172 dot = strchr(myname, '.'); 173 if (dot != NULL) *dot = '\0'; 174 } 175 176 return (const char *)myname; 177} 178 179void 180asl_client_count_increment() 181{ 182 OSSpinLockLock(&count_lock); 183 184#if !TARGET_OS_EMBEDDED 185 if (global.client_count == 0) vproc_trans = vproc_transaction_begin(NULL); 186#endif 187 global.client_count++; 188 189 OSSpinLockUnlock(&count_lock); 190} 191 192void 193asl_client_count_decrement() 194{ 195 OSSpinLockLock(&count_lock); 196 197 if (global.client_count > 0) global.client_count--; 198#if !TARGET_OS_EMBEDDED 199 if (global.client_count == 0) vproc_transaction_end(NULL, vproc_trans); 200#endif 201 202 OSSpinLockUnlock(&count_lock); 203} 204 205/* 206 * Checks message content and sets attributes as required 207 * 208 * SOURCE_INTERNAL log messages sent by syslogd itself 209 * SOURCE_ASL_SOCKET legacy asl(3) TCP socket 210 * SOURCE_BSD_SOCKET legacy syslog(3) UDP socket 211 * SOURCE_UDP_SOCKET from the network 212 * SOURCE_KERN from the kernel 213 * SOURCE_ASL_MESSAGE mach messages sent from Libc by asl(3) and syslog(3) 214 * SOURCE_LAUNCHD forwarded from launchd 215 */ 216 217static uint32_t 218aslmsg_verify(aslmsg msg, uint32_t source, int32_t *kern_post_level, uid_t *uid_out) 219{ 220 const char *val, *fac, *ruval, *rgval; 221 char buf[64]; 222 time_t tick, now; 223 uid_t uid; 224 gid_t gid; 225 uint32_t status, level, fnum; 226 pid_t pid; 227 uuid_string_t ustr; 228 struct proc_uniqidentifierinfo pinfo; 229 230 if (msg == NULL) return VERIFY_STATUS_INVALID_MESSAGE; 231 232 /* Time */ 233 now = time(NULL); 234 235 if (kern_post_level != NULL) *kern_post_level = -1; 236 if (uid_out != NULL) *uid_out = -2; 237 238 /* PID */ 239 pid = 0; 240 241 val = asl_get(msg, ASL_KEY_PID); 242 if (val == NULL) asl_set(msg, ASL_KEY_PID, "0"); 243 else pid = (pid_t)atoi(val); 244 245 /* if PID is 1 (launchd), use the refpid if provided */ 246 if (pid == 1) 247 { 248 val = asl_get(msg, ASL_KEY_REF_PID); 249 if (val != NULL) pid = (pid_t)atoi(val); 250 } 251 252 /* Level */ 253 val = asl_get(msg, ASL_KEY_LEVEL); 254 level = ASL_LEVEL_DEBUG; 255 if ((val != NULL) && (val[1] == '\0') && (val[0] >= '0') && (val[0] <= '7')) level = val[0] - '0'; 256 snprintf(buf, sizeof(buf), "%d", level); 257 asl_set(msg, ASL_KEY_LEVEL, buf); 258 259 /* check kernel quota if enabled and no processes are watching */ 260 if ((pid == 0) && (global.mps_limit > 0) && (global.watchers_active == 0)) 261 { 262 status = kern_quota_check(now, msg, level); 263 if (status != VERIFY_STATUS_OK) return status; 264 } 265 266 if (pid != 0) 267 { 268 /* set Sender_Mach_UUID */ 269 uuid_clear(pinfo.p_uuid); 270 if (proc_pidinfo(pid, PROC_PIDUNIQIDENTIFIERINFO, 1, &pinfo, sizeof(pinfo)) == sizeof(pinfo)) 271 { 272 uuid_unparse(pinfo.p_uuid, ustr); 273 asl_set(msg, ASL_KEY_SENDER_MACH_UUID, ustr); 274 } 275 } 276 277 tick = 0; 278 val = asl_get(msg, ASL_KEY_TIME); 279 if (val != NULL) tick = asl_parse_time(val); 280 281 /* Set time to now if it is unset or from the future (not allowed!) */ 282 if ((tick == 0) || (tick > now)) tick = now; 283 284 /* Canonical form: seconds since the epoch */ 285 snprintf(buf, sizeof(buf) - 1, "%lu", tick); 286 asl_set(msg, ASL_KEY_TIME, buf); 287 288 /* Host */ 289 val = asl_get(msg, ASL_KEY_HOST); 290 if (val == NULL) asl_set(msg, ASL_KEY_HOST, whatsmyhostname()); 291 292 uid = -2; 293 val = asl_get(msg, ASL_KEY_UID); 294 if (val != NULL) 295 { 296 uid = atoi(val); 297 if ((uid == 0) && strcmp(val, "0")) uid = -2; 298 if (uid_out != NULL) *uid_out = uid; 299 } 300 301 gid = -2; 302 val = asl_get(msg, ASL_KEY_GID); 303 if (val != NULL) 304 { 305 gid = atoi(val); 306 if ((gid == 0) && strcmp(val, "0")) gid = -2; 307 } 308 309 /* UID & GID */ 310 switch (source) 311 { 312 case SOURCE_KERN: 313 case SOURCE_INTERNAL: 314 { 315 asl_set(msg, ASL_KEY_UID, "0"); 316 asl_set(msg, ASL_KEY_GID, "0"); 317 break; 318 } 319 case SOURCE_ASL_SOCKET: 320 case SOURCE_ASL_MESSAGE: 321 case SOURCE_LAUNCHD: 322 { 323 /* we trust the UID & GID in the message */ 324 break; 325 } 326 default: 327 { 328 /* we do not trust the UID 0 or GID 0 or 80 in the message */ 329 if (uid == 0) asl_set(msg, ASL_KEY_UID, "-2"); 330 if ((gid == 0) || (gid == 80)) asl_set(msg, ASL_KEY_GID, "-2"); 331 } 332 } 333 334 /* Sender */ 335 val = asl_get(msg, ASL_KEY_SENDER); 336 if (val == NULL) 337 { 338 switch (source) 339 { 340 case SOURCE_KERN: 341 { 342 asl_set(msg, ASL_KEY_SENDER, "kernel"); 343 break; 344 } 345 case SOURCE_INTERNAL: 346 { 347 asl_set(msg, ASL_KEY_SENDER, "syslogd"); 348 break; 349 } 350 default: 351 { 352 asl_set(msg, ASL_KEY_SENDER, "Unknown"); 353 } 354 } 355 } 356 else if ((source != SOURCE_KERN) && (uid != 0) && (!strcmp(val, "kernel"))) 357 { 358 /* allow UID 0 to send messages with "Sender kernel", but nobody else */ 359 asl_set(msg, ASL_KEY_SENDER, "Unknown"); 360 } 361 362 /* Facility */ 363 fac = asl_get(msg, ASL_KEY_FACILITY); 364 if (fac == NULL) 365 { 366 if (source == SOURCE_KERN) fac = "kern"; 367 else fac = "user"; 368 asl_set(msg, ASL_KEY_FACILITY, fac); 369 } 370 else if (fac[0] == '#') 371 { 372 fnum = LOG_USER; 373 if ((fac[1] >= '0') && (fac[1] <= '9')) 374 { 375 fnum = atoi(fac + 1) << 3; 376 if ((fnum == 0) && (strcmp(fac + 1, "0"))) fnum = LOG_USER; 377 } 378 379 fac = asl_syslog_faciliy_num_to_name(fnum); 380 asl_set(msg, ASL_KEY_FACILITY, fac); 381 } 382 else if (!strncmp(fac, SYSTEM_RESERVED, SYSTEM_RESERVED_LEN)) 383 { 384 /* only UID 0 may use "com.apple.system" */ 385 if (uid != 0) asl_set(msg, ASL_KEY_FACILITY, FACILITY_USER); 386 } 387 388 /* 389 * kernel messages are only readable by root and admin group. 390 * all other messages are admin-only readable unless they already 391 * have specific read access controls set. 392 */ 393 if (source == SOURCE_KERN) 394 { 395 asl_set(msg, ASL_KEY_READ_UID, "0"); 396 asl_set(msg, ASL_KEY_READ_GID, "80"); 397 } 398 else 399 { 400 ruval = asl_get(msg, ASL_KEY_READ_UID); 401 rgval = asl_get(msg, ASL_KEY_READ_GID); 402 403 if ((ruval == NULL) && (rgval == NULL)) 404 { 405 asl_set(msg, ASL_KEY_READ_GID, "80"); 406 } 407 } 408 409 /* Set DB Expire Time for com.apple.system.utmpx and lastlog */ 410 if ((!strcmp(fac, "com.apple.system.utmpx")) || (!strcmp(fac, "com.apple.system.lastlog"))) 411 { 412 snprintf(buf, sizeof(buf), "%lu", tick + global.utmp_ttl); 413 asl_set(msg, ASL_KEY_EXPIRE_TIME, buf); 414 } 415 416 /* Set DB Expire Time for Filesystem errors */ 417 if (!strcmp(fac, FSLOG_VAL_FACILITY)) 418 { 419 snprintf(buf, sizeof(buf), "%lu", tick + FS_TTL_SEC); 420 asl_set(msg, ASL_KEY_EXPIRE_TIME, buf); 421 } 422 423 /* 424 * special case handling of kernel disaster messages 425 */ 426 if ((source == SOURCE_KERN) && (level <= KERN_DISASTER_LEVEL)) 427 { 428 if (kern_post_level != NULL) *kern_post_level = level; 429 disaster_message(msg); 430 } 431 432 return VERIFY_STATUS_OK; 433} 434 435void 436list_append_msg(asl_search_result_t *list, aslmsg msg) 437{ 438 if (list == NULL) return; 439 if (msg == NULL) return; 440 441 /* 442 * NB: curr is the list size 443 * grow list if necessary 444 */ 445 if (list->count == list->curr) 446 { 447 if (list->curr == 0) 448 { 449 list->msg = (asl_msg_t **)calloc(LIST_SIZE_DELTA, sizeof(asl_msg_t *)); 450 } 451 else 452 { 453 list->msg = (asl_msg_t **)reallocf(list->msg, (list->curr + LIST_SIZE_DELTA) * sizeof(asl_msg_t *)); 454 } 455 456 if (list->msg == NULL) 457 { 458 list->curr = 0; 459 list->count = 0; 460 return; 461 } 462 463 list->curr += LIST_SIZE_DELTA; 464 } 465 466 list->msg[list->count] = (asl_msg_t *)msg; 467 list->count++; 468} 469 470void 471init_globals(void) 472{ 473 asl_out_rule_t *r; 474 475 OSSpinLockLock(&global.lock); 476 477 global.pid = getpid(); 478 global.debug = 0; 479 free(global.debug_file); 480 global.debug_file = NULL; 481 global.launchd_enabled = 1; 482 483#if TARGET_OS_EMBEDDED 484 global.dbtype = DB_TYPE_MINI; 485#else 486 global.dbtype = DB_TYPE_FILE; 487#endif 488 global.db_file_max = DEFAULT_DB_FILE_MAX; 489 global.db_memory_max = DEFAULT_DB_MEMORY_MAX; 490 global.db_mini_max = DEFAULT_DB_MINI_MAX; 491 global.mps_limit = DEFAULT_MPS_LIMIT; 492 global.remote_delay_time = DEFAULT_REMOTE_DELAY; 493 global.bsd_max_dup_time = DEFAULT_BSD_MAX_DUP_SEC; 494 global.mark_time = DEFAULT_MARK_SEC; 495 global.utmp_ttl = DEFAULT_UTMP_TTL_SEC; 496 497 global.asl_out_module = asl_out_module_init(); 498 OSSpinLockUnlock(&global.lock); 499 500 if (global.asl_out_module != NULL) 501 { 502 for (r = global.asl_out_module->ruleset; r != NULL; r = r->next) 503 { 504 if ((r->action == ACTION_SET_PARAM) && (r->query == NULL) && (!strncmp(r->options, "debug", 5))) control_set_param(r->options, true); 505 } 506 } 507} 508 509/* 510 * Used to set config parameters. 511 * Line format "= name value" 512 */ 513int 514control_set_param(const char *s, bool eval) 515{ 516 char **l; 517 uint32_t intval, count, v32a, v32b, v32c; 518 519 if (s == NULL) return -1; 520 if (s[0] == '\0') return 0; 521 522 /* skip '=' and whitespace */ 523 if (*s == '=') s++; 524 while ((*s == ' ') || (*s == '\t')) s++; 525 526 l = explode(s, " \t"); 527 if (l == NULL) return -1; 528 529 for (count = 0; l[count] != NULL; count++); 530 531 /* name is required */ 532 if (count == 0) 533 { 534 free_string_list(l); 535 return -1; 536 } 537 538 /* Check variables that allow 0 or 1 / boolean */ 539 if (!strcasecmp(l[0], "debug")) 540 { 541 /* = debug [0|1] [file] */ 542 if (count == 1) 543 { 544 intval = (eval) ? 1 : 0; 545 config_debug(intval, NULL); 546 } 547 else if (!strcmp(l[1], "0")) 548 { 549 config_debug(0, l[2]); 550 } 551 else if (!strcmp(l[1], "1")) 552 { 553 config_debug(1, l[2]); 554 } 555 else 556 { 557 intval = (eval) ? 1 : 0; 558 config_debug(intval, l[1]); 559 } 560 561 free_string_list(l); 562 return 0; 563 } 564 565 /* value is required */ 566 if (count == 1) 567 { 568 free_string_list(l); 569 return -1; 570 } 571 572 if (!strcasecmp(l[0], "mark_time")) 573 { 574 /* = mark_time seconds */ 575 OSSpinLockLock(&global.lock); 576 if (eval) global.mark_time = atoll(l[1]); 577 else global.mark_time = 0; 578 OSSpinLockUnlock(&global.lock); 579 } 580 else if (!strcasecmp(l[0], "dup_delay")) 581 { 582 /* = bsd_max_dup_time seconds */ 583 OSSpinLockLock(&global.lock); 584 if (eval) global.bsd_max_dup_time = atoll(l[1]); 585 else global.bsd_max_dup_time = DEFAULT_BSD_MAX_DUP_SEC; 586 OSSpinLockUnlock(&global.lock); 587 } 588 else if (!strcasecmp(l[0], "remote_delay")) 589 { 590 /* = remote_delay microseconds */ 591 OSSpinLockLock(&global.lock); 592 if (eval) global.remote_delay_time = atol(l[1]); 593 else global.remote_delay_time = DEFAULT_REMOTE_DELAY; 594 OSSpinLockUnlock(&global.lock); 595 } 596 else if (!strcasecmp(l[0], "utmp_ttl")) 597 { 598 /* = utmp_ttl seconds */ 599 OSSpinLockLock(&global.lock); 600 if (eval) global.utmp_ttl = (time_t)atoll(l[1]); 601 else global.utmp_ttl = DEFAULT_UTMP_TTL_SEC; 602 OSSpinLockUnlock(&global.lock); 603 } 604 else if (!strcasecmp(l[0], "mps_limit")) 605 { 606 /* = mps_limit number */ 607 OSSpinLockLock(&global.lock); 608 if (eval) global.mps_limit = (uint32_t)atol(l[1]); 609 else global.mps_limit = DEFAULT_MPS_LIMIT; 610 OSSpinLockUnlock(&global.lock); 611 } 612 else if (!strcasecmp(l[0], "max_file_size")) 613 { 614 /* = max_file_size bytes */ 615 pthread_mutex_lock(global.db_lock); 616 617 if (global.dbtype & DB_TYPE_FILE) 618 { 619 asl_store_close(global.file_db); 620 global.file_db = NULL; 621 if (eval) global.db_file_max = atoi(l[1]); 622 else global.db_file_max = DEFAULT_DB_FILE_MAX; 623 } 624 625 pthread_mutex_unlock(global.db_lock); 626 } 627 else if ((!strcasecmp(l[0], "db")) || (!strcasecmp(l[0], "database")) || (!strcasecmp(l[0], "datastore"))) 628 { 629 /* NB this is private / unpublished */ 630 /* = db type [max]... */ 631 if (eval) 632 { 633 v32a = 0; 634 v32b = 0; 635 v32c = 0; 636 637 if ((l[1][0] >= '0') && (l[1][0] <= '9')) 638 { 639 intval = atoi(l[1]); 640 if ((count >= 3) && (strcmp(l[2], "-"))) v32a = atoi(l[2]); 641 if ((count >= 4) && (strcmp(l[3], "-"))) v32b = atoi(l[3]); 642 if ((count >= 5) && (strcmp(l[4], "-"))) v32c = atoi(l[4]); 643 } 644 else if (!strcasecmp(l[1], "file")) 645 { 646 intval = DB_TYPE_FILE; 647 if ((count >= 3) && (strcmp(l[2], "-"))) v32a = atoi(l[2]); 648 } 649 else if (!strncasecmp(l[1], "mem", 3)) 650 { 651 intval = DB_TYPE_MEMORY; 652 if ((count >= 3) && (strcmp(l[2], "-"))) v32b = atoi(l[2]); 653 } 654 else if (!strncasecmp(l[1], "min", 3)) 655 { 656 intval = DB_TYPE_MINI; 657 if ((count >= 3) && (strcmp(l[2], "-"))) v32c = atoi(l[2]); 658 } 659 else 660 { 661 free_string_list(l); 662 return -1; 663 } 664 665 if (v32a == 0) v32a = global.db_file_max; 666 if (v32b == 0) v32b = global.db_memory_max; 667 if (v32c == 0) v32c = global.db_mini_max; 668 669 config_data_store(intval, v32a, v32b, v32c); 670 } 671 else 672 { 673#if TARGET_OS_EMBEDDED 674 intval = DB_TYPE_MINI; 675#else 676 intval = DB_TYPE_FILE; 677#endif 678 config_data_store(intval, DEFAULT_DB_FILE_MAX, DEFAULT_DB_MEMORY_MAX, DEFAULT_DB_MINI_MAX); 679 } 680 } 681 682 free_string_list(l); 683 return 0; 684} 685 686static int 687control_message(aslmsg msg) 688{ 689 const char *str = asl_get(msg, ASL_KEY_MSG); 690 691 if (str == NULL) return 0; 692 693 if (!strncmp(str, "= reset", 7)) 694 { 695 init_globals(); 696 return asl_action_reset(); 697 } 698 else if (!strncmp(str, "= crash", 7)) 699 { 700 abort(); 701 } 702 else if (!strncmp(str, "@ ", 2)) 703 { 704 return asl_action_control_set_param(str); 705 } 706 else if (!strncmp(str, "= ", 2)) 707 { 708 return control_set_param(str, true); 709 } 710 711 return 0; 712} 713 714void 715process_message(aslmsg msg, uint32_t source) 716{ 717 if (msg == NULL) return; 718 719 OSAtomicIncrement32(&global.work_queue_count); 720 dispatch_async(global.work_queue, ^{ 721 int32_t kplevel; 722 uint32_t status; 723 uid_t uid; 724 725 kplevel = -1; 726 uid = -2; 727 728 status = aslmsg_verify(msg, source, &kplevel, &uid); 729 if (status == VERIFY_STATUS_OK) 730 { 731 if ((source == SOURCE_KERN) && (kplevel >= 0)) 732 { 733 if (kplevel > 7) kplevel = 7; 734 if (kern_notify_token[kplevel] < 0) 735 { 736 status = notify_register_plain(kern_notify_key[kplevel], &(kern_notify_token[kplevel])); 737 if (status != 0) asldebug("notify_register_plain(%s) failed status %u\n", status); 738 } 739 740 notify_post(kern_notify_key[kplevel]); 741 } 742 743 if ((uid == 0) && asl_check_option(msg, ASL_OPT_CONTROL)) control_message(msg); 744 745 /* send message to output modules */ 746 asl_out_message(msg); 747#if !TARGET_IPHONE_SIMULATOR 748 if (global.bsd_out_enabled) bsd_out_message(msg); 749#endif 750 } 751 752 asl_free(msg); 753 OSAtomicDecrement32(&global.work_queue_count); 754 }); 755} 756 757int 758internal_log_message(const char *str) 759{ 760 aslmsg msg; 761 762 if (str == NULL) return 1; 763 764 msg = (aslmsg)asl_msg_from_string(str); 765 if (msg == NULL) return 1; 766 767 process_message(msg, SOURCE_INTERNAL); 768 769 return 0; 770} 771 772int 773asldebug(const char *str, ...) 774{ 775 va_list v; 776 FILE *dfp = NULL; 777 778 if (global.debug == 0) return 0; 779 780 if (global.debug_file == NULL) dfp = fopen(_PATH_SYSLOGD_LOG, "a"); 781 else dfp = fopen(global.debug_file, "a"); 782 if (dfp == NULL) return 0; 783 784 va_start(v, str); 785 vfprintf(dfp, str, v); 786 va_end(v); 787 788 fclose(dfp); 789 790 return 0; 791} 792 793void 794asl_mark(void) 795{ 796 char *str = NULL; 797 798 asprintf(&str, "[Sender syslogd] [Level 6] [PID %u] [Message -- MARK --] [UID 0] [UID 0] [Facility syslog]", global.pid); 799 internal_log_message(str); 800 free(str); 801} 802 803aslmsg 804asl_syslog_input_convert(const char *in, int len, char *rhost, uint32_t source) 805{ 806 int pf, pri, index, n; 807 char *p, *colon, *brace, *space, *tmp, *tval, *hval, *sval, *pval, *mval; 808 char prival[8]; 809 const char *fval; 810 aslmsg msg; 811 struct tm time; 812 time_t tick; 813 814 if (in == NULL) return NULL; 815 if (len <= 0) return NULL; 816 817 pri = LOG_DEBUG; 818 tval = NULL; 819 hval = NULL; 820 sval = NULL; 821 pval = NULL; 822 mval = NULL; 823 fval = NULL; 824 825 index = 0; 826 p = (char *)in; 827 828 /* skip leading whitespace */ 829 while ((index < len) && ((*p == ' ') || (*p == '\t'))) 830 { 831 p++; 832 index++; 833 } 834 835 if (index >= len) return NULL; 836 837 /* parse "<NN>" priority (level and facility) */ 838 if (*p == '<') 839 { 840 p++; 841 index++; 842 843 n = sscanf(p, "%d", &pf); 844 if (n == 1) 845 { 846 pri = pf & 0x7; 847 if (pf > 0x7) fval = asl_syslog_faciliy_num_to_name(pf & LOG_FACMASK); 848 } 849 850 while ((index < len) && (*p != '>')) 851 { 852 p++; 853 index++; 854 } 855 856 if (index < len) 857 { 858 p++; 859 index++; 860 } 861 } 862 863 snprintf(prival, sizeof(prival), "%d", pri); 864 865 /* check if a timestamp is included */ 866 if (((len - index) > 15) && (p[9] == ':') && (p[12] == ':') && (p[15] == ' ')) 867 { 868 tmp = malloc(16); 869 if (tmp == NULL) return NULL; 870 871 memcpy(tmp, p, 15); 872 tmp[15] = '\0'; 873 874 tick = asl_parse_time(tmp); 875 if (tick == (time_t)-1) 876 { 877 tval = tmp; 878 } 879 else 880 { 881 free(tmp); 882 gmtime_r(&tick, &time); 883 asprintf(&tval, "%d.%02d.%02d %02d:%02d:%02d UTC", time.tm_year + 1900, time.tm_mon + 1, time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec); 884 } 885 886 p += 16; 887 index += 16; 888 } 889 890 /* stop here for kernel messages */ 891 if (source == SOURCE_KERN) 892 { 893 msg = asl_new(ASL_TYPE_MSG); 894 if (msg == NULL) return NULL; 895 896 asl_set(msg, ASL_KEY_MSG, p); 897 asl_set(msg, ASL_KEY_LEVEL, prival); 898 asl_set(msg, ASL_KEY_PID, "0"); 899 900 return msg; 901 } 902 903 /* if message is from a network socket, hostname follows */ 904 if (source == SOURCE_UDP_SOCKET) 905 { 906 space = strchr(p, ' '); 907 if (space != NULL) 908 { 909 n = space - p; 910 hval = malloc(n + 1); 911 if (hval == NULL) return NULL; 912 913 memcpy(hval, p, n); 914 hval[n] = '\0'; 915 916 p = space + 1; 917 index += (n + 1); 918 } 919 } 920 921 colon = strchr(p, ':'); 922 brace = strchr(p, '['); 923 924 /* check for "sender:" or sender[pid]:" */ 925 if (colon != NULL) 926 { 927 if ((brace != NULL) && (brace < colon)) 928 { 929 n = brace - p; 930 sval = malloc(n + 1); 931 if (sval == NULL) return NULL; 932 933 memcpy(sval, p, n); 934 sval[n] = '\0'; 935 936 n = colon - (brace + 1) - 1; 937 pval = malloc(n + 1); 938 if (pval == NULL) return NULL; 939 940 memcpy(pval, (brace + 1), n); 941 pval[n] = '\0'; 942 } 943 else 944 { 945 n = colon - p; 946 sval = malloc(n + 1); 947 if (sval == NULL) return NULL; 948 949 memcpy(sval, p, n); 950 sval[n] = '\0'; 951 } 952 953 n = colon - p; 954 p = colon + 1; 955 index += (n + 1); 956 } 957 958 if (*p == ' ') 959 { 960 p++; 961 index++; 962 } 963 964 n = len - index; 965 if (n > 0) 966 { 967 mval = malloc(n + 1); 968 if (mval == NULL) return NULL; 969 970 memcpy(mval, p, n); 971 mval[n] = '\0'; 972 } 973 974 if (fval == NULL) fval = asl_syslog_faciliy_num_to_name(LOG_USER); 975 976 msg = asl_new(ASL_TYPE_MSG); 977 if (msg == NULL) return NULL; 978 979 if (tval != NULL) 980 { 981 asl_set(msg, ASL_KEY_TIME, tval); 982 free(tval); 983 } 984 985 if (fval != NULL) asl_set(msg, "Facility", fval); 986 else asl_set(msg, "Facility", "user"); 987 988 if (sval != NULL) 989 { 990 asl_set(msg, ASL_KEY_SENDER, sval); 991 free(sval); 992 } 993 994 if (pval != NULL) 995 { 996 asl_set(msg, ASL_KEY_PID, pval); 997 free(pval); 998 } 999 else 1000 { 1001 asl_set(msg, ASL_KEY_PID, "-1"); 1002 } 1003 1004 if (mval != NULL) 1005 { 1006 asl_set(msg, ASL_KEY_MSG, mval); 1007 free(mval); 1008 } 1009 1010 asl_set(msg, ASL_KEY_LEVEL, prival); 1011 asl_set(msg, ASL_KEY_UID, "-2"); 1012 asl_set(msg, ASL_KEY_GID, "-2"); 1013 1014 if (hval != NULL) 1015 { 1016 asl_set(msg, ASL_KEY_HOST, hval); 1017 free(hval); 1018 } 1019 else if (rhost != NULL) 1020 { 1021 asl_set(msg, ASL_KEY_HOST, rhost); 1022 } 1023 1024 return msg; 1025} 1026 1027aslmsg 1028asl_input_parse(const char *in, int len, char *rhost, uint32_t source) 1029{ 1030 aslmsg msg; 1031 int status, x, legacy, off; 1032 1033 asldebug("asl_input_parse: %s\n", (in == NULL) ? "NULL" : in); 1034 1035 if (in == NULL) return NULL; 1036 1037 legacy = 1; 1038 msg = NULL; 1039 1040 /* calculate length if not provided */ 1041 if (len == 0) len = strlen(in); 1042 1043 /* 1044 * Determine if the input is "old" syslog format or new ASL format. 1045 * Old format lines should start with "<", but they can just be straight text. 1046 * ASL input may start with a length (10 bytes) followed by a space and a '['. 1047 * The length is optional, so ASL messages may also just start with '['. 1048 */ 1049 if ((in[0] != '<') && (len > 11)) 1050 { 1051 status = sscanf(in, "%d ", &x); 1052 if ((status == 1) && (in[10] == ' ') && (in[11] == '[')) legacy = 0; 1053 } 1054 1055 if (legacy == 1) return asl_syslog_input_convert(in, len, rhost, source); 1056 1057 off = 11; 1058 if (in[0] == '[') off = 0; 1059 1060 msg = (aslmsg)asl_msg_from_string(in + off); 1061 if (msg == NULL) return NULL; 1062 1063 if (rhost != NULL) asl_set(msg, ASL_KEY_HOST, rhost); 1064 1065 return msg; 1066} 1067 1068#if !TARGET_IPHONE_SIMULATOR 1069void 1070launchd_callback(struct timeval *when, pid_t from_pid, pid_t about_pid, uid_t sender_uid, gid_t sender_gid, int priority, const char *from_name, const char *about_name, const char *session_name, const char *msg) 1071{ 1072 aslmsg m; 1073 char str[256]; 1074 time_t now; 1075 1076 if (global.launchd_enabled == 0) return; 1077 1078/* 1079 asldebug("launchd_callback Time %lu %lu PID %u RefPID %u UID %d GID %d PRI %d Sender %s Ref %s Session %s Message %s\n", 1080 when->tv_sec, when->tv_usec, from_pid, about_pid, sender_uid, sender_gid, priority, from_name, about_name, session_name, msg); 1081*/ 1082 1083 m = asl_new(ASL_TYPE_MSG); 1084 if (m == NULL) return; 1085 1086 /* Level */ 1087 if (priority < ASL_LEVEL_EMERG) priority = ASL_LEVEL_EMERG; 1088 if (priority > ASL_LEVEL_DEBUG) priority = ASL_LEVEL_DEBUG; 1089 snprintf(str, sizeof(str), "%d", priority); 1090 1091 asl_set(m, ASL_KEY_LEVEL, str); 1092 1093 /* Time */ 1094 if (when != NULL) 1095 { 1096 snprintf(str, sizeof(str), "%lu", when->tv_sec); 1097 asl_set(m, ASL_KEY_TIME, str); 1098 1099 snprintf(str, sizeof(str), "%lu", 1000 * (unsigned long int)when->tv_usec); 1100 asl_set(m, ASL_KEY_TIME_NSEC, str); 1101 } 1102 else 1103 { 1104 now = time(NULL); 1105 snprintf(str, sizeof(str), "%lu", now); 1106 asl_set(m, ASL_KEY_TIME, str); 1107 } 1108 1109 /* Facility */ 1110 asl_set(m, ASL_KEY_FACILITY, FACILITY_CONSOLE); 1111 1112 /* UID */ 1113 snprintf(str, sizeof(str), "%u", (unsigned int)sender_uid); 1114 asl_set(m, ASL_KEY_UID, str); 1115 1116 /* GID */ 1117 snprintf(str, sizeof(str), "%u", (unsigned int)sender_gid); 1118 asl_set(m, ASL_KEY_GID, str); 1119 1120 /* PID */ 1121 if (from_pid != 0) 1122 { 1123 snprintf(str, sizeof(str), "%u", (unsigned int)from_pid); 1124 asl_set(m, ASL_KEY_PID, str); 1125 } 1126 1127 /* Reference PID */ 1128 if ((about_pid > 0) && (about_pid != from_pid)) 1129 { 1130 snprintf(str, sizeof(str), "%u", (unsigned int)about_pid); 1131 asl_set(m, ASL_KEY_REF_PID, str); 1132 } 1133 1134 /* Sender */ 1135 if (from_name != NULL) 1136 { 1137 asl_set(m, ASL_KEY_SENDER, from_name); 1138 } 1139 1140 /* ReadUID */ 1141 if (sender_uid != 0) 1142 { 1143 snprintf(str, sizeof(str), "%d", (int)sender_uid); 1144 asl_set(m, ASL_KEY_READ_UID, str); 1145 } 1146 1147 /* Reference Process */ 1148 if (about_name != NULL) 1149 { 1150 if ((from_name != NULL) && (strcmp(from_name, about_name) != 0)) 1151 { 1152 asl_set(m, ASL_KEY_REF_PROC, about_name); 1153 } 1154 } 1155 1156 /* Session */ 1157 if (session_name != NULL) 1158 { 1159 asl_set(m, ASL_KEY_SESSION, session_name); 1160 } 1161 1162 /* Message */ 1163 if (msg != NULL) 1164 { 1165 asl_set(m, ASL_KEY_MSG, msg); 1166 } 1167 1168 process_message(m, SOURCE_LAUNCHD); 1169} 1170 1171#endif 1172