MiniDLNA update: 1.0.19.1 to 1.0.20
[tomato.git] / release / src / router / portmap / pmap_check.c
blob7153793eda522440ff41df7424c4117e1199c157
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.
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. Also, require
21 * that requests to set/unset the NFSD port come form a privileged port.
23 * If compiled with -DHOSTS_ACCESS, reject requests from hosts that are not
24 * authorized by the /etc/hosts.{allow,deny} files. The local system is
25 * always treated as an authorized host. The access control tables are never
26 * consulted for requests from the local system, and are always consulted
27 * for requests from other hosts. Access control is based on IP addresses
28 * only; attempts to map an address to a host name might cause the
29 * portmapper to hang.
31 * Author: Wietse Venema (wietse@wzv.win.tue.nl), dept. of Mathematics and
32 * Computing Science, Eindhoven University of Technology, The Netherlands.
36 #include <sys/types.h>
37 #include <unistd.h>
38 #include <rpc/rpc.h>
39 #include <rpc/pmap_prot.h>
40 #include <syslog.h>
41 #include <netdb.h>
42 #include <sys/signal.h>
43 #ifdef SYSV40
44 #include <netinet/in.h>
45 #include <rpc/rpcent.h>
46 #endif
47 //#include <tcpd.h>
48 #include <arpa/inet.h>
49 #include <grp.h>
51 #include "pmap_check.h"
53 /* Explicit #defines in case the include files are not available. */
55 #define NFSPROG ((u_long) 100003)
56 #define MOUNTPROG ((u_long) 100005)
57 #define YPXPROG ((u_long) 100069)
58 #define YPPROG ((u_long) 100004)
59 #define YPPROC_DOMAIN_NONACK ((u_long) 2)
60 #define MOUNTPROC_MNT ((u_long) 1)
61 #define NFS_PORT 2049
63 static void logit(int severity, struct sockaddr_in *addr,
64 u_long procnum, u_long prognum, char *text);
65 static void toggle_verboselog(int sig);
66 int verboselog __attribute ((visibility ("hidden"))) = 0;
67 int allow_severity __attribute ((visibility ("hidden"))) = LOG_INFO;
68 int deny_severity __attribute ((visibility ("hidden"))) = LOG_WARNING;
70 /* A handful of macros for "readability". */
72 #define reserved_port(p) (IPPORT_RESERVED/2 < (p) && (p) < IPPORT_RESERVED)
74 #define unreserved_port(p) (IPPORT_RESERVED <= (p) && (p) != NFS_PORT)
76 #define legal_port(a,p) \
77 (reserved_port(ntohs((a)->sin_port)) || unreserved_port(p))
79 #define log_bad_port(addr, proc, prog) \
80 logit(deny_severity, addr, proc, prog, ": request from unprivileged port")
82 #define log_bad_host(addr, proc, prog) \
83 logit(deny_severity, addr, proc, prog, ": request from unauthorized host")
85 #define log_bad_owner(addr, proc, prog) \
86 logit(deny_severity, addr, proc, prog, ": request from non-local host")
88 #define log_no_forward(addr, proc, prog) \
89 logit(deny_severity, addr, proc, prog, ": request not forwarded")
91 #define log_client(addr, proc, prog) \
92 logit(allow_severity, addr, proc, prog, "")
94 /* check_startup - additional startup code */
96 void check_startup(void)
100 * Give up root privileges so that we can never allocate a privileged
101 * port when forwarding an rpc request.
103 setgid(daemon_gid);
104 setgroups(0, NULL);
105 if (setuid(daemon_uid) == -1) {
106 syslog(LOG_ERR, "setuid(1) failed: %m");
107 exit(1);
109 (void) signal(SIGINT, toggle_verboselog);
113 #ifdef HOSTS_ACCESS
114 static int
115 good_client(struct sockaddr_in *addr)
117 if (hosts_ctl("portmap", "", inet_ntoa(addr->sin_addr), ""))
118 return 1;
119 #ifdef ENABLE_DNS
121 struct hostent *hp;
122 char **sp;
123 char *tmpname;
125 /* Check the hostname. */
126 hp = gethostbyaddr ((const char *) &(addr->sin_addr),
127 sizeof (addr->sin_addr), AF_INET);
129 if (!hp)
130 return 0;
132 /* must make sure the hostent is authoritative. */
133 tmpname = alloca (strlen (hp->h_name) + 1);
134 strcpy (tmpname, hp->h_name);
135 hp = gethostbyname(tmpname);
136 if (hp) {
137 /* now make sure the "addr->sin_addr" is on the list */
138 for (sp = hp->h_addr_list ; *sp ; sp++) {
139 if (memcmp(*sp, &(addr->sin_addr), hp->h_length)==0)
140 break;
142 if (!*sp)
143 /* it was a FAKE. */
144 return 0;
145 } else
146 /* never heard of it. misconfigured DNS? */
147 return 0;
149 /* Check the official name first. */
150 if (hosts_ctl("portmap", "", hp->h_name, ""))
151 return 1;
153 /* Check aliases. */
154 for (sp = hp->h_aliases; *sp ; sp++) {
155 if (hosts_ctl("portmap", "", *sp, ""))
156 return 1;
159 #endif /* ENABLE_DNS */
160 return 0;
162 #endif /* HOSTS_ACCESS */
164 /* check_default - additional checks for NULL, DUMP, GETPORT and unknown */
167 check_default(struct sockaddr_in *addr, u_long proc,
168 u_long prog)
170 #ifdef HOSTS_ACCESS
171 if (!(from_local(addr) || good_client(addr))) {
172 log_bad_host(addr, proc, prog);
173 return (FALSE);
175 #endif
176 if (verboselog)
177 log_client(addr, proc, prog);
178 return (TRUE);
181 /* check_privileged_port - additional checks for privileged-port updates */
184 check_privileged_port(struct sockaddr_in *addr, u_long proc,
185 u_long prog, u_long port)
187 #ifdef CHECK_PORT
188 if (!legal_port(addr, port)) {
189 log_bad_port(addr, proc, prog);
190 return (FALSE);
192 #endif
193 return (TRUE);
196 /* check_setunset - additional checks for update requests */
198 #ifdef LOOPBACK_SETUNSET
201 check_setunset(SVCXPRT *xprt, SVCXPRT *ludp_xprt, SVCXPRT *ltcp_xprt,
202 u_long proc, u_long prog, u_long port)
204 struct sockaddr_in *addr = svc_getcaller(xprt);
206 if (xprt != ludp_xprt && xprt != ltcp_xprt) {
207 #ifdef HOSTS_ACCESS
208 (void) good_client(addr); /* because of side effects */
209 #endif
210 log_bad_owner(addr, proc, prog);
211 return (FALSE);
213 if (port && !check_privileged_port(addr, proc, prog, port))
214 return (FALSE);
215 if (verboselog)
216 log_client(addr, proc, prog);
217 return (TRUE);
220 #else
223 check_setunset(struct sockaddr_in *addr, u_long proc,
224 u_long prog, u_long port)
226 if (!from_local(addr)) {
227 #ifdef HOSTS_ACCESS
228 (void) good_client(addr); /* because of side effects */
229 #endif
230 log_bad_owner(addr, proc, prog);
231 return (FALSE);
233 if (port && !check_privileged_port(addr, proc, prog, port))
234 return (FALSE);
235 if (verboselog)
236 log_client(addr, proc, prog);
237 return (TRUE);
240 #endif
242 /* check_callit - additional checks for forwarded requests */
245 check_callit(struct sockaddr_in *addr, u_long proc,
246 u_long prog, u_long aproc)
248 #ifdef HOSTS_ACCESS
249 if (!(from_local(addr) || good_client(addr))) {
250 log_bad_host(addr, proc, prog);
251 return (FALSE);
253 #endif
254 if (prog == PMAPPROG || prog == NFSPROG || prog == YPXPROG ||
255 (prog == MOUNTPROG && aproc == MOUNTPROC_MNT) ||
256 (prog == YPPROG && aproc != YPPROC_DOMAIN_NONACK)) {
257 log_no_forward(addr, proc, prog);
258 return (FALSE);
260 if (verboselog)
261 log_client(addr, proc, prog);
262 return (TRUE);
265 /* toggle_verboselog - toggle verbose logging flag */
267 static void toggle_verboselog(int sig)
269 (void) signal(sig, toggle_verboselog);
270 verboselog = !verboselog;
273 /* logit - report events of interest via the syslog daemon */
275 static void logit(int severity, struct sockaddr_in *addr,
276 u_long procnum, u_long prognum, char *text)
278 char *procname;
279 char procbuf[4 * sizeof(u_long)];
280 char *progname;
281 char progbuf[4 * sizeof(u_long)];
282 struct rpcent *rpc;
283 struct proc_map {
284 u_long code;
285 char *proc;
287 struct proc_map *procp;
288 static struct proc_map procmap[] = {
289 { PMAPPROC_CALLIT, "callit" },
290 { PMAPPROC_DUMP, "dump"} ,
291 { PMAPPROC_GETPORT, "getport"} ,
292 { PMAPPROC_NULL, "null"} ,
293 { PMAPPROC_SET, "set"} ,
294 { PMAPPROC_UNSET, "unset"} ,
295 { 0, 0} ,
299 * Fork off a process or the portmap daemon might hang while
300 * getrpcbynumber() or syslog() does its thing.
303 if (fork() == 0) {
305 /* Try to map program number to name. */
307 if (prognum == 0) {
308 progname = "";
309 } else if ((rpc = getrpcbynumber((int) prognum))) {
310 progname = rpc->r_name;
311 } else {
312 sprintf(progname = progbuf, "%lu", prognum);
315 /* Try to map procedure number to name. */
317 for (procp = procmap; procp->proc && procp->code != procnum; procp++)
318 /* void */ ;
319 if ((procname = procp->proc) == 0)
320 sprintf(procname = procbuf, "%lu", (u_long) procnum);
322 /* Write syslog record. */
324 syslog(severity, "connect from %s to %s(%s)%s",
325 inet_ntoa(addr->sin_addr), procname, progname, text);
326 exit(0);