2  * Copyright (c) 2004-2012 Apple Inc. All rights reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   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 
  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. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  24 #include <TargetConditionals.h> 
  25 #include <sys/types.h> 
  26 #include <sys/socket.h> 
  28 #include <sys/ucred.h> 
  33 #include <netinet/in.h> 
  34 #include <arpa/inet.h> 
  37 #include <sys/fslog.h> 
  40 #include <vproc_priv.h> 
  41 #include <mach/mach.h> 
  42 #include <libkern/OSAtomic.h> 
  44 #include <uuid/uuid.h> 
  45 #include <asl_private.h> 
  48 #define LIST_SIZE_DELTA 256 
  49 #define STATS_TABLE_SIZE 256 
  51 #define forever for(;;) 
  53 #define ASL_MSG_TYPE_MASK 0x0000000f 
  54 #define ASL_TYPE_ERROR 2 
  56 #define ASL_KEY_FACILITY "Facility" 
  58 #define FACILITY_USER "user" 
  59 #define FACILITY_CONSOLE "com.apple.console" 
  60 #define SYSTEM_RESERVED "com.apple.system" 
  61 #define SYSTEM_RESERVED_LEN 16 
  63 #define VERIFY_STATUS_OK 0 
  64 #define VERIFY_STATUS_INVALID_MESSAGE 1 
  65 #define VERIFY_STATUS_EXCEEDED_QUOTA 2 
  67 extern void disaster_message(asl_msg_t 
*m
); 
  68 extern int asl_action_reset(void); 
  69 extern int asl_action_control_set_param(const char *s
); 
  71 static char myname
[MAXHOSTNAMELEN 
+ 1] = {0}; 
  72 static int name_change_token 
= -1; 
  74 static OSSpinLock count_lock 
= 0; 
  76 #if !TARGET_OS_EMBEDDED 
  77 static vproc_transaction_t vproc_trans 
= {0}; 
  80 #define DEFAULT_MEMORY_MAX SYSLOGD_WORK_QUEUE_MEMORY 
  82 #define QUOTA_KERN_EXCEEDED_MESSAGE "*** kernel exceeded %d log message per second limit  -  remaining messages this second discarded ***" 
  84 #define DEFAULT_DB_FILE_MAX 25600000 
  85 #define DEFAULT_DB_MEMORY_MAX 256 
  86 #define DEFAULT_DB_MEMORY_STR_MAX 1024000 
  87 #define DEFAULT_MPS_LIMIT 500 
  88 #define DEFAULT_REMOTE_DELAY 5000 
  89 #define DEFAULT_BSD_MAX_DUP_SEC 30 
  90 #define DEFAULT_MARK_SEC 0 
  91 #define DEFAULT_UTMP_TTL_SEC 31622400 
  92 #define DEFAULT_STATS_INTERVAL 600 
  94 #define ASL_STATS_LEVEL 5 
  96 static time_t quota_time 
= 0; 
  97 static int32_t kern_quota
; 
  98 static int32_t kern_level
; 
 100 static const char *kern_notify_key
[] =  
 102         "com.apple.system.log.kernel.emergency", 
 103         "com.apple.system.log.kernel.alert", 
 104         "com.apple.system.log.kernel.critical", 
 105         "com.apple.system.log.kernel.error", 
 106         "com.apple.system.log.kernel.warning", 
 107         "com.apple.system.log.kernel.notice", 
 108         "com.apple.system.log.kernel.info", 
 109         "com.apple.system.log.kernel.debug" 
 112 static int kern_notify_token
[8] = {-1, -1, -1, -1, -1, -1, -1, -1}; 
 114 static stats_table_t 
* 
 117         stats_table_t 
*t 
= (stats_table_t 
*)malloc(sizeof(stats_table_t
)); 
 118         if (t 
== NULL
) return NULL
; 
 120         t
->bucket_count 
= STATS_TABLE_SIZE
; 
 121         t
->bucket 
= (sender_stats_t 
**)calloc(t
->bucket_count
, sizeof(sender_stats_t 
*)); 
 122         if (t
->bucket 
== NULL
) 
 135 stats_table_final(stats_table_t 
*t
) 
 141         if (t 
== NULL
) return NULL
; 
 143         msg 
= asl_msg_new(ASL_TYPE_MSG
); 
 144         if (msg 
== NULL
) return NULL
; 
 146         asl_msg_set_key_val(msg
, ASL_KEY_MSG
, "ASL Sender Statistics"); 
 147         asl_msg_set_key_val(msg
, ASL_KEY_SENDER
, "syslogd"); 
 148         asl_msg_set_key_val(msg
, ASL_KEY_FACILITY
, "com.apple.asl.statistics"); 
 149         snprintf(val
, sizeof(val
), "%d", global
.pid
); 
 150         asl_msg_set_key_val(msg
, ASL_KEY_PID
, val
); 
 151         snprintf(val
, sizeof(val
), "%d", ASL_STATS_LEVEL
); 
 152         asl_msg_set_key_val(msg
, ASL_KEY_LEVEL
, val
); 
 153         snprintf(val
, sizeof(val
), "%u", t
->mcount
); 
 154         asl_msg_set_key_val(msg
, "MsgCount", val
); 
 155         snprintf(val
, sizeof(val
), "%u", t
->shim_count
); 
 156         asl_msg_set_key_val(msg
, "ShimCount", val
); 
 158         for (i 
= 0; i 
< t
->bucket_count
; i
++) 
 164                         char val
[64], *key 
= NULL
; 
 165                         sender_stats_t 
