/*
 * Copyright (c) 1996-2007, OpenFWTK Development Group
 * All rights reserved. See LICENSE.
 */

#include <stddef.h>
#include <sys/types.h>

#include <stdlib.h>

#include <curses.h>
#include <stdio.h>
#include <sys/un.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <syslog.h>
#include <sys/socket.h>
#include <time.h>
#include <ctype.h>

#include <string.h>
#include <strings.h>

#include <signal.h>

#include "firewall.h"
#include "firewall2.h"


#define UNIX_PATH_MAX 100

#define MAX_STR_LEN 500

#define PWD_LEN  7


#define ESC_SEQ_REQ "\033[5n"
#define ESC_SEQ_BAD "\033[1n"

#define ESC_SEQ_LEN sizeof(ESC_SEQ_REQ) - 1

#define SOCK_REQ  -1

#define AUTH_INITIAL_TIMEOUT 50
#define AUTH_NEXT_TIMEOUT    50

#define RESEND_TIMEOUT  1

#define LOCK_TIMEOUT  1


#define PROMPT_STR  "auth console>"

#define AUTH_CONS_NAME "authcons"

#define AUTH_KEEPALIVE 0
#define AUTH_ASK       1


#define AUTH_PWD 2

#define MAX_AUTH_HISTORY  30


#include "../auth.h"

extern  size_t 	strlcat(char*,const char*,size_t);
extern  size_t 	strlcpy(char*,const char*,size_t);

typedef struct  {
  char req_str[BUFSIZ + 1];
  char accepted;
  int  auth_type;
  char pwd[BUFSIZ + 1]; 
  } t_auth_rec;
  
t_auth_rec *auth_rec[MAX_AUTH_HISTORY + 1];
  

struct sockaddr_un sn;

int auth_req_flag = 0;

int auth_sock;

int auth_type = AUTH_KEEPALIVE;

int nauth = 0, nauth_accepted = 0, nauth_rejected = 0;
int curr_auth = 0, start_history_index = 0;

WINDOW  *authframewin = NULL,  *conswin = NULL, *authwin = NULL;
WINDOW  *statusline = NULL;

void *authsrv_comm_f(void * arg);
int gets_sock(char *buf, int maxlen, int s);

void showstatistic();
void showsettings();
extern void* xmalloc(size_t);

int makeup_sockname(char sockname[], int max_name_len, char *auth_dir, char *host_addr, char *user_name);

int auth_checked(char [], char [], int);
void set_auth_req_occured(int value);
int auth_req_occured();

int authreq_dlg(char req_details[]);

int create_windows();
void deletewindows();

int console_command(char buf[]);
int socket_request(int s);

void timeout_sig(int signum);
int gets_signalled(char *buf, int maxlen);
void auth_req_sig(int sugnum);
int auth_console(char host_addr[], char user_name[]);

void makeup_auth_resp(char buf[], int auth_type, char pwd_buf[]);
void generate_pwd(char buf[]);
void showusage(char *usage);
void deletehistory();
int enargv(char *,char **,int,char *,int);


static	int	f_help();
static	int	f_quit();
static	int     f_auth();
static	int     f_history();



typedef	struct {
	char	*cnam;
	char	*help;
	int	(*cfun)();
} Cmd;
static Cmd ctab[] = {
  {"quit",		"quit\n",					f_quit,         },
  {"exit",		"exit\n",					f_quit,         },
  {"help",		"help\n",					f_help,         },
  {"auth",		"auth <keepalive|ask> [password]\n",		f_auth,         },
  {"history",		"history\n",					f_history,      },
  {"?",			"?\n",  					f_help,         },
  {0,			0,      					0               },
};

static Cmd * find_command();

int should_exit = 0;

sig_atomic_t continue_timer = 0;

