/*
 *	Novell Network Core Protocol Support - by David Maciejak @ GMAIL dot com
 *	Tested on Netware 6.5
 * 
 * you need to install libncp and libncp-dev (tested with version 2.2.6-3)
 * 
 *	you can passed full context as OPT
 *
 * example: ./hydra -L login -P passw 172.16.246.129 ncp .O=cx
 *
 */


#include "hydra-mod.h"

#ifndef LIBNCP
void
dummy_ncp()
{
  printf("\n");
}
#else

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ncp/nwcalls.h>

extern char *HYDRA_EXIT;

typedef struct __NCP_DATA {
  struct ncp_conn_spec spec;
  struct ncp_conn *conn;
  char *context;
} _NCP_DATA;

//uncomment line below to see more trace stack
//#define NCP_DEBUG

int start_ncp(int s, unsigned long int ip, int port, unsigned char options, char *miscptr, FILE * fp)
{

char* login;
char* pass;
char context[256];
unsigned int ncp_lib_error_code;
struct sockaddr_in remote_ip;
char *empty = "";
int object_type = NCP_BINDERY_USER;

_NCP_DATA* session;


memset(&remote_ip, 0, sizeof(remote_ip));
memcpy(&remote_ip.sin_addr.s_addr, &ip, 4);
remote_ip.sin_family = AF_INET;

session = malloc(sizeof(_NCP_DATA));  
memset(session, 0, sizeof(_NCP_DATA));
login=empty;
pass=empty;


	if (strlen(login = hydra_get_next_login()) == 0) {
		login = empty;
	}
	else {
  if (miscptr) {
		  if (strlen(miscptr)+strlen(login) > sizeof(context))
		  {
				return 4;
		  }
		  memset(context, 0, sizeof(context));
        strncpy(context, login, strlen(login));
        strncpy(context+strlen(login), miscptr, sizeof(miscptr)+1);
		  login=context;
		}
	}

  //login and password are case insensitive
  //str_upper(login);

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

ncp_lib_error_code = ncp_find_conn_spec3(inet_ntoa((struct in_addr) remote_ip.sin_addr), login, "", 1, getuid(), 0, &session->spec);
if (ncp_lib_error_code)
{ free(session);return 1;}

ncp_lib_error_code = NWCCOpenConnByName(NULL, session->spec.server, NWCC_NAME_FORMAT_BIND, NWCC_OPEN_NEW_CONN, NWCC_RESERVED, &session->conn);
if (ncp_lib_error_code)
{ free(session);return 1;}

  memset(session->spec.password, 0, sizeof(session->spec.password));
  memcpy(session->spec.password, pass, strlen(pass)+1);
  //str_upper(session->spec.password);

ncp_lib_error_code = ncp_login_conn(session->conn, session->spec.user, object_type, session->spec.password);
 switch (ncp_lib_error_code & 0x0000FFFF)
  {
    case 0x0000:  /* Success */
      #ifdef NCP_DEBUG
		printf("Connection success (%s / %s). Error code: %X\n", login, pass, ncp_lib_error_code);
		#endif
		ncp_close(session->conn);
		hydra_report_found_host(port, ip, "ncp", fp); //ok
		hydra_completed_pair();
		if (memcmp(hydra_get_next_pair(), &HYDRA_EXIT, sizeof(HYDRA_EXIT)) == 0)
			return 3; //exit
		free(session);
		return 2; //next
      break;
    case 0x89DE: /* PASSWORD INVALID */
    case 0x89F0: /* BIND WILDCARD INVALID */
	 case 0x89FF: /* NO OBJ OR BAD PASSWORD */
    case 0xFD63: /* FAILED_AUTHENTICATION */
	 case 0xFDA7: /* NO_SUCH_ENTRY */
      #ifdef NCP_DEBUG
		printf("Incorrect password (%s / %s). Error code: %X\n", login, pass, ncp_lib_error_code);
		#endif
		ncp_close(session->conn);
     	hydra_completed_pair();
     	if (memcmp(hydra_get_next_pair(), &HYDRA_EXIT, sizeof(HYDRA_EXIT)) == 0)
		{
						free(session);
            		return 2;    //next
		}
      break;
    default:
		#ifdef NCP_DEBUG
      printf("Failed to open connection. Error code: %X\n",ncp_lib_error_code);
		#endif
	if (session->conn != NULL) ncp_close(session->conn);
      break;
  }
 free(session);
 return 1; //reconnect
}

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

	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);
					if (port != 0)
						myport = port;
					sock = hydra_connect_tcp(ip, myport);
					port = myport;
				if (sock < 0)
				{
					fprintf(stderr, "Error: Child with pid %d terminating, can not connect\n", (int) getpid());
					hydra_child_exit(1);
				}
				
				next_run = 2;
				break;

			case 2:
      
      				/*
      				 *	Here we start the password cracking process  
				     */
                
				next_run = start_ncp(sock, ip, port, options, miscptr, fp);
				break;
			case 3:
				
				if (sock >= 0)
					sock = hydra_disconnect(sock);
				hydra_child_exit(0);
				return;

		  case 4:

				fprintf(stderr, "Optional parameter too long!\n");
				hydra_child_exit(0);
				exit(-1);
		
			default:
			
				fprintf(stderr, "Caught unknown return code, exiting!\n");
				hydra_child_exit(0);
				exit(-1);
		}
		run = next_run;
	}
}

#endif
