
/*
 *
 * FakeBO - fakes Trojan Servers and logs every attempt to file/stdout
 *
 * Code Maintainer: Vlatko Kosturjak, Kost <kost@iname.com>
 *
 * Distributed under GNU Public License.
 *
 */

#define FAKEBOVER  "0.3.2"
#define FAKEBOCONF "fakebo.conf"


#ifdef sparc
#define WORDS_BIGENDIAN 1
#endif

#ifdef WORDS_BIGENDIAN
#warning using WORDS_BIGENDIAN - use with care!
#define __EL_LONG(x) ((((x) >> 24) & 0x000000FF) | \
                   (((x) >> 8) & 0x0000FF00)  | \
                    (((x) << 8) & 0x00FF0000)  | \
                    (((x) << 24) & 0xFF000000))
#else
#define __EL_LONG(x) (x)
#endif


#include "global.h"
#include "bo.h"
#include "nb.h"

static char *fakeboconfdir[] = { "/etc", "/usr/local/etc","~", ".", NULL };

static  void sighandler ( int sig )
{
    static char *sigs []
        = {"EXIT", "HUP", "INT", "QUIT", "ILL", "TRAP", "ABRT", "BUS"
           , "FPE", "KILL", "USR1", "SEGV", "USR2", "PIPE", "ALRM", "TERM"
           , "STKFLT", "CHLD", "CONT", "STOP", "TSTP", "TTIN", "TTOU"
           , "URG", "XCPU", "XFSZ", "VTALRM", "PROF", "WINCH", "IO", "PWR"
           , "UNUSED", "ZERR", "DEBUG", (char *)(NULL)};
    int         i ;

    if ( sig < 0 )
        sig = - sig ;
    for ( i = 0 ; sigs [i] != (char *)(NULL) ; i++ );
    sig %= i ;
    fprintf(stderr, "fakebo: caught SIG%s, shutting down FakeBO server...\n"
            , sigs [sig]);
    stop = TRUE ;
}

static  void setsignal ( int sig, void(*sighnd)(int signo) )
{
#ifndef NeXT
    struct sigaction sa ;
#endif
#ifdef NeXT
    signal(sig, sighnd);
#else
    sa.sa_handler = sighnd ;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0 ;
    sigaction(sig, &(sa), (struct sigaction *)(NULL));
#endif
}

/*
 * Initializes the signal handling and removes buffering from stderr, stdin 
 * and stdout.
 * 
 */
static  void siginit ( void )
{
    stop = FALSE ;
    setbuf(stdin, (char *)(NULL));
    setbuf(stdout, (char *)(NULL));
    setbuf(stderr, (char *)(NULL));
    setsignal(SIGPIPE, SIG_IGN);
    setsignal(SIGINT, sighandler);
    setsignal(SIGQUIT, sighandler);
    setsignal(SIGTERM, sighandler);
    setsignal(SIGBUS, sighandler);
    setsignal(SIGFPE, sighandler);
    setsignal(SIGILL, sighandler);
    setsignal(SIGHUP, sighandler);
    setsignal(SIGABRT, sighandler);
    setsignal(SIGSEGV, sighandler);
    /* setsignal(SIGCHLD, sighandler); */
    setsignal(SIGKILL, sighandler);
}


/*
 * Returns the current local date and time in timenow. 
 * Here you can modify the output format
 * (default is yyyy-mm-dd hh:mm:ss)
 *   
 */
void whatistime ( char *timenow)
{
    struct tm *curtime ;
    time_t   cartime ;

    time(&cartime);
    curtime = localtime(&cartime);
    switch (logtimeanddate)
    {
    case 1:
    sprintf(timenow, "%02d-%02d-%04d %02d:%02d:%02d", curtime -> tm_mon + 1
            , curtime -> tm_mday, curtime -> tm_year+1900, curtime -> tm_hour
            , curtime -> tm_min, curtime -> tm_sec);
    break;
    case 2:
    sprintf(timenow, "%02d.%02d.%04d %02d:%02d:%02d", curtime -> tm_mday
            , curtime -> tm_mon + 1, curtime -> tm_year+1900, curtime -> tm_hour
            , curtime -> tm_min, curtime -> tm_sec);
    break;
    case 3:
    sprintf(timenow, "%04d-%02d-%02d %02d:%02d:%02d", curtime -> tm_year+1900
            , curtime -> tm_mon + 1, curtime -> tm_mday, curtime -> tm_hour
            , curtime -> tm_min, curtime -> tm_sec);
    break;
    default:
        sprintf (timenow, "Config error (`logtimeanddate' != [0-3])!");
        break;
    }
    
}

/*
 * Recognizes and returns the NetBus commands
 *
 */
char *netbusdesc (char *msgtocmp)
{
	int i;
	for (i=0;i<NETBUSMAXCOM;i++)
	if (strncmp (msgtocmp,netbuscommands[i][0],strlen(netbuscommands[i][0]))==0) return (netbuscommands[i][1]);
	return (unknownnetbuscommand);
}

/*
 * Returns command field of NetBus command
 *
 */
int netbuscommand(char *msgtocmp)
{
    int i;

    for (i = 0; i < NETBUSMAXCOM; i++)
    {
        if (strncmp(msgtocmp, netbuscommands[i][0], strlen(netbuscommands[i][0])) == 0)
        	return (i);
	}
    return (-1);
}