int auth_console(char host_addr[], char user_name[])
{
	    char *auth_dir = AUTHSRV_SOCK_PATH;

       	    char  buf[BUFSIZ + 1] = "";
	    int seed;
	    int i;
            int ret_val;

	    seed = (int)time(NULL);
	    srand(seed);
	    
	    for(i=0; i<MAX_AUTH_HISTORY; i++)  auth_rec[i] = NULL;
	    

	    auth_sock = socket(PF_UNIX, SOCK_STREAM, 0);
	    if (auth_sock < 0) {
		perror("socket");
		syslog(LOG_ERR, "fwtksyserr: can't create unix socket: %s", strerror(errno));
	        closelog();		    
		exit(1);
	    }

	    
	    if(makeup_sockname(sn.sun_path, UNIX_PATH_MAX, auth_dir, host_addr, user_name) < 0)
	    {
	       fputs("buffer overflow while making up socket name\n", stderr);
	       syslog(LOG_ERR, "authconserr: socket name \"%s%s.%s.sock\" is too long (buffer overflow)", auth_dir, host_addr, user_name);
	       closelog();
               exit(1);
	    }
  
	    sn.sun_family = AF_UNIX;
	    
	    unlink(sn.sun_path);
	    if (bind(auth_sock, (struct sockaddr *)&sn, sizeof(sn)) < 0) {
		perror("bind");
		syslog(LOG_ERR, "fwtksyserr: can't bind unix socket %s: %s",sn.sun_path, strerror(errno));
	        closelog();
		exit(1);
	    }
	    
	    
	    if (listen(auth_sock, 1) < 0) {
		perror("listen");
		syslog(LOG_ERR, "fwtksyserr: error while listening to the socket: %s", strerror(errno));
	        closelog();
		exit(1);
	    }
	    
	    create_windows();
	    showsettings();
	    showstatistic();

	    syslog(LOG_NOTICE, "authcons: auth console started");

    
	    for(;;)
	    {
                  waddstr(conswin, PROMPT_STR);	  
		  wrefresh(conswin);
		  
		  buf[0] = '\0';
		  while((ret_val = gets_sock(buf, BUFSIZ, auth_sock)) != 0)   /* not a command */
		  {
                      if(ret_val != SOCK_REQ)  continue;
		      socket_request(auth_sock);
		      showstatistic();
		      wrefresh(conswin);
		  }
		                                                      /* user's input */
		  while(console_command(buf) == SOCK_REQ) {
		      socket_request(auth_sock);
		      showstatistic();		      
		      wrefresh(conswin);
		  }

                    		  
		  showsettings();		  
		  wrefresh(conswin);		    
		  
  	          buf[0] = '\0';		  
		  
		  if(should_exit) break;		    
            }
          
	    deletewindows();
	    deletehistory();
	    
            close(auth_sock);
            unlink(sn.sun_path);
	    endwin();

	    syslog(LOG_NOTICE, "authcons: auth console finished");

            return(0);
}


