/*
 * 
 * guess_os
 *
 * This plugin was written by Renaud Deraison and is released
 * under the GPL
 *
 * Somewhat inspired by the way mscan checks for the remote OSes
 *
 */
#include <includes.h>
#define NAME "guess operating system"
#define DESC "\
This plugin attempts to guess the type of the remote operating\n\
system by looking at the telnet and ftp banners"
#define COPYRIGHT "no copyright"
#define SUMM "guesses the remote OS"

PlugExport int plugin_init(struct arglist *desc);
PlugExport int plugin_init(struct arglist *desc)
{
	plug_set_name(desc, NAME);
	plug_set_description(desc, DESC);
	plug_set_summary(desc, SUMM);
	plug_set_copyright(desc, COPYRIGHT);
	plug_set_category(desc, ACT_GATHER_INFO);
	plug_set_family(desc, "Misc.");
	return(0);
}

static
const char * systems[] = { "WindowsNT", "Linux", "AIX", "IRIX", "FreeBSD", "OpenBSD", 
 		     "Solaris", "Windows 95/98 or NT", "SunOS", "some kind of UNIX"};
#define os_NT 0
#define os_LINUX 1
#define os_AIX 2
#define os_IRIX 3
#define os_FREEBSD 4
#define os_OPENBSD 5
#define os_SOLARIS 6
#define os_WINDOWS 7
#define os_SUNOS 8
#define os_SOME_UNIX 9
char init_telnet_session(int);
int parse_os_from_banner(char *);
PlugExport int plugin_run(struct arglist * args);	
PlugExport int plugin_run(struct arglist * args)
{
	/* we have a dumb strategy. First, we make a ftp connection
         * and have a look at the baner. Then, we make a telnet 
         * connection and just strstr the data
         */
 int soc;
 int os = -1;
 int os_ = -1;
 char * buf = emalloc(255);
        
 if(host_get_port_state(args, 21))
  {
   soc = open_sock_tcp(args, 21);
   if(soc >= 0)
   {
    recv_line(soc, buf, 254);
    if(strstr(buf, "Microsoft"))os = os_NT;
    else if(strstr(buf, "Version wu-"))os_ = os_SOME_UNIX;
    shutdown(soc, 2);
    close(soc);
    }
  }
  if(os < 0)
  {
    /* try though telnet */
   if(host_get_port_state(args, 23))
   {
    if((soc = open_sock_tcp(args, 23))>=0)
    {
     int i;
     buf[0] = init_telnet_session(soc);
     for(i=1;i<255;i++)
     {
      int a = 0;
      ioctl(soc, FIONREAD, &a);
      if(a)recv(soc, &buf[i], 1, 0);
      else i=256;
     }
     os = parse_os_from_banner(buf);  
    }
   }
  }
    
  if(os < 0)os = os_;
  
  if(os >= 0)
  {
   char * str_os = systems[os];
   char * report = emalloc(1024);
   
   sprintf(report, "The operating system of the remote host\nappears to be %s",
   	str_os);
   post_info(args, -1, report);
   efree(&report);
  } 
  efree(&buf);
  return(0);
}


char init_telnet_session(int sock)
{ 
 /* very simple here... we just say "WON'T" to every option */
 unsigned char iac, code, option;
 iac = 255;
 
 while(iac == 255)
 {
   recv(sock, &iac, 1,0);
   if(iac!=255)break;
   recv(sock, &code, 1,0);
   recv(sock, &option, 1,0);
   code = 252; /* WONT */
   send(sock, &iac, 1,0);
   send(sock,&code, 1,0);
   send(sock, &option, 1,0);
  }
  return(iac);
}


int parse_os_from_banner(banner)
 char * banner;
{
 if(strstr(banner, "Linux"))return(os_LINUX);
 if(strstr(banner, "IRIX"))return(os_IRIX);
 if(strstr(banner, "FreeBSD"))return(os_FREEBSD);
 if(strstr(banner, "Open"))return(os_OPENBSD);
 if(strstr(banner, "UNIX System"))return(os_SOLARIS);
 if(strstr(banner, "SunOS"))return(os_SUNOS);
 if(strstr(banner, "AIX"))return(os_AIX);
 if(strstr(banner, "Gate>"))return(os_WINDOWS);
 return(-1);
}
