Subject: fixing syslogd so that outbound forwarding works with -s...
To: None <tech-security@netbsd.org>
From: Luke Mewburn <lukem@cs.rmit.edu.au>
List: tech-security
Date: 02/18/2000 11:30:08
  by redmail.netbsd.org with SMTP; 18 Feb 2000 00:30:12 -0000
	by wombat.cs.rmit.edu.au (8.9.3/8.9.3/cshub) with ESMTP id LAA17209
	for <tech-security@netbsd.org>; Fri, 18 Feb 2000 11:30:08 +1100 (EST)
Message-Id: <200002180030.LAA17209@wombat.cs.rmit.edu.au>
From: Luke Mewburn <lukem@cs.rmit.edu.au>
Reply-to: lukem@cs.rmit.edu.au
To: tech-security@netbsd.org
Subject: fixing syslogd so that outbound forwarding works with -s...
Date: Fri, 18 Feb 2000 11:30:08 +1100

the -s option on syslogd (`secure') stops it listening on internet
sockets. it has the side effect of preventing outbound forwarding
from working as well, which is rather annoying when you have a cluster
of machines and a loghost (where the loghost has filter rules to limit
the clients).

i've whipped up a patch against -current, but i'm not 100% sure it
will prevent DoS attacks against the machine by people trying to fill
up the incoming socket buffers. i've done a shutdown(, SHUT_RD) on the
sockets, but i understand some kernel work will be required to ensure
that this works for UDP.

or should i just listen on the socket, read any data, and toss it if -s
is set? (which probably involves more CPU time in syslogd; i think it's
better if the kernel does the tossing away)

any other problems/comments about what i'm doing?

btw; i still keep doing the `bind' because you may want the outgoing
syslogd packets to originate from the syslog port rather than an
ephemeral port, to allow tigher outgoing ipfilter rules.

Index: syslogd.c
===================================================================
RCS file: /cvsroot/basesrc/usr.sbin/syslogd/syslogd.c,v
retrieving revision 1.33
diff -p -p -r1.33 syslogd.c
*** syslogd.c	1999/12/13 04:25:08	1.33
--- syslogd.c	2000/02/18 00:16:09
*************** struct	filed consfile;
*** 187,194 ****
  int	Debug;			/* debug flag */
  char	LocalHostName[MAXHOSTNAMELEN+1];	/* our hostname */
  char	*LocalDomain;		/* our local domain name */
! int	InetInuse = 0;		/* non-zero if INET sockets are being used */
! int	*finet;			/* Internet datagram socket */
  int	Initialized = 0;	/* set when we have initialized ourselves */
  int	MarkInterval = 20 * 60;	/* interval between marks in seconds */
  int	MarkSeq = 0;		/* mark sequence number */
--- 187,193 ----
  int	Debug;			/* debug flag */
  char	LocalHostName[MAXHOSTNAMELEN+1];	/* our hostname */
  char	*LocalDomain;		/* our local domain name */
! int	*finet;			/* Internet datagram sockets */
  int	Initialized = 0;	/* set when we have initialized ourselves */
  int	MarkInterval = 20 * 60;	/* interval between marks in seconds */
  int	MarkSeq = 0;		/* mark sequence number */
*************** main(argc, argv)
*** 320,333 ****
  		dprintf("listening on unix dgram socket %s\n", *pp);
  	}
  
! 	if (!SecureMode) 
! 		finet = socksetup(PF_UNSPEC);
! 	else
! 		finet = NULL;
! 
! 	if (finet && *finet) {
! 		dprintf("listening on inet and/or inet6 socket\n");
! 		InetInuse = 1;
  	}
  
  	if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) < 0) {
--- 319,336 ----
  		dprintf("listening on unix dgram socket %s\n", *pp);
  	}
  
! 	finet = socksetup(PF_UNSPEC);
! 	if (finet) {
! 		if (SecureMode) {
! 			for (j = 0; j < *finet; j++) {
! 				if (shutdown(finet[j+1], SHUT_RD) < 0) {
! 					logerror("shutdown");
! 					die(0);
! 				}
! 			}
! 		} else
! 			dprintf("listening on inet and/or inet6 socket\n");
! 		dprintf("sending on inet and/or inet6 socket\n");
  	}
  
  	if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) < 0) {
*************** main(argc, argv)
*** 358,364 ****
  		readfds[nfklogix].fd = fklog;
  		readfds[nfklogix].events = POLLIN | POLLPRI;
  	}
