/*
* ezbounce.cpp
*
* (C) 1998-2004 Murat Deligonul
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "autoconf.h"
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "server.h"
#include "general.h"
#include "ezbounce.h"
#include "config.h"
#include "debug.h"
time_t start_time;
static const char * const ezbounce_banner = EZBOUNCE_VERSION
"\n(c) 1998-2004 by Murat Deligonul (druglord@erupt.com)\n\n";
struct proxy_options pcfg;
list<userdef> * users;
list<ruleset> * shitlist;
strlist * vhosts;
static void sig_handler(int);
static void setup_signals();
static void usage(const char *);
static bool parse_cmdline(int, char **, char **, bool *, int *, pid_t *);
void redir_stdxxx(void);
/* disable for now */
#undef HAVE_SET_NEW_HANDLER
#ifdef HAVE_SET_NEW_HANDLER
void new_failed();
#endif
/* #define NOFORK */
static void setup_signals()
{
struct sigaction sv;
sv.sa_flags = 0;
sv.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sv, NULL);
sv.sa_handler = &sig_handler;
sigaction(SIGINT, &sv, NULL);
sigaction(SIGTERM, &sv, NULL);
sigaction(SIGHUP, &sv, NULL);
sigaction(SIGALRM, &sv, NULL);
/* sigaction(SIGSEGV, &sv, NULL); */
}
int main(int argc, char *argv[])
{
char tmp[20];
unsigned num_listening = 0;
#ifndef NOFORK
pid_t pid;
#endif
pid_t uid = 0; /* become this user */
bool nobg = 0; /* go to the back ground? */
char *iface_listen = NULL; /* interface to bind to for listening*/
int logindex = 0; /* argv[logindex] is the log */
#if defined(HAVE_NEW_H) && defined(HAVE_SET_NEW_HANDLER)
set_new_handler(new_failed);
#endif
printf(ezbounce_banner);
if (argc < 2 || !parse_cmdline(argc, argv, &iface_listen, &nobg, &logindex, &uid))
{
usage(argv[0]);
return 1;
}
printf("Reading config file %s ...\n", argv[logindex]);
if ((argc = load_config_file(argv[logindex], &pcfg, &users, &shitlist, &vhosts)) < 0)
{
fprintf(stderr, "Error(s) while loading config file -- exiting.\n");
return 1;
}
else if (argc == 0)
{
perror("Unable to open config file");
return 1;
}
else
printf("Config file successfully loaded.\n");
/* Init sock table */
printf("Socket table initialized: %d%s%d = %.02fkB\n",
pollsocket::create_table(pcfg.max_sockets), "x", sizeof(pollsocket *),
(float) sizeof(pollsocket *) * (float) pcfg.max_sockets / 1024.0);
/* Do listen vhost crap */
if (iface_listen)
{
struct in_addr in;
switch (fill_in_addr(iface_listen, &in))
{
case 0:
fprintf(stderr, "Can't listen on: %s: unknown host\n", iface_listen);
return 1;
case -1:
fprintf(stderr, "Can't listen on: %s: %s\n", iface_listen, strerror(errno));
return 1;
default:
pcfg.iface_listen = in;
}
}
printf("Listening on interface: %s\n", inet_ntoa(pcfg.iface_listen));
start_time = time(NULL);
if(pcfg.ports) {
argc = 1;
printf("Listening on ports");
while (gettok(pcfg.ports, tmp, 20, ',', argc++))
{
if (!ircproxy_listen((u_short)atoi(tmp), &pcfg.iface_listen,0))
printf(" (%s:%s)", tmp, strerror(errno));
else {
printf(" %s", tmp);
num_listening++;
}
}
fputc('\n', stdout);
}
#ifdef _USE_SSL
bool ssl_ready = pollsocket::init_ssl(pcfg.certfile);
if (!ssl_ready)
printf("SSL: cannot init SSL! (check your cert-file '%s')\n", pcfg.certfile);
else
printf("SSL: subsystem initialized\n");
#endif
if(pcfg.sslports
#ifdef _USE_SSL
&& ssl_ready
#endif
)
{
argc = 1;
printf("SSL: listening on ports");
#ifndef _USE_SSL
printf(" [note: SSL support was NOT compiled]");
#endif
while (gettok(pcfg.sslports, tmp, 20, ',', argc++))
{
if (!ircproxy_listen((u_short)atoi(tmp), &pcfg.iface_listen,1))
printf(" (%s:%s)", tmp, strerror(errno));
else {
printf(" %s", tmp);
num_listening++;
}
}
fputc('\n', stdout);
}
printf("Listening on total of %d ports\n", num_listening);
if (!num_listening)
{
fprintf(stderr, "oops, I can't run without listening on any ports\n");
return 1;
}
/* change uid if needed */
if (uid)
{
if (!setuid(uid))
printf("Now operating under userid %d\n.", uid);
else
perror("setuid");
}
/* start the log file */
if (!ircproxy_startlog(pcfg.logfile))
perror("WARNING: Unable to open log file");
#ifndef NOFORK
if ((nobg) || ((pid = fork()) == 0))
{
setsid();
/* redirect stderr to our silly little log file.
close stdin & stdout. */
close(STDIN_FILENO);
/* close(STDOUT_FILENO); -- config file reloading will output to stdout */
if (!nobg)
ircproxy_redir_stdxxx();
#endif
/* Write out pid-file if needed */
if (pcfg.pidfile)
{
int f = open(pcfg.pidfile, O_CREAT | O_WRONLY);
fdprintf(f, "%d", getpid());
fchmod(f, 0644);
close(f);
}
/* no longer needed */
delete[] pcfg.logfile;
delete[] pcfg.pidfile;
pcfg.logfile = NULL;
pcfg.pidfile = NULL;
setup_signals();
set_dns_timeout(pcfg.max_dns_wait_time);
if (pcfg.userfile)
{
printf("Loading user preferences from disk (%s) .... \n", pcfg.userfile);
ircproxy_load_prefs(::users, pcfg.userfile);
}
if (nobg)
printf("Starting IRC proxy ...\n");
start_proxy();
/* Server is finished. */
ircproxy_closelog();
stop_proxy();
delete[] pcfg.configfile;
delete[] pcfg.logfile;
delete[] pcfg.pidfile;
delete[] pcfg.motdfile;
delete[] pcfg.userfile;
delete[] pcfg.logdir;
delete[] pcfg.ports;
delete[] pcfg.dcc_ports;
destroy_list(users, 0);
destroy_list(shitlist, 0);
destroy_list(vhosts, 1);
delete users;
delete shitlist;
delete vhosts;
return 0;
#ifndef NOFORK
}
else if (pid < 0)
perror("Can't go into the background");
else
printf("IRC Proxy started -- pid: %d\n", pid);
#endif
return 0;
}
static void sig_handler(int sig)
{
switch (sig)
{
case SIGHUP:
printlog("Got SIGHUP; reloading configuration file\n");
ircproxy_request_rehash();
break;
case SIGTERM:
printlog("Got terminate signal, killing server now\n");
ircproxy_die(1, "got terminate signal");
break;
case SIGSEGV:
printlog("Got SIGSEGV: goodbye :-(\n");
break;
case SIGINT:
printlog("Interrupt signal: waiting for server to shut down\n");
ircproxy_die(0, "keyboard interrupt");
default:
break;
}
}
static void usage(const char *bname)
{
fprintf(stderr, "Usage:\n%s [options] <configuration file>\n", bname);
fprintf(stderr, "Available options:\n");
fprintf(stderr, " -f don't go into the background\n");
fprintf(stderr, " -b <hostname> listen for connections on a different interface\n");
fprintf(stderr, " -u <uid> become user uid after binding listen socket\n\n");
}
static bool parse_cmdline(int argc, char **argv, char **pIface_listen,
bool * pNobg, int *pIndex, pid_t * uid)
{
for (int z = 1; z < argc; z++)
{
switch (argv[z][0])
{
/* a -flag, next char must be -B or -F */
case '-':
switch (argv[z][1])
{
case 'u':
case 'U':
*uid = atoi(argv[++z]);
continue;
case 'f':
case 'F':
*pNobg = 1;
break;
case 'b':
case 'B':
if (z + 1 < argc)
*pIface_listen = argv[++z];
continue;
case '-':
if (strcasecmp(&argv[z][2], "help") != 0)
continue;
case 'h':
return 0;
default:
break;
}
default:
*pIndex = z;
}
}
return (*pIndex != 0);
}
#ifdef HAVE_SET_NEW_HANDLER
void new_failed()
{
printlog("fatal memory allocation error :(\n");
printlog("notify author\n");
abort();
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1