Commit | Line | Data |
---|---|---|
984263bc MD |
1 | /* |
2 | * Routines for testing only. Not really industrial strength. | |
3 | * | |
4 | * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. | |
5 | * | |
6 | * $FreeBSD: src/contrib/tcp_wrappers/scaffold.c,v 1.2.2.1 2000/07/18 08:34:55 ume Exp $ | |
7 | */ | |
8 | ||
984263bc MD |
9 | /* System libraries. */ |
10 | ||
11 | #include <sys/types.h> | |
12 | #include <sys/stat.h> | |
13 | #include <sys/socket.h> | |
14 | #include <netinet/in.h> | |
15 | #include <arpa/inet.h> | |
16 | #include <netdb.h> | |
17 | #include <stdio.h> | |
18 | #include <syslog.h> | |
19 | #include <setjmp.h> | |
20 | #include <string.h> | |
4badba38 | 21 | #include <stdlib.h> |
984263bc MD |
22 | |
23 | #ifndef INADDR_NONE | |
24 | #define INADDR_NONE (-1) /* XXX should be 0xffffffff */ | |
25 | #endif | |
26 | ||
27 | #ifndef INET6 | |
014c5732 | 28 | #include <stdlib.h> |
984263bc MD |
29 | #endif |
30 | ||
31 | /* Application-specific. */ | |
32 | ||
33 | #include "tcpd.h" | |
34 | #include "scaffold.h" | |
35 | ||
36 | /* | |
37 | * These are referenced by the options module and by rfc931.c. | |
38 | */ | |
39 | int allow_severity = SEVERITY; | |
40 | int deny_severity = LOG_WARNING; | |
41 | int rfc931_timeout = RFC931_TIMEOUT; | |
42 | ||
43 | #ifndef INET6 | |
44 | /* dup_hostent - create hostent in one memory block */ | |
45 | ||
46 | static struct hostent *dup_hostent(hp) | |
47 | struct hostent *hp; | |
48 | { | |
49 | struct hostent_block { | |
50 | struct hostent host; | |
51 | char *addr_list[1]; | |
52 | }; | |
53 | struct hostent_block *hb; | |
54 | int count; | |
55 | char *data; | |
56 | char *addr; | |
57 | ||
58 | for (count = 0; hp->h_addr_list[count] != 0; count++) | |
59 | /* void */ ; | |
60 | ||
61 | if ((hb = (struct hostent_block *) malloc(sizeof(struct hostent_block) | |
62 | + (hp->h_length + sizeof(char *)) * count)) == 0) { | |
63 | fprintf(stderr, "Sorry, out of memory\n"); | |
64 | exit(1); | |
65 | } | |
66 | memset((char *) &hb->host, 0, sizeof(hb->host)); | |
67 | hb->host.h_length = hp->h_length; | |
68 | hb->host.h_addr_list = hb->addr_list; | |
69 | hb->host.h_addr_list[count] = 0; | |
70 | data = (char *) (hb->host.h_addr_list + count + 1); | |
71 | ||
72 | for (count = 0; (addr = hp->h_addr_list[count]) != 0; count++) { | |
73 | hb->host.h_addr_list[count] = data + hp->h_length * count; | |
74 | memcpy(hb->host.h_addr_list[count], addr, hp->h_length); | |
75 | } | |
76 | return (&hb->host); | |
77 | } | |
78 | #endif | |
79 | ||
80 | /* find_inet_addr - find all addresses for this host, result to free() */ | |
81 | ||
82 | #ifdef INET6 | |
83 | struct addrinfo *find_inet_addr(host) | |
84 | char *host; | |
85 | { | |
86 | struct addrinfo hints, *res; | |
87 | ||
88 | memset(&hints, 0, sizeof(hints)); | |
89 | hints.ai_family = PF_UNSPEC; | |
90 | hints.ai_socktype = SOCK_STREAM; | |
91 | hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; | |
92 | if (getaddrinfo(host, NULL, &hints, &res) == 0) | |
93 | return (res); | |
94 | ||
95 | memset(&hints, 0, sizeof(hints)); | |
96 | hints.ai_family = PF_UNSPEC; | |
97 | hints.ai_socktype = SOCK_STREAM; | |
98 | hints.ai_flags = AI_PASSIVE | AI_CANONNAME; | |
99 | if (getaddrinfo(host, NULL, &hints, &res) != 0) { | |
100 | tcpd_warn("%s: host not found", host); | |
101 | return (0); | |
102 | } | |
103 | if (res->ai_family != AF_INET6 && res->ai_family != AF_INET) { | |
104 | tcpd_warn("%d: not an internet host", res->ai_family); | |
105 | freeaddrinfo(res); | |
106 | return (0); | |
107 | } | |
108 | if (!res->ai_canonname) { | |
109 | tcpd_warn("%s: hostname alias", host); | |
ae9447bd | 110 | tcpd_warn("(cannot obtain official name)"); |
984263bc MD |
111 | } else if (STR_NE(host, res->ai_canonname)) { |
112 | tcpd_warn("%s: hostname alias", host); | |
113 | tcpd_warn("(official name: %.*s)", STRING_LENGTH, res->ai_canonname); | |
114 | } | |
115 | return (res); | |
116 | } | |
117 | #else | |
118 | struct hostent *find_inet_addr(host) | |
119 | char *host; | |
120 | { | |
121 | struct in_addr addr; | |
122 | struct hostent *hp; | |
123 | static struct hostent h; | |
124 | static char *addr_list[2]; | |
125 | ||
126 | /* | |
127 | * Host address: translate it to internal form. | |
128 | */ | |
129 | if ((addr.s_addr = dot_quad_addr(host)) != INADDR_NONE) { | |
130 | h.h_addr_list = addr_list; | |
131 | h.h_addr_list[0] = (char *) &addr; | |
132 | h.h_length = sizeof(addr); | |
133 | return (dup_hostent(&h)); | |
134 | } | |
135 | ||
136 | /* | |
137 | * Map host name to a series of addresses. Watch out for non-internet | |
138 | * forms or aliases. The NOT_INADDR() is here in case gethostbyname() has | |
139 | * been "enhanced" to accept numeric addresses. Make a copy of the | |
140 | * address list so that later gethostbyXXX() calls will not clobber it. | |
141 | */ | |
142 | if (NOT_INADDR(host) == 0) { | |
143 | tcpd_warn("%s: not an internet address", host); | |
144 | return (0); | |
145 | } | |
146 | if ((hp = gethostbyname(host)) == 0) { | |
147 | tcpd_warn("%s: host not found", host); | |
148 | return (0); | |
149 | } | |
150 | if (hp->h_addrtype != AF_INET) { | |
151 | tcpd_warn("%d: not an internet host", hp->h_addrtype); | |
152 | return (0); | |
153 | } | |
154 | if (STR_NE(host, hp->h_name)) { | |
155 | tcpd_warn("%s: hostname alias", host); | |
156 | tcpd_warn("(official name: %.*s)", STRING_LENGTH, hp->h_name); | |
157 | } | |
158 | return (dup_hostent(hp)); | |
159 | } | |
160 | #endif | |
161 | ||
162 | /* check_dns - give each address thorough workout, return address count */ | |
163 | ||
164 | int check_dns(host) | |
165 | char *host; | |
166 | { | |
167 | struct request_info request; | |
168 | #ifdef INET6 | |
169 | struct sockaddr_storage sin; | |
170 | struct addrinfo *hp, *res; | |
171 | #else | |
172 | struct sockaddr_in sin; | |
173 | struct hostent *hp; | |
ae9447bd | 174 | char *addr; |
984263bc MD |
175 | #endif |
176 | int count; | |
984263bc MD |
177 | |
178 | if ((hp = find_inet_addr(host)) == 0) | |
179 | return (0); | |
180 | request_init(&request, RQ_CLIENT_SIN, &sin, 0); | |
181 | sock_methods(&request); | |
182 | #ifndef INET6 | |
183 | memset((char *) &sin, 0, sizeof(sin)); | |
184 | sin.sin_family = AF_INET; | |
185 | #endif | |
186 | ||
187 | #ifdef INET6 | |
188 | for (res = hp, count = 0; res; res = res->ai_next, count++) { | |
189 | memcpy(&sin, res->ai_addr, res->ai_addrlen); | |
190 | #else | |
191 | for (count = 0; (addr = hp->h_addr_list[count]) != 0; count++) { | |
192 | memcpy((char *) &sin.sin_addr, addr, sizeof(sin.sin_addr)); | |
193 | #endif | |
194 | ||
195 | /* | |
196 | * Force host name and address conversions. Use the request structure | |
197 | * as a cache. Detect hostname lookup problems. Any name/name or | |
198 | * name/address conflicts will be reported while eval_hostname() does | |
199 | * its job. | |
200 | */ | |
201 | request_set(&request, RQ_CLIENT_ADDR, "", RQ_CLIENT_NAME, "", 0); | |
202 | if (STR_EQ(eval_hostname(request.client), unknown)) | |
203 | tcpd_warn("host address %s->name lookup failed", | |
204 | eval_hostaddr(request.client)); | |
205 | } | |
206 | #ifdef INET6 | |
207 | freeaddrinfo(hp); | |
208 | #else | |
209 | free((char *) hp); | |
210 | #endif | |
211 | return (count); | |
212 | } | |
213 | ||
214 | /* dummy function to intercept the real shell_cmd() */ | |
215 | ||
216 | /* ARGSUSED */ | |
217 | ||
218 | void shell_cmd(command) | |
219 | char *command; | |
220 | { | |
221 | if (hosts_access_verbose) | |
222 | printf("command: %s", command); | |
223 | } | |
224 | ||
225 | /* dummy function to intercept the real clean_exit() */ | |
226 | ||
227 | /* ARGSUSED */ | |
228 | ||
229 | void clean_exit(request) | |
230 | struct request_info *request; | |
231 | { | |
232 | exit(0); | |
233 | } | |
234 | ||
984263bc MD |
235 | /* check_path - examine accessibility */ |
236 | ||
237 | int check_path(path, st) | |
238 | char *path; | |
239 | struct stat *st; | |
240 | { | |
241 | struct stat stbuf; | |
242 | char buf[BUFSIZ]; | |
243 | ||
244 | if (stat(path, st) < 0) | |
245 | return (-1); | |
246 | #ifdef notdef | |
247 | if (st->st_uid != 0) | |
248 | tcpd_warn("%s: not owned by root", path); | |
249 | if (st->st_mode & 020) | |
250 | tcpd_warn("%s: group writable", path); | |
251 | #endif | |
252 | if (st->st_mode & 002) | |
253 | tcpd_warn("%s: world writable", path); | |
254 | if (path[0] == '/' && path[1] != 0) { | |
255 | strrchr(strcpy(buf, path), '/')[0] = 0; | |
256 | (void) check_path(buf[0] ? buf : "/", &stbuf); | |
257 | } | |
258 | return (0); | |
259 | } |