int socket_request(int s)
{
   int auth_fd;
   char buf[BUFSIZ];
   int ret_val;
   socklen_t addr_struct_len;
   int req_num = 0;
   struct sockaddr_un sn;
   static char pwd_buf[BUFSIZ] = "\0";

      addr_struct_len = sizeof(sn);
      if((auth_fd = accept(s, (struct sockaddr *)&sn, &addr_struct_len)) > 0)
      {
	 if((ret_val = sogets(auth_fd, buf, sizeof(buf) - 1)) > 0)
	 {

	   buf[ret_val] = '\0';

	   req_num++;

           if(!strncmp(buf, "auth", 4))   
	   {
	     auth_rec[curr_auth] = (t_auth_rec *)xmalloc(sizeof(t_auth_rec));
	     *(auth_rec[curr_auth]->pwd) = '\0';
	     auth_rec[curr_auth]->auth_type = auth_type;
	     
	     if(auth_checked(buf, auth_rec[curr_auth]->req_str, sizeof(auth_rec[curr_auth]->req_str)))
	     {

	       nauth_accepted++;
	       auth_rec[curr_auth]->accepted = 'y';

	       if(auth_type & AUTH_PWD)
	       {
		 if (!*pwd_buf)
		 {
	           generate_pwd(pwd_buf);
		   strlcpy(auth_rec[curr_auth]->pwd, pwd_buf, BUFSIZ);
	         }
		 strlcpy(buf, " Session pwd: ", BUFSIZ);
		 strlcat(buf, pwd_buf, BUFSIZ); 
		 waddstr(authwin, buf);
	       } else
	         waddstr(authwin, " Accepted.");
	       makeup_auth_resp(buf, auth_type, pwd_buf);	       
	       syslog(LOG_NOTICE, "authcons: auth request has been accepted.");
	     }
	     else
	     {
	       nauth_rejected++;
	       auth_rec[curr_auth]->accepted = 'n';	       
	       waddstr(authwin, " Rejected.");
	       syslog(LOG_NOTICE, "authcons: auth request has been rejected.");		    
	       strlcpy(buf, "reject", sizeof(buf));
	     }
	     
	     nauth++;
	     if(++curr_auth >= MAX_AUTH_HISTORY) curr_auth = 0;
	     if(auth_rec[curr_auth]) {
	       free(auth_rec[curr_auth]);
	       auth_rec[curr_auth]=NULL;
	     }
	     if(curr_auth == start_history_index) start_history_index++;

             if(start_history_index >= MAX_AUTH_HISTORY) start_history_index = 0;

	     if(sosay(auth_fd, buf))
	     {
		 waddstr(authwin, "error while writing to the socket");
		 perror("write (socket)");
		 syslog(LOG_ERR, "fwtksyserr: error while writing to the socket: %s", strerror(errno));
	     }

	   }
      	   else
	   {
	     waddstr(authwin, "Incorrect request from the auth server\n") ;
	     syslog(LOG_ERR, "fwtksyserr: incorrect request from the auth server: %s", buf) ;
	   }
           wrefresh(authwin);
	 }
	 else if(ret_val < 0)
	 { 
	   perror("read (socket)"); 
	   syslog(LOG_ERR, "fwtksyserr: error while reading from the socket: %s", strerror(errno));
	 }
         
      }
      else if(auth_fd < 0)  
      {
	perror("accept");
	syslog(LOG_ERR, "fwtksyserr: error while accepting a connection to the socket: %s", strerror(errno));
      }

      close(auth_fd);

   return req_num;
}


