1 /* Copyright (C) 2009-2020 Greenbone Networks GmbH
2 *
3 * SPDX-License-Identifier: AGPL-3.0-or-later
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as
7 * published by the Free Software Foundation, either version 3 of the
8 * License, or (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 Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /**
20 * @file gmpd.c
21 * @brief The Greenbone Vulnerability Manager GMP daemon.
22 *
23 * This file defines the Greenbone Vulnerability Manager daemon. The Manager
24 * serves the Greenbone Management Protocol (GMP) to clients such as the
25 * Greenbone Security Assistant (GSA). The Manager and GMP give clients full
26 * access to an OpenVAS Scanner.
27 *
28 * The library provides two functions: \ref init_gmpd and \ref serve_gmp.
29 * \ref init_gmpd initialises the daemon.
30 * \ref serve_gmp serves GMP to a single client socket until end of file is
31 * reached on the socket.
32 */
33
34 #include "gmpd.h"
35 #include "gmp.h"
36
37 #include <assert.h>
38 #include <dirent.h>
39 #include <errno.h>
40 #include <string.h>
41 #include <sys/select.h>
42 #include <sys/socket.h>
43 #include <sys/time.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <unistd.h>
47
48 #include <gvm/util/serverutils.h>
49
50 #if FROM_BUFFER_SIZE > SSIZE_MAX
51 #error FROM_BUFFER_SIZE too big for "read"
52 #endif
53
54 #undef G_LOG_DOMAIN
55 /**
56 * @brief GLib log domain.
57 */
58 #define G_LOG_DOMAIN "md main"
59
60 /**
61 * @brief Buffer of input from the client.
62 */
63 char from_client[FROM_BUFFER_SIZE];
64
65 /**
66 * @brief Size of \ref from_client data buffer, in bytes.
67 */
68 buffer_size_t from_buffer_size = FROM_BUFFER_SIZE;
69
70 /**
71 * @brief The start of the data in the \ref from_client buffer.
72 */
73 buffer_size_t from_client_start = 0;
74
75 /**
76 * @brief The end of the data in the \ref from_client buffer.
77 */
78 buffer_size_t from_client_end = 0;
79
80 /**
81 * @brief Initialise the GMP library for the GMP daemon.
82 *
83 * @param[in] log_config Log configuration
84 * @param[in] database Location of manage database.
85 * @param[in] max_ips_per_target Max number of IPs per target.
86 * @param[in] max_email_attachment_size Max size of email attachments.
87 * @param[in] max_email_include_size Max size of email inclusions.
88 * @param[in] max_email_message_size Max size of email user message text.
89 * @param[in] fork_connection Function to fork a connection to the GMP
90 * daemon layer, or NULL.
91 * @param[in] skip_db_check Skip DB check.
92 *
93 * @return 0 success, -1 error, -2 database is wrong version,
94 * -4 max_ips_per_target out of range.
95 */
96 int
init_gmpd(GSList * log_config,const db_conn_info_t * database,int max_ips_per_target,int max_email_attachment_size,int max_email_include_size,int max_email_message_size,manage_connection_forker_t fork_connection,int skip_db_check)97 init_gmpd (GSList *log_config, const db_conn_info_t *database,
98 int max_ips_per_target, int max_email_attachment_size,
99 int max_email_include_size, int max_email_message_size,
100 manage_connection_forker_t fork_connection, int skip_db_check)
101 {
102 return init_gmp (log_config, database, max_ips_per_target,
103 max_email_attachment_size, max_email_include_size,
104 max_email_message_size,
105 fork_connection, skip_db_check);
106 }
107
108 /**
109 * @brief Initialise a process forked within the GMP daemon.
110 *
111 * @param[in] database Location of manage database.
112 * @param[in] disable Commands to disable.
113 */
114 void
init_gmpd_process(const db_conn_info_t * database,gchar ** disable)115 init_gmpd_process (const db_conn_info_t *database, gchar **disable)
116 {
117 from_client_start = 0;
118 from_client_end = 0;
119 init_gmp_process (database, NULL, NULL, disable);
120 }
121
122 /**
123 * @brief Read as much from the client as the \ref from_client buffer will hold.
124 *
125 * @param[in] client_socket The socket.
126 *
127 * @return 0 on reading everything available, -1 on error, -2 if
128 * from_client buffer is full or -3 on reaching end of file.
129 */
130 static int
read_from_client_unix(int client_socket)131 read_from_client_unix (int client_socket)
132 {
133 while (from_client_end < from_buffer_size)
134 {
135 int count;
136 count = read (client_socket,
137 from_client + from_client_end,
138 from_buffer_size - from_client_end);
139 if (count < 0)
140 {
141 if (errno == EAGAIN)
142 /* Got everything available, return to `select'. */
143 return 0;
144 if (errno == EINTR)
145 /* Interrupted, try read again. */
146 continue;
147 g_warning ("%s: failed to read from client: %s",
148 __func__, strerror (errno));
149 return -1;
150 }
151 if (count == 0)
152 {
153 /* End of file. */
154
155 if (from_client_end)
156 /* There's still client input to process, so pretend we read
157 * something, to prevent serve_gmp from exiting.
158 *
159 * This should instead be dealt with in serve_gmp, but that function
160 * has got quite complex. */
161 return 0;
162
163 return -3;
164 }
165 from_client_end += count;
166 }
167
168 /* Buffer full. */
169 return -2;
170 }
171
172 /**
173 * @brief Read as much from the client as the \ref from_client buffer will hold.
174 *
175 * @param[in] client_session The TLS session with the client.
176 *
177 * @return 0 on reading everything available, -1 on error, -2 if
178 * from_client buffer is full or -3 on reaching end of file.
179 */
180 static int
read_from_client_tls(gnutls_session_t * client_session)181 read_from_client_tls (gnutls_session_t* client_session)
182 {
183 while (from_client_end < from_buffer_size)
184 {
185 ssize_t count;
186 count = gnutls_record_recv (*client_session,
187 from_client + from_client_end,
188 from_buffer_size - from_client_end);
189 if (count < 0)
190 {
191 if (count == GNUTLS_E_AGAIN)
192 /* Got everything available, return to `select'. */
193 return 0;
194 if (count == GNUTLS_E_INTERRUPTED)
195 /* Interrupted, try read again. */
196 continue;
197 if (count == GNUTLS_E_REHANDSHAKE)
198 {
199 /** @todo Rehandshake. */
200 g_debug (" should rehandshake");
201 continue;
202 }
203 if (gnutls_error_is_fatal ((int) count) == 0
204 && (count == GNUTLS_E_WARNING_ALERT_RECEIVED
205 || count == GNUTLS_E_FATAL_ALERT_RECEIVED))
206 {
207 int alert = gnutls_alert_get (*client_session);
208 const char* alert_name = gnutls_alert_get_name (alert);
209 g_warning ("%s: TLS Alert %d: %s",
210 __func__, alert, alert_name);
211 }
212 g_warning ("%s: failed to read from client: %s",
213 __func__, gnutls_strerror ((int) count));
214 return -1;
215 }
216 if (count == 0)
217 {
218 /* End of file. */
219
220 if (from_client_end)
221 /* There's still client input to process, so pretend we read
222 * something, to prevent serve_gmp from exiting.
223 *
224 * This should instead be dealt with in serve_gmp, but that function
225 * has got quite complex. */
226 return 0;
227
228 return -3;
229 }
230 from_client_end += count;
231 }
232
233 /* Buffer full. */
234 return -2;
235 }
236
237 /**
238 * @brief Read as much from the client as the \ref from_client buffer will hold.
239 *
240 * @param[in] client_connection The connection with the client.
241 *
242 * @return 0 on reading everything available, -1 on error, -2 if
243 * from_client buffer is full or -3 on reaching end of file.
244 */
245 static int
read_from_client(gvm_connection_t * client_connection)246 read_from_client (gvm_connection_t *client_connection)
247 {
248 if (client_connection->tls)
249 return read_from_client_tls (&client_connection->session);
250 return read_from_client_unix (client_connection->socket);
251 }
252
253 /** @todo Move to openvas-libraries? */
254 /**
255 * @brief Write as much as possible from \ref to_client to the client.
256 *
257 * @param[in] client_session The client session.
258 *
259 * @return 0 wrote everything, -1 error, -2 wrote as much as client accepted.
260 */
261 static int
write_to_client_tls(gnutls_session_t * client_session)262 write_to_client_tls (gnutls_session_t* client_session)
263 {
264 while (to_client_start < to_client_end)
265 {
266 ssize_t count;
267 count = gnutls_record_send (*client_session,
268 to_client + to_client_start,
269 to_client_end - to_client_start);
270 if (count < 0)
271 {
272 if (count == GNUTLS_E_AGAIN)
273 /* Wrote as much as client would accept. */
274 return -2;
275 if (count == GNUTLS_E_INTERRUPTED)
276 /* Interrupted, try write again. */
277 continue;
278 if (count == GNUTLS_E_REHANDSHAKE)
279 /** @todo Rehandshake. */
280 continue;
281 g_warning ("%s: failed to write to client: %s",
282 __func__,
283 gnutls_strerror ((int) count));
284 return -1;
285 }
286 to_client_start += count;
287 g_debug ("=> client %u bytes", (unsigned int) count);
288 }
289 g_debug ("=> client done");
290 to_client_start = to_client_end = 0;
291
292 /* Wrote everything. */
293 return 0;
294 }
295
296 /**
297 * @brief Write as much as possible from \ref to_client to the client.
298 *
299 * @param[in] client_socket The client socket.
300 *
301 * @return 0 wrote everything, -1 error, -2 wrote as much as client accepted.
302 */
303 static int
write_to_client_unix(int client_socket)304 write_to_client_unix (int client_socket)
305 {
306 while (to_client_start < to_client_end)
307 {
308 ssize_t count;
309 count = write (client_socket,
310 to_client + to_client_start,
311 to_client_end - to_client_start);
312 if (count < 0)
313 {
314 if (errno == EAGAIN)
315 /* Wrote as much as client would accept. */
316 return -2;
317 if (errno == EINTR)
318 /* Interrupted, try write again. */
319 continue;
320 g_warning ("%s: failed to write to client: %s",
321 __func__,
322 strerror (errno));
323 return -1;
324 }
325 to_client_start += count;
326 g_debug ("=> client %u bytes", (unsigned int) count);
327 }
328 g_debug ("=> client done");
329 to_client_start = to_client_end = 0;
330
331 /* Wrote everything. */
332 return 0;
333 }
334
335 /**
336 * @brief Write as much as possible from \ref to_client to the client.
337 *
338 * @param[in] client_connection The client connection.
339 *
340 * @return 0 wrote everything, -1 error, -2 wrote as much as client accepted.
341 */
342 static int
write_to_client(gvm_connection_t * client_connection)343 write_to_client (gvm_connection_t *client_connection)
344 {
345 if (client_connection->tls)
346 return write_to_client_tls (&client_connection->session);
347 return write_to_client_unix (client_connection->socket);
348 }
349
350 /**
351 * @brief Send a response message to the client.
352 *
353 * Queue a message in \ref to_client.
354 *
355 * @param[in] msg The message, a string.
356 * @param[in] write_to_client_data Argument to \p write_to_client.
357 *
358 * @return TRUE if write to client failed, else FALSE.
359 */
360 static gboolean
gmpd_send_to_client(const char * msg,void * write_to_client_data)361 gmpd_send_to_client (const char* msg, void* write_to_client_data)
362 {
363 assert (to_client_end <= TO_CLIENT_BUFFER_SIZE);
364 assert (msg);
365
366 while (((buffer_size_t) TO_CLIENT_BUFFER_SIZE) - to_client_end
367 < strlen (msg))
368 {
369 buffer_size_t length;
370
371 /* Too little space in to_client buffer for message. */
372
373 switch (write_to_client (write_to_client_data))
374 {
375 case 0: /* Wrote everything in to_client. */
376 break;
377 case -1: /* Error. */
378 g_debug (" %s full (%i < %zu); client write failed",
379 __func__,
380 ((buffer_size_t) TO_CLIENT_BUFFER_SIZE) - to_client_end,
381 strlen (msg));
382 return TRUE;
383 case -2: /* Wrote as much as client was willing to accept. */
384 break;
385 default: /* Programming error. */
386 assert (0);
387 }
388
389 length = ((buffer_size_t) TO_CLIENT_BUFFER_SIZE) - to_client_end;
390
391 if (length > strlen (msg))
392 break;
393
394 /* length can be 0 if write_to_client returns -2. */
395
396 if (length > 0)
397 {
398 memmove (to_client + to_client_end, msg, length);
399 g_debug ("-> client: %.*s", (int) length, msg);
400 to_client_end += length;
401 msg += length;
402 }
403 }
404
405 if (strlen (msg))
406 {
407 assert (strlen (msg)
408 <= (((buffer_size_t) TO_CLIENT_BUFFER_SIZE) - to_client_end));
409 memmove (to_client + to_client_end, msg, strlen (msg));
410 g_debug ("-> client: %s", msg);
411 to_client_end += strlen (msg);
412 }
413
414 return FALSE;
415 }
416
417 /**
418 * @brief Get nfds value.
419 *
420 * @param[in] socket Highest socket number.
421 *
422 * @return nfds value for select.
423 */
424 static int
get_nfds(int socket)425 get_nfds (int socket)
426 {
427 return 1 + socket;
428 }
429
430 /**
431 * @brief Serve the Greenbone Management Protocol (GMP).
432 *
433 * Loop reading input from the sockets, processing
434 * the input, and writing any results to the appropriate socket.
435 * Exit the loop on reaching end of file on the client socket.
436 *
437 * Read input from the client.
438 * Process the input with \ref process_gmp_client_input. Write the results
439 * to the client.
440 *
441 * \if STATIC
442 *
443 * Read input with \ref read_from_client.
444 * Write the results with \ref write_to_client.
445 *
446 * \endif
447 *
448 * @param[in] client_connection Connection.
449 * @param[in] database Location of manage database.
450 * @param[in] disable Commands to disable.
451 *
452 * @return 0 success, -1 error.
453 */
454 int
serve_gmp(gvm_connection_t * client_connection,const db_conn_info_t * database,gchar ** disable)455 serve_gmp (gvm_connection_t *client_connection, const db_conn_info_t *database,
456 gchar **disable)
457 {
458 int nfds, rc = 0;
459
460 g_debug (" Serving GMP");
461
462 /* Initialise the XML parser and the manage library. */
463 init_gmp_process (database,
464 (int (*) (const char*, void*)) gmpd_send_to_client,
465 (void*) client_connection,
466 disable);
467
468 /** @todo Confirm and clarify complications, especially last one. */
469 /* Loop handling input from the sockets.
470 *
471 * That is, select on all the socket fds and then, as necessary
472 * - read from the client into buffer from_client
473 * - write to the client from buffer to_client.
474 *
475 * On reading from an fd, immediately try react to the input. On reading
476 * from the client call process_gmp_client_input, which parses GMP
477 * commands and may write to to_client.
478 *
479 * There are a few complications here
480 * - the program must read from or write to an fd returned by select
481 * before selecting on the fd again,
482 * - the program need only select on the fds for writing if there is
483 * something to write,
484 * - similarly, the program need only select on the fds for reading
485 * if there is buffer space available,
486 * - the buffer from_client can become full during reading
487 * - a read from the client can be stalled by the to_client buffer
488 * filling up (in which case process_gmp_client_input will try to
489 * write the to_client buffer itself),
490 */
491
492 nfds = get_nfds (client_connection->socket);
493 while (1)
494 {
495 int ret;
496 fd_set readfds, writefds;
497
498 /* Setup for select. */
499
500 /** @todo nfds must only include a socket if it's in >= one set. */
501
502 FD_ZERO (&readfds);
503 FD_ZERO (&writefds);
504
505 /** @todo Shutdown on failure (for example, if a read fails). */
506
507 /* See whether to read from the client. */
508 if (from_client_end < from_buffer_size)
509 FD_SET (client_connection->socket, &readfds);
510 /* See whether to write to the client. */
511 if (to_client_start < to_client_end)
512 FD_SET (client_connection->socket, &writefds);
513
514 /* Select, then handle result. Due to GNUTLS internal buffering
515 * we test for pending records first and emulate a select call
516 * in that case. Note, that GNUTLS guarantees that writes are
517 * not buffered. Note also that GNUTLS versions < 3 did not
518 * exhibit a problem in Scanner due to a different buffering
519 * strategy. */
520 ret = 0;
521 if (client_connection->socket > 0
522 && client_connection->tls
523 && FD_ISSET (client_connection->socket, &readfds)
524 && gnutls_record_check_pending (client_connection->session))
525 {
526 FD_ZERO (&readfds);
527 FD_ZERO (&writefds);
528 ret++;
529 FD_SET (client_connection->socket, &readfds);
530 }
531
532 if (!ret)
533 ret = select (nfds, &readfds, &writefds, NULL, NULL);
534 if ((ret < 0 && errno == EINTR) || ret == 0)
535 continue;
536 if (ret < 0)
537 {
538 g_warning ("%s: child select failed: %s", __func__,
539 strerror (errno));
540 rc = -1;
541 goto client_free;
542 }
543
544 /* Read any data from the client. */
545 if (client_connection->socket > 0
546 && FD_ISSET (client_connection->socket, &readfds))
547 {
548 buffer_size_t initial_start = from_client_end;
549
550 switch (read_from_client (client_connection))
551 {
552 case 0: /* Read everything. */
553 break;
554 case -1: /* Error. */
555 rc = -1;
556 goto client_free;
557 case -2: /* from_client buffer full. */
558 /* There may be more to read. */
559 break;
560 case -3: /* End of file. */
561 g_debug (" EOF reading from client");
562 if (client_connection->socket > 0
563 && FD_ISSET (client_connection->socket, &writefds))
564 /* Write rest of to_client to client, so that the client gets
565 * any buffered output and the response to the error. */
566 write_to_client (client_connection);
567 rc = 0;
568 goto client_free;
569 default: /* Programming error. */
570 assert (0);
571 }
572
573 /* This check prevents output in the "asynchronous network
574 * error" case. */
575 if (from_client_end > initial_start)
576 {
577 if (g_strstr_len (from_client + initial_start,
578 from_client_end - initial_start,
579 "<password>"))
580 g_debug ("<= client Input may contain password, suppressed");
581 else
582 g_debug ("<= client \"%.*s\"",
583 from_client_end - initial_start,
584 from_client + initial_start);
585 }
586
587 ret = process_gmp_client_input ();
588 if (ret == 0)
589 /* Processed all input. */
590 ;
591 else if (ret == -1 || ret == -4)
592 {
593 /* Error. Write rest of to_client to client, so that the
594 * client gets any buffered output and the response to the
595 * error. */
596 write_to_client (client_connection);
597 rc = -1;
598 goto client_free;
599 }
600 else
601 {
602 /* Programming error. */
603 assert (0);
604 }
605 }
606
607 /* Write any data to the client. */
608 if (client_connection->socket > 0
609 && FD_ISSET (client_connection->socket, &writefds))
610 {
611 /* Write as much as possible to the client. */
612
613 switch (write_to_client (client_connection))
614 {
615 case 0: /* Wrote everything in to_client. */
616 break;
617 case -1: /* Error. */
618 rc = -1;
619 goto client_free;
620 case -2: /* Wrote as much as client was willing to accept. */
621 break;
622 default: /* Programming error. */
623 assert (0);
624 }
625 }
626 } /* while (1) */
627
628 client_free:
629 gvm_connection_free (client_connection);
630 return rc;
631 }
632