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