/* 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.
 *
 * UI hooks for the SSL questions
 *
 */
#include <includes.h>
#include "nessus_i18n.h"

#include "globals.h"

#ifdef USE_GTK
#include "gtk-compat.h"
#include <gtk/gtk.h>
#include <xpm/lock.xpm>
/*-------------------------------------------------------------------------*/

static void
sslui_paranoia_callback(w, ctrls)
	GtkWidget * w;
	struct arglist * ctrls;
{
	GSList * list = arg_get_value(ctrls, "LEVEL_RADIO");
	int value;
	if(list)
		while(list)
		{
			GtkWidget * button = list->data;
			if(GTK_TOGGLE_BUTTON(button)->active)
			{
				value = GPOINTER_TO_SIZE(gtk_object_get_data(GTK_OBJECT(button), "level"));
				arg_add_value(ctrls, "LEVEL", ARG_INT,
						sizeof(gpointer), GSIZE_TO_POINTER(value));
				gtk_grab_remove(arg_get_value(ctrls, "WINDOW"));
				gtk_widget_destroy(arg_get_value(ctrls, "WINDOW"));
				gtk_main_quit();
				return;
			}
			list = list->next;
		}
}

static void 
build_dialog(ctrls, prompt)
 struct arglist * ctrls;
 char * prompt;
{
 GtkWidget * w, * table, * ok;
 GdkPixbuf *pixbuf = NULL;
 GtkWidget *img = NULL;
 GtkWidget * hbox, * vbox, * label, *sep, *box;
 GtkWidget * button, * first_button;
 GtkWidget * otable;
 w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 gtk_window_set_position(GTK_WINDOW(w), GTK_WIN_POS_CENTER);
 gtk_widget_realize(w);

  pixbuf = gdk_pixbuf_new_from_xpm_data((const char **)lock_xpm);
  img = gtk_image_new_from_pixbuf(pixbuf);

 
 gtk_window_set_title(GTK_WINDOW(w), _("SSL Setup"));
 gtk_container_border_width(GTK_CONTAINER(w), 5);
 arg_add_value(ctrls, "WINDOW", ARG_PTR, -1, w);
 
 
 vbox = gtk_vbox_new(FALSE, 5);
 hbox = gtk_hbox_new(FALSE, 5);
 
 
 
 gtk_container_add(GTK_CONTAINER(w), hbox);
 gtk_widget_show(hbox);
 
 gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
 gtk_widget_show(vbox);
 
 gtk_box_pack_start(GTK_BOX(vbox), img, FALSE, FALSE, 0);
 gtk_widget_show(img);
 
 sep = gtk_vseparator_new();
 gtk_box_pack_start(GTK_BOX(hbox), sep, FALSE, FALSE, 5);
 gtk_widget_show(sep);
 
 vbox = gtk_vbox_new(FALSE, 5);
 gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
 gtk_widget_show(vbox);
 
 box = gtk_hbox_new(FALSE, 5);
 gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 10);
 gtk_widget_show(box);
 
 label = gtk_label_new(prompt);
  gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 10);
 gtk_widget_show(label);
 
 table  = gtk_table_new(3,1,TRUE);
 gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 5);
 gtk_container_border_width(GTK_CONTAINER(table), 10);
 gtk_widget_show(table);
 
 
 first_button = gtk_radio_button_new_with_label(
		 NULL,
		 _("Display and remember the server certificate, do not care about the CA"));

 gtk_object_set_data(GTK_OBJECT(first_button), "level", (void*)1);
 gtk_table_attach_defaults(GTK_TABLE(table), first_button,0,1,0,1);
 
 
 /*TABLE*/
 gtk_widget_show(first_button);
 button = gtk_radio_button_new_with_label(
		 gtk_radio_button_group(GTK_RADIO_BUTTON(first_button)),
		 _("Trust the server certificate if and only if it is valid and certified by the CA"));

 gtk_object_set_data(GTK_OBJECT(button), "level", (void*)2);
 gtk_table_attach_defaults(GTK_TABLE(table), button,0,1,1,2);
 /*TABLE*/
 gtk_widget_show(button);
 button = gtk_radio_button_new_with_label(
		 gtk_radio_button_group(GTK_RADIO_BUTTON(first_button)),
		 _("Verify that the server certificate is valid *and* remember it"));

 gtk_object_set_data(GTK_OBJECT(button), "level", (void*)3);
 gtk_table_attach_defaults(GTK_TABLE(table), button,0,1,2,3);
 /*TABLE*/
 gtk_widget_show(button);

 arg_add_value(ctrls, "LEVEL_RADIO", ARG_PTR,-1, gtk_radio_button_group(GTK_RADIO_BUTTON(first_button)));

 ok = gtk_button_new_with_label(_("OK"));
 g_signal_connect(GTK_OBJECT(ok), "clicked",
 		    (GtkSignalFunc)sslui_paranoia_callback, 
		    (void*)ctrls);

 otable = gtk_table_new(1,2, TRUE);
 gtk_table_attach_defaults(GTK_TABLE(table), otable, 0,1,5,6);
 gtk_widget_show(otable);
 gtk_table_attach_defaults(GTK_TABLE(otable), ok, 1,2,0,1);
 GTK_WIDGET_SET_FLAGS(ok, GTK_CAN_DEFAULT);
 gtk_widget_grab_default(ok);
 gtk_widget_show(ok);
 gtk_widget_show(w);
 gtk_grab_add(w);
}