int auth_checked(char req[], char req_info[], int max_len)
{
  char buf[ESC_SEQ_LEN + 1];
  int i;
  int c;
  int ret_val;

  char req_details[BUFSIZ];
  char proxy_name[BUFSIZ] = "";
  char ciaddr[BUFSIZ]     = "";
  char *user_name;
  char *usercomment;
  char *p;

  char *timestamp[MAX_STR_LEN];
  time_t time_val;

  int tmp_y, tmp_x;



  if((user_name = index(req, ' ')))  {
    strtrm(++user_name);
    usercomment = index(user_name, ' ');
    strncpy(req_info, user_name, max_len);

    if(usercomment) {
	    *usercomment++ = '\0';
	    strtrm(usercomment);

	    if((usercomment = index(usercomment, '\'')))
	       if(index(++usercomment, '\''))
		 *(index(usercomment, '\'')) = '\0';

	    if(!usercomment)
		waddstr(authwin, "\nAuth req format error");
	    else  {
		  strtrm(usercomment);

		  if ((p = rindex(usercomment,'/')) != (char *)0)
			  strlcpy(ciaddr,p+1,sizeof(ciaddr));
		  else  {
			  strlcpy(ciaddr,"unknown",sizeof(ciaddr));
                          waddstr(authwin, "\nAuth req format error");
		  }

		  strlcpy(proxy_name,usercomment,sizeof(proxy_name));

		  if ((p = index(proxy_name,' ')) != (char *)0)
			  *p= '\0';
	    }
    }
    else {
	    strlcpy(proxy_name,"unknown",sizeof(proxy_name));
	    strlcpy(ciaddr,"unknown",sizeof(ciaddr));
            waddstr(authwin, "\nAuth req format error");
    }
  }
  else {
             waddstr(authwin, "\nAuth req format error");
  }

  if(strlen(user_name) == 0 || strlen(ciaddr) == 0) {
     waddstr(authwin, "\nAuth req format error");
  }


  time(&time_val);
  strftime((char *)timestamp, sizeof(timestamp), "%m.%d.%Y", localtime(&time_val));

  snprintf(req_details,sizeof(req_details),"%s: Auth req for: %s@%s (via %s).",
	   (char *)timestamp, user_name, ciaddr, proxy_name);

  waddstr(authwin, "\n");
  waddstr(authwin, req_details);
  wrefresh(authwin);

 /*  savetty(); */

  flushinp();


  if(auth_type & AUTH_ASK)
  {
    ret_val = authreq_dlg(req_details);
    touchwin(authframewin);
    wrefresh(authframewin);
    touchwin(conswin);
    wrefresh(conswin);

/*    resetty(); */
    return ret_val;
  }

  getyx(authwin, tmp_y, tmp_x);
  move(tmp_y + 1, tmp_x + 1);

  noecho();

  putp(ESC_SEQ_REQ);  /* refresh(); */ ret_val=0;

  if(ret_val < 0)
  {
    perror("write (terminal)");
    syslog(LOG_ERR, "authconserr: error while writing ESC-sequence requesting terminal status: %s", strerror(errno));
/*    resetty();  */
    return 0;
  }

  i = 0;
  halfdelay(AUTH_INITIAL_TIMEOUT);
  buf[0] = getch();
  halfdelay(AUTH_NEXT_TIMEOUT);
  if(buf[0] != ERR)
     for(i=1; i < ESC_SEQ_LEN && (c = getch()) != ERR; buf[i++] = c ) ;
  else
  {  
/*   resetty(); */
    return 0;                                                           /* timeout             */
  }
  buf[i] = '\0';
/*  resetty(); */
  
  if(!strncmp(buf, ESC_SEQ_BAD, ESC_SEQ_LEN))
    return 0;                                                           /* bad terminal status */

  return 1;
}

static Cmd * find_command(Cmd * ctab, char * cmd)
{
	Cmd *cp, *match;
	int nl;

	nl = strlen(cmd);
	match = 0;
	for (cp = ctab; cp->cnam != (char *)0; cp++) {
		if (!strcmp(cp->cnam, cmd))
			return cp;
		else if (!strncasecmp(cp->cnam, cmd, nl)) {
			if (match && cp->cfun != match->cfun)
				return 0; /* ambiguous */
			match = cp;
		}
	}
	return match ? match : cp;
}


static	int
f_quit(ac,av,orig, usage)
int	ac;
char	*av[];
char	*orig;
char    *usage;
{
  should_exit = 1;    
  return 0;
}

static	int
f_auth(ac,av,orig, usage)
int	ac;
char	*av[];
char	*orig;
char    *usage;
{
  int tmp_auth_type = 0;


  if(ac < 2 || ac > 3)
  {
    showusage(usage); return 0;
  }
    
  if(!strncmp(av[1], "ask", strlen(av[1])))
  {
    tmp_auth_type |= AUTH_ASK;
  }
  else if(!strncmp(av[1], "keepalive", strlen(av[1])))
  {}
  else
  {
    showusage(usage); return 0;
  }


  if( ac >= 3 ) {
    if(!strncmp(av[2], "password", strlen(av[2])))
    {
      tmp_auth_type |= AUTH_PWD;
    }
    else
    {
      showusage(usage); return 0;
    }
  }


  auth_type = tmp_auth_type;
    
  return 0;
}

