/*
 *  This is the vuln checker for synscan.
 * When a port is found, this will run protocol-specific checks
 * against the relevant port.
 */

#include <stdio.h>
#include <setjmp.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <netdb.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#ifndef HPUX
#include <sys/select.h>
#endif
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <rpc/rpc.h>
#include <rpc/pmap_prot.h>
#include <rpc/pmap_clnt.h>
#include <sys/time.h>
#include "synscan.h"

jmp_buf jump_bAck;

extern char ircserver[200];
int pbind (char *host);
unsigned long gip;
unsigned int giport;
char bndver[200];

char thathost[0x100];

void
timed_out (int sig)
{
  longjmp (jump_bAck, 0x0);
}

void
fuck_it (int sig)
{
  longjmp (jump_bAck, 0x0);
}


char *
nhost ()
{
  static char eq[1024];
  snprintf (eq, sizeof (eq), "%s(%s)", thathost, rlookup (gip));
  return eq;
}

int
settimeout (unsigned short sockh, unsigned short timeout)
{
  fd_set rfds;
  struct timeval tv;
  FD_ZERO (&rfds);
  FD_SET (sockh, &rfds);
  tv.tv_sec = timeout;
  tv.tv_usec = 0;
  select (sockh + 1, &rfds, NULL, NULL, &tv);
  if (!FD_ISSET (sockh, &rfds))
    {
      return 0;
    }
  else
    {
      return 1;
    }
  /* returns 0=timeout or error, 1=input there */
}

int
sockconnect (unsigned short timeout, unsigned long iP, unsigned short port)
{
  int sock_iT;
  struct sockaddr_in address;

  if ((sock_iT = socket (AF_INET, SOCK_STREAM, 0x0)) == -1)
    {
      return sock_iT;
    }

  address.sin_family = AF_INET;
  address.sin_port = htons (port);
  address.sin_addr.s_addr = iP;
  signal (SIGALRM, timed_out);
  alarm (30);

  if (setjmp (jump_bAck) == 0x0)
    {
      if (connect (sock_iT, (struct sockaddr *) (&address), sizeof (address)))
	{
	  sock_iT = -1;
	}
    }
  else
    {
      sock_iT = -1;
    }

  fflush (stdout);
  alarm (0);
  return sock_iT;

}

#ifdef X11CHECK
int
x11check (int fdi, FILE * output, unsigned long sip)
{
  char buf[200];
  struct in_addr ami;
  ami.s_addr = sip;

  bzero (buf, sizeof (buf));
  strcpy (buf, (char *) inet_ntoa (ami));
  strcat (buf, ":0");
  if (XOpenDisplay (buf) != NULL)
    {
      printf ("\n%s (%d): Open X11 Server\n", nhost (), giport);
      fprintf (output, "\n%s (%d): Open X11 Server\n", nhost (), giport);
      fflush (output);
      close (fdi);
      return 0;
    }
  close (fdi);
  return (-1);
}
#endif

int
squidder (int fdi, char *param)
{
  char buf[200];
  int length;
  snprintf (buf, sizeof (buf), "CONNECT chat.vtm.be:6667 HTTP/1.0\n\n");
  send (fdi, buf, strlen (buf), 0);
  while (settimeout (fdi, 10) == 1)
    {
      memset (buf, 0x0, sizeof (buf));
      length = recv (fdi, buf, sizeof (buf), 0);
      if (length > 0)
	{
	  if (strstr (buf, "200 "))
	    {
	      printf ("\n%s (%d): CONN Connections allowed\n", nhost (),
		      giport);
	      snprintf (param, sizeof (param) + 1,
			"CONN Connections allowed");
	      return fdi;
	    }
	}
      else
	{
	  printf ("\n%s (%d): No CONN-Connections\n", nhost (), giport);
	  snprintf (param, sizeof (param), "No CONN-Connections");
	  close (fdi);
	  return -1;
	}
    }
  printf ("\n%s (%d): No CONN-Connections\n", nhost (), giport);
  close (fdi);
  return -1;
}

