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