static	int
f_help(ac,av,orig,usage)
int	ac;
char	*av[];
char	*orig;
char    *usage;
{
	Cmd	*cp;

	waddstr(conswin, "Command List:\n");
	waddstr(conswin, "(Commands may be invoked with unique leading abbreviation)\n");
	for(cp = ctab; cp->cnam != (char *)0; cp++)

		if(cp->help != (char *)0)
			waddstr(conswin, cp->help);
	return(0);
}

static	int
f_history(ac,av,orig, usage)
int	ac;
char	*av[];
char	*orig;
char    *usage;
{
  static int curr_history_index = -1;
  int wnd_lines = 0, wnd_cols = 0;
  static int page_lines = 2;
  int curr_y, curr_x;
  int ret_val;

  fd_set rfds, efds;

  noecho();
  cbreak();


  if(curr_history_index == -1)  {
    curr_history_index = start_history_index; /* That is displaying should not be continued since the previous
                                               * function call, but entries should be output from the begining
					       */
    wprintw(conswin, "           authreq                 y/n  type     pwd \n");
    wprintw(conswin, "---------------------------------- --- ------- -------\n");
    page_lines = 2;
  }
  else if(!auth_rec[curr_history_index]) {
        wprintw(conswin, "Shown history records have been overwritten as a result of wrapping\n");
  }

  while(auth_rec[curr_history_index])  {
          getmaxyx(conswin, wnd_lines, wnd_cols);
          if(page_lines >= wnd_lines - 1) {
                  getyx(conswin, curr_y, curr_x);
                  mvwprintw(conswin, curr_y, 0, "--MORE--");
                  wrefresh(conswin);
                  wmove(conswin, curr_y, 0);

                  curs_set(0);
                  do {
                          FD_ZERO(&rfds);
                          FD_SET(0, &rfds);
                          FD_SET(auth_sock, &rfds);


                          FD_ZERO(&efds);
                          FD_SET(auth_sock, &efds);


                          ret_val = select(auth_sock+1, &rfds, NULL, &efds, NULL);


                          if (ret_val > 0)
                          {
                                  if(FD_ISSET(auth_sock, &rfds) || FD_ISSET(auth_sock, &efds))  {  /*  socket request  */
                                          return SOCK_REQ;
                                  }
                          }
                          else {
                          /* error */
                          }
                  }
                  while(!FD_ISSET(0, &rfds));



                  wgetch(conswin);
                  curs_set(1);
                  page_lines = 0;
          }

          page_lines++;
          wprintw(conswin, "%-34s  %c  %3s %3s %7s\n",
                                                  auth_rec[curr_history_index]->req_str,
                                                  auth_rec[curr_history_index]->accepted,
                                          (auth_rec[curr_history_index]->auth_type & AUTH_ASK) ? "ASK"            : "KLV",
                                          (auth_rec[curr_history_index]->auth_type & AUTH_PWD) ? "PWD"            : "",
                                          (auth_rec[curr_history_index]->auth_type & AUTH_PWD) ? auth_rec[curr_history_index]->pwd : "");

          if(++curr_history_index >= MAX_AUTH_HISTORY) curr_history_index=0;
  }


  curr_history_index = -1; /* History has been shown completely and next time entries should be displayed
                            * from the begining
			    */
  wrefresh(conswin);
  return 0;
}



int makeup_sockname(char sockname[], int max_name_len, char *auth_dir, char *host_addr, char *user_name)
{
	    strlcpy(sockname, auth_dir,  max_name_len);
            strlcat(sockname, host_addr, max_name_len);  
	    strlcat(sockname, ".", max_name_len); 
            strlcat(sockname, user_name, max_name_len);

	    if(strlen(sockname) + strlen(".sock") > max_name_len)
	      return -1;
	      
            strlcat(sockname, ".sock", max_name_len);
	    return strlen(sockname);
}	    

