File:  [ELWIX - Embedded LightWeight unIX -] / ansh / src / ansh3d.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Tue Oct 4 22:37:46 2011 UTC (12 years, 9 months ago) by misho
Branches: MAIN
CVS tags: HEAD
Initial revision

/*************************************************************************
 * (C) 2011 AITNET - Sofia/Bulgaria - <office@aitnet.org>
 *  by Michael Pounov <misho@elwix.org>
 *
 * $Author: misho $
 * $Id: ansh3d.c,v 1.1 2011/10/04 22:37:46 misho Exp $
 *
 *************************************************************************/
#include "global.h"
#include "anshd.h"
#include "proc.h"


intptr_t Kill;
int Verbose, Crypted = 1;
proc_head_t pH;
int bpfLEN, Timeout, Daemon = 1;

extern char compiled[], compiledby[], compilehost[];

static void
Usage()
{
	printf(	" -= anshd =- ELWIX Layer3 remote management service over ICMP\n"
		"=== %s === %s@%s ===\n\n"
		" Syntax: ansh3d [options]\n\n"
		"\t-a <host>\tBind to host address (default is *any*)\n"
		"\t-i <id>\tService ID (default is 42)\n"
		"\t-U <user>\tRun service with other user\n"
		"\t-C <dir>\tRun service into chroot directory\n"
		"\t-t <timeout>\tTimeout of login if no activity (default is 0 sec)\n"
		"\t-u\t\tSwitch to unencrypted traffic between hosts\n"
		"\t-b\t\tRun into batch mode (default is daemon mode)\n"
		"\t-v\t\tVerbose (more -v, more verbosity ...)\n"
		"\t-h\t\tThis help screen!\n"
		"\n", compiled, compiledby, compilehost);
}

static void
sig(int s)
{
	int state;

	switch (s) {
		case SIGHUP:
			VERB(1) LOG("Got SIGHUP!\n");
			break;
		case SIGTERM:
			Kill++;
			VERB(1) LOG("Got SIGTERM!\n");
			break;
		case SIGPIPE:
			VERB(1) LOG("Got SIGPIPE!\n");
			break;
		case SIGCHLD:
			VERB(1) LOG("Got SIGCHLD!\n");
			while (waitpid(-1, &state, WNOHANG) > 0);
			break;
	}
}

static void *
hook_error(void *root, void *arg)
{
/*	sched_root_task_t *r = root; */

	if (!root)
		return (void*) -1;

	if (arg == (void*) EINTR)
		return (void*) -1;

	return NULL;
}

