/*
 * Copyright (c) 1998-2007, OpenFWTK Development Group
 * All rights reserved. See LICENSE.
 */

/*
 * ident-spoofer.c, an authd/identd serivce emulator for fwtk
 * (C) Copyright 1998-2001 by ArkanoiD <ark@eltex.net>
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <errno.h>
#include <string.h>
#include "firewall.h"
#include "firewall2.h"
#include "fwfunc.h"

static char* moduleId ATTR_UNUSED = "$Id: ident-spoofer.c,v 1.9 2007/09/10 02:49:13 arkenoi Exp $";

#ifndef MAXNAME
#define MAXNAME 32
#endif

#ifndef RANDPREFIX
#define RANDPREFIX "usr"        /* random username prefix */
#endif

#ifndef RANDLEN
#define RANDLEN 8               /* random username length */
#endif

#if defined(linux) || defined (SOLARIS)
extern void initsetproctitle(int,char**);
#endif

static  Cfg                     *confp;

extern	char*	randomname(int);

int
oktotalkto()
{                       
	Cfg     *cf;
	int     x;
   
	cf = cfg_get("hosts", confp);
	while(cf != (Cfg *)0) {
		if(cf->argc > 0) {

			for(x = 0; x < cf->argc && cf->argv[x][0] != '-'; x++) {
				if(hostmatch(cf->argv[x], proxy_stats.riaddr)) {
					if(cf->flags & PERM_DENY) {
						syslog(LLEV, "deny host=%.512s/%.20s ident lookup",
							proxy_stats.rladdr, proxy_stats.riaddr);  
						return(0);
					}
					syslog(LLEV, "permit host=%.512s/%.20s ident lookup",
						proxy_stats.rladdr, proxy_stats.riaddr);
					return(1);
				}
			}
		}
		cf = cfg_get("hosts",(Cfg*)0);
	} 
	syslog(LLEV, "deny host=%.512s/%.20s ident lookup",
		proxy_stats.rladdr, proxy_stats.riaddr);
	return(0);
}


int
main(ac, av)
int ac;
char **av;

{
	char	request[64];
	char	response[128];
	int 	sport, dport;
	char	*tbuf;
	char	*ostype;
	Cfg		*cf;
	char	user[MAXNAME];
	char	myname[128];

	strncpy(myname, av[0], sizeof(myname));

#ifndef LOG_DAEMON
	openlog(myname, LOG_PID);
#else
	openlog(myname, LOG_PID | LOG_NDELAY, LFAC);
#endif

#if 	defined(linux) || defined (SOLARIS)
	initsetproctitle(ac,av);
#endif

	if (ac == 2 && !strcmp(av[ac - 1], "-v")) {
		fprintf(stderr, "version %s\n", moduleId);
		syslog(LLEV, "version %s", moduleId);
		exit(0);
	}


	if((confp = cfg_read(myname)) == (Cfg *)-1)
		exit(1);

	if (peername(0, proxy_stats.rladdr, proxy_stats.riaddr,
	    sizeof(proxy_stats.rladdr)) != 0) {
		syslog (LLEV, "fwtksyserr: cannot get peer name: %s", strerror(errno));
		exit(1);
	}

	if (!oktotalkto())
		exit(1);

	proxy_update_status();

	sotimeout(proxy_conf_timeout(confp));

	if((proxy_stats.inbytes += sogets(0, request, sizeof(request))) <= 2) {
		syslog(LLEV, "peer dropped connection");
		exit(1);
	}

	if ((cf = cfg_get("ostype", confp)) != (Cfg *)0) {
		if (cf->argc != 1) {
			syslog(LLEV,
				"fwtkcfgerr: ostype must have one parameter, line %d",
				cf->ln);
			exit(1);
		}
		ostype = cf->argv[0];
	} else	ostype = "UNIX";

	request[strlen(request)-2] = 0;
	tbuf=(char *)strtok(request, ",");

	if (tbuf)
		sport=atoi(tbuf);
	else
		syslog(LLEV, "malformed request");

	tbuf=(char *)strtok(NULL, ",");	

	if (tbuf)
		dport=atoi(tbuf);
	else
		syslog(LLEV,"malformed request");

	cf = cfg_get("service",confp);

	while (cf != (Cfg *)0) {
		if ((cf->argc < 1) || (cf->argv[0][0] == '-')) {
			syslog(LLEV, "fwtkcfgerr: missing parameter, line %d",
			       cf->ln);
			exit(1);
		}

		if (str_to_port(cf->argv[0]) == dport) {
			if(strncmp("random", cf->argv[1], 6) == 0) {
				strlcpy(user, RANDPREFIX, MAXNAME - 1);
				strlcat(user,
					randomname(MAXNAME - sizeof(RANDPREFIX)), MAXNAME);
			} else strlcpy(user, cf->argv[1], MAXNAME);

			user[RANDLEN] = 0;

			snprintf(response, sizeof(response) - 1,
				 "%d, %d : USERID : %s : %.20s", sport,
			         dport, ostype, user);
			syslog(LLEV, "requested information granted: sp=%d dp=%d "
				"(user=%.20s service=%.20s)",
				sport, dport, user, cf->argv[0]);
			puts(response);
			exit(0);
		}
		cf = cfg_get("service", (Cfg*)0);
	}

	syslog(LLEV,"service unknown, sp=%d dp=%d", sport, dport);
	snprintf(response, sizeof(response) - 1, "%d, %d : ERROR : HIDDEN-USER",
	    	 sport, dport);
	puts(response);
	exit(0);

}
