#ifndef LINT
static char *rcsid="$Id: whosond.c,v 1.24 2003/08/14 12:50:35 crosser Exp $";
#endif

/*
	$Log: whosond.c,v $
	Revision 1.24  2003/08/14 12:50:35  crosser
	Memory leak in the client code (ilya@glas.net)
	Changes to recent autoconf/automake (woods@weird.com)
	use pidfile() if it exists (woods@weird.com)
	
	Revision 1.23  2001/09/23 13:29:17  crosser
	change gid to uid in setreuid
	
	Revision 1.22  2001/09/21 21:31:38  crosser
	even more paranoia added
	
	Revision 1.21  2001/09/21 06:15:56  crosser
	more cleanup in revoking privileges, warnings in configure, version change
	
	Revision 1.20  2001/09/20 21:24:28  crosser
	Some cleanup of security measures
	
	Revision 1.19  2001/09/20 06:09:36  crosser
	clear suppliementary groups in whosond
	
	Revision 1.18  2001/09/20 05:56:39  crosser
	chroot() for whosond
	
	Revision 1.17  1999/12/28 13:25:34  crosser
	check for setreuid; added getopt to cvs
	
	Revision 1.16  1999/11/26 17:18:57  crosser
	tune for sunos4
	
	Revision 1.15  1999/10/06 11:19:52  crosser
	Handle SIGPIPE in the server
	Fix (kludge) for private fields in the config struct
	Make beta3 version
	
	Revision 1.14  1999/07/27 17:17:18  crosser
	remove include version.h
	
	Revision 1.13  1998/07/28 17:51:53  crosser
	make 64bit architecure happy

	Revision 1.12  1998/07/05 00:26:18  crosser
	Change copyright

	Revision 1.11  1998/07/05 00:01:27  crosser
	add user and group set

	Revision 1.10  1998/07/03 09:32:48  crosser
	autoconf for signal and detach

	Revision 1.9  1998/07/02 18:17:12  crosser
	fix proc. of -v option

	Revision 1.8  1998/07/02 18:01:15  crosser
	change error reporting to syslog

	Revision 1.7  1998/07/01 21:55:16  crosser
	cosmetics

	Revision 1.6  1998/07/01 13:39:18  crosser
	make it work on Solaris

	Revision 1.5  1998/07/01 05:18:09  crosser
	minor warnings fix

	Revision 1.4  1998/07/01 05:01:22  crosser
	Big reorganization

*/

/*
	WHAT IS IT:
		Implementation of experimental "whoson" protocol
	AUTHOR:
		Eugene G. Crosser <crosser@average.org>
	COPYRIGHT:
		Public domain
*/

#include "config.h"

#include <sys/types.h>
#include <time.h>
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>
#ifndef OPTARG_DEFINED
#include <getopt.h>
#endif

#include "whosond.h"
#include "serv_common.h"
#include "rtconfig.h"
#include "report.h"
 
int wso_verbose=0;

static void showver(char *name)
{
	fprintf(stderr,"%s Version %s Build %s\n",name,VERSION,__DATE__);
}

static void showhelp(char *name)
{
	fprintf(stderr,"Usage: %s -I configfile -V -v -h\n",name);
	fprintf(stderr,"\t-I configfile\t- replacement config [default: %s]\n",DEFAULT_CONFIG);
	fprintf(stderr,"\t-d\t\t- do not go to background\n");
	fprintf(stderr,"\t-V\t\t- print version\n");
	fprintf(stderr,"\t-v\t\t- increase verbosity\n");
	fprintf(stderr,"\t-h\t\t- print this help message\n");
}