/*
 * Returns data field of NetBus command
 */
void netbusdata(char *allcommand, char *command, char *data)
{
    int i, j;

    if (data==NULL)
        return;
    if ((allcommand==NULL)||(command==NULL))
    {
        data[0]='\0';
        return;
    }
    j=0;
    for (i=0;i<strlen(allcommand);i++)
    {
        if (i>=strlen(command) && allcommand[i]!='\r' && allcommand[i]!='\n')
        	data[j++]=allcommand[i];
    }
    data[j] = '\0';
}


/*
 * Used for debugging of correct packet recognition.
 * 
 */
void bocommandinit ( void )
{
    byte    i ;
    char    tmpstr [80];

    for ( i = 0 ; i < MAXNUMCOMMANDS ; i++ )
    {
        strcpy(tmpstr, bocommands [i]);
        sprintf(bocommands [i], "0x%02X %s", i, tmpstr);
    }
}

/*
 * Loads configuration from config file. 
 *   
 */
void loadconfig ( char *config_file )
{
    FILE    *fp ;
    char    line [LINE_SIZE], *pos, cfgfile[1024];
    int     var, linenb, i ;

    if ( config_file != NULL )
    {
		strcpy(cfgfile, config_file);
        fp = fopen(cfgfile, "rt");
    }
    else
    {
    	i = 0;
    	fp = NULL;
    	while (fakeboconfdir[i]!=NULL && fp==NULL)
    	{
    		strcpy(cfgfile, fakeboconfdir[i]);
    		strcat(cfgfile, "/");
    		strcat(cfgfile, FAKEBOCONF);
    		fprintf(stdout, "Trying to open `%s'...", cfgfile);
	        fp = fopen(cfgfile, "rt");
	        if (fp == NULL)
	        {
	        	fprintf(stdout, " failed.\n");
	        	i++;
	        }
	        else
	        {
	        	fprintf(stdout, " success!\n");
	        	fprintf(stderr, "Using config file `%s'.\n", cfgfile);
	        }
    	}
    }
    if ( fp == NULL )
        fprintf(stderr, "Could not open ANY config file, using defaults.\n");
    else
    {
        linenb = 0 ;
        while ( fgets(line, LINE_SIZE, fp) != NULL )
        {
            linenb++ ;
            if ( line [0] == '#' || line [0] == '\n' )
                continue ;                          /* a comment */
            for ( var = 0 ; var < NB_PARAMS ; var++ )
            {
                if ( strstr(line, keywords [var]) != line )
                    continue ;
                pos = line + strlen(keywords [var]);

                if ( *pos++ != ' ' )                /* keyword must be followed by an espace */
                    continue ;
                sscanf(pos, in_formats [var], addresses [var]);
                break ;
            }
            if ( var == NB_PARAMS )
                fprintf(stderr
                        , "Unrecognized command in config file"
                        " `%s', line %d:\n%s\n"
                        , cfgfile, linenb, line);
        }
        fclose(fp);
    }
    if ( strcmp(logfile, "stdout") == 0 )
    {
        printf("Logging to stdout.\n");
        fptolog = stdout ;
    }
    else
    {
     if ( strcmp(logfile, "stderr") == 0 )
     {
         printf("Logging to stderr.\n");
         fptolog = stderr ;
     }
     else
     {
        fptolog = fopen(logfile, "at");
        if ( fptolog == NULL )
        {
            fprintf(stderr, "Error opening logfile `%s', using stdout\n", logfile);
            fptolog = stdout ;
        }
     }
    }
    if ( bufferedlogging == 0 )
        setbuf(fptolog, (char *)NULL);
}


/*
 * Debug the config set up.
 * 
 */
void debugconfig ( void )
{
    int var ;

    fprintf(stderr, "---[ Config parameters ]---\n");
    for ( var = 0 ; var < NB_PARAMS ; var++ )
    {
        fprintf(stderr, "%s ", keywords [var]);
        if ( strcmp(out_formats [var], "%d") == 0 )
            fprintf(stderr, out_formats [var], *(int *)addresses [var]);
        else
            fprintf(stderr, out_formats [var], addresses[var]);
        fprintf(stderr, "\n");
    }
    fprintf(stderr, "---------[ End ]---------\n");
}



/*
 * Returns just hex BO command
 *
 */
byte whatbocommand (byte t)
{
    byte r;

    r=t;
    if ( r & 0x80 )
        r = r - 0x80 ;
    if ( r & 0x40 )
        r = r - 0x40 ;

    return (r);
}


/*
 * Extracts the BO command from t and returns the pointer to name of command.
 * 
 */
char *typeofbocommand ( byte t )
{
    byte    i ;

    t=whatbocommand (t);

    for ( i = 0 ; i < MAXNUMCOMMANDS ; i++ )
        if ( (t & i) == t )
        {
            return bocommands [i];
        }
    return (notyetimplemented);
}



#ifdef DEBUG

/*
 * Used for debugging of server packets
 *
 */