/*-------------------------------------------------------------------------*/
#endif /* GTK_UI */




/**
 * @brief Ask the level of paranoia the user wants to set.
 *
 * @returns -1 if an error occured, or the level of paranoia selected by the 
 *          user (0, 1 or 2).
 */
int
sslui_ask_paranoia_level ()
{
  int ret;
  char * question =
    _("Please choose your level of SSL paranoia (Hint: if you want to manage\n"
      "many servers from your client, choose 2. Otherwise, choose 1. Or 3,\n"
      "if you are paranoid.\n");

#ifdef USE_GTK
	if(!F_quiet_mode)
	{
	 struct arglist * ctrls = emalloc(sizeof(*ctrls));
	 build_dialog(ctrls, question);
	 gtk_main();
	 ret =  GPOINTER_TO_SIZE(arg_get_value(ctrls, "LEVEL"));
	 arg_free(ctrls);
	 return ret;
	}
  else
#endif

  do {
  fprintf(stderr, "%s", question);
  ret = 0;
  }

  while(scanf("%d", &ret) == 0) /* RATS: ignore, formatting string is sane */
    ;

  if(ret >= 1 && ret <= 3)
   {
   return ret;
   }
  else 
   return -1;
}

/*-------------------------------------------------------------------------*/
#ifdef USE_GTK


static void
showcert_cb(w, ctrls, accept)
 GtkWidget * w;
 struct arglist * ctrls;
 int accept;
{
 gtk_widget_hide(arg_get_value(ctrls, "WINDOW"));
 gtk_widget_destroy(arg_get_value(ctrls, "WINDOW"));
 if(accept)
  arg_add_value(ctrls, "RESULT", ARG_INT, sizeof(int),(void*) 1);
 gtk_main_quit();
}


static void 
showcert_accept_cb(w, ctrls)
 GtkWidget* w;
 struct arglist *ctrls;
{
 showcert_cb(w,ctrls, 1);
}

static void
showcert_refuse_cb(w, ctrls)
 GtkWidget* w;
 struct arglist *ctrls;
{
 showcert_cb(w,ctrls, 0);
}



/**
 * Displays certificate and asks whether to trust it or not.
 * (Callbacks showcert_accept_cb and showcert_refuse_cb which ultimately call 
 * showcert_cb).
 * 
 * @param cert The certificate text.
 * @return Arglist with WINDOW and RESULT entry (RESULT is 1 if the certificate 
 *         was accepted).
 */