int
lpdcheck (int fdi, FILE * output)
{
  char buf[200];
  int length;
  snprintf (buf, sizeof (buf), "\n");
  send (fdi, buf, strlen (buf), 0);
  length = recv (fdi, buf, sizeof (buf), 0);
  if (length > 0)
    {
      if (strstr (buf, "Invalid protocol request"))
	{
	  printf ("\n%s (%d): Solaris style lpd\n", nhost (), giport);
	  fprintf (output, "\n%s (%d): Solaris style lpd\n", nhost (),
		   giport);
	  fflush (output);
	  return fdi;
	}
    }
  else
    {
      printf ("\n%s (%d): Linux style lpd\n", nhost (), giport);
      fprintf (output, "\n%s (%d): Linux style lpd\n", nhost (), giport);
      fflush (output);
      return fdi;
    }
  printf ("\n%s (%d): non solaris lpd", nhost (), giport);
  fprintf (output, "\n%s (%d): non solaris lpd", nhost (), giport);
  fflush (stdout);
  return fdi;
}

int
squidder2 (int fdi, char *param)
{
  char buf[200];
  int length;
  snprintf (buf, sizeof (buf),
	    "POST http://chat.vtm.be:6667 HTTP/1.0\nContent-Length: 1000\n\nUSER sdf09889 a b :s80922\nNICK s092303\n");
  send (fdi, buf, strlen (buf), 0);
  while (settimeout (fdi, 10) == 1)
    {
      memset (buf, 0x0, sizeof (buf));
      length = recv (fdi, buf, sizeof (buf), 0);
      if (length > 0)
	{
	  if (strstr (buf, "ERROR :"))
	    {
	      printf ("\n%s (%d): POST Connections allowed\n", nhost (),
		      giport);
	      snprintf (param, sizeof (param) + 1,
			"POST Connections allowed");
	      return fdi;
	    }
	}
      else
	{
	  printf ("\n%s (%d): No POST-Connections\n", nhost (), giport);
	  snprintf (param, sizeof (param), "No POST-Connections");
	  close (fdi);
	  return -1;
	}
    }
  printf ("\n%s (%d): No POST-Connections\n", nhost (), giport);
  close (fdi);
  return -1;
}

int
fingercheck (int fdi, char *param)
{
  char buf[200];
  int length;
  snprintf (buf, sizeof (buf), "0 1 2 3 4 5 6 7 8 9");
  send (fdi, buf, strlen (buf), 0);
  while (settimeout (fdi, 10) == 1)
    {
      memset (buf, 0x0, sizeof (buf));
      length = recv (fdi, buf, sizeof (buf), 0);
      if (length > 0)
	{
	  if (strstr (buf, " .  .  .  . "))
	    {
	      printf ("\n%s (%d): fingerd - expired users on solaris\n",
		      nhost (), giport);
	      snprintf (param, sizeof (param),
			"fingerd - expired users on solaris");
	      return fdi;
	    }
	}
      else
	{
	  printf ("\n%s (%d): fingerd not vuln\n", nhost (), giport);
	  snprintf (param, sizeof (param), "fingerd not vuln");
	  close (fdi);
	  return -1;
	}
    }
  printf ("\n%s (%d): fingerd not vuln\n", nhost (), giport);
  close (fdi);
  return -1;
}

int
gettelnet (int fdi, FILE * output)
{
  int sockit, length;
  unsigned char data[4096];


  sockit = fdi;

/*  if ( port == 79 ) { 
    write( sockit, "\n", strlen( "\n" ));
  }
*/

  while (0x1)
    {
      memset (data, 0x0, sizeof (data));
      if (!(read (sockit, data, 0x1) == 0x1))
	{
	  close (fdi);
	  return -1;
	}

/* -- is it an IAC code .. then say that we DON'T know any options -- */

      if (*data == 255)
	{
	  read (sockit, data + 0x1, 0x2);

	  if (data[0x1] == 253)
	    {
	      if (!(data[0x2] == 0x0))
		{
		  data[0x1] = 252;
		  write (sockit, data, 0x3);
		}
	    }
	}
      else
	{
	  while (settimeout (fdi, 10) == 1)
	    {
	      memset (data, 0x0, sizeof (data));
	      length = recv (fdi, data, sizeof (data), 0);
	      if (strlen (data) > 10)
		{
		  printf ("\n%s (%d): %s\n", nhost (), giport, data);
		  fprintf (output, "\n%s (%d): %s\n", nhost (), giport, data);
		  fflush (output);
		}
	    }
	  return fdi;
	}
    }
}

