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