]> git.saurik.com Git - apple/syslog.git/blob - syslogd.tproj/asl_action.c
syslog-100.2.tar.gz
[apple/syslog.git] / syslogd.tproj / asl_action.c
1 /*
2 * Copyright (c) 2004-2009 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 <sys/un.h>
28 #include <sys/uio.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <netdb.h>
36 #include <notify.h>
37 #include <pthread.h>
38 #include <asl_core.h>
39 #include "daemon.h"
40
41 #define _PATH_WALL "/usr/bin/wall"
42 #define _PATH_ASL_CONF "/etc/asl.conf"
43 #define MY_ID "asl_action"
44
45 #define ACTION_NONE 0
46 #define ACTION_IGNORE 1
47 #define ACTION_NOTIFY 2
48 #define ACTION_BROADCAST 3
49 #define ACTION_ACCESS 4
50 #define ACTION_STORE 5
51 #define ACTION_STORE_DIR 6
52 #define ACTION_FORWARD 7
53
54 #define IndexNull ((uint32_t)-1)
55 #define forever for(;;)
56
57 #define ACT_STORE_FLAG_STAY_OPEN 0x00000001
58 #define ACT_STORE_FLAG_EXCLUDE_ASLDB 0x00000002
59
60 static asl_msg_t *query = NULL;
61 static int reset = RESET_NONE;
62 static pthread_mutex_t reset_lock = PTHREAD_MUTEX_INITIALIZER;
63
64 typedef struct action_rule_s
65 {
66 asl_msg_t *query;
67 int action;
68 char *options;
69 void *data;
70 struct action_rule_s *next;
71 } action_rule_t;
72
73 struct store_data
74 {
75 asl_file_t *store;
76 FILE *storedata;
77 char *dir;
78 char *path;
79 mode_t mode;
80 uid_t uid;
81 gid_t gid;
82 uint64_t next_id;
83 uint32_t flags;
84 uint32_t p_year;
85 uint32_t p_month;
86 uint32_t p_day;
87 };
88
89 static action_rule_t *asl_action_rule = NULL;
90 static action_rule_t *asl_datastore_rule = NULL;
91 static int filter_token = -1;
92
93 int asl_action_close();
94 static int _parse_config_file(const char *);
95 extern void db_save_message(asl_msg_t *m);
96
97 static char *
98 _next_word(char **s)
99 {
100 char *a, *p, *e, *out;
101 int quote, len;
102
103 if (s == NULL) return NULL;
104 if (*s == NULL) return NULL;
105
106 quote = 0;
107
108 p = *s;
109 a = p;
110 e = p;
111
112 while (*p != '\0')
113 {
114 if (*p == '\\')
115 {
116 p++;
117 e = p;
118
119 if (*p == '\0')
120 {
121 p--;
122 break;
123 }
124
125 p++;
126 e = p;
127 continue;
128 }
129
130 if (*p == '"')
131 {
132 if (quote == 0) quote = 1;
133 else quote = 0;
134 }
135
136 if (((*p == ' ') || (*p == '\t')) && (quote == 0))
137 {
138 e = p + 1;
139 break;
140 }
141
142 p++;
143 e = p;
144 }
145
146 *s = e;
147
148 len = p - a;
149 if (len == 0) return NULL;
150
151 out = malloc(len + 1);
152 if (out == NULL) return NULL;
153
154 memcpy(out, a, len);
155 out[len] = '\0';
156 return out;
157 }
158
159 static void
160 _do_reset(void)
161 {
162 pthread_mutex_lock(&reset_lock);
163
164 asl_action_close();
165 _parse_config_file(_PATH_ASL_CONF);
166 reset = RESET_NONE;
167
168 pthread_mutex_unlock(&reset_lock);
169 }
170
171 /*
172 * Config File format:
173 * Set parameter rule - initializes a parameter.
174 * = param args...
175 * Query rule - if a message matches the query, then the action is invoked.
176 * The rule may be identified by either "?" or "Q".
177 * ? [k v] [k v] ... action args...
178 * Q [k v] [k v] ... action args...
179 * Universal match rule - the action is invoked for all messages
180 * * action args...
181 */
182
183 /* Skip over query */
184 static char *
185 _find_action(char *s)
186 {
187 char *p;
188
189 p = s;
190 if (p == NULL) return NULL;
191 if ((*p != 'Q') && (*p != '?') && (*p != '*')) return NULL;
192
193 p++;
194
195 forever
196 {
197 /* Find next [ */
198 while ((*p == ' ') || (*p == '\t')) p++;
199
200 if (*p == '\0') return NULL;
201 if (*p != '[') return p;
202
203 /* skip to closing ] */
204 while (*p != ']')
205 {
206 p++;
207 if (*p == '\\')
208 {
209 p++;
210 if (*p == ']') p++;
211 }
212 }
213
214 if (*p == ']') p++;
215 }
216
217 return NULL;
218 }
219
220 static int
221 _parse_query_action(char *s)
222 {
223 char *act, *p;
224 action_rule_t *out, *rule;
225
226 act = _find_action(s);
227 if (act == NULL) return -1;
228
229 out = (action_rule_t *)calloc(1, sizeof(action_rule_t));
230 if (out == NULL) return -1;
231
232 p = strchr(act, ' ');
233 if (p != NULL) *p = '\0';
234
235 if (!strcasecmp(act, "ignore")) out->action = ACTION_IGNORE;
236 else if (!strcasecmp(act, "notify")) out->action = ACTION_NOTIFY;
237 else if (!strcasecmp(act, "broadcast")) out->action = ACTION_BROADCAST;
238 else if (!strcasecmp(act, "access")) out->action = ACTION_ACCESS;
239 else if (!strcasecmp(act, "store")) out->action = ACTION_STORE;
240 else if (!strcasecmp(act, "save")) out->action = ACTION_STORE;
241 else if (!strcasecmp(act, "store_directory")) out->action = ACTION_STORE_DIR;
242 else if (!strcasecmp(act, "store_dir")) out->action = ACTION_STORE_DIR;
243 else if (!strcasecmp(act, "forward")) out->action = ACTION_FORWARD;
244
245 if (p != NULL)
246 {
247 out->options = strdup(p+1);
248
249 if (out->options == NULL)
250 {
251 free(out);
252 return -1;
253 }
254 }
255
256 p = act - 1;
257
258 *p = '\0';
259
260 if (s[0] == '*') out->query = asl_new(ASL_TYPE_QUERY);
261 else
262 {
263 s[0] = 'Q';
264 out->query = asl_msg_from_string(s);
265 }
266
267 if (out->query == NULL)
268 {
269 asldebug("out->query is NULL (ERROR)\n");
270 if (out->options != NULL) free(out->options);
271 free(out);
272 return -1;
273 }
274
275 if ((out->action == ACTION_STORE) && (out->options == NULL))
276 {
277 asldebug("action = ACTION_STORE options = NULL\n");
278 if (asl_datastore_rule == NULL) asl_datastore_rule = out;
279 else
280 {
281 for (rule = asl_datastore_rule; rule->next != NULL; rule = rule->next);
282 rule->next = out;
283 }
284 }
285 else
286 {
287 asldebug("action = %d options = %s\n", out->action, out->options);
288 if (asl_action_rule == NULL) asl_action_rule = out;
289 else
290 {
291 for (rule = asl_action_rule; rule->next != NULL; rule = rule->next);
292 rule->next = out;
293 }
294 }
295
296 return 0;
297 }
298
299 /*
300 * Used to sed config parameters.
301 * Line format "= name value"
302 */
303 static int
304 _parse_set_param(char *s)
305 {
306 char **l;
307 uint32_t intval, count, v32a, v32b, v32c;
308
309 if (s == NULL) return -1;
310 if (s[0] == '\0') return 0;
311
312 /* skip '=' and whitespace */
313 s++;
314 while ((*s == ' ') || (*s == '\t')) s++;
315
316 l = explode(s, " \t");
317 if (l == NULL) return -1;
318
319 for (count = 0; l[count] != NULL; count++);
320
321 /* name is required */
322 if (count == 0)
323 {
324 freeList(l);
325 return -1;
326 }
327
328 /* value is required */
329 if (count == 1)
330 {
331 freeList(l);
332 return -1;
333 }
334
335 if (!strcasecmp(l[0], "debug"))
336 {
337 /* = debug {0|1} [file] */
338 intval = atoi(l[1]);
339 config_debug(intval, l[2]);
340 }
341 else if (!strcasecmp(l[0], "cutoff"))
342 {
343 /* = cutoff level */
344 intval = atoi(l[1]);
345 if (intval > ASL_LEVEL_DEBUG) intval = ASL_LEVEL_DEBUG;
346 global.asl_log_filter = ASL_FILTER_MASK_UPTO(intval);
347 }
348 else if (!strcasecmp(l[0], "mark_time"))
349 {
350 /* = mark_time seconds */
351 OSSpinLockLock(&global.lock);
352 global.mark_time = atoll(l[1]);
353 OSSpinLockUnlock(&global.lock);
354 }
355 else if (!strcasecmp(l[0], "dup_delay"))
356 {
357 /* = bsd_max_dup_time seconds */
358 OSSpinLockLock(&global.lock);
359 global.bsd_max_dup_time = atoll(l[1]);
360 OSSpinLockUnlock(&global.lock);
361 }
362 else if (!strcasecmp(l[0], "asl_store_ping_time"))
363 {
364 /* NB this is private / unpublished */
365 /* = asl_store_ping_time seconds */
366 OSSpinLockLock(&global.lock);
367 global.asl_store_ping_time = atoll(l[1]);
368 OSSpinLockUnlock(&global.lock);
369 }
370 else if (!strcasecmp(l[0], "utmp_ttl"))
371 {
372 /* = utmp_ttl seconds */
373 OSSpinLockLock(&global.lock);
374 global.utmp_ttl = (time_t)atoll(l[1]);
375 OSSpinLockUnlock(&global.lock);
376 }
377 else if (!strcasecmp(l[0], "fs_ttl"))
378 {
379 /* = fs_ttl seconds */
380 OSSpinLockLock(&global.lock);
381 global.fs_ttl = (time_t)atoll(l[1]);
382 OSSpinLockUnlock(&global.lock);
383 }
384 else if (!strcasecmp(l[0], "mps_limit"))
385 {
386 /* = mps_limit number */
387 OSSpinLockLock(&global.lock);
388 global.mps_limit = (uint32_t)atol(l[1]);
389 OSSpinLockUnlock(&global.lock);
390 }
391 else if (!strcasecmp(l[0], "max_file_size"))
392 {
393 /* = max_file_size bytes */
394 pthread_mutex_lock(global.db_lock);
395
396 if (global.dbtype & DB_TYPE_FILE)
397 {
398 asl_store_close(global.file_db);
399 global.file_db = NULL;
400 global.db_file_max = atoi(l[1]);
401 }
402
403 pthread_mutex_unlock(global.db_lock);
404 }
405 else if ((!strcasecmp(l[0], "db")) || (!strcasecmp(l[0], "database")) || (!strcasecmp(l[0], "datastore")))
406 {
407 /* NB this is private / unpublished */
408 /* = db type [max]... */
409
410 v32a = 0;
411 v32b = 0;
412 v32c = 0;
413
414 if ((l[1][0] >= '0') && (l[1][0] <= '9'))
415 {
416 intval = atoi(l[1]);
417 if ((count >= 3) && (strcmp(l[2], "-"))) v32a = atoi(l[2]);
418 if ((count >= 4) && (strcmp(l[3], "-"))) v32b = atoi(l[3]);
419 if ((count >= 5) && (strcmp(l[4], "-"))) v32c = atoi(l[4]);
420 }
421 else if (!strcasecmp(l[1], "file"))
422 {
423 intval = DB_TYPE_FILE;
424 if ((count >= 3) && (strcmp(l[2], "-"))) v32a = atoi(l[2]);
425 }
426 else if (!strncasecmp(l[1], "mem", 3))
427 {
428 intval = DB_TYPE_MEMORY;
429 if ((count >= 3) && (strcmp(l[2], "-"))) v32b = atoi(l[2]);
430 }
431 else if (!strncasecmp(l[1], "min", 3))
432 {
433 intval = DB_TYPE_MINI;
434 if ((count >= 3) && (strcmp(l[2], "-"))) v32c = atoi(l[2]);
435 }
436 else
437 {
438 freeList(l);
439 return -1;
440 }
441
442 if (v32a == 0) v32a = global.db_file_max;
443 if (v32b == 0) v32b = global.db_memory_max;
444 if (v32c == 0) v32c = global.db_mini_max;
445
446 config_data_store(intval, v32a, v32b, v32c);
447 }
448
449 freeList(l);
450 return 0;
451 }
452
453 static int
454 _parse_line(char *s)
455 {
456 char *str;
457 int status;
458
459 if (s == NULL) return -1;
460 while ((*s == ' ') || (*s == '\t')) s++;
461
462 /* First non-whitespace char is the rule type */
463 switch (*s)
464 {
465 case '\0':
466 case '#':
467 {
468 /* Blank Line or Comment */
469 return 0;
470 }
471 case 'Q':
472 case '?':
473 case '*':
474 {
475 /* Query-match action */
476 status = _parse_query_action(s);
477 break;
478 }
479 case '=':
480 {
481 /* Set parameter */
482 status = _parse_set_param(s);
483 break;
484 }
485 default:
486 {
487 status = -1;
488 break;
489 }
490 }
491
492 if (status != 0)
493 {
494 str = NULL;
495 asprintf(&str, "[%s syslogd] [%s %u] [%s %u] [%s Ignoring unrecognized entry in %s: %s] [%s 0] [%s 0] [Facility syslog]",
496 ASL_KEY_SENDER,
497 ASL_KEY_LEVEL, ASL_LEVEL_ERR,
498 ASL_KEY_PID, getpid(),
499 ASL_KEY_MSG, _PATH_ASL_CONF, s,
500 ASL_KEY_UID, ASL_KEY_GID);
501
502 asl_log_string(str);
503 if (str != NULL) free(str);
504 }
505
506 return status;
507 }
508
509 static void
510 _act_notify(action_rule_t *r)
511 {
512 if (r == NULL) return;
513 if (r->options == NULL) return;
514
515 notify_post(r->options);
516 }
517
518 static void
519 _act_broadcast(action_rule_t *r, asl_msg_t *msg)
520 {
521 FILE *pw;
522 const char *val;
523
524 if (r == NULL) return;
525 if (msg == NULL) return;
526
527 val = r->options;
528 if (val == NULL) val = asl_get(msg, ASL_KEY_MSG);
529 if (val == NULL) return;
530
531 pw = popen(_PATH_WALL, "w");
532 if (pw < 0)
533 {
534 asldebug("%s: error sending wall message: %s\n", MY_ID, strerror(errno));
535 return;
536 }
537
538 fprintf(pw, "%s", val);
539 pclose(pw);
540 }
541
542 static void
543 _act_access_control(action_rule_t *r, asl_msg_t *msg)
544 {
545 int32_t ruid, rgid;
546 char *p;
547
548 ruid = atoi(r->options);
549 rgid = -1;
550 p = strchr(r->options, ' ');
551 if (p == NULL) p = strchr(r->options, '\t');
552 if (p != NULL)
553 {
554 *p = '\0';
555 p++;
556 rgid = atoi(p);
557 }
558
559 if (ruid != -1) asl_set((aslmsg)msg, ASL_KEY_READ_UID, r->options);
560 if (p != NULL)
561 {
562 if (rgid != -1) asl_set((aslmsg)msg, ASL_KEY_READ_GID, p);
563 p--;
564 *p = ' ';
565 }
566 }
567
568 static uint32_t
569 _act_store_file_setup(struct store_data *sd)
570 {
571 uint32_t status;
572
573 if (sd == NULL) return ASL_STATUS_INVALID_STORE;
574 if (sd->store == NULL) return ASL_STATUS_INVALID_STORE;
575 if (sd->store->store == NULL) return ASL_STATUS_INVALID_STORE;
576
577 status = asl_file_read_set_position(sd->store, ASL_FILE_POSITION_LAST);
578 if (status != ASL_STATUS_OK) return status;
579
580 sd->next_id = sd->store->cursor_xid + 1;
581 if (fseek(sd->store->store, 0, SEEK_END) != 0) return ASL_STATUS_ACCESS_DENIED;
582
583 return ASL_STATUS_OK;
584 }
585
586 static uint32_t
587 _act_store_dir_setup(struct store_data *sd, time_t tick)
588 {
589 struct tm ctm;
590 char *path;
591 struct stat sb;
592 uint64_t xid;
593 int status;
594
595 if (sd == NULL) return ASL_STATUS_INVALID_STORE;
596 if (sd->dir == NULL) return ASL_STATUS_INVALID_STORE;
597
598 /* get / set message id from StoreData file */
599 xid = 0;
600
601 if (sd->storedata == NULL)
602 {
603 path = NULL;
604 asprintf(&path, "%s/%s", sd->dir, FILE_ASL_STORE_DATA);
605 if (path == NULL) return ASL_STATUS_NO_MEMORY;
606
607 memset(&sb, 0, sizeof(struct stat));
608 status = stat(path, &sb);
609 if (status == 0)
610 {
611 /* StoreData exists: open and read last xid */
612 sd->storedata = fopen(path, "r+");
613 if (sd->storedata == NULL)
614 {
615 free(path);
616 return ASL_STATUS_FAILED;
617 }
618
619 if (fread(&xid, sizeof(uint64_t), 1, sd->storedata) != 1)
620 {
621 free(path);
622 fclose(sd->storedata);
623 sd->storedata = NULL;
624 return ASL_STATUS_READ_FAILED;
625 }
626 }
627 else if (errno != ENOENT)
628 {
629 /* Unexpected stat error */
630 free(path);
631 return ASL_STATUS_FAILED;
632 }
633 else
634 {
635 /* StoreData does not exist: create it */
636 sd->storedata = fopen(path, "w");
637 if (sd->storedata == NULL)
638 {
639 free(path);
640 return ASL_STATUS_FAILED;
641 }
642 }
643
644 free(path);
645 }
646 else
647 {
648 rewind(sd->storedata);
649 if (fread(&xid, sizeof(uint64_t), 1, sd->storedata) != 1)
650 {
651 fclose(sd->storedata);
652 sd->storedata = NULL;
653 return ASL_STATUS_READ_FAILED;
654 }
655 }
656
657 xid = asl_core_ntohq(xid);
658 xid++;
659 sd->next_id = xid;
660
661 xid = asl_core_htonq(xid);
662 rewind(sd->storedata);
663 status = fwrite(&xid, sizeof(uint64_t), 1, sd->storedata);
664 if (status != 1)
665 {
666 fclose(sd->storedata);
667 sd->storedata = NULL;
668 return ASL_STATUS_WRITE_FAILED;
669 }
670
671 if ((sd->flags & ACT_STORE_FLAG_STAY_OPEN) == 0)
672 {
673 fclose(sd->storedata);
674 sd->storedata = NULL;
675 }
676
677 memset(&ctm, 0, sizeof(struct tm));
678
679 if (localtime_r((const time_t *)&tick, &ctm) == NULL) return ASL_STATUS_FAILED;
680 if ((sd->p_year == ctm.tm_year) && (sd->p_month == ctm.tm_mon) && (sd->p_day == ctm.tm_mday) && (sd->path != NULL)) return ASL_STATUS_OK;
681
682 if (sd->store != NULL) asl_file_close(sd->store);
683
684 sd->p_year = 0;
685 sd->p_month = 0;
686 sd->p_day = 0;
687
688 if (sd->path != NULL) free(sd->path);
689 sd->path = NULL;
690
691 asprintf(&(sd->path), "%s/%d.%02d.%02d.asl", sd->dir, ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
692 if (sd->path == NULL) return ASL_STATUS_NO_MEMORY;
693
694 sd->p_year = ctm.tm_year;
695 sd->p_month = ctm.tm_mon;
696 sd->p_day = ctm.tm_mday;
697
698 return ASL_STATUS_OK;
699 }
700
701 static void
702 _act_store(action_rule_t *r, asl_msg_t *msg)
703 {
704 struct store_data *sd;
705 asl_file_t *s;
706 uint8_t x;
707 uint32_t status;
708 uint64_t mid;
709 mode_t tmp_mode;
710 char *str, *opts, *p;
711 const char *val;
712 time_t tick;
713
714 s = NULL;
715
716 /* _act_store is not used for the main ASL data store */
717 if (r->options == NULL) return;
718
719 if (r->data == NULL)
720 {
721 /* set up store data */
722 sd = (struct store_data *)calloc(1, sizeof(struct store_data));
723 if (sd == NULL) return;
724
725 opts = r->options;
726 sd->store = NULL;
727
728 if (r->action == ACTION_STORE)
729 {
730 sd->path = _next_word(&opts);
731 if (sd->path == NULL)
732 {
733 free(sd);
734 r->action = ACTION_NONE;
735 return;
736 }
737 }
738 else if (r->action == ACTION_STORE_DIR)
739 {
740 sd->dir = _next_word(&opts);
741 if (sd->dir == NULL)
742 {
743 free(sd);
744 r->action = ACTION_NONE;
745 return;
746 }
747 }
748
749 sd->mode = 0644;
750 sd->next_id = 0;
751 sd->uid = 0;
752 sd->gid = 0;
753 sd->flags = 0;
754
755 while (NULL != (p = _next_word(&opts)))
756 {
757 if (!strcmp(p, "stayopen")) sd->flags |= ACT_STORE_FLAG_STAY_OPEN;
758 else if (!strcmp(p, "exclude_asldb")) sd->flags |= ACT_STORE_FLAG_EXCLUDE_ASLDB;
759 else if (!strncmp(p, "mode=0", 6))
760 {
761 sd->mode = 0;
762 x = *(p + 6);
763 if ((x < '0') || (x > '7'))
764 {
765 free(p);
766 if (sd->path != NULL) free(sd->path);
767 if (sd->dir != NULL) free(sd->dir);
768 free(sd);
769 r->action = ACTION_NONE;
770 return;
771 }
772
773 tmp_mode = x - '0';
774 sd->mode += tmp_mode << 6;
775
776 x = *(p + 7);
777 if ((x < '0') || (x > '7'))
778 {
779 free(p);
780 if (sd->path != NULL) free(sd->path);
781 if (sd->dir != NULL) free(sd->dir);
782 free(sd);
783 r->action = ACTION_NONE;
784 return;
785 }
786
787 tmp_mode = x - '0';
788 sd->mode += tmp_mode << 3;
789
790 x = *(p + 8);
791 if ((x < '0') || (x > '7'))
792 {
793 free(p);
794 if (sd->path != NULL) free(sd->path);
795 if (sd->dir != NULL) free(sd->dir);
796 free(sd);
797 r->action = ACTION_NONE;
798 return;
799 }
800
801 tmp_mode = x - '0';
802 sd->mode += tmp_mode;
803 }
804 else if (!strncmp(p, "mode=", 5)) sd->mode = atoi(p+4);
805 else if (!strncmp(p, "uid=", 4)) sd->uid = atoi(p+4);
806 else if (!strncmp(p, "gid=", 4)) sd->gid = atoi(p+4);
807
808 free(p);
809 p = NULL;
810 }
811
812 r->data = sd;
813 }
814 else
815 {
816 sd = (struct store_data *)r->data;
817 }
818
819 if (r->action == ACTION_STORE_DIR)
820 {
821 val = asl_get(msg, ASL_KEY_TIME);
822 if (val == NULL) return;
823
824 tick = atol(val);
825 status = _act_store_dir_setup(sd, tick);
826 if (status != ASL_STATUS_OK)
827 {
828 asldebug("_act_store_dir_setup %s failed: %s\n", sd->path, asl_core_error(status));
829
830 /* disable further activity */
831 asl_file_close(sd->store);
832 sd->store = NULL;
833 r->action = ACTION_NONE;
834 return;
835 }
836 }
837
838 if (sd->store == NULL)
839 {
840 s = NULL;
841 status = asl_file_open_write(sd->path, sd->mode, sd->uid, sd->gid, &s);
842 if ((status != ASL_STATUS_OK) || (s == NULL))
843 {
844 asldebug("asl_file_open_write %s failed: %s\n", sd->path, asl_core_error(status));
845
846 /* disable further activity */
847 asl_file_close(sd->store);
848 sd->store = NULL;
849 r->action = ACTION_NONE;
850 return;
851 }
852
853 sd->store = s;
854 }
855
856 if (r->action != ACTION_STORE_DIR)
857 {
858 status = _act_store_file_setup(sd);
859 if (status != ASL_STATUS_OK)
860 {
861 asldebug("_act_store_file_setup %s failed: %s\n", sd->path, asl_core_error(status));
862
863 /* disable further activity */
864 asl_file_close(sd->store);
865 sd->store = NULL;
866 r->action = ACTION_NONE;
867 return;
868 }
869 }
870
871 mid = sd->next_id;
872
873 status = asl_file_save(sd->store, msg, &mid);
874 if (status != ASL_STATUS_OK)
875 {
876 asldebug("asl_file_save %s failed: %s\n", sd->path, asl_core_error(status));
877
878 /* disable further activity on this file */
879 asl_file_close(sd->store);
880 sd->store = NULL;
881 r->action = ACTION_NONE;
882 return;
883 }
884
885 if ((sd->flags & ACT_STORE_FLAG_STAY_OPEN) == 0)
886 {
887 asl_file_close(sd->store);
888 sd->store = NULL;
889 }
890
891 if (sd->flags & ACT_STORE_FLAG_EXCLUDE_ASLDB)
892 {
893 opts = (char *)asl_get(msg, ASL_KEY_OPTION);
894 if (opts == NULL)
895 {
896 asl_set(msg, ASL_KEY_OPTION, ASL_OPT_IGNORE);
897 }
898 else
899 {
900 str = NULL;
901 asprintf(&str, "%s %s", ASL_OPT_IGNORE, opts);
902 if (str != NULL)
903 {
904 asl_set(msg, ASL_KEY_OPTION, str);
905 free(str);
906 }
907 }
908 }
909 }
910
911 static void
912 _act_forward(action_rule_t *r, asl_msg_t *msg)
913 {
914 /* To do: <rdar://problem/6130747> Add a "forward" action to asl.conf */
915 }
916
917 static void
918 send_to_asl_store(asl_msg_t *msg)
919 {
920 const char *vlevel, *val;
921 uint64_t v64;
922 uint32_t status, level, lmask;
923 int x, log_me;
924 action_rule_t *r;
925
926 /* ASLOption "ignore" keeps a message out of the ASL datastore */
927 if (asl_check_option(msg, ASL_OPT_IGNORE) != 0) return;
928
929 if (filter_token == -1)
930 {
931 /* set up com.apple.syslog.asl_filter */
932 status = notify_register_check(NOTIFY_SYSTEM_ASL_FILTER, &filter_token);
933 if (status != NOTIFY_STATUS_OK)
934 {
935 filter_token = -1;
936 }
937 else
938 {
939 status = notify_check(filter_token, &x);
940 if (status == NOTIFY_STATUS_OK)
941 {
942 v64 = global.asl_log_filter;
943 status = notify_set_state(filter_token, v64);
944 }
945 if (status != NOTIFY_STATUS_OK)
946 {
947 notify_cancel(filter_token);
948 filter_token = -1;
949 }
950 }
951 }
952
953 /* ASLOption "store" forces a message to be saved */
954 log_me = asl_check_option(msg, ASL_OPT_STORE);
955 if (log_me == 1)
956 {
957 db_save_message(msg);
958 return;
959 }
960
961 log_me = 0;
962 if (filter_token >= 0)
963 {
964 x = 0;
965 status = notify_check(filter_token, &x);
966 if ((status == NOTIFY_STATUS_OK) && (x == 1))
967 {
968 v64 = 0;
969 status = notify_get_state(filter_token, &v64);
970 if ((status == NOTIFY_STATUS_OK) && (v64 != 0)) global.asl_log_filter = v64;
971 }
972 }
973
974 /* PID 0 (kernel) or PID 1 (launchd) messages are saved */
975 val = asl_get(msg, ASL_KEY_PID);
976 if ((val != NULL) && (atoi(val) <= 1)) log_me = 1;
977 else
978 {
979 vlevel = asl_get(msg, ASL_KEY_LEVEL);
980 level = 7;
981 if (vlevel != NULL) level = atoi(vlevel);
982 lmask = ASL_FILTER_MASK(level);
983 if ((lmask & global.asl_log_filter) != 0) log_me = 1;
984 }
985
986 if (log_me == 0) return;
987
988 /* if there are no rules, save the message */
989 if (asl_datastore_rule == NULL)
990 {
991 db_save_message(msg);
992 return;
993 }
994
995 for (r = asl_datastore_rule; r != NULL; r = r->next)
996 {
997 if (asl_msg_cmp(r->query, msg) == 1)
998 {
999 /* if any rule matches, save the message (once!) */
1000 db_save_message(msg);
1001 return;
1002 }
1003 }
1004 }
1005
1006 int
1007 asl_action_sendmsg(asl_msg_t *msg, const char *outid)
1008 {
1009 action_rule_t *r;
1010
1011 if (reset == RESET_CONFIG) _do_reset();
1012
1013 if (msg == NULL) return -1;
1014
1015 for (r = asl_action_rule; r != NULL; r = r->next)
1016 {
1017 if (asl_msg_cmp(r->query, msg) == 1)
1018 {
1019 if (r->action == ACTION_NONE) continue;
1020 else if (r->action == ACTION_IGNORE) return 0;
1021 else if (r->action == ACTION_ACCESS) _act_access_control(r, msg);
1022 else if (r->action == ACTION_NOTIFY) _act_notify(r);
1023 else if (r->action == ACTION_STORE) _act_store(r, msg);
1024 else if (r->action == ACTION_STORE_DIR) _act_store(r, msg);
1025 else if (r->action == ACTION_BROADCAST) _act_broadcast(r, msg);
1026 else if (r->action == ACTION_FORWARD) _act_forward(r, msg);
1027 }
1028 }
1029
1030 send_to_asl_store(msg);
1031
1032 return 0;
1033 }
1034
1035 static int
1036 _parse_config_file(const char *name)
1037 {
1038 FILE *cf;
1039 char *line;
1040
1041 cf = fopen(name, "r");
1042 if (cf == NULL) return 1;
1043
1044 while (NULL != (line = get_line_from_file(cf)))
1045 {
1046 _parse_line(line);
1047 free(line);
1048 }
1049
1050 fclose(cf);
1051
1052 return 0;
1053 }
1054
1055 int
1056 asl_action_init(void)
1057 {
1058 asldebug("%s: init\n", MY_ID);
1059
1060 query = asl_new(ASL_TYPE_QUERY);
1061 aslevent_addmatch(query, MY_ID);
1062 aslevent_addoutput(asl_action_sendmsg, MY_ID);
1063
1064 _parse_config_file(_PATH_ASL_CONF);
1065 return 0;
1066 }
1067
1068 int
1069 asl_action_reset(void)
1070 {
1071 reset = global.reset;
1072 return 0;
1073 }
1074
1075 int
1076 asl_action_close(void)
1077 {
1078 action_rule_t *r, *n;
1079 struct store_data *sd;
1080 n = NULL;
1081 for (r = asl_action_rule; r != NULL; r = n)
1082 {
1083 n = r->next;
1084
1085 if (((r->action == ACTION_STORE) || (r->action == ACTION_STORE_DIR) || (r->action == ACTION_NONE)) && (r->data != NULL))
1086 {
1087 sd = (struct store_data *)r->data;
1088 if (sd->store != NULL) asl_file_close(sd->store);
1089 if (sd->storedata != NULL) fclose(sd->storedata);
1090 if (sd->path != NULL) free(sd->path);
1091 if (sd->dir != NULL) free(sd->dir);
1092 sd->store = NULL;
1093 free(sd);
1094 }
1095
1096 if (r->query != NULL) asl_free(r->query);
1097 if (r->options != NULL) free(r->options);
1098
1099 free(r);
1100 }
1101
1102 asl_action_rule = NULL;
1103
1104 n = NULL;
1105 for (r = asl_datastore_rule; r != NULL; r = n)
1106 {
1107 n = r->next;
1108
1109 if (r->query != NULL) asl_free(r->query);
1110 if (r->options != NULL) free(r->options);
1111
1112 free(r);
1113 }
1114
1115 asl_datastore_rule = NULL;
1116
1117 return 0;
1118 }