BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * @file PasswordListener.c
3 * @author Ambroz Bizjak <ambrop7@gmail.com>
4 *
5 * @section LICENSE
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the
15 * names of its contributors may be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29  
30 #include <stdlib.h>
31  
32 #include <prerror.h>
33  
34 #include <nss/ssl.h>
35  
36 #include <misc/offset.h>
37 #include <misc/byteorder.h>
38 #include <misc/balloc.h>
39 #include <misc/compare.h>
40 #include <base/BLog.h>
41 #include <security/BRandom.h>
42 #include <nspr_support/DummyPRFileDesc.h>
43  
44 #include <client/PasswordListener.h>
45  
46 #include <generated/blog_channel_PasswordListener.h>
47  
48 static int password_comparator (void *user, uint64_t *p1, uint64_t *p2);
49 static void remove_client (struct PasswordListenerClient *client);
50 static void listener_handler (PasswordListener *l);
51 static void client_connection_handler (struct PasswordListenerClient *client, int event);
52 static void client_sslcon_handler (struct PasswordListenerClient *client, int event);
53 static void client_receiver_handler (struct PasswordListenerClient *client);
54  
55 int password_comparator (void *user, uint64_t *p1, uint64_t *p2)
56 {
57 return B_COMPARE(*p1, *p2);
58 }
59  
60 void remove_client (struct PasswordListenerClient *client)
61 {
62 PasswordListener *l = client->l;
63  
64 // stop using any buffers before they get freed
65 if (l->ssl) {
66 BSSLConnection_ReleaseBuffers(&client->sslcon);
67 }
68  
69 // free receiver
70 SingleStreamReceiver_Free(&client->receiver);
71  
72 // free SSL
73 if (l->ssl) {
74 BSSLConnection_Free(&client->sslcon);
75 ASSERT_FORCE(PR_Close(client->sock->ssl_prfd) == PR_SUCCESS)
76 }
77  
78 // free connection interfaces
79 BConnection_RecvAsync_Free(&client->sock->con);
80 BConnection_SendAsync_Free(&client->sock->con);
81  
82 // free connection
83 BConnection_Free(&client->sock->con);
84  
85 // free sslsocket structure
86 free(client->sock);
87  
88 // move to free list
89 LinkedList1_Remove(&l->clients_used, &client->list_node);
90 LinkedList1_Append(&l->clients_free, &client->list_node);
91 }
92  
93 void listener_handler (PasswordListener *l)
94 {
95 DebugObject_Access(&l->d_obj);
96  
97 // obtain client entry
98 if (LinkedList1_IsEmpty(&l->clients_free)) {
99 struct PasswordListenerClient *client = UPPER_OBJECT(LinkedList1_GetFirst(&l->clients_used), struct PasswordListenerClient, list_node);
100 remove_client(client);
101 }
102 struct PasswordListenerClient *client = UPPER_OBJECT(LinkedList1_GetLast(&l->clients_free), struct PasswordListenerClient, list_node);
103 LinkedList1_Remove(&l->clients_free, &client->list_node);
104 LinkedList1_Append(&l->clients_used, &client->list_node);
105  
106 // allocate sslsocket structure
107 if (!(client->sock = (sslsocket *)malloc(sizeof(*client->sock)))) {
108 BLog(BLOG_ERROR, "malloc failedt");
109 goto fail0;
110 }
111  
112 // accept connection
113 if (!BConnection_Init(&client->sock->con, BConnection_source_listener(&l->listener, NULL), l->bsys, client, (BConnection_handler)client_connection_handler)) {
114 BLog(BLOG_ERROR, "BConnection_Init failed");
115 goto fail1;
116 }
117  
118 BLog(BLOG_INFO, "Connection accepted");
119  
120 // init connection interfaces
121 BConnection_SendAsync_Init(&client->sock->con);
122 BConnection_RecvAsync_Init(&client->sock->con);
123  
124 StreamPassInterface *send_if = BConnection_SendAsync_GetIf(&client->sock->con);
125 StreamRecvInterface *recv_if = BConnection_RecvAsync_GetIf(&client->sock->con);
126  
127 if (l->ssl) {
128 // create bottom NSPR file descriptor
129 if (!BSSLConnection_MakeBackend(&client->sock->bottom_prfd, send_if, recv_if, l->twd, l->ssl_flags)) {
130 BLog(BLOG_ERROR, "BSSLConnection_MakeBackend failed");
131 goto fail2;
132 }
133  
134 // create SSL file descriptor from the bottom NSPR file descriptor
135 if (!(client->sock->ssl_prfd = SSL_ImportFD(l->model_prfd, &client->sock->bottom_prfd))) {
136 ASSERT_FORCE(PR_Close(&client->sock->bottom_prfd) == PR_SUCCESS)
137 goto fail2;
138 }
139  
140 // set server mode
141 if (SSL_ResetHandshake(client->sock->ssl_prfd, PR_TRUE) != SECSuccess) {
142 BLog(BLOG_ERROR, "SSL_ResetHandshake failed");
143 goto fail3;
144 }
145  
146 // set require client certificate
147 if (SSL_OptionSet(client->sock->ssl_prfd, SSL_REQUEST_CERTIFICATE, PR_TRUE) != SECSuccess) {
148 BLog(BLOG_ERROR, "SSL_OptionSet(SSL_REQUEST_CERTIFICATE) failed");
149 goto fail3;
150 }
151 if (SSL_OptionSet(client->sock->ssl_prfd, SSL_REQUIRE_CERTIFICATE, PR_TRUE) != SECSuccess) {
152 BLog(BLOG_ERROR, "SSL_OptionSet(SSL_REQUIRE_CERTIFICATE) failed");
153 goto fail3;
154 }
155  
156 // initialize SSLConnection
157 BSSLConnection_Init(&client->sslcon, client->sock->ssl_prfd, 0, BReactor_PendingGroup(l->bsys), client, (BSSLConnection_handler)client_sslcon_handler);
158  
159 send_if = BSSLConnection_GetSendIf(&client->sslcon);
160 recv_if = BSSLConnection_GetRecvIf(&client->sslcon);
161 }
162  
163 // init receiver
164 SingleStreamReceiver_Init(&client->receiver, (uint8_t *)&client->recv_buffer, sizeof(client->recv_buffer), recv_if, BReactor_PendingGroup(l->bsys), client, (SingleStreamReceiver_handler)client_receiver_handler);
165  
166 return;
167  
168 // cleanup on error
169 fail3:
170 if (l->ssl) {
171 ASSERT_FORCE(PR_Close(client->sock->ssl_prfd) == PR_SUCCESS)
172 }
173 fail2:
174 BConnection_RecvAsync_Free(&client->sock->con);
175 BConnection_SendAsync_Free(&client->sock->con);
176 BConnection_Free(&client->sock->con);
177 fail1:
178 free(client->sock);
179 fail0:
180 LinkedList1_Remove(&l->clients_used, &client->list_node);
181 LinkedList1_Append(&l->clients_free, &client->list_node);
182 }
183  
184 void client_connection_handler (struct PasswordListenerClient *client, int event)
185 {
186 PasswordListener *l = client->l;
187 DebugObject_Access(&l->d_obj);
188  
189 if (event == BCONNECTION_EVENT_RECVCLOSED) {
190 BLog(BLOG_INFO, "connection closed");
191 } else {
192 BLog(BLOG_INFO, "connection error");
193 }
194  
195 remove_client(client);
196 }
197  
198 void client_sslcon_handler (struct PasswordListenerClient *client, int event)
199 {
200 PasswordListener *l = client->l;
201 DebugObject_Access(&l->d_obj);
202 ASSERT(l->ssl)
203 ASSERT(event == BSSLCONNECTION_EVENT_ERROR)
204  
205 BLog(BLOG_INFO, "SSL error");
206  
207 remove_client(client);
208 }
209  
210 void client_receiver_handler (struct PasswordListenerClient *client)
211 {
212 PasswordListener *l = client->l;
213 DebugObject_Access(&l->d_obj);
214  
215 // check password
216 uint64_t received_pass = ltoh64(client->recv_buffer);
217 BAVLNode *pw_tree_node = BAVL_LookupExact(&l->passwords, &received_pass);
218 if (!pw_tree_node) {
219 BLog(BLOG_WARNING, "unknown password");
220 remove_client(client);
221 return;
222 }
223 PasswordListener_pwentry *pw_entry = UPPER_OBJECT(pw_tree_node, PasswordListener_pwentry, tree_node);
224  
225 BLog(BLOG_INFO, "Password recognized");
226  
227 // remove password entry
228 BAVL_Remove(&l->passwords, &pw_entry->tree_node);
229  
230 // stop using any buffers before they get freed
231 if (l->ssl) {
232 BSSLConnection_ReleaseBuffers(&client->sslcon);
233 }
234  
235 // free receiver
236 SingleStreamReceiver_Free(&client->receiver);
237  
238 if (l->ssl) {
239 // free SSL connection
240 BSSLConnection_Free(&client->sslcon);
241 } else {
242 // free connection interfaces
243 BConnection_RecvAsync_Free(&client->sock->con);
244 BConnection_SendAsync_Free(&client->sock->con);
245 }
246  
247 // remove connection handler
248 BConnection_SetHandlers(&client->sock->con, NULL, NULL);
249  
250 // move client entry to free list
251 LinkedList1_Remove(&l->clients_used, &client->list_node);
252 LinkedList1_Append(&l->clients_free, &client->list_node);
253  
254 // give the socket to the handler
255 pw_entry->handler_client(pw_entry->user, client->sock);
256 return;
257 }
258  
259 int PasswordListener_Init (PasswordListener *l, BReactor *bsys, BThreadWorkDispatcher *twd, BAddr listen_addr, int max_clients, int ssl, int ssl_flags, CERTCertificate *cert, SECKEYPrivateKey *key)
260 {
261 ASSERT(BConnection_AddressSupported(listen_addr))
262 ASSERT(max_clients > 0)
263 ASSERT(ssl == 0 || ssl == 1)
264  
265 // init arguments
266 l->bsys = bsys;
267 l->twd = twd;
268 l->ssl = ssl;
269 l->ssl_flags = ssl_flags;
270  
271 // allocate client entries
272 if (!(l->clients_data = (struct PasswordListenerClient *)BAllocArray(max_clients, sizeof(struct PasswordListenerClient)))) {
273 BLog(BLOG_ERROR, "BAllocArray failed");
274 goto fail0;
275 }
276  
277 if (l->ssl) {
278 // initialize model SSL fd
279 DummyPRFileDesc_Create(&l->model_dprfd);
280 if (!(l->model_prfd = SSL_ImportFD(NULL, &l->model_dprfd))) {
281 BLog(BLOG_ERROR, "SSL_ImportFD failed");
282 ASSERT_FORCE(PR_Close(&l->model_dprfd) == PR_SUCCESS)
283 goto fail1;
284 }
285  
286 // set server certificate
287 if (SSL_ConfigSecureServer(l->model_prfd, cert, key, NSS_FindCertKEAType(cert)) != SECSuccess) {
288 BLog(BLOG_ERROR, "SSL_ConfigSecureServer failed");
289 goto fail2;
290 }
291 }
292  
293 // initialize client entries
294 LinkedList1_Init(&l->clients_free);
295 LinkedList1_Init(&l->clients_used);
296 for (int i = 0; i < max_clients; i++) {
297 struct PasswordListenerClient *conn = &l->clients_data[i];
298 conn->l = l;
299 LinkedList1_Append(&l->clients_free, &conn->list_node);
300 }
301  
302 // initialize passwords tree
303 BAVL_Init(&l->passwords, OFFSET_DIFF(PasswordListener_pwentry, password, tree_node), (BAVL_comparator)password_comparator, NULL);
304  
305 // initialize listener
306 if (!BListener_Init(&l->listener, listen_addr, l->bsys, l, (BListener_handler)listener_handler)) {
307 BLog(BLOG_ERROR, "Listener_Init failed");
308 goto fail2;
309 }
310  
311 DebugObject_Init(&l->d_obj);
312 return 1;
313  
314 // cleanup
315 fail2:
316 if (l->ssl) {
317 ASSERT_FORCE(PR_Close(l->model_prfd) == PR_SUCCESS)
318 }
319 fail1:
320 BFree(l->clients_data);
321 fail0:
322 return 0;
323 }
324  
325 void PasswordListener_Free (PasswordListener *l)
326 {
327 DebugObject_Free(&l->d_obj);
328  
329 // free clients
330 LinkedList1Node *node;
331 while (node = LinkedList1_GetFirst(&l->clients_used)) {
332 struct PasswordListenerClient *client = UPPER_OBJECT(node, struct PasswordListenerClient, list_node);
333 remove_client(client);
334 }
335  
336 // free listener
337 BListener_Free(&l->listener);
338  
339 // free model SSL file descriptor
340 if (l->ssl) {
341 ASSERT_FORCE(PR_Close(l->model_prfd) == PR_SUCCESS)
342 }
343  
344 // free client entries
345 BFree(l->clients_data);
346 }
347  
348 uint64_t PasswordListener_AddEntry (PasswordListener *l, PasswordListener_pwentry *entry, PasswordListener_handler_client handler_client, void *user)
349 {
350 DebugObject_Access(&l->d_obj);
351  
352 while (1) {
353 // generate password
354 BRandom_randomize((uint8_t *)&entry->password, sizeof(entry->password));
355  
356 // try inserting
357 if (BAVL_Insert(&l->passwords, &entry->tree_node, NULL)) {
358 break;
359 }
360 }
361  
362 entry->handler_client = handler_client;
363 entry->user = user;
364  
365 return entry->password;
366 }
367  
368 void PasswordListener_RemoveEntry (PasswordListener *l, PasswordListener_pwentry *entry)
369 {
370 DebugObject_Access(&l->d_obj);
371  
372 // remove
373 BAVL_Remove(&l->passwords, &entry->tree_node);
374 }