Nobody ever seemed to be interested in reviewing these changes, and i

found that my syslogd is now running them for several months...

Add an option to syslogd to restrict the IP addresses that are allowed
to log to this syslogd.  It's too late to develop the inter-syslogd
communications protocol mentioned in the BUGS section, some 10 years
too late.  Thus, restricting the IP address range is about the most
effective change we can do if we want to allow incoming syslog
messages at all.

IMHO, we should encourage the system administrators to use this option,
and thus provide a knob in /etc/rc.* for it, defaulting to -a 127.0.0.1/32
(just as a hint about the usage).

Please state opinions about whether to merge this change into 2.2 or
not (i've got it running on RELENG_2_2 anyway).
This commit is contained in:
Joerg Wunsch 1997-05-03 22:17:43 +00:00
parent ce34628b4b
commit 3548606371
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=25437
2 changed files with 284 additions and 10 deletions

View File

@ -30,7 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)syslogd.8 8.1 (Berkeley) 6/6/93
.\" $Id: syslogd.8,v 1.9 1997/04/26 00:00:32 pst Exp $
.\" $Id: syslogd.8,v 1.10 1997/04/29 09:09:40 jmg Exp $
.\"
.Dd October 12, 1995
.Dt SYSLOGD 8
@ -40,10 +40,11 @@
.Nd log systems messages
.Sh SYNOPSIS
.Nm
.Op Fl \&dI
.Op Fl a Ar allowed_peer
.Op Fl f Ar config_file
.Op Fl m Ar mark_interval
.Op Fl p Ar log_socket
.Op Fl s
.Sh DESCRIPTION
The
.Nm
@ -51,6 +52,55 @@ daemon reads and logs messages to the system console, log files, other
machines and/or users as specified by its configuration file.
The options are as follows:
.Bl -tag -width Ds
.It Fl a Ar allowed_peer
Allow
.Ar allowed_peer
to log to this
.Nm syslogd
using UDP datagrams. Multiple
.Fl a
options may be specified.
.Pp
.Ar Allowed_peer
can be any of the following:
.Bl -tag -width "ipaddr/masklen[:service]XX"
.It Ar ipaddr/masklen Ns Op Ar :service
Accept datagrams from
.Ar ipaddr
(in the usual dotted quad notation) with
.Ar masklen
bits being taken into account when doing the address comparision. If
specified,
.Ar service
is the name or number of an UDP service (see
.Xr services 5 ) Ns
the source packet must belong to. A
.Ar service
of
.Ql \&*
allows packets being sent from any UDP port. The default
.Ar service
is
.Ql syslog .
A missing
.Ar masklen
will be substituted by the historic class A or class B netmasks if
.Ar ipaddr
belongs into the address range of class A or B, respectively, or
by 24 otherwise.
.It Ar domainname Ns Op Ar :service
Accept datagrams where the reverse address lookup yields
.Ar domainname
for the sender address. The meaning of
.Ar service
is as explained above.
.It Ar *domainname Ns Op Ar :service
Same as before, except that any source host whose name
.Em ends
in
.Ar domainname
will get permission.
.El
.It Fl d
Put
.Nm
@ -60,8 +110,6 @@ into debugging mode. This is probably only of use to developers working on
Specify the pathname of an alternate configuration file;
the default is
.Pa /etc/syslog.conf .
.It Fl s
Operate in secure mode. Do not listen for log message from remote machines.
.It Fl m
Select the number of minutes between
.Dq mark
@ -70,6 +118,8 @@ messages; the default is 20 minutes.
Specify the pathname of an alternate log socket;
the default is
.Pa /var/run/log .
.It Fl s
Operate in secure mode. Do not listen for log message from remote machines.
.El
.Pp
The
@ -134,12 +184,32 @@ The
.Nm
command appeared in
.Bx 4.3 .
.Pp
The
.Fl s
and
.Fl a
options are
.Fx 2.2
extensions.
.Sh BUGS
The ability to log messages received in UDP packets is equivalent to
an unauthenticated remote disk-filling service, and should probably be
disabled by default. Some sort of
.No inter- Ns Nm syslogd
authentication mechanism ought to be worked out.
authentication mechanism ought to be worked out. To prevent the worst
abuse, use of the
.Fl a
option is therefore highly recommended.
.Pp
The
.Fl a
matching algorithm doesn't pretend to be very efficient; use of numeric
IP addresses is faster than domain name comparision. Since the allowed
peer list is being walked linearly, peer groups where frequent messages
are being anticipated from should be put early into the
.Fl a
list.
.Pp
The log socket was moved from
.Pa /dev