int
getbanner (int fdi, char *param)
{
  char buf[200];
  int length;
  while (settimeout (fdi, 10) == 1)
    {
      memset (buf, 0x0, sizeof (buf));
      length = recv (fdi, buf, sizeof (buf), 0);
      snprintf (param, 399, "%s", buf);
      printf ("\n%s (%d): %s\n", nhost (), giport, param);
      return fdi;
    }
  printf ("\n%s (%d): timed out response\n", nhost (), giport);
  close (fdi);
  return -1;
}

int
is_samba (char *ip, unsigned long time_out, FILE * output)
{
  char nbtname[] =		/* netbios name packet */
  {
    0x80, 0xf0, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x20, 0x43, 0x4b, 0x41,
    0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
    0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
    0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
    0x41, 0x41, 0x41, 0x41, 0x41, 0x00, 0x00, 0x21,
    0x00, 0x01
  };

  unsigned char recv_buf[1024];
  unsigned char *ptr;

  int i = 0;
  int s = 0;

  unsigned int total = 0;

  if ((s = socket (PF_INET, SOCK_DGRAM, 17)) <= 0)
    return -1;

  if (Connect (s, ip, 137, time_out) == -1)
    {
      close (s);
      return -1;
    }

  memset (recv_buf, 0x00, sizeof (recv_buf));

  if (write_timer (s, time_out) == 1)
    {
      if (write (s, nbtname, sizeof (nbtname)) <= 0)
	{
	  close (s);
	  return -1;
	}
    }

  if (read_timer (s, time_out) == 1)
    {
      if (read (s, recv_buf, sizeof (recv_buf)) <= 0)
	{
	  close (s);
	  return -1;
	}

      ptr = recv_buf + 57;
      total = *(ptr - 1);	/* max names */

      while (ptr < recv_buf + sizeof (recv_buf))
	{
	  ptr += 18;
	  if (i == total)
	    {

	      ptr -= 19;

	      if (*(ptr + 1) == 0x00 && *(ptr + 2) == 0x00
		  && *(ptr + 3) == 0x00 && *(ptr + 4) == 0x00
		  && *(ptr + 5) == 0x00 && *(ptr + 6) == 0x00)
		{
		  close (s);
		  printf ("\n%s (%d): Samba found \n", nhost (), giport);
		  fprintf (output, "\n%s (%d): Samba found\n", nhost (),
			   giport);
		  fflush (output);
		  return 0;
		}

	      close (s);
	      printf ("\n%s (%d): Doze-SMB found \n", nhost (), giport);
/* this line comented out, we dont care about doze
            			fprintf(output, "\n%s (%d): Doze-SMB found\n",nhost(),giport);
                                fflush(output);
*/
	      return 1;
	    }

	  i++;
	}

    }
  close (s);
  printf ("\n%s (%d): dead host", nhost (), giport);
  fflush (stdout);
  return -1;
}
int
wvcheck (int fdi, FILE * output)
{
  char buf[200], *start, *end;
  int length;
/*
    if (fdi!=-1)
    {
       close(fdi);
       fprintf(output,"%s : %s\r\n",nhost(),buf);
    }
    fdi=sockconnect(10,gip,giport);
*/
  memset (buf, 0x0, sizeof (buf));
  alarm (15);			/* for http reply */
  sprintf (buf, "HEAD / HTTP/1.0\n\n");
  send (fdi, buf, strlen (buf), 0);
  while (settimeout (fdi, 10) == 1)
    {
      memset (buf, 0x0, sizeof (buf));
      length = recv (fdi, buf, sizeof (buf), 0);
      if (length > 0)
	{
	  if (strstr (buf, "Server: "));
	  {
	    printf ("got server:\n");
	    start = strstr (buf, "Server: ");
	    end = strchr (start, 10);
	    if (end != NULL)
	      {
		end[0] = 0;
	      }
	    printf ("\n%s (%d): %s\n", nhost (), giport, start);
	    fprintf (output, "%s (%d): %s\n", nhost (), giport, start);
	    fflush (stdout);
	    close (fdi);
	    break;
	  }
	}
      sleep (1);
    }
  alarm (0);
  return -1;
}


