]>
Commit | Line | Data |
---|---|---|
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 | 64 | static pthread_mutex_t db_lock = PTHREAD_MUTEX_INITIALIZER; |
5dd30d76 A |
65 | |
66 | extern char *asl_list_to_string(asl_search_result_t *list, uint32_t *outlen); | |
67 | extern asl_search_result_t *asl_list_from_string(const char *buf); | |
57b0aad2 | 68 | extern boolean_t asl_ipc_server(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP); |
c4fdb7d1 | 69 | extern uint32_t bb_convert(const char *name); |
5dd30d76 | 70 | |
c4fdb7d1 A |
71 | static task_name_t *client_tasks = NULL; |
72 | static uint32_t client_tasks_count = 0; | |
5dd30d76 | 73 | |
a83ff38a A |
74 | static int *direct_watch = NULL; |
75 | /* N.B. ports are in network byte order */ | |
76 | static uint16_t *direct_watch_port = NULL; | |
77 | static uint32_t direct_watch_count = 0; | |
78 | ||
5dd30d76 A |
79 | typedef union |
80 | { | |
81 | mach_msg_header_t head; | |
82 | union __RequestUnion__asl_ipc_subsystem request; | |
83 | } asl_request_msg; | |
84 | ||
85 | typedef union | |
86 | { | |
87 | mach_msg_header_t head; | |
88 | union __ReplyUnion__asl_ipc_subsystem reply; | |
89 | } asl_reply_msg; | |
90 | ||
91 | void | |
c4fdb7d1 | 92 | db_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 |
103 | void |
104 | db_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 | */ | |
185 | void | |
c4fdb7d1 | 186 | output_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 | ||
238 | void | |
239 | send_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 | */ | |
347 | void | |
a83ff38a | 348 | db_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 | 437 | void |
a83ff38a | 438 | disaster_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 | */ | |
459 | uint32_t | |
460 | db_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 |
502 | static void |
503 | register_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 | ||
543 | static void | |
544 | cancel_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 |
572 | static uint32_t |
573 | register_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 | ||
638 | static void | |
639 | cancel_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 | */ | |
693 | void | |
694 | database_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 | ||
787 | kern_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 | ||
859 | kern_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 | ||
878 | kern_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 | |
891 | kern_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 | ||
950 | kern_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 | ||
1059 | kern_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 | ||
1076 | kern_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 | } |