
/*
 * Unusually, some words about the LDAP module here
 *
 * Sometimes, you need a DN to authenticate to. If you do not now the DN
 * you have to guess it. To make the module flexible, you can do the following:
 *
 * use either   -l dn-scope   or   -m dn-scope   to define a fix one
 *              -L DN-GUESS-FILE                 to guess password AND dn
 * or none of these, and the module will try to authenticate to an empty
 * dn-scope
 *
 * Have fun, van Hauser / THC
 *
 */

#include "hydra-mod.h"

extern char *HYDRA_EXIT;

char *buf;
int counter;

int
start_ldap(int s, unsigned long int ip, int port, unsigned char options, char *miscptr, FILE * fp, char version)
{
  char *empty = "";
  char *login = "", *pass, buffer[512];
  int length;

  if (miscptr == NULL) {
    if (strlen(login = hydra_get_next_login()) == 0)
      login = empty;
  } else
    login = miscptr;
  if (strlen(pass = hydra_get_next_password()) == 0)
    pass = empty;

  length = 14 + strlen(login) + strlen(pass);

  memset(buffer, 0, sizeof(buffer));
  buffer[0] = 48;
  buffer[1] = length - 2;

  buffer[2] = 2;
  buffer[3] = 1;
  buffer[4] = counter % 256;

  buffer[5] = 96;
  buffer[6] = length - 7;
  buffer[7] = 2;
  buffer[8] = 1;
  buffer[9] = version;

  buffer[10] = 4;
  buffer[11] = strlen(login);   /* DN */
  memcpy(&buffer[12], login, strlen(login));

  buffer[12 + strlen(login)] = (unsigned char) 128;
  buffer[13 + strlen(login)] = strlen(pass);
  memcpy(&buffer[14 + strlen(login)], pass, strlen(pass));      /* PASS */

  if (hydra_send(s, buffer, length, 0) < 0)
    return 1;
  if ((buf = hydra_receive_line(s)) == NULL)
    return 1;

  /* success is: 0a 01 00 - failure is: 0a 01 31 */
  if ((buf[0] != 0 && buf[9] == 0) || (buf[0] != 32 && buf[9] == 32)) {
    hydra_report_found_host(port, ip, "ldap", fp);
    hydra_completed_pair_found();
    if (memcmp(hydra_get_next_pair(), &HYDRA_EXIT, sizeof(HYDRA_EXIT)) == 0)
      return 3;
    return 1;
  }

  if ((buf[0] != 0 && buf[0] != 32) && buf[9] == 2) {
    hydra_report(stderr, "Invalid protocol version, you tried ldap%c, better try ldap%c\n", version + '0', version == 2 ? '3' : '2');
    hydra_child_exit(2);
    sleep(1);
    exit(-1);
  }

  if (buf[9] != 49 && buf[9] != 2) {
    hydra_report(stderr, "Uh, unknown LDAP response, remember, this module is beta! Please report this:\n");
    hydra_report(stderr, "Dump: %.2x %.2x %.2x %.2x  %.2x %.2x %.2x %.2x   %.2x %.2x %.2x %.2x  %.2x %.2x %.2x %.2x\n",
            buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
    return 3;
  }

  hydra_completed_pair();
  if (memcmp(hydra_get_next_pair(), &HYDRA_EXIT, sizeof(HYDRA_EXIT)) == 0)
    return 3;
  return 2;
}

void
service_ldap(unsigned long int ip, int sp, unsigned char options, char *miscptr, FILE * fp, int port, char version)
{
  int run = 1, next_run, sock = -1;
  int myport = PORT_LDAP, mysslport = PORT_LDAP_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(275000);
      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) {
        fprintf(stderr, "Error: Child with pid %d terminating, can not connect\n", (int) getpid());
        hydra_child_exit(1);
      }
      counter = 1;
      next_run = 2;
      break;
    case 2:                    /* run the cracking function */
      next_run = start_ldap(sock, ip, port, options, miscptr, fp, version);
      counter++;
      break;
    case 3:                    /* clean exit */
      if (sock >= 0)
        sock = hydra_disconnect(sock);
      hydra_child_exit(0);
      return;
    default:
      fprintf(stderr, "Caught unknown return code, exiting!\n");
      hydra_child_exit(0);
      exit(-1);
    }
    run = next_run;
  }
}

void service_ldap2(unsigned long int ip, int sp, unsigned char options, char *miscptr, FILE * fp, int port) {
  service_ldap(ip, sp, options, miscptr, fp, port, 2);
}

void service_ldap3(unsigned long int ip, int sp, unsigned char options, char *miscptr, FILE * fp, int port) {
  service_ldap(ip, sp, options, miscptr, fp, port, 3);
}