void debugspacket ( bopacket *vamo )
{
    printf("MAGIC=%.8s\t", vamo -> hdr.magic);
    printf("Len=%ld\t", __EL_LONG(vamo -> hdr.len));
    printf("ID=%ld\t", __EL_LONG(vamo -> hdr.id));
    printf("Type=0x%02X\n", vamo -> hdr.t);
    printf("%s\n", typeofbocommand(vamo -> hdr.t));
    printf("Data\n");
    printf("%s\n", &vamo -> buf [sizeof(vamo -> hdr)]);
    printf("End.\n");
}


/*
 * Used for debugging client packets.
 *
 */
void debugcpacket ( bopacket *vamo )
{
    char    *c ;

    printf("MAGIC=%.8s\t", vamo -> hdr.magic);
    printf("Len=%ld\t", __EL_LONG(vamo -> hdr.len));
    printf("ID=%ld\t", __EL_LONG(vamo -> hdr.id));
    printf("Type=0x%02X\n", vamo -> hdr.t);
    printf("%s\n", typeofbocommand(vamo -> hdr.t));
    printf("Data1\n");
    c = &vamo -> buf [sizeof(vamo -> hdr)];
    printf("%s\n", c);
    printf("Data2\n");
    c += strlen(c) + 1 ;
    printf("%s\n", c);
    printf("End.\n");
}

#endif


void removeunprintable (char *s, int n)
{
	int i;
	
	for (i=0; i<n;i++)
	if (!(isprint(s[i]) || s[i] == 0 || isspace(s[i]) ))
		s[i]='.';
}

/*
 * log contents from fmt to log file
 *
 */
static char repeatbuf[MAXLOGRECSIZE]; /* buffer to compare */
static int repeatcount=0; /* Counter for 'message repeated x times' */
void logprintf (BOOL dotime, char *fmt, ...)
{
	va_list va;
	char buf[MAXLOGRECSIZE], buf2[MAXLOGRECSIZE];

	va_start(va, fmt);
	vsprintf(buf, fmt, va);
	va_end(va);
	
	if (strcmp(buf,repeatbuf)==0)
	{
		repeatcount++;
		return;
	}
	
	removeunprintable (buf,sizeof(buf));
	
	if (repeatcount>0)
	{
		if (logtimeanddate>0)
		{
			whatistime (buf2);
			fprintf (fptolog, "%s Last message repeated %d time(s)\n", buf2, repeatcount);
		}
		else
			fprintf (fptolog, "Last message repeated %d time(s)\n",repeatcount);
		repeatcount=0;
		memset(repeatbuf,0,sizeof(repeatbuf));
	}

	memcpy (repeatbuf,buf,sizeof(buf));
	
	if (dotime && logtimeanddate > 0)
	{
                whatistime(buf2);
		fprintf(fptolog, "%s %s", buf2, buf);
	}
	else
		fprintf(fptolog, "%s", buf);
}

void syslogprintf (char *fmt, ...)
{
	va_list va;
	char buf[MAXLOGRECSIZE];
	
	if (logtosyslog!=0)
	{
		va_start (va, fmt);
		vsprintf (buf, fmt, va);
		va_end(va);

		openlog ("FakeBO", LOG_CONS, LOG_USER);
		syslog (LOG_WARNING, buf);
		closelog();
	}
}

/*
 * Logs the client packet to file stream fptolog.
 *
 */
void logcpacket ( bopacket *vamo )
{
    char    *c ;

    switch ( logreceivedpackets )
    {
        case 3 :

        logprintf(TRUE, "\tCommand: %s\n"
                         , typeofbocommand(vamo -> hdr.t));
            
            c = &vamo -> buf [sizeof(vamo -> hdr)];
            logprintf(TRUE, "\t(%s)", c);
            c += strlen(c) + 1 ;
            logprintf (FALSE, "(%s)\n", c);

            logprintf(TRUE, "\tMagic=%.8s\t", vamo -> hdr.magic);
#ifdef __alpha
	    logprintf(FALSE, "Len=%d\t", vamo->hdr.len);
	    logprintf(FALSE, "ID=%d\t", vamo->hdr.id);
#else
            logprintf(FALSE, "Len=%ld\t", __EL_LONG(vamo -> hdr.len));
            logprintf(FALSE, "ID=%ld\t", __EL_LONG(vamo -> hdr.id));
#endif
            logprintf(FALSE, "Type=0x%02X\n", vamo -> hdr.t);
             break;
             
        case 2 :
        logprintf(TRUE, "\tCommand: %s\n"
                         , typeofbocommand(vamo -> hdr.t));
                         
            c = &vamo -> buf [sizeof(vamo -> hdr)];
            logprintf(TRUE, "\t(%s)", c);
            c += strlen(c) + 1 ;
            logprintf (FALSE, "(%s)\n", c);
		break;
		
        case 1 : 
        logprintf(TRUE, "\tCommand: %s\n"
                         , typeofbocommand(vamo -> hdr.t));
                     break;
    }
}


/*
 * Logs the server packet via logprintf()
 *
 */