! 	if (finet) {
  		nfinetix = malloc(*finet * sizeof(*nfinetix));
  		for (j = 0; j < *finet; j++) {
  			nfinetix[j] = nfds++;
--- 361,367 ----
  		readfds[nfklogix].fd = fklog;
  		readfds[nfklogix].events = POLLIN | POLLPRI;
  	}
! 	if (finet && !SecureMode) {
  		nfinetix = malloc(*finet * sizeof(*nfinetix));
  		for (j = 0; j < *finet; j++) {
  			nfinetix[j] = nfds++;
*************** main(argc, argv)
*** 418,433 ****
  				logerror(buf);
  			}
  		}
! 		if (finet) {
  			for (j = 0; j < *finet; j++) {
! 		    		if (readfds[nfinetix[j]].revents & (POLLIN | POLLPRI)) {
  					dprintf("inet socket active\n");
  					len = sizeof(frominet);
! 					i = recvfrom(finet[j+1], line, MAXLINE, 0,
! 			    				(struct sockaddr *)&frominet, &len);
  					if (i > 0) {
  						line[i] = '\0';
! 						printline(cvthname(&frominet), line);
  					} else if (i < 0 && errno != EINTR)
  						logerror("recvfrom inet");
  				}
--- 421,439 ----
  				logerror(buf);
  			}
  		}
! 		if (finet && !SecureMode) {
  			for (j = 0; j < *finet; j++) {
! 		    		if (readfds[nfinetix[j]].revents &
! 				    (POLLIN | POLLPRI)) {
  					dprintf("inet socket active\n");
  					len = sizeof(frominet);
! 					i = recvfrom(finet[j+1], line, MAXLINE,
! 					    0, (struct sockaddr *)&frominet,
! 					    &len);
  					if (i > 0) {
  						line[i] = '\0';
! 						printline(cvthname(&frominet),
! 						    line);
  					} else if (i < 0 && errno != EINTR)
  						logerror("recvfrom inet");
  				}
*************** main(argc, argv)
*** 439,447 ****
  void
  usage()
  {
  
  	(void)fprintf(stderr,
! 	    "usage: syslogd [-f conffile] [-m markinterval] [-p logpath1] [-p logpath2 ..]\n");
  	exit(1);
  }
  
--- 445,455 ----
  void
  usage()
  {
+ 	extern char *__progname;
  
  	(void)fprintf(stderr,
! "usage: %s [-f conffile] [-m markinterval] [-p logpath1] [-p logpath2 ..]\n",
! 	    __progname);
  	exit(1);
  }
  
*************** fprintlog(f, flags, msg)
*** 765,771 ****
  
  	case F_FORW:
  		dprintf(" %s\n", f->f_un.f_forw.f_hname);
! 		/* check for local vs remote messages (from FreeBSD PR#bin/7055) */
  		if (strcmp(f->f_prevhost, LocalHostName)) {
  			l = snprintf(line, sizeof(line) - 1,
  				     "<%d>%.15s [%s]: %s",
--- 773,782 ----
  
  	case F_FORW:
  		dprintf(" %s\n", f->f_un.f_forw.f_hname);
! 			/*
! 			 * check for local vs remote messages
! 			 * (from FreeBSD PR#bin/7055)
! 			 */
  		if (strcmp(f->f_prevhost, LocalHostName)) {
  			l = snprintf(line, sizeof(line) - 1,
  				     "<%d>%.15s [%s]: %s",
*************** fprintlog(f, flags, msg)
*** 778,791 ****
  		}
  		if (l > MAXLINE)
  			l = MAXLINE;
! 		if (finet && *finet) {
  			for (r = f->f_un.f_forw.f_addr; r; r = r->ai_next) {
  				for (j = 0; j < *finet; j++) {
  #if 0 
! 					/* should we check AF first, or just trial and error? FWD */
! 					if (r->ai_family == address_family_of(finet[j+1])) 
  #endif
! 					lsent = sendto(finet[j+1], line, l, 0, r->ai_addr, r->ai_addrlen);
  					if (lsent == l) 
  						break;
  				}
--- 789,807 ----
  		}
  		if (l > MAXLINE)
  			l = MAXLINE;
! 		if (finet) {
  			for (r = f->f_un.f_forw.f_addr; r; r = r->ai_next) {
  				for (j = 0; j < *finet; j++) {
  #if 0 
! 					/*
! 					 * should we check AF first, or just
! 					 * trial and error? FWD
! 					 */
! 					if (r->ai_family ==
! 					    address_family_of(finet[j+1])) 
  #endif
! 					lsent = sendto(finet[j+1], line, l, 0,
! 					    r->ai_addr, r->ai_addrlen);
  					if (lsent == l) 
  						break;
  				}
*************** init(signo)
*** 1115,1121 ****
  				break;
  
  			case F_USERS:
! 				for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
  					printf("%s, ", f->f_un.f_uname[i]);
  				break;
  			}
--- 1131,1138 ----
  				break;
  
  			case F_USERS:
! 				for (i = 0;
! 				    i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
  					printf("%s, ", f->f_un.f_uname[i]);
  				break;
  			}
*************** cfline(line, f)
*** 1211,1224 ****
  	switch (*p)
  	{
  	case '@':
! 		if (!InetInuse)
  			break;
  		(void)strcpy(f->f_un.f_forw.f_hname, ++p);
  		memset(&hints, 0, sizeof(hints));
  		hints.ai_family = AF_UNSPEC;
  		hints.ai_socktype = SOCK_DGRAM;
  		hints.ai_protocol = 0;
! 		error = getaddrinfo(f->f_un.f_forw.f_hname, "syslog", &hints, &res);
  		if (error) {
  			logerror(gai_strerror(error));
  			break;
--- 1228,1242 ----
  	switch (*p)
  	{
  	case '@':
! 		if (!finet)
  			break;
  		(void)strcpy(f->f_un.f_forw.f_hname, ++p);
  		memset(&hints, 0, sizeof(hints));
  		hints.ai_family = AF_UNSPEC;
  		hints.ai_socktype = SOCK_DGRAM;
  		hints.ai_protocol = 0;
! 		error = getaddrinfo(f->f_un.f_forw.f_hname, "syslog", &hints,
! 		    &res);
  		if (error) {
  			logerror(gai_strerror(error));
  			break;
*************** socksetup(af)
*** 1331,1337 ****
  	}
  
  	/* Count max number of sockets we may open */
! 	for (maxs = 0, r = res; r; r = r->ai_next, maxs++);
  	socks = malloc ((maxs+1) * sizeof(int));
  	if (!socks) {
  		logerror("couldn't allocate memory for sockets");
--- 1349,1356 ----
  	}
  
  	/* Count max number of sockets we may open */
! 	for (maxs = 0, r = res; r; r = r->ai_next, maxs++)
! 		continue;
  	socks = malloc ((maxs+1) * sizeof(int));
  	if (!socks) {
  		logerror("couldn't allocate memory for sockets");