1 /*
2  * ProFTPD - FTP server daemon
3  * Copyright (c) 2001-2020 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 /* ProFTPD bindings support routines. */
26 
27 #ifndef PR_BINDINGS_H
28 #define PR_BINDINGS_H
29 
30 #include "conf.h"
31 #include "pool.h"
32 
33 /* NOTE: the is* members could possibly become a bitmasked number */
34 
35 /* Structure associating an IP address to a server_rec */
36 typedef struct ipbind_rec {
37   struct ipbind_rec *ib_next;
38 
39   /* IP address to which this binding is "bound" */
40   const pr_netaddr_t *ib_addr;
41   unsigned int ib_port;
42 
43   /* Default server to handle requests to this binding.  If namebinds are
44    * present, they will be checked before using this server
45    */
46   server_rec *ib_server;
47 
48   /* Listener associated with this binding.  This listener, and
49    * ib_server->listen, are the same listener.  The duplicate locations
50    * are necessary for inetd-run servers (at present).
51    */
52   conn_t *ib_listener;
53 
54   /* List of name-based servers bound to the above IP address.  Note that
55    * if this functionality becomes widely adopted and used, a more efficient
56    * search-and-lookup mechanism will be needed, for performance reasons.
57    */
58   array_header *ib_namebinds;
59 
60   /* If this binding is the DefaultServer binding */
61   unsigned char ib_isdefault;
62 
63   /* If this binding handles localhost requests */
64   unsigned char ib_islocalhost;
65 
66   /* If this binding is active */
67   unsigned char ib_isactive;
68 
69 } pr_ipbind_t;
70 
71 /* Structure associating a name to a server_rec */
72 typedef struct namebind_rec {
73   const char *nb_name;
74   unsigned char nb_iswildcard;
75   unsigned char nb_isactive;
76   server_rec *nb_server;
77   unsigned int nb_server_port;
78 
79 } pr_namebind_t;
80 
81 /* Define the size of the hash table used to store server configurations.
82  * It needs to be a power of two.
83  */
84 #define PR_BINDINGS_TABLE_SIZE	256
85 
86 /* Given an fd returned by select(), accept() and return the connt_t structure
87  * for the binding associated with that fd.  Returns the conn_t if successful,
88  * NULL if not found or if the arguments were NULL.
89  */
90 conn_t *pr_ipbind_accept_conn(fd_set *readfds, int *listenfd);
91 
92 /* Create a new IP-based binding for the server given, using the provided
93  * arguments. The new binding is added the list maintained by the bindings
94  * layer.  Returns 0 on success, -1 on failure.
95  */
96 int pr_ipbind_create(server_rec *server, const pr_netaddr_t *addr,
97   unsigned int port);
98 
99 /* Close all IP bindings associated with the given IP address/port combination.
100  * The bindings are then marked as inactive, so that future lookups via
101  * pr_ipbind_find() skip these bindings.  Returns 0 on success, -1 on failure
102  * (eg no associated bindings found).
103  */
104 int pr_ipbind_close(const pr_netaddr_t *addr, unsigned int port,
105   unsigned char close_namebinds);
106 
107 /* Close all listenings fds.  This needs to happen just after a process
108  * has been forked to handle a session.
109  */
110 int pr_ipbind_close_listeners(void);
111 
112 /* Search through the given server's configuration records, and for each
113  * associated bind configuration found, create an additional IP binding for
114  * that bind address.  Honors SocketBindTight, if set.  Returns 0 on
115  * success, -1 on failure (if server == NULL, for example).
116  */
117 int pr_ipbind_add_binds(server_rec *server);
118 
119 /* Search the binding list, and return the pr_ipbind_t for the given addr and
120  * port.  If requested, skip over inactive bindings while searching.
121  */
122 pr_ipbind_t *pr_ipbind_find(const pr_netaddr_t *addr, unsigned int port,
123   unsigned char skip_inactive);
124 
125 /* Iterate through the binding list, returning the next ipbind.  Returns NULL
126  * once the end of the list is reached.  If prev is NULL, the iterator
127  * restarts at the beginning of the list.
128  */
129 pr_ipbind_t *pr_ipbind_get(pr_ipbind_t *prev);
130 
131 /* Search the binding list, and return the server_rec * that is bound to the
132  * given IP address/port combination.
133  */
134 server_rec *pr_ipbind_get_server(const pr_netaddr_t *addr, unsigned int port);
135 
136 /* Listens on each file descriptor in the given set, and returns the file
137  * descriptor associated with an incoming connection request.  Returns -1
138  * on error, as when the fd_set argument is NULL.
139  */
140 int pr_ipbind_listen(fd_set *readfds);
141 
142 /* Prepares the IP-based binding associated with the given server for listening.
143  * Returns 0 on success, -1 on failure.
144  */
145 int pr_ipbind_open(const pr_netaddr_t *addr, unsigned int port,
146   conn_t *listen_conn, unsigned char isdefault, unsigned char islocalhost,
147   unsigned char open_namebinds);
148 
149 conn_t *pr_ipbind_get_listening_conn(server_rec *server,
150   const pr_netaddr_t *addr, unsigned int port);
151 
152 /* Close the pr_namebind_t with the given name. */
153 int pr_namebind_close(const char *name, const pr_netaddr_t *addr);
154 
155 /* Create a pr_namebind_t, similar to a pr_ipbind_t, which maps the name (usu.
156  * DNS hostname) to the server_rec.  The given addr is used to associate this
157  * pr_namebind_t with the given IP address (to which the DNS hostname should
158  * resolve).
159  */
160 int pr_namebind_create(server_rec *server, const char *name,
161   pr_ipbind_t *ipbind, const pr_netaddr_t *addr, unsigned int port);
162 
163 /* Search the Bindings layer, and return the pr_namebind_t associated with
164  * the given addr, port, and name.  If requested, skip over inactive
165  * bindings while searching.
166  */
167 pr_namebind_t *pr_namebind_find(const char *name, const pr_netaddr_t *addr,
168   unsigned int port, unsigned char skip_inactive);
169 
170 /* Find the server_rec associated with the given name.  If none are found,
171  * default to the server_rec of the containing pr_ipbind_t.
172  */
173 server_rec *pr_namebind_get_server(const char *name, const pr_netaddr_t *addr,
174   unsigned int port);
175 
176 /* Opens the pr_namebind_t with the given name. */
177 int pr_namebind_open(const char *name, const pr_netaddr_t *addr,
178   unsigned int port);
179 
180 /* Provides a count of the number of namebinds associated with this
181  * server_rec.
182  */
183 unsigned int pr_namebind_count(server_rec *);
184 
185 /* Initialize the Bindings layer. */
186 void init_bindings(void);
187 
188 /* Free the Bindings layer. */
189 void free_bindings(void);
190 
191 /* Macro error-handling wrappers */
192 #define PR_ADD_IPBINDS(s) \
193   if ((res = pr_ipbind_add_binds((s))) < 0) \
194     pr_log_pri(PR_LOG_NOTICE, \
195       "%s:%d: notice: unable to add binds to ipbind '%s': %s", \
196       __FILE__, __LINE__, (s)->ServerAddress, strerror(errno))
197 
198 #define PR_CLOSE_IPBIND(a, p, c) \
199   if ((res = pr_ipbind_close((a), (p), (c))) < 0) \
200     pr_log_pri(PR_LOG_NOTICE, \
201       "%s:%d: notice: unable to close ipbind: %s", \
202       __FILE__, __LINE__, strerror(errno))
203 
204 #define PR_CREATE_IPBIND(s, a, p) \
205   if ((res = pr_ipbind_create((s), (a), (p))) < 0) \
206     pr_log_pri(PR_LOG_NOTICE, \
207       "%s:%d: notice: unable to create ipbind '%s#%u': %s", \
208       __FILE__, __LINE__, (s)->ServerAddress, (p), strerror(errno))
209 
210 #define PR_OPEN_IPBIND(a, p, c, d, l, o) \
211   if ((res = pr_ipbind_open((a), (p), (c), (d), (l), (o))) < 0) \
212     pr_log_pri(PR_LOG_NOTICE, \
213       "%s:%d: notice: unable to open ipbind '%s': %s", \
214       __FILE__, __LINE__, pr_netaddr_get_ipstr((a)), strerror(errno))
215 
216 #endif /* PR_BINDINGS_H */
217