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