tcpwrapper: Fix signage problems in the tcp_wrappers hash function
[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
38 #ifdef HAVE_LIBWRAP
39 #include <unistd.h>
40 #include <string.h>
41 #include <rpc/rpc.h>
42 #include <rpc/pmap_prot.h>
43 #include <netdb.h>
44 #include <pwd.h>
45 #include <sys/types.h>
46 #include <sys/signal.h>
47 #include <sys/queue.h>
48 #include <sys/stat.h>
49 #include <tcpd.h>
50
51 #include "tcpwrapper.h"
52 #include "xlog.h"
53
54 #ifdef SYSV40
55 #include <netinet/in.h>
56 #include <rpc/rpcent.h>
57 #endif
58
59 static int check_files(void);
60
61 #define ALLOW 1
62 #define DENY 0
63
64 typedef struct _haccess_t {
65         TAILQ_ENTRY(_haccess_t) list;
66         int access;
67     struct in_addr addr;
68 } haccess_t;
69
70 #define HASH_TABLE_SIZE 1021
71 typedef struct _hash_head {
72         TAILQ_HEAD(host_list, _haccess_t) h_head;
73 } hash_head;
74 hash_head haccess_tbl[HASH_TABLE_SIZE];
75 static haccess_t *haccess_lookup(struct sockaddr_in *addr, u_long);
76 static void haccess_add(struct sockaddr_in *addr, u_long, int);
77
78 static unsigned long
79 strtoint(const char *str)
80 {
81         unsigned long i, n = 0;
82         size_t len = strlen(str);
83
84         for (i = 0; i < len; i++)
85                 n += (unsigned char)str[i] * i;
86
87         return n;
88 }
89
90 static unsigned int
91 hashint(const unsigned long num)
92 {
93         return (unsigned int)(num % HASH_TABLE_SIZE);
94 }
95
96 static unsigned int
97 HASH(const char *addr, const unsigned long program)
98 {
99         return hashint(strtoint(addr) + program);
100 }
101
102 void haccess_add(struct sockaddr_in *addr, u_long prog, int access)
103 {
104         hash_head *head;
105         haccess_t *hptr;
106         unsigned int hash;
107
108         hptr = (haccess_t *)malloc(sizeof(haccess_t));
109         if (hptr == NULL)
110                 return;
111
112         hash = HASH(inet_ntoa(addr->sin_addr), prog);
113         head = &(haccess_tbl[hash]);
114
115         hptr->access = access;
116         hptr->addr.s_addr = addr->sin_addr.s_addr;
117
118         if (TAILQ_EMPTY(&head->h_head))
119                 TAILQ_INSERT_HEAD(&head->h_head, hptr, list);
120         else
121                 TAILQ_INSERT_TAIL(&head->h_head, hptr, list);
122 }
123 haccess_t *haccess_lookup(struct sockaddr_in *addr, u_long prog)
124 {
125         hash_head *head;
126         haccess_t *hptr;
127         unsigned int hash;
128
129         hash = HASH(inet_ntoa(addr->sin_addr), prog);
130         head = &(haccess_tbl[hash]);
131
132         TAILQ_FOREACH(hptr, &head->h_head, list) {
133                 if (hptr->addr.s_addr == addr->sin_addr.s_addr)
134                         return hptr;
135         }
136         return NULL;
137 }
138
139 static void
140 logit(const struct sockaddr_in *sin)
141 {
142         char buf[INET_ADDRSTRLEN];
143
144         xlog_warn("connect from %s denied: request from unauthorized host",
145                         inet_ntop(AF_INET, &sin->sin_addr, buf, sizeof(buf)));
146                 
147 }
148
149 int
150 good_client(daemon, addr)
151 char *daemon;
152 struct sockaddr_in *addr;
153 {
154         struct request_info req;
155
156         request_init(&req, RQ_DAEMON, daemon, RQ_CLIENT_SIN, addr, 0);
157         sock_methods(&req);
158
159         if (hosts_access(&req)) 
160                 return ALLOW;
161
162         return DENY;
163 }
164
165 /* check_files - check to see if either access files have changed */
166
167 static int check_files()
168 {
169         static time_t allow_mtime, deny_mtime;
170         struct stat astat, dstat;
171         int changed = 0;
172
173         if (stat("/etc/hosts.allow", &astat) < 0)
174                 astat.st_mtime = 0;
175         if (stat("/etc/hosts.deny", &dstat) < 0)
176                 dstat.st_mtime = 0;
177
178         if(!astat.st_mtime || !dstat.st_mtime)
179                 return changed;
180
181         if (astat.st_mtime != allow_mtime)
182                 changed = 1;
183         else if (dstat.st_mtime != deny_mtime)
184                 changed = 1;
185
186         allow_mtime = astat.st_mtime;
187         deny_mtime = dstat.st_mtime;
188
189         return changed;
190 }
191
192 /**
193  * check_default - additional checks for NULL, DUMP, GETPORT and unknown
194  * @daemon: pointer to '\0'-terminated ASCII string containing name of the
195  *              daemon requesting the access check
196  * @addr: pointer to socket address containing address of caller
197  * @prog: RPC program number caller is attempting to access
198  *
199  * Returns TRUE if the caller is allowed access; otherwise FALSE is returned.
200  */
201 int
202 check_default(char *daemon, struct sockaddr_in *addr, u_long prog)
203 {
204         haccess_t *acc = NULL;
205         int changed = check_files();
206
207         acc = haccess_lookup(addr, prog);
208         if (acc && changed == 0)
209                 return (acc->access);
210
211         if (!(from_local((struct sockaddr *)addr) || good_client(daemon, addr))) {
212                 logit(addr);
213                 if (acc)
214                         acc->access = FALSE;
215                 else 
216                         haccess_add(addr, prog, FALSE);
217                 return (FALSE);
218         }
219
220         if (acc)
221                 acc->access = TRUE;
222         else 
223                 haccess_add(addr, prog, TRUE);
224
225     return (TRUE);
226 }
227
228 #endif  /* HAVE_LIBWRAP */