/* * @brief Reloads the scanner if a reload was requested. */ static void check_and_reload () { if (reload != 0) { proctitle_set ("openvassd: Reloading"); reload_openvassd (); proctitle_set ("openvassd: Waiting for incoming connections"); } }
/* * @brief Starts a process to handle client requests while the scanner is * loading. * * @return process id of loading handler. */ static pid_t loading_handler_start () { pid_t child_pid; init_loading_shm (); child_pid = fork (); if (child_pid != 0) return child_pid; proctitle_set ("openvassd (Loading Handler)"); openvas_signal (SIGTERM, sighand_loading_handler); /* * Forked process will handle client requests until parent stops it with * loading_handler_stop (). */ while (1) { unsigned int lg_address; struct sockaddr_in6 address6; int soc; if (loading_stop) break; lg_address = sizeof (struct sockaddr_in6); soc = accept (global_iana_socket, (struct sockaddr *) (&address6), &lg_address); loading_client_handle (soc); } exit (0); }
static void main_loop () { log_write ("openvassd %s started\n", OPENVASSD_VERSION); proctitle_set ("openvassd: Waiting for incoming connections"); for (;;) { int soc; int family; unsigned int lg_address; struct sockaddr_in6 address6; struct sockaddr_in6 *p_addr; struct arglist *globals; struct addrinfo *ai; check_and_reload (); wait_for_children1 (); ai = arg_get_value (g_options, "addr"); lg_address = sizeof (struct sockaddr_in6); soc = accept (global_iana_socket, (struct sockaddr *) (&address6), &lg_address); if (soc == -1) continue; /* * MA: you cannot share an open SSL connection through fork/multithread * The SSL connection shall be open _after_ the fork */ globals = emalloc (sizeof (struct arglist)); arg_add_value (globals, "global_socket", ARG_INT, -1, GSIZE_TO_POINTER (soc)); arg_add_value (globals, "plugins", ARG_ARGLIST, -1, global_plugins); arg_add_value (globals, "preferences", ARG_ARGLIST, -1, global_preferences); p_addr = emalloc (sizeof (struct sockaddr_in6)); family = ai->ai_family; memcpy (p_addr, &address6, sizeof (address6)); arg_add_value (globals, "client_address", ARG_PTR, -1, p_addr); arg_add_value (globals, "family", ARG_INT, -1, GSIZE_TO_POINTER (family)); /* we do not want to create an io thread, yet so the last argument is -1 */ if (create_process ((process_func_t) scanner_thread, globals) < 0) { log_write ("Could not fork - client won't be served"); sleep (2); } close (soc); arg_free (globals); } }
static void monitor_daemon(pid_t daemon_pid) { /* XXX Should log daemon's stderr output at startup time. */ time_t last_restart; char *status_msg; int crashes; set_subprogram_name("monitor"); status_msg = xstrdup("healthy"); last_restart = TIME_MIN; crashes = 0; for (;;) { int retval; int status; proctitle_set("monitoring pid %lu (%s)", (unsigned long int) daemon_pid, status_msg); do { retval = waitpid(daemon_pid, &status, 0); } while (retval == -1 && errno == EINTR); if (retval == -1) { VLOG_FATAL("waitpid failed (%s)", ovs_strerror(errno)); } else if (retval == daemon_pid) { char *s = process_status_msg(status); if (should_restart(status)) { free(status_msg); status_msg = xasprintf("%d crashes: pid %lu died, %s", ++crashes, (unsigned long int) daemon_pid, s); free(s); if (WCOREDUMP(status)) { /* Disable further core dumps to save disk space. */ struct rlimit r; r.rlim_cur = 0; r.rlim_max = 0; if (setrlimit(RLIMIT_CORE, &r) == -1) { VLOG_WARN("failed to disable core dumps: %s", ovs_strerror(errno)); } } /* Throttle restarts to no more than once every 10 seconds. */ if (time(NULL) < last_restart + 10) { VLOG_WARN("%s, waiting until 10 seconds since last " "restart", status_msg); for (;;) { time_t now = time(NULL); time_t wakeup = last_restart + 10; if (now >= wakeup) { break; } xsleep(wakeup - now); } } last_restart = time(NULL); VLOG_ERR("%s, restarting", status_msg); daemon_pid = fork_and_wait_for_startup(&daemonize_fd); if (!daemon_pid) { break; } } else { VLOG_INFO("pid %lu died, %s, exiting", (unsigned long int) daemon_pid, s); free(s); exit(0); } } } free(status_msg); /* Running in new daemon process. */ proctitle_restore(); set_subprogram_name(""); }
/** * @brief Attack one host. */ static void attack_host (struct arglist *globals, struct arglist *hostinfos, char *hostname, plugins_scheduler_t sched) { /* Used for the status */ int num_plugs = 0; int cur_plug = 1; kb_t kb; gboolean new_kb = FALSE; int forks_retry = 0; struct arglist *plugins = arg_get_value (globals, "plugins"); struct arglist *tmp; proctitle_set ("openvassd: testing %s", arg_get_value (hostinfos, "NAME")); kb = init_host_kb (globals, hostname, hostinfos, &new_kb); num_plugs = get_active_plugins_number (plugins); tmp = emalloc (sizeof (struct arglist)); arg_add_value (tmp, "HOSTNAME", ARG_ARGLIST, -1, hostinfos); /* launch the plugins */ pluginlaunch_init (globals); for (;;) { struct scheduler_plugin *plugin; pid_t parent; /* Check that our father is still alive */ parent = getppid (); if (parent <= 1 || process_alive (parent) == 0) { pluginlaunch_stop (); return; } /* Idle if the scan has been paused. */ if (pause_whole_test) { /* Let the running NVTs complete. */ pluginlaunch_wait (); /* Send the PAUSE status to the client. */ if (comm_send_status (globals, hostname, "pause", cur_plug, num_plugs) < 0) { pluginlaunch_stop (); goto host_died; } /* Wait for resume. */ while (pause_whole_test) sleep (1); /* Send the RESUME status to the client. */ if (comm_send_status (globals, hostname, "resume", cur_plug, num_plugs) < 0) { pluginlaunch_stop (); goto host_died; } } plugin = plugins_scheduler_next (sched); if (plugin != NULL && plugin != PLUG_RUNNING) { int e; again: e = launch_plugin (globals, sched, plugin, hostname, &cur_plug, num_plugs, hostinfos, kb, new_kb); if (e < 0) { /* * Remote host died */ if (e == ERR_HOST_DEAD) goto host_died; else if (e == ERR_CANT_FORK) { if (forks_retry < MAX_FORK_RETRIES) { forks_retry++; log_write ("fork() failed - sleeping %d seconds (%s)", forks_retry, strerror (errno)); fork_sleep (forks_retry); goto again; } else { log_write ("fork() failed too many times - aborting"); goto host_died; } } } } else if (plugin == NULL) break; else pluginlaunch_wait_for_free_process (); } pluginlaunch_wait (); host_died: comm_send_status (globals, hostname, "attack", num_plugs, num_plugs); arg_free (tmp); pluginlaunch_stop (); plugins_scheduler_free (sched); gchar *network_scan_status = arg_get_value (globals, "network_scan_status"); if (network_scan_status != NULL) { if (g_ascii_strcasecmp (network_scan_status, "busy") == 0) { save_kb_close (globals, "network"); } } else if (new_kb == TRUE) save_kb_close (globals, hostname); }
static void scanner_thread (struct arglist *globals) { struct arglist *prefs = arg_get_value (globals, "preferences"); char asciiaddr[INET6_ADDRSTRLEN], x509_dname[512] = { '\0' }; int opt = 1, soc2 = -1, nice_retval, family, soc; void *addr = arg_get_value (globals, "client_address"); struct sockaddr_in *saddr = NULL; struct sockaddr_in6 *s6addr = NULL; family = GPOINTER_TO_SIZE (arg_get_value (globals, "family")); soc = GPOINTER_TO_SIZE (arg_get_value (globals, "global_socket")); if (family == AF_INET) { saddr = (struct sockaddr_in *) addr; inet_ntop (AF_INET, &saddr->sin_addr, asciiaddr, sizeof(asciiaddr)); } else { s6addr = (struct sockaddr_in6 *) addr; inet_ntop (AF_INET6, &s6addr->sin6_addr, asciiaddr, sizeof (asciiaddr)); } proctitle_set ("openvassd: Serving %s", asciiaddr); /* Everyone runs with a nicelevel of 10 */ if (preferences_benice (prefs)) { errno = 0; nice_retval = nice (10); if (nice_retval == -1 && errno != 0) { log_write ("Unable to renice process: %d", errno); } } /* Close the scanner thread - it is useless for us now */ close (global_iana_socket); soc2 = ovas_scanner_context_attach (ovas_scanner_ctx, soc); if (soc2 < 0) goto shutdown_and_exit; /* FIXME: The pre-gnutls code optionally printed information about * the peer's certificate at this point. */ setsockopt (soc, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof (opt)); /* arg_set_value *replaces* an existing value, but it shouldn't fail here */ (void) arg_set_value (globals, "global_socket", -1, GSIZE_TO_POINTER (soc2)); if (comm_init (soc2) < 0) { close_stream_connection (soc); exit (0); } /* Get X.509 cert subject name */ if (get_x509_dname (soc2, x509_dname, sizeof (x509_dname)) != 0) goto shutdown_and_exit; if (!check_client (x509_dname)) { auth_printf (globals, "Bad login attempt !\n"); log_write ("bad login attempt from %s\n", asciiaddr); goto shutdown_and_exit; } handle_client (globals); shutdown_and_exit: if (soc2 >= 0) close_stream_connection (soc2); else { shutdown (soc, 2); close (soc); } /* Kill left overs */ end_daemon_mode (); exit (0); }