/*
 *	Apple Filing Protocol Support - by David Maciejak @ GMAIL dot com
 *	
 *	based on pMonkey <pmonkey@foofus.net> GPL code
 *
 *	tested with afpfs-ng 0.8.1
 *	AFPFS-NG: http://alexthepuffin.googlepages.com/home
 *
 */

#include "hydra-mod.h"

#ifndef LIBAFP
void
dummy_afp()
{
  printf("\n");
}
#else

#define FREE(x) \
        if (x != NULL) { \
           free(x); \
           x = NULL; \
        }

#include <stdio.h>
#include <afpfs-ng/afp.h>
#include <afpfs-ng/libafpclient.h>

extern char *HYDRA_EXIT;

void
stdout_fct(void * priv, enum loglevels loglevel, int logtype, const char *message)
{
  //fprintf(stderr, "Caught unknown error %s\n", message);
}

static struct libafpclient afpclient = {
        .unmount_volume = NULL,
        .log_for_client = stdout_fct,
        .forced_ending_hook = NULL,
        .scan_extra_fds = NULL,
        .loop_started = NULL ,
};

static int
server_subconnect(struct afp_url url)
{
  struct afp_connection_request *conn_req;
  struct afp_server * server = NULL;

  conn_req = malloc( sizeof(struct afp_connection_request) );
  server = malloc( sizeof(struct afp_server) );
 
  memset(conn_req, 0, sizeof(struct afp_connection_request));

  conn_req->url=url;
  conn_req->url.requested_version=31;

  //fprintf(stderr, "AFP connection - username: %s password: %s server: %s\n", url.username, url.password, url.servername); 

  if (strlen(url.uamname) > 0) 
  {
    if ((conn_req->uam_mask = find_uam_by_name(url.uamname)) == 0) {
      fprintf(stderr,  "Unknown UAM: %s", url.uamname); 
      FREE(conn_req);
      FREE(server);
      return -1;
    }
  } 
  else 
  {
    conn_req->uam_mask=default_uams_mask();
  }

  //fprintf(stderr,  "Initiating connection attempt.\n");
  if ((server = afp_server_full_connect(NULL, conn_req)) == NULL) 
  {
    FREE(conn_req);
    FREE(server);
    return -1;
  }

  //fprintf(stderr,  "Connected to server: %s via UAM: %s\n", server->server_name_printable, uam_bitmap_to_string(server->using_uam));

  FREE(conn_req);
  FREE(server);

  return 0;
}

int
start_afp(int s, unsigned long int ip, int port, unsigned char options, char *miscptr, FILE * fp)
{
  char *empty = "";
  char *login, *pass;
  struct in_addr remote_ip;

  struct afp_url tmpurl;
 
  /* Build AFP authentication request */ 
  libafpclient_register(&afpclient);  
  afp_main_quick_startup(NULL);  
  init_uams();
  afp_default_url(&tmpurl);

  remote_ip.s_addr = ip;
    
    
  if (strlen(login = hydra_get_next_login()) == 0)
	login = empty;
  if (strlen(pass = hydra_get_next_password()) == 0)
	pass = empty;

  memcpy(&tmpurl.servername, inet_ntoa(remote_ip), AFP_SERVER_NAME_LEN); 
  memcpy(&tmpurl.username, login, AFP_MAX_USERNAME_LEN);
  memcpy(&tmpurl.password, pass, AFP_MAX_PASSWORD_LEN);

  if ( server_subconnect(tmpurl) == 0 ) {
	hydra_report_found_host(port, ip, "afp", fp);
	hydra_completed_pair();
	if (memcmp(hydra_get_next_pair(), &HYDRA_EXIT, sizeof(HYDRA_EXIT)) == 0)
		return 3;
	return 2;
  } else {

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

void
service_afp(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_AFP;

	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 ((options & OPTION_SSL) == 0) 
				{
					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_afp(sock, ip, port, options, miscptr, fp);
				break;
			case 3:
				
				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;
	}
}

#endif