int
rpccheck (int fdi, FILE * output)
{
  struct sockaddr_in rpc;
  struct pmaplist *pmap, *spmap;
  int rpcid, nop;
  FILE *rpcs;
  char rpcline[1024], rpcp[1024];
  struct hostent *ho;
  char *moe;

  if ((ho = gethostbyname (thathost)) == NULL)
    return -1;

  memset (&rpc, 0, sizeof (struct sockaddr_in));
  rpc.sin_family = AF_INET;
  rpc.sin_port = htons (PMAPPORT);
  memcpy (&rpc.sin_addr.s_addr, ho->h_addr_list[0], ho->h_length);

  if ((pmap = pmap_getmaps (&rpc)) == NULL)
    return -1;
  spmap = pmap;

  rpcs = fopen ("rpcs.txt", "r");
  if (rpcs == NULL)
    return -1;
  while (fgets (rpcline, sizeof (rpcline), rpcs))
    {
      moe = strchr (rpcline, ' ');
      if (moe != NULL)
	{
	  *moe = 0;
	  moe++;
	  rpcid = atol (rpcline);
	  strcpy (rpcp, moe);
	  moe = strchr (rpcp, '\n');
	  if (moe != NULL)
	    *moe = 0;
	}
      else
	{
	  rpcid = 0;
	  strcpy (rpcp, "(invalid)");
	}
      pmap = spmap;
      for (; pmap != NULL; pmap = pmap->pml_next)
	{
	  if (pmap->pml_map.pm_prog == rpcid)
	    {
	      printf ("%s : Found RPC %s\n", nhost (), rpcp);
	      fprintf (output, "%s : RPC :%s\r\n", nhost (), rpcp);
	      fflush (output);
//	      break;
	      goto eg;
	    }
	}
    eg:
nop=1;
    }
  fclose (rpcs);
  close (fdi);
  return -1;
}

int
bindcheck (int fdi, FILE * output)
{
  close (fdi);
  if (pbind (thathost) == 1)
    {
      fprintf (output, "%s", bndver);
    }
  else
    {
      printf ("%s : bind not vuln.\n", nhost ());
    }
  fflush (output);
  return -1;
}

int
cgicheck (int fdi, char *file, FILE * output)
{
  FILE *cgis;
  char *pt;
  char cgiline[600];
  char buf[4096];
  int approved;
  int length;
  fflush (stdout);
  if ((cgis = fopen ("cgis.txt", "r")) == NULL)
    {
      wvcheck (fdi, output);
      return -1;
    }

  /* closing it */
  fdi = squidder (fdi, buf);
  fflush (stdout);
  if (fdi != -1)
    {
      close (fdi);
      fprintf (output, "%s : %s\r\n", nhost (), buf);
    }
  while (fgets (cgiline, sizeof (cgiline), cgis))
    {
      approved = 0;
      fdi = sockconnect (10, gip, giport);
      if (fdi == -1)
	{
	  printf ("\n%s (%d) : cant connect, aborting.\n", nhost (), giport);
	  return -1;
	}
      pt = strchr (cgiline, '\r');
      if (pt == NULL)
	pt = strchr (cgiline, '\n');
      if (pt != NULL)
	*pt = 0;
      snprintf (buf, sizeof (buf), "%s\n\n", cgiline);
      write (fdi, buf, strlen (buf));
      while (settimeout (fdi, 10) == 1)
	{
	  memset (buf, 0x0, sizeof (buf));
	  length = read (fdi, buf, sizeof (buf));
	  if (length == 0)
	    goto ttt;
	  if (approved == 1)
	    {
	      fputs (buf, output);
	    }
	  if (approved == 0 && strstr (buf, " 200 ") != NULL)
	    {
	      approved = 1;
	      printf ("\n%s (%d) CGI (%s): vulnerable\n", nhost (), giport,
		      cgiline);
	      fflush (stdout);
	      fprintf (output, "%s : %s vulnerable, playing output :\r\n",
		       nhost (), cgiline);
	    }
	}
    ttt:
      if (approved == 0)
	printf ("\n%s (%d) CGI (%s) not vulnerable\n", nhost (), giport,
		cgiline);
      fflush (stdout);
      close (fdi);
    }
  fclose (cgis);
  fflush (output);
  return -1;
}

void
brokenpipe ()
{
  printf ("\n%s (%d): broken Pipe\n", thathost, giport);
  return;
}