void logspacket ( bopacket *vamo )
{
    switch ( logsendingpackets )
    {
        case 3 :
        	logprintf(TRUE, "\tCommand: %s\n"
                         , typeofbocommand(vamo -> hdr.t));

        	logprintf(TRUE, "\t(%s)\n"
                         , &vamo -> buf [sizeof(vamo -> hdr)]);
                
            logprintf(TRUE, "\tMagic=%.8s\t", vamo -> hdr.magic);
#ifdef __alpha
	    logprintf(FALSE, "Len=%d\t", vamo->hdr.len);
            logprintf(FALSE, "ID=%d\t", vamo->hdr.id);
#else
            logprintf(FALSE, "Len=%ld\t", __EL_LONG(vamo -> hdr.len));
            logprintf(FALSE, "ID=%ld\t", __EL_LONG(vamo -> hdr.id));
#endif
            logprintf(FALSE, "Type=0x%02X\n", vamo -> hdr.t);
            break;
        case 2 : 
        	logprintf(TRUE, "\tCommand: %s\n"
                         , typeofbocommand(vamo -> hdr.t));
        	logprintf(TRUE, "\t(%s)\n"
                         , &vamo -> buf [sizeof(vamo -> hdr)]);
                break;
        case 1 : 
        	logprintf(TRUE, "\tCommand: %s\n"
                         , typeofbocommand(vamo -> hdr.t));
        	break ;
    }
}


/*
 * Sets global seed value.
 *   
 */
void msrand ( unsigned int seed )
{
    holdrand = (long)seed ;
}

int mrand ( void )
{
    return ((holdrand = holdrand * 214013L + 2531011L) >> 16) & 0x7FFF;
}


/*
 * Calculates the word value from password.
 *   
 */
unsigned int getkey ()
{
    int             x, y ;
    unsigned int    z ;

    y = strlen(g_password);
    if ( !y )
        return 31337 ;
    else
    {
        z = 0 ;
        for ( x = 0 ; x < y ; x++ )
            z += g_password [x];
        for ( x = 0 ; x < y ; x++ )
        {
            if ( x % 2 )
                z -= g_password [x] * (y - x + 1);
            else
                z += g_password [x] * (y - x + 1);
            z = z % RAND_MAX ;
        }
        z = z * y % RAND_MAX ;
        return z ;
    }
}


/*
 * Main function for crypting/decrypting the BO packet.
 *
 */
void cryptpacket ( unsigned char *buff, int len )
{
    int y ;

    if ( !len )
        return ;
    msrand(getkey());
    for ( y = 0 ; y < len ; y++ )
        buff [y] = buff [y] ^ (mrand() % 256);
}

int atoport ( char *service, char *proto )
{
    int           port ;
    long int      lport ;
    struct servent *serv ;
    char          *errpos ;

    serv = getservbyname(service, proto);
    if ( serv != NULL )
        port = serv -> s_port ;
    else
    {
        lport = strtol(service, &errpos, 0);
        if ( errpos [0] != 0 || lport < 1 || lport > 65535 )
            return - 1 ;
        port = htons(lport);
    }
    return port ;
}


void strreplace(char *str, char *s1, char *s2, unsigned size)
{
	char *c, *c2, tmp[1024];

	if (str == NULL)
		return;
	if (size > sizeof(tmp))
		size = sizeof(tmp);
	c = str;
	do
	{
		memset(tmp, 0, sizeof(tmp));
		c = ((c != NULL) ? (strstr(c, s1)) : (NULL));
		if (c == NULL)
			continue;
		if ((c != str) && ((*(c - 1)) == '\\'))
		{
			c2 = c;
			while ((*c) != '\0')
			{
				(*(c - 1)) = (*c);
				c++;
			}
			(*(c - 1)) = '\0';
			/* c += ((strlen(s1) < strlen(c)) ? (strlen(s1)) : (size)); */
			c = c2;
			continue;
		}
		c2 = c;
		if ((strlen(c) - strlen(s1)) < sizeof(tmp))
		{
			memcpy(tmp, c + strlen(s1), strlen(c) - strlen(s1));
			if ((c + strlen(s2)) < (str + size))
			{
				memcpy(c, s2, strlen(s2));
				c += strlen(s2);
				if (strlen(tmp) < (size - (c - str)))
				{
					memcpy(c, tmp, strlen(tmp));
					c += strlen(tmp);
					if ((c - str) < size)
						(*c) = '\0';
				}
			}
		}
		c = c2;
	} while (c != NULL);
}

/*
 * Displays intro message 
 *
 */
void intro (void)
{
	printf("FakeBO  version " FAKEBOVER "  Copyright (C) 1998,99 by KoSt\n\n");
}

/*
 * Main program.
 *
 */
