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