int
tcpconnect (unsigned long sip,
	    unsigned long iP,
	    unsigned short port,
	    unsigned short timeout,
	    unsigned short iiport, char *param, FILE * output)
{

  int sock_iT, rc;
  struct sigaction sv;
  struct hostent *athost;
  struct sockaddr_in addr;
  char buffer[512];
  int tries, length;

  char scheisse2[100];
  sock_iT = -1;
  tries = 0;
/* no, this cant be exploited because nlookup only returns 16 bytes */
  strcpy (thathost, nlookup (sip));
  giport = iiport;
  sigemptyset (&sv.sa_mask);
  sv.sa_handler = brokenpipe;
  sigaction (SIGPIPE, &sv, NULL);


  addr.sin_addr.s_addr = sip;

athost = gethostbyaddr ((char *) &addr.sin_addr, sizeof (addr.sin_addr), AF_INET);

  *param = 0;
  fprintf (stdout, "\n%s : Port %d open\n", rlookup (sip), iiport);
  fflush (stdout);
  if ((sock_iT = sockconnect (timeout, sip, iiport)) == -1)
    {
      sock_iT = -1;
      return sock_iT;
    }
  if (sock_iT == -1)
    {
      return sock_iT;
    }
  else
    {
      giport = iiport;
      gip = sip;
      if (iiport == 3128 || iiport == 8080)
	{
	  rc = squidder (sock_iT, param);
	  if (rc == -1)
	    {
	      sock_iT = sockconnect (timeout, sip, iiport);
	      if (sock_iT == -1)
		return -1;
	      rc = squidder2 (sock_iT, param);
	    }
	  return rc;
	}
      if (iiport == 515)
	{
	  return lpdcheck (sock_iT, output);
	}
      if (iiport == 139)
	{
	  snprintf (scheisse2, 256, "%s", nlookup (sip));
	  return is_samba (scheisse2, 15, output);
	}
      if (iiport == 111)
	{
	  return rpccheck (sock_iT, output);
	}
      if (iiport == 23)
	{
	  return gettelnet (sock_iT, output);
	}
      if (iiport == 80)
	{
	  return cgicheck (sock_iT, param, output);
	}
      if (iiport == 443)
	{
	  return cgicheck (sock_iT, param, output);
	}
      if (iiport == 79)
	{
	  return fingercheck (sock_iT, param);
	}
      if (iiport == 53)
	{
	  return bindcheck (sock_iT, output);
	}
#ifdef X11CHECK
      if (iiport == 6000)
	{
	  return x11check (sock_iT, output, sip);
	}
#endif
      if (iiport != 1080)
	return getbanner (sock_iT, param);
      snprintf (buffer, sizeof (buffer), "\x04\x01%c%c%c%c%c%c",
		(giport >> 8) & 0xFF, giport & 0xFF,
		(char) athost->h_addr[0],
		(char) athost->h_addr[1],
		(char) athost->h_addr[2], (char) athost->h_addr[3]);
      length = 8;
      if (1)
	{
	  send (sock_iT, buffer, length + 1, 0);
	  if (settimeout (sock_iT, timeout) == 1)
	    {
	      if ((length = recv (sock_iT, buffer, length, 0)) <= 0)
		{
		  /*alarm (0x0); */
		  close (sock_iT);
		  sock_iT = -1;
		  return -1;
		}
	      else
		{
		  if (buffer[1] == 0x5b)
		    sock_iT = -1;
		}
	    }
	  else
	    {
	      close (sock_iT);
	      sock_iT = -1;
	    }
	}
      else
	{
	  sock_iT = -1;
	}
    }


  /*alarm( 0x0 );
   */
  if (sock_iT != -1)
    {
      printf ("\n%s (%d): SOCKS4\n", thathost, giport);
      strcpy (param, "SOCKS4");
    }
  fflush (output);
  return sock_iT;
}


