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