Commit | Line | Data |
---|---|---|
e677da31 | 1 | #ifndef lint |
dec31094 | 2 | static char sccsid[] = "@(#)syslogd.c 4.12 (Berkeley) %G%"; |
e677da31 RC |
3 | #endif |
4 | ||
5 | /* | |
6 | * syslogd -- log system messages | |
7 | * | |
8 | * This program implements a system log. It takes a series of lines. | |
9 | * Each line may have a priority, signified as "<n>" as | |
a49a6aba RC |
10 | * the first characters of the line. If this is |
11 | * not present, a default priority is used. | |
e677da31 RC |
12 | * |
13 | * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will | |
14 | * cause it to reread its configuration file. | |
15 | * | |
16 | * Defined Constants: | |
17 | * | |
e677da31 | 18 | * MAXLINE -- the maximimum line length that can be handled. |
a49a6aba RC |
19 | * NLOGS -- the maximum number of simultaneous log files. |
20 | * NUSERS -- the maximum number of people that can | |
21 | * be designated as "superusers" on your system. | |
22 | * DEFUPRI -- the default priority for user messages | |
23 | * DEFSPRI -- the default priority for kernel messages | |
ada83039 RC |
24 | * |
25 | * Author: Eric Allman | |
a49a6aba | 26 | * extensive changes by Ralph Campbell |
e677da31 RC |
27 | */ |
28 | ||
a49a6aba RC |
29 | #define NLOGS 10 /* max number of log files */ |
30 | #define NSUSERS 10 /* max number of special users */ | |
31 | #define MAXLINE 1024 /* maximum line length */ | |
32 | #define DEFUPRI LOG_NOTICE | |
dec31094 | 33 | #define DEFSPRI KERN_ERR |
e677da31 RC |
34 | |
35 | #include <syslog.h> | |
36 | #include <errno.h> | |
37 | #include <stdio.h> | |
38 | #include <utmp.h> | |
39 | #include <ctype.h> | |
a24c481a RC |
40 | #include <signal.h> |
41 | #include <sysexits.h> | |
42 | #include <strings.h> | |
43 | ||
e677da31 RC |
44 | #include <sys/types.h> |
45 | #include <sys/ioctl.h> | |
46 | #include <sys/stat.h> | |
84555b38 | 47 | #include <sys/wait.h> |
e677da31 RC |
48 | #include <sys/socket.h> |
49 | #include <sys/file.h> | |
63cb489e | 50 | #include <sys/msgbuf.h> |
ada83039 | 51 | #include <sys/uio.h> |
e677da31 | 52 | #include <sys/un.h> |
a24c481a | 53 | |
e677da31 RC |
54 | #include <netinet/in.h> |
55 | #include <netdb.h> | |
56 | ||
57 | char logname[] = "/dev/log"; | |
58 | char defconf[] = "/etc/syslog.conf"; | |
59 | char defpid[] = "/etc/syslog.pid"; | |
60 | char ctty[] = "/dev/console"; | |
61 | ||
e677da31 RC |
62 | #define dprintf if (Debug) printf |
63 | ||
64 | #define UNAMESZ 8 /* length of a login name */ | |
65 | ||
a49a6aba RC |
66 | #define mask(x) (1 << (x)) |
67 | ||
8a7154b1 RC |
68 | /* |
69 | * Flags to logmsg(). | |
70 | */ | |
71 | #define IGN_CONS 0x1 | |
72 | #define SYNC_FILE 0x2 | |
a49a6aba RC |
73 | #define NOCOPY 0x4 |
74 | #define ISMARK 0x10 | |
8a7154b1 | 75 | |
e677da31 RC |
76 | /* |
77 | * This structure represents the files that will have log | |
78 | * copies printed. | |
79 | */ | |
80 | ||
81 | struct filed { | |
82 | int f_file; /* file descriptor */ | |
a49a6aba RC |
83 | u_int f_pmask; /* priority mask */ |
84 | u_int f_flags; /* see #defines below */ | |
e677da31 RC |
85 | struct sockaddr_in f_addr; /* forwarding address */ |
86 | char f_name[248]; /* filename */ | |
87 | }; | |
88 | ||
1386dfed RC |
89 | #define F_TTY 001 /* file is a tty */ |
90 | #define F_MARK 002 /* write to the file periodically */ | |
91 | #define F_FORW 004 /* forward message to another host */ | |
92 | #define F_CONS 010 /* file is the console */ | |
e677da31 RC |
93 | |
94 | struct filed Files[NLOGS]; | |
95 | ||
96 | /* list of superusers */ | |
97 | struct susers { | |
a49a6aba | 98 | u_int s_pmask; /* priority mask */ |
e677da31 RC |
99 | char s_name[UNAMESZ+1]; |
100 | }; | |
101 | ||
102 | struct susers Susers[NSUSERS]; | |
103 | ||
104 | int Debug; /* debug flag */ | |
105 | int LogFile; /* log file descriptor */ | |
a49a6aba | 106 | u_int Sumask; /* priorities written to super-users */ |
e677da31 RC |
107 | int MarkIntvl = 15; /* mark interval in minutes */ |
108 | char *ConfFile = defconf; /* configuration file */ | |
ada83039 | 109 | char host[32]; /* our hostname */ |
e677da31 | 110 | char rhost[32]; /* hostname of sender (forwarded messages) */ |
ada83039 RC |
111 | int inet = 0; /* non-zero if INET sockets are being used */ |
112 | int port; /* port number for INET connections */ | |
a49a6aba RC |
113 | u_int Copymask = 0xffffffff; /* priorities to supress multiple copies */ |
114 | char prevline[MAXLINE + 1]; /* copy of last line to supress repeats */ | |
115 | char *prevdate; /* pointer to the date in prevline */ | |
116 | char prevhost[32]; /* previous host */ | |
117 | int prevflags; | |
118 | int prevpri; | |
119 | int count = 0; /* number of times seen */ | |
e677da31 RC |
120 | |
121 | extern int errno, sys_nerr; | |
122 | extern char *sys_errlist[]; | |
a49a6aba | 123 | extern char *ctime(), *index(); |
e677da31 RC |
124 | |
125 | main(argc, argv) | |
126 | int argc; | |
127 | char **argv; | |
128 | { | |
129 | register int i; | |
130 | register char *p; | |
84555b38 | 131 | int funix, finet, inetm, fklog, klogm, len; |
e677da31 RC |
132 | struct sockaddr_un sun, fromunix; |
133 | struct sockaddr_in sin, frominet; | |
134 | FILE *fp; | |
63cb489e | 135 | char line[MSG_BSIZE + 1]; |
84555b38 | 136 | extern int die(), domark(), reapchild(); |
e677da31 RC |
137 | |
138 | sun.sun_family = AF_UNIX; | |
139 | strncpy(sun.sun_path, logname, sizeof sun.sun_path); | |
ada83039 | 140 | gethostname(host, sizeof host); |
e677da31 RC |
141 | |
142 | while (--argc > 0) { | |
143 | p = *++argv; | |
a49a6aba RC |
144 | if (p[0] != '-') |
145 | usage(); | |
146 | switch (p[1]) { | |
147 | case 'm': /* set mark interval */ | |
148 | MarkIntvl = atoi(&p[2]); | |
149 | if (MarkIntvl <= 0) | |
150 | MarkIntvl = 1; | |
151 | break; | |
152 | ||
153 | case 'f': /* configuration file */ | |
154 | if (p[2] != '\0') | |
155 | ConfFile = &p[2]; | |
156 | break; | |
157 | ||
158 | case 'd': /* debug */ | |
159 | Debug++; | |
160 | break; | |
161 | ||
162 | case 'p': /* path */ | |
163 | if (p[2] != '\0') | |
164 | strncpy(sun.sun_path, &p[2], | |
165 | sizeof sun.sun_path); | |
166 | break; | |
167 | ||
168 | default: | |
169 | usage(); | |
e677da31 RC |
170 | } |
171 | } | |
172 | ||
173 | if (!Debug) { | |
174 | if (fork()) | |
175 | exit(0); | |
176 | for (i = 0; i < 10; i++) | |
177 | (void) close(i); | |
178 | (void) open("/", 0); | |
179 | (void) dup2(0, 1); | |
180 | (void) dup2(0, 2); | |
a49a6aba | 181 | untty(); |
84555b38 RC |
182 | } else |
183 | setlinebuf(stdout); | |
184 | ||
e677da31 | 185 | signal(SIGTERM, die); |
a49a6aba | 186 | signal(SIGINT, die); |
84555b38 | 187 | signal(SIGCHLD, reapchild); |
e677da31 | 188 | funix = socket(AF_UNIX, SOCK_DGRAM, 0); |
84555b38 RC |
189 | if (funix < 0 || bind(funix, &sun, |
190 | sizeof(sun.sun_family)+strlen(sun.sun_path)) < 0 || | |
191 | chmod(sun.sun_path, 0666) < 0) { | |
e677da31 | 192 | fp = fopen(ctty, "w"); |
a49a6aba | 193 | fprintf(fp, "\r\nsyslogd: cannot create %s (%d)\r\n", logname, errno); |
e677da31 RC |
194 | dprintf("cannot create %s (%d)\n", logname, errno); |
195 | exit(1); | |
196 | } | |
e677da31 RC |
197 | finet = socket(AF_INET, SOCK_DGRAM, 0); |
198 | if (finet >= 0) { | |
199 | struct servent *sp; | |
200 | ||
201 | sp = getservbyname("syslog", "udp"); | |
202 | if (sp == NULL) { | |
203 | errno = 0; | |
204 | logerror("syslog/udp: unknown service"); | |
205 | die(); | |
206 | } | |
207 | sin.sin_family = AF_INET; | |
ada83039 | 208 | sin.sin_port = port = sp->s_port; |
e677da31 RC |
209 | if (bind(finet, &sin, sizeof(sin), 0) < 0) { |
210 | logerror("bind"); | |
211 | die(); | |
212 | } | |
84555b38 | 213 | inetm = mask(finet); |
ada83039 | 214 | inet = 1; |
e677da31 | 215 | } |
84555b38 RC |
216 | if ((fklog = open("/dev/klog", O_RDONLY)) >= 0) |
217 | klogm = mask(fklog); | |
218 | else { | |
63cb489e | 219 | dprintf("can't open /dev/klog (%d)\n", errno); |
a49a6aba RC |
220 | klogm = 0; |
221 | } | |
e677da31 RC |
222 | |
223 | /* tuck my process id away */ | |
224 | fp = fopen(defpid, "w"); | |
225 | if (fp != NULL) { | |
226 | fprintf(fp, "%d\n", getpid()); | |
227 | fclose(fp); | |
228 | } | |
229 | ||
230 | dprintf("off & running....\n"); | |
231 | ||
232 | for (i = 0; i < NLOGS; i++) | |
233 | Files[i].f_file = -1; | |
234 | init(); | |
84555b38 | 235 | signal(SIGHUP, init); |
454c883a RC |
236 | signal(SIGALRM, domark); |
237 | alarm(MarkIntvl * 60); | |
238 | ||
e677da31 | 239 | for (;;) { |
84555b38 | 240 | int nfds, readfds = mask(funix) | inetm | klogm; |
e677da31 | 241 | |
84555b38 | 242 | dprintf("readfds = %#x\n", readfds, funix, finet, fklog); |
e677da31 | 243 | nfds = select(20, &readfds, 0, 0, 0); |
a49a6aba | 244 | dprintf("got a message (%d, %#x)\n", nfds, readfds); |
e677da31 RC |
245 | if (nfds == 0) |
246 | continue; | |
247 | if (nfds < 0) { | |
248 | if (errno == EINTR) | |
249 | continue; | |
250 | logerror("select"); | |
251 | continue; | |
252 | } | |
a49a6aba | 253 | if (readfds & klogm) { |
84555b38 | 254 | i = read(fklog, line, sizeof(line) - 1); |
8a7154b1 RC |
255 | if (i > 0) { |
256 | line[i] = '\0'; | |
257 | printsys(line); | |
a49a6aba | 258 | } else if (i < 0 && errno != EINTR) { |
84555b38 RC |
259 | logerror("klog"); |
260 | fklog = -1; | |
a49a6aba RC |
261 | klogm = 0; |
262 | } | |
8a7154b1 | 263 | } |
a49a6aba | 264 | if (readfds & mask(funix)) { |
e677da31 RC |
265 | len = sizeof fromunix; |
266 | i = recvfrom(funix, line, MAXLINE, 0, &fromunix, &len); | |
a24c481a RC |
267 | if (i > 0) { |
268 | line[i] = '\0'; | |
269 | printline(1, line); | |
270 | } else if (i < 0 && errno != EINTR) | |
271 | logerror("recvfrom"); | |
272 | } | |
84555b38 | 273 | if (readfds & inetm) { |
e677da31 RC |
274 | len = sizeof frominet; |
275 | i = recvfrom(finet, line, MAXLINE, 0, &frominet, &len); | |
a24c481a RC |
276 | if (i > 0 && chkhost(&frominet)) { |
277 | line[i] = '\0'; | |
278 | printline(0, line); | |
279 | } else if (i < 0 && errno != EINTR) | |
280 | logerror("recvfrom"); | |
281 | } | |
e677da31 RC |
282 | } |
283 | } | |
284 | ||
a49a6aba RC |
285 | usage() |
286 | { | |
287 | fprintf(stderr, "usage: syslogd [-m#] [-d] [-ppath] [-fconffile]\n"); | |
288 | exit(1); | |
289 | } | |
290 | ||
291 | untty() | |
292 | { | |
293 | int i; | |
294 | ||
295 | if (!Debug) { | |
296 | i = open("/dev/tty", O_RDWR); | |
297 | if (i >= 0) { | |
298 | ioctl(i, TIOCNOTTY, (char *)0); | |
299 | (void) close(i); | |
300 | } | |
301 | } | |
302 | } | |
303 | ||
e677da31 RC |
304 | /* |
305 | * Take a raw input line, decode the message, and print the message | |
306 | * on the appropriate log files. | |
307 | */ | |
308 | ||
309 | printline(local, msg) | |
310 | int local; | |
311 | char *msg; | |
312 | { | |
313 | register char *p, *q; | |
314 | register int c; | |
63cb489e | 315 | char line[MAXLINE + 1]; |
e677da31 RC |
316 | int pri; |
317 | ||
318 | /* test for special codes */ | |
a49a6aba | 319 | pri = DEFUPRI; |
e677da31 | 320 | p = msg; |
a49a6aba RC |
321 | if (*p == '<') { |
322 | pri = 0; | |
323 | while (isdigit(*++p)) | |
324 | pri = 10 * pri + (*p - '0'); | |
325 | if (*p == '>') | |
326 | ++p; | |
327 | if (pri <= 0 || pri >= 32) | |
328 | pri = DEFUPRI; | |
e677da31 RC |
329 | } |
330 | ||
331 | q = line; | |
e677da31 | 332 | while ((c = *p++ & 0177) != '\0' && c != '\n' && |
63cb489e | 333 | q < &line[sizeof(line) - 1]) { |
e677da31 RC |
334 | if (iscntrl(c)) { |
335 | *q++ = '^'; | |
336 | *q++ = c ^ 0100; | |
337 | } else | |
338 | *q++ = c; | |
339 | } | |
e677da31 RC |
340 | *q = '\0'; |
341 | ||
1386dfed | 342 | logmsg(pri, line, local ? host : rhost, 0); |
e677da31 RC |
343 | } |
344 | ||
63cb489e RC |
345 | /* |
346 | * Take a raw input line from /dev/klog, split and format similar to syslog(). | |
347 | */ | |
348 | ||
349 | printsys(msg) | |
350 | char *msg; | |
351 | { | |
352 | register char *p, *q; | |
353 | register int c; | |
354 | char line[MAXLINE + 1]; | |
8a7154b1 | 355 | int pri, flags; |
a49a6aba | 356 | char *lp; |
63cb489e RC |
357 | long now; |
358 | ||
359 | time(&now); | |
a49a6aba RC |
360 | sprintf(line, "vmunix: %.15s-- ", ctime(&now) + 4); |
361 | lp = line + strlen(line); | |
63cb489e | 362 | for (p = msg; *p != '\0'; ) { |
8a7154b1 | 363 | flags = SYNC_FILE; /* fsync file after write */ |
a49a6aba RC |
364 | pri = DEFSPRI; |
365 | if (*p == '<') { | |
366 | pri = 0; | |
367 | while (isdigit(*++p)) | |
368 | pri = 10 * pri + (*p - '0'); | |
369 | if (*p == '>') | |
370 | ++p; | |
371 | if (pri <= 0 || pri >= 32) | |
372 | pri = DEFSPRI; | |
8a7154b1 RC |
373 | } else { |
374 | /* kernel printf's come out on console */ | |
375 | flags |= IGN_CONS; | |
376 | } | |
a49a6aba RC |
377 | q = lp; |
378 | while (*p != '\0' && (c = *p++) != '\n' && | |
379 | q < &line[MAXLINE]) | |
63cb489e RC |
380 | *q++ = c; |
381 | *q = '\0'; | |
8a7154b1 | 382 | logmsg(pri, line, host, flags); |
63cb489e RC |
383 | } |
384 | } | |
385 | ||
e677da31 RC |
386 | /* |
387 | * Log a message to the appropriate log files, users, etc. based on | |
388 | * the priority. | |
389 | */ | |
390 | ||
8a7154b1 | 391 | logmsg(pri, msg, from, flags) |
e677da31 | 392 | int pri; |
ada83039 | 393 | char *msg, *from; |
8a7154b1 | 394 | int flags; |
e677da31 RC |
395 | { |
396 | char line[MAXLINE + 1]; | |
397 | register struct filed *f; | |
398 | register int l; | |
ada83039 RC |
399 | struct iovec iov[4]; |
400 | register struct iovec *v = iov; | |
84555b38 RC |
401 | int omask; |
402 | ||
403 | omask = sigblock(sigmask(SIGALRM)|sigmask(SIGHUP)); | |
ada83039 | 404 | |
a49a6aba RC |
405 | if ((flags & NOCOPY) == 0) { |
406 | register char *cp; | |
407 | ||
408 | /* | |
409 | * Check to see if copies should be supressed or | |
410 | * msg looks non-standard (e.g., 'prog: Feb 16 13:23:56-- '). | |
411 | */ | |
412 | if ((Copymask & mask(pri)) == 0 || | |
413 | (cp = index(msg, ':')) == NULL || strlen(cp) < 20 || | |
414 | cp[5] != ' ' || cp[8] != ' ' || cp[11] != ':' || | |
415 | cp[14] != ':' || cp[17] != '-' || cp[18] != '-' || | |
416 | cp[19] != ' ') | |
417 | flushmsg(); | |
418 | else if (!strncmp(msg, prevline, cp-msg) && | |
419 | !strcmp(cp+20, prevdate+18)) { | |
420 | /* we found a match, update the time */ | |
421 | strncpy(prevdate, cp+2, 15); | |
422 | count++; | |
2af4dea2 | 423 | (void) sigsetmask(omask); |
a49a6aba RC |
424 | return; |
425 | } else { | |
426 | /* new line, save it */ | |
427 | flushmsg(); | |
428 | strcpy(prevline, msg); | |
429 | strcpy(prevhost, from); | |
430 | prevdate = prevline + (cp - msg) + 2; | |
431 | prevflags = flags; | |
432 | prevpri = pri; | |
433 | } | |
434 | } | |
435 | ||
ada83039 RC |
436 | v->iov_base = from; |
437 | v->iov_len = strlen(v->iov_base); | |
438 | v++; | |
439 | v->iov_base = " "; | |
440 | v->iov_len = 1; | |
441 | v++; | |
442 | v->iov_base = msg; | |
443 | v->iov_len = strlen(v->iov_base); | |
444 | v++; | |
e677da31 RC |
445 | /* log the message to the particular outputs */ |
446 | for (f = Files; f < &Files[NLOGS]; f++) { | |
a49a6aba | 447 | if (f->f_file < 0) |
1386dfed | 448 | continue; |
a49a6aba | 449 | if (flags & ISMARK) { /* mark message */ |
1386dfed RC |
450 | if (!(f->f_flags & F_MARK)) |
451 | continue; | |
84555b38 RC |
452 | if (!(f->f_flags & F_CONS)) { |
453 | struct stat stb; | |
454 | long now; | |
455 | ||
456 | if (fstat(f->f_file, &stb) < 0) | |
457 | continue; | |
458 | time(&now); | |
459 | if (stb.st_mtime > now - MarkIntvl * 60) | |
460 | continue; | |
461 | } | |
a49a6aba RC |
462 | } else if ((f->f_pmask & mask(pri)) == 0 || |
463 | (flags & IGN_CONS) && (f->f_flags & F_CONS)) | |
464 | continue; | |
e677da31 RC |
465 | if (f->f_flags & F_FORW) { |
466 | sprintf(line, "<%d>%s", pri, msg); | |
467 | l = strlen(line); | |
468 | if (l > MAXLINE) | |
469 | l = MAXLINE; | |
470 | if (sendto(f->f_file, line, l, 0, | |
8a7154b1 RC |
471 | &f->f_addr, sizeof f->f_addr) != l) { |
472 | int e = errno; | |
473 | (void) close(f->f_file); | |
474 | f->f_file = -1; | |
475 | errno = e; | |
e677da31 | 476 | logerror("sendto"); |
8a7154b1 | 477 | } |
e677da31 RC |
478 | continue; |
479 | } | |
ada83039 RC |
480 | if (f->f_flags & F_TTY) { |
481 | v->iov_base = "\r\n"; | |
482 | v->iov_len = 2; | |
483 | } else { | |
484 | v->iov_base = "\n"; | |
485 | v->iov_len = 1; | |
e677da31 | 486 | } |
ada83039 | 487 | if (writev(f->f_file, iov, 4) < 0) { |
8a7154b1 | 488 | int e = errno; |
e677da31 | 489 | (void) close(f->f_file); |
84555b38 RC |
490 | /* |
491 | * Check for EBADF on the console due to vhangup() XXX | |
492 | */ | |
493 | if (e == EBADF && (f->f_flags & F_TTY)) { | |
494 | f->f_file = open(f->f_name, O_WRONLY|O_APPEND); | |
495 | if (f->f_file < 0) | |
496 | logerror(f->f_name); | |
497 | } else { | |
498 | f->f_file = -1; | |
499 | errno = e; | |
500 | logerror(f->f_name); | |
501 | } | |
8a7154b1 RC |
502 | } else if (flags & SYNC_FILE) |
503 | (void) fsync(f->f_file); | |
e677da31 RC |
504 | } |
505 | ||
506 | /* | |
507 | * Output high priority messages to terminals. | |
508 | */ | |
84555b38 | 509 | if (!(flags & ISMARK) && (mask(pri) & Sumask)) |
ada83039 | 510 | wallmsg(pri, msg, from); |
84555b38 RC |
511 | |
512 | (void) sigsetmask(omask); | |
e677da31 RC |
513 | } |
514 | ||
515 | /* | |
a49a6aba | 516 | * INIT -- Initialize syslogd from configuration table |
e677da31 | 517 | * |
a49a6aba RC |
518 | * The configuration table consists of a series of lines broken |
519 | * into two sections by a blank line. The first section gives a | |
520 | * list of files to log on. Each line begins with a | |
521 | * comma-separated list of digits or ranges of digits (pairs of | |
522 | * digits separated by a dash); if the priority of a message falls | |
523 | * in the set of digits defined by this list, then the message is | |
524 | * logged in the file corresponding to this line. If the | |
525 | * following character is an asterisk, then syslogd arranges for | |
526 | * something to be printed every fifteen minutes (even if only a | |
527 | * null line), so that crashes and other events can be localized. | |
528 | * The rest of the line is the pathname of the log file. The | |
529 | * second section is a list of user names; these people are all | |
530 | * notified when subalert messages occur (if they are logged on). | |
531 | * These lines may also have associated priority lists. | |
e677da31 | 532 | * |
a49a6aba RC |
533 | * The configuration table will be reread by this routine if a |
534 | * SIGHUP signal occurs; for that reason, it is tricky about not | |
535 | * re-opening files and closing files it will not be using. | |
e677da31 RC |
536 | */ |
537 | ||
538 | init() | |
539 | { | |
540 | register int i; | |
541 | register FILE *cf; | |
542 | register struct filed *f; | |
543 | register char *p; | |
544 | char cline[BUFSIZ]; | |
e677da31 RC |
545 | struct hostent *hp; |
546 | int pmask, flags; | |
547 | long now; | |
a49a6aba | 548 | char *getpmask(); |
e677da31 RC |
549 | |
550 | dprintf("init\n"); | |
551 | ||
a49a6aba RC |
552 | /* flush any pending output */ |
553 | flushmsg(); | |
554 | ||
e677da31 RC |
555 | /* |
556 | * Close all open log files. | |
557 | */ | |
558 | for (f = Files; f < &Files[NLOGS]; f++) { | |
1386dfed | 559 | if (f->f_file >= 0) |
e677da31 RC |
560 | (void) close(f->f_file); |
561 | f->f_file = -1; | |
562 | } | |
563 | ||
564 | /* open the configuration file */ | |
565 | if ((cf = fopen(ConfFile, "r")) == NULL) { | |
566 | dprintf("cannot open %s\n", ConfFile); | |
567 | f = Files; | |
568 | if ((f->f_file = open(ctty, O_WRONLY)) >= 0) { | |
569 | strncpy(f->f_name, ctty, sizeof(f->f_name)-1); | |
a49a6aba | 570 | f->f_pmask = mask(LOG_CRIT); |
1386dfed | 571 | f->f_flags = F_TTY|F_MARK|F_CONS; |
a49a6aba | 572 | untty(); |
e677da31 RC |
573 | } |
574 | return; | |
575 | } | |
576 | ||
577 | /* | |
578 | * Foreach line in the conf table, open that file. | |
579 | */ | |
580 | f = Files; | |
e677da31 RC |
581 | while (fgets(cline, sizeof cline, cf) != NULL) { |
582 | /* check for end-of-section */ | |
583 | if (cline[0] == '\n') | |
584 | break; | |
585 | ||
586 | /* strip off newline character */ | |
a24c481a RC |
587 | p = index(cline, '\n'); |
588 | if (p) | |
589 | *p = '\0'; | |
e677da31 RC |
590 | |
591 | dprintf("F: got line '%s'\n", cline); | |
592 | ||
593 | /* extract priority mask and mark flag */ | |
594 | p = cline; | |
595 | flags = 0; | |
a49a6aba | 596 | p = getpmask(p, &pmask); |
e677da31 RC |
597 | if (*p == '*') { |
598 | p++; | |
599 | flags |= F_MARK; | |
600 | } | |
601 | ||
602 | if (f >= &Files[NLOGS]) | |
603 | continue; | |
604 | ||
605 | /* mark entry as used and update flags */ | |
606 | if (*p == '@') { | |
ada83039 RC |
607 | if (!inet) |
608 | continue; | |
e677da31 | 609 | hp = gethostbyname(++p); |
ada83039 RC |
610 | if (hp == NULL) { |
611 | char buf[100]; | |
612 | ||
613 | sprintf(buf, "unknown host %s", p); | |
614 | errno = 0; | |
615 | logerror(buf); | |
616 | continue; | |
617 | } | |
618 | bzero(&f->f_addr, sizeof f->f_addr); | |
619 | f->f_addr.sin_family = AF_INET; | |
620 | f->f_addr.sin_port = port; | |
621 | bcopy(hp->h_addr, (char *) &f->f_addr.sin_addr, hp->h_length); | |
622 | f->f_file = socket(AF_INET, SOCK_DGRAM, 0); | |
623 | if (f->f_file < 0) { | |
624 | logerror("socket"); | |
625 | continue; | |
e677da31 RC |
626 | } |
627 | flags |= F_FORW; | |
628 | f->f_pmask = pmask; | |
629 | f->f_flags = flags; | |
a49a6aba | 630 | dprintf("Host %s pmask %#x flags %#x\n", p, pmask, flags); |
e677da31 RC |
631 | f++; |
632 | continue; | |
633 | } | |
634 | strncpy(f->f_name, p, sizeof(f->f_name)-1); | |
84555b38 | 635 | if ((f->f_file = open(p, O_WRONLY|O_APPEND)) < 0) { |
e677da31 RC |
636 | logerror(p); |
637 | continue; | |
638 | } | |
a49a6aba | 639 | if (isatty(f->f_file)) { |
e677da31 | 640 | flags |= F_TTY; |
a49a6aba RC |
641 | untty(); |
642 | } | |
1386dfed RC |
643 | if (strcmp(p, ctty) == 0) |
644 | flags |= F_CONS; | |
e677da31 RC |
645 | f->f_pmask = pmask; |
646 | f->f_flags = flags; | |
a49a6aba | 647 | dprintf("File %s pmask %#x flags %#x\n", p, pmask, flags); |
e677da31 RC |
648 | f++; |
649 | } | |
650 | ||
651 | /* | |
652 | * Read the list of users. | |
653 | * | |
654 | * Anyone in this list is informed directly if s/he | |
655 | * is logged in when a high priority message comes through. | |
656 | */ | |
4bbbecf7 | 657 | Sumask = mask(KERN_EMERG)|mask(LOG_EMERG); |
e677da31 RC |
658 | for (i = 0; i < NSUSERS && fgets(cline, sizeof cline, cf) != NULL; i++) { |
659 | /* strip off newline */ | |
a24c481a RC |
660 | p = index(cline, '\n'); |
661 | if (p) | |
662 | *p = '\0'; | |
e677da31 RC |
663 | dprintf("U: got line '%s'\n", cline); |
664 | p = cline; | |
84555b38 | 665 | if (isdigit(*p)) |
a49a6aba | 666 | p = getpmask(p, &pmask); |
84555b38 RC |
667 | else |
668 | pmask = mask(LOG_SALERT); | |
669 | Susers[i].s_pmask = pmask; | |
670 | Sumask |= pmask; | |
e677da31 | 671 | strncpy(Susers[i].s_name, p, UNAMESZ); |
a49a6aba | 672 | dprintf("Suser %s pmask %#x\n", p, pmask); |
e677da31 RC |
673 | } |
674 | ||
675 | /* zero the rest of the old superusers */ | |
676 | while (i < NSUSERS) | |
677 | Susers[i++].s_name[0] = '\0'; | |
678 | ||
679 | /* close the configuration file */ | |
680 | (void) fclose(cf); | |
681 | ||
ada83039 | 682 | dprintf("syslogd: restarted\n"); |
e677da31 RC |
683 | } |
684 | ||
685 | /* | |
686 | * WALLMSG -- Write a message to the world at large | |
687 | * | |
688 | * Write the specified message to either the entire | |
689 | * world, or a list of approved users. | |
690 | */ | |
691 | ||
ada83039 | 692 | wallmsg(pri, msg, from) |
e677da31 | 693 | int pri; |
ada83039 | 694 | char *msg, *from; |
e677da31 RC |
695 | { |
696 | register char *p; | |
697 | register int i; | |
ada83039 RC |
698 | int f, flags, len, e; |
699 | FILE *uf; | |
e677da31 RC |
700 | struct utmp ut; |
701 | long now; | |
702 | char line[MAXLINE + 100]; | |
e677da31 RC |
703 | |
704 | /* open the user login file */ | |
ada83039 | 705 | if ((uf = fopen("/etc/utmp", "r")) == NULL) { |
84555b38 RC |
706 | i = Sumask; |
707 | Sumask = 0; | |
ada83039 | 708 | logerror("/etc/utmp"); |
84555b38 | 709 | Sumask = i; |
e677da31 | 710 | return; |
ada83039 | 711 | } |
e677da31 RC |
712 | |
713 | time(&now); | |
e677da31 | 714 | sprintf(line, |
ada83039 RC |
715 | "\r\n\7Message from syslogd@%s at %.24s ...\r\n%s\r\n", |
716 | from, ctime(&now), msg); | |
e677da31 RC |
717 | len = strlen(line); |
718 | ||
719 | /* scan the user login file */ | |
ada83039 | 720 | while (fread(&ut, sizeof ut, 1, uf) == 1) { |
e677da31 RC |
721 | /* is this slot used? */ |
722 | if (ut.ut_name[0] == '\0') | |
723 | continue; | |
724 | ||
725 | /* should we send the message to this user? */ | |
726 | if (pri != LOG_ALERT) { | |
727 | for (i = 0; i < NSUSERS; i++) { | |
a49a6aba | 728 | if ((mask(pri) & Susers[i].s_pmask) == 0) |
e677da31 RC |
729 | continue; |
730 | if (strncmp(Susers[i].s_name, ut.ut_name, | |
84555b38 | 731 | UNAMESZ) == 0) |
e677da31 RC |
732 | goto prmsg; |
733 | } | |
734 | continue; | |
735 | } | |
1386dfed | 736 | prmsg: |
e677da31 RC |
737 | |
738 | /* compute the device name */ | |
739 | p = "/dev/12345678"; | |
740 | strcpyn(&p[5], ut.ut_line, UNAMESZ); | |
741 | ||
84555b38 RC |
742 | /* |
743 | * Might as well fork instead of using nonblocking I/O | |
744 | * and doing notty(). | |
745 | */ | |
e677da31 | 746 | if (fork() == 0) { |
84555b38 RC |
747 | signal(SIGALRM, SIG_DFL); |
748 | alarm(30); | |
749 | /* open the terminal */ | |
750 | f = open(p, O_WRONLY); | |
751 | if (f >= 0) | |
752 | (void) write(f, line, len); | |
e677da31 RC |
753 | exit(0); |
754 | } | |
e677da31 | 755 | } |
e677da31 | 756 | /* close the user login file */ |
84555b38 RC |
757 | (void) fclose(uf); |
758 | } | |
759 | ||
760 | reapchild() | |
761 | { | |
762 | union wait status; | |
763 | ||
764 | while (wait3(&status, WNOHANG, 0) > 0) | |
765 | ; | |
e677da31 RC |
766 | } |
767 | ||
768 | /* | |
769 | * Make sure every marked file gets written to periodically. | |
770 | * Reset the alarm clock to call itself after MarkIntvl minutes. | |
771 | */ | |
772 | domark() | |
773 | { | |
84555b38 | 774 | char buf[50]; |
e677da31 RC |
775 | long now; |
776 | ||
777 | dprintf("domark\n"); | |
778 | ||
779 | time(&now); | |
1386dfed | 780 | sprintf(buf, "syslogd: %.24s-- MARK", ctime(&now)); |
a49a6aba RC |
781 | flushmsg(); |
782 | logmsg(0, buf, host, NOCOPY|ISMARK); | |
e677da31 RC |
783 | alarm(MarkIntvl * 60); |
784 | } | |
785 | ||
786 | /* | |
787 | * Check to see if we should log this message. | |
788 | */ | |
789 | chkhost(f) | |
790 | struct sockaddr_in *f; | |
791 | { | |
792 | struct hostent *hp; | |
793 | extern char *inet_ntoa(); | |
794 | ||
795 | dprintf("chkhost\n"); | |
796 | ||
797 | if (f->sin_family != AF_INET) { | |
798 | dprintf("Malformed from address\n"); | |
799 | return (0); | |
800 | } | |
801 | hp = gethostbyaddr(&f->sin_addr, sizeof(struct in_addr), f->sin_family); | |
802 | if (hp == 0) { | |
803 | dprintf("Host name for your address (%s) unknown\n", | |
804 | inet_ntoa(f->sin_addr)); | |
805 | return (0); | |
806 | } | |
807 | strncpy(rhost, hp->h_name, sizeof rhost); | |
808 | return (1); | |
809 | } | |
810 | ||
a49a6aba RC |
811 | flushmsg() |
812 | { | |
813 | if (count == 0) | |
814 | return; | |
815 | if (count > 1) | |
816 | sprintf(prevdate+18, "last message repeated %d times", count); | |
84555b38 | 817 | count = 0; |
a49a6aba RC |
818 | logmsg(prevpri, prevline, prevhost, prevflags|NOCOPY); |
819 | prevline[0] = '\0'; | |
a49a6aba RC |
820 | } |
821 | ||
e677da31 RC |
822 | /* |
823 | * Print syslogd errors some place. | |
824 | */ | |
825 | logerror(type) | |
826 | char *type; | |
827 | { | |
828 | char buf[100]; | |
ada83039 | 829 | long now; |
e677da31 | 830 | |
ada83039 | 831 | time(&now); |
e677da31 | 832 | if (errno == 0) |
ada83039 | 833 | sprintf(buf, "syslogd: %.24s-- %s", ctime(&now), type); |
e677da31 | 834 | else if ((unsigned) errno > sys_nerr) |
ada83039 RC |
835 | sprintf(buf, "syslogd: %.24s-- %s: error %d", |
836 | ctime(&now), type, errno); | |
e677da31 | 837 | else |
ada83039 RC |
838 | sprintf(buf, "syslogd: %.24s-- %s: %s", |
839 | ctime(&now), type, sys_errlist[errno]); | |
e677da31 | 840 | errno = 0; |
ada83039 | 841 | dprintf("%s\n", buf); |
1386dfed | 842 | logmsg(LOG_ERR, buf, host, 0); |
e677da31 RC |
843 | } |
844 | ||
845 | die() | |
846 | { | |
ada83039 | 847 | |
a49a6aba | 848 | flushmsg(); |
ada83039 | 849 | dprintf("syslogd: going down\n"); |
e677da31 RC |
850 | (void) unlink(logname); |
851 | exit(0); | |
852 | } | |
a49a6aba RC |
853 | |
854 | /* | |
855 | * getpmask() parses a string cp looking for a set of numbers like | |
856 | * '1-5,8,16' and returns in *ppmask the set of bits represented by | |
857 | * these numbers. A notation '1-5' is interpreted to mean 'turn on | |
858 | * bits 1 through 5 inclusive'. getpmask() returns the address of | |
859 | * first byte after the number set. | |
860 | */ | |
861 | char * | |
862 | getpmask(cp, ppmask) | |
863 | register char *cp; | |
864 | unsigned *ppmask; | |
865 | { | |
866 | int count1, count2; | |
867 | register int i; | |
868 | ||
869 | *ppmask = 0; | |
870 | while (isdigit(*cp)) { | |
871 | count1 = count2 = 0; | |
872 | do { | |
873 | count1 = 10 * count1 + (*cp++ - '0'); | |
874 | } while (isdigit(*cp)); | |
875 | switch (*cp) { | |
876 | case ',': | |
877 | ++cp; | |
878 | /* FALL THRU */ | |
879 | default: | |
880 | *ppmask |= mask(count1); | |
881 | continue; | |
882 | ||
883 | case '-': | |
884 | while (isdigit(*++cp)) | |
885 | count2 = 10 * count2 + (*cp - '0'); | |
886 | for (i = count1; i <= count2; ++i) | |
887 | *ppmask |= mask(i); | |
888 | if (*cp == ',') | |
889 | ++cp; | |
890 | continue; | |
891 | } | |
892 | } | |
893 | ||
894 | return (cp); | |
895 | } |