]> git.saurik.com Git - apple/syslog.git/blob - syslogd.tproj/daemon.c
06b74517118d006f79f5d26913fec5af8fac5879
[apple/syslog.git] / syslogd.tproj / daemon.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/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 <sys/fslog.h>
38 #include <vproc.h>
39 #include <pthread.h>
40 #include <vproc_priv.h>
41 #include <mach/mach.h>
42 #include "daemon.h"
43
44 #define streq(A,B) (strcmp(A,B)==0)
45 #define forever for(;;)
46
47 #define ASL_MSG_TYPE_MASK 0x0000000f
48 #define ASL_TYPE_ERROR 2
49
50 #define ASL_KEY_FACILITY "Facility"
51
52 #define FACILITY_USER "user"
53 #define FACILITY_CONSOLE "com.apple.console"
54 #define SYSTEM_RESERVED "com.apple.system"
55 #define SYSTEM_RESERVED_LEN 16
56
57 extern void disaster_message(asl_msg_t *m);
58
59 static char myname[MAXHOSTNAMELEN + 1] = {0};
60
61 static pthread_mutex_t event_lock = PTHREAD_MUTEX_INITIALIZER;
62
63 static const char *kern_notify_key[] =
64 {
65 "com.apple.system.log.kernel.emergency",
66 "com.apple.system.log.kernel.alert",
67 "com.apple.system.log.kernel.critical",
68 "com.apple.system.log.kernel.error",
69 "com.apple.system.log.kernel.warning",
70 "com.apple.system.log.kernel.notice",
71 "com.apple.system.log.kernel.info",
72 "com.apple.system.log.kernel.debug"
73 };
74
75 struct aslevent
76 {
77 int fd;
78 unsigned char read:1;
79 unsigned char write:1;
80 unsigned char except:1;
81 aslreadfn readfn;
82 aslwritefn writefn;
83 aslexceptfn exceptfn;
84 char *sender;
85 uid_t uid;
86 gid_t gid;
87 TAILQ_ENTRY(aslevent) entries;
88 };
89
90 struct asloutput
91 {
92 aslsendmsgfn sendmsg;
93 const char *outid;
94 TAILQ_ENTRY(asloutput) entries;
95 };
96
97 struct aslmatch
98 {
99 char *outid;
100 asl_msg_t *query;
101 TAILQ_ENTRY(aslmatch) entries;
102 };
103
104 TAILQ_HEAD(ae, aslevent) Eventq;
105 TAILQ_HEAD(ao, asloutput) Outq;
106 TAILQ_HEAD(am, aslmatch) Matchq;
107
108 static struct aslevent *launchd_event;
109
110 int
111 aslevent_init(void)
112 {
113 TAILQ_INIT(&Eventq);
114 TAILQ_INIT(&Outq);
115 TAILQ_INIT(&Matchq);
116
117 return 0;
118 }
119
120 int
121 aslevent_log(asl_msg_t *msg, char *outid)
122 {
123 struct asloutput *i;
124 int status = -1;
125
126 for (i = Outq.tqh_first; i != NULL; i = i->entries.tqe_next)
127 {
128 if ((outid != NULL) && (strcmp(i->outid, outid) == 0))
129 {
130 status = i->sendmsg(msg, outid);
131 }
132 }
133
134 return status;
135 }
136
137 int
138 aslevent_addmatch(asl_msg_t *query, char *outid)
139 {
140 struct aslmatch *tmp;
141
142 if (query == NULL) return -1;
143 if (outid == NULL) return -1;
144
145 tmp = calloc(1, sizeof(struct aslmatch));
146 if (tmp == NULL) return -1;
147
148 tmp->query = query;
149 tmp->outid = outid;
150 TAILQ_INSERT_TAIL(&Matchq, tmp, entries);
151
152 return 0;
153 }
154
155 void
156 aslevent_match(asl_msg_t *msg)
157 {
158 struct aslmatch *i;
159
160 if (msg == NULL) return;
161
162 for (i = Matchq.tqh_first; i != NULL; i = i->entries.tqe_next)
163 {
164 if (asl_msg_cmp(i->query, msg) != 0)
165 {
166 aslevent_log(msg, i->outid);
167 }
168 }
169 }
170
171 int
172 aslevent_removefd(int fd)
173 {
174 struct aslevent *e, *next;
175
176 e = Eventq.tqh_first;
177
178 while (e != NULL)
179 {
180 next = e->entries.tqe_next;
181 if (fd == e->fd)
182 {
183 e->fd = -1;
184 return 0;
185 }
186
187 e = next;
188 }
189
190 return -1;
191 }
192
193 const char *
194 whatsmyhostname()
195 {
196 char *dot;
197
198 if (gethostname(myname, MAXHOSTNAMELEN) < 0)
199 {
200 memset(myname, 0, sizeof(myname));
201 return "localhost";
202 }
203
204 dot = strchr(myname, '.');
205 if (dot != NULL) *dot = '\0';
206
207 return (const char *)myname;
208 }
209
210 int
211 aslevent_addfd(int fd, uint32_t flags, aslreadfn readfn, aslwritefn writefn, aslexceptfn exceptfn)
212 {
213 struct aslevent *e;
214 int found = 0, status;
215 #ifdef LOCAL_PEERCRED
216 struct xucred cr;
217 #endif
218 socklen_t len;
219 uid_t u;
220 gid_t g;
221 struct sockaddr_storage ss;
222 char *sender, str[256];
223
224 u = 99;
225 g = 99;
226 sender = NULL;
227
228 memset(&ss, 0, sizeof(struct sockaddr_storage));
229 memset(str, 0, sizeof(str));
230
231 len = sizeof(struct sockaddr_storage);
232
233 if (flags & ADDFD_FLAGS_LOCAL)
234 {
235 snprintf(str, sizeof(str), "localhost");
236 sender = str;
237
238 #ifdef LOCAL_PEERCRED
239 len = sizeof(cr);
240
241 status = getsockopt(fd, LOCAL_PEERCRED, 1, &cr, &len);
242 if (status == 0)
243 {
244 u = cr.cr_uid;
245 g = cr.cr_gid;
246 }
247 #endif
248 }
249 else
250 {
251 status = getpeername(fd, (struct sockaddr *)&ss, &len);
252 if (status == 0)
253 {
254 if (len == 0)
255 {
256 /* UNIX Domain socket */
257 snprintf(str, sizeof(str), "localhost");
258 sender = str;
259 }
260 else
261 {
262 if (inet_ntop(ss.ss_family, (struct sockaddr *)&ss, str, 256) == NULL) sender = str;
263 }
264 }
265 }
266
267 asldebug("fd %d flags 0x%08x UID %d GID %d Sender %s\n", fd, flags, u, g, (sender == NULL) ? "NULL" : sender );
268
269 for (e = Eventq.tqh_first; e != NULL; e = e->entries.tqe_next)
270 {
271 if (fd == e->fd)
272 {
273 e->readfn = readfn;
274 e->writefn = writefn;
275 e->exceptfn = exceptfn;
276 if (e->sender != NULL) free(e->sender);
277 e->sender = NULL;
278 if (sender != NULL)
279 {
280 e->sender = strdup(sender);
281 if (e->sender == NULL) return -1;
282 }
283
284 e->uid = u;
285 e->gid = g;
286 found = 1;
287 }
288 }
289
290 if (found) return 0;
291
292 e = calloc(1, sizeof(struct aslevent));
293 if (e == NULL) return -1;
294
295 e->fd = fd;
296 e->readfn = readfn;
297 e->writefn = writefn;
298 e->exceptfn = exceptfn;
299 e->sender = NULL;
300 if (sender != NULL)
301 {
302 e->sender = strdup(sender);
303 if (e->sender == NULL) return -1;
304 }
305
306 e->uid = u;
307 e->gid = g;
308
309 TAILQ_INSERT_TAIL(&Eventq, e, entries);
310
311 return 0;
312 }
313
314 static int
315 aslmsg_verify(struct aslevent *e, asl_msg_t *msg, int32_t *kern_post_level)
316 {
317 const char *val, *fac;
318 char buf[32], *timestr;
319 time_t tick, now;
320 struct tm gtime;
321 uid_t uid;
322 uint32_t level, fnum, kern;
323 int isreserved;
324
325 if (msg == NULL) return -1;
326
327 *kern_post_level = -1;
328
329 kern = 0;
330 if ((e != NULL) && (e->fd == global.kfd)) kern = 1;
331
332 /* Time */
333 now = time(NULL);
334
335 tick = 0;
336 val = asl_get(msg, ASL_KEY_TIME);
337 if (val != NULL) tick = asl_parse_time(val);
338
339 /* Set time to now if it is unset or from the future (not allowed!) */
340 if ((tick == 0) || (tick > now)) tick = now;
341
342 memset(&gtime, 0, sizeof(struct tm));
343 gmtime_r(&tick, &gtime);
344
345 /* Canonical form: YYYY.MM.DD hh:mm:ss UTC */
346 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);
347 if (timestr != NULL)
348 {
349 asl_set(msg, ASL_KEY_TIME, timestr);
350 free(timestr);
351 }
352
353 /* Host */
354 if (e == NULL) asl_set(msg, ASL_KEY_HOST, whatsmyhostname());
355 else if (e->sender != NULL)
356 {
357 if (!strcmp(e->sender, "localhost")) asl_set(msg, ASL_KEY_HOST, whatsmyhostname());
358 else asl_set(msg, ASL_KEY_HOST, e->sender);
359 }
360
361 /* PID */
362 val = asl_get(msg, ASL_KEY_PID);
363 if (val == NULL) asl_set(msg, ASL_KEY_PID, "0");
364
365 /* UID */
366 uid = -2;
367 val = asl_get(msg, ASL_KEY_UID);
368 if (kern == 1)
369 {
370 uid = 0;
371 asl_set(msg, ASL_KEY_UID, "0");
372 }
373 else if (val == NULL)
374 {
375 if (e == NULL) asl_set(msg, ASL_KEY_UID, "-2");
376 else if (e->uid == 99) asl_set(msg, ASL_KEY_UID, "-2");
377 else
378 {
379 uid = e->uid;
380 snprintf(buf, sizeof(buf), "%d", e->uid);
381 asl_set(msg, ASL_KEY_UID, buf);
382 }
383 }
384 else if ((e != NULL) && (e->uid != 99))
385 {
386 uid = e->uid;
387 snprintf(buf, sizeof(buf), "%d", e->uid);
388 asl_set(msg, ASL_KEY_UID, buf);
389 }
390
391 /* GID */
392 val = asl_get(msg, ASL_KEY_GID);
393 if (kern == 1)
394 {
395 asl_set(msg, ASL_KEY_GID, "0");
396 }
397 else if (val == NULL)
398 {
399 if (e == NULL) asl_set(msg, ASL_KEY_GID, "-2");
400 else if (e->gid == 99) asl_set(msg, ASL_KEY_GID, "-2");
401 else
402 {
403 snprintf(buf, sizeof(buf), "%d", e->gid);
404 asl_set(msg, ASL_KEY_GID, buf);
405 }
406 }
407 else if ((e != NULL) && (e->gid != 99))
408 {
409 snprintf(buf, sizeof(buf), "%d", e->gid);
410 asl_set(msg, ASL_KEY_GID, buf);
411 }
412
413 /* Sender */
414 val = asl_get(msg, ASL_KEY_SENDER);
415 if (val == NULL)
416 {
417 if (kern == 0) asl_set(msg, ASL_KEY_SENDER, "Unknown");
418 else asl_set(msg, ASL_KEY_SENDER, "kernel");
419 }
420 else if ((kern == 0) && (uid != 0) && (!strcmp(val, "kernel")))
421 {
422 asl_set(msg, ASL_KEY_SENDER, "Unknown");
423 }
424
425 /* Level */
426 val = asl_get(msg, ASL_KEY_LEVEL);
427 level = ASL_LEVEL_DEBUG;
428 if ((val != NULL) && (val[1] == '\0') && (val[0] >= '0') && (val[0] <= '7')) level = val[0] - '0';
429 snprintf(buf, sizeof(buf), "%d", level);
430 asl_set(msg, ASL_KEY_LEVEL, buf);
431
432 /* Facility */
433 fac = asl_get(msg, ASL_KEY_FACILITY);
434 if (fac == NULL)
435 {
436 if (kern == 1) fac = "kern";
437 else fac = "user";
438 asl_set(msg, ASL_KEY_FACILITY, fac);
439 }
440 else if (fac[0] == '#')
441 {
442 fnum = LOG_USER;
443 if ((fac[1] >= '0') && (fac[1] <= '9'))
444 {
445 fnum = atoi(fac + 1) << 3;
446 if ((fnum == 0) && (strcmp(fac + 1, "0"))) fnum = LOG_USER;
447 }
448
449 fac = asl_syslog_faciliy_num_to_name(fnum);
450 asl_set(msg, ASL_KEY_FACILITY, fac);
451 }
452
453 /*
454 * Access Control: only UID 0 may use facility com.apple.system (or anything with that prefix).
455 * N.B. kernel can use any facility name.
456 */
457
458 /* Set DB Expire Time for com.apple.system.utmpx and lastlog */
459 if ((!strcmp(fac, "com.apple.system.utmpx")) || (!strcmp(fac, "com.apple.system.lastlog")))
460 {
461 snprintf(buf, sizeof(buf), "%lu", tick + global.utmp_ttl);
462 asl_set(msg, ASL_KEY_EXPIRE_TIME, buf);
463 }
464
465 /* Set DB Expire Time for Filestsrem errors */
466 if (!strcmp(fac, FSLOG_VAL_FACILITY))
467 {
468 snprintf(buf, sizeof(buf), "%lu", tick + global.fs_ttl);
469 asl_set(msg, ASL_KEY_EXPIRE_TIME, buf);
470 }
471
472 if (e != NULL)
473 {
474 isreserved = 0;
475 if (!strncmp(fac, SYSTEM_RESERVED, SYSTEM_RESERVED_LEN))
476 {
477 if (uid != 0) asl_set(msg, ASL_KEY_FACILITY, FACILITY_USER);
478 else isreserved = 1;
479 }
480 }
481
482 /*
483 * special case handling of kernel disaster messages
484 */
485 if ((kern == 1) && (level <= KERN_DISASTER_LEVEL))
486 {
487 *kern_post_level = level;
488 disaster_message(msg);
489 }
490
491 return 0;
492 }
493
494 int
495 aslevent_addoutput(aslsendmsgfn fn, const char *outid)
496 {
497 struct asloutput *tmp;
498
499 tmp = calloc(1, sizeof(struct asloutput));
500 if (tmp == NULL) return -1;
501
502 tmp->sendmsg = fn;
503 tmp->outid = outid;
504
505 TAILQ_INSERT_TAIL(&Outq, tmp, entries);
506
507 return 0;
508 }
509
510 int
511 aslevent_fdsets(fd_set *rd, fd_set *wr, fd_set *ex)
512 {
513 struct aslevent *e;
514 int status = 0;
515
516 // asldebug("--> aslevent_fdsets\n");
517 FD_ZERO(rd);
518 FD_ZERO(wr);
519 FD_ZERO(ex);
520
521 for (e = Eventq.tqh_first; e != NULL; e = e->entries.tqe_next)
522 {
523 if (e->fd < 0) continue;
524
525 // asldebug("adding fd %d\n", e->fd);
526 if (e->readfn)
527 {
528 FD_SET(e->fd, rd);
529 status = MAX(e->fd, status);
530 }
531
532 if (e->writefn)
533 {
534 FD_SET(e->fd, wr);
535 status = MAX(e->fd, status);
536 }
537
538 if (e->exceptfn)
539 {
540 FD_SET(e->fd, ex);
541 status = MAX(e->fd, status);
542 }
543 }
544
545 // asldebug("<--aslevent_fdsets\n");
546 return status;
547 }
548
549 void
550 aslevent_cleanup()
551 {
552 struct aslevent *e, *next;
553
554 e = Eventq.tqh_first;
555
556 while (e != NULL)
557 {
558 next = e->entries.tqe_next;
559 if (e->fd < 0)
560 {
561 TAILQ_REMOVE(&Eventq, e, entries);
562 if (e->sender != NULL) free(e->sender);
563 free(e);
564 }
565
566 e = next;
567 }
568 }
569
570 void
571 aslevent_handleevent(fd_set *rd, fd_set *wr, fd_set *ex)
572 {
573 struct aslevent *e;
574 char *out = NULL;
575 asl_msg_t *msg;
576 int32_t kplevel, cleanup;
577
578 // asldebug("--> aslevent_handleevent\n");
579
580 cleanup = 0;
581
582 for (e = Eventq.tqh_first; e != NULL; e = e->entries.tqe_next)
583 {
584 if (e->fd < 0)
585 {
586 cleanup = 1;
587 continue;
588 }
589
590 if (FD_ISSET(e->fd, rd) && (e->readfn != NULL))
591 {
592 // asldebug("handling read event on %d\n", e->fd);
593 msg = e->readfn(e->fd);
594 if (msg == NULL) continue;
595
596 /* type field is overloaded to provide retain/release inside syslogd */
597 msg->type |= 0x10;
598
599 pthread_mutex_lock(&event_lock);
600
601 kplevel = -1;
602 if (aslmsg_verify(e, msg, &kplevel) < 0)
603 {
604 asl_msg_release(msg);
605 asldebug("recieved invalid message\n\n");
606 }
607 else
608 {
609 aslevent_match(msg);
610 asl_msg_release(msg);
611 if (kplevel >= 0) notify_post(kern_notify_key[kplevel]);
612 }
613
614 pthread_mutex_unlock(&event_lock);
615 }
616
617 if (FD_ISSET(e->fd, ex) && e->exceptfn)
618 {
619 asldebug("handling except event on %d\n", e->fd);
620 out = e->exceptfn(e->fd);
621 if (out == NULL) asldebug("error writing message\n\n");
622 }
623 }
624
625 if (cleanup != 0) aslevent_cleanup();
626
627 // asldebug("<-- aslevent_handleevent\n");
628 }
629
630 int
631 asl_log_string(const char *str)
632 {
633 asl_msg_t *msg;
634 int32_t unused;
635
636 if (str == NULL) return 1;
637
638 msg = asl_msg_from_string(str);
639
640 /* set retain count */
641 msg->type |= 0x10;
642
643 pthread_mutex_lock(&event_lock);
644
645 unused = -1;
646 if (aslmsg_verify(NULL, msg, &unused) < 0)
647 {
648 pthread_mutex_unlock(&event_lock);
649 asl_msg_release(msg);
650 return -1;
651 }
652
653 aslevent_match(msg);
654 asl_msg_release(msg);
655
656 pthread_mutex_unlock(&event_lock);
657
658 return 0;
659 }
660
661 int
662 asldebug(const char *str, ...)
663 {
664 va_list v;
665 int status;
666 FILE *dfp;
667
668 if (global.debug == 0) return 0;
669
670 dfp = stderr;
671 if (global.debug_file != NULL) dfp = fopen(global.debug_file, "a");
672 if (dfp == NULL) return 0;
673
674 va_start(v, str);
675 status = vfprintf(dfp, str, v);
676 va_end(v);
677
678 if (global.debug_file != NULL) fclose(dfp);
679 return status;
680 }
681
682 void
683 asl_mark(void)
684 {
685 char *str;
686
687 str = NULL;
688 asprintf(&str, "[%s syslogd] [%s %u] [%s %u] [%s -- MARK --] [%s 0] [%s 0] [Facility syslog]",
689 ASL_KEY_SENDER,
690 ASL_KEY_LEVEL, ASL_LEVEL_INFO,
691 ASL_KEY_PID, getpid(),
692 ASL_KEY_MSG, ASL_KEY_UID, ASL_KEY_GID);
693
694 asl_log_string(str);
695 if (str != NULL) free(str);
696 }
697
698 asl_msg_t *
699 asl_syslog_input_convert(const char *in, int len, char *rhost, int kern)
700 {
701 int pf, pri, index, n;
702 char *p, *colon, *brace, *tmp, *tval, *sval, *pval, *mval;
703 char prival[8];
704 const char *fval;
705 asl_msg_t *msg;
706 struct tm time;
707 time_t tick;
708
709 if (in == NULL) return NULL;
710 if (len <= 0) return NULL;
711
712 pri = LOG_DEBUG;
713 tval = NULL;
714 sval = NULL;
715 pval = NULL;
716 mval = NULL;
717 fval = NULL;
718
719 index = 0;
720 p = (char *)in;
721
722 while ((index < len) && ((*p == ' ') || (*p == '\t')))
723 {
724 p++;
725 index++;
726 }
727
728 if (index >= len) return NULL;
729
730 if (*p == '<')
731 {
732 p++;
733 index++;
734
735 n = sscanf(p, "%d", &pf);
736 if (n == 1)
737 {
738 pri = pf & 0x7;
739 if (pf > 0x7) fval = asl_syslog_faciliy_num_to_name(pf & LOG_FACMASK);
740 }
741
742 while ((index < len) && (*p != '>'))
743 {
744 p++;
745 index++;
746 }
747
748 if (index < len)
749 {
750 p++;
751 index++;
752 }
753 }
754
755 snprintf(prival, sizeof(prival), "%d", pri);
756
757 if (((len - index) > 15) && (p[9] == ':') && (p[12] == ':') && (p[15] == ' '))
758 {
759 tmp = malloc(16);
760 if (tmp == NULL) return NULL;
761
762 memcpy(tmp, p, 15);
763 tmp[15] = '\0';
764
765 tick = asl_parse_time(tmp);
766 if (tick == (time_t)-1)
767 {
768 tval = tmp;
769 }
770 else
771 {
772 free(tmp);
773 gmtime_r(&tick, &time);
774 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);
775 }
776
777 p += 16;
778 index += 16;
779 }
780
781 if (kern != 0)
782 {
783 msg = (asl_msg_t *)calloc(1, sizeof(asl_msg_t));
784 if (msg == NULL) return NULL;
785
786
787 asl_set(msg, ASL_KEY_MSG, p);
788
789 asl_set(msg, ASL_KEY_LEVEL, prival);
790
791 asl_set(msg, ASL_KEY_PID, "0");
792
793 asl_set(msg, ASL_KEY_HOST, whatsmyhostname());
794
795 return msg;
796 }
797
798 colon = strchr(p, ':');
799 brace = strchr(p, '[');
800
801 if (colon != NULL)
802 {
803 if ((brace != NULL) && (brace < colon))
804 {
805 n = brace - p;
806 sval = malloc(n + 1);
807 if (sval == NULL) return NULL;
808
809 memcpy(sval, p, n);
810 sval[n] = '\0';
811
812 n = colon - (brace + 1) - 1;
813 pval = malloc(n + 1);
814 if (pval == NULL) return NULL;
815
816 memcpy(pval, (brace + 1), n);
817 pval[n] = '\0';
818 }
819 else
820 {
821 n = colon - p;
822 sval = malloc(n + 1);
823 if (sval == NULL) return NULL;
824
825 memcpy(sval, p, n);
826 sval[n] = '\0';
827 }
828
829 n = colon - p;
830 p = colon + 1;
831 index += (n + 1);
832 }
833
834 if (*p == ' ')
835 {
836 p++;
837 index++;
838 }
839
840 n = len - index;
841 if (n > 0)
842 {
843 mval = malloc(n + 1);
844 if (mval == NULL) return NULL;
845
846 memcpy(mval, p, n);
847 mval[n] = '\0';
848 }
849
850 if (fval == NULL) fval = asl_syslog_faciliy_num_to_name(LOG_USER);
851
852 msg = (asl_msg_t *)calloc(1, sizeof(asl_msg_t));
853 if (msg == NULL) return NULL;
854
855 if (tval != NULL)
856 {
857 asl_set(msg, ASL_KEY_TIME, tval);
858 free(tval);
859 }
860
861 if (fval != NULL) asl_set(msg, "Facility", fval);
862 else asl_set(msg, "Facility", "user");
863
864 if (sval != NULL)
865 {
866 asl_set(msg, ASL_KEY_SENDER, sval);
867 free(sval);
868 }
869
870 if (pval != NULL)
871 {
872 asl_set(msg, ASL_KEY_PID, pval);
873 free(pval);
874 }
875 else asl_set(msg, ASL_KEY_PID, "-1");
876
877 if (mval != NULL)
878 {
879 asl_set(msg, ASL_KEY_MSG, mval);
880 free(mval);
881 }
882
883 asl_set(msg, ASL_KEY_LEVEL, prival);
884 asl_set(msg, ASL_KEY_UID, "-2");
885 asl_set(msg, ASL_KEY_GID, "-2");
886
887 if (rhost == NULL) asl_set(msg, ASL_KEY_HOST, whatsmyhostname());
888 else asl_set(msg, ASL_KEY_HOST, rhost);
889
890 if (msg->count == 0)
891 {
892 asl_msg_release(msg);
893 return NULL;
894 }
895
896 return msg;
897 }
898
899 asl_msg_t *
900 asl_input_parse(const char *in, int len, char *rhost, int kern)
901 {
902 asl_msg_t *m;
903 int status, x, legacy;
904
905 asldebug("asl_input_parse: %s\n", (in == NULL) ? "NULL" : in);
906
907 if (in == NULL) return NULL;
908
909 legacy = 1;
910 m = NULL;
911
912 /* calculate length if not provided */
913 if (len == 0) len = strlen(in);
914
915 /*
916 * Determine if the input is "old" syslog format or new ASL format.
917 * Old format lines should start with "<", but they can just be straight text.
918 * ASL input starts with a length (10 bytes) followed by a space and a '['.
919 */
920 if ((in[0] != '<') && (len > 11))
921 {
922 status = sscanf(in, "%d ", &x);
923 if ((status == 1) && (in[10] == ' ') && (in[11] == '[')) legacy = 0;
924 }
925
926 if (legacy == 1) return asl_syslog_input_convert(in, len, rhost, kern);
927
928 m = asl_msg_from_string(in + 11);
929 if (m == NULL) return NULL;
930
931 if (rhost != NULL) asl_set(m, ASL_KEY_HOST, rhost);
932
933 return m;
934 }
935
936 char *
937 get_line_from_file(FILE *f)
938 {
939 char *s, *out;
940 size_t len;
941
942 out = fgetln(f, &len);
943 if (out == NULL) return NULL;
944 if (len == 0) return NULL;
945
946 s = malloc(len + 1);
947 if (s == NULL) return NULL;
948
949 memcpy(s, out, len);
950
951 s[len - 1] = '\0';
952 return s;
953 }
954
955 uint32_t
956 asl_msg_type(asl_msg_t *m)
957 {
958 if (m == NULL) return ASL_TYPE_ERROR;
959 return (m->type & ASL_MSG_TYPE_MASK);
960 }
961
962 void
963 asl_msg_release(asl_msg_t *m)
964 {
965 uint32_t refcount;
966
967 if (m == NULL) return;
968
969 refcount = m->type >> 4;
970 if (refcount > 0)
971 {
972 refcount--;
973 m->type -= 0x10;
974 }
975
976 if (refcount > 0) return;
977 asl_free(m);
978 }
979
980 asl_msg_t *
981 asl_msg_retain(asl_msg_t *m)
982 {
983 if (m == NULL) return NULL;
984
985 m->type += 0x10;
986 return m;
987 }
988
989 void
990 launchd_callback(struct timeval *when, pid_t from_pid, pid_t about_pid, uid_t sender_uid, gid_t sender_gid, int priority, const char *from_name, const char *about_name, const char *session_name, const char *msg)
991 {
992 asl_msg_t *m;
993 char str[256];
994 int32_t unused;
995 int status;
996 time_t now;
997
998 /*
999 asldebug("launchd_callback Time %lu %lu PID %u RefPID %u UID %d GID %d PRI %d Sender %s Ref %s Session %s Message %s\n",
1000 when->tv_sec, when->tv_usec, from_pid, about_pid, sender_uid, sender_gid, priority, from_name, about_name, session_name, msg);
1001 */
1002
1003 if (launchd_event != NULL)
1004 {
1005 launchd_event->uid = sender_uid;
1006 launchd_event->gid = sender_gid;
1007 }
1008
1009 m = asl_new(ASL_TYPE_MSG);
1010 if (m == NULL) return;
1011
1012 /* Level */
1013 if (priority < ASL_LEVEL_EMERG) priority = ASL_LEVEL_EMERG;
1014 if (priority > ASL_LEVEL_DEBUG) priority = ASL_LEVEL_DEBUG;
1015 snprintf(str, sizeof(str), "%d", priority);
1016
1017 asl_set(m, ASL_KEY_LEVEL, str);
1018
1019 /* Time */
1020 if (when != NULL)
1021 {
1022 snprintf(str, sizeof(str), "%lu", when->tv_sec);
1023 asl_set(m, ASL_KEY_TIME, str);
1024
1025 snprintf(str, sizeof(str), "%lu", 1000 * (unsigned long int)when->tv_usec);
1026 asl_set(m, ASL_KEY_TIME_NSEC, str);
1027 }
1028 else
1029 {
1030 now = time(NULL);
1031 snprintf(str, sizeof(str), "%lu", now);
1032 asl_set(m, ASL_KEY_TIME, str);
1033 }
1034
1035 /* Host */
1036 asl_set(m, ASL_KEY_HOST, whatsmyhostname());
1037
1038 /* Facility */
1039 asl_set(m, ASL_KEY_FACILITY, FACILITY_CONSOLE);
1040
1041 /* PID */
1042 if (from_pid != 0)
1043 {
1044 snprintf(str, sizeof(str), "%u", (unsigned int)from_pid);
1045 asl_set(m, ASL_KEY_PID, str);
1046 }
1047
1048 /* Reference PID */
1049 if ((about_pid > 0) && (about_pid != from_pid))
1050 {
1051 snprintf(str, sizeof(str), "%u", (unsigned int)about_pid);
1052 asl_set(m, ASL_KEY_REF_PID, str);
1053 }
1054
1055 /* Sender */
1056 if (from_name != NULL)
1057 {
1058 asl_set(m, ASL_KEY_SENDER, from_name);
1059 }
1060
1061 /* ReadUID */
1062 if (sender_uid != 0)
1063 {
1064 snprintf(str, sizeof(str), "%d", (int)sender_uid);
1065 asl_set(m, ASL_KEY_READ_UID, str);
1066 }
1067
1068 /* Reference Process */
1069 if (about_name != NULL)
1070 {
1071 if ((from_name != NULL) && (strcmp(from_name, about_name) != 0))
1072 {
1073 asl_set(m, ASL_KEY_REF_PROC, about_name);
1074 }
1075 }
1076
1077 /* Session */
1078 if (session_name != NULL)
1079 {
1080 asl_set(m, ASL_KEY_SESSION, session_name);
1081 }
1082
1083 /* Message */
1084 if (msg != NULL)
1085 {
1086 asl_set(m, ASL_KEY_MSG, msg);
1087 }
1088
1089 /* set retain count */
1090 m->type |= 0x10;
1091
1092 /* verify and push to receivers */
1093 status = aslmsg_verify(launchd_event, m, &unused);
1094 if (status >= 0) aslevent_match(m);
1095
1096 asl_msg_release(m);
1097 }
1098
1099 void
1100 launchd_drain()
1101 {
1102 launchd_event = (struct aslevent *)calloc(1, sizeof(struct aslevent));
1103
1104 forever
1105 {
1106 _vprocmgr_log_drain(NULL, &event_lock, launchd_callback);
1107 }
1108 }