xref: /NextBSD/usr.sbin/asl/dbserver.c (revision 33da5adc555b3bc29986eeadca03829e4ad06b1e)
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 <sys/fileport.h>
39 #include <mach/mach.h>
40 #include <mach/mach_error.h>
41 #include <bsm/libbsm.h>
42 #include <errno.h>
43 #include <netinet/in.h>
44 #include <netinet/tcp.h>
45 #include <sys/event.h>
46 #include <servers/bootstrap.h>
47 #include <pthread.h>
48 #include <notify.h>
49 #include <sys/time.h>
50 #include <xpc/xpc.h>
51 //#include <xpc/private.h>
52 #include <libproc.h>
53 #include <uuid/uuid.h>
54 #include "daemon.h"
55 #include "asl_ipc.h"
56 
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
db_asl_open(uint32_t dbtype)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
add_lockdown_session(int fd)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
remove_lockdown_session(int fd)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
sweep_lockdown_session_fds()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
_internal_send_to_direct_watchers(asl_msg_t * msg)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
send_to_direct_watchers(asl_msg_t * msg)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
db_save_message(asl_msg_t * msg)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 			// XXX 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
disaster_message(asl_msg_t * msg)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
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)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
register_session(task_name_t task_name,pid_t pid)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
cancel_session(task_name_t task_name)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
register_direct_watch(uint16_t port)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
cancel_direct_watch(uint16_t port)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
syslogd_state_query(asl_msg_t * q,asl_msg_list_t ** res,uid_t uid)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
database_server()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); // XXX | 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
caller_get_read_entitlement(pid_t pid,uid_t * uid,gid_t * gid)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
__asl_server_query_internal(mach_port_t server,caddr_t request,mach_msg_type_number_t requestCnt,uint64_t startid,int count,uint32_t duration,int direction,caddr_t * reply,mach_msg_type_number_t * replyCnt,uint64_t * lastid,int * status,uid_t uid,gid_t gid,pid_t pid)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
__asl_server_query_2(mach_port_t server,caddr_t request,mach_msg_type_number_t requestCnt,uint64_t startid,int count,int flags,caddr_t * reply,mach_msg_type_number_t * replyCnt,uint64_t * lastid,int * status,audit_token_t token)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
__asl_server_query(mach_port_t server,caddr_t request,mach_msg_type_number_t requestCnt,uint64_t startid,int count,int flags,caddr_t * reply,mach_msg_type_number_t * replyCnt,uint64_t * lastid,int * status,security_token_t * token)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
__asl_server_query_timeout(mach_port_t server,caddr_t request,mach_msg_type_number_t requestCnt,uint64_t startid,int count,int flags,caddr_t * reply,mach_msg_type_number_t * replyCnt,uint64_t * lastid,int * status,audit_token_t token)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
__asl_server_match(mach_port_t server,caddr_t request,mach_msg_type_number_t requestCnt,uint64_t startid,uint64_t count,uint32_t duration,int direction,caddr_t * reply,mach_msg_type_number_t * replyCnt,uint64_t * lastid,int * status,audit_token_t token)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
__asl_server_prune(mach_port_t server,caddr_t request,mach_msg_type_number_t requestCnt,int * status,security_token_t * token)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
__asl_server_message(mach_port_t server,caddr_t message,mach_msg_type_number_t messageCnt,audit_token_t token)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
__asl_server_create_aux_link(mach_port_t server,caddr_t message,mach_msg_type_number_t messageCnt,mach_port_t * fileport,caddr_t * newurl,mach_msg_type_number_t * newurlCnt,int * status,audit_token_t token)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 0
1566 	if (fileport_makeport(fd, (fileport_t *)fileport) < 0)
1567 	{
1568 		close(fd);
1569 		free(url);
1570 		*status = ASL_STATUS_FAILED;
1571 		return KERN_SUCCESS;
1572 	}
1573 #endif
1574 
1575 	close(fd);
1576 
1577 	*newurlCnt = strlen(url) + 1;
1578 
1579 	kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmbuffer, *newurlCnt, TRUE);
1580 	if (kstatus != KERN_SUCCESS)
1581 	{
1582 		free(url);
1583 		return kstatus;
1584 	}
1585 
1586 	memmove(vmbuffer, url, *newurlCnt);
1587 	free(url);
1588 
1589 	*newurl = vmbuffer;
1590 
1591 	return KERN_SUCCESS;
1592 }
1593 
1594 kern_return_t
__asl_server_register_direct_watch(mach_port_t server,int port,audit_token_t token)1595 __asl_server_register_direct_watch
1596 (
1597 	mach_port_t server,
1598 	int port,
1599 	audit_token_t token
1600 )
1601 {
1602 	uint16_t p16 = port;
1603 	pid_t pid = (pid_t)-1;
1604 
1605 	audit_token_to_au32(token, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL);
1606 
1607 	asldebug("__asl_server_register_direct_watch: pid %u port %hu\n", pid, ntohs(p16));
1608 
1609 	dispatch_once(&watch_init_once, ^{
1610 		watch_queue = dispatch_queue_create("Direct Watch Queue", NULL);
1611 	});
1612 
1613 	dispatch_async(watch_queue, ^{ register_direct_watch(p16); });
1614 
1615 	return KERN_SUCCESS;
1616 }
1617 
1618 kern_return_t
__asl_server_cancel_direct_watch(mach_port_t server,int port,audit_token_t token)1619 __asl_server_cancel_direct_watch
1620 (
1621 	mach_port_t server,
1622 	int port,
1623 	audit_token_t token
1624 )
1625 {
1626 	uint16_t p16 = port;
1627 
1628 	asldebug("__asl_server_cancel_direct_watch: %hu\n", ntohs(p16));
1629 
1630 	dispatch_once(&watch_init_once, ^{
1631 		watch_queue = dispatch_queue_create("Direct Watch Queue", NULL);
1632 	});
1633 
1634 	dispatch_async(watch_queue, ^{ cancel_direct_watch(p16); });
1635 
1636 	return KERN_SUCCESS;
1637 }
1638