Remove __P macros from src/usr.bin and src/usr.sbin.
[dragonfly.git] / usr.sbin / portmap / pmap_check.c
1  /*
2   * pmap_check - additional portmap security.
3   *
4   * Always reject non-local requests to update the portmapper tables.
5   *
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.
9   *
10   * Refuse to forward requests to the nfsd process.
11   *
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.
15   *
16   * Always allocate an unprivileged port when forwarding a request.
17   *
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.
21   *
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
28   * portmapper to hang.
29   *
30   * Author: Wietse Venema (wietse@wzv.win.tue.nl), dept. of Mathematics and
31   * Computing Science, Eindhoven University of Technology, The Netherlands.
32   */
33
34 /*
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.3 2003/11/03 19:31:40 eirikn Exp $
38  */
39 #include <stdio.h>
40 #include <unistd.h>
41 #include <sys/types.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
45
46 #include <rpc/rpc.h>
47 #include <rpc/pmap_prot.h>
48 #include <syslog.h>
49 #include <netdb.h>
50 #include <sys/signal.h>
51
52 #include "pmap_check.h"
53
54 /* Explicit #defines in case the include files are not available. */
55
56 #define NFSPROG         ((u_long) 100003)
57 #define MOUNTPROG       ((u_long) 100005)
58 #define YPXPROG         ((u_long) 100069)
59 #define YPPROG          ((u_long) 100004)
60 #define YPPROC_DOMAIN_NONACK ((u_long) 2)
61 #define MOUNTPROC_MNT   ((u_long) 1)
62
63 static void logit(int, struct sockaddr_in *, u_long, u_long, const char *);
64 static void toggle_verboselog(int);
65
66 int     verboselog = 0;
67 int     allow_severity = LOG_INFO;
68 int     deny_severity = LOG_WARNING;
69
70 /* A handful of macros for "readability". */
71
72 #define good_client(a) hosts_ctl("portmap", "", inet_ntoa(a->sin_addr), "")
73
74 #define legal_port(a,p) \
75   (ntohs((a)->sin_port) < IPPORT_RESERVED || (p) >= IPPORT_RESERVED)
76
77 #define log_bad_port(addr, proc, prog) \
78   logit(deny_severity, addr, proc, prog, ": request from unprivileged port")
79
80 #define log_bad_host(addr, proc, prog) \
81   logit(deny_severity, addr, proc, prog, ": request from unauthorized host")
82
83 #define log_bad_owner(addr, proc, prog) \
84   logit(deny_severity, addr, proc, prog, ": request from non-local host")
85
86 #define log_no_forward(addr, proc, prog) \
87   logit(deny_severity, addr, proc, prog, ": request not forwarded")
88
89 #define log_client(addr, proc, prog) \
90   logit(allow_severity, addr, proc, prog, "")
91
92 /* check_startup - additional startup code */
93
94 void
95 check_startup()
96 {
97
98     /*
99      * Give up root privileges so that we can never allocate a privileged
100      * port when forwarding an rpc request.
101      */
102     if (setuid(1) == -1) {
103         syslog(LOG_ERR, "setuid(1) failed: %m");
104         exit(1);
105     }
106     (void) signal(SIGINT, toggle_verboselog);
107 }
108
109 /* check_default - additional checks for NULL, DUMP, GETPORT and unknown */
110
111 int
112 check_default(addr, proc, prog)
113     struct sockaddr_in *addr;
114     u_long proc, prog;
115 {
116 #ifdef HOSTS_ACCESS
117     if (!(from_local(addr) || good_client(addr))) {
118         log_bad_host(addr, proc, prog);
119         return (FALSE);
120     }
121 #endif
122     if (verboselog)
123         log_client(addr, proc, prog);
124     return (TRUE);
125 }
126
127 /* check_privileged_port - additional checks for privileged-port updates */
128
129 int
130 check_privileged_port(addr, proc, prog, port)
131     struct sockaddr_in *addr;
132     u_long proc, prog, port;
133 {
134 #ifdef CHECK_PORT
135     if (!legal_port(addr, port)) {
136         log_bad_port(addr, proc, prog);
137         return (FALSE);
138     }
139 #endif
140     return (TRUE);
141 }
142
143 /* check_setunset - additional checks for update requests */
144
145 int
146 check_setunset(addr, proc, prog, port)
147     struct sockaddr_in *addr;
148     u_long proc, prog, port;
149 {
150     if (!from_local(addr)) {
151 #ifdef HOSTS_ACCESS
152         (void) good_client(addr);               /* because of side effects */
153 #endif
154         log_bad_owner(addr, proc, prog);
155         return (FALSE);
156     }
157     if (port && !check_privileged_port(addr, proc, prog, port))
158         return (FALSE);
159     if (verboselog)
160         log_client(addr, proc, prog);
161     return (TRUE);
162 }
163
164 /* check_callit - additional checks for forwarded requests */
165
166 int
167 check_callit(addr, proc, prog, aproc)
168     struct sockaddr_in *addr;
169     u_long proc, prog, aproc;
170 {
171 #ifdef HOSTS_ACCESS
172     if (!(from_local(addr) || good_client(addr))) {
173         log_bad_host(addr, proc, prog);
174         return (FALSE);
175     }
176 #endif
177     if (prog == PMAPPROG || prog == NFSPROG || prog == YPXPROG ||
178         (prog == MOUNTPROG && aproc == MOUNTPROC_MNT) ||
179         (prog == YPPROG && aproc != YPPROC_DOMAIN_NONACK)) {
180         log_no_forward(addr, proc, prog);
181         return (FALSE);
182     }
183     if (verboselog)
184         log_client(addr, proc, prog);
185     return (TRUE);
186 }
187
188 /* toggle_verboselog - toggle verbose logging flag */
189
190 static void
191 toggle_verboselog(sig)
192     int sig;
193 {
194     (void) signal(sig, toggle_verboselog);
195     verboselog = !verboselog;
196 }
197
198 /* logit - report events of interest via the syslog daemon */
199
200 static void
201 logit(severity, addr, procnum, prognum, text)
202     int severity;
203     struct sockaddr_in *addr;
204     u_long procnum, prognum;
205     const char *text;
206 {
207     const char *procname;
208     char    procbuf[4 * sizeof(u_long)];
209     const char *progname;
210     char    progbuf[4 * sizeof(u_long)];
211     struct rpcent *rpc;
212     struct proc_map {
213         u_long  code;
214         const char *proc;
215     };
216     struct proc_map *procp;
217     static struct proc_map procmap[] = {
218         {PMAPPROC_CALLIT, "callit"},
219         {PMAPPROC_DUMP, "dump"},
220         {PMAPPROC_GETPORT, "getport"},
221         {PMAPPROC_NULL, "null"},
222         {PMAPPROC_SET, "set"},
223         {PMAPPROC_UNSET, "unset"},
224         {0, 0},
225     };
226
227     /*
228      * Fork off a process or the portmap daemon might hang while
229      * getrpcbynumber() or syslog() does its thing.
230      */
231
232     if (fork() == 0) {
233
234         /* Try to map program number to name. */
235
236         if (prognum == 0) {
237             progname = "";
238         } else if ((rpc = getrpcbynumber((int) prognum))) {
239             progname = rpc->r_name;
240         } else {
241             sprintf(progbuf, "%lu", prognum);
242             progname = progbuf;
243         }
244
245         /* Try to map procedure number to name. */
246
247         for (procp = procmap; procp->proc && procp->code != procnum; procp++)
248              /* void */ ;
249         if ((procname = procp->proc) == 0) {
250             sprintf(procbuf, "%lu", (u_long) procnum);
251             procname = procbuf;
252         }
253
254         /* Write syslog record. */
255
256         syslog(severity, "connect from %s to %s(%s)%s",
257                inet_ntoa(addr->sin_addr), procname, progname, text);
258         exit(0);
259     }
260 }