From dd339ee3f84171935b3d0b10a5fade3d73503d7c Mon Sep 17 00:00:00 2001 From: Bleep Date: Fri, 15 Sep 2000 07:27:09 +0000 Subject: [PATCH] Author: Bleep Log message: More general mayhem in confland. Convert listeners, t lines, admin stuff. General cleanups, test the whole mess. Moved hostent validation to res.c and rewrite using a regex. Note: The validation rules are somewhat restrictive, I didn't modify the rules. Specifically it disallows underscores in the hostname. We may want to consider relaxing this rule, most people do. Perhaps we should put this in a config file? git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@288 c9e4aea6-c8fd-4c43-8297-357d70d61c8c --- ChangeLog | 11 +- doc/example.conf | 17 +- include/ircd_reply.h | 5 +- include/s_conf.h | 17 +- ircd/ircd_reply.c | 16 +- ircd/m_admin.c | 10 +- ircd/m_stats.c | 8 +- ircd/res.c | 65 +++-- ircd/s_conf.c | 579 +++++++++++++++++++++---------------------- ircd/s_stats.c | 12 +- 10 files changed, 390 insertions(+), 350 deletions(-) diff --git a/ChangeLog b/ChangeLog index 19d4f03..60e7861 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2000-09-15 Thomas Helvey + * ircd/s_conf.c: start adding code for new conf data structs, changed + listeners, admin line, motd lines, class lines. Move validate_hostent + to resolver. General mayhem. + * include/s_conf.h: new data structs and accessors + * ircd/res.c: move validate_hostent here, rewrite, use regular + expression for validation. + * doc/example.conf: update docs for port + 2000-09-14 Thomas Helvey * ircd/s_conf.c (conf_init): rewrite conf file parser, start to break up conf_init into managable chunks. @@ -1308,7 +1317,7 @@ # # ChangeLog for ircu2.10.11 # -# $Id: ChangeLog,v 1.161 2000-09-14 06:53:37 bleep Exp $ +# $Id: ChangeLog,v 1.162 2000-09-15 07:27:08 bleep Exp $ # # Insert new changes at beginning of the change list. # diff --git a/doc/example.conf b/doc/example.conf index f867212..7c1be76 100644 --- a/doc/example.conf +++ b/doc/example.conf @@ -179,11 +179,13 @@ I:*@193.37.*::*@*.london.ac.uk::10 # I:Resolved:1:*@*.swipnet.se::1 # I:Resolved:2:*@dial??.*::1 +# +# T:Lines # # It is possible to show a different Message of the Day to a connecting # client depending on its origin. # T:: - +# # DPATH/net_com.motd contains a special MOTD where users are encouraged # to register their domains and get their own I: lines if they're in # Europe, or move to US.UnderNet.org if they're in the USA. @@ -336,6 +338,15 @@ O:*@*.cs.vu.nl:VRKLKuGKn0jLs:Niels::10 # IANA says we should use port 194, but that requires us to run as root, so # we don't do that. # +# P:::<[CS][H]>: +# +# The hostmask setting allows you to specify a range of IP addresses that +# you will allow connections from. This should only contain IP addresses +# and '*' if used. This field only uses IP addresses. This does not use +# DNS in any way so you can't use it to allow *.nl or *.uk. Attempting +# to specify anything other than numbers, dots and stars [0-9.*] will result +# in the port allowing connections from anyone. +# # The interface setting allows multiply homed hosts to specify which # interface to use on a port by port basis, if an interface is not specified # the default interface will be used. The interface MUST be the complete @@ -349,7 +360,7 @@ O:*@*.cs.vu.nl:VRKLKuGKn0jLs:Niels::10 # If you want to hide a port from /stats p from non-opers follow the C # or S with an H # -# P:::<[CS][H]>: +# P:::<[CS][H]>: # # This is a normal server port, you need to have at least one server # port defined if you want to connect your server to other servers. @@ -360,7 +371,7 @@ P:::S:4400 # The following are normal client ports P:::C:6667 P::::6668 -P:*.nl:::6666 +P:192.168.*:::6666 # This is a hidden client port, listening on the interface associated # with the IP address 168.8.21.107 diff --git a/include/ircd_reply.h b/include/ircd_reply.h index a99ac3e..91d48fb 100644 --- a/include/ircd_reply.h +++ b/include/ircd_reply.h @@ -23,12 +23,11 @@ #define INCLUDED_ircd_reply_h struct Client; -struct ConfItem; extern int need_more_params(struct Client* cptr, const char* cmd); extern int send_error_to_client(struct Client* cptr, int error, ...); -extern int send_reply(struct Client *to, int reply, ...); -extern int send_admin_info(struct Client* sptr, const struct ConfItem* data); +extern int send_reply(struct Client* to, int reply, ...); +extern int send_admin_info(struct Client* to); #define SND_EXPLICIT 0x40000000 /* first arg is a pattern to use */ diff --git a/include/s_conf.h b/include/s_conf.h index 5059efd..b969f4d 100644 --- a/include/s_conf.h +++ b/include/s_conf.h @@ -85,9 +85,9 @@ struct LocalConf { char* vhost_address; char* description; char* numeric_id; - char* admin_line1; - char* admin_line2; - char* admin_line3; + char* location1; + char* location2; + char* contact; }; struct MotdItem { @@ -95,6 +95,12 @@ struct MotdItem { struct MotdItem *next; }; +struct MotdConf { + char* hostmask; + char* path; + struct MotdConf* next; +}; + struct TRecord { char *hostmask; struct MotdItem *tmotd; @@ -124,6 +130,10 @@ extern struct TRecord* tdata; /* * Proto types */ + +extern const struct LocalConf* conf_get_local(void); +extern const struct MotdConf* conf_get_motd_list(void); + extern struct ConfItem* attach_confs_byhost(struct Client* cptr, const char* host, int statmask); extern struct ConfItem* find_conf_byhost(struct SLink* lp, const char* host, @@ -136,7 +146,6 @@ const char* conf_eval_crule(struct ConfItem* conf); extern void det_confs_butmask(struct Client *cptr, int mask); extern int detach_conf(struct Client *cptr, struct ConfItem *aconf); extern enum AuthorizationCheckResult attach_conf(struct Client *cptr, struct ConfItem *aconf); -extern struct ConfItem* find_admin(void); extern struct ConfItem* find_me(void); extern struct ConfItem* find_conf_exact(const char* name, const char* user, diff --git a/ircd/ircd_reply.c b/ircd/ircd_reply.c index 9020eaa..742923d 100644 --- a/ircd/ircd_reply.c +++ b/ircd/ircd_reply.c @@ -125,17 +125,15 @@ int send_reply(struct Client *to, int reply, ...) return 0; /* convenience return */ } -int send_admin_info(struct Client* sptr, const struct ConfItem* admin) +int send_admin_info(struct Client* sptr) { + const struct LocalConf* admin = conf_get_local(); assert(0 != sptr); - if (admin) { - send_reply(sptr, RPL_ADMINME, me.name); - send_reply(sptr, RPL_ADMINLOC1, admin->host); - send_reply(sptr, RPL_ADMINLOC2, admin->passwd); - send_reply(sptr, RPL_ADMINEMAIL, admin->name); - } - else - send_reply(sptr, ERR_NOADMININFO, me.name); + + send_reply(sptr, RPL_ADMINME, me.name); + send_reply(sptr, RPL_ADMINLOC1, admin->location1); + send_reply(sptr, RPL_ADMINLOC2, admin->location2); + send_reply(sptr, RPL_ADMINEMAIL, admin->contact); return 0; } diff --git a/ircd/m_admin.c b/ircd/m_admin.c index adde000..eb57816 100644 --- a/ircd/m_admin.c +++ b/ircd/m_admin.c @@ -114,11 +114,10 @@ int m_admin(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) return send_reply(sptr, ERR_NOSUCHSERVER, parv[1]); parv[1] = acptr->name; - if (hunt_server_cmd(sptr, CMD_ADMIN, cptr, 0, ":%C", 1, parc, parv) != - HUNTED_ISME) + if (hunt_server_cmd(sptr, CMD_ADMIN, cptr, 0, ":%C", 1, parc, parv) != HUNTED_ISME) return 0; } - return send_admin_info(sptr, find_admin()); + return send_admin_info(sptr); } /* @@ -135,10 +134,9 @@ int ms_admin(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) if (parc < 2) return 0; - if (hunt_server_cmd(sptr, CMD_ADMIN, cptr, 0, ":%C", 1, parc, parv) != - HUNTED_ISME) + if (hunt_server_cmd(sptr, CMD_ADMIN, cptr, 0, ":%C", 1, parc, parv) != HUNTED_ISME) return 0; - return send_admin_info(sptr, find_admin()); + return send_admin_info(sptr); } diff --git a/ircd/m_stats.c b/ircd/m_stats.c index 6282c09..54a7406 100644 --- a/ircd/m_stats.c +++ b/ircd/m_stats.c @@ -367,7 +367,7 @@ int m_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) tstats(sptr, parv[0]); break; case 'T': - report_configured_links(sptr, CONF_TLINES); + report_motd_list(sptr); break; case 'U': report_configured_links(sptr, CONF_UWORLD); @@ -673,7 +673,7 @@ int ms_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) tstats(sptr, parv[0]); break; case 'T': - report_configured_links(sptr, CONF_TLINES); + report_motd_list(sptr); break; case 'U': report_configured_links(sptr, CONF_UWORLD); @@ -967,7 +967,7 @@ int mo_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) tstats(sptr, parv[0]); break; case 'T': - report_configured_links(sptr, CONF_TLINES); + report_motd_list(sptr); break; case 'U': report_configured_links(sptr, CONF_UWORLD); @@ -1355,7 +1355,7 @@ int m_stats(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) tstats(sptr, parv[0]); break; case 'T': - report_configured_links(sptr, CONF_TLINES); + report_motd_list(sptr); break; case 'U': report_configured_links(sptr, CONF_UWORLD); diff --git a/ircd/res.c b/ircd/res.c index ba447e2..4426b88 100644 --- a/ircd/res.c +++ b/ircd/res.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -157,10 +158,10 @@ * Nov. 17, 1997 --Bleep */ -typedef struct Hostent { +struct Hostent { struct hostent h; /* the hostent struct we are passing around */ char* buf; /* buffer for data pointed to from hostent */ -} aHostent; +}; struct ResRequest { struct ResRequest* next; @@ -176,7 +177,7 @@ struct ResRequest { struct in_addr addr; char* name; struct DNSQuery query; /* query callback for this request */ - aHostent he; + struct Hostent he; }; struct CacheEntry { @@ -237,7 +238,7 @@ static struct CacheEntry* find_cache_number(struct ResRequest* request, const char* addr); static struct ResRequest* find_id(int); -static struct cacheinfo { +static struct cacheinfo { int ca_adds; int ca_dels; int ca_expires; @@ -260,6 +261,16 @@ static struct resinfo { int re_unkrep; } reinfo; +/* + * Disallow a hostname label to contain anything but a [-a-zA-Z0-9]. + * It may not start or end on a '.'. + * A label may not end on a '-', the maximum length of a label is + * 63 characters. + * On top of that (which seems to be the RFC) we demand that the + * top domain does not contain any digits. + */ +static const char* hostExpr = "([-0-9A-Za-z]*[0-9A-Za-z]\\.)+[A-Za-z]+"; +static regex_t hostRegex; /* * From bind 8.3, these aren't declared in earlier versions of bind @@ -277,7 +288,7 @@ extern u_int _getlong(const u_char *); * paul vixie, 29may94 */ static int -res_ourserver(const struct __res_state* statp, const struct sockaddr_in *inp) +res_ourserver(const struct __res_state* statp, const struct sockaddr_in* inp) { struct sockaddr_in ina; int ns; @@ -353,9 +364,14 @@ int init_resolver(void) memset(hashtable, 0, sizeof(hashtable)); memset(&reinfo, 0, sizeof(reinfo)); - requestListHead = requestListTail = NULL; + requestListHead = requestListTail = 0; errno = h_errno = 0; + + if (regcomp(&hostRegex, hostExpr, REG_EXTENDED | REG_NOSUB)) { + ircd_log(L_CRIT, "Resolver: error compiling host expression %s", hostExpr); + exit(2); + } start_resolver(); Debug((DEBUG_DNS, "Resolver: fd %d errno: %d h_errno: %d: %s", ResolverFileDescriptor, errno, h_errno, @@ -372,6 +388,18 @@ void restart_resolver(void) start_resolver(); } +static int validate_hostent(const struct hostent* hp) +{ + const char* name; + int i = 0; + assert(0 != hp); + for (name = hp->h_name; name; name = hp->h_aliases[i++]) { + if (HOSTLEN < strlen(name) || 0 != regexec(&hostRegex, name, 0, 0, 0)) + return 0; + } + return 1; +} + /* * add_request - place a new request in the request list */ @@ -995,8 +1023,7 @@ int resolver_read(void) * check against possibly fake replies */ if (!res_ourserver(&_res, &sin)) { - Debug((DEBUG_DNS, "Resolver: fake reply from: %s", - (const char*) &sin.sin_addr)); + Debug((DEBUG_DNS, "Resolver: fake reply from: %s", (const char*) &sin.sin_addr)); ++reinfo.re_unkrep; return 1; } @@ -1049,7 +1076,7 @@ int resolver_read(void) answer_count = proc_answer(request, header, buf, buf + rc); if (answer_count) { if (T_PTR == request->type) { - struct DNSReply* reply = NULL; + struct DNSReply* reply = 0; if (0 == request->he.h.h_name) { /* * got a PTR response with no name, something bogus is happening @@ -1068,7 +1095,10 @@ int resolver_read(void) * extra kludges. */ reply = gethost_byname(request->he.h.h_name, &request->query); - if (0 == reply) { + if (reply) { + (*request->query.callback)(request->query.vptr, reply); + } + else { /* * If name wasn't found, a request has been queued and it will * be the last one queued. This is rather nasty way to keep @@ -1079,8 +1109,6 @@ int resolver_read(void) request->he.buf = 0; memcpy(&requestListTail->he.h, &request->he.h, sizeof(struct hostent)); } - else - (*request->query.callback)(request->query.vptr, reply); rem_request(request); } else { @@ -1091,9 +1119,12 @@ int resolver_read(void) * PTR returned a CNAME, cp was not checked before so the * callback was being called with a value of 0x2C != NULL. */ - cp = make_cache(request); - (*request->query.callback)(request->query.vptr, - (cp) ? &cp->reply : 0); + struct DNSReply* reply = 0; + if (validate_hostent(&request->he.h)) { + if ((cp = make_cache(request))) + reply = &cp->reply; + } + (*request->query.callback)(request->query.vptr, reply); rem_request(request); } } @@ -1152,7 +1183,7 @@ static size_t calc_hostent_buffer_size(const struct hostent* hp) * dup_hostent - Duplicate a hostent struct, allocate only enough memory for * the data we're putting in it. */ -static void dup_hostent(aHostent* new_hp, struct hostent* hp) +static void dup_hostent(struct Hostent* new_hp, struct hostent* hp) { char* p; char** ap; @@ -1217,7 +1248,7 @@ static void dup_hostent(aHostent* new_hp, struct hostent* hp) /* * update_hostent - Add records to a Hostent struct in place. */ -static void update_hostent(aHostent* hp, char** addr, char** alias) +static void update_hostent(struct Hostent* hp, char** addr, char** alias) { char* p; char** ap; diff --git a/ircd/s_conf.c b/ircd/s_conf.c index 024997d..8be6bbd 100644 --- a/ircd/s_conf.c +++ b/ircd/s_conf.c @@ -74,6 +74,8 @@ struct MotdItem* rmotd = NULL; struct TRecord* tdata = NULL; struct tm motd_tm; +static struct LocalConf localConf; +static struct MotdConf* motdConfList; /* * output the reason for being k lined from a file - Mmmm @@ -286,53 +288,6 @@ const char* conf_eval_crule(struct ConfItem* conf) return 0; } - -/* - * field breakup for ircd.conf file. - */ -static char* getfield(char* newline, char fs) -{ - static char* gfline = NULL; - char* end; - char* field; - - if (newline) - gfline = newline; - - if (gfline == NULL) - return NULL; - - end = field = gfline; - - if (fs != ':') { - if (*end == fs) - ++end; - else - fs = ':'; - } - do { - while (*end != fs) { - if (!*end) { - end = NULL; - break; - } - ++end; - } - } while (end && fs != ':' && *++end != ':' && *end != '\n') ; - - if (end == NULL) { - gfline = NULL; - if ((end = strchr(field, '\n')) == NULL) - end = field + strlen(field); - } - else - gfline = end + 1; - - *end = '\0'; - - return field; -} - /* * Remove all conf entries from the client except those which match * the status field mask. @@ -348,69 +303,6 @@ void det_confs_butmask(struct Client *cptr, int mask) } } -/* - * validate_hostent - make sure hostnames are valid in a hostent struct - * XXX - this is terrible, what's worse is it used to be in the inner - * loop of scanning all the I:lines --Bleep - */ -static int validate_hostent(struct hostent* hp) -{ - char fullname[HOSTLEN + 1]; - int i = 0; - int error = 0; - const char* hname; - - for (hname = hp->h_name; hname; hname = hp->h_aliases[i++]) { - unsigned int fullnamelen = 0; - unsigned int label_count = 0; - - ircd_strncpy(fullname, hname, HOSTLEN); - fullname[HOSTLEN] = '\0'; - /* - * Disallow a hostname label to contain anything but a [-a-zA-Z0-9]. - * It may not start or end on a '.'. - * A label may not end on a '-', the maximum length of a label is - * 63 characters. - * On top of that (which seems to be the RFC) we demand that the - * top domain does not contain any digits. - */ - error = (*hname == '.') ? 1 : 0; /* May not start with a '.' */ - if (!error) { - char *p; - for (p = fullname; *p; ++p, ++fullnamelen) { - if (*p == '.') { - /* Label may not end on '-' and May not end on a '.' */ - if (p[-1] == '-' || p[1] == 0) { - error = 1; - break; - } - label_count = 0; - error = 0; /* Was not top domain */ - continue; - } - if (++label_count > 63) { - /* Label not longer then 63 */ - error = 1; - break; - } - if (*p >= '0' && *p <= '9') { - /* In case this is top domain */ - error = 1; - continue; - } - if (!(*p >= 'a' && *p <= 'z') - && !(*p >= 'A' && *p <= 'Z') && *p != '-') { - error = 1; - break; - } - } - } - if (error) - break; - } - return (0 == error); -} - /* * check_limit_and_attach - check client limits and attach I:line * @@ -448,11 +340,11 @@ enum AuthorizationCheckResult attach_iline(struct Client* cptr) static char fullname[HOSTLEN + 1]; struct hostent* hp = 0; - if (cptr->dns_reply) { + assert(0 != cptr); + + if (cptr->dns_reply) hp = cptr->dns_reply->hp; - if (!validate_hostent(hp)) - hp = 0; - } + for (aconf = GlobalConfList; aconf; aconf = aconf->next) { if (aconf->status != CONF_CLIENT) continue; @@ -573,15 +465,9 @@ enum AuthorizationCheckResult attach_conf(struct Client *cptr, struct ConfItem * return ACR_OK; } -struct ConfItem *find_admin(void) +const struct LocalConf* conf_get_local(void) { - struct ConfItem *aconf; - - for (aconf = GlobalConfList; aconf; aconf = aconf->next) { - if (aconf->status & CONF_ADMIN) - break; - } - return aconf; + return &localConf; } struct ConfItem* find_me(void) @@ -793,154 +679,105 @@ static struct ConfItem *find_conf_entry(struct ConfItem *aconf, return bconf; } + /* - * rehash - * - * Actual REHASH service routine. Called with sig == 0 if it has been called - * as a result of an operator issuing this command, else assume it has been - * called as a result of the server receiving a HUP signal. + * If conf line is a class definition, create a class entry + * for it and make the conf_line illegal and delete it. */ -int rehash(struct Client *cptr, int sig) +void conf_add_class(const char* const* fields, int count) { - struct ConfItem** tmp = &GlobalConfList; - struct ConfItem* tmp2; - struct ConfClass* cltmp; - struct Client* acptr; - struct MotdItem* temp; - int i; - int ret = 0; - int found_g = 0; - - if (1 == sig) - sendto_opmask_butone(0, SNO_OLDSNO, - "Got signal SIGHUP, reloading ircd conf. file"); + if (count < 6) + return; + add_class(atoi(fields[1]), atoi(fields[2]), atoi(fields[3]), + atoi(fields[4]), atoi(fields[5])); +} - while ((tmp2 = *tmp)) { - if (tmp2->clients) { - /* - * Configuration entry is still in use by some - * local clients, cannot delete it--mark it so - * that it will be deleted when the last client - * exits... - */ - if (!(tmp2->status & CONF_CLIENT)) { - *tmp = tmp2->next; - tmp2->next = 0; - } - else - tmp = &tmp2->next; - tmp2->status |= CONF_ILLEGAL; - } - else { - *tmp = tmp2->next; - /* free expression trees of connect rules */ - if ((tmp2->status & (CONF_CRULEALL | CONF_CRULEAUTO)) && - (tmp2->passwd != NULL)) - crule_free(&(tmp2->passwd)); - free_conf(tmp2); - } - } +void conf_add_listener(const char* const* fields, int count) +{ + int is_server = 0; + int is_hidden = 0; /* - * We don't delete the class table, rather mark all entries - * for deletion. The table is cleaned up by check_class(). - avalon + * need a port */ - for (cltmp = NextClass(FirstClass()); cltmp; cltmp = NextClass(cltmp)) - MarkDelete(cltmp); + if (count < 5 || EmptyString(fields[4])) + return; + + if (!EmptyString(fields[3])) { + const char* x = fields[3]; + if ('S' == ToUpper(*x)) + is_server = 1; + ++x; + if ('H' == ToUpper(*x)) + is_hidden = 1; + } + /* port vhost mask */ + add_listener(atoi(fields[4]), fields[2], fields[1], is_server, is_hidden); +} +void conf_add_admin(const char* const* fields, int count) +{ /* - * delete the juped nicks list + * if you have one, it MUST have 3 lines */ - clearNickJupes(); + if (count < 4) { + Debug((DEBUG_FATAL, "Your A: line must have 4 fields!\n")); + ircd_log(L_CRIT, "Your A: line must have 4 fields!\n"); + exit(-1); + } + MyFree(localConf.location1); + DupString(localConf.location1, fields[1]); - if (sig != 2) - flush_resolver_cache(); + MyFree(localConf.location2); + DupString(localConf.location2, fields[2]); - mark_listeners_closing(); + MyFree(localConf.contact); + DupString(localConf.contact, fields[3]); +} - if (!conf_init()) /* This calls check_class(), */ - check_class(); /* unless it fails */ +void conf_add_motd(const char* const* fields, int count, struct MotdConf** list) +{ + struct MotdConf* conf; + if (count < 3 || EmptyString(fields[1]) || EmptyString(fields[2])) + return; - /* - * make sure that the server listener is re-added so it doesn't get - * closed - */ - close_listeners(); + conf = (struct MotdConf*) MyMalloc(sizeof(struct MotdConf)); + assert(0 != conf); - /* - * Flush out deleted I and P lines although still in use. - */ - for (tmp = &GlobalConfList; (tmp2 = *tmp);) { - if (!(tmp2->status & CONF_ILLEGAL)) - tmp = &tmp2->next; - else - { - *tmp = tmp2->next; - tmp2->next = NULL; - if (!tmp2->clients) - free_conf(tmp2); - } - } - for (i = 0; i <= HighestFd; i++) { - if ((acptr = LocalClientArray[i])) { - assert(!IsMe(acptr)); - if (IsServer(acptr)) { - det_confs_butmask(acptr, - ~(CONF_HUB | CONF_LEAF | CONF_UWORLD | CONF_ILLEGAL)); - attach_confs_byname(acptr, acptr->name, - CONF_HUB | CONF_LEAF | CONF_UWORLD); - } - /* Because admin's are getting so uppity about people managing to - * get past K/G's etc, we'll "fix" the bug by actually explaining - * whats going on. - */ - if ((found_g = find_kill(acptr))) { - sendto_opmask_butone(0, found_g == -2 ? SNO_GLINE : SNO_OPERKILL, - found_g == -2 ? "G-line active for %s%s" : - "K-line active for %s%s", - IsUnknown(acptr) ? "Unregistered Client ":"", - get_client_name(acptr, HIDE_IP)); - if (exit_client(cptr, acptr, &me, found_g == -2 ? "G-lined" : - "K-lined") == CPTR_KILLED) - ret = CPTR_KILLED; - } - } - } - /* - * free old motd structs - */ - while (motd) { - temp = motd->next; - MyFree(motd); - motd = temp; - } - while (rmotd) { - temp = rmotd->next; - MyFree(rmotd); - rmotd = temp; - } - /* reload motd files */ - read_tlines(); - rmotd = read_motd(RPATH); - motd = read_motd(MPATH); - return ret; + DupString(conf->hostmask, fields[1]); + collapse(conf->hostmask); + + DupString(conf->path, fields[2]); + + assert(0 != list); + + conf->next = *list; + *list = conf; } +void erase_motd_conf_list(struct MotdConf** list) +{ + struct MotdConf* p; + struct MotdConf* next; -/* - * If conf line is a class definition, create a class entry - * for it and make the conf_line illegal and delete it. - */ -void conf_create_class(const char* const* fields, int count) + assert(0 != list); + + for (p = *list; p; p = next) { + next = p->next; + MyFree(p->hostmask); + MyFree(p->path); + MyFree(p); + } + *list = 0; +} + +const struct MotdConf* conf_get_motd_list(void) { - if (count < 6) - return; - add_class(atoi(fields[1]), atoi(fields[2]), atoi(fields[3]), - atoi(fields[4]), atoi(fields[5])); + return motdConfList; } /* - * conf_init + * read_configuration_file * * Read configuration file. * @@ -950,8 +787,7 @@ void conf_create_class(const char* const* fields, int count) #define MAXCONFLINKS 150 - -int conf_init(void) +int read_configuration_file(void) { enum { MAX_FIELDS = 15 }; @@ -966,7 +802,7 @@ int conf_init(void) int field_count = 0; const char* field_vector[MAX_FIELDS + 1]; - Debug((DEBUG_DEBUG, "conf_init: ircd.conf = %s", configfile)); + Debug((DEBUG_DEBUG, "read_configuration_file: ircd.conf = %s", configfile)); if (0 == (file = fbopen(configfile, "r"))) { return 0; } @@ -1061,7 +897,7 @@ int conf_init(void) } *dest = '\0'; - if (field_count < 3 || EmptyString(field_vector[0])) + if (field_count < 2 || EmptyString(field_vector[0])) continue; if (aconf) @@ -1071,8 +907,9 @@ int conf_init(void) switch (*field_vector[0]) { case 'A': /* Name, e-mail address of administrator */ - case 'a': /* of this server. */ - aconf->status = CONF_ADMIN; + case 'a': /* of this server. CONF_ADMIN */ + conf_add_admin(field_vector, field_count); + aconf->status = CONF_ILLEGAL; break; case 'C': /* Server where I should try to connect */ case 'c': /* in case of lp failures */ @@ -1121,12 +958,14 @@ int conf_init(void) aconf->status = CONF_LOCOP; break; case 'P': /* listen port line */ - case 'p': - aconf->status = CONF_LISTEN_PORT; + case 'p': /* CONF_LISTEN_PORT */ + conf_add_listener(field_vector, field_count); + aconf->status = CONF_ILLEGAL; break; case 'T': /* print out different motd's */ - case 't': /* based on hostmask */ - aconf->status = CONF_TLINES; + case 't': /* based on hostmask - CONF_TLINES */ + conf_add_motd(field_vector, field_count, &motdConfList); + aconf->status = CONF_ILLEGAL; break; case 'U': /* Underworld server, allowed to hack modes */ case 'u': /* *Every* server on the net must define the same !!! */ @@ -1134,7 +973,7 @@ int conf_init(void) break; case 'Y': case 'y': /* CONF_CLASS */ - conf_create_class(field_vector, field_count); + conf_add_class(field_vector, field_count); aconf->status = CONF_ILLEGAL; break; default: @@ -1180,21 +1019,6 @@ int conf_init(void) if (aconf->confClass == 0) aconf->confClass = find_class(0); } - if (aconf->status & CONF_LISTEN_PORT) { - int is_server = 0; - int is_hidden = 0; - if (!EmptyString(aconf->name)) { - const char* x = aconf->name; - if ('S' == ToUpper(*x)) - is_server = 1; - ++x; - if ('H' == ToUpper(*x)) - is_hidden = 1; - } - add_listener(aconf->port, aconf->passwd, aconf->host, - is_server, is_hidden); - continue; - } if (aconf->status & CONF_CLIENT) { struct ConfItem *bconf; @@ -1298,13 +1122,6 @@ int conf_init(void) if ((aconf->status == CONF_UWORLD) && (aconf->passwd) && (*aconf->passwd)) addNickJupes(aconf->passwd); - if (aconf->status & CONF_ADMIN) { - if (!aconf->host || !aconf->passwd || !aconf->name) { - Debug((DEBUG_FATAL, "Your A: line must have 4 fields!\n")); - ircd_log(L_WARNING, "Your A: line must have 4 fields!\n"); - exit(-1); - } - } collapse(aconf->host); collapse(aconf->name); Debug((DEBUG_NOTICE, @@ -1323,6 +1140,169 @@ int conf_init(void) return 1; } +/* + * rehash + * + * Actual REHASH service routine. Called with sig == 0 if it has been called + * as a result of an operator issuing this command, else assume it has been + * called as a result of the server receiving a HUP signal. + */ +int rehash(struct Client *cptr, int sig) +{ + struct ConfItem** tmp = &GlobalConfList; + struct ConfItem* tmp2; + struct ConfClass* cltmp; + struct Client* acptr; + struct MotdItem* temp; + int i; + int ret = 0; + int found_g = 0; + + if (1 == sig) + sendto_opmask_butone(0, SNO_OLDSNO, + "Got signal SIGHUP, reloading ircd conf. file"); + + while ((tmp2 = *tmp)) { + if (tmp2->clients) { + /* + * Configuration entry is still in use by some + * local clients, cannot delete it--mark it so + * that it will be deleted when the last client + * exits... + */ + if (!(tmp2->status & CONF_CLIENT)) { + *tmp = tmp2->next; + tmp2->next = 0; + } + else + tmp = &tmp2->next; + tmp2->status |= CONF_ILLEGAL; + } + else { + *tmp = tmp2->next; + /* free expression trees of connect rules */ + if ((tmp2->status & (CONF_CRULEALL | CONF_CRULEAUTO)) && + (tmp2->passwd != NULL)) + crule_free(&(tmp2->passwd)); + free_conf(tmp2); + } + } + erase_motd_conf_list(&motdConfList); + /* + * We don't delete the class table, rather mark all entries + * for deletion. The table is cleaned up by check_class(). - avalon + */ + for (cltmp = NextClass(FirstClass()); cltmp; cltmp = NextClass(cltmp)) + MarkDelete(cltmp); + + /* + * delete the juped nicks list + */ + clearNickJupes(); + + if (sig != 2) + flush_resolver_cache(); + + mark_listeners_closing(); + + if (!read_configuration_file()) /* This calls check_class(), */ + check_class(); /* unless it fails */ + + /* + * make sure that the server listener is re-added so it doesn't get + * closed + */ + close_listeners(); + + /* + * Flush out deleted I and P lines although still in use. + */ + for (tmp = &GlobalConfList; (tmp2 = *tmp);) { + if (!(tmp2->status & CONF_ILLEGAL)) + tmp = &tmp2->next; + else + { + *tmp = tmp2->next; + tmp2->next = NULL; + if (!tmp2->clients) + free_conf(tmp2); + } + } + for (i = 0; i <= HighestFd; i++) { + if ((acptr = LocalClientArray[i])) { + assert(!IsMe(acptr)); + if (IsServer(acptr)) { + det_confs_butmask(acptr, + ~(CONF_HUB | CONF_LEAF | CONF_UWORLD | CONF_ILLEGAL)); + attach_confs_byname(acptr, acptr->name, + CONF_HUB | CONF_LEAF | CONF_UWORLD); + } + /* Because admin's are getting so uppity about people managing to + * get past K/G's etc, we'll "fix" the bug by actually explaining + * whats going on. + */ + if ((found_g = find_kill(acptr))) { + sendto_opmask_butone(0, found_g == -2 ? SNO_GLINE : SNO_OPERKILL, + found_g == -2 ? "G-line active for %s%s" : + "K-line active for %s%s", + IsUnknown(acptr) ? "Unregistered Client ":"", + get_client_name(acptr, HIDE_IP)); + if (exit_client(cptr, acptr, &me, found_g == -2 ? "G-lined" : + "K-lined") == CPTR_KILLED) + ret = CPTR_KILLED; + } + } + } + /* + * free old motd structs + */ + while (motd) { + temp = motd->next; + MyFree(motd); + motd = temp; + } + while (rmotd) { + temp = rmotd->next; + MyFree(rmotd); + rmotd = temp; + } + /* reload motd files */ + read_tlines(); + rmotd = read_motd(RPATH); + motd = read_motd(MPATH); + return ret; +} + +/* + * conf_init + * + * Read configuration file. + * + * returns 0, if file cannot be opened + * 1, if file read + */ + +int conf_init(void) +{ + if (read_configuration_file()) { + /* + * make sure we're sane to start if the config + * file read didn't get everything we need. + * XXX - should any of these abort the server? + * TODO: add warning messages + */ + if (0 == localConf.location1) + DupString(localConf.location1, ""); + if (0 == localConf.location2) + DupString(localConf.location2, ""); + if (0 == localConf.contact) + DupString(localConf.contact, ""); + + return 1; + } + return 0; +} + /* read_tlines * Read info from T:lines into TRecords which include the file @@ -1331,17 +1311,15 @@ int conf_init(void) */ void read_tlines() { - struct ConfItem *tmp; + struct MotdConf* conf; struct TRecord *temp; struct TRecord *last = NULL; /* Init. to avoid compiler warning */ struct MotdItem *amotd; /* Free the old trecords and the associated motd contents first */ - while (tdata) - { + while (tdata) { last = tdata->next; - while (tdata->tmotd) - { + while (tdata->tmotd) { amotd = tdata->tmotd->next; MyFree(tdata->tmotd); tdata->tmotd = amotd; @@ -1350,21 +1328,20 @@ void read_tlines() tdata = last; } - for (tmp = GlobalConfList; tmp; tmp = tmp->next) { - if (tmp->status == CONF_TLINES && tmp->host && tmp->passwd) { - temp = (struct TRecord*) MyMalloc(sizeof(struct TRecord)); - assert(0 != temp); - - temp->hostmask = tmp->host; - temp->tmotd = read_motd(tmp->passwd); - temp->tmotd_tm = motd_tm; - temp->next = NULL; - if (!tdata) - tdata = temp; - else - last->next = temp; - last = temp; - } + for (conf = motdConfList; conf; conf = conf->next) { + temp = (struct TRecord*) MyMalloc(sizeof(struct TRecord)); + assert(0 != temp); + + temp->hostmask = conf->hostmask; + temp->tmotd = read_motd(conf->path); + temp->tmotd_tm = motd_tm; + temp->next = 0; + + if (!tdata) + tdata = temp; + else + last->next = temp; + last = temp; } } diff --git a/ircd/s_stats.c b/ircd/s_stats.c index ad675c5..28bac49 100644 --- a/ircd/s_stats.c +++ b/ircd/s_stats.c @@ -134,8 +134,6 @@ void report_configured_links(struct Client *sptr, int mask) */ else if ((tmp->status & CONF_CRULE)) send_reply(sptr, p[1], c, host, name); - else if ((tmp->status & CONF_TLINES)) - send_reply(sptr, p[1], c, host, pass); else if ((tmp->status & CONF_UWORLD)) send_reply(sptr, p[1], c, host, pass, name, port, get_conf_class(tmp)); else if ((tmp->status & (CONF_SERVER | CONF_HUB))) @@ -146,6 +144,16 @@ void report_configured_links(struct Client *sptr, int mask) } } +/* + * {CONF_TLINES, RPL_STATSTLINE, 'T'}, + */ +void report_motd_list(struct Client* to) +{ + const struct MotdConf* conf = conf_get_motd_list(); + for ( ; conf; conf = conf->next) + send_reply(to, RPL_STATSTLINE, 'T', conf->hostmask, conf->path); +} + /* m_stats is so obnoxiously full of special cases that the different * hunt_server() possiblites were becoming very messy. It now uses a * switch() so as to be easier to read and update as params change. -- 2.20.1