int
main(int argc, char **argv)
{
	struct sockaddr sa = { 0 };
	struct sockaddr_in *sin4 = (struct sockaddr_in*) &sa;
	struct sockaddr_in6 *sin6 = (struct sockaddr_in6*) &sa;
	struct hostent *host;
	struct passwd *pass;
	int fd, h = 0, uid = 0, gid = 0;
	long id = ANSH_ID;
	char ch, szUser[STRSIZ] = "root", szChroot[STRSIZ] = "/";
	struct sigaction sact;
	sched_root_task_t *root = NULL;
	struct tagProc *proc;

	while ((ch = getopt(argc, argv, "hvubt:a:i:U:C:")) != -1)
		switch (ch) {
			case 'U':
				pass = getpwnam(optarg);
				if (!pass) {
					printf("Error:: User %s not found!\n", optarg);
					return 1;
				} else {
					strlcpy(szUser, optarg, sizeof szUser);
					uid = pass->pw_uid;
					gid = pass->pw_gid;
				}
				endpwent();
				break;
			case 'C':
				if (access(optarg, R_OK)) {
					printf("Error:: in chroot %s #%d - %s\n", optarg, errno, strerror(errno));
					return 1;
				} else
					strlcpy(szChroot, optarg, sizeof szChroot);
				break;
			case 'i':
				id = strtol(optarg, NULL, 0);
				break;
			case 't':
				Timeout = abs(strtol(optarg, NULL, 0));
				break;
			case 'a':
				host = gethostbyname(optarg);
				if (!host) {
					printf("Error:: in bind address '%s' #%d - %s\n", 
							optarg, h_errno, hstrerror(h_errno));
					return 1;
				}
				switch (host->h_addrtype) {
					case AF_INET:
						sin4->sin_len = sizeof(struct sockaddr_in);
						sin4->sin_family = AF_INET;
						memcpy(&sin4->sin_addr.s_addr, host->h_addr, host->h_length);
						break;
					case AF_INET6:
						sin6->sin6_len = sizeof(struct sockaddr_in6);
						sin6->sin6_family = AF_INET6;
						memcpy(&sin6->sin6_addr.s6_addr, host->h_addr, host->h_length);
						break;
					default:
						printf("Error:: Unknown address type %d !!!\n", host->h_addrtype);
						return 1;
				}
				break;
			case 'u':
				Crypted ^= Crypted;
				break;
			case 'b':
				Daemon ^= Daemon;
				break;
			case 'v':
				Verbose++;
				break;
			case 'h':
			default:
				Usage();
				return 1;
		}
	argc -= optind;
	argv += optind;

	/* sanity check for openned descriptor */
	if (!sa.sa_family) {
		sin4->sin_len = sizeof(struct sockaddr_in);
		sin4->sin_family = AF_INET;
	}

	/* catch signals */
	memset(&sact, 0, sizeof sact);
	sigemptyset(&sact.sa_mask);
	sact.sa_handler = sig;
	sigaction(SIGPIPE, &sact, NULL);
	sigaction(SIGCHLD, &sact, NULL);
	sigaction(SIGTERM, &sact, NULL);
	sigaction(SIGHUP, &sact, NULL);

	openlog("ansh3d", LOG_CONS | LOG_PID, LOG_DAEMON);

	if (Daemon) {
		switch (fork()) {
			case -1:
				ERR("Daemon mode #%d - %s\n", errno, strerror(errno));
				closelog();
				return 1;
			case 0:
				VERB(1) LOG("Welcome to dark ...\n");

				setsid();

				fd = open("/dev/null", O_WRONLY);
				if (fd) {
					dup2(fd, STDIN_FILENO);
					dup2(fd, STDOUT_FILENO);
					dup2(fd, STDERR_FILENO);
					if (fd > 2)
						close(fd);
				}
				break;
			default:
				VERB(1) LOG("Going to shadow land ...\n");
				closelog();
				return 0;
		}
	}

	if (ioCreatePIDFile(PIDFILE_ANSH3D, 42)) {
		ERR("Error:: already started ansh3d service ...\n");
		closelog();
		return 1;
	}

	h = PrepareL3(&sa, &bpfLEN);
	if (h == -1) {
		ERR("Error:: Descriptor not opened ... abort!\n");
		unlink(PIDFILE_ANSH3D);
		closelog();
		return 2;
	}

	SLIST_INIT(&pH);
	if (!(proc = InitProc(h, NULL, id, bpfLEN))) {
		ERR("Error:: Not enough memory ...\n");
		close(h);
		unlink(PIDFILE_ANSH3D);
		closelog();
		return 3;
	}

	root = schedBegin();
	if (!root) {
		ERR("Scheduler not init #%d - %s\n", sched_GetErrno(), sched_GetError());
		DestroyProc(id);
		close(h);
		unlink(PIDFILE_ANSH3D);
		closelog();
		return 4;
	} else
		root->root_hooks.hook_root.error = hook_error;

	chdir("/");
	chroot(szChroot);

	setgid(gid);
	setuid(uid);

	if (schedRead(root, icmpRx, (void*) id, h)) {
		schedRun(root, &Kill);
	} else
		ERR("Failed to add reader task #%d - %s\n", sched_GetErrno(), sched_GetError());

	VERB(1) LOG("Finish process.");
	schedEnd(&root);
	DestroyProc(id);
	close(h);
	unlink(PIDFILE_ANSH3D);
	closelog();
	return 0;
}

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>