]> git.saurik.com Git - apple/syslog.git/blame - syslogd.tproj/daemon.c
syslog-13.tar.gz
[apple/syslog.git] / syslogd.tproj / daemon.c
CommitLineData
b16a592a
A
1/*
2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 2004 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25#include <sys/types.h>
26#include <sys/socket.h>
27#include <sys/un.h>
28#include <sys/ucred.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <unistd.h>
33#include <sys/queue.h>
34#include <netinet/in.h>
35#include <arpa/inet.h>
36#define SYSLOG_NAMES
37#include <syslog.h>
38#include "daemon.h"
39
40#define streq(A,B) (strcmp(A,B)==0)
41
42static char myname[MAXHOSTNAMELEN + 1] = {0};
43static int gotname = 0;
44
45struct aslevent
46{
47 int fd;
48 unsigned char read:1;
49 unsigned char write:1;
50 unsigned char except:1;
51 aslreadfn readfn;
52 aslwritefn writefn;
53 aslexceptfn exceptfn;
54 char *sender;
55 uid_t uid;
56 gid_t gid;
57 TAILQ_ENTRY(aslevent) entries;
58};
59
60struct asloutput
61{
62 aslsendmsgfn sendmsg;
63 const char *outid;
64 TAILQ_ENTRY(asloutput) entries;
65};
66
67struct aslmatch
68{
69 char *outid;
70 asl_msg_t *query;
71 TAILQ_ENTRY(aslmatch) entries;
72};
73
74TAILQ_HEAD(ae, aslevent) Eventq;
75TAILQ_HEAD(ao, asloutput) Outq;
76TAILQ_HEAD(am, aslmatch) Matchq;
77
78int
79aslevent_init(void)
80{
81 TAILQ_INIT(&Eventq);
82 TAILQ_INIT(&Outq);
83 TAILQ_INIT(&Matchq);
84
85 return 0;
86}
87
88int
89aslevent_log(asl_msg_t *msg, char *outid)
90{
91 struct asloutput *i;
92 int status = -1;
93
94 for (i = Outq.tqh_first; i != NULL; i = i->entries.tqe_next)
95 {
96 if ((outid != NULL) && (strcmp(i->outid, outid) == 0))
97 {
98 status = i->sendmsg(msg, outid);
99 }
100 }
101
102 return status;
103}
104
105int
106aslevent_addmatch(asl_msg_t *query, char *outid)
107{
108 struct aslmatch *tmp;
109
110 if (query == NULL) return -1;
111 if (outid == NULL) return -1;
112
113 tmp = calloc(1, sizeof(struct aslmatch));
114 if (tmp == NULL) return -1;
115 tmp->query = query;
116 tmp->outid = outid;
117 TAILQ_INSERT_TAIL(&Matchq, tmp, entries);
118
119 return 0;
120}
121
122void
123aslevent_match(asl_msg_t *msg)
124{
125 struct aslmatch *i;
126
127 if (msg == NULL) return;
128
129 for (i = Matchq.tqh_first; i != NULL; i = i->entries.tqe_next)
130 {
131 if (asl_msg_cmp(i->query, msg) != 0)
132 {
133 aslevent_log(msg, i->outid);
134 }
135 }
136}
137
138int
139aslevent_removefd(int fd)
140{
141 struct aslevent *i;
142 int found = -1;
143
144 for (i = Eventq.tqh_first; i != NULL; i = i->entries.tqe_next)
145 {
146 if (fd == i->fd)
147 {
148 asldebug("removing %d\n", i->fd);
149 TAILQ_REMOVE(&Eventq, i, entries);
150 found = 0;
151 if (i->sender != NULL) free(i->sender);
152 free(i);
153 i = NULL;
154 return 0;
155 }
156 }
157
158 return -1;
159}
160
161const char *
162whatsmyhostname()
163{
164 char *dot;
165
166 if (gotname != 0) return (const char *)myname;
167
168 if (gethostname(myname, MAXHOSTNAMELEN) < 0)
169 {
170 memset(myname, 0, sizeof(myname));
171 return "localhost";
172 }
173
174 if (strcmp(myname, "localhost")) gotname = 1;
175
176 dot = strchr(myname, '.');
177 if (dot != NULL) *dot = '\0';
178
179 return (const char *)myname;
180}
181
182int
183aslevent_addfd(int fd, aslreadfn readfn, aslwritefn writefn, aslexceptfn exceptfn)
184{
185 struct aslevent *e;
186 int found = 0;
187#ifdef LOCAL_PEERCRED
188 struct xucred cr;
189#endif
190 int len;
191 uid_t u;
192 gid_t g;
193 struct sockaddr_storage ss;
194 char *sender, str[256];
195
196 u = 99;
197 g = 99;
198 sender = NULL;
199
200 memset(&ss, 0, sizeof(struct sockaddr_storage));
201
202 len = sizeof(struct sockaddr_storage);
203
204 if (getpeername(fd, (struct sockaddr *)&ss, &len) == 0)
205 {
206 if (len == 0)
207 {
208 /* UNIX Domain socket */
209 snprintf(str, sizeof(str), whatsmyhostname());
210 sender = str;
211 }
212 else
213 {
214 if (inet_ntop(ss.ss_family, (struct sockaddr *)&ss, str, 256) == 0) sender = str;
215 }
216 }
217
218#ifdef LOCAL_PEERCRED
219 len = sizeof(cr);
220
221 if (getsockopt(fd, LOCAL_PEERCRED, 1, &cr, &len) == 0)
222 {
223 u = cr.cr_uid;
224 g = cr.cr_gid;
225 }
226#endif
227
228 asldebug("fd %d UID %d GID %d Sender %s\n", fd, u, g, (sender == NULL) ? "NULL" : sender );
229
230 for (e = Eventq.tqh_first; e != NULL; e = e->entries.tqe_next)
231 {
232 if (fd == e->fd)
233 {
234 e->readfn = readfn;
235 e->writefn = writefn;
236 e->exceptfn = exceptfn;
237 if (e->sender != NULL) free(e->sender);
238 e->sender = NULL;
239 if (sender != NULL) e->sender = strdup(sender);
240 e->uid = u;
241 e->gid = g;
242 found = 1;
243 }
244 }
245
246 if (found) return 0;
247
248 e = calloc(1, sizeof(struct aslevent));
249 if (e == NULL) return -1;
250
251 e->fd = fd;
252 e->readfn = readfn;
253 e->writefn = writefn;
254 e->exceptfn = exceptfn;
255 e->sender = NULL;
256 if (sender != NULL) e->sender = strdup(sender);
257 e->uid = u;
258 e->gid = g;
259
260 TAILQ_INSERT_TAIL(&Eventq, e, entries);
261
262 return 0;
263}
264
265int
266aslmsg_verify(struct aslevent *e, asl_msg_t *msg)
267{
268 const char *val;
269 char buf[32], *timestr;
270 time_t tick;
271 struct tm gtime;
272
273 if (msg == NULL) return -1;
274
275 /* Time */
276 tick = 0;
277 val = asl_get(msg, ASL_KEY_TIME);
278 if (val != NULL) tick = asl_parse_time(val);
279
280 if (tick == 0) tick = time(NULL);
281 memset(&gtime, 0, sizeof(struct tm));
282 gmtime_r(&tick, &gtime);
283
284 /* Canonical form: YYYY.MM.DD hh:mm:ss UTC */
285 asprintf(&timestr, "%d.%02d.%02d %02d:%02d:%02d UTC", gtime.tm_year + 1900, gtime.tm_mon + 1, gtime.tm_mday, gtime.tm_hour, gtime.tm_min, gtime.tm_sec);
286 if (timestr != NULL)
287 {
288 asl_set(msg, ASL_KEY_TIME, timestr);
289 free(timestr);
290 }
291
292 /* Host */
293 if (e == NULL) asl_set(msg, ASL_KEY_HOST, whatsmyhostname());
294 else if (e->sender != NULL) asl_set(msg, ASL_KEY_HOST, e->sender);
295
296 /* Sender */
297 val = asl_get(msg, ASL_KEY_SENDER);
298 if (val == NULL) asl_set(msg, ASL_KEY_SENDER, "Unknown");
299
300 /* PID */
301 val = asl_get(msg, ASL_KEY_PID);
302 if (val == NULL) asl_set(msg, ASL_KEY_PID, "0");
303
304 /* UID */
305 val = asl_get(msg, ASL_KEY_UID);
306 if (val == NULL)
307 {
308 if (e == NULL) asl_set(msg, ASL_KEY_UID, "-2");
309 else if (e->uid == 99) asl_set(msg, ASL_KEY_UID, "-2");
310 else
311 {
312 snprintf(buf, sizeof(buf), "%d", e->uid);
313 asl_set(msg, ASL_KEY_UID, buf);
314 }
315 }
316 else if ((e != NULL) && (e->uid != 99))
317 {
318 snprintf(buf, sizeof(buf), "%d", e->uid);
319 asl_set(msg, ASL_KEY_UID, buf);
320 }
321
322 /* GID */
323 val = asl_get(msg, ASL_KEY_GID);
324 if (val == NULL)
325 {
326 if (e == NULL) asl_set(msg, ASL_KEY_GID, "-2");
327 else if (e->gid == 99) asl_set(msg, ASL_KEY_GID, "-2");
328 else
329 {
330 snprintf(buf, sizeof(buf), "%d", e->gid);
331 asl_set(msg, ASL_KEY_GID, buf);
332 }
333 }
334 else if ((e != NULL) && (e->gid != 99))
335 {
336 snprintf(buf, sizeof(buf), "%d", e->gid);
337 asl_set(msg, ASL_KEY_GID, buf);
338 }
339
340 /* Level */
341 val = asl_get(msg, ASL_KEY_LEVEL);
342 if (val == NULL) asl_set(msg, ASL_KEY_LEVEL, "7");
343
344 return 0;
345}
346
347int
348aslevent_addoutput(aslsendmsgfn fn, const char *outid)
349{
350 struct asloutput *tmp;
351
352 tmp = calloc(1, sizeof(struct asloutput));
353 if (tmp == NULL) return -1;
354
355 tmp->sendmsg = fn;
356 tmp->outid = outid;
357
358 TAILQ_INSERT_TAIL(&Outq, tmp, entries);
359
360 return 0;
361}
362
363int
364aslevent_fdsets(fd_set *rd, fd_set *wr, fd_set *ex)
365{
366 struct aslevent *e;
367 int status = 0;
368
369 asldebug("--> aslevent_fdsets\n");
370 FD_ZERO(rd);
371 FD_ZERO(wr);
372 FD_ZERO(ex);
373
374 for (e = Eventq.tqh_first; e != NULL; e = e->entries.tqe_next)
375 {
376 asldebug("adding fd %d\n", e->fd);
377 if (e->readfn)
378 {
379 FD_SET(e->fd, rd);
380 status = MAX(e->fd, status);
381 }
382
383 if (e->writefn)
384 {
385 FD_SET(e->fd, wr);
386 status = MAX(e->fd, status);
387 }
388
389 if (e->exceptfn)
390 {
391 FD_SET(e->fd, ex);
392 status = MAX(e->fd, status);
393 }
394 }
395
396 asldebug("<--aslevent_fdsets\n");
397 return status;
398}
399
400void
401aslevent_handleevent(fd_set rd, fd_set wr, fd_set ex, char *errstr)
402{
403 struct aslevent *e;
404 char *out = NULL;
405 asl_msg_t *msg;
406
407 asldebug("--> aslevent_handleevent\n");
408 if (errstr) errstr = NULL;
409
410 for (e = Eventq.tqh_first; e != NULL; e = e->entries.tqe_next)
411 {
412 if (FD_ISSET(e->fd, &rd) && (e->readfn != NULL))
413 {
414 asldebug("handling read event on %d\n", e->fd);
415 msg = e->readfn(e->fd);
416 if (msg == NULL)
417 {
418 asldebug("error reading message\n");
419 continue;
420 }
421
422 if (aslmsg_verify(e, msg) < 0)
423 {
424 asl_free(msg);
425 asldebug("recieved invalid message\n");
426 }
427 else
428 {
429 aslevent_match(msg);
430 asl_free(msg);
431 }
432 }
433
434 if (FD_ISSET(e->fd, &ex) && e->exceptfn)
435 {
436 asldebug("handling except event on %d\n", e->fd);
437 out = e->exceptfn(e->fd);
438 if (out == NULL) asldebug("error writing message\n");
439 }
440 }
441
442 asldebug("<-- aslevent_handleevent\n");
443}
444
445int
446asl_log_string(const char *str)
447{
448 asl_msg_t *msg;
449
450 if (str == NULL) return 1;
451
452 msg = asl_msg_from_string(str);
453 if (aslmsg_verify(NULL, msg) < 0)
454 {
455 asl_free(msg);
456 return -1;
457 }
458
459 aslevent_match(msg);
460 asl_free(msg);
461 return 0;
462}
463
464void
465aslmark(void)
466{
467 char *str;
468
469 str = NULL;
470 asprintf(&str, "[%s syslogd] [%s %u] [%s %u] [%s -- MARK --] [%s 0] [%s 0] [Facility syslog]",
471 ASL_KEY_SENDER,
472 ASL_KEY_LEVEL, ASL_LEVEL_INFO,
473 ASL_KEY_PID, getpid(),
474 ASL_KEY_MSG, ASL_KEY_UID, ASL_KEY_GID);
475
476 asl_log_string(str);
477 if (str != NULL) free(str);
478}
479
480asl_msg_t *
481asl_syslog_input_convert(const char *in, int len, char *rhost, int kern)
482{
483 int pf, pri, index, n;
484 char *p, *colon, *brace, *tmp, *tval, *sval, *pval, *mval;
485 char prival[8];
486 const char *fval;
487 asl_msg_t *msg;
488 struct tm time;
489 time_t tick;
490
491 if (in == NULL) return NULL;
492 if (len <= 0) return NULL;
493
494 asldebug("asl_syslog_input_convert: %s\n", in);
495
496 pri = LOG_DEBUG;
497 tval = NULL;
498 sval = NULL;
499 pval = NULL;
500 mval = NULL;
501 fval = NULL;
502
503 index = 0;
504 p = (char *)in;
505
506 while ((index < len) && ((*p == ' ') || (*p == '\t')))
507 {
508 p++;
509 index++;
510 }
511
512 if (index >= len) return NULL;
513
514 if (*p == '<')
515 {
516 p++;
517 index++;
518
519 n = sscanf(p, "%d", &pf);
520 if (n == 1)
521 {
522 pri = pf & 0x7;
523 if (pf > 0x7) fval = asl_syslog_faciliy_num_to_name(pf & LOG_FACMASK);
524 }
525
526 while ((index < len) && (*p != '>'))
527 {
528 p++;
529 index++;
530 }
531
532 if (index < len)
533 {
534 p++;
535 index++;
536 }
537 }
538
539 snprintf(prival, sizeof(prival), "%d", pri);
540
541 if (((len - index) > 15) && (p[9] == ':') && (p[12] == ':') && (p[15] == ' '))
542 {
543 tmp = malloc(16);
544 memcpy(tmp, p, 15);
545 tmp[15] = '\0';
546
547 tick = asl_parse_time(tmp);
548 if (tick == (time_t)-1)
549 {
550 tval = tmp;
551 }
552 else
553 {
554 free(tmp);
555 gmtime_r(&tick, &time);
556 asprintf(&tval, "%d.%02d.%02d %02d:%02d:%02d UTC", time.tm_year + 1900, time.tm_mon + 1, time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec);
557 }
558
559 p += 16;
560 index += 16;
561 }
562
563 if (kern != 0)
564 {
565 msg = (asl_msg_t *)calloc(1, sizeof(asl_msg_t));
566 msg->type = ASL_TYPE_MSG;
567
568 asl_set(msg, ASL_KEY_SENDER, "kernel");
569
570 asl_set(msg, "Facility", "kern");
571 if (tval != NULL)
572 {
573 asl_set(msg, ASL_KEY_TIME, tval);
574 free(tval);
575 }
576
577 asl_set(msg, ASL_KEY_MSG, p);
578
579 asl_set(msg, ASL_KEY_LEVEL, prival);
580
581 asl_set(msg, ASL_KEY_PID, "0");
582
583 asl_set(msg, ASL_KEY_UID, "0");
584
585 asl_set(msg, ASL_KEY_GID, "0");
586
587 asl_set(msg, ASL_KEY_HOST, whatsmyhostname());
588
589 return msg;
590 }
591
592 colon = strchr(p, ':');
593 brace = strchr(p, '[');
594
595 if (colon != NULL)
596 {
597 if ((brace != NULL) && (brace < colon))
598 {
599 n = brace - p;
600 sval = malloc(n + 1);
601 memcpy(sval, p, n);
602 sval[n] = '\0';
603
604 n = colon - (brace + 1) - 1;
605 pval = malloc(n + 1);
606 memcpy(pval, (brace + 1), n);
607 pval[n] = '\0';
608 }
609 else
610 {
611 n = colon - p;
612 sval = malloc(n + 1);
613 memcpy(sval, p, n);
614 sval[n] = '\0';
615 }
616
617 n = colon - p;
618 p = colon + 1;
619 index += (n + 1);
620 }
621
622 if (*p == ' ')
623 {
624 p++;
625 index++;
626 }
627
628 n = len - index;
629 if (n > 0)
630 {
631 mval = malloc(n + 1);
632 memcpy(mval, p, n);
633 mval[n] = '\0';
634 }
635
636 if (fval == NULL) fval = asl_syslog_faciliy_num_to_name(LOG_USER);
637
638 msg = (asl_msg_t *)calloc(1, sizeof(asl_msg_t));
639 msg->type = ASL_TYPE_MSG;
640
641 if (tval != NULL)
642 {
643 asl_set(msg, ASL_KEY_TIME, tval);
644 free(tval);
645 }
646
647 if (fval != NULL) asl_set(msg, "Facility", fval);
648 else asl_set(msg, "Facility", "user");
649
650 if (sval != NULL)
651 {
652 asl_set(msg, ASL_KEY_SENDER, sval);
653 free(sval);
654 }
655
656 if (pval != NULL)
657 {
658 asl_set(msg, ASL_KEY_PID, pval);
659 free(pval);
660 }
661 else asl_set(msg, ASL_KEY_PID, "-1");
662
663 if (mval != NULL)
664 {
665 asl_set(msg, ASL_KEY_MSG, mval);
666 free(mval);
667 }
668
669 asl_set(msg, ASL_KEY_LEVEL, prival);
670 asl_set(msg, ASL_KEY_UID, "-2");
671 asl_set(msg, ASL_KEY_GID, "-2");
672
673 if (rhost == NULL) asl_set(msg, ASL_KEY_HOST, whatsmyhostname());
674 else asl_set(msg, ASL_KEY_HOST, rhost);
675
676 if (msg->count == 0)
677 {
678 asl_free(msg);
679 return NULL;
680 }
681
682 return msg;
683}
684
685char *
686get_line_from_file(FILE *f)
687{
688 char *s, *out;
689 size_t len;
690
691 out = fgetln(f, &len);
692 if (out == NULL) return NULL;
693 if (len == 0) return NULL;
694
695 s = malloc(len + 1);
696 memcpy(s, out, len);
697
698 s[len - 1] = '\0';
699 return s;
700}