
/* 
 * Minimal fake ident server for firewalls / NAT gateways.
 * This code is very basic, but at least _secure_ .
 * 
 * Compile with : make minidentd
 * Install with : strip minidentd
 *                cp minidentd /usr/local/bin/
 * Spawn from your favorite superserver (inetd, tcpserver, etc), from port
 * 113 / TCP .
 * 
 * Public domain, make what you want with this source code.
 * -Jedi/Sector One <j@pureftpd.org> .
 */


/* An empty directory in your filesystem */
#define EMPTY "/var/empty"

/* The user to switch to */
#define USER "nobody"

/* The default reply */
#define DEFAULT_USER "minidentd"

/* Timeout in seconds */
#define TIMEOUT 5U

/* Don't change anything below that line */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pwd.h>
#include <grp.h>
#include <errno.h>

#ifndef errno
extern int errno;
#endif

#if defined(_BSD_SOURCE) || defined(_SYSV_SOURCE) || defined(_XOPEN_SOURCE)
# define HAVE_SETGROUPS
#endif

static int parse(char *line, const char * const user)
{
    char *coma;
    char *endptr;
    unsigned int p1, p2;
    
    if ((coma = strchr(line, ',')) == NULL) {
	inv:
	puts("0, 0 : ERROR : X-INVALID-REQUEST\r");	
	return -1;
    }
    *coma++ = 0;
    for (;;) {
	if (*coma == 0) {
	    goto inv;
	}
	if (isspace((unsigned char) *coma)) {
	    *coma++ = 0;
	    continue;
	}
	if (isdigit((unsigned char) *coma)) {
	    break;
	}
	goto inv;
    }
    p1 = (unsigned int) strtoul(line, &endptr, 10);
    if (endptr == line || p1 > 65535U) {
	goto inv;
    }
    p2 = (unsigned int) strtoul(coma, &endptr, 10);
    if (endptr == coma || p2 > 65535U) {
	goto inv;
    }
    printf("%u, %u : USERID : UNIX : %s\r\n", p1, p2, user);
    
    return 0;
}

static int safe(void)
{
    struct passwd *pw;
    
    if (geteuid() != (uid_t) 0U) {
	return 0;
    }
    if ((pw = getpwnam(USER)) == NULL || pw->pw_uid <= (uid_t) 0U ||
	chdir(EMPTY) != 0 || chroot(EMPTY) != 0 || chdir("/") != 0) {
	return -1;
    }
    if (
#ifdef HAVE_SETGROUPS
	setgroups((size_t) 1U, &pw->pw_gid) != 0 ||
#endif	
	setgid(pw->pw_gid) != 0 || setegid(pw->pw_gid) != 0 ||
	setuid(pw->pw_uid) != 0 || seteuid(pw->pw_uid) != 0) {
	return -1;
    }
    return 0;
}

int main(int a, char *b[])
{
    const char *user = DEFAULT_USER;
    char line[42];    
    
    if (safe() != 0) {
	return -1;
    }
    (void) close(2);
    (void) alarm(TIMEOUT);
    if (isatty(1)) {
	puts("Usage : tcpserver -HRql0 0 113 "
	     "/usr/local/bin/minidentd [user]\n\n"
	     "You can of course run it from any other superserver "
	     "(inetd, jnetd, xinetd, ...)");
	return 2;
    }
    if (a == 2) {
	user = b[1];
    }
    if (fgets(line, sizeof line, stdin) == NULL) {
	return 1;
    }
    return parse(line, user);
}
