]> git.decadent.org.uk Git - nfs-utils.git/blob - support/misc/tcpwrapper.c
When clients are define as IP addresses in /etc/hosts.deny,
[nfs-utils.git] / support / misc / tcpwrapper.c
1 /* This is copied from portmap 4.0-29 in RedHat. */
2
3  /*
4   * pmap_check - additional portmap security.
5   * 
6   * Always reject non-local requests to update the portmapper tables.
7   * 
8   * Refuse to forward mount requests to the nfs mount daemon. Otherwise, the
9   * requests would appear to come from the local system, and nfs export
10   * restrictions could be bypassed.
11   * 
12   * Refuse to forward requests to the nfsd process.
13   * 
14   * Refuse to forward requests to NIS (YP) daemons; The only exception is the
15   * YPPROC_DOMAIN_NONACK broadcast rpc call that is used to establish initial
16   * contact with the NIS server.
17   * 
18   * Always allocate an unprivileged port when forwarding a request.
19   * 
20   * If compiled with -DCHECK_PORT, require that requests to register or
21   * unregister a privileged port come from a privileged port. This makes it
22   * more difficult to replace a critical service by a trojan.
23   * 
24   * If compiled with -DHOSTS_ACCESS, reject requests from hosts that are not
25   * authorized by the /etc/hosts.{allow,deny} files. The local system is
26   * always treated as an authorized host. The access control tables are never
27   * consulted for requests from the local system, and are always consulted
28   * for requests from other hosts.
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 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
37 #include <tcpwrapper.h>
38 #include <unistd.h>
39 #include <string.h>
40 #include <rpc/rpc.h>
41 #include <rpc/pmap_prot.h>
42 #include <syslog.h>
43 #include <netdb.h>
44 #include <pwd.h>
45 #include <sys/types.h>
46 #include <sys/signal.h>
47 #ifdef SYSV40
48 #include <netinet/in.h>
49 #include <rpc/rpcent.h>
50 #endif
51
52 static void logit(int severity, struct sockaddr_in *addr,
53                   u_long procnum, u_long prognum, char *text);
54 static void toggle_verboselog(int sig);
55 int     verboselog = 0;
56 int     allow_severity = LOG_INFO;
57 int     deny_severity = LOG_WARNING;
58
59 /* A handful of macros for "readability". */
60
61 #ifdef HAVE_LIBWRAP
62 /* coming from libwrap.a (tcp_wrappers) */
63 extern int hosts_ctl(char *daemon, char *name, char *addr, char *user);
64 #else
65 int hosts_ctl(char *daemon, char *name, char *addr, char *user)
66 {
67         return 0;
68 }
69 #endif
70
71 #define legal_port(a,p) \
72   (ntohs((a)->sin_port) < IPPORT_RESERVED || (p) >= IPPORT_RESERVED)
73
74 #define log_bad_port(addr, proc, prog) \
75   logit(deny_severity, addr, proc, prog, ": request from unprivileged port")
76
77 #define log_bad_host(addr, proc, prog) \
78   logit(deny_severity, addr, proc, prog, ": request from unauthorized host")
79
80 #define log_bad_owner(addr, proc, prog) \
81   logit(deny_severity, addr, proc, prog, ": request from non-local host")
82
83 #define log_no_forward(addr, proc, prog) \
84   logit(deny_severity, addr, proc, prog, ": request not forwarded")
85
86 #define log_client(addr, proc, prog) \
87   logit(allow_severity, addr, proc, prog, "")
88
89 #define ALLOW 1
90 #define DENY 0
91
92 int
93 good_client(daemon, addr)
94 char *daemon;
95 struct sockaddr_in *addr;
96 {
97     struct hostent *hp;
98     char **sp;
99     char *tmpname;
100
101         /* First check the address. */
102         if (hosts_ctl(daemon, "", inet_ntoa(addr->sin_addr), "") == DENY)
103                 return DENY;
104
105         /* Now do the hostname lookup */
106         hp = gethostbyaddr ((const char *) &(addr->sin_addr),
107                 sizeof (addr->sin_addr), AF_INET);
108         if (!hp)
109                 return DENY; /* never heard of it. misconfigured DNS? */
110
111         /* Make sure the hostent is authorative. */
112         tmpname = strdup(hp->h_name);
113         if (!tmpname)
114                 return DENY;
115         hp = gethostbyname(tmpname);
116         free(tmpname);
117         if (!hp)
118                 return DENY; /* never heard of it. misconfigured DNS? */
119
120         /* Now make sure the address is on the list */
121         for (sp = hp->h_addr_list ; *sp ; sp++) {
122             if (memcmp(*sp, &(addr->sin_addr), hp->h_length) == 0)
123                         break;
124         }
125         if (!*sp)
126             return DENY; /* it was a FAKE. */
127
128         /* Check the official name and address. */
129         if (hosts_ctl(daemon, hp->h_name, inet_ntoa(addr->sin_addr), "") == DENY)
130                 return DENY;
131
132         /* Now check aliases. */
133         for (sp = hp->h_aliases; *sp ; sp++) {
134                 if (hosts_ctl(daemon, *sp, inet_ntoa(addr->sin_addr), "") == DENY)
135                 return DENY;
136         }
137
138    return ALLOW;
139 }
140
141 /* check_startup - additional startup code */
142
143 void    check_startup(void)
144 {
145
146     /*
147      * Give up root privileges so that we can never allocate a privileged
148      * port when forwarding an rpc request.
149      *
150      * Fix 8/3/00 Philipp Knirsch: First lookup our rpc user. If we find it,
151      * switch to that uid, otherwise simply resue the old bin user and print
152      * out a warning in syslog.
153      */
154
155     struct passwd *pwent;
156
157     pwent = getpwnam("rpc");
158     if (pwent == NULL) {
159         syslog(LOG_WARNING, "user rpc not found, reverting to user bin");
160         if (setuid(1) == -1) {
161             syslog(LOG_ERR, "setuid(1) failed: %m");
162             exit(1);
163         }
164     }
165     else {
166         if (setuid(pwent->pw_uid) == -1) {
167             syslog(LOG_WARNING, "setuid() to rpc user failed: %m");
168             if (setuid(1) == -1) {
169                 syslog(LOG_ERR, "setuid(1) failed: %m");
170                 exit(1);
171             }
172         }
173     }
174
175     (void) signal(SIGINT, toggle_verboselog);
176 }
177
178 /* check_default - additional checks for NULL, DUMP, GETPORT and unknown */
179
180 int
181 check_default(daemon, addr, proc, prog)
182 char *daemon;
183 struct sockaddr_in *addr;
184 u_long  proc;
185 u_long  prog;
186 {
187         if (!(from_local(addr) || good_client(daemon, addr))) {
188                 log_bad_host(addr, proc, prog);
189                 return (FALSE);
190         }
191         if (verboselog)
192                 log_client(addr, proc, prog);
193
194     return (TRUE);
195 }
196
197 /* check_privileged_port - additional checks for privileged-port updates */
198 int
199 check_privileged_port(struct sockaddr_in *addr, 
200                       u_long proc, u_long prog, u_long port)
201 {
202 #ifdef CHECK_PORT
203     if (!legal_port(addr, port)) {
204         log_bad_port(addr, proc, prog);
205         return (FALSE);
206     }
207 #endif
208     return (TRUE);
209 }
210
211 /* toggle_verboselog - toggle verbose logging flag */
212
213 static void toggle_verboselog(int sig)
214 {
215     (void) signal(sig, toggle_verboselog);
216     verboselog = !verboselog;
217 }
218
219 /* logit - report events of interest via the syslog daemon */
220
221 static void logit(int severity, struct sockaddr_in *addr,
222                   u_long procnum, u_long prognum, char *text)
223 {
224     char   *procname;
225     char    procbuf[16 + 4 * sizeof(u_long)];
226     char   *progname;
227     char    progbuf[16 + 4 * sizeof(u_long)];
228     struct rpcent *rpc;
229
230     /*
231      * Fork off a process or the portmap daemon might hang while
232      * getrpcbynumber() or syslog() does its thing.
233      *
234      * Don't forget to wait for the children, too...
235      */
236
237     if (fork() == 0) {
238
239         /* Try to map program number to name. */
240
241         if (prognum == 0) {
242             progname = "";
243         } else if ((rpc = getrpcbynumber((int) prognum))) {
244             progname = rpc->r_name;
245         } else {
246             snprintf(progname = progbuf, sizeof (progbuf),
247                      "prog (%lu)", prognum);
248         }
249
250         /* Try to map procedure number to name. */
251
252         snprintf(procname = procbuf, sizeof (procbuf),
253                  "proc (%lu)", (u_long) procnum);
254
255         /* Write syslog record. */
256
257         syslog(severity, "connect from %s to %s in %s%s",
258                inet_ntoa(addr->sin_addr), procname, progname, text);
259         exit(0);
260     }
261 }