]> git.saurik.com Git - apple/syslog.git/blame - syslogd.tproj/dbserver.c
syslog-377.0.1.tar.gz
[apple/syslog.git] / syslogd.tproj / dbserver.c
CommitLineData
57b0aad2 1/*
5222c21d 2 * Copyright (c) 2007-2015 Apple Inc. All rights reserved.
57b0aad2
A
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
81582353
A
24#include <TargetConditionals.h>
25
5dd30d76
A
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>
57b0aad2 37#include <sys/errno.h>
5dd30d76
A
38#include <mach/mach.h>
39#include <mach/mach_error.h>
5222c21d 40#include <mach/vm_param.h>
c4fdb7d1 41#include <bsm/libbsm.h>
5dd30d76
A
42#include <errno.h>
43#include <netinet/in.h>
a83ff38a 44#include <netinet/tcp.h>
5dd30d76
A
45#include <sys/event.h>
46#include <servers/bootstrap.h>
47#include <pthread.h>
48#include <notify.h>
49#include <sys/time.h>
81582353
A
50#include <xpc/xpc.h>
51#include <xpc/private.h>
52#include <libproc.h>
53#include <uuid/uuid.h>
db78b1bd 54#include "daemon.h"
a83ff38a
A
55#include "asl_ipc.h"
56#include "asl_ipcServer.h"
5dd30d76
A
57
58#define forever for(;;)
59
60#define LIST_SIZE_DELTA 256
5dd30d76
A
61
62#define SEND_NOTIFICATION 0xfadefade
63
64#define QUERY_FLAG_SEARCH_REVERSE 0x00000001
f3df4c03
A
65#define QUERY_DURATION_UNLIMITED 0
66
5dd30d76
A
67#define SEARCH_FORWARD 1
68#define SEARCH_BACKWARD -1
69
db78b1bd
A
70#define MAX_AGAIN 100
71
81582353
A
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
5222c21d
A
76#define PAGE_ROUND_UP(x) ((((x)+PAGE_SIZE-1)/PAGE_SIZE)*PAGE_SIZE)
77
db78b1bd 78static dispatch_queue_t asl_server_queue;
81582353
A
79static dispatch_queue_t watch_queue;
80static dispatch_once_t watch_init_once;
5dd30d76 81
57b0aad2 82extern boolean_t asl_ipc_server(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP);
5dd30d76 83
c4fdb7d1
A
84static task_name_t *client_tasks = NULL;
85static uint32_t client_tasks_count = 0;
5dd30d76 86
a83ff38a
A
87static int *direct_watch = NULL;
88/* N.B. ports are in network byte order */
89static uint16_t *direct_watch_port = NULL;
90static uint32_t direct_watch_count = 0;
91
5dd30d76
A
92typedef union
93{
94 mach_msg_header_t head;
95 union __RequestUnion__asl_ipc_subsystem request;
96} asl_request_msg;
97
98typedef union
99{
100 mach_msg_header_t head;
101 union __ReplyUnion__asl_ipc_subsystem reply;
102} asl_reply_msg;
103
db78b1bd
A
104static void
105db_asl_open(uint32_t dbtype)
57b0aad2
A
106{
107 uint32_t status;
108 struct stat sb;
109
db78b1bd 110 if ((dbtype & DB_TYPE_FILE) && (global.file_db == NULL))
57b0aad2
A
111 {
112 memset(&sb, 0, sizeof(struct stat));
113 if (stat(PATH_ASL_STORE, &sb) == 0)
114 {
115 /* must be a directory */
a83ff38a 116 if (!S_ISDIR(sb.st_mode))
57b0aad2
A
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;
c4fdb7d1 131 }
57b0aad2
A
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);
5222c21d 149 asl_trigger_aslmanager();
57b0aad2
A
150 }
151 }
152
db78b1bd 153 if ((dbtype & DB_TYPE_MEMORY) && (global.memory_db == NULL))
57b0aad2 154 {
f3df4c03 155 status = asl_memory_open(global.db_memory_max, global.db_memory_str_max, &(global.memory_db));
57b0aad2
A
156 if (status != ASL_STATUS_OK)
157 {
158 asldebug("asl_memory_open: %s\n", asl_core_error(status));
159 }
160 }
57b0aad2
A
161}
162
5dd30d76 163void
81582353
A
164add_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
741c57cd 173 global.lockdown_session_fds = reallocf(global.lockdown_session_fds, (global.lockdown_session_count + 1) * sizeof(int));
81582353
A
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
189void
190remove_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
236static void
237sweep_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
274static void
275_internal_send_to_direct_watchers(asl_msg_t *msg)
5dd30d76 276{
db78b1bd
A
277 uint32_t i, j, nlen, outlen, cleanup, total_sent, again;
278 ssize_t sent;
279 char *out;
5dd30d76 280
db78b1bd
A
281#ifdef LOCKDOWN
282 static struct timeval last_time;
5dd30d76 283
81582353
A
284 cleanup = 0;
285
286 if (global.lockdown_session_count > 0)
5dd30d76 287 {
db78b1bd 288 if (global.remote_delay_time > 0)
c4fdb7d1 289 {
db78b1bd
A
290 struct timeval now;
291 uint64_t delta;
81582353 292
db78b1bd 293 if (gettimeofday(&now, NULL) == 0)
c4fdb7d1 294 {
db78b1bd
A
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 }
81582353 302
db78b1bd
A
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 }
5dd30d76 311
db78b1bd
A
312 if (now.tv_usec >= 1000000)
313 {
314 now.tv_sec += 1;
315 now.tv_usec -= 1000000;
316 }
c4fdb7d1 317
db78b1bd
A
318 last_time = now;
319 }
c4fdb7d1
A
320 }
321
a83ff38a 322 out = asl_format_message(msg, ASL_MSG_FMT_STD, ASL_TIME_FMT_LCL, ASL_ENCODE_SAFE, &outlen);
81582353
A
323
324 for (i = 0; i < global.lockdown_session_count; i++)
a83ff38a 325 {
81582353
A
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 }
a83ff38a
A
333 }
334
335 free(out);
336 }
81582353
A
337
338 if (cleanup != 0) sweep_lockdown_session_fds();
a83ff38a
A
339#endif
340
db78b1bd
A
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 }
a83ff38a
A
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;
db78b1bd
A
372 again = 0;
373
a83ff38a
A
374 while (total_sent < outlen)
375 {
db78b1bd 376 errno = 0;
a83ff38a 377 sent = send(direct_watch[i], out + total_sent, outlen - total_sent, 0);
db78b1bd 378 if (sent <= 0)
a83ff38a 379 {
db78b1bd
A
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
a83ff38a
A
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];
a83ff38a 420 }
af7d442c 421 j++;
a83ff38a
A
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 }
c4fdb7d1
A
448 }
449}
450
81582353
A
451void
452send_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
c4fdb7d1
A
466/*
467 * Called from asl_action.c to save messgaes to the ASL data store
468 */
469void
f3df4c03 470db_save_message(asl_msg_t *msg)
c4fdb7d1
A
471{
472 uint64_t msgid;
db78b1bd
A
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 });
c4fdb7d1 487
a83ff38a
A
488 send_to_direct_watchers((asl_msg_t *)msg);
489
db78b1bd
A
490 dbtype = global.dbtype;
491
492 if (asl_check_option(msg, ASL_OPT_DB_FILE)) dbtype |= DB_TYPE_FILE;
db78b1bd 493 if (asl_check_option(msg, ASL_OPT_DB_MEMORY)) dbtype |= DB_TYPE_MEMORY;
c4fdb7d1 494
db78b1bd 495 db_asl_open(dbtype);
5dd30d76 496
db78b1bd 497 if (dbtype & DB_TYPE_FILE)
c4fdb7d1
A
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));
f3df4c03 504 asl_store_release(global.file_db);
c4fdb7d1
A
505 global.file_db = NULL;
506
db78b1bd 507 db_asl_open(dbtype);
c4fdb7d1
A
508 status = asl_store_save(global.file_db, msg);
509 if (status != ASL_STATUS_OK)
5dd30d76 510 {
c4fdb7d1 511 asldebug("(retry) asl_store_save: %s\n", asl_core_error(status));
f3df4c03 512 asl_store_release(global.file_db);
c4fdb7d1
A
513 global.file_db = NULL;
514
515 global.dbtype |= DB_TYPE_MEMORY;
db78b1bd 516 dbtype |= DB_TYPE_MEMORY;
c4fdb7d1 517 if (global.memory_db == NULL)
5dd30d76 518 {
f3df4c03 519 status = asl_memory_open(global.db_memory_max, global.db_memory_str_max, &(global.memory_db));
57b0aad2
A
520 if (status != ASL_STATUS_OK)
521 {
c4fdb7d1 522 asldebug("asl_memory_open: %s\n", asl_core_error(status));
57b0aad2 523 }
5dd30d76 524 }
57b0aad2 525 }
c4fdb7d1
A
526 }
527 }
5dd30d76 528
db78b1bd 529 if (dbtype & DB_TYPE_MEMORY)
c4fdb7d1
A
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
db78b1bd 540 db_asl_open(dbtype);
c4fdb7d1
A
541 msgid = 0;
542 status = asl_memory_save(global.memory_db, msg, &msgid);
543 if (status != ASL_STATUS_OK)
57b0aad2 544 {
c4fdb7d1
A
545 asldebug("(retry) asl_memory_save: %s\n", asl_core_error(status));
546 asl_memory_close(global.memory_db);
547 global.memory_db = NULL;
5dd30d76 548 }
c4fdb7d1
A
549 }
550 }
5dd30d76 551
db78b1bd
A
552 if (armed == 0)
553 {
554 armed = 1;
81582353 555 dispatch_source_set_timer(timer_src, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC / 2), DISPATCH_TIME_FOREVER, 0);
db78b1bd
A
556 dispatch_resume(timer_src);
557 }
5dd30d76
A
558}
559
57b0aad2 560void
f3df4c03 561disaster_message(asl_msg_t *msg)
5dd30d76 562{
57b0aad2
A
563 uint64_t msgid;
564 uint32_t status;
5dd30d76 565
57b0aad2 566 msgid = 0;
5dd30d76 567
f3df4c03 568 if ((global.dbtype & DB_TYPE_MEMORY) == 0)
5dd30d76 569 {
f3df4c03 570 if (global.memory_db == NULL)
5dd30d76 571 {
f3df4c03
A
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);
5dd30d76 575 }
5dd30d76 576 }
5dd30d76
A
577}
578
579/*
580 * Do a database search.
581 */
582uint32_t
f3df4c03 583db_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)
5dd30d76
A
584{
585 uint32_t status, ucount;
81582353
A
586 uuid_string_t ustr;
587 struct proc_uniqidentifierinfo pinfo;
588 const char *str = NULL;
5dd30d76 589
e125da38
A
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 {
81582353
A
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 }
e125da38
A
609 }
610
5dd30d76 611 ucount = count;
5dd30d76 612
57b0aad2 613 status = ASL_STATUS_FAILED;
5dd30d76 614
f3df4c03 615 if ((global.dbtype & DB_TYPE_MEMORY) || (global.disaster_occurred != 0))
e125da38 616 {
f3df4c03 617 status = asl_memory_match_restricted_uuid(global.memory_db, query, res, lastid, startid, ucount, duration, direction, ruid, rgid, str);
e125da38 618 }
5dd30d76 619
5dd30d76
A
620 return status;
621}
622
c4fdb7d1
A
623static void
624register_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;
c4fdb7d1 630
a83ff38a
A
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 }
c4fdb7d1
A
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
a83ff38a
A
646 if (client_tasks == NULL)
647 {
648 mach_port_deallocate(mach_task_self(), task_name);
649 return;
650 }
651
c4fdb7d1
A
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 */
30cde84f 658 previous = MACH_PORT_NULL;
c4fdb7d1
A
659 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);
660 mach_port_deallocate(mach_task_self(), previous);
661
662 asl_client_count_increment();
663}
664
665static void
666cancel_session(task_name_t task_name)
667{
668 uint32_t i;
669
670 for (i = 0; (i < client_tasks_count) && (task_name != client_tasks[i]); i++);
671
672 if (i >= client_tasks_count) return;
673
674 if (client_tasks_count == 1)
675 {
676 free(client_tasks);
677 client_tasks = NULL;
678 client_tasks_count = 0;
679 }
680 else
681 {
682 for (i++; i < client_tasks_count; i++) client_tasks[i-1] = client_tasks[i];
683 client_tasks_count--;
684 client_tasks = (task_name_t *)reallocf(client_tasks, client_tasks_count * sizeof(task_name_t));
685 }
686
687 asldebug("cancel_session: %u\n", (unsigned int)task_name);
a83ff38a
A
688
689 /* we hold a send right or dead name right for the task name port */
690 mach_port_deallocate(mach_task_self(), task_name);
c4fdb7d1
A
691 asl_client_count_decrement();
692}
693
a83ff38a
A
694static uint32_t
695register_direct_watch(uint16_t port)
696{
81582353 697#if TARGET_OS_EMBEDDED
a83ff38a
A
698 uint32_t i;
699 int sock, flags;
700 struct sockaddr_in address;
701
702 if (port == 0) return ASL_STATUS_FAILED;
703
704 sock = socket(AF_INET, SOCK_STREAM, 0);
705 if (sock < 0) return ASL_STATUS_FAILED;
706
707 address.sin_family = AF_INET;
708 /* port must be sent in network byte order */
709 address.sin_port = port;
710 address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
711
712 if (connect(sock, (struct sockaddr*)&address, sizeof(address)) != 0) return ASL_STATUS_FAILED;
713
714 i = 1;
715 setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, &i, sizeof(i));
716
717 i = 1;
718 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &i, sizeof(i));
719
720 /* make socket non-blocking */
721 flags = fcntl(sock, F_GETFL, 0);
722 if (flags == -1) flags = 0;
723 fcntl(sock, F_SETFL, flags | O_NONBLOCK);
724
725 if (direct_watch_count == 0)
726 {
727 direct_watch = (int *)calloc(1, sizeof(int));
728 direct_watch_port = (uint16_t *)calloc(1, sizeof(uint16_t));
729 }
730 else
731 {
732 direct_watch = (int *)reallocf(direct_watch, (direct_watch_count + 1) * sizeof(int));
733 direct_watch_port = (uint16_t *)reallocf(direct_watch_port, (direct_watch_count + 1) * sizeof(uint16_t));
734 }
735
736 if ((direct_watch == NULL) || (direct_watch_port == NULL))
737 {
738 close(sock);
739
740 free(direct_watch);
741 direct_watch = NULL;
742
743 free(direct_watch_port);
744 direct_watch_port = NULL;
745
746 direct_watch_count = 0;
747 global.watchers_active = 0;
81582353 748 if (global.lockdown_session_count > 0) global.watchers_active = 1;
a83ff38a
A
749
750 return ASL_STATUS_FAILED;
751 }
752
753 direct_watch[direct_watch_count] = sock;
754 direct_watch_port[direct_watch_count] = port;
755 direct_watch_count++;
81582353 756 global.watchers_active = direct_watch_count + global.lockdown_session_count;
a83ff38a
A
757
758 return ASL_STATUS_OK;
db78b1bd
A
759#else
760 return ASL_STATUS_FAILED;
761#endif
a83ff38a
A
762}
763
764static void
765cancel_direct_watch(uint16_t port)
766{
81582353 767#if TARGET_OS_EMBEDDED
a83ff38a
A
768 uint32_t i;
769
770 for (i = 0; (i < direct_watch_count) && (port != direct_watch_port[i]); i++);
771
772 if (i >= direct_watch_count) return;
773
774 if (direct_watch_count == 1)
775 {
776 free(direct_watch);
777 direct_watch = NULL;
778
779 free(direct_watch_port);
780 direct_watch_port = NULL;
781
782 direct_watch_count = 0;
783 global.watchers_active = 0;
81582353 784 if (global.lockdown_session_count > 0) global.watchers_active = 1;
a83ff38a
A
785 }
786 else
787 {
788 for (i++; i < direct_watch_count; i++)
789 {
790 direct_watch[i-1] = direct_watch[i];
791 direct_watch_port[i-1] = direct_watch_port[i];
792 }
793
794 direct_watch_count--;
81582353 795 global.watchers_active = direct_watch_count + global.lockdown_session_count;
a83ff38a
A
796
797 direct_watch = (int *)reallocf(direct_watch, direct_watch_count * sizeof(int));
798 direct_watch_port = (uint16_t *)reallocf(direct_watch_port, direct_watch_count * sizeof(uint16_t));
799
800 if ((direct_watch == NULL) || (direct_watch_port == NULL))
801 {
802 free(direct_watch);
803 direct_watch = NULL;
804
805 free(direct_watch_port);
806 direct_watch_port = NULL;
807
808 direct_watch_count = 0;
809 global.watchers_active = 0;
81582353
A
810 if (global.lockdown_session_count > 0) global.watchers_active = 1;
811 }
812 }
813#endif
814}
815
816static int
f3df4c03 817syslogd_state_query(asl_msg_t *q, asl_msg_list_t **res, uid_t uid)
81582353 818{
f3df4c03 819 asl_msg_list_t *out;
81582353
A
820 uint32_t i, n;
821 bool all = false;
f3df4c03 822 asl_msg_t *m;
81582353
A
823 char val[256];
824 const char *mval;
81582353
A
825
826 if (res == NULL) return ASL_STATUS_INVALID_ARG;
827 *res = NULL;
828
f3df4c03 829 out = asl_msg_list_new();
81582353
A
830 if (out == NULL) return ASL_STATUS_NO_MEMORY;
831
f3df4c03 832 m = asl_msg_new(ASL_TYPE_MSG);
81582353
A
833 if (m == NULL)
834 {
f3df4c03 835 asl_msg_list_release(out);
81582353
A
836 return ASL_STATUS_NO_MEMORY;
837 }
838
f3df4c03 839 asl_msg_list_append(out, m);
81582353
A
840
841 /* q must have [ASLOption control], so a "null" query really has count == 1 */
842 if (asl_msg_count(q) == 1) all = true;
843
844 if (all || (0 == asl_msg_lookup(q, "debug", NULL, NULL)))
845 {
846 if (global.debug == 0) snprintf(val, sizeof(val), "0");
847 else snprintf(val, sizeof(val), "1 %s", global.debug_file);
f3df4c03 848 asl_msg_set_key_val(m, "debug", val);
81582353
A
849 }
850
851 if (all || (0 == asl_msg_lookup(q, "dbtype", NULL, NULL)))
852 {
853 n = 0;
854 if (global.dbtype & DB_TYPE_FILE) n++;
855 if (global.dbtype & DB_TYPE_MEMORY) n++;
81582353
A
856
857 if (n == 0)
858 {
f3df4c03 859 asl_msg_set_key_val(m, "dbtype", "unknown");
81582353
A
860 }
861 else
862 {
863 i = 0;
864 memset(val, 0, sizeof(val));
865
866 if (global.dbtype & DB_TYPE_FILE)
867 {
868 i++;
869 strncat(val, "file", 4);
870 if (i < n) strncat(val, " ", 1);
871 }
872
873 if (global.dbtype & DB_TYPE_MEMORY)
874 {
875 i++;
876 strncat(val, "memory", 6);
877 if (i < n) strncat(val, " ", 1);
878 }
879
f3df4c03 880 asl_msg_set_key_val(m, "dbtype", val);
a83ff38a
A
881 }
882 }
81582353
A
883
884 if (all || (0 == asl_msg_lookup(q, "db_file_max", NULL, NULL)))
885 {
886 snprintf(val, sizeof(val), "%u", global.db_file_max);
f3df4c03 887 asl_msg_set_key_val(m, "db_file_max", val);
81582353
A
888 }
889
890 if (all || (0 == asl_msg_lookup(q, "db_memory_max", NULL, NULL)))
891 {
892 snprintf(val, sizeof(val), "%u", global.db_memory_max);
f3df4c03 893 asl_msg_set_key_val(m, "db_memory_max", val);
81582353 894 }
f3df4c03
A
895
896 if (all || (0 == asl_msg_lookup(q, "db_memory_str_max", NULL, NULL)))
81582353 897 {
f3df4c03
A
898 snprintf(val, sizeof(val), "%u", global.db_memory_str_max);
899 asl_msg_set_key_val(m, "db_memory_str_max", val);
81582353 900 }
f3df4c03 901
81582353
A
902 if (all || (0 == asl_msg_lookup(q, "mps_limit", NULL, NULL)))
903 {
904 snprintf(val, sizeof(val), "%u", global.mps_limit);
f3df4c03 905 asl_msg_set_key_val(m, "mps_limit", val);
81582353
A
906 }
907
908 if (all || (0 == asl_msg_lookup(q, "bsd_max_dup_time", NULL, NULL)))
909 {
910 snprintf(val, sizeof(val), "%llu", global.bsd_max_dup_time);
f3df4c03 911 asl_msg_set_key_val(m, "bsd_max_dup_time", val);
81582353
A
912 }
913
914 if (all || (0 == asl_msg_lookup(q, "mark_time", NULL, NULL)))
915 {
916 snprintf(val, sizeof(val), "%llu", global.mark_time);
f3df4c03 917 asl_msg_set_key_val(m, "mark_time", val);
81582353
A
918 }
919
920 if (all || (0 == asl_msg_lookup(q, "utmp_ttl", NULL, NULL)))
921 {
5222c21d 922 snprintf(val, sizeof(val), "%llu", (unsigned long long) global.utmp_ttl);
f3df4c03
A
923 asl_msg_set_key_val(m, "utmp_ttl", val);
924 }
925
5222c21d 926 if (all || (0 == asl_msg_lookup(q, "memory_size", NULL, NULL)))
f3df4c03 927 {
5222c21d
A
928 snprintf(val, sizeof(val), "%lld", global.memory_size);
929 asl_msg_set_key_val(m, "memory_size", val);
930 }
931
932 if (all || (0 == asl_msg_lookup(q, "memory_max", NULL, NULL)))
933 {
934 snprintf(val, sizeof(val), "%lld", global.memory_max);
935 asl_msg_set_key_val(m, "memory_max", val);
936 }
937
938 if (all || (0 == asl_msg_lookup(q, "stats_interval", NULL, NULL)))
939 {
940 snprintf(val, sizeof(val), "%lld", (long long) global.stats_interval);
941 asl_msg_set_key_val(m, "stats_interval", val);
81582353
A
942 }
943
944 if (all || (0 == asl_msg_lookup(q, "work_queue_count", NULL, NULL)))
945 {
946 snprintf(val, sizeof(val), "%d", global.work_queue_count);
f3df4c03 947 asl_msg_set_key_val(m, "work_queue_count", val);
81582353
A
948 }
949
950 if (all || (0 == asl_msg_lookup(q, "asl_queue_count", NULL, NULL)))
951 {
952 snprintf(val, sizeof(val), "%d", global.asl_queue_count);
f3df4c03 953 asl_msg_set_key_val(m, "asl_queue_count", val);
81582353
A
954 }
955
956 if (all || (0 == asl_msg_lookup(q, "bsd_queue_count", NULL, NULL)))
957 {
958 snprintf(val, sizeof(val), "%d", global.bsd_queue_count);
f3df4c03 959 asl_msg_set_key_val(m, "bsd_queue_count", val);
81582353
A
960 }
961
962 if (all || (0 == asl_msg_lookup(q, "client_count", NULL, NULL)))
963 {
964 snprintf(val, sizeof(val), "%d", global.client_count);
f3df4c03 965 asl_msg_set_key_val(m, "client_count", val);
81582353
A
966 }
967
968 if (all || (0 == asl_msg_lookup(q, "disaster_occurred", NULL, NULL)))
969 {
970 snprintf(val, sizeof(val), "%d", global.disaster_occurred);
f3df4c03 971 asl_msg_set_key_val(m, "disaster_occurred", val);
81582353
A
972 }
973
974#ifdef LOCKDOWN
975 if (all || (0 == asl_msg_lookup(q, "lockdown_session_count", NULL, NULL)))
976 {
977 snprintf(val, sizeof(val), "%d", global.lockdown_session_count);
f3df4c03 978 asl_msg_set_key_val(m, "lockdown_session_count", val);
81582353
A
979 }
980
981 if (all || (0 == asl_msg_lookup(q, "remote_delay_time", NULL, NULL)))
982 {
983 snprintf(val, sizeof(val), "%u", global.remote_delay_time);
f3df4c03 984 asl_msg_set_key_val(m, "remote_delay_time", val);
81582353
A
985 }
986
db78b1bd 987#endif
81582353
A
988
989 if (all || (0 == asl_msg_lookup(q, "watchers_active", NULL, NULL)))
990 {
991 snprintf(val, sizeof(val), "%d", global.watchers_active);
f3df4c03 992 asl_msg_set_key_val(m, "watchers_active", val);
81582353
A
993 }
994
995 for (i = 0; i < global.module_count; i++)
996 {
997 if (all || (0 == asl_msg_lookup(q, global.module[i]->name, NULL, NULL)))
998 {
999 snprintf(val, sizeof(val), "%s", global.module[i]->enabled ? "enabled" : "disabled");
f3df4c03 1000 asl_msg_set_key_val(m, global.module[i]->name, val);
81582353
A
1001 }
1002 }
1003
c8dfc69e
A
1004 /* output module query must be on the asl_action_queue */
1005 asl_action_out_module_query(q, m, all);
81582353
A
1006
1007 /* synchronous actions use queries, since messages are simpleroutines */
1008 if (0 == asl_msg_lookup(q, "action", &mval, NULL))
1009 {
1010 int res = -1;
1011 if (uid == 0) res = asl_action_control_set_param(mval);
1012 snprintf(val, sizeof(val), "%d", res);
f3df4c03 1013 asl_msg_set_key_val(m, "action", val);
81582353
A
1014 }
1015
f3df4c03 1016 asl_msg_release(m);
81582353
A
1017 *res = out;
1018 return ASL_STATUS_OK;
a83ff38a
A
1019}
1020
86a8bcf5 1021static void
5222c21d
A
1022_server_message_processing(asl_request_msg *request)
1023{
1024 const uint32_t sbits = MACH_SEND_MSG | MACH_SEND_TIMEOUT;;
1025 kern_return_t ks;
1026 asl_reply_msg *reply = calloc(1, sizeof(asl_reply_msg) + MAX_TRAILER_SIZE);
1027
1028 voucher_mach_msg_state_t voucher = voucher_mach_msg_adopt(&(request->head));
1029
1030 /* MIG server routine */
1031 asl_ipc_server(&(request->head), &(reply->head));
1032
1033 if (!(reply->head.msgh_bits & MACH_MSGH_BITS_COMPLEX))
1034 {
1035 if (reply->reply.Reply__asl_server_message.RetCode == MIG_NO_REPLY)
1036 {
1037 reply->head.msgh_remote_port = MACH_PORT_NULL;
1038 }
1039 else if ((reply->reply.Reply__asl_server_message.RetCode != KERN_SUCCESS) && (request->head.msgh_bits & MACH_MSGH_BITS_COMPLEX))
1040 {
1041 /* destroy the request - but not the reply port */
1042 request->head.msgh_remote_port = MACH_PORT_NULL;
1043 mach_msg_destroy(&(request->head));
1044 }
1045 }
1046
1047 if (reply->head.msgh_remote_port != MACH_PORT_NULL)
1048 {
1049 ks = mach_msg(&(reply->head), sbits, reply->head.msgh_size, 0, MACH_PORT_NULL, 10, MACH_PORT_NULL);
1050 if ((ks == MACH_SEND_INVALID_DEST) || (ks == MACH_SEND_TIMED_OUT))
1051 {
1052 /* clean up */
1053 mach_msg_destroy(&(reply->head));
1054 }
1055 else if (ks == MACH_SEND_INVALID_HEADER)
1056 {
1057 /*
1058 * This should never happen, but we can continue running.
1059 */
1060 char str[256];
1061 asldebug("ERROR: mach_msg() send failed with MACH_SEND_INVALID_HEADER 0x%08x\n", ks);
1062 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);
1063 internal_log_message(str);
1064 mach_msg_destroy(&(reply->head));
1065 }
1066 else if (ks == MACH_SEND_NO_BUFFER)
1067 {
1068 /*
1069 * This should never happen, but the kernel can run out of memory.
1070 * We clean up and continue running.
1071 */
1072 char str[256];
1073 asldebug("ERROR: mach_msg() send failed with MACH_SEND_NO_BUFFER 0x%08x\n", ks);
1074 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);
1075 internal_log_message(str);
1076 mach_msg_destroy(&(reply->head));
1077 }
1078 else if (ks != KERN_SUCCESS)
1079 {
1080 /*
1081 * Failed to send a reply message. This should never happen,
1082 * but the best action is to crash.
1083 */
1084 char str[256];
1085 asldebug("FATAL ERROR: mach_msg() send failed with status 0x%08x\n", ks);
1086 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);
1087 internal_log_message(str);
1088 sleep(1);
1089 abort();
1090 }
1091 }
1092 else if (reply->head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
1093 {
1094 mach_msg_destroy(&reply->head);
1095 }
1096
1097 voucher_mach_msg_revert(voucher);
1098 free(request);
1099 free(reply);
1100}
1101
5dd30d76
A
1102/*
1103 * Receives messages on the "com.apple.system.logger" mach port.
57b0aad2 1104 * Services database search requests.
5dd30d76 1105 * Runs in it's own thread.
5222c21d
A
1106 *
1107 * The logic in this routine got a bit more complex due to (1) increased logging load and (2) 16K page size.
1108 * Out-of-line (OOL) memory sent to syslogd from libasl is allocated in pages, so the minimum size of a
1109 * message is one page. Since this routine can get slammed with messages at a very high rate, and since
1110 * the message queue in the kernel is only 5 messages, it is critical that this routine service the port
1111 * as fast as possible. To that end, it needs to do as little processing as possible.
1112 * In the version of this code found up to syslog-312, this routine received messages and dispatched them
1113 * on the asl_server_queue for further processing. When pages were only 4K, this was not a problem. With
1114 * 16K pages, it only takes about 650 messages to run syslogd's dirty memoory size up to the point of its
1115 * jetsam limit. Code was added here to track the memory being used in this queue + the work queue that's
1116 * used by process_message(), such that messages will get dropped if the queues reach a memory limit.
1117 * The actual message data in the VM pages is typically only a few hundred bytes, so holding VM pages in
1118 * the queue was a waste, and seriously limited the number of queued messages.
1119 *
1120 * The solution implemented here is a bit of a hack. It peeks at the received message header to determine
1121 * which MIG routine is being called. If the call is for _asl_server_message, it calls asl_ipc_server()
1122 * on the server thread. This routes the call through the MIG server code for error checking and so on,
1123 * and invokes _asl_server_message() on this thread. _asl_server_message() has been modified to copy
1124 * the message data into malloced memory, vm_deallocate the OOL memory, and then it dispatches the real
1125 * work onto the asl_server_queue.
5dd30d76
A
1126 */
1127void
1128database_server()
1129{
5dd30d76 1130 asl_request_msg *request;
5222c21d
A
1131 uint32_t rqs, asl_server_message_num = 0;
1132 size_t i;
5dd30d76 1133 struct timeval now, send_time;
c4fdb7d1 1134 mach_dead_name_notification_t *deadname;
f3df4c03 1135 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;
5dd30d76
A
1136 send_time.tv_sec = 0;
1137 send_time.tv_usec = 0;
5222c21d
A
1138 struct mig_map_s {
1139 const char *routine;
1140 int num;
1141 } migmap[] = { subsystem_to_name_map_asl_ipc };
1142
1143 for (i = 0; (i < (sizeof(migmap) / sizeof(struct mig_map_s))) && (asl_server_message_num == 0); i++)
1144 {
1145 if (!strcmp(migmap[i].routine, "_asl_server_message")) asl_server_message_num = migmap[i].num;
1146 }
5dd30d76
A
1147
1148 rqs = sizeof(asl_request_msg) + MAX_TRAILER_SIZE;
5dd30d76 1149
db78b1bd
A
1150 asl_server_queue = dispatch_queue_create("ASL Server Queue", NULL);
1151
5dd30d76
A
1152 forever
1153 {
f3df4c03
A
1154 kern_return_t ks;
1155
5dd30d76
A
1156 now.tv_sec = 0;
1157 now.tv_usec = 0;
1158
5dd30d76
A
1159 request = (asl_request_msg *)calloc(1, rqs);
1160 if (request == NULL) continue;
1161
57b0aad2 1162 request->head.msgh_local_port = global.server_port;
5dd30d76
A
1163 request->head.msgh_size = rqs;
1164
f3df4c03
A
1165 ks = mach_msg(&(request->head), rbits, 0, rqs, global.listen_set, 0, MACH_PORT_NULL);
1166 if (ks != KERN_SUCCESS)
1167 {
1168 /*
1169 * This shouldn't happen, but if we get a failure the best thing to do is to crash.
1170 */
1171 char str[256];
1172 asldebug("FATAL ERROR: mach_msg() receive failed with status 0x%08x\n", ks);
1173 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);
1174 internal_log_message(str);
1175 sleep(1);
1176 abort();
1177 }
5dd30d76 1178
c8dfc69e
A
1179 if (request->head.msgh_local_port == global.dead_session_port &&
1180 request->head.msgh_id == MACH_NOTIFY_DEAD_NAME)
c4fdb7d1
A
1181 {
1182 deadname = (mach_dead_name_notification_t *)request;
db78b1bd
A
1183 dispatch_async(asl_server_queue, ^{
1184 cancel_session(deadname->not_port);
1185 /* dead name notification includes a dead name right */
1186 mach_port_deallocate(mach_task_self(), deadname->not_port);
1187 free(request);
1188 });
a83ff38a 1189
c4fdb7d1
A
1190 continue;
1191 }
1192
5222c21d
A
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 }
5dd30d76
A
1201 }
1202}
1203
81582353 1204static void
86a8bcf5 1205caller_get_read_entitlement(audit_token_t *token, uid_t *uid, gid_t *gid)
81582353
A
1206{
1207#if TARGET_OS_EMBEDDED
86a8bcf5 1208 xpc_object_t entitlements, val;
81582353
A
1209 bool bval = false;
1210 int64_t ival = -2;
81582353 1211
86a8bcf5 1212 entitlements = xpc_copy_entitlement_for_token(NULL, token);
81582353
A
1213 if (entitlements == NULL) return;
1214
81582353
A
1215 bval = xpc_dictionary_get_bool(entitlements, ASL_ENTITLEMENT_KEY);
1216 if (bval && (uid != NULL))
1217 {
1218 *uid = 0;
1219 xpc_release(entitlements);
1220 return;
1221 }
1222
1223 val = xpc_dictionary_get_value(entitlements, ASL_ENTITLEMENT_UID_KEY);
1224 if (val != NULL)
1225 {
1226 if ((xpc_get_type(val) == XPC_TYPE_INT64) && (uid != NULL))
1227 {
1228 ival = xpc_int64_get_value(val);
1229 *uid = ival;
1230 }
1231 }
1232
1233 val = xpc_dictionary_get_value(entitlements, ASL_ENTITLEMENT_GID_KEY);
1234 if (val != NULL)
1235 {
1236 if ((xpc_get_type(val) == XPC_TYPE_INT64) && (gid != NULL))
1237 {
1238 ival = xpc_int64_get_value(val);
1239 *gid = ival;
1240 }
1241 }
1242
1243 xpc_release(entitlements);
1244#endif
1245}
1246
1247static kern_return_t
1248__asl_server_query_internal
5dd30d76 1249(
c4fdb7d1
A
1250 mach_port_t server,
1251 caddr_t request,
1252 mach_msg_type_number_t requestCnt,
1253 uint64_t startid,
1254 int count,
f3df4c03
A
1255 uint32_t duration,
1256 int direction,
c4fdb7d1
A
1257 caddr_t *reply,
1258 mach_msg_type_number_t *replyCnt,
1259 uint64_t *lastid,
1260 int *status,
86a8bcf5 1261 audit_token_t *token
5dd30d76
A
1262)
1263{
f3df4c03
A
1264 asl_msg_list_t *query;
1265 asl_msg_list_t *res;
5dd30d76
A
1266 char *out, *vmbuffer;
1267 uint32_t outlen;
1268 kern_return_t kstatus;
1269
30cde84f
A
1270 *reply = NULL;
1271 *replyCnt = 0;
1272 *lastid = 0;
5dd30d76 1273 *status = ASL_STATUS_OK;
a83ff38a
A
1274
1275 if ((request != NULL) && (request[requestCnt - 1] != '\0'))
1276 {
a83ff38a 1277 vm_deallocate(mach_task_self(), (vm_address_t)request, requestCnt);
30cde84f 1278 *status = ASL_STATUS_INVALID_ARG;
a83ff38a
A
1279 return KERN_SUCCESS;
1280 }
1281
f3df4c03 1282 query = asl_msg_list_from_string(request);
a83ff38a 1283 if (request != NULL) vm_deallocate(mach_task_self(), (vm_address_t)request, requestCnt);
5dd30d76
A
1284 res = NULL;
1285
86a8bcf5
A
1286 uid_t uid = (uid_t)-1;
1287 gid_t gid = (gid_t)-1;
1288 pid_t pid = (pid_t)-1;
1289 audit_token_to_au32(*token, NULL, &uid, &gid, NULL, NULL, &pid, NULL, NULL);
1290
81582353
A
1291 /* A query list containing a single query, which itself contains
1292 * [ASLOption control] is an internal state query */
f3df4c03 1293 if ((query != NULL) && (query->count == 1) && asl_check_option(query->msg[0], ASL_OPT_CONTROL))
81582353
A
1294 {
1295 *status = syslogd_state_query(query->msg[0], &res, uid);
1296 }
1297 else
1298 {
1299 int x = 0;
1300#if TARGET_OS_EMBEDDED
1301 x = pid;
1302#endif
1303
1304 if (pid > 0)
1305 {
86a8bcf5 1306 caller_get_read_entitlement(token, &uid, &gid);
81582353
A
1307 if (uid == 0) x = 0;
1308 }
1309
f3df4c03 1310 *status = db_query(query, &res, startid, count, duration, direction, lastid, uid, gid, x);
81582353 1311 }
57b0aad2 1312
f3df4c03 1313 asl_msg_list_release(query);
e125da38
A
1314 if (*status != ASL_STATUS_INVALID_STORE)
1315 {
1316 /* ignore */
1317 }
1318 else if (*status != ASL_STATUS_OK)
5dd30d76 1319 {
f3df4c03 1320 if (res != NULL) asl_msg_list_release(res);
57b0aad2 1321 return KERN_SUCCESS;
5dd30d76 1322 }
5dd30d76 1323
57b0aad2
A
1324 out = NULL;
1325 outlen = 0;
f3df4c03
A
1326 out = asl_msg_list_to_string(res, &outlen);
1327 asl_msg_list_release(res);
5dd30d76
A
1328
1329 if ((out == NULL) || (outlen == 0)) return KERN_SUCCESS;
1330
5222c21d 1331 kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmbuffer, outlen, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
5dd30d76
A
1332 if (kstatus != KERN_SUCCESS)
1333 {
1334 free(out);
30cde84f
A
1335 *status = ASL_STATUS_FAILED;
1336 return KERN_SUCCESS;
5dd30d76
A
1337 }
1338
1339 memmove(vmbuffer, out, outlen);
1340 free(out);
1341
1342 *reply = vmbuffer;
1343 *replyCnt = outlen;
1344
1345 return KERN_SUCCESS;
1346}
1347
81582353
A
1348kern_return_t
1349__asl_server_query_2
1350(
1351 mach_port_t server,
1352 caddr_t request,
1353 mach_msg_type_number_t requestCnt,
1354 uint64_t startid,
1355 int count,
1356 int flags,
1357 caddr_t *reply,
1358 mach_msg_type_number_t *replyCnt,
1359 uint64_t *lastid,
1360 int *status,
1361 audit_token_t token
1362)
1363{
f3df4c03
A
1364 int direction = SEARCH_FORWARD;
1365 if (flags & QUERY_FLAG_SEARCH_REVERSE) direction = SEARCH_BACKWARD;
1366
86a8bcf5 1367 return __asl_server_query_internal(server, request, requestCnt, startid, count, QUERY_DURATION_UNLIMITED, direction, reply, replyCnt, lastid, status, &token);
f3df4c03
A
1368}
1369
1370kern_return_t
1371__asl_server_match
1372(
1373 mach_port_t server,
1374 caddr_t request,
1375 mach_msg_type_number_t requestCnt,
1376 uint64_t startid,
1377 uint64_t count,
1378 uint32_t duration,
1379 int direction,
1380 caddr_t *reply,
1381 mach_msg_type_number_t *replyCnt,
1382 uint64_t *lastid,
1383 int *status,
1384 audit_token_t token
81582353 1385)
5dd30d76 1386{
86a8bcf5 1387 return __asl_server_query_internal(server, request, requestCnt, startid, count, duration, direction, reply, replyCnt, lastid, status, &token);
5dd30d76 1388}
c4fdb7d1 1389
5222c21d
A
1390/*
1391 * Does the actual processing for __asl_server_message.
1392 * Dispatched on asl_server_queue. This lets us avoid
1393 * calling asl_msg_from_string(), task_name_for_pid(),
1394 * and register_session() on the database_server() thread.
1395 */
1396static void
1397_asl_message_processing(char *mbuf, uint64_t msize, uid_t uid, gid_t gid, pid_t pid)
1398{
1399 asl_msg_t *msg;
1400 char tmp[64];
1401 kern_return_t kstatus;
1402 mach_port_name_t client;
1403
1404 msg = asl_msg_from_string(mbuf);
1405 free(mbuf);
1406
1407 /*
1408 * process_message() will update global.memory_size with the
1409 * size of msg, and it increements the work_queue_count.
1410 */
1411 OSAtomicAdd64(-1ll * msize, &global.memory_size);
1412 OSAtomicDecrement32(&global.work_queue_count);
1413
1414 if (msg == NULL) return;
1415
1416 client = MACH_PORT_NULL;
1417 kstatus = task_name_for_pid(mach_task_self(), pid, &client);
1418 if (kstatus == KERN_SUCCESS) register_session(client, pid);
1419
1420 snprintf(tmp, sizeof(tmp), "%d", uid);
1421 asl_msg_set_key_val(msg, ASL_KEY_UID, tmp);
1422
1423 snprintf(tmp, sizeof(tmp), "%d", gid);
1424 asl_msg_set_key_val(msg, ASL_KEY_GID, tmp);
1425
1426 snprintf(tmp, sizeof(tmp), "%d", pid);
1427 asl_msg_set_key_val(msg, ASL_KEY_PID, tmp);
1428
1429 process_message(msg, SOURCE_ASL_MESSAGE);
1430}
1431
1432/*
1433 * This MIG server routine is something of a special case in database_server() above.
1434 * It is called on the server thread that's responsible for servicing syslogd's mach port.
1435 * In this routine we copy the actual ASL message raw string out of the message into
1436 * malloc memory, deallocate the message, and dispatch the real work onto the asl_server_queue.
1437 */
c4fdb7d1
A
1438kern_return_t
1439__asl_server_message
1440(
1441 mach_port_t server,
1442 caddr_t message,
1443 mach_msg_type_number_t messageCnt,
1444 audit_token_t token
1445)
1446{
c4fdb7d1
A
1447 uid_t uid;
1448 gid_t gid;
1449 pid_t pid;
5222c21d 1450 char *mbuf;
c4fdb7d1 1451
5222c21d
A
1452 if (message == NULL) return KERN_SUCCESS;
1453
1454 if (message[messageCnt - 1] != '\0')
a83ff38a 1455 {
5222c21d 1456 vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt);
a83ff38a
A
1457 return KERN_SUCCESS;
1458 }
1459
5222c21d
A
1460 asldebug("__asl_server_message: %s\n", message);
1461
1462 if ((global.memory_size + messageCnt) > global.memory_max)
a83ff38a 1463 {
5222c21d
A
1464 char str[256];
1465 asldebug("Server queue dropped message. message size %u queue size %lld max %lld\n", messageCnt, global.memory_size, global.memory_max);
1466 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);
1467 internal_log_message(str);
1468
a83ff38a
A
1469 vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt);
1470 return KERN_SUCCESS;
1471 }
1472
5222c21d
A
1473 mbuf = malloc(messageCnt);
1474 if (mbuf != NULL) memcpy(mbuf, message, messageCnt);
c4fdb7d1
A
1475 vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt);
1476
5222c21d 1477 if (mbuf == NULL) return KERN_SUCCESS;
a83ff38a 1478
c4fdb7d1
A
1479 uid = (uid_t)-1;
1480 gid = (gid_t)-1;
db78b1bd 1481 pid = (pid_t)-1;
c4fdb7d1
A
1482 audit_token_to_au32(token, NULL, &uid, &gid, NULL, NULL, &pid, NULL, NULL);
1483
5222c21d
A
1484 OSAtomicIncrement32(&global.work_queue_count);
1485 OSAtomicAdd64(messageCnt, &(global.memory_size));
c4fdb7d1 1486
5222c21d 1487 dispatch_async(asl_server_queue, ^{ _asl_message_processing(mbuf, messageCnt, uid, gid, pid); });
a83ff38a
A
1488
1489 return KERN_SUCCESS;
1490}
1491
1492kern_return_t
1493__asl_server_create_aux_link
1494(
1495 mach_port_t server,
1496 caddr_t message,
1497 mach_msg_type_number_t messageCnt,
1498 mach_port_t *fileport,
1499 caddr_t *newurl,
1500 mach_msg_type_number_t *newurlCnt,
1501 int *status,
1502 audit_token_t token
1503)
1504{
f3df4c03 1505 asl_msg_t *msg;
a83ff38a
A
1506 char tmp[64];
1507 uid_t uid;
1508 gid_t gid;
1509 pid_t pid;
1510 kern_return_t kstatus;
1511 mach_port_name_t client;
1512 char *url, *vmbuffer;
1513 int fd;
1514
f3df4c03 1515 *fileport = MACH_PORT_NULL;
30cde84f
A
1516 *newurl = NULL;
1517 *newurlCnt = 0;
1518 *status = ASL_STATUS_OK;
a83ff38a
A
1519
1520 if (message == NULL)
1521 {
1522 *status = ASL_STATUS_INVALID_ARG;
1523 return KERN_SUCCESS;
1524 }
1525
1526 if (message[messageCnt - 1] != '\0')
1527 {
a83ff38a 1528 vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt);
30cde84f 1529 *status = ASL_STATUS_INVALID_ARG;
a83ff38a
A
1530 return KERN_SUCCESS;
1531 }
1532
1533 asldebug("__asl_server_create_aux_link: %s\n", (message == NULL) ? "NULL" : message);
1534
1535 if ((global.dbtype & DB_TYPE_FILE) == 0)
1536 {
30cde84f 1537 vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt);
a83ff38a
A
1538 *status = ASL_STATUS_INVALID_STORE;
1539 return KERN_SUCCESS;
1540 }
1541
f3df4c03 1542 msg = asl_msg_from_string(message);
a83ff38a
A
1543 vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt);
1544
1545 if (msg == NULL) return KERN_SUCCESS;
1546
1547 uid = (uid_t)-1;
1548 gid = (gid_t)-1;
db78b1bd 1549 pid = (pid_t)-1;
a83ff38a
A
1550 audit_token_to_au32(token, NULL, &uid, &gid, NULL, NULL, &pid, NULL, NULL);
1551
1552 client = MACH_PORT_NULL;
1553 kstatus = task_name_for_pid(mach_task_self(), pid, &client);
1554 if (kstatus == KERN_SUCCESS) register_session(client, pid);
1555
1556 snprintf(tmp, sizeof(tmp), "%d", uid);
f3df4c03 1557 asl_msg_set_key_val(msg, ASL_KEY_UID, tmp);
a83ff38a
A
1558
1559 snprintf(tmp, sizeof(tmp), "%d", gid);
f3df4c03 1560 asl_msg_set_key_val(msg, ASL_KEY_GID, tmp);
a83ff38a
A
1561
1562 snprintf(tmp, sizeof(tmp), "%d", pid);
f3df4c03 1563 asl_msg_set_key_val(msg, ASL_KEY_PID, tmp);
a83ff38a
A
1564
1565 /* create a file for the client */
1566 *status = asl_store_open_aux(global.file_db, msg, &fd, &url);
f3df4c03 1567 asl_msg_release(msg);
a83ff38a
A
1568 if (*status != ASL_STATUS_OK) return KERN_SUCCESS;
1569 if (url == NULL)
1570 {
1571 if (fd >= 0) close(fd);
1572 *status = ASL_STATUS_FAILED;
1573 return KERN_SUCCESS;
1574 }
1575
1576 if (fileport_makeport(fd, (fileport_t *)fileport) < 0)
1577 {
1578 close(fd);
1579 free(url);
1580 *status = ASL_STATUS_FAILED;
1581 return KERN_SUCCESS;
1582 }
1583
1584 close(fd);
1585
1586 *newurlCnt = strlen(url) + 1;
1587
5222c21d 1588 kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmbuffer, *newurlCnt, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
a83ff38a
A
1589 if (kstatus != KERN_SUCCESS)
1590 {
1591 free(url);
30cde84f
A
1592 *status = ASL_STATUS_FAILED;
1593 return KERN_SUCCESS;
a83ff38a
A
1594 }
1595
1596 memmove(vmbuffer, url, *newurlCnt);
1597 free(url);
81582353
A
1598
1599 *newurl = vmbuffer;
1600
a83ff38a
A
1601 return KERN_SUCCESS;
1602}
1603
1604kern_return_t
1605__asl_server_register_direct_watch
1606(
1607 mach_port_t server,
1608 int port,
1609 audit_token_t token
1610)
1611{
1612 uint16_t p16 = port;
db78b1bd
A
1613 pid_t pid = (pid_t)-1;
1614
1615 audit_token_to_au32(token, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL);
a83ff38a 1616
db78b1bd 1617 asldebug("__asl_server_register_direct_watch: pid %u port %hu\n", pid, ntohs(p16));
a83ff38a 1618
81582353
A
1619 dispatch_once(&watch_init_once, ^{
1620 watch_queue = dispatch_queue_create("Direct Watch Queue", NULL);
1621 });
1622
1623 dispatch_async(watch_queue, ^{ register_direct_watch(p16); });
a83ff38a
A
1624
1625 return KERN_SUCCESS;
1626}
1627
1628kern_return_t
1629__asl_server_cancel_direct_watch
1630(
1631 mach_port_t server,
1632 int port,
1633 audit_token_t token
1634)
1635{
1636 uint16_t p16 = port;
1637
1638 asldebug("__asl_server_cancel_direct_watch: %hu\n", ntohs(p16));
1639
81582353
A
1640 dispatch_once(&watch_init_once, ^{
1641 watch_queue = dispatch_queue_create("Direct Watch Queue", NULL);
1642 });
1643
1644 dispatch_async(watch_queue, ^{ cancel_direct_watch(p16); });
c4fdb7d1
A
1645
1646 return KERN_SUCCESS;
1647}