]> git.saurik.com Git - apple/syslog.git/blame - syslogd.tproj/daemon.c
syslog-69.0.4.tar.gz
[apple/syslog.git] / syslogd.tproj / daemon.c
CommitLineData
b16a592a 1/*
57b0aad2 2 * Copyright (c) 2004-2008 Apple Inc. All rights reserved.
b16a592a
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
5dd30d76
A
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.
b16a592a
A
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,
5dd30d76
A
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.
b16a592a
A
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>
5dd30d76
A
37#include <sys/fslog.h>
38#include <vproc.h>
39#include <pthread.h>
40#include <vproc_priv.h>
41#include <mach/mach.h>
b16a592a
A
42#include "daemon.h"
43
44#define streq(A,B) (strcmp(A,B)==0)
5dd30d76
A
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
57extern void disaster_message(asl_msg_t *m);
b16a592a
A
58
59static char myname[MAXHOSTNAMELEN + 1] = {0};
5dd30d76
A
60
61static pthread_mutex_t event_lock = PTHREAD_MUTEX_INITIALIZER;
62
63static 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};
b16a592a
A
74
75struct 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
90struct asloutput
91{
92 aslsendmsgfn sendmsg;
93 const char *outid;
94 TAILQ_ENTRY(asloutput) entries;
95};
96
97struct aslmatch
98{
99 char *outid;
100 asl_msg_t *query;
101 TAILQ_ENTRY(aslmatch) entries;
102};
103
104TAILQ_HEAD(ae, aslevent) Eventq;
105TAILQ_HEAD(ao, asloutput) Outq;
106TAILQ_HEAD(am, aslmatch) Matchq;
107
5dd30d76
A
108static struct aslevent *launchd_event;
109
b16a592a
A
110int
111aslevent_init(void)
112{
113 TAILQ_INIT(&Eventq);
114 TAILQ_INIT(&Outq);
115 TAILQ_INIT(&Matchq);
116
117 return 0;
118}
119
120int
121aslevent_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
137int
138aslevent_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;
5dd30d76 147
b16a592a
A
148 tmp->query = query;
149 tmp->outid = outid;
150 TAILQ_INSERT_TAIL(&Matchq, tmp, entries);
151
152 return 0;
153}
154
155void
156aslevent_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
171int
172aslevent_removefd(int fd)
173{
5dd30d76
A
174 struct aslevent *e, *next;
175
176 e = Eventq.tqh_first;
b16a592a 177
5dd30d76 178 while (e != NULL)
b16a592a 179 {
5dd30d76
A
180 next = e->entries.tqe_next;
181 if (fd == e->fd)
b16a592a 182 {
5dd30d76 183 e->fd = -1;
b16a592a
A
184 return 0;
185 }
5dd30d76
A
186
187 e = next;
b16a592a
A
188 }
189
190 return -1;
191}
192
193const char *
194whatsmyhostname()
195{
196 char *dot;
197
b16a592a
A
198 if (gethostname(myname, MAXHOSTNAMELEN) < 0)
199 {
200 memset(myname, 0, sizeof(myname));
201 return "localhost";
202 }
203
b16a592a
A
204 dot = strchr(myname, '.');
205 if (dot != NULL) *dot = '\0';
206
207 return (const char *)myname;
208}
209
210int
5dd30d76 211aslevent_addfd(int fd, uint32_t flags, aslreadfn readfn, aslwritefn writefn, aslexceptfn exceptfn)
b16a592a
A
212{
213 struct aslevent *e;
5dd30d76 214 int found = 0, status;
b16a592a
A
215#ifdef LOCAL_PEERCRED
216 struct xucred cr;
217#endif
5dd30d76 218 socklen_t len;
b16a592a
A
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));
5dd30d76 229 memset(str, 0, sizeof(str));
b16a592a
A
230
231 len = sizeof(struct sockaddr_storage);
232
5dd30d76 233 if (flags & ADDFD_FLAGS_LOCAL)
b16a592a 234 {
5dd30d76
A
235 snprintf(str, sizeof(str), "localhost");
236 sender = str;
b16a592a
A
237
238#ifdef LOCAL_PEERCRED
5dd30d76 239 len = sizeof(cr);
b16a592a 240
5dd30d76
A
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
b16a592a 250 {
5dd30d76
A
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 }
b16a592a 265 }
b16a592a 266
5dd30d76 267 asldebug("fd %d flags 0x%08x UID %d GID %d Sender %s\n", fd, flags, u, g, (sender == NULL) ? "NULL" : sender );
b16a592a
A
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;
5dd30d76
A
278 if (sender != NULL)
279 {
280 e->sender = strdup(sender);
281 if (e->sender == NULL) return -1;
282 }
283
b16a592a
A
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;
5dd30d76
A
300 if (sender != NULL)
301 {
302 e->sender = strdup(sender);
303 if (e->sender == NULL) return -1;
304 }
305
b16a592a
A
306 e->uid = u;
307 e->gid = g;
308
309 TAILQ_INSERT_TAIL(&Eventq, e, entries);
310
311 return 0;
312}
313
5dd30d76
A
314static int
315aslmsg_verify(struct aslevent *e, asl_msg_t *msg, int32_t *kern_post_level)
b16a592a 316{
5dd30d76 317 const char *val, *fac;
b16a592a 318 char buf[32], *timestr;
5dd30d76 319 time_t tick, now;
b16a592a 320 struct tm gtime;
5dd30d76
A
321 uid_t uid;
322 uint32_t level, fnum, kern;
323 int isreserved;
b16a592a
A
324
325 if (msg == NULL) return -1;
326
5dd30d76
A
327 *kern_post_level = -1;
328
329 kern = 0;
57b0aad2 330 if ((e != NULL) && (e->fd == global.kfd)) kern = 1;
5dd30d76 331
b16a592a 332 /* Time */
5dd30d76
A
333 now = time(NULL);
334
b16a592a
A
335 tick = 0;
336 val = asl_get(msg, ASL_KEY_TIME);
337 if (val != NULL) tick = asl_parse_time(val);
338
5dd30d76
A
339 /* Set time to now if it is unset or from the future (not allowed!) */
340 if ((tick == 0) || (tick > now)) tick = now;
341
b16a592a
A
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());
5dd30d76
A
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 }
b16a592a
A
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 */
5dd30d76 366 uid = -2;
b16a592a 367 val = asl_get(msg, ASL_KEY_UID);
5dd30d76
A
368 if (kern == 1)
369 {
370 uid = 0;
371 asl_set(msg, ASL_KEY_UID, "0");
372 }
373 else if (val == NULL)
b16a592a
A
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 {
5dd30d76 379 uid = e->uid;
b16a592a
A
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 {
5dd30d76 386 uid = e->uid;
b16a592a
A
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);
5dd30d76
A
393 if (kern == 1)
394 {
395 asl_set(msg, ASL_KEY_GID, "0");
396 }
397 else if (val == NULL)
b16a592a
A
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
5dd30d76
A
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
b16a592a
A
425 /* Level */
426 val = asl_get(msg, ASL_KEY_LEVEL);
5dd30d76
A
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 {
57b0aad2 461 snprintf(buf, sizeof(buf), "%lu", tick + global.utmp_ttl);
5dd30d76
A
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 {
57b0aad2 468 snprintf(buf, sizeof(buf), "%lu", tick + global.fs_ttl);
5dd30d76
A
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 }
b16a592a
A
490
491 return 0;
492}
493
494int
495aslevent_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
510int
511aslevent_fdsets(fd_set *rd, fd_set *wr, fd_set *ex)
512{
513 struct aslevent *e;
514 int status = 0;
515
5dd30d76 516// asldebug("--> aslevent_fdsets\n");
b16a592a
A
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 {
5dd30d76
A
523 if (e->fd < 0) continue;
524
525// asldebug("adding fd %d\n", e->fd);
b16a592a
A
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
5dd30d76 545// asldebug("<--aslevent_fdsets\n");
b16a592a
A
546 return status;
547}
548
549void
5dd30d76
A
550aslevent_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
570void
571aslevent_handleevent(fd_set *rd, fd_set *wr, fd_set *ex)
b16a592a
A
572{
573 struct aslevent *e;
574 char *out = NULL;
575 asl_msg_t *msg;
5dd30d76 576 int32_t kplevel, cleanup;
b16a592a 577
5dd30d76
A
578// asldebug("--> aslevent_handleevent\n");
579
580 cleanup = 0;
b16a592a
A
581
582 for (e = Eventq.tqh_first; e != NULL; e = e->entries.tqe_next)
583 {
5dd30d76 584 if (e->fd < 0)
b16a592a 585 {
5dd30d76
A
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);
b16a592a 593 msg = e->readfn(e->fd);
5dd30d76 594 if (msg == NULL) continue;
b16a592a 595
5dd30d76
A
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)
b16a592a 603 {
5dd30d76
A
604 asl_msg_release(msg);
605 asldebug("recieved invalid message\n\n");
b16a592a
A
606 }
607 else
608 {
609 aslevent_match(msg);
5dd30d76
A
610 asl_msg_release(msg);
611 if (kplevel >= 0) notify_post(kern_notify_key[kplevel]);
b16a592a 612 }
5dd30d76
A
613
614 pthread_mutex_unlock(&event_lock);
b16a592a
A
615 }
616
5dd30d76 617 if (FD_ISSET(e->fd, ex) && e->exceptfn)
b16a592a
A
618 {
619 asldebug("handling except event on %d\n", e->fd);
620 out = e->exceptfn(e->fd);
5dd30d76 621 if (out == NULL) asldebug("error writing message\n\n");
b16a592a
A
622 }
623 }
624
5dd30d76
A
625 if (cleanup != 0) aslevent_cleanup();
626
627// asldebug("<-- aslevent_handleevent\n");
b16a592a
A
628}
629
630int
631asl_log_string(const char *str)
632{
633 asl_msg_t *msg;
5dd30d76 634 int32_t unused;
b16a592a
A
635
636 if (str == NULL) return 1;
637
638 msg = asl_msg_from_string(str);
5dd30d76
A
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)
b16a592a 647 {
5dd30d76
A
648 pthread_mutex_unlock(&event_lock);
649 asl_msg_release(msg);
b16a592a
A
650 return -1;
651 }
652
653 aslevent_match(msg);
5dd30d76
A
654 asl_msg_release(msg);
655
656 pthread_mutex_unlock(&event_lock);
657
b16a592a
A
658 return 0;
659}
660
5dd30d76
A
661int
662asldebug(const char *str, ...)
663{
664 va_list v;
665 int status;
666 FILE *dfp;
667
57b0aad2 668 if (global.debug == 0) return 0;
5dd30d76
A
669
670 dfp = stderr;
57b0aad2 671 if (global.debug_file != NULL) dfp = fopen(global.debug_file, "a");
5dd30d76
A
672 if (dfp == NULL) return 0;
673
674 va_start(v, str);
675 status = vfprintf(dfp, str, v);
676 va_end(v);
677
57b0aad2 678 if (global.debug_file != NULL) fclose(dfp);
5dd30d76
A
679 return status;
680}
681
b16a592a 682void
5dd30d76 683asl_mark(void)
b16a592a
A
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
698asl_msg_t *
699asl_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
b16a592a
A
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);
5dd30d76
A
760 if (tmp == NULL) return NULL;
761
b16a592a
A
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));
5dd30d76 784 if (msg == NULL) return NULL;
b16a592a 785
b16a592a
A
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
b16a592a
A
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);
5dd30d76
A
807 if (sval == NULL) return NULL;
808
b16a592a
A
809 memcpy(sval, p, n);
810 sval[n] = '\0';
811
812 n = colon - (brace + 1) - 1;
813 pval = malloc(n + 1);
5dd30d76
A
814 if (pval == NULL) return NULL;
815
b16a592a
A
816 memcpy(pval, (brace + 1), n);
817 pval[n] = '\0';
818 }
819 else
820 {
821 n = colon - p;
822 sval = malloc(n + 1);
5dd30d76
A
823 if (sval == NULL) return NULL;
824
b16a592a
A
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);
5dd30d76
A
844 if (mval == NULL) return NULL;
845
b16a592a
A
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));
5dd30d76 853 if (msg == NULL) return NULL;
b16a592a
A
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 {
5dd30d76 892 asl_msg_release(msg);
b16a592a
A
893 return NULL;
894 }
895
896 return msg;
897}
898
5dd30d76
A
899asl_msg_t *
900asl_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
b16a592a
A
936char *
937get_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);
5dd30d76
A
947 if (s == NULL) return NULL;
948
b16a592a
A
949 memcpy(s, out, len);
950
951 s[len - 1] = '\0';
952 return s;
953}
5dd30d76
A
954
955uint32_t
956asl_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
962void
963asl_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
980asl_msg_t *
981asl_msg_retain(asl_msg_t *m)
982{
983 if (m == NULL) return NULL;
984
985 m->type += 0x10;
986 return m;
987}
988
989void
990launchd_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);
57b0aad2 1016
5dd30d76
A
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 */
57b0aad2
A
1056 if (from_name != NULL)
1057 {
1058 asl_set(m, ASL_KEY_SENDER, from_name);
1059 }
5dd30d76
A
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 {
57b0aad2
A
1071 if ((from_name != NULL) && (strcmp(from_name, about_name) != 0))
1072 {
1073 asl_set(m, ASL_KEY_REF_PROC, about_name);
1074 }
5dd30d76
A
1075 }
1076
1077 /* Session */
57b0aad2
A
1078 if (session_name != NULL)
1079 {
1080 asl_set(m, ASL_KEY_SESSION, session_name);
1081 }
5dd30d76
A
1082
1083 /* Message */
57b0aad2
A
1084 if (msg != NULL)
1085 {
1086 asl_set(m, ASL_KEY_MSG, msg);
1087 }
5dd30d76
A
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
1099void
1100launchd_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}