X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=ircd%2Fs_conf.c;h=b0547819c4cc22fa4aa0bcbffd1470be8e050076;hb=ae91ef6320f611af74e70a0db2620c338fbaa7d5;hp=05da98d91375036aacfefca511e2a92a8e02b86c;hpb=eeff5dd006459c6c56f025f13852fdafb2961339;p=ircu2.10.12-pk.git diff --git a/ircd/s_conf.c b/ircd/s_conf.c index 05da98d..b054781 100644 --- a/ircd/s_conf.c +++ b/ircd/s_conf.c @@ -16,84 +16,361 @@ * 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$ */ +#include "s_conf.h" +#include "IPcheck.h" +#include "class.h" +#include "client.h" +#include "crule.h" +#include "fileio.h" +#include "gline.h" +#include "hash.h" +#include "ircd.h" +#include "ircd_alloc.h" +#include "ircd_chattr.h" +#include "ircd_log.h" +#include "ircd_string.h" +#include "list.h" +#include "listener.h" +#include "match.h" +#include "numeric.h" +#include "numnicks.h" +#include "opercmds.h" +#include "parse.h" +#include "res.h" +#include "s_bsd.h" +#include "s_debug.h" +#include "s_misc.h" +#include "send.h" +#include "sprintf_irc.h" +#include "struct.h" +#include "support.h" #include "sys.h" -#include -#if HAVE_FCNTL_H + +#include +#include +#include #include -#endif +#include +#include +#include +#include +#include +#include -#if HAVE_SYS_WAIT_H -# include -#endif -#ifndef WEXITSTATUS -# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) -#endif -#ifndef WIFEXITED -# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#ifndef INADDR_NONE +#define INADDR_NONE 0xffffffff #endif -#include -#ifdef R_LINES -#include -#endif -#if HAVE_UNISTD_H -#include +struct ConfItem* GlobalConfList = 0; +int GlobalConfCount = 0; +struct MotdItem* motd = NULL; +struct MotdItem* rmotd = NULL; +struct TRecord* tdata = NULL; +struct tm motd_tm; + + +/* + * is the K line field an interval or a comment? - Mmmm + */ +static int is_comment(const char *comment) +{ + size_t i; + size_t len = strlen(comment); + for (i = 0; i < len; ++i) { + if (!IsKTimeChar(comment[i])) + return 1; + } + return 0; +} + +/* + * check against a set of time intervals + */ +static int check_time_interval(char *interval, char *reply) +{ + struct tm* tptr; + char* p; + int perm_min_hours; + int perm_min_minutes; + int perm_max_hours; + int perm_max_minutes; + int nowm; + int perm_min; + int perm_max; + + tptr = localtime(&CurrentTime); + nowm = tptr->tm_hour * 60 + tptr->tm_min; + + while (interval) { + p = strchr(interval, ','); + if (p) + *p = '\0'; + if (sscanf(interval, "%2d%2d-%2d%2d", &perm_min_hours, &perm_min_minutes, + &perm_max_hours, &perm_max_minutes) != 4) + { + if (p) + *p = ','; + return 0; + } + if (p) + *(p++) = ','; + perm_min = 60 * perm_min_hours + perm_min_minutes; + perm_max = 60 * perm_max_hours + perm_max_minutes; + /* + * The following check allows intervals over midnight ... + */ + if ((perm_min < perm_max) + ? (perm_min <= nowm && nowm <= perm_max) + : (perm_min <= nowm || nowm <= perm_max)) + { + sprintf_irc(reply, ":%%s %%d %%s :%s %d:%02d to %d:%02d.", + "You are not allowed to connect from", + perm_min_hours, perm_min_minutes, + perm_max_hours, perm_max_minutes); + return (ERR_YOUREBANNEDCREEP); + } + if ((perm_min < perm_max) + ? (perm_min <= nowm + 5 && nowm + 5 <= perm_max) + : (perm_min <= nowm + 5 || nowm + 5 <= perm_max)) + { + sprintf_irc(reply, ":%%s %%d %%s :%d minute%s%s", + perm_min - nowm, (perm_min - nowm) > 1 ? "s " : " ", + "and you will be denied for further access"); + return (ERR_YOUWILLBEBANNED); + } + interval = p; + } + return 0; +} + +/* + * output the reason for being k lined from a file - Mmmm + * sptr is server + * parv is the sender prefix + * filename is the file that is to be output to the K lined client + */ +static void killcomment(struct Client *sptr, char *parv, char *filename) +{ + FBFILE* file = NULL; + char line[80]; + char* tmp; + struct stat sb; + struct tm* tm; + + if (NULL == (file = fbopen(filename, "r"))) { + sendto_one(sptr, err_str(ERR_NOMOTD), me.name, parv); + sendto_one(sptr, + ":%s %d %s :Connection from your host is refused on this server.", + me.name, ERR_YOUREBANNEDCREEP, parv); + return; + } + fbstat(&sb, file); + tm = localtime((time_t*) &sb.st_mtime); /* NetBSD needs cast */ + while (fbgets(line, sizeof(line) - 1, file)) { + if ((tmp = strchr(line, '\n'))) + *tmp = '\0'; + if ((tmp = strchr(line, '\r'))) + *tmp = '\0'; + /* sendto_one(sptr, + * ":%s %d %s : %s.", + * me.name, ERR_YOUREBANNEDCREEP, parv,line); */ + sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv, line); + } + sendto_one(sptr, + ":%s %d %s :Connection from your host is refused on this server.", + me.name, ERR_YOUREBANNEDCREEP, parv); + fbclose(file); +} + +struct ConfItem* make_conf(void) +{ + struct ConfItem* aconf; + + aconf = (struct ConfItem*) MyMalloc(sizeof(struct ConfItem)); + assert(0 != aconf); +#ifdef DEBUGMODE + ++GlobalConfCount; #endif -#include -#include -#include -#include -#ifdef USE_SYSLOG -#include + aconf->status = CONF_ILLEGAL; + aconf->clients = 0; + aconf->ipnum.s_addr = INADDR_NONE; + aconf->host = 0; + aconf->passwd = 0; + aconf->name = 0; + aconf->port = 0; + aconf->hold = 0; + aconf->dns_pending = 0; + aconf->confClass = 0; + aconf->next = 0; + 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 = NULL; +} + +void free_conf(struct ConfItem *aconf) +{ + Debug((DEBUG_DEBUG, "free_conf: %s %s %d", + aconf->host ? aconf->host : "*", + aconf->name ? aconf->name : "*", + aconf->port)); + if (aconf->dns_pending) + delete_resolver_queries(aconf); + MyFree(aconf->host); + if (aconf->passwd) + memset(aconf->passwd, 0, strlen(aconf->passwd)); + MyFree(aconf->passwd); + MyFree(aconf->name); + MyFree(aconf); +#ifdef DEBUGMODE + --GlobalConfCount; #endif -#include "h.h" -#include "struct.h" -#include "s_serv.h" -#include "opercmds.h" -#include "numeric.h" -#include "send.h" -#include "s_conf.h" -#include "class.h" -#include "s_misc.h" -#include "match.h" -#include "common.h" -#include "s_err.h" -#include "s_bsd.h" -#include "ircd.h" -#include "crule.h" -#include "res.h" -#include "support.h" -#include "parse.h" -#include "numnicks.h" -#include "sprintf_irc.h" -#include "IPcheck.h" -#include "hash.h" -#include "fileio.h" +} -RCSTAG_CC("$Id$"); +/* + * 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 + */ +static void conf_dns_callback(void* vptr, struct DNSReply* reply) +{ + struct ConfItem* aconf = (struct ConfItem*) vptr; + aconf->dns_pending = 0; + if (reply) + memcpy(&aconf->ipnum, reply->hp->h_addr, sizeof(struct in_addr)); +} -static int check_time_interval(char *, char *); -static int lookup_confhost(aConfItem *); -static int is_comment(char *); -static void killcomment(aClient *sptr, char *parv, char *filename); +/* + * 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 + */ +static struct DNSReply* 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; + } + 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. + */ +static 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; + } + /* + * 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 + */ + aconf->ipnum.s_addr = inet_addr(aconf->host); + if (INADDR_NONE == aconf->ipnum.s_addr) { + Debug((DEBUG_ERROR, "Host/server name error: (%s) (%s)", + aconf->host, aconf->name)); + } + } + else if ((reply = conf_dns_lookup(aconf))) + memcpy(&aconf->ipnum, reply->hp->h_addr, sizeof(struct in_addr)); +} + +/* + * 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) + */ +struct ConfItem* conf_find_server(const char* name) +{ + struct ConfItem* conf; + assert(0 != name); + + for (conf = GlobalConfList; conf; conf = conf->next) { + if (CONF_SERVER == conf->status) { + /* + * Check first servernames, then try hostnames. + * XXX - match returns 0 if there _is_ a match... guess they + * haven't decided what true is yet + */ + if (0 == match(name, conf->name)) + return conf; + } + } + 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 (CRULEALL) not d lines (CRULEAUTO). + */ +const char* conf_eval_crule(struct ConfItem* conf) +{ + struct ConfItem* rule; + assert(0 != conf); + + for (rule = GlobalConfList; rule; rule = rule->next) { + if ((CONF_CRULEALL == rule->status) && (0 == match(rule->host, conf->name))) { + if (crule_eval(rule->passwd)) + return rule->name; + } + } + return 0; +} -aConfItem *conf = NULL; -aGline *gline = NULL; -aGline *badchan = NULL; -aMotdItem *motd = NULL; -aMotdItem *rmotd = NULL; -atrecord *tdata = NULL; -struct tm motd_tm; /* * field breakup for ircd.conf file. */ -static char *gfline = NULL; -char *getfield(char *newline, char fs) +static char* getfield(char* newline, char fs) { - char *end, *field; + static char* gfline = NULL; + char* end; + char* field; if (newline) gfline = newline; @@ -103,29 +380,23 @@ char *getfield(char *newline, char fs) end = field = gfline; - if (fs != ':') - { + if (fs != ':') { if (*end == fs) ++end; else fs = ':'; } - do - { - while (*end != fs) - { - if (!*end) - { - end = NULL; - break; + do { + while (*end != fs) { + if (!*end) { + end = NULL; + break; } ++end; } - } - while (end && fs != ':' && *++end != ':' && *end != '\n'); + } while (end && fs != ':' && *++end != ':' && *end != '\n') ; - if (end == NULL) - { + if (end == NULL) { gfline = NULL; if ((end = strchr(field, '\n')) == NULL) end = field + strlen(field); @@ -142,12 +413,11 @@ char *getfield(char *newline, char fs) * Remove all conf entries from the client except those which match * the status field mask. */ -void det_confs_butmask(aClient *cptr, int mask) +void det_confs_butmask(struct Client *cptr, int mask) { - Reg1 Link *tmp, *tmp2; + struct SLink *tmp, *tmp2; - for (tmp = cptr->confs; tmp; tmp = tmp2) - { + for (tmp = cptr->confs; tmp; tmp = tmp2) { tmp2 = tmp->next; if ((tmp->value.aconf->status & mask) == 0) detach_conf(cptr, tmp->value.aconf); @@ -155,192 +425,184 @@ void det_confs_butmask(aClient *cptr, int mask) } /* - * Find the first (best) I line to attach. + * 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 */ -enum AuthorizationCheckResult attach_Iline(aClient *cptr, struct hostent *hp, - char *sockhost) +static int validate_hostent(struct hostent* hp) { - Reg1 aConfItem *aconf; - Reg3 const char *hname; - Reg4 int i; - static char uhost[HOSTLEN + USERLEN + 3]; - static char fullname[HOSTLEN + 1]; + char fullname[HOSTLEN + 1]; + int i = 0; + int error = 0; + const char* hname; - for (aconf = conf; aconf; aconf = aconf->next) - { + for (hname = hp->h_name; hname; hname = hp->h_aliases[i++]) { + size_t fullnamelen = 0; + size_t 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 + */ +static int check_limit_and_attach(struct Client* cptr, struct ConfItem* aconf) +{ + if (aconf->passwd) { + /* Special case: exactly one digit */ + if (IsDigit(*aconf->passwd) && !aconf->passwd[1]) { + /* + * Refuse connections when there are already + * clients connected with the same IP number + */ + unsigned short nr = *aconf->passwd - '0'; + if (IPcheck_nr(cptr) > nr) + return ACR_TOO_MANY_FROM_IP; /* Already got nr with that ip# */ + } +#ifdef USEONE + else if (0 == strcmp(aconf->passwd, "ONE")) { + int i; + for (i = HighestFd; i > -1; --i) { + if (LocalClientArray[i] && MyUser(LocalClientArray[i]) && + LocalClientArray[i]->ip.s_addr == cptr->ip.s_addr) + return ACR_TOO_MANY_FROM_IP; /* Already got one with that ip# */ + } + } +#endif + } + return attach_conf(cptr, aconf); +} + +/* + * Find the first (best) I line to attach. + */ +int 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; + + 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; - if (aconf->port && aconf->port != cptr->acpt->port) + if (aconf->port && aconf->port != cptr->listener->port) continue; if (!aconf->host || !aconf->name) continue; - if (hp) - for (i = 0, hname = hp->h_name; hname; hname = hp->h_aliases[i++]) - { - size_t fullnamelen = 0; - size_t label_count = 0; - int error; - - 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 == '.') - { - if (p[-1] == '-' /* Label may not end on '-' */ - || p[1] == 0) /* May not end on a '.' */ - { - 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') - { - error = 1; /* In case this is top domain */ - continue; - } - if (!(*p >= 'a' && *p <= 'z') - && !(*p >= 'A' && *p <= 'Z') && *p != '-') - { - error = 1; - break; - } - } - } - if (error) - { - hp = NULL; - break; - } - - add_local_domain(fullname, HOSTLEN - fullnamelen); - Debug((DEBUG_DNS, "a_il: %s->%s", sockhost, fullname)); - if (strchr(aconf->name, '@')) - { - strcpy(uhost, cptr->username); - strcat(uhost, "@"); - } - else - *uhost = '\0'; - strncat(uhost, fullname, sizeof(uhost) - 1 - strlen(uhost)); - uhost[sizeof(uhost) - 1] = 0; - if (!match(aconf->name, uhost)) - { - if (strchr(uhost, '@')) - cptr->flags |= FLAGS_DOID; - goto attach_iline; - } + if (hp) { + for (i = 0, hname = hp->h_name; hname; hname = hp->h_aliases[i++]) { + ircd_strncpy(fullname, hname, HOSTLEN); + fullname[HOSTLEN] = '\0'; + + Debug((DEBUG_DNS, "a_il: %s->%s", cptr->sockhost, fullname)); + + if (strchr(aconf->name, '@')) { + strcpy(uhost, cptr->username); + strcat(uhost, "@"); + } + 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, '@')) + cptr->flags |= FLAGS_DOID; + return check_limit_and_attach(cptr, aconf); + } } - - if (strchr(aconf->host, '@')) - { - strncpy(uhost, cptr->username, sizeof(uhost) - 2); + } + if (strchr(aconf->host, '@')) { + ircd_strncpy(uhost, cptr->username, sizeof(uhost) - 2); uhost[sizeof(uhost) - 2] = 0; strcat(uhost, "@"); } else *uhost = '\0'; - strncat(uhost, sockhost, sizeof(uhost) - 1 - strlen(uhost)); + strncat(uhost, cptr->sock_ip, sizeof(uhost) - 1 - strlen(uhost)); uhost[sizeof(uhost) - 1] = 0; if (match(aconf->host, uhost)) continue; if (strchr(uhost, '@')) cptr->flags |= FLAGS_DOID; - if (hp && hp->h_name) - { - strncpy(uhost, hp->h_name, HOSTLEN); - uhost[HOSTLEN] = 0; - add_local_domain(uhost, HOSTLEN - strlen(uhost)); - } - attach_iline: - get_sockhost(cptr, uhost); - if (aconf->passwd) - { - if (isDigit(*aconf->passwd) && !aconf->passwd[1]) /* Special case: exactly one digit */ - { - /* Refuse connections when there are already clients connected with the same IP number */ - unsigned short nr = *aconf->passwd - '0'; - if (IPcheck_nr(cptr) > nr) - return ACR_TOO_MANY_FROM_IP; /* Already got nr with that ip# */ - } -#ifdef USEONE - else if (!strcmp(aconf->passwd, "ONE")) - { - for (i = highest_fd; i >= 0; i--) - if (loc_clients[i] && MyUser(loc_clients[i]) && - loc_clients[i]->ip.s_addr == cptr->ip.s_addr) - return ACR_TOO_MANY_FROM_IP; /* Already got one with that ip# */ - } -#endif - } - return attach_conf(cptr, aconf); + return check_limit_and_attach(cptr, aconf); } return ACR_NO_AUTHORIZATION; } /* - * Find the single N line and return pointer to it (from list). - * If more than one then return NULL pointer. + * detach_conf - Disassociate configuration from the client. */ -aConfItem *count_cnlines(Link *lp) +int detach_conf(struct Client *cptr, struct ConfItem *aconf) { - Reg1 aConfItem *aconf, *cline = NULL, *nline = NULL; + struct SLink** lp; + struct SLink* tmp; - for (; lp; lp = lp->next) - { - aconf = lp->value.aconf; - if (!(aconf->status & CONF_SERVER_MASK)) - continue; - if (aconf->status == CONF_CONNECT_SERVER && !cline) - cline = aconf; - else if (aconf->status == CONF_NOCONNECT_SERVER && !nline) - nline = aconf; - } - return nline; -} - -/* - * detach_conf - * - * Disassociate configuration from the client. - */ -int detach_conf(aClient *cptr, aConfItem *aconf) -{ - Reg1 Link **lp, *tmp; + assert(0 != aconf); + assert(0 != cptr); + assert(0 < aconf->clients); lp = &(cptr->confs); - while (*lp) - { - if ((*lp)->value.aconf == aconf) - { - if (aconf && (aconf->confClass) - && (aconf->status & CONF_CLIENT_MASK) && ConfLinks(aconf) > 0) - --ConfLinks(aconf); - if (aconf && !--aconf->clients && IsIllegal(aconf)) - free_conf(aconf); + while (*lp) { + if ((*lp)->value.aconf == aconf) { + if (aconf->confClass && (aconf->status & CONF_CLIENT_MASK) && + ConfLinks(aconf) > 0) + --ConfLinks(aconf); + if (0 == --aconf->clients && IsIllegal(aconf)) + free_conf(aconf); tmp = *lp; *lp = tmp->next; free_link(tmp); @@ -352,9 +614,9 @@ int detach_conf(aClient *cptr, aConfItem *aconf) return -1; } -static int is_attached(aConfItem *aconf, aClient *cptr) +static int is_attached(struct ConfItem *aconf, struct Client *cptr) { - Reg1 Link *lp; + struct SLink *lp; for (lp = cptr->confs; lp; lp = lp->next) if (lp->value.aconf == aconf) @@ -371,9 +633,9 @@ static int is_attached(aConfItem *aconf, aClient *cptr) * connection). Note, that this automaticly changes the * attachment if there was an old one... */ -enum AuthorizationCheckResult attach_conf(aClient *cptr, aConfItem *aconf) +int attach_conf(struct Client *cptr, struct ConfItem *aconf) { - Reg1 Link *lp; + struct SLink *lp; if (is_attached(aconf, cptr)) return ACR_ALREADY_AUTHORIZED; @@ -381,119 +643,113 @@ enum AuthorizationCheckResult attach_conf(aClient *cptr, aConfItem *aconf) return ACR_NO_AUTHORIZATION; if ((aconf->status & (CONF_LOCOP | CONF_OPERATOR | CONF_CLIENT)) && ConfLinks(aconf) >= ConfMaxLinks(aconf) && ConfMaxLinks(aconf) > 0) - return ACR_TOO_MANY_IN_CLASS; /* Use this for printing error message */ + return ACR_TOO_MANY_IN_CLASS; /* Use this for printing error message */ lp = make_link(); lp->next = cptr->confs; lp->value.aconf = aconf; cptr->confs = lp; - aconf->clients++; + ++aconf->clients; if (aconf->status & CONF_CLIENT_MASK) ConfLinks(aconf)++; return ACR_OK; } -aConfItem *find_admin(void) +struct ConfItem *find_admin(void) { - Reg1 aConfItem *aconf; + struct ConfItem *aconf; - for (aconf = conf; aconf; aconf = aconf->next) + for (aconf = GlobalConfList; aconf; aconf = aconf->next) { if (aconf->status & CONF_ADMIN) break; - - return (aconf); + } + return aconf; } -aConfItem *find_me(void) +struct ConfItem* find_me(void) { - Reg1 aConfItem *aconf; - for (aconf = conf; aconf; aconf = aconf->next) + struct ConfItem* aconf; + for (aconf = GlobalConfList; aconf; aconf = aconf->next) { if (aconf->status & CONF_ME) break; - - return (aconf); + } + return aconf; } /* - * attach_confs + * 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:*::*. */ -aConfItem *attach_confs(aClient *cptr, const char *name, int statmask) +struct ConfItem* attach_confs_byname(struct Client* cptr, const char* name, + int statmask) { - Reg1 aConfItem *tmp; - aConfItem *first = NULL; - int len = strlen(name); + struct ConfItem* tmp; + struct ConfItem* first = NULL; - if (!name || len > HOSTLEN) - return NULL; - for (tmp = conf; tmp; tmp = tmp->next) - { - if ((tmp->status & statmask) && !IsIllegal(tmp) && - ((tmp->status & (CONF_SERVER_MASK | CONF_HUB)) == 0) && - tmp->name && !match(tmp->name, name)) - { - if (attach_conf(cptr, tmp) == ACR_OK && !first) - first = tmp; - } - else if ((tmp->status & statmask) && !IsIllegal(tmp) && - (tmp->status & (CONF_SERVER_MASK | CONF_HUB)) && - tmp->name && !strCasediff(tmp->name, name)) - { - if (attach_conf(cptr, tmp) == ACR_OK && !first) - first = tmp; + assert(0 != name); + + if (HOSTLEN < strlen(name)) + return 0; + + for (tmp = GlobalConfList; tmp; tmp = tmp->next) { + if (0 != (tmp->status & statmask) && !IsIllegal(tmp)) { + assert(0 != tmp->name); + if (0 == match(tmp->name, name) || 0 == ircd_strcmp(tmp->name, name)) { + if (ACR_OK == attach_conf(cptr, tmp) && !first) + first = tmp; + } } } - return (first); + return first; } /* * Added for new access check meLazy */ -aConfItem *attach_confs_host(aClient *cptr, char *host, int statmask) +struct ConfItem* attach_confs_byhost(struct Client* cptr, const char* host, + int statmask) { - Reg1 aConfItem *tmp; - aConfItem *first = NULL; - int len = strlen(host); + struct ConfItem* tmp; + struct ConfItem* first = 0; - if (!host || len > HOSTLEN) - return NULL; + assert(0 != host); + if (HOSTLEN < strlen(host)) + return 0; - for (tmp = conf; tmp; tmp = tmp->next) - { - if ((tmp->status & statmask) && !IsIllegal(tmp) && - (tmp->status & CONF_SERVER_MASK) == 0 && - (!tmp->host || match(tmp->host, host) == 0)) - { - if (attach_conf(cptr, tmp) == ACR_OK && !first) - first = tmp; - } - else if ((tmp->status & statmask) && !IsIllegal(tmp) && - (tmp->status & CONF_SERVER_MASK) && - (tmp->host && strCasediff(tmp->host, host) == 0)) - { - if (attach_conf(cptr, tmp) == ACR_OK && !first) - first = tmp; + for (tmp = GlobalConfList; tmp; tmp = tmp->next) { + if (0 != (tmp->status & statmask) && !IsIllegal(tmp)) { + assert(0 != tmp->host); + if (0 == match(tmp->host, host) || 0 == ircd_strcmp(tmp->host, host)) { + if (ACR_OK == attach_conf(cptr, tmp) && !first) + first = tmp; + } } } - return (first); + return first; } /* * find a conf entry which matches the hostname and has the same name. */ -aConfItem *find_conf_exact(char *name, char *user, char *host, int statmask) +struct ConfItem* find_conf_exact(const char* name, const char* user, + const char* host, int statmask) { - Reg1 aConfItem *tmp; + struct ConfItem *tmp; char userhost[USERLEN + HOSTLEN + 3]; - sprintf_irc(userhost, "%s@%s", user, host); + /* + * XXX - buffer overflow possible, unchecked variables + */ + if (user) + sprintf_irc(userhost, "%s@%s", user, host); + else + ircd_strncpy(userhost, host, sizeof(userhost) - 1); - for (tmp = conf; tmp; tmp = tmp->next) - { + for (tmp = GlobalConfList; tmp; tmp = tmp->next) { if (!(tmp->status & statmask) || !tmp->name || !tmp->host || - strCasediff(tmp->name, name)) + 0 != ircd_strcmp(tmp->name, name)) continue; /* * Accept if the *real* hostname (usually sockecthost) @@ -502,59 +758,59 @@ aConfItem *find_conf_exact(char *name, char *user, char *host, int statmask) */ if (match(tmp->host, userhost)) continue; - if (tmp->status & (CONF_OPERATOR | CONF_LOCOP)) - { + if (tmp->status & (CONF_OPERATOR | CONF_LOCOP)) { if (tmp->clients < MaxLinks(tmp->confClass)) - return tmp; + return tmp; else - continue; + continue; } else return tmp; } - return NULL; + return 0; } -aConfItem *find_conf(Link *lp, const char *name, int statmask) +struct ConfItem* find_conf_byname(struct SLink* lp, const char* name, + int statmask) { - Reg1 aConfItem *tmp; - int namelen = name ? strlen(name) : 0; + struct ConfItem* tmp; + assert(0 != name); - if (namelen > HOSTLEN) - return (aConfItem *)0; + if (HOSTLEN < strlen(name)) + return 0; - for (; lp; lp = lp->next) - { + for (; lp; lp = lp->next) { tmp = lp->value.aconf; - if ((tmp->status & statmask) && - (((tmp->status & (CONF_SERVER_MASK | CONF_HUB)) && - tmp->name && !strCasediff(tmp->name, name)) || - ((tmp->status & (CONF_SERVER_MASK | CONF_HUB)) == 0 && - tmp->name && !match(tmp->name, name)))) - return tmp; + if (0 != (tmp->status & statmask)) { + assert(0 != tmp->name); + if (0 == ircd_strcmp(tmp->name, name) || 0 == match(tmp->name, name)) + return tmp; + } } - return NULL; + return 0; } /* * Added for new access check meLazy */ -aConfItem *find_conf_host(Link *lp, char *host, int statmask) +struct ConfItem* find_conf_byhost(struct SLink* lp, const char* host, + int statmask) { - Reg1 aConfItem *tmp; - int hostlen = host ? strlen(host) : 0; + struct ConfItem* tmp; + assert(0 != host); - if (hostlen > HOSTLEN || BadPtr(host)) - return (aConfItem *)NULL; - for (; lp; lp = lp->next) - { + if (HOSTLEN < strlen(host)) + return 0; + + for (; lp; lp = lp->next) { tmp = lp->value.aconf; - if (tmp->status & statmask && - (!(tmp->status & CONF_SERVER_MASK || tmp->host) || - (tmp->host && !match(tmp->host, host)))) - return tmp; + if (0 != (tmp->status & statmask)) { + assert(0 != tmp->host); + if (0 == match(tmp->host, host)) + return tmp; + } } - return NULL; + return 0; } /* @@ -563,28 +819,19 @@ aConfItem *find_conf_host(Link *lp, char *host, int statmask) * Find a conf line using the IP# stored in it to search upon. * Added 1/8/92 by Avalon. */ -aConfItem *find_conf_ip(Link *lp, char *ip, char *user, int statmask) +struct ConfItem* find_conf_byip(struct SLink* lp, const char* ip, + int statmask) { - Reg1 aConfItem *tmp; - Reg2 char *s; + struct ConfItem* tmp; - for (; lp; lp = lp->next) - { - tmp = lp->value.aconf; - if (!(tmp->status & statmask)) - continue; - s = strchr(tmp->host, '@'); - *s = '\0'; - if (match(tmp->host, user)) - { - *s = '@'; - continue; + 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; } - *s = '@'; - if (!memcmp(&tmp->ipnum, ip, sizeof(struct in_addr))) - return tmp; } - return NULL; + return 0; } /* @@ -592,35 +839,38 @@ aConfItem *find_conf_ip(Link *lp, char *ip, char *user, int statmask) * * - looks for a match on all given fields. */ -static aConfItem *find_conf_entry(aConfItem *aconf, unsigned int mask) +static struct ConfItem *find_conf_entry(struct ConfItem *aconf, + unsigned int mask) { - Reg1 aConfItem *bconf; + struct ConfItem *bconf; + assert(0 != aconf); - for (bconf = conf, mask &= ~CONF_ILLEGAL; bconf; bconf = bconf->next) - { + mask &= ~CONF_ILLEGAL; + + for (bconf = GlobalConfList; bconf; bconf = bconf->next) { if (!(bconf->status & mask) || (bconf->port != aconf->port)) continue; - if ((BadPtr(bconf->host) && !BadPtr(aconf->host)) || - (BadPtr(aconf->host) && !BadPtr(bconf->host))) + if ((EmptyString(bconf->host) && !EmptyString(aconf->host)) || + (EmptyString(aconf->host) && !EmptyString(bconf->host))) continue; - if (!BadPtr(bconf->host) && strCasediff(bconf->host, aconf->host)) + if (!EmptyString(bconf->host) && 0 != ircd_strcmp(bconf->host, aconf->host)) continue; - if ((BadPtr(bconf->passwd) && !BadPtr(aconf->passwd)) || - (BadPtr(aconf->passwd) && !BadPtr(bconf->passwd))) + if ((EmptyString(bconf->passwd) && !EmptyString(aconf->passwd)) || + (EmptyString(aconf->passwd) && !EmptyString(bconf->passwd))) continue; - if (!BadPtr(bconf->passwd) && (!isDigit(*bconf->passwd) || bconf->passwd[1]) + if (!EmptyString(bconf->passwd) && (!IsDigit(*bconf->passwd) || bconf->passwd[1]) #ifdef USEONE - && strCasediff(bconf->passwd, "ONE") + && 0 != ircd_strcmp(bconf->passwd, "ONE") #endif - && strCasediff(bconf->passwd, aconf->passwd)) + && 0 != ircd_strcmp(bconf->passwd, aconf->passwd)) continue; - if ((BadPtr(bconf->name) && !BadPtr(aconf->name)) || - (BadPtr(aconf->name) && !BadPtr(bconf->name))) + if ((EmptyString(bconf->name) && !EmptyString(aconf->name)) || + (EmptyString(aconf->name) && !EmptyString(bconf->name))) continue; - if (!BadPtr(bconf->name) && strCasediff(bconf->name, aconf->name)) + if (!EmptyString(bconf->name) && 0 != ircd_strcmp(bconf->name, aconf->name)) continue; break; } @@ -634,57 +884,45 @@ static aConfItem *find_conf_entry(aConfItem *aconf, unsigned int mask) * 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(aClient *cptr, int sig) +int rehash(struct Client *cptr, int sig) { - Reg1 aConfItem **tmp = &conf, *tmp2; - Reg2 aConfClass *cltmp; - Reg1 aClient *acptr; - Reg2 aMotdItem *temp; - Reg2 int i; - int ret = 0, found_g; - - if (sig == 1) + 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_ops("Got signal SIGHUP, reloading ircd conf. file"); - for (i = 0; i <= highest_fd; i++) - if ((acptr = loc_clients[i]) && !IsMe(acptr)) - { - /* - * Nullify any references from client structures to - * this host structure which is about to be freed. - * Could always keep reference counts instead of - * this....-avalon - */ - acptr->hostp = NULL; - } - - while ((tmp2 = *tmp)) - if (tmp2->clients || tmp2->status & CONF_LISTEN_PORT) - { + 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_LISTEN_PORT | CONF_CLIENT))) - { - *tmp = tmp2->next; - tmp2->next = NULL; + if (!(tmp2->status & CONF_CLIENT)) { + *tmp = tmp2->next; + tmp2->next = 0; } else - tmp = &tmp2->next; + tmp = &tmp2->next; tmp2->status |= CONF_ILLEGAL; } - else - { + else { *tmp = tmp2->next; /* free expression trees of connect rules */ if ((tmp2->status & (CONF_CRULEALL | CONF_CRULEAUTO)) && - (tmp2->passwd != NULL)) - crule_free(&(tmp2->passwd)); + (tmp2->passwd != NULL)) + crule_free(&(tmp2->passwd)); free_conf(tmp2); } + } /* * We don't delete the class table, rather mark all entries @@ -699,15 +937,23 @@ int rehash(aClient *cptr, int sig) clearNickJupes(); if (sig != 2) - flush_cache(); - if (initconf(0) == -1) /* This calls check_class(), */ - check_class(); /* unless it fails */ + flush_resolver_cache(); + + mark_listeners_closing(); + + if (initconf(0) == -1) /* 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 = &conf; (tmp2 = *tmp);) + for (tmp = &GlobalConfList; (tmp2 = *tmp);) { if (!(tmp2->status & CONF_ILLEGAL)) tmp = &tmp2->next; else @@ -715,50 +961,45 @@ int rehash(aClient *cptr, int sig) *tmp = tmp2->next; tmp2->next = NULL; if (!tmp2->clients) - free_conf(tmp2); + free_conf(tmp2); } - - for (i = 0; i <= highest_fd; i++) { - if ((acptr = loc_clients[i]) && !IsMe(acptr)) { + } + 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(acptr, acptr->name, CONF_HUB | CONF_LEAF | CONF_UWORLD); + det_confs_butmask(acptr, + ~(CONF_HUB | CONF_LEAF | CONF_UWORLD | CONF_ILLEGAL)); + attach_confs_byname(acptr, acptr->name, + CONF_HUB | CONF_LEAF | CONF_UWORLD); } if ((found_g = find_kill(acptr))) { - sendto_op_mask(found_g == -2 ? SNO_GLINE : SNO_OPERKILL, - found_g == -2 ? "G-line active for %s" : "K-line active for %s", - get_client_name(acptr, FALSE)); - if (exit_client(cptr, acptr, &me, found_g == -2 ? "G-lined" : - "K-lined") == CPTR_KILLED) - ret = CPTR_KILLED; - } -#if defined(R_LINES) && defined(R_LINES_REHASH) && !defined(R_LINES_OFTEN) - if (find_restrict(acptr)) { - sendto_ops("Restricting %s, closing lp", get_client_name(acptr, FALSE)); - if (exit_client(cptr, acptr, &me, "R-lined") == CPTR_KILLED) - ret = CPTR_KILLED; + sendto_op_mask(found_g == -2 ? SNO_GLINE : SNO_OPERKILL, + found_g == -2 ? "G-line active for %s" : "K-line active for %s", + get_client_name(acptr, HIDE_IP)); + if (exit_client(cptr, acptr, &me, found_g == -2 ? "G-lined" : + "K-lined") == CPTR_KILLED) + ret = CPTR_KILLED; } -#endif } } - - /* free old motd structs */ + /* + * free old motd structs + */ while (motd) { temp = motd->next; - RunFree(motd); + MyFree(motd); motd = temp; } while (rmotd) { temp = rmotd->next; - RunFree(rmotd); + MyFree(rmotd); rmotd = temp; } /* reload motd files */ read_tlines(); rmotd = read_motd(RPATH); motd = read_motd(MPATH); - return ret; } @@ -773,7 +1014,6 @@ int rehash(aClient *cptr, int sig) #define MAXCONFLINKS 150 -unsigned short server_port; int initconf(int opt) { @@ -787,52 +1027,48 @@ int initconf(int opt) {'\\', '\\'}, {0, 0} }; - Reg1 char *tmp, *s; + char *tmp, *s; FBFILE *file; int i; char line[512]; - int ccount = 0, ncount = 0; - aConfItem *aconf = NULL; + int ccount = 0; + struct ConfItem *aconf = 0; Debug((DEBUG_DEBUG, "initconf(): ircd.conf = %s", configfile)); - if (NULL == (file = fbopen(configfile, "r"))) - { + if (0 == (file = fbopen(configfile, "r"))) { return -1; } - while (fbgets(line, sizeof(line) - 1, file)) - { + while (fbgets(line, sizeof(line) - 1, file)) { if ((tmp = strchr(line, '\n'))) *tmp = '\0'; /* * Do quoting of characters and # detection. */ - for (tmp = line; *tmp; tmp++) - { - if (*tmp == '\\') - { - for (i = 0; quotes[i][0]; i++) - if (quotes[i][0] == *(tmp + 1)) - { - *tmp = quotes[i][1]; - break; - } - if (!quotes[i][0]) - *tmp = *(tmp + 1); - if (!*(tmp + 1)) - break; - else - for (s = tmp; (*s = *(s + 1)); s++) - ; + for (tmp = line; *tmp; tmp++) { + if (*tmp == '\\') { + for (i = 0; quotes[i][0]; i++) { + if (quotes[i][0] == *(tmp + 1)) { + *tmp = quotes[i][1]; + break; + } + } + if (!quotes[i][0]) + *tmp = *(tmp + 1); + if (!*(tmp + 1)) + break; + else { + for (s = tmp; (*s = *(s + 1)); s++) + ; + } } else if (*tmp == '#') - *tmp = '\0'; + *tmp = '\0'; } if (!*line || line[0] == '#' || line[0] == '\n' || - line[0] == ' ' || line[0] == '\t') + line[0] == ' ' || line[0] == '\t') continue; /* Could we test if it's conf line at all? -Vesa */ - if (line[1] != ':') - { + if (line[1] != ':') { Debug((DEBUG_ERROR, "Bad config line: %s", line)); continue; } @@ -843,207 +1079,197 @@ int initconf(int opt) tmp = getfield(line, ':'); if (!tmp) continue; - switch (*tmp) - { - case 'A': /* Name, e-mail address of administrator */ - case 'a': /* of this server. */ - aconf->status = CONF_ADMIN; - break; - case 'C': /* Server where I should try to connect */ - case 'c': /* in case of lp failures */ - ccount++; - aconf->status = CONF_CONNECT_SERVER; - break; - /* Connect rule */ - case 'D': - aconf->status = CONF_CRULEALL; - break; - /* Connect rule - autos only */ - case 'd': - aconf->status = CONF_CRULEAUTO; - 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 */ - aconf->status = CONF_KILL; - break; - case 'k': /* Kill user line based on IP in ircd.conf */ - aconf->status = CONF_IPKILL; - 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': - aconf->status = CONF_ME; - break; - case 'N': /* Server where I should NOT try to */ - case 'n': /* connect in case of lp failures */ - /* but which tries to connect ME */ - ++ncount; - aconf->status = CONF_NOCONNECT_SERVER; - 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': - aconf->status = CONF_LISTEN_PORT; - break; -#ifdef R_LINES - case 'R': /* extended K line */ - case 'r': /* Offers more options of how to restrict */ - aconf->status = CONF_RESTRICT; - break; -#endif - case 'T': /* print out different motd's */ - case 't': /* based on hostmask */ - aconf->status = CONF_TLINES; - 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': - aconf->status = CONF_CLASS; - break; - default: - Debug((DEBUG_ERROR, "Error in config file: %s", line)); - break; + switch (*tmp) { + case 'A': /* Name, e-mail address of administrator */ + case 'a': /* of this server. */ + aconf->status = CONF_ADMIN; + 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': + aconf->status = CONF_CRULEALL; + break; + /* Connect rule - autos only */ + case 'd': + aconf->status = CONF_CRULEAUTO; + 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 */ + aconf->status = CONF_KILL; + break; + case 'k': /* Kill user line based on IP in ircd.conf */ + aconf->status = CONF_IPKILL; + 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': + aconf->status = CONF_ME; + 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': + aconf->status = CONF_LISTEN_PORT; + break; + case 'T': /* print out different motd's */ + case 't': /* based on hostmask */ + aconf->status = CONF_TLINES; + 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': + aconf->status = CONF_CLASS; + break; + default: + Debug((DEBUG_ERROR, "Error in config file: %s", line)); + break; } if (IsIllegal(aconf)) continue; - for (;;) /* Fake loop, that I can use break here --msa */ - { + for (;;) { /* Fake loop, that I can use break here --msa */ if ((tmp = getfield(NULL, ':')) == NULL) - break; + break; DupString(aconf->host, tmp); if ((tmp = getfield(NULL, (aconf->status == CONF_KILL - || aconf->status == CONF_IPKILL) ? '"' : ':')) == NULL) - break; + || aconf->status == CONF_IPKILL) ? '"' : ':')) == NULL) + break; DupString(aconf->passwd, tmp); if ((tmp = getfield(NULL, ':')) == NULL) - break; + break; DupString(aconf->name, tmp); if ((tmp = getfield(NULL, ':')) == NULL) - break; + break; aconf->port = atoi(tmp); tmp = getfield(NULL, ':'); - if (aconf->status & CONF_ME) - { - server_port = aconf->port; - if (!tmp) - { - Debug((DEBUG_FATAL, "Your M: line must have the Numeric, " - "assigned to you by routing-com, behind the port number!\n")); -#ifdef USE_SYSLOG - syslog(LOG_WARNING, "Your M: line must have the Numeric, " - "assigned to you by routing-com, behind the port number!\n"); -#endif - exit(-1); - } - SetYXXServerName(&me, atoi(tmp)); /* Our Numeric Nick */ + if (aconf->status & CONF_ME) { + if (!tmp) { + Debug((DEBUG_FATAL, "Your M: line must have the Numeric, " + "assigned to you by routing-com, behind the port number!\n")); + ircd_log(L_WARNING, "Your M: line must have the Numeric, " + "assigned to you by routing-com, behind the port number!\n"); + exit(-1); + } + SetYXXServerName(&me, atoi(tmp)); /* Our Numeric Nick */ } else if (tmp) - aconf->confClass = find_class(atoi(tmp)); + aconf->confClass = find_class(atoi(tmp)); break; } /* * If conf line is a class definition, create a class entry * for it and make the conf_line illegal and delete it. */ - if (aconf->status & CONF_CLASS) - { + if (aconf->status & CONF_CLASS) { add_class(atoi(aconf->host), atoi(aconf->passwd), - atoi(aconf->name), aconf->port, tmp ? atoi(tmp) : 0); + atoi(aconf->name), aconf->port, tmp ? atoi(tmp) : 0); continue; } /* * Associate each conf line with a class by using a pointer * to the correct class record. -avalon */ - if (aconf->status & (CONF_CLIENT_MASK | CONF_LISTEN_PORT)) - { + if (aconf->status & CONF_CLIENT_MASK) { if (aconf->confClass == 0) - aconf->confClass = find_class(0); + aconf->confClass = find_class(0); } - if (aconf->status & (CONF_LISTEN_PORT | CONF_CLIENT)) - { - aConfItem *bconf; - - if ((bconf = find_conf_entry(aconf, aconf->status))) - { - delist_conf(bconf); - bconf->status &= ~CONF_ILLEGAL; - if (aconf->status == CONF_CLIENT) - { - char *passwd = bconf->passwd; - bconf->passwd = aconf->passwd; - aconf->passwd = passwd; - ConfLinks(bconf) -= bconf->clients; - bconf->confClass = aconf->confClass; - if (bconf->confClass) - ConfLinks(bconf) += bconf->clients; - } - free_conf(aconf); - aconf = bconf; + 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; + + 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->confClass = aconf->confClass; + if (bconf->confClass) + ConfLinks(bconf) += bconf->clients; + } + free_conf(aconf); + aconf = bconf; } - else if (aconf->host && aconf->status == CONF_LISTEN_PORT) - add_listener(aconf); } - if (aconf->status & CONF_SERVER_MASK) - if (ncount > MAXCONFLINKS || ccount > MAXCONFLINKS || - !aconf->host || strchr(aconf->host, '*') || - strchr(aconf->host, '?') || !aconf->name) - continue; - - if (aconf->status & (CONF_SERVER_MASK | CONF_LOCOP | CONF_OPERATOR)) - if (!strchr(aconf->host, '@') && *aconf->host != '/') - { - char *newhost; - int len = 3; /* *@\0 = 3 */ - - len += strlen(aconf->host); - newhost = (char *)RunMalloc(len); - sprintf_irc(newhost, "*@%s", aconf->host); - RunFree(aconf->host); - aconf->host = newhost; + 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); + sprintf_irc(newhost, "*@%s", aconf->host); + MyFree(aconf->host); + aconf->host = newhost; } - if (aconf->status & CONF_SERVER_MASK) - { - if (BadPtr(aconf->passwd)) - continue; + } + if (aconf->status & CONF_SERVER) { + if (EmptyString(aconf->passwd)) + continue; else if (!(opt & BOOT_QUICK)) - lookup_confhost(aconf); + lookup_confhost(aconf); } /* Create expression tree from connect rule... * If there's a parsing error, nuke the conf structure */ - if (aconf->status & (CONF_CRULEALL | CONF_CRULEAUTO)) - { - RunFree(aconf->passwd); - if ((aconf->passwd = (char *)crule_parse(aconf->name)) == NULL) - { - free_conf(aconf); - aconf = NULL; - continue; + if (aconf->status & (CONF_CRULEALL | CONF_CRULEAUTO)) { + MyFree(aconf->passwd); + if ((aconf->passwd = (char *)crule_parse(aconf->name)) == NULL) { + free_conf(aconf); + aconf = NULL; + continue; } } @@ -1054,11 +1280,8 @@ int initconf(int opt) * if previously defined. Note, that "info"-field can be * changed by "/rehash". */ - if (aconf->status == CONF_ME) - { - strncpy(me.info, aconf->name, sizeof(me.info) - 1); - if (portnum == 0) - portnum = aconf->port; + if (aconf->status == CONF_ME) { + ircd_strncpy(me.info, aconf->name, REALLEN); } /* @@ -1070,92 +1293,42 @@ int initconf(int opt) 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")); -#ifdef USE_SYSLOG - syslog(LOG_WARNING, "Your A: line must have 4 fields!\n"); -#endif - exit(-1); + 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, - "Read Init: (%d) (%s) (%s) (%s) (%u) (%p)", - aconf->status, aconf->host, aconf->passwd, - aconf->name, aconf->port, aconf->confClass)); - aconf->next = conf; - conf = aconf; + "Read Init: (%d) (%s) (%s) (%s) (%u) (%p)", + aconf->status, aconf->host, aconf->passwd, + aconf->name, aconf->port, aconf->confClass)); + aconf->next = GlobalConfList; + GlobalConfList = aconf; aconf = NULL; } if (aconf) free_conf(aconf); fbclose(file); check_class(); - nextping = nextconnect = now; - return 0; -} - -/* - * 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. - */ -static int lookup_confhost(aConfItem *aconf) -{ - Reg2 char *s; - Reg3 struct hostent *hp; - Link ln; - - if (BadPtr(aconf->host) || BadPtr(aconf->name)) - goto badlookup; - if ((s = strchr(aconf->host, '@'))) - s++; - else - s = aconf->host; - /* - * Do name lookup now on hostnames given and store the - * ip numbers in conf structure. - */ - if (!isAlpha(*s) && !isDigit(*s)) - goto badlookup; - - /* - * Prepare structure in case we have to wait for a - * reply which we get later and store away. - */ - ln.value.aconf = aconf; - ln.flags = ASYNC_CONF; - - if (isDigit(*s)) - aconf->ipnum.s_addr = inet_addr(s); - else if ((hp = gethost_byname(s, &ln))) - memcpy(&(aconf->ipnum), hp->h_addr, sizeof(struct in_addr)); - - if (aconf->ipnum.s_addr == INADDR_NONE) - goto badlookup; + nextping = nextconnect = CurrentTime; return 0; -badlookup: - if (aconf->ipnum.s_addr == INADDR_NONE) - memset(&aconf->ipnum, 0, sizeof(struct in_addr)); - Debug((DEBUG_ERROR, "Host/server name error: (%s) (%s)", - aconf->host, aconf->name)); - return -1; } /* read_tlines - * Read info from T:lines into trecords which include the file + * Read info from T:lines into TRecords which include the file * timestamp, the hostmask, and the contents of the motd file * -Ghostwolf 7sep97 */ void read_tlines() { - aConfItem *tmp; - atrecord *temp, *last = NULL; /* Init. to avoid compiler warning */ - aMotdItem *amotd; + struct ConfItem *tmp; + 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) @@ -1164,36 +1337,40 @@ void read_tlines() while (tdata->tmotd) { amotd = tdata->tmotd->next; - RunFree(tdata->tmotd); + MyFree(tdata->tmotd); tdata->tmotd = amotd; } - RunFree(tdata); + MyFree(tdata); tdata = last; } - for (tmp = conf; tmp; tmp = tmp->next) - if (tmp->status == CONF_TLINES && tmp->host && tmp->passwd) - { - temp = (atrecord *) RunMalloc(sizeof(atrecord)); - if (!temp) - outofmemory(); + 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; + tdata = temp; else - last->next = temp; + last->next = temp; last = temp; } + } } -int find_kill(aClient *cptr) +int find_kill(struct Client *cptr) { - char reply[256], *host, *name; - aConfItem *tmp; - aGline *agline = NULL; + char reply[256]; + const char* host; + const char* name; + struct ConfItem* tmp; + struct Gline* agline = NULL; + + assert(0 != cptr); if (!cptr->user) return 0; @@ -1201,64 +1378,67 @@ int find_kill(aClient *cptr) host = cptr->sockhost; name = cptr->user->username; +#if 0 + /* + * whee :) + * XXX - if this ever happens, we're already screwed + */ if (strlen(host) > (size_t)HOSTLEN || (name ? strlen(name) : 0) > (size_t)HOSTLEN) return (0); +#endif reply[0] = '\0'; - for (tmp = conf; tmp; tmp = tmp->next) + for (tmp = GlobalConfList; tmp; tmp = tmp->next) { /* Added a check against the user's IP address as well. * If the line is either CONF_KILL or CONF_IPKILL, check it; if and only * if it's CONF_IPKILL, check the IP address as well (the && below will * short circuit and the match won't even get run) -Kev */ if ((tmp->status & CONF_KLINE) && tmp->host && tmp->name && - (match(tmp->host, host) == 0 || - ((tmp->status == CONF_IPKILL) && - match(tmp->host, inetntoa(cptr->ip)) == 0)) && - (!name || match(tmp->name, name) == 0) && - (!tmp->port || (tmp->port == cptr->acpt->port))) + (match(tmp->host, host) == 0 || + ((tmp->status == CONF_IPKILL) && + match(tmp->host, ircd_ntoa((const char*) &cptr->ip)) == 0)) && + (!name || match(tmp->name, name) == 0) && + (!tmp->port || (tmp->port == cptr->listener->port))) { /* * Can short-circuit evaluation - not taking chances * because check_time_interval destroys tmp->passwd * - Mmmm */ - if (BadPtr(tmp->passwd)) - break; + if (EmptyString(tmp->passwd)) + break; else if (is_comment(tmp->passwd)) - break; + break; else if (check_time_interval(tmp->passwd, reply)) - break; + break; } - + } if (reply[0]) sendto_one(cptr, reply, me.name, ERR_YOUREBANNEDCREEP, cptr->name); - else if (tmp) - { - if (BadPtr(tmp->passwd)) + else if (tmp) { + if (EmptyString(tmp->passwd)) sendto_one(cptr, - ":%s %d %s :Connection from your host is refused on this server.", - me.name, ERR_YOUREBANNEDCREEP, cptr->name); - else - { - if (*tmp->passwd == '"') - { - char *sbuf = - sprintf_irc(sendbuf, ":%s %d %s :%s", me.name, ERR_YOUREBANNEDCREEP, - cptr->name, &tmp->passwd[1]); - sbuf[-1] = '.'; /* Overwrite last quote with a dot */ - sendbufto_one(cptr); + ":%s %d %s :Connection from your host is refused on this server.", + me.name, ERR_YOUREBANNEDCREEP, cptr->name); + else { + if (*tmp->passwd == '"') { + char *sbuf = + sprintf_irc(sendbuf, ":%s %d %s :%s", me.name, ERR_YOUREBANNEDCREEP, + cptr->name, &tmp->passwd[1]); + sbuf[-1] = '.'; /* Overwrite last quote with a dot */ + sendbufto_one(cptr); } else if (*tmp->passwd == '!') - killcomment(cptr, cptr->name, &tmp->passwd[1]); + killcomment(cptr, cptr->name, &tmp->passwd[1]); else #ifdef COMMENT_IS_FILE - killcomment(cptr, cptr->name, tmp->passwd); + killcomment(cptr, cptr->name, tmp->passwd); #else - sendto_one(cptr, ":%s %d %s :%s.", me.name, ERR_YOUREBANNEDCREEP, - cptr->name, tmp->passwd); + sendto_one(cptr, ":%s %d %s :%s.", me.name, ERR_YOUREBANNEDCREEP, + cptr->name, tmp->passwd); #endif } } @@ -1267,274 +1447,175 @@ int find_kill(aClient *cptr) /* added a check against the user's IP address to find_gline() -Kev */ else if ((agline = find_gline(cptr, NULL)) && GlineIsActive(agline)) sendto_one(cptr, ":%s %d %s :%s.", me.name, ERR_YOUREBANNEDCREEP, - cptr->name, agline->reason); + cptr->name, agline->reason); else - agline = NULL; /* if a gline was found, it was inactive */ + agline = NULL; /* if a gline was found, it was inactive */ return (tmp ? -1 : (agline ? -2 : 0)); } -#ifdef R_LINES -/* - * find_restrict - * - * Works against host/name and calls an outside program - * to determine whether a client is allowed to connect. This allows - * more freedom to determine who is legal and who isn't, for example - * machine load considerations. The outside program is expected to - * return a reply line where the first word is either 'Y' or 'N' meaning - * "Yes Let them in" or "No don't let them in." If the first word - * begins with neither 'Y' or 'N' the default is to let the person on. - * It returns a value of 0 if the user is to be let through -Hoppie - */ -int find_restrict(aClient *cptr) +struct MotdItem* read_motd(const char* motdfile) { - aConfItem *tmp; - char reply[80], temprpl[80]; - char *rplhold = reply, *host, *name, *s; - char rplchar = 'Y'; - int pi[2], rc = 0, n; - FBFILE *file = NULL; - - if (!cptr->user) - return 0; - name = cptr->user->username; - host = cptr->sockhost; - Debug((DEBUG_INFO, "R-line check for %s[%s]", name, host)); - - for (tmp = conf; tmp; tmp = tmp->next) - { - if (tmp->status != CONF_RESTRICT || - (tmp->host && host && match(tmp->host, host)) || - (tmp->name && name && match(tmp->name, name))) - continue; - - if (BadPtr(tmp->passwd)) - { - sendto_ops("Program missing on R-line %s/%s, ignoring", name, host); - continue; - } - - if (pipe(pi) == -1) - { - report_error("Error creating pipe for R-line %s: %s", &me); - return 0; - } - switch (rc = fork()) - { - case -1: - report_error("Error forking for R-line %s: %s", &me); - return 0; - case 0: - { - Reg1 int i; - - close(pi[0]); - for (i = 2; i < MAXCONNECTIONS; i++) - if (i != pi[1]) - close(i); - if (pi[1] != 2) - dup2(pi[1], 2); - dup2(2, 1); - if (pi[1] != 2 && pi[1] != 1) - close(pi[1]); - execlp(tmp->passwd, tmp->passwd, name, host, 0); - exit(-1); - } - default: - close(pi[1]); - break; - } - *reply = '\0'; - file = fdbopen(pi[0], "r"); - while (fbgets(temprpl, sizeof(temprpl) - 1, file)) - { - if ((s = strchr(temprpl, '\n'))) - *s = '\0'; - if (strlen(temprpl) + strlen(reply) < sizeof(reply) - 2) - sprintf_irc(rplhold, "%s %s", rplhold, temprpl); - else - { - sendto_ops("R-line %s/%s: reply too long!", name, host); - break; - } - } - fbclose(file); - kill(rc, SIGKILL); /* cleanup time */ - wait(0); - - rc = 0; - while (*rplhold == ' ') - rplhold++; - rplchar = *rplhold; /* Pull out the yes or no */ - while (*rplhold != ' ') - rplhold++; - while (*rplhold == ' ') - rplhold++; - strcpy(reply, rplhold); - rplhold = reply; - - if ((rc = (rplchar == 'n' || rplchar == 'N'))) - break; - } - if (rc) - { - sendto_one(cptr, ":%s %d %s :Restriction: %s", - me.name, ERR_YOUREBANNEDCREEP, cptr->name, reply); - return -1; + FBFILE* file = NULL; + struct MotdItem* temp; + struct MotdItem* newmotd; + struct MotdItem* last; + struct stat sb; + char line[80]; + char* tmp; + + if (NULL == (file = fbopen(motdfile, "r"))) { + Debug((DEBUG_ERROR, "Couldn't open \"%s\": %s", motdfile, strerror(errno))); + return NULL; } - return 0; -} -#endif - -/* - * output the reason for being k lined from a file - Mmmm - * sptr is server - * parv is the sender prefix - * filename is the file that is to be output to the K lined client - */ -static void killcomment(aClient *sptr, char *parv, char *filename) -{ - FBFILE *file = NULL; - char line[80]; - Reg1 char *tmp; - struct stat sb; - struct tm *tm; - - if (NULL == (file = fbopen(filename, "r"))) - { - sendto_one(sptr, err_str(ERR_NOMOTD), me.name, parv); - sendto_one(sptr, - ":%s %d %s :Connection from your host is refused on this server.", - me.name, ERR_YOUREBANNEDCREEP, parv); - return; + if (-1 == fbstat(&sb, file)) { + fbclose(file); + return NULL; } - fbstat(&sb, file); - tm = localtime((time_t *) & sb.st_mtime); /* NetBSD needs cast */ - while (fbgets(line, sizeof(line) - 1, file)) - { - if ((tmp = strchr(line, '\n'))) + newmotd = last = NULL; + motd_tm = *localtime((time_t *) & sb.st_mtime); /* NetBSD needs cast */ + while (fbgets(line, sizeof(line) - 1, file)) { + if ((tmp = (char *)strchr(line, '\n'))) *tmp = '\0'; - if ((tmp = strchr(line, '\r'))) + if ((tmp = (char *)strchr(line, '\r'))) *tmp = '\0'; - /* sendto_one(sptr, - * ":%s %d %s : %s.", - * me.name, ERR_YOUREBANNEDCREEP, parv,line); */ - sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv, line); + temp = (struct MotdItem*) MyMalloc(sizeof(struct MotdItem)); + assert(0 != temp); + strcpy(temp->line, line); + temp->next = NULL; + if (!newmotd) + newmotd = temp; + else + last->next = temp; + last = temp; } - sendto_one(sptr, - ":%s %d %s :Connection from your host is refused on this server.", - me.name, ERR_YOUREBANNEDCREEP, parv); fbclose(file); - return; + return newmotd; } + /* - * is the K line field an interval or a comment? - Mmmm + * Ordinary client access check. Look for conf lines which have the same + * status as the flags passed. */ -static int is_comment(char *comment) +enum AuthorizationCheckResult conf_check_client(struct Client *cptr) { - size_t i; - for (i = 0; i < strlen(comment); i++) - if ((comment[i] != ' ') && (comment[i] != '-') - && (comment[i] != ',') && ((comment[i] < '0') || (comment[i] > '9'))) - return (1); + int acr; + + ClearAccess(cptr); - return (0); + if ((acr = attach_iline(cptr))) { + Debug((DEBUG_DNS, "ch_cl: access denied: %s[%s]", + cptr->name, cptr->sockhost)); + return acr; + } + return ACR_OK; } /* - * check against a set of time intervals + * check_server() + * + * 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. */ -static int check_time_interval(char *interval, char *reply) +int conf_check_server(struct Client *cptr) { - struct tm *tptr; - char *p; - int perm_min_hours, perm_min_minutes, perm_max_hours, perm_max_minutes; - int nowm, perm_min, perm_max; + struct ConfItem* c_conf = NULL; + struct SLink* lp; - tptr = localtime(&now); - nowm = tptr->tm_hour * 60 + tptr->tm_min; + Debug((DEBUG_DNS, "sv_cl: check access for %s[%s]", + cptr->name, cptr->sockhost)); - while (interval) - { - p = strchr(interval, ','); - if (p) - *p = '\0'; - if (sscanf(interval, "%2d%2d-%2d%2d", &perm_min_hours, &perm_min_minutes, - &perm_max_hours, &perm_max_minutes) != 4) - { - if (p) - *p = ','; - return (0); - } - if (p) - *(p++) = ','; - perm_min = 60 * perm_min_hours + perm_min_minutes; - perm_max = 60 * perm_max_hours + perm_max_minutes; - /* - * The following check allows intervals over midnight ... - */ - if ((perm_min < perm_max) - ? (perm_min <= nowm && nowm <= perm_max) - : (perm_min <= nowm || nowm <= perm_max)) - { - printf(reply, - ":%%s %%d %%s :%s %d:%02d to %d:%02d.", - "You are not allowed to connect from", - perm_min_hours, perm_min_minutes, perm_max_hours, perm_max_minutes); - return (ERR_YOUREBANNEDCREEP); - } - if ((perm_min < perm_max) - ? (perm_min <= nowm + 5 && nowm + 5 <= perm_max) - : (perm_min <= nowm + 5 || nowm + 5 <= perm_max)) - { - sprintf_irc(reply, ":%%s %%d %%s :%d minute%s%s", - perm_min - nowm, (perm_min - nowm) > 1 ? "s " : " ", - "and you will be denied for further access"); - return (ERR_YOUWILLBEBANNED); + if (IsUnknown(cptr) && !attach_confs_byname(cptr, cptr->name, CONF_SERVER)) { + Debug((DEBUG_DNS, "No C/N lines for %s", cptr->sockhost)); + return -1; + } + lp = cptr->confs; + /* + * We initiated this connection so the client should have a C and N + * line already attached after passing through the connect_server() + * function earlier. + */ + if (IsConnecting(cptr) || IsHandshake(cptr)) { + c_conf = find_conf_byname(lp, cptr->name, CONF_SERVER); + if (!c_conf) { + sendto_ops("Connect Error: lost C:line for %s", cptr->name); + det_confs_butmask(cptr, 0); + return -1; } - interval = p; } - return (0); -} -aMotdItem *read_motd(char *motdfile) -{ - FBFILE *file = NULL; - register aMotdItem *temp, *newmotd, *last; - struct stat sb; - char line[80]; - register char *tmp; + ClearAccess(cptr); - if (NULL == (file = fbopen(motdfile, "r"))) - { - Debug((DEBUG_ERROR, "Couldn't open \"%s\": %s", motdfile, strerror(errno))); - return NULL; - } - if (-1 == fbstat(&sb, file)) - { - return NULL; + if (!c_conf) { + if (cptr->dns_reply) { + int i; + struct hostent* hp = cptr->dns_reply->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(cptr->sockhost, 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, cptr->sockhost, CONF_SERVER); + } } - newmotd = last = NULL; - motd_tm = *localtime((time_t *) & sb.st_mtime); /* NetBSD needs cast */ - while (fbgets(line, sizeof(line) - 1, file)) - { - if ((tmp = (char *)strchr(line, '\n'))) - *tmp = '\0'; - if ((tmp = (char *)strchr(line, '\r'))) - *tmp = '\0'; - temp = (aMotdItem *) RunMalloc(sizeof(aMotdItem)); - if (!temp) - outofmemory(); - strcpy(temp->line, line); - temp->next = NULL; - if (!newmotd) - newmotd = temp; - else - last->next = temp; - last = temp; + /* + * 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*) &cptr->ip, 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 (!c_conf) { + Debug((DEBUG_DNS, "sv_cl: access denied: %s[%s@%s]", + cptr->name, cptr->username, cptr->sockhost)); + return -1; } - fbclose(file); - return newmotd; + ircd_strncpy(cptr->name, c_conf->name, HOSTLEN); + /* + * attach the C and N lines to the client structure for later use. + */ + attach_conf(cptr, c_conf); + attach_confs_byname(cptr, cptr->name, CONF_HUB | CONF_LEAF | CONF_UWORLD); + + if (INADDR_NONE == c_conf->ipnum.s_addr) + c_conf->ipnum.s_addr = cptr->ip.s_addr; + + Debug((DEBUG_DNS, "sv_cl: access ok: %s[%s]", cptr->name, cptr->sockhost)); + return 0; } +