/* Nessus * Copyright (C) 1998 - 2001 Renaud Deraison * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, * as published by the Free Software Foundation * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * In addition, as a special exception, Renaud Deraison * gives permission to link the code of this program with any * version of the OpenSSL library which is distributed under a * license identical to that listed in the included COPYING.OpenSSL * file, and distribute linked combinations including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * this file, you may extend this exception to your version of the * file, but you are not obligated to do so. If you do not wish to * do so, delete this exception statement from your version. * */ #include #ifdef USE_GTK #include #include "backend.h" #include "nessus_plugin.h" #include "context.h" #include "preferences.h" #include "attack.h" #include "comm.h" #include "auth.h" #include "parser.h" #include "report.h" #include "globals.h" #include "error_dialog.h" #include "xpm/computer.xpm" #include "monitor_dialog.h" #include "nessus_i18n.h" #include "prefs_dialog/prefs_context.h" #include "prefs_dialog/prefs_scope_tree.h" static void monitor_input_callback(struct arglist *); static void monitor_add_host(struct arglist *, char *, int); static void monitor_stop_test(GtkWidget *, struct context *); static void monitor_list_update(struct arglist *, char *, int); static int monitor_stop_whole_test_destroy(void*, void*, struct arglist *); static int monitor_stop_whole_test(GtkWidget * , struct arglist *); static int is_server_present(soc) int soc; { fd_set rd; struct timeval tv = {2,0}; int fd = nessus_get_socket_from_connection(soc); if(fd < 0 || fd >= FD_SETSIZE) { fprintf(stderr, _("is_server_present: fd(%d) out of range\n"), fd); return 0; } FD_ZERO(&rd); FD_SET(fd, &rd); if(select(fd+1, &rd, NULL, NULL, &tv) > 0) { int len = -1; ioctl(fd, FIONREAD, &len); if(!len){ return 0; } } return 1; } /* * Function called when the UI is idle, which checks * whether the server sent us anything. We use this rather * than the traditional gdk input watcher, because it * works under Win32 */ static int idle_socket(struct arglist * ctrls) { fd_set rd; struct timeval tv = {0,100}; int n, soc; struct context * context = arg_get_value(ctrls, "CONTEXT"); if ( context == NULL ) return FALSE; if(context->socket < 0) { fprintf(stderr, "idle_socket: context->socket=%d\n", context->socket); return FALSE; } if ( stream_pending(context->socket) ) { monitor_input_callback(ctrls); return TRUE; } soc = nessus_get_socket_from_connection(context->socket); if((soc < 0) || (soc >= FD_SETSIZE)) { fprintf(stderr, _("idle_server: soc(%d) out of range\n"), soc); return -1; } FD_ZERO(&rd); FD_SET(soc, &rd); n = select(soc+1, &rd, NULL, NULL, &tv); if(FD_ISSET(soc, &rd)&& (n > 0)) monitor_input_callback(ctrls); return TRUE; } /* column IDs of scanner TreeView Model */ enum { COL_ICON, COL_HOSTNAME, COL_PORTSCAN, COL_CHECKS, NUM_COLS }; static void stop_toggled(cell, path_str, data) GtkCellRendererToggle *cell; gchar *path_str; gpointer data; { GtkListStore * store = arg_get_value(data, "MON_STORE"); struct context * context = arg_get_value(data, "CONTEXT"); GtkTreeIter iter; char * hostname; gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(store), &iter, path_str); gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, COL_HOSTNAME, &hostname, -1); network_printf(context->socket, "CLIENT <|> STOP_ATTACK <|> %s <|> CLIENT\n", hostname); } /* * monitor_dialog_setup * * This function draws the window which will * show the attack status */ void monitor_dialog_setup(char * victim, struct context * context) { struct arglist * ctrls = emalloc(sizeof(struct arglist)); GtkWindow* parent = arg_get_value(MainDialog, "CONTEXT"); GtkWidget * scrolled_window; GtkWidget * w, * box; char* window_title; const char* host_name; int tag; int backend = backend_init(NULL); /* Could not create a backend */ if( backend < 0 ) return; arg_add_value(ctrls, "MONITOR_BACKEND", ARG_INT, -1, (void*)backend); arg_add_value(ctrls, "PARENT", ARG_PTR, -1, parent); arg_add_value(ctrls, "CONTEXT", ARG_PTR, -1, context); context->action = CONTEXT_SCANNING; prefs_context_update(context); w = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_default_size(GTK_WINDOW(w), 640,480); /* TODO make the window non-modal * This can be done when context is kept for all called functions */ #if 0 gtk_window_set_modal(GTK_WINDOW(w), FALSE); gtk_window_set_transient_for(GTK_WINDOW(w), parent); arg_set_value(MainDialog, "CONTEXT", -1, w); #endif gtk_widget_realize(w); gtk_signal_connect(GTK_OBJECT(w), "delete_event", (GtkSignalFunc)monitor_stop_whole_test_destroy,ctrls); host_name = prefs_get_string(context, "nessusd_host"); if(host_name)window_title = emalloc(strlen(host_name) + 255); else window_title = emalloc(255); sprintf(window_title, _("Scanning network from %s"), host_name?host_name:_("some host")); gtk_window_set_title(GTK_WINDOW(w), window_title); efree(&window_title); gtk_container_border_width(GTK_CONTAINER(w), 10); arg_add_value(ctrls, "WINDOW", ARG_PTR, -1, w); gtk_widget_show(w); box = gtk_vbox_new(FALSE,10); gtk_container_add(GTK_CONTAINER(w), box); gtk_widget_show(box); { /* XXX: This is part of the MVC version */ GtkListStore * store; GtkCellRenderer * renderer; GtkTreeViewColumn * column; scrolled_window = gtk_scrolled_window_new (NULL, NULL); gtk_container_border_width (GTK_CONTAINER (scrolled_window), 10); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_container_border_width(GTK_CONTAINER(scrolled_window), 10); gtk_box_pack_start(GTK_BOX(box), scrolled_window, TRUE, TRUE, 0); store = gtk_list_store_new(NUM_COLS, GDK_TYPE_PIXBUF, G_TYPE_STRING, GTK_TYPE_INT, GTK_TYPE_INT); arg_add_value(ctrls, "MON_STORE", ARG_PTR, -1, store); w = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); /* The Icon column */ renderer = gtk_cell_renderer_pixbuf_new(); column = gtk_tree_view_column_new_with_attributes (NULL, renderer, "pixbuf", COL_ICON, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (w), column); /* The hostname column */ renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes (_("Hostname"), renderer, "text", COL_HOSTNAME, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (w), column); /* The port scan progress bar column */ renderer = gtk_cell_renderer_progress_new(); column = gtk_tree_view_column_new_with_attributes (_("Portscan"), renderer, "value", COL_PORTSCAN, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (w), column); /* The checks progress bar column */ renderer = gtk_cell_renderer_progress_new(); column = gtk_tree_view_column_new_with_attributes (_("Checks"), renderer, "value", COL_CHECKS, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (w), column); /* The stop action as toggle */ renderer = gtk_cell_renderer_toggle_new(); g_signal_connect(renderer, "toggled", G_CALLBACK(stop_toggled), ctrls); column = gtk_tree_view_column_new_with_attributes(_("Stop"), renderer, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW (w), column); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window), w); gtk_widget_show(w); gtk_widget_show (scrolled_window); } scrolled_window = gtk_scrolled_window_new (NULL, NULL); gtk_container_border_width (GTK_CONTAINER (scrolled_window), 10); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_container_border_width(GTK_CONTAINER(scrolled_window), 10); gtk_box_pack_start(GTK_BOX(box), scrolled_window, TRUE, TRUE, 0); w = gtk_list_new(); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window), w); gtk_widget_show(w); gtk_widget_show (scrolled_window); arg_add_value(ctrls, "LIST", ARG_PTR, -1, w); tag = gtk_idle_add((GtkFunction)idle_socket, ctrls); arg_add_value(ctrls, "TAG", ARG_INT, sizeof(int), (void*)tag); w = gtk_button_new_with_label(_("Stop the whole test")); gtk_signal_connect(GTK_OBJECT(w), "clicked", (GtkSignalFunc)monitor_stop_whole_test,ctrls); gtk_box_pack_start(GTK_BOX(box), w, FALSE, TRUE, 0); gtk_widget_show(w); if(!attack_host(victim, context)) { gtk_widget_hide(arg_get_value(ctrls, "WINDOW")); gtk_idle_remove(tag); gtk_widget_destroy(arg_get_value(ctrls, "WINDOW")); #if 0 arg_set_value(MainDialog, "CONTEXT", -1, parent); #endif prefs_context_update(context); scopetreeview_connected_update(context); } } /* * monitor_list_update * * Updates the progress bars */ static void monitor_list_update(ctrls,msg, short_status) struct arglist * ctrls; char * msg; int short_status; { char * hostname; char * action; char* current = NULL; int max; gfloat gmax; gfloat gcurrent; GList * dlist; GtkObject * item; GtkWidget * gtkw; char * list_hostname; int flag = 0; static harglst * hosts = NULL; int v = 1; if(!hosts) { hosts = harg_create(65000); } if(!short_status) parse_nessusd_status(msg, &hostname, &action, ¤t, &max); else parse_nessusd_short_status(msg, &hostname, &action, ¤t, &max); if(hostname) { v = harg_get_int(hosts, hostname); if(!v){ harg_add_int(hosts, hostname, 1); v = 1; } else { v++; harg_set_int(hosts, hostname, v); } } { /* XXX: This is part of the MVC version */ GtkListStore * store = arg_get_value(ctrls, "MON_STORE"); GtkTreeIter iter; int f = (atoi(current) * 100) / max; if(f>=100)f=100; if(f<=0)f=0; if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) { do { gtk_tree_model_get (GTK_TREE_MODEL(store), &iter, COL_HOSTNAME, &list_hostname, -1); if(!list_hostname){ fprintf(stderr, _("Error ! Null hostname in the list\n")); return; } if (!strcmp(list_hostname, hostname)) { if( strcmp(action, "portscan") == 0 ) gtk_list_store_set(store, &iter, COL_PORTSCAN, f, -1); else gtk_list_store_set(store, &iter, COL_CHECKS, f, -1); /* flag = 1; activate only if old progress below gets removed */ break; } } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter)); } } gtkw = arg_get_value(ctrls, "LIST"); dlist = GTK_LIST(gtkw)->children; while(dlist && !flag) { item = GTK_OBJECT(dlist->data); list_hostname = gtk_object_get_data(item, "hostname"); if(!list_hostname){ fprintf(stderr, _("Error ! Null hostname in the list\n")); /*exit(1);*/ return; } if(!strcmp(list_hostname, hostname)) { GtkWidget * progress_bar; gfloat f; if( strcmp(action, "portscan") == 0 ) progress_bar = gtk_object_get_data(item, "progress_bar_portscan"); else progress_bar = gtk_object_get_data(item, "progress_bar_attack"); gmax = max; gcurrent = atoi(current); f = (gcurrent/gmax); if(f>=1.0)f=1.0; if(f<=0.0)f=0.0; gtk_progress_bar_update (GTK_PROGRESS_BAR(progress_bar), f); flag = 1; } dlist = dlist->next; } if(!flag) { /* the host was not found, we must add one... */ monitor_add_host(ctrls, estrdup(hostname), atoi(current)); } efree(&hostname); efree(&action); if(current)efree(¤t); } /* * monitor_remove_host */ static void monitor_remove_host(ctrls, host) struct arglist * ctrls; char * host; { GtkWidget * item; GList * list = NULL; item = gtk_object_get_data(GTK_OBJECT(arg_get_value(ctrls, "LIST")),host); if(!item){ /* * If this happens, then it's very likely that the server * thinks the communication has been cut between the client * and itself. Which is not a good thing. */ return; } if(item != (void*)-1) { list = g_list_append(list, item); gtk_list_remove_items(GTK_LIST(arg_get_value(ctrls, "LIST")), list); gtk_object_remove_data(GTK_OBJECT(arg_get_value(ctrls, "LIST")), host); g_list_free(list); } { /* XXX: This is part of the MVC version */ GtkListStore * store = arg_get_value(ctrls, "MON_STORE"); GtkTreeIter iter; char * list_hostname; if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) { do { gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, COL_HOSTNAME, &list_hostname, -1); if (!strcmp(list_hostname, host)) { gtk_list_store_remove(store, &iter); break; } } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter)); } } } /* * monitor_add_host * * this function adds a new hostname and progress bar in * the monitor window */ void monitor_add_host(ctrls,hostname,port) struct arglist * ctrls; char * hostname; int port; { GtkWidget * progress_bar_portscan; GtkWidget * progress_bar_attack; GtkWidget * table; GtkWidget * label; GtkWidget * item; GtkWidget * button; GtkWidget * separator; GtkWidget * box, * hbox; GdkPixbuf *pixbuf; GtkWidget *img; GList * dlist; GtkWidget * window = arg_get_value(ctrls,"WINDOW"); struct context * context = arg_get_value(ctrls, "CONTEXT"); item = gtk_list_item_new(); dlist = NULL; table = gtk_table_new(4, 3, FALSE); gtk_table_set_col_spacings(GTK_TABLE(table), 15); gtk_table_set_row_spacings(GTK_TABLE(table), 5); gtk_container_add(GTK_CONTAINER(item), table); hbox = gtk_hbox_new(FALSE,0); gtk_widget_show(hbox); gtk_table_attach_defaults(GTK_TABLE(table), hbox, 0,1,0,3); /* * Host name */ box = gtk_vbox_new(TRUE,0); gtk_widget_show(box); gtk_box_pack_start(GTK_BOX(hbox), box, FALSE, FALSE, 0); if(F_show_pixmaps) { pixbuf = gdk_pixbuf_new_from_xpm_data((const char **)computer_xpm); img = gtk_image_new_from_pixbuf(pixbuf); gtk_box_pack_start(GTK_BOX(box), img, FALSE, FALSE, 0); gtk_widget_show(img); } label = gtk_label_new(hostname); gtk_object_set_data(GTK_OBJECT(item), "label", label); gtk_widget_set_usize(label, 150, 15); gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0); gtk_widget_show(label); /* * Portscan, Attack and Plugin labels */ box = gtk_vbox_new(TRUE, 0); gtk_widget_show(box); gtk_box_pack_end(GTK_BOX(hbox), box, FALSE, FALSE, 0); label = gtk_label_new(_("Portscan:")); gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0); gtk_widget_show(label); label = gtk_label_new(_("Checks:")); gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0); gtk_widget_show(label); /* * Progress bars */ box = gtk_vbox_new(FALSE,0); gtk_table_attach_defaults(GTK_TABLE(table), box, 1,2,0,3); gtk_widget_show(box); progress_bar_portscan = gtk_progress_bar_new(); /* gtk_table_attach_defaults(GTK_TABLE(table),progress_bar_portscan, 1,2,0,1); */ gtk_box_pack_start(GTK_BOX(box), progress_bar_portscan, TRUE, TRUE,0); gtk_widget_show(progress_bar_portscan); progress_bar_attack = gtk_progress_bar_new(); /* gtk_table_attach_defaults(GTK_TABLE(table),progress_bar_attack, 1,2,1,2); */ gtk_box_pack_start(GTK_BOX(box), progress_bar_attack, TRUE, TRUE,0); gtk_widget_show(progress_bar_attack); /* * Stop button */ box = gtk_vbox_new(TRUE,0); gtk_table_attach_defaults(GTK_TABLE(table), box, 2,3,0,2); gtk_widget_show(box); button = gtk_button_new_with_label(_("Stop")); gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc)monitor_stop_test, context); gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0); gtk_object_set_data(GTK_OBJECT(button), "hostname", hostname); gtk_widget_show(button); separator = gtk_hseparator_new(); gtk_table_attach_defaults(GTK_TABLE(table), separator, 0,3,3,4); gtk_widget_show(separator); gtk_object_set_data(GTK_OBJECT(item), "hostname", hostname); gtk_object_set_data(GTK_OBJECT(item), "progress_bar_attack", progress_bar_attack); gtk_object_set_data(GTK_OBJECT(item), "progress_bar_portscan", progress_bar_portscan); gtk_widget_show(table); gtk_widget_show(item); dlist = g_list_append(dlist, item); gtk_object_set_data(GTK_OBJECT(arg_get_value(ctrls, "LIST")), hostname,item); gtk_list_append_items(GTK_LIST(arg_get_value(ctrls, "LIST")), dlist); { /* XXX: This is part of the MVC version */ GtkListStore * store = arg_get_value(ctrls, "MON_STORE"); GtkTreeIter iter; GdkPixbuf *pixbuf = gdk_pixbuf_new_from_xpm_data((const char **)computer_xpm); gtk_list_store_append(store, &iter); /* Acquire an iterator */ gtk_list_store_set(store, &iter, COL_ICON, pixbuf, COL_HOSTNAME, hostname, COL_PORTSCAN, 0, COL_CHECKS, 0, -1); } } /* * monitor_stop_test * * This function will stop the connection between * nessusd and the client, and will report the results * to the screen */ static int monitor_stop_whole_test_destroy(a,b,ctrls) void * a, * b; struct arglist * ctrls; { return monitor_stop_whole_test(NULL, ctrls); } static int monitor_stop_whole_test(w, ctrls) GtkWidget * w; struct arglist * ctrls; { int type = 0, n; char * msg; char buf[32768]; struct context * context; GtkWindow* parent = arg_get_value(ctrls, "PARENT"); context = arg_get_value(ctrls, "CONTEXT"); network_printf(context->socket, "CLIENT <|> STOP_WHOLE_TEST <|> CLIENT\n"); gtk_idle_remove((int)arg_get_value(ctrls, "TAG")); /* * Read the data remaining... */ while(type != MSG_BYE) { buf[sizeof(buf) - 1] = '\0'; network_gets_raw(context->socket, buf, sizeof(buf) - 1); if( buf[0] == '\0') { break; } if ((n = strlen (buf)) && buf [n-1] == '\n') buf [n-1] = '\0'; msg = emalloc(strlen(buf)+1); type = parse_server_message(context, buf, (int)arg_get_value(ctrls, "MONITOR_BACKEND"), msg); efree(&msg); } context->action = CONTEXT_IDLE; prefs_context_update(context); gtk_widget_hide(arg_get_value(ctrls, "WINDOW")); #if 0 arg_set_value(MainDialog, "CONTEXT", -1, parent); #endif report_save(context, (int)arg_get_value(ctrls, "MONITOR_BACKEND"), NULL); return(FALSE); } /* * monitor_input_callback * * This function is called whenever there is new * data coming from the server. */ void monitor_input_callback(ctrls) struct arglist * ctrls; { GtkWindow* parent = arg_get_value(ctrls, "PARENT"); int finished = 0; static char * buf = NULL; static int bufsz = 0; static char * msg = NULL; int n, type = -1; int interrupted = 0; struct context * context = arg_get_value(ctrls, "CONTEXT"); if ( context == NULL ) return; if ( buf == NULL ) { bufsz = 1024 * 1024; buf = emalloc( bufsz ); msg = emalloc( bufsz ); } network_gets_raw( context->socket, buf, bufsz ); if ((n = strlen (buf)) && buf [n-1] == '\n') buf [n-1] = '\0'; if( buf[0] == '\0') { if(!is_server_present(context->socket)) { interrupted++; goto scan_finished; } else return; } type = parse_server_message(context, buf, (int)arg_get_value(ctrls, "MONITOR_BACKEND"), msg); switch(type) { case MSG_BYE : network_printf(context->socket, "CLIENT <|> BYE <|> ACK\n"); finished = 1; break; case MSG_STAT2 : monitor_list_update(ctrls,buf+2, 1); break; case MSG_STAT : monitor_list_update(ctrls, msg, 0); break; case MSG_FINISHED : monitor_remove_host(ctrls, msg); break; } buf[0] = '\0'; msg[0] = '\0'; if(finished) { scan_finished : gtk_widget_hide(arg_get_value(ctrls, "WINDOW")); gtk_idle_remove((int)arg_get_value(ctrls, "TAG")); gtk_widget_destroy(arg_get_value(ctrls, "WINDOW")); #if 0 arg_set_value(MainDialog, "CONTEXT", -1, parent); #endif report_save(context, (int)arg_get_value(ctrls, "MONITOR_BACKEND"), NULL); context->action = CONTEXT_IDLE; prefs_context_update(context); } } /* * monitor_stop_test * * this function stops one test */ void monitor_stop_test(GtkWidget * w,struct context * context) { char * hostname = gtk_object_get_data(GTK_OBJECT(w), "hostname"); network_printf(context->socket, "CLIENT <|> STOP_ATTACK <|> %s <|> CLIENT\n", hostname); } #endif