/************************************************************************ * IRC - Internet Relay Chat, src/s_conf.c * Copyright (C) 1990 Jarkko Oikarinen and * University of Oulu, Computing Center * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 1, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* $Id: s_conf.c,v 1.12 2006/01/07 22:13:26 trystanscott Exp $ */ #include "struct.h" #include "common.h" #include "sys.h" #include "numeric.h" #include "inet.h" #include #include "h.h" #include "userban.h" #include "confparse.h" #include "memcount.h" /* This entire file has basically been rewritten from scratch with the * exception of lookup_confhost and attach_Iline/attach_iline fucntions * Feb04 -epi */ extern int rehashed; extern int forked; extern tConf tconftab[]; extern sConf sconftab[]; /* internally defined functions */ static int lookup_confhost(aConnect *); static int attach_iline(aClient *, aAllow *, char *, int); /* externally defined functions */ extern aClass *make_class(); extern aOper *make_oper(); extern aConnect *make_connect(); extern aAllow *make_allow(); extern struct Conf_Me *make_me(); extern aPort *make_port(); extern void read_shortmotd(char *); /* these are our global lists of ACTIVE conf entries */ #define MAXUSERVS 24 aConnect *connects = NULL; /* connects, C/N pairs */ aAllow *allows = NULL; /* allows - I lines */ Conf_Me *MeLine = NULL; /* meline - only one */ aOper *opers = NULL; /* opers - Olines */ aPort *ports = NULL; /* ports - P/M lines */ aClass *classes = NULL; /* classes - Ylines */ char *uservers[MAXUSERVS]; /* uservers = Ulines */ Conf_Modules *modules = NULL; /* this set of lists is used for loading and rehashing the config file */ aConnect *new_connects = NULL; aAllow *new_allows = NULL; Conf_Me *new_MeLine = NULL; aOper *new_opers = NULL; aPort *new_ports = NULL; aClass *new_classes = NULL; char *new_uservers[MAXUSERVS+1]; /* null terminated array */ Conf_Modules *new_modules = NULL; #ifdef LOCKFILE extern void do_pending_klines(void); #endif extern void confparse_error(char *, int); extern int klinestore_init(int); #ifdef TOYS extern void init_chef(); #endif /* initclass() * initialize the default class */ void initclass() { new_classes = make_class(); DupString(new_classes->name, "default"); new_classes->connfreq = CONNECTFREQUENCY; new_classes->pingfreq = PINGFREQUENCY; new_classes->maxlinks = MAXIMUM_LINKS; new_classes->maxsendq = MAXSENDQLENGTH; new_classes->links = 0; } /* init_globals * initialize our major globals to the defaults first */ void init_globals() { strncpyzt(ProxyMonURL, DEFAULT_WGMON_URL, sizeof(ProxyMonURL)); strncpyzt(ProxyMonHost, DEFAULT_WGMON_HOST, sizeof(ProxyMonHost)); strncpyzt(Network_Name, DEFAULT_NETWORK, sizeof(Network_Name)); strncpyzt(Services_Name, DEFAULT_SERVICES_NAME, sizeof(Services_Name)); strncpyzt(Stats_Name, DEFAULT_STATS_NAME, sizeof(Stats_Name)); strncpyzt(NS_Register_URL, DEFAULT_NS_REGISTER_URL, sizeof(NS_Register_URL)); strncpyzt(Network_Kline_Address, DEFAULT_NKLINE_ADDY, sizeof(Network_Kline_Address)); strncpyzt(Local_Kline_Address, DEFAULT_LKLINE_ADDY, sizeof(Local_Kline_Address)); strncpyzt(Staff_Address, DEFAULT_STAFF_ADDRESS, sizeof(Staff_Address)); maxchannelsperuser = DEFAULT_MAXCHANNELSPERUSER; tsmaxdelta = DEFAULT_TSMAXDELTA; tswarndelta = DEFAULT_TSWARNDELTA; local_ip_limit = DEFAULT_LOCAL_IP_CLONES; local_ip24_limit = DEFAULT_LOCAL_IP24_CLONES; global_ip_limit = DEFAULT_GLOBAL_IP_CLONES; global_ip24_limit = DEFAULT_GLOBAL_IP24_CLONES; strncpyzt(HostPrefix, Network_Name, sizeof(HostPrefix)); strncpyzt(HostDomain, DEFAULT_HOST_DOMAIN, sizeof(HostDomain)); strncpyzt(HiddenServName, HIDDEN_SERVER_NAME, sizeof(HiddenServName)); strncpyzt(HiddenServDesc, HIDDEN_SERVER_DESC, sizeof(HiddenServDesc)); strncpyzt(HELPCHAN, DEFAULT_HELPCHAN, sizeof(HELPCHAN)); strncpyzt(WEBSITE, DEFAULT_WEBSITE, sizeof(WEBSITE)); strncpyzt(AUP, DEFAULT_AUP, sizeof(AUP)); } /* free_ routines * free the requested conf structure * feb.04 -epi */ void free_connect(aConnect *ptr) { MyFree(ptr->host); MyFree(ptr->apasswd); MyFree(ptr->cpasswd); MyFree(ptr->source); MyFree(ptr->name); MyFree(ptr->class_name); MyFree(ptr); return; } void free_allow(aAllow *ptr) { MyFree(ptr->ipmask); MyFree(ptr->passwd); MyFree(ptr->hostmask); MyFree(ptr->class_name); MyFree(ptr); return; } void free_oper(aOper *ptr) { int i = 0; while(ptr->hosts[i]) { MyFree(ptr->hosts[i]); i++; } MyFree(ptr->passwd); MyFree(ptr->nick); MyFree(ptr->class_name); MyFree(ptr); return; } void free_port(aPort *ptr) { MyFree(ptr->allow); MyFree(ptr->address); MyFree(ptr); return; } void free_class(aClass *ptr) { MyFree(ptr->name); MyFree(ptr); return; } void expire_class(aClass *cl) { aClass *ccl, *pcl = NULL; if (cl->refs == 0 && cl->maxlinks == -1) { for (ccl = classes; ccl; ccl = ccl->next) { if (ccl == cl) { if (pcl) pcl->next = ccl->next; else classes = ccl->next; free_class(ccl); break; } pcl = ccl; } } } /* clear_conflinks() * remove associated confs from this client * and free the conf if it is scheduled to be deleted * Feb04 -epi */ void clear_conflinks(aClient *cptr) { if (cptr->class) { cptr->class->links--; cptr->class->refs--; expire_class(cptr->class); } if(IsServer(cptr)) { aConnect *x; if((x = cptr->serv->aconn)) { x->acpt = NULL; if (x->legal == -1) /* scheduled for removal? */ { aConnect *aconn = NULL; if (x == connects) connects = x->next; else { for (aconn = connects; aconn != NULL && aconn->next != x; aconn = aconn->next); if (aconn != NULL) aconn->next = x->next; else sendto_realops_lev(DEBUG_LEV, "Deleting scheduled " "connect, but it isn't in the " "list?? [%s]", x->name); } x->class->refs--; expire_class(x->class); free_connect(x); } cptr->serv->aconn = NULL; } } else if (cptr->user != NULL) { aAllow *x; aOper *y; if((x = cptr->user->allow)) { x->clients--; if(x->clients <= 0 && x->legal == -1) { /* remove this allow now that its empty */ aAllow *allow = NULL; if (allows == x) allows = x->next; else { for (allow = allows; allow != NULL && allow->next != x; allow = allow->next); if (allow != NULL) allow->next = x->next; else sendto_realops_lev(DEBUG_LEV, "Deleting scheduled " "allow, but it isn't in the list?? " "[%s / %s]", x->ipmask,x->hostmask); } x->class->refs--; expire_class(x->class); free_allow(x); } cptr->user->allow = NULL; } if((y = cptr->user->oper)) { y->opers--; if(y->legal == -1 && y->opers <= 0) { aOper *oper = NULL; if (opers == y) opers = y->next; else { for (oper = opers; oper != NULL && oper->next != y; oper = oper->next); if (oper != NULL) oper->next = y->next; else sendto_realops_lev(DEBUG_LEV, "Deleting scheduled " "oper, but it isn't in the list?? " "[%s]", y->nick); } y->class->refs--; expire_class(y->class); free_oper(y); } cptr->user->oper = NULL; } } return; } /* find the appropriate conf and return it */ aConnect * find_aConnect(char *name) { aConnect *tmp; for(tmp = connects; tmp; tmp = tmp->next) if(!match(name, tmp->name)) break; return tmp; } static inline aPort * find_port(int port, char *bind) { aPort *tmp; for(tmp = ports; tmp; tmp = tmp->next) if (tmp->port == port) { if (tmp->address == bind) /* both NULL */ break; if (tmp->address && bind && !mycmp(tmp->address, bind)) break; } return tmp; } aConnect * find_aConnect_match(char *name, char *username, char *host) { aConnect *aconn; char userhost[USERLEN + HOSTLEN + 3]; ircsprintf(userhost, "%s@%s", username, host); for(aconn = connects; aconn; aconn = aconn->next) { if (aconn->legal == -1) continue; if(!mycmp(name, aconn->name) && !match(userhost, aconn->host)) break; } return aconn; } int find_aUserver(char *name) { int i; for(i = 0; uservers[i]; i++) { if(!mycmp(name, uservers[i])) return 1; } return 0; } aOper * find_oper(char *name, char *username, char *sockhost, char *hostip) { aOper *aoper; char userhost[USERLEN + HOSTLEN + 3]; char userip[USERLEN + HOSTLEN + 3]; int i; /* sockhost OR hostip must match our host field */ ircsprintf(userhost, "%s@%s", username, sockhost); ircsprintf(userip, "%s@%s", username, hostip); for(aoper = opers; aoper; aoper = aoper->next) { if (aoper->legal == -1) continue; for(i = 0; aoper->hosts[i]; i++) { if(!mycmp(name, aoper->nick) && (!match(aoper->hosts[i], userhost) || !match(aoper->hosts[i], userip))) return aoper; } } return NULL; } static inline aOper * find_oper_byname(char *name) { aOper *aoper; for(aoper = opers; aoper; aoper = aoper->next) if(!mycmp(name, aoper->nick)) break; return aoper; } static inline aClass * find_class(char *name) { aClass *tmp; if(!name) return find_class("default"); for(tmp = classes; tmp; tmp = tmp->next) if(!mycmp(name, tmp->name)) break; return tmp; } /* set_effective_class * sets the class for cptr properly */ void set_effective_class(aClient *cptr) { if (cptr->class) { cptr->class->links--; cptr->class->refs--; expire_class(cptr->class); } if(IsServer(cptr)) { if(cptr->serv->aconn->class) cptr->class = cptr->serv->aconn->class; else cptr->class = find_class("default"); } else { if(cptr->user && cptr->user->oper) cptr->class = cptr->user->oper->class; else if(cptr->user && cptr->user->allow) cptr->class = cptr->user->allow->class; else cptr->class = find_class("default"); } cptr->class->refs++; cptr->class->links++; return; } /* find the first (best) I line to attach. * rewritten in feb04 for the overdue death of aConfItem * and all the shit that came with it. -epi * Rewritten again in Mar04 to optimize and get rid of deceptive logic. * Whoever wrote this originally must have been drunk... -Quension */ int attach_Iline(aClient *cptr, struct hostent *hp, char *sockhost) { aAllow *allow; static char useriphost[USERLEN + 1 + HOSTLEN + 1]; static char usernamehost[USERLEN + 1 + HOSTLEN + 1]; char *iphost; char *namehost = NULL; /* squish compiler warning */ int len; /* user@host in both buffers, plus pointers to host only */ len = ircsprintf(useriphost, "%s@", cptr->username); iphost = useriphost + len; strcpy(iphost, sockhost); if (hp) { memcpy(usernamehost, useriphost, USERLEN+2); namehost = usernamehost + len; len = sizeof(usernamehost) - len; strncpy(namehost, hp->h_name, len); add_local_domain(namehost, len - strlen(namehost)); } for (allow = allows; allow; allow = allow->next) { if(allow->legal == -1) continue; if (allow->port && (allow->port != cptr->lstn->port)) continue; if (!allow->ipmask || !allow->hostmask) return (attach_iline(cptr, allow, iphost, 0)); /* match hostmask against both resolved name and IP, prefer name */ if (allow->flags & CONF_FLAGS_I_MATCH_NAME) { if (allow->flags & CONF_FLAGS_I_NAME_HAS_AT) { if (hp && !match(allow->hostmask, usernamehost)) return (attach_iline(cptr, allow, namehost, 1)); if (!match(allow->hostmask, useriphost)) return (attach_iline(cptr, allow, hp?namehost:iphost, 1)); } else { if (hp && !match(allow->hostmask, namehost)) return (attach_iline(cptr, allow, namehost, 0)); if (!match(allow->hostmask, iphost)) return (attach_iline(cptr, allow, hp?namehost:iphost, 0)); } } if (allow->flags & CONF_FLAGS_I_MATCH_HOST) { if (allow->flags & CONF_FLAGS_I_HOST_HAS_AT) { if (!match(allow->ipmask, useriphost)) return (attach_iline(cptr, allow, iphost, 1)); } else { if (!match(allow->ipmask, iphost)) return (attach_iline(cptr, allow, iphost, 0)); } } } return -1; /* no match */ } /* * rewrote to remove the "ONE" lamity *BLEH* I agree with comstud on * this one. - Dianora */ static int attach_iline(aClient *cptr, aAllow *allow, char *uhost, int doid) { if(allow->class->links >= allow->class->maxlinks) return -3; if (doid) cptr->flags |= FLAGS_DOID; get_sockhost(cptr, uhost); cptr->user->allow = allow; allow->clients++; return 0; } /* confadd_ functions * add a config item * Feb.15/04 -epi */ static int oper_access[] = { ~0, '*', OFLAG_LOCAL, 'o', OFLAG_GLOBAL, 'O', OFLAG_REHASH, 'r', OFLAG_DIE, 'D', OFLAG_RESTART, 'R', OFLAG_GLOBOP, 'h', OFLAG_WALLOP, 'w', OFLAG_LOCOP, 'l', OFLAG_LROUTE, 'c', OFLAG_GROUTE, 'C', OFLAG_LKILL, 'k', OFLAG_GKILL, 'K', OFLAG_KLINE, 'b', OFLAG_UNKLINE, 'B', OFLAG_LNOTICE, 'n', OFLAG_GNOTICE, 'N', OFLAG_ADMIN, 'A', OFLAG_SADMIN, 'a', OFLAG_UMODEc, 'u', OFLAG_UMODEf, 'f', OFLAG_UMODEF, 'F', OFLAG_UMODEb, 'W', OFLAG_UMODEd, 'd', OFLAG_UMODEy, 'y', 0, 0 }; int confadd_oper(cVar *vars[], int lnum) { cVar *tmp; aOper *x = make_oper(); int *i, flag, c = 0, hc = 0; char *m = "*"; for(tmp = vars[c]; tmp; tmp = vars[++c]) { if(tmp->type && (tmp->type->flag & SCONFF_NAME)) { if(x->nick) { confparse_error("Multiple name definitions", lnum); free_oper(x); return -1; } tmp->type = NULL; DupString(x->nick, tmp->value); } else if(tmp->type && (tmp->type->flag & SCONFF_HOST)) { if((hc+1) > MAXHOSTS) { confparse_error("Excessive host definitions", lnum); free_oper(x); return -1; } tmp->type = NULL; if (!strchr(tmp->value, '@') && *tmp->value != '/') { char *newhost; int len = 3; len += strlen(tmp->value); newhost = (char *) MyMalloc(len); ircsprintf(newhost, "*@%s", tmp->value); x->hosts[hc] = newhost; } else DupString(x->hosts[hc], tmp->value); hc++; } else if(tmp->type && (tmp->type->flag & SCONFF_PASSWD)) { if(x->passwd) { confparse_error("Multiple password definitions", lnum); free_oper(x); return -1; } tmp->type = NULL; DupString(x->passwd, tmp->value); } else if(tmp->type && (tmp->type->flag & SCONFF_ACCESS)) { if(x->flags > 0) { confparse_error("Multiple access definitions", lnum); free_oper(x); return -1; } for (m=(*tmp->value) ? tmp->value : m; *m; m++) { for (i=oper_access; (flag = *i); i+=2) if (*m==(char)(*(i+1))) { x->flags |= flag; break; } } } else if(tmp->type && (tmp->type->flag & SCONFF_CLASS)) { if(x->class_name) { confparse_error("Multiple class definitions", lnum); free_oper(x); return -1; } tmp->type = NULL; DupString(x->class_name, tmp->value); } } if(!x->nick) { confparse_error("Lacking name in oper block", lnum); free_oper(x); return -1; } if(!x->hosts[0]) { confparse_error("Lacking host in oper block", lnum); free_oper(x); return -1; } if(!x->passwd) { confparse_error("Lacking passwd in oper block", lnum); free_oper(x); return -1; } if(x->flags == 0) { confparse_error("Lacking access in oper block", lnum); free_oper(x); return -1; } x->next = new_opers; new_opers = x; return lnum; } static int server_info[] = { CONN_ZIP, 'Z', CONN_DKEY, 'E', CONN_HUB, 'H', 0, 0 }; int confadd_connect(cVar *vars[], int lnum) { cVar *tmp; aConnect *x = make_connect(); int *i, flag, c = 0; char *m = "*"; for(tmp = vars[c]; tmp; tmp = vars[++c]) { if(tmp->type && (tmp->type->flag & SCONFF_NAME)) { if(x->name) { confparse_error("Multiple name definitions", lnum); free_connect(x); return -1; } tmp->type = NULL; DupString(x->name, tmp->value); } else if(tmp->type && (tmp->type->flag & SCONFF_HOST)) { if(x->host) { confparse_error("Multiple host definitions", lnum); free_connect(x); return -1; } tmp->type = NULL; if (!strchr(tmp->value, '@') && *tmp->value != '/') { char *newhost; int len = 3; len += strlen(tmp->value); newhost = (char *) MyMalloc(len); ircsprintf(newhost, "*@%s", tmp->value); x->host = newhost; } else DupString(x->host, tmp->value); } else if(tmp->type && (tmp->type->flag & SCONFF_APASSWD)) { if(x->apasswd) { confparse_error("Multiple apasswd definitions", lnum); free_connect(x); return -1; } tmp->type = NULL; DupString(x->apasswd, tmp->value); } else if(tmp->type && (tmp->type->flag & SCONFF_CPASSWD)) { if(x->cpasswd) { confparse_error("Multiple cpasswd definitions", lnum); free_connect(x); return -1; } tmp->type = NULL; DupString(x->cpasswd, tmp->value); } else if(tmp->type && (tmp->type->flag & SCONFF_FLAGS)) { if(x->flags > 0) { confparse_error("Multiple flag definitions", lnum); free_connect(x); return -1; } tmp->type = NULL; x->flags = 0; for (m=(*tmp->value) ? tmp->value : m; *m; m++) { for (i=server_info; (flag = *i); i+=2) if (*m==(char)(*(i+1))) { x->flags |= flag; break; } } } else if(tmp->type && (tmp->type->flag & SCONFF_PORT)) { if(x->port > 0) { confparse_error("Multiple port definitions", lnum); free_connect(x); return -1; } tmp->type = NULL; x->port = atoi(tmp->value); } else if(tmp->type && (tmp->type->flag & SCONFF_BIND)) { if(x->source) { confparse_error("Multiple source definitions", lnum); free_connect(x); return -1; } tmp->type = NULL; DupString(x->source, tmp->value); } else if(tmp->type && (tmp->type->flag & SCONFF_CLASS)) { if(x->class_name) { confparse_error("Multiple class definitions", lnum); free_connect(x); return -1; } tmp->type = NULL; DupString(x->class_name, tmp->value); } } if(!x->name) { confparse_error("Lacking name in connect block", lnum); free_connect(x); return -1; } if(!x->apasswd) { confparse_error("Lacking apasswd in connect block", lnum); free_connect(x); return -1; } if(!x->cpasswd) { confparse_error("Lacking cpasswd in connect block", lnum); free_connect(x); return -1; } if(!x->host) { confparse_error("Lacking host in connect block", lnum); free_connect(x); return -1; } x->next = new_connects; new_connects = x; return lnum; } int confadd_options(cVar *vars[], int lnum) { cVar *tmp; int c = 0; char *s; /* here, because none of the option peice are interdependent * all the items are added immediately. Makes life easier * ...except the option flags, which are handled specially -Quension */ for(tmp = vars[c]; tmp; tmp = vars[++c]) { if(tmp->type && (tmp->type->flag & OPTF_NETNAME)) { tmp->type = NULL; strncpyzt(Network_Name, tmp->value, sizeof(Network_Name)); } else if(tmp->type && (tmp->type->flag & OPTF_SERVNAME)) { tmp->type = NULL; strncpyzt(Services_Name, tmp->value, sizeof(Services_Name)); } else if(tmp->type && (tmp->type->flag & OPTF_STATSNAME)) { tmp->type = NULL; strncpyzt(Stats_Name, tmp->value, sizeof(Stats_Name)); } else if(tmp->type && (tmp->type->flag & OPTF_WGMONHOST)) { tmp->type = NULL; new_confopts |= FLAGS_WGMONHOST; strncpyzt(ProxyMonHost, tmp->value, sizeof(ProxyMonHost)); } else if(tmp->type && (tmp->type->flag & OPTF_WGMONURL)) { tmp->type = NULL; new_confopts |= FLAGS_WGMONURL; strncpyzt(ProxyMonURL, tmp->value, sizeof(ProxyMonURL)); } else if(tmp->type && (tmp->type->flag & OPTF_NSREGURL)) { tmp->type = NULL; strncpyzt(NS_Register_URL, tmp->value, sizeof(NS_Register_URL)); } else if(tmp->type && (tmp->type->flag & OPTF_MAXCHAN)) { tmp->type = NULL; maxchannelsperuser = atoi(tmp->value); } else if(tmp->type && (tmp->type->flag & OPTF_SERVTYPE)) { tmp->type = NULL; if(!mycmp("HUB", tmp->value)) { new_confopts |= FLAGS_HUB; new_confopts &= ~FLAGS_SERVHUB; } else if(!mycmp("SERVICESHUB", tmp->value)) { new_confopts |= FLAGS_SERVHUB; new_confopts |= FLAGS_HUB; } else if(!mycmp("CLIENT", tmp->value)) new_confopts &= ~(FLAGS_HUB|FLAGS_SERVHUB); else { confparse_error("Unknown servtype in option block", lnum); return -1; } } else if(tmp->type && (tmp->type->flag & OPTF_NKLINEADDY)) { tmp->type = NULL; strncpyzt(Network_Kline_Address, tmp->value, sizeof(Network_Kline_Address)); } else if(tmp->type && (tmp->type->flag & OPTF_LKLINEADDY)) { tmp->type = NULL; strncpyzt(Local_Kline_Address, tmp->value, sizeof(Local_Kline_Address)); } else if(tmp->type && (tmp->type->flag & OPTF_STAFFADDY)) { tmp->type = NULL; strncpyzt(Staff_Address, tmp->value, sizeof(Staff_Address)); } else if(tmp->type && (tmp->type->flag & OPTF_LCLONES)) { tmp->type = NULL; local_ip_limit = strtol(tmp->value, &s, 10); if (*s == ':') local_ip24_limit = atoi(s+1); if (local_ip_limit < 1) local_ip_limit = DEFAULT_LOCAL_IP_CLONES; if (local_ip24_limit < 1) local_ip24_limit = DEFAULT_LOCAL_IP24_CLONES; } else if(tmp->type && (tmp->type->flag & OPTF_GCLONES)) { tmp->type = NULL; global_ip_limit = strtol(tmp->value, &s, 10); if (*s == ':') global_ip24_limit = atoi(s+1); if (global_ip_limit < 1) global_ip_limit = DEFAULT_GLOBAL_IP_CLONES; if (global_ip24_limit < 1) global_ip24_limit = DEFAULT_GLOBAL_IP24_CLONES; } else if(tmp->type && (tmp->type->flag & OPTF_SMOTD)) { tmp->type = NULL; new_confopts |= FLAGS_SMOTD; } else if(tmp->type && (tmp->type->flag & OPTF_SMOTD)) { tmp->type = NULL; new_confopts |= FLAGS_SMOTD; } else if(tmp->type && (tmp->type->flag & OPTF_CRYPTPASS)) { tmp->type = NULL; new_confopts |= FLAGS_CRYPTPASS; } else if(tmp->type && (tmp->type->flag & OPTF_SHOWLINKS)) { tmp->type = NULL; new_confopts |= FLAGS_SHOWLINKS; } else if(tmp->type && (tmp->type->flag & OPTF_SPLITOPOK)) { tmp->type = NULL; new_confopts |= FLAGS_SPLITOPOK; } else if(tmp->type && (tmp->type->flag & OPTF_TSMAXDELTA)) { tmp->type = NULL; tsmaxdelta = atoi(tmp->value); } else if(tmp->type && (tmp->type->flag & OPTF_TSWARNDELTA)) { tmp->type = NULL; tswarndelta = atoi(tmp->value); } else if(tmp->type && (tmp->type->flag & OPTF_RQUIT)) { tmp->type = NULL; new_confopts |= FLAGS_RQUIT; } else if(tmp->type && (tmp->type->flag & OPTF_HOSTPREFIX)) { tmp->type = NULL; strncpyzt(HostPrefix, tmp->value, sizeof(HostPrefix)); } else if(tmp->type && (tmp->type->flag & OPTF_DOMAIN)) { tmp->type = NULL; strncpyzt(HostDomain, tmp->value, sizeof(HostDomain)); } else if(tmp->type && (tmp->type->flag & OPTF_AUTOUMODEV)) { tmp->type = NULL; new_confopts |= FLAGS_AUTOUMODE_v; } else if(tmp->type && (tmp->type->flag & OPTF_AUTOUMODER)) { tmp->type = NULL; new_confopts |= FLAGS_AUTOUMODE_R; } else if (tmp->type && (tmp->type->flag & OPTF_HIDDENSERVNAME)) { tmp->type = NULL; strncpyzt(HiddenServName, tmp->value, sizeof(HiddenServName)); } else if (tmp->type && (tmp->type->flag & OPTF_HIDDENSERVDESC)) { tmp->type = NULL; strncpyzt(HiddenServDesc, tmp->value, sizeof(HiddenServDesc)); } else if(tmp->type && (tmp->type->flag & OPTF_BOTCLASS)) { tmp->type = NULL; DupString(bot_class, tmp->value); } else if (tmp->type && (tmp->type->flag & OPTF_HELPCHAN)) { tmp->type = NULL; strncpyzt(HELPCHAN, tmp->value, sizeof(HELPCHAN)); } else if (tmp->type && (tmp->type->flag & OPTF_WEBSITE)) { tmp->type = NULL; strncpyzt(WEBSITE, tmp->value, sizeof(WEBSITE)); } else if (tmp->type && (tmp->type->flag & OPTF_AUP)) { tmp->type = NULL; strncpyzt(AUP, tmp->value, sizeof(AUP)); } } return lnum; } int confadd_allow(cVar *vars[], int lnum) { cVar *tmp; aAllow *x = make_allow(); int c = 0; /* Currently, Allows are the only config types without * easy identifiers - so we dont worry about duplicate types. * -epi */ for(tmp = vars[c]; tmp; tmp = vars[++c]) { if(tmp->type && (tmp->type->flag & SCONFF_IPMASK)) { if(x->ipmask) { confparse_error("Multiple ipmask definitions", lnum); free_allow(x); return -1; } tmp->type = NULL; DupString(x->ipmask, tmp->value); if(strchr(x->ipmask, '@')) x->flags |= CONF_FLAGS_I_HOST_HAS_AT; x->flags |= CONF_FLAGS_I_MATCH_HOST; } else if(tmp->type && (tmp->type->flag & SCONFF_HOST)) { if(x->hostmask) { confparse_error("Multiple host definitions", lnum); free_allow(x); return -1; } tmp->type = NULL; DupString(x->hostmask, tmp->value); if(strchr(x->hostmask, '@')) x->flags |= CONF_FLAGS_I_NAME_HAS_AT; x->flags |= CONF_FLAGS_I_MATCH_NAME; } else if(tmp->type && (tmp->type->flag & SCONFF_PASSWD)) { if(x->passwd) { confparse_error("Multiple passwd definitions", lnum); free_allow(x); return -1; } tmp->type = NULL; DupString(x->passwd, tmp->value); #if (RIDICULOUS_PARANOIA_LEVEL>=1) if(myncmp(x->passwd, "oper", 4) == 0) { if((x->passwd[4] == '.') || (x->passwd[4] == '\0')) { char *tmpd = x->passwd; char *tmp = x->passwd + 4; x->flags |= CONF_FLAGS_I_OPERPORT; if(*tmp) tmp++; DupString(x->passwd, tmp); MyFree(tmpd); } } #endif } else if(tmp->type && (tmp->type->flag & SCONFF_PORT)) { if(x->port > 0) { confparse_error("Multiple host definitions", lnum); free_allow(x); return -1; } tmp->type = NULL; x->port = atoi(tmp->value); } else if(tmp->type && (tmp->type->flag & SCONFF_CLASS)) { if(x->class_name) { confparse_error("Multiple class definitions", lnum); free_allow(x); return -1; } tmp->type = NULL; DupString(x->class_name, tmp->value); } else if(tmp->type && (tmp->type->flag & SCONFF_FLAGS)) { char *s = tmp->value; while (*s) switch (*s++) { case 'm': x->flags |= CONF_FLAGS_I_OPERPORT; break; case 'T': x->flags |= CONF_FLAGS_NOTHROTTLE; break; case 'F': x->flags |= CONF_FLAGS_FORCEFLOOD; break; case 'C': x->flags |= CONF_FLAGS_SKIPCLONES; break; default: confparse_error("Unknown flag", lnum); free_allow(x); return -1; } tmp->type = NULL; } } if(!x->ipmask && !x->hostmask) { confparse_error("Lacking both ipmask and host for allow", lnum); free_allow(x); return -1; } if(!x->ipmask) DupString(x->ipmask, "-"); if(!x->hostmask) DupString(x->hostmask, "-"); x->next = new_allows; new_allows = x; return lnum; } int confadd_port(cVar *vars[], int lnum) { cVar *tmp; aPort *x; int c = 0; x = make_port(); for(tmp = vars[c]; tmp; tmp = vars[++c]) { if(tmp->type && (tmp->type->flag & SCONFF_IPMASK)) { if(x->allow) { confparse_error("Multiple ipmask definitions", lnum); free_port(x); return -1; } tmp->type = NULL; DupString(x->allow, tmp->value); } else if(tmp->type && (tmp->type->flag & SCONFF_BIND)) { if(x->address) { confparse_error("Multiple bind definitions", lnum); free_port(x); return -1; } tmp->type = NULL; DupString(x->address, tmp->value); } else if(tmp->type && (tmp->type->flag & SCONFF_PORT)) { if(x->port > 0) { confparse_error("Multiple port definitions", lnum); free_port(x); return -1; } tmp->type = NULL; x->port = atoi(tmp->value); } #ifdef HAVE_SSL else if(tmp->type && (tmp->type->flag & SCONFF_TYPE)) { x->ptype = NULL; if(!mycmp("SSL", tmp->value)) x->ptype = "SSL"; else { confparse_error("Unknown type in port block", lnum); return -1; } } #endif } if(!(x->port > 0)) { confparse_error("Lacking port in port block", lnum); free_port(x); return -1; } x->next = new_ports; new_ports = x; return lnum; } int confadd_global(cVar *vars[], int lnum) { cVar *tmp; Conf_Me *x = new_MeLine; int c = 0; /* note: * we dont free this here because we'll do that if we pull out */ if(!x) { x = make_me(); new_MeLine = x; } for(tmp = vars[c]; tmp; tmp = vars[++c]) { if(tmp->type && (tmp->type->flag & SCONFF_NAME)) { unsigned char *s; int valid = 0; if(x->servername) { confparse_error("Multiple name definitions", lnum); return -1; } /* validate server name, based on m_server() */ for (s = (unsigned char *) tmp->value; *s; s++) { if (*s < ' ' || *s > '~') { valid = 0; break; } if (*s == '.') valid = 1; } if (!valid) { confparse_error("Invalid server name", lnum); return -1; } tmp->type = NULL; DupString(x->servername, tmp->value); } else if(tmp->type && (tmp->type->flag & SCONFF_INFO)) { if(x->info) { confparse_error("Multiple info definitions", lnum); return -1; } tmp->type = NULL; DupString(x->info, tmp->value); } else if(tmp->type && (tmp->type->flag & SCONFF_DPASS)) { if(x->diepass) { confparse_error("Multiple dpass definitions", lnum); return -1; } tmp->type = NULL; DupString(x->diepass, tmp->value); } else if(tmp->type && (tmp->type->flag & SCONFF_RPASS)) { if(x->restartpass) { confparse_error("Multiple rpass definitions", lnum); return -1; } tmp->type = NULL; DupString(x->restartpass, tmp->value); } } if(!x->servername) { confparse_error("Lacking name definition in global block", lnum); return -1; } if(!x->info) { confparse_error("Lacking info definition in global block", lnum); return -1; } return lnum; } int confadd_admin(cVar *vars[], int lnum) { cVar *tmp; Conf_Me *x = new_MeLine; int c = 0; if(!x) { x = make_me(); new_MeLine = x; } if (x->admin[0]) { confparse_error("Multiple admin blocks", lnum); return -1; } for(tmp = vars[c]; tmp && (c != 3); tmp = vars[++c]) DupString(x->admin[c], tmp->value); return lnum; } int confadd_class(cVar *vars[], int lnum) { cVar *tmp; aClass *x = make_class(); int c = 0; char *s; for(tmp = vars[c]; tmp; tmp = vars[++c]) { if(tmp->type && (tmp->type->flag & SCONFF_NAME)) { if(x->name) { confparse_error("Multiple name definitions", lnum); free_class(x); return -1; } tmp->type = NULL; DupString(x->name, tmp->value); } else if(tmp->type && (tmp->type->flag & SCONFF_PINGFREQ)) { if(x->pingfreq > 0) { confparse_error("Multiple pingfreq definitions", lnum); free_class(x); return -1; } tmp->type = NULL; x->pingfreq = atoi(tmp->value); } else if(tmp->type && (tmp->type->flag & SCONFF_CONNFREQ)) { if(x->connfreq > 0) { confparse_error("Multiple maxclones/connfreq definitions", lnum); free_class(x); return -1; } tmp->type = NULL; x->connfreq = strtol(tmp->value, &s, 10); if (*s == ':') x->ip24clones = atoi(s+1); if (x->connfreq < 1) x->connfreq = 0; if (x->ip24clones < 1) x->ip24clones = 0; } else if(tmp->type && (tmp->type->flag & SCONFF_MAXUSERS)) { if(x->maxlinks > 0) { confparse_error("Multiple maxusers/maxlinks definitions" " (you can only have one or the other)", lnum); free_class(x); return -1; } tmp->type = NULL; x->maxlinks = atoi(tmp->value); } else if(tmp->type && (tmp->type->flag & SCONFF_MAXSENDQ)) { if(x->maxsendq > 0) { confparse_error("Multiple maxsendq definitions", lnum); free_class(x); return -1; } tmp->type = NULL; x->maxsendq = atoi(tmp->value); } } if(!x->name) { confparse_error("Lacking name definition", lnum); free_class(x); return -1; } if(!(x->maxsendq > 0)) { confparse_error("Lacking maxsendq definition", lnum); free_class(x); return -1; } x->next = new_classes; new_classes = x; return lnum; } int confadd_kill(cVar *vars[], int lnum) { cVar *tmp; struct userBan *ban; int c = 0; char *ub_u = NULL, *ub_r = NULL, *host = NULL; for(tmp = vars[c]; tmp; tmp = vars[++c]) { if(tmp->type && (tmp->type->flag & SCONFF_MASK)) { if(host) { confparse_error("Multiple mask definitions", lnum); return -1; } tmp->type = NULL; if((host = strchr(tmp->value, '@'))) { *host = '\0'; host++; ub_u = tmp->value; } else host = tmp->value; } if(tmp->type && (tmp->type->flag & SCONFF_REASON)) { if(ub_r) { confparse_error("Multiple reason definitions", lnum); return -1; } tmp->type = NULL; ub_r = tmp->value; break; } } if(!host) { confparse_error("Lacking mask definition", lnum); return -1; } ub_u = BadPtr(ub_u) ? "*" : ub_u; ub_r = BadPtr(ub_r) ? "" : ub_r; ban = make_hostbased_ban(ub_u, host); if(!ban) return lnum; /* this isnt a parser problem - dont pull out */ ban->flags |= (UBAN_LOCAL|UBAN_CONF); DupString(ban->reason, ub_r); ban->timeset = NOW; add_hostbased_userban(ban); userban_sweep(ban); return lnum; } int confadd_super(cVar *vars[], int lnum) { cVar *tmp; int c = 0; int i; /* If multiple super blocks are specified, set up to append */ for (i = 0; new_uservers[i]; i++) ; for(tmp = vars[c]; tmp; tmp = vars[++c]) { if (i == MAXUSERVS) { confparse_error("Excessive super server definitions", lnum); return -1; } DupString(new_uservers[i], tmp->value); i++; } new_uservers[i] = NULL; return lnum; } int confadd_restrict(cVar *vars[], int lnum) { cVar *tmp; int c = 0, type = 0; char *mask = NULL, *reason = NULL; struct simBan *ban; for(tmp = vars[c]; tmp; tmp = vars[++c]) { if(tmp->type && (tmp->type->flag & SCONFF_TYPE)) { if(type > 0) { confparse_error("Multiple type definitions", lnum); return -1; } tmp->type = NULL; if(!mycmp("CHAN", tmp->value)) type = SBAN_CHAN; else if(!mycmp("NICK", tmp->value)) type = SBAN_NICK; else if(!mycmp("GCOS", tmp->value)) type = SBAN_GCOS; else { confparse_error("Unknown type in restrict block", lnum); return -1; } type |= SBAN_LOCAL; } else if(tmp->type && (tmp->type->flag & SCONFF_MASK)) { if(mask) { confparse_error("Mutliple mask definitions", lnum); return -1; } tmp->type = NULL; mask = tmp->value; } else if(tmp->type && (tmp->type->flag & SCONFF_REASON)) { if(reason) { confparse_error("Multiple reason definitions", lnum); return -1; } tmp->type = NULL; reason = tmp->value; } } if(!mask) { confparse_error("Missing mask in restrict block", lnum); return -1; } if(!(type > 0)) { confparse_error("Missing type in restrict block", lnum); return -1; } ban = make_simpleban(type, mask); if(!ban) return lnum; if(find_simban_exact(ban) != NULL) /* dont add duplicates */ { simban_free(ban); return lnum; } if(!reason) { if(type & SBAN_CHAN) reason = "Reserved Channel"; else if(type & SBAN_NICK) reason = "Reserved Nick"; else if(type & SBAN_GCOS) reason = "Bad GCOS"; } DupString(ban->reason, reason); ban->timeset = NOW; add_simban(ban); return lnum; } int confadd_ssl(cVar *vars[], int lnum) { cVar *tmp; int c = 0; for(tmp = vars[c]; tmp; tmp = vars[++c]) { if (tmp->type && (tmp->type->flag & SSTF_CERTIFICATE)) { tmp->type = NULL; strncpyzt(SSL_Certificate, tmp->value, sizeof(SSL_Certificate)); } else if (tmp->type && (tmp->type->flag & SSTF_KEYFILE)) { tmp->type = NULL; strncpyzt(SSL_Keyfile, tmp->value, sizeof(SSL_Keyfile)); } else if (tmp->type && (tmp->type->flag & SSTF_UMODEZ)) { tmp->type = NULL; new_confopts |= FLAGS_LETUMODE_z; } } return lnum; } #ifdef TOYS int confadd_elmer(cVar *vars[], int lnum) { cVar *tmp; int c = 0; static char *last_word; for(tmp = vars[c]; tmp; tmp = vars[++c]) { if (tmp->type && (tmp->type->flag & EETF_STRING)) { tmp->type = NULL; DupString(last_word, tmp->value); } if (tmp->type && (tmp->type->flag & EETF_TRANSLATE)) { tmp->type = NULL; if (last_word) { add_translate(last_word, tmp->value); MyFree(last_word); } } } return lnum; } #endif int confadd_modules(cVar *vars[], int lnum) { cVar *tmp; Conf_Modules *x = new_modules; int c = 0, ac = 0, oc = 0; /* this is like the global block - we dont free here because we do * it if we fail */ if(!x) { x = (Conf_Modules *) MyMalloc(sizeof(Conf_Modules)); memset((char *) x, '\0', sizeof(Conf_Modules)); new_modules = x; } else { confparse_error("Multiple module blocks in config file", lnum); return -1; } for(tmp = vars[c]; tmp; tmp = vars[++c]) { if(tmp->type && (tmp->type->flag & MBTF_PATH)) { if(x->module_path) { confparse_error("Multiple module paths defined", lnum); return -1; } tmp->type = NULL; DupString(x->module_path, tmp->value); } else if(tmp->type && (tmp->type->flag & MBTF_AUTOLOAD)) { if((ac+1) > 128) { confparse_error("Excessive autoloading modules (max 128)", lnum); return -1; } tmp->type = NULL; DupString(x->autoload[ac], tmp->value); ac++; } else if(tmp->type && (tmp->type->flag & MBTF_OPTLOAD)) { if((oc+1) > 128) { confparse_error("Excessive optional modules (max 128)", lnum); return -1; } tmp->type = NULL; DupString(x->optload[oc], tmp->value); oc++; } } if(!x->autoload[0] && !x->optload[0]) { confparse_error("No modules defined in module block", lnum); return -1; } return lnum; } /* set_classes * after loading the config into temporary lists, we must * set the appropriate classes for each conf. If we run into * problems, then back out. */ static inline aClass * find_new_class(char *name) { aClass *tmp; if(!name) return find_new_class("default"); for(tmp = new_classes; tmp; tmp = tmp->next) if(!mycmp(name, tmp->name)) break; return tmp; } char * set_classes(void) { aConnect *aconn; aAllow *allow; aOper *aoper; /* Note: * You may be wondering why we're doing this here and appearently * again in our merge routines! well, this is for sanity. if * for whatever reason we dont have a class for each definition here, * back out of the conf load immediately and we wont have distroyed * or overwritten any of our active data. * After we run our merge_classes() routine at the start of our * merge, then some of these classes will update currently active * classes and be free()'d - meaning some of these references are useless. * That is why we run it again inside the merge routines. * -epi */ for(aconn = new_connects; aconn; aconn = aconn->next) if(!(aconn->class = find_new_class(aconn->class_name))) return aconn->class_name; for(allow = new_allows; allow; allow = allow->next) if(!(allow->class = find_new_class(allow->class_name))) return allow->class_name; for(aoper = new_opers; aoper; aoper = aoper->next) if(!(aoper->class = find_new_class(aoper->class_name))) return aoper->class_name; return NULL; } /* merge routines. used to mirge together new lists and old lists * after a rehash. Feb27/04 -epi */ static void merge_me() { if(MeLine) { MyFree(MeLine->info); MyFree(MeLine->diepass); MyFree(MeLine->restartpass); MyFree(MeLine->admin[0]); MyFree(MeLine->admin[1]); MyFree(MeLine->admin[2]); /* MeLine->info is guaranteed to be replaced */ MeLine->diepass = NULL; MeLine->restartpass = NULL; MeLine->admin[0] = NULL; MeLine->admin[1] = NULL; MeLine->admin[2] = NULL; } else { MeLine = new_MeLine; strncpyzt(me.name, MeLine->servername, sizeof(me.name)); strncpyzt(me.info, MeLine->info, sizeof(me.info)); new_MeLine = NULL; return; } DupString(MeLine->info, new_MeLine->info); strncpyzt(me.info, MeLine->info, sizeof(me.info)); if(new_MeLine->diepass) DupString(MeLine->diepass, new_MeLine->diepass); if(new_MeLine->restartpass) DupString(MeLine->restartpass, new_MeLine->restartpass); if(new_MeLine->admin[0]) DupString(MeLine->admin[0], new_MeLine->admin[0]); if(new_MeLine->admin[1]) DupString(MeLine->admin[1], new_MeLine->admin[1]); if(new_MeLine->admin[2]) DupString(MeLine->admin[2], new_MeLine->admin[2]); MyFree(new_MeLine->servername); MyFree(new_MeLine->info); MyFree(new_MeLine->diepass); MyFree(new_MeLine->restartpass); MyFree(new_MeLine->admin[0]); MyFree(new_MeLine->admin[1]); MyFree(new_MeLine->admin[2]); MyFree(new_MeLine); new_MeLine = NULL; return; } static void merge_connects() { aConnect *aconn, *old_aconn, *ptr = NULL, *ptrn; /* first merge the list, then prune the list */ /* set old as deletable */ for(old_aconn = connects; old_aconn; old_aconn = old_aconn->next) old_aconn->legal = -1; /* update or add new */ for (aconn = new_connects; aconn; aconn = ptrn) { ptrn = aconn->next; if ((old_aconn = find_aConnect(aconn->name))) { MyFree(old_aconn->host); MyFree(old_aconn->apasswd); MyFree(old_aconn->cpasswd); MyFree(old_aconn->source); MyFree(old_aconn->class_name); old_aconn->class->refs--; expire_class(old_aconn->class); old_aconn->host = aconn->host; old_aconn->apasswd = aconn->apasswd; old_aconn->cpasswd = aconn->cpasswd; old_aconn->source = aconn->source; old_aconn->class_name = aconn->class_name; old_aconn->port = aconn->port; old_aconn->flags = aconn->flags; old_aconn->class = find_class(aconn->class_name); old_aconn->class->refs++; old_aconn->legal = 1; lookup_confhost(old_aconn); MyFree(aconn->name); MyFree(aconn); } else { aconn->class = find_class(aconn->class_name); aconn->class->refs++; aconn->legal = 1; lookup_confhost(aconn); aconn->next = connects; connects = aconn; } } new_connects = NULL; ptr = NULL; /* and prune the active list */ aconn = connects; while(aconn) { ptrn = aconn->next; if((aconn->legal == -1) && !aconn->acpt) { if(ptr) ptr->next = aconn->next; else connects = aconn->next; aconn->class->refs--; expire_class(aconn->class); free_connect(aconn); } else ptr = aconn; aconn = ptrn; } return; } static void merge_allows() { aAllow *allow, *ptr = NULL, *ptrn; for(allow = allows; allow; allow = allow->next) allow->legal = -1; allow = new_allows; while(allow) { allow->class = find_class(allow->class_name); allow->class->refs++; /* we dont really have to merge anything here.. */ /* ..but we should avoid duplicates anyway */ for (ptr = allows; ptr; ptr = ptr->next) { if (ptr->class != allow->class) continue; if (ptr->port != allow->port) continue; if (ptr->flags != allow->flags) continue; if (mycmp(ptr->ipmask, allow->ipmask)) continue; if (mycmp(ptr->hostmask, allow->hostmask)) continue; /* inverted logic below */ if (ptr->passwd && allow->passwd && !mycmp(ptr->passwd, allow->passwd)) break; if (ptr->passwd == allow->passwd) break; } /* if duplicate, mark for deletion but add anyway */ if (ptr) { ptr->legal = 1; allow->legal = -1; } ptr = allow->next; allow->next = allows; allows = allow; allow = ptr; } new_allows = NULL; ptr = NULL; allow = allows; while(allow) { ptrn = allow->next; if((allow->legal == -1) && (allow->clients <= 0)) { if(ptr) ptr->next = allow->next; else allows = allow->next; allow->class->refs--; expire_class(allow->class); free_allow(allow); } else ptr = allow; allow = ptrn; } return; /* this one is easy */ } static void merge_opers() { aOper *aoper, *old_oper, *ptrn = NULL, *ptr = NULL; for(old_oper = opers; old_oper; old_oper = old_oper->next) old_oper->legal = -1; /* add or merge and del new ones */ for (aoper = new_opers; aoper; aoper = ptrn) { ptrn = aoper->next; if ((old_oper = find_oper_byname(aoper->nick))) { int i; for (i = 0; old_oper->hosts[i]; i++) MyFree(old_oper->hosts[i]); MyFree(old_oper->passwd); MyFree(old_oper->class_name); old_oper->class->refs--; expire_class(old_oper->class); for (i = 0; aoper->hosts[i]; i++) old_oper->hosts[i] = aoper->hosts[i]; old_oper->hosts[i] = NULL; old_oper->passwd = aoper->passwd; old_oper->class_name = aoper->class_name; old_oper->class = find_class(aoper->class_name); old_oper->class->refs++; old_oper->flags = aoper->flags; old_oper->legal = 1; MyFree(aoper->nick); MyFree(aoper); } else { aoper->class = find_class(aoper->class_name); aoper->class->refs++; aoper->legal = 1; aoper->next = opers; opers = aoper; } } new_opers = NULL; /* del old ones */ ptr = NULL; aoper = opers; while(aoper) { ptrn = aoper->next; if((aoper->legal == -1) && (aoper->opers <= 0)) { if(ptr) ptr->next = aoper->next; else opers = aoper->next; free_oper(aoper); } else ptr = aoper; aoper = ptrn; } return; } static void merge_ports() { aPort *aport, *old_port, *ptrn; if(forked) close_listeners(); /* marks ports for deletion */ /* add or merge and del new ones */ for (aport = new_ports; aport; aport = ptrn) { ptrn = aport->next; if ((old_port = find_port(aport->port, aport->address))) { MyFree(old_port->allow); old_port->allow = aport->allow; old_port->legal = 1; MyFree(aport->address); MyFree(aport); } else { aport->next = ports; ports = aport; } } new_ports = NULL; if(forked) open_listeners(); return; } static void merge_classes() { aClass *class, *old_class, *ptr; for(old_class = classes; old_class; old_class = old_class->next) old_class->maxlinks = -1; for (class = new_classes; class; class = class->next) { if((old_class = find_class(class->name))) { old_class->connfreq = class->connfreq; old_class->pingfreq = class->pingfreq; old_class->maxlinks = class->maxlinks; old_class->maxsendq = class->maxsendq; old_class->ip24clones = class->ip24clones; class->maxlinks = -1; } } /* add classes from new_classes that are not maxlinks = -1 */ for (class = new_classes; class; class = old_class) { old_class = class->next; if (class->maxlinks == -1) free_class(class); else { class->next = classes; classes = class; } } new_classes = NULL; /* now remove any classes from the list marked and w/o refs */ for (class = classes; class; class = ptr) { ptr = class->next; expire_class(class); } return; } void merge_options(void) { if (forked && !(confopts & FLAGS_SMOTD) && (new_confopts & FLAGS_SMOTD)) read_shortmotd(SHORTMOTD); confopts = new_confopts; } void merge_confs() { int i; merge_classes(); /* this should always be done first */ merge_me(); merge_connects(); merge_allows(); merge_opers(); merge_ports(); merge_options(); for(i = 0; uservers[i]; i++) MyFree(uservers[i]); for(i = 0; new_uservers[i]; i++) { DupString(uservers[i], new_uservers[i]); MyFree(new_uservers[i]); } new_uservers[0] = NULL; /* dont worry about accually merging module data - its fairly * inactive and static data. Just replace it. */ if(modules) { MyFree(modules->module_path); for(i = 0; modules->autoload[i]; i++) MyFree(modules->autoload[i]); for(i = 0; modules->optload[i]; i++) MyFree(modules->optload[i]); MyFree(modules); } modules = new_modules; new_modules = NULL; return; } static void clear_newconfs() { aConnect *aconn = new_connects, *aconn_p; aClass *class = new_classes, *class_p; aOper *aoper = new_opers, *aoper_p; aPort *aport = new_ports, *aport_p; aAllow *allow = new_allows, *allow_p; int i = 0; while(aconn) { aconn_p = aconn->next; free_connect(aconn); aconn = aconn_p; } new_connects = NULL; while(class) { class_p = class->next; free_class(class); class = class_p; } new_classes = NULL; while(aoper) { aoper_p = aoper->next; free_oper(aoper); aoper = aoper_p; } new_opers = NULL; while(aport) { aport_p = aport->next; free_port(aport); aport = aport_p; } new_ports = NULL; while(allow) { allow_p = allow->next; free_allow(allow); allow = allow_p; } new_allows = NULL; if(new_MeLine) { MyFree(new_MeLine->servername); MyFree(new_MeLine->info); MyFree(new_MeLine->diepass); MyFree(new_MeLine->restartpass); MyFree(new_MeLine->admin[0]); MyFree(new_MeLine->admin[1]); MyFree(new_MeLine->admin[2]); MyFree(new_MeLine); new_MeLine = NULL; } while(new_uservers[i]) { DupString(uservers[i], new_uservers[i]); MyFree(new_uservers[i]); i++; } new_uservers[0] = NULL; if(new_modules) { for(i = 0; new_modules->autoload[i]; i++) MyFree(new_modules->autoload[i]); for(i = 0; new_modules->optload[i]; i++) MyFree(new_modules->optload[i]); MyFree(new_modules->module_path); MyFree(new_modules); new_modules = NULL; } return; } /* * rehash * * Actual REHASH service routine. Called with sig == 0 if it has been * called as a result of an operator issuing this command, else assume * it has been called as a result of the server receiving a HUP signal. */ int rehash(aClient *cptr, aClient *sptr, int sig) { aClient *acptr; int i; char *conferr; if (sig == SIGHUP) { sendto_ops("Got signal SIGHUP, reloading ircd conf. file"); remove_userbans_match_flags(UBAN_NETWORK, 0); /* remove all but kill {} blocks from conf */ remove_userbans_match_flags(UBAN_LOCAL, UBAN_CONF); remove_simbans_match_flags(SBAN_NICK|SBAN_LOCAL|SBAN_TEMPORARY, 0); remove_simbans_match_flags(SBAN_CHAN|SBAN_LOCAL|SBAN_TEMPORARY, 0); remove_simbans_match_flags(SBAN_GCOS|SBAN_LOCAL|SBAN_TEMPORARY, 0); } /* Shadowfax's LOCKFILE code */ #ifdef LOCKFILE do_pending_klines(); #endif for (i = 0; i <= highest_fd; i++) if ((acptr = local[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; } if (sig != SIGINT) flush_cache(); /* Flush DNS cache */ /* remove kill {} blocks */ remove_userbans_match_flags(UBAN_LOCAL|UBAN_CONF, 0); remove_simbans_match_flags(SBAN_NICK|SBAN_LOCAL, SBAN_TEMPORARY); remove_simbans_match_flags(SBAN_CHAN|SBAN_LOCAL, SBAN_TEMPORARY); remove_simbans_match_flags(SBAN_GCOS|SBAN_LOCAL, SBAN_TEMPORARY); initclass(); new_confopts = 0; #ifdef TOYS init_chef(); /* For now */ #endif if(initconf(configfile) == -1) { sendto_realops("Rehash Aborted"); clear_newconfs(); return 1; } conferr = finishconf(); if (conferr) { sendto_realops("Rehash Aborted: %s", conferr); clear_newconfs(); return 1; } merge_confs(); build_rplcache(); nextconnect = 1; /* reset autoconnects */ /* replay journal if necessary */ klinestore_init( (sig == SIGHUP) ? 0 : 1 ); rehashed = 1; return 1; } /* * 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. * * cleaned up Aug 3'97 - Dianora * rewritten to kill aConfItem, Feb/04 - epi */ static int lookup_confhost(aConnect *aconn) { char *s; struct hostent *hp; Link ln; if (BadPtr(aconn->host) || BadPtr(aconn->name)) { if (aconn->ipnum.s_addr == -1) memset((char *) &aconn->ipnum, '\0', sizeof(struct in_addr)); Debug((DEBUG_ERROR, "Host/server name error: (%s) (%s)", aconn->host, aconn->name)); return -1; } if ((s = strchr(aconn->host, '@'))) s++; else s = aconn->host; /* * Do name lookup now on hostnames given and store the ip * numbers in conf structure. */ if (!IsAlpha(*s) && !IsDigit(*s)) { if (aconn->ipnum.s_addr == -1) memset((char *) &aconn->ipnum, '\0', sizeof(struct in_addr)); Debug((DEBUG_ERROR, "Host/server name error: (%s) (%s)", aconn->host, aconn->name)); return -1; } /* * Prepare structure in case we have to wait for a reply which * we get later and store away. */ ln.value.aconn = aconn; ln.flags = ASYNC_CONF; if (IsDigit(*s)) aconn->ipnum.s_addr = inet_addr(s); else if ((hp = gethost_byname(s, &ln))) memcpy((char *) &(aconn->ipnum), hp->h_addr, sizeof(struct in_addr)); if (aconn->ipnum.s_addr == -1) memset((char *) &aconn->ipnum, '\0', sizeof(struct in_addr)); { Debug((DEBUG_ERROR, "Host/server name error: (%s) (%s)", aconn->host, aconn->name)); return -1; } /* NOTREACHED */ return 0; } u_long memcount_s_conf(MCs_conf *mc) { aConnect *conn; aAllow *allow; aOper *oper; aPort *port; aClass *class; int i; mc->file = __FILE__; for (conn = connects; conn; conn = conn->next) { mc->connects.c++; mc->connects.m += sizeof(*conn); if (conn->host) mc->connects.m += strlen(conn->host) + 1; if (conn->apasswd) mc->connects.m += strlen(conn->apasswd) + 1; if (conn->cpasswd) mc->connects.m += strlen(conn->cpasswd) + 1; if (conn->name) mc->connects.m += strlen(conn->name) + 1; if (conn->source) mc->connects.m += strlen(conn->source) + 1; if (conn->class_name) mc->connects.m += strlen(conn->class_name) + 1; } mc->total.c += mc->connects.c; mc->total.m += mc->connects.m; for (allow = allows; allow; allow = allow->next) { mc->allows.c++; mc->allows.m += sizeof(*allow); if (allow->ipmask) mc->allows.m += strlen(allow->ipmask) + 1; if (allow->passwd) mc->allows.m += strlen(allow->passwd) + 1; if (allow->hostmask) mc->allows.m += strlen(allow->hostmask) + 1; if (allow->class_name) mc->allows.m += strlen(allow->class_name) + 1; } mc->total.c += mc->allows.c; mc->total.m += mc->allows.m; for (oper = opers; oper; oper = oper->next) { mc->opers.c++; mc->opers.m += sizeof(*oper); if (oper->passwd) mc->opers.m += strlen(oper->passwd) + 1; if (oper->nick) mc->opers.m += strlen(oper->nick) + 1; if (oper->class_name) mc->opers.m += strlen(oper->class_name) + 1; for (i = 0; oper->hosts[i]; i++) mc->opers.m += strlen(oper->hosts[i]) + 1; } mc->total.c += mc->opers.c; mc->total.m += mc->opers.m; for (port = ports; port; port = port->next) { mc->ports.c++; mc->ports.m += sizeof(*port); if (port->allow) mc->ports.m += strlen(port->allow) + 1; if (port->address) mc->ports.m += strlen(port->address) + 1; } mc->total.c += mc->ports.c; mc->total.m += mc->ports.m; for (class = classes; class; class = class->next) { mc->classes.c++; mc->classes.m += sizeof(*class); if (class->name) mc->classes.m += strlen(class->name) + 1; } mc->total.c += mc->classes.c; mc->total.m += mc->classes.m; for (i = 0; uservers[i]; i++) { mc->uservers.c++; mc->uservers.m += strlen(uservers[i]) + 1; } mc->total.c += mc->uservers.c; mc->total.m += mc->uservers.m; if (modules) { mc->modules.c = 1; mc->modules.m = sizeof(*modules); if (modules->module_path) mc->modules.m += strlen(modules->module_path) + 1; for (i = 0; modules->autoload[i]; i++) mc->modules.m += strlen(modules->autoload[i]) + 1; for (i = 0; modules->optload[i]; i++) mc->modules.m += strlen(modules->optload[i]) + 1; } mc->total.c += mc->modules.c; mc->total.m += mc->modules.m; if (MeLine) { mc->me.c = 1; mc->me.m += sizeof(*MeLine); if (MeLine->servername) mc->me.m += strlen(MeLine->servername) + 1; if (MeLine->info) mc->me.m += strlen(MeLine->info) + 1; if (MeLine->diepass) mc->me.m += strlen(MeLine->diepass) + 1; if (MeLine->restartpass) mc->me.m += strlen(MeLine->restartpass) + 1; if (MeLine->admin[0]) mc->me.m += strlen(MeLine->admin[0]) + 1; if (MeLine->admin[1]) mc->me.m += strlen(MeLine->admin[1]) + 1; if (MeLine->admin[2]) mc->me.m += strlen(MeLine->admin[2]) + 1; } mc->total.c += mc->me.c; mc->total.m += mc->me.m; return mc->total.m; }