*n 
= s
->next
; 
 167                         snprintf(val
, sizeof(val
), "%llu %llu", s
->count
, s
->size
); 
 168                         asprintf(&key
, "*%s", s
->sender
); 
 169                         if (key 
!= NULL
) asl_msg_set_key_val(msg
, key
, val
); 
 184 stats_table_update(stats_table_t 
*t
, const char *sender
, uint64_t msg_size
) 
 190         if (t 
== NULL
) return; 
 191         if (sender 
== NULL
) return; 
 195         for (p 
= (uint8_t *)sender
; *p 
!= '\0'; p
++) i 
= (i 
<< 1) ^ (i 
^ *p
); 
 196         i 
%= STATS_TABLE_SIZE
; 
 198         for (s 
= t
->bucket
[i
]; s 
!= NULL
; s 
= s
->next
) 
 200                 if ((s
->sender 
!= NULL
) && (strcmp(sender
, s
->sender
) == 0)) 
 208         s 
= (sender_stats_t 
*)malloc(sizeof(sender_stats_t
)); 
 209         s
->sender 
= strdup(sender
); 
 210         if (s
->sender 
== NULL
) 
 218         s
->next 
= t
->bucket
[i
]; 
 223 kern_quota_check(time_t now
, asl_msg_t 
*msg
, uint32_t level
) 
 227         if (msg 
== NULL
) return VERIFY_STATUS_INVALID_MESSAGE
; 
 228         if (global
.mps_limit 
== 0) return VERIFY_STATUS_OK
; 
 230         if (quota_time 
!= now
) 
 232                 kern_quota 
= global
.mps_limit
; 
 237         if (level 
< kern_level
) kern_level 
= level
; 
 238         if (kern_quota 
> 0) kern_quota
--; 
 240         if (kern_quota 
> 0) return VERIFY_STATUS_OK
; 
 241         if (kern_quota 
< 0)     return VERIFY_STATUS_EXCEEDED_QUOTA
; 
 246         asprintf(&str
, QUOTA_KERN_EXCEEDED_MESSAGE
, global
.mps_limit
); 
 249                 asl_msg_set_key_val(msg
, ASL_KEY_MSG
, str
); 
 251                 lstr
[0] = kern_level 
+ '0'; 
 253                 asl_msg_set_key_val(msg
, ASL_KEY_LEVEL
, lstr
); 
 256         return VERIFY_STATUS_OK
; 
 260 stats_msg(const char *sender
, time_t now
, asl_msg_t 
*msg
) 
 265         /* flush stats after N seconds */ 
 266         if ((global
.stats_interval 
!= 0) && ((now 
- global
.stats_last
) >= global
.stats_interval
) && (global
.stats 
!= NULL
)) 
 268                 asl_msg_t 
*msg 
= stats_table_final(global
.stats
); 
 269                 process_message(msg
, SOURCE_INTERNAL
); 
 271                 global
.stats_last 
= now
; 
 274         if (global
.stats 
== NULL
) global
.stats 
= stats_table_new(); 
 276         for (x 
= msg
; x 
!= NULL
; x 
= x
->next
) msize 
+= x
->mem_size
; 
 278         const char *shim_vers 
= asl_msg_get_val_for_key(msg
, "ASLSHIM"); 
 279         global
.stats
->mcount
++; 
 280         if (shim_vers 
!= NULL
) global
.stats
->shim_count
++; 
 282         /* update count and total size - total and for this sender */ 
 283         stats_table_update(global
.stats
, "*", msize
); 
 284         stats_table_update(global
.stats
, sender
, msize
); 
 290         static dispatch_once_t once
