Commit | Line | Data |
---|---|---|
e677da31 | 1 | #ifndef lint |
a24c481a | 2 | static char sccsid[] = "@(#)syslogd.c 4.6 (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 | |
10 | * the first three characters of the line. If this is | |
11 | * not present, a default priority (DefPri) is used, which | |
1386dfed | 12 | * starts out as LOG_NOTICE. The default priority can get |
e677da31 RC |
13 | * changed using "<*>n". |
14 | * | |
15 | * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will | |
16 | * cause it to reread its configuration file. | |
17 | * | |
18 | * Defined Constants: | |
19 | * | |
20 | * DAEMON -- Userid number to setuid to after setup. | |
21 | * MAXLINE -- the maximimum line length that can be handled. | |
22 | * NLOGS -- the maximum number of simultaneous log files. | |
23 | * NUSERS -- the maximum number of people that can | |
24 | * be designated as "superusers" on your system. | |
ada83039 RC |
25 | * |
26 | * Author: Eric Allman | |
27 | * Modified to use UNIX domain IPC by Ralph Campbell | |
e677da31 RC |
28 | */ |
29 | ||
30 | #define DAEMON 1 /* Daemon user-id */ | |
31 | #define NLOGS 10 /* max number of log files */ | |
32 | #define NSUSERS 10 /* max number of special users */ | |
33 | #define MAXLINE 1024 /* maximum line length */ | |
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> | |
e677da31 RC |
47 | #include <sys/socket.h> |
48 | #include <sys/file.h> | |
63cb489e | 49 | #include <sys/msgbuf.h> |
ada83039 | 50 | #include <sys/uio.h> |
e677da31 | 51 | #include <sys/un.h> |
a24c481a | 52 | |
e677da31 RC |
53 | #include <netinet/in.h> |
54 | #include <netdb.h> | |
55 | ||
56 | char logname[] = "/dev/log"; | |
57 | char defconf[] = "/etc/syslog.conf"; | |
58 | char defpid[] = "/etc/syslog.pid"; | |
59 | char ctty[] = "/dev/console"; | |
60 | ||
e677da31 RC |
61 | #define dprintf if (Debug) printf |
62 | ||
63 | #define UNAMESZ 8 /* length of a login name */ | |
64 | ||
65 | /* | |
66 | * This structure represents the files that will have log | |
67 | * copies printed. | |
68 | */ | |
69 | ||
70 | struct filed { | |
71 | int f_file; /* file descriptor */ | |
72 | short f_pmask; /* priority mask */ | |
73 | short f_flags; /* see #defines below */ | |
74 | struct sockaddr_in f_addr; /* forwarding address */ | |
75 | char f_name[248]; /* filename */ | |
76 | }; | |
77 | ||
1386dfed RC |
78 | #define F_TTY 001 /* file is a tty */ |
79 | #define F_MARK 002 /* write to the file periodically */ | |
80 | #define F_FORW 004 /* forward message to another host */ | |
81 | #define F_CONS 010 /* file is the console */ | |
e677da31 RC |
82 | |
83 | struct filed Files[NLOGS]; | |
84 | ||
85 | /* list of superusers */ | |
86 | struct susers { | |
87 | short s_pmask; /* priority mask */ | |
88 | char s_name[UNAMESZ+1]; | |
89 | }; | |
90 | ||
91 | struct susers Susers[NSUSERS]; | |
92 | ||
93 | int Debug; /* debug flag */ | |
94 | int LogFile; /* log file descriptor */ | |
1386dfed RC |
95 | int DefPri = LOG_NOTICE; /* default priority for untagged msgs */ |
96 | int DefSysPri = LOG_EMERG; /* default priority for untagged system msgs */ | |
ada83039 | 97 | int Sumask; /* lowest priority written to super-users */ |
e677da31 RC |
98 | int MarkIntvl = 15; /* mark interval in minutes */ |
99 | char *ConfFile = defconf; /* configuration file */ | |
ada83039 | 100 | char host[32]; /* our hostname */ |
e677da31 | 101 | char rhost[32]; /* hostname of sender (forwarded messages) */ |
ada83039 RC |
102 | int inet = 0; /* non-zero if INET sockets are being used */ |
103 | int port; /* port number for INET connections */ | |
e677da31 RC |
104 | |
105 | extern int errno, sys_nerr; | |
106 | extern char *sys_errlist[]; | |
107 | extern char *ctime(); | |
108 | ||
109 | main(argc, argv) | |
110 | int argc; | |
111 | char **argv; | |
112 | { | |
113 | register int i; | |
114 | register char *p; | |
63cb489e | 115 | int klog, funix, finet, defreadfds, len; |
e677da31 RC |
116 | struct sockaddr_un sun, fromunix; |
117 | struct sockaddr_in sin, frominet; | |
118 | FILE *fp; | |
63cb489e | 119 | char line[MSG_BSIZE + 1]; |
ada83039 | 120 | extern int die(), domark(); |
e677da31 RC |
121 | |
122 | sun.sun_family = AF_UNIX; | |
123 | strncpy(sun.sun_path, logname, sizeof sun.sun_path); | |
ada83039 | 124 | gethostname(host, sizeof host); |
e677da31 RC |
125 | |
126 | while (--argc > 0) { | |
127 | p = *++argv; | |
128 | if (p[0] == '-') { | |
129 | switch (p[1]) { | |
130 | case 'm': /* set mark interval */ | |
131 | MarkIntvl = atoi(&p[2]); | |
132 | if (MarkIntvl <= 0) | |
133 | MarkIntvl = 1; | |
134 | break; | |
135 | ||
136 | case 'f': /* configuration file */ | |
137 | if (p[2] != '\0') | |
138 | ConfFile = &p[2]; | |
139 | break; | |
140 | ||
141 | case 'd': /* debug */ | |
142 | Debug++; | |
143 | break; | |
144 | ||
ada83039 | 145 | case 'p': /* path */ |
e677da31 RC |
146 | if (p[2] != '\0') |
147 | strncpy(sun.sun_path, &p[2], | |
148 | sizeof sun.sun_path); | |
149 | break; | |
150 | } | |
151 | } | |
152 | } | |
153 | ||
154 | if (!Debug) { | |
155 | if (fork()) | |
156 | exit(0); | |
157 | for (i = 0; i < 10; i++) | |
158 | (void) close(i); | |
159 | (void) open("/", 0); | |
160 | (void) dup2(0, 1); | |
161 | (void) dup2(0, 2); | |
ada83039 | 162 | i = open("/dev/tty", O_RDWR); |
e677da31 RC |
163 | if (i >= 0) { |
164 | ioctl(i, TIOCNOTTY, (char *)0); | |
165 | (void) close(i); | |
166 | } | |
167 | } | |
168 | signal(SIGTERM, die); | |
e677da31 RC |
169 | funix = socket(AF_UNIX, SOCK_DGRAM, 0); |
170 | if (funix >= 0 && bind(funix, &sun, | |
171 | sizeof(sun.sun_family)+strlen(sun.sun_path)) < 0) { | |
172 | close(funix); | |
173 | funix = -1; | |
174 | } | |
175 | if (funix < 0) { | |
176 | fp = fopen(ctty, "w"); | |
177 | fprintf(fp, "\r\nsyslog: cannot create %s (%d)\r\n", logname, errno); | |
178 | dprintf("cannot create %s (%d)\n", logname, errno); | |
179 | exit(1); | |
180 | } | |
181 | defreadfds = 1 << funix; | |
182 | finet = socket(AF_INET, SOCK_DGRAM, 0); | |
183 | if (finet >= 0) { | |
184 | struct servent *sp; | |
185 | ||
186 | sp = getservbyname("syslog", "udp"); | |
187 | if (sp == NULL) { | |
188 | errno = 0; | |
189 | logerror("syslog/udp: unknown service"); | |
190 | die(); | |
191 | } | |
192 | sin.sin_family = AF_INET; | |
ada83039 | 193 | sin.sin_port = port = sp->s_port; |
e677da31 RC |
194 | if (bind(finet, &sin, sizeof(sin), 0) < 0) { |
195 | logerror("bind"); | |
196 | die(); | |
197 | } | |
198 | defreadfds |= 1 << finet; | |
ada83039 | 199 | inet = 1; |
e677da31 | 200 | } |
63cb489e RC |
201 | if ((klog = open("/dev/klog", O_RDONLY)) >= 0) |
202 | defreadfds |= 1 << klog; | |
203 | else | |
204 | dprintf("can't open /dev/klog (%d)\n", errno); | |
e677da31 RC |
205 | |
206 | /* tuck my process id away */ | |
207 | fp = fopen(defpid, "w"); | |
208 | if (fp != NULL) { | |
209 | fprintf(fp, "%d\n", getpid()); | |
210 | fclose(fp); | |
211 | } | |
212 | ||
213 | dprintf("off & running....\n"); | |
214 | ||
215 | for (i = 0; i < NLOGS; i++) | |
216 | Files[i].f_file = -1; | |
217 | init(); | |
454c883a RC |
218 | signal(SIGALRM, domark); |
219 | alarm(MarkIntvl * 60); | |
220 | ||
e677da31 | 221 | for (;;) { |
a24c481a | 222 | int nfds, readfds = defreadfds; |
e677da31 RC |
223 | |
224 | nfds = select(20, &readfds, 0, 0, 0); | |
225 | if (nfds == 0) | |
226 | continue; | |
227 | if (nfds < 0) { | |
228 | if (errno == EINTR) | |
229 | continue; | |
230 | logerror("select"); | |
231 | continue; | |
232 | } | |
233 | if (readfds & (1 << funix)) { | |
e677da31 RC |
234 | len = sizeof fromunix; |
235 | i = recvfrom(funix, line, MAXLINE, 0, &fromunix, &len); | |
a24c481a RC |
236 | if (i > 0) { |
237 | line[i] = '\0'; | |
238 | printline(1, line); | |
239 | } else if (i < 0 && errno != EINTR) | |
240 | logerror("recvfrom"); | |
241 | } | |
242 | if (readfds & (1 << finet)) { | |
e677da31 RC |
243 | len = sizeof frominet; |
244 | i = recvfrom(finet, line, MAXLINE, 0, &frominet, &len); | |
a24c481a RC |
245 | if (i > 0 && chkhost(&frominet)) { |
246 | line[i] = '\0'; | |
247 | printline(0, line); | |
248 | } else if (i < 0 && errno != EINTR) | |
249 | logerror("recvfrom"); | |
250 | } | |
251 | if (readfds & (1 << klog)) { | |
63cb489e | 252 | i = read(klog, line, sizeof(line) - 1); |
a24c481a RC |
253 | if (i > 0) { |
254 | line[i] = '\0'; | |
255 | printsys(line); | |
256 | } else if (i < 0 && errno != EINTR) | |
63cb489e | 257 | logerror("read"); |
e677da31 | 258 | } |
e677da31 RC |
259 | } |
260 | } | |
261 | ||
262 | /* | |
263 | * Take a raw input line, decode the message, and print the message | |
264 | * on the appropriate log files. | |
265 | */ | |
266 | ||
267 | printline(local, msg) | |
268 | int local; | |
269 | char *msg; | |
270 | { | |
271 | register char *p, *q; | |
272 | register int c; | |
63cb489e | 273 | char line[MAXLINE + 1]; |
e677da31 RC |
274 | int pri; |
275 | ||
276 | /* test for special codes */ | |
277 | pri = DefPri; | |
278 | p = msg; | |
279 | if (p[0] == '<' && p[2] == '>') { | |
280 | switch (p[1]) { | |
281 | case '*': /* reset default message priority */ | |
282 | dprintf("default priority = %c\n", p[3]); | |
283 | c = p[3] - '0'; | |
284 | if ((unsigned) c <= 9) | |
285 | DefPri = c; | |
286 | break; | |
287 | ||
288 | case '$': /* reconfigure */ | |
289 | dprintf("reconfigure\n"); | |
290 | init(); | |
291 | } | |
292 | p++; | |
293 | pri = *p++ - '0'; | |
294 | p++; | |
295 | if ((unsigned) pri > LOG_DEBUG) | |
296 | pri = DefPri; | |
297 | } | |
298 | ||
299 | q = line; | |
e677da31 | 300 | while ((c = *p++ & 0177) != '\0' && c != '\n' && |
63cb489e | 301 | q < &line[sizeof(line) - 1]) { |
e677da31 RC |
302 | if (iscntrl(c)) { |
303 | *q++ = '^'; | |
304 | *q++ = c ^ 0100; | |
305 | } else | |
306 | *q++ = c; | |
307 | } | |
e677da31 RC |
308 | *q = '\0'; |
309 | ||
1386dfed | 310 | logmsg(pri, line, local ? host : rhost, 0); |
e677da31 RC |
311 | } |
312 | ||
63cb489e RC |
313 | /* |
314 | * Take a raw input line from /dev/klog, split and format similar to syslog(). | |
315 | */ | |
316 | ||
317 | printsys(msg) | |
318 | char *msg; | |
319 | { | |
320 | register char *p, *q; | |
321 | register int c; | |
322 | char line[MAXLINE + 1]; | |
1386dfed RC |
323 | static char prevline[MAXLINE + 1]; |
324 | static int count = 0; | |
325 | int pri, ign; | |
63cb489e RC |
326 | long now; |
327 | ||
328 | time(&now); | |
329 | for (p = msg; *p != '\0'; ) { | |
330 | /* test for special codes */ | |
1386dfed RC |
331 | ign = 0; |
332 | pri = DefSysPri; | |
63cb489e RC |
333 | if (p[0] == '<' && p[2] == '>') { |
334 | switch (p[1]) { | |
335 | case '*': /* reset default message priority */ | |
336 | dprintf("default priority = %c\n", p[3]); | |
337 | c = p[3] - '0'; | |
338 | if ((unsigned) c <= 9) | |
1386dfed | 339 | DefSysPri = c; |
63cb489e RC |
340 | break; |
341 | ||
342 | case '$': /* reconfigure */ | |
343 | dprintf("reconfigure\n"); | |
344 | init(); | |
345 | } | |
346 | p++; | |
347 | pri = *p++ - '0'; | |
348 | p++; | |
349 | if ((unsigned) pri > LOG_DEBUG) | |
1386dfed RC |
350 | pri = DefSysPri; |
351 | } else | |
352 | ign = 1; /* kernel printf's come out on console */ | |
63cb489e RC |
353 | |
354 | q = line; | |
355 | sprintf(q, "vmunix: %.15s-- ", ctime(&now) + 4); | |
356 | q += strlen(q); | |
357 | while ((c = *p++) != '\0' && c != '\n' && | |
358 | q < &line[sizeof(line) - 1]) | |
359 | *q++ = c; | |
360 | *q = '\0'; | |
1386dfed RC |
361 | if (strcmp(line+26, prevline+26) == 0) { |
362 | count++; | |
363 | strncpy(prevline+8, line+8, 15); /* update time */ | |
364 | continue; | |
365 | } | |
366 | if (count) { | |
367 | if (count > 1) | |
368 | sprintf(prevline+26, | |
369 | "last message repeated %d times", count); | |
370 | logmsg(pri, prevline, host, ign); | |
371 | } | |
372 | count = 0; | |
373 | strcpy(prevline, line); | |
374 | logmsg(pri, line, host, ign); | |
63cb489e RC |
375 | } |
376 | } | |
377 | ||
e677da31 RC |
378 | /* |
379 | * Log a message to the appropriate log files, users, etc. based on | |
380 | * the priority. | |
381 | */ | |
382 | ||
1386dfed | 383 | logmsg(pri, msg, from, igncons) |
e677da31 | 384 | int pri; |
ada83039 | 385 | char *msg, *from; |
1386dfed | 386 | int igncons; |
e677da31 RC |
387 | { |
388 | char line[MAXLINE + 1]; | |
389 | register struct filed *f; | |
390 | register int l; | |
ada83039 RC |
391 | struct iovec iov[4]; |
392 | register struct iovec *v = iov; | |
393 | ||
394 | v->iov_base = from; | |
395 | v->iov_len = strlen(v->iov_base); | |
396 | v++; | |
397 | v->iov_base = " "; | |
398 | v->iov_len = 1; | |
399 | v++; | |
400 | v->iov_base = msg; | |
401 | v->iov_len = strlen(v->iov_base); | |
402 | v++; | |
e677da31 RC |
403 | /* log the message to the particular outputs */ |
404 | for (f = Files; f < &Files[NLOGS]; f++) { | |
405 | if (f->f_file < 0 || f->f_pmask < pri) | |
406 | continue; | |
1386dfed RC |
407 | if (igncons && (f->f_flags & F_CONS)) |
408 | continue; | |
409 | if (pri < 0) { /* mark message */ | |
410 | struct stat stb; | |
411 | long now; | |
412 | ||
413 | if (!(f->f_flags & F_MARK)) | |
414 | continue; | |
415 | if (fstat(f->f_file, &stb) < 0) | |
416 | continue; | |
417 | time(&now); | |
418 | if (!(f->f_flags & F_CONS) && | |
419 | stb.st_mtime > now - MarkIntvl * 60) | |
420 | continue; | |
421 | } | |
e677da31 RC |
422 | if (f->f_flags & F_FORW) { |
423 | sprintf(line, "<%d>%s", pri, msg); | |
424 | l = strlen(line); | |
425 | if (l > MAXLINE) | |
426 | l = MAXLINE; | |
427 | if (sendto(f->f_file, line, l, 0, | |
428 | &f->f_addr, sizeof f->f_addr) != l) | |
429 | logerror("sendto"); | |
430 | continue; | |
431 | } | |
ada83039 RC |
432 | if (f->f_flags & F_TTY) { |
433 | v->iov_base = "\r\n"; | |
434 | v->iov_len = 2; | |
435 | } else { | |
436 | v->iov_base = "\n"; | |
437 | v->iov_len = 1; | |
e677da31 | 438 | } |
ada83039 | 439 | if (writev(f->f_file, iov, 4) < 0) { |
e677da31 RC |
440 | logerror(f->f_name); |
441 | (void) close(f->f_file); | |
442 | f->f_file = -1; | |
443 | } | |
444 | } | |
445 | ||
446 | /* | |
447 | * Output high priority messages to terminals. | |
448 | */ | |
1386dfed | 449 | if (pri >= 0 && pri <= Sumask) |
ada83039 | 450 | wallmsg(pri, msg, from); |
e677da31 RC |
451 | } |
452 | ||
453 | /* | |
454 | * INIT -- Initialize syslog from configuration table | |
455 | * | |
456 | * The configuration table consists of a series of lines | |
457 | * broken into two sections by a blank line. The first | |
458 | * section gives a list of files to log on. The first | |
459 | * character is a digit which is the priority mask for | |
460 | * that file. If the second character is an asterisk, then | |
461 | * syslog arranges for something to be printed every fifteen | |
462 | * minutes (even if only a null line), so that crashes and | |
463 | * other events can be localized. The rest of the line is | |
464 | * the pathname of the log file. The second section is | |
465 | * a list of user names; these people are all notified | |
466 | * when subalert messages occur (if they are logged on). | |
467 | * | |
468 | * The configuration table will be reread by this routine | |
469 | * if a signal 1 occurs; for that reason, it is tricky | |
470 | * about not re-opening files and closing files it will | |
471 | * not be using. | |
472 | */ | |
473 | ||
474 | init() | |
475 | { | |
476 | register int i; | |
477 | register FILE *cf; | |
478 | register struct filed *f; | |
479 | register char *p; | |
480 | char cline[BUFSIZ]; | |
481 | struct servent *sp; | |
482 | struct hostent *hp; | |
483 | int pmask, flags; | |
484 | long now; | |
485 | ||
486 | dprintf("init\n"); | |
487 | ||
488 | /* ignore interrupts during this routine */ | |
489 | signal(SIGHUP, SIG_IGN); | |
490 | ||
491 | /* | |
492 | * Close all open log files. | |
493 | */ | |
494 | for (f = Files; f < &Files[NLOGS]; f++) { | |
1386dfed | 495 | if (f->f_file >= 0) |
e677da31 RC |
496 | (void) close(f->f_file); |
497 | f->f_file = -1; | |
498 | } | |
499 | ||
500 | /* open the configuration file */ | |
501 | if ((cf = fopen(ConfFile, "r")) == NULL) { | |
502 | dprintf("cannot open %s\n", ConfFile); | |
503 | f = Files; | |
504 | if ((f->f_file = open(ctty, O_WRONLY)) >= 0) { | |
505 | strncpy(f->f_name, ctty, sizeof(f->f_name)-1); | |
506 | f->f_pmask = LOG_CRIT; | |
1386dfed | 507 | f->f_flags = F_TTY|F_MARK|F_CONS; |
e677da31 RC |
508 | } |
509 | return; | |
510 | } | |
511 | ||
512 | /* | |
513 | * Foreach line in the conf table, open that file. | |
514 | */ | |
515 | f = Files; | |
516 | sp = getservbyname("syslogd", "udp"); | |
517 | while (fgets(cline, sizeof cline, cf) != NULL) { | |
518 | /* check for end-of-section */ | |
519 | if (cline[0] == '\n') | |
520 | break; | |
521 | ||
522 | /* strip off newline character */ | |
a24c481a RC |
523 | p = index(cline, '\n'); |
524 | if (p) | |
525 | *p = '\0'; | |
e677da31 RC |
526 | |
527 | dprintf("F: got line '%s'\n", cline); | |
528 | ||
529 | /* extract priority mask and mark flag */ | |
530 | p = cline; | |
531 | flags = 0; | |
532 | pmask = *p++ - '0'; | |
533 | if (*p == '*') { | |
534 | p++; | |
535 | flags |= F_MARK; | |
536 | } | |
537 | ||
538 | if (f >= &Files[NLOGS]) | |
539 | continue; | |
540 | ||
541 | /* mark entry as used and update flags */ | |
542 | if (*p == '@') { | |
ada83039 RC |
543 | if (!inet) |
544 | continue; | |
e677da31 | 545 | hp = gethostbyname(++p); |
ada83039 RC |
546 | if (hp == NULL) { |
547 | char buf[100]; | |
548 | ||
549 | sprintf(buf, "unknown host %s", p); | |
550 | errno = 0; | |
551 | logerror(buf); | |
552 | continue; | |
553 | } | |
554 | bzero(&f->f_addr, sizeof f->f_addr); | |
555 | f->f_addr.sin_family = AF_INET; | |
556 | f->f_addr.sin_port = port; | |
557 | bcopy(hp->h_addr, (char *) &f->f_addr.sin_addr, hp->h_length); | |
558 | f->f_file = socket(AF_INET, SOCK_DGRAM, 0); | |
559 | if (f->f_file < 0) { | |
560 | logerror("socket"); | |
561 | continue; | |
e677da31 RC |
562 | } |
563 | flags |= F_FORW; | |
564 | f->f_pmask = pmask; | |
565 | f->f_flags = flags; | |
566 | dprintf("Host %s pmask %d flags %o\n", p, pmask, flags); | |
567 | f++; | |
568 | continue; | |
569 | } | |
570 | strncpy(f->f_name, p, sizeof(f->f_name)-1); | |
1386dfed | 571 | if ((f->f_file = open(p, O_WRONLY|O_APPEND|O_NDELAY)) < 0) { |
e677da31 RC |
572 | logerror(p); |
573 | continue; | |
574 | } | |
575 | if (isatty(f->f_file)) | |
576 | flags |= F_TTY; | |
1386dfed RC |
577 | if (strcmp(p, ctty) == 0) |
578 | flags |= F_CONS; | |
e677da31 RC |
579 | f->f_pmask = pmask; |
580 | f->f_flags = flags; | |
581 | dprintf("File %s pmask %d flags %o\n", p, pmask, flags); | |
582 | f++; | |
583 | } | |
584 | ||
585 | /* | |
586 | * Read the list of users. | |
587 | * | |
588 | * Anyone in this list is informed directly if s/he | |
589 | * is logged in when a high priority message comes through. | |
590 | */ | |
ada83039 | 591 | Sumask = LOG_SALERT; |
e677da31 RC |
592 | for (i = 0; i < NSUSERS && fgets(cline, sizeof cline, cf) != NULL; i++) { |
593 | /* strip off newline */ | |
a24c481a RC |
594 | p = index(cline, '\n'); |
595 | if (p) | |
596 | *p = '\0'; | |
e677da31 RC |
597 | dprintf("U: got line '%s'\n", cline); |
598 | p = cline; | |
599 | if (isdigit(*p)) { | |
600 | Susers[i].s_pmask = pmask = *p++ - '0'; | |
601 | if (pmask > Sumask) | |
602 | Sumask = pmask; | |
603 | } else | |
ada83039 | 604 | Susers[i].s_pmask = pmask = LOG_SALERT; |
e677da31 RC |
605 | strncpy(Susers[i].s_name, p, UNAMESZ); |
606 | dprintf("Suser %s pmask %d\n", p, pmask); | |
607 | } | |
608 | ||
609 | /* zero the rest of the old superusers */ | |
610 | while (i < NSUSERS) | |
611 | Susers[i++].s_name[0] = '\0'; | |
612 | ||
613 | /* close the configuration file */ | |
614 | (void) fclose(cf); | |
615 | ||
ada83039 | 616 | dprintf("syslogd: restarted\n"); |
e677da31 RC |
617 | |
618 | /* arrange for signal 1 to reconfigure */ | |
619 | signal(SIGHUP, init); | |
620 | } | |
621 | ||
622 | /* | |
623 | * WALLMSG -- Write a message to the world at large | |
624 | * | |
625 | * Write the specified message to either the entire | |
626 | * world, or a list of approved users. | |
627 | */ | |
628 | ||
ada83039 | 629 | wallmsg(pri, msg, from) |
e677da31 | 630 | int pri; |
ada83039 | 631 | char *msg, *from; |
e677da31 RC |
632 | { |
633 | register char *p; | |
634 | register int i; | |
ada83039 RC |
635 | int f, flags, len, e; |
636 | FILE *uf; | |
e677da31 RC |
637 | struct utmp ut; |
638 | long now; | |
639 | char line[MAXLINE + 100]; | |
e677da31 RC |
640 | |
641 | /* open the user login file */ | |
ada83039 RC |
642 | if ((uf = fopen("/etc/utmp", "r")) == NULL) { |
643 | logerror("/etc/utmp"); | |
e677da31 | 644 | return; |
ada83039 | 645 | } |
e677da31 RC |
646 | |
647 | time(&now); | |
e677da31 | 648 | sprintf(line, |
ada83039 RC |
649 | "\r\n\7Message from syslogd@%s at %.24s ...\r\n%s\r\n", |
650 | from, ctime(&now), msg); | |
e677da31 RC |
651 | len = strlen(line); |
652 | ||
653 | /* scan the user login file */ | |
ada83039 | 654 | while (fread(&ut, sizeof ut, 1, uf) == 1) { |
e677da31 RC |
655 | /* is this slot used? */ |
656 | if (ut.ut_name[0] == '\0') | |
657 | continue; | |
658 | ||
659 | /* should we send the message to this user? */ | |
660 | if (pri != LOG_ALERT) { | |
661 | for (i = 0; i < NSUSERS; i++) { | |
662 | if (pri > Susers[i].s_pmask) | |
663 | continue; | |
664 | if (strncmp(Susers[i].s_name, ut.ut_name, | |
665 | sizeof ut.ut_name) == 0) | |
666 | goto prmsg; | |
667 | } | |
668 | continue; | |
669 | } | |
1386dfed | 670 | prmsg: |
e677da31 RC |
671 | |
672 | /* compute the device name */ | |
673 | p = "/dev/12345678"; | |
674 | strcpyn(&p[5], ut.ut_line, UNAMESZ); | |
675 | ||
676 | /* open the terminal */ | |
677 | f = open(p, O_WRONLY|O_NDELAY); | |
678 | if (f < 0) | |
679 | continue; | |
1386dfed RC |
680 | if ((flags = fcntl(f, F_GETFL, 0)) == -1) { |
681 | (void) close(f); | |
e677da31 | 682 | continue; |
1386dfed | 683 | } |
e677da31 RC |
684 | if (fcntl(f, F_SETFL, flags | FNDELAY) == -1) |
685 | goto oldway; | |
686 | i = write(f, line, len); | |
687 | e = errno; | |
688 | (void) fcntl(f, F_SETFL, flags); | |
689 | if (i == len || e != EWOULDBLOCK) { | |
690 | (void) close(f); | |
691 | continue; | |
692 | } | |
693 | oldway: | |
694 | if (fork() == 0) { | |
695 | (void) write(f, line, len); | |
696 | exit(0); | |
697 | } | |
698 | (void) close(f); | |
699 | } | |
700 | ||
701 | /* close the user login file */ | |
702 | (void) close(uf); | |
703 | } | |
704 | ||
705 | /* | |
706 | * Make sure every marked file gets written to periodically. | |
707 | * Reset the alarm clock to call itself after MarkIntvl minutes. | |
708 | */ | |
709 | domark() | |
710 | { | |
e677da31 RC |
711 | char buf[40]; |
712 | long now; | |
713 | ||
714 | dprintf("domark\n"); | |
715 | ||
716 | time(&now); | |
1386dfed RC |
717 | sprintf(buf, "syslogd: %.24s-- MARK", ctime(&now)); |
718 | logmsg(-1, buf, host, 0); | |
e677da31 RC |
719 | alarm(MarkIntvl * 60); |
720 | } | |
721 | ||
722 | /* | |
723 | * Check to see if we should log this message. | |
724 | */ | |
725 | chkhost(f) | |
726 | struct sockaddr_in *f; | |
727 | { | |
728 | struct hostent *hp; | |
729 | extern char *inet_ntoa(); | |
730 | ||
731 | dprintf("chkhost\n"); | |
732 | ||
733 | if (f->sin_family != AF_INET) { | |
734 | dprintf("Malformed from address\n"); | |
735 | return (0); | |
736 | } | |
737 | hp = gethostbyaddr(&f->sin_addr, sizeof(struct in_addr), f->sin_family); | |
738 | if (hp == 0) { | |
739 | dprintf("Host name for your address (%s) unknown\n", | |
740 | inet_ntoa(f->sin_addr)); | |
741 | return (0); | |
742 | } | |
743 | strncpy(rhost, hp->h_name, sizeof rhost); | |
744 | return (1); | |
745 | } | |
746 | ||
747 | /* | |
748 | * Print syslogd errors some place. | |
749 | */ | |
750 | logerror(type) | |
751 | char *type; | |
752 | { | |
753 | char buf[100]; | |
ada83039 | 754 | long now; |
e677da31 | 755 | |
ada83039 | 756 | time(&now); |
e677da31 | 757 | if (errno == 0) |
ada83039 | 758 | sprintf(buf, "syslogd: %.24s-- %s", ctime(&now), type); |
e677da31 | 759 | else if ((unsigned) errno > sys_nerr) |
ada83039 RC |
760 | sprintf(buf, "syslogd: %.24s-- %s: error %d", |
761 | ctime(&now), type, errno); | |
e677da31 | 762 | else |
ada83039 RC |
763 | sprintf(buf, "syslogd: %.24s-- %s: %s", |
764 | ctime(&now), type, sys_errlist[errno]); | |
e677da31 | 765 | errno = 0; |
ada83039 | 766 | dprintf("%s\n", buf); |
1386dfed | 767 | logmsg(LOG_ERR, buf, host, 0); |
e677da31 RC |
768 | } |
769 | ||
770 | die() | |
771 | { | |
ada83039 RC |
772 | |
773 | dprintf("syslogd: going down\n"); | |
e677da31 RC |
774 | (void) unlink(logname); |
775 | exit(0); | |
776 | } |