/src/proftpd/src/bindings.c
Line | Count | Source |
1 | | /* |
2 | | * ProFTPD - FTP server daemon |
3 | | * Copyright (c) 2001-2025 The ProFTPD Project team |
4 | | * |
5 | | * This program is free software; you can redistribute it and/or modify |
6 | | * it under the terms of the GNU General Public License as published by |
7 | | * the Free Software Foundation; either version 2 of the License, or |
8 | | * (at your option) any later version. |
9 | | * |
10 | | * This program is distributed in the hope that it will be useful, |
11 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | | * GNU General Public License for more details. |
14 | | * |
15 | | * You should have received a copy of the GNU General Public License |
16 | | * along with this program; if not, write to the Free Software |
17 | | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. |
18 | | * |
19 | | * As a special exemption, The ProFTPD Project team and other respective |
20 | | * copyright holders give permission to link this program with OpenSSL, and |
21 | | * distribute the resulting executable, without including the source code for |
22 | | * OpenSSL in the source distribution. |
23 | | */ |
24 | | |
25 | | /* Routines to work with ProFTPD bindings. */ |
26 | | |
27 | | #include "conf.h" |
28 | | |
29 | | /* From src/dirtree.c */ |
30 | | extern xaset_t *server_list; |
31 | | extern server_rec *main_server; |
32 | | |
33 | | static pr_ipbind_t *ipbind_table[PR_BINDINGS_TABLE_SIZE]; |
34 | | static int ipbind_table_initialized = FALSE; |
35 | | |
36 | | static pool *binding_pool = NULL; |
37 | | static pr_ipbind_t *ipbind_default_server = NULL, |
38 | | *ipbind_localhost_server = NULL; |
39 | | |
40 | | static const char *trace_channel = "binding"; |
41 | | |
42 | | static void trace_ipbind_table(void); |
43 | | |
44 | 0 | static void init_ipbind_table(void) { |
45 | 0 | if (ipbind_table_initialized == TRUE) { |
46 | 0 | return; |
47 | 0 | } |
48 | | |
49 | 0 | memset(ipbind_table, 0, sizeof(ipbind_table)); |
50 | 0 | ipbind_table_initialized = TRUE; |
51 | 0 | } |
52 | | |
53 | | /* Server cleanup callback function */ |
54 | 0 | static void server_cleanup_cb(void *conn) { |
55 | 0 | *((conn_t **) conn) = NULL; |
56 | 0 | } |
57 | | |
58 | | /* The hashing function for the hash table of bindings. This algorithm |
59 | | * is stolen from Apache's http_vhost.c |
60 | | */ |
61 | | static unsigned int ipbind_hash_addr(const pr_netaddr_t *addr, |
62 | 0 | unsigned int port) { |
63 | 0 | size_t offset; |
64 | 0 | unsigned int key, idx; |
65 | |
|
66 | 0 | offset = pr_netaddr_get_inaddr_len(addr); |
67 | | |
68 | | /* The key is the last four bytes of the IP address. |
69 | | * For IPv4, this is the entire address, as always. |
70 | | * For IPv6, this is usually part of the MAC address. |
71 | | */ |
72 | 0 | key = *(unsigned *) ((char *) pr_netaddr_get_inaddr(addr) + offset - 4); |
73 | | |
74 | | /* Add in the port number, to give better spread of key values when many |
75 | | * different port values are used. |
76 | | */ |
77 | 0 | key += port; |
78 | |
|
79 | 0 | key ^= (key >> 16); |
80 | 0 | idx = ((key >> 8) ^ key) % PR_BINDINGS_TABLE_SIZE; |
81 | 0 | return idx; |
82 | 0 | } |
83 | | |
84 | | static pool *listening_conn_pool = NULL; |
85 | | static xaset_t *listening_conn_list = NULL; |
86 | | struct listener_rec { |
87 | | struct listener_rec *next, *prev; |
88 | | |
89 | | pool *pool; |
90 | | const pr_netaddr_t *addr; |
91 | | unsigned int port; |
92 | | conn_t *conn; |
93 | | int claimed; |
94 | | }; |
95 | | |
96 | | conn_t *pr_ipbind_get_listening_conn(server_rec *server, |
97 | 0 | const pr_netaddr_t *addr, unsigned int port) { |
98 | 0 | conn_t *l, *sl; |
99 | 0 | pool *p; |
100 | 0 | struct listener_rec *lr; |
101 | |
|
102 | 0 | if (listening_conn_list) { |
103 | 0 | for (lr = (struct listener_rec *) listening_conn_list->xas_list; lr; |
104 | 0 | lr = lr->next) { |
105 | 0 | int use_elt = FALSE; |
106 | |
|
107 | 0 | pr_signals_handle(); |
108 | |
|
109 | 0 | if (addr != NULL && |
110 | 0 | lr->addr != NULL) { |
111 | 0 | const char *lr_ipstr = NULL; |
112 | |
|
113 | 0 | lr_ipstr = pr_netaddr_get_ipstr(lr->addr); |
114 | | |
115 | | /* Note: lr_ipstr should never be null. If it is, it means that |
116 | | * the lr->addr object never had its IP address resolved/stashed, |
117 | | * and in attempting to do, getnameinfo(3) failed for some reason. |
118 | | * |
119 | | * The IP address on which it's listening, if not available via |
120 | | * lr->addr, should thus be available via lr->conn->local_addr. |
121 | | */ |
122 | |
|
123 | 0 | if (lr_ipstr == NULL && |
124 | 0 | lr->conn != NULL) { |
125 | 0 | lr_ipstr = pr_netaddr_get_ipstr(lr->conn->local_addr); |
126 | 0 | } |
127 | |
|
128 | 0 | if (lr_ipstr != NULL) { |
129 | 0 | if (strcmp(pr_netaddr_get_ipstr(addr), lr_ipstr) == 0 && |
130 | 0 | port == lr->port) { |
131 | 0 | use_elt = TRUE; |
132 | 0 | } |
133 | 0 | } |
134 | |
|
135 | 0 | } else if (addr == NULL && |
136 | 0 | port == lr->port) { |
137 | 0 | use_elt = TRUE; |
138 | 0 | } |
139 | |
|
140 | 0 | if (use_elt == TRUE) { |
141 | 0 | lr->claimed = TRUE; |
142 | 0 | return lr->conn; |
143 | 0 | } |
144 | 0 | } |
145 | 0 | } |
146 | | |
147 | 0 | if (listening_conn_pool == NULL) { |
148 | 0 | listening_conn_pool = make_sub_pool(permanent_pool); |
149 | 0 | pr_pool_tag(listening_conn_pool, "Listening Connection Pool"); |
150 | |
|
151 | 0 | listening_conn_list = xaset_create(listening_conn_pool, NULL); |
152 | 0 | } |
153 | |
|
154 | 0 | p = make_sub_pool(listening_conn_pool); |
155 | 0 | pr_pool_tag(p, "Listening conn subpool"); |
156 | |
|
157 | 0 | l = pr_inet_create_conn(p, -1, addr, port, FALSE); |
158 | 0 | if (l == NULL) { |
159 | 0 | return NULL; |
160 | 0 | } |
161 | | |
162 | | /* Inform any interested listeners that this socket was opened. In order |
163 | | * to convey the discovered conn_t `l` to the event listener, we set it |
164 | | * on the server `s` temporarily. |
165 | | */ |
166 | 0 | sl = server->listen; |
167 | 0 | server->listen = l; |
168 | 0 | pr_inet_generate_socket_event("core.ctrl-listen", server, l->local_addr, |
169 | 0 | l->listen_fd); |
170 | 0 | server->listen = sl; |
171 | |
|
172 | 0 | lr = pcalloc(p, sizeof(struct listener_rec)); |
173 | 0 | lr->pool = p; |
174 | 0 | lr->conn = l; |
175 | 0 | lr->addr = pr_netaddr_dup(p, addr); |
176 | 0 | if (lr->addr == NULL && |
177 | 0 | errno != EINVAL) { |
178 | 0 | return NULL; |
179 | 0 | } |
180 | 0 | lr->port = port; |
181 | 0 | lr->claimed = TRUE; |
182 | |
|
183 | 0 | xaset_insert(listening_conn_list, (xasetmember_t *) lr); |
184 | 0 | return l; |
185 | 0 | } |
186 | | |
187 | | /* Slight (clever?) optimization: the loop in server_loop() always |
188 | | * calls pr_ipbind_listen(), selects, then pr_ipbind_accept_conn(). Now, |
189 | | * rather than having both pr_ipbind_listen() and pr_ipbind_accept_conn() |
190 | | * scan the entire ipbind table looking for matches, what if pr_ipbind_listen |
191 | | * kept track of which listeners (connt_s) it used, so that |
192 | | * pr_ipbind_accept_conn() need merely check those listeners, rather than |
193 | | * scanning the entire table itself? |
194 | | */ |
195 | | |
196 | | static array_header *listener_list = NULL; |
197 | | |
198 | 0 | conn_t *pr_ipbind_accept_conn(fd_set *readfds, int *listenfd) { |
199 | 0 | conn_t **listeners = listener_list->elts; |
200 | 0 | register unsigned int i = 0; |
201 | |
|
202 | 0 | if (readfds == NULL || |
203 | 0 | listenfd == NULL) { |
204 | 0 | errno = EINVAL; |
205 | 0 | return NULL; |
206 | 0 | } |
207 | | |
208 | 0 | for (i = 0; i < listener_list->nelts; i++) { |
209 | 0 | conn_t *listener = listeners[i]; |
210 | |
|
211 | 0 | pr_signals_handle(); |
212 | 0 | if (FD_ISSET(listener->listen_fd, readfds) && |
213 | 0 | listener->mode == CM_LISTEN) { |
214 | 0 | int fd = pr_inet_accept_nowait(listener->pool, listener); |
215 | |
|
216 | 0 | if (fd == -1) { |
217 | 0 | int xerrno = errno; |
218 | | |
219 | | /* Handle errors gracefully. If we're here, then |
220 | | * ipbind->ib_server->listen contains either error information, or |
221 | | * we just got caught in a blocking condition. |
222 | | */ |
223 | 0 | if (listener->mode == CM_ERROR) { |
224 | | |
225 | | /* Ignore ECONNABORTED, as they tend to be health checks/probes by |
226 | | * e.g. load balancers and other naive TCP clients. |
227 | | */ |
228 | 0 | if (listener->xerrno != ECONNABORTED) { |
229 | 0 | pr_log_pri(PR_LOG_ERR, "error: unable to accept an incoming " |
230 | 0 | "connection: %s", strerror(listener->xerrno)); |
231 | 0 | } |
232 | |
|
233 | 0 | listener->xerrno = 0; |
234 | 0 | listener->mode = CM_LISTEN; |
235 | |
|
236 | 0 | errno = xerrno; |
237 | 0 | return NULL; |
238 | 0 | } |
239 | 0 | } |
240 | | |
241 | 0 | *listenfd = fd; |
242 | 0 | return listener; |
243 | 0 | } |
244 | 0 | } |
245 | | |
246 | 0 | errno = ENOENT; |
247 | 0 | return NULL; |
248 | 0 | } |
249 | | |
250 | 0 | int pr_ipbind_add_binds(server_rec *serv) { |
251 | 0 | int res = 0; |
252 | 0 | config_rec *c = NULL; |
253 | 0 | conn_t *listen_conn = NULL; |
254 | 0 | const pr_netaddr_t *addr = NULL; |
255 | |
|
256 | 0 | if (serv == NULL) { |
257 | 0 | errno = EINVAL; |
258 | 0 | return -1; |
259 | 0 | } |
260 | | |
261 | 0 | c = find_config(serv->conf, CONF_PARAM, "_bind_", FALSE); |
262 | 0 | while (c != NULL) { |
263 | 0 | listen_conn = NULL; |
264 | |
|
265 | 0 | pr_signals_handle(); |
266 | |
|
267 | 0 | addr = pr_netaddr_get_addr(serv->pool, c->argv[0], NULL); |
268 | 0 | if (addr == NULL) { |
269 | 0 | pr_log_pri(PR_LOG_WARNING, |
270 | 0 | "notice: unable to determine IP address of '%s'", (char *) c->argv[0]); |
271 | 0 | c = find_config_next(c, c->next, CONF_PARAM, "_bind_", FALSE); |
272 | 0 | continue; |
273 | 0 | } |
274 | | |
275 | | /* If the SocketBindTight directive is in effect, create a separate |
276 | | * listen socket for this address, and add it to the binding list. |
277 | | */ |
278 | 0 | if (SocketBindTight && |
279 | 0 | serv->ServerPort) { |
280 | 0 | listen_conn = pr_ipbind_get_listening_conn(serv, addr, serv->ServerPort); |
281 | 0 | if (listen_conn == NULL) { |
282 | 0 | return -1; |
283 | 0 | } |
284 | | |
285 | 0 | res = pr_ipbind_create(serv, addr, serv->ServerPort); |
286 | 0 | if (res < 0) { |
287 | 0 | pr_log_pri(PR_LOG_NOTICE, |
288 | 0 | "%s:%d: notice: unable to create ipbind '%s#%u': %s", __FILE__, |
289 | 0 | __LINE__, serv->ServerAddress, serv->ServerPort, strerror(errno)); |
290 | 0 | } |
291 | |
|
292 | 0 | res = pr_ipbind_open(addr, serv->ServerPort, listen_conn, FALSE, FALSE, |
293 | 0 | TRUE); |
294 | 0 | if (res < 0) { |
295 | 0 | pr_log_pri(PR_LOG_NOTICE, |
296 | 0 | "%s:%d: notice: unable to open ipbind '%s': %s", __FILE__, __LINE__, |
297 | 0 | pr_netaddr_get_ipstr(addr), strerror(errno)); |
298 | 0 | } |
299 | |
|
300 | 0 | } else { |
301 | 0 | res = pr_ipbind_create(serv, addr, serv->ServerPort); |
302 | 0 | if (res < 0) { |
303 | 0 | pr_log_pri(PR_LOG_NOTICE, |
304 | 0 | "%s:%d: notice: unable to create ipbind '%s#%u': %s", __FILE__, |
305 | 0 | __LINE__, serv->ServerAddress, serv->ServerPort, strerror(errno)); |
306 | 0 | } |
307 | |
|
308 | 0 | res = pr_ipbind_open(addr, serv->ServerPort, serv->listen, FALSE, FALSE, |
309 | 0 | TRUE); |
310 | 0 | if (res < 0) { |
311 | 0 | pr_log_pri(PR_LOG_NOTICE, |
312 | 0 | "%s:%d: notice: unable to open ipbind '%s': %s", __FILE__, __LINE__, |
313 | 0 | pr_netaddr_get_ipstr(addr), strerror(errno)); |
314 | 0 | } |
315 | 0 | } |
316 | | |
317 | 0 | c = find_config_next(c, c->next, CONF_PARAM, "_bind_", FALSE); |
318 | 0 | } |
319 | | |
320 | 0 | return 0; |
321 | 0 | } |
322 | | |
323 | | int pr_ipbind_close(const pr_netaddr_t *addr, unsigned int port, |
324 | 0 | unsigned char close_namebinds) { |
325 | 0 | register unsigned int i = 0; |
326 | |
|
327 | 0 | if (addr != NULL) { |
328 | 0 | pr_ipbind_t *ipbind = NULL; |
329 | 0 | unsigned char have_ipbind = FALSE; |
330 | |
|
331 | 0 | i = ipbind_hash_addr(addr, port); |
332 | |
|
333 | 0 | if (ipbind_table[i] == NULL) { |
334 | 0 | pr_log_pri(PR_LOG_NOTICE, "notice: no ipbind found for %s:%d", |
335 | 0 | pr_netaddr_get_ipstr(addr), port); |
336 | 0 | errno = ENOENT; |
337 | 0 | return -1; |
338 | 0 | } |
339 | | |
340 | 0 | for (ipbind = ipbind_table[i]; ipbind; ipbind = ipbind->ib_next) { |
341 | 0 | pr_signals_handle(); |
342 | |
|
343 | 0 | if (pr_netaddr_cmp(ipbind->ib_addr, addr) == 0 && |
344 | 0 | (!ipbind->ib_port || ipbind->ib_port == port)) { |
345 | 0 | have_ipbind = TRUE; |
346 | 0 | break; |
347 | 0 | } |
348 | 0 | } |
349 | |
|
350 | 0 | if (have_ipbind == FALSE) { |
351 | 0 | pr_log_pri(PR_LOG_NOTICE, "notice: no ipbind found for %s:%d", |
352 | 0 | pr_netaddr_get_ipstr(addr), port); |
353 | 0 | errno = ENOENT; |
354 | 0 | return -1; |
355 | 0 | } |
356 | | |
357 | | /* If already closed, exit now. */ |
358 | 0 | if (ipbind->ib_isactive == FALSE) { |
359 | 0 | errno = EPERM; |
360 | 0 | return -1; |
361 | 0 | } |
362 | | |
363 | | /* Close the ipbinding's listen connection, if present. The trick |
364 | | * here is determining whether this binding's listen member is |
365 | | * _the_ listening socket for the master daemon, or whether it's |
366 | | * been created for SocketBindTight, and can be closed. |
367 | | * |
368 | | * Actually, it's not that hard. It's only _the_ listening socket |
369 | | * for the master daemon in inetd mode, in which case virtual servers |
370 | | * can't be shutdown via ftpdctl, anyway. |
371 | | */ |
372 | 0 | if (SocketBindTight && |
373 | 0 | ipbind->ib_listener != NULL) { |
374 | 0 | pr_inet_close(ipbind->ib_server->pool, ipbind->ib_listener); |
375 | 0 | ipbind->ib_listener = ipbind->ib_server->listen = NULL; |
376 | 0 | } |
377 | | |
378 | | /* Mark this ipbind as inactive. For SocketBindTight sockets, the |
379 | | * closing of the listening connection will suffice, from the clients' |
380 | | * point of view. However, this covers the non-SocketBindTight case, |
381 | | * and will prevent this binding from returning its server_rec pointer |
382 | | * on future lookup requests via pr_ipbind_get_server(). |
383 | | */ |
384 | 0 | ipbind->ib_isactive = FALSE; |
385 | |
|
386 | 0 | if (close_namebinds == TRUE && |
387 | 0 | ipbind->ib_namebinds != NULL) { |
388 | 0 | register unsigned int j = 0; |
389 | 0 | pr_namebind_t **namebinds = NULL; |
390 | |
|
391 | 0 | namebinds = (pr_namebind_t **) ipbind->ib_namebinds->elts; |
392 | 0 | for (j = 0; j < ipbind->ib_namebinds->nelts; j++) { |
393 | 0 | pr_namebind_t *nb; |
394 | |
|
395 | 0 | pr_signals_handle(); |
396 | |
|
397 | 0 | nb = namebinds[j]; |
398 | 0 | if (pr_namebind_close(nb->nb_name, nb->nb_server->addr) < 0) { |
399 | 0 | pr_trace_msg(trace_channel, 7, |
400 | 0 | "notice: error closing namebind '%s' for address %s: %s", |
401 | 0 | nb->nb_name, pr_netaddr_get_ipstr(nb->nb_server->addr), |
402 | 0 | strerror(errno)); |
403 | 0 | } |
404 | 0 | } |
405 | 0 | } |
406 | |
|
407 | 0 | } else { |
408 | | /* A NULL addr has a special meaning: close _all_ ipbinds in the list. */ |
409 | 0 | for (i = 0; i < PR_BINDINGS_TABLE_SIZE; i++) { |
410 | 0 | pr_ipbind_t *ipbind = NULL; |
411 | |
|
412 | 0 | pr_signals_handle(); |
413 | |
|
414 | 0 | for (ipbind = ipbind_table[i]; ipbind; ipbind = ipbind->ib_next) { |
415 | 0 | if (SocketBindTight && |
416 | 0 | ipbind->ib_listener != NULL) { |
417 | 0 | pr_inet_close(main_server->pool, ipbind->ib_listener); |
418 | 0 | ipbind->ib_listener = ipbind->ib_server->listen = NULL; |
419 | 0 | } |
420 | | |
421 | | /* Note: do not need to check if this ipbind was previously closed, |
422 | | * for the NULL addr is a request to shut down all ipbinds, |
423 | | * regardless of their current state. |
424 | | */ |
425 | 0 | ipbind->ib_isactive = FALSE; |
426 | |
|
427 | 0 | if (close_namebinds && |
428 | 0 | ipbind->ib_namebinds != NULL) { |
429 | 0 | register unsigned int j = 0; |
430 | 0 | pr_namebind_t **namebinds = NULL; |
431 | |
|
432 | 0 | namebinds = (pr_namebind_t **) ipbind->ib_namebinds->elts; |
433 | 0 | for (j = 0; j < ipbind->ib_namebinds->nelts; j++) { |
434 | 0 | pr_namebind_t *nb; |
435 | |
|
436 | 0 | pr_signals_handle(); |
437 | |
|
438 | 0 | nb = namebinds[j]; |
439 | 0 | if (pr_namebind_close(nb->nb_name, nb->nb_server->addr) < 0) { |
440 | 0 | pr_trace_msg(trace_channel, 7, |
441 | 0 | "notice: error closing namebind '%s' for address %s: %s", |
442 | 0 | nb->nb_name, pr_netaddr_get_ipstr(nb->nb_server->addr), |
443 | 0 | strerror(errno)); |
444 | 0 | } |
445 | 0 | } |
446 | 0 | } |
447 | 0 | } |
448 | 0 | } |
449 | 0 | } |
450 | | |
451 | 0 | return 0; |
452 | 0 | } |
453 | | |
454 | | /* Need a way to close all listening fds in a child process. */ |
455 | 0 | int pr_ipbind_close_listeners(void) { |
456 | 0 | conn_t **listeners; |
457 | 0 | register unsigned int i = 0; |
458 | |
|
459 | 0 | if (listener_list == NULL || |
460 | 0 | listener_list->nelts == 0) { |
461 | 0 | return 0; |
462 | 0 | } |
463 | | |
464 | 0 | listeners = listener_list->elts; |
465 | 0 | for (i = 0; i < listener_list->nelts; i++) { |
466 | 0 | conn_t *listener; |
467 | |
|
468 | 0 | pr_signals_handle(); |
469 | |
|
470 | 0 | listener = listeners[i]; |
471 | 0 | if (listener->listen_fd != -1) { |
472 | 0 | (void) close(listener->listen_fd); |
473 | 0 | listener->listen_fd = -1; |
474 | 0 | } |
475 | 0 | } |
476 | |
|
477 | 0 | return 0; |
478 | 0 | } |
479 | | |
480 | | int pr_ipbind_create(server_rec *server, const pr_netaddr_t *addr, |
481 | 0 | unsigned int port) { |
482 | 0 | pr_ipbind_t *existing = NULL, *ipbind = NULL; |
483 | 0 | register unsigned int i = 0; |
484 | |
|
485 | 0 | if (server == NULL|| |
486 | 0 | addr == NULL) { |
487 | 0 | errno = EINVAL; |
488 | 0 | return -1; |
489 | 0 | } |
490 | | |
491 | | /* Ensure the ipbind table has been initialized. */ |
492 | 0 | init_ipbind_table(); |
493 | |
|
494 | 0 | i = ipbind_hash_addr(addr, port); |
495 | 0 | pr_trace_msg(trace_channel, 29, "hashed address '%s' to index %u", |
496 | 0 | pr_netaddr_get_ipstr(addr), i); |
497 | | |
498 | | /* Make sure the address is not already in use */ |
499 | 0 | for (ipbind = ipbind_table[i]; ipbind; ipbind = ipbind->ib_next) { |
500 | 0 | pr_signals_handle(); |
501 | |
|
502 | 0 | if (pr_netaddr_cmp(ipbind->ib_addr, addr) == 0 && |
503 | 0 | ipbind->ib_port == port) { |
504 | 0 | existing = ipbind; |
505 | 0 | break; |
506 | 0 | } |
507 | 0 | } |
508 | |
|
509 | 0 | if (existing != NULL) { |
510 | 0 | config_rec *c; |
511 | | |
512 | | /* If the given server config does not have any ServerAlias directives, |
513 | | * then this is an IP/port collision, and we need to return an error. |
514 | | * |
515 | | * However, if there are ServerAliases, this is a name-based config and |
516 | | * should be processed properly. |
517 | | */ |
518 | |
|
519 | 0 | c = find_config(server->conf, CONF_PARAM, "ServerAlias", FALSE); |
520 | 0 | if (c == NULL) { |
521 | 0 | pr_log_pri(PR_LOG_WARNING, "notice: '%s' (%s:%u) already bound to '%s'", |
522 | 0 | server->ServerName, pr_netaddr_get_ipstr(addr), port, |
523 | 0 | existing->ib_server->ServerName); |
524 | 0 | errno = EADDRINUSE; |
525 | 0 | return -1; |
526 | 0 | } |
527 | | |
528 | 0 | pr_log_debug(DEBUG9, "notice: '%s' (%s:%u) already bound to '%s'", |
529 | 0 | server->ServerName, pr_netaddr_get_ipstr(addr), port, |
530 | 0 | existing->ib_server->ServerName); |
531 | 0 | } |
532 | | |
533 | 0 | if (binding_pool == NULL) { |
534 | 0 | binding_pool = make_sub_pool(permanent_pool); |
535 | 0 | pr_pool_tag(binding_pool, "Bindings Pool"); |
536 | 0 | } |
537 | |
|
538 | 0 | ipbind = pcalloc(server->pool, sizeof(pr_ipbind_t)); |
539 | 0 | ipbind->ib_server = server; |
540 | 0 | ipbind->ib_addr = addr; |
541 | 0 | ipbind->ib_port = port; |
542 | 0 | ipbind->ib_namebinds = NULL; |
543 | 0 | ipbind->ib_isdefault = FALSE; |
544 | 0 | ipbind->ib_islocalhost = FALSE; |
545 | 0 | ipbind->ib_isactive = FALSE; |
546 | |
|
547 | 0 | pr_trace_msg(trace_channel, 8, "created ipbind %p for %s#%u, server %p (%s)", |
548 | 0 | ipbind, pr_netaddr_get_ipstr(ipbind->ib_addr), ipbind->ib_port, |
549 | 0 | ipbind->ib_server, ipbind->ib_server->ServerName); |
550 | | |
551 | | /* Add the ipbind to the table, maintaining insertion order. */ |
552 | 0 | if (existing != NULL) { |
553 | 0 | pr_trace_msg(trace_channel, 19, |
554 | 0 | "found existing ipbind %p (server %p) at index %u in iptable table, " |
555 | 0 | "adding to %p", existing, existing->ib_server, i, existing); |
556 | 0 | if (existing->ib_next != NULL) { |
557 | 0 | ipbind->ib_next = existing->ib_next; |
558 | 0 | } |
559 | 0 | existing->ib_next = ipbind; |
560 | |
|
561 | 0 | } else { |
562 | 0 | if (ipbind_table[i] != NULL) { |
563 | 0 | ipbind->ib_next = ipbind_table[i]; |
564 | 0 | } |
565 | 0 | ipbind_table[i] = ipbind; |
566 | 0 | } |
567 | |
|
568 | 0 | return 0; |
569 | 0 | } |
570 | | |
571 | | /* Returns the LAST matching ipbind for the given port, if any. If provided, |
572 | | * the match_count pointer will contain the number of ipbinds found that |
573 | | * matched that port. |
574 | | */ |
575 | | static pr_ipbind_t *ipbind_find_port(unsigned int port, |
576 | 0 | unsigned char skip_inactive, unsigned int *match_count) { |
577 | 0 | register unsigned int i; |
578 | 0 | pr_ipbind_t *matched_ipbind = NULL; |
579 | |
|
580 | 0 | for (i = 0; i < PR_BINDINGS_TABLE_SIZE; i++) { |
581 | 0 | pr_ipbind_t *ipbind; |
582 | |
|
583 | 0 | for (ipbind = ipbind_table[i]; ipbind; ipbind = ipbind->ib_next) { |
584 | 0 | pr_signals_handle(); |
585 | |
|
586 | 0 | if (skip_inactive && |
587 | 0 | !ipbind->ib_isactive) { |
588 | 0 | continue; |
589 | 0 | } |
590 | | |
591 | 0 | if (ipbind->ib_port == port) { |
592 | 0 | if (match_count != NULL) { |
593 | 0 | (*match_count)++; |
594 | 0 | } |
595 | |
|
596 | 0 | matched_ipbind = ipbind; |
597 | 0 | } |
598 | 0 | } |
599 | 0 | } |
600 | |
|
601 | 0 | if (matched_ipbind == NULL) { |
602 | 0 | errno = ENOENT; |
603 | 0 | return NULL; |
604 | 0 | } |
605 | | |
606 | 0 | return matched_ipbind; |
607 | 0 | } |
608 | | |
609 | | pr_ipbind_t *pr_ipbind_find(const pr_netaddr_t *addr, unsigned int port, |
610 | 0 | unsigned char skip_inactive) { |
611 | 0 | register unsigned int i; |
612 | 0 | pr_ipbind_t *ipbind = NULL; |
613 | |
|
614 | 0 | if (addr == NULL) { |
615 | 0 | errno = EINVAL; |
616 | 0 | return NULL; |
617 | 0 | } |
618 | | |
619 | | /* Ensure the ipbind table has been initialized. */ |
620 | 0 | init_ipbind_table(); |
621 | |
|
622 | 0 | i = ipbind_hash_addr(addr, port); |
623 | |
|
624 | 0 | for (ipbind = ipbind_table[i]; ipbind; ipbind = ipbind->ib_next) { |
625 | 0 | pr_signals_handle(); |
626 | |
|
627 | 0 | if (ipbind->ib_isactive == FALSE && |
628 | 0 | skip_inactive == TRUE) { |
629 | 0 | continue; |
630 | 0 | } |
631 | | |
632 | 0 | if (pr_netaddr_cmp(ipbind->ib_addr, addr) == 0) { |
633 | 0 | if (ipbind->ib_port == 0 || |
634 | 0 | port == 0 || |
635 | 0 | ipbind->ib_port == port) { |
636 | 0 | return ipbind; |
637 | 0 | } |
638 | 0 | } |
639 | 0 | } |
640 | | |
641 | 0 | errno = ENOENT; |
642 | 0 | return NULL; |
643 | 0 | } |
644 | | |
645 | 0 | pr_ipbind_t *pr_ipbind_get(pr_ipbind_t *prev) { |
646 | 0 | static unsigned int i = 0; |
647 | |
|
648 | 0 | if (prev != NULL) { |
649 | | /* If there's another ipbind in this chain, simply return that. */ |
650 | 0 | if (prev->ib_next != NULL) { |
651 | 0 | return prev->ib_next; |
652 | 0 | } |
653 | | |
654 | | /* If the increment is at the maximum size, return NULL (no more chains |
655 | | * to be examined). |
656 | | */ |
657 | 0 | if (i == PR_BINDINGS_TABLE_SIZE) { |
658 | 0 | errno = ENOENT; |
659 | 0 | return NULL; |
660 | 0 | } |
661 | | |
662 | | /* Increment the index. At this point, we know that the given pointer is |
663 | | * the last in the chain, and that there are more chains in the table |
664 | | * to be examined. |
665 | | */ |
666 | 0 | i++; |
667 | |
|
668 | 0 | } else { |
669 | | /* Reset the index if prev is NULL. */ |
670 | 0 | i = 0; |
671 | 0 | } |
672 | | |
673 | | /* Search for the next non-empty chain in the table. */ |
674 | 0 | for (; i < PR_BINDINGS_TABLE_SIZE; i++) { |
675 | 0 | pr_signals_handle(); |
676 | |
|
677 | 0 | if (ipbind_table[i] != NULL) { |
678 | 0 | return ipbind_table[i]; |
679 | 0 | } |
680 | 0 | } |
681 | | |
682 | 0 | errno = ENOENT; |
683 | 0 | return NULL; |
684 | 0 | } |
685 | | |
686 | 0 | server_rec *pr_ipbind_get_server(const pr_netaddr_t *addr, unsigned int port) { |
687 | 0 | pr_ipbind_t *ipbind = NULL; |
688 | 0 | pr_netaddr_t wildcard_addr; |
689 | 0 | int addr_family; |
690 | 0 | unsigned int match_count = 0; |
691 | | |
692 | | /* If we've got a binding configured for this exact address, return it |
693 | | * straight away. |
694 | | */ |
695 | 0 | ipbind = pr_ipbind_find(addr, port, TRUE); |
696 | 0 | if (ipbind != NULL) { |
697 | 0 | pr_log_debug(DEBUG7, "matching vhost found for %s#%u, using '%s'", |
698 | 0 | pr_netaddr_get_ipstr(addr), port, ipbind->ib_server->ServerName); |
699 | 0 | return ipbind->ib_server; |
700 | 0 | } |
701 | | |
702 | | /* Look for a vhost bound to the wildcard address (i.e. INADDR_ANY). |
703 | | * |
704 | | * This allows for "<VirtualHost 0.0.0.0>" configurations, where the |
705 | | * IP address to which the client might connect is not known at |
706 | | * configuration time. (Usually happens when the same config file |
707 | | * is deployed to multiple machines.) |
708 | | */ |
709 | | |
710 | 0 | addr_family = pr_netaddr_get_family(addr); |
711 | |
|
712 | 0 | pr_netaddr_clear(&wildcard_addr); |
713 | 0 | pr_netaddr_set_family(&wildcard_addr, addr_family); |
714 | 0 | pr_netaddr_set_sockaddr_any(&wildcard_addr); |
715 | |
|
716 | 0 | ipbind = pr_ipbind_find(&wildcard_addr, port, TRUE); |
717 | 0 | if (ipbind != NULL) { |
718 | 0 | pr_log_debug(DEBUG7, "no matching vhost found for %s#%u, using " |
719 | 0 | "'%s' listening on wildcard address", pr_netaddr_get_ipstr(addr), port, |
720 | 0 | ipbind->ib_server->ServerName); |
721 | 0 | return ipbind->ib_server; |
722 | 0 | } |
723 | | |
724 | 0 | #ifdef PR_USE_IPV6 |
725 | 0 | if (addr_family == AF_INET6 && |
726 | 0 | pr_netaddr_use_ipv6()) { |
727 | | |
728 | | /* The pr_ipbind_find() probably returned NULL because there aren't any |
729 | | * <VirtualHost> sections configured explicitly for the wildcard IPv6 |
730 | | * address of "::", just the IPv4 wildcard "0.0.0.0" address. |
731 | | * |
732 | | * So try the pr_ipbind_find() again, this time using the IPv4 |
733 | | * wildcard. |
734 | | */ |
735 | 0 | pr_netaddr_clear(&wildcard_addr); |
736 | 0 | pr_netaddr_set_family(&wildcard_addr, AF_INET); |
737 | 0 | pr_netaddr_set_sockaddr_any(&wildcard_addr); |
738 | |
|
739 | 0 | ipbind = pr_ipbind_find(&wildcard_addr, port, TRUE); |
740 | 0 | if (ipbind != NULL) { |
741 | 0 | pr_log_debug(DEBUG7, "no matching vhost found for %s#%u, using " |
742 | 0 | "'%s' listening on wildcard address", pr_netaddr_get_ipstr(addr), |
743 | 0 | port, ipbind->ib_server->ServerName); |
744 | 0 | return ipbind->ib_server; |
745 | 0 | } |
746 | 0 | } |
747 | 0 | #endif /* PR_USE_IPV6 */ |
748 | | |
749 | | /* Check for any bindings that match the port. IF there is only one ONE |
750 | | * vhost which matches the requested port, use that (Bug#4251). |
751 | | */ |
752 | 0 | ipbind = ipbind_find_port(port, TRUE, &match_count); |
753 | 0 | if (ipbind != NULL) { |
754 | 0 | pr_trace_msg(trace_channel, 18, "found %u possible %s for port %u", |
755 | 0 | match_count, match_count != 1 ? "ipbinds" : "ipbind", port); |
756 | 0 | if (match_count == 1) { |
757 | 0 | return ipbind->ib_server; |
758 | 0 | } |
759 | 0 | } |
760 | | |
761 | | /* Use the default server, if set. */ |
762 | 0 | if (ipbind_default_server && |
763 | 0 | ipbind_default_server->ib_isactive) { |
764 | 0 | pr_log_debug(DEBUG7, "no matching vhost found for %s#%u, using " |
765 | 0 | "DefaultServer '%s'", pr_netaddr_get_ipstr(addr), port, |
766 | 0 | ipbind_default_server->ib_server->ServerName); |
767 | 0 | return ipbind_default_server->ib_server; |
768 | 0 | } |
769 | | |
770 | | /* Not found in binding list, and no DefaultServer, so see if it's the |
771 | | * loopback address |
772 | | */ |
773 | 0 | if (ipbind_localhost_server && |
774 | 0 | pr_netaddr_is_loopback(addr)) { |
775 | 0 | return ipbind_localhost_server->ib_server; |
776 | 0 | } |
777 | | |
778 | 0 | return NULL; |
779 | 0 | } |
780 | | |
781 | 0 | int pr_ipbind_listen(fd_set *readfds) { |
782 | 0 | int listen_flags = PR_INET_LISTEN_FL_FATAL_ON_ERROR, maxfd = 0; |
783 | 0 | register unsigned int i = 0; |
784 | | |
785 | | /* sanity check */ |
786 | 0 | if (readfds == NULL) { |
787 | 0 | errno = EINVAL; |
788 | 0 | return -1; |
789 | 0 | } |
790 | | |
791 | 0 | FD_ZERO(readfds); |
792 | |
|
793 | 0 | if (binding_pool == NULL) { |
794 | 0 | binding_pool = make_sub_pool(permanent_pool); |
795 | 0 | pr_pool_tag(binding_pool, "Bindings Pool"); |
796 | 0 | } |
797 | | |
798 | | /* Reset the listener list. */ |
799 | 0 | if (listener_list == NULL) { |
800 | 0 | listener_list = make_array(binding_pool, 1, sizeof(conn_t *)); |
801 | |
|
802 | 0 | } else { |
803 | | /* Nasty hack to "clear" the list by making it think it has no |
804 | | * elements. |
805 | | */ |
806 | 0 | listener_list->nelts = 0; |
807 | 0 | } |
808 | | |
809 | | /* Slower than the hash lookup, but...we have to check each and every |
810 | | * ipbind in the table. |
811 | | */ |
812 | 0 | for (i = 0; i < PR_BINDINGS_TABLE_SIZE; i++) { |
813 | 0 | pr_ipbind_t *ipbind = NULL; |
814 | |
|
815 | 0 | for (ipbind = ipbind_table[i]; ipbind; ipbind = ipbind->ib_next) { |
816 | 0 | pr_signals_handle(); |
817 | | |
818 | | /* Skip inactive bindings, but only if SocketBindTight is in effect. */ |
819 | 0 | if (SocketBindTight && |
820 | 0 | ipbind->ib_isactive == FALSE) { |
821 | 0 | continue; |
822 | 0 | } |
823 | | |
824 | 0 | if (ipbind->ib_listener != NULL) { |
825 | 0 | if (ipbind->ib_listener->mode == CM_NONE) { |
826 | 0 | pr_inet_listen(ipbind->ib_listener->pool, ipbind->ib_listener, |
827 | 0 | tcpBackLog, listen_flags); |
828 | 0 | } |
829 | |
|
830 | 0 | if (ipbind->ib_listener->mode == CM_ACCEPT) { |
831 | 0 | if (pr_inet_resetlisten(ipbind->ib_listener->pool, |
832 | 0 | ipbind->ib_listener) < 0) { |
833 | 0 | pr_trace_msg(trace_channel, 3, |
834 | 0 | "error resetting %s#%u for listening: %s", |
835 | 0 | pr_netaddr_get_ipstr(ipbind->ib_addr), ipbind->ib_port, |
836 | 0 | strerror(errno)); |
837 | 0 | } |
838 | 0 | } |
839 | |
|
840 | 0 | if (ipbind->ib_listener->mode == CM_LISTEN) { |
841 | 0 | FD_SET(ipbind->ib_listener->listen_fd, readfds); |
842 | 0 | if (ipbind->ib_listener->listen_fd > maxfd) { |
843 | 0 | maxfd = ipbind->ib_listener->listen_fd; |
844 | 0 | } |
845 | | |
846 | | /* Add this to the listener list as well. */ |
847 | 0 | *((conn_t **) push_array(listener_list)) = ipbind->ib_listener; |
848 | 0 | } |
849 | 0 | } |
850 | 0 | } |
851 | 0 | } |
852 | |
|
853 | 0 | return maxfd; |
854 | 0 | } |
855 | | |
856 | | int pr_ipbind_open(const pr_netaddr_t *addr, unsigned int port, |
857 | | conn_t *listen_conn, unsigned char isdefault, unsigned char islocalhost, |
858 | 0 | unsigned char open_namebinds) { |
859 | 0 | pr_ipbind_t *ipbind = NULL; |
860 | |
|
861 | 0 | if (addr == NULL) { |
862 | 0 | errno = EINVAL; |
863 | 0 | return -1; |
864 | 0 | } |
865 | | |
866 | | /* Find the binding for this server/address */ |
867 | 0 | ipbind = pr_ipbind_find(addr, port, FALSE); |
868 | 0 | if (ipbind == NULL) { |
869 | 0 | errno = ENOENT; |
870 | 0 | return -1; |
871 | 0 | } |
872 | | |
873 | 0 | if (listen_conn != NULL) { |
874 | 0 | listen_conn->next = NULL; |
875 | 0 | } |
876 | |
|
877 | 0 | ipbind->ib_listener = ipbind->ib_server->listen = listen_conn; |
878 | 0 | ipbind->ib_listener = listen_conn; |
879 | 0 | ipbind->ib_isdefault = isdefault; |
880 | 0 | ipbind->ib_islocalhost = islocalhost; |
881 | | |
882 | | /* Stash a pointer to this ipbind, since it is designated as the |
883 | | * default server (via the DefaultServer directive), for use in the |
884 | | * lookup functions. |
885 | | * |
886 | | * Stash pointers to this ipbind for use in the lookup functions if: |
887 | | * |
888 | | * - It's the default server (specified via the DefaultServer directive) |
889 | | * - It handles connections to the loopback interface |
890 | | */ |
891 | 0 | if (isdefault) { |
892 | 0 | ipbind_default_server = ipbind; |
893 | 0 | } |
894 | |
|
895 | 0 | if (islocalhost) { |
896 | 0 | ipbind_localhost_server = ipbind; |
897 | 0 | } |
898 | | |
899 | | /* If requested, look for any namebinds for this ipbind, and open them. */ |
900 | 0 | if (open_namebinds && |
901 | 0 | ipbind->ib_namebinds) { |
902 | 0 | register unsigned int i = 0; |
903 | 0 | pr_namebind_t **namebinds = NULL; |
904 | | |
905 | | /* NOTE: in the future, these namebinds may need to be stored/ |
906 | | * manipulated in hash tables themselves, but, for now, linked lists |
907 | | * should suffice. |
908 | | */ |
909 | 0 | namebinds = (pr_namebind_t **) ipbind->ib_namebinds->elts; |
910 | 0 | for (i = 0; i < ipbind->ib_namebinds->nelts; i++) { |
911 | 0 | int res; |
912 | 0 | pr_namebind_t *nb; |
913 | |
|
914 | 0 | pr_signals_handle(); |
915 | |
|
916 | 0 | nb = namebinds[i]; |
917 | 0 | res = pr_namebind_open(nb->nb_name, nb->nb_server->addr, |
918 | 0 | nb->nb_server_port); |
919 | 0 | if (res < 0) { |
920 | 0 | pr_trace_msg(trace_channel, 2, |
921 | 0 | "notice: unable to open namebind '%s': %s", nb->nb_name, |
922 | 0 | strerror(errno)); |
923 | 0 | } |
924 | 0 | } |
925 | 0 | } |
926 | | |
927 | | /* Mark this binding as now being active. */ |
928 | 0 | ipbind->ib_isactive = TRUE; |
929 | |
|
930 | 0 | return 0; |
931 | 0 | } |
932 | | |
933 | 0 | int pr_namebind_close(const char *name, const pr_netaddr_t *addr) { |
934 | 0 | pr_namebind_t *namebind = NULL; |
935 | 0 | unsigned int port; |
936 | |
|
937 | 0 | if (name == NULL|| |
938 | 0 | addr == NULL) { |
939 | 0 | errno = EINVAL; |
940 | 0 | return -1; |
941 | 0 | } |
942 | | |
943 | 0 | port = ntohs(pr_netaddr_get_port(addr)); |
944 | 0 | namebind = pr_namebind_find(name, addr, port, FALSE); |
945 | 0 | if (namebind == NULL) { |
946 | 0 | errno = ENOENT; |
947 | 0 | return -1; |
948 | 0 | } |
949 | | |
950 | 0 | namebind->nb_isactive = FALSE; |
951 | 0 | return 0; |
952 | 0 | } |
953 | | |
954 | | int pr_namebind_create(server_rec *server, const char *name, |
955 | 0 | pr_ipbind_t *ipbind, const pr_netaddr_t *addr, unsigned int server_port) { |
956 | 0 | pr_namebind_t *namebind = NULL, **namebinds = NULL; |
957 | 0 | unsigned int port; |
958 | |
|
959 | 0 | if (server == NULL || |
960 | 0 | name == NULL) { |
961 | 0 | errno = EINVAL; |
962 | 0 | return -1; |
963 | 0 | } |
964 | | |
965 | | /* First, find the ipbind to hold this namebind. */ |
966 | 0 | port = ntohs(pr_netaddr_get_port(addr)); |
967 | 0 | if (port == 0) { |
968 | 0 | port = server_port; |
969 | 0 | } |
970 | |
|
971 | 0 | if (ipbind == NULL) { |
972 | 0 | pr_netaddr_t wildcard_addr; |
973 | 0 | int addr_family; |
974 | | |
975 | | /* If not found, look for the wildcard address. */ |
976 | |
|
977 | 0 | addr_family = pr_netaddr_get_family(addr); |
978 | 0 | pr_netaddr_clear(&wildcard_addr); |
979 | 0 | pr_netaddr_set_family(&wildcard_addr, addr_family); |
980 | 0 | pr_netaddr_set_sockaddr_any(&wildcard_addr); |
981 | |
|
982 | 0 | ipbind = pr_ipbind_find(&wildcard_addr, port, FALSE); |
983 | 0 | #ifdef PR_USE_IPV6 |
984 | 0 | if (ipbind == FALSE && |
985 | 0 | addr_family == AF_INET6 && |
986 | 0 | pr_netaddr_use_ipv6()) { |
987 | | |
988 | | /* No IPv6 wildcard address found; try the IPv4 wildcard address. */ |
989 | 0 | pr_netaddr_clear(&wildcard_addr); |
990 | 0 | pr_netaddr_set_family(&wildcard_addr, AF_INET); |
991 | 0 | pr_netaddr_set_sockaddr_any(&wildcard_addr); |
992 | |
|
993 | 0 | ipbind = pr_ipbind_find(&wildcard_addr, port, FALSE); |
994 | 0 | } |
995 | 0 | #endif /* PR_USE_IPV6 */ |
996 | |
|
997 | 0 | pr_trace_msg(trace_channel, 19, |
998 | 0 | "found wildcard ipbind %p for namebind (name '%s', addr %s, port %u)", |
999 | 0 | ipbind, name, pr_netaddr_get_ipstr(addr), port); |
1000 | 0 | } |
1001 | |
|
1002 | 0 | if (ipbind == NULL) { |
1003 | 0 | errno = ENOENT; |
1004 | 0 | return -1; |
1005 | 0 | } |
1006 | | |
1007 | | /* Make sure we can add this namebind. */ |
1008 | 0 | if (ipbind->ib_namebinds == NULL) { |
1009 | 0 | ipbind->ib_namebinds = make_array(binding_pool, 0, sizeof(pr_namebind_t *)); |
1010 | |
|
1011 | 0 | } else { |
1012 | 0 | register unsigned int i = 0; |
1013 | 0 | namebinds = (pr_namebind_t **) ipbind->ib_namebinds->elts; |
1014 | | |
1015 | | /* See if there is already a namebind for the given name. */ |
1016 | 0 | for (i = 0; i < ipbind->ib_namebinds->nelts; i++) { |
1017 | 0 | pr_signals_handle(); |
1018 | |
|
1019 | 0 | namebind = namebinds[i]; |
1020 | 0 | if (namebind != NULL && |
1021 | 0 | namebind->nb_name != NULL) { |
1022 | | |
1023 | | /* DNS names are case-insensitive, hence the case-insensitive check |
1024 | | * here. |
1025 | | * |
1026 | | * XXX Ideally, we should check whether any existing namebinds which |
1027 | | * are globs will match the newly added namebind as well. |
1028 | | */ |
1029 | |
|
1030 | 0 | if (strcasecmp(namebind->nb_name, name) == 0) { |
1031 | 0 | errno = EEXIST; |
1032 | 0 | return -1; |
1033 | 0 | } |
1034 | 0 | } |
1035 | 0 | } |
1036 | 0 | } |
1037 | | |
1038 | 0 | namebind = (pr_namebind_t *) pcalloc(server->pool, sizeof(pr_namebind_t)); |
1039 | 0 | namebind->nb_name = name; |
1040 | 0 | namebind->nb_server = server; |
1041 | 0 | namebind->nb_server_port = server_port; |
1042 | 0 | namebind->nb_isactive = FALSE; |
1043 | |
|
1044 | 0 | if (pr_str_is_fnmatch(name) == TRUE) { |
1045 | 0 | namebind->nb_iswildcard = TRUE; |
1046 | 0 | } |
1047 | |
|
1048 | 0 | pr_trace_msg(trace_channel, 8, |
1049 | 0 | "created namebind '%s' for %s#%u, server '%s' [%p]", name, |
1050 | 0 | pr_netaddr_get_ipstr(server->addr), server->ServerPort, server->ServerName, |
1051 | 0 | server); |
1052 | | |
1053 | | /* The given server should already have the following populated: |
1054 | | * |
1055 | | * server->ServerName |
1056 | | * server->ServerAddress |
1057 | | * server->ServerFQDN |
1058 | | */ |
1059 | |
|
1060 | 0 | *((pr_namebind_t **) push_array(ipbind->ib_namebinds)) = namebind; |
1061 | 0 | return 0; |
1062 | 0 | } |
1063 | | |
1064 | | pr_namebind_t *pr_namebind_find(const char *name, const pr_netaddr_t *addr, |
1065 | 0 | unsigned int port, unsigned char skip_inactive) { |
1066 | 0 | pr_ipbind_t *ipbind = NULL, *iter; |
1067 | |
|
1068 | 0 | if (name == NULL || |
1069 | 0 | addr == NULL) { |
1070 | 0 | errno = EINVAL; |
1071 | 0 | return NULL; |
1072 | 0 | } |
1073 | | |
1074 | | /* First, find an active ipbind for the given address. */ |
1075 | 0 | ipbind = pr_ipbind_find(addr, port, skip_inactive); |
1076 | 0 | if (ipbind == NULL) { |
1077 | 0 | pr_netaddr_t wildcard_addr; |
1078 | 0 | int addr_family; |
1079 | | |
1080 | | /* If not found, look for the wildcard address. */ |
1081 | |
|
1082 | 0 | addr_family = pr_netaddr_get_family(addr); |
1083 | 0 | pr_netaddr_clear(&wildcard_addr); |
1084 | 0 | pr_netaddr_set_family(&wildcard_addr, addr_family); |
1085 | 0 | pr_netaddr_set_sockaddr_any(&wildcard_addr); |
1086 | |
|
1087 | 0 | ipbind = pr_ipbind_find(&wildcard_addr, port, FALSE); |
1088 | 0 | #ifdef PR_USE_IPV6 |
1089 | 0 | if (ipbind == FALSE && |
1090 | 0 | addr_family == AF_INET6 && |
1091 | 0 | pr_netaddr_use_ipv6()) { |
1092 | | |
1093 | | /* No IPv6 wildcard address found; try the IPv4 wildcard address. */ |
1094 | 0 | pr_netaddr_clear(&wildcard_addr); |
1095 | 0 | pr_netaddr_set_family(&wildcard_addr, AF_INET); |
1096 | 0 | pr_netaddr_set_sockaddr_any(&wildcard_addr); |
1097 | |
|
1098 | 0 | ipbind = pr_ipbind_find(&wildcard_addr, port, FALSE); |
1099 | 0 | } |
1100 | 0 | #endif /* PR_USE_IPV6 */ |
1101 | 0 | } else { |
1102 | 0 | pr_trace_msg(trace_channel, 17, |
1103 | 0 | "found ipbind %p (server '%s' [%p]) for %s#%u", ipbind, |
1104 | 0 | ipbind->ib_server->ServerName, ipbind->ib_server, |
1105 | 0 | pr_netaddr_get_ipstr(addr), port); |
1106 | 0 | } |
1107 | |
|
1108 | 0 | if (ipbind == NULL) { |
1109 | 0 | errno = ENOENT; |
1110 | 0 | return NULL; |
1111 | 0 | } |
1112 | | |
1113 | | /* Now we need to search this ipbind list, to see if any of them have a |
1114 | | * matching namebind. |
1115 | | */ |
1116 | | |
1117 | 0 | for (iter = ipbind; iter; iter = iter->ib_next) { |
1118 | 0 | register unsigned int i = 0; |
1119 | 0 | pr_namebind_t *namebind = NULL, **namebinds = NULL; |
1120 | |
|
1121 | 0 | pr_signals_handle(); |
1122 | |
|
1123 | 0 | if (iter->ib_namebinds == NULL) { |
1124 | 0 | pr_trace_msg(trace_channel, 17, |
1125 | 0 | "ipbind %p (server %p) for %s#%u has no namebinds", iter, |
1126 | 0 | iter->ib_server, pr_netaddr_get_ipstr(addr), port); |
1127 | 0 | continue; |
1128 | 0 | } |
1129 | | |
1130 | 0 | namebinds = (pr_namebind_t **) iter->ib_namebinds->elts; |
1131 | 0 | pr_trace_msg(trace_channel, 17, |
1132 | 0 | "ipbind %p (server %p) for %s#%u has namebinds (%d)", iter, |
1133 | 0 | iter->ib_server, pr_netaddr_get_ipstr(addr), port, |
1134 | 0 | iter->ib_namebinds->nelts); |
1135 | |
|
1136 | 0 | for (i = 0; i < iter->ib_namebinds->nelts; i++) { |
1137 | 0 | pr_signals_handle(); |
1138 | |
|
1139 | 0 | namebind = namebinds[i]; |
1140 | 0 | if (namebind == NULL) { |
1141 | 0 | continue; |
1142 | 0 | } |
1143 | | |
1144 | | /* Skip inactive namebinds */ |
1145 | 0 | if (skip_inactive == TRUE && |
1146 | 0 | namebind->nb_isactive == FALSE) { |
1147 | 0 | pr_trace_msg(trace_channel, 17, |
1148 | 0 | "namebind #%u: %s is inactive, skipping", i, namebind->nb_name); |
1149 | 0 | continue; |
1150 | 0 | } |
1151 | | |
1152 | | /* At present, this looks for an exactly matching name. In the future, |
1153 | | * we may want to have something like Apache's matching scheme, which |
1154 | | * looks for the most specific domain to the most general. Note that |
1155 | | * that scheme, however, is specific to DNS; should any other naming |
1156 | | * scheme be desired, that sort of matching will be unnecessary. |
1157 | | */ |
1158 | 0 | if (namebind->nb_name != NULL) { |
1159 | 0 | pr_trace_msg(trace_channel, 17, |
1160 | 0 | "namebind #%u: %s (%s)", i, namebind->nb_name, |
1161 | 0 | namebind->nb_isactive ? "active" : "inactive"); |
1162 | |
|
1163 | 0 | if (namebind->nb_iswildcard == FALSE) { |
1164 | 0 | if (strcasecmp(namebind->nb_name, name) == 0) { |
1165 | 0 | return namebind; |
1166 | 0 | } |
1167 | |
|
1168 | 0 | } else { |
1169 | 0 | int match_flags = PR_FNM_NOESCAPE|PR_FNM_CASEFOLD; |
1170 | |
|
1171 | 0 | if (pr_fnmatch(namebind->nb_name, name, match_flags) == 0) { |
1172 | 0 | pr_trace_msg(trace_channel, 9, |
1173 | 0 | "matched name '%s' against pattern '%s'", name, |
1174 | 0 | namebind->nb_name); |
1175 | 0 | return namebind; |
1176 | 0 | } |
1177 | | |
1178 | 0 | pr_trace_msg(trace_channel, 9, |
1179 | 0 | "failed to match name '%s' against pattern '%s'", name, |
1180 | 0 | namebind->nb_name); |
1181 | 0 | } |
1182 | 0 | } |
1183 | 0 | } |
1184 | 0 | } |
1185 | | |
1186 | 0 | return NULL; |
1187 | 0 | } |
1188 | | |
1189 | | server_rec *pr_namebind_get_server(const char *name, const pr_netaddr_t *addr, |
1190 | 0 | unsigned int port) { |
1191 | 0 | pr_namebind_t *namebind = NULL; |
1192 | | |
1193 | | /* Basically, just a wrapper around pr_namebind_find() */ |
1194 | |
|
1195 | 0 | namebind = pr_namebind_find(name, addr, port, TRUE); |
1196 | 0 | if (namebind == NULL) { |
1197 | 0 | return NULL; |
1198 | 0 | } |
1199 | | |
1200 | 0 | return namebind->nb_server; |
1201 | 0 | } |
1202 | | |
1203 | 0 | unsigned int pr_namebind_count(server_rec *srv) { |
1204 | 0 | unsigned int count = 0; |
1205 | 0 | pr_ipbind_t *ipbind = NULL; |
1206 | |
|
1207 | 0 | if (srv == NULL) { |
1208 | 0 | return 0; |
1209 | 0 | } |
1210 | | |
1211 | 0 | ipbind = pr_ipbind_find(srv->addr, srv->ServerPort, FALSE); |
1212 | 0 | if (ipbind != NULL && |
1213 | 0 | ipbind->ib_namebinds != NULL) { |
1214 | 0 | count = ipbind->ib_namebinds->nelts; |
1215 | 0 | } |
1216 | |
|
1217 | 0 | return count; |
1218 | 0 | } |
1219 | | |
1220 | | int pr_namebind_open(const char *name, const pr_netaddr_t *addr, |
1221 | 0 | unsigned int server_port) { |
1222 | 0 | pr_namebind_t *namebind = NULL; |
1223 | 0 | unsigned int port; |
1224 | |
|
1225 | 0 | if (name == NULL || |
1226 | 0 | addr == NULL) { |
1227 | 0 | errno = EINVAL; |
1228 | 0 | return -1; |
1229 | 0 | } |
1230 | | |
1231 | 0 | port = ntohs(pr_netaddr_get_port(addr)); |
1232 | 0 | if (port == 0) { |
1233 | 0 | port = server_port; |
1234 | 0 | } |
1235 | |
|
1236 | 0 | namebind = pr_namebind_find(name, addr, port, FALSE); |
1237 | 0 | if (namebind == NULL) { |
1238 | 0 | errno = ENOENT; |
1239 | 0 | return -1; |
1240 | 0 | } |
1241 | | |
1242 | 0 | namebind->nb_isactive = TRUE; |
1243 | 0 | return 0; |
1244 | 0 | } |
1245 | | |
1246 | 0 | void free_bindings(void) { |
1247 | 0 | if (binding_pool) { |
1248 | 0 | destroy_pool(binding_pool); |
1249 | 0 | binding_pool = NULL; |
1250 | 0 | listener_list = NULL; |
1251 | 0 | } |
1252 | |
|
1253 | 0 | memset(ipbind_table, 0, sizeof(ipbind_table)); |
1254 | 0 | ipbind_table_initialized = FALSE; |
1255 | | |
1256 | | /* Mark all listening conns as "unclaimed"; any that remaining unclaimed |
1257 | | * after init_bindings() can be closed. |
1258 | | */ |
1259 | 0 | if (listening_conn_list != NULL) { |
1260 | 0 | struct listener_rec *lr; |
1261 | |
|
1262 | 0 | for (lr = (struct listener_rec *) listening_conn_list->xas_list; lr; lr = lr->next) { |
1263 | 0 | pr_signals_handle(); |
1264 | 0 | lr->claimed = FALSE; |
1265 | 0 | } |
1266 | 0 | } |
1267 | 0 | } |
1268 | | |
1269 | 0 | static int init_inetd_bindings(void) { |
1270 | 0 | int res = 0; |
1271 | 0 | server_rec *serv = NULL; |
1272 | 0 | unsigned char *default_server = NULL, is_default = FALSE; |
1273 | | |
1274 | | /* We explicitly do NOT use the get_listening_conn() function here, since |
1275 | | * inetd-run daemons will not a) handle restarts, and thus b) will not have |
1276 | | * already-open connections to choose from. |
1277 | | */ |
1278 | |
|
1279 | 0 | main_server->listen = pr_inet_create_conn(main_server->pool, STDIN_FILENO, |
1280 | 0 | NULL, INPORT_ANY, FALSE); |
1281 | 0 | if (main_server->listen == NULL) { |
1282 | 0 | return -1; |
1283 | 0 | } |
1284 | | |
1285 | | /* Note: Since we are being called via inetd/xinetd, any socket options |
1286 | | * which may be attempted by listeners for this event may not work. |
1287 | | */ |
1288 | 0 | pr_inet_generate_socket_event("core.ctrl-listen", main_server, |
1289 | 0 | main_server->addr, main_server->listen->listen_fd); |
1290 | | |
1291 | | /* Fill in all the important connection information. */ |
1292 | 0 | if (pr_inet_get_conn_info(main_server->listen, STDIN_FILENO) == -1) { |
1293 | 0 | int xerrno = errno; |
1294 | |
|
1295 | 0 | pr_log_pri(PR_LOG_WARNING, "fatal: unable to get connection info: %s", |
1296 | 0 | strerror(xerrno)); |
1297 | |
|
1298 | 0 | if (xerrno == ENOTSOCK) { |
1299 | 0 | pr_log_pri(PR_LOG_ERR, "(Running from command line? " |
1300 | 0 | "Use `ServerType standalone' in config file!)"); |
1301 | 0 | } |
1302 | |
|
1303 | 0 | exit(1); |
1304 | 0 | } |
1305 | | |
1306 | 0 | default_server = get_param_ptr(main_server->conf, "DefaultServer", FALSE); |
1307 | 0 | if (default_server != NULL && |
1308 | 0 | *default_server == TRUE) { |
1309 | 0 | is_default = TRUE; |
1310 | 0 | } |
1311 | |
|
1312 | 0 | res = pr_ipbind_create(main_server, main_server->addr, |
1313 | 0 | main_server->ServerPort); |
1314 | 0 | if (res < 0) { |
1315 | 0 | pr_log_pri(PR_LOG_NOTICE, |
1316 | 0 | "%s:%d: notice: unable to create ipbind '%s#%u': %s", __FILE__, __LINE__, |
1317 | 0 | main_server->ServerAddress, main_server->ServerPort, strerror(errno)); |
1318 | 0 | } |
1319 | |
|
1320 | 0 | res = pr_ipbind_open(main_server->addr, main_server->ServerPort, |
1321 | 0 | main_server->listen, is_default, TRUE, TRUE); |
1322 | 0 | if (res < 0) { |
1323 | 0 | pr_log_pri(PR_LOG_NOTICE, |
1324 | 0 | "%s:%d: notice: unable to open ipbind '%s': %s", __FILE__, __LINE__, |
1325 | 0 | pr_netaddr_get_ipstr(main_server->addr), strerror(errno)); |
1326 | 0 | } |
1327 | |
|
1328 | 0 | res = pr_ipbind_add_binds(main_server); |
1329 | 0 | if (res < 0) { |
1330 | 0 | pr_log_pri(PR_LOG_NOTICE, |
1331 | 0 | "%s:%d: notice: unable to add binds to ipbind '%s': %s", __FILE__, |
1332 | 0 | __LINE__, main_server->ServerAddress, strerror(errno)); |
1333 | 0 | } |
1334 | | |
1335 | | /* Now attach the faked connection to all virtual servers. */ |
1336 | 0 | for (serv = main_server->next; serv; serv = serv->next) { |
1337 | | |
1338 | | /* Because this server is sharing the connection with the |
1339 | | * main server, we need a cleanup handler to remove |
1340 | | * the server's reference when the original connection's |
1341 | | * pool is destroyed. |
1342 | | */ |
1343 | |
|
1344 | 0 | serv->listen = main_server->listen; |
1345 | 0 | register_cleanup2(serv->listen->pool, &serv->listen, server_cleanup_cb); |
1346 | |
|
1347 | 0 | is_default = FALSE; |
1348 | 0 | default_server = get_param_ptr(serv->conf, "DefaultServer", FALSE); |
1349 | 0 | if (default_server != NULL && |
1350 | 0 | *default_server == TRUE) { |
1351 | 0 | is_default = TRUE; |
1352 | 0 | } |
1353 | |
|
1354 | 0 | res = pr_ipbind_create(serv, serv->addr, serv->ServerPort); |
1355 | 0 | if (res < 0) { |
1356 | 0 | pr_log_pri(PR_LOG_NOTICE, |
1357 | 0 | "%s:%d: notice: unable to create ipbind '%s#%u': %s", __FILE__, |
1358 | 0 | __LINE__, serv->ServerAddress, serv->ServerPort, strerror(errno)); |
1359 | 0 | } |
1360 | |
|
1361 | 0 | res = pr_ipbind_open(serv->addr, serv->ServerPort, serv->listen, |
1362 | 0 | is_default, FALSE, TRUE); |
1363 | 0 | if (res < 0) { |
1364 | 0 | pr_log_pri(PR_LOG_NOTICE, |
1365 | 0 | "%s:%d: notice: unable to open ipbind '%s': %s", __FILE__, __LINE__, |
1366 | 0 | pr_netaddr_get_ipstr(serv->addr), strerror(errno)); |
1367 | 0 | } |
1368 | |
|
1369 | 0 | res = pr_ipbind_add_binds(serv); |
1370 | 0 | if (res < 0) { |
1371 | 0 | pr_log_pri(PR_LOG_NOTICE, |
1372 | 0 | "%s:%d: notice: unable to add binds to ipbind '%s': %s", __FILE__, |
1373 | 0 | __LINE__, serv->ServerAddress, strerror(errno)); |
1374 | 0 | } |
1375 | 0 | } |
1376 | |
|
1377 | 0 | return 0; |
1378 | 0 | } |
1379 | | |
1380 | 0 | static array_header *find_server_ipbinds(pool *p, server_rec *s) { |
1381 | 0 | register unsigned int i; |
1382 | 0 | array_header *ipbinds = NULL; |
1383 | |
|
1384 | 0 | for (i = 0; i < PR_BINDINGS_TABLE_SIZE; i++) { |
1385 | 0 | pr_ipbind_t *ipbind; |
1386 | |
|
1387 | 0 | for (ipbind = ipbind_table[i]; ipbind != NULL; ipbind = ipbind->ib_next) { |
1388 | 0 | pr_signals_handle(); |
1389 | |
|
1390 | 0 | if (ipbind->ib_server == s) { |
1391 | 0 | if (ipbinds == NULL) { |
1392 | 0 | ipbinds = make_array(p, 16, sizeof(pr_ipbind_t *)); |
1393 | 0 | } |
1394 | |
|
1395 | 0 | *((pr_ipbind_t **) push_array(ipbinds)) = ipbind; |
1396 | 0 | } |
1397 | 0 | } |
1398 | 0 | } |
1399 | |
|
1400 | 0 | return ipbinds; |
1401 | 0 | } |
1402 | | |
1403 | 0 | static unsigned int process_serveralias(server_rec *s) { |
1404 | 0 | unsigned namebind_count = 0; |
1405 | 0 | config_rec *c; |
1406 | 0 | pr_ipbind_t *ipbind; |
1407 | 0 | array_header *ipbinds; |
1408 | 0 | pool *tmp_pool; |
1409 | | |
1410 | | /* If there is no ipbind already for this server, we cannot associate |
1411 | | * any ServerAlias-based namebinds to it. |
1412 | | * |
1413 | | * Keep in mind that there may be multiple ipbinds pointed at this server: |
1414 | | * |
1415 | | * <VirtualHost 1.2.3.4 5.6.7.8> |
1416 | | * ServerAlias alias |
1417 | | * </VirtualHost> |
1418 | | * |
1419 | | * And that multiple namebinds can point to the same ipbind for this server: |
1420 | | * |
1421 | | * <VirtualHost 1.2.3.4> |
1422 | | * ServerAlias first |
1423 | | * </VirtualHost> |
1424 | | * |
1425 | | * <VirtualHost 2.3.4.5> |
1426 | | * ServerAlias second |
1427 | | * </VirtualHost> |
1428 | | */ |
1429 | |
|
1430 | 0 | tmp_pool = make_sub_pool(s->pool); |
1431 | 0 | pr_pool_tag(tmp_pool, "ServerAlias Processing Pool"); |
1432 | | |
1433 | | /* Remember that this will return cases where port is zero, too. */ |
1434 | 0 | ipbind = pr_ipbind_find(s->addr, s->ServerPort, FALSE); |
1435 | 0 | if (ipbind != NULL && |
1436 | 0 | ipbind->ib_server->ServerPort == s->ServerPort) { |
1437 | 0 | ipbinds = make_array(tmp_pool, 1, sizeof(pr_ipbind_t *)); |
1438 | 0 | *((pr_ipbind_t **) push_array(ipbinds)) = ipbind; |
1439 | |
|
1440 | 0 | } else { |
1441 | 0 | ipbinds = find_server_ipbinds(tmp_pool, s); |
1442 | 0 | if (ipbinds == NULL) { |
1443 | 0 | destroy_pool(tmp_pool); |
1444 | 0 | return 0; |
1445 | 0 | } |
1446 | 0 | } |
1447 | | |
1448 | 0 | c = find_config(s->conf, CONF_PARAM, "ServerAlias", FALSE); |
1449 | 0 | while (c != NULL) { |
1450 | 0 | register unsigned int i; |
1451 | 0 | int res; |
1452 | 0 | pr_ipbind_t **elts; |
1453 | |
|
1454 | 0 | pr_signals_handle(); |
1455 | |
|
1456 | 0 | pr_trace_msg(trace_channel, 7, "handling ipbinds (%d) for ServerAlias '%s'", |
1457 | 0 | ipbinds->nelts, (char *) c->argv[0]); |
1458 | |
|
1459 | 0 | elts = ipbinds->elts; |
1460 | 0 | for (i = 0; i < ipbinds->nelts; i++) { |
1461 | 0 | pr_signals_handle(); |
1462 | |
|
1463 | 0 | ipbind = elts[i]; |
1464 | 0 | pr_trace_msg(trace_channel, 7, "adding ServerAlias '%s' to server '%s'", |
1465 | 0 | (char *) c->argv[0], s->ServerName); |
1466 | |
|
1467 | 0 | res = pr_namebind_create(s, c->argv[0], ipbind, s->addr, s->ServerPort); |
1468 | 0 | if (res == 0) { |
1469 | 0 | namebind_count++; |
1470 | |
|
1471 | 0 | res = pr_namebind_open(c->argv[0], ipbind->ib_addr, ipbind->ib_port); |
1472 | 0 | if (res < 0) { |
1473 | 0 | pr_trace_msg(trace_channel, 2, |
1474 | 0 | "notice: unable to open namebind '%s': %s", (char *) c->argv[0], |
1475 | 0 | strerror(errno)); |
1476 | 0 | } |
1477 | |
|
1478 | 0 | } else { |
1479 | 0 | if (errno != ENOENT) { |
1480 | 0 | pr_trace_msg(trace_channel, 3, |
1481 | 0 | "unable to create namebind for '%s' to %s#%u: %s", |
1482 | 0 | (char *) c->argv[0], pr_netaddr_get_ipstr(ipbind->ib_addr), |
1483 | 0 | ipbind->ib_port, strerror(errno)); |
1484 | 0 | } |
1485 | 0 | } |
1486 | 0 | } |
1487 | |
|
1488 | 0 | c = find_config_next(c, c->next, CONF_PARAM, "ServerAlias", FALSE); |
1489 | 0 | } |
1490 | |
|
1491 | 0 | destroy_pool(tmp_pool); |
1492 | 0 | return namebind_count; |
1493 | 0 | } |
1494 | | |
1495 | 0 | static void trace_ipbind_table(void) { |
1496 | 0 | register unsigned int i; |
1497 | |
|
1498 | 0 | if (pr_trace_get_level(trace_channel) < 25) { |
1499 | 0 | return; |
1500 | 0 | } |
1501 | | |
1502 | 0 | pr_trace_msg(trace_channel, 25, "displaying ipbind table:"); |
1503 | 0 | for (i = 0; i < PR_BINDINGS_TABLE_SIZE; i++) { |
1504 | 0 | pr_ipbind_t *ipbind; |
1505 | |
|
1506 | 0 | pr_signals_handle(); |
1507 | |
|
1508 | 0 | if (ipbind_table[i] == NULL) { |
1509 | 0 | continue; |
1510 | 0 | } |
1511 | | |
1512 | 0 | pr_trace_msg(trace_channel, 25, " index %u:", i); |
1513 | 0 | for (ipbind = ipbind_table[i]; ipbind; ipbind = ipbind->ib_next) { |
1514 | 0 | array_header *namebinds; |
1515 | |
|
1516 | 0 | pr_signals_handle(); |
1517 | 0 | namebinds = ipbind->ib_namebinds; |
1518 | |
|
1519 | 0 | pr_trace_msg(trace_channel, 25, " ipbind %p:", ipbind); |
1520 | 0 | pr_trace_msg(trace_channel, 25, " address: %s#%u", |
1521 | 0 | pr_netaddr_get_ipstr(ipbind->ib_addr), ipbind->ib_port); |
1522 | 0 | pr_trace_msg(trace_channel, 25, " server: %s (%p)", |
1523 | 0 | ipbind->ib_server->ServerName, ipbind->ib_server); |
1524 | 0 | pr_trace_msg(trace_channel, 25, " active: %s", |
1525 | 0 | ipbind->ib_isactive ? "TRUE" : "FALSE"); |
1526 | |
|
1527 | 0 | if (namebinds != NULL) { |
1528 | 0 | register unsigned int k; |
1529 | 0 | pr_namebind_t **elts; |
1530 | |
|
1531 | 0 | pr_trace_msg(trace_channel, 25, " namebinds:"); |
1532 | 0 | elts = namebinds->elts; |
1533 | 0 | for (k = 0; k < namebinds->nelts; k++) { |
1534 | 0 | pr_namebind_t *namebind; |
1535 | |
|
1536 | 0 | pr_signals_handle(); |
1537 | 0 | namebind = elts[k]; |
1538 | 0 | pr_trace_msg(trace_channel, 25, " #%u: %p", k+1, namebind); |
1539 | 0 | pr_trace_msg(trace_channel, 25, " name: %s", |
1540 | 0 | namebind->nb_server->ServerName); |
1541 | 0 | pr_trace_msg(trace_channel, 25, " alias: %s", |
1542 | 0 | namebind->nb_name); |
1543 | 0 | pr_trace_msg(trace_channel, 25, " server: %p", |
1544 | 0 | namebind->nb_server); |
1545 | 0 | pr_trace_msg(trace_channel, 25, " active: %s", |
1546 | 0 | namebind->nb_isactive ? "TRUE" : "FALSE"); |
1547 | 0 | } |
1548 | 0 | } |
1549 | 0 | } |
1550 | 0 | } |
1551 | 0 | } |
1552 | | |
1553 | 0 | static int init_standalone_bindings(void) { |
1554 | 0 | int res = 0; |
1555 | 0 | server_rec *serv = NULL; |
1556 | 0 | unsigned char *default_server = NULL, is_default = FALSE; |
1557 | | |
1558 | | /* Ensure the ipbind table has been initialized. */ |
1559 | 0 | init_ipbind_table(); |
1560 | | |
1561 | | /* If a port is set to zero, the address/port is not bound to a socket |
1562 | | * at all. |
1563 | | */ |
1564 | 0 | if (main_server->ServerPort > 0) { |
1565 | | /* If SocketBindTight is off, then pr_inet_create_conn() will |
1566 | | * create and bind to a wildcard socket. However, should it be an |
1567 | | * IPv4 or an IPv6 wildcard socket? |
1568 | | */ |
1569 | 0 | if (!SocketBindTight) { |
1570 | 0 | #if defined(PR_USE_IPV6) |
1571 | 0 | if (pr_netaddr_use_ipv6()) { |
1572 | 0 | pr_inet_set_default_family(NULL, AF_INET6); |
1573 | |
|
1574 | 0 | } else { |
1575 | 0 | int default_family; |
1576 | |
|
1577 | 0 | default_family = pr_netaddr_get_family(main_server->addr); |
1578 | 0 | pr_inet_set_default_family(NULL, default_family); |
1579 | 0 | } |
1580 | | #else |
1581 | | pr_inet_set_default_family(NULL, |
1582 | | pr_netaddr_get_family(main_server->addr)); |
1583 | | #endif /* PR_USE_IPV6 */ |
1584 | 0 | } |
1585 | |
|
1586 | 0 | main_server->listen = pr_ipbind_get_listening_conn(main_server, |
1587 | 0 | (SocketBindTight ? main_server->addr : NULL), main_server->ServerPort); |
1588 | 0 | if (main_server->listen == NULL) { |
1589 | 0 | return -1; |
1590 | 0 | } |
1591 | |
|
1592 | 0 | } else { |
1593 | 0 | main_server->listen = NULL; |
1594 | 0 | } |
1595 | | |
1596 | 0 | default_server = get_param_ptr(main_server->conf, "DefaultServer", FALSE); |
1597 | 0 | if (default_server != NULL && |
1598 | 0 | *default_server == TRUE) { |
1599 | 0 | is_default = TRUE; |
1600 | 0 | } |
1601 | |
|
1602 | 0 | if (main_server->ServerPort == 0) { |
1603 | | /* If there is no server port, then this vhost cannot be treated as the |
1604 | | * DefaultServer. |
1605 | | */ |
1606 | 0 | is_default = FALSE; |
1607 | 0 | } |
1608 | |
|
1609 | 0 | if (main_server->ServerPort > 0 || |
1610 | 0 | is_default == TRUE) { |
1611 | |
|
1612 | 0 | res = pr_ipbind_create(main_server, main_server->addr, |
1613 | 0 | main_server->ServerPort); |
1614 | 0 | if (res < 0) { |
1615 | 0 | pr_log_pri(PR_LOG_NOTICE, |
1616 | 0 | "%s:%d: notice: unable to create ipbind '%s#%u': %s", __FILE__, |
1617 | 0 | __LINE__, main_server->ServerAddress, main_server->ServerPort, |
1618 | 0 | strerror(errno)); |
1619 | 0 | } |
1620 | |
|
1621 | 0 | res = pr_ipbind_open(main_server->addr, main_server->ServerPort, |
1622 | 0 | main_server->listen, is_default, TRUE, TRUE); |
1623 | 0 | if (res < 0) { |
1624 | 0 | pr_log_pri(PR_LOG_NOTICE, |
1625 | 0 | "%s:%d: notice: unable to open ipbind '%s': %s", __FILE__, __LINE__, |
1626 | 0 | pr_netaddr_get_ipstr(main_server->addr), strerror(errno)); |
1627 | 0 | } |
1628 | |
|
1629 | 0 | res = pr_ipbind_add_binds(main_server); |
1630 | 0 | if (res < 0) { |
1631 | 0 | pr_log_pri(PR_LOG_NOTICE, |
1632 | 0 | "%s:%d: notice: unable to add binds to ipbind '%s': %s", __FILE__, |
1633 | 0 | __LINE__, main_server->ServerAddress, strerror(errno)); |
1634 | 0 | } |
1635 | 0 | } |
1636 | |
|
1637 | 0 | for (serv = main_server->next; serv; serv = serv->next) { |
1638 | 0 | unsigned int namebind_count; |
1639 | |
|
1640 | 0 | pr_signals_handle(); |
1641 | |
|
1642 | 0 | namebind_count = process_serveralias(serv); |
1643 | 0 | if (namebind_count > 0) { |
1644 | | /* If we successfully added ServerAlias namebinds, move on to the next |
1645 | | * server. |
1646 | | */ |
1647 | 0 | continue; |
1648 | 0 | } |
1649 | | |
1650 | 0 | if (serv->ServerPort != main_server->ServerPort || |
1651 | 0 | SocketBindTight || |
1652 | 0 | !main_server->listen) { |
1653 | 0 | is_default = FALSE; |
1654 | |
|
1655 | 0 | default_server = get_param_ptr(serv->conf, "DefaultServer", FALSE); |
1656 | 0 | if (default_server != NULL && |
1657 | 0 | *default_server == TRUE) { |
1658 | 0 | is_default = TRUE; |
1659 | 0 | } |
1660 | |
|
1661 | 0 | if (serv->ServerPort == 0) { |
1662 | | /* If there is no server port, then this vhost cannot be treated as the |
1663 | | * DefaultServer. |
1664 | | */ |
1665 | 0 | is_default = FALSE; |
1666 | 0 | } |
1667 | |
|
1668 | 0 | if (serv->ServerPort > 0) { |
1669 | 0 | if (SocketBindTight == FALSE) { |
1670 | 0 | #ifdef PR_USE_IPV6 |
1671 | 0 | if (pr_netaddr_use_ipv6()) { |
1672 | 0 | pr_inet_set_default_family(NULL, AF_INET6); |
1673 | |
|
1674 | 0 | } else { |
1675 | 0 | pr_inet_set_default_family(NULL, pr_netaddr_get_family(serv->addr)); |
1676 | 0 | } |
1677 | | #else |
1678 | | pr_inet_set_default_family(NULL, pr_netaddr_get_family(serv->addr)); |
1679 | | #endif /* PR_USE_IPV6 */ |
1680 | 0 | } |
1681 | |
|
1682 | 0 | serv->listen = pr_ipbind_get_listening_conn(serv, |
1683 | 0 | (SocketBindTight ? serv->addr : NULL), serv->ServerPort); |
1684 | 0 | if (serv->listen == NULL) { |
1685 | 0 | return -1; |
1686 | 0 | } |
1687 | | |
1688 | 0 | res = pr_ipbind_create(serv, serv->addr, serv->ServerPort); |
1689 | 0 | if (res < 0) { |
1690 | 0 | pr_log_pri(PR_LOG_NOTICE, |
1691 | 0 | "%s:%d: notice: unable to create ipbind '%s#%u': %s", __FILE__, |
1692 | 0 | __LINE__, serv->ServerAddress, serv->ServerPort, strerror(errno)); |
1693 | 0 | } |
1694 | |
|
1695 | 0 | res = pr_ipbind_open(serv->addr, serv->ServerPort, serv->listen, |
1696 | 0 | is_default, FALSE, TRUE); |
1697 | 0 | if (res < 0) { |
1698 | 0 | pr_log_pri(PR_LOG_NOTICE, |
1699 | 0 | "%s:%d: notice: unable to open ipbind '%s': %s", __FILE__, __LINE__, |
1700 | 0 | pr_netaddr_get_ipstr(serv->addr), strerror(errno)); |
1701 | 0 | } |
1702 | |
|
1703 | 0 | res = pr_ipbind_add_binds(serv); |
1704 | 0 | if (res < 0) { |
1705 | 0 | pr_log_pri(PR_LOG_NOTICE, |
1706 | 0 | "%s:%d: notice: unable to add binds to ipbind '%s': %s", __FILE__, |
1707 | 0 | __LINE__, serv->ServerAddress, strerror(errno)); |
1708 | 0 | } |
1709 | |
|
1710 | 0 | } else if (is_default == TRUE) { |
1711 | 0 | serv->listen = NULL; |
1712 | |
|
1713 | 0 | res = pr_ipbind_create(serv, serv->addr, serv->ServerPort); |
1714 | 0 | if (res < 0) { |
1715 | 0 | pr_log_pri(PR_LOG_NOTICE, |
1716 | 0 | "%s:%d: notice: unable to create ipbind '%s#%u': %s", __FILE__, |
1717 | 0 | __LINE__, serv->ServerAddress, serv->ServerPort, strerror(errno)); |
1718 | 0 | } |
1719 | |
|
1720 | 0 | res = pr_ipbind_open(serv->addr, serv->ServerPort, serv->listen, |
1721 | 0 | is_default, FALSE, TRUE); |
1722 | 0 | if (res < 0) { |
1723 | 0 | pr_log_pri(PR_LOG_NOTICE, |
1724 | 0 | "%s:%d: notice: unable to open ipbind '%s': %s", __FILE__, __LINE__, |
1725 | 0 | pr_netaddr_get_ipstr(serv->addr), strerror(errno)); |
1726 | 0 | } |
1727 | |
|
1728 | 0 | res = pr_ipbind_add_binds(serv); |
1729 | 0 | if (res < 0) { |
1730 | 0 | pr_log_pri(PR_LOG_NOTICE, |
1731 | 0 | "%s:%d: notice: unable to add binds to ipbind '%s': %s", __FILE__, |
1732 | 0 | __LINE__, serv->ServerAddress, strerror(errno)); |
1733 | 0 | } |
1734 | |
|
1735 | 0 | } else { |
1736 | 0 | serv->listen = NULL; |
1737 | 0 | } |
1738 | |
|
1739 | 0 | } else { |
1740 | | /* Because this server is sharing the connection with the main server, |
1741 | | * we need a cleanup handler to remove the server's reference when the |
1742 | | * original connection's pool is destroyed. |
1743 | | */ |
1744 | |
|
1745 | 0 | is_default = FALSE; |
1746 | 0 | default_server = get_param_ptr(serv->conf, "DefaultServer", FALSE); |
1747 | 0 | if (default_server != NULL && |
1748 | 0 | *default_server == TRUE) { |
1749 | 0 | is_default = TRUE; |
1750 | 0 | } |
1751 | |
|
1752 | 0 | serv->listen = main_server->listen; |
1753 | 0 | register_cleanup2(serv->listen->pool, &serv->listen, server_cleanup_cb); |
1754 | |
|
1755 | 0 | res = pr_ipbind_create(serv, serv->addr, serv->ServerPort); |
1756 | 0 | if (res < 0) { |
1757 | 0 | pr_log_pri(PR_LOG_NOTICE, |
1758 | 0 | "%s:%d: notice: unable to create ipbind '%s#%u': %s", __FILE__, |
1759 | 0 | __LINE__, serv->ServerAddress, serv->ServerPort, strerror(errno)); |
1760 | 0 | } |
1761 | |
|
1762 | 0 | res = pr_ipbind_open(serv->addr, serv->ServerPort, NULL, is_default, |
1763 | 0 | FALSE, TRUE); |
1764 | 0 | if (res < 0) { |
1765 | 0 | pr_log_pri(PR_LOG_NOTICE, |
1766 | 0 | "%s:%d: notice: unable to open ipbind '%s': %s", __FILE__, __LINE__, |
1767 | 0 | pr_netaddr_get_ipstr(serv->addr), strerror(errno)); |
1768 | 0 | } |
1769 | |
|
1770 | 0 | res = pr_ipbind_add_binds(serv); |
1771 | 0 | if (res < 0) { |
1772 | 0 | pr_log_pri(PR_LOG_NOTICE, |
1773 | 0 | "%s:%d: notice: unable to add binds to ipbind '%s': %s", __FILE__, |
1774 | 0 | __LINE__, serv->ServerAddress, strerror(errno)); |
1775 | 0 | } |
1776 | 0 | } |
1777 | | |
1778 | | /* Process any ServerAlias directives AFTER the server's ipbind has been |
1779 | | * created/opened (Issue #932). |
1780 | | */ |
1781 | 0 | process_serveralias(serv); |
1782 | 0 | } |
1783 | | |
1784 | 0 | trace_ipbind_table(); |
1785 | | |
1786 | | /* Any "unclaimed" listening conns can be removed and closed. */ |
1787 | 0 | if (listening_conn_list != NULL) { |
1788 | 0 | struct listener_rec *lr, *lrn; |
1789 | |
|
1790 | 0 | for (lr = (struct listener_rec *) listening_conn_list->xas_list; lr; lr = lrn) { |
1791 | 0 | pr_signals_handle(); |
1792 | |
|
1793 | 0 | lrn = lr->next; |
1794 | 0 | if (lr->claimed == FALSE) { |
1795 | 0 | xaset_remove(listening_conn_list, (xasetmember_t *) lr); |
1796 | 0 | destroy_pool(lr->pool); |
1797 | 0 | } |
1798 | 0 | } |
1799 | 0 | } |
1800 | |
|
1801 | 0 | return 0; |
1802 | 0 | } |
1803 | | |
1804 | 0 | void init_bindings(void) { |
1805 | 0 | int res = 0; |
1806 | |
|
1807 | 0 | #ifdef PR_USE_IPV6 |
1808 | 0 | int sock; |
1809 | | |
1810 | | /* Check to see whether we can actually create an IPv6 socket. */ |
1811 | 0 | sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); |
1812 | 0 | if (sock < 0) { |
1813 | 0 | pr_netaddr_disable_ipv6(); |
1814 | |
|
1815 | 0 | } else { |
1816 | 0 | (void) close(sock); |
1817 | 0 | } |
1818 | 0 | #endif /* PR_USE_IPV6 */ |
1819 | |
|
1820 | 0 | if (ServerType == SERVER_INETD) { |
1821 | 0 | res = init_inetd_bindings(); |
1822 | |
|
1823 | 0 | } else if (ServerType == SERVER_STANDALONE) { |
1824 | 0 | res = init_standalone_bindings(); |
1825 | 0 | } |
1826 | |
|
1827 | 0 | if (res < 0) { |
1828 | 0 | pr_log_pri(PR_LOG_ERR, "%s", |
1829 | 0 | "Unable to start proftpd; check logs for more details"); |
1830 | 0 | exit(1); |
1831 | 0 | } |
1832 | 0 | } |