1 /* This is copied from portmap 4.0-29 in RedHat. */
4 * pmap_check - additional portmap security.
6 * Always reject non-local requests to update the portmapper tables.
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.
12 * Refuse to forward requests to the nfsd process.
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.
18 * Always allocate an unprivileged port when forwarding a request.
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.
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.
30 * Author: Wietse Venema (wietse@wzv.win.tue.nl), dept. of Mathematics and
31 * Computing Science, Eindhoven University of Technology, The Netherlands.
42 #include <rpc/pmap_prot.h>
45 #include <sys/types.h>
46 #include <sys/signal.h>
47 #include <sys/queue.h>
52 #include "tcpwrapper.h"
56 #include <netinet/in.h>
57 #include <rpc/rpcent.h>
65 present_address(const struct sockaddr *sap, char *buf, const size_t buflen)
67 const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
68 const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap;
69 socklen_t len = (socklen_t)buflen;
71 switch (sap->sa_family) {
73 if (inet_ntop(AF_INET, &sin->sin_addr, buf, len) != 0)
76 if (inet_ntop(AF_INET6, &sin6->sin6_addr, buf, len) != 0)
80 memset(buf, 0, buflen);
81 strncpy(buf, "unrecognized caller", buflen);
83 #else /* !IPV6_SUPPORTED */
85 present_address(const struct sockaddr *sap, char *buf, const size_t buflen)
87 const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
88 socklen_t len = (socklen_t)buflen;
90 if (sap->sa_family == AF_INET)
91 if (inet_ntop(AF_INET, &sin->sin_addr, buf, len) != 0)
94 memset(buf, 0, buflen);
95 strncpy(buf, "unrecognized caller", (size_t)buflen);
97 #endif /* !IPV6_SUPPORTED */
99 typedef struct _haccess_t {
100 TAILQ_ENTRY(_haccess_t) list;
102 union nfs_sockaddr address;
105 #define HASH_TABLE_SIZE 1021
106 typedef struct _hash_head {
107 TAILQ_HEAD(host_list, _haccess_t) h_head;
110 static hash_head haccess_tbl[HASH_TABLE_SIZE];
113 strtoint(const char *str)
115 unsigned long i, n = 0;
116 size_t len = strlen(str);
118 for (i = 0; i < len; i++)
119 n += (unsigned char)str[i] * i;
125 hashint(const unsigned long num)
127 return (unsigned int)(num % HASH_TABLE_SIZE);
131 HASH(const char *addr, const unsigned long program)
133 return hashint(strtoint(addr) + program);
137 haccess_add(const struct sockaddr *sap, const char *address,
138 const unsigned long program, const int allowed)
144 hptr = (haccess_t *)malloc(sizeof(haccess_t));
148 hash = HASH(address, program);
149 head = &(haccess_tbl[hash]);
151 hptr->allowed = allowed;
152 memcpy(&hptr->address, sap, (size_t)nfs_sockaddr_length(sap));
154 if (TAILQ_EMPTY(&head->h_head))
155 TAILQ_INSERT_HEAD(&head->h_head, hptr, list);
157 TAILQ_INSERT_TAIL(&head->h_head, hptr, list);
161 haccess_lookup(const struct sockaddr *sap, const char *address,
162 const unsigned long program)
168 hash = HASH(address, program);
169 head = &(haccess_tbl[hash]);
171 TAILQ_FOREACH(hptr, &head->h_head, list) {
172 if (nfs_compare_sockaddr(&hptr->address.sa, sap))
179 logit(const char *address)
181 xlog_warn("connect from %s denied: request from unauthorized host",
186 good_client(char *name, struct sockaddr *sap)
188 struct request_info req;
190 request_init(&req, RQ_DAEMON, name, RQ_CLIENT_SIN, sap, 0);
193 if (hosts_access(&req))
202 static time_t allow_mtime, deny_mtime;
203 struct stat astat, dstat;
206 if (stat("/etc/hosts.allow", &astat) < 0)
208 if (stat("/etc/hosts.deny", &dstat) < 0)
211 if(!astat.st_mtime || !dstat.st_mtime)
214 if (astat.st_mtime != allow_mtime)
216 else if (dstat.st_mtime != deny_mtime)
219 allow_mtime = astat.st_mtime;
220 deny_mtime = dstat.st_mtime;
226 * check_default - additional checks for NULL, DUMP, GETPORT and unknown
227 * @name: pointer to '\0'-terminated ASCII string containing name of the
228 * daemon requesting the access check
229 * @sap: pointer to sockaddr containing network address of caller
230 * @program: RPC program number caller is attempting to access
232 * Returns TRUE if the caller is allowed access; otherwise FALSE is returned.
235 check_default(char *name, struct sockaddr *sap, const unsigned long program)
237 haccess_t *acc = NULL;
238 int changed = check_files();
239 char buf[INET6_ADDRSTRLEN];
241 present_address(sap, buf, sizeof(buf));
243 acc = haccess_lookup(sap, buf, program);
244 if (acc != NULL && changed == 0) {
245 xlog(D_GENERAL, "%s: access by %s %s (cached)", __func__,
246 buf, acc->allowed ? "ALLOWED" : "DENIED");
250 if (!(from_local(sap) || good_client(name, sap))) {
253 acc->allowed = FALSE;
255 haccess_add(sap, buf, program, FALSE);
256 xlog(D_GENERAL, "%s: access by %s DENIED", __func__, buf);
263 haccess_add(sap, buf, program, TRUE);
264 xlog(D_GENERAL, "%s: access by %s ALLOWED", __func__, buf);
269 #endif /* HAVE_LIBWRAP */