/*****************************************************************
 * PTlink IRCd is (C) CopyRight PTlink Coders Team 1999-2000     *
 * http://www.ptlink.net/Coders - coders@PTlink.net              *
 * This program is distributed under GNU Public License          *
 * Please read the file COPYING for copyright information.       *
 *****************************************************************
 *   $Id: spoof.c,v 1.4 2001/02/10 19:00:43 jpinto Exp $ 
 
  File: spoof.c
  Desc: host spoofing routines
  Author: Lamego@PTlink.net
*/

#include "m_commands.h"
#include "client.h"
#include "ircd.h"
#include "numeric.h"
#include "s_log.h"
#include "s_serv.h"
#include "send.h"
#include "whowas.h"
#include "irc_string.h"
#include "spoof.h"
#include "s_user.h"
#include "crypt.h"
#include "conf_vars.h"

#include <stdlib.h>
#include <string.h>

int tagcount = 0;
#define MAXVIRTSIZE     (3 + 5 + 1)
#define HASHVAL_TOTAL   30011
#define HASHVAL_PARTIAL 211


void truncstring(char *stringvar, int firstlast, int amount);
int Maskchecksum (char *data, int len);
unsigned z(char *s);
void remove_dots_and_slashes(char* msg);
int str2array(char **pparv, char *string, char *delim);

/*
 * spoofed
 *
 * inputs       - client to be spoofed
 * output       - spoofed hostname
 * side effects - 
 */

char *spoofed(struct Client *acptr)
{
       if (is_vhost(acptr->realhost)) {                            
         return maskme_myCrypt2(acptr->realhost, acptr->ip.s_addr, is_vhost(acptr->realhost));
       }
       else if(SpoofMethod==0)		
	  return maskme(acptr->realhost);
	else
	  return maskme_myCrypt(acptr->realhost, acptr->ip.s_addr);
}

#define B_BASE                  0x1000
void truncstring(char *stringvar, int firstlast, int amount){
   if (firstlast)
   {
    stringvar+=amount;
    *stringvar=0;
    stringvar-=amount;
   }
    else
   {
    stringvar+=strlen(stringvar);
    stringvar-=amount;
   }
}

int Maskchecksum (char *data, int len)
{
        int                     i;
        int                     j;

        j=0;
        for (i=0 ; i<len ; i++)
        {
          j += *data++ * (i < 16 ? (i+1)*(i+1) : i*(i-15));

        }

        return (j+1000)%0xffff;
}

unsigned z(char *s)
{
    unsigned int i;
        i = Maskchecksum (s, strlen(s));
    return i;
}

int str2array(char **pparv, char *string, char *delim)
{
    char *tok;
    int pparc = 0;

    tok = strtok(string, delim);
    while (tok != NULL) {
	pparv[pparc++] = tok;
	tok = strtok(NULL, delim);
    }

    return pparc;
}


char *maskme(char *curr)
{
    static char mask[HOSTLEN + 1];
    unsigned hash_total = z(curr) % HASHVAL_TOTAL, hash_partial;
    char     destroy[HOSTLEN+1], *parv[HOSTLEN+1], *ptr;
    int      parc=0, len=0, overflow=0;

	if(!HostPrefix)
	  {
		strncpy(mask, curr, HOSTLEN);
		return mask;
	  }
	  
    strncpy(destroy, curr, HOSTLEN);

    len = strlen(destroy);

    if ((len + MAXVIRTSIZE) > HOSTLEN)
    {
        overflow = (len + MAXVIRTSIZE) - HOSTLEN;

        ptr = &destroy[overflow];
    }
    else
        ptr = &destroy[0];
    if(!strchr(curr,'.')) {
    	strncpy(mask, curr, HOSTLEN);
    	return mask;
    }    
    parc = str2array(parv, ptr, ".");
    if (parc == 4)
    {
        len = strlen(parv[3]);

        if (IsDigit(parv[3][len-1]))
        {
            hash_partial = (z(parv[0])+z(parv[1])+z(parv[2])) % HASHVAL_PARTIAL;
            ircsprintf(mask, "%s.%s.%u.%s-%u",
                parv[0], parv[1], hash_partial, HostPrefix, hash_total);
            return mask;
        }
    }
    if (parc == 2)
    {
        ircsprintf(mask, "%s-%u.%s.%s",
            HostPrefix, hash_total, parv[parc-2], parv[parc-1]);
        return mask;
    }
    len = strlen(parv[parc-1]);
    if (len == 2)
    {
        ircsprintf(mask, "%s-%u.%s.%s", /* Fixes spoofing - Lamego 1999*/
            HostPrefix, hash_total, parv[parc-2], parv[parc-1]);	
        return mask;
    }
    ircsprintf(mask, "%s-%u.%s.%s", HostPrefix, hash_total, parv[parc-2], parv[parc-1]);
    return mask;    
}

