Portmap 3.0 from win.tue.nl

This commit is contained in:
pst 1994-09-29 09:32:22 +00:00
parent 2233bc697f
commit 42d798d589
10 changed files with 625 additions and 7 deletions

View File

@ -1,8 +1,10 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= portmap
DPADD= ${LIBRPC}
LDADD= -lrpc
MAN8= portmap.0
MAN8= portmap.8
SRCS= portmap.c from_local.c pmap_check.c
SUBDIR= pmap_set pmap_dump
CFLAGS+=-DCHECK_PORT # -DHOSTS_ACCESS (requires tcpwrapper libraries)
.include <bsd.prog.mk>

View File

@ -0,0 +1,147 @@
/*
* Check if an address belongs to the local system. Adapted from:
*
* @(#)pmap_svc.c 1.32 91/03/11 Copyright 1984,1990 Sun Microsystems, Inc.
* @(#)get_myaddress.c 2.1 88/07/29 4.0 RPCSRC.
*/
/*
* Sun RPC is a product of Sun Microsystems, Inc. and is provided for
* unrestricted use provided that this legend is included on all tape
* media and as a part of the software program in whole or part. Users
* may copy or modify Sun RPC without charge, but are not authorized
* to license or distribute it to anyone else except as part of a product or
* program developed by the user or with the express written consent of
* Sun Microsystems, Inc.
*
* SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
* WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
*
* Sun RPC is provided with no support and without any obligation on the
* part of Sun Microsystems, Inc. to assist in its use, correction,
* modification or enhancement.
*
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
* OR ANY PART THEREOF.
*
* In no event will Sun Microsystems, Inc. be liable for any lost revenue
* or profits or other special, indirect and consequential damages, even if
* Sun has been advised of the possibility of such damages.
*
* Sun Microsystems, Inc.
* 2550 Garcia Avenue
* Mountain View, California 94043
*/
#ifndef lint
static char sccsid[] = "@(#) from_local.c 1.2 93/11/16 21:50:02";
#endif
#ifdef TEST
#undef perror
#endif
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <syslog.h>
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
/* How many interfaces could there be on a computer? */
#define MAX_LOCAL 16
static int num_local = -1;
static struct in_addr addrs[MAX_LOCAL];
/* find_local - find all IP addresses for this host */
find_local()
{
struct ifconf ifc;
struct ifreq ifreq;
struct ifreq *ifr;
struct ifreq *the_end;
int sock;
char buf[MAX_LOCAL * sizeof(struct ifreq)];
/* Get list of network interfaces. */
if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket");
return (0);
}
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = buf;
if (ioctl(sock, SIOCGIFCONF, (char *) &ifc) < 0) {
perror("SIOCGIFCONF");
(void) close(sock);
return (0);
}
/* Get IP address of each active IP network interface. */
the_end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
num_local = 0;
for (ifr = ifc.ifc_req; ifr < the_end; ifr++) {
if (ifr->ifr_addr.sa_family == AF_INET) { /* IP net interface */
ifreq = *ifr;
if (ioctl(sock, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
perror("SIOCGIFFLAGS");
} else if (ifreq.ifr_flags & IFF_UP) { /* active interface */
if (ioctl(sock, SIOCGIFADDR, (char *) &ifreq) < 0) {
perror("SIOCGIFADDR");
} else {
addrs[num_local++] = ((struct sockaddr_in *)
& ifreq.ifr_addr)->sin_addr;
}
}
}
if (num_local >= MAX_LOCAL)
break;
/* Support for variable-length addresses. */
ifr = (struct ifreq *) ((caddr_t) ifr
+ ifr->ifr_addr.sa_len - sizeof(struct sockaddr));
}
(void) close(sock);
return (num_local);
}
/* from_local - determine whether request comes from the local system */
from_local(addr)
struct sockaddr_in *addr;
{
int i;
if (num_local == -1 && find_local() == 0)
syslog(LOG_ERR, "cannot find any active local network interfaces");
for (i = 0; i < num_local; i++) {
if (memcmp((char *) &(addr->sin_addr), (char *) &(addrs[i]),
sizeof(struct in_addr)) == 0)
return (TRUE);
}
return (FALSE);
}
#ifdef TEST
main()
{
char *inet_ntoa();
int i;
find_local();
for (i = 0; i < num_local; i++)
printf("%s\n", inet_ntoa(addrs[i]));
}
#endif

