diff --git a/Changes b/Changes index 0183683a7..64008d0d9 100644 --- a/Changes +++ b/Changes @@ -2628,3 +2628,9 @@ seen. gmtime warning still there - Partial cleanup of m_part (hopefully I didn't destroy anything). - Minor stats compile warning fixed - Started some work on the remote include system +- Fixed a bug with set::who-limit sending multiple error notices, reported by doh +- Fixed a bug with the configure script reported by doh where Unreal would ignore the + manually specified directory for OpenSSL (and also Zlib) +- Made the ./configure --help display a bit cleaner +- Added include/types.h to hold any new datatypes we create +- A lot more work on the remote include system diff --git a/autoconf/aclocal.m4 b/autoconf/aclocal.m4 index 154774b8a..e5f8a780c 100644 --- a/autoconf/aclocal.m4 +++ b/autoconf/aclocal.m4 @@ -349,12 +349,10 @@ dnl the following 2 macros are based on CHECK_SSL by Mark Ethan Trostler &5 echo $ECHO_N "checking for openssl... $ECHO_C" >&6 - for dir in $withval /usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr; do + for dir in $enableval /usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr; do ssldir="$dir" if test -f "$dir/include/openssl/ssl.h"; then echo "$as_me:$LINENO: result: found in $ssldir/include/openssl" >&5 @@ -9554,7 +9556,7 @@ if test "${enable_ziplinks+set}" = set; then echo "$as_me:$LINENO: checking for zlib" >&5 echo $ECHO_N "checking for zlib... $ECHO_C" >&6 - for dir in $withval /usr/local /usr /usr/pkg; do + for dir in $enableval /usr/local /usr /usr/pkg; do zlibdir="$dir" if test -f "$dir/include/zlib.h"; then echo "$as_me:$LINENO: result: found in $zlibdir" >&5 diff --git a/include/modules.h b/include/modules.h index cfd5a803c..7867ffc40 100644 --- a/include/modules.h +++ b/include/modules.h @@ -20,13 +20,11 @@ */ #ifndef MODULES_H #define MODULES_H +#include "types.h" #define MOD_VERSION "3.2-b5-1" #define MOD_WE_SUPPORT "3.2-b5*" #define MAXCUSTOMHOOKS 30 #define MAXHOOKTYPES 70 -typedef void (*vFP)(); /* Void function pointer */ -typedef int (*iFP)(); /* Integer function pointer */ -typedef char (*cFP)(); /* char * function pointer */ #if defined(_WIN32) #define DLLFUNC _declspec(dllexport) #define irc_dlopen(x,y) LoadLibrary(x) diff --git a/include/struct.h b/include/struct.h index 5d825ba5f..f62da7e5e 100644 --- a/include/struct.h +++ b/include/struct.h @@ -634,6 +634,8 @@ struct aloopStruct { unsigned do_bancheck : 1; unsigned ircd_rehashing : 1; unsigned tainted : 1; + aClient *rehash_save_cptr, *rehash_save_sptr; + int rehash_save_sig; }; typedef struct Whowas { @@ -1178,12 +1180,17 @@ struct _configitem_alias_format { regex_t expr; }; -#define INCLUDE_NOTLOADED 1 +#define INCLUDE_NOTLOADED 0x1 +#define INCLUDE_REMOTE 0x2 +#define INCLUDE_DLQUEUED 0x4 struct _configitem_include { ConfigItem *prev, *next; ConfigFlag_ban flag; char *file; +#ifdef USE_LIBCURL + char *url; +#endif }; struct _configitem_help { diff --git a/include/types.h b/include/types.h new file mode 100644 index 000000000..6a9f3c011 --- /dev/null +++ b/include/types.h @@ -0,0 +1,27 @@ +/* + * Unreal Internet Relay Chat Daemon, src/url.c + * (C) 2003 The UnrealIRCd 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 + * the Free Software Foundation; either version 1, 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. + */ + +#ifndef TYPES_H +#define TYPES_H + +typedef void (*vFP)(); /* Void function pointer */ +typedef int (*iFP)(); /* Integer function pointer */ +typedef char (*cFP)(); /* char * function pointer */ + +#endif diff --git a/src/ircd.c b/src/ircd.c index f354e9a98..2d4811bab 100644 --- a/src/ircd.c +++ b/src/ircd.c @@ -855,6 +855,9 @@ int InitwIRCD(int argc, char *argv[]) bzero(&StatsZ, sizeof(StatsZ)); setup_signals(); init_ircstats(); +#ifdef USE_LIBCURL + url_init(); +#endif umode_init(); #ifdef EXTCMODE extcmode_init(); diff --git a/src/modules/m_who.c b/src/modules/m_who.c index 14fc7a85e..4cc54fa62 100644 --- a/src/modules/m_who.c +++ b/src/modules/m_who.c @@ -612,7 +612,7 @@ matchok: if (WHOLIMIT && !IsAnOper(sptr) && ++i > WHOLIMIT) { sendto_one(sptr, rpl_str(ERR_WHOLIMEXCEED), me.name, sptr->name, WHOLIMIT); - continue; + return; } channel = first_visible_channel(sptr, acptr, &flg); diff --git a/src/s_bsd.c b/src/s_bsd.c index 923c246eb..fe8e36f10 100644 --- a/src/s_bsd.c +++ b/src/s_bsd.c @@ -1649,7 +1649,9 @@ int read_message(time_t delay, fdlist *listp) #ifdef _WIN32 FD_ZERO(&excpt_set); #endif - +#ifdef USE_LIBCURL + url_do_transfers_async(); +#endif #ifdef NO_FDLIST for (i = LastSlot; i >= 0; i--) #else diff --git a/src/s_conf.c b/src/s_conf.c index 86d97208e..9e525d7d5 100644 --- a/src/s_conf.c +++ b/src/s_conf.c @@ -18,6 +18,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "struct.h" +#include "url.h" #include "common.h" #include "sys.h" #include "numeric.h" @@ -378,6 +379,14 @@ ConfigFile *conf = NULL; int config_error_flag = 0; int config_verbose = 0; +void add_include(char *); +#ifdef USE_LIBCURL +void add_remote_include(char *, char *); +#endif +void unload_notloaded_includes(void); +void load_includes(void); +void unload_loaded_includes(void); + /* Pick out the ip address and the port number from a string. * The string syntax is: ip:port. ip must be enclosed in brackets ([]) if its an ipv6 * address because they contain colon (:) separators. The ip part is optional. If the string @@ -1358,8 +1367,6 @@ aCommand *cmptr = find_Command_simple("PART"); int init_conf(char *rootconf, int rehash) { - ConfigItem_include *inc, *next; - config_status("Loading IRCd configuration .."); if (conf) { @@ -1381,15 +1388,7 @@ int init_conf(char *rootconf, int rehash) #ifndef STATIC_LINKING Unload_all_testing_modules(); #endif - for (inc = conf_include; inc; inc = next) - { - next = (ConfigItem_include *)inc->next; - if (inc->flag.type != INCLUDE_NOTLOADED) - continue; - ircfree(inc->file); - DelListItem(inc, conf_include); - MyFree(inc); - } + unload_notloaded_includes(); config_free(conf); conf = NULL; free_iConf(&tempiConf); @@ -1404,19 +1403,11 @@ int init_conf(char *rootconf, int rehash) #else RunHook0(HOOKTYPE_REHASH); #endif - for (inc = conf_include; inc; inc = next) - { - next = (ConfigItem_include *)inc->next; - if (inc->flag.type == INCLUDE_NOTLOADED) - continue; - ircfree(inc->file); - DelListItem(inc, conf_include); - MyFree(inc); - } - + unload_loaded_includes(); } #ifndef STATIC_LINKING Init_all_testing_modules(); + load_includes(); #else if (!rehash) { ModuleInfo ModCoreInfo; @@ -1426,11 +1417,6 @@ int init_conf(char *rootconf, int rehash) l_commands_Init(&ModCoreInfo); } #endif - for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next) - { - if (inc->flag.type == INCLUDE_NOTLOADED) - inc->flag.type = 0; - } if (config_run() < 0) { config_error("Bad case of config errors. Server will now die. This really shouldn't happen"); @@ -1444,15 +1430,6 @@ int init_conf(char *rootconf, int rehash) } else { - for (inc = conf_include; inc; inc = next) - { - next = (ConfigItem_include *)inc->next; - if (inc->flag.type != INCLUDE_NOTLOADED) - continue; - ircfree(inc->file); - DelListItem(inc, conf_include); - MyFree(inc); - } config_error("IRCd configuration failed to load"); config_free(conf); conf = NULL; @@ -1480,7 +1457,6 @@ int load_conf(char *filename) ConfigFile *cfptr, *cfptr2, **cfptr3; ConfigEntry *ce; int ret; - ConfigItem_include *includes; if (config_verbose > 0) config_status("Loading config file %s ..", filename); @@ -1509,19 +1485,6 @@ int load_conf(char *filename) if (ret < 0) return ret; } - if (stricmp(filename, CPATH)) { - for (includes = conf_include; includes; includes = (ConfigItem_include *)includes->next) { - if (includes->flag.type == INCLUDE_NOTLOADED && - !stricmp(includes->file, filename)) - break; - } - if (!includes) { - includes = MyMalloc(sizeof(ConfigItem_include)); - includes->file = strdup(filename); - includes->flag.type = INCLUDE_NOTLOADED; - AddListItem(includes, conf_include); - } - } return 1; } else @@ -2480,6 +2443,10 @@ int _conf_include(ConfigFile *conf, ConfigEntry *ce) ce->ce_varlinenum); return -1; } +#ifdef USE_LIBCURL + if (url_is_valid(ce->ce_vardata)) + return remote_include(ce); +#endif #if !defined(_WIN32) && !defined(_AMIGA) && DEFAULT_PERMISSIONS != 0 chmod(ce->ce_vardata, DEFAULT_PERMISSIONS); #endif @@ -2503,6 +2470,7 @@ int _conf_include(ConfigFile *conf, ConfigEntry *ce) globfree(&files); return ret; } + add_include(files.gl_pathv[i]); } globfree(&files); #elif defined(_WIN32) @@ -2526,15 +2494,23 @@ int _conf_include(ConfigFile *conf, ConfigEntry *ce) strcpy(path,cPath); strcat(path,FindData.cFileName); ret = load_conf(path); + if (ret >= 0) + add_include(path); free(path); + } else + { ret = load_conf(FindData.cFileName); + if (ret >= 0) + add_include(FindData.cFileName); + } if (ret < 0) { FindClose(hFind); return ret; } + ret = 0; while (FindNextFile(hFind, &FindData) != 0) { if (cPath) { @@ -2542,18 +2518,32 @@ int _conf_include(ConfigFile *conf, ConfigEntry *ce) strcpy(path,cPath); strcat(path,FindData.cFileName); ret = load_conf(path); - free(path); - if (ret < 0) + if (ret >= 0) + { + add_include(path); + free(path); + } + else + { + free(path); break; + } } else + { ret = load_conf(FindData.cFileName); + if (ret >= 0) + add_include(FindData.cFileName); + } } FindClose(hFind); if (ret < 0) return ret; #else - return (load_conf(ce->ce_vardata)); + ret = load_conf(ce->ce_vardata); + if (ret >= 0) + add_include(ce->ce_vardata); + return ret; #endif return 1; } @@ -6937,10 +6927,88 @@ int _test_deny(ConfigFile *conf, ConfigEntry *ce) return errors; } +#ifdef USE_LIBCURL +static void conf_download_complete(char *url, char *file, char *errorbuf, int cached) +{ + ConfigItem_include *inc; + if (!loop.ircd_rehashing) + { + remove(file); + return; + } + if (!file && !cached) + { + config_error("Error downloading %s: %s", url, errorbuf); + loop.ircd_rehashing = 0; + unload_notloaded_includes(); + return; + } + for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next) + { + if (!(inc->flag.type & INCLUDE_REMOTE)) + continue; + if (inc->flag.type & INCLUDE_NOTLOADED) + continue; + if (!stricmp(url, inc->url)) + { + inc->flag.type &= ~INCLUDE_DLQUEUED; + break; + } + } + if (cached) + { + char *urlfile = url_getfilename(url); + char *tmp = unreal_mktemp("tmp", urlfile); + free(urlfile); + unreal_copyfile(inc->file, tmp); + add_remote_include(tmp, url); + } + else + add_remote_include(file, url); + for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next) + { + if (inc->flag.type & INCLUDE_DLQUEUED) + return; + } + rehash_internal(loop.rehash_save_cptr, loop.rehash_save_sptr, loop.rehash_save_sig); +} +#endif int rehash(aClient *cptr, aClient *sptr, int sig) { +#ifdef USE_LIBCURL + ConfigItem_include *inc; + if (loop.ircd_rehashing) + { + if (!sig) + sendto_one(sptr, ":%s NOTICE %s :A rehash is already in progress", + me.name, sptr->name); + return 0; + } + loop.ircd_rehashing = 1; + loop.rehash_save_cptr = cptr; + loop.rehash_save_sptr = sptr; + loop.rehash_save_sig = sig; + for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next) + { + struct stat sb; + if (!(inc->flag.type & INCLUDE_REMOTE)) + continue; + if (inc->flag.type & INCLUDE_NOTLOADED) + continue; + stat(inc->file, &sb); + download_file_async(inc->url, sb.st_ctime, conf_download_complete); + inc->flag.type |= INCLUDE_DLQUEUED; + } + return 0; +#else + return rehash_internal(cptr, sptr, sig); +#endif +} + +int rehash_internal(aClient *cptr, aClient *sptr, int sig) +{ flush_connections(&me); if (sig == 1) { @@ -6995,3 +7063,153 @@ void listen_cleanup() if (i) close_listeners(); } + +#ifdef USE_LIBCURL +char *find_remote_include(char *url) +{ + ConfigItem_include *inc; + for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next) + { + if (!(inc->flag.type & INCLUDE_NOTLOADED)) + continue; + if (!(inc->flag.type & INCLUDE_REMOTE)) + continue; + if (!stricmp(url, inc->url)) + return inc->file; + } + return NULL; +} + +int remote_include(ConfigEntry *ce) +{ + char *file = find_remote_include(ce->ce_vardata); + int ret; + if (!loop.ircd_rehashing || (loop.ircd_rehashing && !file)) + { + char *error; + if (config_verbose > 0) + config_status("Downloading %s", ce->ce_vardata); + file = download_file(ce->ce_vardata, &error); + if (!file) + { + config_error("%s:%i: include: error downloading '%s': %s", + ce->ce_fileptr->cf_filename, ce->ce_varlinenum, + ce->ce_vardata, error); + return -1; + } + else + { + if ((ret = load_conf(file)) >= 0) + add_remote_include(file, ce->ce_vardata); + free(file); + return ret; + } + } + else + { + if (config_verbose > 0) + config_status("Loading %s from download", ce->ce_vardata); + if ((ret = load_conf(file)) >= 0) + add_remote_include(file, ce->ce_vardata); + return ret; + } + return 0; +} +#endif + +void add_include(char *file) +{ + ConfigItem_include *inc; + if (!stricmp(file, CPATH)) + return; + + for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next) + { + if (!(inc->flag.type & INCLUDE_NOTLOADED)) + continue; + if (!stricmp(file, inc->file)) + return; + } + inc = MyMallocEx(sizeof(ConfigItem_include)); + inc->file = strdup(file); + inc->flag.type = INCLUDE_NOTLOADED; + AddListItem(inc, conf_include); +} + +#ifdef USE_LIBCURL +void add_remote_include(char *file, char *url) +{ + ConfigItem_include *inc; + + for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next) + { + if (!(inc->flag.type & INCLUDE_REMOTE)) + continue; + if (!(inc->flag.type & INCLUDE_NOTLOADED)) + continue; + if (!stricmp(url, inc->url)) + return; + } + inc = MyMallocEx(sizeof(ConfigItem_include)); + inc->file = strdup(file); + inc->url = strdup(url); + inc->flag.type = (INCLUDE_NOTLOADED|INCLUDE_REMOTE); + AddListItem(inc, conf_include); +} +#endif + +void unload_notloaded_includes(void) +{ + ConfigItem_include *inc, *next; + + for (inc = conf_include; inc; inc = next) + { + next = (ConfigItem_include *)inc->next; + if (inc->flag.type & INCLUDE_NOTLOADED) + { +#ifdef USE_LIBCURL + if (inc->flag.type & INCLUDE_REMOTE) + { + remove(inc->file); + free(inc->url); + } +#endif + free(inc->file); + DelListItem(inc, conf_include); + free(inc); + } + } +} + +void unload_loaded_includes(void) +{ + ConfigItem_include *inc, *next; + + for (inc = conf_include; inc; inc = next) + { + next = (ConfigItem_include *)inc->next; + if (inc->flag.type & INCLUDE_NOTLOADED) + continue; +#ifdef USE_LIBCURL + if (inc->flag.type & INCLUDE_REMOTE) + { + remove(inc->file); + free(inc->url); + } +#endif + free(inc->file); + DelListItem(inc, conf_include); + free(inc); + } +} + +void load_includes(void) +{ + ConfigItem_include *inc; + + /* Doing this for all the modules should actually be faster + * than only doing it for modules that are not-loaded + */ + for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next) + inc->flag.type &= ~INCLUDE_NOTLOADED; +} diff --git a/src/s_serv.c b/src/s_serv.c index de2bfb894..6ff8d34b3 100644 --- a/src/s_serv.c +++ b/src/s_serv.c @@ -2915,6 +2915,12 @@ CMD_FUNC(m_rehash) #endif if (parv[2] == NULL) { + if (loop.ircd_rehashing) + { + sendto_one(sptr, ":%s NOTICE %s :A rehash is already in progress", + me.name, sptr->name); + return 0; + } sendto_serv_butone(&me, ":%s GLOBOPS :%s is remotely rehashing server config file", me.name, sptr->name); @@ -2999,7 +3005,15 @@ CMD_FUNC(m_rehash) } } else + { + if (loop.ircd_rehashing) + { + sendto_one(sptr, ":%s NOTICE %s :A rehash is already in progress", + me.name, sptr->name); + return 0; + } sendto_ops("%s is rehashing server config file", parv[0]); + } /* Normal rehash, rehash motds&rules too, just like the on in the tld block will :p */ reread_motdsandrules(); diff --git a/src/support.c b/src/support.c index b4b7712d1..cd477a868 100644 --- a/src/support.c +++ b/src/support.c @@ -1750,7 +1750,7 @@ int unreal_copyfile(char *src, char *dest) if (srcfd < 0) return 0; - destfd = open(dest, O_WRONLY|O_CREAT, S_IRUSR|S_IXUSR); + destfd = open(dest, O_WRONLY|O_CREAT, DEFAULT_PERMISSIONS); if (destfd < 0) { diff --git a/src/url.c b/src/url.c index a849dc028..3064612cd 100644 --- a/src/url.c +++ b/src/url.c @@ -108,7 +108,8 @@ static size_t do_download(void *ptr, size_t size, size_t nmemb, void *stream) * knowledge of how libcurl works. If the function succeeds, the * filename the file was downloaded to is returned. Otherwise NULL * is returned and the string pointed to by error contains the error - * message. + * message. The returned filename is malloc'ed and must be freed by + * the caller. */ char *download_file(char *url, char **error) { @@ -116,7 +117,8 @@ char *download_file(char *url, char **error) CURL *curl = curl_easy_init(); CURLcode res; char *file = url_getfilename(url); - char *tmp = unreal_mktemp("tmp", file ? file : "download.conf"); + char *filename = unreal_getfilename(file); + char *tmp = unreal_mktemp("tmp", filename ? filename : "download.conf"); if (curl) { FILE *fd = fopen(tmp, "wb"); @@ -133,7 +135,7 @@ char *download_file(char *url, char **error) free(file); curl_easy_cleanup(curl); if (res == CURLE_OK) - return tmp; + return strdup(tmp); else { remove(tmp); @@ -145,8 +147,9 @@ char *download_file(char *url, char **error) /* * Initializes the URL system */ -void url_init() +void url_init(void) { + curl_global_init(CURL_GLOBAL_ALL); multihandle = curl_multi_init(); } @@ -157,17 +160,21 @@ void url_init() * called when the download completes, or the download fails. The * callback function is defined as: * - * void callback(char *filename, char *errorbuf); + * void callback(char *url, char *filename, char *errorbuf, int cached); + * url will contain the URL that was downloaded * filename will contain the name of the file (if successful, NULL otherwise) * errorbuf will contain the error message (if failed, NULL otherwise) + * cached 1 if the specified cachetime is >= the current file on the server, + * if so, both filename and errorbuf will be NULL */ -void download_file_async(char *url, vFP callback) +void download_file_async(char *url, time_t cachetime, vFP callback) { CURL *curl = curl_easy_init(); if (curl) { char *file = url_getfilename(url); - char *tmp = unreal_mktemp("tmp", file ? file : "download.conf"); + char *filename = unreal_getfilename(file); + char *tmp = unreal_mktemp("tmp", filename ? filename : "download.conf"); FileHandle *handle = malloc(sizeof(FileHandle)); if (file) free(file); @@ -181,6 +188,12 @@ void download_file_async(char *url, vFP callback) bzero(handle->errorbuf, CURL_ERROR_SIZE); curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, handle->errorbuf); curl_easy_setopt(curl, CURLOPT_PRIVATE, (char *)handle); + if (cachetime) + { + curl_easy_setopt(curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFMODSINCE); + curl_easy_setopt(curl, CURLOPT_TIMEVALUE, cachetime); + } + curl_multi_add_handle(multihandle, curl); } } @@ -189,7 +202,7 @@ void download_file_async(char *url, vFP callback) * Called in the select loop. Handles the transferring of any * queued asynchronous transfers. */ -void url_do_transfers_async() +void url_do_transfers_async(void) { int cont; int msgs_left; @@ -228,13 +241,25 @@ void url_do_transfers_async() if (msg->msg == CURLMSG_DONE) { FileHandle *handle; + char *url; + long code; + curl_easy_getinfo(msg->easy_handle, CURLINFO_RESPONSE_CODE, &code); curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, (char*)&handle); - fclose(handle->fd); + curl_easy_getinfo(msg->easy_handle, CURLINFO_EFFECTIVE_URL, &url); + fclose(handle->fd); if (msg->data.result == CURLE_OK) - handle->callback(handle->filename, NULL); + { + if (code == 304) + { + handle->callback(url, NULL, NULL, 1); + remove(handle->filename); + } + else + handle->callback(url, handle->filename, NULL, 0); + } else { - handle->callback(NULL, handle->errorbuf); + handle->callback(url, NULL, handle->errorbuf, 0); remove(handle->filename); } free(handle);