2 * Copyright (c) 2007-2012 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 #include <TargetConditionals.h>
26 #include <sys/types.h>
31 #include <sys/socket.h>
35 #include <sys/fcntl.h>
36 #include <sys/signal.h>
37 #include <sys/errno.h>
38 #include <mach/mach.h>
39 #include <mach/mach_error.h>
40 #include <bsm/libbsm.h>
42 #include <netinet/in.h>
43 #include <netinet/tcp.h>
44 #include <sys/event.h>
45 #include <servers/bootstrap.h>
50 #include <xpc/private.h>
52 #include <uuid/uuid.h>
55 #include "asl_ipcServer.h"
57 #define forever for(;;)
59 #define LIST_SIZE_DELTA 256
61 #define SEND_NOTIFICATION 0xfadefade
63 #define QUERY_FLAG_SEARCH_REVERSE 0x00000001
64 #define QUERY_DURATION_UNLIMITED 0
66 #define SEARCH_FORWARD 1
67 #define SEARCH_BACKWARD -1
71 #define ASL_ENTITLEMENT_KEY "com.apple.asl.access_as_root"
72 #define ASL_ENTITLEMENT_UID_KEY "com.apple.asl.access_as_uid"
73 #define ASL_ENTITLEMENT_GID_KEY "com.apple.asl.access_as_gid"
75 static dispatch_queue_t asl_server_queue
;
76 static dispatch_queue_t watch_queue
;
77 static dispatch_once_t watch_init_once
;
79 extern boolean_t
asl_ipc_server(mach_msg_header_t
*InHeadP
, mach_msg_header_t
*OutHeadP
);
81 static task_name_t
*client_tasks
= NULL
;
82 static uint32_t client_tasks_count
= 0;
84 static int *direct_watch
= NULL
;
85 /* N.B. ports are in network byte order */
86 static uint16_t *direct_watch_port
= NULL
;
87 static uint32_t direct_watch_count
= 0;
91 mach_msg_header_t head
;
92 union __RequestUnion__asl_ipc_subsystem request
;
97 mach_msg_header_t head
;
98 union __ReplyUnion__asl_ipc_subsystem reply
;
102 db_asl_open(uint32_t dbtype
)
107 if ((dbtype
& DB_TYPE_FILE
) && (global
.file_db
== NULL
))
109 memset(&sb
, 0, sizeof(struct stat
));
110 if (stat(PATH_ASL_STORE
, &sb
) == 0)
112 /* must be a directory */
113 if (!S_ISDIR(sb
.st_mode
))
115 asldebug("error: %s is not a directory", PATH_ASL_STORE
);
123 /* /var/log/asl doesn't exist - create it */
124 if (mkdir(PATH_ASL_STORE
, 0755) != 0)
126 asldebug("error: can't create data store %s: %s\n", PATH_ASL_STORE
, strerror(errno
));
132 /* stat failed for some other reason */
133 asldebug("error: can't stat data store %s: %s\n", PATH_ASL_STORE
, strerror(errno
));
138 status
= asl_store_open_write(NULL
, &(global
.file_db
));
139 if (status
!= ASL_STATUS_OK
)
141 asldebug("asl_store_open_write: %s\n", asl_core_error(status
));
145 if (global
.db_file_max
!= 0) asl_store_max_file_size(global
.file_db
, global
.db_file_max
);
146 trigger_aslmanager();
150 if ((dbtype
& DB_TYPE_MEMORY
) && (global
.memory_db
== NULL
))
152 status
= asl_memory_open(global
.db_memory_max
, global
.db_memory_str_max
, &(global
.memory_db
));
153 if (status
!= ASL_STATUS_OK
)
155 asldebug("asl_memory_open: %s\n", asl_core_error(status
));
161 add_lockdown_session(int fd
)
163 dispatch_once(&watch_init_once
, ^{
164 watch_queue
= dispatch_queue_create("Direct Watch Queue", NULL
);
167 dispatch_async(watch_queue
, ^{
168 if (global
.lockdown_session_count
== 0) global
.lockdown_session_fds
= NULL
;
170 global
.lockdown_session_fds
= reallocf(global
.lockdown_session_fds
, global
.lockdown_session_count
+ 1 * sizeof(int));
172 if (global
.lockdown_session_fds
== NULL
)
174 asldebug("add_lockdown_session: realloc failed\n");
175 global
.lockdown_session_count
= 0;
179 global
.lockdown_session_fds
[global
.lockdown_session_count
++] = fd
;
182 global
.watchers_active
= direct_watch_count
+ global
.lockdown_session_count
;
187 remove_lockdown_session(int fd
)
189 dispatch_once(&watch_init_once
, ^{
190 watch_queue
= dispatch_queue_create("Direct Watch Queue", NULL
);
193 dispatch_async(watch_queue
, ^{
196 for (i
= 0, n
= 0; i
< global
.lockdown_session_count
; i
++)
198 if (global
.lockdown_session_fds
[i
] == fd
)
203 if (i
!= n
) global
.lockdown_session_fds
[n
] = global
.lockdown_session_fds
[i
];
210 free(global
.lockdown_session_fds
);
211 global
.lockdown_session_fds
= NULL
;
212 global
.lockdown_session_count
= 0;
216 global
.lockdown_session_fds
= reallocf(global
.lockdown_session_fds
, n
* sizeof(int));
217 if (global
.lockdown_session_fds
== NULL
)
219 asldebug("remove_lockdown_session: realloc failed\n");
220 global
.lockdown_session_count
= 0;
224 global
.lockdown_session_count
= n
;
228 global
.watchers_active
= direct_watch_count
+ global
.lockdown_session_count
;
234 sweep_lockdown_session_fds()
238 for (i
= 0, n
= 0; i
< global
.lockdown_session_count
; i
++)
240 if (global
.lockdown_session_fds
[i
] >= 0)
242 if (i
!= n
) global
.lockdown_session_fds
[n
] = global
.lockdown_session_fds
[i
];
249 free(global
.lockdown_session_fds
);
250 global
.lockdown_session_fds
= NULL
;
251 global
.lockdown_session_count
= 0;
255 global
.lockdown_session_fds
= reallocf(global
.lockdown_session_fds
, n
* sizeof(int));
256 if (global
.lockdown_session_fds
== NULL
)
258 asldebug("sweep_lockdown_session_fds: realloc failed\n");
259 global
.lockdown_session_count
= 0;
263 global
.lockdown_session_count
= n
;
267 global
.watchers_active
= direct_watch_count
+ global
.lockdown_session_count
;
272 _internal_send_to_direct_watchers(asl_msg_t
*msg
)
274 uint32_t i
, j
, nlen
, outlen
, cleanup
, total_sent
, again
;
279 static struct timeval last_time
;
283 if (global
.lockdown_session_count
> 0)
285 if (global
.remote_delay_time
> 0)
290 if (gettimeofday(&now
, NULL
) == 0)
292 if (last_time
.tv_sec
!= 0)
294 if (now
.tv_sec
> last_time
.tv_sec
)
297 now
.tv_usec
+= 1000000;
300 delta
= now
.tv_sec
- last_time
.tv_sec
;
302 delta
+= (now
.tv_usec
- last_time
.tv_usec
);
303 if (delta
< global
.remote_delay_time
)
309 if (now
.tv_usec
>= 1000000)
312 now
.tv_usec
-= 1000000;
319 out
= asl_format_message(msg
, ASL_MSG_FMT_STD
, ASL_TIME_FMT_LCL
, ASL_ENCODE_SAFE
, &outlen
);
321 for (i
= 0; i
< global
.lockdown_session_count
; i
++)
323 if (write(global
.lockdown_session_fds
[i
], out
, outlen
) < 0)
325 asldebug("send_to_direct_watchers: lockdown %d write error: %d %s\n", global
.lockdown_session_fds
[i
], errno
, strerror(errno
));
326 close(global
.lockdown_session_fds
[i
]);
327 global
.lockdown_session_fds
[i
] = -1;
335 if (cleanup
!= 0) sweep_lockdown_session_fds();
338 if (direct_watch_count
== 0)
344 if (direct_watch
== NULL
)
346 direct_watch_count
= 0;
351 out
= asl_msg_to_string(msg
, &outlen
);
353 if (out
== NULL
) return;
355 nlen
= htonl(outlen
);
356 for (i
= 0; i
< direct_watch_count
; i
++)
358 sent
= send(direct_watch
[i
], &nlen
, sizeof(nlen
), 0);
359 if (sent
< sizeof(nlen
))
361 /* bail out if we can't send 4 bytes */
362 close(direct_watch
[i
]);
363 direct_watch
[i
] = -1;
371 while (total_sent
< outlen
)
374 sent
= send(direct_watch
[i
], out
+ total_sent
, outlen
- total_sent
, 0);
377 asldebug("send_to_direct_watchers: send returned %d (errno %d)\n", sent
, errno
);
380 if (again
> MAX_AGAIN
)
382 asldebug("send_to_direct_watchers: exceeded EAGAIN limit - closing connection\n");
393 close(direct_watch
[i
]);
394 direct_watch
[i
] = -1;
406 if (cleanup
== 0) return;
409 for (i
= 0; i
< direct_watch_count
; i
++)
411 if (direct_watch
[i
] >= 0)
415 direct_watch
[j
] = direct_watch
[i
];
416 direct_watch_port
[j
] = direct_watch_port
[i
];
422 direct_watch_count
= j
;
423 if (direct_watch_count
== 0)
428 free(direct_watch_port
);
429 direct_watch_port
= NULL
;
433 direct_watch
= reallocf(direct_watch
, direct_watch_count
* sizeof(int));
434 direct_watch_port
= reallocf(direct_watch_port
, direct_watch_count
* sizeof(uint16_t));
435 if ((direct_watch
== NULL
) || (direct_watch_port
== NULL
))
440 free(direct_watch_port
);
441 direct_watch_port
= NULL
;
443 direct_watch_count
= 0;
449 send_to_direct_watchers(asl_msg_t
*msg
)
451 dispatch_once(&watch_init_once
, ^{
452 watch_queue
= dispatch_queue_create("Direct Watch Queue", NULL
);
457 dispatch_async(watch_queue
, ^{
458 _internal_send_to_direct_watchers(msg
);
459 asl_msg_release(msg
);
464 * Called from asl_action.c to save messgaes to the ASL data store
467 db_save_message(asl_msg_t
*msg
)
470 uint32_t status
, dbtype
;
472 static dispatch_source_t timer_src
;
473 static dispatch_once_t once
;
475 dispatch_once(&once
, ^{
476 timer_src
= dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER
, 0, 0, dispatch_get_main_queue());
477 dispatch_source_set_event_handler(timer_src
, ^{
478 notify_post(kNotifyASLDBUpdate
);
479 dispatch_suspend(timer_src
);
485 send_to_direct_watchers((asl_msg_t
*)msg
);
487 dbtype
= global
.dbtype
;
489 if (asl_check_option(msg
, ASL_OPT_DB_FILE
)) dbtype
|= DB_TYPE_FILE
;
490 if (asl_check_option(msg
, ASL_OPT_DB_MEMORY
)) dbtype
|= DB_TYPE_MEMORY
;
494 if (dbtype
& DB_TYPE_FILE
)
496 status
= asl_store_save(global
.file_db
, msg
);
497 if (status
!= ASL_STATUS_OK
)
499 /* write failed - reopen & retry */
500 asldebug("asl_store_save: %s\n", asl_core_error(status
));
501 asl_store_release(global
.file_db
);
502 global
.file_db
= NULL
;
505 status
= asl_store_save(global
.file_db
, msg
);
506 if (status
!= ASL_STATUS_OK
)
508 asldebug("(retry) asl_store_save: %s\n", asl_core_error(status
));
509 asl_store_release(global
.file_db
);
510 global
.file_db
= NULL
;
512 global
.dbtype
|= DB_TYPE_MEMORY
;
513 dbtype
|= DB_TYPE_MEMORY
;
514 if (global
.memory_db
== NULL
)
516 status
= asl_memory_open(global
.db_memory_max
, global
.db_memory_str_max
, &(global
.memory_db
));
517 if (status
!= ASL_STATUS_OK
)
519 asldebug("asl_memory_open: %s\n", asl_core_error(status
));
526 if (dbtype
& DB_TYPE_MEMORY
)
529 status
= asl_memory_save(global
.memory_db
, msg
, &msgid
);
530 if (status
!= ASL_STATUS_OK
)
532 /* save failed - reopen & retry*/
533 asldebug("asl_memory_save: %s\n", asl_core_error(status
));
534 asl_memory_close(global
.memory_db
);
535 global
.memory_db
= NULL
;
539 status
= asl_memory_save(global
.memory_db
, msg
, &msgid
);
540 if (status
!= ASL_STATUS_OK
)
542 asldebug("(retry) asl_memory_save: %s\n", asl_core_error(status
));
543 asl_memory_close(global
.memory_db
);
544 global
.memory_db
= NULL
;
552 dispatch_source_set_timer(timer_src
, dispatch_time(DISPATCH_TIME_NOW
, NSEC_PER_SEC
/ 2), DISPATCH_TIME_FOREVER
, 0);
553 dispatch_resume(timer_src
);
558 disaster_message(asl_msg_t
*msg
)
565 if ((global
.dbtype
& DB_TYPE_MEMORY
) == 0)
567 if (global
.memory_db
== NULL
)
569 status
= asl_memory_open(global
.db_memory_max
, global
.db_memory_str_max
, &(global
.memory_db
));
570 if (status
!= ASL_STATUS_OK
) asldebug("asl_memory_open: %s\n", asl_core_error(status
));
571 else asl_memory_save(global
.memory_db
, msg
, &msgid
);
577 * Do a database search.
580 db_query(asl_msg_list_t
*query
, asl_msg_list_t
**res
, uint64_t startid
, int count
, uint32_t duration
, int direction
, uint64_t *lastid
, int32_t ruid
, int32_t rgid
, int raccess
)
582 uint32_t status
, ucount
;
584 struct proc_uniqidentifierinfo pinfo
;
585 const char *str
= NULL
;
588 * Special case: if count is -1, we return ASL_STATUS_OK to indicate that the store is
589 * in memory, and ASL_STATUS_INVALID_STORE to indicate that the file store is in use.
593 if (global
.dbtype
& DB_TYPE_FILE
) return ASL_STATUS_INVALID_STORE
;
594 return ASL_STATUS_OK
;
600 uuid_clear(pinfo
.p_uuid
);
601 if (proc_pidinfo(raccess
, PROC_PIDUNIQIDENTIFIERINFO
, 1, &pinfo
, sizeof(pinfo
)) == sizeof(pinfo
))
603 uuid_unparse(pinfo
.p_uuid
, ustr
);
604 str
= (const char *)ustr
;
610 status
= ASL_STATUS_FAILED
;
612 if ((global
.dbtype
& DB_TYPE_MEMORY
) || (global
.disaster_occurred
!= 0))
614 status
= asl_memory_match_restricted_uuid(global
.memory_db
, query
, res
, lastid
, startid
, ucount
, duration
, direction
, ruid
, rgid
, str
);
621 register_session(task_name_t task_name
, pid_t pid
)
623 mach_port_t previous
;
626 if (task_name
== MACH_PORT_NULL
) return;
628 if (global
.dead_session_port
== MACH_PORT_NULL
)
630 mach_port_deallocate(mach_task_self(), task_name
);
634 for (i
= 0; i
< client_tasks_count
; i
++) if (task_name
== client_tasks
[i
])
636 mach_port_deallocate(mach_task_self(), task_name
);
640 if (client_tasks_count
== 0) client_tasks
= (task_name_t
*)calloc(1, sizeof(task_name_t
));
641 else client_tasks
= (task_name_t
*)reallocf(client_tasks
, (client_tasks_count
+ 1) * sizeof(task_name_t
));
643 if (client_tasks
== NULL
)
645 mach_port_deallocate(mach_task_self(), task_name
);
649 client_tasks
[client_tasks_count
] = task_name
;
650 client_tasks_count
++;
652 asldebug("register_session: %u PID %d\n", (unsigned int)task_name
, (int)pid
);
654 /* register for port death notification */
655 mach_port_request_notification(mach_task_self(), task_name
, MACH_NOTIFY_DEAD_NAME
, 0, global
.dead_session_port
, MACH_MSG_TYPE_MAKE_SEND_ONCE
, &previous
);
656 mach_port_deallocate(mach_task_self(), previous
);
658 asl_client_count_increment();
662 cancel_session(task_name_t task_name
)
666 for (i
= 0; (i
< client_tasks_count
) && (task_name
!= client_tasks
[i
]); i
++);
668 if (i
>= client_tasks_count
) return;
670 if (client_tasks_count
== 1)
674 client_tasks_count
= 0;
678 for (i
++; i
< client_tasks_count
; i
++) client_tasks
[i
-1] = client_tasks
[i
];
679 client_tasks_count
--;
680 client_tasks
= (task_name_t
*)reallocf(client_tasks
, client_tasks_count
* sizeof(task_name_t
));
683 asldebug("cancel_session: %u\n", (unsigned int)task_name
);
685 /* we hold a send right or dead name right for the task name port */
686 mach_port_deallocate(mach_task_self(), task_name
);
687 asl_client_count_decrement();
691 register_direct_watch(uint16_t port
)
693 #if TARGET_OS_EMBEDDED
696 struct sockaddr_in address
;
698 if (port
== 0) return ASL_STATUS_FAILED
;
700 sock
= socket(AF_INET
, SOCK_STREAM
, 0);
701 if (sock
< 0) return ASL_STATUS_FAILED
;
703 address
.sin_family
= AF_INET
;
704 /* port must be sent in network byte order */
705 address
.sin_port
= port
;
706 address
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
708 if (connect(sock
, (struct sockaddr
*)&address
, sizeof(address
)) != 0) return ASL_STATUS_FAILED
;
711 setsockopt(sock
, SOL_SOCKET
, SO_NOSIGPIPE
, &i
, sizeof(i
));
714 setsockopt(sock
, IPPROTO_TCP
, TCP_NODELAY
, &i
, sizeof(i
));
716 /* make socket non-blocking */
717 flags
= fcntl(sock
, F_GETFL
, 0);
718 if (flags
== -1) flags
= 0;
719 fcntl(sock
, F_SETFL
, flags
| O_NONBLOCK
);
721 if (direct_watch_count
== 0)
723 direct_watch
= (int *)calloc(1, sizeof(int));
724 direct_watch_port
= (uint16_t *)calloc(1, sizeof(uint16_t));
728 direct_watch
= (int *)reallocf(direct_watch
, (direct_watch_count
+ 1) * sizeof(int));
729 direct_watch_port
= (uint16_t *)reallocf(direct_watch_port
, (direct_watch_count
+ 1) * sizeof(uint16_t));
732 if ((direct_watch
== NULL
) || (direct_watch_port
== NULL
))
739 free(direct_watch_port
);
740 direct_watch_port
= NULL
;
742 direct_watch_count
= 0;
743 global
.watchers_active
= 0;
744 if (global
.lockdown_session_count
> 0) global
.watchers_active
= 1;
746 return ASL_STATUS_FAILED
;
749 direct_watch
[direct_watch_count
] = sock
;
750 direct_watch_port
[direct_watch_count
] = port
;
751 direct_watch_count
++;
752 global
.watchers_active
= direct_watch_count
+ global
.lockdown_session_count
;
754 return ASL_STATUS_OK
;
756 return ASL_STATUS_FAILED
;
761 cancel_direct_watch(uint16_t port
)
763 #if TARGET_OS_EMBEDDED
766 for (i
= 0; (i
< direct_watch_count
) && (port
!= direct_watch_port
[i
]); i
++);
768 if (i
>= direct_watch_count
) return;
770 if (direct_watch_count
== 1)
775 free(direct_watch_port
);
776 direct_watch_port
= NULL
;
778 direct_watch_count
= 0;
779 global
.watchers_active
= 0;
780 if (global
.lockdown_session_count
> 0) global
.watchers_active
= 1;
784 for (i
++; i
< direct_watch_count
; i
++)
786 direct_watch
[i
-1] = direct_watch
[i
];
787 direct_watch_port
[i
-1] = direct_watch_port
[i
];
790 direct_watch_count
--;
791 global
.watchers_active
= direct_watch_count
+ global
.lockdown_session_count
;
793 direct_watch
= (int *)reallocf(direct_watch
, direct_watch_count
* sizeof(int));
794 direct_watch_port
= (uint16_t *)reallocf(direct_watch_port
, direct_watch_count
* sizeof(uint16_t));
796 if ((direct_watch
== NULL
) || (direct_watch_port
== NULL
))
801 free(direct_watch_port
);
802 direct_watch_port
= NULL
;
804 direct_watch_count
= 0;
805 global
.watchers_active
= 0;
806 if (global
.lockdown_session_count
> 0) global
.watchers_active
= 1;
813 syslogd_state_query(asl_msg_t
*q
, asl_msg_list_t
**res
, uid_t uid
)
821 asl_out_module_t
*om
;
823 if (res
== NULL
) return ASL_STATUS_INVALID_ARG
;
826 out
= asl_msg_list_new();
827 if (out
== NULL
) return ASL_STATUS_NO_MEMORY
;
829 m
= asl_msg_new(ASL_TYPE_MSG
);
832 asl_msg_list_release(out
);
833 return ASL_STATUS_NO_MEMORY
;
836 asl_msg_list_append(out
, m
);
838 /* q must have [ASLOption control], so a "null" query really has count == 1 */
839 if (asl_msg_count(q
) == 1) all
= true;
841 if (all
|| (0 == asl_msg_lookup(q
, "debug", NULL
, NULL
)))
843 if (global
.debug
== 0) snprintf(val
, sizeof(val
), "0");
844 else snprintf(val
, sizeof(val
), "1 %s", global
.debug_file
);
845 asl_msg_set_key_val(m
, "debug", val
);
848 if (all
|| (0 == asl_msg_lookup(q
, "dbtype", NULL
, NULL
)))
851 if (global
.dbtype
& DB_TYPE_FILE
) n
++;
852 if (global
.dbtype
& DB_TYPE_MEMORY
) n
++;
856 asl_msg_set_key_val(m
, "dbtype", "unknown");
861 memset(val
, 0, sizeof(val
));
863 if (global
.dbtype
& DB_TYPE_FILE
)
866 strncat(val
, "file", 4);
867 if (i
< n
) strncat(val
, " ", 1);
870 if (global
.dbtype
& DB_TYPE_MEMORY
)
873 strncat(val
, "memory", 6);
874 if (i
< n
) strncat(val
, " ", 1);
877 asl_msg_set_key_val(m
, "dbtype", val
);
881 if (all
|| (0 == asl_msg_lookup(q
, "db_file_max", NULL
, NULL
)))
883 snprintf(val
, sizeof(val
), "%u", global
.db_file_max
);
884 asl_msg_set_key_val(m
, "db_file_max", val
);
887 if (all
|| (0 == asl_msg_lookup(q
, "db_memory_max", NULL
, NULL
)))
889 snprintf(val
, sizeof(val
), "%u", global
.db_memory_max
);
890 asl_msg_set_key_val(m
, "db_memory_max", val
);
893 if (all
|| (0 == asl_msg_lookup(q
, "db_memory_str_max", NULL
, NULL
)))
895 snprintf(val
, sizeof(val
), "%u", global
.db_memory_str_max
);
896 asl_msg_set_key_val(m
, "db_memory_str_max", val
);
899 if (all
|| (0 == asl_msg_lookup(q
, "mps_limit", NULL
, NULL
)))
901 snprintf(val
, sizeof(val
), "%u", global
.mps_limit
);
902 asl_msg_set_key_val(m
, "mps_limit", val
);
905 if (all
|| (0 == asl_msg_lookup(q
, "bsd_max_dup_time", NULL
, NULL
)))
907 snprintf(val
, sizeof(val
), "%llu", global
.bsd_max_dup_time
);
908 asl_msg_set_key_val(m
, "bsd_max_dup_time", val
);
911 if (all
|| (0 == asl_msg_lookup(q
, "mark_time", NULL
, NULL
)))
913 snprintf(val
, sizeof(val
), "%llu", global
.mark_time
);
914 asl_msg_set_key_val(m
, "mark_time", val
);
917 if (all
|| (0 == asl_msg_lookup(q
, "utmp_ttl", NULL
, NULL
)))
919 snprintf(val
, sizeof(val
), "%lu", global
.utmp_ttl
);
920 asl_msg_set_key_val(m
, "utmp_ttl", val
);
923 if (all
|| (0 == asl_msg_lookup(q
, "max_work_queue_size", NULL
, NULL
)))
925 snprintf(val
, sizeof(val
), "%lld", global
.max_work_queue_size
);
926 asl_msg_set_key_val(m
, "max_work_queue_size", val
);
929 if (all
|| (0 == asl_msg_lookup(q
, "work_queue_count", NULL
, NULL
)))
931 snprintf(val
, sizeof(val
), "%d", global
.work_queue_count
);
932 asl_msg_set_key_val(m
, "work_queue_count", val
);
935 if (all
|| (0 == asl_msg_lookup(q
, "asl_queue_count", NULL
, NULL
)))
937 snprintf(val
, sizeof(val
), "%d", global
.asl_queue_count
);
938 asl_msg_set_key_val(m
, "asl_queue_count", val
);
941 if (all
|| (0 == asl_msg_lookup(q
, "bsd_queue_count", NULL
, NULL
)))
943 snprintf(val
, sizeof(val
), "%d", global
.bsd_queue_count
);
944 asl_msg_set_key_val(m
, "bsd_queue_count", val
);
947 if (all
|| (0 == asl_msg_lookup(q
, "client_count", NULL
, NULL
)))
949 snprintf(val
, sizeof(val
), "%d", global
.client_count
);
950 asl_msg_set_key_val(m
, "client_count", val
);
953 if (all
|| (0 == asl_msg_lookup(q
, "disaster_occurred", NULL
, NULL
)))
955 snprintf(val
, sizeof(val
), "%d", global
.disaster_occurred
);
956 asl_msg_set_key_val(m
, "disaster_occurred", val
);
960 if (all
|| (0 == asl_msg_lookup(q
, "lockdown_session_count", NULL
, NULL
)))
962 snprintf(val
, sizeof(val
), "%d", global
.lockdown_session_count
);
963 asl_msg_set_key_val(m
, "lockdown_session_count", val
);
966 if (all
|| (0 == asl_msg_lookup(q
, "remote_delay_time", NULL
, NULL
)))
968 snprintf(val
, sizeof(val
), "%u", global
.remote_delay_time
);
969 asl_msg_set_key_val(m
, "remote_delay_time", val
);
974 if (all
|| (0 == asl_msg_lookup(q
, "watchers_active", NULL
, NULL
)))
976 snprintf(val
, sizeof(val
), "%d", global
.watchers_active
);
977 asl_msg_set_key_val(m
, "watchers_active", val
);
980 for (i
= 0; i
< global
.module_count
; i
++)
982 if (all
|| (0 == asl_msg_lookup(q
, global
.module[i
]->name
, NULL
, NULL
)))
984 snprintf(val
, sizeof(val
), "%s", global
.module[i
]->enabled
? "enabled" : "disabled");
985 asl_msg_set_key_val(m
, global
.module[i
]->name
, val
);
989 for (om
= global
.asl_out_module
; om
!= NULL
; om
= om
->next
)
991 if (all
|| (0 == asl_msg_lookup(q
, om
->name
, NULL
, NULL
)))
993 snprintf(val
, sizeof(val
), "%s", om
->flags
& MODULE_FLAG_ENABLED
? "enabled" : "disabled");
994 if (om
->name
== NULL
) asl_msg_set_key_val(m
, "asl.conf", val
);
995 else asl_msg_set_key_val(m
, om
->name
, val
);
999 /* synchronous actions use queries, since messages are simpleroutines */
1000 if (0 == asl_msg_lookup(q
, "action", &mval
, NULL
))
1003 if (uid
== 0) res
= asl_action_control_set_param(mval
);
1004 snprintf(val
, sizeof(val
), "%d", res
);
1005 asl_msg_set_key_val(m
, "action", val
);
1010 return ASL_STATUS_OK
;
1014 * Receives messages on the "com.apple.system.logger" mach port.
1015 * Services database search requests.
1016 * Runs in it's own thread.
1021 asl_request_msg
*request
;
1023 struct timeval now
, send_time
;
1024 mach_dead_name_notification_t
*deadname
;
1025 const uint32_t rbits
= MACH_RCV_MSG
| MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT
) | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0
) | MACH_RCV_VOUCHER
;
1027 send_time
.tv_sec
= 0;
1028 send_time
.tv_usec
= 0;
1030 rqs
= sizeof(asl_request_msg
) + MAX_TRAILER_SIZE
;
1032 asl_server_queue
= dispatch_queue_create("ASL Server Queue", NULL
);
1041 request
= (asl_request_msg
*)calloc(1, rqs
);
1042 if (request
== NULL
) continue;
1044 request
->head
.msgh_local_port
= global
.server_port
;
1045 request
->head
.msgh_size
= rqs
;
1047 ks
= mach_msg(&(request
->head
), rbits
, 0, rqs
, global
.listen_set
, 0, MACH_PORT_NULL
);
1048 if (ks
!= KERN_SUCCESS
)
1051 * This shouldn't happen, but if we get a failure the best thing to do is to crash.
1054 asldebug("FATAL ERROR: mach_msg() receive failed with status 0x%08x\n", ks
);
1055 snprintf(str
, sizeof(str
), "[Sender syslogd] [Level 1] [PID %u] [Facility syslog] [Message FATAL ERROR: mach_msg() receive failed with status 0x%08x]", global
.pid
, ks
);
1056 internal_log_message(str
);
1061 if (request
->head
.msgh_id
== MACH_NOTIFY_DEAD_NAME
)
1063 deadname
= (mach_dead_name_notification_t
*)request
;
1064 dispatch_async(asl_server_queue
, ^{
1065 cancel_session(deadname
->not_port
);
1066 /* dead name notification includes a dead name right */
1067 mach_port_deallocate(mach_task_self(), deadname
->not_port
);
1074 dispatch_async(asl_server_queue
, ^{
1075 const uint32_t sbits
= MACH_SEND_MSG
| MACH_SEND_TIMEOUT
;;
1077 asl_reply_msg
*reply
= calloc(1, sizeof(asl_reply_msg
) + MAX_TRAILER_SIZE
);
1079 voucher_mach_msg_state_t voucher
= voucher_mach_msg_adopt(&(request
->head
));
1081 /* MIG server routine */
1082 asl_ipc_server(&(request
->head
), &(reply
->head
));
1084 if (!(reply
->head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
))
1086 if (reply
->reply
.Reply__asl_server_message
.RetCode
== MIG_NO_REPLY
)
1088 reply
->head
.msgh_remote_port
= MACH_PORT_NULL
;
1090 else if ((reply
->reply
.Reply__asl_server_message
.RetCode
!= KERN_SUCCESS
) && (request
->head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
))
1092 /* destroy the request - but not the reply port */
1093 request
->head
.msgh_remote_port
= MACH_PORT_NULL
;
1094 mach_msg_destroy(&(request
->head
));
1098 if (reply
->head
.msgh_remote_port
!= MACH_PORT_NULL
)
1100 ks
= mach_msg(&(reply
->head
), sbits
, reply
->head
.msgh_size
, 0, MACH_PORT_NULL
, 10, MACH_PORT_NULL
);
1101 if ((ks
== MACH_SEND_INVALID_DEST
) || (ks
== MACH_SEND_TIMED_OUT
))
1104 mach_msg_destroy(&(reply
->head
));
1106 else if (ks
== MACH_SEND_INVALID_HEADER
)
1109 * This should never happen, but we can continue running.
1112 asldebug("ERROR: mach_msg() send failed with MACH_SEND_INVALID_HEADER 0x%08x\n", ks
);
1113 snprintf(str
, sizeof(str
), "[Sender syslogd] [Level 3] [PID %u] [Facility syslog] [Message mach_msg() send failed with status 0x%08x (MACH_SEND_INVALID_HEADER)]", global
.pid
, ks
);
1114 internal_log_message(str
);
1115 mach_msg_destroy(&(reply
->head
));
1117 else if (ks
== MACH_SEND_NO_BUFFER
)
1120 * This should never happen, but the kernel can run out of memory.
1121 * We clean up and continue running.
1124 asldebug("ERROR: mach_msg() send failed with MACH_SEND_NO_BUFFER 0x%08x\n", ks
);
1125 snprintf(str
, sizeof(str
), "[Sender syslogd] [Level 3] [PID %u] [Facility syslog] [Message mach_msg() send failed with status 0x%08x (MACH_SEND_NO_BUFFER)]", global
.pid
, ks
);
1126 internal_log_message(str
);
1127 mach_msg_destroy(&(reply
->head
));
1129 else if (ks
!= KERN_SUCCESS
)
1132 * Failed to send a reply message. This should never happen,
1133 * but the best action is to crash.
1136 asldebug("FATAL ERROR: mach_msg() send failed with status 0x%08x\n", ks
);
1137 snprintf(str
, sizeof(str
), "[Sender syslogd] [Level 1] [PID %u] [Facility syslog] [Message FATAL ERROR: mach_msg() send failed with status 0x%08x]", global
.pid
, ks
);
1138 internal_log_message(str
);
1143 else if (reply
->head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
)
1145 mach_msg_destroy(&reply
->head
);
1148 voucher_mach_msg_revert(voucher
);
1156 caller_get_read_entitlement(pid_t pid
, uid_t
*uid
, gid_t
*gid
)
1158 #if TARGET_OS_EMBEDDED
1159 xpc_object_t edata
, entitlements
, val
;
1165 edata
= xpc_copy_entitlements_for_pid(pid
);
1166 if (edata
== NULL
) return;
1168 ptr
= xpc_data_get_bytes_ptr(edata
);
1169 len
= xpc_data_get_length(edata
);
1171 entitlements
= xpc_create_from_plist(ptr
, len
);
1173 if (entitlements
== NULL
) return;
1175 if (xpc_get_type(entitlements
) != XPC_TYPE_DICTIONARY
)
1177 asldebug("xpc_copy_entitlements_for_pid has non-dictionary data for pid %d\n", pid
);
1181 bval
= xpc_dictionary_get_bool(entitlements
, ASL_ENTITLEMENT_KEY
);
1182 if (bval
&& (uid
!= NULL
))
1185 xpc_release(entitlements
);
1189 val
= xpc_dictionary_get_value(entitlements
, ASL_ENTITLEMENT_UID_KEY
);
1192 if ((xpc_get_type(val
) == XPC_TYPE_INT64
) && (uid
!= NULL
))
1194 ival
= xpc_int64_get_value(val
);
1199 val
= xpc_dictionary_get_value(entitlements
, ASL_ENTITLEMENT_GID_KEY
);
1202 if ((xpc_get_type(val
) == XPC_TYPE_INT64
) && (gid
!= NULL
))
1204 ival
= xpc_int64_get_value(val
);
1209 xpc_release(entitlements
);
1213 static kern_return_t
1214 __asl_server_query_internal
1218 mach_msg_type_number_t requestCnt
,
1224 mach_msg_type_number_t
*replyCnt
,
1232 asl_msg_list_t
*query
;
1233 asl_msg_list_t
*res
;
1234 char *out
, *vmbuffer
;
1236 kern_return_t kstatus
;
1238 *status
= ASL_STATUS_OK
;
1240 if ((request
!= NULL
) && (request
[requestCnt
- 1] != '\0'))
1242 *status
= ASL_STATUS_INVALID_ARG
;
1243 vm_deallocate(mach_task_self(), (vm_address_t
)request
, requestCnt
);
1244 return KERN_SUCCESS
;
1247 query
= asl_msg_list_from_string(request
);
1248 if (request
!= NULL
) vm_deallocate(mach_task_self(), (vm_address_t
)request
, requestCnt
);
1251 /* A query list containing a single query, which itself contains
1252 * [ASLOption control] is an internal state query */
1253 if ((query
!= NULL
) && (query
->count
== 1) && asl_check_option(query
->msg
[0], ASL_OPT_CONTROL
))
1255 *status
= syslogd_state_query(query
->msg
[0], &res
, uid
);
1260 #if TARGET_OS_EMBEDDED
1266 caller_get_read_entitlement(pid
, &uid
, &gid
);
1267 if (uid
== 0) x
= 0;
1270 *status
= db_query(query
, &res
, startid
, count
, duration
, direction
, lastid
, uid
, gid
, x
);
1273 asl_msg_list_release(query
);
1274 if (*status
!= ASL_STATUS_INVALID_STORE
)
1278 else if (*status
!= ASL_STATUS_OK
)
1280 if (res
!= NULL
) asl_msg_list_release(res
);
1281 return KERN_SUCCESS
;
1286 out
= asl_msg_list_to_string(res
, &outlen
);
1287 asl_msg_list_release(res
);
1289 if ((out
== NULL
) || (outlen
== 0)) return KERN_SUCCESS
;
1291 kstatus
= vm_allocate(mach_task_self(), (vm_address_t
*)&vmbuffer
, outlen
, TRUE
);
1292 if (kstatus
!= KERN_SUCCESS
)
1298 memmove(vmbuffer
, out
, outlen
);
1304 return KERN_SUCCESS
;
1308 __asl_server_query_2
1312 mach_msg_type_number_t requestCnt
,
1317 mach_msg_type_number_t
*replyCnt
,
1323 uid_t uid
= (uid_t
)-1;
1324 gid_t gid
= (gid_t
)-1;
1325 pid_t pid
= (pid_t
)-1;
1327 int direction
= SEARCH_FORWARD
;
1328 if (flags
& QUERY_FLAG_SEARCH_REVERSE
) direction
= SEARCH_BACKWARD
;
1330 audit_token_to_au32(token
, NULL
, &uid
, &gid
, NULL
, NULL
, &pid
, NULL
, NULL
);
1332 return __asl_server_query_internal(server
, request
, requestCnt
, startid
, count
, QUERY_DURATION_UNLIMITED
, direction
, reply
, replyCnt
, lastid
, status
, uid
, gid
, pid
);
1340 mach_msg_type_number_t requestCnt
,
1345 mach_msg_type_number_t
*replyCnt
,
1348 security_token_t
*token
1351 int direction
= SEARCH_FORWARD
;
1352 if (flags
& QUERY_FLAG_SEARCH_REVERSE
) direction
= SEARCH_BACKWARD
;
1354 return __asl_server_query_internal(server
, request
, requestCnt
, startid
, count
, QUERY_DURATION_UNLIMITED
, direction
, reply
, replyCnt
, lastid
, status
, (uid_t
)token
->val
[0], (gid_t
)token
->val
[1], (pid_t
)-1);
1358 __asl_server_query_timeout
1362 mach_msg_type_number_t requestCnt
,
1367 mach_msg_type_number_t
*replyCnt
,
1373 uid_t uid
= (uid_t
)-1;
1374 gid_t gid
= (gid_t
)-1;
1375 pid_t pid
= (pid_t
)-1;
1376 int direction
= SEARCH_FORWARD
;
1377 if (flags
& QUERY_FLAG_SEARCH_REVERSE
) direction
= SEARCH_BACKWARD
;
1379 audit_token_to_au32(token
, NULL
, &uid
, &gid
, NULL
, NULL
, &pid
, NULL
, NULL
);
1381 return __asl_server_query_internal(server
, request
, requestCnt
, startid
, count
, QUERY_DURATION_UNLIMITED
, direction
, reply
, replyCnt
, lastid
, status
, uid
, gid
, pid
);
1389 mach_msg_type_number_t requestCnt
,
1395 mach_msg_type_number_t
*replyCnt
,
1401 uid_t uid
= (uid_t
)-1;
1402 gid_t gid
= (gid_t
)-1;
1403 pid_t pid
= (pid_t
)-1;
1405 audit_token_to_au32(token
, NULL
, &uid
, &gid
, NULL
, NULL
, &pid
, NULL
, NULL
);
1407 return __asl_server_query_internal(server
, request
, requestCnt
, startid
, count
, duration
, direction
, reply
, replyCnt
, lastid
, status
, uid
, gid
, pid
);
1415 mach_msg_type_number_t requestCnt
,
1417 security_token_t
*token
1420 return KERN_SUCCESS
;
1424 __asl_server_message
1428 mach_msg_type_number_t messageCnt
,
1437 kern_return_t kstatus
;
1438 mach_port_name_t client
;
1440 if (message
== NULL
)
1442 return KERN_SUCCESS
;
1445 if (message
[messageCnt
- 1] != '\0')
1447 vm_deallocate(mach_task_self(), (vm_address_t
)message
, messageCnt
);
1448 return KERN_SUCCESS
;
1451 asldebug("__asl_server_message: %s\n", (message
== NULL
) ? "NULL" : message
);
1453 msg
= asl_msg_from_string(message
);
1454 vm_deallocate(mach_task_self(), (vm_address_t
)message
, messageCnt
);
1456 if (msg
== NULL
) return KERN_SUCCESS
;
1461 audit_token_to_au32(token
, NULL
, &uid
, &gid
, NULL
, NULL
, &pid
, NULL
, NULL
);
1463 client
= MACH_PORT_NULL
;
1464 kstatus
= task_name_for_pid(mach_task_self(), pid
, &client
);
1465 if (kstatus
== KERN_SUCCESS
) register_session(client
, pid
);
1467 snprintf(tmp
, sizeof(tmp
), "%d", uid
);
1468 asl_msg_set_key_val(msg
, ASL_KEY_UID
, tmp
);
1470 snprintf(tmp
, sizeof(tmp
), "%d", gid
);
1471 asl_msg_set_key_val(msg
, ASL_KEY_GID
, tmp
);
1473 snprintf(tmp
, sizeof(tmp
), "%d", pid
);
1474 asl_msg_set_key_val(msg
, ASL_KEY_PID
, tmp
);
1476 process_message(msg
, SOURCE_ASL_MESSAGE
);
1478 return KERN_SUCCESS
;
1482 __asl_server_create_aux_link
1486 mach_msg_type_number_t messageCnt
,
1487 mach_port_t
*fileport
,
1489 mach_msg_type_number_t
*newurlCnt
,
1499 kern_return_t kstatus
;
1500 mach_port_name_t client
;
1501 char *url
, *vmbuffer
;
1504 *status
= ASL_STATUS_OK
;
1505 *fileport
= MACH_PORT_NULL
;
1508 if (message
== NULL
)
1510 *status
= ASL_STATUS_INVALID_ARG
;
1511 return KERN_SUCCESS
;
1514 if (message
[messageCnt
- 1] != '\0')
1516 *status
= ASL_STATUS_INVALID_ARG
;
1517 vm_deallocate(mach_task_self(), (vm_address_t
)message
, messageCnt
);
1518 return KERN_SUCCESS
;
1521 asldebug("__asl_server_create_aux_link: %s\n", (message
== NULL
) ? "NULL" : message
);
1523 if ((global
.dbtype
& DB_TYPE_FILE
) == 0)
1525 *status
= ASL_STATUS_INVALID_STORE
;
1526 return KERN_SUCCESS
;
1529 *fileport
= MACH_PORT_NULL
;
1531 msg
= asl_msg_from_string(message
);
1532 vm_deallocate(mach_task_self(), (vm_address_t
)message
, messageCnt
);
1534 if (msg
== NULL
) return KERN_SUCCESS
;
1539 audit_token_to_au32(token
, NULL
, &uid
, &gid
, NULL
, NULL
, &pid
, NULL
, NULL
);
1541 client
= MACH_PORT_NULL
;
1542 kstatus
= task_name_for_pid(mach_task_self(), pid
, &client
);
1543 if (kstatus
== KERN_SUCCESS
) register_session(client
, pid
);
1545 snprintf(tmp
, sizeof(tmp
), "%d", uid
);
1546 asl_msg_set_key_val(msg
, ASL_KEY_UID
, tmp
);
1548 snprintf(tmp
, sizeof(tmp
), "%d", gid
);
1549 asl_msg_set_key_val(msg
, ASL_KEY_GID
, tmp
);
1551 snprintf(tmp
, sizeof(tmp
), "%d", pid
);
1552 asl_msg_set_key_val(msg
, ASL_KEY_PID
, tmp
);
1554 /* create a file for the client */
1555 *status
= asl_store_open_aux(global
.file_db
, msg
, &fd
, &url
);
1556 asl_msg_release(msg
);
1557 if (*status
!= ASL_STATUS_OK
) return KERN_SUCCESS
;
1560 if (fd
>= 0) close(fd
);
1561 *status
= ASL_STATUS_FAILED
;
1562 return KERN_SUCCESS
;
1565 if (fileport_makeport(fd
, (fileport_t
*)fileport
) < 0)
1569 *status
= ASL_STATUS_FAILED
;
1570 return KERN_SUCCESS
;
1575 *newurlCnt
= strlen(url
) + 1;
1577 kstatus
= vm_allocate(mach_task_self(), (vm_address_t
*)&vmbuffer
, *newurlCnt
, TRUE
);
1578 if (kstatus
!= KERN_SUCCESS
)
1584 memmove(vmbuffer
, url
, *newurlCnt
);
1589 return KERN_SUCCESS
;
1593 __asl_server_register_direct_watch
1600 uint16_t p16
= port
;
1601 pid_t pid
= (pid_t
)-1;
1603 audit_token_to_au32(token
, NULL
, NULL
, NULL
, NULL
, NULL
, &pid
, NULL
, NULL
);
1605 asldebug("__asl_server_register_direct_watch: pid %u port %hu\n", pid
, ntohs(p16
));
1607 dispatch_once(&watch_init_once
, ^{
1608 watch_queue
= dispatch_queue_create("Direct Watch Queue", NULL
);
1611 dispatch_async(watch_queue
, ^{ register_direct_watch(p16
); });
1613 return KERN_SUCCESS
;
1617 __asl_server_cancel_direct_watch
1624 uint16_t p16
= port
;
1626 asldebug("__asl_server_cancel_direct_watch: %hu\n", ntohs(p16
));
1628 dispatch_once(&watch_init_once
, ^{
1629 watch_queue
= dispatch_queue_create("Direct Watch Queue", NULL
);
1632 dispatch_async(watch_queue
, ^{ cancel_direct_watch(p16
); });
1634 return KERN_SUCCESS
;