View File

@ -0,0 +1,251 @@
/*
* pmap_check - additional portmap security.
*
* Always reject non-local requests to update the portmapper tables.
*
* Refuse to forward mount requests to the nfs mount daemon. Otherwise, the
* requests would appear to come from the local system, and nfs export
* restrictions could be bypassed.
*
* Refuse to forward requests to the nfsd process.
*
* Refuse to forward requests to NIS (YP) daemons; The only exception is the
* YPPROC_DOMAIN_NONACK broadcast rpc call that is used to establish initial
* contact with the NIS server.
*
* Always allocate an unprivileged port when forwarding a request.
*
* If compiled with -DCHECK_PORT, require that requests to register or
* unregister a privileged port come from a privileged port. This makes it
* more difficult to replace a critical service by a trojan.
*
* If compiled with -DHOSTS_ACCESS, reject requests from hosts that are not
* authorized by the /etc/hosts.{allow,deny} files. The local system is
* always treated as an authorized host. The access control tables are never
* consulted for requests from the local system, and are always consulted
* for requests from other hosts. Access control is based on IP addresses
* only; attempts to map an address to a host name might cause the
* portmapper to hang.
*
* Author: Wietse Venema (wietse@wzv.win.tue.nl), dept. of Mathematics and
* Computing Science, Eindhoven University of Technology, The Netherlands.
*/
#ifndef lint
static char sccsid[] = "@(#) pmap_check.c 1.6 93/11/21 20:58:59";
#endif
#include <rpc/rpc.h>
#include <rpc/pmap_prot.h>
#include <syslog.h>
#include <netdb.h>
#include <sys/signal.h>
extern char *inet_ntoa();
#include "pmap_check.h"
/* Explicit #defines in case the include files are not available. */
#define NFSPROG ((u_long) 100003)
#define MOUNTPROG ((u_long) 100005)
#define YPXPROG ((u_long) 100069)
#define YPPROG ((u_long) 100004)
#define YPPROC_DOMAIN_NONACK ((u_long) 2)
#define MOUNTPROC_MNT ((u_long) 1)
static void logit();
static void toggle_verboselog();
int verboselog = 0;
int allow_severity = LOG_INFO;
int deny_severity = LOG_WARNING;
/* A handful of macros for "readability". */
#define good_client(a) hosts_ctl("portmap", "", inet_ntoa(a->sin_addr), "")
#define legal_port(a,p) \
(ntohs((a)->sin_port) < IPPORT_RESERVED || (p) >= IPPORT_RESERVED)
#define log_bad_port(addr, proc, prog) \
logit(deny_severity, addr, proc, prog, ": request from unprivileged port")
#define log_bad_host(addr, proc, prog) \
logit(deny_severity, addr, proc, prog, ": request from unauthorized host")
#define log_bad_owner(addr, proc, prog) \
logit(deny_severity, addr, proc, prog, ": request from non-local host")
#define log_no_forward(addr, proc, prog) \
logit(deny_severity, addr, proc, prog, ": request not forwarded")
#define log_client(addr, proc, prog) \
logit(allow_severity, addr, proc, prog, "")
/* check_startup - additional startup code */
void check_startup()
{
/*
* Give up root privileges so that we can never allocate a privileged
* port when forwarding an rpc request.
*/
if (setuid(1) == -1) {
syslog(LOG_ERR, "setuid(1) failed: %m");
exit(1);
}
(void) signal(SIGINT, toggle_verboselog);
}
/* check_default - additional checks for NULL, DUMP, GETPORT and unknown */
check_default(addr, proc, prog)
struct sockaddr_in *addr;
u_long proc;
u_long prog;
{
#ifdef HOSTS_ACCESS
if (!(from_local(addr) || good_client(addr))) {
log_bad_host(addr, proc, prog);
return (FALSE);
}
#endif
if (verboselog)
log_client(addr, proc, prog);
return (TRUE);
}
/* check_privileged_port - additional checks for privileged-port updates */
check_privileged_port(addr, proc, prog, port)
struct sockaddr_in *addr;
u_long proc;
u_long prog;
u_long port;
{
#ifdef CHECK_PORT
if (!legal_port(addr, port)) {
log_bad_port(addr, proc, prog);
return (FALSE);
}
#endif
return (TRUE);
}
/* check_setunset - additional checks for update requests */
check_setunset(addr, proc, prog, port)
struct sockaddr_in *addr;
u_long proc;
u_long prog;
u_long port;
{
if (!from_local(addr)) {
#ifdef HOSTS_ACCESS
(void) good_client(addr); /* because of side effects */
#endif
log_bad_owner(addr, proc, prog);
return (FALSE);
}
if (port && !check_privileged_port(addr, proc, prog, port))
return (FALSE);
if (verboselog)
log_client(addr, proc, prog);
return (TRUE);
}
/* check_callit - additional checks for forwarded requests */
check_callit(addr, proc, prog, aproc)
struct sockaddr_in *addr;
u_long proc;
u_long prog;
u_long aproc;
{
#ifdef HOSTS_ACCESS
if (!(from_local(addr) || good_client(addr))) {
log_bad_host(addr, proc, prog);
return (FALSE);
}
#endif
if (prog == PMAPPROG || prog == NFSPROG || prog == YPXPROG ||
(prog == MOUNTPROG && aproc == MOUNTPROC_MNT) ||
(prog == YPPROG && aproc != YPPROC_DOMAIN_NONACK)) {
log_no_forward(addr, proc, prog);
return (FALSE);
}
if (verboselog)
log_client(addr, proc, prog);
return (TRUE);
}
/* toggle_verboselog - toggle verbose logging flag */
static void toggle_verboselog(sig)
int sig;
{
(void) signal(sig, toggle_verboselog);
verboselog = !verboselog;
}
/* logit - report events of interest via the syslog daemon */
static 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 {
sprintf(progname = 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)
sprintf(procname = 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);
}
}