int console_command(char buf[])
{
	    Cmd	 *cp;	    
	    char *xa[128];
	    char  xb[BUFSIZ + 1];
	    int	  xc;
	    

  	    xc = enargv(buf,xa,sizeof(xa)/sizeof(char *),xb,sizeof(xb));

	    if(xc < 0) {
		    waddstr(conswin, "Too many command parameters.\n");
		    return 0;
	    }
	    if(xc == 0)
		    return 0;


	    cp = find_command(ctab, xa[0]);
	    if (!cp) {
		    char	xuf[BUFSIZ];
		    snprintf(xuf,sizeof(xuf),"Command \"%.200s\" is ambiguous.\n",xa[0]);
		    waddstr(conswin,  xuf);
		    return 0;
	    }
	    if(cp->cnam == (char *)0) {
		    char	xuf[BUFSIZ];
		    snprintf(xuf,sizeof(xuf),"Command \"%.200s\" unrecognized.\n",xa[0]);
		    waddstr(conswin,  xuf);
		    return 0;
	    }

	    return (*cp->cfun)(xc,xa,buf,cp->help);
}



void showusage(char *usage)
{
  char buf[BUFSIZ] = "Usage: ";
  strlcat(buf, usage, sizeof(buf)); strlcat(buf, "\n", sizeof(buf));
  waddstr(conswin, buf);
  wrefresh(conswin);
}


void makeup_auth_resp(char buf[], int auth_type, char pwd_buf[])
{
  strlcpy(buf, "auth", BUFSIZ);
  if(auth_type & AUTH_PWD) {
    strlcat(buf, " ", BUFSIZ);
    strlcat(buf, pwd_buf, BUFSIZ);
  }
  strlcat(buf, "\n", BUFSIZ);
}
  
void generate_pwd(char buf[])
{
  int i;
  char char_code;
  
  for(i=0; i<PWD_LEN; i++) {
    char_code = 40 +(int) ((126.0 - 40)*rand()/RAND_MAX);
    buf[i] = char_code;
  }
  buf[i] = '\0';
}



int gets_sock(char *buf, int maxlen, int s)
{

           int ret_val = 0;
	   int i;
           int c;
           fd_set rfds, efds;
           int sel_ret_val;


           cbreak();
           noecho();
           keypad(conswin, 1);  
	   
  
	   for(i=strlen(buf); i<maxlen; )
	   {

               FD_ZERO(&rfds);
               FD_SET(0, &rfds);
               FD_SET(s, &rfds);	   


               FD_ZERO(&efds);
               FD_SET(s, &efds);


               sel_ret_val = select(s+1, &rfds, NULL, &efds, NULL);


               if (sel_ret_val > 0)
	       {
		 if(FD_ISSET(s, &rfds))    /*  socket request  */
		 {
		   ret_val = SOCK_REQ;
		   break;
		 }
                 else if(FD_ISSET(s, &efds))
                 {
                   ret_val = -1;
                   break;
                 }
		 else if(FD_ISSET(0, &rfds))
		 {

		   c=wgetch(conswin);

		   if(c == '\n')
		   {
		     buf[i] = '\0';
		     waddstr(conswin, "\n"); wrefresh(conswin);
		     break;
		   }
		   else if(c == '\b' || c == KEY_BACKSPACE)
		   {
		     if(i > 0)
		     {
		       i--;
		       wechochar(conswin, '\b');
		       wdelch(conswin);  wrefresh(conswin);
		     }
		   }
		   else if(c != ERR)
		   {
		     buf[i++] = c; buf[i] = '\0';
		     wechochar(conswin, c);
		   }
		   else
		   {                               /* error  */
		     ret_val = errno;
		     break;
		   }
        	 }
	       }
	       else
	       {
		/* error */
		ret_val = errno;
		break;
	       }
	   }
	   buf[maxlen] = '\0';
	   return ret_val;
}


