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