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