View File

@ -0,0 +1,11 @@
/* @(#) pmap_check.h 1.3 93/11/21 16:18:53 */
extern int from_local();
extern void check_startup();
extern int check_default();
extern int check_setunset();
extern int check_privileged_port();
extern int check_callit();
extern int verboselog;
extern int allow_severity;
extern int deny_severity;

View File

@ -0,0 +1,7 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= pmap_dump
NOMAN= noman
.include "${.CURDIR}/../../Makefile.inc"
.include <bsd.prog.mk>

View File

@ -0,0 +1,63 @@
/*
* pmap_dump - dump portmapper table in format readable by pmap_set
*
* Author: Wietse Venema (wietse@wzv.win.tue.nl), dept. of Mathematics and
* Computing Science, Eindhoven University of Technology, The Netherlands.
*/
#ifndef lint
static char sccsid[] = "@(#) pmap_dump.c 1.1 92/06/11 22:53:15";
#endif
#include <stdio.h>
#include <sys/types.h>
#ifdef SYSV40
#include <netinet/in.h>
#include <rpc/rpcent.h>
#else
#include <netdb.h>
#endif
#include <rpc/rpc.h>
#include <rpc/pmap_clnt.h>
#include <rpc/pmap_prot.h>
static char *protoname();
main(argc, argv)
int argc;
char **argv;
{
struct sockaddr_in addr;
register struct pmaplist *list;
register struct rpcent *rpc;
get_myaddress(&addr);
for (list = pmap_getmaps(&addr); list; list = list->pml_next) {
rpc = getrpcbynumber((int) list->pml_map.pm_prog);
printf("%10lu %4lu %5s %6lu %s\n",
list->pml_map.pm_prog,
list->pml_map.pm_vers,
protoname(list->pml_map.pm_prot),
list->pml_map.pm_port,
rpc ? rpc->r_name : "");
}
#undef perror
return (fclose(stdout) ? (perror(argv[0]), 1) : 0);
}
static char *protoname(proto)
u_long proto;
{
static char buf[BUFSIZ];
switch (proto) {
case IPPROTO_UDP:
return ("udp");
case IPPROTO_TCP:
return ("tcp");
default:
sprintf(buf, "%lu", proto);
return (buf);
}
}