View File

@ -39,7 +39,7 @@ static const char copyright[] =
static char sccsid[] = "@(#)syslogd.c 8.3 (Berkeley) 4/4/94";
*/
static const char rcsid[] =
"$Id: syslogd.c,v 1.23 1997/04/26 00:00:33 pst Exp $";
"$Id: syslogd.c,v 1.24 1997/04/26 00:03:21 pst Exp $";
#endif /* not lint */
/*
@ -94,11 +94,13 @@ static const char rcsid[] =
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <regex.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <unistd.h>
#include <utmp.h>
#include "pathnames.h"
@ -183,6 +185,26 @@ struct deadq_entry {
typedef struct deadq_entry *dq_t;
/*
* Struct to hold records of network addresses that are allowed to log
* to us.
*/
struct allowedpeer {
int isnumeric;
u_short port;
union {
struct {
struct in_addr addr;
struct in_addr mask;
} numeric;
char *name;
} u;
#define a_addr u.numeric.addr
#define a_mask u.numeric.mask
#define a_name u.name
};
/*
* Intervals at which we flush out "message repeated" messages,
* in seconds after previous message is logged. After each flush,
@ -226,6 +248,10 @@ int SecureMode = 0; /* when true, speak only unix domain socks */
int created_lsock = 0; /* Flag if local socket created */
char bootfile[MAXLINE+1]; /* booted kernel file */
struct allowedpeer *AllowedPeers;
int NumAllowed = 0; /* # of AllowedPeer entries */
int allowaddr __P((char *));
void cfline __P((char *, struct filed *, char *));
char *cvthname __P((struct sockaddr_in *));
void deadq_enter __P((pid_t));
@ -242,6 +268,7 @@ int p_open __P((char *, pid_t *));
void reapchild __P((int));
char *ttymsg __P((struct iovec *, int, char *, int));
void usage __P((void));
int validate __P((struct sockaddr_in *, const char *));
void wallmsg __P((struct filed *, struct iovec *));
int waitdaemon __P((int, int, int));
void timedout __P((int));
@ -255,15 +282,19 @@ main(argc, argv)
struct sockaddr_un sunx, fromunix;
struct sockaddr_in sin, frominet;
FILE *fp;
char *p, line[MSG_BSIZE + 1];
char *p, *hname, line[MSG_BSIZE + 1];
struct timeval tv, *tvp;
pid_t ppid;
while ((ch = getopt(argc, argv, "dsf:m:p:")) != -1)
while ((ch = getopt(argc, argv, "a:dsf:m:p:")) != -1)
switch(ch) {
case 'd': /* debug */
Debug++;
break;
case 'a': /* allow specific network addresses only */
if (allowaddr(optarg) == -1)
usage();
break;
case 'f': /* configuration file */
ConfFile = optarg;
break;
@ -290,6 +321,9 @@ main(argc, argv)
} else
setlinebuf(stdout);
if (NumAllowed)
endservent();
consfile.f_type = F_CONSOLE;
(void)strcpy(consfile.f_un.f_fname, ctty + sizeof _PATH_DEV - 1);
(void)gethostname(LocalHostName, sizeof(LocalHostName));
@ -421,7 +455,9 @@ main(argc, argv)
(struct sockaddr *)&frominet, &len);
if (i > 0) {
line[i] = '\0';
printline(cvthname(&frominet), line);
hname = cvthname(&frominet);
if (validate(&frominet, hname))
printline(hname, line);
} else if (i < 0 && errno != EINTR)
logerror("recvfrom inet");
}
@ -434,7 +470,7 @@ usage()
fprintf(stderr,
"usage: syslogd [-ds] [-f conffile] [-m markinterval]"
" [-p logpath]\n");
" [-p logpath] [-a allowaddr]\n");
exit(1);
}
@ -1441,6 +1477,174 @@ timedout(sig)
exit(0);
}
/*
* Add `s' to the list of allowable peer addresses to accept messages
* from.
*
* `s' is a string in the form:
*
* [*]domainname[:{servicename|portnumber|*}]
*
* or
*
* netaddr/maskbits[:{servicename|portnumber|*}]
*
* Returns -1 on error, 0 if the argument was valid.
*/
int
allowaddr(s)
char *s;
{
char *cp1, *cp2;
struct allowedpeer ap;
struct servent *se;
regex_t re;
int i;
if ((cp1 = strrchr(s, ':'))) {
/* service/port provided */
*cp1++ = '\0';
if (strlen(cp1) == 1 && *cp1 == '*')
/* any port allowed */
ap.port = htons(0);
else if ((se = getservbyname(cp1, "udp")))
ap.port = se->s_port;
else {
ap.port = htons((int)strtol(cp1, &cp2, 0));
if (*cp2 != '\0')
return -1; /* port not numeric */
}
} else {
if ((se = getservbyname("syslog", "udp")))
ap.port = se->s_port;
else
/* sanity, should not happen */
ap.port = htons(514);
}
/* the regexp's are ugly, but the cleanest way */
if (regcomp(&re, "^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+(/[0-9]+)?$",
REG_EXTENDED))
/* if RE compilation fails, that's an internal error */
abort();
if (regexec(&re, s, 0, 0, 0) == 0) {
/* arg `s' is numeric */
ap.isnumeric = 1;
if ((cp1 = strchr(s, '/')) != NULL) {
*cp1++ = '\0';
i = atoi(cp1);
if (i < 0 || i > 32)
return -1;
/* convert masklen to netmask */
ap.a_mask.s_addr = htonl(~((1 << (32 - i)) - 1));
}
if (ascii2addr(AF_INET, s, &ap.a_addr) == -1)
return -1;
if (cp1 == NULL) {
/* use default netmask */
if (IN_CLASSA(ntohl(ap.a_addr.s_addr)))
ap.a_mask.s_addr = htonl(IN_CLASSA_NET);
else if (IN_CLASSB(ntohl(ap.a_addr.s_addr)))
ap.a_mask.s_addr = htonl(IN_CLASSB_NET);
else
ap.a_mask.s_addr = htonl(IN_CLASSC_NET);
}
} else {
/* arg `s' is domain name */
ap.isnumeric = 0;
ap.a_name = s;
}
regfree(&re);
if (Debug) {
printf("allowaddr: rule %d: ", NumAllowed);
if (ap.isnumeric) {
printf("numeric, ");
printf("addr = %s, ",
addr2ascii(AF_INET, &ap.a_addr, sizeof(struct in_addr), 0));
printf("mask = %s; ",
addr2ascii(AF_INET, &ap.a_mask, sizeof(struct in_addr), 0));
} else
printf("domainname = %s; ", ap.a_name);
printf("port = %d\n", ntohs(ap.port));
}
if ((AllowedPeers = realloc(AllowedPeers,
++NumAllowed * sizeof(struct allowedpeer)))
== NULL) {
fprintf(stderr, "Out of memory!\n");
exit(EX_OSERR);
}
memcpy(&AllowedPeers[NumAllowed - 1], &ap, sizeof(struct allowedpeer));
return 0;
}
/*
* Validate that the remote peer has permission to log to us.
*/
int
validate(sin, hname)
struct sockaddr_in *sin;
const char *hname;
{
int i;
size_t l1, l2;
char *cp, name[MAXHOSTNAMELEN];
struct allowedpeer *ap;
if (NumAllowed == 0)
/* traditional behaviour, allow everything */
return 1;
strncpy(name, hname, sizeof name);
if (strchr(name, '.') == NULL) {
strncat(name, ".", sizeof name - strlen(name) - 1);
strncat(name, LocalDomain, sizeof name - strlen(name) - 1);
}
dprintf("validate: dgram from IP %s, port %d, name %s;\n",
addr2ascii(AF_INET, &sin->sin_addr, sizeof(struct in_addr), 0),
ntohs(sin->sin_port), name);
/* now, walk down the list */
for (i = 0, ap = AllowedPeers; i < NumAllowed; i++, ap++) {
if (ntohs(ap->port) != 0 && ap->port != sin->sin_port) {
dprintf("rejected in rule %d due to port mismatch.\n", i);
continue;
}
if (ap->isnumeric) {
if ((sin->sin_addr.s_addr & ap->a_mask.s_addr)
!= ap->a_addr.s_addr) {
dprintf("rejected in rule %d due to IP mismatch.\n", i);
continue;
}
} else {
cp = ap->a_name;
l1 = strlen(name);
if (*cp == '*') {
/* allow wildmatch */
cp++;
l2 = strlen(cp);
if (l2 > l1 || memcmp(cp, &name[l1 - l2], l2) != 0) {
dprintf("rejected in rule %d due to name mismatch.\n", i);
continue;
}
} else {
/* exact match */
l2 = strlen(cp);
if (l2 != l1 || memcmp(cp, name, l1) != 0) {
dprintf("rejected in rule %d due to name mismatch.\n", i);
continue;
}
}
}
dprintf("accepted in rule %d.\n", i);
return 1; /* hooray! */
}
return 0;
}
/*
* Fairly similar to popen(3), but returns an open descriptor, as
* opposed to a FILE *.