1 #include <sys/types.h>
2 #include <netinet/in.h>
3 #include <arpa/inet.h>
4 #include <sys/socket.h>
5 #include <sys/stat.h>
6 #include <sys/un.h>
7 #include <unistd.h>
8 #include <string.h>
9 #include <errno.h>
10 #include "byte.h"
11 #include "buffer.h"
12 #include "error.h"
13 #include "strerr.h"
14 #include "scan.h"
15 #include "env.h"
16 #include "prot.h"
17 #include "sig.h"
18 #include "open.h"
19 #include "sgetopt.h"
20
21 #define SYSLOG_NAMES
22 #include <syslog.h>
23
24 #if defined(__sun__) && defined(__sparc__) && defined(__unix__) && defined(__svr4__)
25 #define SOLARIS
26 # include <stropts.h>
27 # include <sys/strlog.h>
28 # include <fcntl.h>
29 # include "syslognames.h"
30 #if WANT_SUN_DOOR
31 # include <door.h>
32 #endif
33 #endif
34
35 /* #define WARNING "socklog: warning: " */
36 #define FATAL "socklog: fatal: "
37
38 #ifdef SOLARIS
39 #define USAGE " [-rRU] [unix|inet|ucspi|sun_stream] [args]"
40 #else
41 #define USAGE " [-rRU] [unix|inet|ucspi] [args]"
42 #endif
43
44 #define VERSION "$Id: socklog.c,v 1.18 2004/06/26 09:36:25 pape Exp $"
45 #define DEFAULTINET "0"
46 #define DEFAULTPORT "514"
47 #define DEFAULTUNIX "/dev/log"
48
49 const char *progname;
50
51 #define LINEC 1024
52 #define MODE_UNIX 0
53 #define MODE_INET 1
54 #define MODE_UCSPI 2
55 #ifdef SOLARIS
56 #define MODE_SUN_STREAM 3
57 #endif
58
59 int mode =MODE_UNIX;
60 char line[LINEC];
61 const char *address =NULL;
62 char *uid, *gid;
63 unsigned int lograw =0;
64 unsigned int noumask =0;
65
66 int flag_exitasap = 0;
sig_term_catch(void)67 void sig_term_catch(void) {
68 flag_exitasap = 1;
69 }
70
usage()71 void usage() {
72 strerr_die4x(1, "usage: ", progname, USAGE, "\n");
73 }
74
out(const char * s1,const char * s2)75 void out(const char *s1, const char *s2) {
76 if (s1) buffer_puts(buffer_1, s1);
77 if (s2) buffer_puts(buffer_1, s2);
78 }
err(const char * s1,const char * s2,const char * s3)79 void err(const char *s1, const char *s2, const char *s3) {
80 if (s1) buffer_puts(buffer_2, s1);
81 if (s2) buffer_puts(buffer_2, s2);
82 if (s3) buffer_puts(buffer_2, s3);
83 }
84
setuidgid()85 void setuidgid() {
86 /* drop permissions */
87 if ((gid = env_get("GID")) != NULL) {
88 unsigned long g;
89
90 scan_ulong(gid, &g);
91 err("gid=", gid, ", ");
92 if (prot_gid(g) == -1)
93 strerr_die2sys(111, FATAL, "unable to setgid: ");
94 }
95 if ((uid = env_get("UID")) != NULL) {
96 unsigned long u;
97
98 scan_ulong(uid, &u);
99 err("uid=", uid, ", ");
100 if (prot_uid(u) == -1)
101 strerr_die2sys(111, FATAL, "unable to setuid: ");
102 }
103 }
104
print_syslog_names(int fpr,buffer * buf)105 int print_syslog_names(int fpr, buffer *buf) {
106 int fp =LOG_FAC(fpr) <<3;
107 CODE *p;
108 int rc =1;
109 for (p =facilitynames; p->c_name; p++) {
110 if (p->c_val == fp) {
111 buffer_puts(buf, p->c_name);
112 buffer_puts(buf, ".");
113 break;
114 }
115 }
116 if (! p->c_name) {
117 buffer_puts(buf, "unknown.");
118 rc =0;
119 }
120 fp =LOG_PRI(fpr);
121 for (p =prioritynames; p->c_name; p++) {
122 if (p->c_val == fp) {
123 buffer_puts(buf, p->c_name);
124 buffer_puts(buf, ": ");
125 break;
126 }
127 }
128 if (! p->c_name) {
129 buffer_puts(buf, "unknown: ");
130 rc =0;
131 }
132 return(rc);
133 }
134
scan_syslog_names(char * l,int lc,buffer * buf)135 int scan_syslog_names (char *l, int lc, buffer *buf) {
136 int i;
137 int ok =0;
138 int fpr =0;
139
140 if (l[0] != '<') return(0);
141 for (i =1; (i < 5) && (i < lc); i++) {
142 if (l[i] == '>') {
143 ok =1;
144 break;
145 }
146 if (('0' <= l[i]) && (l[i] <= '9')) {
147 fpr =10 *fpr + l[i] -'0';
148 } else {
149 return(0);
150 }
151 }
152 if (!ok || !fpr) return(0);
153 return(print_syslog_names(fpr, buf) ? ++i : 0);
154 }
155
remote_info(struct sockaddr_in * sa)156 void remote_info (struct sockaddr_in *sa) {
157 char *host;
158
159 host =inet_ntoa(sa->sin_addr);
160 out(host, ": ");
161 }
162
socket_unix(const char * f)163 int socket_unix (const char* f) {
164 int s;
165 struct sockaddr_un sa;
166
167 if ((s =socket(AF_UNIX, SOCK_DGRAM, 0)) == -1)
168 strerr_die2sys(111, FATAL, "socket(): ");
169 byte_zero(&sa, sizeof(sa));
170 sa.sun_family =AF_UNIX;
171 strncpy(sa.sun_path, f, sizeof(sa.sun_path));
172 unlink(f);
173 if (! noumask) umask(0);
174 if (bind(s, (struct sockaddr*) &sa, sizeof sa) == -1)
175 strerr_die2sys(111, FATAL, "bind(): ");
176
177 err("listening on ", f, ", ");
178 return(s);
179 }
180
socket_inet(const char * ip,const char * port)181 int socket_inet (const char* ip, const char* port) {
182 int s;
183 unsigned long p;
184 struct sockaddr_in sa;
185
186 byte_zero(&sa, sizeof(sa));
187 if (ip[0] == '0') {
188 sa.sin_addr.s_addr =INADDR_ANY;
189 } else {
190 #ifndef SOLARIS
191 if (inet_aton(ip, &sa.sin_addr) == 0) {
192 strerr_die2sys(111, FATAL, "inet_aton(): ");
193 }
194 #else
195 sa.sin_addr.s_addr =inet_addr(ip);
196 #endif
197 }
198 if ((s =socket(AF_INET, SOCK_DGRAM, 0)) == -1)
199 strerr_die2sys(111, FATAL, "socket(): ");
200 if (scan_ulong(port, &p) == 0)
201 strerr_die3x(111, FATAL, "bad port number: ", port);
202
203 sa.sin_family =AF_INET;
204 sa.sin_port =htons(p);
205 if (bind(s, (struct sockaddr*) &sa, sizeof sa) == -1)
206 strerr_die2sys(111, FATAL, "bind(): ");
207
208 ip =inet_ntoa(sa.sin_addr);
209 err("listening on ", ip, 0);
210 err(":", port, ", ");
211 return(s);
212 }
213
read_socket(int s)214 int read_socket (int s) {
215 sig_catch(sig_term, sig_term_catch);
216 sig_catch(sig_int, sig_term_catch);
217 /* drop permissions */
218 setuidgid();
219 buffer_putsflush(buffer_2, "starting.\n");
220
221 for(;;) {
222 struct sockaddr_in saf;
223 int dummy =sizeof saf;
224 int linec;
225 int os;
226
227 linec =recvfrom(s, line, LINEC, 0, (struct sockaddr *) &saf, &dummy);
228 if (linec == -1) {
229 if (errno != error_intr)
230 strerr_die2sys(111, FATAL, "recvfrom(): ");
231 else
232 linec =0;
233 }
234 if (flag_exitasap) break;
235
236 while (linec && (line[linec -1] == 0)) linec--;
237 if (linec == 0) continue;
238
239 if (lograw) {
240 buffer_put(buffer_1, line, linec);
241 if (line[linec -1] != '\n') {
242 if (linec == LINEC) out("...", 0);
243 out("\n", 0);
244 }
245 if (lograw == 2) {
246 buffer_flush(buffer_1);
247 continue;
248 }
249 }
250
251 if (mode == MODE_INET) remote_info(&saf);
252 os =scan_syslog_names(line, linec, buffer_1);
253
254 buffer_put(buffer_1, line +os, linec -os);
255 if (line[linec -1] != '\n') {
256 if (linec == LINEC) out("...", 0);
257 out("\n", 0);
258 }
259 buffer_flush(buffer_1);
260 }
261 return(0);
262 }
263
read_ucspi(int fd,const char ** vars)264 int read_ucspi (int fd, const char **vars) {
265 char *envs[9];
266 int flageol =1;
267 int i;
268
269 for (i =0; *vars && (i < 8); vars++) {
270 if ((envs[i] =env_get(*vars)) != NULL)
271 i++;
272 }
273 envs[i] =NULL;
274
275 for(;;) {
276 int linec;
277 char *l, *p;
278
279 linec =buffer_get(buffer_0, line, LINEC);
280 if (linec == -1)
281 strerr_die2sys(111, FATAL, "read(): ");
282
283 if (linec == 0) {
284 if (! flageol) err("\n", 0, 0);
285 buffer_flush(buffer_2);
286 return(0);
287 }
288
289 for (l =p =line; l -line < linec; l++) {
290 if (flageol) {
291 if (! *l || (*l == '\n')) continue;
292 for (i =0; envs[i]; i++) {
293 err(envs[i], ": ", 0);
294 }
295 /* could fail on eg <13\0>user.notice: ... */
296 l += scan_syslog_names(l, line -l +linec, buffer_2);
297 p =l;
298 flageol =0;
299 }
300 if (! *l || (*l == '\n')) {
301 buffer_put(buffer_2, p, l -p);
302 buffer_putsflush(buffer_2, "\n");
303 flageol =1;
304 }
305 }
306 if (!flageol) buffer_putflush(buffer_2, p, l -p);
307 }
308 }
309
310 #ifdef SOLARIS
311 #if WANT_SUN_DOOR
door_proc(void * cookie,char * argp,size_t arg_size,door_desc_t * dp,uint_t ndesc)312 static void door_proc(void *cookie, char *argp, size_t arg_size,
313 door_desc_t *dp, uint_t ndesc) {
314 door_return(NULL, 0, NULL, 0);
315 return;
316 }
317
door_setup(const char * door)318 static int door_setup(const char *door) {
319 int dfd;
320 struct door_info di;
321
322 if ( (dfd = open_trunc(door)) == -1)
323 strerr_die2sys(111, FATAL, "open_trunc(): ");
324
325 if (door_info(dfd, &di) == -1) {
326 if (errno != EBADF)
327 strerr_die2sys(111, FATAL, "door_info(): ");
328 }
329 else {
330 /*XXX: could log the pid of the door owner. */
331 if (di.di_target != -1)
332 strerr_die4x(100, FATAL, "door ", door, " allready in use.");
333 }
334
335 close(dfd);
336 fdetach(door); /* highjack the door file */
337
338 if ((dfd =door_create(door_proc, NULL, 0)) == -1)
339 strerr_die2sys(111, FATAL, "door_create(): ");
340
341 if (fattach(dfd, door) == -1)
342 strerr_die2sys(111, FATAL, "fattach(): ");
343
344 err("door path is ", door, ", ");
345 return(dfd);
346 }
347 #endif /*WANT_SUN_DOOR*/
348
stream_sun(const char * address)349 static int stream_sun(const char *address) {
350 int sfd;
351 struct strioctl sc;
352
353 if ((sfd = open(address, O_RDONLY | O_NOCTTY)) == -1)
354 strerr_die2sys(111, FATAL, "open(): ");
355
356 memset(&sc, 0, sizeof(sc));
357 sc.ic_cmd =I_CONSLOG;
358 if (ioctl(sfd, I_STR, &sc) < 0)
359 strerr_die2sys(111, FATAL, "ioctl(): ");
360
361 err("sun_stream is ", address, ", ");
362 return(sfd);
363 }
364
read_stream_sun(int fd)365 static void read_stream_sun(int fd) {
366 struct strbuf ctl, data;
367 struct log_ctl logctl;
368 int flags;
369
370 ctl.maxlen =ctl.len =sizeof(logctl);
371 ctl.buf =(char *) &logctl;
372 data.maxlen =LINEC;
373 data.len =0;
374 data.buf =line;
375 flags =0;
376
377 sig_catch(sig_term, sig_term_catch);
378 sig_catch(sig_int, sig_term_catch);
379 setuidgid();
380 buffer_putsflush(buffer_2, "starting.\n");
381
382 /* read the messages */
383 for (;;) {
384
385 if ((getmsg(fd, &ctl, &data, &flags) & MORECTL) && (errno != error_intr))
386 strerr_die2sys(111, FATAL, "getmsg(): ");
387
388 if (flag_exitasap)
389 return;
390
391 if (data.len) {
392 int shorten =data.len;
393 if (!line[shorten-1])
394 shorten--;
395 while (line[shorten-1] == '\n')
396 shorten--;
397
398 (void) print_syslog_names(logctl.pri, buffer_1);
399
400 buffer_put(buffer_1, line, shorten);
401 if (data.len == LINEC) out("...", 0);
402 out("\n", 0);
403
404 buffer_flush(buffer_1);
405 }
406 }
407 }
408
409 #endif
410
main(int argc,const char ** argv,const char * const * envp)411 int main(int argc, const char **argv, const char *const *envp) {
412 int opt;
413 int s =0;
414
415 progname =*argv;
416
417 while ((opt =getopt(argc, argv, "rRUV")) != opteof) {
418 switch(opt) {
419 case 'r': lograw =1; break;
420 case 'R': lograw =2; break;
421 case 'U': noumask =1; break;
422 case 'V':
423 err(VERSION, 0, 0);
424 buffer_putsflush(buffer_2, "\n\n");
425 case '?': usage();
426 }
427 }
428 argv +=optind;
429
430 if (*argv) {
431 switch (**argv) {
432 case 'u':
433 if (! *(++*argv)) usage();
434 switch (**argv) {
435 case 'n':
436 mode =MODE_UNIX;
437 break;
438 case 'c':
439 mode =MODE_UCSPI;
440 argv--;
441 break;
442 default:
443 usage();
444 }
445 break;
446 case 'i':
447 mode =MODE_INET;
448 break;
449 #ifdef SOLARIS
450 case 's':
451 mode =MODE_SUN_STREAM;
452 break;
453 #endif
454 default:
455 usage();
456 }
457 argv++;
458 }
459
460 if (*argv) address =*argv++;
461
462 switch (mode) {
463 case MODE_INET: {
464 const char* port =NULL;
465
466 if (*argv) port =*argv++;
467 if (*argv) usage();
468 if (!address) address =DEFAULTINET;
469 if (!port) port =DEFAULTPORT;
470 s =socket_inet(address, port);
471 return(read_socket(s));
472 }
473 case MODE_UNIX: {
474 if (*argv) usage();
475 if (!address) address =DEFAULTUNIX;
476 s =socket_unix(address);
477 return(read_socket(s));
478 }
479 #ifdef SOLARIS
480 case MODE_SUN_STREAM: {
481 #if WANT_SUN_DOOR
482 const char *door =NULL;
483 int dfd =-1;
484 if (*argv) door =*argv++;
485 #endif
486 if (!address) address =DEFAULTUNIX;
487 if (*argv) usage();
488
489 s =stream_sun(address);
490
491 #if WANT_SUN_DOOR
492 if (door)
493 dfd = door_setup(door);
494 #endif
495
496 read_stream_sun(s);
497
498 #if WANT_SUN_DOOR
499 if (dfd != -1)
500 door_revoke(dfd);
501 /*
502 ** syslogd does unlink() the door file, but we can't, since we droped
503 ** all privs before.
504 */
505 #endif
506 return 0;
507 }
508 #endif /*SOLARIS*/
509 case MODE_UCSPI:
510 s =0;
511 return(read_ucspi(0, argv));
512 }
513 /* not reached */
514 return(1);
515 }
516