View File

@ -0,0 +1,7 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= pmap_set
NOMAN= noman
.include "${.CURDIR}/../../Makefile.inc"
.include <bsd.prog.mk>

View File

@ -0,0 +1,70 @@
/*
* pmap_set - set portmapper table from data produced by pmap_dump
*
* Author: Wietse Venema (wietse@wzv.win.tue.nl), dept. of Mathematics and
* Computing Science, Eindhoven University of Technology, The Netherlands.
*/
#ifndef lint
static char sccsid[] = "@(#) pmap_set.c 1.1 92/06/11 22:53:16";
#endif
#include <stdio.h>
#include <sys/types.h>
#ifdef SYSV40
#include <netinet/in.h>
#endif
#include <rpc/rpc.h>
#include <rpc/pmap_clnt.h>
main(argc, argv)
int argc;
char **argv;
{
struct sockaddr_in addr;
char buf[BUFSIZ];
u_long prog;
u_long vers;
int prot;
unsigned port;
get_myaddress(&addr);
while (fgets(buf, sizeof(buf), stdin)) {
if (parse_line(buf, &prog, &vers, &prot, &port) == 0) {
fprintf(stderr, "%s: malformed line: %s", argv[0], buf);
return (1);
}
if (pmap_set(prog, vers, prot, (unsigned short) port) == 0)
fprintf(stderr, "not registered: %s", buf);
}
return (0);
}
/* parse_line - convert line to numbers */
parse_line(buf, prog, vers, prot, port)
char *buf;
u_long *prog;
u_long *vers;
int *prot;
unsigned *port;
{
char proto_name[BUFSIZ];
if (sscanf(buf, "%lu %lu %s %u", prog, vers, proto_name, port) != 4) {
return (0);
}
if (strcmp(proto_name, "tcp") == 0) {
*prot = IPPROTO_TCP;
return (1);
}
if (strcmp(proto_name, "udp") == 0) {
*prot = IPPROTO_UDP;
return (1);
}
if (sscanf(proto_name, "%d", prot) == 1) {
return (1);
}
return (0);
}

View File

@ -94,6 +94,8 @@ Option available:
from running as a daemon,
and causes errors and debugging information
to be printed to the standard error output.
.It Fl v
(verbose) enable verbose logging access control checks.
.El
.Sh SEE ALSO
.Xr inetd.conf 5 ,

View File

