2 * pmap_check - additional portmap security.
4 * Always reject non-local requests to update the portmapper tables.
6 * Refuse to forward mount requests to the nfs mount daemon. Otherwise, the
7 * requests would appear to come from the local system, and nfs export
8 * restrictions could be bypassed.
10 * Refuse to forward requests to the nfsd process.
12 * Refuse to forward requests to NIS (YP) daemons; The only exception is the
13 * YPPROC_DOMAIN_NONACK broadcast rpc call that is used to establish initial
14 * contact with the NIS server.
16 * Always allocate an unprivileged port when forwarding a request.
18 * If compiled with -DCHECK_PORT, require that requests to register or
19 * unregister a privileged port come from a privileged port. This makes it
20 * more difficult to replace a critical service by a trojan.
22 * If compiled with -DHOSTS_ACCESS, reject requests from hosts that are not
23 * authorized by the /etc/hosts.{allow,deny} files. The local system is
24 * always treated as an authorized host. The access control tables are never
25 * consulted for requests from the local system, and are always consulted
26 * for requests from other hosts. Access control is based on IP addresses
27 * only; attempts to map an address to a host name might cause the
30 * Author: Wietse Venema (wietse@wzv.win.tue.nl), dept. of Mathematics and
31 * Computing Science, Eindhoven University of Technology, The Netherlands.
35 * @(#) pmap_check.c 1.6 93/11/21 20:58:59
36 * $FreeBSD: src/usr.sbin/portmap/pmap_check.c,v 1.6 2000/01/15 23:08:28 brian Exp $
37 * $DragonFly: src/usr.sbin/portmap/pmap_check.c,v 1.4 2004/03/30 04:58:59 cpressey Exp $
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <sys/signal.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
46 #include <rpc/pmap_prot.h>
53 #include "pmap_check.h"
55 /* Explicit #defines in case the include files are not available. */
57 #define NFSPROG ((u_long) 100003)
58 #define MOUNTPROG ((u_long) 100005)
59 #define YPXPROG ((u_long) 100069)
60 #define YPPROG ((u_long) 100004)
61 #define YPPROC_DOMAIN_NONACK ((u_long) 2)
62 #define MOUNTPROC_MNT ((u_long) 1)
64 static void logit(int, struct sockaddr_in
*, u_long
, u_long
, const char *);
65 static void toggle_verboselog(int);
68 int allow_severity
= LOG_INFO
;
69 int deny_severity
= LOG_WARNING
;
71 /* A handful of macros for "readability". */
73 #define good_client(a) hosts_ctl("portmap", "", inet_ntoa(a->sin_addr), "")
75 #define legal_port(a,p) \
76 (ntohs((a)->sin_port) < IPPORT_RESERVED || (p) >= IPPORT_RESERVED)
78 #define log_bad_port(addr, proc, prog) \
79 logit(deny_severity, addr, proc, prog, ": request from unprivileged port")
81 #define log_bad_host(addr, proc, prog) \
82 logit(deny_severity, addr, proc, prog, ": request from unauthorized host")
84 #define log_bad_owner(addr, proc, prog) \
85 logit(deny_severity, addr, proc, prog, ": request from non-local host")
87 #define log_no_forward(addr, proc, prog) \
88 logit(deny_severity, addr, proc, prog, ": request not forwarded")
90 #define log_client(addr, proc, prog) \
91 logit(allow_severity, addr, proc, prog, "")
93 /* check_startup - additional startup code */
99 * Give up root privileges so that we can never allocate a privileged
100 * port when forwarding an rpc request.
102 if (setuid(1) == -1) {
103 syslog(LOG_ERR
, "setuid(1) failed: %m");
106 signal(SIGINT
, toggle_verboselog
);
109 /* check_default - additional checks for NULL, DUMP, GETPORT and unknown */
112 check_default(struct sockaddr_in
*addr
, u_long proc
, u_long prog
)
115 if (!(from_local(addr
) || good_client(addr
))) {
116 log_bad_host(addr
, proc
, prog
);
121 log_client(addr
, proc
, prog
);
125 /* check_privileged_port - additional checks for privileged-port updates */
128 check_privileged_port(struct sockaddr_in
*addr
,
129 u_long proc
, u_long prog
, u_long port
)
132 if (!legal_port(addr
, port
)) {
133 log_bad_port(addr
, proc
, prog
);
140 /* check_setunset - additional checks for update requests */
143 check_setunset(struct sockaddr_in
*addr
,
144 u_long proc
, u_long prog
, u_long port
)
146 if (!from_local(addr
)) {
148 good_client(addr
); /* because of side effects */
150 log_bad_owner(addr
, proc
, prog
);
153 if (port
&& !check_privileged_port(addr
, proc
, prog
, port
))
156 log_client(addr
, proc
, prog
);
160 /* check_callit - additional checks for forwarded requests */
163 check_callit(struct sockaddr_in
*addr
, u_long proc
, u_long prog
, u_long aproc
)
166 if (!(from_local(addr
) || good_client(addr
))) {
167 log_bad_host(addr
, proc
, prog
);
171 if (prog
== PMAPPROG
|| prog
== NFSPROG
|| prog
== YPXPROG
||
172 (prog
== MOUNTPROG
&& aproc
== MOUNTPROC_MNT
) ||
173 (prog
== YPPROG
&& aproc
!= YPPROC_DOMAIN_NONACK
)) {
174 log_no_forward(addr
, proc
, prog
);
178 log_client(addr
, proc
, prog
);
182 /* toggle_verboselog - toggle verbose logging flag */
185 toggle_verboselog(int sig
)
187 signal(sig
, toggle_verboselog
);
188 verboselog
= !verboselog
;
191 /* logit - report events of interest via the syslog daemon */
194 logit(int severity
, struct sockaddr_in
*addr
, u_long procnum
, u_long prognum
,
197 const char *procname
;
198 char procbuf
[4 * sizeof(u_long
)];
199 const char *progname
;
200 char progbuf
[4 * sizeof(u_long
)];
206 struct proc_map
*procp
;
207 static struct proc_map procmap
[] = {
208 {PMAPPROC_CALLIT
, "callit"},
209 {PMAPPROC_DUMP
, "dump"},
210 {PMAPPROC_GETPORT
, "getport"},
211 {PMAPPROC_NULL
, "null"},
212 {PMAPPROC_SET
, "set"},
213 {PMAPPROC_UNSET
, "unset"},
218 * Fork off a process or the portmap daemon might hang while
219 * getrpcbynumber() or syslog() does its thing.
224 /* Try to map program number to name. */
228 } else if ((rpc
= getrpcbynumber((int) prognum
))) {
229 progname
= rpc
->r_name
;
231 sprintf(progbuf
, "%lu", prognum
);
235 /* Try to map procedure number to name. */
237 for (procp
= procmap
; procp
->proc
&& procp
->code
!= procnum
; procp
++)
239 if ((procname
= procp
->proc
) == 0) {
240 sprintf(procbuf
, "%lu", (u_long
) procnum
);
244 /* Write syslog record. */
246 syslog(severity
, "connect from %s to %s(%s)%s",
247 inet_ntoa(addr
->sin_addr
), procname
, progname
, text
);