
/*
 * Some of the code ripped from FX/Phenolite :-)
 *
 */

#ifdef PALM
#include "palm/hydra-mod.h"
#else
#include "hydra-mod.h"
#endif

#include "d3des.h"

#define CHALLENGESIZE 16

extern char *HYDRA_EXIT;
char *buf;

/*
 * Encrypt CHALLENGESIZE bytes in memory using a password.
 * Ripped from vncauth.c
 */

void
vncEncryptBytes(unsigned char *bytes, char *passwd)
{
  unsigned char key[8];
  int i;

  /* key is simply password padded with nulls */
  for (i = 0; i < 8; i++) {
    if (i < strlen(passwd)) {
      key[i] = passwd[i];
    } else {
      key[i] = 0;
    }
  }
  deskey(key, EN0);
  for (i = 0; i < CHALLENGESIZE; i += 8) {
    des(bytes + i, bytes + i);
  }
}

int
start_vnc(int s, unsigned long int ip, int port, unsigned char options, char *miscptr, FILE * fp)
{
  char *empty = "";
  char *pass;

  if (strlen(pass = hydra_get_next_password()) == 0)
    pass = empty;

  buf = malloc(CHALLENGESIZE + 4);
#ifdef PALM
  if (hydra_recv(s, buf, 20) != 20)
#else
  if (recv(s, buf, 20, 0) != 20)
#endif
    return 4;

      switch (buf[3]) {
      case 0:
      case 32:
        hydra_report(stderr, "Error: VNC server told us to quit\n");
        hydra_child_exit(0);
#ifdef PALM
        return -1;
#else
        exit(-1);
#endif
      case 1:
        hydra_report(fp, "VNC server does not require authentication.\n");
        if (fp != stdout)
          hydra_report(stdout,"VNC server does not require authentication.\n");
        hydra_child_exit(2);
#ifdef PALM
        return -1;
#else
        exit(-1);
#endif
      case 2:
        break;
      default:
        hydra_report(stderr, "Error: unknown VNC authentication type\n");
        hydra_child_exit(2);
#ifdef PALM
        return -1;
#else
        exit(-1);
#endif
      }

  vncEncryptBytes((unsigned char *) (buf + 4), pass);

  if (hydra_send(s, buf + 4, CHALLENGESIZE, 0) < 0) {
    return 1;
  }
  free(buf);

  if ((buf = hydra_receive_line(s)) == NULL)
    return 1;

  switch (buf[3]) {
  case 0:
  case 32:
    hydra_report_found_host(port, ip, "vnc", fp);
    hydra_completed_pair_found();
    free(buf);
    if (memcmp(hydra_get_next_pair(), &HYDRA_EXIT, sizeof(HYDRA_EXIT)) == 0)
      return 3;
    return 1;
  case 1:
    free(buf);
    hydra_completed_pair();
    if (memcmp(hydra_get_next_pair(), &HYDRA_EXIT, sizeof(HYDRA_EXIT)) == 0)
      return 3;
    return 1;
  case 2:
    free(buf);
    if (verbose)
      hydra_report(stdout,"[VERBOSE] VNC server is angry, waiting for a minute\n");
    hydra_disconnect(s);
    sleep(60);
    return 1;
  default:
    free(buf);
    hydra_report(stderr, "Error: unknown VNC server response\n");
    return 1;
  }

  return 1;                     /* never reached */
}

void
service_vnc(unsigned long int ip, int sp, unsigned char options, char *miscptr, FILE * fp, int port)
{
  int run = 1, next_run = 1, sock = -1;
  int myport = PORT_VNC, mysslport = PORT_VNC_SSL;

  hydra_register_socket(sp);
  if (memcmp(hydra_get_next_pair(), &HYDRA_EXIT, sizeof(HYDRA_EXIT)) == 0)
    return;
  while (1) {
    switch (run) {
    case 1:                    /* connect and service init function */
      if (sock >= 0)
        sock = hydra_disconnect(sock);
//      usleep(300000);
      if ((options & OPTION_SSL) == 0) {
        if (port != 0)
          myport = port;
        sock = hydra_connect_tcp(ip, myport);
        port = myport;
      } else {
        if (port != 0)
          mysslport = port;
        sock = hydra_connect_ssl(ip, mysslport);
        port = mysslport;
      }
      if (sock < 0) {
        hydra_report(stderr, "Error: Child with pid %d terminating, can not connect\n", (int) getpid());
        hydra_child_exit(1);
      }
      buf = hydra_receive_line(sock);
#ifdef PALM
      if (buf == NULL || (StrNCompare(buf, "RFB", 3) != 0)) { /* check the first line */
#else
      if (buf == NULL || (strncmp(buf, "RFB", 3) != 0)) { /* check the first line */
#endif
        hydra_report(stderr, "Error: Not an VNC protocol or service shutdown: %s\n", buf);
        hydra_child_exit(2);
#ifdef PALM
        return;
#else
        exit(-1);
#endif
      }
      if (buf == NULL) {
        hydra_report(stderr, "No response from server, exiting...\n");
        next_run = 3;
      }
#ifdef PALM
      if (buf != NULL && (StrCompare(buf, "RFB.003.003") != 0)) { /* check the first line */
#else
      if (buf != NULL && (strcmp(buf, "RFB.003.003") != 0)) { /* check the first line */
#endif
        hydra_report(stderr, "Warning: protocol %s is not verified to work. Please report if not.\n", buf);
        free(buf);
        buf = strdup("RFC.003.003");
      }
      if (buf != NULL) {
        hydra_send(sock, buf, strlen(buf), 0);
        free(buf);
        next_run = 2;
      }
      break;
    case 2:                    /* run the cracking function */
      next_run = start_vnc(sock, ip, port, options, miscptr, fp);
      break;
    case 3:                    /* clean exit */
      if (sock >= 0)
        sock = hydra_disconnect(sock);
      hydra_child_exit(0);
      return;
    case 4:
      if (sock >=0)
        sock = hydra_disconnect(sock);
      hydra_child_exit(2);
      return;
    default:
      hydra_report(stderr, "Caught unknown return code, exiting!\n");
      hydra_child_exit(0);
#ifdef PALM
        return;
#else
        exit(-1);
#endif
    }
    run = next_run;
  }
}