/* BCRYPT */
void remove_dots_and_slashes(char* msg) {
  static char temp[HOSTLEN+1];
  register int i,j;
  strncpy(temp, msg, HOSTLEN);
  for(i = j = 0; i < strlen(temp); i++,j++) {
    if(temp[i] == '.') {
      msg[j] = '7';
   } else if (temp[i] == '/') {
      msg[j] = 't';
    } else
      msg[j] = temp[i];
  }
  msg[j] = 0;
}   

/*
 * Adapted from brasmircd IRCd - Lamego
 */
char* maskme_myCrypt(char* host, long IP) 
{
#ifndef OWN_CRYPT
  extern  char *crypt();
#endif
  static char hexa[HOSTLEN+1];
  static char ret[HOSTLEN+1];
  static char salt[2] = "br";
  static char pass[8] = "87654312";
  register int i, res, hostlen;

  ret[0] = 0;

  if(HostPrefix) {
        salt[0] = HostPrefix[0];
        salt[1] = HostPrefix[1];
        salt[2] = 0;
        strncpy(pass, HostPrefix+2, 8);
        pass[8] = 0;
  }
  ircsprintf(hexa, "%X", ntohl(IP));
  for(i = 0; i < 8 && pass[i]; i++)
    hexa[i] = (pass[i] == hexa[i])?hexa[i]:pass[i]^hexa[i];
#ifdef OWN_CRYPT
  strcpy(hexa, (char *)crypt_des(hexa, salt));
#else
  strcpy(hexa, (char *)crypt(hexa, salt));
#endif
  remove_dots_and_slashes(hexa);
  hostlen = strlen(host);
  
  if(!IsDigit(host[hostlen-1]))
	{
  	  for(i=0; host[i] && host[i] != '.'; i++);
  		strcpy(ret, hexa+2);
  		if(host[i]) 
  		  {
                    res=HOSTLEN-( hostlen - i )-strlen(ret);
  		    if(res<0) 
  		    	i-=res;
		  strcat(ret, host+i);
	} 
	} 
  else 
	{
  	  strcpy(ret, hexa+2);
  	  strcat(ret, ".");
  	  strcat(ret, host);
  	  for(i = hostlen+1; i && (host[i] != '.'); i--);
  	  ret[strlen(hexa+2)+i+1] = 0;
  	  strcat(ret, ".O");
	}
	return ret;
}
/*
** m_newmask - Ported to PTlink6 (nick added by hardman)
**      parv[0] = sender prefix
**      parv[1] = nick to change mask for
**      parv[2] = new mask (if no @ host is assumed)
*/
int	m_newmask(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
  {
	char    *newhost = NULL, *newuser = NULL;
        char tmp[NICKLEN+HOSTLEN+USERLEN+4];
        struct Client *acptr;

	if (!IsServer(sptr))
	  {
           if(MyClient(sptr))
             sendto_one(sptr,form_str(ERR_NOPRIVILEGES),
                 MENAME(sptr), parv[0]);
           return 0;                            
	  }

      if (parc<3 || EmptyString(parv[2]))
    	{
#if 0
		  if(MyClient(sptr))
       	sendto_one(sptr, ":%s NOTICE %s :*** Syntax: /NEWMASK nick <user@host|user@|host>", me.name, parv[0]);
#endif
          return 0;
        }
          acptr = find_client(parv[1], NULL);
      
          if (!acptr) return -1;
      
	  newhost = strchr(parv[2],'@');
	  
	  if(newhost)
		{
		  (*newhost++) = '\0';
		  newuser = parv[2];
		} 
	  else 
		newhost = parv[2];
  		
	  if (!EmptyString(newhost)) 
		{

    	  if (strlen(newhost) > (HOSTLEN)) 
			{
#if 0
  	      	  sendto_one(sptr, ":%s NOTICE %s :*** Error: Hostname too long", 
			  me.name, parv[0]);
#endif
    	  	  return -1;
      		}
  
    	  if (!valid_hostname(newhost)) 
		  {
#if 0
      		sendto_one(sptr, ":%s NOTICE %s :*** Error: Invalid hostname", 
			  me.name, parv[0]);
#endif
            return -1;
      	  }
		
		  strcpy(acptr->host, newhost);
		}

	  if (!EmptyString(newuser)) 
		{

    	  if (strlen(newuser) > (USERLEN)) 
			{
#if 0
  	         sendto_one(sptr, ":%s NOTICE %s :*** Error: username too long", me.name, parv[0]);
#endif
    	     return -1;
      	  }
  
    	  if (!valid_username(newuser)) 
		  {
#if 0
      		sendto_one(sptr, ":%s NOTICE %s :*** Error: Invalid username",
			  me.name, parv[0]);
#endif
            return -1;
      	  }
		  
		  strcpy(acptr->username, newuser);
		}

                MyFree((char *)acptr->user->prefix);
               
                ircsprintf(tmp, "%s!%s@%s", acptr->name, acptr->username, acptr->host);

                acptr->user->prefix = strdup(tmp);

		sendto_serv_butone(cptr, ":%s NEWMASK %s %s@%s", parv[0], parv[1],
			newuser ? newuser :"", newhost ? newhost :"");
#if 0          
	  if (MyClient(cptr)) /* We will not send new mask notices if it comes from me */
	    sendto_one(sptr, ":%s NOTICE %s :*** New mask: \2%s (%s@%s)\2", me.name, parv[0],
							parv[0], sptr->username, sptr->host);
#endif
	  return 0;	    
  }
char *spoofed2(struct Client *acptr)
{
	if(SpoofMethod==0)		
	  return maskme(acptr->realhost);
	else
	  return maskme_myCrypt2(acptr->realhost, acptr->ip.s_addr, "vip.brasmirc.org");
}
char* maskme_myCrypt2(char* host, long IP, char* vhost) 
{
#ifndef OWN_CRYPT
  extern  char *crypt();
#endif
  static char hexa[HOSTLEN+1];
  static char ret[HOSTLEN+1];
  static char salt[2] = "br";
  static char pass[8] = "87654312";
  register int i, res, hostlen;

  ret[0] = 0;

  if(HostPrefix) {
        salt[0] = HostPrefix[0];
        salt[1] = HostPrefix[1];
        salt[2] = 0;
        strncpy(pass, HostPrefix+2, 8);
        pass[8] = 0;
  }
  ircsprintf(hexa, "%X", ntohl(IP));
  for(i = 0; i < 8 && pass[i]; i++)
  hexa[i] = (pass[i] == hexa[i])?hexa[i]:pass[i]^hexa[i];
#ifdef OWN_CRYPT
  strcpy(hexa, (char *)crypt_des(hexa, salt));
#else
  strcpy(hexa, (char *)crypt(hexa, salt));
#endif
  remove_dots_and_slashes(hexa);
  hostlen = strlen(host);
  	  strcpy(ret, hexa+2);
  	  strcat(ret, ".");
  	  strcat(ret, vhost);
	return ret;
}
