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