int create_windows()
{
  conswin = newwin(LINES/2, COLS,LINES - LINES/2 - 1, 0);
  wbkgd(conswin, COLOR_PAIR(1));  
  scrollok(conswin, 1);
  
  authframewin = newwin(LINES - LINES/2 - 1,COLS, 0, 0);
  wbkgd(authframewin, COLOR_PAIR(1));
  box(authframewin, 0, 0);  
  mvwaddstr(authframewin, 0, 2, " Auth req: ");
  wrefresh(authframewin);
  
  authwin = derwin(authframewin, LINES - LINES/2 - 3, COLS - 2, 1, 1);
  scrollok(authwin, 1);
  
  statusline = newwin(1,COLS, LINES - 1, 0);
  wbkgd(statusline, COLOR_PAIR(2));
  mvwaddstr(statusline, 0, 1, "Auth settings:");
  
  wrefresh(statusline);
  wrefresh(authwin);
  wrefresh(conswin);
  
  return 1;
}


int authreq_dlg(char req_details[])
{
	WINDOW *my_form_win, *my_form_win_frame;
	int ch;
	
	int allow_auth = 1;
	
	noecho();
	
	curs_set(0);

        my_form_win_frame = newwin(13, 60, 5, 10);
	wbkgd(my_form_win_frame, COLOR_PAIR(1));
        box(my_form_win_frame, 0, 0);	
	wrefresh(my_form_win_frame);
	my_form_win = derwin(my_form_win_frame,10, 54, 2, 3);
	
        keypad(my_form_win, TRUE);
	
/*	wcolor_set(my_form_win, 2, NULL); */
	
	mvwaddstr(my_form_win, 0, 0, req_details);
	
	mvwaddstr(my_form_win, 5, 23, "Allow it?");

	wstandout(my_form_win);
	mvwaddstr(my_form_win, 8, 24, "Yes");
	wstandend(my_form_win);
	
	mvwaddstr(my_form_win, 8, 29, "No");

	wmove(my_form_win, 8, 24 + (1 - allow_auth)*5);
	
	wrefresh(my_form_win);


	/* Loop through to get user requests */
	while((ch = tolower(wgetch(my_form_win))) != ' ' && ch != '\n' && ch != 'y' && ch != 'n')
	{	
                allow_auth = 1 - allow_auth;

		wmove(my_form_win, 8, 24 + (1 - allow_auth)*5);
		wstandout(my_form_win);
		waddstr(my_form_win, allow_auth ? "Yes" : "No");
		wstandend(my_form_win);
	
		
		wmove(my_form_win, 8, 24 + allow_auth*5);
		waddstr(my_form_win, (1 - allow_auth) ? "Yes" : "No");



		touchline(my_form_win, 8, 1);
		wrefresh(my_form_win);
	}
	
	if(ch == 'y')
	  allow_auth = 1;
	else if(ch == 'n')
	  allow_auth = 0;
	
	delwin(my_form_win);
	delwin(my_form_win_frame);
	curs_set(1);

	return allow_auth;
}

void showsettings()
{
  if(auth_type & AUTH_ASK)
    mvwaddstr(statusline, 0, 16, "ASK      ");
  else
    mvwaddstr(statusline, 0, 16, "KEEPALIVE");
    
  if(auth_type & AUTH_PWD)
    mvwaddstr(statusline, 0, 26, "PWD");
  else
    mvwaddstr(statusline, 0, 26, "   ");  
    
  mvwaddstr(statusline, 0, 30, "|");
  
  
  wrefresh(statusline);
}

void showstatistic()
{
  mvwprintw(statusline, 0, 33, "Auth requested: %d (accepted: %d; rejected: %d)", nauth, nauth_accepted, nauth_rejected);
  wrefresh(statusline);
}

void deletewindows()
{
  if(conswin)      delwin(conswin);
  if(authframewin) delwin(authframewin);
  if(authwin)      delwin(authwin);
  if(statusline)   delwin(statusline);
  
  conswin = authframewin = authwin = statusline = NULL;
}

void deletehistory()
{
  int i;
  for(i=0; i <= MAX_AUTH_HISTORY; i++)  
    if(auth_rec[i]) { 
      free(auth_rec[i]);
      auth_rec[i] = NULL;
    }
}
