]> git.saurik.com Git - apple/syslog.git/blob - syslogd.tproj/dbserver.c
7c355b62c1c17b26654bd189fa9e7c0d2b6af24f
[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 }
421 j++;
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
825 if (res == NULL) return ASL_STATUS_INVALID_ARG;
826 *res = NULL;
827
828 out = asl_msg_list_new();
829 if (out == NULL) return ASL_STATUS_NO_MEMORY;
830
831 m = asl_msg_new(ASL_TYPE_MSG);
832 if (m == NULL)
833 {
834 asl_msg_list_release(out);
835 return ASL_STATUS_NO_MEMORY;
836 }
837
838 asl_msg_list_append(out, m);
839
840 /* q must have [ASLOption control], so a "null" query really has count == 1 */
841 if (asl_msg_count(q) == 1) all = true;
842
843 if (all || (0 == asl_msg_lookup(q, "debug", NULL, NULL)))
844 {
845 if (global.debug == 0) snprintf(val, sizeof(val), "0");
846 else snprintf(val, sizeof(val), "1 %s", global.debug_file);
847 asl_msg_set_key_val(m, "debug", val);
848 }
849
850 if (all || (0 == asl_msg_lookup(q, "dbtype", NULL, NULL)))
851 {
852 n = 0;
853 if (global.dbtype & DB_TYPE_FILE) n++;
854 if (global.dbtype & DB_TYPE_MEMORY) n++;
855
856 if (n == 0)
857 {
858 asl_msg_set_key_val(m, "dbtype", "unknown");
859 }
860 else
861 {
862 i = 0;
863 memset(val, 0, sizeof(val));
864
865 if (global.dbtype & DB_TYPE_FILE)
866 {
867 i++;
868 strncat(val, "file", 4);
869 if (i < n) strncat(val, " ", 1);
870 }
871
872 if (global.dbtype & DB_TYPE_MEMORY)
873 {
874 i++;
875 strncat(val, "memory", 6);
876 if (i < n) strncat(val, " ", 1);
877 }
878
879 asl_msg_set_key_val(m, "dbtype", val);
880 }
881 }
882
883 if (all || (0 == asl_msg_lookup(q, "db_file_max", NULL, NULL)))
884 {
885 snprintf(val, sizeof(val), "%u", global.db_file_max);
886 asl_msg_set_key_val(m, "db_file_max", val);
887 }
888
889 if (all || (0 == asl_msg_lookup(q, "db_memory_max", NULL, NULL)))
890 {
891 snprintf(val, sizeof(val), "%u", global.db_memory_max);
892 asl_msg_set_key_val(m, "db_memory_max", val);
893 }
894
895 if (all || (0 == asl_msg_lookup(q, "db_memory_str_max", NULL, NULL)))
896 {
897 snprintf(val, sizeof(val), "%u", global.db_memory_str_max);
898 asl_msg_set_key_val(m, "db_memory_str_max", val);
899 }
900
901 if (all || (0 == asl_msg_lookup(q, "mps_limit", NULL, NULL)))
902 {
903 snprintf(val, sizeof(val), "%u", global.mps_limit);
904 asl_msg_set_key_val(m, "mps_limit", val);
905 }
906
907 if (all || (0 == asl_msg_lookup(q, "bsd_max_dup_time", NULL, NULL)))
908 {
909 snprintf(val, sizeof(val), "%llu", global.bsd_max_dup_time);
910 asl_msg_set_key_val(m, "bsd_max_dup_time", val);
911 }
912
913 if (all || (0 == asl_msg_lookup(q, "mark_time", NULL, NULL)))
914 {
915 snprintf(val, sizeof(val), "%llu", global.mark_time);
916 asl_msg_set_key_val(m, "mark_time", val);
917 }
918
919 if (all || (0 == asl_msg_lookup(q, "utmp_ttl", NULL, NULL)))
920 {
921 snprintf(val, sizeof(val), "%llu", (unsigned long long) global.utmp_ttl);
922 asl_msg_set_key_val(m, "utmp_ttl", val);
923 }
924
925 if (all || (0 == asl_msg_lookup(q, "memory_size", NULL, NULL)))
926 {
927 snprintf(val, sizeof(val), "%lld", global.memory_size);
928 asl_msg_set_key_val(m, "memory_size", val);
929 }
930
931 if (all || (0 == asl_msg_lookup(q, "memory_max", NULL, NULL)))
932 {
933 snprintf(val, sizeof(val), "%lld", global.memory_max);
934 asl_msg_set_key_val(m, "memory_max", val);
935 }
936
937 if (all || (0 == asl_msg_lookup(q, "stats_interval", NULL, NULL)))
938 {
939 snprintf(val, sizeof(val), "%lld", (long long) global.stats_interval);
940 asl_msg_set_key_val(m, "stats_interval", val);
941 }
942
943 if (all || (0 == asl_msg_lookup(q, "work_queue_count", NULL, NULL)))
944 {
945 snprintf(val, sizeof(val), "%d", global.work_queue_count);
946 asl_msg_set_key_val(m, "work_queue_count", val);
947 }
948
949 if (all || (0 == asl_msg_lookup(q, "asl_queue_count", NULL, NULL)))
950 {
951 snprintf(val, sizeof(val), "%d", global.asl_queue_count);
952 asl_msg_set_key_val(m, "asl_queue_count", val);
953 }
954
955 if (all || (0 == asl_msg_lookup(q, "bsd_queue_count", NULL, NULL)))
956 {
957 snprintf(val, sizeof(val), "%d", global.bsd_queue_count);
958 asl_msg_set_key_val(m, "bsd_queue_count", val);
959 }
960
961 if (all || (0 == asl_msg_lookup(q, "client_count", NULL, NULL)))
962 {
963 snprintf(val, sizeof(val), "%d", global.client_count);
964 asl_msg_set_key_val(m, "client_count", val);
965 }
966
967 if (all || (0 == asl_msg_lookup(q, "disaster_occurred", NULL, NULL)))
968 {
969 snprintf(val, sizeof(val), "%d", global.disaster_occurred);
970 asl_msg_set_key_val(m, "disaster_occurred", val);
971 }
972
973 #ifdef LOCKDOWN
974 if (all || (0 == asl_msg_lookup(q, "lockdown_session_count", NULL, NULL)))
975 {
976 snprintf(val, sizeof(val), "%d", global.lockdown_session_count);
977 asl_msg_set_key_val(m, "lockdown_session_count", val);
978 }
979
980 if (all || (0 == asl_msg_lookup(q, "remote_delay_time", NULL, NULL)))
981 {
982 snprintf(val, sizeof(val), "%u", global.remote_delay_time);
983 asl_msg_set_key_val(m, "remote_delay_time", val);
984 }
985
986 #endif
987
988 if (all || (0 == asl_msg_lookup(q, "watchers_active", NULL, NULL)))
989 {
990 snprintf(val, sizeof(val), "%d", global.watchers_active);
991 asl_msg_set_key_val(m, "watchers_active", val);
992 }
993
994 for (i = 0; i < global.module_count; i++)
995 {
996 if (all || (0 == asl_msg_lookup(q, global.module[i]->name, NULL, NULL)))
997 {
998 snprintf(val, sizeof(val), "%s", global.module[i]->enabled ? "enabled" : "disabled");
999 asl_msg_set_key_val(m, global.module[i]->name, val);
1000 }
1001 }
1002
1003 /* output module query must be on the asl_action_queue */
1004 asl_action_out_module_query(q, m, all);
1005
1006 /* synchronous actions use queries, since messages are simpleroutines */
1007 if (0 == asl_msg_lookup(q, "action", &mval, NULL))
1008 {
1009 int res = -1;
1010 if (uid == 0) res = asl_action_control_set_param(mval);
1011 snprintf(val, sizeof(val), "%d", res);
1012 asl_msg_set_key_val(m, "action", val);
1013 }
1014
1015 asl_msg_release(m);
1016 *res = out;
1017 return ASL_STATUS_OK;
1018 }
1019
1020 static kern_return_t
1021 _server_message_processing(asl_request_msg *request)
1022 {
1023 const uint32_t sbits = MACH_SEND_MSG | MACH_SEND_TIMEOUT;;
1024 kern_return_t ks;
1025 asl_reply_msg *reply = calloc(1, sizeof(asl_reply_msg) + MAX_TRAILER_SIZE);
1026
1027 voucher_mach_msg_state_t voucher = voucher_mach_msg_adopt(&(request->head));
1028
1029 /* MIG server routine */
1030 asl_ipc_server(&(request->head), &(reply->head));
1031
1032 if (!(reply->head.msgh_bits & MACH_MSGH_BITS_COMPLEX))
1033 {
1034 if (reply->reply.Reply__asl_server_message.RetCode == MIG_NO_REPLY)
1035 {
1036 reply->head.msgh_remote_port = MACH_PORT_NULL;
1037 }
1038 else if ((reply->reply.Reply__asl_server_message.RetCode != KERN_SUCCESS) && (request->head.msgh_bits & MACH_MSGH_BITS_COMPLEX))
1039 {
1040 /* destroy the request - but not the reply port */
1041 request->head.msgh_remote_port = MACH_PORT_NULL;
1042 mach_msg_destroy(&(request->head));
1043 }
1044 }
1045
1046 if (reply->head.msgh_remote_port != MACH_PORT_NULL)
1047 {
1048 ks = mach_msg(&(reply->head), sbits, reply->head.msgh_size, 0, MACH_PORT_NULL, 10, MACH_PORT_NULL);
1049 if ((ks == MACH_SEND_INVALID_DEST) || (ks == MACH_SEND_TIMED_OUT))
1050 {
1051 /* clean up */
1052 mach_msg_destroy(&(reply->head));
1053 }
1054 else if (ks == MACH_SEND_INVALID_HEADER)
1055 {
1056 /*
1057 * This should never happen, but we can continue running.
1058 */
1059 char str[256];
1060 asldebug("ERROR: mach_msg() send failed with MACH_SEND_INVALID_HEADER 0x%08x\n", ks);
1061 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);
1062 internal_log_message(str);
1063 mach_msg_destroy(&(reply->head));
1064 }
1065 else if (ks == MACH_SEND_NO_BUFFER)
1066 {
1067 /*
1068 * This should never happen, but the kernel can run out of memory.
1069 * We clean up and continue running.
1070 */
1071 char str[256];
1072 asldebug("ERROR: mach_msg() send failed with MACH_SEND_NO_BUFFER 0x%08x\n", ks);
1073 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);
1074 internal_log_message(str);
1075 mach_msg_destroy(&(reply->head));
1076 }
1077 else if (ks != KERN_SUCCESS)
1078 {
1079 /*
1080 * Failed to send a reply message. This should never happen,
1081 * but the best action is to crash.
1082 */
1083 char str[256];
1084 asldebug("FATAL ERROR: mach_msg() send failed with status 0x%08x\n", ks);
1085 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);
1086 internal_log_message(str);
1087 sleep(1);
1088 abort();
1089 }
1090 }
1091 else if (reply->head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
1092 {
1093 mach_msg_destroy(&reply->head);
1094 }
1095
1096 voucher_mach_msg_revert(voucher);
1097 free(request);
1098 free(reply);
1099 }
1100
1101 /*
1102 * Receives messages on the "com.apple.system.logger" mach port.
1103 * Services database search requests.
1104 * Runs in it's own thread.
1105 *
1106 * The logic in this routine got a bit more complex due to (1) increased logging load and (2) 16K page size.
1107 * Out-of-line (OOL) memory sent to syslogd from libasl is allocated in pages, so the minimum size of a
1108 * message is one page. Since this routine can get slammed with messages at a very high rate, and since
1109 * the message queue in the kernel is only 5 messages, it is critical that this routine service the port
1110 * as fast as possible. To that end, it needs to do as little processing as possible.
1111 * In the version of this code found up to syslog-312, this routine received messages and dispatched them
1112 * on the asl_server_queue for further processing. When pages were only 4K, this was not a problem. With
1113 * 16K pages, it only takes about 650 messages to run syslogd's dirty memoory size up to the point of its
1114 * jetsam limit. Code was added here to track the memory being used in this queue + the work queue that's
1115 * used by process_message(), such that messages will get dropped if the queues reach a memory limit.
1116 * The actual message data in the VM pages is typically only a few hundred bytes, so holding VM pages in
1117 * the queue was a waste, and seriously limited the number of queued messages.
1118 *
1119 * The solution implemented here is a bit of a hack. It peeks at the received message header to determine
1120 * which MIG routine is being called. If the call is for _asl_server_message, it calls asl_ipc_server()
1121 * on the server thread. This routes the call through the MIG server code for error checking and so on,
1122 * and invokes _asl_server_message() on this thread. _asl_server_message() has been modified to copy
1123 * the message data into malloced memory, vm_deallocate the OOL memory, and then it dispatches the real
1124 * work onto the asl_server_queue.
1125 */
1126 void
1127 database_server()
1128 {
1129 asl_request_msg *request;
1130 uint32_t rqs, asl_server_message_num = 0;
1131 size_t i;
1132 struct timeval now, send_time;
1133 mach_dead_name_notification_t *deadname;
1134 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;
1135 send_time.tv_sec = 0;
1136 send_time.tv_usec = 0;
1137 struct mig_map_s {
1138 const char *routine;
1139 int num;
1140 } migmap[] = { subsystem_to_name_map_asl_ipc };
1141
1142 for (i = 0; (i < (sizeof(migmap) / sizeof(struct mig_map_s))) && (asl_server_message_num == 0); i++)
1143 {
1144 if (!strcmp(migmap[i].routine, "_asl_server_message")) asl_server_message_num = migmap[i].num;
1145 }
1146
1147 rqs = sizeof(asl_request_msg) + MAX_TRAILER_SIZE;
1148
1149 asl_server_queue = dispatch_queue_create("ASL Server Queue", NULL);
1150
1151 forever
1152 {
1153 kern_return_t ks;
1154
1155 now.tv_sec = 0;
1156 now.tv_usec = 0;
1157
1158 request = (asl_request_msg *)calloc(1, rqs);
1159 if (request == NULL) continue;
1160
1161 request->head.msgh_local_port = global.server_port;
1162 request->head.msgh_size = rqs;
1163
1164 ks = mach_msg(&(request->head), rbits, 0, rqs, global.listen_set, 0, MACH_PORT_NULL);
1165 if (ks != KERN_SUCCESS)
1166 {
1167 /*
1168 * This shouldn't happen, but if we get a failure the best thing to do is to crash.
1169 */
1170 char str[256];
1171 asldebug("FATAL ERROR: mach_msg() receive failed with status 0x%08x\n", ks);
1172 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);
1173 internal_log_message(str);
1174 sleep(1);
1175 abort();
1176 }
1177
1178 if (request->head.msgh_local_port == global.dead_session_port &&
1179 request->head.msgh_id == MACH_NOTIFY_DEAD_NAME)
1180 {
1181 deadname = (mach_dead_name_notification_t *)request;
1182 dispatch_async(asl_server_queue, ^{
1183 cancel_session(deadname->not_port);
1184 /* dead name notification includes a dead name right */
1185 mach_port_deallocate(mach_task_self(), deadname->not_port);
1186 free(request);
1187 });
1188
1189 continue;
1190 }
1191
1192 int64_t msize = 0;
1193 if (request->head.msgh_id == asl_server_message_num)
1194 {
1195 _server_message_processing(request);
1196 }
1197 else
1198 {
1199 dispatch_async(asl_server_queue, ^{ _server_message_processing(request); });
1200 }
1201 }
1202 }
1203
1204 static void
1205 caller_get_read_entitlement(pid_t pid, uid_t *uid, gid_t *gid)
1206 {
1207 #if TARGET_OS_EMBEDDED
1208 xpc_object_t edata, entitlements, val;
1209 bool bval = false;
1210 int64_t ival = -2;
1211 size_t len;
1212 const void *ptr;
1213
1214 edata = xpc_copy_entitlements_for_pid(pid);
1215 if (edata == NULL) return;
1216
1217 ptr = xpc_data_get_bytes_ptr(edata);
1218 len = xpc_data_get_length(edata);
1219
1220 entitlements = xpc_create_from_plist(ptr, len);
1221 xpc_release(edata);
1222 if (entitlements == NULL) return;
1223
1224 if (xpc_get_type(entitlements) != XPC_TYPE_DICTIONARY)
1225 {
1226 asldebug("xpc_copy_entitlements_for_pid has non-dictionary data for pid %d\n", pid);
1227 return;
1228 }
1229
1230 bval = xpc_dictionary_get_bool(entitlements, ASL_ENTITLEMENT_KEY);
1231 if (bval && (uid != NULL))
1232 {
1233 *uid = 0;
1234 xpc_release(entitlements);
1235 return;
1236 }
1237
1238 val = xpc_dictionary_get_value(entitlements, ASL_ENTITLEMENT_UID_KEY);
1239 if (val != NULL)
1240 {
1241 if ((xpc_get_type(val) == XPC_TYPE_INT64) && (uid != NULL))
1242 {
1243 ival = xpc_int64_get_value(val);
1244 *uid = ival;
1245 }
1246 }
1247
1248 val = xpc_dictionary_get_value(entitlements, ASL_ENTITLEMENT_GID_KEY);
1249 if (val != NULL)
1250 {
1251 if ((xpc_get_type(val) == XPC_TYPE_INT64) && (gid != NULL))
1252 {
1253 ival = xpc_int64_get_value(val);
1254 *gid = ival;
1255 }
1256 }
1257
1258 xpc_release(entitlements);
1259 #endif
1260 }
1261
1262 static kern_return_t
1263 __asl_server_query_internal
1264 (
1265 mach_port_t server,
1266 caddr_t request,
1267 mach_msg_type_number_t requestCnt,
1268 uint64_t startid,
1269 int count,
1270 uint32_t duration,
1271 int direction,
1272 caddr_t *reply,
1273 mach_msg_type_number_t *replyCnt,
1274 uint64_t *lastid,
1275 int *status,
1276 uid_t uid,
1277 gid_t gid,
1278 pid_t pid
1279 )
1280 {
1281 asl_msg_list_t *query;
1282 asl_msg_list_t *res;
1283 char *out, *vmbuffer;
1284 uint32_t outlen;
1285 kern_return_t kstatus;
1286
1287 *status = ASL_STATUS_OK;
1288
1289 if ((request != NULL) && (request[requestCnt - 1] != '\0'))
1290 {
1291 *status = ASL_STATUS_INVALID_ARG;
1292 vm_deallocate(mach_task_self(), (vm_address_t)request, requestCnt);
1293 return KERN_SUCCESS;
1294 }
1295
1296 query = asl_msg_list_from_string(request);
1297 if (request != NULL) vm_deallocate(mach_task_self(), (vm_address_t)request, requestCnt);
1298 res = NULL;
1299
1300 /* A query list containing a single query, which itself contains
1301 * [ASLOption control] is an internal state query */
1302 if ((query != NULL) && (query->count == 1) && asl_check_option(query->msg[0], ASL_OPT_CONTROL))
1303 {
1304 *status = syslogd_state_query(query->msg[0], &res, uid);
1305 }
1306 else
1307 {
1308 int x = 0;
1309 #if TARGET_OS_EMBEDDED
1310 x = pid;
1311 #endif
1312
1313 if (pid > 0)
1314 {
1315 caller_get_read_entitlement(pid, &uid, &gid);
1316 if (uid == 0) x = 0;
1317 }
1318
1319 *status = db_query(query, &res, startid, count, duration, direction, lastid, uid, gid, x);
1320 }
1321
1322 asl_msg_list_release(query);
1323 if (*status != ASL_STATUS_INVALID_STORE)
1324 {
1325 /* ignore */
1326 }
1327 else if (*status != ASL_STATUS_OK)
1328 {
1329 if (res != NULL) asl_msg_list_release(res);
1330 return KERN_SUCCESS;
1331 }
1332
1333 out = NULL;
1334 outlen = 0;
1335 out = asl_msg_list_to_string(res, &outlen);
1336 asl_msg_list_release(res);
1337
1338 if ((out == NULL) || (outlen == 0)) return KERN_SUCCESS;
1339
1340 kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmbuffer, outlen, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
1341 if (kstatus != KERN_SUCCESS)
1342 {
1343 free(out);
1344 return kstatus;
1345 }
1346
1347 memmove(vmbuffer, out, outlen);
1348 free(out);
1349
1350 *reply = vmbuffer;
1351 *replyCnt = outlen;
1352
1353 return KERN_SUCCESS;
1354 }
1355
1356 kern_return_t
1357 __asl_server_query_2
1358 (
1359 mach_port_t server,
1360 caddr_t request,
1361 mach_msg_type_number_t requestCnt,
1362 uint64_t startid,
1363 int count,
1364 int flags,
1365 caddr_t *reply,
1366 mach_msg_type_number_t *replyCnt,
1367 uint64_t *lastid,
1368 int *status,
1369 audit_token_t token
1370 )
1371 {
1372 uid_t uid = (uid_t)-1;
1373 gid_t gid = (gid_t)-1;
1374 pid_t pid = (pid_t)-1;
1375
1376 int direction = SEARCH_FORWARD;
1377 if (flags & QUERY_FLAG_SEARCH_REVERSE) direction = SEARCH_BACKWARD;
1378
1379 audit_token_to_au32(token, NULL, &uid, &gid, NULL, NULL, &pid, NULL, NULL);
1380
1381 return __asl_server_query_internal(server, request, requestCnt, startid, count, QUERY_DURATION_UNLIMITED, direction, reply, replyCnt, lastid, status, uid, gid, pid);
1382 }
1383
1384 kern_return_t
1385 __asl_server_query
1386 (
1387 mach_port_t server,
1388 caddr_t request,
1389 mach_msg_type_number_t requestCnt,
1390 uint64_t startid,
1391 int count,
1392 int flags,
1393 caddr_t *reply,
1394 mach_msg_type_number_t *replyCnt,
1395 uint64_t *lastid,
1396 int *status,
1397 security_token_t *token
1398 )
1399 {
1400 int direction = SEARCH_FORWARD;
1401 if (flags & QUERY_FLAG_SEARCH_REVERSE) direction = SEARCH_BACKWARD;
1402
1403 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);
1404 }
1405
1406 kern_return_t
1407 __asl_server_query_timeout
1408 (
1409 mach_port_t server,
1410 caddr_t request,
1411 mach_msg_type_number_t requestCnt,
1412 uint64_t startid,
1413 int count,
1414 int flags,
1415 caddr_t *reply,
1416 mach_msg_type_number_t *replyCnt,
1417 uint64_t *lastid,
1418 int *status,
1419 audit_token_t token
1420 )
1421 {
1422 uid_t uid = (uid_t)-1;
1423 gid_t gid = (gid_t)-1;
1424 pid_t pid = (pid_t)-1;
1425 int direction = SEARCH_FORWARD;
1426 if (flags & QUERY_FLAG_SEARCH_REVERSE) direction = SEARCH_BACKWARD;
1427
1428 audit_token_to_au32(token, NULL, &uid, &gid, NULL, NULL, &pid, NULL, NULL);
1429
1430 return __asl_server_query_internal(server, request, requestCnt, startid, count, QUERY_DURATION_UNLIMITED, direction, reply, replyCnt, lastid, status, uid, gid, pid);
1431 }
1432
1433 kern_return_t
1434 __asl_server_match
1435 (
1436 mach_port_t server,
1437 caddr_t request,
1438 mach_msg_type_number_t requestCnt,
1439 uint64_t startid,
1440 uint64_t count,
1441 uint32_t duration,
1442 int direction,
1443 caddr_t *reply,
1444 mach_msg_type_number_t *replyCnt,
1445 uint64_t *lastid,
1446 int *status,
1447 audit_token_t token
1448 )
1449 {
1450 uid_t uid = (uid_t)-1;
1451 gid_t gid = (gid_t)-1;
1452 pid_t pid = (pid_t)-1;
1453
1454 audit_token_to_au32(token, NULL, &uid, &gid, NULL, NULL, &pid, NULL, NULL);
1455
1456 return __asl_server_query_internal(server, request, requestCnt, startid, count, duration, direction, reply, replyCnt, lastid, status, uid, gid, pid);
1457 }
1458
1459 kern_return_t
1460 __asl_server_prune
1461 (
1462 mach_port_t server,
1463 caddr_t request,
1464 mach_msg_type_number_t requestCnt,
1465 int *status,
1466 security_token_t *token
1467 )
1468 {
1469 return KERN_SUCCESS;
1470 }
1471
1472 /*
1473 * Does the actual processing for __asl_server_message.
1474 * Dispatched on asl_server_queue. This lets us avoid
1475 * calling asl_msg_from_string(), task_name_for_pid(),
1476 * and register_session() on the database_server() thread.
1477 */
1478 static void
1479 _asl_message_processing(char *mbuf, uint64_t msize, uid_t uid, gid_t gid, pid_t pid)
1480 {
1481 asl_msg_t *msg;
1482 char tmp[64];
1483 kern_return_t kstatus;
1484 mach_port_name_t client;
1485
1486 msg = asl_msg_from_string(mbuf);
1487 free(mbuf);
1488
1489 /*
1490 * process_message() will update global.memory_size with the
1491 * size of msg, and it increements the work_queue_count.
1492 */
1493 OSAtomicAdd64(-1ll * msize, &global.memory_size);
1494 OSAtomicDecrement32(&global.work_queue_count);
1495
1496 if (msg == NULL) return;
1497
1498 client = MACH_PORT_NULL;
1499 kstatus = task_name_for_pid(mach_task_self(), pid, &client);
1500 if (kstatus == KERN_SUCCESS) register_session(client, pid);
1501
1502 snprintf(tmp, sizeof(tmp), "%d", uid);
1503 asl_msg_set_key_val(msg, ASL_KEY_UID, tmp);
1504
1505 snprintf(tmp, sizeof(tmp), "%d", gid);
1506 asl_msg_set_key_val(msg, ASL_KEY_GID, tmp);
1507
1508 snprintf(tmp, sizeof(tmp), "%d", pid);
1509 asl_msg_set_key_val(msg, ASL_KEY_PID, tmp);
1510
1511 process_message(msg, SOURCE_ASL_MESSAGE);
1512 }
1513
1514 /*
1515 * This MIG server routine is something of a special case in database_server() above.
1516 * It is called on the server thread that's responsible for servicing syslogd's mach port.
1517 * In this routine we copy the actual ASL message raw string out of the message into
1518 * malloc memory, deallocate the message, and dispatch the real work onto the asl_server_queue.
1519 */
1520 kern_return_t
1521 __asl_server_message
1522 (
1523 mach_port_t server,
1524 caddr_t message,
1525 mach_msg_type_number_t messageCnt,
1526 audit_token_t token
1527 )
1528 {
1529 uid_t uid;
1530 gid_t gid;
1531 pid_t pid;
1532 char *mbuf;
1533
1534 if (message == NULL) return KERN_SUCCESS;
1535
1536 if (message[messageCnt - 1] != '\0')
1537 {
1538 vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt);
1539 return KERN_SUCCESS;
1540 }
1541
1542 asldebug("__asl_server_message: %s\n", message);
1543
1544 if ((global.memory_size + messageCnt) > global.memory_max)
1545 {
1546 char str[256];
1547 asldebug("Server queue dropped message. message size %u queue size %lld max %lld\n", messageCnt, global.memory_size, global.memory_max);
1548 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);
1549 internal_log_message(str);
1550
1551 vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt);
1552 return KERN_SUCCESS;
1553 }
1554
1555 mbuf = malloc(messageCnt);
1556 if (mbuf != NULL) memcpy(mbuf, message, messageCnt);
1557 vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt);
1558
1559 if (mbuf == NULL) return KERN_SUCCESS;
1560
1561 uid = (uid_t)-1;
1562 gid = (gid_t)-1;
1563 pid = (pid_t)-1;
1564 audit_token_to_au32(token, NULL, &uid, &gid, NULL, NULL, &pid, NULL, NULL);
1565
1566 OSAtomicIncrement32(&global.work_queue_count);
1567 OSAtomicAdd64(messageCnt, &(global.memory_size));
1568
1569 dispatch_async(asl_server_queue, ^{ _asl_message_processing(mbuf, messageCnt, uid, gid, pid); });
1570
1571 return KERN_SUCCESS;
1572 }
1573
1574 kern_return_t
1575 __asl_server_create_aux_link
1576 (
1577 mach_port_t server,
1578 caddr_t message,
1579 mach_msg_type_number_t messageCnt,
1580 mach_port_t *fileport,
1581 caddr_t *newurl,
1582 mach_msg_type_number_t *newurlCnt,
1583 int *status,
1584 audit_token_t token
1585 )
1586 {
1587 asl_msg_t *msg;
1588 char tmp[64];
1589 uid_t uid;
1590 gid_t gid;
1591 pid_t pid;
1592 kern_return_t kstatus;
1593 mach_port_name_t client;
1594 char *url, *vmbuffer;
1595 int fd;
1596
1597 *status = ASL_STATUS_OK;
1598 *fileport = MACH_PORT_NULL;
1599 *newurl = 0;
1600
1601 if (message == NULL)
1602 {
1603 *status = ASL_STATUS_INVALID_ARG;
1604 return KERN_SUCCESS;
1605 }
1606
1607 if (message[messageCnt - 1] != '\0')
1608 {
1609 *status = ASL_STATUS_INVALID_ARG;
1610 vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt);
1611 return KERN_SUCCESS;
1612 }
1613
1614 asldebug("__asl_server_create_aux_link: %s\n", (message == NULL) ? "NULL" : message);
1615
1616 if ((global.dbtype & DB_TYPE_FILE) == 0)
1617 {
1618 *status = ASL_STATUS_INVALID_STORE;
1619 return KERN_SUCCESS;
1620 }
1621
1622 *fileport = MACH_PORT_NULL;
1623
1624 msg = asl_msg_from_string(message);
1625 vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt);
1626
1627 if (msg == NULL) return KERN_SUCCESS;
1628
1629 uid = (uid_t)-1;
1630 gid = (gid_t)-1;
1631 pid = (pid_t)-1;
1632 audit_token_to_au32(token, NULL, &uid, &gid, NULL, NULL, &pid, NULL, NULL);
1633
1634 client = MACH_PORT_NULL;
1635 kstatus = task_name_for_pid(mach_task_self(), pid, &client);
1636 if (kstatus == KERN_SUCCESS) register_session(client, pid);
1637
1638 snprintf(tmp, sizeof(tmp), "%d", uid);
1639 asl_msg_set_key_val(msg, ASL_KEY_UID, tmp);
1640
1641 snprintf(tmp, sizeof(tmp), "%d", gid);
1642 asl_msg_set_key_val(msg, ASL_KEY_GID, tmp);
1643
1644 snprintf(tmp, sizeof(tmp), "%d", pid);
1645 asl_msg_set_key_val(msg, ASL_KEY_PID, tmp);
1646
1647 /* create a file for the client */
1648 *status = asl_store_open_aux(global.file_db, msg, &fd, &url);
1649 asl_msg_release(msg);
1650 if (*status != ASL_STATUS_OK) return KERN_SUCCESS;
1651 if (url == NULL)
1652 {
1653 if (fd >= 0) close(fd);
1654 *status = ASL_STATUS_FAILED;
1655 return KERN_SUCCESS;
1656 }
1657
1658 if (fileport_makeport(fd, (fileport_t *)fileport) < 0)
1659 {
1660 close(fd);
1661 free(url);
1662 *status = ASL_STATUS_FAILED;
1663 return KERN_SUCCESS;
1664 }
1665
1666 close(fd);
1667
1668 *newurlCnt = strlen(url) + 1;
1669
1670 kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmbuffer, *newurlCnt, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
1671 if (kstatus != KERN_SUCCESS)
1672 {
1673 free(url);
1674 return kstatus;
1675 }
1676
1677 memmove(vmbuffer, url, *newurlCnt);
1678 free(url);
1679
1680 *newurl = vmbuffer;
1681
1682 return KERN_SUCCESS;
1683 }
1684
1685 kern_return_t
1686 __asl_server_register_direct_watch
1687 (
1688 mach_port_t server,
1689 int port,
1690 audit_token_t token
1691 )
1692 {
1693 uint16_t p16 = port;
1694 pid_t pid = (pid_t)-1;
1695
1696 audit_token_to_au32(token, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL);
1697
1698 asldebug("__asl_server_register_direct_watch: pid %u port %hu\n", pid, ntohs(p16));
1699
1700 dispatch_once(&watch_init_once, ^{
1701 watch_queue = dispatch_queue_create("Direct Watch Queue", NULL);
1702 });
1703
1704 dispatch_async(watch_queue, ^{ register_direct_watch(p16); });
1705
1706 return KERN_SUCCESS;
1707 }
1708
1709 kern_return_t
1710 __asl_server_cancel_direct_watch
1711 (
1712 mach_port_t server,
1713 int port,
1714 audit_token_t token
1715 )
1716 {
1717 uint16_t p16 = port;
1718
1719 asldebug("__asl_server_cancel_direct_watch: %hu\n", ntohs(p16));
1720
1721 dispatch_once(&watch_init_once, ^{
1722 watch_queue = dispatch_queue_create("Direct Watch Queue", NULL);
1723 });
1724
1725 dispatch_async(watch_queue, ^{ cancel_direct_watch(p16); });
1726
1727 return KERN_SUCCESS;
1728 }