static struct arglist * 
sslui_showcert(char* cert)
{
 struct arglist * ctrls = emalloc(sizeof(*ctrls));
 GtkWidget * w;
 GtkWidget * vbox, *hbox;
 GtkWidget * label, *text, *sep, *button;
 GtkWidget* scrollwin;
 
 w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 gtk_window_set_default_size(GTK_WINDOW(w), 640, 480);
 gtk_window_set_position(GTK_WINDOW(w), GTK_WIN_POS_CENTER);
 gtk_widget_realize(w);
 arg_add_value(ctrls, "WINDOW", ARG_PTR, -1, w);
 
 vbox = gtk_vbox_new(FALSE, 5);
 gtk_container_add(GTK_CONTAINER(w), vbox);
 gtk_widget_show(vbox);
 
 label = gtk_label_new(_("This certificate has never been shown before. \
Here it is:"));
 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5);
 gtk_widget_show(label);
 
 /* Initialize scroll area */
 scrollwin = gtk_scrolled_window_new(NULL, NULL);
 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW (scrollwin),
                                 GTK_POLICY_AUTOMATIC,
                                 GTK_POLICY_AUTOMATIC);
 gtk_box_pack_start(GTK_BOX(vbox), scrollwin, TRUE, TRUE, 0);
 
 /* Initialize text view */
 text = gtk_text_view_new();
 gtk_text_view_set_editable(GTK_TEXT_VIEW(text), FALSE);

 /* Add certificate text to text view */
 GtkTextBuffer* textbuffer;
 textbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text));
 gtk_text_buffer_set_text(textbuffer, cert, -1);
 
 /* Add and show scroll area and text view */
 gtk_container_add(GTK_CONTAINER(scrollwin), text);
 gtk_widget_show(text);						
 gtk_widget_show(scrollwin);
 
 /* Seperator, buttons and callbacks */
 sep = gtk_hseparator_new();
 gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0);
 gtk_widget_show(sep);
 
 label = gtk_label_new(_("Do you accept this certificate?"));
 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
 gtk_widget_show(label);

 hbox = gtk_hbox_new(FALSE, 5);
 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
 gtk_widget_show(hbox);
 
 button = gtk_button_new_with_label(_("Yes"));
 gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
 g_signal_connect(GTK_OBJECT(button), "clicked",
 	GTK_SIGNAL_FUNC(showcert_accept_cb), ctrls);
 gtk_widget_show(button);
 
 button = gtk_button_new_with_label(_("No"));
 gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
 g_signal_connect(GTK_OBJECT(button), "clicked",
 	GTK_SIGNAL_FUNC(showcert_refuse_cb), ctrls);
 gtk_widget_show(button);
 
 g_signal_connect (G_OBJECT (w), "destroy", 
                   GTK_SIGNAL_FUNC(showcert_refuse_cb), ctrls);

 
 gtk_widget_show(w);
 gtk_window_set_modal(GTK_WINDOW(w), TRUE);
 return ctrls;
}


#endif /* USE_GTK */


/**
 * Shows the SSL certificate to the user.
 *
 * @param ssl The ssl connection
 * @return 0 if the certificate is accepted, -1 if the certificate is invalid.
 */ 
int
sslui_check_cert(ssl)
	SSL * ssl;
{
 char * ascii_cert;
 X509 * cert = SSL_get_peer_certificate(ssl);
 BIO * b;
 BUF_MEM * bptr;
 int x;
 
 b = BIO_new(BIO_s_mem());
 if(X509_print(b, cert) > 0)
 {
  BIO_get_mem_ptr(b, &bptr);
  ascii_cert = emalloc(1 + bptr->length);
  memcpy(ascii_cert, bptr->data, bptr->length); /* RATS: ignore, Correct buffer size ensured in line above */
 }
 else
 {
  ascii_cert = emalloc(1024);
  sprintf(ascii_cert,
    _("This certificate has never been seen before and can't be shown\n"));
 }
 BIO_free(b);
 
#ifdef USE_GTK 
 if(!F_quiet_mode)
 {
  int ret;
  struct arglist * ctrls = sslui_showcert(ascii_cert);
  efree(&ascii_cert);
  gtk_main();
  ret =  GPOINTER_TO_SIZE(arg_get_value(ctrls, "RESULT"));
  arg_free(ctrls);
  if(ret) 
    return 0;
  else
    return -1;
 }
#endif
 fprintf(stderr, "%s\n", ascii_cert);
 fprintf(stderr, _("Do you accept it? (y/n) "));
 fflush(stderr);
 do {
  x = getchar();
 } while (x != EOF && x !='y' && x != 'n');
 
 return (x == 'y') ? 0:-1;
}
	
	

char*
sslui_ask_trusted_ca_path()
{
 return NULL;
}

