Add four big changes:
* portmap is now tcp-wrapped (i.e. obeys hosts.{allow,deny}) both for lookups (as `portmap') and for forwarded calls to specific services. * the new -l flag, analagous to inetd -l, logs all connections to portmap. * the new -s flag causes portmap to suid to the user daemon after binding it's port, so that outgoing connections do not come from privileged ports. This prevents users from using portmap to get a free privileged port. * portmap now _only_ accepts SETs and UNSETs on the loopback interface. In the past, anyone in the world could do all sorts of nasty things to your portmap tables. Note that our libc already_only_ uses the loopback interface to register rpc ports. This work is modeled after/partially taken from Wietse Venema's tcp- wrapped version of the BSD 4.3 portmap. It has benefitted greatly from my discussions with Luke, Matt and many others.
This commit is contained in:
parent
33b1cd5328
commit
2badef4d79
|
@ -1,7 +1,11 @@
|
|||
# $NetBSD: Makefile,v 1.8 1997/10/17 05:40:16 mrg Exp $
|
||||
# $NetBSD: Makefile,v 1.9 1999/01/11 20:51:09 jwise Exp $
|
||||
# from: @(#)Makefile 8.1 (Berkeley) 6/6/93
|
||||
|
||||
PROG= portmap
|
||||
MAN= portmap.8
|
||||
|
||||
CPPFLAGS+=-DLIBWRAP
|
||||
LDADD+= -lwrap
|
||||
DPADD+= ${LIBWRAP}
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.\" $NetBSD: portmap.8,v 1.4 1997/10/17 12:01:19 lukem Exp $
|
||||
.\" $NetBSD: portmap.8,v 1.5 1999/01/11 20:51:09 jwise Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1987 Sun Microsystems
|
||||
.\" Copyright (c) 1990, 1991, 1993
|
||||
|
@ -40,13 +40,13 @@
|
|||
.Sh NAME
|
||||
.Nm portmap
|
||||
.Nd
|
||||
.Tn DARPA
|
||||
port to
|
||||
.Tn RPC
|
||||
program number mapper
|
||||
program number to
|
||||
.Tn DARPA
|
||||
port mapper
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl d
|
||||
.Op Fl dls
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is a server that converts
|
||||
|
@ -88,19 +88,47 @@ like any other daemon.
|
|||
then logs errors using
|
||||
.Xr syslog 3 .
|
||||
.Pp
|
||||
.Nm
|
||||
uses
|
||||
.Xr libwrap
|
||||
style access control (the
|
||||
.Pa /etc/hosts.allow
|
||||
and
|
||||
.Pa /etc/hosts.deny
|
||||
files)
|
||||
to control access to the portmapper itself and control forwarding
|
||||
of requests. This prevents clients from using
|
||||
.Nm
|
||||
to circumvent host-based services in individual services.
|
||||
.Pp
|
||||
Option available:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl d
|
||||
(debug) prevents
|
||||
prevents
|
||||
.Nm
|
||||
from running as a daemon,
|
||||
and causes errors and debugging information
|
||||
to be printed to the standard error output.
|
||||
.It Fl l
|
||||
Turns on libwrap connection logging.
|
||||
.It Fl s
|
||||
causes
|
||||
.Nm
|
||||
to change to the user daemon as soon as possible.
|
||||
This causes
|
||||
.Nm
|
||||
to use non-privileged ports for outgoing connections, preventing non-privileged
|
||||
clients from using
|
||||
.Nm
|
||||
to connect to services from a privileged port.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr inetd.conf 5 ,
|
||||
.Xr rpcinfo 8 ,
|
||||
.Xr inetd 8
|
||||
.Xr inetd 8 ,
|
||||
.Xr syslog 3 ,
|
||||
.Xr hosts_access 3 ,
|
||||
.Xr hosts_options 3
|
||||
.Sh BUGS
|
||||
If
|
||||
.Nm
|
||||
|
@ -109,4 +137,8 @@ crashes, all servers must be restarted.
|
|||
The
|
||||
.Nm
|
||||
command appeared in
|
||||
.Bx 4.3
|
||||
.Bx 4.3 .
|
||||
The security features documented herein derive from work by Wietse Venema
|
||||
at Eindhoven University of Technology, The Netherlands, and first appeared
|
||||
in
|
||||
.Nx 1.4 .
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: portmap.c,v 1.13 1998/02/10 07:04:21 lukem Exp $ */
|
||||
/* $NetBSD: portmap.c,v 1.14 1999/01/11 20:51:09 jwise Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1990, 1993
|
||||
|
@ -44,7 +44,7 @@ __COPYRIGHT(
|
|||
#if 0
|
||||
static char sccsid[] = "@(#)portmap.c 8.1 (Berkeley) 6/6/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: portmap.c,v 1.13 1998/02/10 07:04:21 lukem Exp $");
|
||||
__RCSID("$NetBSD: portmap.c,v 1.14 1999/01/11 20:51:09 jwise Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
|
@ -87,22 +87,45 @@ static char sccsid[] = "@(#)portmap.c 1.32 87/08/06 Copyr 1984 Sun Micro";
|
|||
* Mountain View, California 94043
|
||||
*/
|
||||
|
||||
/* who to suid to if -s is given */
|
||||
#define RUN_AS "daemon"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/resource.h>
|
||||
#include <rpc/rpc.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <rpc/rpc.h>
|
||||
#include <netdb.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#ifdef LIBWRAP
|
||||
# include <tcpd.h>
|
||||
#ifndef LIBWRAP_ALLOW_FACILITY
|
||||
# define LIBWRAP_ALLOW_FACILITY LOG_AUTH
|
||||
#endif
|
||||
#ifndef LIBWRAP_ALLOW_SEVERITY
|
||||
# define LIBWRAP_ALLOW_SEVERITY LOG_INFO
|
||||
#endif
|
||||
#ifndef LIBWRAP_DENY_FACILITY
|
||||
# define LIBWRAP_DENY_FACILITY LOG_AUTH
|
||||
#endif
|
||||
#ifndef LIBWRAP_DENY_SEVERITY
|
||||
# define LIBWRAP_DENY_SEVERITY LOG_WARNING
|
||||
#endif
|
||||
int allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY;
|
||||
int deny_severity = LIBWRAP_DENY_FACILITY|LIBWRAP_DENY_SEVERITY;
|
||||
#endif
|
||||
|
||||
struct encap_parms {
|
||||
u_int arglen;
|
||||
|
@ -121,15 +144,22 @@ static void callit __P((struct svc_req *, SVCXPRT *));
|
|||
static struct pmaplist *find_service __P((u_long, u_long, u_long));
|
||||
int main __P((int, char *[]));
|
||||
void reap __P((int));
|
||||
void toggle_verboselog __P((int));
|
||||
void reg_service __P((struct svc_req *, SVCXPRT *));
|
||||
static bool_t xdr_encap_parms __P((XDR *, struct encap_parms *));
|
||||
static bool_t xdr_len_opaque_parms __P((XDR *, struct rmtcallargs *));
|
||||
static bool_t xdr_opaque_parms __P((XDR *, struct rmtcallargs *));
|
||||
static bool_t xdr_rmtcall_args __P((XDR *, struct rmtcallargs *));
|
||||
static bool_t xdr_rmtcall_result __P((XDR *, struct rmtcallargs *));
|
||||
void logit __P((int, struct sockaddr_in *, u_long, u_long, char *));
|
||||
int check_access __P((struct sockaddr_in *, u_long, u_long));
|
||||
int is_loopback __P((struct sockaddr_in *));
|
||||
|
||||
|
||||
struct pmaplist *pmaplist;
|
||||
int debugging = 0;
|
||||
int runasdaemon = 0;
|
||||
int verboselog = 0;
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
|
@ -142,13 +172,21 @@ main(argc, argv)
|
|||
int len = sizeof(struct sockaddr_in);
|
||||
struct pmaplist *pml;
|
||||
|
||||
while ((c = getopt(argc, argv, "d")) != -1) {
|
||||
while ((c = getopt(argc, argv, "dls")) != -1) {
|
||||
switch (c) {
|
||||
|
||||
case 'd':
|
||||
debugging = 1;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
verboselog = 1;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
runasdaemon = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
(void) fprintf(stderr, "usage: %s [-d]\n", argv[0]);
|
||||
exit(1);
|
||||
|
@ -215,22 +253,26 @@ main(argc, argv)
|
|||
(void)svc_register(xprt, PMAPPROG, PMAPVERS, reg_service, FALSE);
|
||||
|
||||
(void)signal(SIGCHLD, reap);
|
||||
(void) signal(SIGUSR1, toggle_verboselog);
|
||||
|
||||
if (runasdaemon) {
|
||||
struct passwd *p;
|
||||
|
||||
if((p = getpwnam(RUN_AS)) == NULL) {
|
||||
syslog(LOG_ERR, "cannot get uid of daemon: %m");
|
||||
exit(1);
|
||||
}
|
||||
if (setuid(p->pw_uid) == -1) {
|
||||
syslog(LOG_ERR, "setuid to daemon failed: %m");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
svc_run();
|
||||
syslog(LOG_ERR, "svc_run returned unexpectedly");
|
||||
abort();
|
||||
}
|
||||
|
||||
#ifndef lint
|
||||
/* need to override perror calls in rpc library */
|
||||
void
|
||||
perror(what)
|
||||
const char *what;
|
||||
{
|
||||
|
||||
syslog(LOG_ERR, "%s: %m", what);
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct pmaplist *
|
||||
find_service(prog, vers, prot)
|
||||
u_long prog, vers, prot;
|
||||
|
@ -267,10 +309,11 @@ reg_service(rqstp, xprt)
|
|||
/*
|
||||
* Null proc call
|
||||
*/
|
||||
if (!svc_sendreply(xprt, xdr_void, (caddr_t)0) && debugging) {
|
||||
abort();
|
||||
}
|
||||
break;
|
||||
check_access(svc_getcaller(xprt), rqstp->rq_proc, (u_long) 0);
|
||||
if (!svc_sendreply(xprt, xdr_void, (caddr_t)0) && debugging) {
|
||||
abort();
|
||||
}
|
||||
break;
|
||||
|
||||
case PMAPPROC_SET:
|
||||
/*
|
||||
|
@ -279,6 +322,13 @@ reg_service(rqstp, xprt)
|
|||
if (!svc_getargs(xprt, xdr_pmap, (caddr_t)®))
|
||||
svcerr_decode(xprt);
|
||||
else {
|
||||
if (verboselog)
|
||||
logit(allow_severity, svc_getcaller(xprt), rqstp->rq_proc, reg.pm_prog, "");
|
||||
if(!is_loopback(svc_getcaller(xprt))) {
|
||||
ans = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* check to see if already used
|
||||
* find_service returns a hit even if
|
||||
|
@ -329,6 +379,12 @@ reg_service(rqstp, xprt)
|
|||
svcerr_decode(xprt);
|
||||
else {
|
||||
ans = 0;
|
||||
if (verboselog)
|
||||
logit(allow_severity, svc_getcaller(xprt), rqstp->rq_proc, reg.pm_prog, "");
|
||||
if(!is_loopback(svc_getcaller(xprt))) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (prevpml = NULL, pml = pmaplist; pml != NULL; ) {
|
||||
if ((pml->pml_map.pm_prog != reg.pm_prog) ||
|
||||
(pml->pml_map.pm_vers != reg.pm_vers)) {
|
||||
|
@ -338,7 +394,7 @@ reg_service(rqstp, xprt)
|
|||
continue;
|
||||
}
|
||||
/* found it; pml moves forward, prevpml stays */
|
||||
ans = 1;
|
||||
ans = 1;
|
||||
t = (caddr_t)pml;
|
||||
pml = pml->pml_next;
|
||||
if (prevpml == NULL)
|
||||
|
@ -362,14 +418,18 @@ reg_service(rqstp, xprt)
|
|||
if (!svc_getargs(xprt, xdr_pmap, (caddr_t)®))
|
||||
svcerr_decode(xprt);
|
||||
else {
|
||||
if (!check_access(svc_getcaller(xprt), rqstp->rq_proc, reg.pm_prog)) {
|
||||
ans = 0;
|
||||
/* this is a little bogus -- done is up above, under another case */
|
||||
goto done;
|
||||
}
|
||||
fnd = find_service(reg.pm_prog, reg.pm_vers,
|
||||
reg.pm_prot);
|
||||
if (fnd)
|
||||
port = fnd->pml_map.pm_port;
|
||||
else
|
||||
port = 0;
|
||||
if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&port)) &&
|
||||
debugging) {
|
||||
if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&port)) && debugging) {
|
||||
(void) fprintf(stderr, "svc_sendreply\n");
|
||||
abort();
|
||||
}
|
||||
|
@ -383,8 +443,14 @@ reg_service(rqstp, xprt)
|
|||
if (!svc_getargs(xprt, xdr_void, NULL))
|
||||
svcerr_decode(xprt);
|
||||
else {
|
||||
if ((!svc_sendreply(xprt, xdr_pmaplist,
|
||||
(caddr_t)&pmaplist)) && debugging) {
|
||||
struct pmaplist *p;
|
||||
if (!check_access(svc_getcaller(xprt), rqstp->rq_proc, (u_long) 0)) {
|
||||
p = 0; /* send empty list */
|
||||
} else {
|
||||
p = pmaplist;
|
||||
}
|
||||
|
||||
if ((!svc_sendreply(xprt, xdr_pmaplist, (caddr_t)&p)) && debugging) {
|
||||
(void) fprintf(stderr, "svc_sendreply\n");
|
||||
abort();
|
||||
}
|
||||
|
@ -403,6 +469,7 @@ reg_service(rqstp, xprt)
|
|||
break;
|
||||
|
||||
default:
|
||||
check_access(svc_getcaller(xprt), rqstp->rq_proc, (u_long) 0);
|
||||
svcerr_noproc(xprt);
|
||||
break;
|
||||
}
|
||||
|
@ -518,6 +585,9 @@ callit(rqstp, xprt)
|
|||
a.rmt_args.args = buf;
|
||||
if (!svc_getargs(xprt, xdr_rmtcall_args, (caddr_t)&a))
|
||||
return;
|
||||
/* host and service access control */
|
||||
if (!check_access(svc_getcaller(xprt), rqstp->rq_proc, a.rmt_prog))
|
||||
return;
|
||||
if ((pml = find_service(a.rmt_prog, a.rmt_vers,
|
||||
(u_long)IPPROTO_UDP)) == NULL)
|
||||
return;
|
||||
|
@ -570,3 +640,105 @@ reap(dummy)
|
|||
;
|
||||
errno = save_errno;
|
||||
}
|
||||
|
||||
void
|
||||
toggle_verboselog(dummy)
|
||||
int dummy;
|
||||
{
|
||||
verboselog = !verboselog;
|
||||
}
|
||||
|
||||
int
|
||||
check_access(addr, proc, prog)
|
||||
struct sockaddr_in *addr;
|
||||
u_long proc;
|
||||
u_long prog;
|
||||
{
|
||||
#ifdef LIBWRAP
|
||||
struct request_info req;
|
||||
#endif
|
||||
|
||||
#ifdef LIBWRAP
|
||||
request_init(&req, RQ_DAEMON, "portmap", RQ_CLIENT_SIN, addr, 0);
|
||||
fromhost(&req);
|
||||
if(!hosts_access(&req)) {
|
||||
logit(deny_severity, addr, proc, prog, ": request from unauthorized host");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (verboselog)
|
||||
logit(allow_severity, addr, proc, prog, "");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
is_loopback(addr)
|
||||
struct sockaddr_in *addr;
|
||||
{
|
||||
if (addr->sin_addr.s_addr != INADDR_LOOPBACK)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* logit - report events of interest via the syslog daemon */
|
||||
void
|
||||
logit(severity, addr, procnum, prognum, text)
|
||||
int severity;
|
||||
struct sockaddr_in *addr;
|
||||
u_long procnum;
|
||||
u_long prognum;
|
||||
char *text;
|
||||
{
|
||||
char *procname;
|
||||
char procbuf[4 * sizeof(u_long)];
|
||||
char *progname;
|
||||
char progbuf[4 * sizeof(u_long)];
|
||||
struct rpcent *rpc;
|
||||
struct proc_map {
|
||||
u_long code;
|
||||
char *proc;
|
||||
};
|
||||
struct proc_map *procp;
|
||||
static struct proc_map procmap[] = {
|
||||
{PMAPPROC_CALLIT, "callit"},
|
||||
{PMAPPROC_DUMP, "dump"},
|
||||
{PMAPPROC_GETPORT, "getport"},
|
||||
{PMAPPROC_NULL, "null"},
|
||||
{PMAPPROC_SET, "set"},
|
||||
{PMAPPROC_UNSET, "unset"},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
/*
|
||||
* Fork off a process or the portmap daemon might hang while
|
||||
* getrpcbynumber() or syslog() does its thing.
|
||||
*/
|
||||
|
||||
if (fork() == 0) {
|
||||
|
||||
/* Try to map program number to name. */
|
||||
|
||||
if (prognum == 0) {
|
||||
progname = "";
|
||||
} else if ((rpc = getrpcbynumber((int) prognum))) {
|
||||
progname = rpc->r_name;
|
||||
} else {
|
||||
snprintf(progname = progbuf, sizeof(progbuf), "%lu", prognum);
|
||||
}
|
||||
|
||||
/* Try to map procedure number to name. */
|
||||
|
||||
for (procp = procmap; procp->proc && procp->code != procnum; procp++)
|
||||
/* void */ ;
|
||||
if ((procname = procp->proc) == 0)
|
||||
snprintf(procname = procbuf, sizeof(procbuf), "%lu", (u_long) procnum);
|
||||
|
||||
/* Write syslog record. */
|
||||
|
||||
syslog(severity, "connect from %s to %s(%s)%s",
|
||||
inet_ntoa(addr->sin_addr), procname, progname, text);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue