X-Git-Url: https://jfr.im/git/irc/rqf/shadowircd.git/blobdiff_plain/68ff929f3d4d614c131b8e3b67052ba0a2bbec8e..6795400d0a60f52576c859eedbccf9fb6a0ede13:/src/ircd.c diff --git a/src/ircd.c b/src/ircd.c index bef2eab..a9f6cfb 100644 --- a/src/ircd.c +++ b/src/ircd.c @@ -1,10 +1,11 @@ /* - * ircd-ratbox: A slightly useful ircd. + * charybdis: A slightly useful ircd. * ircd.c: Starts up and runs the ircd. * * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center * Copyright (C) 1996-2002 Hybrid Development Team - * Copyright (C) 2002-2005 ircd-ratbox development team + * Copyright (C) 2002-2008 ircd-ratbox development team + * Copyright (C) 2005-2008 charybdis development team * * 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 @@ -21,25 +22,21 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * - * $Id: ircd.c 3249 2007-03-05 18:51:17Z nenolod $ + * $Id$ */ +#include "ratbox_lib.h" #include "stdinc.h" #include "setup.h" #include "config.h" - -#include "tools.h" #include "ircd.h" #include "channel.h" #include "class.h" #include "client.h" #include "common.h" -#include "event.h" #include "hash.h" -#include "irc_string.h" +#include "match.h" #include "ircd_signal.h" -#include "sprintf_irc.h" -#include "s_gline.h" #include "msg.h" /* msgtab */ #include "hostmask.h" #include "numeric.h" @@ -47,9 +44,8 @@ #include "res.h" #include "restart.h" #include "s_auth.h" -#include "commio.h" #include "s_conf.h" -#include "s_log.h" +#include "logger.h" #include "s_serv.h" /* try_connections */ #include "s_user.h" #include "s_stats.h" @@ -58,30 +54,100 @@ #include "supported.h" #include "whowas.h" #include "modules.h" -#include "memory.h" #include "hook.h" #include "ircd_getopt.h" -#include "balloc.h" #include "newconf.h" -#include "patricia.h" #include "reject.h" #include "s_conf.h" #include "s_newconf.h" #include "cache.h" #include "monitor.h" -#include "libcharybdis.h" #include "patchlevel.h" #include "serno.h" +#include "sslproc.h" +#include "chmode.h" +#include "privilege.h" +#include "bandbi.h" + +/* /quote set variables */ +struct SetOptions GlobalSetOptions; + +/* configuration set from ircd.conf */ +struct config_file_entry ConfigFileEntry; +/* server info set from ircd.conf */ +struct server_info ServerInfo; +/* admin info set from ircd.conf */ +struct admin_info AdminInfo; + +struct Counter Count; +struct ServerStatistics ServerStats; + +int maxconnections; +struct Client me; /* That's me */ +struct LocalUser meLocalUser; /* That's also part of me */ + +rb_dlink_list global_client_list; + +/* unknown/client pointer lists */ +rb_dlink_list unknown_list; /* unknown clients ON this server only */ +rb_dlink_list lclient_list; /* local clients only ON this server */ +rb_dlink_list serv_list; /* local servers to this server ONLY */ +rb_dlink_list global_serv_list; /* global servers on the network */ +rb_dlink_list local_oper_list; /* our opers, duplicated in lclient_list */ +rb_dlink_list oper_list; /* network opers */ + +const char *logFileName = LPATH; +const char *pidFileName = PPATH; + +char **myargv; +int dorehash = 0; +int dorehashbans = 0; +int doremotd = 0; +int kline_queued = 0; +int server_state_foreground = 0; +int opers_see_all_users = 0; +int ssl_ok = 0; +int zlib_ok = 1; + +int testing_conf = 0; +time_t startup_time; + +int default_server_capabs = CAP_MASK; + +int splitmode; +int splitchecking; +int split_users; +int split_servers; +int eob_count; -/* - * Try and find the correct name to use with getrlimit() for setting the max. - * number of files allowed to be open by this process. - */ -int _charybdis_data_version = CHARYBDIS_DV; +void +ircd_shutdown(const char *reason) +{ + struct Client *target_p; + rb_dlink_node *ptr; + + RB_DLINK_FOREACH(ptr, lclient_list.head) + { + target_p = ptr->data; + + sendto_one(target_p, ":%s NOTICE %s :Server Terminating. %s", + me.name, target_p->name, reason); + } + + RB_DLINK_FOREACH(ptr, serv_list.head) + { + target_p = ptr->data; -extern int ServerRunning; -extern struct LocalUser meLocalUser; -extern char **myargv; + sendto_one(target_p, ":%s ERROR :Terminated by %s", + me.name, reason); + } + + ilog(L_MAIN, "Server Terminating. %s", reason); + close_logfiles(); + + unlink(pidFileName); + exit(0); +} /* * print_startup - print startup information @@ -105,30 +171,6 @@ print_startup(int pid) dup2(0, 2); } -static void -ircd_log_cb(const char *str) -{ - ilog(L_MAIN, "%s", str); -} - -/* - * Why EXIT_FAILURE here? - * Because if ircd_die_cb() is called it's because of a fatal - * error inside libcharybdis, and we don't know how to handle the - * exception, so it is logical to return a FAILURE exit code here. - * --nenolod - */ -static void -ircd_die_cb(const char *str) -{ - /* Try to get the message out to currently logged in operators. */ - sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Server panic! %s", str); - inotice("server panic: %s", str); - - unlink(pidFileName); - exit(EXIT_FAILURE); -} - /* * init_sys * @@ -139,28 +181,22 @@ ircd_die_cb(const char *str) static void init_sys(void) { -#if defined(RLIMIT_FD_MAX) && defined(HAVE_SYS_RLIMIT_H) +#if defined(RLIMIT_NOFILE) && defined(HAVE_SYS_RESOURCE_H) struct rlimit limit; - if(!getrlimit(RLIMIT_FD_MAX, &limit)) + if(!getrlimit(RLIMIT_NOFILE, &limit)) { - if(limit.rlim_max < MAXCONNECTIONS) - { - fprintf(stderr, "ircd's bootstrap fd table is too big\n"); - fprintf(stderr, "Hard Limit: %ld bootstrap size: %d\n", - (long) limit.rlim_max, MAXCONNECTIONS); - fprintf(stderr, "Fix MAXCONNECTIONS\n"); - exit(-1); - } - - limit.rlim_cur = limit.rlim_max; /* make soft limit the max */ - if(setrlimit(RLIMIT_FD_MAX, &limit) == -1) + maxconnections = limit.rlim_cur; + if(maxconnections <= MAX_BUFFER) { - fprintf(stderr, "error setting max fd's to %ld\n", (long) limit.rlim_cur); + fprintf(stderr, "ERROR: Shell FD limits are too low.\n"); + fprintf(stderr, "ERROR: charybdis reserves %d FDs, shell limits must be above this\n", MAX_BUFFER); exit(EXIT_FAILURE); } + return; } #endif /* RLIMIT_FD_MAX */ + maxconnections = MAXCONNECTIONS; } static int @@ -207,16 +243,8 @@ make_daemon(void) static int printVersion = 0; struct lgetopt myopts[] = { - {"dlinefile", &ConfigFileEntry.dlinefile, - STRING, "File to use for dlines.conf"}, {"configfile", &ConfigFileEntry.configfile, STRING, "File to use for ircd.conf"}, - {"klinefile", &ConfigFileEntry.klinefile, - STRING, "File to use for kline.conf"}, - {"xlinefile", &ConfigFileEntry.xlinefile, - STRING, "File to use for xline.conf"}, - {"resvfile", &ConfigFileEntry.resvfile, - STRING, "File to use for resv.conf"}, {"logfile", &logFileName, STRING, "File to use for ircd.log"}, {"pidfile", &pidFileName, @@ -231,32 +259,6 @@ struct lgetopt myopts[] = { {NULL, NULL, STRING, NULL}, }; -void -set_time(void) -{ - struct timeval newtime; - newtime.tv_sec = 0; - newtime.tv_usec = 0; -#ifdef HAVE_GETTIMEOFDAY - if(gettimeofday(&newtime, NULL) == -1) - { - ilog(L_MAIN, "Clock Failure (%d)", errno); - sendto_realops_snomask(SNO_GENERAL, L_ALL, - "Clock Failure (%d), TS can be corrupted", errno); - - restart("Clock Failure"); - } -#else - newtime.tv_sec = time(NULL); - -#endif - if(newtime.tv_sec < CurrentTime) - set_back_events(CurrentTime - newtime.tv_sec); - - SystemTime.tv_sec = newtime.tv_sec; - SystemTime.tv_usec = newtime.tv_usec; -} - static void check_rehash(void *unused) { @@ -279,32 +281,11 @@ check_rehash(void *unused) { sendto_realops_snomask(SNO_GENERAL, L_ALL, "Got signal SIGUSR1, reloading ircd motd file"); - free_cachefile(user_motd); - user_motd = cache_file(MPATH, "ircd.motd", 0); + cache_user_motd(); doremotd = 0; } } -void -charybdis_io_loop(void) -{ - time_t delay; - - while (ServerRunning) - { - /* Run pending events, then get the number of seconds to the next - * event - */ - - delay = eventNextTime(); - if(delay <= CurrentTime) - eventRun(); - - - comm_select(250); - } -} - /* * initalialize_global_set_options * @@ -318,7 +299,11 @@ initialize_global_set_options(void) memset(&GlobalSetOptions, 0, sizeof(GlobalSetOptions)); /* memset( &ConfigFileEntry, 0, sizeof(ConfigFileEntry)); */ - GlobalSetOptions.maxclients = MAX_CLIENTS; + GlobalSetOptions.maxclients = ServerInfo.default_max_clients; + + if(GlobalSetOptions.maxclients > (maxconnections - MAX_BUFFER) || (GlobalSetOptions.maxclients <= 0)) + GlobalSetOptions.maxclients = maxconnections - MAX_BUFFER; + GlobalSetOptions.autoconn = 1; GlobalSetOptions.spam_time = MIN_JOIN_LEAVE_TIME; @@ -341,10 +326,10 @@ initialize_global_set_options(void) GlobalSetOptions.ident_timeout = IDENT_TIMEOUT; - strlcpy(GlobalSetOptions.operstring, + rb_strlcpy(GlobalSetOptions.operstring, ConfigFileEntry.default_operstring, sizeof(GlobalSetOptions.operstring)); - strlcpy(GlobalSetOptions.adminstring, + rb_strlcpy(GlobalSetOptions.adminstring, ConfigFileEntry.default_adminstring, sizeof(GlobalSetOptions.adminstring)); @@ -383,7 +368,7 @@ write_pidfile(const char *filename) { unsigned int pid = (unsigned int) getpid(); - ircsnprintf(buff, sizeof(buff), "%u\n", pid); + rb_snprintf(buff, sizeof(buff), "%u\n", pid); if((fputs(buff, fb) == -1)) { ilog(L_MAIN, "Error writing %u to pid file %s (%s)", @@ -453,6 +438,85 @@ setup_corefile(void) #endif } +static void +ircd_log_cb(const char *str) +{ + ilog(L_MAIN, "libratbox reports: %s", str); +} + +static void +ircd_restart_cb(const char *str) +{ + inotice("libratbox has called the restart callback: %s", str); + restart(str); +} + +/* + * Why EXIT_FAILURE here? + * Because if ircd_die_cb() is called it's because of a fatal + * error inside libcharybdis, and we don't know how to handle the + * exception, so it is logical to return a FAILURE exit code here. + * --nenolod + */ +static void +ircd_die_cb(const char *str) +{ + if(str != NULL) + { + /* Try to get the message out to currently logged in operators. */ + sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "libratbox has called the die callback..aborting: %s", str); + inotice("libratbox has called the die callback..aborting: %s", str); + } + else + inotice("libratbox has called the die callback..aborting"); + + unlink(pidFileName); + exit(EXIT_FAILURE); +} + +struct ev_entry *check_splitmode_ev = NULL; + +static int +seed_with_urandom(void) +{ + unsigned int seed; + int fd; + + fd = open("/dev/urandom", O_RDONLY); + if(fd >= 0) + { + if(read(fd, &seed, sizeof(seed)) == sizeof(seed)) + { + close(fd); + srand(seed); + return 1; + } + } + return 0; +} + +static void +seed_with_clock(void) +{ + const struct timeval *tv; + rb_set_time(); + tv = rb_current_time_tv(); + srand(tv->tv_sec ^ (tv->tv_usec | (getpid() << 20))); +} + +static void +seed_random(void *unused) +{ + unsigned int seed; + if(rb_get_random(&seed, sizeof(seed)) == -1) + { + if(!seed_with_urandom()) + seed_with_clock(); + return; + } + srand(seed); +} + /* * main * @@ -474,18 +538,30 @@ main(int argc, char *argv[]) return -1; } - /* - * save server boot time right away, so getrusage works correctly - */ - set_time(); + init_sys(); + + ConfigFileEntry.dpath = DPATH; + ConfigFileEntry.configfile = CPATH; /* Server configuration file */ + ConfigFileEntry.connect_timeout = 30; /* Default to 30 */ + + umask(077); /* better safe than sorry --SRB */ + + myargv = argv; + parseargs(&argc, &argv, myopts); + + if(chdir(ConfigFileEntry.dpath)) + { + fprintf(stderr, "Unable to chdir to %s: %s\n", ConfigFileEntry.dpath, strerror(errno)); + exit(EXIT_FAILURE); + } + + rb_set_time(); + /* * Setup corefile size immediately after boot -kre */ setup_corefile(); - ServerRunning = 0; - /* It ain't random, but it ought to be a little harder to guess */ - srand(SystemTime.tv_sec ^ (SystemTime.tv_usec | (getpid() << 20))); memset(&me, 0, sizeof(me)); memset(&meLocalUser, 0, sizeof(meLocalUser)); me.localClient = &meLocalUser; @@ -498,44 +574,26 @@ main(int argc, char *argv[]) memset(&local_oper_list, 0, sizeof(local_oper_list)); memset(&oper_list, 0, sizeof(oper_list)); - dlinkAddTail(&me, &me.node, &global_client_list); + rb_dlinkAddTail(&me, &me.node, &global_client_list); - memset((void *) &Count, 0, sizeof(Count)); - memset((void *) &ServerInfo, 0, sizeof(ServerInfo)); - memset((void *) &AdminInfo, 0, sizeof(AdminInfo)); + memset(&Count, 0, sizeof(Count)); + memset(&ServerInfo, 0, sizeof(ServerInfo)); + memset(&AdminInfo, 0, sizeof(AdminInfo)); + memset(&ServerStats, 0, sizeof(struct ServerStatistics)); /* Initialise the channel capability usage counts... */ init_chcap_usage_counts(); - ConfigFileEntry.dpath = DPATH; - ConfigFileEntry.configfile = CPATH; /* Server configuration file */ - ConfigFileEntry.klinefile = KPATH; /* Server kline file */ - ConfigFileEntry.dlinefile = DLPATH; /* dline file */ - ConfigFileEntry.xlinefile = XPATH; - ConfigFileEntry.resvfile = RESVPATH; - ConfigFileEntry.connect_timeout = 30; /* Default to 30 */ - myargv = argv; - umask(077); /* better safe than sorry --SRB */ - - parseargs(&argc, &argv, myopts); - if(printVersion) { - printf("ircd: version %s\n", ircd_version); + printf("ircd: version %s(%s)\n", ircd_version, serno); + printf("ircd: %s\n", rb_lib_version()); exit(EXIT_SUCCESS); } - if(chdir(ConfigFileEntry.dpath)) - { - fprintf(stderr, "Unable to chdir to %s: %s\n", ConfigFileEntry.dpath, strerror(errno)); - exit(EXIT_FAILURE); - } - setup_signals(); -#ifdef __CYGWIN__ - server_state_foreground = 1; -#endif + setup_signals(); if (testing_conf) server_state_foreground = 1; @@ -558,20 +616,22 @@ main(int argc, char *argv[]) if(!server_state_foreground) make_daemon(); inotice("starting %s ...", ircd_version); + inotice("%s", rb_lib_version()); } /* Init the event subsystem */ - libcharybdis_init(ircd_log_cb, restart, ircd_die_cb); - init_sys(); + rb_lib_init(ircd_log_cb, ircd_restart_cb, ircd_die_cb, !server_state_foreground, maxconnections, DNODE_HEAP_SIZE, FD_HEAP_SIZE); + rb_linebuf_init(LINEBUF_HEAP_SIZE); - fdlist_init(); - if(!server_state_foreground) + if(ConfigFileEntry.use_egd && (ConfigFileEntry.egdpool_path != NULL)) { - comm_close_all(); - } + rb_init_prng(ConfigFileEntry.egdpool_path, RB_PRNG_EGD); + } else + rb_init_prng(NULL, RB_PRNG_DEFAULT); + + seed_random(NULL); init_main_logfile(); - init_patricia(); newconf_init(); init_s_conf(); init_s_newconf(); @@ -580,33 +640,39 @@ main(int argc, char *argv[]) init_host_hash(); clear_hash_parse(); init_client(); - initUser(); init_hook(); init_channels(); initclass(); initwhowas(); - init_stats(); init_reject(); init_cache(); init_monitor(); init_isupport(); + + construct_cflags_strings(); + load_all_modules(1); #ifndef STATIC_MODULES load_core_modules(1); #endif init_auth(); /* Initialise the auth code */ init_resolver(); /* Needs to be setup before the io loop */ + privilegeset_set_new("default", "", 0); if (testing_conf) fprintf(stderr, "\nBeginning config test\n"); read_conf_files(YES); /* cold start init conf files */ - rehash_bans(0); #ifndef STATIC_MODULES mod_add_path(MODULE_DIR); mod_add_path(MODULE_DIR "/autoload"); #endif + init_bandb(); + init_ssld(); + + rehash_bans(0); + initialize_server_capabs(); /* Set up default_server_capabs */ initialize_global_set_options(); @@ -615,7 +681,7 @@ main(int argc, char *argv[]) ierror("no server name specified in serverinfo block."); return -1; } - strlcpy(me.name, ServerInfo.name, sizeof(me.name)); + rb_strlcpy(me.name, ServerInfo.name, sizeof(me.name)); if(ServerInfo.sid[0] == '\0') { @@ -631,7 +697,19 @@ main(int argc, char *argv[]) ierror("no server description specified in serverinfo block."); return -3; } - strlcpy(me.info, ServerInfo.description, sizeof(me.info)); + rb_strlcpy(me.info, ServerInfo.description, sizeof(me.info)); + + if(ServerInfo.ssl_cert != NULL && ServerInfo.ssl_private_key != NULL) + { + /* just do the rb_setup_ssl_server to validate the config */ + if(!rb_setup_ssl_server(ServerInfo.ssl_cert, ServerInfo.ssl_private_key, ServerInfo.ssl_dh_params)) + { + ilog(L_MAIN, "WARNING: Unable to setup SSL."); + ssl_ok = 0; + } + else + ssl_ok = 1; + } if (testing_conf) { @@ -644,12 +722,12 @@ main(int argc, char *argv[]) me.servptr = &me; SetMe(&me); make_server(&me); - me.serv->up = me.name; - startup_time = CurrentTime; + startup_time = rb_current_time(); add_to_client_hash(me.name, &me); add_to_id_hash(me.id, &me); + me.serv->nameinfo = scache_connect(me.name, me.info, 0); - dlinkAddAlloc(&me, &global_serv_list); + rb_dlinkAddAlloc(&me, &global_serv_list); construct_umodebuf(); @@ -660,37 +738,22 @@ main(int argc, char *argv[]) ilog(L_MAIN, "Server Ready"); - eventAddIsh("cleanup_glines", cleanup_glines, NULL, CLEANUP_GLINES_TIME); - /* We want try_connections to be called as soon as possible now! -- adrian */ /* No, 'cause after a restart it would cause all sorts of nick collides */ /* um. by waiting even longer, that just means we have even *more* * nick collisions. what a stupid idea. set an event for the IO loop --fl */ - eventAddIsh("try_connections", try_connections, NULL, STARTUP_CONNECTIONS_TIME); - eventAddOnce("try_connections_startup", try_connections, NULL, 0); - - eventAddIsh("collect_zipstats", collect_zipstats, NULL, ZIPSTATS_TIME); - - /* Setup the timeout check. I'll shift it later :) -- adrian */ - eventAddIsh("comm_checktimeouts", comm_checktimeouts, NULL, 1); - - eventAdd("check_rehash", check_rehash, NULL, 1); - - if(ConfigServerHide.links_delay > 0) - eventAdd("cache_links", cache_links, NULL, - ConfigServerHide.links_delay); - else - ConfigServerHide.links_disabled = 1; + rb_event_addish("try_connections", try_connections, NULL, STARTUP_CONNECTIONS_TIME); + rb_event_addonce("try_connections_startup", try_connections, NULL, 2); + rb_event_add("check_rehash", check_rehash, NULL, 3); + rb_event_addish("reseed_srand", seed_random, NULL, 300); /* reseed every 10 minutes */ if(splitmode) - eventAdd("check_splitmode", check_splitmode, NULL, 2); - - ServerRunning = 1; + check_splitmode_ev = rb_event_add("check_splitmode", check_splitmode, NULL, 5); print_startup(getpid()); - charybdis_io_loop(); + rb_lib_loop(0); return 0; }