]> git.saurik.com Git - apple/syslog.git/blame - syslogd.tproj/remote.c
syslog-217.1.4.tar.gz
[apple/syslog.git] / syslogd.tproj / remote.c
CommitLineData
57b0aad2 1/*
81582353 2 * Copyright (c) 2004-2012 Apple Inc. All rights reserved.
57b0aad2
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
81582353
A
24#include <TargetConditionals.h>
25
26#if TARGET_IPHONE_SIMULATOR
27struct _not_empty;
28#else
29
57b0aad2
A
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <sys/socket.h>
33#include <netinet/in.h>
34#include <netinet/tcp.h>
35#include <arpa/inet.h>
36#include <sys/un.h>
37#include <sys/uio.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include <fcntl.h>
42#include <errno.h>
43#include <unistd.h>
44#include <netdb.h>
45#include <pthread.h>
46#include <notify.h>
57b0aad2
A
47#include "daemon.h"
48
49#define forever for(;;)
50
51#define MY_ID "remote"
52#define MAXLINE 4096
53#define LOCKDOWN_PATH "/var/run/lockdown"
54#define SYSLOG_SOCK_PATH "/var/run/lockdown/syslog.sock"
55#define ASL_REMOTE_PORT 203
56
57#define PRINT_STD 0
58#define PRINT_RAW 1
59
a83ff38a
A
60#define WATCH_OFF 0
61#define WATCH_LOCKDOWN_START 1
62#define WATCH_RUN 2
63
64#define SESSION_FLAGS_LOCKDOWN 0x00000001
65
57b0aad2
A
66#define MAXSOCK 1
67
68static int rfd4 = -1;
69static int rfd6 = -1;
70static int rfdl = -1;
71
db78b1bd
A
72static dispatch_source_t in_src_local;
73static dispatch_source_t in_src_tcp;
74static dispatch_queue_t in_queue;
75
57b0aad2
A
76#ifdef NSS32
77typedef uint32_t notify_state_t;
78extern int notify_set_state(int, notify_state_t);
79#else
80typedef uint64_t notify_state_t;
81#endif
82
83extern char *asl_list_to_string(asl_search_result_t *list, uint32_t *outlen);
84extern size_t asl_memory_size(asl_memory_t *s);
81582353
A
85extern uint32_t db_query(aslresponse query, aslresponse *res, uint64_t startid, int count, int flags, uint64_t *lastid, int32_t ruid, int32_t rgid, int raccess);
86
87extern void add_lockdown_session(int fd);
88extern void remove_lockdown_session(int fd);
57b0aad2
A
89
90#define SESSION_WRITE(f,x) if (write(f, x, strlen(x)) < 0) goto exit_session
91
a83ff38a
A
92typedef struct
93{
94 int sock;
95 uint32_t flags;
96} session_args_t;
97
57b0aad2
A
98uint32_t
99remote_db_size(uint32_t sel)
100{
101 if (sel == DB_TYPE_FILE) return global.db_file_max;
102 if (sel == DB_TYPE_MEMORY) return global.db_memory_max;
103 if (sel == DB_TYPE_MINI) return global.db_mini_max;
104 return 0;
105}
106
107uint32_t
108remote_db_set_size(uint32_t sel, uint32_t size)
109{
110 if (sel == DB_TYPE_FILE) global.db_file_max = size;
111 if (sel == DB_TYPE_MEMORY) global.db_memory_max = size;
112 if (sel == DB_TYPE_MINI) global.db_mini_max = size;
113 return 0;
114}
115
a83ff38a 116aslmsg
57b0aad2
A
117remote_db_stats(uint32_t sel)
118{
a83ff38a 119 aslmsg m;
57b0aad2
A
120 m = NULL;
121
122 if (sel == DB_TYPE_FILE) asl_store_statistics(global.file_db, &m);
123 if (sel == DB_TYPE_MEMORY) asl_memory_statistics(global.memory_db, &m);
124 if (sel == DB_TYPE_MINI) asl_mini_memory_statistics(global.mini_db, &m);
125 return m;
126}
127
128void
129session(void *x)
130{
db78b1bd 131 int i, s, wfd, status, pfmt, watch, wtoken, nfd, do_prompt;
57b0aad2
A
132 aslresponse res;
133 asl_search_result_t ql;
134 uint32_t outlen;
a83ff38a 135 aslmsg stats;
57b0aad2
A
136 asl_msg_t *query;
137 asl_msg_t *qlq[1];
138 char str[1024], *p, *qs, *out;
139 ssize_t len;
db78b1bd 140 fd_set readfds, errfds;
57b0aad2 141 uint64_t low_id, high_id;
a83ff38a
A
142 uint32_t dbselect, flags;
143 session_args_t *sp;
57b0aad2
A
144
145 if (x == NULL) pthread_exit(NULL);
146
a83ff38a
A
147 sp = (session_args_t *)x;
148 s = sp->sock;
149 flags = sp->flags;
57b0aad2
A
150 free(x);
151
db78b1bd
A
152 asldebug("%s %d: starting interactive session for %ssocket %d\n", MY_ID, s, (flags & SESSION_FLAGS_LOCKDOWN) ? "lockdown " : "", s);
153
154 do_prompt = 1;
a83ff38a 155 watch = WATCH_OFF;
57b0aad2
A
156 wfd = -1;
157 wtoken = -1;
158
159 dbselect = 0;
160 if (global.dbtype & DB_TYPE_MEMORY) dbselect = DB_TYPE_MEMORY;
161 else if (global.dbtype & DB_TYPE_MINI) dbselect = DB_TYPE_MINI;
162 else if (global.dbtype & DB_TYPE_FILE) dbselect = DB_TYPE_FILE;
163
164 low_id = 0;
165 high_id = 0;
166
167 pfmt = PRINT_STD;
168 query = NULL;
169 memset(&ql, 0, sizeof(asl_search_result_t));
170
81582353
A
171 if (flags & SESSION_FLAGS_LOCKDOWN) sleep(1);
172
db78b1bd 173 snprintf(str, sizeof(str), "\n========================\nASL is here to serve you\n");
57b0aad2
A
174 if (write(s, str, strlen(str)) < 0)
175 {
176 close(s);
177 pthread_exit(NULL);
178 return;
179 }
180
81582353
A
181 if (flags & SESSION_FLAGS_LOCKDOWN)
182 {
183 snprintf(str, sizeof(str), "> ");
184 SESSION_WRITE(s, str);
185 }
186
57b0aad2
A
187 forever
188 {
db78b1bd 189 if (((flags & SESSION_FLAGS_LOCKDOWN) == 0) && (do_prompt > 0))
57b0aad2 190 {
db78b1bd 191 snprintf(str, sizeof(str), "> ");
57b0aad2
A
192 SESSION_WRITE(s, str);
193 }
194
195 do_prompt = 1;
db78b1bd 196
57b0aad2
A
197 memset(str, 0, sizeof(str));
198
199 FD_ZERO(&readfds);
200 FD_SET(s, &readfds);
db78b1bd
A
201 FD_ZERO(&errfds);
202 FD_SET(s, &errfds);
57b0aad2
A
203 nfd = s;
204
205 if (wfd != -1)
206 {
207 FD_SET(wfd, &readfds);
208 if (wfd > nfd) nfd = wfd;
209 }
210
db78b1bd
A
211 status = select(nfd + 1, &readfds, NULL, &errfds, NULL);
212 if (status == 0) continue;
213 if (status < 0)
214 {
215 asldebug("%s %d: select %d %s\n", MY_ID, s, errno, strerror(errno));
216 goto exit_session;
217 }
218
219 if (FD_ISSET(s, &errfds))
220 {
221 asldebug("%s %d: error on socket %d\n", MY_ID, s, s);
222 goto exit_session;
223 }
57b0aad2
A
224
225 if ((wfd != -1) && (FD_ISSET(wfd, &readfds)))
226 {
db78b1bd 227 (void)read(wfd, &i, sizeof(int));
57b0aad2
A
228 }
229
81582353
A
230 if (FD_ISSET(s, &errfds))
231 {
232 asldebug("%s %d: socket %d reported error\n", MY_ID, s, s);
233 goto exit_session;
234 }
235
57b0aad2
A
236 if (FD_ISSET(s, &readfds))
237 {
238 len = read(s, str, sizeof(str) - 1);
db78b1bd
A
239 if (len <= 0)
240 {
241 asldebug("%s %d: read error on socket %d: %d %s\n", MY_ID, s, s, errno, strerror(errno));
242 goto exit_session;
243 }
57b0aad2
A
244
245 while ((len > 1) && ((str[len - 1] == '\n') || (str[len - 1] == '\r')))
246 {
247 str[len - 1] = '\0';
248 len--;
249 }
250
251 if ((!strcmp(str, "q")) || (!strcmp(str, "quit")) || (!strcmp(str, "exit")))
252 {
db78b1bd 253 snprintf(str, sizeof(str), "Goodbye\n");
57b0aad2
A
254 write(s, str, strlen(str));
255 close(s);
256 s = -1;
257 break;
258 }
259
260 if ((!strcmp(str, "?")) || (!strcmp(str, "help")))
261 {
db78b1bd 262 snprintf(str, sizeof(str), "Commands\n");
57b0aad2 263 SESSION_WRITE(s, str);
db78b1bd 264 snprintf(str, sizeof(str), " quit exit session\n");
57b0aad2 265 SESSION_WRITE(s, str);
db78b1bd 266 snprintf(str, sizeof(str), " select [val] get [set] current database\n");
57b0aad2 267 SESSION_WRITE(s, str);
db78b1bd 268 snprintf(str, sizeof(str), " val must be \"file\", \"mem\", or \"mini\"\n");
57b0aad2 269 SESSION_WRITE(s, str);
db78b1bd 270 snprintf(str, sizeof(str), " file [on/off] enable / disable file store\n");
57b0aad2 271 SESSION_WRITE(s, str);
db78b1bd 272 snprintf(str, sizeof(str), " memory [on/off] enable / disable memory store\n");
57b0aad2 273 SESSION_WRITE(s, str);
db78b1bd 274 snprintf(str, sizeof(str), " mini [on/off] enable / disable mini memory store\n");
57b0aad2 275 SESSION_WRITE(s, str);
db78b1bd 276 snprintf(str, sizeof(str), " stats database statistics\n");
57b0aad2 277 SESSION_WRITE(s, str);
db78b1bd 278 snprintf(str, sizeof(str), " flush flush database\n");
57b0aad2 279 SESSION_WRITE(s, str);
db78b1bd 280 snprintf(str, sizeof(str), " dbsize [val] get [set] database size (# of records)\n");
57b0aad2 281 SESSION_WRITE(s, str);
db78b1bd 282 snprintf(str, sizeof(str), " watch print new messages as they arrive\n");
57b0aad2 283 SESSION_WRITE(s, str);
db78b1bd 284 snprintf(str, sizeof(str), " stop stop watching for new messages\n");
57b0aad2 285 SESSION_WRITE(s, str);
db78b1bd 286 snprintf(str, sizeof(str), " raw use raw format for printing messages\n");
57b0aad2 287 SESSION_WRITE(s, str);
db78b1bd 288 snprintf(str, sizeof(str), " std use standard format for printing messages\n");
57b0aad2 289 SESSION_WRITE(s, str);
db78b1bd 290 snprintf(str, sizeof(str), " * show all log messages\n");
57b0aad2 291 SESSION_WRITE(s, str);
db78b1bd 292 snprintf(str, sizeof(str), " * key val equality search for messages (single key/value pair)\n");
57b0aad2 293 SESSION_WRITE(s, str);
db78b1bd 294 snprintf(str, sizeof(str), " * op key val search for matching messages (single key/value pair)\n");
57b0aad2 295 SESSION_WRITE(s, str);
db78b1bd 296 snprintf(str, sizeof(str), " * [op key val] ... search for matching messages (multiple key/value pairs)\n");
57b0aad2 297 SESSION_WRITE(s, str);
db78b1bd 298 snprintf(str, sizeof(str), " operators: = < > ! (not equal) T (key exists) R (regex)\n");
57b0aad2 299 SESSION_WRITE(s, str);
db78b1bd 300 snprintf(str, sizeof(str), " modifiers (must follow operator):\n");
57b0aad2 301 SESSION_WRITE(s, str);
db78b1bd 302 snprintf(str, sizeof(str), " C=casefold N=numeric S=substring A=prefix Z=suffix\n");
57b0aad2 303 SESSION_WRITE(s, str);
db78b1bd 304 snprintf(str, sizeof(str), "\n");
57b0aad2
A
305 SESSION_WRITE(s, str);
306 continue;
307 }
308 else if (!strcmp(str, "stats"))
309 {
310 stats = remote_db_stats(dbselect);
a83ff38a 311 out = asl_format_message((asl_msg_t *)stats, ASL_MSG_FMT_RAW, ASL_TIME_FMT_SEC, ASL_ENCODE_NONE, &outlen);
57b0aad2
A
312 write(s, out, outlen);
313 free(out);
314 asl_free(stats);
315 continue;
316 }
317 else if (!strcmp(str, "flush"))
318 {}
319 else if (!strncmp(str, "select", 6))
320 {
321 p = str + 6;
322 while ((*p == ' ') || (*p == '\t')) p++;
323 if (*p == '\0')
324 {
db78b1bd
A
325 if (dbselect == 0) snprintf(str, sizeof(str), "no store\n");
326 else if (dbselect == DB_TYPE_FILE) snprintf(str, sizeof(str), "file store\n");
327 else if (dbselect == DB_TYPE_MEMORY) snprintf(str, sizeof(str), "memory store\n");
328 else if (dbselect == DB_TYPE_MINI) snprintf(str, sizeof(str), "mini memory store\n");
57b0aad2
A
329 SESSION_WRITE(s, str);
330 continue;
331 }
332
333 if (!strncmp(p, "file", 4))
334 {
335 if ((global.dbtype & DB_TYPE_FILE) == 0)
336 {
db78b1bd 337 snprintf(str, sizeof(str), "file database is not enabled\n");
57b0aad2
A
338 SESSION_WRITE(s, str);
339 continue;
340 }
341
342 dbselect = DB_TYPE_FILE;
343 }
344 else if (!strncmp(p, "mem", 3))
345 {
346 if ((global.dbtype & DB_TYPE_MEMORY) == 0)
347 {
db78b1bd 348 snprintf(str, sizeof(str), "memory database is not enabled\n");
57b0aad2
A
349 SESSION_WRITE(s, str);
350 continue;
351 }
352
353 dbselect = DB_TYPE_MEMORY;
354 }
355 else if (!strncmp(p, "mini", 4))
356 {
357 if ((global.dbtype & DB_TYPE_MINI) == 0)
358 {
359 if (global.mini_db != NULL)
360 {
db78b1bd 361 snprintf(str, sizeof(str), "mini memory database is enabled for disaster messages\n");
57b0aad2
A
362 SESSION_WRITE(s, str);
363 }
364 else
365 {
db78b1bd 366 snprintf(str, sizeof(str), "mini memory database is not enabled\n");
57b0aad2
A
367 SESSION_WRITE(s, str);
368 continue;
369 }
370 }
371
372 dbselect = DB_TYPE_MINI;
373 }
374 else
375 {
db78b1bd 376 snprintf(str, sizeof(str), "unknown database type\n");
57b0aad2
A
377 SESSION_WRITE(s, str);
378 continue;
379 }
380
db78b1bd 381 snprintf(str, sizeof(str), "OK\n");
57b0aad2
A
382 SESSION_WRITE(s, str);
383 continue;
384 }
385 else if (!strncmp(str, "file", 4))
386 {
387 p = str + 4;
388 while ((*p == ' ') || (*p == '\t')) p++;
389 if (*p == '\0')
390 {
db78b1bd 391 snprintf(str, sizeof(str), "file database is %senabled\n", (global.dbtype & DB_TYPE_FILE) ? "" : "not ");
57b0aad2
A
392 SESSION_WRITE(s, str);
393 if ((global.dbtype & DB_TYPE_FILE) != 0) dbselect = DB_TYPE_FILE;
394 continue;
395 }
396
397 if (!strcmp(p, "on")) global.dbtype |= DB_TYPE_FILE;
398 else if (!strcmp(p, "off")) global.dbtype &= ~ DB_TYPE_FILE;
399
db78b1bd 400 snprintf(str, sizeof(str), "OK\n");
57b0aad2
A
401 SESSION_WRITE(s, str);
402 continue;
403 }
404 else if (!strncmp(str, "memory", 6))
405 {
406 p = str + 6;
407 while ((*p == ' ') || (*p == '\t')) p++;
408 if (*p == '\0')
409 {
db78b1bd 410 snprintf(str, sizeof(str), "memory database is %senabled\n", (global.dbtype & DB_TYPE_MEMORY) ? "" : "not ");
57b0aad2
A
411 SESSION_WRITE(s, str);
412 if ((global.dbtype & DB_TYPE_MEMORY) != 0) dbselect = DB_TYPE_MEMORY;
413 continue;
414 }
415
416 if (!strcmp(p, "on")) global.dbtype |= DB_TYPE_MEMORY;
417 else if (!strcmp(p, "off")) global.dbtype &= ~ DB_TYPE_MEMORY;
418
db78b1bd 419 snprintf(str, sizeof(str), "OK\n");
57b0aad2
A
420 SESSION_WRITE(s, str);
421 continue;
422 }
423 else if (!strncmp(str, "mini", 4))
424 {
425 p = str + 4;
426 while ((*p == ' ') || (*p == '\t')) p++;
427 if (*p == '\0')
428 {
db78b1bd 429 snprintf(str, sizeof(str), "mini database is %senabled\n", (global.dbtype & DB_TYPE_MINI) ? "" : "not ");
57b0aad2
A
430 SESSION_WRITE(s, str);
431 if ((global.dbtype & DB_TYPE_MINI) != 0) dbselect = DB_TYPE_MINI;
432 continue;
433 }
434
435 if (!strcmp(p, "on")) global.dbtype |= DB_TYPE_MINI;
436 else if (!strcmp(p, "off")) global.dbtype &= ~ DB_TYPE_MINI;
437
db78b1bd 438 snprintf(str, sizeof(str), "OK\n");
57b0aad2
A
439 SESSION_WRITE(s, str);
440 continue;
441 }
442 else if (!strncmp(str, "dbsize", 6))
443 {
444 if (dbselect == 0)
445 {
db78b1bd 446 snprintf(str, sizeof(str), "no store\n");
57b0aad2
A
447 SESSION_WRITE(s, str);
448 continue;
449 }
450
451 p = str + 6;
452 while ((*p == ' ') || (*p == '\t')) p++;
453 if (*p == '\0')
454 {
db78b1bd 455 snprintf(str, sizeof(str), "DB size %u\n", remote_db_size(dbselect));
57b0aad2
A
456 SESSION_WRITE(s, str);
457 continue;
458 }
459
460 i = atoi(p);
461 remote_db_set_size(dbselect, i);
462
db78b1bd 463 snprintf(str, sizeof(str), "OK\n");
57b0aad2
A
464 SESSION_WRITE(s, str);
465 continue;
466 }
57b0aad2
A
467 else if (!strcmp(str, "stop"))
468 {
a83ff38a 469 if (watch != WATCH_OFF)
57b0aad2 470 {
a83ff38a 471 watch = WATCH_OFF;
57b0aad2
A
472 notify_cancel(wtoken);
473 wfd = -1;
474 wtoken = -1;
475
476 low_id = 0;
477 high_id = 0;
478
479 if (query != NULL) free(query);
480 query = NULL;
481
db78b1bd 482 snprintf(str, sizeof(str), "OK\n");
57b0aad2
A
483 SESSION_WRITE(s, str);
484 continue;
485 }
486
db78b1bd 487 snprintf(str, sizeof(str), "not watching!\n");
57b0aad2
A
488 SESSION_WRITE(s, str);
489 continue;
490 }
491 else if (!strcmp(str, "raw"))
492 {
493 pfmt = PRINT_RAW;
494 continue;
495 }
496 else if (!strcmp(str, "std"))
497 {
498 pfmt = PRINT_STD;
499 continue;
500 }
501 else if (!strcmp(str, "watch"))
502 {
db78b1bd 503 if (((flags & SESSION_FLAGS_LOCKDOWN) == 0) && (watch != WATCH_OFF))
57b0aad2 504 {
db78b1bd 505 snprintf(str, sizeof(str), "already watching!\n");
57b0aad2
A
506 SESSION_WRITE(s, str);
507 continue;
508 }
509
a83ff38a 510 if (flags & SESSION_FLAGS_LOCKDOWN)
57b0aad2 511 {
81582353
A
512 /*
513 * If this session is PurpleConsole or Xcode watching for log messages,
514 * we pass through the bottom of the loop (below) once to pick up
515 * existing messages already in memory. After that, dbserver will
516 * send new messages in send_to_direct_watchers(). We wait until
517 * the initial messages are sent before adding the connection to
518 * global.lockdown_session_fds to allow this query to complete before
519 * dbserver starts sending. To prevent a race between this query and
520 * when messages are sent by send_to_direct_watchers, we suspend the
521 * work queue and resume it when lockdown_session_fds has been updated.
522 */
a83ff38a 523 watch = WATCH_LOCKDOWN_START;
81582353 524 dispatch_suspend(global.work_queue);
57b0aad2 525 }
a83ff38a
A
526 else
527 {
db78b1bd 528 status = notify_register_file_descriptor(kNotifyASLDBUpdate, &wfd, 0, &wtoken);
a83ff38a
A
529 if (status != 0)
530 {
db78b1bd 531 snprintf(str, sizeof(str), "notify_register_file_descriptor failed: %d\n", status);
a83ff38a
A
532 SESSION_WRITE(s, str);
533 continue;
534 }
57b0aad2 535
a83ff38a
A
536 watch = WATCH_RUN;
537 }
57b0aad2 538
db78b1bd 539 snprintf(str, sizeof(str), "OK\n");
57b0aad2
A
540 SESSION_WRITE(s, str);
541 do_prompt = 2;
542 }
543 else if ((str[0] == '*') || (str[0] == 'T') || (str[0] == '=') || (str[0] == '!') || (str[0] == '<') || (str[0] == '>'))
544 {
545 memset(&ql, 0, sizeof(asl_search_result_t));
546 if (query != NULL) free(query);
547 query = NULL;
548
549 p = str;
550 if (*p == '*') p++;
551 while ((*p == ' ') || (*p == '\t')) p++;
552
553 if (*p == '\0')
554 {
555 /* NULL query */
556 }
557 else if (*p == '[')
558 {
559 qs = NULL;
560 asprintf(&qs, "Q %s", p);
561 query = asl_msg_from_string(qs);
562 free(qs);
563 }
564 else if ((*p == 'T') || (*p == '=') || (*p == '!') || (*p == '<') || (*p == '>') || (*p == 'R'))
565 {
566 qs = NULL;
567 asprintf(&qs, "Q [%s]", p);
568 query = asl_msg_from_string(qs);
569 free(qs);
570 }
571 else
572 {
573 qs = NULL;
574 asprintf(&qs, "Q [= %s]", p);
575 query = asl_msg_from_string(qs);
576 free(qs);
577 }
578 }
579 else
580 {
db78b1bd 581 snprintf(str, sizeof(str), "unrecognized command\n");
57b0aad2 582 SESSION_WRITE(s, str);
db78b1bd 583 snprintf(str, sizeof(str), "enter \"help\" for help\n");
57b0aad2
A
584 SESSION_WRITE(s, str);
585 continue;
586 }
587 }
588
a83ff38a
A
589 if ((flags & SESSION_FLAGS_LOCKDOWN) && (watch == WATCH_RUN)) continue;
590
81582353 591 /* Bottom of the loop: do a database query and print the results */
a83ff38a 592
57b0aad2
A
593 if (query != NULL)
594 {
595 ql.count = 1;
596 qlq[0] = query;
597 ql.msg = qlq;
598 }
599
a83ff38a 600 if (watch == WATCH_OFF) low_id = 0;
57b0aad2
A
601
602 memset(&res, 0, sizeof(aslresponse));
603 high_id = 0;
81582353 604 (void)db_query(&ql, (aslresponse *)&res, low_id, 0, 0, &high_id, 0, 0, 0);
57b0aad2 605
a83ff38a 606 if ((watch == WATCH_RUN) && (high_id >= low_id)) low_id = high_id + 1;
57b0aad2
A
607
608 if (res == NULL)
609 {
a83ff38a 610 if (watch == WATCH_OFF)
57b0aad2 611 {
db78b1bd 612 snprintf(str, sizeof(str), "-nil-\n");
57b0aad2
A
613 SESSION_WRITE(s, str);
614 }
615 else
616 {
617 if (do_prompt != 2) do_prompt = 0;
618 }
619 }
620 else if (pfmt == PRINT_RAW)
621 {
a83ff38a 622 if (watch == WATCH_RUN)
57b0aad2 623 {
db78b1bd 624 snprintf(str, sizeof(str), "\n");
57b0aad2
A
625 SESSION_WRITE(s, str);
626 }
627
628 outlen = 0;
629 out = asl_list_to_string((asl_search_result_t *)res, &outlen);
630 write(s, out, outlen);
631 free(out);
632
db78b1bd 633 snprintf(str, sizeof(str), "\n");
57b0aad2
A
634 SESSION_WRITE(s, str);
635 }
636 else
637 {
81582353 638 if ((watch == WATCH_RUN) || (watch == WATCH_LOCKDOWN_START))
57b0aad2 639 {
db78b1bd 640 snprintf(str, sizeof(str), "\n");
57b0aad2
A
641 SESSION_WRITE(s, str);
642 }
643
db78b1bd 644 snprintf(str, sizeof(str), "\n");
57b0aad2
A
645 for (i = 0; i < res->count; i++)
646 {
db78b1bd
A
647 int wstatus;
648
57b0aad2 649 out = asl_format_message(res->msg[i], ASL_MSG_FMT_STD, ASL_TIME_FMT_LCL, ASL_ENCODE_SAFE, &outlen);
db78b1bd
A
650
651 do
652 {
653 int n = 0;
654
655 errno = 0;
656 wstatus = write(s, out, outlen);
657 if (wstatus < 0)
658 {
659 asldebug("%s %d: %d/%d write data failed: %d %s\n", MY_ID, s, i, res->count, errno, strerror(errno));
660 if (errno == EAGAIN)
661 {
662 n++;
663 if (n > 10) break;
664 usleep(10000);
665 }
666 else
667 {
668 goto exit_session;
669 }
670 }
671 } while (errno == EAGAIN);
672
57b0aad2 673 free(out);
db78b1bd 674 if (global.remote_delay_time > 0) usleep(global.remote_delay_time);
57b0aad2
A
675 }
676 }
677
678 aslresponse_free(res);
a83ff38a
A
679
680 if (watch == WATCH_LOCKDOWN_START)
681 {
81582353 682 add_lockdown_session(s);
a83ff38a 683 watch = WATCH_RUN;
db78b1bd 684 dispatch_resume(global.work_queue);
a83ff38a 685 }
57b0aad2
A
686 }
687
688exit_session:
689
db78b1bd
A
690 asldebug("%s %d: terminating session for %ssocket %d\n", MY_ID, s, (flags & SESSION_FLAGS_LOCKDOWN) ? "lockdown " : "", s);
691
57b0aad2
A
692 if (s >= 0)
693 {
81582353 694 if (flags & SESSION_FLAGS_LOCKDOWN) remove_lockdown_session(s);
57b0aad2 695 close(s);
57b0aad2
A
696 }
697
db78b1bd
A
698 if (watch == WATCH_LOCKDOWN_START) dispatch_resume(global.work_queue);
699 if (wtoken >= 0) notify_cancel(wtoken);
a83ff38a 700 if (query != NULL) asl_msg_release(query);
57b0aad2
A
701 pthread_exit(NULL);
702}
703
a83ff38a 704aslmsg
57b0aad2
A
705remote_acceptmsg(int fd, int tcp)
706{
707 socklen_t fromlen;
db78b1bd 708 int s, flags, status, v;
57b0aad2
A
709 pthread_attr_t attr;
710 pthread_t t;
711 struct sockaddr_storage from;
a83ff38a 712 session_args_t *sp;
57b0aad2
A
713
714 fromlen = sizeof(struct sockaddr_un);
715 if (tcp == 1) fromlen = sizeof(struct sockaddr_storage);
716
717 memset(&from, 0, sizeof(from));
718
719 s = accept(fd, (struct sockaddr *)&from, &fromlen);
720 if (s == -1)
721 {
722 asldebug("%s: accept: %s\n", MY_ID, strerror(errno));
723 return NULL;
724 }
725
726 flags = fcntl(s, F_GETFL, 0);
727 flags &= ~ O_NONBLOCK;
728 status = fcntl(s, F_SETFL, flags);
729 if (status < 0)
730 {
731 asldebug("%s: fcntl: %s\n", MY_ID, strerror(errno));
732 close(s);
733 return NULL;
734 }
735
a83ff38a
A
736 v = 1;
737 setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, &v, sizeof(v));
738
57b0aad2
A
739 if (tcp == 1)
740 {
741 flags = 1;
742 setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof(int));
743 }
744
a83ff38a 745 sp = (session_args_t *)calloc(1, sizeof(session_args_t));
57b0aad2
A
746 if (sp == NULL)
747 {
748 asldebug("%s: malloc: %s\n", MY_ID, strerror(errno));
749 close(s);
750 return NULL;
751 }
752
a83ff38a 753 sp->sock = s;
81582353 754 if (tcp == 0) sp->flags |= SESSION_FLAGS_LOCKDOWN;
57b0aad2
A
755
756 pthread_attr_init(&attr);
757 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
758 pthread_create(&t, &attr, (void *(*)(void *))session, (void *)sp);
759 pthread_attr_destroy(&attr);
760
761 return NULL;
762}
763
a83ff38a 764aslmsg
57b0aad2
A
765remote_acceptmsg_local(int fd)
766{
767 return remote_acceptmsg(fd, 0);
768}
769
a83ff38a 770aslmsg
57b0aad2
A
771remote_acceptmsg_tcp(int fd)
772{
773 return remote_acceptmsg(fd, 1);
774}
775
776int
777remote_init_lockdown(void)
778{
779 int status, reuse, fd;
780 struct sockaddr_un local;
781
782 fd = socket(AF_UNIX, SOCK_STREAM, 0);
783 if (fd < 0)
784 {
785 asldebug("%s: socket: %s\n", MY_ID, strerror(errno));
786 return -1;
787 }
788
789 reuse = 1;
790 status = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(int));
791 if (status < 0)
792 {
793 asldebug("%s: setsockopt: %s\n", MY_ID, strerror(errno));
794 close(fd);
795 return -1;
796 }
797
798 /* make sure the lockdown directory exists */
799 mkdir(LOCKDOWN_PATH, 0777);
800
801 memset(&local, 0, sizeof(local));
802 local.sun_family = AF_UNIX;
803 strlcpy(local.sun_path, SYSLOG_SOCK_PATH, sizeof(local.sun_path));
804 unlink(local.sun_path);
805
806 status = bind(fd, (struct sockaddr *)&local, sizeof(local.sun_family) + sizeof(local.sun_path));
807
808 if (status < 0)
809 {
810 asldebug("%s: bind: %s\n", MY_ID, strerror(errno));
811 close(fd);
812 return -1;
813 }
814
815 status = fcntl(fd, F_SETFL, O_NONBLOCK);
816 if (status < 0)
817 {
818 asldebug("%s: fcntl: %s\n", MY_ID, strerror(errno));
819 close(fd);
820 return -1;
821 }
822
823 status = listen(fd, 5);
824 if (status < 0)
825 {
826 asldebug("%s: listen: %s\n", MY_ID, strerror(errno));
827 close(fd);
828 return -1;
829 }
830
831 chmod(SYSLOG_SOCK_PATH, 0666);
832
db78b1bd
A
833 in_src_local = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, (uintptr_t)fd, 0, in_queue);
834 dispatch_source_set_event_handler(in_src_local, ^{ remote_acceptmsg_local(fd); });
835 dispatch_resume(in_src_local);
836
57b0aad2
A
837 return fd;
838}
839
840int
841remote_init_tcp(int family)
842{
843 int status, reuse, fd;
844 struct sockaddr_in a4;
845 struct sockaddr_in6 a6;
846 struct sockaddr *s;
847 socklen_t len;
848
849 fd = socket(family, SOCK_STREAM, 0);
850 if (fd < 0)
851 {
852 asldebug("%s: socket: %s\n", MY_ID, strerror(errno));
853 return -1;
854 }
855
856 reuse = 1;
857 status = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(int));
858 if (status < 0)
859 {
860 asldebug("%s: setsockopt: %s\n", MY_ID, strerror(errno));
861 close(fd);
862 return -1;
863 }
864
865 memset(&(a4.sin_addr), 0, sizeof(struct in_addr));
866 a4.sin_family = AF_INET;
867 a4.sin_port = htons(ASL_REMOTE_PORT);
868
869 memset(&(a6.sin6_addr), 0, sizeof(struct in6_addr));
870 a6.sin6_family = AF_INET6;
871 a6.sin6_port = htons(ASL_REMOTE_PORT);
872
873 s = (struct sockaddr *)&a4;
874 len = sizeof(struct sockaddr_in);
875
876 if (family == AF_INET6)
877 {
878 s = (struct sockaddr *)&a6;
879 len = sizeof(struct sockaddr_in6);
880 }
881
882 status = bind(fd, s, len);
883 if (status < 0)
884 {
885 asldebug("%s: bind: %s\n", MY_ID, strerror(errno));
886 close(fd);
887 return -1;
888 }
889
890 status = fcntl(fd, F_SETFL, O_NONBLOCK);
891 if (status < 0)
892 {
893 asldebug("%s: fcntl: %s\n", MY_ID, strerror(errno));
894 close(fd);
895 return -1;
896 }
897
898 status = listen(fd, 5);
899 if (status < 0)
900 {
901 asldebug("%s: listen: %s\n", MY_ID, strerror(errno));
902 close(fd);
903 return -1;
904 }
905
db78b1bd
A
906 in_src_tcp = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, (uintptr_t)fd, 0, in_queue);
907 dispatch_source_set_event_handler(in_src_tcp, ^{ remote_acceptmsg_tcp(fd); });
908 dispatch_resume(in_src_tcp);
909
57b0aad2
A
910 return fd;
911}
912
913int
914remote_init(void)
915{
db78b1bd
A
916 static dispatch_once_t once;
917
918 dispatch_once(&once, ^{
919 in_queue = dispatch_queue_create(MY_ID, NULL);
920 });
921
57b0aad2
A
922 asldebug("%s: init\n", MY_ID);
923
924#ifdef LOCKDOWN
925 rfdl = remote_init_lockdown();
926#endif
927
928#ifdef REMOTE_IPV4
929 rfd4 = remote_init_tcp(AF_INET);
930#endif
931
932#ifdef REMOTE_IPV6
933 rfd6 = remote_init_tcp(AF_INET6);
934#endif
935
936 return 0;
937}
938
939int
940remote_close(void)
941{
a83ff38a
A
942 if (rfdl >= 0)
943 {
a83ff38a
A
944 close(rfdl);
945 }
946
57b0aad2
A
947 rfdl = -1;
948
a83ff38a
A
949 if (rfd4 >= 0)
950 {
a83ff38a
A
951 close(rfd4);
952 }
953
57b0aad2
A
954 rfd4 = -1;
955
a83ff38a
A
956 if (rfd6 >= 0)
957 {
a83ff38a
A
958 close(rfd6);
959 }
960
57b0aad2
A
961 rfd6 = -1;
962
963 return 0;
964}
965
966int
967remote_reset(void)
968{
db78b1bd
A
969 return 0;
970
57b0aad2
A
971 remote_close();
972 return remote_init();
973}
81582353
A
974
975#endif /* !TARGET_IPHONE_SIMULATOR */