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 SEARCH_FORWARD 1
65 #define SEARCH_BACKWARD -1
69 #define ASL_ENTITLEMENT_KEY "com.apple.asl.access_as_root"
70 #define ASL_ENTITLEMENT_UID_KEY "com.apple.asl.access_as_uid"
71 #define ASL_ENTITLEMENT_GID_KEY "com.apple.asl.access_as_gid"
73 static dispatch_queue_t asl_server_queue
;
74 static dispatch_queue_t watch_queue
;
75 static dispatch_once_t watch_init_once
;
77 extern char *asl_list_to_string(asl_search_result_t
*list
, uint32_t *outlen
);
78 extern asl_search_result_t
*asl_list_from_string(const char *buf
);
79 extern boolean_t
asl_ipc_server(mach_msg_header_t
*InHeadP
, mach_msg_header_t
*OutHeadP
);
80 extern uint32_t bb_convert(const char *name
);
82 static task_name_t
*client_tasks
= NULL
;
83 static uint32_t client_tasks_count
= 0;
85 static int *direct_watch
= NULL
;
86 /* N.B. ports are in network byte order */
87 static uint16_t *direct_watch_port
= NULL
;
88 static uint32_t direct_watch_count
= 0;
92 mach_msg_header_t head
;
93 union __RequestUnion__asl_ipc_subsystem request
;
98 mach_msg_header_t head
;
99 union __ReplyUnion__asl_ipc_subsystem reply
;
103 db_asl_open(uint32_t dbtype
)
108 if ((dbtype
& DB_TYPE_FILE
) && (global
.file_db
== NULL
))
110 memset(&sb
, 0, sizeof(struct stat
));
111 if (stat(PATH_ASL_STORE
, &sb
) == 0)
113 /* must be a directory */
114 if (!S_ISDIR(sb
.st_mode
))
116 asldebug("error: %s is not a directory", PATH_ASL_STORE
);
124 /* /var/log/asl doesn't exist - create it */
125 if (mkdir(PATH_ASL_STORE
, 0755) != 0)
127 asldebug("error: can't create data store %s: %s\n", PATH_ASL_STORE
, strerror(errno
));
133 /* stat failed for some other reason */
134 asldebug("error: can't stat data store %s: %s\n", PATH_ASL_STORE
, strerror(errno
));
140 * One-time store conversion from the old "LongTTL" style to the new "Best Before" style.
141 * bb_convert returns quickly if the store has already been converted.
143 status
= bb_convert(PATH_ASL_STORE
);
144 if (status
!= ASL_STATUS_OK
)
146 asldebug("ASL data store conversion failed!: %s\n", asl_core_error(status
));
149 status
= asl_store_open_write(NULL
, &(global
.file_db
));
150 if (status
!= ASL_STATUS_OK
)
152 asldebug("asl_store_open_write: %s\n", asl_core_error(status
));
156 if (global
.db_file_max
!= 0) asl_store_max_file_size(global
.file_db
, global
.db_file_max
);
157 asl_trigger_aslmanager();
161 if ((dbtype
& DB_TYPE_MEMORY
) && (global
.memory_db
== NULL
))
163 status
= asl_memory_open(global
.db_memory_max
, &(global
.memory_db
));
164 if (status
!= ASL_STATUS_OK
)
166 asldebug("asl_memory_open: %s\n", asl_core_error(status
));
170 if ((dbtype
& DB_TYPE_MINI
) && (global
.mini_db
== NULL
))
172 status
= asl_mini_memory_open(global
.db_mini_max
, &(global
.mini_db
));
173 if (status
!= ASL_STATUS_OK
)
175 asldebug("asl_mini_memory_open: %s\n", asl_core_error(status
));
181 add_lockdown_session(int fd
)
183 dispatch_once(&watch_init_once
, ^{
184 watch_queue
= dispatch_queue_create("Direct Watch Queue", NULL
);
187 dispatch_async(watch_queue
, ^{
188 if (global
.lockdown_session_count
== 0) global
.lockdown_session_fds
= NULL
;
190 global
.lockdown_session_fds
= reallocf(global
.lockdown_session_fds
, global
.lockdown_session_count
+ 1 * sizeof(int));
192 if (global
.lockdown_session_fds
== NULL
)
194 asldebug("add_lockdown_session: realloc failed\n");
195 global
.lockdown_session_count
= 0;
199 global
.lockdown_session_fds
[global
.lockdown_session_count
++] = fd
;
202 global
.watchers_active
= direct_watch_count
+ global
.lockdown_session_count
;
207 remove_lockdown_session(int fd
)
209 dispatch_once(&watch_init_once
, ^{
210 watch_queue
= dispatch_queue_create("Direct Watch Queue", NULL
);
213 dispatch_async(watch_queue
, ^{
216 for (i
= 0, n
= 0; i
< global
.lockdown_session_count
; i
++)
218 if (global
.lockdown_session_fds
[i
] == fd
)
223 if (i
!= n
) global
.lockdown_session_fds
[n
] = global
.lockdown_session_fds
[i
];
230 free(global
.lockdown_session_fds
);
231 global
.lockdown_session_fds
= NULL
;
232 global
.lockdown_session_count
= 0;
236 global
.lockdown_session_fds
= reallocf(global
.lockdown_session_fds
, n
* sizeof(int));
237 if (global
.lockdown_session_fds
== NULL
)
239 asldebug("remove_lockdown_session: realloc failed\n");
240 global
.lockdown_session_count
= 0;
244 global
.lockdown_session_count
= n
;
248 global
.watchers_active
= direct_watch_count
+ global
.lockdown_session_count
;
254 sweep_lockdown_session_fds()
258 for (i
= 0, n
= 0; i
< global
.lockdown_session_count
; i
++)
260 if (global
.lockdown_session_fds
[i
] >= 0)
262 if (i
!= n
) global
.lockdown_session_fds
[n
] = global
.lockdown_session_fds
[i
];
269 free(global
.lockdown_session_fds
);
270 global
.lockdown_session_fds
= NULL
;
271 global
.lockdown_session_count
= 0;
275 global
.lockdown_session_fds
= reallocf(global
.lockdown_session_fds
, n
* sizeof(int));
276 if (global
.lockdown_session_fds
== NULL
)
278 asldebug("sweep_lockdown_session_fds: realloc failed\n");
279 global
.lockdown_session_count
= 0;
283 global
.lockdown_session_count
= n
;
287 global
.watchers_active
= direct_watch_count
+ global
.lockdown_session_count
;
292 _internal_send_to_direct_watchers(asl_msg_t
*msg
)
294 uint32_t i
, j
, nlen
, outlen
, cleanup
, total_sent
, again
;
299 static struct timeval last_time
;
303 if (global
.lockdown_session_count
> 0)
305 if (global
.remote_delay_time
> 0)
310 if (gettimeofday(&now
, NULL
) == 0)
312 if (last_time
.tv_sec
!= 0)
314 if (now
.tv_sec
> last_time
.tv_sec
)
317 now
.tv_usec
+= 1000000;
320 delta
= now
.tv_sec
- last_time
.tv_sec
;
322 delta
+= (now
.tv_usec
- last_time
.tv_usec
);
323 if (delta
< global
.remote_delay_time
)
329 if (now
.tv_usec
>= 1000000)
332 now
.tv_usec
-= 1000000;
339 out
= asl_format_message(msg
, ASL_MSG_FMT_STD
, ASL_TIME_FMT_LCL
, ASL_ENCODE_SAFE
, &outlen
);
341 for (i
= 0; i
< global
.lockdown_session_count
; i
++)
343 if (write(global
.lockdown_session_fds
[i
], out
, outlen
) < 0)
345 asldebug("send_to_direct_watchers: lockdown %d write error: %d %s\n", global
.lockdown_session_fds
[i
], errno
, strerror(errno
));
346 close(global
.lockdown_session_fds
[i
]);
347 global
.lockdown_session_fds
[i
] = -1;
355 if (cleanup
!= 0) sweep_lockdown_session_fds();
358 if (direct_watch_count
== 0)
364 if (direct_watch
== NULL
)
366 direct_watch_count
= 0;
371 out
= asl_msg_to_string(msg
, &outlen
);
373 if (out
== NULL
) return;
375 nlen
= htonl(outlen
);
376 for (i
= 0; i
< direct_watch_count
; i
++)
378 sent
= send(direct_watch
[i
], &nlen
, sizeof(nlen
), 0);
379 if (sent
< sizeof(nlen
))
381 /* bail out if we can't send 4 bytes */
382 close(direct_watch
[i
]);
383 direct_watch
[i
] = -1;
391 while (total_sent
< outlen
)
394 sent
= send(direct_watch
[i
], out
+ total_sent
, outlen
- total_sent
, 0);
397 asldebug("send_to_direct_watchers: send returned %d (errno %d)\n", sent
, errno
);
400 if (again
> MAX_AGAIN
)
402 asldebug("send_to_direct_watchers: exceeded EAGAIN limit - closing connection\n");
413 close(direct_watch
[i
]);
414 direct_watch
[i
] = -1;
426 if (cleanup
== 0) return;
429 for (i
= 0; i
< direct_watch_count
; i
++)
431 if (direct_watch
[i
] >= 0)
435 direct_watch
[j
] = direct_watch
[i
];
436 direct_watch_port
[j
] = direct_watch_port
[i
];
442 direct_watch_count
= j
;
443 if (direct_watch_count
== 0)
448 free(direct_watch_port
);
449 direct_watch_port
= NULL
;
453 direct_watch
= reallocf(direct_watch
, direct_watch_count
* sizeof(int));
454 direct_watch_port
= reallocf(direct_watch_port
, direct_watch_count
* sizeof(uint16_t));
455 if ((direct_watch
== NULL
) || (direct_watch_port
== NULL
))
460 free(direct_watch_port
);
461 direct_watch_port
= NULL
;
463 direct_watch_count
= 0;
469 send_to_direct_watchers(asl_msg_t
*msg
)
471 dispatch_once(&watch_init_once
, ^{
472 watch_queue
= dispatch_queue_create("Direct Watch Queue", NULL
);
477 dispatch_async(watch_queue
, ^{
478 _internal_send_to_direct_watchers(msg
);
479 asl_msg_release(msg
);
484 * Called from asl_action.c to save messgaes to the ASL data store
487 db_save_message(aslmsg msg
)
490 uint32_t status
, dbtype
;
492 static dispatch_source_t timer_src
;
493 static dispatch_once_t once
;
495 dispatch_once(&once
, ^{
496 timer_src
= dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER
, 0, 0, dispatch_get_main_queue());
497 dispatch_source_set_event_handler(timer_src
, ^{
498 notify_post(kNotifyASLDBUpdate
);
499 dispatch_suspend(timer_src
);
505 send_to_direct_watchers((asl_msg_t
*)msg
);
507 dbtype
= global
.dbtype
;
509 if (asl_check_option(msg
, ASL_OPT_DB_FILE
)) dbtype
|= DB_TYPE_FILE
;
510 if (asl_check_option(msg
, ASL_OPT_DB_MINI
)) dbtype
|= DB_TYPE_MINI
;
511 if (asl_check_option(msg
, ASL_OPT_DB_MEMORY
)) dbtype
|= DB_TYPE_MEMORY
;
515 if (dbtype
& DB_TYPE_FILE
)
517 status
= asl_store_save(global
.file_db
, msg
);
518 if (status
!= ASL_STATUS_OK
)
520 /* write failed - reopen & retry */
521 asldebug("asl_store_save: %s\n", asl_core_error(status
));
522 asl_store_close(global
.file_db
);
523 global
.file_db
= NULL
;
526 status
= asl_store_save(global
.file_db
, msg
);
527 if (status
!= ASL_STATUS_OK
)
529 asldebug("(retry) asl_store_save: %s\n", asl_core_error(status
));
530 asl_store_close(global
.file_db
);
531 global
.file_db
= NULL
;
533 global
.dbtype
|= DB_TYPE_MEMORY
;
534 dbtype
|= DB_TYPE_MEMORY
;
535 if (global
.memory_db
== NULL
)
537 status
= asl_memory_open(global
.db_memory_max
, &(global
.memory_db
));
538 if (status
!= ASL_STATUS_OK
)
540 asldebug("asl_memory_open: %s\n", asl_core_error(status
));
547 if (dbtype
& DB_TYPE_MEMORY
)
550 status
= asl_memory_save(global
.memory_db
, msg
, &msgid
);
551 if (status
!= ASL_STATUS_OK
)
553 /* save failed - reopen & retry*/
554 asldebug("asl_memory_save: %s\n", asl_core_error(status
));
555 asl_memory_close(global
.memory_db
);
556 global
.memory_db
= NULL
;
560 status
= asl_memory_save(global
.memory_db
, msg
, &msgid
);
561 if (status
!= ASL_STATUS_OK
)
563 asldebug("(retry) asl_memory_save: %s\n", asl_core_error(status
));
564 asl_memory_close(global
.memory_db
);
565 global
.memory_db
= NULL
;
570 if (dbtype
& DB_TYPE_MINI
)
572 status
= asl_mini_memory_save(global
.mini_db
, msg
, &msgid
);
573 if (status
!= ASL_STATUS_OK
)
575 /* save failed - reopen & retry*/
576 asldebug("asl_mini_memory_save: %s\n", asl_core_error(status
));
577 asl_mini_memory_close(global
.mini_db
);
578 global
.mini_db
= NULL
;
581 status
= asl_mini_memory_save(global
.mini_db
, msg
, &msgid
);
582 if (status
!= ASL_STATUS_OK
)
584 asldebug("(retry) asl_memory_save: %s\n", asl_core_error(status
));
585 asl_mini_memory_close(global
.mini_db
);
586 global
.mini_db
= NULL
;
594 dispatch_source_set_timer(timer_src
, dispatch_time(DISPATCH_TIME_NOW
, NSEC_PER_SEC
/ 2), DISPATCH_TIME_FOREVER
, 0);
595 dispatch_resume(timer_src
);
600 disaster_message(aslmsg msg
)
607 if ((global
.dbtype
& DB_TYPE_MINI
) == 0)
609 if (global
.mini_db
== NULL
)
611 status
= asl_mini_memory_open(global
.db_mini_max
, &(global
.mini_db
));
612 if (status
!= ASL_STATUS_OK
) asldebug("asl_mini_memory_open: %s\n", asl_core_error(status
));
613 else asl_mini_memory_save(global
.mini_db
, msg
, &msgid
);
619 * Do a database search.
622 db_query(aslresponse query
, aslresponse
*res
, uint64_t startid
, int count
, int flags
, uint64_t *lastid
, int32_t ruid
, int32_t rgid
, int raccess
)
624 uint32_t status
, ucount
;
627 struct proc_uniqidentifierinfo pinfo
;
628 const char *str
= NULL
;
631 * Special case: if count is -1, we return ASL_STATUS_OK to indicate that the store is
632 * in memory, and ASL_STATUS_INVALID_STORE to indicate that the file store is in use.
636 if (global
.dbtype
& DB_TYPE_FILE
) return ASL_STATUS_INVALID_STORE
;
637 return ASL_STATUS_OK
;
643 uuid_clear(pinfo
.p_uuid
);
644 if (proc_pidinfo(raccess
, PROC_PIDUNIQIDENTIFIERINFO
, 1, &pinfo
, sizeof(pinfo
)) == sizeof(pinfo
))
646 uuid_unparse(pinfo
.p_uuid
, ustr
);
647 str
= (const char *)ustr
;
652 dir
= SEARCH_FORWARD
;
653 if (flags
& QUERY_FLAG_SEARCH_REVERSE
) dir
= SEARCH_BACKWARD
;
655 status
= ASL_STATUS_FAILED
;
657 if (global
.dbtype
& DB_TYPE_MEMORY
)
659 status
= asl_memory_match_restricted_uuid(global
.memory_db
, query
, res
, lastid
, startid
, ucount
, dir
, ruid
, rgid
, str
);
661 else if (global
.dbtype
& DB_TYPE_MINI
)
663 status
= asl_mini_memory_match_restricted_uuid(global
.mini_db
, query
, res
, lastid
, startid
, ucount
, dir
, ruid
, rgid
, str
);
665 else if (global
.disaster_occurred
!= 0)
667 /* KernelEventAgent calls us to get the kernel disaster messages. */
668 status
= asl_mini_memory_match_restricted_uuid(global
.mini_db
, query
, res
, lastid
, startid
, ucount
, dir
, ruid
, rgid
, str
);
675 register_session(task_name_t task_name
, pid_t pid
)
677 mach_port_t previous
;
680 if (task_name
== MACH_PORT_NULL
) return;
682 if (global
.dead_session_port
== MACH_PORT_NULL
)
684 mach_port_deallocate(mach_task_self(), task_name
);
688 for (i
= 0; i
< client_tasks_count
; i
++) if (task_name
== client_tasks
[i
])
690 mach_port_deallocate(mach_task_self(), task_name
);
694 if (client_tasks_count
== 0) client_tasks
= (task_name_t
*)calloc(1, sizeof(task_name_t
));
695 else client_tasks
= (task_name_t
*)reallocf(client_tasks
, (client_tasks_count
+ 1) * sizeof(task_name_t
));
697 if (client_tasks
== NULL
)
699 mach_port_deallocate(mach_task_self(), task_name
);
703 client_tasks
[client_tasks_count
] = task_name
;
704 client_tasks_count
++;
706 asldebug("register_session: %u PID %d\n", (unsigned int)task_name
, (int)pid
);
708 /* register for port death notification */
709 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
);
710 mach_port_deallocate(mach_task_self(), previous
);
712 asl_client_count_increment();
716 cancel_session(task_name_t task_name
)
720 for (i
= 0; (i
< client_tasks_count
) && (task_name
!= client_tasks
[i
]); i
++);
722 if (i
>= client_tasks_count
) return;
724 if (client_tasks_count
== 1)
728 client_tasks_count
= 0;
732 for (i
++; i
< client_tasks_count
; i
++) client_tasks
[i
-1] = client_tasks
[i
];
733 client_tasks_count
--;
734 client_tasks
= (task_name_t
*)reallocf(client_tasks
, client_tasks_count
* sizeof(task_name_t
));
737 asldebug("cancel_session: %u\n", (unsigned int)task_name
);
739 /* we hold a send right or dead name right for the task name port */
740 mach_port_deallocate(mach_task_self(), task_name
);
741 asl_client_count_decrement();
745 register_direct_watch(uint16_t port
)
747 #if TARGET_OS_EMBEDDED
750 struct sockaddr_in address
;
752 if (port
== 0) return ASL_STATUS_FAILED
;
754 sock
= socket(AF_INET
, SOCK_STREAM
, 0);
755 if (sock
< 0) return ASL_STATUS_FAILED
;
757 address
.sin_family
= AF_INET
;
758 /* port must be sent in network byte order */
759 address
.sin_port
= port
;
760 address
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
762 if (connect(sock
, (struct sockaddr
*)&address
, sizeof(address
)) != 0) return ASL_STATUS_FAILED
;
765 setsockopt(sock
, SOL_SOCKET
, SO_NOSIGPIPE
, &i
, sizeof(i
));
768 setsockopt(sock
, IPPROTO_TCP
, TCP_NODELAY
, &i
, sizeof(i
));
770 /* make socket non-blocking */
771 flags
= fcntl(sock
, F_GETFL
, 0);
772 if (flags
== -1) flags
= 0;
773 fcntl(sock
, F_SETFL
, flags
| O_NONBLOCK
);
775 if (direct_watch_count
== 0)
777 direct_watch
= (int *)calloc(1, sizeof(int));
778 direct_watch_port
= (uint16_t *)calloc(1, sizeof(uint16_t));
782 direct_watch
= (int *)reallocf(direct_watch
, (direct_watch_count
+ 1) * sizeof(int));
783 direct_watch_port
= (uint16_t *)reallocf(direct_watch_port
, (direct_watch_count
+ 1) * sizeof(uint16_t));
786 if ((direct_watch
== NULL
) || (direct_watch_port
== NULL
))
793 free(direct_watch_port
);
794 direct_watch_port
= NULL
;
796 direct_watch_count
= 0;
797 global
.watchers_active
= 0;
798 if (global
.lockdown_session_count
> 0) global
.watchers_active
= 1;
800 return ASL_STATUS_FAILED
;
803 direct_watch
[direct_watch_count
] = sock
;
804 direct_watch_port
[direct_watch_count
] = port
;
805 direct_watch_count
++;
806 global
.watchers_active
= direct_watch_count
+ global
.lockdown_session_count
;
808 return ASL_STATUS_OK
;
810 return ASL_STATUS_FAILED
;
815 cancel_direct_watch(uint16_t port
)
817 #if TARGET_OS_EMBEDDED
820 for (i
= 0; (i
< direct_watch_count
) && (port
!= direct_watch_port
[i
]); i
++);
822 if (i
>= direct_watch_count
) return;
824 if (direct_watch_count
== 1)
829 free(direct_watch_port
);
830 direct_watch_port
= NULL
;
832 direct_watch_count
= 0;
833 global
.watchers_active
= 0;
834 if (global
.lockdown_session_count
> 0) global
.watchers_active
= 1;
838 for (i
++; i
< direct_watch_count
; i
++)
840 direct_watch
[i
-1] = direct_watch
[i
];
841 direct_watch_port
[i
-1] = direct_watch_port
[i
];
844 direct_watch_count
--;
845 global
.watchers_active
= direct_watch_count
+ global
.lockdown_session_count
;
847 direct_watch
= (int *)reallocf(direct_watch
, direct_watch_count
* sizeof(int));
848 direct_watch_port
= (uint16_t *)reallocf(direct_watch_port
, direct_watch_count
* sizeof(uint16_t));
850 if ((direct_watch
== NULL
) || (direct_watch_port
== NULL
))
855 free(direct_watch_port
);
856 direct_watch_port
= NULL
;
858 direct_watch_count
= 0;
859 global
.watchers_active
= 0;
860 if (global
.lockdown_session_count
> 0) global
.watchers_active
= 1;
867 syslogd_state_query(asl_msg_t
*q
, aslresponse
*res
, uid_t uid
)
869 asl_search_result_t
*out
;
875 asl_out_module_t
*om
;
877 if (res
== NULL
) return ASL_STATUS_INVALID_ARG
;
880 out
= (asl_search_result_t
*)calloc(1, sizeof(asl_search_result_t
));
881 if (out
== NULL
) return ASL_STATUS_NO_MEMORY
;
883 m
= asl_new(ASL_TYPE_MSG
);
887 return ASL_STATUS_NO_MEMORY
;
891 out
->msg
= (asl_msg_t
**)calloc(1, sizeof(asl_msg_t
*));
892 if (out
->msg
== NULL
)
896 return ASL_STATUS_NO_MEMORY
;
899 out
->msg
[0] = (asl_msg_t
*)m
;
901 /* q must have [ASLOption control], so a "null" query really has count == 1 */
902 if (asl_msg_count(q
) == 1) all
= true;
904 if (all
|| (0 == asl_msg_lookup(q
, "debug", NULL
, NULL
)))
906 if (global
.debug
== 0) snprintf(val
, sizeof(val
), "0");
907 else snprintf(val
, sizeof(val
), "1 %s", global
.debug_file
);
908 asl_set(m
, "debug", val
);
911 if (all
|| (0 == asl_msg_lookup(q
, "dbtype", NULL
, NULL
)))
914 if (global
.dbtype
& DB_TYPE_FILE
) n
++;
915 if (global
.dbtype
& DB_TYPE_MEMORY
) n
++;
916 if (global
.dbtype
& DB_TYPE_MINI
) n
++;
920 asl_set(m
, "dbtype", "unknown");
925 memset(val
, 0, sizeof(val
));
927 if (global
.dbtype
& DB_TYPE_FILE
)
930 strncat(val
, "file", 4);
931 if (i
< n
) strncat(val
, " ", 1);
934 if (global
.dbtype
& DB_TYPE_MEMORY
)
937 strncat(val
, "memory", 6);
938 if (i
< n
) strncat(val
, " ", 1);
941 if (global
.dbtype
& DB_TYPE_MINI
)
943 strncat(val
, "mini-memory", 11);
946 asl_set(m
, "dbtype", val
);
950 if (all
|| (0 == asl_msg_lookup(q
, "db_file_max", NULL
, NULL
)))
952 snprintf(val
, sizeof(val
), "%u", global
.db_file_max
);
953 asl_set(m
, "db_file_max", val
);
956 if (all
|| (0 == asl_msg_lookup(q
, "db_memory_max", NULL
, NULL
)))
958 snprintf(val
, sizeof(val
), "%u", global
.db_memory_max
);
959 asl_set(m
, "db_memory_max", val
);
962 if (all
|| (0 == asl_msg_lookup(q
, "db_mini_max", NULL
, NULL
)))
964 snprintf(val
, sizeof(val
), "%u", global
.db_mini_max
);
965 asl_set(m
, "db_mini_max", val
);
968 if (all
|| (0 == asl_msg_lookup(q
, "mps_limit", NULL
, NULL
)))
970 snprintf(val
, sizeof(val
), "%u", global
.mps_limit
);
971 asl_set(m
, "mps_limit", val
);
974 if (all
|| (0 == asl_msg_lookup(q
, "bsd_max_dup_time", NULL
, NULL
)))
976 snprintf(val
, sizeof(val
), "%llu", global
.bsd_max_dup_time
);
977 asl_set(m
, "bsd_max_dup_time", val
);
980 if (all
|| (0 == asl_msg_lookup(q
, "mark_time", NULL
, NULL
)))
982 snprintf(val
, sizeof(val
), "%llu", global
.mark_time
);
983 asl_set(m
, "mark_time", val
);
986 if (all
|| (0 == asl_msg_lookup(q
, "utmp_ttl", NULL
, NULL
)))
988 snprintf(val
, sizeof(val
), "%lu", global
.utmp_ttl
);
989 asl_set(m
, "utmp_ttl", val
);
992 if (all
|| (0 == asl_msg_lookup(q
, "work_queue_count", NULL
, NULL
)))
994 snprintf(val
, sizeof(val
), "%d", global
.work_queue_count
);
995 asl_set(m
, "work_queue_count", val
);
998 if (all
|| (0 == asl_msg_lookup(q
, "asl_queue_count", NULL
, NULL
)))
1000 snprintf(val
, sizeof(val
), "%d", global
.asl_queue_count
);
1001 asl_set(m
, "asl_queue_count", val
);
1004 if (all
|| (0 == asl_msg_lookup(q
, "bsd_queue_count", NULL
, NULL
)))
1006 snprintf(val
, sizeof(val
), "%d", global
.bsd_queue_count
);
1007 asl_set(m
, "bsd_queue_count", val
);
1010 if (all
|| (0 == asl_msg_lookup(q
, "client_count", NULL
, NULL
)))
1012 snprintf(val
, sizeof(val
), "%d", global
.client_count
);
1013 asl_set(m
, "client_count", val
);
1016 if (all
|| (0 == asl_msg_lookup(q
, "disaster_occurred", NULL
, NULL
)))
1018 snprintf(val
, sizeof(val
), "%d", global
.disaster_occurred
);
1019 asl_set(m
, "disaster_occurred", val
);
1023 if (all
|| (0 == asl_msg_lookup(q
, "lockdown_session_count", NULL
, NULL
)))
1025 snprintf(val
, sizeof(val
), "%d", global
.lockdown_session_count
);
1026 asl_set(m
, "lockdown_session_count", val
);
1029 if (all
|| (0 == asl_msg_lookup(q
, "remote_delay_time", NULL
, NULL
)))
1031 snprintf(val
, sizeof(val
), "%u", global
.remote_delay_time
);
1032 asl_set(m
, "remote_delay_time", val
);
1037 if (all
|| (0 == asl_msg_lookup(q
, "watchers_active", NULL
, NULL
)))
1039 snprintf(val
, sizeof(val
), "%d", global
.watchers_active
);
1040 asl_set(m
, "watchers_active", val
);
1043 for (i
= 0; i
< global
.module_count
; i
++)
1045 if (all
|| (0 == asl_msg_lookup(q
, global
.module[i
]->name
, NULL
, NULL
)))
1047 snprintf(val
, sizeof(val
), "%s", global
.module[i
]->enabled
? "enabled" : "disabled");
1048 asl_set(m
, global
.module[i
]->name
, val
);
1052 for (om
= global
.asl_out_module
; om
!= NULL
; om
= om
->next
)
1054 if (all
|| (0 == asl_msg_lookup(q
, om
->name
, NULL
, NULL
)))
1056 snprintf(val
, sizeof(val
), "%s", om
->flags
& MODULE_FLAG_ENABLED
? "enabled" : "disabled");
1057 if (om
->name
== NULL
) asl_set(m
, "asl.conf", val
);
1058 else asl_set(m
, om
->name
, val
);
1062 /* synchronous actions use queries, since messages are simpleroutines */
1063 if (0 == asl_msg_lookup(q
, "action", &mval
, NULL
))
1066 if (uid
== 0) res
= asl_action_control_set_param(mval
);
1067 snprintf(val
, sizeof(val
), "%d", res
);
1068 asl_set(m
, "action", val
);
1072 return ASL_STATUS_OK
;
1076 * Receives messages on the "com.apple.system.logger" mach port.
1077 * Services database search requests.
1078 * Runs in it's own thread.
1083 asl_request_msg
*request
;
1085 uint32_t rbits
, sbits
;
1087 struct timeval now
, send_time
;
1088 mach_dead_name_notification_t
*deadname
;
1090 send_time
.tv_sec
= 0;
1091 send_time
.tv_usec
= 0;
1093 rqs
= sizeof(asl_request_msg
) + MAX_TRAILER_SIZE
;
1095 rbits
= MACH_RCV_MSG
| MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT
) | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0
);
1096 sbits
= MACH_SEND_MSG
| MACH_SEND_TIMEOUT
;
1098 asl_server_queue
= dispatch_queue_create("ASL Server Queue", NULL
);
1105 request
= (asl_request_msg
*)calloc(1, rqs
);
1106 if (request
== NULL
) continue;
1108 request
->head
.msgh_local_port
= global
.server_port
;
1109 request
->head
.msgh_size
= rqs
;
1113 (void)mach_msg(&(request
->head
), flags
, 0, rqs
, global
.listen_set
, 0, MACH_PORT_NULL
);
1115 if (request
->head
.msgh_id
== MACH_NOTIFY_DEAD_NAME
)
1117 deadname
= (mach_dead_name_notification_t
*)request
;
1118 dispatch_async(asl_server_queue
, ^{
1119 cancel_session(deadname
->not_port
);
1120 /* dead name notification includes a dead name right */
1121 mach_port_deallocate(mach_task_self(), deadname
->not_port
);
1128 dispatch_async(asl_server_queue
, ^{
1130 asl_reply_msg
*reply
= calloc(1, sizeof(asl_reply_msg
) + MAX_TRAILER_SIZE
);
1132 asl_ipc_server(&(request
->head
), &(reply
->head
));
1133 ks
= mach_msg(&(reply
->head
), sbits
, reply
->head
.msgh_size
, 0, MACH_PORT_NULL
, 10, MACH_PORT_NULL
);
1135 if ((ks
== MACH_SEND_INVALID_DEST
) || (ks
== MACH_SEND_TIMED_OUT
))
1138 mach_msg_destroy(&(reply
->head
));
1147 caller_get_read_entitlement(pid_t pid
, uid_t
*uid
, gid_t
*gid
)
1149 #if TARGET_OS_EMBEDDED
1150 xpc_object_t edata
, entitlements
, val
;
1156 edata
= xpc_copy_entitlements_for_pid(pid
);
1157 if (edata
== NULL
) return;
1159 ptr
= xpc_data_get_bytes_ptr(edata
);
1160 len
= xpc_data_get_length(edata
);
1162 entitlements
= xpc_create_from_plist(ptr
, len
);
1164 if (entitlements
== NULL
) return;
1166 if (xpc_get_type(entitlements
) != XPC_TYPE_DICTIONARY
)
1168 asldebug("xpc_copy_entitlements_for_pid has non-dictionary data for pid %d\n", pid
);
1172 bval
= xpc_dictionary_get_bool(entitlements
, ASL_ENTITLEMENT_KEY
);
1173 if (bval
&& (uid
!= NULL
))
1176 xpc_release(entitlements
);
1180 val
= xpc_dictionary_get_value(entitlements
, ASL_ENTITLEMENT_UID_KEY
);
1183 if ((xpc_get_type(val
) == XPC_TYPE_INT64
) && (uid
!= NULL
))
1185 ival
= xpc_int64_get_value(val
);
1190 val
= xpc_dictionary_get_value(entitlements
, ASL_ENTITLEMENT_GID_KEY
);
1193 if ((xpc_get_type(val
) == XPC_TYPE_INT64
) && (gid
!= NULL
))
1195 ival
= xpc_int64_get_value(val
);
1200 xpc_release(entitlements
);
1204 static kern_return_t
1205 __asl_server_query_internal
1209 mach_msg_type_number_t requestCnt
,
1214 mach_msg_type_number_t
*replyCnt
,
1224 char *out
, *vmbuffer
;
1226 kern_return_t kstatus
;
1228 *status
= ASL_STATUS_OK
;
1230 if ((request
!= NULL
) && (request
[requestCnt
- 1] != '\0'))
1232 *status
= ASL_STATUS_INVALID_ARG
;
1233 vm_deallocate(mach_task_self(), (vm_address_t
)request
, requestCnt
);
1234 return KERN_SUCCESS
;
1237 query
= asl_list_from_string(request
);
1238 if (request
!= NULL
) vm_deallocate(mach_task_self(), (vm_address_t
)request
, requestCnt
);
1241 /* A query list containing a single query, which itself contains
1242 * [ASLOption control] is an internal state query */
1243 if ((query
!= NULL
) && (query
->count
== 1) && asl_check_option((aslmsg
)query
->msg
[0], ASL_OPT_CONTROL
))
1245 *status
= syslogd_state_query(query
->msg
[0], &res
, uid
);
1250 #if TARGET_OS_EMBEDDED
1256 caller_get_read_entitlement(pid
, &uid
, &gid
);
1257 if (uid
== 0) x
= 0;
1260 *status
= db_query(query
, &res
, startid
, count
, flags
, lastid
, uid
, gid
, x
);
1263 aslresponse_free(query
);
1264 if (*status
!= ASL_STATUS_INVALID_STORE
)
1268 else if (*status
!= ASL_STATUS_OK
)
1270 if (res
!= NULL
) aslresponse_free(res
);
1271 return KERN_SUCCESS
;
1276 out
= asl_list_to_string((asl_search_result_t
*)res
, &outlen
);
1277 aslresponse_free(res
);
1279 if ((out
== NULL
) || (outlen
== 0)) return KERN_SUCCESS
;
1281 kstatus
= vm_allocate(mach_task_self(), (vm_address_t
*)&vmbuffer
, outlen
, TRUE
);
1282 if (kstatus
!= KERN_SUCCESS
)
1288 memmove(vmbuffer
, out
, outlen
);
1294 return KERN_SUCCESS
;
1298 __asl_server_query_2
1302 mach_msg_type_number_t requestCnt
,
1307 mach_msg_type_number_t
*replyCnt
,
1313 uid_t uid
= (uid_t
)-1;
1314 gid_t gid
= (gid_t
)-1;
1315 pid_t pid
= (pid_t
)-1;
1317 audit_token_to_au32(token
, NULL
, &uid
, &gid
, NULL
, NULL
, &pid
, NULL
, NULL
);
1319 return __asl_server_query_internal(server
, request
, requestCnt
, startid
, count
, flags
, reply
, replyCnt
, lastid
, status
, uid
, gid
, pid
);
1326 mach_msg_type_number_t requestCnt
,
1331 mach_msg_type_number_t
*replyCnt
,
1334 security_token_t
*token
1337 return __asl_server_query_internal(server
, request
, requestCnt
, startid
, count
, flags
, reply
, replyCnt
, lastid
, status
, (uid_t
)token
->val
[0], (gid_t
)token
->val
[1], (pid_t
)-1);
1342 __asl_server_query_timeout
1346 mach_msg_type_number_t requestCnt
,
1351 mach_msg_type_number_t
*replyCnt
,
1354 security_token_t
*token
1357 return __asl_server_query_internal(server
, request
, requestCnt
, startid
, count
, flags
, reply
, replyCnt
, lastid
, status
, (uid_t
)token
->val
[0], (gid_t
)token
->val
[1], (pid_t
)-1);
1365 mach_msg_type_number_t requestCnt
,
1367 security_token_t
*token
1370 return KERN_SUCCESS
;
1374 __asl_server_message
1378 mach_msg_type_number_t messageCnt
,
1387 kern_return_t kstatus
;
1388 mach_port_name_t client
;
1390 if (message
== NULL
)
1392 return KERN_SUCCESS
;
1395 if (message
[messageCnt
- 1] != '\0')
1397 vm_deallocate(mach_task_self(), (vm_address_t
)message
, messageCnt
);
1398 return KERN_SUCCESS
;
1401 asldebug("__asl_server_message: %s\n", (message
== NULL
) ? "NULL" : message
);
1403 msg
= (aslmsg
)asl_msg_from_string(message
);
1404 vm_deallocate(mach_task_self(), (vm_address_t
)message
, messageCnt
);
1406 if (msg
== NULL
) return KERN_SUCCESS
;
1411 audit_token_to_au32(token
, NULL
, &uid
, &gid
, NULL
, NULL
, &pid
, NULL
, NULL
);
1413 client
= MACH_PORT_NULL
;
1414 kstatus
= task_name_for_pid(mach_task_self(), pid
, &client
);
1415 if (kstatus
== KERN_SUCCESS
) register_session(client
, pid
);
1417 snprintf(tmp
, sizeof(tmp
), "%d", uid
);
1418 asl_set(msg
, ASL_KEY_UID
, tmp
);
1420 snprintf(tmp
, sizeof(tmp
), "%d", gid
);
1421 asl_set(msg
, ASL_KEY_GID
, tmp
);
1423 snprintf(tmp
, sizeof(tmp
), "%d", pid
);
1424 asl_set(msg
, ASL_KEY_PID
, tmp
);
1426 process_message(msg
, SOURCE_ASL_MESSAGE
);
1428 return KERN_SUCCESS
;
1432 __asl_server_create_aux_link
1436 mach_msg_type_number_t messageCnt
,
1437 mach_port_t
*fileport
,
1439 mach_msg_type_number_t
*newurlCnt
,
1449 kern_return_t kstatus
;
1450 mach_port_name_t client
;
1451 char *url
, *vmbuffer
;
1454 *status
= ASL_STATUS_OK
;
1456 if (message
== NULL
)
1458 *status
= ASL_STATUS_INVALID_ARG
;
1459 return KERN_SUCCESS
;
1462 if (message
[messageCnt
- 1] != '\0')
1464 *status
= ASL_STATUS_INVALID_ARG
;
1465 vm_deallocate(mach_task_self(), (vm_address_t
)message
, messageCnt
);
1466 return KERN_SUCCESS
;
1469 asldebug("__asl_server_create_aux_link: %s\n", (message
== NULL
) ? "NULL" : message
);
1471 if ((global
.dbtype
& DB_TYPE_FILE
) == 0)
1473 *status
= ASL_STATUS_INVALID_STORE
;
1474 return KERN_SUCCESS
;
1477 *fileport
= MACH_PORT_NULL
;
1479 msg
= (aslmsg
)asl_msg_from_string(message
);
1480 vm_deallocate(mach_task_self(), (vm_address_t
)message
, messageCnt
);
1482 if (msg
== NULL
) return KERN_SUCCESS
;
1487 audit_token_to_au32(token
, NULL
, &uid
, &gid
, NULL
, NULL
, &pid
, NULL
, NULL
);
1489 client
= MACH_PORT_NULL
;
1490 kstatus
= task_name_for_pid(mach_task_self(), pid
, &client
);
1491 if (kstatus
== KERN_SUCCESS
) register_session(client
, pid
);
1493 snprintf(tmp
, sizeof(tmp
), "%d", uid
);
1494 asl_set(msg
, ASL_KEY_UID
, tmp
);
1496 snprintf(tmp
, sizeof(tmp
), "%d", gid
);
1497 asl_set(msg
, ASL_KEY_GID
, tmp
);
1499 snprintf(tmp
, sizeof(tmp
), "%d", pid
);
1500 asl_set(msg
, ASL_KEY_PID
, tmp
);
1502 /* create a file for the client */
1503 *status
= asl_store_open_aux(global
.file_db
, msg
, &fd
, &url
);
1505 if (*status
!= ASL_STATUS_OK
) return KERN_SUCCESS
;
1508 if (fd
>= 0) close(fd
);
1509 *status
= ASL_STATUS_FAILED
;
1510 return KERN_SUCCESS
;
1513 if (fileport_makeport(fd
, (fileport_t
*)fileport
) < 0)
1517 *status
= ASL_STATUS_FAILED
;
1518 return KERN_SUCCESS
;
1523 *newurlCnt
= strlen(url
) + 1;
1525 kstatus
= vm_allocate(mach_task_self(), (vm_address_t
*)&vmbuffer
, *newurlCnt
, TRUE
);
1526 if (kstatus
!= KERN_SUCCESS
)
1532 memmove(vmbuffer
, url
, *newurlCnt
);
1537 return KERN_SUCCESS
;
1541 __asl_server_register_direct_watch
1548 uint16_t p16
= port
;
1549 pid_t pid
= (pid_t
)-1;
1551 audit_token_to_au32(token
, NULL
, NULL
, NULL
, NULL
, NULL
, &pid
, NULL
, NULL
);
1553 asldebug("__asl_server_register_direct_watch: pid %u port %hu\n", pid
, ntohs(p16
));
1555 dispatch_once(&watch_init_once
, ^{
1556 watch_queue
= dispatch_queue_create("Direct Watch Queue", NULL
);
1559 dispatch_async(watch_queue
, ^{ register_direct_watch(p16
); });
1561 return KERN_SUCCESS
;
1565 __asl_server_cancel_direct_watch
1572 uint16_t p16
= port
;
1574 asldebug("__asl_server_cancel_direct_watch: %hu\n", ntohs(p16
));
1576 dispatch_once(&watch_init_once
, ^{
1577 watch_queue
= dispatch_queue_create("Direct Watch Queue", NULL
);
1580 dispatch_async(watch_queue
, ^{ cancel_direct_watch(p16
); });
1582 return KERN_SUCCESS
;