int main(int argc, char *argv[])
{
	struct _evdesc (*evvec[FD_SETSIZE]) (int fd, void *priv);
	void *priv[FD_SETSIZE];
	struct _evdesc evdesc;
	struct _servdesc *servdesc;
	int i;
	char *configfile=DEFAULT_CONFIG;
	int daemon=1;

	while ((i=getopt(argc,argv,"I:dvVh")) != EOF) switch (i) {
	case 'I':
		/* if someone decides to modify the name displayed in
		   the "ps" output it may be useful to copy the arg... */
		configfile=(char *)malloc(strlen(optarg)+1);
		strcpy(configfile,optarg);
		break;
	case 'd':
		daemon=0;
		break;
	case 'V':
		showver(argv[0]);
		return 0;
	case 'v':
		wso_verbose++;
		break;
	case 'h':
		showhelp(argv[0]);
		return 0;
	default:
		showhelp(argv[0]);
		return 1;
	}

	if (daemon) {
		int child;
		if ((child=fork()) > 0) {
			sleep(1);
			return 0;
		} else if (child < 0) {
			ERRLOG((LOG_ERR,"fork error: %m"))
			return 1;
		} else {
			fflush(stdin);
			fflush(stdout);
			fflush(stderr);
			setbuf(stdin,NULL);
			setbuf(stdout,NULL);
			setbuf(stderr,NULL);
			close(0);
			close(1);
			close(2);
			open("/dev/null",O_RDWR);
			dup(0);
			dup(0);
#ifdef HAVE_SETSID
			setsid();
#else
#ifdef HAVE_SETPGRP
#ifdef SETPGRP_VOID
			setpgrp();
#else
			setpgrp(0,0);
#endif
#endif
#endif
#ifdef HAVE_PIDFILE
			pidfile((char *) NULL);
#endif
		}
	}

#ifdef HAVE_SYSLOG
	tzset(); /* will not work automatically from chrooted environment */
	openlog("whosond",LOG_CONS|LOG_PID
#ifdef LOG_NDELAY
					|LOG_NDELAY
#endif
						,LOG_DAEMON);
#endif

	for (i=0;i<FD_SETSIZE;i++) {
		evvec[i]=0;
		priv[i]=0;
	}

	if (!(servdesc=wso_read_config(configfile,1))) {
		ERRLOG((LOG_ERR,"No configured servers\n"))
		return 1;
	}

	i=0;
	for (;servdesc;servdesc=servdesc->next) {
		evdesc=(servdesc->root.init)(servdesc->priv);
		if (evdesc.fd >= 0) {
			evvec[evdesc.fd]=evdesc.evproc;
			priv[evdesc.fd]=evdesc.priv;
			i++;
		}
	}

	if (i == 0) {
		ERRLOG((LOG_ERR,"No initialized servers\n"))
		return 1;
	}

	if (newroot) {
#ifdef HAVE_CHROOT
		if (chdir(newroot) == 0) {
			if (chroot(newroot)) {
				ERRLOG((LOG_ERR,"chroot(%s): %m\n",newroot))
				return 1;
			}
		} else {
			ERRLOG((LOG_ERR,"chdir(%s): %m\n",newroot))
			return 1;
		}
#else
		ERRLOG((LOG_ERR,"function chroot() not present,\n"))
		ERRLOG((LOG_ERR,"remove it from the config file\n"))
		return 1;
#endif
	}

	if (rungid) {
#ifdef HAVE_SETGROUPS
		/* Solar Designer says (quoting DJB) that there are
		   systems where you cannot set null list of supplementary
		   groups, and also there are systems where gid_t is
		   short but setgroups accepts array of int-s.  Weird.
		   BTW I suspect that we may run into SIGBUS in the latter
		   case... */
		gid_t groups[2];
		groups[0]=groups[1]=rungid;
		if (setgroups(1,groups) == -1) {
			ERRLOG((LOG_ERR,"setgroups() failed: %m\n"))
			return 1;
		}
#endif
#ifdef HAVE_SETREUID
		setregid(rungid,rungid);
#else
		setegid(rungid);
		setgid(rungid);
#endif
	}
	if (runuid) {
#ifdef HAVE_SETREUID
		setreuid(runuid,runuid);
#else
		seteuid(runuid);
		setuid(runuid);
#endif
	}

	/* In case the client disconnects before reading our responce */
	(void)signal(SIGPIPE,SIG_IGN);
	/* is this setting saved after raising the signal on SysV?
	   User signal handlers are reset to SIG_DFL.  Let us hope
	   that SIG_IGN is a special setting and is kept forever. */

	mainloop(evvec,priv);

	return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1