]> git.saurik.com Git - apple/syslog.git/blame - libsystem_asl.tproj/src/asl.c
syslog-323.50.1.tar.gz
[apple/syslog.git] / libsystem_asl.tproj / src / asl.c
CommitLineData
81582353 1/*
5222c21d 2 * Copyright (c) 2004-2015 Apple Inc. All rights reserved.
81582353
A
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
81582353
A
24#include <string.h>
25#include <stdint.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <ctype.h>
29#include <unistd.h>
30#include <stdarg.h>
31#include <syslog.h>
32#include <errno.h>
33#include <limits.h>
34#include <time.h>
f3df4c03 35#include <sys/stat.h>
81582353
A
36#include <sys/time.h>
37#include <sys/fcntl.h>
f3df4c03
A
38#include <sys/param.h>
39#include <sys/fileport.h>
81582353
A
40#include <crt_externs.h>
41#include <asl.h>
42#include <regex.h>
43#include <notify.h>
44#include <mach/mach.h>
45#include <mach/std_types.h>
46#include <mach/mig.h>
47#include <mach/mach_types.h>
48#include <sys/types.h>
49#include <servers/bootstrap.h>
50#include <bootstrap_priv.h>
51#include <pthread.h>
52#include <dispatch/dispatch.h>
53#include <libkern/OSAtomic.h>
f3df4c03 54#include <os/activity.h>
5222c21d
A
55#include <os/trace.h>
56#include <os/log_private.h>
81582353 57#include <asl_ipc.h>
f3df4c03
A
58#include <asl_client.h>
59#include <asl_core.h>
60#include <asl_msg.h>
61#include <asl_msg_list.h>
62#include <asl_store.h>
63#include <asl_private.h>
81582353
A
64
65#define forever for(;;)
66
67#define FETCH_BATCH 256
68
5222c21d
A
69#define EVAL_DEFAULT_ACTION (EVAL_SEND_ASL | EVAL_SEND_TRACE)
70#define EVAL_ASL (EVAL_SEND_ASL | EVAL_TEXT_FILE | EVAL_ASL_FILE)
81582353
A
71
72/*
73 * Clients get a max of 36000 messages per hour.
74 * Their quota gets refilled at a rate of 10 messages per second.
75 */
76#define QUOTA_MPH 36000
77#define QUOTA_MPS 10
78#define QUOTA_MSG_INTERVAL 60
f3df4c03
A
79#define NOQUOTA_ENV "ASL_QUOTA_DISABLED"
80#define QUOTA_DISABLED_MSG "*** MESSAGE QUOTA DISABLED FOR THIS PROCESS ***"
81582353 81#define QUOTA_MSG "*** LOG MESSAGE QUOTA EXCEEDED - SOME MESSAGES FROM THIS PROCESS HAVE BEEN DISCARDED ***"
5222c21d
A
82#define QUOTA_LEVEL ASL_LEVEL_CRIT
83#define QUOTA_LEVEL_STR ASL_STRING_CRIT
84
85/*
86 * Limit the size of messages sent to syslogd.
87 */
88#define SIZE_LIMIT_MSG "*** ASL MESSAGE SIZE (%u bytes) EXCEEDED MAXIMIMUM SIZE (%u bytes) ***"
89
90static const uint8_t shim_asl_to_trace_type[8] = {
91 OS_TRACE_TYPE_FAULT, OS_TRACE_TYPE_FAULT, OS_TRACE_TYPE_FAULT, // Emergency, Alert, Critical
92 OS_TRACE_TYPE_ERROR, // Error
93 OS_TRACE_TYPE_RELEASE, OS_TRACE_TYPE_RELEASE, OS_TRACE_TYPE_RELEASE, // Warning, Notice, Info
94 OS_TRACE_TYPE_DEBUG // Debug
95};
96
81582353
A
97
98/* forward */
f3df4c03 99static ASL_STATUS _asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *mstring);
81582353
A
100__private_extern__ asl_client_t *_asl_open_default();
101
81582353
A
102/* notify SPI */
103uint32_t notify_register_plain(const char *name, int *out_token);
104
f3df4c03
A
105/* fork handling in asl_fd.c */
106extern void _asl_redirect_fork_child(void);
81582353
A
107
108typedef struct
109{
110 int fd;
111 asl_msg_t *msg;
112 dispatch_semaphore_t sem;
113} asl_aux_context_t;
114
115typedef struct
116{
117 int notify_count;
118 int rc_change_token;
119 int notify_token;
120 int master_token;
121 uint64_t proc_filter;
122 uint64_t master_filter;
123 time_t last_send;
124 time_t last_oq_msg;
125 uint32_t quota;
81582353
A
126 mach_port_t server_port;
127 char *sender;
128 pthread_mutex_t lock;
129 int aux_count;
130 asl_aux_context_t **aux_ctx;
131 asl_client_t *asl;
132} _asl_global_t;
133
f3df4c03 134__private_extern__ _asl_global_t _asl_global = {0, -1, -1, -1, 0LL, 0LL, 0LL, 0LL, 0, MACH_PORT_NULL, NULL, PTHREAD_MUTEX_INITIALIZER, 0, NULL, NULL};
81582353 135
f3df4c03 136static const char *level_to_number_string[] = {"0", "1", "2", "3", "4", "5", "6", "7"};
81582353
A
137
138#define ASL_SERVICE_NAME "com.apple.system.logger"
139
140/*
141 * Called from the child process inside fork() to clean up
142 * inherited state from the parent process.
143 *
144 * NB. A lock isn't required, since we're single threaded in this call.
145 */
146void
147_asl_fork_child()
148{
149 _asl_global.notify_count = 0;
150 _asl_global.rc_change_token = -1;
151 _asl_global.master_token = -1;
152 _asl_global.notify_token = -1;
153 _asl_global.quota = 0;
154 _asl_global.last_send = 0;
155 _asl_global.last_oq_msg = 0;
156
81582353
A
157 _asl_global.server_port = MACH_PORT_NULL;
158
159 pthread_mutex_init(&(_asl_global.lock), NULL);
f3df4c03
A
160
161 _asl_redirect_fork_child();
81582353
A
162}
163
164/*
165 * asl_remote_notify_name: returns the notification key for remote-control filter
166 * changes for this process.
167 */
168char *
169asl_remote_notify_name()
170{
171 pid_t pid = getpid();
172 uid_t euid = geteuid();
173 char *str = NULL;
174
175 if (euid == 0) asprintf(&str, "%s.%d", NOTIFY_PREFIX_SYSTEM, pid);
176 else asprintf(&str, "user.uid.%d.syslog.%d", euid, pid);
177
178 return str;
179}
180
f3df4c03 181static ASL_STATUS
81582353
A
182_asl_notify_open(int do_lock)
183{
184 char *notify_name;
185 uint32_t status;
186
187 if (do_lock != 0) pthread_mutex_lock(&_asl_global.lock);
188
189 _asl_global.notify_count++;
190
191 if (_asl_global.notify_token != -1)
192 {
193 if (do_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
f3df4c03 194 return ASL_STATUS_OK;
81582353
A
195 }
196
197 if (_asl_global.rc_change_token == -1)
198 {
199 status = notify_register_check(NOTIFY_RC, &_asl_global.rc_change_token);
200 if (status != NOTIFY_STATUS_OK) _asl_global.rc_change_token = -1;
201 }
202
203 if (_asl_global.master_token == -1)
204 {
205 status = notify_register_plain(NOTIFY_SYSTEM_MASTER, &_asl_global.master_token);
206 if (status != NOTIFY_STATUS_OK) _asl_global.master_token = -1;
207 }
208
209 notify_name = asl_remote_notify_name();
210 if (notify_name != NULL)
211 {
212 status = notify_register_plain(notify_name, &_asl_global.notify_token);
213 free(notify_name);
214 if (status != NOTIFY_STATUS_OK) _asl_global.notify_token = -1;
215 }
216
217 if (do_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
218
f3df4c03
A
219 if (_asl_global.notify_token == -1) return ASL_STATUS_FAILED;
220 return ASL_STATUS_OK;
81582353
A
221}
222
f3df4c03 223#ifdef UNDEF
81582353
A
224static void
225_asl_notify_close()
226{
227 pthread_mutex_lock(&_asl_global.lock);
228
229 if (_asl_global.notify_count > 0) _asl_global.notify_count--;
230
231 if (_asl_global.notify_count > 0)
232 {
233 pthread_mutex_unlock(&_asl_global.lock);
234 return;
235 }
236
237 if (_asl_global.rc_change_token >= 0) notify_cancel(_asl_global.rc_change_token);
238 _asl_global.rc_change_token = -1;
239
240 if (_asl_global.master_token >= 0) notify_cancel(_asl_global.master_token);
241 _asl_global.master_token = -1;
242
243 if (_asl_global.notify_token >= 0) notify_cancel(_asl_global.notify_token);
244 _asl_global.notify_token = -1;
245
246 pthread_mutex_unlock(&_asl_global.lock);
247}
f3df4c03 248#endif
81582353
A
249
250static void
f3df4c03 251_asl_global_init(int reset)
81582353 252{
f3df4c03 253 _asl_global.server_port = asl_core_get_service_port(reset);
81582353
A
254}
255
f3df4c03
A
256#pragma mark -
257#pragma mark asl_client
81582353 258
f3df4c03 259asl_object_t
81582353
A
260asl_open(const char *ident, const char *facility, uint32_t opts)
261{
f3df4c03
A
262 asl_client_t *asl = asl_client_open(ident, facility, opts);
263 if (asl == NULL) return NULL;
81582353 264
f3df4c03
A
265 _asl_global_init(0);
266 if (!(opts & ASL_OPT_NO_REMOTE)) _asl_notify_open(1);
81582353 267
f3df4c03 268 return (asl_object_t)asl;
81582353
A
269}
270
f3df4c03 271asl_object_t
81582353
A
272asl_open_from_file(int fd, const char *ident, const char *facility)
273{
f3df4c03 274 return (asl_object_t)asl_client_open_from_file(fd, ident, facility);
81582353
A
275}
276
277void
f3df4c03 278asl_close(asl_object_t obj)
81582353 279{
f3df4c03 280 asl_release(obj);
81582353
A
281}
282
283__private_extern__ asl_client_t *
284_asl_open_default()
285{
286 static dispatch_once_t once;
287
288 dispatch_once(&once, ^{
289 /*
290 * Do a sleight-of-hand with ASL_OPT_NO_REMOTE to avoid a deadlock
291 * since asl_open(xxx, yyy, 0) calls _asl_notify_open(1)
292 * which locks _asl_global.lock.
293 */
f3df4c03 294 _asl_global.asl = (asl_client_t *)asl_open(NULL, NULL, ASL_OPT_NO_REMOTE);
81582353
A
295
296 /* Reset options to clear ASL_OPT_NO_REMOTE bit */
297 if (_asl_global.asl != NULL) _asl_global.asl->options = 0;
298
299 /* Now call _asl_notify_open(0) to finish the work */
300 _asl_notify_open(0);
301 });
302
303 return _asl_global.asl;
304}
305
306/*
307 * asl_add_file: write log messages to the given file descriptor
308 * Log messages will be written to this file as well as to the server.
309 */
310int
f3df4c03 311asl_add_output_file(asl_object_t client, int fd, const char *mfmt, const char *tfmt, int filter, int text_encoding)
81582353 312{
f3df4c03 313 int status, use_global_lock = 0;
81582353
A
314 asl_client_t *asl;
315
f3df4c03
A
316 if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT)) return -1;
317
318 asl = (asl_client_t *)client;
81582353
A
319 if (asl == NULL)
320 {
321 asl = _asl_open_default();
322 if (asl == NULL) return -1;
323 pthread_mutex_lock(&_asl_global.lock);
324 use_global_lock = 1;
325 }
326
f3df4c03 327 status = asl_client_add_output_file(asl, fd, mfmt, tfmt, filter, text_encoding);
81582353
A
328
329 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
f3df4c03 330 return (status == ASL_STATUS_OK) ? 0 : -1;
81582353
A
331}
332
f3df4c03 333/* returns previous filter value or -1 on error */
81582353 334int
f3df4c03 335asl_set_output_file_filter(asl_object_t client, int fd, int filter)
81582353 336{
f3df4c03
A
337 uint32_t last;
338 int use_global_lock = 0;
81582353
A
339 asl_client_t *asl;
340
f3df4c03
A
341 if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT)) return -1;
342
343 asl = (asl_client_t *)client;
81582353
A
344 if (asl == NULL)
345 {
346 asl = _asl_open_default();
347 if (asl == NULL) return -1;
348 pthread_mutex_lock(&_asl_global.lock);
349 use_global_lock = 1;
350 }
351
f3df4c03 352 last = asl_client_set_output_file_filter(asl, fd, filter);
81582353
A
353
354 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
355 return last;
356}
357
358/* SPI - Deprecated */
359int
f3df4c03 360asl_add_output(asl_object_t client, int fd, const char *mfmt, const char *tfmt, uint32_t text_encoding)
81582353 361{
f3df4c03 362 return asl_add_output_file(client, fd, mfmt, tfmt, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG), text_encoding);
81582353
A
363}
364
f3df4c03 365/* SPI - Deprecated */
81582353 366int
f3df4c03 367asl_add_log_file(asl_object_t client, int fd)
81582353 368{
f3df4c03 369 return asl_add_output_file(client, fd, ASL_MSG_FMT_STD, ASL_TIME_FMT_LCL, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG), ASL_ENCODE_SAFE);
81582353
A
370}
371
372/*
373 * asl_remove_output: stop writing log messages to the given file descriptor
374 */
375int
f3df4c03 376asl_remove_output_file(asl_object_t client, int fd)
81582353 377{
f3df4c03 378 int status, use_global_lock = 0;
81582353
A
379 asl_client_t *asl;
380
f3df4c03
A
381 if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT)) return -1;
382
383 asl = (asl_client_t *)client;
81582353
A
384 if (asl == NULL)
385 {
386 asl = _asl_open_default();
387 if (asl == NULL) return -1;
388 pthread_mutex_lock(&_asl_global.lock);
389 use_global_lock = 1;
390 }
391
f3df4c03 392 status = asl_client_remove_output_file(asl, fd);
81582353
A
393
394 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
f3df4c03 395 return (status == ASL_STATUS_OK) ? 0 : -1;
81582353
A
396}
397
398int
f3df4c03 399asl_remove_output(asl_object_t client, int fd)
81582353 400{
f3df4c03 401 return asl_remove_output_file(client, fd);
81582353
A
402}
403
404int
f3df4c03 405asl_remove_log_file(asl_object_t client, int fd)
81582353 406{
f3df4c03 407 return asl_remove_output_file(client, fd);
81582353
A
408}
409
f3df4c03 410/* returns previous filter value or -1 on error */
81582353 411int
f3df4c03 412asl_set_filter(asl_object_t client, int f)
81582353 413{
f3df4c03 414 int last, use_global_lock = 0;
81582353
A
415 asl_client_t *asl;
416
f3df4c03
A
417 if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT)) return -1;
418
419 asl = (asl_client_t *)client;
81582353
A
420 if (asl == NULL)
421 {
422 asl = _asl_open_default();
423 if (asl == NULL) return -1;
424 pthread_mutex_lock(&_asl_global.lock);
425 use_global_lock = 1;
426 }
427
f3df4c03 428 last = asl_client_set_filter(asl, f);
81582353
A
429
430 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
431 return last;
432}
433
f3df4c03
A
434
435#pragma mark -
436#pragma mark message sending
437
81582353
A
438/*
439 * Evaluate client / message / level to determine what to do with a message.
5222c21d
A
440 * Checks filters, tunneling, and log files.
441 * Returns the bits below, ORed with the message level.
81582353 442 *
5222c21d
A
443 * EVAL_SEND_ASL - send this message to syslogd
444 * EVAL_SEND_TRACE - log this message with Activity Tracing
445 * EVAL_ASL_FILE - write to a standalone ASL file (see asl_open_from_file)
446 * EVAL_TEXT_FILE - write this message to a text file / stderr
447 * EVAL_TUNNEL - tunneling enabled when sending to syslogd
81582353
A
448 */
449uint32_t
f3df4c03 450_asl_evaluate_send(asl_object_t client, asl_object_t m, int slevel)
81582353 451{
f3df4c03
A
452 asl_client_t *asl;
453 asl_msg_t *msg = (asl_msg_t *)m;
81582353 454 uint32_t level, lmask, filter, status, tunnel;
f3df4c03 455 int check;
81582353
A
456 uint64_t v64;
457 const char *val;
5222c21d 458 uint32_t eval;
81582353 459
f3df4c03
A
460 level = ASL_LEVEL_DEBUG;
461 if (slevel >= 0) level = slevel;
5222c21d 462
f3df4c03
A
463 val = NULL;
464 if ((asl_msg_lookup(msg, ASL_KEY_LEVEL, &val, NULL) == 0) && (val != NULL)) level = atoi(val);
5222c21d 465
f3df4c03
A
466 if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
467 else if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
468
469 if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT))
470 {
471 /* sending to something other than a client */
5222c21d 472 return EVAL_ACTIVE | EVAL_SEND_ASL | level;
f3df4c03
A
473 }
474
475 asl = (asl_client_t *)client;
5222c21d
A
476 if ((asl != NULL) && (asl->aslfile != NULL)) return (EVAL_ASL_FILE | level);
477
478 if (asl == NULL) asl = _asl_open_default();
81582353
A
479 if (asl == NULL)
480 {
5222c21d
A
481 eval = EVAL_ACTIVE | EVAL_DEFAULT_ACTION | level;
482 eval &= ~EVAL_SEND_ASL;
483 return eval;
81582353
A
484 }
485
5222c21d 486 eval = (asl_client_get_control(asl) & EVAL_ACTION_MASK) | level;
81582353
A
487
488 filter = asl->filter & 0xff;
489 tunnel = (asl->filter & ASL_FILTER_MASK_TUNNEL) >> 8;
5222c21d
A
490 if (tunnel != 0) eval |= EVAL_TUNNEL;
491
492 /* don't send MessageTracer messages to Activity Tracing */
493 val = NULL;
494 if ((asl_msg_lookup(msg, ASL_KEY_MESSAGETRACER, &val, NULL) == 0) && (val != NULL)) eval &= ~EVAL_SEND_TRACE;
f3df4c03 495
5222c21d 496 if ((asl->options & ASL_OPT_NO_REMOTE) == 0)
81582353
A
497 {
498 pthread_mutex_lock(&_asl_global.lock);
499
500 if (_asl_global.rc_change_token >= 0)
501 {
502 /* initialize or re-check process-specific and master filters */
503 check = 0;
504 status = notify_check(_asl_global.rc_change_token, &check);
505 if ((status == NOTIFY_STATUS_OK) && (check != 0))
506 {
507 if (_asl_global.master_token >= 0)
508 {
509 v64 = 0;
510 status = notify_get_state(_asl_global.master_token, &v64);
511 if (status == NOTIFY_STATUS_OK) _asl_global.master_filter = v64;
512 }
513
514 if (_asl_global.notify_token >= 0)
515 {
516 v64 = 0;
517 status = notify_get_state(_asl_global.notify_token, &v64);
518 if (status == NOTIFY_STATUS_OK) _asl_global.proc_filter = v64;
519 }
520 }
521 }
522
5222c21d 523 if (_asl_global.master_filter & EVAL_ACTIVE)
81582353 524 {
5222c21d
A
525 /* clear bits and set according to master */
526 eval &= ~(EVAL_SEND_ASL | EVAL_SEND_TRACE);
527 eval |= (_asl_global.master_filter & (EVAL_SEND_ASL | EVAL_SEND_TRACE));
528 eval |= EVAL_TUNNEL;
81582353 529
5222c21d 530 if ((_asl_global.master_filter & EVAL_LEVEL_MASK) != 0) filter = _asl_global.proc_filter & EVAL_LEVEL_MASK;
81582353 531 }
81582353 532
5222c21d
A
533 if (_asl_global.proc_filter & EVAL_ACTIVE)
534 {
535 /* clear bits and set according to proc */
536 eval &= ~(EVAL_SEND_ASL | EVAL_SEND_TRACE | EVAL_TEXT_FILE);
537 eval |= (_asl_global.proc_filter & (EVAL_SEND_ASL | EVAL_SEND_TRACE | EVAL_TEXT_FILE));
538 eval |= EVAL_TUNNEL;
81582353 539
5222c21d
A
540 if ((_asl_global.proc_filter & EVAL_LEVEL_MASK) != 0) filter = _asl_global.proc_filter & EVAL_LEVEL_MASK;
541 }
81582353 542
5222c21d 543 pthread_mutex_unlock(&_asl_global.lock);
81582353
A
544 }
545
5222c21d
A
546 lmask = ASL_FILTER_MASK(level);
547 if ((filter != 0) && ((filter & lmask) == 0)) eval &= ~EVAL_SEND_ASL;
548 if (asl->out_count > 0) eval |= EVAL_TEXT_FILE;
81582353 549
5222c21d 550 return eval;
81582353
A
551}
552
81582353
A
553/*
554 * _asl_lib_vlog
555 * Internal routine used by asl_vlog.
f3df4c03 556 * msg: an asl messsage
81582353
A
557 * eval: log level and send flags for the message
558 * format: A formating string
559 * ap: va_list for the format
560 * returns 0 for success, non-zero for failure
561 */
5222c21d 562__private_extern__ ASL_STATUS
f3df4c03 563_asl_lib_vlog(asl_object_t obj, uint32_t eval, asl_object_t msg, const char *format, va_list ap)
81582353
A
564{
565 int saved_errno = errno;
566 int status;
567 char *str, *fmt, estr[NL_TEXTMAX];
568 uint32_t i, len, elen, expand;
81582353 569
f3df4c03 570 if (format == NULL) return ASL_STATUS_INVALID_ARG;
81582353
A
571
572 /* insert strerror for %m */
573 len = 0;
574 elen = 0;
575
576 expand = 0;
577 for (i = 0; format[i] != '\0'; i++)
578 {
579 if (format[i] == '%')
580 {
581 if (format[i+1] == '\0') len++;
582 else if (format[i+1] == 'm')
583 {
584 expand = 1;
585 strerror_r(saved_errno, estr, sizeof(estr));
586 elen = strlen(estr);
587 len += elen;
588 i++;
589 }
590 else
591 {
592 len += 2;
593 i++;
594 }
595 }
596 else len++;
597 }
598
599 fmt = (char *)format;
600
601 if (expand != 0)
602 {
603 fmt = malloc(len + 1);
5222c21d 604 if (fmt == NULL) return ASL_STATUS_NO_MEMORY;
81582353
A
605
606 len = 0;
607
608 for (i = 0; format[i] != '\0'; i++)
609 {
610 if (format[i] == '%')
611 {
612 if (format[i+1] == '\0')
613 {
614 }
615 else if ((format[i+1] == 'm') && (elen != 0))
616 {
617 memcpy(fmt+len, estr, elen);
618 len += elen;
619 i++;
620 }
621 else
622 {
623 fmt[len++] = format[i++];
624 fmt[len++] = format[i];
625 }
626 }
627 else fmt[len++] = format[i];
628 }
629
630 fmt[len] = '\0';
631 }
632
633 str = NULL;
634 vasprintf(&str, fmt, ap);
635 if (expand != 0) free(fmt);
636
f3df4c03 637 if (str == NULL) return ASL_STATUS_NO_MEMORY;
81582353 638
f3df4c03 639 status = _asl_send_message(obj, eval, (asl_msg_t *)msg, str);
81582353
A
640 free(str);
641
642 return status;
643}
644
645/*
646 * asl_vlog
647 * Similar to asl_log, but take a va_list instead of a list of arguments.
f3df4c03 648 * msg: an asl message
81582353
A
649 * level: the log level of the associated message
650 * format: A formating string
651 * ap: va_list for the format
652 * returns 0 for success, non-zero for failure
653 */
654int
f3df4c03 655asl_vlog(asl_object_t client, asl_object_t msg, int level, const char *format, va_list ap)
81582353 656{
5222c21d 657 ASL_STATUS status = ASL_STATUS_OK;
f3df4c03 658 uint32_t eval = _asl_evaluate_send(client, msg, level);
81582353 659
5222c21d
A
660 if (eval & EVAL_SEND_TRACE)
661 {
662 va_list ap_copy;
663 if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
664 if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
665 uint8_t trace_type = shim_asl_to_trace_type[level];
666
667 va_copy(ap_copy, ap);
668 os_log_shim_with_va_list(__builtin_return_address(0), OS_LOG_DEFAULT, trace_type, format, ap_copy, ^(xpc_object_t xdict) {_asl_log_args_to_xpc(client, msg, xdict);} );
669 va_end(ap_copy);
670 }
671
672 if (os_log_shim_legacy_logging_enabled() && (eval & EVAL_ASL))
673 {
674 asl_msg_t *smsg = asl_msg_new(ASL_TYPE_MSG);
675 if (eval & EVAL_SEND_TRACE) asl_msg_set_key_val(smsg, "ASLSHIM", "1");
676 smsg = asl_msg_merge(smsg, (asl_msg_t *)msg);
677
678 status = _asl_lib_vlog(client, eval, (asl_object_t)smsg, format, ap);
679
680 asl_msg_release(smsg);
681 }
682
f3df4c03 683 return (status == ASL_STATUS_OK) ? 0 : -1;
81582353
A
684}
685
686/*
687 * _asl_lib_log
5222c21d 688 * SPI used by legacy (non-shim) ASL_PREFILTER_LOG. Converts format arguments to a va_list and
81582353 689 * forwards the call to _asl_lib_vlog.
f3df4c03 690 * msg: an asl message
81582353
A
691 * eval: log level and send flags for the message
692 * format: A formating string
693 * ... args for format
694 * returns 0 for success, non-zero for failure
695 */
696int
f3df4c03 697_asl_lib_log(asl_object_t client, uint32_t eval, asl_object_t msg, const char *format, ...)
81582353 698{
5222c21d 699 int status = 0;
81582353 700
5222c21d
A
701 if (eval & EVAL_ASL)
702 {
703 va_list ap;
704
705 va_start(ap, format);
706 status = _asl_lib_vlog(client, eval, msg, format, ap);
707 va_end(ap);
708 }
81582353
A
709
710 return status;
711}
712
713/*
714 * asl_log
715 * Processes an ASL log message.
f3df4c03 716 * msg: an asl message
81582353
A
717 * level: the log level of the associated message
718 * format: A formating string
719 * ... args for format
720 * returns 0 for success, non-zero for failure
721 */
722int
f3df4c03 723asl_log(asl_object_t client, asl_object_t msg, int level, const char *format, ...)
81582353 724{
5222c21d 725 ASL_STATUS status = ASL_STATUS_OK;
f3df4c03 726 uint32_t eval = _asl_evaluate_send(client, msg, level);
81582353 727
5222c21d
A
728 if (eval & EVAL_SEND_TRACE)
729 {
730 va_list ap;
731 if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
732 if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
733 uint8_t trace_type = shim_asl_to_trace_type[level];
734
735 va_start(ap, format);
736 os_log_shim_with_va_list(__builtin_return_address(0), OS_LOG_DEFAULT, trace_type, format, ap, ^(xpc_object_t xdict) {_asl_log_args_to_xpc(client, msg, xdict);} );
737 va_end(ap);
738 }
739
740 if (os_log_shim_legacy_logging_enabled() && (eval & EVAL_ASL))
741 {
742 va_list ap;
743 asl_msg_t *smsg = asl_msg_new(ASL_TYPE_MSG);
744 if (eval & EVAL_SEND_TRACE) asl_msg_set_key_val(smsg, "ASLSHIM", "1");
745 smsg = asl_msg_merge(smsg, (asl_msg_t *)msg);
746
747 va_start(ap, format);
748 status = _asl_lib_vlog(client, eval, (asl_object_t)smsg, format, ap);
749 va_end(ap);
750
751 asl_msg_release(smsg);
752 }
81582353 753
f3df4c03 754 return (status == ASL_STATUS_OK) ? 0 : -1;
81582353
A
755}
756
f3df4c03
A
757/*
758 * asl_log_message
759 * Like asl_log, supplies NULL client and msg.
760 * level: the log level of the associated message
761 * format: A formating string
762 * ... args for format
763 * returns 0 for success, non-zero for failure
764 */
765int
766asl_log_message(int level, const char *format, ...)
767{
5222c21d 768 ASL_STATUS status = ASL_STATUS_OK;
f3df4c03 769 uint32_t eval = _asl_evaluate_send(NULL, NULL, level);
f3df4c03 770
5222c21d
A
771 if (eval & EVAL_SEND_TRACE)
772 {
773 va_list ap;
774 if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
775 if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
776 uint8_t trace_type = shim_asl_to_trace_type[level];
777
778 va_start(ap, format);
779 os_log_shim_with_va_list(__builtin_return_address(0), OS_LOG_DEFAULT, trace_type, format, ap, NULL);
780 va_end(ap);
781 }
782
783 if (os_log_shim_legacy_logging_enabled() && (eval & EVAL_ASL))
784 {
785 va_list ap;
786 asl_msg_t *smsg = asl_msg_new(ASL_TYPE_MSG);
787 if (eval & EVAL_SEND_TRACE) asl_msg_set_key_val(smsg, "ASLSHIM", "1");
788
789 va_start(ap, format);
790 status = _asl_lib_vlog(NULL, eval, (asl_object_t)smsg, format, ap);
791 va_end(ap);
792
793 asl_msg_release(smsg);
794 }
f3df4c03
A
795
796 return (status == ASL_STATUS_OK) ? 0 : -1;
797}
81582353
A
798
799/*
800 * asl_get_filter: gets the values for the local, master, and remote filters,
801 * and indicates which one is active.
802 */
803int
f3df4c03 804asl_get_filter(asl_object_t client, int *local, int *master, int *remote, int *active)
81582353
A
805{
806 asl_client_t *asl, *asl_default;
807 int l, m, r, x;
808 int status, check;
809 uint64_t v64;
810
f3df4c03
A
811 if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT)) return -1;
812
81582353
A
813 l = 0;
814 m = 0;
815 r = 0;
816 x = 0;
817
818 asl_default = _asl_open_default();
819
f3df4c03 820 asl = (asl_client_t *)client;
81582353 821 if (asl == NULL) asl = asl_default;
5222c21d 822 if (asl != NULL) l = asl->filter & EVAL_LEVEL_MASK;
81582353
A
823
824 if ((asl_default != NULL) && (!(asl_default->options & ASL_OPT_NO_REMOTE)))
825 {
826 pthread_mutex_lock(&_asl_global.lock);
827
828 if (_asl_global.rc_change_token >= 0)
829 {
830 /* initialize or re-check process-specific and master filters */
831 check = 0;
832 status = notify_check(_asl_global.rc_change_token, &check);
833 if ((status == NOTIFY_STATUS_OK) && (check != 0))
834 {
835 if (_asl_global.master_token >= 0)
836 {
837 v64 = 0;
838 status = notify_get_state(_asl_global.master_token, &v64);
839 if (status == NOTIFY_STATUS_OK) _asl_global.master_filter = v64;
840 }
841
842 if (_asl_global.notify_token >= 0)
843 {
844 v64 = 0;
845 status = notify_get_state(_asl_global.notify_token, &v64);
846 if (status == NOTIFY_STATUS_OK) _asl_global.proc_filter = v64;
847 }
848 }
849 }
850
851 m = _asl_global.master_filter;
852 if (m != 0) x = 1;
853
854 r = _asl_global.proc_filter;
855 if (r != 0) x = 2;
856
857 pthread_mutex_unlock(&_asl_global.lock);
858 }
859
860 if (local != NULL) *local = l;
861 if (master != NULL) *master = m;
862 if (remote != NULL) *remote = r;
863 if (active != NULL) *active = x;
864
865 return 0;
866}
867
5222c21d
A
868/* SPI for SHIM control */
869uint32_t
870asl_set_local_control(asl_object_t client, uint32_t filter)
871{
872 asl_client_t *asl = (asl_client_t *)client;
873 if (asl == NULL)
874 {
875 asl = _asl_open_default();
876 if (asl == NULL) return UINT32_MAX;
877 }
878 else if (asl_get_type(client) != ASL_TYPE_CLIENT) return UINT32_MAX;
879
880 return asl_client_set_control(asl, filter);
881}
882
883uint32_t
884asl_get_local_control(asl_object_t client)
885{
886 asl_client_t *asl = (asl_client_t *)client;
887 if (asl == NULL)
888 {
889 asl = _asl_open_default();
890 if (asl == NULL) return UINT32_MAX;
891 }
892 else if (asl_get_type(client) != ASL_TYPE_CLIENT) return UINT32_MAX;
893
894 return asl_client_get_control(asl);
895}
896
f3df4c03 897/*
5222c21d 898 * Sets PID and OSActivityID values in a new message.
f3df4c03
A
899 * Also sets Level, Time, TimeNanoSec, Sender, Facility and Message if provided.
900 */
901asl_msg_t *
902asl_base_msg(asl_client_t *asl, uint32_t level, const struct timeval *tv, const char *sstr, const char *fstr, const char *mstr)
81582353 903{
81582353 904 char aux_val[64];
81582353 905 asl_msg_t *aux;
f3df4c03
A
906 int status;
907 unsigned int osacount = 1;
908 os_activity_t osaid = 0;
81582353 909
81582353 910 aux = asl_msg_new(ASL_TYPE_MSG);
f3df4c03 911 if (aux == NULL) return NULL;
81582353 912
f3df4c03
A
913 /* Level */
914 if (level <= 7) asl_msg_set_key_val(aux, ASL_KEY_LEVEL, level_to_number_string[level]);
81582353 915
f3df4c03
A
916 /* Time and TimeNanoSec */
917 if (tv != NULL)
81582353 918 {
5222c21d 919 snprintf(aux_val, sizeof(aux_val), "%llu", (unsigned long long) tv->tv_sec);
81582353 920 asl_msg_set_key_val(aux, ASL_KEY_TIME, aux_val);
f3df4c03
A
921
922 snprintf(aux_val, sizeof(aux_val), "%d", tv->tv_usec * 1000);
81582353
A
923 asl_msg_set_key_val(aux, ASL_KEY_TIME_NSEC, aux_val);
924 }
81582353 925
f3df4c03
A
926 /* Message */
927 if (mstr != NULL) asl_msg_set_key_val(aux, ASL_KEY_MSG, mstr);
928
f3df4c03 929 /* PID */
81582353
A
930 snprintf(aux_val, sizeof(aux_val), "%u", getpid());
931 asl_msg_set_key_val(aux, ASL_KEY_PID, aux_val);
932
f3df4c03
A
933 /* OSActivityID */
934 if (os_activity_get_active(&osaid, &osacount) == 1)
81582353 935 {
f3df4c03
A
936 snprintf(aux_val, sizeof(aux_val), "0x%016llx", (uint64_t)osaid);
937 asl_msg_set_key_val(aux, ASL_KEY_OS_ACTIVITY_ID, aux_val);
938 }
939
940 /* Sender */
5222c21d 941 if ((sstr == NULL) && (asl != NULL))
f3df4c03
A
942 {
943 /* See if the client has a value for ASL_KEY_SENDER */
944 status = asl_msg_lookup((asl_msg_t *)asl->kvdict, ASL_KEY_SENDER, &sstr, NULL);
945 if ((status != 0) || (sstr == NULL))
81582353 946 {
f3df4c03
A
947 sstr = NULL;
948
949 /* See if the global cache has a value for ASL_KEY_SENDER */
81582353
A
950 if (_asl_global.sender == NULL)
951 {
f3df4c03
A
952 /* Get the process name with _NSGetArgv */
953 char *name = *(*_NSGetArgv());
81582353
A
954 if (name != NULL)
955 {
f3df4c03 956 char *x = strrchr(name, '/');
81582353
A
957 if (x != NULL) x++;
958 else x = name;
959
f3df4c03 960 /* Set the cache value */
81582353
A
961 pthread_mutex_lock(&_asl_global.lock);
962 if (_asl_global.sender == NULL) _asl_global.sender = strdup(x);
963 pthread_mutex_unlock(&_asl_global.lock);
964 }
965 }
966
967 if (_asl_global.sender != NULL) asl_msg_set_key_val(aux, ASL_KEY_SENDER, _asl_global.sender);
968 else asl_msg_set_key_val(aux, ASL_KEY_SENDER, "Unknown");
969 }
970 }
971
f3df4c03
A
972 if (sstr != NULL) asl_msg_set_key_val(aux, ASL_KEY_SENDER, sstr);
973
974 /* Facility */
5222c21d 975 if ((fstr == NULL) && (asl != NULL))
81582353 976 {
f3df4c03
A
977 status = asl_msg_lookup((asl_msg_t *)asl->kvdict, ASL_KEY_FACILITY, &fstr, NULL);
978 if (status != 0) fstr = NULL;
81582353
A
979 }
980
f3df4c03
A
981 if (fstr != NULL) asl_msg_set_key_val(aux, ASL_KEY_FACILITY, fstr);
982
983 return aux;
984}
985
986#ifdef NOTDEF
987/*
988 * Possibly useful someday...
989 */
990asl_msg_t *
991asl_prepared_message(asl_client_t *asl, asl_msg_t *msg)
992{
993 uint32_t i, len, level, outstatus;
994 const char *val, *sstr, *fstr;
995 struct timeval tval = {0, 0};
996 int status;
997 asl_msg_t *out;
998
999 if (asl == NULL)
1000 {
1001 asl = _asl_open_default();
1002 if (asl == NULL) return NULL;
1003 }
1004
1005 status = gettimeofday(&tval, NULL);
1006 if (status != 0)
1007 {
1008 time_t tick = time(NULL);
1009 tval.tv_sec = tick;
1010 tval.tv_usec = 0;
1011 }
1012
1013 val = NULL;
1014 status = asl_msg_lookup(msg, ASL_KEY_LEVEL, &val, NULL);
1015 if (status != 0) val = NULL;
1016
1017 level = ASL_LEVEL_DEBUG;
1018 if (val != NULL) level = atoi(val);
1019 if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
1020
1021 sstr = NULL;
1022 status = asl_msg_lookup(msg, ASL_KEY_SENDER, &sstr, NULL);
1023 if (status != 0) sstr = NULL;
1024
1025 fstr = NULL;
1026 status = asl_msg_lookup(msg, ASL_KEY_FACILITY, &fstr, NULL);
1027 if (status != 0) fstr = NULL;
1028
1029 out = asl_base_msg(asl, level, &tval, sstr, fstr, NULL);
1030 out = asl_msg_merge(out, msg);
1031
1032 return out;
1033}
1034#endif
1035
5222c21d
A
1036static void
1037_asl_set_option(asl_msg_t *msg, const char *opt)
1038{
1039 const char *val = NULL;
1040 uint32_t status;
1041
1042 if (msg == NULL) return;
1043 if (opt == NULL) return;
1044
1045 status = asl_msg_lookup(msg, ASL_KEY_OPTION, &val, NULL);
1046 if ((status != 0) || (val == NULL))
1047 {
1048 asl_msg_set_key_val(msg, ASL_KEY_OPTION, opt);
1049 }
1050 else
1051 {
1052 char *option = NULL;
1053 asprintf(&option, "%s %s", opt, val);
1054 asl_msg_set_key_val(msg, ASL_KEY_OPTION, option);
1055 free(option);
1056 }
1057}
1058
f3df4c03
A
1059static ASL_STATUS
1060_asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *mstr)
1061{
1062 uint32_t i, len, level, lmask, outstatus, objtype;
1063 const char *sstr, *fstr;
1064 struct timeval tval = {0, 0};
1065 int status;
1066 int use_global_lock = 0;
1067 kern_return_t kstatus;
1068 asl_msg_t *sendmsg;
1069 asl_msg_t *qd_msg = NULL;
1070 asl_client_t *asl = NULL;
1071 static dispatch_once_t noquota_once;
1072
5222c21d 1073 if ((eval & EVAL_ASL) == 0) return ASL_STATUS_OK;
81582353 1074
f3df4c03
A
1075 if (obj == NULL)
1076 {
1077 asl = _asl_open_default();
1078 if (asl == NULL) return ASL_STATUS_FAILED;
1079 use_global_lock = 1;
1080 objtype = ASL_TYPE_CLIENT;
1081 }
1082 else
1083 {
1084 objtype = asl_get_type(obj);
1085 if (objtype == ASL_TYPE_CLIENT) asl = (asl_client_t *)obj;
f3df4c03
A
1086 }
1087
5222c21d 1088 level = eval & EVAL_LEVEL_MASK;
f3df4c03 1089 if (level > 7) level = 7;
f3df4c03
A
1090 lmask = ASL_FILTER_MASK(level);
1091
1092 if ((objtype == ASL_TYPE_CLIENT) && (asl->aslfile != NULL)) use_global_lock = 1;
1093
1094 status = gettimeofday(&tval, NULL);
1095 if (status != 0)
1096 {
1097 time_t tick = time(NULL);
1098 tval.tv_sec = tick;
1099 tval.tv_usec = 0;
1100 }
1101
1102 sstr = NULL;
1103 status = asl_msg_lookup(msg, ASL_KEY_SENDER, &sstr, NULL);
1104 if (status != 0) sstr = NULL;
1105
1106 fstr = NULL;
1107 status = asl_msg_lookup(msg, ASL_KEY_FACILITY, &fstr, NULL);
1108 if (status != 0) fstr = NULL;
1109
1110 sendmsg = asl_base_msg(asl, level, &tval, sstr, fstr, mstr);
1111 if (sendmsg == NULL) return ASL_STATUS_FAILED;
1112
1113 /* Set "ASLOption store" if tunneling */
5222c21d 1114 if (eval & EVAL_TUNNEL) _asl_set_option(sendmsg, ASL_OPT_STORE);
81582353
A
1115
1116 outstatus = -1;
1117
1118 if (use_global_lock != 0) pthread_mutex_lock(&_asl_global.lock);
1119
f3df4c03
A
1120 sendmsg = asl_msg_merge(sendmsg, msg);
1121
1122 if (objtype != ASL_TYPE_CLIENT)
1123 {
1124 asl_append(obj, (asl_object_t)sendmsg);
1125 asl_msg_release(sendmsg);
1126 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
1127 return ASL_STATUS_OK;
1128 }
81582353
A
1129
1130 /*
1131 * If there is an aslfile this is a stand-alone file client.
1132 * Just save to the file.
1133 */
1134 if (asl->aslfile != NULL)
1135 {
1136 outstatus = ASL_STATUS_FAILED;
1137
f3df4c03 1138 if (sendmsg != NULL)
81582353 1139 {
f3df4c03 1140 outstatus = asl_file_save(asl->aslfile, sendmsg, &(asl->aslfileid));
81582353
A
1141 asl->aslfileid++;
1142 }
1143
f3df4c03 1144 asl_msg_release(sendmsg);
81582353
A
1145
1146 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
1147 return outstatus;
1148 }
1149
f3df4c03 1150 _asl_global_init(0);
81582353
A
1151 outstatus = 0;
1152
f3df4c03
A
1153 /*
1154 * ASL message quota
1155 * Quotas are disabled if:
1156 * - a remote control filter is in place (EVAL_TUNNEL)
1157 * - Environment variable ASL_QUOTA_DISABLED == 1
1158 * - /etc/asl/.noquota existed at the time that the process started
1159 *
5222c21d 1160 * We just check /etc/asl/.noquota once, since it would be
f3df4c03 1161 * expensive to stat() for every log message.
5222c21d
A
1162 *
1163 * We only check the Environment variable once, since getenv() is
1164 * not thread safe. If someone is changing the environment,
1165 * this can crash.
f3df4c03 1166 */
5222c21d 1167
f3df4c03
A
1168 dispatch_once(&noquota_once, ^{
1169 struct stat sb;
1170 memset(&sb, 0, sizeof(struct stat));
5222c21d
A
1171
1172 int save_errno = errno;
1173
1174 if (stat(NOQUOTA_FILE_PATH, &sb) == 0)
f3df4c03
A
1175 {
1176 _asl_global.quota = UINT32_MAX;
f3df4c03 1177 }
5222c21d
A
1178 else
1179 {
1180 const char *qtest = getenv(NOQUOTA_ENV);
1181 if ((qtest != NULL) && (!strcmp(qtest, "1"))) _asl_global.quota = UINT32_MAX;
1182 }
1183
1184 /* reset errno since we want stat() to fail silently */
1185 errno = save_errno;
1186 });
1187
f3df4c03 1188 if (((eval & EVAL_TUNNEL) == 0) && (_asl_global.quota != UINT32_MAX))
81582353
A
1189 {
1190 time_t last_send = _asl_global.last_send;
1191 time_t last_oq = _asl_global.last_oq_msg;
1192 uint32_t qcurr = _asl_global.quota;
1193 time_t delta;
1194 uint32_t qinc, qnew;
1195
1196 qnew = qcurr;
1197
1198 /* add QUOTA_MPS to quota for each second we've been idle */
1199 if (tval.tv_sec > last_send)
1200 {
1201 delta = tval.tv_sec - last_send;
1202
1203 qinc = QUOTA_MPH;
1204 if (delta < (QUOTA_MPH / QUOTA_MPS)) qinc = delta * QUOTA_MPS;
1205
1206 qnew = MIN(QUOTA_MPH, qcurr + qinc);
1207 OSAtomicCompareAndSwapLongBarrier(last_send, tval.tv_sec, (long *)&_asl_global.last_send);
1208 }
1209
1210 if (qnew == 0)
1211 {
1212 if ((tval.tv_sec - last_oq) > QUOTA_MSG_INTERVAL)
1213 {
1214 eval |= EVAL_QUOTA;
1215 OSAtomicCompareAndSwapLongBarrier(last_oq, tval.tv_sec, (long *)&_asl_global.last_oq_msg);
1216 }
1217 else
1218 {
5222c21d 1219 eval &= ~EVAL_SEND_ASL;
81582353
A
1220 }
1221 }
1222 else
1223 {
1224 OSAtomicCompareAndSwap32Barrier(qcurr, qnew - 1, (int32_t *)&_asl_global.quota);
1225 }
1226 }
1227
5222c21d 1228 if ((_asl_global.server_port != MACH_PORT_NULL) && (eval & EVAL_SEND_ASL))
81582353
A
1229 {
1230 asl_string_t *send_str;
1231 const char *str;
1232 size_t vmsize;
1233
1234 if (eval & EVAL_QUOTA)
1235 {
f3df4c03
A
1236 asl_msg_set_key_val(sendmsg, ASL_KEY_LEVEL, QUOTA_LEVEL_STR);
1237 asl_msg_set_key_val(sendmsg, ASL_KEY_MSG, QUOTA_MSG);
81582353
A
1238 }
1239
f3df4c03
A
1240 if (qd_msg != NULL)
1241 {
1242 send_str = asl_msg_to_string_raw(ASL_STRING_MIG, qd_msg, "raw");
1243 len = asl_string_length(send_str);
1244 vmsize = asl_string_allocated_size(send_str);
1245 str = asl_string_release_return_bytes(send_str);
1246 if (len != 0) kstatus = _asl_server_message(_asl_global.server_port, (caddr_t)str, len);
1247 if ((str != NULL) && (vmsize != 0)) vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
1248 asl_msg_release(qd_msg);
1249 }
5222c21d 1250
f3df4c03 1251 send_str = asl_msg_to_string_raw(ASL_STRING_MIG, sendmsg, "raw");
81582353 1252 len = asl_string_length(send_str);
5222c21d
A
1253
1254 if (len > LIBASL_MAX_MSG_SIZE)
1255 {
1256 char tmp[256];
1257
1258 snprintf(tmp, sizeof(tmp), SIZE_LIMIT_MSG, len, LIBASL_MAX_MSG_SIZE);
1259 asl_msg_t *limitmsg = asl_base_msg(asl, ASL_LEVEL_CRIT, &tval, sstr, fstr, tmp);
1260
1261 asl_string_release(send_str);
1262 len = 0;
1263
1264 if (limitmsg != NULL)
1265 {
1266 /* Set "ASLOption store" if tunneling */
1267 if (eval & EVAL_TUNNEL) _asl_set_option(limitmsg, ASL_OPT_STORE);
1268
1269 send_str = asl_msg_to_string_raw(ASL_STRING_MIG, limitmsg, "raw");
1270 len = asl_string_length(send_str);
1271 asl_msg_release(limitmsg);
1272 }
1273 }
1274
81582353 1275 vmsize = asl_string_allocated_size(send_str);
f3df4c03 1276 str = asl_string_release_return_bytes(send_str);
81582353
A
1277
1278 if (len != 0)
1279 {
1280 /* send a mach message to syslogd */
1281 kstatus = _asl_server_message(_asl_global.server_port, (caddr_t)str, len);
1282 if (kstatus != KERN_SUCCESS)
1283 {
1284 /* retry once if the call failed */
f3df4c03 1285 _asl_global_init(1);
81582353
A
1286 kstatus = _asl_server_message(_asl_global.server_port, (caddr_t)str, len);
1287 if (kstatus != KERN_SUCCESS)
1288 {
81582353
A
1289 vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
1290 outstatus = -1;
1291 }
1292 }
1293 }
1294 else if (vmsize >0) vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
1295 }
1296
f3df4c03 1297 if ((sendmsg != NULL) && (asl->out_count > 0))
81582353
A
1298 {
1299 /* write to file descriptors */
1300 for (i = 0; i < asl->out_count; i++)
1301 {
1302 if ((asl->out_list[i].fd >= 0) && (asl->out_list[i].filter != 0) && ((asl->out_list[i].filter & lmask) != 0))
1303 {
1304 char *str;
1305
1306 len = 0;
f3df4c03 1307 str = asl_format_message(sendmsg, asl->out_list[i].mfmt, asl->out_list[i].tfmt, asl->out_list[i].encoding, &len);
81582353
A
1308 if (str == NULL) continue;
1309
1310 status = write(asl->out_list[i].fd, str, len - 1);
1311 if (status < 0)
1312 {
1313 /* soft error for fd 2 (stderr) */
1314 if (asl->out_list[i].fd != 2) outstatus = -1;
1315 asl->out_list[i].fd = -1;
1316 }
1317
1318 free(str);
1319 }
1320 }
1321 }
1322
f3df4c03 1323 asl_msg_release(sendmsg);
81582353
A
1324
1325 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
1326
1327 return outstatus;
1328}
1329
1330/*
1331 * asl_send: send a message
f3df4c03 1332 * This routine may be used instead of asl_log() or asl_vlog() if asl_set()
81582353
A
1333 * has been used to set all of a message's attributes.
1334 * eval: hints about what to do with the message
f3df4c03 1335 * msg: an asl message
81582353
A
1336 * returns 0 for success, non-zero for failure
1337 */
f3df4c03
A
1338__private_extern__ ASL_STATUS
1339asl_client_internal_send(asl_object_t obj, asl_object_t msg)
81582353 1340{
f3df4c03
A
1341 int status = ASL_STATUS_OK;
1342 uint32_t eval = _asl_evaluate_send(obj, msg, -1);
1343 if (eval != 0) status = _asl_send_message(obj, eval, (asl_msg_t *)msg, NULL);
81582353
A
1344
1345 return status;
1346}
1347
f3df4c03
A
1348#pragma mark -
1349#pragma mark auxiliary files and URLs
1350
1351static ASL_STATUS
81582353
A
1352_asl_aux_save_context(asl_aux_context_t *ctx)
1353{
f3df4c03 1354 if (ctx == NULL) return ASL_STATUS_FAILED;
81582353
A
1355
1356 pthread_mutex_lock(&_asl_global.lock);
1357
1358 _asl_global.aux_ctx = (asl_aux_context_t **)reallocf(_asl_global.aux_ctx, (_asl_global.aux_count + 1) * sizeof(asl_aux_context_t *));
1359 if (_asl_global.aux_ctx == NULL)
1360 {
1361 _asl_global.aux_count = 0;
f3df4c03
A
1362 pthread_mutex_unlock(&_asl_global.lock);
1363 return ASL_STATUS_FAILED;
81582353
A
1364 }
1365
1366 _asl_global.aux_ctx[_asl_global.aux_count++] = ctx;
1367
1368 pthread_mutex_unlock(&_asl_global.lock);
1369
f3df4c03 1370 return ASL_STATUS_OK;
81582353
A
1371}
1372
1373/*
1374 * Creates an auxiliary file that may be used to save arbitrary data. The ASL message msg
1375 * will be saved at the time that the auxiliary file is created. The message will include
1376 * any keys and values found in msg, and it will include the title and Uniform Type
1377 * Identifier specified. Output parameter out_fd will contain the file descriptor of the
1378 * new auxiliary file.
1379 */
f3df4c03 1380static ASL_STATUS
81582353
A
1381_asl_auxiliary(asl_msg_t *msg, const char *title, const char *uti, const char *url, int *out_fd)
1382{
1383 asl_msg_t *aux;
1384 asl_string_t *send_str;
1385 const char *str;
1386 fileport_t fileport;
1387 kern_return_t kstatus;
1388 size_t len, vmsize;
1389 uint32_t newurllen, where;
1390 int status, fd, fdpair[2];
1391 caddr_t newurl;
1392 dispatch_queue_t pipe_q;
1393 dispatch_io_t pipe_channel;
1394 dispatch_semaphore_t sem;
1395
1396 aux = asl_msg_new(ASL_TYPE_MSG);
1397
f3df4c03
A
1398 if (url != NULL) asl_msg_set_key_val(aux, ASL_KEY_AUX_URL, url);
1399 if (title != NULL) asl_msg_set_key_val(aux, ASL_KEY_AUX_TITLE, title);
1400 if (uti == NULL) asl_msg_set_key_val(aux, ASL_KEY_AUX_UTI, "public.data");
1401 else asl_msg_set_key_val(aux, ASL_KEY_AUX_UTI, uti);
81582353
A
1402
1403 aux = asl_msg_merge(aux, msg);
1404
1405 /* if (out_fd == NULL), this is from asl_log_auxiliary_location */
1406 if (out_fd == NULL)
1407 {
f3df4c03 1408 uint32_t eval = _asl_evaluate_send(NULL, (asl_object_t)aux, -1);
81582353
A
1409 status = _asl_send_message(NULL, eval, aux, NULL);
1410 asl_msg_release(aux);
1411 return status;
1412 }
1413
1414 where = asl_store_location();
81582353
A
1415 if (where == ASL_STORE_LOCATION_MEMORY)
1416 {
1417 /* create a pipe */
81582353 1418 asl_aux_context_t *ctx = (asl_aux_context_t *)calloc(1, sizeof(asl_aux_context_t));
f3df4c03 1419 if (ctx == NULL) return ASL_STATUS_FAILED;
81582353
A
1420
1421 status = pipe(fdpair);
1422 if (status < 0)
1423 {
1424 free(ctx);
f3df4c03 1425 return ASL_STATUS_FAILED;
81582353
A
1426 }
1427
1428 /* give read end to dispatch_io_read */
1429 fd = fdpair[0];
1430 sem = dispatch_semaphore_create(0);
1431 ctx->sem = sem;
1432 ctx->fd = fdpair[1];
1433
1434 status = _asl_aux_save_context(ctx);
f3df4c03 1435 if (status != ASL_STATUS_OK)
81582353
A
1436 {
1437 close(fdpair[0]);
1438 close(fdpair[1]);
1439 dispatch_release(sem);
1440 free(ctx);
f3df4c03 1441 return ASL_STATUS_FAILED;
81582353
A
1442 }
1443
f3df4c03 1444 pipe_q = dispatch_queue_create("ASL_AUX_PIPE_Q", NULL);
81582353
A
1445 pipe_channel = dispatch_io_create(DISPATCH_IO_STREAM, fd, pipe_q, ^(int err){
1446 close(fd);
1447 });
1448
1449 *out_fd = fdpair[1];
1450
1451 dispatch_io_set_low_water(pipe_channel, SIZE_MAX);
1452
1453 dispatch_io_read(pipe_channel, 0, SIZE_MAX, pipe_q, ^(bool done, dispatch_data_t pipedata, int err){
1454 if (err == 0)
1455 {
1456 size_t len = dispatch_data_get_size(pipedata);
1457 if (len > 0)
1458 {
1459 const char *bytes = NULL;
1460 char *encoded;
1461 uint32_t eval;
1462
1463 dispatch_data_t md = dispatch_data_create_map(pipedata, (const void **)&bytes, &len);
1464 encoded = asl_core_encode_buffer(bytes, len);
1465 asl_msg_set_key_val(aux, ASL_KEY_AUX_DATA, encoded);
1466 free(encoded);
f3df4c03 1467 eval = _asl_evaluate_send(NULL, (asl_object_t)aux, -1);
81582353
A
1468 _asl_send_message(NULL, eval, aux, NULL);
1469 asl_msg_release(aux);
1470 dispatch_release(md);
1471 }
1472 }
1473
1474 if (done)
1475 {
1476 dispatch_semaphore_signal(sem);
1477 dispatch_release(pipe_channel);
1478 dispatch_release(pipe_q);
1479 }
1480 });
1481
f3df4c03 1482 return ASL_STATUS_OK;
81582353
A
1483 }
1484
f3df4c03
A
1485 _asl_global_init(0);
1486 if (_asl_global.server_port == MACH_PORT_NULL) return ASL_STATUS_FAILED;
81582353
A
1487
1488 send_str = asl_msg_to_string_raw(ASL_STRING_MIG, aux, "raw");
1489 len = asl_string_length(send_str);
1490 vmsize = asl_string_allocated_size(send_str);
f3df4c03 1491 str = asl_string_release_return_bytes(send_str);
81582353
A
1492
1493 if (len == 0)
1494 {
1495 asl_msg_release(aux);
1496 vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
f3df4c03 1497 return ASL_STATUS_FAILED;
81582353
A
1498 }
1499
1500 status = 0;
1501 fileport = MACH_PORT_NULL;
1502 status = KERN_SUCCESS;
1503
1504 kstatus = _asl_server_create_aux_link(_asl_global.server_port, (caddr_t)str, len, &fileport, &newurl, &newurllen, &status);
1505 if (kstatus != KERN_SUCCESS)
1506 {
1507 /* retry once if the call failed */
f3df4c03 1508 _asl_global_init(1);
81582353
A
1509 kstatus = _asl_server_create_aux_link(_asl_global.server_port, (caddr_t)str, len, &fileport, &newurl, &newurllen, &status);
1510 if (kstatus != KERN_SUCCESS)
1511 {
81582353
A
1512 vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
1513 asl_msg_release(aux);
f3df4c03 1514 return ASL_STATUS_FAILED;
81582353
A
1515 }
1516 }
1517
1518 if (status != 0)
1519 {
1520 asl_msg_release(aux);
1521 return status;
1522 }
1523
1524 if (newurl != NULL)
1525 {
1526 asl_msg_set_key_val(aux, ASL_KEY_AUX_URL, newurl);
1527 vm_deallocate(mach_task_self(), (vm_address_t)newurl, newurllen);
1528 }
1529
1530 if (fileport == MACH_PORT_NULL)
1531 {
1532 asl_msg_release(aux);
f3df4c03 1533 return ASL_STATUS_FAILED;
81582353
A
1534 }
1535
1536 fd = fileport_makefd(fileport);
1537 mach_port_deallocate(mach_task_self(), fileport);
1538 if (fd < 0)
1539 {
1540 asl_msg_release(aux);
1541 status = -1;
1542 }
1543 else
1544 {
1545 asl_aux_context_t *ctx = (asl_aux_context_t *)calloc(1, sizeof(asl_aux_context_t));
1546 if (ctx == NULL)
1547 {
1548 status = -1;
1549 }
1550 else
1551 {
1552 *out_fd = fd;
1553
1554 ctx->fd = fd;
1555 ctx->msg = aux;
1556
1557 status = _asl_aux_save_context(ctx);
1558 }
1559 }
1560
1561 return status;
1562}
1563
1564int
f3df4c03 1565asl_create_auxiliary_file(asl_object_t msg, const char *title, const char *uti, int *out_fd)
81582353
A
1566{
1567 if (out_fd == NULL) return -1;
1568
f3df4c03
A
1569 ASL_STATUS status = _asl_auxiliary((asl_msg_t *)msg, title, uti, NULL, out_fd);
1570 return (status == ASL_STATUS_OK) ? 0 : -1;
81582353
A
1571}
1572
1573int
f3df4c03 1574asl_log_auxiliary_location(asl_object_t msg, const char *title, const char *uti, const char *url)
81582353 1575{
f3df4c03
A
1576 ASL_STATUS status = _asl_auxiliary((asl_msg_t *)msg, title, uti, url, NULL);
1577 return (status == ASL_STATUS_OK) ? 0 : -1;
81582353
A
1578}
1579
1580/*
1581 * Close an auxiliary file.
1582 * Sends the cached auxiliary message to syslogd.
f3df4c03 1583 * Returns 0 on success, -1 on error.
81582353
A
1584 */
1585int
1586asl_close_auxiliary_file(int fd)
1587{
1588 int i, j, status;
1589 asl_msg_t *aux_msg;
1590 dispatch_semaphore_t aux_sem = NULL;
1591
1592 pthread_mutex_lock(&(_asl_global.lock));
1593
1594 aux_msg = NULL;
1595 status = -1;
1596
1597 for (i = 0; i < _asl_global.aux_count; i++)
1598 {
1599 if (_asl_global.aux_ctx[i]->fd == fd)
1600 {
1601 status = 0;
1602
1603 aux_msg = _asl_global.aux_ctx[i]->msg;
1604 aux_sem = _asl_global.aux_ctx[i]->sem;
1605
1606 free(_asl_global.aux_ctx[i]);
1607
1608 for (j = i + 1; j < _asl_global.aux_count; i++, j++)
1609 {
1610 _asl_global.aux_ctx[i] = _asl_global.aux_ctx[j];
1611 }
1612
1613 _asl_global.aux_count--;
1614
1615 if (_asl_global.aux_count == 0)
1616 {
1617 free(_asl_global.aux_ctx);
1618 _asl_global.aux_ctx = NULL;
1619 }
1620 else
1621 {
1622 _asl_global.aux_ctx = (asl_aux_context_t **)reallocf(_asl_global.aux_ctx, _asl_global.aux_count * sizeof(asl_aux_context_t *));
1623 if (_asl_global.aux_ctx == NULL)
1624 {
1625 _asl_global.aux_count = 0;
1626 status = -1;
1627 }
1628 }
1629
1630 break;
1631 }
1632 }
1633
1634 pthread_mutex_unlock(&(_asl_global.lock));
1635
1636 close(fd);
1637
1638 if (aux_msg != NULL)
1639 {
f3df4c03 1640 uint32_t eval = _asl_evaluate_send(NULL, (asl_object_t)aux_msg, -1);
81582353
A
1641 if (_asl_send_message(NULL, eval, aux_msg, NULL) != ASL_STATUS_OK) status = -1;
1642 asl_msg_release(aux_msg);
1643 }
1644
1645 if (aux_sem != NULL)
1646 {
1647 dispatch_semaphore_wait(aux_sem, DISPATCH_TIME_FOREVER);
1648 dispatch_release(aux_sem);
1649 }
1650
1651 return status;
1652}
1653
f3df4c03 1654#pragma mark -
81582353 1655
f3df4c03 1656asl_msg_t *
81582353
A
1657_asl_server_control_query(void)
1658{
f3df4c03
A
1659 asl_msg_list_t *list = NULL;
1660 char *res;
81582353
A
1661 uint32_t len, reslen, status;
1662 uint64_t cmax, qmin;
1663 kern_return_t kstatus;
1664 caddr_t vmstr;
1665 asl_msg_t *m = NULL;
1666 static const char ctlstr[] = "1\nQ [= ASLOption control]\n";
1667
f3df4c03 1668 _asl_global_init(0);
81582353
A
1669 if (_asl_global.server_port == MACH_PORT_NULL) return NULL;
1670
1671 len = strlen(ctlstr) + 1;
1672
1673 qmin = 0;
1674 cmax = 0;
1675 res = NULL;
1676 reslen = 0;
1677
5222c21d 1678 kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
81582353
A
1679 if (kstatus != KERN_SUCCESS) return NULL;
1680
1681 memmove(vmstr, ctlstr, len);
1682
1683 status = 0;
1684 kstatus = _asl_server_query_2(_asl_global.server_port, vmstr, len, qmin, FETCH_BATCH, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status);
1685 if (kstatus != KERN_SUCCESS)
1686 {
1687 /* retry once if the call failed */
f3df4c03 1688 _asl_global_init(1);
81582353 1689 kstatus = _asl_server_query_2(_asl_global.server_port, vmstr, len, qmin, FETCH_BATCH, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status);
81582353 1690 }
f3df4c03
A
1691
1692 list = asl_msg_list_from_string(res);
81582353
A
1693 vm_deallocate(mach_task_self(), (vm_address_t)res, reslen);
1694
1695 if (list == NULL) return NULL;
1696 if (list->count > 0) m = asl_msg_retain(list->msg[0]);
f3df4c03
A
1697 asl_msg_list_release(list);
1698 return m;
81582353
A
1699}
1700
f3df4c03
A
1701/*
1702 * Returns ASL_STORE_LOCATION_FILE or ASL_STORE_LOCATION_MEMORY
1703 */
81582353
A
1704int
1705asl_store_location()
1706{
1707 kern_return_t kstatus;
1708 char *res;
1709 uint32_t reslen, status;
1710 uint64_t cmax;
1711
f3df4c03 1712 _asl_global_init(0);
81582353
A
1713 if (_asl_global.server_port == MACH_PORT_NULL) return ASL_STORE_LOCATION_FILE;
1714
1715 res = NULL;
1716 reslen = 0;
1717 cmax = 0;
1718 status = ASL_STATUS_OK;
1719
1720 kstatus = _asl_server_query_2(_asl_global.server_port, NULL, 0, 0, -1, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status);
1721 if (kstatus != KERN_SUCCESS)
1722 {
1723 /* retry once if the call failed */
f3df4c03 1724 _asl_global_init(1);
81582353
A
1725 kstatus = _asl_server_query_2(_asl_global.server_port, NULL, 0, 0, -1, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status);
1726 }
1727
1728 /* res should never be returned, but just to be certain we don't leak VM ... */
1729 if (res != NULL) vm_deallocate(mach_task_self(), (vm_address_t)res, reslen);
1730
f3df4c03 1731 if (kstatus != KERN_SUCCESS) return ASL_STORE_LOCATION_FILE;
81582353
A
1732 if (status == ASL_STATUS_OK) return ASL_STORE_LOCATION_MEMORY;
1733 return ASL_STORE_LOCATION_FILE;
1734}
1735
f3df4c03
A
1736asl_object_t
1737asl_open_path(const char *path, uint32_t opts)
81582353 1738{
f3df4c03
A
1739 struct stat sb;
1740 asl_file_t *fout = NULL;
1741 asl_store_t *sout = NULL;
81582353 1742
f3df4c03 1743 if (opts == 0) opts = ASL_OPT_OPEN_READ;
81582353 1744
f3df4c03 1745 if (opts & ASL_OPT_OPEN_READ)
81582353 1746 {
f3df4c03
A
1747 if (path == NULL)
1748 {
1749 if (asl_store_open_read(ASL_PLACE_DATABASE_DEFAULT, &sout) != ASL_STATUS_OK) return NULL;
1750 return (asl_object_t)sout;
1751 }
81582353 1752
f3df4c03
A
1753 memset(&sb, 0, sizeof(struct stat));
1754 if (stat(path, &sb) < 0) return NULL;
81582353 1755
f3df4c03 1756 if (sb.st_mode & S_IFREG)
81582353 1757 {
f3df4c03
A
1758 if (asl_file_open_read(path, &fout) != ASL_STATUS_OK) return NULL;
1759 return (asl_object_t)fout;
81582353 1760 }
f3df4c03 1761 else if (sb.st_mode & S_IFDIR)
81582353 1762 {
f3df4c03
A
1763 if (asl_store_open_read(path, &sout) != ASL_STATUS_OK) return NULL;
1764 return (asl_object_t)sout;
81582353 1765 }
f3df4c03
A
1766
1767 return NULL;
1768 }
1769 else if (opts & ASL_OPT_OPEN_WRITE)
1770 {
1771 if (path == NULL) return NULL;
1772
1773 memset(&sb, 0, sizeof(struct stat));
1774 if (stat(path, &sb) < 0)
81582353 1775 {
f3df4c03
A
1776 if (errno != ENOENT) return NULL;
1777
1778 if (opts & ASL_OPT_CREATE_STORE)
1779 {
1780 if (asl_store_open_write(path, &sout) != ASL_STATUS_OK) return NULL;
5222c21d 1781 return (asl_object_t)sout;
f3df4c03
A
1782 }
1783 else
1784 {
1785 if (asl_file_open_write(path, 0644, geteuid(), getegid(), &fout) != ASL_STATUS_OK) return NULL;
1786 return (asl_object_t)fout;
1787 }
81582353 1788 }
f3df4c03 1789 else if (sb.st_mode & S_IFREG)
81582353 1790 {
f3df4c03
A
1791 if (asl_file_open_write(path, 0644, geteuid(), getegid(), &fout) != ASL_STATUS_OK) return NULL;
1792 return (asl_object_t)fout;
81582353 1793 }
f3df4c03 1794 else if (sb.st_mode & S_IFDIR)
81582353 1795 {
f3df4c03
A
1796 if (asl_store_open_write(path, &sout) != ASL_STATUS_OK) return NULL;
1797 return (asl_object_t)sout;
81582353 1798 }
81582353
A
1799 }
1800
f3df4c03 1801 return NULL;
81582353 1802}