]>
Commit | Line | Data |
---|---|---|
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 | ||
57 | extern void disaster_message(asl_msg_t *m); | |
b16a592a A |
58 | |
59 | static char myname[MAXHOSTNAMELEN + 1] = {0}; | |
5dd30d76 A |
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 | }; | |
b16a592a A |
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 | ||
5dd30d76 A |
108 | static struct aslevent *launchd_event; |
109 | ||
b16a592a A |
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; | |
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 | ||
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 | { | |
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 | ||
193 | const char * | |
194 | whatsmyhostname() | |
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 | ||
210 | int | |
5dd30d76 | 211 | aslevent_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 |
314 | static int |
315 | aslmsg_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(>ime, 0, sizeof(struct tm)); |
343 | gmtime_r(&tick, >ime); | |
344 | ||
345 | /* Canonical form: YYYY.MM.DD hh:mm:ss UTC */ | |
346 | asprintf(×tr, "%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 | ||
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 | ||
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 | ||
549 | void | |
5dd30d76 A |
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) | |
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 | ||
630 | int | |
631 | asl_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 |
661 | int |
662 | asldebug(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 | 682 | void |
5dd30d76 | 683 | asl_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 | ||
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 | ||
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 |
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 | ||
b16a592a A |
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); | |
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 | |
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); | |
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 | ||
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 | } |