; 
 293         if (global
.hostname 
!= NULL
) return global
.hostname
; 
 295         dispatch_once(&once
, ^{ 
 296                 snprintf(myname
, sizeof(myname
), "%s", "localhost"); 
 297                 notify_register_check(kNotifySCHostNameChange
, &name_change_token
); 
 303         if (name_change_token 
>= 0) status 
= notify_check(name_change_token
, &check
); 
 305         if ((status 
== 0) && (check 
== 0)) return (const char *)myname
; 
 307         if (gethostname(myname
, MAXHOSTNAMELEN
) < 0) 
 309                 snprintf(myname
, sizeof(myname
), "%s", "localhost"); 
 314                 dot 
= strchr(myname
, '.'); 
 315                 if (dot 
!= NULL
) *dot 
= '\0'; 
 318         return (const char *)myname
; 
 322 asl_client_count_increment() 
 324         OSSpinLockLock(&count_lock
); 
 326 #if !TARGET_OS_EMBEDDED 
 327         if (global
.client_count 
== 0) vproc_trans 
= vproc_transaction_begin(NULL
); 
 329         global
.client_count
++; 
 331         OSSpinLockUnlock(&count_lock
); 
 335 asl_client_count_decrement() 
 337         OSSpinLockLock(&count_lock
); 
 339         if (global
.client_count 
> 0) global
.client_count
--; 
 340 #if !TARGET_OS_EMBEDDED 
 341         if (global
.client_count 
== 0) vproc_transaction_end(NULL
, vproc_trans
); 
 344         OSSpinLockUnlock(&count_lock
); 
 348  * Checks message content and sets attributes as required 
 350  * SOURCE_INTERNAL log messages sent by syslogd itself 
 351  * SOURCE_ASL_SOCKET legacy asl(3) TCP socket 
 352  * SOURCE_BSD_SOCKET legacy syslog(3) UDP socket 
 353  * SOURCE_UDP_SOCKET from the network 
 354  * SOURCE_KERN from the kernel 
 355  * SOURCE_ASL_MESSAGE mach messages sent from Libc by asl(3) and syslog(3) 
 356  * SOURCE_LAUNCHD forwarded from launchd 
 360 aslmsg_verify(asl_msg_t 
*msg
, uint32_t source
, int32_t *kern_post_level
, uid_t 
*uid_out
) 
 362         const char *val
, *fac
, *ruval
, *rgval
, *sval 
= NULL
; 
 367         uint32_t status
, level
, fnum
; 
 370         struct proc_uniqidentifierinfo pinfo
; 
 372         if (msg 
== NULL
) return VERIFY_STATUS_INVALID_MESSAGE
; 
 377         if (kern_post_level 
!= NULL
) *kern_post_level 
= -1; 
 378         if (uid_out 
!= NULL
) *uid_out 
= -2; 
 383         val 
= asl_msg_get_val_for_key(msg
, ASL_KEY_PID
); 
 384         if (val 
== NULL
) asl_msg_set_key_val(msg
, ASL_KEY_PID
, "0"); 
 385         else pid 
= (pid_t
)atoi(val
); 
 387         /* if PID is 1 (launchd), use the RefPID and RefProc provided */ 
 390                 val 
= asl_msg_get_val_for_key(msg
, ASL_KEY_REF_PID
); 
 391                 if (val 
!= NULL
) pid 
= (pid_t
)atoi(val
); 
 393                 sval 
= asl_msg_get_val_for_key(msg
, ASL_KEY_REF_PROC
); 
 397         val 
= asl_msg_get_val_for_key(msg
, ASL_KEY_LEVEL
); 
 398         level 
= ASL_LEVEL_DEBUG
; 
 399         if (source 
== SOURCE_KERN
) level 
= ASL_LEVEL_NOTICE
; 
 401         if ((val 
!= NULL
) && (val
[1] == '\0') && (val
[0] >= '0') && (val
[0] <= '7')) level 
= val
[0] - '0'; 
 402         snprintf(buf
, sizeof(buf
), "%d", level
); 
 403         asl_msg_set_key_val(msg
, ASL_KEY_LEVEL
, buf
); 
 406         /* check kernel quota if enabled and no processes are watching */ 
 407         if ((pid 
== 0) && (global
.mps_limit 
> 0) && (global
.watchers_active 
== 0)) 
 409                 status 
= kern_quota_check(now
, msg
, level
); 
 410                 if (status 
!= VERIFY_STATUS_OK
) return status
; 
 415                 /* set Sender_Mach_UUID */ 
 416                 uuid_clear(pinfo
.p_uuid
); 
 417                 if (proc_pidinfo(pid
, PROC_PIDUNIQIDENTIFIERINFO
, 1, &pinfo
, sizeof(pinfo
)) == sizeof(pinfo
)) 
 419                         uuid_unparse(pinfo
.p_uuid
, ustr
); 
 420                         asl_msg_set_key_val(msg
, ASL_KEY_SENDER_MACH_UUID
, ustr
); 
 425         val 
= asl_msg_get_val_for_key(msg
, ASL_KEY_TIME
); 
 426         if (val 
!= NULL
) tick 
= asl_core_parse_time(val
, NULL
); 
 428         /* Set time to now if it is unset or from the future (not allowed!) */ 
 429         if ((tick 
== 0) || (tick 
> now
)) tick 
= now
; 
 431         /* Canonical form: seconds since the epoch */ 
 432         snprintf(buf
, sizeof(buf
) - 1, "%llu", (unsigned long long) tick
); 
 433         asl_msg_set_key_val(msg
, ASL_KEY_TIME
, buf
); 
 436         val 
= asl_msg_get_val_for_key(msg
, ASL_KEY_HOST
); 
 437         if (val 
== NULL
) asl_msg_set_key_val(msg
, ASL_KEY_HOST
, whatsmyhostname()); 
 441         val 
= asl_msg_get_val_for_key(msg
, ASL_KEY_UID
); 
 444                 asl_msg_set_key_val(msg
, ASL_KEY_UID
, "-2"); 
 449                 if ((uid 
== 0) && strcmp(val
, "0")) 
 452                         asl_msg_set_key_val(msg
, ASL_KEY_UID
, "-2"); 
 457         val 
= asl_msg_get_val_for_key(msg
, ASL_KEY_GID
); 
 460                 asl_msg_set_key_val(msg
, ASL_KEY_GID
, "-2"); 
 465                 if ((gid 
== 0) && strcmp(val
, "0")) 
 468                         asl_msg_set_key_val(msg
, ASL_KEY_GID
, "-2"); 
 475                 case SOURCE_INTERNAL
: 
 478                         asl_msg_set_key_val(msg
, ASL_KEY_UID
, "0"); 
 481                         asl_msg_set_key_val(msg
, ASL_KEY_GID
, "0"); 
 485                 case SOURCE_ASL_MESSAGE
: 
 492                         /* do not trust the UID 0 or GID 0 or 80 in SOURCE_BSD_SOCKET or SOURCE_UNKNOWN */ 
 496                                 asl_msg_set_key_val(msg
, ASL_KEY_UID
, "-2"); 
 499                         if ((gid 
== 0) || (gid 
== 80)) 
 502                                 asl_msg_set_key_val(msg
, ASL_KEY_GID
, "-2"); 
 507         if (uid_out 
!= NULL
) *uid_out 
= uid
; 
 510         if (sval 
== NULL
) sval 
= asl_msg_get_val_for_key(msg
, ASL_KEY_SENDER
); 
 518                                 asl_msg_set_key_val(msg
, ASL_KEY_SENDER
, sval
); 
 521                         case SOURCE_INTERNAL
: 
 524                                 asl_msg_set_key_val(msg
, ASL_KEY_SENDER
, sval
); 
 529                                 asl_msg_set_key_val(msg
, ASL_KEY_SENDER
, "Unknown"); 
 533         else if ((source 
!= SOURCE_KERN
) && (uid 
!= 0) && (!strcmp(sval
, "kernel"))) 
 535                 /* allow UID 0 to send messages with "Sender kernel", but nobody else */ 
 536                 asl_msg_set_key_val(msg
, ASL_KEY_SENDER
, "Unknown"); 
 541         fac 
= asl_msg_get_val_for_key(msg
, ASL_KEY_FACILITY
); 
 544                 if (source 
== SOURCE_KERN
) fac 
= "kern"; 
 546                 asl_msg_set_key_val(msg
, ASL_KEY_FACILITY
, fac
); 
 548         else if (fac
[0] == '#') 
 551                 if ((fac
[1] >= '0') && (fac
[1] <= '9')) 
 553                         fnum 
= atoi(fac 
+ 1) << 3; 
 554                         if ((fnum 
== 0) && (strcmp(fac 
+ 1, "0"))) fnum 
= LOG_USER
; 
 557                 fac 
= asl_syslog_faciliy_num_to_name(fnum
); 
 558                 asl_msg_set_key_val(msg
, ASL_KEY_FACILITY
, fac
); 
 560         else if (!strncmp(fac
, SYSTEM_RESERVED
, SYSTEM_RESERVED_LEN
)) 
 562                 /* only UID 0 may use "com.apple.system" */ 
 563                 if (uid 
!= 0) asl_msg_set_key_val(msg
, ASL_KEY_FACILITY
, FACILITY_USER
); 
 567          * kernel messages are only readable by root and admin group. 
 568          * all other messages are admin-only readable unless they already 
 569          * have specific read access controls set. 
 571         if (source 
== SOURCE_KERN
) 
 573                 asl_msg_set_key_val(msg
, ASL_KEY_READ_UID
, "0"); 
 574                 asl_msg_set_key_val(msg
, ASL_KEY_READ_GID
, "80"); 
 578                 ruval 
= asl_msg_get_val_for_key(msg
, ASL_KEY_READ_UID
); 
 579                 rgval 
= asl_msg_get_val_for_key(msg
, ASL_KEY_READ_GID
); 
 581                 if ((ruval 
== NULL
) && (rgval 
== NULL
)) 
 583                         asl_msg_set_key_val(msg
, ASL_KEY_READ_GID
, "80"); 
 587         /* Set DB Expire Time for com.apple.system.utmpx and lastlog */ 
 588         if ((!strcmp(fac
, "com.apple.system.utmpx")) || (!strcmp(fac
, "com.apple.system.lastlog"))) 
 590                 snprintf(buf
, sizeof(buf
), "%llu", (unsigned long long) tick 
+ global
.utmp_ttl
); 
 591                 asl_msg_set_key_val(msg
, ASL_KEY_EXPIRE_TIME
, buf
); 
 594         /* Set DB Expire Time for Filesystem errors */ 
 595         if (!strcmp(fac
, FSLOG_VAL_FACILITY
)) 
 597                 snprintf(buf
, sizeof(buf
), "%llu", (unsigned long long) tick 
+ FS_TTL_SEC
); 
 598                 asl_msg_set_key_val(msg
, ASL_KEY_EXPIRE_TIME
, buf
); 
 602          * special case handling of kernel disaster messages 
 604         if ((source 
== SOURCE_KERN
) && (level 
<= KERN_DISASTER_LEVEL
)) 
 606                 if (kern_post_level 
!= NULL
) *kern_post_level 
= level
; 
 607                 disaster_message(msg
); 
 611          * gather sender stats 
 613         if (source 
!= SOURCE_INTERNAL
) stats_msg(sval
, now
, msg
); 
 615         return VERIFY_STATUS_OK
; 
 619 list_append_msg(asl_msg_list_t 
*list
, asl_msg_t 
*msg
) 
 621         if (list 
== NULL
) return; 
 622         if (msg 
== NULL
) return; 
 625          * NB: curr is the list size 
 626          * grow list if necessary 
 628         if (list
->count 
== list
->curr
) 
 632                         list
->msg 
= (asl_msg_t 
**)calloc(LIST_SIZE_DELTA
, sizeof(asl_msg_t 
*)); 
 636                         list
->msg 
= (asl_msg_t 
**)reallocf(list
->msg
, (list
->curr 
+ LIST_SIZE_DELTA
) * sizeof(asl_msg_t 
*)); 
 639                 if (list
->msg 
== NULL
) 
 646                 list
->curr 
+= LIST_SIZE_DELTA
; 
 649         list
->msg
[list
->count
] = (asl_msg_t 
*)msg
; 
 658         OSSpinLockLock(&global
.lock
); 
 660         global
.pid 
= getpid(); 
 662         free(global
.debug_file
); 
 663         global
.debug_file 
= NULL
; 
 664         global
.launchd_enabled 
= 1; 
 666 #if TARGET_OS_EMBEDDED 
 667         global
.dbtype 
= DB_TYPE_MEMORY
; 
 669         global
.dbtype 
= DB_TYPE_FILE
; 
 671         global
.db_file_max 
= DEFAULT_DB_FILE_MAX
; 
 672         global
.db_memory_max 
= DEFAULT_DB_MEMORY_MAX
; 
 673         global
.db_memory_str_max 
= DEFAULT_DB_MEMORY_STR_MAX
; 
 674         global
.mps_limit 
= DEFAULT_MPS_LIMIT
; 
 675         global
.remote_delay_time 
= DEFAULT_REMOTE_DELAY
; 
 676         global
.bsd_max_dup_time 
= DEFAULT_BSD_MAX_DUP_SEC
; 
 677         global
.mark_time 
= DEFAULT_MARK_SEC
; 
 678         global
.utmp_ttl 
= DEFAULT_UTMP_TTL_SEC
; 
 679         global
.memory_max 
= DEFAULT_MEMORY_MAX
; 
 680         global
.stats_interval 
= DEFAULT_STATS_INTERVAL
; 
 682         global
.asl_out_module 
= asl_out_module_init(); 
 683         OSSpinLockUnlock(&global
.lock
); 
 685         if (global
.asl_out_module 
!= NULL
) 
 687                 for (r 
= global
.asl_out_module
->ruleset
; r 
!= NULL
; r 
= r
->next
) 
 689                         if ((r
->action 
== ACTION_SET_PARAM
) && (r
->query 
== NULL
) && (!strncmp(r
->options
, "debug", 5))) control_set_param(r
->options
, true); 
 695  * Used to set config parameters. 
 696  * Line format "= name value" 
 699 control_set_param(const char *s
, bool eval
) 
 702         uint32_t intval
, count
, v32a
, v32b
, v32c
; 
 704         if (s 
== NULL
) return -1; 
 705         if (s
[0] == '\0') return 0; 
 707         /* skip '=' and whitespace */ 
 709         while ((*s 
== ' ') || (*s 
== '\t')) s
++; 
 711         l 
= explode(s
, " \t"); 
 712         if (l 
== NULL
) return -1; 
 714         for (count 
= 0; l
[count
] != NULL
; count
++); 
 716         /* name is required */ 
 723         /* Check variables that allow 0 or 1 / boolean */ 
 724         if (!strcasecmp(l
[0], "debug")) 
 726                 /* = debug [0|1] [file] */ 
 729                         intval 
= (eval
) ? 1 : 0; 
 730                         config_debug(intval
, NULL
); 
 732                 else if (!strcmp(l
[1], "0")) 
 734                         config_debug(0, l
[2]); 
 736                 else if (!strcmp(l
[1], "1")) 
 738                         config_debug(1, l
[2]); 
 742                         intval 
= (eval
) ? 1 : 0; 
 743                         config_debug(intval
, l
[1]); 
 750         /* value is required */ 
 757         if (!strcasecmp(l
[0], "hostname")) 
 759                 /* = hostname name */ 
 760                 OSSpinLockLock(&global
.lock
); 
 763                         global
.hostname 
= strdup(l
[1]); 
 767                         free(global
.hostname
); 
 768                         global
.hostname 
= NULL
; 
 770                 OSSpinLockUnlock(&global
.lock
); 
 772         else if (!strcasecmp(l
[0], "mark_time")) 
 774                 /* = mark_time seconds */ 
 775                 OSSpinLockLock(&global
.lock
); 
 776                 if (eval
) global
.mark_time 
= atoll(l
[1]); 
 777                 else global
.mark_time 
= 0; 
 778                 OSSpinLockUnlock(&global
.lock
); 
 780         else if (!strcasecmp(l
[0], "dup_delay")) 
 782                 /* = bsd_max_dup_time seconds */ 
 783                 OSSpinLockLock(&global
.lock
); 
 784                 if (eval
) global
.bsd_max_dup_time 
= atoll(l
[1]); 
 785                 else global
.bsd_max_dup_time 
= DEFAULT_BSD_MAX_DUP_SEC
; 
 786                 OSSpinLockUnlock(&global
.lock
); 
 788         else if (!strcasecmp(l
[0], "remote_delay")) 
 790                 /* = remote_delay microseconds */ 
 791                 OSSpinLockLock(&global
.lock
); 
 792                 if (eval
) global
.remote_delay_time 
= atol(l
[1]); 
 793                 else global
.remote_delay_time 
= DEFAULT_REMOTE_DELAY
; 
 794                 OSSpinLockUnlock(&global
.lock
); 
 796         else if (!strcasecmp(l
[0], "utmp_ttl")) 
 798                 /* = utmp_ttl seconds */ 
 799                 OSSpinLockLock(&global
.lock
); 
 800                 if (eval
) global
.utmp_ttl 
= (time_t)atoll(l
[1]); 
 801                 else global
.utmp_ttl 
= DEFAULT_UTMP_TTL_SEC
; 
 802                 OSSpinLockUnlock(&global
.lock
); 
 804         else if (!strcasecmp(l
[0], "mps_limit")) 
 806                 /* = mps_limit number */ 
 807                 OSSpinLockLock(&global
.lock
); 
 808                 if (eval
) global
.mps_limit 
= (uint32_t)atol(l
[1]); 
 809                 else global
.mps_limit 
= DEFAULT_MPS_LIMIT
; 
 810                 OSSpinLockUnlock(&global
.lock
); 
 812         else if (!strcasecmp(l
[0], "memory_max")) 
 814                 /* = memory_max number */ 
 815                 OSSpinLockLock(&global
.lock
); 
 816                 if (eval
) global
.memory_max 
= (int64_t)atoll(l
[1]); 
 817                 else global
.memory_max 
= DEFAULT_MEMORY_MAX
; 
 818                 OSSpinLockUnlock(&global
.lock
); 
 820         else if (!strcasecmp(l
[0], "stats_interval")) 
 822                 /* = stats_interval number */ 
 823                 OSSpinLockLock(&global
.lock
); 
 824                 if (eval
) global
.stats_interval 
= (time_t)atoll(l
[1]); 
 825                 else global
.stats_interval 
= DEFAULT_STATS_INTERVAL
; 
 826                 OSSpinLockUnlock(&global
.lock
); 
 828         else if (!strcasecmp(l
[0], "max_file_size")) 
 830                 /* = max_file_size bytes */ 
 831                 pthread_mutex_lock(global
.db_lock
); 
 833                 if (global
.dbtype 
& DB_TYPE_FILE
) 
 835                         asl_store_close(global
.file_db
); 
 836                         global
.file_db 
= NULL
; 
 837                         if (eval
) global
.db_file_max 
= atoi(l
[1]); 
 838                         else global
.db_file_max 
= DEFAULT_DB_FILE_MAX
; 
 841                 pthread_mutex_unlock(global
.db_lock
); 
 843         else if ((!strcasecmp(l
[0], "db")) || (!strcasecmp(l
[0], "database")) || (!strcasecmp(l
[0], "datastore"))) 
 845                 /* NB this is private / unpublished */ 
 846                 /* = db type [max]... */ 
 853                         if ((l
[1][0] >= '0') && (l
[1][0] <= '9')) 
 856                                 if ((count 
>= 3) && (strcmp(l
[2], "-"))) v32a 
= atoi(l
[2]); 
 857                                 if ((count 
>= 4) && (strcmp(l
[3], "-"))) v32b 
= atoi(l
[3]); 
 858                                 if ((count 
>= 5) && (strcmp(l
[4], "-"))) v32c 
= atoi(l
[4]); 
 860                         else if (!strcasecmp(l
[1], "file")) 
 862                                 intval 
= DB_TYPE_FILE
; 
 863                                 if ((count 
>= 3) && (strcmp(l
[2], "-"))) v32a 
= atoi(l
[2]); 
 865                         else if (!strncasecmp(l
[1], "mem", 3)) 
 867                                 intval 
= DB_TYPE_MEMORY
; 
 868                                 if ((count 
>= 3) && (strcmp(l
[2], "-"))) v32b 
= atoi(l
[2]); 
 876                         if (v32a 
== 0) v32a 
= global
.db_file_max
; 
 877                         if (v32b 
== 0) v32b 
= global
.db_memory_max
; 
 878                         if (v32c 
== 0) v32c 
= global
.db_memory_str_max
; 
 880                         config_data_store(intval
, v32a
, v32b
, v32c
); 
 884 #if TARGET_OS_EMBEDDED 
 885                         intval 
= DB_TYPE_MEMORY
; 
 887                         intval 
= DB_TYPE_FILE
; 
 889                         config_data_store(intval
, DEFAULT_DB_FILE_MAX
, DEFAULT_DB_MEMORY_MAX
, DEFAULT_DB_MEMORY_STR_MAX
); 
 898 control_message(asl_msg_t 
*msg
) 
 900         const char *str 
= asl_msg_get_val_for_key(msg
, ASL_KEY_MSG
); 
 902         if (str 
== NULL
) return 0; 
 904         if (!strncmp(str
, "= reset", 7)) 
 907                 return asl_action_reset(); 
 909         else if (!strncmp(str
, "= crash", 7)) 
 913         else if (!strncmp(str
, "@ ", 2)) 
 915                 return asl_action_control_set_param(str
); 
 917         else if (!strncmp(str
, "= ", 2)) 
 919                 return control_set_param(str
, true); 
 926 process_message(asl_msg_t 
*msg
, uint32_t source
) 
 929         static bool wq_draining 
= false; 
 930         bool is_control 
= false; 
 933         if (msg 
== NULL
) return; 
 935         is_control 
= asl_check_option(msg
, ASL_OPT_CONTROL
) != 0; 
 937         if ((!is_control
) && wq_draining
) 
 939                 if (global
.memory_size 
>= (global
.memory_max 
/ 2)) 
 941                         asldebug("Work queue draining: dropped message.\n"); 
 942                         asl_msg_release(msg
); 
 947                         asldebug("Work queue re-enabled at 1/2 max.  size %lld  max %lld\n", global
.memory_size
, global
.memory_max
); 
 952         __block vproc_transaction_t vt 
= vproc_transaction_begin(NULL
); 
 954         for (x 
= msg
; x 
!= NULL
; x 
= x
->next
) msize 
+= x
->mem_size
; 
 956         if ((global
.memory_size 
+ msize
) >= global
.memory_max
) 
 961                 asl_msg_release(msg
); 
 963                 asldebug("Work queue disabled.  msize %lld  size %lld  max %lld\n", msize
, global
.memory_size 
+ msize
, global
.memory_max
); 
 964                 snprintf(str
, sizeof(str
), "[Sender syslogd] [Level 2] [PID %u] [Message Internal memory size limit %lld exceeded - dropping messages] [UID 0] [UID 0] [Facility syslog]", global
.pid
, global
.memory_max
); 
 965                 msg 
= asl_msg_from_string(str
); 
 968         OSAtomicAdd64(msize
, &global
.memory_size
); 
 969         OSAtomicIncrement32(&global
.work_queue_count
); 
 971         dispatch_async(global
.work_queue
, ^{ 
 979                 status 
= aslmsg_verify(msg
, source
, &kplevel
, &uid
); 
 980                 if (status 
== VERIFY_STATUS_OK
) 
 982                         if ((source 
== SOURCE_KERN
) && (kplevel 
>= 0)) 
 984                                 if (kplevel 
> 7) kplevel 
= 7; 
 985                                 if (kern_notify_token
[kplevel
] < 0) 
 987                                         status 
= notify_register_plain(kern_notify_key
[kplevel
], &(kern_notify_token
[kplevel
])); 
 988                                         if (status 
!= 0) asldebug("notify_register_plain(%s) failed status %u\n", status
); 
 991                                 notify_post(kern_notify_key
[kplevel
]); 
 994                         if ((uid 
== 0) && is_control
) control_message(msg
); 
 997                          * Send message to output module chain (asl is first). 
 998                          * The last module in the chain will decrement global.memory_size. 
1000                         asl_out_message(msg
, msize
); 
1004                         OSAtomicAdd64(-1ll * msize
, &global
.memory_size
); 
1007                 asl_msg_release(msg
); 
1009                 OSAtomicDecrement32(&global
.work_queue_count
); 
1010                 vproc_transaction_end(NULL
, vt
); 
1015 internal_log_message(const char *str
) 
1019         if (str 
== NULL
) return 1; 
1021         msg 
= asl_msg_from_string(str
); 
1022         if (msg 
== NULL
) return 1; 
1024         process_message(msg
, SOURCE_INTERNAL
); 
1030 asldebug(const char *str
, ...) 
1035         if (global
.debug 
== 0) return 0; 
1037         if (global
.debug_file 
== NULL
) dfp 
= fopen(_PATH_SYSLOGD_LOG
, "a"); 
1038         else dfp 
= fopen(global
.debug_file
, "a"); 
1039         if (dfp 
== NULL
) return 0; 
1042         fprintf(dfp
, "W %d %llu", global
.work_queue_count
, global
.memory_size
); 
1043         if (global
.memory_db 
!= NULL
) fprintf(dfp
, "   M %u %u %lu", global
.memory_db
->record_count
, global
.memory_db
->string_count
, global
.memory_db
->curr_string_mem
); 
1044         fprintf(dfp
, " ; "); 
1045         vfprintf(dfp
, str
, v
); 
1058         asprintf(&str
, "[Sender syslogd] [Level 6] [PID %u] [Message -- MARK --] [UID 0] [UID 0] [Facility syslog]", global
.pid
); 
1059         internal_log_message(str
); 
1064 asl_syslog_input_convert(const char *in
, int len
, char *rhost
, uint32_t source
) 
1066         int pf
, pri
, index
, n
; 
1067         char *p
, *colon
, *brace
, *space
, *tmp
, *tval
, *hval
, *sval
, *pval
, *mval
; 
1074         if (in 
== NULL
) return NULL
; 
1075         if (len 
<= 0) return NULL
; 
1078         if (source 
== SOURCE_KERN
) pri 
= LOG_NOTICE
; 
1090         /* skip leading whitespace */ 
1091         while ((index 
< len
) && ((*p 
== ' ') || (*p 
== '\t'))) 
1097         if (index 
>= len
) return NULL
; 
1099         /* parse "<NN>" priority (level and facility) */ 
1105                 n 
= sscanf(p
, "%d", &pf
); 
1109                         if (pf 
> 0x7) fval 
= asl_syslog_faciliy_num_to_name(pf 
& LOG_FACMASK
); 
1112                 while ((index 
< len
) && (*p 
!= '>')) 
1125         snprintf(prival
, sizeof(prival
), "%d", pri
); 
1127         /* check if a timestamp is included */ 
1128         if (((len 
- index
) > 15) && (p
[9] == ':') && (p
[12] == ':') && (p
[15] == ' ')) 
1131                 if (tmp 
== NULL
) return NULL
; 
1136                 tick 
= asl_core_parse_time(tmp
, NULL
); 
1137                 if (tick 
== (time_t)-1) 
1144                         gmtime_r(&tick
, &time
); 
1145                         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
); 
1152         /* stop here for kernel messages */ 
1153         if (source 
== SOURCE_KERN
) 
1155                 msg 
= asl_msg_new(ASL_TYPE_MSG
); 
1156                 if (msg 
== NULL
) return NULL
; 
1158                 asl_msg_set_key_val(msg
, ASL_KEY_MSG
, p
); 
1159                 asl_msg_set_key_val(msg
, ASL_KEY_LEVEL
, prival
); 
1160                 asl_msg_set_key_val(msg
, ASL_KEY_PID
, "0"); 
1165         /* if message is from a network socket, hostname follows */ 
1166         if (source 
== SOURCE_UDP_SOCKET
) 
1168                 space 
= strchr(p
, ' '); 
1172                         hval 
= malloc(n 
+ 1); 
1173                         if (hval 
== NULL
) return NULL
; 
1183         colon 
= strchr(p
, ':'); 
1184         brace 
= strchr(p
, '['); 
1186         /* check for "sender:" or sender[pid]:"  */ 
1189                 if ((brace 
!= NULL
) && (brace 
< colon
)) 
1192                         sval 
= malloc(n 
+ 1); 
1193                         if (sval 
== NULL
) return NULL
; 
1198                         n 
= colon 
- (brace 
+ 1) - 1; 
1199                         pval 
= malloc(n 
+ 1); 
1200                         if (pval 
== NULL
) return NULL
; 
1202                         memcpy(pval
, (brace 
+ 1), n
); 
1208                         sval 
= malloc(n 
+ 1); 
1209                         if (sval 
== NULL
) return NULL
; 
1229                 mval 
= malloc(n 
+ 1); 
1230                 if (mval 
== NULL
) return NULL
; 
1236         if (fval 
== NULL
) fval 
= asl_syslog_faciliy_num_to_name(LOG_USER
); 
1238         msg 
= asl_msg_new(ASL_TYPE_MSG
); 
1239         if (msg 
== NULL
) return NULL
; 
1243                 asl_msg_set_key_val(msg
, ASL_KEY_TIME
, tval
); 
1247         if (fval 
!= NULL
) asl_msg_set_key_val(msg
, "Facility", fval
); 
1248         else asl_msg_set_key_val(msg
, "Facility", "user"); 
1252                 asl_msg_set_key_val(msg
, ASL_KEY_SENDER
, sval
); 
1258                 asl_msg_set_key_val(msg
, ASL_KEY_PID
, pval
); 
1263                 asl_msg_set_key_val(msg
, ASL_KEY_PID
, "-1"); 
1268                 asl_msg_set_key_val(msg
, ASL_KEY_MSG
, mval
); 
1272         asl_msg_set_key_val(msg
, ASL_KEY_LEVEL
, prival
); 
1273         asl_msg_set_key_val(msg
, ASL_KEY_UID
, "-2"); 
1274         asl_msg_set_key_val(msg
, ASL_KEY_GID
, "-2"); 
1278                 asl_msg_set_key_val(msg
, ASL_KEY_HOST
, hval
); 
1281         else if (rhost 
!= NULL
) 
1283                 asl_msg_set_key_val(msg
, ASL_KEY_HOST
, rhost
); 
1290 asl_input_parse(const char *in
, int len
, char *rhost
, uint32_t source
) 
1293         int status
, x
, legacy
, off
; 
1295         asldebug("asl_input_parse: %s\n", (in 
== NULL
) ? "NULL" : in
); 
1297         if (in 
== NULL
) return NULL
; 
1302         /* calculate length if not provided */ 
1303         if (len 
== 0) len 
= strlen(in
); 
1306          * Determine if the input is "old" syslog format or new ASL format. 
1307          * Old format lines should start with "<", but they can just be straight text. 
1308          * ASL input may start with a length (10 bytes) followed by a space and a '['. 
1309          * The length is optional, so ASL messages may also just start with '['. 
1311         if ((in
[0] != '<') && (len 
> 11)) 
1313                 status 
= sscanf(in
, "%d ", &x
); 
1314                 if ((status 
== 1) && (in
[10] == ' ') && (in
[11] == '[')) legacy 
= 0; 
1317         if (legacy 
== 1) return asl_syslog_input_convert(in
, len
, rhost
, source
); 
1320         if (in
[0] == '[') off 
= 0; 
1322         msg 
= asl_msg_from_string(in 
+ off
); 
1323         if (msg 
== NULL
) return NULL
; 
1325         if (rhost 
!= NULL
) asl_msg_set_key_val(msg
, ASL_KEY_HOST
, rhost
); 
1330 #if !TARGET_IPHONE_SIMULATOR 
1332 launchd_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
) 
1338         if (global
.launchd_enabled 
== 0) return; 
1341         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", 
1342         when->tv_sec, when->tv_usec, from_pid, about_pid, sender_uid, sender_gid, priority, from_name, about_name, session_name, msg); 
1345         m 
= asl_msg_new(ASL_TYPE_MSG
); 
1346         if (m 
== NULL
) return; 
1349         if (priority 
< ASL_LEVEL_EMERG
) priority 
= ASL_LEVEL_EMERG
; 
1350         if (priority 
> ASL_LEVEL_DEBUG
) priority 
= ASL_LEVEL_DEBUG
; 
1351         snprintf(str
, sizeof(str
), "%d", priority
); 
1353         asl_msg_set_key_val(m
, ASL_KEY_LEVEL
, str
); 
1358                 snprintf(str
, sizeof(str
), "%llu", (unsigned long long) when
->tv_sec
); 
1359                 asl_msg_set_key_val(m
, ASL_KEY_TIME
, str
); 
1361                 snprintf(str
, sizeof(str
), "%lu", 1000 * (unsigned long int)when
->tv_usec
); 
1362                 asl_msg_set_key_val(m
, ASL_KEY_TIME_NSEC
, str
); 
1367                 snprintf(str
, sizeof(str
), "%llu", (unsigned long long) now
); 
1368                 asl_msg_set_key_val(m
, ASL_KEY_TIME
, str
); 
1372         asl_msg_set_key_val(m
, ASL_KEY_FACILITY
, FACILITY_CONSOLE
); 
1375         snprintf(str
, sizeof(str
), "%u", (unsigned int)sender_uid
); 
1376         asl_msg_set_key_val(m
, ASL_KEY_UID
, str
); 
1379         snprintf(str
, sizeof(str
), "%u", (unsigned int)sender_gid
); 
1380         asl_msg_set_key_val(m
, ASL_KEY_GID
, str
); 
1385                 snprintf(str
, sizeof(str
), "%u", (unsigned int)from_pid
); 
1386                 asl_msg_set_key_val(m
, ASL_KEY_PID
, str
); 
1390         if ((about_pid 
> 0) && (about_pid 
!= from_pid
)) 
1392                 snprintf(str
, sizeof(str
), "%u", (unsigned int)about_pid
); 
1393                 asl_msg_set_key_val(m
, ASL_KEY_REF_PID
, str
); 
1397         if (from_name 
!= NULL
) 
1399                 asl_msg_set_key_val(m
, ASL_KEY_SENDER
, from_name
); 
1403         if (sender_uid 
!= 0) 
1405                 snprintf(str
, sizeof(str
), "%d", (int)sender_uid
); 
1406                 asl_msg_set_key_val(m
, ASL_KEY_READ_UID
, str
); 
1409         /* Reference Process */ 
1410         if (about_name 
!= NULL
) 
1412                 if ((from_name 
!= NULL
) && (strcmp(from_name
, about_name
) != 0)) 
1414                         asl_msg_set_key_val(m
, ASL_KEY_REF_PROC
, about_name
); 
1419         if (session_name 
!= NULL
) 
1421                 asl_msg_set_key_val(m
, ASL_KEY_SESSION
, session_name
); 
1427                 asl_msg_set_key_val(m
, ASL_KEY_MSG
, msg
); 
1430         process_message(m
, SOURCE_LAUNCHD
);