int
Connect (int fd, char *ip, unsigned int port, unsigned int time_out)
{
  /* ripped from no1 */

  int flags;
  int select_status;
  fd_set connect_read, connect_write;
  struct timeval timeout;
  int getsockopt_length = 0;
  int getsockopt_error = 0;
  struct sockaddr_in server;
  bzero (&server, sizeof (server));
  server.sin_family = AF_INET;
/*        inet_pton(AF_INET, ip, &server.sin_addr); */
  server.sin_addr.s_addr = inet_addr (ip);
/*        inet_aton(ip, &server.sin_addr); */
  server.sin_port = htons (port);

  if ((flags = fcntl (fd, F_GETFL, 0)) < 0)
    {
      close (fd);
      return -1;
    }

  if (fcntl (fd, F_SETFL, flags | O_NONBLOCK) < 0)
    {
      close (fd);
      return -1;
    }

  timeout.tv_sec = time_out;
  timeout.tv_usec = 0;
  FD_ZERO (&connect_read);
  FD_ZERO (&connect_write);
  FD_SET (fd, &connect_read);
  FD_SET (fd, &connect_write);

  if ((connect (fd, (struct sockaddr *) &server, sizeof (server))) < 0)
    {
      if (errno != EINPROGRESS)
	{
	  close (fd);
	  return -1;
	}
    }
  else
    {
      if (fcntl (fd, F_SETFL, flags) < 0)
	{
	  close (fd);
	  return -1;
	}

      return 1;

    }

  select_status =
    select (fd + 1, &connect_read, &connect_write, NULL, &timeout);

  if (select_status == 0)
    {
      close (fd);
      return -1;

    }

  if (select_status == -1)
    {
      close (fd);
      return -1;
    }

  if (FD_ISSET (fd, &connect_read) || FD_ISSET (fd, &connect_write))
    {
      if (FD_ISSET (fd, &connect_read) && FD_ISSET (fd, &connect_write))
	{
	  getsockopt_length = sizeof (getsockopt_error);

	  if (getsockopt
	      (fd, SOL_SOCKET, SO_ERROR, &getsockopt_error,
	       &getsockopt_length) < 0)
	    {
	      errno = ETIMEDOUT;
	      close (fd);
	      return -1;
	    }

	  if (getsockopt_error == 0)
	    {
	      if (fcntl (fd, F_SETFL, flags) < 0)
		{
		  close (fd);
		  return -1;
		}
	      return 1;
	    }

	  else
	    {
	      errno = getsockopt_error;
	      close (fd);
	      return (-1);
	    }

	}
    }
  else
    {
      close (fd);
      return 1;
    }

  if (fcntl (fd, F_SETFL, flags) < 0)
    {
      close (fd);
      return -1;
    }
  return 1;
}

int
read_timer (int fd, unsigned int time_out)
{

  /* ripped from no1 */

  int flags;
  int select_status;
  fd_set fdread;
  struct timeval timeout;

  if ((flags = fcntl (fd, F_GETFL, 0)) < 0)
    {
      close (fd);
      return (-1);
    }

  if (fcntl (fd, F_SETFL, flags | O_NONBLOCK) < 0)
    {
      close (fd);
      return (-1);
    }

  timeout.tv_sec = time_out;
  timeout.tv_usec = 0;
  FD_ZERO (&fdread);
  FD_SET (fd, &fdread);
  select_status = select (fd + 1, &fdread, NULL, NULL, &timeout);

  if (select_status == 0)
    {
      close (fd);
      return (-1);
    }

  if (select_status == -1)
    {
      close (fd);
      return (-1);
    }

  if (FD_ISSET (fd, &fdread))
    {

      if (fcntl (fd, F_SETFL, flags) < 0)
	{
	  close (fd);
	  return -1;
	}

      return 1;

    }
  else
    {
      close (fd);
      return 1;

    }
}
int
write_timer (int fd, unsigned int time_out)
{

  /* ripped from no1 */

  int flags;
  int select_status;
  fd_set fdwrite;
  struct timeval timeout;

  if ((flags = fcntl (fd, F_GETFL, 0)) < 0)
    {
      close (fd);
      return (-1);
    }

  if (fcntl (fd, F_SETFL, flags | O_NONBLOCK) < 0)
    {
      close (fd);
      return (-1);
    }

  timeout.tv_sec = time_out;
  timeout.tv_usec = 0;
  FD_ZERO (&fdwrite);
  FD_SET (fd, &fdwrite);

  select_status = select (fd + 1, NULL, &fdwrite, NULL, &timeout);

  if (select_status == 0)
    {
      close (fd);
      return -1;
    }

  if (select_status == -1)
    {
      close (fd);
      return -1;
    }

  if (FD_ISSET (fd, &fdwrite))
    {
      if (fcntl (fd, F_SETFL, flags) < 0)
	{
	  close (fd);
	  return -1;
	}
      return 1;
    }
  else
    {
      close (fd);
      return -1;
    }
}

