]> git.saurik.com Git - apple/syslog.git/blob - syslogd.tproj/dbserver.c
7f829594ea3ad4209e392ded75010de8d1a85edc
[apple/syslog.git] / syslogd.tproj / dbserver.c
1 /*
2 * Copyright (c) 2007-2015 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 <TargetConditionals.h>
25
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <sys/socket.h>
32 #include <sys/un.h>
33 #include <sys/ipc.h>
34 #include <sys/mman.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 <mach/vm_param.h>
41 #include <bsm/libbsm.h>
42 #include <errno.h>
43 #include <netinet/in.h>
44 #include <netinet/tcp.h>
45 #include <sys/event.h>
46 #include <servers/bootstrap.h>
47 #include <pthread.h>
48 #include <notify.h>
49 #include <sys/time.h>
50 #include <xpc/xpc.h>
51 #include <xpc/private.h>
52 #include <libproc.h>
53 #include <uuid/uuid.h>
54 #include "daemon.h"
55 #include "asl_ipc.h"
56 #include "asl_ipcServer.h"
57
58 #define forever for(;;)
59
60 #define LIST_SIZE_DELTA 256
61
62 #define SEND_NOTIFICATION 0xfadefade
63
64 #define QUERY_FLAG_SEARCH_REVERSE 0x00000001
65 #define QUERY_DURATION_UNLIMITED 0
66
67 #define SEARCH_FORWARD 1
68 #define SEARCH_BACKWARD -1
69
70 #define MAX_AGAIN 100
71
72 #define ASL_ENTITLEMENT_KEY "com.apple.asl.access_as_root"
73 #define ASL_ENTITLEMENT_UID_KEY "com.apple.asl.access_as_uid"
74 #define ASL_ENTITLEMENT_GID_KEY "com.apple.asl.access_as_gid"
75
76 #define PAGE_ROUND_UP(x) ((((x)+PAGE_SIZE-1)/PAGE_SIZE)*PAGE_SIZE)
77
78 static dispatch_queue_t asl_server_queue;
79 static dispatch_queue_t watch_queue;
80 static dispatch_once_t watch_init_once;
81
82 extern boolean_t asl_ipc_server(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP);
83
84 static task_name_t *client_tasks = NULL;
85 static uint32_t client_tasks_count = 0;
86
87 static int *direct_watch = NULL;
88 /* N.B. ports are in network byte order */
89 static uint16_t *direct_watch_port = NULL;
90 static uint32_t direct_watch_count = 0;
91
92 typedef union
93 {
94 mach_msg_header_t head;
95 union __RequestUnion__asl_ipc_subsystem request;
96 } asl_request_msg;
97
98 typedef union
99 {
100 mach_msg_header_t head;
101 union __ReplyUnion__asl_ipc_subsystem reply;
102 } asl_reply_msg;
103
104 static void
105 db_asl_open(uint32_t dbtype)
106 {
107 uint32_t status;
108 struct stat sb;
109
110 if ((dbtype & DB_TYPE_FILE) && (global.file_db == NULL))
111 {
112 memset(&sb, 0, sizeof(struct stat));
113 if (stat(PATH_ASL_STORE, &sb) == 0)
114 {
115 /* must be a directory */
116 if (!S_ISDIR(sb.st_mode))
117 {
118 asldebug("error: %s is not a directory", PATH_ASL_STORE);
119 return;
120 }
121 }
122 else
123 {
124 if (errno == ENOENT)
125 {
126 /* /var/log/asl doesn't exist - create it */
127 if (mkdir(PATH_ASL_STORE, 0755) != 0)
128 {
129 asldebug("error: can't create data store %s: %s\n", PATH_ASL_STORE, strerror(errno));
130 return;
131 }
132 }
133 else
134 {
135 /* stat failed for some other reason */
136 asldebug("error: can't stat data store %s: %s\n", PATH_ASL_STORE, strerror(errno));
137 return;
138 }
139 }
140
141 status = asl_store_open_write(NULL, &(global.file_db));
142 if (status != ASL_STATUS_OK)
143 {
144 asldebug("asl_store_open_write: %s\n", asl_core_error(status));
145 }
146 else
147 {
148 if (global.db_file_max != 0) asl_store_max_file_size(global.file_db, global.db_file_max);
149 asl_trigger_aslmanager();
150 }
151 }
152
153 if ((dbtype & DB_TYPE_MEMORY) && (global.memory_db == NULL))
154 {
155 status = asl_memory_open(global.db_memory_max, global.db_memory_str_max, &(global.memory_db));
156 if (status != ASL_STATUS_OK)
157 {
158 asldebug("asl_memory_open: %s\n", asl_core_error(status));
159 }
160 }
161 }
162
163 void
164 add_lockdown_session(int fd)
165 {
166 dispatch_once(&watch_init_once, ^{
167 watch_queue = dispatch_queue_create("Direct Watch Queue", NULL);
168 });
169
170 dispatch_async(watch_queue, ^{
171 if (global.lockdown_session_count == 0) global.lockdown_session_fds = NULL;
172
173 global.lockdown_session_fds = reallocf(global.lockdown_session_fds, global.lockdown_session_count + 1 * sizeof(int));
174
175 if (global.lockdown_session_fds == NULL)
176 {
177 asldebug("add_lockdown_session: realloc failed\n");
178 global.lockdown_session_count = 0;
179 }
180 else
181 {
182 global.lockdown_session_fds[global.lockdown_session_count++] = fd;
183 }
184
185 global.watchers_active = direct_watch_count + global.lockdown_session_count;
186 });
187 }
188
189 void
190 remove_lockdown_session(int fd)
191 {
192 dispatch_once(&watch_init_once, ^{
193 watch_queue = dispatch_queue_create("Direct Watch Queue", NULL);
194 });
195
196 dispatch_async(watch_queue, ^{
197 int i, n;
198
199 for (i = 0, n = 0; i < global.lockdown_session_count; i++)
200 {
201 if (global.lockdown_session_fds[i] == fd)
202 {
203 }
204 else
205 {
206 if (i != n) global.lockdown_session_fds[n] = global.lockdown_session_fds[i];
207 n++;
208 }
209 }
210
211 if (n == 0)
212 {
213 free(global.lockdown_session_fds);
214 global.lockdown_session_fds = NULL;
215 global.lockdown_session_count = 0;
216 }
217 else
218 {
219 global.lockdown_session_fds = reallocf(global.lockdown_session_fds, n * sizeof(int));
220 if (global.lockdown_session_fds == NULL)
221 {
222 asldebug("remove_lockdown_session: realloc failed\n");
223 global.lockdown_session_count = 0;
224 }
225 else
226 {
227 global.lockdown_session_count = n;
228 }
229 }
230
231 global.watchers_active = direct_watch_count + global.lockdown_session_count;
232 });
233 }
234
235 #ifdef LOCKDOWN
236 static void
237 sweep_lockdown_session_fds()
238 {
239 int i, n;
240
241 for (i = 0, n = 0; i < global.lockdown_session_count; i++)
242 {
243 if (global.lockdown_session_fds[i] >= 0)
244 {
245 if (i != n) global.lockdown_session_fds[n] = global.lockdown_session_fds[i];
246 n++;
247 }
248 }
249
250 if (n == 0)
251 {
252 free(global.lockdown_session_fds);
253 global.lockdown_session_fds = NULL;
254 global.lockdown_session_count = 0;
255 }
256 else
257 {
258 global.lockdown_session_fds = reallocf(global.lockdown_session_fds, n * sizeof(int));
259 if (global.lockdown_session_fds == NULL)
260 {
261 asldebug("sweep_lockdown_session_fds: realloc failed\n");
262 global.lockdown_session_count = 0;
263 }
264 else
265 {
266 global.lockdown_session_count = n;
267 }
268 }
269
270 global.watchers_active = direct_watch_count + global.lockdown_session_count;
271 }
272 #endif
273
274 static void
275 _internal_send_to_direct_watchers(asl_msg_t *msg)
276 {
277 uint32_t i, j, nlen, outlen, cleanup, total_sent, again;
278 ssize_t sent;
279 char *out;
280
281 #ifdef LOCKDOWN
282 static struct timeval last_time;
283
284 cleanup = 0;
285
286 if (global.lockdown_session_count > 0)
287 {
288 if (global.remote_delay_time > 0)
289 {
290 struct timeval now;
291 uint64_t delta;
292
293 if (gettimeofday(&now, NULL) == 0)
294 {
295 if (last_time.tv_sec != 0)
296 {
297 if (now.tv_sec > last_time.tv_sec)
298 {
299 now.tv_sec -= 1;
300 now.tv_usec += 1000000;
301 }
302
303 delta = now.tv_sec - last_time.tv_sec;
304 delta *= 1000000;
305 delta += (now.tv_usec - last_time.tv_usec);
306 if (delta < global.remote_delay_time)
307 {
308 usleep(delta);
309 }
310 }
311
312 if (now.tv_usec >= 1000000)
313 {
314 now.tv_sec += 1;
315 now.tv_usec -= 1000000;
316 }
317
318 last_time = now;
319 }
320 }
321
322 out = asl_format_message(msg, ASL_MSG_FMT_STD, ASL_TIME_FMT_LCL, ASL_ENCODE_SAFE, &outlen);
323
324 for (i = 0; i < global.lockdown_session_count; i++)
325 {
326 if (write(global.lockdown_session_fds[i], out, outlen) < 0)
327 {
328 asldebug("send_to_direct_watchers: lockdown %d write error: %d %s\n", global.lockdown_session_fds[i], errno, strerror(errno));
329 close(global.lockdown_session_fds[i]);
330 global.lockdown_session_fds[i] = -1;
331 cleanup = 1;
332 }
333 }
334
335 free(out);
336 }
337
338 if (cleanup != 0) sweep_lockdown_session_fds();
339 #endif
340
341 if (direct_watch_count == 0)
342 {
343 direct_watch = NULL;
344 return;
345 }
346
347 if (direct_watch == NULL)
348 {
349 direct_watch_count = 0;
350 return;
351 }
352
353 cleanup = 0;
354 out = asl_msg_to_string(msg, &outlen);
355
356 if (out == NULL) return;
357
358 nlen = htonl(outlen);
359 for (i = 0; i < direct_watch_count; i++)
360 {
361 sent = send(direct_watch[i], &nlen, sizeof(nlen), 0);
362 if (sent < sizeof(nlen))
363 {
364 /* bail out if we can't send 4 bytes */
365 close(direct_watch[i]);
366 direct_watch[i] = -1;
367 cleanup = 1;
368 }
369 else
370 {
371 total_sent = 0;
372 again = 0;
373
374 while (total_sent < outlen)
375 {
376 errno = 0;
377 sent = send(direct_watch[i], out + total_sent, outlen - total_sent, 0);
378 if (sent <= 0)
379 {
380 asldebug("send_to_direct_watchers: send returned %d (errno %d)\n", sent, errno);
381 if (errno == EAGAIN)
382 {
383 if (again > MAX_AGAIN)
384 {
385 asldebug("send_to_direct_watchers: exceeded EAGAIN limit - closing connection\n");
386 break;
387 }
388 else
389 {
390 again++;
391 errno = 0;
392 continue;
393 }
394 }
395
396 close(direct_watch[i]);
397 direct_watch[i] = -1;
398 cleanup = 1;
399 break;
400 }
401
402 total_sent += sent;
403 }
404 }
405 }
406
407 free(out);
408
409 if (cleanup == 0) return;
410
411 j = 0;
412 for (i = 0; i < direct_watch_count; i++)
413 {
414 if (direct_watch[i] >= 0)
415 {
416 if (j != i)
417 {
418 direct_watch[j] = direct_watch[i];
419 direct_watch_port[j] = direct_watch_port[i];
420 j++;
421 }
422 }
423 }
424
425 direct_watch_count = j;
426 if (direct_watch_count == 0)
427 {
428 free(direct_watch);
429 direct_watch = NULL;
430
431 free(direct_watch_port);
432 direct_watch_port = NULL;
433 }
434 else
435 {
436 direct_watch = reallocf(direct_watch, direct_watch_count * sizeof(int));
437 direct_watch_port = reallocf(direct_watch_port, direct_watch_count * sizeof(uint16_t));
438 if ((direct_watch == NULL) || (direct_watch_port == NULL))
439 {
440 free(direct_watch);
441 direct_watch = NULL;
442
443 free(direct_watch_port);
444 direct_watch_port = NULL;
445
446 direct_watch_count = 0;
447 }
448 }
449 }
450
451 void
452 send_to_direct_watchers(asl_msg_t *msg)
453 {
454 dispatch_once(&watch_init_once, ^{
455 watch_queue = dispatch_queue_create("Direct Watch Queue", NULL);
456 });
457
458 asl_msg_retain(msg);
459
460 dispatch_async(watch_queue, ^{
461 _internal_send_to_direct_watchers(msg);
462 asl_msg_release(msg);
463 });
464 }
465
466 /*
467 * Called from asl_action.c to save messgaes to the ASL data store
468 */
469 void
470 db_save_message(asl_msg_t *msg)
471 {
472 uint64_t msgid;
473 uint32_t status, dbtype;
474 static int armed;
475 static dispatch_source_t timer_src;
476 static dispatch_once_t once;
477
478 dispatch_once(&once, ^{
479 timer_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
480 dispatch_source_set_event_handler(timer_src, ^{
481 notify_post(kNotifyASLDBUpdate);
482 dispatch_suspend(timer_src);
483 armed = 0;
484 });
485 armed = 0;
486 });
487
488 send_to_direct_watchers((asl_msg_t *)msg);
489
490 dbtype = global.dbtype;
491
492 if (asl_check_option(msg, ASL_OPT_DB_FILE)) dbtype |= DB_TYPE_FILE;
493 if (asl_check_option(msg, ASL_OPT_DB_MEMORY)) dbtype |= DB_TYPE_MEMORY;
494
495 db_asl_open(dbtype);
496
497 if (dbtype & DB_TYPE_FILE)
498 {
499 status = asl_store_save(global.file_db, msg);
500 if (status != ASL_STATUS_OK)
501 {
502 /* write failed - reopen & retry */
503 asldebug("asl_store_save: %s\n", asl_core_error(status));
504 asl_store_release(global.file_db);
505 global.file_db = NULL;
506
507 db_asl_open(dbtype);
508 status = asl_store_save(global.file_db, msg);
509 if (status != ASL_STATUS_OK)
510 {
511 asldebug("(retry) asl_store_save: %s\n", asl_core_error(status));
512 asl_store_release(global.file_db);
513 global.file_db = NULL;
514
515 global.dbtype |= DB_TYPE_MEMORY;
516 dbtype |= DB_TYPE_MEMORY;
517 if (global.memory_db == NULL)
518 {
519 status = asl_memory_open(global.db_memory_max, global.db_memory_str_max, &(global.memory_db));
520 if (status != ASL_STATUS_OK)
521 {
522 asldebug("asl_memory_open: %s\n", asl_core_error(status));
523 }
524 }
525 }
526 }
527 }
528
529 if (dbtype & DB_TYPE_MEMORY)
530 {
531 msgid = 0;
532 status = asl_memory_save(global.memory_db, msg, &msgid);
533 if (status != ASL_STATUS_OK)
534 {
535 /* save failed - reopen & retry*/
536 asldebug("asl_memory_save: %s\n", asl_core_error(status));
537 asl_memory_close(global.memory_db);
538 global.memory_db = NULL;
539
540 db_asl_open(dbtype);
541 msgid = 0;
542 status = asl_memory_save(global.memory_db, msg, &msgid);
543 if (status != ASL_STATUS_OK)
544 {
545 asldebug("(retry) asl_memory_save: %s\n", asl_core_error(status));
546 asl_memory_close(global.memory_db);
547 global.memory_db = NULL;
548 }
549 }
550 }
551
552 if (armed == 0)
553 {
554 armed = 1;
555 dispatch_source_set_timer(timer_src, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC / 2), DISPATCH_TIME_FOREVER, 0);
556 dispatch_resume(timer_src);
557 }
558 }
559
560 void
561 disaster_message(asl_msg_t *msg)
562 {
563 uint64_t msgid;
564 uint32_t status;
565
566 msgid = 0;
567
568 if ((global.dbtype & DB_TYPE_MEMORY) == 0)
569 {
570 if (global.memory_db == NULL)
571 {
572 status = asl_memory_open(global.db_memory_max, global.db_memory_str_max, &(global.memory_db));
573 if (status != ASL_STATUS_OK) asldebug("asl_memory_open: %s\n", asl_core_error(status));
574 else asl_memory_save(global.memory_db, msg, &msgid);
575 }
576 }
577 }
578
579 /*
580 * Do a database search.
581 */
582 uint32_t
583 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)
584 {
585 uint32_t status, ucount;
586 uuid_string_t ustr;
587 struct proc_uniqidentifierinfo pinfo;
588 const char *str = NULL;
589
590 /*
591 * Special case: if count is -1, we return ASL_STATUS_OK to indicate that the store is
592 * in memory, and ASL_STATUS_INVALID_STORE to indicate that the file store is in use.
593 */
594 if (count == -1)
595 {
596 if (global.dbtype & DB_TYPE_FILE) return ASL_STATUS_INVALID_STORE;
597 return ASL_STATUS_OK;
598 }
599
600 if (raccess != 0)
601 {
602 str = "NO ACCESS";
603 uuid_clear(pinfo.p_uuid);
604 if (proc_pidinfo(raccess, PROC_PIDUNIQIDENTIFIERINFO, 1, &pinfo, sizeof(pinfo)) == sizeof(pinfo))
605 {
606 uuid_unparse(pinfo.p_uuid, ustr);
607 str = (const char *)ustr;
608 }
609 }
610
611 ucount = count;
612
613 status = ASL_STATUS_FAILED;
614
615 if ((global.dbtype & DB_TYPE_MEMORY) || (global.disaster_occurred != 0))
616 {
617 status = asl_memory_match_restricted_uuid(global.memory_db, query, res, lastid, startid, ucount, duration, direction, ruid, rgid, str);
618 }
619
620 return status;
621 }
622
623 static void
624 register_session(task_name_t task_name, pid_t pid)
625 {
626 mach_port_t previous;
627 uint32_t i;
628
629 if (task_name == MACH_PORT_NULL) return;
630
631 if (global.dead_session_port == MACH_PORT_NULL)
632 {
633 mach_port_deallocate(mach_task_self(), task_name);
634 return;
635 }
636
637 for (i = 0; i < client_tasks_count; i++) if (task_name == client_tasks[i])
638 {
639 mach_port_deallocate(mach_task_self(), task_name);
640 return;
641 }
642
643 if (client_tasks_count == 0) client_tasks = (task_name_t *)calloc(1, sizeof(task_name_t));
644 else client_tasks = (task_name_t *)reallocf(client_tasks, (client_tasks_count + 1) * sizeof(task_name_t));
645
646 if (client_tasks == NULL)
647 {
648 mach_port_deallocate(mach_task_self(), task_name);
649 return;
650 }
651
652 client_tasks[client_tasks_count] = task_name;
653 client_tasks_count++;
654
655 asldebug("register_session: %u PID %d\n", (unsigned int)task_name, (int)pid);
656
657 /* register for port death notification */
658 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);
659 mach_port_deallocate(mach_task_self(), previous);
660
661 asl_client_count_increment();
662 }
663
664 static void
665 cancel_session(task_name_t task_name)
666 {
667 uint32_t i;
668
669 for (i = 0; (i < client_tasks_count) && (task_name != client_tasks[i]); i++);
670
671 if (i >= client_tasks_count) return;
672
673 if (client_tasks_count == 1)
674 {
675 free(client_tasks);
676 client_tasks = NULL;
677 client_tasks_count = 0;
678 }
679 else
680 {
681 for (i++; i < client_tasks_count; i++) client_tasks[i-1] = client_tasks[i];
682 client_tasks_count--;
683 client_tasks = (task_name_t *)reallocf(client_tasks, client_tasks_count * sizeof(task_name_t));
684 }
685
686 asldebug("cancel_session: %u\n", (unsigned int)task_name);
687
688 /* we hold a send right or dead name right for the task name port */
689 mach_port_deallocate(mach_task_self(), task_name);
690 asl_client_count_decrement();
691 }
692
693 static uint32_t
694 register_direct_watch(uint16_t port)
695 {
696 #if TARGET_OS_EMBEDDED
697 uint32_t i;
698 int sock, flags;
699 struct sockaddr_in address;
700
701 if (port == 0) return ASL_STATUS_FAILED;
702
703 sock = socket(AF_INET, SOCK_STREAM, 0);
704 if (sock < 0) return ASL_STATUS_FAILED;
705
706 address.sin_family = AF_INET;
707 /* port must be sent in network byte order */
708 address.sin_port = port;
709 address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
710
711 if (connect(sock, (struct sockaddr*)&address, sizeof(address)) != 0) return ASL_STATUS_FAILED;
712
713 i = 1;
714 setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, &i, sizeof(i));
715
716 i = 1;
717 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &i, sizeof(i));
718
719 /* make socket non-blocking */
720 flags = fcntl(sock, F_GETFL, 0);
721 if (flags == -1) flags = 0;
722 fcntl(sock, F_SETFL, flags | O_NONBLOCK);
723
724 if (direct_watch_count == 0)
725 {
726 direct_watch = (int *)calloc(1, sizeof(int));
727 direct_watch_port = (uint16_t *)calloc(1, sizeof(uint16_t));
728 }
729 else
730 {
731 direct_watch = (int *)reallocf(direct_watch, (direct_watch_count + 1) * sizeof(int));
732 direct_watch_port = (uint16_t *)reallocf(direct_watch_port, (direct_watch_count + 1) * sizeof(uint16_t));
733 }
734
735 if ((direct_watch == NULL) || (direct_watch_port == NULL))
736 {
737 close(sock);
738
739 free(direct_watch);
740 direct_watch = NULL;
741
742 free(direct_watch_port);
743 direct_watch_port = NULL;
744
745 direct_watch_count = 0;
746 global.watchers_active = 0;
747 if (global.lockdown_session_count > 0) global.watchers_active = 1;
748
749 return ASL_STATUS_FAILED;
750 }
751
752 direct_watch[direct_watch_count] = sock;
753 direct_watch_port[direct_watch_count] = port;
754 direct_watch_count++;
755 global.watchers_active = direct_watch_count + global.lockdown_session_count;
756
757 return ASL_STATUS_OK;
758 #else
759 return ASL_STATUS_FAILED;
760 #endif
761 }
762
763 static void
764 cancel_direct_watch(uint16_t port)
765 {
766 #if TARGET_OS_EMBEDDED
767 uint32_t i;
768
769 for (i = 0; (i < direct_watch_count) && (port != direct_watch_port[i]); i++);
770
771 if (i >= direct_watch_count) return;
772
773 if (direct_watch_count == 1)
774 {
775 free(direct_watch);
776 direct_watch = NULL;
777
778 free(direct_watch_port);
779 direct_watch_port = NULL;
780
781 direct_watch_count = 0;
782 global.watchers_active = 0;
783 if (global.lockdown_session_count > 0) global.watchers_active = 1;
784 }
785 else
786 {
787 for (i++; i < direct_watch_count; i++)
788 {
789 direct_watch[i-1] = direct_watch[i];
790 direct_watch_port[i-1] = direct_watch_port[i];
791 }
792
793 direct_watch_count--;
794 global.watchers_active = direct_watch_count + global.lockdown_session_count;
795
796 direct_watch = (int *)reallocf(direct_watch, direct_watch_count * sizeof(int));
797 direct_watch_port = (uint16_t *)reallocf(direct_watch_port, direct_watch_count * sizeof(uint16_t));
798
799 if ((direct_watch == NULL) || (direct_watch_port == NULL))
800 {
801 free(direct_watch);
802 direct_watch = NULL;
803
804 free(direct_watch_port);
805 direct_watch_port = NULL;
806
807 direct_watch_count = 0;
808 global.watchers_active = 0;
809 if (global.lockdown_session_count > 0) global.watchers_active = 1;
810 }
811 }
812 #endif
813 }
814
815 static int
816 syslogd_state_query(asl_msg_t *q, asl_msg_list_t **res, uid_t uid)
817 {
818 asl_msg_list_t *out;
819 uint32_t i, n;
820 bool all = false;
821 asl_msg_t *m;
822 char val[256];
823 const char *mval;
824 asl_out_module_t *om;
825
826 if (res == NULL) return ASL_STATUS_INVALID_ARG;
827 *res = NULL;
828
829 out = asl_msg_list_new();
830 if (out == NULL) return ASL_STATUS_NO_MEMORY;
831
832 m = asl_msg_new(ASL_TYPE_MSG);
833 if (m == NULL)
834 {
835 asl_msg_list_release(out);
836 return ASL_STATUS_NO_MEMORY;
837 }
838
839 asl_msg_list_append(out, m);
840
841 /* q must have [ASLOption control], so a "null" query really has count == 1 */
842 if (asl_msg_count(q) == 1) all = true;
843
844 if (all || (0 == asl_msg_lookup(q, "debug", NULL, NULL)))
845 {
846 if (global.debug == 0) snprintf(val, sizeof(val), "0");
847 else snprintf(val, sizeof(val), "1 %s", global.debug_file);
848 asl_msg_set_key_val(m, "debug", val);
849 }
850
851 if (all || (0 == asl_msg_lookup(q, "dbtype", NULL, NULL)))
852 {
853 n = 0;
854 if (global.dbtype & DB_TYPE_FILE) n++;
855 if (global.dbtype & DB_TYPE_MEMORY) n++;
856
857 if (n == 0)
858 {
859 asl_msg_set_key_val(m, "dbtype", "unknown");
860 }
861 else
862 {
863 i = 0;
864 memset(val, 0, sizeof(val));
865
866 if (global.dbtype & DB_TYPE_FILE)
867 {
868 i++;
869 strncat(val, "file", 4);
870 if (i < n) strncat(val, " ", 1);
871 }
872
873 if (global.dbtype & DB_TYPE_MEMORY)
874 {
875 i++;
876 strncat(val, "memory", 6);
877 if (i < n) strncat(val, " ", 1);
878 }
879
880 asl_msg_set_key_val(m, "dbtype", val);
881 }
882 }
883
884 if (all || (0 == asl_msg_lookup(q, "db_file_max", NULL, NULL)))
885 {
886 snprintf(val, sizeof(val), "%u", global.db_file_max);
887 asl_msg_set_key_val(m, "db_file_max", val);
888 }
889
890 if (all || (0 == asl_msg_lookup(q, "db_memory_max", NULL, NULL)))
891 {
892 snprintf(val, sizeof(val), "%u", global.db_memory_max);
893 asl_msg_set_key_val(m, "db_memory_max", val);
894 }
895
896 if (all || (0 == asl_msg_lookup(q, "db_memory_str_max", NULL, NULL)))
897 {
898 snprintf(val, sizeof(val), "%u", global.db_memory_str_max);
899 asl_msg_set_key_val(m, "db_memory_str_max", val);
900 }
901
902 if (all || (0 == asl_msg_lookup(q, "mps_limit", NULL, NULL)))
903 {
904 snprintf(val, sizeof(val), "%u", global.mps_limit);
905 asl_msg_set_key_val(m, "mps_limit", val);
906 }
907
908 if (all || (0 == asl_msg_lookup(q, "bsd_max_dup_time", NULL, NULL)))
909 {
910 snprintf(val, sizeof(val), "%llu", global.bsd_max_dup_time);
911 asl_msg_set_key_val(m, "bsd_max_dup_time", val);
912 }
913
914 if (all || (0 == asl_msg_lookup(q, "mark_time", NULL, NULL)))
915 {
916 snprintf(val, sizeof(val), "%llu", global.mark_time);
917 asl_msg_set_key_val(m, "mark_time", val);
918 }
919
920 if (all || (0 == asl_msg_lookup(q, "utmp_ttl", NULL, NULL)))
921 {
922 snprintf(val, sizeof(val), "%llu", (unsigned long long) global.utmp_ttl);
923 asl_msg_set_key_val(m, "utmp_ttl", val);
924 }
925
926 if (all || (0 == asl_msg_lookup(q, "memory_size", NULL, NULL)))
927 {
928 snprintf(val, sizeof(val), "%lld", global.memory_size);
929 asl_msg_set_key_val(m, "memory_size", val);
930 }
931
932 if (all || (0 == asl_msg_lookup(q, "memory_max", NULL, NULL)))
933 {
934 snprintf(val, sizeof(val), "%lld", global.memory_max);
935 asl_msg_set_key_val(m, "memory_max", val);
936 }
937
938 if (all || (0 == asl_msg_lookup(q, "stats_interval", NULL, NULL)))
939 {
940 snprintf(val, sizeof(val), "%lld", (long long) global.stats_interval);
941 asl_msg_set_key_val(m, "stats_interval", val);
942 }
943
944 if (all || (0 == asl_msg_lookup(q, "work_queue_count", NULL, NULL)))
945 {
946 snprintf(val, sizeof(val), "%d", global.work_queue_count);
947 asl_msg_set_key_val(m, "work_queue_count", val);
948 }
949
950 if (all || (0 == asl_msg_lookup(q, "asl_queue_count", NULL, NULL)))
951 {
952 snprintf(val, sizeof(val), "%d", global.asl_queue_count);
953 asl_msg_set_key_val(m, "asl_queue_count", val);
954 }
955
956 if (all || (0 == asl_msg_lookup(q, "bsd_queue_count", NULL, NULL)))
957 {
958 snprintf(val, sizeof(val), "%d", global.bsd_queue_count);
959 asl_msg_set_key_val(m, "bsd_queue_count", val);
960 }
961
962 if (all || (0 == asl_msg_lookup(q, "client_count", NULL, NULL)))
963 {
964 snprintf(val, sizeof(val), "%d", global.client_count);
965 asl_msg_set_key_val(m, "client_count", val);
966 }
967
968 if (all || (0 == asl_msg_lookup(q, "disaster_occurred", NULL, NULL)))
969 {
970 snprintf(val, sizeof(val), "%d", global.disaster_occurred);
971 asl_msg_set_key_val(m, "disaster_occurred", val);
972 }
973
974 #ifdef LOCKDOWN
975 if (all || (0 == asl_msg_lookup(q, "lockdown_session_count", NULL, NULL)))
976 {
977 snprintf(val, sizeof(val), "%d", global.lockdown_session_count);
978 asl_msg_set_key_val(m, "lockdown_session_count", val);
979 }
980
981 if (all || (0 == asl_msg_lookup(q, "remote_delay_time", NULL, NULL)))
982 {
983 snprintf(val, sizeof(val), "%u", global.remote_delay_time);
984 asl_msg_set_key_val(m, "remote_delay_time", val);
985 }
986
987 #endif
988
989 if (all || (0 == asl_msg_lookup(q, "watchers_active", NULL, NULL)))
990 {
991 snprintf(val, sizeof(val), "%d", global.watchers_active);
992 asl_msg_set_key_val(m, "watchers_active", val);
993 }
994
995 for (i = 0; i < global.module_count; i++)
996 {
997 if (all || (0 == asl_msg_lookup(q, global.module[i]->name, NULL, NULL)))
998 {
999 snprintf(val, sizeof(val), "%s", global.module[i]->enabled ? "enabled" : "disabled");
1000 asl_msg_set_key_val(m, global.module[i]->name, val);
1001 }
1002 }
1003
1004 for (om = global.asl_out_module; om != NULL; om = om->next)
1005 {
1006 if (all || (0 == asl_msg_lookup(q, om->name, NULL, NULL)))
1007 {
1008 snprintf(val, sizeof(val), "%s", om->flags & MODULE_FLAG_ENABLED ? "enabled" : "disabled");
1009 if (om->name == NULL) asl_msg_set_key_val(m, "asl.conf", val);
1010 else asl_msg_set_key_val(m, om->name, val);
1011 }
1012 }
1013
1014 /* synchronous actions use queries, since messages are simpleroutines */
1015 if (0 == asl_msg_lookup(q, "action", &mval, NULL))
1016 {
1017 int res = -1;
1018 if (uid == 0) res = asl_action_control_set_param(mval);
1019 snprintf(val, sizeof(val), "%d", res);
1020 asl_msg_set_key_val(m, "action", val);
1021 }
1022
1023 asl_msg_release(m);
1024 *res = out;
1025 return ASL_STATUS_OK;
1026 }
1027
1028 static kern_return_t
1029 _server_message_processing(asl_request_msg *request)
1030 {
1031 const uint32_t sbits = MACH_SEND_MSG | MACH_SEND_TIMEOUT;;
1032 kern_return_t ks;
1033 asl_reply_msg *reply = calloc(1, sizeof(asl_reply_msg) + MAX_TRAILER_SIZE);
1034
1035 voucher_mach_msg_state_t voucher = voucher_mach_msg_adopt(&(request->head));
1036
1037 /* MIG server routine */
1038 asl_ipc_server(&(request->head), &(reply->head));
1039
1040 if (!(reply->head.msgh_bits & MACH_MSGH_BITS_COMPLEX))
1041 {
1042 if (reply->reply.Reply__asl_server_message.RetCode == MIG_NO_REPLY)
1043 {
1044 reply->head.msgh_remote_port = MACH_PORT_NULL;
1045 }
1046 else if ((reply->reply.Reply__asl_server_message.RetCode != KERN_SUCCESS) && (request->head.msgh_bits & MACH_MSGH_BITS_COMPLEX))
1047 {
1048 /* destroy the request - but not the reply port */
1049 request->head.msgh_remote_port = MACH_PORT_NULL;
1050 mach_msg_destroy(&(request->head));
1051 }
1052 }
1053
1054 if (reply->head.msgh_remote_port != MACH_PORT_NULL)
1055 {
1056 ks = mach_msg(&(reply->head), sbits, reply->head.msgh_size, 0, MACH_PORT_NULL, 10, MACH_PORT_NULL);
1057 if ((ks == MACH_SEND_INVALID_DEST) || (ks == MACH_SEND_TIMED_OUT))
1058 {
1059 /* clean up */
1060 mach_msg_destroy(&(reply->head));
1061 }
1062 else if (ks == MACH_SEND_INVALID_HEADER)
1063 {
1064 /*
1065 * This should never happen, but we can continue running.
1066 */
1067 char str[256];
1068 asldebug("ERROR: mach_msg() send failed with MACH_SEND_INVALID_HEADER 0x%08x\n", ks);
1069 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);
1070 internal_log_message(str);
1071 mach_msg_destroy(&(reply->head));
1072 }
1073 else if (ks == MACH_SEND_NO_BUFFER)
1074 {
1075 /*
1076 * This should never happen, but the kernel can run out of memory.
1077 * We clean up and continue running.
1078 */
1079 char str[256];
1080 asldebug("ERROR: mach_msg() send failed with MACH_SEND_NO_BUFFER 0x%08x\n", ks);
1081 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);
1082 internal_log_message(str);
1083 mach_msg_destroy(&(reply->head));
1084 }
1085 else if (ks != KERN_SUCCESS)
1086 {
1087 /*
1088 * Failed to send a reply message. This should never happen,
1089 * but the best action is to crash.
1090 */
1091 char str[256];
1092 asldebug("FATAL ERROR: mach_msg() send failed with status 0x%08x\n", ks);
1093 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);
1094 internal_log_message(str);
1095 sleep(1);
1096 abort();
1097 }
1098 }
1099 else if (reply->head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
1100 {
1101 mach_msg_destroy(&reply->head);
1102 }
1103
1104 voucher_mach_msg_revert(voucher);
1105 free(request);
1106 free(reply);
1107 }
1108
1109 /*
1110 * Receives messages on the "com.apple.system.logger" mach port.
1111 * Services database search requests.
1112 * Runs in it's own thread.
1113 *
1114 * The logic in this routine got a bit more complex due to (1) increased logging load and (2) 16K page size.
1115 * Out-of-line (OOL) memory sent to syslogd from libasl is allocated in pages, so the minimum size of a
1116 * message is one page. Since this routine can get slammed with messages at a very high rate, and since
1117 * the message queue in the kernel is only 5 messages, it is critical that this routine service the port
1118 * as fast as possible. To that end, it needs to do as little processing as possible.
1119 * In the version of this code found up to syslog-312, this routine received messages and dispatched them
1120 * on the asl_server_queue for further processing. When pages were only 4K, this was not a problem. With
1121 * 16K pages, it only takes about 650 messages to run syslogd's dirty memoory size up to the point of its
1122 * jetsam limit. Code was added here to track the memory being used in this queue + the work queue that's
1123 * used by process_message(), such that messages will get dropped if the queues reach a memory limit.
1124 * The actual message data in the VM pages is typically only a few hundred bytes, so holding VM pages in
1125 * the queue was a waste, and seriously limited the number of queued messages.
1126 *
1127 * The solution implemented here is a bit of a hack. It peeks at the received message header to determine
1128 * which MIG routine is being called. If the call is for _asl_server_message, it calls asl_ipc_server()
1129 * on the server thread. This routes the call through the MIG server code for error checking and so on,
1130 * and invokes _asl_server_message() on this thread. _asl_server_message() has been modified to copy
1131 * the message data into malloced memory, vm_deallocate the OOL memory, and then it dispatches the real
1132 * work onto the asl_server_queue.
1133 */
1134 void
1135 database_server()
1136 {
1137 asl_request_msg *request;
1138 uint32_t rqs, asl_server_message_num = 0;
1139 size_t i;
1140 struct timeval now, send_time;
1141 mach_dead_name_notification_t *deadname;
1142 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;
1143 send_time.tv_sec = 0;
1144 send_time.tv_usec = 0;
1145 struct mig_map_s {
1146 const char *routine;
1147 int num;
1148 } migmap[] = { subsystem_to_name_map_asl_ipc };
1149
1150 for (i = 0; (i < (sizeof(migmap) / sizeof(struct mig_map_s))) && (asl_server_message_num == 0); i++)
1151 {
1152 if (!strcmp(migmap[i].routine, "_asl_server_message")) asl_server_message_num = migmap[i].num;
1153 }
1154
1155 rqs = sizeof(asl_request_msg) + MAX_TRAILER_SIZE;
1156
1157 asl_server_queue = dispatch_queue_create("ASL Server Queue", NULL);
1158
1159 forever
1160 {
1161 kern_return_t ks;
1162
1163 now.tv_sec = 0;
1164 now.tv_usec = 0;
1165
1166 request = (asl_request_msg *)calloc(1, rqs);
1167 if (request == NULL) continue;
1168
1169 request->head.msgh_local_port = global.server_port;
1170 request->head.msgh_size = rqs;
1171
1172 ks = mach_msg(&(request->head), rbits, 0, rqs, global.listen_set, 0, MACH_PORT_NULL);
1173 if (ks != KERN_SUCCESS)
1174 {
1175 /*
1176 * This shouldn't happen, but if we get a failure the best thing to do is to crash.
1177 */
1178 char str[256];
1179 asldebug("FATAL ERROR: mach_msg() receive failed with status 0x%08x\n", ks);
1180 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);
1181 internal_log_message(str);
1182 sleep(1);
1183 abort();
1184 }
1185
1186 if (request->head.msgh_id == MACH_NOTIFY_DEAD_NAME)
1187 {
1188 deadname = (mach_dead_name_notification_t *)request;
1189 dispatch_async(asl_server_queue, ^{
1190 cancel_session(deadname->not_port);
1191 /* dead name notification includes a dead name right */
1192 mach_port_deallocate(mach_task_self(), deadname->not_port);
1193 free(request);
1194 });
1195
1196 continue;
1197 }
1198
1199 int64_t msize = 0;
1200 if (request->head.msgh_id == asl_server_message_num)
1201 {
1202 _server_message_processing(request);
1203 }
1204 else
1205 {
1206 dispatch_async(asl_server_queue, ^{ _server_message_processing(request); });
1207 }
1208 }
1209 }
1210
1211 static void
1212 caller_get_read_entitlement(pid_t pid, uid_t *uid, gid_t *gid)
1213 {
1214 #if TARGET_OS_EMBEDDED
1215 xpc_object_t edata, entitlements, val;
1216 bool bval = false;
1217 int64_t ival = -2;
1218 size_t len;
1219 const void *ptr;
1220
1221 edata = xpc_copy_entitlements_for_pid(pid);
1222 if (edata == NULL) return;
1223
1224 ptr = xpc_data_get_bytes_ptr(edata);
1225 len = xpc_data_get_length(edata);
1226
1227 entitlements = xpc_create_from_plist(ptr, len);
1228 xpc_release(edata);
1229 if (entitlements == NULL) return;
1230
1231 if (xpc_get_type(entitlements) != XPC_TYPE_DICTIONARY)
1232 {
1233 asldebug("xpc_copy_entitlements_for_pid has non-dictionary data for pid %d\n", pid);
1234 return;
1235 }
1236
1237 bval = xpc_dictionary_get_bool(entitlements, ASL_ENTITLEMENT_KEY);
1238 if (bval && (uid != NULL))
1239 {
1240 *uid = 0;
1241 xpc_release(entitlements);
1242 return;
1243 }
1244
1245 val = xpc_dictionary_get_value(entitlements, ASL_ENTITLEMENT_UID_KEY);
1246 if (val != NULL)
1247 {
1248 if ((xpc_get_type(val) == XPC_TYPE_INT64) && (uid != NULL))
1249 {
1250 ival = xpc_int64_get_value(val);
1251 *uid = ival;
1252 }
1253 }
1254
1255 val = xpc_dictionary_get_value(entitlements, ASL_ENTITLEMENT_GID_KEY);
1256 if (val != NULL)
1257 {
1258 if ((xpc_get_type(val) == XPC_TYPE_INT64) && (gid != NULL))
1259 {
1260 ival = xpc_int64_get_value(val);
1261 *gid = ival;
1262 }
1263 }
1264
1265 xpc_release(entitlements);
1266 #endif
1267 }
1268
1269 static kern_return_t
1270 __asl_server_query_internal
1271 (
1272 mach_port_t server,
1273 caddr_t request,
1274 mach_msg_type_number_t requestCnt,
1275 uint64_t startid,
1276 int count,
1277 uint32_t duration,
1278 int direction,
1279 caddr_t *reply,
1280 mach_msg_type_number_t *replyCnt,
1281 uint64_t *lastid,
1282 int *status,
1283 uid_t uid,
1284 gid_t gid,
1285 pid_t pid
1286 )
1287 {
1288 asl_msg_list_t *query;
1289 asl_msg_list_t *res;
1290 char *out, *vmbuffer;
1291 uint32_t outlen;
1292 kern_return_t kstatus;
1293
1294 *status = ASL_STATUS_OK;
1295
1296 if ((request != NULL) && (request[requestCnt - 1] != '\0'))
1297 {
1298 *status = ASL_STATUS_INVALID_ARG;
1299 vm_deallocate(mach_task_self(), (vm_address_t)request, requestCnt);
1300 return KERN_SUCCESS;
1301 }
1302
1303 query = asl_msg_list_from_string(request);
1304 if (request != NULL) vm_deallocate(mach_task_self(), (vm_address_t)request, requestCnt);
1305 res = NULL;
1306
1307 /* A query list containing a single query, which itself contains
1308 * [ASLOption control] is an internal state query */
1309 if ((query != NULL) && (query->count == 1) && asl_check_option(query->msg[0], ASL_OPT_CONTROL))
1310 {
1311 *status = syslogd_state_query(query->msg[0], &res, uid);
1312 }
1313 else
1314 {
1315 int x = 0;
1316 #if TARGET_OS_EMBEDDED
1317 x = pid;
1318 #endif
1319
1320 if (pid > 0)
1321 {
1322 caller_get_read_entitlement(pid, &uid, &gid);
1323 if (uid == 0) x = 0;
1324 }
1325
1326 *status = db_query(query, &res, startid, count, duration, direction, lastid, uid, gid, x);
1327 }
1328
1329 asl_msg_list_release(query);
1330 if (*status != ASL_STATUS_INVALID_STORE)
1331 {
1332 /* ignore */
1333 }
1334 else if (*status != ASL_STATUS_OK)
1335 {
1336 if (res != NULL) asl_msg_list_release(res);
1337 return KERN_SUCCESS;
1338 }
1339
1340 out = NULL;
1341 outlen = 0;
1342 out = asl_msg_list_to_string(res, &outlen);
1343 asl_msg_list_release(res);
1344
1345 if ((out == NULL) || (outlen == 0)) return KERN_SUCCESS;
1346
1347 kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmbuffer, outlen, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
1348 if (kstatus != KERN_SUCCESS)
1349 {
1350 free(out);
1351 return kstatus;
1352 }
1353
1354 memmove(vmbuffer, out, outlen);
1355 free(out);
1356
1357 *reply = vmbuffer;
1358 *replyCnt = outlen;
1359
1360 return KERN_SUCCESS;
1361 }
1362
1363 kern_return_t
1364 __asl_server_query_2
1365 (
1366 mach_port_t server,
1367 caddr_t request,
1368 mach_msg_type_number_t requestCnt,
1369 uint64_t startid,
1370 int count,
1371 int flags,
1372 caddr_t *reply,
1373 mach_msg_type_number_t *replyCnt,
1374 uint64_t *lastid,
1375 int *status,
1376 audit_token_t token
1377 )
1378 {
1379 uid_t uid = (uid_t)-1;
1380 gid_t gid = (gid_t)-1;
1381 pid_t pid = (pid_t)-1;
1382
1383 int direction = SEARCH_FORWARD;
1384 if (flags & QUERY_FLAG_SEARCH_REVERSE) direction = SEARCH_BACKWARD;
1385
1386 audit_token_to_au32(token, NULL, &uid, &gid, NULL, NULL, &pid, NULL, NULL);
1387
1388 return __asl_server_query_internal(server, request, requestCnt, startid, count, QUERY_DURATION_UNLIMITED, direction, reply, replyCnt, lastid, status, uid, gid, pid);
1389 }
1390
1391 kern_return_t
1392 __asl_server_query
1393 (
1394 mach_port_t server,
1395 caddr_t request,
1396 mach_msg_type_number_t requestCnt,
1397 uint64_t startid,
1398 int count,
1399 int flags,
1400 caddr_t *reply,
1401 mach_msg_type_number_t *replyCnt,
1402 uint64_t *lastid,
1403 int *status,
1404 security_token_t *token
1405 )
1406 {
1407 int direction = SEARCH_FORWARD;
1408 if (flags & QUERY_FLAG_SEARCH_REVERSE) direction = SEARCH_BACKWARD;
1409
1410 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);
1411 }
1412
1413 kern_return_t
1414 __asl_server_query_timeout
1415 (
1416 mach_port_t server,
1417 caddr_t request,
1418 mach_msg_type_number_t requestCnt,
1419 uint64_t startid,
1420 int count,
1421 int flags,
1422 caddr_t *reply,
1423 mach_msg_type_number_t *replyCnt,
1424 uint64_t *lastid,
1425 int *status,
1426 audit_token_t token
1427 )
1428 {
1429 uid_t uid = (uid_t)-1;
1430 gid_t gid = (gid_t)-1;
1431 pid_t pid = (pid_t)-1;
1432 int direction = SEARCH_FORWARD;
1433 if (flags & QUERY_FLAG_SEARCH_REVERSE) direction = SEARCH_BACKWARD;
1434
1435 audit_token_to_au32(token, NULL, &uid, &gid, NULL, NULL, &pid, NULL, NULL);
1436
1437 return __asl_server_query_internal(server, request, requestCnt, startid, count, QUERY_DURATION_UNLIMITED, direction, reply, replyCnt, lastid, status, uid, gid, pid);
1438 }
1439
1440 kern_return_t
1441 __asl_server_match
1442 (
1443 mach_port_t server,
1444 caddr_t request,
1445 mach_msg_type_number_t requestCnt,
1446 uint64_t startid,
1447 uint64_t count,
1448 uint32_t duration,
1449 int direction,
1450 caddr_t *reply,
1451 mach_msg_type_number_t *replyCnt,
1452 uint64_t *lastid,
1453 int *status,
1454 audit_token_t token
1455 )
1456 {
1457 uid_t uid = (uid_t)-1;
1458 gid_t gid = (gid_t)-1;
1459 pid_t pid = (pid_t)-1;
1460
1461 audit_token_to_au32(token, NULL, &uid, &gid, NULL, NULL, &pid, NULL, NULL);
1462
1463 return __asl_server_query_internal(server, request, requestCnt, startid, count, duration, direction, reply, replyCnt, lastid, status, uid, gid, pid);
1464 }
1465
1466 kern_return_t
1467 __asl_server_prune
1468 (
1469 mach_port_t server,
1470 caddr_t request,
1471 mach_msg_type_number_t requestCnt,
1472 int *status,
1473 security_token_t *token
1474 )
1475 {
1476 return KERN_SUCCESS;
1477 }
1478
1479 /*
1480 * Does the actual processing for __asl_server_message.
1481 * Dispatched on asl_server_queue. This lets us avoid
1482 * calling asl_msg_from_string(), task_name_for_pid(),
1483 * and register_session() on the database_server() thread.
1484 */
1485 static void
1486 _asl_message_processing(char *mbuf, uint64_t msize, uid_t uid, gid_t gid, pid_t pid)
1487 {
1488 asl_msg_t *msg;
1489 char tmp[64];
1490 kern_return_t kstatus;
1491 mach_port_name_t client;
1492
1493 msg = asl_msg_from_string(mbuf);
1494 free(mbuf);
1495
1496 /*
1497 * process_message() will update global.memory_size with the
1498 * size of msg, and it increements the work_queue_count.
1499 */
1500 OSAtomicAdd64(-1ll * msize, &global.memory_size);
1501 OSAtomicDecrement32(&global.work_queue_count);
1502
1503 if (msg == NULL) return;
1504
1505 client = MACH_PORT_NULL;
1506 kstatus = task_name_for_pid(mach_task_self(), pid, &client);
1507 if (kstatus == KERN_SUCCESS) register_session(client, pid);
1508
1509 snprintf(tmp, sizeof(tmp), "%d", uid);
1510 asl_msg_set_key_val(msg, ASL_KEY_UID, tmp);
1511
1512 snprintf(tmp, sizeof(tmp), "%d", gid);
1513 asl_msg_set_key_val(msg, ASL_KEY_GID, tmp);
1514
1515 snprintf(tmp, sizeof(tmp), "%d", pid);
1516 asl_msg_set_key_val(msg, ASL_KEY_PID, tmp);
1517
1518 process_message(msg, SOURCE_ASL_MESSAGE);
1519 }
1520
1521 /*
1522 * This MIG server routine is something of a special case in database_server() above.
1523 * It is called on the server thread that's responsible for servicing syslogd's mach port.
1524 * In this routine we copy the actual ASL message raw string out of the message into
1525 * malloc memory, deallocate the message, and dispatch the real work onto the asl_server_queue.
1526 */
1527 kern_return_t
1528 __asl_server_message
1529 (
1530 mach_port_t server,
1531 caddr_t message,
1532 mach_msg_type_number_t messageCnt,
1533 audit_token_t token
1534 )
1535 {
1536 uid_t uid;
1537 gid_t gid;
1538 pid_t pid;
1539 char *mbuf;
1540
1541 if (message == NULL) return KERN_SUCCESS;
1542
1543 if (message[messageCnt - 1] != '\0')
1544 {
1545 vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt);
1546 return KERN_SUCCESS;
1547 }
1548
1549 asldebug("__asl_server_message: %s\n", message);
1550
1551 if ((global.memory_size + messageCnt) > global.memory_max)
1552 {
1553 char str[256];
1554 asldebug("Server queue dropped message. message size %u queue size %lld max %lld\n", messageCnt, global.memory_size, global.memory_max);
1555 snprintf(str, sizeof(str), "[Sender syslogd] [Level 2] [PID %u] [Message Received message size %u overflows work queue (size %lld limit %lld) - dropping message] [UID 0] [UID 0] [Facility syslog]", global.pid, messageCnt, global.memory_size, global.memory_max);
1556 internal_log_message(str);
1557
1558 vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt);
1559 return KERN_SUCCESS;
1560 }
1561
1562 mbuf = malloc(messageCnt);
1563 if (mbuf != NULL) memcpy(mbuf, message, messageCnt);
1564 vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt);
1565
1566 if (mbuf == NULL) return KERN_SUCCESS;
1567
1568 uid = (uid_t)-1;
1569 gid = (gid_t)-1;
1570 pid = (pid_t)-1;
1571 audit_token_to_au32(token, NULL, &uid, &gid, NULL, NULL, &pid, NULL, NULL);
1572
1573 OSAtomicIncrement32(&global.work_queue_count);
1574 OSAtomicAdd64(messageCnt, &(global.memory_size));
1575
1576 dispatch_async(asl_server_queue, ^{ _asl_message_processing(mbuf, messageCnt, uid, gid, pid); });
1577
1578 return KERN_SUCCESS;
1579 }
1580
1581 kern_return_t
1582 __asl_server_create_aux_link
1583 (
1584 mach_port_t server,
1585 caddr_t message,
1586 mach_msg_type_number_t messageCnt,
1587 mach_port_t *fileport,
1588 caddr_t *newurl,
1589 mach_msg_type_number_t *newurlCnt,
1590 int *status,
1591 audit_token_t token
1592 )
1593 {
1594 asl_msg_t *msg;
1595 char tmp[64];
1596 uid_t uid;
1597 gid_t gid;
1598 pid_t pid;
1599 kern_return_t kstatus;
1600 mach_port_name_t client;
1601 char *url, *vmbuffer;
1602 int fd;
1603
1604 *status = ASL_STATUS_OK;
1605 *fileport = MACH_PORT_NULL;
1606 *newurl = 0;
1607
1608 if (message == NULL)
1609 {
1610 *status = ASL_STATUS_INVALID_ARG;
1611 return KERN_SUCCESS;
1612 }
1613
1614 if (message[messageCnt - 1] != '\0')
1615 {
1616 *status = ASL_STATUS_INVALID_ARG;
1617 vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt);
1618 return KERN_SUCCESS;
1619 }
1620
1621 asldebug("__asl_server_create_aux_link: %s\n", (message == NULL) ? "NULL" : message);
1622
1623 if ((global.dbtype & DB_TYPE_FILE) == 0)
1624 {
1625 *status = ASL_STATUS_INVALID_STORE;
1626 return KERN_SUCCESS;
1627 }
1628
1629 *fileport = MACH_PORT_NULL;
1630
1631 msg = asl_msg_from_string(message);
1632 vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt);
1633
1634 if (msg == NULL) return KERN_SUCCESS;
1635
1636 uid = (uid_t)-1;
1637 gid = (gid_t)-1;
1638 pid = (pid_t)-1;
1639 audit_token_to_au32(token, NULL, &uid, &gid, NULL, NULL, &pid, NULL, NULL);
1640
1641 client = MACH_PORT_NULL;
1642 kstatus = task_name_for_pid(mach_task_self(), pid, &client);
1643 if (kstatus == KERN_SUCCESS) register_session(client, pid);
1644
1645 snprintf(tmp, sizeof(tmp), "%d", uid);
1646 asl_msg_set_key_val(msg, ASL_KEY_UID, tmp);
1647
1648 snprintf(tmp, sizeof(tmp), "%d", gid);
1649 asl_msg_set_key_val(msg, ASL_KEY_GID, tmp);
1650
1651 snprintf(tmp, sizeof(tmp), "%d", pid);
1652 asl_msg_set_key_val(msg, ASL_KEY_PID, tmp);
1653
1654 /* create a file for the client */
1655 *status = asl_store_open_aux(global.file_db, msg, &fd, &url);
1656 asl_msg_release(msg);
1657 if (*status != ASL_STATUS_OK) return KERN_SUCCESS;
1658 if (url == NULL)
1659 {
1660 if (fd >= 0) close(fd);
1661 *status = ASL_STATUS_FAILED;
1662 return KERN_SUCCESS;
1663 }
1664
1665 if (fileport_makeport(fd, (fileport_t *)fileport) < 0)
1666 {
1667 close(fd);
1668 free(url);
1669 *status = ASL_STATUS_FAILED;
1670 return KERN_SUCCESS;
1671 }
1672
1673 close(fd);
1674
1675 *newurlCnt = strlen(url) + 1;
1676
1677 kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmbuffer, *newurlCnt, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
1678 if (kstatus != KERN_SUCCESS)
1679 {
1680 free(url);
1681 return kstatus;
1682 }
1683
1684 memmove(vmbuffer, url, *newurlCnt);
1685 free(url);
1686
1687 *newurl = vmbuffer;
1688
1689 return KERN_SUCCESS;
1690 }
1691
1692 kern_return_t
1693 __asl_server_register_direct_watch
1694 (
1695 mach_port_t server,
1696 int port,
1697 audit_token_t token
1698 )
1699 {
1700 uint16_t p16 = port;
1701 pid_t pid = (pid_t)-1;
1702
1703 audit_token_to_au32(token, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL);
1704
1705 asldebug("__asl_server_register_direct_watch: pid %u port %hu\n", pid, ntohs(p16));
1706
1707 dispatch_once(&watch_init_once, ^{
1708 watch_queue = dispatch_queue_create("Direct Watch Queue", NULL);
1709 });
1710
1711 dispatch_async(watch_queue, ^{ register_direct_watch(p16); });
1712
1713 return KERN_SUCCESS;
1714 }
1715
1716 kern_return_t
1717 __asl_server_cancel_direct_watch
1718 (
1719 mach_port_t server,
1720 int port,
1721 audit_token_t token
1722 )
1723 {
1724 uint16_t p16 = port;
1725
1726 asldebug("__asl_server_cancel_direct_watch: %hu\n", ntohs(p16));
1727
1728 dispatch_once(&watch_init_once, ^{
1729 watch_queue = dispatch_queue_create("Direct Watch Queue", NULL);
1730 });
1731
1732 dispatch_async(watch_queue, ^{ cancel_direct_watch(p16); });
1733
1734 return KERN_SUCCESS;
1735 }