]> git.saurik.com Git - apple/syslog.git/blob - syslogd.tproj/dbserver.c
ecdec48e6d74f641758308e54cdc52988eff09df
[apple/syslog.git] / syslogd.tproj / dbserver.c
1 /*
2 * Copyright (c) 2007-2011 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 <sys/types.h>
25 #include <sys/stat.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <sys/socket.h>
30 #include <sys/un.h>
31 #include <sys/ipc.h>
32 #include <sys/mman.h>
33 #include <sys/fcntl.h>
34 #include <sys/signal.h>
35 #include <sys/errno.h>
36 #include <mach/mach.h>
37 #include <mach/mach_error.h>
38 #include <bsm/libbsm.h>
39 #include <errno.h>
40 #include <netinet/in.h>
41 #include <netinet/tcp.h>
42 #include <sys/event.h>
43 #include <servers/bootstrap.h>
44 #include <pthread.h>
45 #include <notify.h>
46 #include <sys/time.h>
47 #include "daemon.h"
48 #include "asl_ipc.h"
49 #include "asl_ipcServer.h"
50
51 #define forever for(;;)
52
53 #define LIST_SIZE_DELTA 256
54
55 #define SEND_NOTIFICATION 0xfadefade
56
57 #define QUERY_FLAG_SEARCH_REVERSE 0x00000001
58 #define SEARCH_FORWARD 1
59 #define SEARCH_BACKWARD -1
60
61 #define MAX_AGAIN 100
62
63 static dispatch_queue_t asl_server_queue;
64
65 extern char *asl_list_to_string(asl_search_result_t *list, uint32_t *outlen);
66 extern asl_search_result_t *asl_list_from_string(const char *buf);
67 extern boolean_t asl_ipc_server(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP);
68 extern uint32_t bb_convert(const char *name);
69
70 static task_name_t *client_tasks = NULL;
71 static uint32_t client_tasks_count = 0;
72
73 static int *direct_watch = NULL;
74 /* N.B. ports are in network byte order */
75 static uint16_t *direct_watch_port = NULL;
76 static uint32_t direct_watch_count = 0;
77
78 typedef union
79 {
80 mach_msg_header_t head;
81 union __RequestUnion__asl_ipc_subsystem request;
82 } asl_request_msg;
83
84 typedef union
85 {
86 mach_msg_header_t head;
87 union __ReplyUnion__asl_ipc_subsystem reply;
88 } asl_reply_msg;
89
90 static void
91 db_asl_open(uint32_t dbtype)
92 {
93 uint32_t status;
94 struct stat sb;
95
96 if ((dbtype & DB_TYPE_FILE) && (global.file_db == NULL))
97 {
98 memset(&sb, 0, sizeof(struct stat));
99 if (stat(PATH_ASL_STORE, &sb) == 0)
100 {
101 /* must be a directory */
102 if (!S_ISDIR(sb.st_mode))
103 {
104 asldebug("error: %s is not a directory", PATH_ASL_STORE);
105 return;
106 }
107 }
108 else
109 {
110 if (errno == ENOENT)
111 {
112 /* /var/log/asl doesn't exist - create it */
113 if (mkdir(PATH_ASL_STORE, 0755) != 0)
114 {
115 asldebug("error: can't create data store %s: %s\n", PATH_ASL_STORE, strerror(errno));
116 return;
117 }
118 }
119 else
120 {
121 /* stat failed for some other reason */
122 asldebug("error: can't stat data store %s: %s\n", PATH_ASL_STORE, strerror(errno));
123 return;
124 }
125 }
126
127 /*
128 * One-time store conversion from the old "LongTTL" style to the new "Best Before" style.
129 * bb_convert returns quickly if the store has already been converted.
130 */
131 status = bb_convert(PATH_ASL_STORE);
132 if (status != ASL_STATUS_OK)
133 {
134 asldebug("ASL data store conversion failed!: %s\n", asl_core_error(status));
135 }
136
137 status = asl_store_open_write(NULL, &(global.file_db));
138 if (status != ASL_STATUS_OK)
139 {
140 asldebug("asl_store_open_write: %s\n", asl_core_error(status));
141 }
142 else
143 {
144 if (global.db_file_max != 0) asl_store_max_file_size(global.file_db, global.db_file_max);
145 asl_store_signal_sweep(global.file_db);
146 }
147 }
148
149 if ((dbtype & DB_TYPE_MEMORY) && (global.memory_db == NULL))
150 {
151 status = asl_memory_open(global.db_memory_max, &(global.memory_db));
152 if (status != ASL_STATUS_OK)
153 {
154 asldebug("asl_memory_open: %s\n", asl_core_error(status));
155 }
156 }
157
158 if ((dbtype & DB_TYPE_MINI) && (global.mini_db == NULL))
159 {
160 status = asl_mini_memory_open(global.db_mini_max, &(global.mini_db));
161 if (status != ASL_STATUS_OK)
162 {
163 asldebug("asl_mini_memory_open: %s\n", asl_core_error(status));
164 }
165 }
166 }
167
168 void
169 send_to_direct_watchers(asl_msg_t *msg)
170 {
171 uint32_t i, j, nlen, outlen, cleanup, total_sent, again;
172 ssize_t sent;
173 char *out;
174
175 #ifdef LOCKDOWN
176 static struct timeval last_time;
177
178 if (global.lockdown_session_fd >= 0)
179 {
180 if (global.remote_delay_time > 0)
181 {
182 struct timeval now;
183 uint64_t delta;
184
185 if (gettimeofday(&now, NULL) == 0)
186 {
187 if (last_time.tv_sec != 0)
188 {
189 if (now.tv_sec > last_time.tv_sec)
190 {
191 now.tv_sec -= 1;
192 now.tv_usec += 1000000;
193 }
194
195 delta = now.tv_sec - last_time.tv_sec;
196 delta *= 1000000;
197 delta += (now.tv_usec - last_time.tv_usec);
198 if (delta < global.remote_delay_time)
199 {
200 usleep(delta);
201 }
202 }
203
204 if (now.tv_usec >= 1000000)
205 {
206 now.tv_sec += 1;
207 now.tv_usec -= 1000000;
208 }
209
210 last_time = now;
211 }
212 }
213
214 out = asl_format_message(msg, ASL_MSG_FMT_STD, ASL_TIME_FMT_LCL, ASL_ENCODE_SAFE, &outlen);
215 if ((write(global.lockdown_session_fd, out, outlen) < 0) || (write(global.lockdown_session_fd, "\n", 1) < 0))
216 {
217 asldebug("send_to_direct_watchers: lockdown write error: %d %s\n", errno, strerror(errno));
218 close(global.lockdown_session_fd);
219 global.lockdown_session_fd = -1;
220 global.watchers_active = direct_watch_count + ((global.lockdown_session_fd < 0) ? 0 : 1);
221 }
222
223 free(out);
224
225 }
226 #endif
227
228 if (direct_watch_count == 0)
229 {
230 direct_watch = NULL;
231 return;
232 }
233
234 if (direct_watch == NULL)
235 {
236 direct_watch_count = 0;
237 return;
238 }
239
240 cleanup = 0;
241 out = asl_msg_to_string(msg, &outlen);
242
243 if (out == NULL) return;
244
245 nlen = htonl(outlen);
246 for (i = 0; i < direct_watch_count; i++)
247 {
248 sent = send(direct_watch[i], &nlen, sizeof(nlen), 0);
249 if (sent < sizeof(nlen))
250 {
251 /* bail out if we can't send 4 bytes */
252 close(direct_watch[i]);
253 direct_watch[i] = -1;
254 cleanup = 1;
255 }
256 else
257 {
258 total_sent = 0;
259 again = 0;
260
261 while (total_sent < outlen)
262 {
263 errno = 0;
264 sent = send(direct_watch[i], out + total_sent, outlen - total_sent, 0);
265 if (sent <= 0)
266 {
267 asldebug("send_to_direct_watchers: send returned %d (errno %d)\n", sent, errno);
268 if (errno == EAGAIN)
269 {
270 if (again > MAX_AGAIN)
271 {
272 asldebug("send_to_direct_watchers: exceeded EAGAIN limit - closing connection\n");
273 break;
274 }
275 else
276 {
277 again++;
278 errno = 0;
279 continue;
280 }
281 }
282
283 close(direct_watch[i]);
284 direct_watch[i] = -1;
285 cleanup = 1;
286 break;
287 }
288
289 total_sent += sent;
290 }
291 }
292 }
293
294 free(out);
295
296 if (cleanup == 0) return;
297
298 j = 0;
299 for (i = 0; i < direct_watch_count; i++)
300 {
301 if (direct_watch[i] >= 0)
302 {
303 if (j != i)
304 {
305 direct_watch[j] = direct_watch[i];
306 direct_watch_port[j] = direct_watch_port[i];
307 j++;
308 }
309 }
310 }
311
312 direct_watch_count = j;
313 if (direct_watch_count == 0)
314 {
315 free(direct_watch);
316 direct_watch = NULL;
317
318 free(direct_watch_port);
319 direct_watch_port = NULL;
320 }
321 else
322 {
323 direct_watch = reallocf(direct_watch, direct_watch_count * sizeof(int));
324 direct_watch_port = reallocf(direct_watch_port, direct_watch_count * sizeof(uint16_t));
325 if ((direct_watch == NULL) || (direct_watch_port == NULL))
326 {
327 free(direct_watch);
328 direct_watch = NULL;
329
330 free(direct_watch_port);
331 direct_watch_port = NULL;
332
333 direct_watch_count = 0;
334 }
335 }
336 }
337
338 /*
339 * Called from asl_action.c to save messgaes to the ASL data store
340 */
341 void
342 db_save_message(aslmsg msg)
343 {
344 uint64_t msgid;
345 uint32_t status, dbtype;
346 static int armed;
347 static dispatch_source_t timer_src;
348 static dispatch_once_t once;
349
350 dispatch_once(&once, ^{
351 timer_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
352 dispatch_source_set_event_handler(timer_src, ^{
353 notify_post(kNotifyASLDBUpdate);
354 dispatch_suspend(timer_src);
355 armed = 0;
356 });
357 armed = 0;
358 });
359
360 send_to_direct_watchers((asl_msg_t *)msg);
361
362 dbtype = global.dbtype;
363
364 if (asl_check_option(msg, ASL_OPT_DB_FILE)) dbtype |= DB_TYPE_FILE;
365 if (asl_check_option(msg, ASL_OPT_DB_MINI)) dbtype |= DB_TYPE_MINI;
366 if (asl_check_option(msg, ASL_OPT_DB_MEMORY)) dbtype |= DB_TYPE_MEMORY;
367
368 db_asl_open(dbtype);
369
370 if (dbtype & DB_TYPE_FILE)
371 {
372 status = asl_store_save(global.file_db, msg);
373 if (status != ASL_STATUS_OK)
374 {
375 /* write failed - reopen & retry */
376 asldebug("asl_store_save: %s\n", asl_core_error(status));
377 asl_store_close(global.file_db);
378 global.file_db = NULL;
379
380 db_asl_open(dbtype);
381 status = asl_store_save(global.file_db, msg);
382 if (status != ASL_STATUS_OK)
383 {
384 asldebug("(retry) asl_store_save: %s\n", asl_core_error(status));
385 asl_store_close(global.file_db);
386 global.file_db = NULL;
387
388 global.dbtype |= DB_TYPE_MEMORY;
389 dbtype |= DB_TYPE_MEMORY;
390 if (global.memory_db == NULL)
391 {
392 status = asl_memory_open(global.db_memory_max, &(global.memory_db));
393 if (status != ASL_STATUS_OK)
394 {
395 asldebug("asl_memory_open: %s\n", asl_core_error(status));
396 }
397 }
398 }
399 }
400 }
401
402 if (dbtype & DB_TYPE_MEMORY)
403 {
404 msgid = 0;
405 status = asl_memory_save(global.memory_db, msg, &msgid);
406 if (status != ASL_STATUS_OK)
407 {
408 /* save failed - reopen & retry*/
409 asldebug("asl_memory_save: %s\n", asl_core_error(status));
410 asl_memory_close(global.memory_db);
411 global.memory_db = NULL;
412
413 db_asl_open(dbtype);
414 msgid = 0;
415 status = asl_memory_save(global.memory_db, msg, &msgid);
416 if (status != ASL_STATUS_OK)
417 {
418 asldebug("(retry) asl_memory_save: %s\n", asl_core_error(status));
419 asl_memory_close(global.memory_db);
420 global.memory_db = NULL;
421 }
422 }
423 }
424
425 if (dbtype & DB_TYPE_MINI)
426 {
427 status = asl_mini_memory_save(global.mini_db, msg, &msgid);
428 if (status != ASL_STATUS_OK)
429 {
430 /* save failed - reopen & retry*/
431 asldebug("asl_mini_memory_save: %s\n", asl_core_error(status));
432 asl_mini_memory_close(global.mini_db);
433 global.mini_db = NULL;
434
435 db_asl_open(dbtype);
436 status = asl_mini_memory_save(global.mini_db, msg, &msgid);
437 if (status != ASL_STATUS_OK)
438 {
439 asldebug("(retry) asl_memory_save: %s\n", asl_core_error(status));
440 asl_mini_memory_close(global.mini_db);
441 global.mini_db = NULL;
442 }
443 }
444 }
445
446 if (armed == 0)
447 {
448 armed = 1;
449 dispatch_source_set_timer(timer_src, dispatch_walltime(NULL, NSEC_PER_SEC / 2), DISPATCH_TIME_FOREVER, 0);
450 dispatch_resume(timer_src);
451 }
452 }
453
454 void
455 disaster_message(aslmsg msg)
456 {
457 uint64_t msgid;
458 uint32_t status;
459
460 msgid = 0;
461
462 if ((global.dbtype & DB_TYPE_MINI) == 0)
463 {
464 if (global.mini_db == NULL)
465 {
466 status = asl_mini_memory_open(global.db_mini_max, &(global.mini_db));
467 if (status != ASL_STATUS_OK) asldebug("asl_mini_memory_open: %s\n", asl_core_error(status));
468 else asl_mini_memory_save(global.mini_db, msg, &msgid);
469 }
470 }
471 }
472
473 /*
474 * Do a database search.
475 */
476 uint32_t
477 db_query(aslresponse query, aslresponse *res, uint64_t startid, int count, int flags, uint64_t *lastid, int32_t ruid, int32_t rgid)
478 {
479 uint32_t status, ucount;
480 int32_t dir;
481
482 /*
483 * Special case: if count is -1, we return ASL_STATUS_OK to indicate that the store is
484 * in memory, and ASL_STATUS_INVALID_STORE to indicate that the file store is in use.
485 */
486 if (count == -1)
487 {
488 if ((global.dbtype & DB_TYPE_MEMORY) || (global.dbtype & DB_TYPE_MINI)) return ASL_STATUS_OK;
489 else return ASL_STATUS_INVALID_STORE;
490 }
491
492 ucount = count;
493 dir = SEARCH_FORWARD;
494 if (flags & QUERY_FLAG_SEARCH_REVERSE) dir = SEARCH_BACKWARD;
495
496 status = ASL_STATUS_FAILED;
497
498 if (global.dbtype & DB_TYPE_MEMORY)
499 {
500 status = asl_memory_match(global.memory_db, query, res, lastid, startid, ucount, dir, ruid, rgid);
501 }
502 else if (global.dbtype & DB_TYPE_MINI)
503 {
504 status = asl_mini_memory_match(global.mini_db, query, res, lastid, startid, ucount, dir);
505 }
506 else if (global.disaster_occurred != 0)
507 {
508 /* KernelEventAgent calls us to get the kernel disaster messages. */
509 status = asl_mini_memory_match(global.mini_db, query, res, lastid, startid, ucount, dir);
510 }
511
512 return status;
513 }
514
515 static void
516 register_session(task_name_t task_name, pid_t pid)
517 {
518 mach_port_t previous;
519 uint32_t i;
520
521 if (task_name == MACH_PORT_NULL) return;
522
523 if (global.dead_session_port == MACH_PORT_NULL)
524 {
525 mach_port_deallocate(mach_task_self(), task_name);
526 return;
527 }
528
529 for (i = 0; i < client_tasks_count; i++) if (task_name == client_tasks[i])
530 {
531 mach_port_deallocate(mach_task_self(), task_name);
532 return;
533 }
534
535 if (client_tasks_count == 0) client_tasks = (task_name_t *)calloc(1, sizeof(task_name_t));
536 else client_tasks = (task_name_t *)reallocf(client_tasks, (client_tasks_count + 1) * sizeof(task_name_t));
537
538 if (client_tasks == NULL)
539 {
540 mach_port_deallocate(mach_task_self(), task_name);
541 return;
542 }
543
544 client_tasks[client_tasks_count] = task_name;
545 client_tasks_count++;
546
547 asldebug("register_session: %u PID %d\n", (unsigned int)task_name, (int)pid);
548
549 /* register for port death notification */
550 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);
551 mach_port_deallocate(mach_task_self(), previous);
552
553 asl_client_count_increment();
554 }
555
556 static void
557 cancel_session(task_name_t task_name)
558 {
559 uint32_t i;
560
561 for (i = 0; (i < client_tasks_count) && (task_name != client_tasks[i]); i++);
562
563 if (i >= client_tasks_count) return;
564
565 if (client_tasks_count == 1)
566 {
567 free(client_tasks);
568 client_tasks = NULL;
569 client_tasks_count = 0;
570 }
571 else
572 {
573 for (i++; i < client_tasks_count; i++) client_tasks[i-1] = client_tasks[i];
574 client_tasks_count--;
575 client_tasks = (task_name_t *)reallocf(client_tasks, client_tasks_count * sizeof(task_name_t));
576 }
577
578 asldebug("cancel_session: %u\n", (unsigned int)task_name);
579
580 /* we hold a send right or dead name right for the task name port */
581 mach_port_deallocate(mach_task_self(), task_name);
582 asl_client_count_decrement();
583 }
584
585 static uint32_t
586 register_direct_watch(uint16_t port)
587 {
588 #ifdef CONFIG_IPHONE
589 uint32_t i;
590 int sock, flags;
591 struct sockaddr_in address;
592
593 if (port == 0) return ASL_STATUS_FAILED;
594
595 sock = socket(AF_INET, SOCK_STREAM, 0);
596 if (sock < 0) return ASL_STATUS_FAILED;
597
598 address.sin_family = AF_INET;
599 /* port must be sent in network byte order */
600 address.sin_port = port;
601 address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
602
603 if (connect(sock, (struct sockaddr*)&address, sizeof(address)) != 0) return ASL_STATUS_FAILED;
604
605 i = 1;
606 setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, &i, sizeof(i));
607
608 i = 1;
609 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &i, sizeof(i));
610
611 /* make socket non-blocking */
612 flags = fcntl(sock, F_GETFL, 0);
613 if (flags == -1) flags = 0;
614 fcntl(sock, F_SETFL, flags | O_NONBLOCK);
615
616 if (direct_watch_count == 0)
617 {
618 direct_watch = (int *)calloc(1, sizeof(int));
619 direct_watch_port = (uint16_t *)calloc(1, sizeof(uint16_t));
620 }
621 else
622 {
623 direct_watch = (int *)reallocf(direct_watch, (direct_watch_count + 1) * sizeof(int));
624 direct_watch_port = (uint16_t *)reallocf(direct_watch_port, (direct_watch_count + 1) * sizeof(uint16_t));
625 }
626
627 if ((direct_watch == NULL) || (direct_watch_port == NULL))
628 {
629 close(sock);
630
631 free(direct_watch);
632 direct_watch = NULL;
633
634 free(direct_watch_port);
635 direct_watch_port = NULL;
636
637 direct_watch_count = 0;
638 global.watchers_active = 0;
639 if (global.lockdown_session_fd >= 0) global.watchers_active = 1;
640
641 return ASL_STATUS_FAILED;
642 }
643
644 direct_watch[direct_watch_count] = sock;
645 direct_watch_port[direct_watch_count] = port;
646 direct_watch_count++;
647 global.watchers_active = direct_watch_count + ((global.lockdown_session_fd < 0) ? 0 : 1);
648
649 return ASL_STATUS_OK;
650 #else
651 return ASL_STATUS_FAILED;
652 #endif
653 }
654
655 static void
656 cancel_direct_watch(uint16_t port)
657 {
658 #ifdef CONFIG_IPHONE
659 uint32_t i;
660
661 for (i = 0; (i < direct_watch_count) && (port != direct_watch_port[i]); i++);
662
663 if (i >= direct_watch_count) return;
664
665 if (direct_watch_count == 1)
666 {
667 free(direct_watch);
668 direct_watch = NULL;
669
670 free(direct_watch_port);
671 direct_watch_port = NULL;
672
673 direct_watch_count = 0;
674 global.watchers_active = 0;
675 if (global.lockdown_session_fd >= 0) global.watchers_active = 1;
676 }
677 else
678 {
679 for (i++; i < direct_watch_count; i++)
680 {
681 direct_watch[i-1] = direct_watch[i];
682 direct_watch_port[i-1] = direct_watch_port[i];
683 }
684
685 direct_watch_count--;
686 global.watchers_active = direct_watch_count + ((global.lockdown_session_fd < 0) ? 0 : 1);
687
688 direct_watch = (int *)reallocf(direct_watch, direct_watch_count * sizeof(int));
689 direct_watch_port = (uint16_t *)reallocf(direct_watch_port, direct_watch_count * sizeof(uint16_t));
690
691 if ((direct_watch == NULL) || (direct_watch_port == NULL))
692 {
693 free(direct_watch);
694 direct_watch = NULL;
695
696 free(direct_watch_port);
697 direct_watch_port = NULL;
698
699 direct_watch_count = 0;
700 global.watchers_active = 0;
701 if (global.lockdown_session_fd >= 0) global.watchers_active = 1;
702 }
703 }
704 #endif
705 }
706
707 /*
708 * Receives messages on the "com.apple.system.logger" mach port.
709 * Services database search requests.
710 * Runs in it's own thread.
711 */
712 void
713 database_server()
714 {
715 asl_request_msg *request;
716 uint32_t rqs;
717 uint32_t rbits, sbits;
718 uint32_t flags;
719 struct timeval now, send_time;
720 mach_dead_name_notification_t *deadname;
721
722 send_time.tv_sec = 0;
723 send_time.tv_usec = 0;
724
725 rqs = sizeof(asl_request_msg) + MAX_TRAILER_SIZE;
726
727 rbits = MACH_RCV_MSG | MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT) | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0);
728 sbits = MACH_SEND_MSG | MACH_SEND_TIMEOUT;
729
730 asl_server_queue = dispatch_queue_create("ASL Server Queue", NULL);
731
732 forever
733 {
734 now.tv_sec = 0;
735 now.tv_usec = 0;
736
737 request = (asl_request_msg *)calloc(1, rqs);
738 if (request == NULL) continue;
739
740 request->head.msgh_local_port = global.server_port;
741 request->head.msgh_size = rqs;
742
743 flags = rbits;
744
745 (void)mach_msg(&(request->head), flags, 0, rqs, global.listen_set, 0, MACH_PORT_NULL);
746
747 if (request->head.msgh_id == MACH_NOTIFY_DEAD_NAME)
748 {
749 deadname = (mach_dead_name_notification_t *)request;
750 dispatch_async(asl_server_queue, ^{
751 cancel_session(deadname->not_port);
752 /* dead name notification includes a dead name right */
753 mach_port_deallocate(mach_task_self(), deadname->not_port);
754 free(request);
755 });
756
757 continue;
758 }
759
760 dispatch_async(asl_server_queue, ^{
761 kern_return_t ks;
762 asl_reply_msg *reply = calloc(1, sizeof(asl_reply_msg) + MAX_TRAILER_SIZE);
763
764 asl_ipc_server(&(request->head), &(reply->head));
765 ks = mach_msg(&(reply->head), sbits, reply->head.msgh_size, 0, MACH_PORT_NULL, 10, MACH_PORT_NULL);
766 free(reply);
767 if ((ks == MACH_SEND_INVALID_DEST) || (ks == MACH_SEND_TIMED_OUT))
768 {
769 /* clean up */
770 mach_msg_destroy(&(reply->head));
771 }
772
773 free(request);
774 });
775 }
776 }
777
778 kern_return_t
779 __asl_server_query
780 (
781 mach_port_t server,
782 caddr_t request,
783 mach_msg_type_number_t requestCnt,
784 uint64_t startid,
785 int count,
786 int flags,
787 caddr_t *reply,
788 mach_msg_type_number_t *replyCnt,
789 uint64_t *lastid,
790 int *status,
791 security_token_t *token
792 )
793 {
794 aslresponse query;
795 aslresponse res;
796 char *out, *vmbuffer;
797 uint32_t outlen;
798 kern_return_t kstatus;
799
800 *status = ASL_STATUS_OK;
801
802 if ((request != NULL) && (request[requestCnt - 1] != '\0'))
803 {
804 *status = ASL_STATUS_INVALID_ARG;
805 vm_deallocate(mach_task_self(), (vm_address_t)request, requestCnt);
806 return KERN_SUCCESS;
807 }
808
809 query = asl_list_from_string(request);
810 if (request != NULL) vm_deallocate(mach_task_self(), (vm_address_t)request, requestCnt);
811 res = NULL;
812
813 *status = db_query(query, &res, startid, count, flags, lastid, token->val[0], token->val[1]);
814
815 aslresponse_free(query);
816 if (*status != ASL_STATUS_INVALID_STORE)
817 {
818 /* ignore */
819 }
820 else if (*status != ASL_STATUS_OK)
821 {
822 if (res != NULL) aslresponse_free(res);
823 return KERN_SUCCESS;
824 }
825
826 out = NULL;
827 outlen = 0;
828 out = asl_list_to_string((asl_search_result_t *)res, &outlen);
829 aslresponse_free(res);
830
831 if ((out == NULL) || (outlen == 0)) return KERN_SUCCESS;
832
833 kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmbuffer, outlen, TRUE);
834 if (kstatus != KERN_SUCCESS)
835 {
836 free(out);
837 return kstatus;
838 }
839
840 memmove(vmbuffer, out, outlen);
841 free(out);
842
843 *reply = vmbuffer;
844 *replyCnt = outlen;
845
846 return KERN_SUCCESS;
847 }
848
849
850 kern_return_t
851 __asl_server_query_timeout
852 (
853 mach_port_t server,
854 caddr_t request,
855 mach_msg_type_number_t requestCnt,
856 uint64_t startid,
857 int count,
858 int flags,
859 caddr_t *reply,
860 mach_msg_type_number_t *replyCnt,
861 uint64_t *lastid,
862 int *status,
863 security_token_t *token
864 )
865 {
866 return __asl_server_query(server, request, requestCnt, startid, count, flags, reply, replyCnt, lastid, status, token);
867 }
868
869 kern_return_t
870 __asl_server_prune
871 (
872 mach_port_t server,
873 caddr_t request,
874 mach_msg_type_number_t requestCnt,
875 int *status,
876 security_token_t *token
877 )
878 {
879 return KERN_SUCCESS;
880 }
881
882 kern_return_t
883 __asl_server_message
884 (
885 mach_port_t server,
886 caddr_t message,
887 mach_msg_type_number_t messageCnt,
888 audit_token_t token
889 )
890 {
891 aslmsg msg;
892 char tmp[64];
893 uid_t uid;
894 gid_t gid;
895 pid_t pid;
896 kern_return_t kstatus;
897 mach_port_name_t client;
898
899 if (message == NULL)
900 {
901 return KERN_SUCCESS;
902 }
903
904 if (message[messageCnt - 1] != '\0')
905 {
906 vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt);
907 return KERN_SUCCESS;
908 }
909
910 asldebug("__asl_server_message: %s\n", (message == NULL) ? "NULL" : message);
911
912 msg = (aslmsg)asl_msg_from_string(message);
913 vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt);
914
915 if (msg == NULL) return KERN_SUCCESS;
916
917 uid = (uid_t)-1;
918 gid = (gid_t)-1;
919 pid = (pid_t)-1;
920 audit_token_to_au32(token, NULL, &uid, &gid, NULL, NULL, &pid, NULL, NULL);
921
922 client = MACH_PORT_NULL;
923 kstatus = task_name_for_pid(mach_task_self(), pid, &client);
924 if (kstatus == KERN_SUCCESS) register_session(client, pid);
925
926 snprintf(tmp, sizeof(tmp), "%d", uid);
927 asl_set(msg, ASL_KEY_UID, tmp);
928
929 snprintf(tmp, sizeof(tmp), "%d", gid);
930 asl_set(msg, ASL_KEY_GID, tmp);
931
932 snprintf(tmp, sizeof(tmp), "%d", pid);
933 asl_set(msg, ASL_KEY_PID, tmp);
934
935 dispatch_async(global.work_queue, ^{ process_message(msg, SOURCE_ASL_MESSAGE); });
936
937 return KERN_SUCCESS;
938 }
939
940 kern_return_t
941 __asl_server_create_aux_link
942 (
943 mach_port_t server,
944 caddr_t message,
945 mach_msg_type_number_t messageCnt,
946 mach_port_t *fileport,
947 caddr_t *newurl,
948 mach_msg_type_number_t *newurlCnt,
949 int *status,
950 audit_token_t token
951 )
952 {
953 aslmsg msg;
954 char tmp[64];
955 uid_t uid;
956 gid_t gid;
957 pid_t pid;
958 kern_return_t kstatus;
959 mach_port_name_t client;
960 char *url, *vmbuffer;
961 int fd;
962
963 *status = ASL_STATUS_OK;
964
965 if (message == NULL)
966 {
967 *status = ASL_STATUS_INVALID_ARG;
968 return KERN_SUCCESS;
969 }
970
971 if (message[messageCnt - 1] != '\0')
972 {
973 *status = ASL_STATUS_INVALID_ARG;
974 vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt);
975 return KERN_SUCCESS;
976 }
977
978 asldebug("__asl_server_create_aux_link: %s\n", (message == NULL) ? "NULL" : message);
979
980 if ((global.dbtype & DB_TYPE_FILE) == 0)
981 {
982 *status = ASL_STATUS_INVALID_STORE;
983 return KERN_SUCCESS;
984 }
985
986 *fileport = MACH_PORT_NULL;
987
988 msg = (aslmsg)asl_msg_from_string(message);
989 vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt);
990
991 if (msg == NULL) return KERN_SUCCESS;
992
993 uid = (uid_t)-1;
994 gid = (gid_t)-1;
995 pid = (pid_t)-1;
996 audit_token_to_au32(token, NULL, &uid, &gid, NULL, NULL, &pid, NULL, NULL);
997
998 client = MACH_PORT_NULL;
999 kstatus = task_name_for_pid(mach_task_self(), pid, &client);
1000 if (kstatus == KERN_SUCCESS) register_session(client, pid);
1001
1002 snprintf(tmp, sizeof(tmp), "%d", uid);
1003 asl_set(msg, ASL_KEY_UID, tmp);
1004
1005 snprintf(tmp, sizeof(tmp), "%d", gid);
1006 asl_set(msg, ASL_KEY_GID, tmp);
1007
1008 snprintf(tmp, sizeof(tmp), "%d", pid);
1009 asl_set(msg, ASL_KEY_PID, tmp);
1010
1011 /* create a file for the client */
1012 *status = asl_store_open_aux(global.file_db, msg, &fd, &url);
1013 asl_free(msg);
1014 if (*status != ASL_STATUS_OK) return KERN_SUCCESS;
1015 if (url == NULL)
1016 {
1017 if (fd >= 0) close(fd);
1018 *status = ASL_STATUS_FAILED;
1019 return KERN_SUCCESS;
1020 }
1021
1022 if (fileport_makeport(fd, (fileport_t *)fileport) < 0)
1023 {
1024 close(fd);
1025 free(url);
1026 *status = ASL_STATUS_FAILED;
1027 return KERN_SUCCESS;
1028 }
1029
1030 close(fd);
1031
1032 *newurlCnt = strlen(url) + 1;
1033
1034 kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmbuffer, *newurlCnt, TRUE);
1035 if (kstatus != KERN_SUCCESS)
1036 {
1037 free(url);
1038 return kstatus;
1039 }
1040
1041 memmove(vmbuffer, url, *newurlCnt);
1042 free(url);
1043
1044 *newurl = vmbuffer;
1045
1046 return KERN_SUCCESS;
1047 }
1048
1049 kern_return_t
1050 __asl_server_register_direct_watch
1051 (
1052 mach_port_t server,
1053 int port,
1054 audit_token_t token
1055 )
1056 {
1057 uint16_t p16 = port;
1058 pid_t pid = (pid_t)-1;
1059
1060 audit_token_to_au32(token, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL);
1061
1062 asldebug("__asl_server_register_direct_watch: pid %u port %hu\n", pid, ntohs(p16));
1063
1064 register_direct_watch(p16);
1065
1066 return KERN_SUCCESS;
1067 }
1068
1069 kern_return_t
1070 __asl_server_cancel_direct_watch
1071 (
1072 mach_port_t server,
1073 int port,
1074 audit_token_t token
1075 )
1076 {
1077 uint16_t p16 = port;
1078
1079 asldebug("__asl_server_cancel_direct_watch: %hu\n", ntohs(p16));
1080
1081 cancel_direct_watch(p16);
1082
1083 return KERN_SUCCESS;
1084 }