X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=ircd%2Fs_conf.c;h=7db9ff2e4722e68136e3532d6cc7cc5446b475df;hb=refs%2Fheads%2Fupstream;hp=276d4265b80d73654a9e093e2581b8febafe3c99;hpb=56f512008e81aeae915b2b7f6bcdd54b549188d3;p=ircu2.10.12-pk.git diff --git a/ircd/s_conf.c b/ircd/s_conf.c index 276d426..7db9ff2 100644 --- a/ircd/s_conf.c +++ b/ircd/s_conf.c @@ -16,8 +16,10 @@ * 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. - * - * $Id$ + */ +/** @file + * @brief ircd configuration file driver + * @version $Id$ */ #include "config.h" @@ -46,16 +48,15 @@ #include "opercmds.h" #include "parse.h" #include "res.h" +#include "s_auth.h" #include "s_bsd.h" #include "s_debug.h" #include "s_misc.h" #include "send.h" #include "struct.h" -#include "support.h" #include "sys.h" -#include -#include +/* #include -- Now using assert in ircd_log.h */ #include #include #include @@ -65,29 +66,34 @@ #include #include -#ifndef INADDR_NONE -#define INADDR_NONE 0xffffffff -#endif - -struct ConfItem* GlobalConfList = 0; -int GlobalConfCount = 0; - -static struct LocalConf localConf; -static struct CRuleConf* cruleConfList; -static struct ServerConf* serverConfList; -static struct DenyConf* denyConfList; - -/* - * output the reason for being k lined from a file - Mmmm - * sptr is client being dumped - * filename is the file that is to be output to the K lined client +/** Global list of all ConfItem structures. */ +struct ConfItem *GlobalConfList; +/** Count of items in #GlobalConfList. */ +int GlobalConfCount; +/** Global list of service mappings. */ +struct s_map *GlobalServiceMapList; +/** Global list of channel quarantines. */ +struct qline *GlobalQuarantineList; + +/** Current line number in scanner input. */ +int lineno; + +/** Configuration information for #me. */ +struct LocalConf localConf; +/** Global list of connection rules. */ +struct CRuleConf* cruleConfList; +/** Global list of K-lines. */ +struct DenyConf* denyConfList; + +/** Tell a user that they are banned, dumping the message from a file. + * @param sptr Client being rejected + * @param filename Send this file's contents to \a sptr */ static void killcomment(struct Client* sptr, const char* filename) { FBFILE* file = 0; char line[80]; struct stat sb; - struct tm* tm; if (NULL == (file = fbopen(filename, "r"))) { send_reply(sptr, ERR_NOMOTD); @@ -96,7 +102,6 @@ static void killcomment(struct Client* sptr, const char* filename) return; } fbstat(&sb, file); - tm = localtime((time_t*) &sb.st_mtime); /* NetBSD needs cast */ while (fbgets(line, sizeof(line) - 1, file)) { char* end = line + strlen(line); while (end > line) { @@ -113,56 +118,49 @@ static void killcomment(struct Client* sptr, const char* filename) fbclose(file); } -struct ConfItem* make_conf(void) +/** Allocate a new struct ConfItem and link it to #GlobalConfList. + * @return Newly allocated structure. + */ +struct ConfItem* make_conf(int type) { struct ConfItem* aconf; aconf = (struct ConfItem*) MyMalloc(sizeof(struct ConfItem)); assert(0 != aconf); -#ifdef DEBUGMODE ++GlobalConfCount; -#endif memset(aconf, 0, sizeof(struct ConfItem)); - aconf->status = CONF_ILLEGAL; - aconf->ipnum.s_addr = INADDR_NONE; + aconf->status = type; + aconf->next = GlobalConfList; + GlobalConfList = aconf; return aconf; } -void delist_conf(struct ConfItem *aconf) -{ - if (aconf == GlobalConfList) - GlobalConfList = GlobalConfList->next; - else { - struct ConfItem *bconf; - - for (bconf = GlobalConfList; aconf != bconf->next; bconf = bconf->next) - ; - bconf->next = aconf->next; - } - aconf->next = 0; -} - +/** Free a struct ConfItem and any resources it owns. + * @param aconf Item to free. + */ void free_conf(struct ConfItem *aconf) { Debug((DEBUG_DEBUG, "free_conf: %s %s %d", aconf->host ? aconf->host : "*", aconf->name ? aconf->name : "*", - aconf->port)); + aconf->address.port)); if (aconf->dns_pending) delete_resolver_queries(aconf); + MyFree(aconf->username); MyFree(aconf->host); + MyFree(aconf->origin_name); if (aconf->passwd) memset(aconf->passwd, 0, strlen(aconf->passwd)); MyFree(aconf->passwd); MyFree(aconf->name); + MyFree(aconf->hub_limit); MyFree(aconf); -#ifdef DEBUGMODE --GlobalConfCount; -#endif } -/* - * detach_conf - Disassociate configuration from the client. +/** Disassociate configuration from the client. + * @param cptr Client to operate on. + * @param aconf ConfItem to detach. */ static void detach_conf(struct Client* cptr, struct ConfItem* aconf) { @@ -192,84 +190,101 @@ static void detach_conf(struct Client* cptr, struct ConfItem* aconf) } } -/* - * conf_dns_callback - called when resolver query finishes - * if the query resulted in a successful search, hp will contain - * a non-null pointer, otherwise hp will be null. - * if successful save hp in the conf item it was called with +/** Parse a user\@host mask into username and host or IP parts. + * If \a host contains no username part, set \a aconf->username to + * NULL. If the host part of \a host looks like an IP mask, set \a + * aconf->addrbits and \a aconf->address to match. Otherwise, set + * \a aconf->host, and set \a aconf->addrbits to -1. + * @param[in,out] aconf Configuration item to set. + * @param[in] host user\@host mask to parse. */ -static void conf_dns_callback(void* vptr, struct DNSReply* reply) +void conf_parse_userhost(struct ConfItem *aconf, char *host) +{ + char *host_part; + unsigned char addrbits; + + MyFree(aconf->username); + MyFree(aconf->host); + host_part = strchr(host, '@'); + if (host_part) { + *host_part = '\0'; + DupString(aconf->username, host); + host_part++; + } else { + aconf->username = NULL; + host_part = host; + } + DupString(aconf->host, host_part); + if (ipmask_parse(aconf->host, &aconf->address.addr, &addrbits)) + aconf->addrbits = addrbits; + else + aconf->addrbits = -1; +} + +/** Copies a completed DNS query into its ConfItem. + * @param vptr Pointer to struct ConfItem for the block. + * @param hp DNS reply, or NULL if the lookup failed. + */ +static void conf_dns_callback(void* vptr, const struct irc_in_addr *addr, const char *h_name) { struct ConfItem* aconf = (struct ConfItem*) vptr; + assert(aconf); aconf->dns_pending = 0; - if (reply) - memcpy(&aconf->ipnum, reply->hp->h_addr, sizeof(struct in_addr)); + if (addr) + memcpy(&aconf->address.addr, addr, sizeof(aconf->address.addr)); } -/* - * conf_dns_lookup - do a nameserver lookup of the conf host - * if the conf entry is currently doing a ns lookup do nothing, otherwise - * if the lookup returns a null pointer, set the conf dns_pending flag +/** Start a nameserver lookup of the conf host. If the conf entry is + * currently doing a lookup, do nothing. + * @param aconf ConfItem for which to start a request. */ -static struct DNSReply* conf_dns_lookup(struct ConfItem* aconf) +static void conf_dns_lookup(struct ConfItem* aconf) { - struct DNSReply* dns_reply = 0; if (!aconf->dns_pending) { char buf[HOSTLEN + 1]; - struct DNSQuery query; - query.vptr = aconf; - query.callback = conf_dns_callback; - host_from_uh(buf, aconf->host, HOSTLEN); - buf[HOSTLEN] = '\0'; - if (0 == (dns_reply = gethost_byname(buf, &query))) - aconf->dns_pending = 1; + host_from_uh(buf, aconf->host, HOSTLEN); + gethost_byname(buf, conf_dns_callback, aconf); + aconf->dns_pending = 1; } - return dns_reply; } -/* - * lookup_confhost - * - * Do (start) DNS lookups of all hostnames in the conf line and convert - * an IP addresses in a.b.c.d number for to IP#s. +/** Start lookups of all addresses in the conf line. The origin must + * be a numeric IP address. If the remote host field is not an IP + * address, start a DNS lookup for it. + * @param aconf Connection to do lookups for. */ -static void lookup_confhost(struct ConfItem *aconf) +void +lookup_confhost(struct ConfItem *aconf) { - struct DNSReply* reply; - if (EmptyString(aconf->host) || EmptyString(aconf->name)) { Debug((DEBUG_ERROR, "Host/server name error: (%s) (%s)", aconf->host, aconf->name)); return; } + if (aconf->origin_name + && !ircd_aton(&aconf->origin.addr, aconf->origin_name)) { + Debug((DEBUG_ERROR, "Origin name error: (%s) (%s)", + aconf->origin_name, aconf->name)); + } /* * Do name lookup now on hostnames given and store the * ip numbers in conf structure. */ - if (IsDigit(*aconf->host)) { - /* - * rfc 1035 sez host names may not start with a digit - * XXX - this has changed code needs to be updated - */ - aconf->ipnum.s_addr = inet_addr(aconf->host); - if (INADDR_NONE == aconf->ipnum.s_addr) { + if (IsIP6Char(*aconf->host)) { + if (!ircd_aton(&aconf->address.addr, aconf->host)) { Debug((DEBUG_ERROR, "Host/server name error: (%s) (%s)", - aconf->host, aconf->name)); + aconf->host, aconf->name)); } } - else if ((reply = conf_dns_lookup(aconf))) - memcpy(&aconf->ipnum, reply->hp->h_addr, sizeof(struct in_addr)); + else + conf_dns_lookup(aconf); } -/* - * conf_find_server - find a server by name or hostname - * returns a server conf item pointer if found, 0 otherwise - * - * NOTE: at some point when we don't have to scan the entire - * list it may be cheaper to look for server names and host - * names in separate loops (original code did it that way) +/** Find a server by name or hostname. + * @param name Server name to find. + * @return Pointer to the corresponding ConfItem, or NULL if none exists. */ struct ConfItem* conf_find_server(const char* name) { @@ -290,14 +305,10 @@ struct ConfItem* conf_find_server(const char* name) return 0; } -/* - * conf_eval_crule - evaluate connection rules - * returns the name of the rule triggered if found, 0 otherwise - * - * Evaluate connection rules... If no rules found, allow the - * connect. Otherwise stop with the first true rule (ie: rules - * are ored together. Oper connects are effected only by D - * lines (CRULE_ALL) not d lines (CRULE_AUTO). +/** Evaluate connection rules. + * @param name Name of server to check + * @param mask Filter for CRule types (only consider if type & \a mask != 0). + * @return Name of rule that forbids the connection; NULL if no prohibitions. */ const char* conf_eval_crule(const char* name, int mask) { @@ -313,9 +324,10 @@ const char* conf_eval_crule(const char* name, int mask) return 0; } -/* - * Remove all conf entries from the client except those which match +/** Remove all conf entries from the client except those which match * the status field mask. + * @param cptr Client to operate on. + * @param mask ConfItem types to keep. */ void det_confs_butmask(struct Client* cptr, int mask) { @@ -330,96 +342,184 @@ void det_confs_butmask(struct Client* cptr, int mask) } } -/* - * check_limit_and_attach - check client limits and attach I:line - * - * Made it accept 1 charactor, and 2 charactor limits (0->99 now), - * and dislallow more than 255 people here as well as in ipcheck. - * removed the old "ONE" scheme too. - * -- Isomer 2000-06-22 +/** Find the first (best) Client block to attach. + * @param cptr Client for whom to check rules. + * @return Authorization check result. */ -static enum AuthorizationCheckResult -check_limit_and_attach(struct Client* cptr, struct ConfItem* aconf) -{ - int number = 255; - - if (aconf->passwd) { - if (IsDigit(*aconf->passwd) && !aconf->passwd[1]) - number = *aconf->passwd-'0'; - else if (IsDigit(*aconf->passwd) && IsDigit(aconf->passwd[1]) && - !aconf->passwd[2]) - number = (*aconf->passwd-'0')*10+(aconf->passwd[1]-'0'); - } - if (IPcheck_nr(cptr) > number) - return ACR_TOO_MANY_FROM_IP; - return attach_conf(cptr, aconf); -} - -/* - * Find the first (best) I line to attach. - */ -enum AuthorizationCheckResult attach_iline(struct Client* cptr) +enum AuthorizationCheckResult attach_iline(struct Client* cptr) { struct ConfItem* aconf; - const char* hname; - int i; - static char uhost[HOSTLEN + USERLEN + 3]; - static char fullname[HOSTLEN + 1]; - struct hostent* hp = 0; assert(0 != cptr); - if (cli_dns_reply(cptr)) - hp = cli_dns_reply(cptr)->hp; - for (aconf = GlobalConfList; aconf; aconf = aconf->next) { if (aconf->status != CONF_CLIENT) continue; - if (aconf->port && aconf->port != cli_listener(cptr)->port) + /* If you change any of this logic, please make corresponding + * changes in conf_debug_iline() below. + */ + if (aconf->address.port && aconf->address.port != cli_listener(cptr)->addr.port) + continue; + if (aconf->username && match(aconf->username, cli_username(cptr))) + continue; + if (aconf->host && match(aconf->host, cli_sockhost(cptr))) continue; - if (!aconf->host || !aconf->name) + if ((aconf->addrbits >= 0) + && !ipmask_check(&cli_ip(cptr), &aconf->address.addr, aconf->addrbits)) + continue; + if (IPcheck_nr(cptr) > aconf->maximum) + return ACR_TOO_MANY_FROM_IP; + if (aconf->username) + SetFlag(cptr, FLAG_DOID); + return attach_conf(cptr, aconf); + } + return ACR_NO_AUTHORIZATION; +} + +/** Interpret \a client as a client specifier and show which Client + * block(s) match that client. + * + * The client specifier may contain an IP address, hostname, listener + * port, or a combination of those separated by commas. IP addresses + * and hostnamese may be preceded by "username@"; the last given + * username will be used for the match. + * + * @param[in] client Client specifier. + * @return Matching Client block structure. + */ +struct ConfItem *conf_debug_iline(const char *client) +{ + struct irc_in_addr address; + struct ConfItem *aconf; + struct DenyConf *deny; + char *sep; + unsigned short listener; + char username[USERLEN+1], hostname[HOSTLEN+1], realname[REALLEN+1]; + + /* Initialize variables. */ + listener = 0; + memset(&address, 0, sizeof(address)); + memset(&username, 0, sizeof(username)); + memset(&hostname, 0, sizeof(hostname)); + memset(&realname, 0, sizeof(realname)); + + /* Parse client specifier. */ + while (*client) { + struct irc_in_addr tmpaddr; + long tmp; + + /* Try to parse as listener port number first. */ + tmp = strtol(client, &sep, 10); + if (tmp && (*sep == '\0' || *sep == ',')) { + listener = tmp; + client = sep + (*sep != '\0'); continue; - if (hp) { - for (i = 0, hname = hp->h_name; hname; hname = hp->h_aliases[i++]) { - ircd_strncpy(fullname, hname, HOSTLEN); - fullname[HOSTLEN] = '\0'; + } + + /* Maybe username@ before an IP address or hostname? */ + tmp = strcspn(client, ",@"); + if (client[tmp] == '@') { + if (tmp > USERLEN) + tmp = USERLEN; + ircd_strncpy(username, client, tmp); + /* and fall through */ + client += tmp + 1; + } - Debug((DEBUG_DNS, "a_il: %s->%s", cli_sockhost(cptr), fullname)); + /* Looks like an IP address? */ + tmp = ircd_aton(&tmpaddr, client); + if (tmp && (client[tmp] == '\0' || client[tmp] == ',')) { + memcpy(&address, &tmpaddr, sizeof(address)); + client += tmp + (client[tmp] != '\0'); + continue; + } - if (strchr(aconf->name, '@')) { - strcpy(uhost, cli_username(cptr)); - strcat(uhost, "@"); - } + /* Realname? */ + if (client[0] == '$' && client[1] == 'R') { + client += 2; + for (tmp = 0; *client != '\0' && *client != ',' && tmp < REALLEN; ++client, ++tmp) { + if (*client == '\\') + realname[tmp] = *++client; else - *uhost = '\0'; - strncat(uhost, fullname, sizeof(uhost) - 1 - strlen(uhost)); - uhost[sizeof(uhost) - 1] = 0; - if (0 == match(aconf->name, uhost)) { - if (strchr(uhost, '@')) - cli_flags(cptr) |= FLAGS_DOID; - return check_limit_and_attach(cptr, aconf); - } + realname[tmp] = *client; } + continue; + } + + /* Else must be a hostname. */ + tmp = strcspn(client, ","); + if (tmp > HOSTLEN) + tmp = HOSTLEN; + ircd_strncpy(hostname, client, tmp); + client += tmp + (client[tmp] != '\0'); + } + + /* Walk configuration to find matching Client block. */ + for (aconf = GlobalConfList; aconf; aconf = aconf->next) { + if (aconf->status != CONF_CLIENT) + continue; + if (aconf->address.port && aconf->address.port != listener) { + fprintf(stdout, "Listener port mismatch: %u != %u\n", aconf->address.port, listener); + continue; } - if (strchr(aconf->host, '@')) { - ircd_strncpy(uhost, cli_username(cptr), sizeof(uhost) - 2); - uhost[sizeof(uhost) - 2] = 0; - strcat(uhost, "@"); + if (aconf->username && match(aconf->username, username)) { + fprintf(stdout, "Username mismatch: %s != %s\n", aconf->username, username); + continue; } - else - *uhost = '\0'; - strncat(uhost, cli_sock_ip(cptr), sizeof(uhost) - 1 - strlen(uhost)); - uhost[sizeof(uhost) - 1] = 0; - if (match(aconf->host, uhost)) + if (aconf->host && match(aconf->host, hostname)) { + fprintf(stdout, "Hostname mismatch: %s != %s\n", aconf->host, hostname); + continue; + } + if ((aconf->addrbits >= 0) + && !ipmask_check(&address, &aconf->address.addr, aconf->addrbits)) { + fprintf(stdout, "IP address mismatch: %s != %s\n", aconf->name, ircd_ntoa(&address)); continue; - if (strchr(uhost, '@')) - cli_flags(cptr) |= FLAGS_DOID; + } + fprintf(stdout, "Match! username=%s host=%s ip=%s class=%s maxlinks=%u password=%s\n", + (aconf->username ? aconf->username : "(null)"), + (aconf->host ? aconf->host : "(null)"), + (aconf->name ? aconf->name : "(null)"), + ConfClass(aconf), aconf->maximum, + (aconf->passwd ? aconf->passwd : "(null)")); + break; + } - return check_limit_and_attach(cptr, aconf); + /* If no authorization, say so and exit. */ + if (!aconf) + { + fprintf(stdout, "No authorization found.\n"); + return NULL; } - return ACR_NO_AUTHORIZATION; + + /* Look for a Kill block with the user's name on it. */ + for (deny = denyConfList; deny; deny = deny->next) { + if (deny->usermask && match(deny->usermask, username)) + continue; + if (deny->realmask && match(deny->realmask, realname)) + continue; + if (deny->bits > 0) { + if (!ipmask_check(&address, &deny->address, deny->bits)) + continue; + } else if (deny->hostmask && match(deny->hostmask, hostname)) + continue; + + /* Looks like a match; report it. */ + fprintf(stdout, "Denied! usermask=%s realmask=\"%s\" hostmask=%s (bits=%u)\n", + deny->usermask ? deny->usermask : "(null)", + deny->realmask ? deny->realmask : "(null)", + deny->hostmask ? deny->hostmask : "(null)", + deny->bits); + } + + return aconf; } +/** Check whether a particular ConfItem is already attached to a + * Client. + * @param aconf ConfItem to search for + * @param cptr Client to check + * @return Non-zero if \a aconf is attached to \a cptr, zero if not. + */ static int is_attached(struct ConfItem *aconf, struct Client *cptr) { struct SLink *lp; @@ -431,13 +531,12 @@ static int is_attached(struct ConfItem *aconf, struct Client *cptr) return 0; } -/* - * attach_conf - * - * Associate a specific configuration entry to a *local* - * client (this is the one which used in accepting the - * connection). Note, that this automaticly changes the - * attachment if there was an old one... +/** Associate a specific configuration entry to a *local* client (this + * is the one which used in accepting the connection). Note, that this + * automatically changes the attachment if there was an old one... + * @param cptr Client to attach \a aconf to + * @param aconf ConfItem to attach + * @return Authorization check result. */ enum AuthorizationCheckResult attach_conf(struct Client *cptr, struct ConfItem *aconf) { @@ -447,7 +546,7 @@ enum AuthorizationCheckResult attach_conf(struct Client *cptr, struct ConfItem * return ACR_ALREADY_AUTHORIZED; if (IsIllegal(aconf)) return ACR_NO_AUTHORIZATION; - if ((aconf->status & (CONF_LOCOP | CONF_OPERATOR | CONF_CLIENT)) && + if ((aconf->status & (CONF_OPERATOR | CONF_CLIENT)) && ConfLinks(aconf) >= ConfMaxLinks(aconf) && ConfMaxLinks(aconf) > 0) return ACR_TOO_MANY_IN_CLASS; /* Use this for printing error message */ lp = make_link(); @@ -460,17 +559,20 @@ enum AuthorizationCheckResult attach_conf(struct Client *cptr, struct ConfItem * return ACR_OK; } +/** Return our LocalConf configuration structure. + * @return A pointer to #localConf. + */ const struct LocalConf* conf_get_local(void) { return &localConf; } -/* - * attach_confs_byname - * - * Attach a CONF line to a client if the name passed matches that for - * the conf file (for non-C/N lines) or is an exact match (C/N lines - * only). The difference in behaviour is to stop C:*::* and N:*::*. +/** Attach ConfItems to a client if the name passed matches that for + * the ConfItems or is an exact match for them. + * @param cptr Client getting the ConfItem attachments. + * @param name Filter to match ConfItem::name. + * @param statmask Filter to limit ConfItem::status. + * @return First ConfItem attached to \a cptr. */ struct ConfItem* attach_confs_byname(struct Client* cptr, const char* name, int statmask) @@ -495,8 +597,12 @@ struct ConfItem* attach_confs_byname(struct Client* cptr, const char* name, return first; } -/* - * Added for new access check meLazy +/** Attach ConfItems to a client if the host passed matches that for + * the ConfItems or is an exact match for them. + * @param cptr Client getting the ConfItem attachments. + * @param host Filter to match ConfItem::host. + * @param statmask Filter to limit ConfItem::status. + * @return First ConfItem attached to \a cptr. */ struct ConfItem* attach_confs_byhost(struct Client* cptr, const char* host, int statmask) @@ -520,43 +626,48 @@ struct ConfItem* attach_confs_byhost(struct Client* cptr, const char* host, return first; } -/* - * find a conf entry which matches the hostname and has the same name. +/** Find a ConfItem that has the same name and user+host fields as + * specified. Requires an exact match for \a name. + * @param name Name to match + * @param cptr Client to match against + * @param statmask Filter for ConfItem::status + * @return First found matching ConfItem. */ -struct ConfItem* find_conf_exact(const char* name, const char* user, - const char* host, int statmask) +struct ConfItem* find_conf_exact(const char* name, struct Client *cptr, int statmask) { struct ConfItem *tmp; - char userhost[USERLEN + HOSTLEN + 3]; - - if (user) - ircd_snprintf(0, userhost, sizeof(userhost), "%s@%s", user, host); - else - ircd_strncpy(userhost, host, sizeof(userhost) - 1); for (tmp = GlobalConfList; tmp; tmp = tmp->next) { if (!(tmp->status & statmask) || !tmp->name || !tmp->host || 0 != ircd_strcmp(tmp->name, name)) continue; - /* - * Accept if the *real* hostname (usually sockecthost) - * socket host) matches *either* host or name field - * of the configuration. - */ - if (match(tmp->host, userhost)) + if (tmp->username + && (EmptyString(cli_username(cptr)) + || match(tmp->username, cli_username(cptr)))) continue; - if (tmp->status & (CONF_OPERATOR | CONF_LOCOP)) { - if (tmp->clients < MaxLinks(tmp->conn_class)) - return tmp; - else + if (tmp->addrbits < 0) + { + if (match(tmp->host, cli_sockhost(cptr))) continue; } - else - return tmp; + else if (!ipmask_check(&cli_ip(cptr), &tmp->address.addr, tmp->addrbits)) + continue; + if ((tmp->status & CONF_OPERATOR) + && (MaxLinks(tmp->conn_class) > 0) + && (tmp->clients >= MaxLinks(tmp->conn_class))) + continue; + return tmp; } return 0; } +/** Find a ConfItem from a list that has a name that matches \a name. + * @param lp List to search in. + * @param name Filter for ConfItem::name field; matches either exactly + * or as a glob. + * @param statmask Filter for ConfItem::status. + * @return First matching ConfItem from \a lp. + */ struct ConfItem* find_conf_byname(struct SLink* lp, const char* name, int statmask) { @@ -577,8 +688,11 @@ struct ConfItem* find_conf_byname(struct SLink* lp, const char* name, return 0; } -/* - * Added for new access check meLazy +/** Find a ConfItem from a list that has a host that matches \a host. + * @param lp List to search in. + * @param host Filter for ConfItem::host field; matches as a glob. + * @param statmask Filter for ConfItem::status. + * @return First matching ConfItem from \a lp. */ struct ConfItem* find_conf_byhost(struct SLink* lp, const char* host, int statmask) @@ -600,185 +714,27 @@ struct ConfItem* find_conf_byhost(struct SLink* lp, const char* host, return 0; } -/* - * find_conf_ip - * - * Find a conf line using the IP# stored in it to search upon. - * Added 1/8/92 by Avalon. +/** Find a ConfItem from a list that has an address equal to \a ip. + * @param lp List to search in. + * @param ip Filter for ConfItem::address field; matches exactly. + * @param statmask Filter for ConfItem::status. + * @return First matching ConfItem from \a lp. */ -struct ConfItem* find_conf_byip(struct SLink* lp, const char* ip, +struct ConfItem* find_conf_byip(struct SLink* lp, const struct irc_in_addr* ip, int statmask) { struct ConfItem* tmp; for (; lp; lp = lp->next) { tmp = lp->value.aconf; - if (0 != (tmp->status & statmask)) { - if (0 == memcmp(&tmp->ipnum, ip, sizeof(struct in_addr))) - return tmp; - } + if (0 != (tmp->status & statmask) + && !irc_in_addr_cmp(&tmp->address.addr, ip)) + return tmp; } return 0; } -/* - * find_conf_entry - * - * - looks for a match on all given fields. - */ -static struct ConfItem *find_conf_entry(struct ConfItem *aconf, - unsigned int mask) -{ - struct ConfItem *bconf; - assert(0 != aconf); - - mask &= ~CONF_ILLEGAL; - - for (bconf = GlobalConfList; bconf; bconf = bconf->next) { - if (!(bconf->status & mask) || (bconf->port != aconf->port)) - continue; - - if ((EmptyString(bconf->host) && !EmptyString(aconf->host)) || - (EmptyString(aconf->host) && !EmptyString(bconf->host))) - continue; - if (!EmptyString(bconf->host) && 0 != ircd_strcmp(bconf->host, aconf->host)) - continue; - - if ((EmptyString(bconf->passwd) && !EmptyString(aconf->passwd)) || - (EmptyString(aconf->passwd) && !EmptyString(bconf->passwd))) - continue; - if (!EmptyString(bconf->passwd) && (!IsDigit(*bconf->passwd) || bconf->passwd[1]) - && 0 != ircd_strcmp(bconf->passwd, aconf->passwd)) - continue; - - if ((EmptyString(bconf->name) && !EmptyString(aconf->name)) || - (EmptyString(aconf->name) && !EmptyString(bconf->name))) - continue; - if (!EmptyString(bconf->name) && 0 != ircd_strcmp(bconf->name, aconf->name)) - continue; - break; - } - return bconf; -} - - -/* - * If conf line is a class definition, create a class entry - * for it and make the conf_line illegal and delete it. - */ -void conf_add_class(const char* const* fields, int count) -{ - if (count < 6) - return; - add_class(atoi(fields[1]), atoi(fields[2]), atoi(fields[3]), - atoi(fields[4]), atoi(fields[5])); -} - -void conf_add_listener(const char* const* fields, int count) -{ - int is_server = 0; - int is_hidden = 0; - - /* - * need a port - */ - 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_local(const char* const* fields, int count) -{ - if (count < 6 || EmptyString(fields[1]) || EmptyString(fields[5])) { - log_write(LS_CONFIG, L_CRIT, 0, "Your M: line must have 6 fields!"); - return; - } - /* - * these two can only be set the first time - */ - if (0 == localConf.name) { - if (string_is_hostname(fields[1])) - DupString(localConf.name, fields[1]); - } - if (0 == localConf.numeric) { - localConf.numeric = atoi(fields[5]); - if (0 == localConf.numeric) - log_write(LS_CONFIG, L_WARNING, 0, - "Your M: line must have a Numeric value greater than 0"); - } - /* - * these two can be changed while the server is running - */ - if (string_is_address(fields[2])) { - if (INADDR_NONE == (localConf.vhost_address.s_addr = inet_addr(fields[2]))) - localConf.vhost_address.s_addr = INADDR_ANY; - } - MyFree(localConf.description); - DupString(localConf.description, fields[3]); - /* - * XXX - shouldn't be setting these directly here - */ - ircd_strncpy(cli_info(&me), fields[3], REALLEN); - set_virtual_host(localConf.vhost_address); -} - -void conf_add_admin(const char* const* fields, int count) -{ - /* - * if you have one, it MUST have 3 lines - */ - if (count < 4) { - log_write(LS_CONFIG, L_CRIT, 0, "Your A: line must have 4 fields!"); - return; - } - MyFree(localConf.location1); - DupString(localConf.location1, fields[1]); - - MyFree(localConf.location2); - DupString(localConf.location2, fields[2]); - - MyFree(localConf.contact); - DupString(localConf.contact, fields[3]); -} - -/* - * conf_add_crule - Create expression tree from connect rule and add it - * to the crule list - */ -void conf_add_crule(const char* const* fields, int count, int type) -{ - struct CRuleNode* node; - assert(0 != fields); - - if (count < 4 || EmptyString(fields[1]) || EmptyString(fields[3])) - return; - - if ((node = crule_parse(fields[3]))) { - struct CRuleConf* p = (struct CRuleConf*) MyMalloc(sizeof(struct CRuleConf)); - assert(0 != p); - - DupString(p->hostmask, fields[1]); - collapse(p->hostmask); - - DupString(p->rule, fields[3]); - - p->type = type; - p->node = node; - p->next = cruleConfList; - cruleConfList = p; - } -} - +/** Free all CRules from #cruleConfList. */ void conf_erase_crule_list(void) { struct CRuleConf* next; @@ -794,108 +750,15 @@ void conf_erase_crule_list(void) cruleConfList = 0; } +/** Return #cruleConfList. + * @return #cruleConfList + */ const struct CRuleConf* conf_get_crule_list(void) { return cruleConfList; } -void conf_add_server(const char* const* fields, int count) -{ - struct ServerConf* server; - struct in_addr addr; - assert(0 != fields); - /* - * missing host, password, or alias? - */ - if (count < 6 || EmptyString(fields[1]) || EmptyString(fields[2]) || EmptyString(fields[3])) - return; - /* - * check the host - */ - if (string_is_hostname(fields[1])) - addr.s_addr = INADDR_NONE; - else if (INADDR_NONE == (addr.s_addr = inet_addr(fields[1]))) - return; - - server = (struct ServerConf*) MyMalloc(sizeof(struct ServerConf)); - assert(0 != server); - DupString(server->hostname, fields[1]); - DupString(server->passwd, fields[2]); - DupString(server->alias, fields[3]); - server->address.s_addr = addr.s_addr; - server->port = atoi(fields[4]); - server->dns_pending = 0; - server->connected = 0; - server->hold = 0; - server->conn_class = find_class(atoi(fields[5])); - - server->next = serverConfList; - serverConfList = server; - - /* if (INADDR_NONE == server->address.s_addr) */ - /* lookup_confhost(server); */ -} - -void conf_add_deny(const char* const* fields, int count, int ip_kill) -{ - struct DenyConf* conf; - - if (count < 4 || EmptyString(fields[1]) || EmptyString(fields[3])) - return; - - conf = (struct DenyConf*) MyMalloc(sizeof(struct DenyConf)); - assert(0 != conf); - memset(conf, 0, sizeof(struct DenyConf)); - - if (fields[1][0] == '$' && fields[1][1] == 'R') - conf->flags |= DENY_FLAGS_REALNAME; - - DupString(conf->hostmask, fields[1]); - collapse(conf->hostmask); - - if (!EmptyString(fields[2])) { - const char* p = fields[2]; - if ('!' == *p) { - conf->flags |= DENY_FLAGS_FILE; - ++p; - } - DupString(conf->message, p); - } - DupString(conf->usermask, fields[3]); - collapse(conf->usermask); - - if (ip_kill) { - /* - * Here we use the same kludge as in listener.c to parse - * a.b.c.d, or a.b.c.*, or a.b.c.d/e. - */ - int c_class; - char ipname[16]; - int ad[4] = { 0 }; - int bits2 = 0; - c_class = sscanf(conf->hostmask, "%d.%d.%d.%d/%d", - &ad[0], &ad[1], &ad[2], &ad[3], &bits2); - if (c_class != 5) { - conf->bits = c_class * 8; - } - else { - conf->bits = bits2; - } - ircd_snprintf(0, ipname, sizeof(ipname), "%d.%d.%d.%d", ad[0], ad[1], - ad[2], ad[3]); - - /* - * This ensures endian correctness - */ - conf->address = inet_addr(ipname); - Debug((DEBUG_DEBUG, "IPkill: %s = %08x/%i (%08x)", ipname, - conf->address, conf->bits, NETMASK(conf->bits))); - conf->flags |= DENY_FLAGS_IP; - } - conf->next = denyConfList; - denyConfList = conf; -} - +/** Free all deny rules from #denyConfList. */ void conf_erase_deny_list(void) { struct DenyConf* next; @@ -905,343 +768,134 @@ void conf_erase_deny_list(void) MyFree(p->hostmask); MyFree(p->usermask); MyFree(p->message); + MyFree(p->realmask); MyFree(p); } denyConfList = 0; } - + +/** Return #denyConfList. + * @return #denyConfList + */ const struct DenyConf* conf_get_deny_list(void) { return denyConfList; } -/* - * read_configuration_file - * - * Read configuration file. - * - * returns 0, if file cannot be opened - * 1, if file read +/** Find any existing quarantine for the named channel. + * @param chname Channel name to search for. + * @return Reason for channel's quarantine, or NULL if none exists. */ +const char* +find_quarantine(const char *chname) +{ + struct qline *qline; -#define MAXCONFLINKS 150 + for (qline = GlobalQuarantineList; qline; qline = qline->next) + if (!ircd_strcmp(qline->chname, chname)) + return qline->reason; + return NULL; +} -int read_configuration_file(void) +/** Free all qline structs from #GlobalQuarantineList. */ +void clear_quarantines(void) { - enum { MAX_FIELDS = 15 }; - - char* src; - char* dest; - int quoted; - FBFILE *file; - char line[512]; - int ccount = 0; - struct ConfItem *aconf = 0; - - int field_count = 0; - const char* field_vector[MAX_FIELDS + 1]; - - Debug((DEBUG_DEBUG, "read_configuration_file: ircd.conf = %s", configfile)); - if (0 == (file = fbopen(configfile, "r"))) { - return 0; + struct qline *qline; + while ((qline = GlobalQuarantineList)) + { + GlobalQuarantineList = qline->next; + MyFree(qline->reason); + MyFree(qline->chname); + MyFree(qline); } +} - feature_unmark(); /* unmark all features for resetting later */ - - while (fbgets(line, sizeof(line) - 1, file)) { - if ('#' == *line || IsSpace(*line)) - continue; - - if ((src = strchr(line, '\n'))) - *src = '\0'; - - if (':' != line[1]) { - Debug((DEBUG_ERROR, "Bad config line: %s", line)); - sendto_opmask_butone(0, SNO_OLDSNO,"Bad Config line"); - continue; - } - - /* - * do escapes, quoting, comments, and field breakup in place - * in one pass with a poor mans state machine - */ - field_vector[0] = line; - field_count = 1; - quoted = 0; - - for (src = line, dest = line; *src; ) { - switch (*src) { - case '\\': - ++src; - switch (*src) { - case 'b': - *dest++ = '\b'; - ++src; - break; - case 'f': - *dest++ = '\f'; - ++src; - break; - case 'n': - *dest++ = '\n'; - ++src; - break; - case 'r': - *dest++ = '\r'; - ++src; - break; - case 't': - *dest++ = '\t'; - ++src; - break; - case 'v': - *dest++ = '\v'; - ++src; - break; - case '\\': - *dest++ = '\\'; - ++src; - break; - case '\0': - break; - default: - *dest++ = *src++; - break; - } - break; - case '"': - if (quoted) - quoted = 0; - else - quoted = 1; - /* - * strip quotes - */ - ++src; - break; - case ':': - if (quoted) - *dest++ = *src++; - else { - *dest++ = '\0'; - field_vector[field_count++] = dest; - if (field_count > MAX_FIELDS) - *src = '\0'; - else - ++src; - } - break; - case '#': - *src = '\0'; - break; - default: - *dest++ = *src++; - break; - } - } - *dest = '\0'; - - if (field_count < 2 || EmptyString(field_vector[0])) - continue; +/** When non-zero, indicates that a configuration error has been seen in this pass. */ +static int conf_error; +/** When non-zero, indicates that the configuration file was loaded at least once. */ +static int conf_already_read; +extern void yyparse(void); +extern int init_lexer(void); +extern void deinit_lexer(void); - if (aconf) - free_conf(aconf); - - aconf = make_conf(); - - switch (*field_vector[0]) { - case 'A': /* Name, e-mail address of administrator */ - 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 */ - ++ccount; - aconf->status = CONF_SERVER; - break; - /* Connect rule */ - case 'D': /* CONF_CRULEALL */ - conf_add_crule(field_vector, field_count, CRULE_ALL); - aconf->status = CONF_ILLEGAL; - break; - /* Connect rule - autos only */ - case 'd': /* CONF_CRULEAUTO */ - conf_add_crule(field_vector, field_count, CRULE_AUTO); - aconf->status = CONF_ILLEGAL; - break; - case 'F': /* Feature line */ - case 'f': - feature_set(0, &field_vector[1], field_count - 1); - aconf->status = CONF_ILLEGAL; - break; - case 'H': /* Hub server line */ - case 'h': - aconf->status = CONF_HUB; - break; - case 'I': /* Just plain normal irc client trying */ - case 'i': /* to connect me */ - aconf->status = CONF_CLIENT; - break; - case 'K': /* Kill user line on irc.conf */ - conf_add_deny(field_vector, field_count, 0); - aconf->status = CONF_ILLEGAL; - break; - case 'k': /* Kill user line based on IP in ircd.conf */ - conf_add_deny(field_vector, field_count, 1); - aconf->status = CONF_ILLEGAL; - break; - /* Operator. Line should contain at least */ - /* password and host where connection is */ - case 'L': /* guaranteed leaf server */ - case 'l': - aconf->status = CONF_LEAF; - break; - /* Me. Host field is name used for this host */ - /* and port number is the number of the port */ - case 'M': - case 'm': /* CONF_ME */ - conf_add_local(field_vector, field_count); - aconf->status = CONF_ILLEGAL; - break; - case 'O': - aconf->status = CONF_OPERATOR; - break; - /* Local Operator, (limited privs --SRB) */ - case 'o': - aconf->status = CONF_LOCOP; - break; - case 'P': /* listen port line */ - 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 - CONF_TLINES */ - motd_add(field_vector[1], field_vector[2]); - aconf->status = CONF_ILLEGAL; - break; - case 'U': /* Underworld server, allowed to hack modes */ - case 'u': /* *Every* server on the net must define the same !!! */ - aconf->status = CONF_UWORLD; - break; - case 'Y': - case 'y': /* CONF_CLASS */ - conf_add_class(field_vector, field_count); - aconf->status = CONF_ILLEGAL; - break; - default: - Debug((DEBUG_ERROR, "Error in config file: %s", line)); - sendto_opmask_butone(0, SNO_OLDSNO, "Unknown prefix in config file: %c", - *field_vector[0]); - aconf->status = CONF_ILLEGAL; - break; - } - if (IsIllegal(aconf)) - continue; +/** Read configuration file. + * @return Zero on failure, non-zero on success. */ +int read_configuration_file(void) +{ + conf_error = 0; + feature_unmark(); /* unmark all features for resetting later */ + clear_nameservers(); /* clear previous list of DNS servers */ + if (!init_lexer()) + return 0; + yyparse(); + deinit_lexer(); + feature_mark(); /* reset unmarked features */ + conf_already_read = 1; + return 1; +} - if (!EmptyString(field_vector[1])) - DupString(aconf->host, field_vector[1]); +/** Report an error message about the configuration file. + * @param msg The error to report. + */ +void +yyerror(const char *msg) +{ + sendto_opmask_butone(0, SNO_ALL, "Config file parse error line %d: %s", + lineno, msg); + log_write(LS_CONFIG, L_ERROR, 0, "Config file parse error line %d: %s", + lineno, msg); + if (!conf_already_read) + fprintf(stderr, "Config file parse error line %d: %s\n", lineno, msg); + conf_error = 1; +} - if (!EmptyString(field_vector[2])) - DupString(aconf->passwd, field_vector[2]); +/** Attach CONF_UWORLD items to a server and everything attached to it. */ +static void +attach_conf_uworld(struct Client *cptr) +{ + struct DLink *lp; - if (field_count > 3 && !EmptyString(field_vector[3])) - DupString(aconf->name, field_vector[3]); + attach_confs_byhost(cptr, cli_name(cptr), CONF_UWORLD); + for (lp = cli_serv(cptr)->down; lp; lp = lp->next) + attach_conf_uworld(lp->value.cptr); +} - if (field_count > 4 && !EmptyString(field_vector[4])) - aconf->port = atoi(field_vector[4]); +/** Free all memory associated with service mapping \a smap. + * @param smap[in] The mapping to free. + */ +void free_mapping(struct s_map *smap) +{ + struct nick_host *nh, *next; + for (nh = smap->services; nh; nh = next) + { + next = nh->next; + MyFree(nh); + } + MyFree(smap->name); + MyFree(smap->command); + MyFree(smap->prepend); + MyFree(smap); +} - if (field_count > 5 && !EmptyString(field_vector[5])) - aconf->conn_class = find_class(atoi(field_vector[5])); +/** Unregister and free all current service mappings. */ +static void close_mappings(void) +{ + struct s_map *map, *next; - /* - * Associate each conf line with a class by using a pointer - * to the correct class record. -avalon - */ - if (aconf->status & CONF_CLIENT_MASK) { - if (aconf->conn_class == 0) - aconf->conn_class = find_class(0); - } - if (aconf->status & CONF_CLIENT) { - struct ConfItem *bconf; - - if ((bconf = find_conf_entry(aconf, aconf->status))) { - delist_conf(bconf); - bconf->status &= ~CONF_ILLEGAL; - if (aconf->status == CONF_CLIENT) { - /* - * copy the password field in case it changed - */ - MyFree(bconf->passwd); - bconf->passwd = aconf->passwd; - aconf->passwd = 0; - - ConfLinks(bconf) -= bconf->clients; - bconf->conn_class = aconf->conn_class; - if (bconf->conn_class) - ConfLinks(bconf) += bconf->clients; - } - free_conf(aconf); - aconf = bconf; - } - } - if (aconf->status & CONF_SERVER) { - if (ccount > MAXCONFLINKS || !aconf->host || strchr(aconf->host, '*') || - strchr(aconf->host, '?') || !aconf->name) - continue; - } - if (aconf->status & (CONF_LOCOP | CONF_OPERATOR)) { - if (!strchr(aconf->host, '@')) { - char* newhost; - int len = 3; /* *@\0 = 3 */ - - len += strlen(aconf->host); - newhost = (char*) MyMalloc(len); - assert(0 != newhost); - ircd_snprintf(0, newhost, len, "*@%s", aconf->host); - MyFree(aconf->host); - aconf->host = newhost; - } - } - if (aconf->status & CONF_SERVER) { - if (EmptyString(aconf->passwd)) - continue; - lookup_confhost(aconf); - } - /* - * Juped nicks are listed in the 'password' field of U:lines, - * the list is comma separated and might be empty and/or contain - * empty elements... the only limit is that it MUST be shorter - * than 512 chars, or they will be cutted out :) - */ - if ((aconf->status == CONF_UWORLD) && (aconf->passwd) && (*aconf->passwd)) - addNickJupes(aconf->passwd); - - collapse(aconf->host); - collapse(aconf->name); - Debug((DEBUG_NOTICE, - "Read Init: (%d) (%s) (%s) (%s) (%u) (%p)", - aconf->status, aconf->host, aconf->passwd, - aconf->name, aconf->port, aconf->conn_class)); - aconf->next = GlobalConfList; - GlobalConfList = aconf; - aconf = NULL; + for (map = GlobalServiceMapList; map; map = next) { + next = map->next; + unregister_mapping(map); + free_mapping(map); } - if (aconf) - free_conf(aconf); - fbclose(file); -/* nextping = nextconnect = CurrentTime; */ - feature_mark(); /* reset unmarked features */ - return 1; + GlobalServiceMapList = NULL; } -/* - * 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. +/** Reload the configuration file. + * @param cptr Client that requested rehash (if a signal, &me). + * @param sig Type of rehash (0 = oper-requested, 1 = signal, 2 = + * oper-requested but do not restart resolver) + * @return CPTR_KILLED if any client was K/G-lined because of the + * rehash; otherwise 0. */ int rehash(struct Client *cptr, int sig) { @@ -1286,16 +940,21 @@ int rehash(struct Client *cptr, int sig) */ clearNickJupes(); - if (sig != 2) - flush_resolver_cache(); + clear_quarantines(); class_mark_delete(); mark_listeners_closing(); + auth_mark_closing(); + close_mappings(); read_configuration_file(); + if (sig != 2) + restart_resolver(); + log_reopen(); /* reopen log files */ + auth_close_unused(); close_listeners(); class_delete_marked(); /* unless it fails */ @@ -1312,15 +971,12 @@ int rehash(struct Client *cptr, int sig) else tmp = &tmp2->next; } + 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, cli_name(acptr), - CONF_HUB | CONF_LEAF | CONF_UWORLD); - } + if (IsServer(acptr)) + det_confs_butmask(acptr, ~(CONF_UWORLD | CONF_ILLEGAL)); /* 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. @@ -1329,24 +985,22 @@ int rehash(struct Client *cptr, int sig) 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)); + IsUnknown(acptr) ? "Unregistered Client ":"", + get_client_name(acptr, SHOW_IP)); if (exit_client(cptr, acptr, &me, found_g == -2 ? "G-lined" : "K-lined") == CPTR_KILLED) ret = CPTR_KILLED; } } } + + attach_conf_uworld(&me); + return ret; } -/* - * init_conf - * - * Read configuration file. - * - * returns 0, if file cannot be opened - * 1, if file read +/** Read configuration file for the very first time. + * @return Non-zero on success, zero on failure. */ int init_conf(void) @@ -1360,6 +1014,8 @@ int init_conf(void) */ if (0 == localConf.name || 0 == localConf.numeric) return 0; + if (conf_error) + return 0; if (0 == localConf.location1) DupString(localConf.location1, ""); @@ -1367,22 +1023,17 @@ int init_conf(void) DupString(localConf.location2, ""); if (0 == localConf.contact) DupString(localConf.contact, ""); - + return 1; } return 0; } -/* - * find_kill - * input: - * client pointer - * returns: - * 0: Client may continue to try and connect - * -1: Client was K/k:'d - sideeffect: reason was sent. - * -2: Client was G/g:'d - sideeffect: reason was sent. - * sideeffects: - * Client may have been sent a reason why they are denied, as above. +/** Searches for a K/G-line for a client. If one is found, notify the + * user and disconnect them. + * @param cptr Client to search for. + * @return 0 if client is accepted; -1 if client was locally denied + * (K-line); -2 if client was globally denied (G-line). */ int find_kill(struct Client *cptr) { @@ -1409,25 +1060,16 @@ int find_kill(struct Client *cptr) * -- Isomer */ for (deny = denyConfList; deny; deny = deny->next) { - if (0 != match(deny->usermask, name)) + if (deny->usermask && match(deny->usermask, name)) + continue; + if (deny->realmask && match(deny->realmask, realname)) + continue; + if (deny->bits > 0) { + if (!ipmask_check(&cli_ip(cptr), &deny->address, deny->bits)) + continue; + } else if (deny->hostmask && match(deny->hostmask, host)) continue; - if (EmptyString(deny->hostmask)) - break; - - if (deny->flags & DENY_FLAGS_REALNAME) { /* K: by real name */ - if (0 == match(deny->hostmask + 2, realname)) - break; - } else if (deny->flags & DENY_FLAGS_IP) { /* k: by IP */ - Debug((DEBUG_DEBUG, "ip: %08x network: %08x/%i mask: %08x", - cli_ip(cptr).s_addr, deny->address, deny->bits, NETMASK(deny->bits))); - if ((cli_ip(cptr).s_addr & NETMASK(deny->bits)) == deny->address) - break; - } - else if (0 == match(deny->hostmask, host)) - break; - } - if (deny) { if (EmptyString(deny->message)) send_reply(cptr, SND_EXPLICIT | ERR_YOUREBANNEDCREEP, ":Connection from your host is refused on this server."); @@ -1437,35 +1079,30 @@ int find_kill(struct Client *cptr) else send_reply(cptr, SND_EXPLICIT | ERR_YOUREBANNEDCREEP, ":%s.", deny->message); } + return -1; } - else if ((agline = gline_lookup(cptr, 0)) && GlineIsActive(agline)) { + + if (!feature_bool(FEAT_DISABLE_GLINES) && (agline = gline_lookup(cptr, 0))) { /* * find active glines * added a check against the user's IP address to find_gline() -Kev */ send_reply(cptr, SND_EXPLICIT | ERR_YOUREBANNEDCREEP, ":%s.", GlineReason(agline)); + return -2; } - else - agline = 0; /* if a gline was found, it was inactive */ - if (deny) - return -1; - if (agline) - return -2; - return 0; } -/* - * Ordinary client access check. Look for conf lines which have the same - * status as the flags passed. +/** Attempt to attach Client blocks to \a cptr. If attach_iline() + * fails for the client, emit a debugging message. + * @param cptr Client to check for access. + * @return Access check result. */ enum AuthorizationCheckResult conf_check_client(struct Client *cptr) { enum AuthorizationCheckResult acr = ACR_OK; - ClearAccess(cptr); - if ((acr = attach_iline(cptr))) { Debug((DEBUG_DNS, "ch_cl: access denied: %s[%s]", cli_name(cptr), cli_sockhost(cptr))); @@ -1474,19 +1111,13 @@ enum AuthorizationCheckResult conf_check_client(struct Client *cptr) return ACR_OK; } -/* - * check_server() - * - * Check access for a server given its name (passed in cptr struct). +/** Check access for a server given its name (passed in cptr struct). * Must check for all C/N lines which have a name which matches the * name given and a host which matches. A host alias which is the * same as the server name is also acceptable in the host field of a * C/N line. - * - * Returns - * 0 = Success - * -1 = Access denied - * -2 = Bad socket. + * @param cptr Peer server to check. + * @return 0 if accepted, -1 if access denied. */ int conf_check_server(struct Client *cptr) { @@ -1509,76 +1140,47 @@ int conf_check_server(struct Client *cptr) if (IsConnecting(cptr) || IsHandshake(cptr)) { c_conf = find_conf_byname(lp, cli_name(cptr), CONF_SERVER); if (!c_conf) { - sendto_opmask_butone(0, SNO_OLDSNO, "Connect Error: lost C:line for %s", + sendto_opmask_butone(0, SNO_OLDSNO, + "Connect Error: lost Connect block for %s", cli_name(cptr)); det_confs_butmask(cptr, 0); return -1; } } - ClearAccess(cptr); + /* Try finding the Connect block by DNS name and IP next. */ + if (!c_conf && !(c_conf = find_conf_byhost(lp, cli_sockhost(cptr), CONF_SERVER))) + c_conf = find_conf_byip(lp, &cli_ip(cptr), CONF_SERVER); - if (!c_conf) { - if (cli_dns_reply(cptr)) { - int i; - struct hostent* hp = cli_dns_reply(cptr)->hp; - const char* name = hp->h_name; - /* - * If we are missing a C or N line from above, search for - * it under all known hostnames we have for this ip#. - */ - for (i = 0; name; name = hp->h_aliases[i++]) { - if ((c_conf = find_conf_byhost(lp, name, CONF_SERVER))) { - ircd_strncpy(cli_sockhost(cptr), name, HOSTLEN); - break; - } - } - if (!c_conf) { - for (i = 0; hp->h_addr_list[i]; i++) { - if ((c_conf = find_conf_byip(lp, hp->h_addr_list[i], CONF_SERVER))) - break; - } - } - } - else { - /* - * Check for C lines with the hostname portion the ip number - * of the host the server runs on. This also checks the case where - * there is a server connecting from 'localhost'. - */ - c_conf = find_conf_byhost(lp, cli_sockhost(cptr), CONF_SERVER); - } - } /* * Attach by IP# only if all other checks have failed. * It is quite possible to get here with the strange things that can * happen when using DNS in the way the irc server does. -avalon */ if (!c_conf) - c_conf = find_conf_byip(lp, (const char*) &(cli_ip(cptr)), CONF_SERVER); + c_conf = find_conf_byip(lp, &cli_ip(cptr), CONF_SERVER); /* * detach all conf lines that got attached by attach_confs() */ det_confs_butmask(cptr, 0); /* - * if no C or no N lines, then deny access + * if no Connect block, then deny access */ if (!c_conf) { Debug((DEBUG_DNS, "sv_cl: access denied: %s[%s@%s]", cli_name(cptr), cli_username(cptr), cli_sockhost(cptr))); return -1; } - ircd_strncpy(cli_name(cptr), c_conf->name, HOSTLEN); /* - * attach the C and N lines to the client structure for later use. + * attach the Connect block to the client structure for later use. */ attach_conf(cptr, c_conf); - attach_confs_byname(cptr, cli_name(cptr), CONF_HUB | CONF_LEAF | CONF_UWORLD); - if (INADDR_NONE == c_conf->ipnum.s_addr) - c_conf->ipnum.s_addr = cli_ip(cptr).s_addr; + if (!irc_in_addr_valid(&c_conf->address.addr)) + memcpy(&c_conf->address.addr, &cli_ip(cptr), sizeof(c_conf->address.addr)); - Debug((DEBUG_DNS, "sv_cl: access ok: %s[%s]", cli_name(cptr), cli_sockhost(cptr))); + Debug((DEBUG_DNS, "sv_cl: access ok: %s[%s]", + cli_name(cptr), cli_sockhost(cptr))); return 0; }