int main ( int argc, char *argv [] )
{
    bopacket bo ;
    unsigned long slen = 0 ;
    int opt ;
    char *config_file = NULL ;
    int debug = FALSE, about = FALSE ;
    int sock ;
    struct sockaddr_in client, server ;
    int recvd ;
    int structlength ;
    int port ;
    struct linger linger ;
    struct timeval tv ;
    struct hostent *he ;
    fd_set fds ;
    char *msg;
    char ad [256], *ipaddr ;
    char tmpexecute[512];
    int tosendpacket = 1 ;
    int howmany = 0;
    FILE *tmpfp;
    char tmpcustomreply[1024];
    int isdaemon = 0;
    /* NetBus variable support */
    char netbusbuf[BUFLEN];
    int netbuson, netbusi, netbusj, netbussl, netbusr;
    unsigned int netbuslen;
    int netbusmfd, netbustcp, netbuscfd;
    struct protoent *netbustcpproto;
    struct timeval netbustv;
    struct hostent *netbushe;
    char netbusad[BUFLEN], *netbusipaddr;
    fd_set netbusfds, netbuswfds;
    char nbdatabuf[BUFLEN];
    char nblogbuf[BUFLEN*3];
    /* End of NetBus variable support */

	memset (repeatbuf,0,sizeof(repeatbuf));
	
    while ( (opt = getopt(argc, argv, "c:dihba")) != EOF )
        switch ( opt )
        {
            case 'c' :
                config_file = optarg ;
                break ;
            case 'd' :
                debug = TRUE ;
                break ;
            case 'i' :
                bocommandinit();
                break ;
            case 'h' :
                intro();
                printf(usage, argv [0]);
                printf ("\nPath where config file will be searched: \n");
                netbusi=0;
                while (fakeboconfdir[netbusi]!=NULL)
                printf ("\"%s\", ",fakeboconfdir[netbusi++]);
                printf ("\n");
                return 0 ;
            case 'b':
            	isdaemon = 1;
            	break;
            case 'a':
            	about = TRUE;
            	break;
            default :
            	fprintf(stderr, "Unknown switch `-%c'. Try `%s -h'.\n",
            		opt, argv[0]);
                return (-1) ;
        }
    if (!about)
	    loadconfig(config_file);
    if (isdaemon)
    	startasdaemon = 1;

	if (!startasdaemon || about)
	{
		intro();
		if (!about)
			printf("Type `%s -a' for details.\n", argv[0]);
		printf("\n");
	}
	if (about)
	{
		printf("This program is free software; you can redistribute it and/or modify\n");
		printf("it under the terms of the GNU General Public License as published by\n");
		printf("the Free Software Foundation; either version 2 of the License, or\n");
		printf("(at your option) any later version.\n");
		printf("\n");
		printf("This program is distributed in the hope that it will be useful,\n");
		printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
		printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
		printf("GNU General Public License for more details.\n");
		printf("\n");
		printf("You should have received a copy of the GNU General Public License\n");
		printf("along with this program; if not, write to the Free Software\n");
		printf("Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n");
		printf("\n");
		return (0);
	}


    if ( debug )
        debugconfig();
    port = atoport(boporttolisten, "udp");
    memset(g_password, 0, sizeof(g_password));
    if ( port < 0 )
    {
        fprintf(stderr, "Unable to find port %s.\n", argv [1]);
        exit(EXIT_FAILURE);
    }
    sock = socket(AF_INET, SOCK_DGRAM, 0);
    if ( sock < 0 )
    {
        perror("socket");
        exit(EXIT_FAILURE);
    }
    siginit();                                      /* initialize signal handlers */

    linger.l_onoff = 0 ;                            /* dont linger */
    setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger));
    memset((char *)&client, 0, sizeof(client));
    client.sin_family = AF_INET ;
    client.sin_addr.s_addr = htonl(INADDR_ANY);
    client.sin_port = port ;
    memset((char *)&server, 0, sizeof(server));
    server.sin_family = AF_INET ;
    server.sin_addr.s_addr = htonl(INADDR_ANY);
    server.sin_port = port ;
    structlength = sizeof(server);
    if ( bind(sock, (struct sockaddr *)&server, structlength) < 0 )
    {
        perror("bind");
        exit(EXIT_FAILURE);
    }
    /* End of BO Support */

    /* NetBus Support */
	netbuslfd = -1;
	netbuson = 1;
	netbustcp = -1;
	netbustcpproto = getprotobyname("tcp");
	if (netbustcpproto != (struct protoent *)(NULL)) netbustcp = netbustcpproto->p_proto;
	netbuslfd = socket(PF_INET, SOCK_STREAM,	0);
	if (netbuslfd < 0)
	{
		logprintf(TRUE,"[NB] Call to `socket()' failed!\n");
		return	(-1);
	}
	netbusaddr.sin_family = AF_INET;
	netbusaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	netbusaddr.sin_port = htons(nbport);
	setsockopt(netbuslfd, SOL_SOCKET, SO_REUSEADDR, (char *)(&(netbuson)),sizeof(netbuson));
	if (bind(netbuslfd, (struct sockaddr *)(&(netbusaddr)),sizeof(netbusaddr))	< 0)
	{
		logprintf(TRUE,"Unable to `bind()' on NetBus port %d!\n", nbport);
		return (-1);
	}
	listen(netbuslfd, 5);
    /* End of NetBus Support */

    logprintf (TRUE, "FakeBO %s started.\n", FAKEBOVER);

    if (startasdaemon)
    {
    	pid_t pid = 0;
    	int i;

		/* Close all file descriptors except std- ones */
		for (i = 0; i < 255; i++)
		{
			if ((i != sock) && (i != netbuslfd) && (i != fileno(fptolog)))
				close(i);
		}
		/* Fork into the background here */
		if ((pid = fork()) < 0)
			printf("Fork error, remaining in foreground.\n");
		/* Let the parent process die */
		else
		{
			if (pid > 0)
				return (0);
		}
		setsid();
		if ((pid = fork()) < 0)
			printf("Fork error, remaining in foreground.\n");
		/* Let the parent process die */
		else
		{
			if (pid > 0)
				return (0);
		}
		open("/dev/null", O_RDONLY);		/* stdin  */
		open("/dev/null", O_WRONLY);		/* stdout */
		open("/dev/null", O_WRONLY);		/* stderr */
    }
    while ( stop == FALSE )
    {
        slen = 0 ;
        memset((char *)&bo, 0, sizeof(bo));
        structlength = sizeof(client);
        recvd = 0 ;

        FD_ZERO(&fds);
        FD_SET(sock, &fds);
        tv.tv_sec = 1 ;
        tv.tv_usec = 0 ;
        if ((select(sock + 1, &fds, NULL, NULL, &tv) < 0) && (!stop))
        {
            logprintf (TRUE, "[BO] Call to `select()' failed\n");
            return (-1);
        }
        if ((FD_ISSET(sock, &fds)) && (!stop))
        {
        recvd = recvfrom(sock, &bo, sizeof(bo), 0,
          (struct sockaddr *)&client, &structlength);
        }

        if ( stop == TRUE )
            continue ;
        if ( recvd < 0 )
        {
            logprintf (TRUE, "[BO] Error at recvfrom");
            exit(EXIT_FAILURE);
        }
        if (recvd > 0)
        {
        cryptpacket((unsigned char *)&bo, recvd);
        slen = __EL_LONG(bo.hdr.len) ;
        he = gethostbyaddr((char *)(&client.sin_addr)
                           , sizeof(client.sin_addr), AF_INET);
        ipaddr = inet_ntoa(client.sin_addr);
        if ( he != (struct hostent *)(NULL) )
            sprintf(ad, "%s (%s)", he -> h_name, ipaddr);
        else
            sprintf(ad, "%s", ipaddr);
        
        if ( strncmp(bo.hdr.magic, MAGICSTRING, MAGICSTRINGLEN) == 0
                && slen != 0 )
        {
	    if ( logconnection != 0 ) 
	    	logprintf (TRUE, "[BO] Received BO packet from %s\n",ad);
            if ( logconnection != 0 ) logprintf (FALSE, "BO PACKET!\n");
            
            if (logtosyslog==1) syslogprintf("BO Packet from %s", ad);
            else syslogprintf("[BO] packet from %s : %s", ad, typeofbocommand(bo.hdr.t));

            logcpacket(&bo);                        /* log the packet from client */
            FD_ZERO(&fds);
            FD_SET(sock, &fds);
            tv.tv_sec = 10 ;
            tv.tv_usec = 0 ;
            if ( select(sock + 1, NULL, &fds, NULL, &tv) == 0 )
            {
                logprintf (TRUE, "[BO] select (timeout error)\n");
                continue ;
            }
            msg = &bo.buf [sizeof(bo.hdr)];
            if ( sendfakereply == 1 && bo.hdr.t == 0x01 )
            {
                strcpy(msg, "  !PONG!");
                strcat(msg, bofakever);
                strcat(msg, "!");
                strcat(msg, machinename);
                strcat(msg, "!");
            }
            else
                if (usecustomreplies!=0)
                {
                    sprintf (tmpcustomreply,"%s%02X",customrepliespath,whatbocommand(bo.hdr.t));
                    tmpfp=fopen (tmpcustomreply,"rt");
                    if (tmpfp==NULL) sprintf (msg, bomessage, ad);
                    else
                    {
                        howmany = fread (msg,sizeof(byte),MAXSIZECUSTOM,tmpfp);
                        fclose (tmpfp);
                        if (howmany<0) howmany=0;
                        msg[howmany]='\0';
                    }
                }
                else
                    sprintf(msg, bomessage, ad);

            tosendpacket = 0 ;
            if ( silentmode == 0 )
                tosendpacket = 1 ;
            else if ( bo.hdr.t == 0x01 && sendfakereply == 1 )
                tosendpacket = 1 ;
             slen = __EL_LONG (bo.hdr.len) + strlen (msg) + 2;
             bo.hdr.len=__EL_LONG (slen);
            /*
            bo.hdr.len += strlen(msg) + 2 ;
            slen = bo.hdr.len;
            */
            holdrand = 1L ;
            if ( tosendpacket )
            {
                if ( logconnection != 0 )
                    logprintf (TRUE, "[BO] Sending packet to %s...\n",ad);
                logspacket(&bo);
                cryptpacket((unsigned char *)&bo, sizeof(bo));
                if ( FD_ISSET(sock, &fds) )
                    if ( sendto(sock, &bo, slen, 0
                                , (struct sockaddr *)&client
                                , sizeof(client))
                            != slen )
                    {
                        logprintf (TRUE, "[BO] Error replying in sendto:\n");
                    }
            }
            if (toexecutescript!=0)
            {
				if (fork() == 0)
				{
				    for (netbusi =0;netbusi < netbusclients; netbusi++)
				    	close(netbuskfd[netbusi]);
				    close(netbuslfd);
					close(sock);
    	            memset(tmpexecute, 0, sizeof(tmpexecute));
        	        strcpy (tmpexecute, executescript);
                        strreplace(tmpexecute, "!", ipaddr, sizeof(tmpexecute));
                       if (execlp(executescriptshell, executescriptshell, "-c",
		       	tmpexecute, NULL) != 0)
		       	{
		       	logprintf(TRUE, "Unable to execute custom script `%s'!\n",
		       		tmpexecute);
		       	return (0);
		       }
		       	logprintf(TRUE, "Unable to `fork()', cannot execute custom script!\n");
		       	}
            }
        }
        else
        {
            if ( logconnection != 0 )
                logprintf (TRUE, "[BO] Non-BO data received from %s\n",ad);
            
            syslogprintf ("[BO] non-BO data from %s", ad);
            
            if ( lognotbopackets != 0 )
            {
                logprintf (TRUE, "---[Begining of Data]---\n");
                fwrite(bo.buf, sizeof(bo.buf), 1, fptolog);
                logprintf (FALSE,"\n");
                logprintf (TRUE, "---[End of Data]---\n");
            }
        }
        }
        /* End of BO support */

        /* Begin of NetBus support */
		FD_ZERO(&(netbusfds));
		FD_ZERO(&(netbuswfds));
		netbusmfd = netbuslfd;
		for (netbusi = 0; netbusi < netbusclients; netbusi++)
		{
			FD_SET(netbuskfd[netbusi], &(netbusfds));
			FD_SET(netbuskfd[netbusi], &(netbuswfds));
			if (netbuskfd[netbusi] > netbusmfd)
			netbusmfd = netbuskfd[netbusi];
		}
		FD_SET(netbuslfd, &(netbusfds));
		netbustv.tv_sec = 0;
		netbustv.tv_usec = 500000;
		netbussl = select((netbusmfd + 1), &(netbusfds), &(netbuswfds), (fd_set *)(NULL), &(netbustv));
		if (netbussl < 0)
		{
			if (errno != EINTR)
			{
				logprintf(TRUE, "[NB] Call to `select()' failed!\n");
				return (-1);
			}
			else continue;
		}
		if (netbussl == 0) continue;
		if (FD_ISSET(netbuslfd, &(netbusfds)))
		{

			/* New NetBus Connection */
			netbuslen = sizeof(netbusaddr);
			netbuscfd = accept(netbuslfd, (struct sockaddr *)(&(netbusaddr)), &(netbuslen));

			if (netbuscfd < 0)
			{
				if (errno == EINTR) continue;
				else
				{
					logprintf(TRUE,"[NB] Unable to `accept()' connection (maybe a tcp SYN stealth port scan?)\n");
					
					syslogprintf ("[NB] Unable to `accept()' connection (maybe a tcp SYN stealth scan?)");
					continue;
				}
			}
			
			/*  Get IP address */
			netbushe = gethostbyaddr((char *)(&(netbusaddr.sin_addr)),
			sizeof(netbusaddr.sin_addr), AF_INET);
			netbusipaddr = inet_ntoa(netbusaddr.sin_addr);
			if (netbushe != (struct hostent *)(NULL)) sprintf(netbusad, "`%s' (%s)", netbushe->h_name, netbusipaddr);
                        else sprintf(netbusad, "%s", netbusipaddr);


	    syslogprintf ("[NB] Connection[#%d] from %s", netbusclients, netbusad);
            
            /* Fork and execute the script if specified */
	    if (toexecutescript!=0)
            {
                                if (fork() == 0)
                                {
                                    for (netbusi =0;netbusi < netbusclients; netbusi++)
                                        close(netbuskfd[netbusi]);
                                    close(netbuslfd);
                                        close(sock);
                    memset(tmpexecute, 0, sizeof(tmpexecute));
                        strcpy (tmpexecute, executescript);
                        strreplace(tmpexecute, "!", netbusipaddr, sizeof(tmpexecute));
                       if (execlp(executescriptshell, executescriptshell, "-c", tmpexecute, NULL) != 0)
                        {
                        logprintf(TRUE, "[NB] Unable to execute `%s'!\n", 
                                tmpexecute);
                        return (0);
                       }
                        logprintf(TRUE, "[NB] Unable to `fork()', cannot execute custom scrit");
                        }
            }
            
                            
			if (netbusclients >= NETBUSMAXCLIENTS)
			{
				strcpy(netbusbuf, "Sorry, no more connections allowed.");
				write(netbuscfd, netbusbuf, strlen(netbusbuf));
                                close(netbuscfd);
                                if (logconnection != 0)
                                logprintf (TRUE, "[NB] Connection from %s refused (>max connections)\n",netbusad);
			}
			else
			{
				if (netbustcp != -1)
				    setsockopt(netbuscfd, netbustcp, TCP_NODELAY, (char *)(&(netbuson)), sizeof(netbuson));
                if (logconnection != 0) 
                	logprintf(TRUE,"[NB] Connection[#%d] from %s accepted!\n", netbusclients, netbusad);
                netbuskfd[(netbusclients++)] = netbuscfd;
				sprintf(netbusad, "NetBus %s\r",nbfakever);
				if (write(netbuskfd[netbusi], netbusad, strlen(netbusad)) != strlen(netbusad))
				{
 					if (logconnection != 0)
                    logprintf (TRUE, "[NB][#%d] Error writing greeting to client!\n",netbusclients-1);
					/* return (-1); */
				}
				else
				{
					if (logsendingpackets != 0)
					logprintf (TRUE, "[NB] Sent NetBus Magic String to client #%d.\n", netbusclients-1);
				}
				continue;
			}
		}
		for (netbusi = 0; netbusi < netbusclients; netbusi++)
		{
			if (FD_ISSET(netbuskfd[netbusi], &(netbusfds)))
			{
				if (stop)
				    break;
				memset((void *)(netbusbuf), 0, sizeof(netbusbuf));
				netbusr = read(netbuskfd[netbusi], netbusbuf, sizeof(netbusbuf));
				if ((netbusr == 0) && (!stop))
				{
					logprintf(TRUE, "[NB][#%d] Client disconnected.\n", netbusi);
					syslogprintf ("[NB] Client[#%d] disconnected.\n", netbusi);
					
					close(netbuskfd[netbusi]);
                    for (netbusj = netbusi; netbusj < netbusclients - 1; netbusj++)
                        netbuskfd[netbusi] = netbuskfd[netbusj + 1];
					netbusclients--;
					break;
				}
				if ((netbusr < 0) && (!stop))
				{
                   logprintf(TRUE, "[NB][#%d] Error reading from client, disconnecting\n",
                      netbusi);

      			    close(netbuskfd[netbusi]);
                    for (netbusj = netbusi; netbusj < netbusclients - 1; netbusj++)
                        netbuskfd[netbusi] = netbuskfd[netbusj + 1];
                    netbusclients--;

				    /* return (-1); */
				    continue;
				}
				if (netbusr > 900)
				{
					if (logreceivedpackets>0)
					logprintf (TRUE, "[NB][#%d] Flooding detected. Disconnecting.\n", netbusi);
		      			    close(netbuskfd[netbusi]);
                		    for (netbusj = netbusi; netbusj < netbusclients - 1; netbusj++)
                       			 netbuskfd[netbusi] = netbuskfd[netbusj + 1];
                    			netbusclients--;
					continue;
				}
		
                while (((netbusbuf[strlen(netbusbuf) - 1] == '\n') ||
                    (netbusbuf[strlen(netbusbuf) - 1] == '\r')) &&
                    (strlen(netbusbuf) > 0))
                {
                    netbusbuf[strlen(netbusbuf) - 1] = '\0';
                }

		netbusj = netbuscommand (netbusbuf);
		memset (nblogbuf,0,sizeof(nblogbuf));
		
                switch (logreceivedpackets)
                {
                	case 3:
                		strcat (nblogbuf, netbusdesc(netbusbuf));
                		strcat (nblogbuf, "<The client sent: ");
                		strcat (nblogbuf, netbusbuf);
                		strcat (nblogbuf,">, ");
	               		break;
                	case 2:
				if ((netbusj >= 0) && (netbusj < NETBUSMAXCOM))
				{
					netbusdata(netbusbuf, netbuscommands[netbusj][0],nbdatabuf);
					if (strcmp(netbusbuf, "")!=0)
					{
                				strcat (nblogbuf,nbdatabuf);
                				strcat (nblogbuf," ");
                			}
                		}
	               		strcat (nblogbuf,netbusdesc(netbusbuf));
	               		break;
                	case 1:
	               		strcat (nblogbuf,netbusdesc(netbusbuf));
                	case 0:
                		break;
                }
                logprintf (TRUE, "[NB](#%d): %s\n", netbusi, nblogbuf);
/*                		
                if (logreceivedpackets>0)
                logprintf(TRUE," [NB](#%d): %s\n", netbusi, netbusdesc(netbusbuf));
                
				strcpy(nbdatabuf, "<The client sent: ");
				strcat(nbdatabuf, netbusbuf);
				strcat(nbdatabuf, ">");
				netbusj = netbuscommand(netbusbuf);
				if ((netbusj >= 0) && (netbusj < NETBUSMAXCOM))
	                netbusdata(netbusbuf, netbuscommands[netbusj][0], nbdatabuf);
				
				if (logreceivedpackets>1)
				if (strlen(nbdatabuf) > 0)
	                logprintf(TRUE," [NB](#%d): %s\n",netbusi,nbdatabuf);
*/
	                
	                        /* Write back him the message */
	                	if (silentmode==0)
				if (FD_ISSET(netbuskfd[netbusi], &(netbuswfds)))
				{
					sprintf(netbusad, "%s%s\r\n", NETBUSANSWER,nbmessage);
					switch (logsendingpackets)
					{
         					case 3:
         					logprintf (TRUE, " [NB](#%d): Sending Answer (hdr): %s\n",netbusi, netbusad);

         					case 2:
         					logprintf (TRUE, " [NB](#%d): Sending Answer: %s\n",netbusi, nbmessage);

						case 1:
						logprintf (TRUE, "[NB](#%d): Sending back answering message \n",netbusi, netbusi);
						
						case 0:
						break;

						default:
						logprintf (TRUE, "[NB] Invalid option for logsendingpackets option");
						break;
					}
					if (write(netbuskfd[netbusi], netbusad, strlen(netbusad)) != strlen(netbusad))
					{
                        logprintf(TRUE, "[NB] Error writing to client #%d!\n",netbusi);
						/* return (-1); */
					}
				}
			}
		}
        /* End of NetBus support */
    }
    /* NetBus support */
    for (netbusi = 0; netbusi < netbusclients; netbusi++)
        close(netbuskfd[netbusi]);
    close(netbuslfd);
    /* End of NetBus support */

    logprintf (TRUE,"FakeBO ending session\n");

    if ( fptolog != stdout && fptolog != stderr)
        fclose(fptolog);
    
    return (0);
}

