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