@ -94,6 +94,8 @@ static char sccsid[] = "@(#)portmap.c 1.32 87/08/06 Copyr 1984 Sun Micro";
#include <sys/signal.h>
#include <sys/resource.h>
#include "pmap_check.h"
void reg_service();
void reap();
static void callit();
@ -111,15 +113,21 @@ main(argc, argv)
int len = sizeof(struct sockaddr_in);
register struct pmaplist *pml;
while ((c = getopt(argc, argv, "d")) != EOF) {
while ((c = getopt(argc, argv, "dv")) != EOF) {
switch (c) {
case 'd':
debugging = 1;
break;
case 'v':
verboselog = 1;
break;
default:
(void) fprintf(stderr, "usage: %s [-d]\n", argv[0]);
(void) fprintf(stderr, "usage: %s [-dv]\n", argv[0]);
(void) fprintf(stderr, "-d: debugging mode\n");
(void) fprintf(stderr, "-v: verbose logging\n");
exit(1);
}
}
@ -182,6 +190,8 @@ main(argc, argv)
(void)svc_register(xprt, PMAPPROG, PMAPVERS, reg_service, FALSE);
/* additional initializations */
check_startup();
(void)signal(SIGCHLD, reap);
svc_run();
syslog(LOG_ERR, "run_svc returned unexpectedly");
@ -230,6 +240,13 @@ reg_service(rqstp, xprt)
int ans, port;
caddr_t t;
/*
* Later wrappers change the logging severity on the fly. Reset to
* defaults before handling the next request.
*/
allow_severity = LOG_INFO;
deny_severity = LOG_WARNING;
if (debugging)
(void) fprintf(stderr, "server: about do a switch\n");
switch (rqstp->rq_proc) {
@ -238,6 +255,8 @@ reg_service(rqstp, xprt)
/*
* Null proc call
*/
/* remote host authorization check */
check_default(svc_getcaller(xprt), rqstp->rq_proc, (u_long) 0);
if (!svc_sendreply(xprt, xdr_void, (caddr_t)0) && debugging) {
abort();
}
@ -250,6 +269,12 @@ reg_service(rqstp, xprt)
if (!svc_getargs(xprt, xdr_pmap, &reg))
svcerr_decode(xprt);
else {
/* reject non-local requests, protect priv. ports */
if (!check_setunset(svc_getcaller(xprt),
rqstp->rq_proc, reg.pm_prog, reg.pm_port)) {
ans = 0;
goto done;
}
/*
* check to see if already used
* find_service returns a hit even if
@ -299,6 +324,10 @@ reg_service(rqstp, xprt)
svcerr_decode(xprt);
else {
ans = 0;
/* reject non-local requests */
if (!check_setunset(svc_getcaller(xprt),
rqstp->rq_proc, reg.pm_prog, (u_long) 0))
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)) {
@ -308,6 +337,14 @@ reg_service(rqstp, xprt)
continue;
}
/* found it; pml moves forward, prevpml stays */
/* privileged port check */
if (!check_privileged_port(svc_getcaller(xprt),
rqstp->rq_proc,
reg.pm_prog,
pml->pml_map.pm_port)) {
ans = 0;
break;
}
ans = 1;
t = (caddr_t)pml;
pml = pml->pml_next;
@ -332,6 +369,13 @@ reg_service(rqstp, xprt)
if (!svc_getargs(xprt, xdr_pmap, &reg))
svcerr_decode(xprt);
else {
/* remote host authorization check */
if (!check_default(svc_getcaller(xprt),
rqstp->rq_proc,
reg.pm_prog)) {
ans = 0;
goto done;
}
fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot);
if (fnd)
port = fnd->pml_map.pm_port;
@ -352,8 +396,16 @@ reg_service(rqstp, xprt)
if (!svc_getargs(xprt, xdr_void, NULL))
svcerr_decode(xprt);
else {
/* remote host authorization check */
struct pmaplist *p;
if (!check_default(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)&pmaplist)) && debugging) {
(caddr_t)&p)) && debugging) {
(void) fprintf(stderr, "svc_sendreply\n");
abort();
}
@ -372,6 +424,8 @@ reg_service(rqstp, xprt)
break;
default:
/* remote host authorization check */
check_default(svc_getcaller(xprt), rqstp->rq_proc, (u_long) 0);
svcerr_noproc(xprt);
break;
}
@ -384,7 +438,7 @@ reg_service(rqstp, xprt)
#define ARGSIZE 9000
struct encap_parms {
u_long arglen;
u_int arglen;
char *args;
};
@ -500,6 +554,10 @@ callit(rqstp, xprt)
a.rmt_args.args = buf;
if (!svc_getargs(xprt, xdr_rmtcall_args, &a))
return;
/* host and service access control */
if (!check_callit(svc_getcaller(xprt),
rqstp->rq_proc, a.rmt_prog, a.rmt_proc))
return;
if ((pml = find_service(a.rmt_prog, a.rmt_vers,
(u_long)IPPROTO_UDP)) == NULL)
return;