]> git.saurik.com Git - apple/syslog.git/blob - syslogd.tproj/remote.c
d127d9f178ba48b9d1625225185ecb497d2d5d0b
[apple/syslog.git] / syslogd.tproj / remote.c
1 /*
2 * Copyright (c) 2004-2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <TargetConditionals.h>
25
26 #if TARGET_IPHONE_SIMULATOR
27 struct _not_empty;
28 #else
29
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>
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
60 #define WATCH_OFF 0
61 #define WATCH_LOCKDOWN_START 1
62 #define WATCH_RUN 2
63
64 #define SESSION_FLAGS_LOCKDOWN 0x00000001
65
66 #define MAXSOCK 1
67
68 static int rfd4 = -1;
69 static int rfd6 = -1;
70 static int rfdl = -1;
71
72 static dispatch_source_t in_src_local;
73 static dispatch_source_t in_src_tcp;
74 static dispatch_queue_t in_queue;
75
76 #ifdef NSS32
77 typedef uint32_t notify_state_t;
78 extern int notify_set_state(int, notify_state_t);
79 #else
80 typedef uint64_t notify_state_t;
81 #endif
82
83 extern char *asl_list_to_string(asl_search_result_t *list, uint32_t *outlen);
84 extern size_t asl_memory_size(asl_memory_t *s);
85 extern 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
87 extern void add_lockdown_session(int fd);
88 extern void remove_lockdown_session(int fd);
89
90 #define SESSION_WRITE(f,x) if (write(f, x, strlen(x)) < 0) goto exit_session
91
92 typedef struct
93 {
94 int sock;
95 uint32_t flags;
96 } session_args_t;
97
98 uint32_t
99 remote_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
107 uint32_t
108 remote_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
116 aslmsg
117 remote_db_stats(uint32_t sel)
118 {
119 aslmsg m;
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
128 void
129 session(void *x)
130 {
131 int i, s, wfd, status, pfmt, watch, wtoken, nfd, do_prompt;
132 aslresponse res;
133 asl_search_result_t ql;
134 uint32_t outlen;
135 aslmsg stats;
136 asl_msg_t *query;
137 asl_msg_t *qlq[1];
138 char str[1024], *p, *qs, *out;
139 ssize_t len;
140 fd_set readfds, errfds;
141 uint64_t low_id, high_id;
142 uint32_t dbselect, flags;
143 session_args_t *sp;
144
145 if (x == NULL) pthread_exit(NULL);
146
147 sp = (session_args_t *)x;
148 s = sp->sock;
149 flags = sp->flags;
150 free(x);
151
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;
155 watch = WATCH_OFF;
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
171 if (flags & SESSION_FLAGS_LOCKDOWN) sleep(1);
172
173 snprintf(str, sizeof(str), "\n========================\nASL is here to serve you\n");
174 if (write(s, str, strlen(str)) < 0)
175 {
176 close(s);
177 pthread_exit(NULL);
178 return;
179 }
180
181 if (flags & SESSION_FLAGS_LOCKDOWN)
182 {
183 snprintf(str, sizeof(str), "> ");
184 SESSION_WRITE(s, str);
185 }
186
187 forever
188 {
189 if (((flags & SESSION_FLAGS_LOCKDOWN) == 0) && (do_prompt > 0))
190 {
191 snprintf(str, sizeof(str), "> ");
192 SESSION_WRITE(s, str);
193 }
194
195 do_prompt = 1;
196
197 memset(str, 0, sizeof(str));
198
199 FD_ZERO(&readfds);
200 FD_SET(s, &readfds);
201 FD_ZERO(&errfds);
202 FD_SET(s, &errfds);
203 nfd = s;
204
205 if (wfd != -1)
206 {
207 FD_SET(wfd, &readfds);
208 if (wfd > nfd) nfd = wfd;
209 }
210
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 }
224
225 if ((wfd != -1) && (FD_ISSET(wfd, &readfds)))
226 {
227 (void)read(wfd, &i, sizeof(int));
228 }
229
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
236 if (FD_ISSET(s, &readfds))
237 {
238 len = read(s, str, sizeof(str) - 1);
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 }
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 {
253 snprintf(str, sizeof(str), "Goodbye\n");
254 write(s, str, strlen(str));
255 close(s);
256 s = -1;
257 break;
258 }
259
260 if ((!strcmp(str, "?")) || (!strcmp(str, "help")))
261 {
262 snprintf(str, sizeof(str), "Commands\n");
263 SESSION_WRITE(s, str);
264 snprintf(str, sizeof(str), " quit exit session\n");
265 SESSION_WRITE(s, str);
266 snprintf(str, sizeof(str), " select [val] get [set] current database\n");
267 SESSION_WRITE(s, str);
268 snprintf(str, sizeof(str), " val must be \"file\", \"mem\", or \"mini\"\n");
269 SESSION_WRITE(s, str);
270 snprintf(str, sizeof(str), " file [on/off] enable / disable file store\n");
271 SESSION_WRITE(s, str);
272 snprintf(str, sizeof(str), " memory [on/off] enable / disable memory store\n");
273 SESSION_WRITE(s, str);
274 snprintf(str, sizeof(str), " mini [on/off] enable / disable mini memory store\n");
275 SESSION_WRITE(s, str);
276 snprintf(str, sizeof(str), " stats database statistics\n");
277 SESSION_WRITE(s, str);
278 snprintf(str, sizeof(str), " flush flush database\n");
279 SESSION_WRITE(s, str);
280 snprintf(str, sizeof(str), " dbsize [val] get [set] database size (# of records)\n");
281 SESSION_WRITE(s, str);
282 snprintf(str, sizeof(str), " watch print new messages as they arrive\n");
283 SESSION_WRITE(s, str);
284 snprintf(str, sizeof(str), " stop stop watching for new messages\n");
285 SESSION_WRITE(s, str);
286 snprintf(str, sizeof(str), " raw use raw format for printing messages\n");
287 SESSION_WRITE(s, str);
288 snprintf(str, sizeof(str), " std use standard format for printing messages\n");
289 SESSION_WRITE(s, str);
290 snprintf(str, sizeof(str), " * show all log messages\n");
291 SESSION_WRITE(s, str);
292 snprintf(str, sizeof(str), " * key val equality search for messages (single key/value pair)\n");
293 SESSION_WRITE(s, str);
294 snprintf(str, sizeof(str), " * op key val search for matching messages (single key/value pair)\n");
295 SESSION_WRITE(s, str);
296 snprintf(str, sizeof(str), " * [op key val] ... search for matching messages (multiple key/value pairs)\n");
297 SESSION_WRITE(s, str);
298 snprintf(str, sizeof(str), " operators: = < > ! (not equal) T (key exists) R (regex)\n");
299 SESSION_WRITE(s, str);
300 snprintf(str, sizeof(str), " modifiers (must follow operator):\n");
301 SESSION_WRITE(s, str);
302 snprintf(str, sizeof(str), " C=casefold N=numeric S=substring A=prefix Z=suffix\n");
303 SESSION_WRITE(s, str);
304 snprintf(str, sizeof(str), "\n");
305 SESSION_WRITE(s, str);
306 continue;
307 }
308 else if (!strcmp(str, "stats"))
309 {
310 stats = remote_db_stats(dbselect);
311 out = asl_format_message((asl_msg_t *)stats, ASL_MSG_FMT_RAW, ASL_TIME_FMT_SEC, ASL_ENCODE_NONE, &outlen);
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 {
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");
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 {
337 snprintf(str, sizeof(str), "file database is not enabled\n");
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 {
348 snprintf(str, sizeof(str), "memory database is not enabled\n");
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 {
361 snprintf(str, sizeof(str), "mini memory database is enabled for disaster messages\n");
362 SESSION_WRITE(s, str);
363 }
364 else
365 {
366 snprintf(str, sizeof(str), "mini memory database is not enabled\n");
367 SESSION_WRITE(s, str);
368 continue;
369 }
370 }
371
372 dbselect = DB_TYPE_MINI;
373 }
374 else
375 {
376 snprintf(str, sizeof(str), "unknown database type\n");
377 SESSION_WRITE(s, str);
378 continue;
379 }
380
381 snprintf(str, sizeof(str), "OK\n");
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 {
391 snprintf(str, sizeof(str), "file database is %senabled\n", (global.dbtype & DB_TYPE_FILE) ? "" : "not ");
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
400 snprintf(str, sizeof(str), "OK\n");
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 {
410 snprintf(str, sizeof(str), "memory database is %senabled\n", (global.dbtype & DB_TYPE_MEMORY) ? "" : "not ");
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
419 snprintf(str, sizeof(str), "OK\n");
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 {
429 snprintf(str, sizeof(str), "mini database is %senabled\n", (global.dbtype & DB_TYPE_MINI) ? "" : "not ");
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
438 snprintf(str, sizeof(str), "OK\n");
439 SESSION_WRITE(s, str);
440 continue;
441 }
442 else if (!strncmp(str, "dbsize", 6))
443 {
444 if (dbselect == 0)
445 {
446 snprintf(str, sizeof(str), "no store\n");
447 SESSION_WRITE(s, str);
448 continue;
449 }
450
451 p = str + 6;
452 while ((*p == ' ') || (*p == '\t')) p++;
453 if (*p == '\0')
454 {
455 snprintf(str, sizeof(str), "DB size %u\n", remote_db_size(dbselect));
456 SESSION_WRITE(s, str);
457 continue;
458 }
459
460 i = atoi(p);
461 remote_db_set_size(dbselect, i);
462
463 snprintf(str, sizeof(str), "OK\n");
464 SESSION_WRITE(s, str);
465 continue;
466 }
467 else if (!strcmp(str, "stop"))
468 {
469 if (watch != WATCH_OFF)
470 {
471 watch = WATCH_OFF;
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
482 snprintf(str, sizeof(str), "OK\n");
483 SESSION_WRITE(s, str);
484 continue;
485 }
486
487 snprintf(str, sizeof(str), "not watching!\n");
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 {
503 if (((flags & SESSION_FLAGS_LOCKDOWN) == 0) && (watch != WATCH_OFF))
504 {
505 snprintf(str, sizeof(str), "already watching!\n");
506 SESSION_WRITE(s, str);
507 continue;
508 }
509
510 if (flags & SESSION_FLAGS_LOCKDOWN)
511 {
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 */
523 watch = WATCH_LOCKDOWN_START;
524 dispatch_suspend(global.work_queue);
525 }
526 else
527 {
528 status = notify_register_file_descriptor(kNotifyASLDBUpdate, &wfd, 0, &wtoken);
529 if (status != 0)
530 {
531 snprintf(str, sizeof(str), "notify_register_file_descriptor failed: %d\n", status);
532 SESSION_WRITE(s, str);
533 continue;
534 }
535
536 watch = WATCH_RUN;
537 }
538
539 snprintf(str, sizeof(str), "OK\n");
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 {
581 snprintf(str, sizeof(str), "unrecognized command\n");
582 SESSION_WRITE(s, str);
583 snprintf(str, sizeof(str), "enter \"help\" for help\n");
584 SESSION_WRITE(s, str);
585 continue;
586 }
587 }
588
589 if ((flags & SESSION_FLAGS_LOCKDOWN) && (watch == WATCH_RUN)) continue;
590
591 /* Bottom of the loop: do a database query and print the results */
592
593 if (query != NULL)
594 {
595 ql.count = 1;
596 qlq[0] = query;
597 ql.msg = qlq;
598 }
599
600 if (watch == WATCH_OFF) low_id = 0;
601
602 memset(&res, 0, sizeof(aslresponse));
603 high_id = 0;
604 (void)db_query(&ql, (aslresponse *)&res, low_id, 0, 0, &high_id, 0, 0, 0);
605
606 if ((watch == WATCH_RUN) && (high_id >= low_id)) low_id = high_id + 1;
607
608 if (res == NULL)
609 {
610 if (watch == WATCH_OFF)
611 {
612 snprintf(str, sizeof(str), "-nil-\n");
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 {
622 if (watch == WATCH_RUN)
623 {
624 snprintf(str, sizeof(str), "\n");
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
633 snprintf(str, sizeof(str), "\n");
634 SESSION_WRITE(s, str);
635 }
636 else
637 {
638 if ((watch == WATCH_RUN) || (watch == WATCH_LOCKDOWN_START))
639 {
640 snprintf(str, sizeof(str), "\n");
641 SESSION_WRITE(s, str);
642 }
643
644 snprintf(str, sizeof(str), "\n");
645 for (i = 0; i < res->count; i++)
646 {
647 int wstatus;
648
649 out = asl_format_message(res->msg[i], ASL_MSG_FMT_STD, ASL_TIME_FMT_LCL, ASL_ENCODE_SAFE, &outlen);
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
673 free(out);
674 if (global.remote_delay_time > 0) usleep(global.remote_delay_time);
675 }
676 }
677
678 aslresponse_free(res);
679
680 if (watch == WATCH_LOCKDOWN_START)
681 {
682 add_lockdown_session(s);
683 watch = WATCH_RUN;
684 dispatch_resume(global.work_queue);
685 }
686 }
687
688 exit_session:
689
690 asldebug("%s %d: terminating session for %ssocket %d\n", MY_ID, s, (flags & SESSION_FLAGS_LOCKDOWN) ? "lockdown " : "", s);
691
692 if (s >= 0)
693 {
694 if (flags & SESSION_FLAGS_LOCKDOWN) remove_lockdown_session(s);
695 close(s);
696 }
697
698 if (watch == WATCH_LOCKDOWN_START) dispatch_resume(global.work_queue);
699 if (wtoken >= 0) notify_cancel(wtoken);
700 if (query != NULL) asl_msg_release(query);
701 pthread_exit(NULL);
702 }
703
704 aslmsg
705 remote_acceptmsg(int fd, int tcp)
706 {
707 socklen_t fromlen;
708 int s, flags, status, v;
709 pthread_attr_t attr;
710 pthread_t t;
711 struct sockaddr_storage from;
712 session_args_t *sp;
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
736 v = 1;
737 setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, &v, sizeof(v));
738
739 if (tcp == 1)
740 {
741 flags = 1;
742 setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof(int));
743 }
744
745 sp = (session_args_t *)calloc(1, sizeof(session_args_t));
746 if (sp == NULL)
747 {
748 asldebug("%s: malloc: %s\n", MY_ID, strerror(errno));
749 close(s);
750 return NULL;
751 }
752
753 sp->sock = s;
754 if (tcp == 0) sp->flags |= SESSION_FLAGS_LOCKDOWN;
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
764 aslmsg
765 remote_acceptmsg_local(int fd)
766 {
767 return remote_acceptmsg(fd, 0);
768 }
769
770 aslmsg
771 remote_acceptmsg_tcp(int fd)
772 {
773 return remote_acceptmsg(fd, 1);
774 }
775
776 int
777 remote_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
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
837 return fd;
838 }
839
840 int
841 remote_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
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
910 return fd;
911 }
912
913 int
914 remote_init(void)
915 {
916 static dispatch_once_t once;
917
918 dispatch_once(&once, ^{
919 in_queue = dispatch_queue_create(MY_ID, NULL);
920 });
921
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
939 int
940 remote_close(void)
941 {
942 if (rfdl >= 0)
943 {
944 close(rfdl);
945 }
946
947 rfdl = -1;
948
949 if (rfd4 >= 0)
950 {
951 close(rfd4);
952 }
953
954 rfd4 = -1;
955
956 if (rfd6 >= 0)
957 {
958 close(rfd6);
959 }
960
961 rfd6 = -1;
962
963 return 0;
964 }
965
966 int
967 remote_reset(void)
968 {
969 return 0;
970
971 remote_close();
972 return remote_init();
973 }
974
975 #endif /* !TARGET_IPHONE_SIMULATOR */