/** Count number of users who match \a mask. * @param[in] mask ip mask to check. * @param[in] flags Bitmask possibly containing the value ZLINE_LOCAL, to limit searches to this server. * @return Count of matching users. */ static int count_users(char *mask, int flags) { struct irc_in_addr ipmask; struct Client *acptr; int count = 0; int ipmask_valid; char ipbuf[SOCKIPLEN + 2]; unsigned char ipmask_len; ipmask_valid = ipmask_parse(mask, &ipmask, &ipmask_len); for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) { if (!IsUser(acptr)) continue; if ((flags & ZLINE_LOCAL) && !MyConnect(acptr)) continue; ircd_snprintf(0, ipbuf, sizeof(ipbuf), "%s", ircd_ntoa(&cli_ip(acptr))); if (!match(mask, ipbuf) || (ipmask_valid && ipmask_check(&cli_ip(acptr), &ipmask, ipmask_len) && (irc_in_addr_type_cmp(&cli_ip(acptr), &ipmask) && ipmask_len))) count++; } return count; }
/** Find Except configuration for \a cptr with flags matching \a flags * @param[in] cptr Client to match an Except configuration against. * @param[in] mask Bitmask of EFLAG_* flags to test for exemption. * @return -1 if an exception was found, 0 otherwise. */ int find_except_conf(struct Client *cptr, int flags) { struct ExceptConf *econf; if (flags & EFLAG_IPCHECK) { if (IsIPCheckExempt(cptr)) return -1; if (IsNotIPCheckExempt(cptr)) return 0; } for(econf = exceptConfList; econf; econf = econf->next) { if (!(econf->flags & flags)) continue; if (econf->usermask && match(econf->usermask, cli_username(cptr))) continue; if (econf->bits > 0) { if (!ipmask_check(&cli_ip(cptr), &econf->address, econf->bits)) continue; } else if (econf->hostmask && match(econf->hostmask, cli_sockhost(cptr))) continue; if (econf->flags & EFLAG_IPCHECK) SetIPCheckExempt(cptr); return -1; } if (flags & EFLAG_IPCHECK) SetNotIPCheckExempt(cptr); return 0; }
/** Find a ConfItem that has the same name and user+host fields as * specified. Requires an exact match for \a name. * @param name Name to match * @param cptr Client to match against * @param statmask Filter for ConfItem::status * @return First found matching ConfItem. */ struct ConfItem* find_conf_exact(const char* name, struct Client *cptr, int statmask) { struct ConfItem *tmp; for (tmp = GlobalConfList; tmp; tmp = tmp->next) { if (!(tmp->status & statmask) || !tmp->name || !tmp->host || 0 != ircd_strcmp(tmp->name, name)) continue; if (tmp->username && (EmptyString(cli_username(cptr)) || match(tmp->username, cli_username(cptr)))) continue; if (tmp->addrbits < 0) { if (match(tmp->host, cli_sockhost(cptr))) continue; } else if (!ipmask_check(&cli_ip(cptr), &tmp->address.addr, tmp->addrbits)) continue; if ((tmp->status & CONF_OPERATOR) && (MaxLinks(tmp->conn_class) > 0) && (tmp->clients >= MaxLinks(tmp->conn_class))) continue; return tmp; } return 0; }
/** Find a matching Z-line for a user. * @param[in] cptr Client to compare against. * @param[in] flags Bitwise combination of ZLINE_GLOBAL and/or * ZLINE_LASTMOD to limit matches. * @return Matching Z-line, or NULL if none are found. */ struct Zline * zline_lookup(struct Client *cptr, unsigned int flags) { struct Zline *zline; struct Zline *szline; if (find_except_conf(cptr, EFLAG_ZLINE)) return 0; zliter(GlobalZlineList, zline, szline) { if ((flags & ZLINE_GLOBAL && zline->zl_flags & ZLINE_LOCAL) || (flags & ZLINE_LASTMOD && !zline->zl_lastmod)) continue; if (ZlineIsIpMask(zline)) { if (!irc_in_addr_type_cmp(&cli_ip(cptr), &zline->zl_addr) && zline->zl_bits) continue; if (!ipmask_check(&cli_ip(cptr), &zline->zl_addr, zline->zl_bits)) continue; } else { if (match(zline->zl_mask, cli_sock_ip(cptr)) != 0) continue; } if (ZlineIsActive(zline)) return zline; } /* * No Zlines matched */ return 0; }
/** Find Except configuration for \a addr with flags matching \a flags * @param[in] addr IP Address to match an Except configuration against. * @param[in] mask Bitmask of EFLAG_* flags to test for exemption. * @return -1 if an exception was found, 0 otherwise. */ int find_except_conf_by_ip(const struct irc_in_addr *addr, int flags) { struct ExceptConf *econf; char ipbuf[SOCKIPLEN]; ircd_ntoa_r(ipbuf, addr); for(econf = exceptConfList; econf; econf = econf->next) { if (!(econf->flags & flags)) continue; /* Attempt to match usermask against "%nobody" to ensure this isn't * an Except that requires a user name to match. */ if (econf->usermask && match(econf->usermask, "%nobody")) continue; if (econf->bits > 0) { if (!ipmask_check(addr, &econf->address, econf->bits)) continue; } else if (econf->hostmask && match(econf->hostmask, ipbuf)) continue; return -1; } return 0; }
/** Find Spoofhost configuration for \a cptr with spoof host matching host and * a password matching \a passwd * @param[in] cptr Client to match Spoofhost configuration against. * @param[in] host Spoofhost host to look for, if NULL look for an autoapply Spoofhost. * @param[in] passwd Password to compare against Spoofhost configuration. * @param[out] status 0 for Success, 1 for invalid password and 2 for no Spoofhost configuration. * @return SHostConf struct of matching Spoofhost configuration or 0 on error. */ struct SHostConf* find_shost_conf(struct Client *cptr, char *host, char *passwd, int *status) { struct SHostConf* sconf; char *crypted; int res = 0; *status = 2; for(sconf = shostConfList; sconf; sconf = sconf->next) { if ((host == NULL) && !(sconf->flags & SHFLAG_AUTOAPPLY)) continue; if (host != NULL) { if (!(sconf->flags & SHFLAG_ISMASK) && strcmp(sconf->spoofhost, host)) continue; if ((sconf->flags & SHFLAG_ISMASK) && match(sconf->spoofhost, host)) continue; } if (sconf->usermask) { if (match(sconf->usermask, cli_username(cptr)) && !((sconf->flags & SHFLAG_MATCHUSER) && !match(sconf->usermask, cli_user(cptr)->username))) continue; } if (sconf->bits > 0) { if (!ipmask_check(&cli_ip(cptr), &sconf->address, sconf->bits)) continue; } else if (sconf->hostmask && match(sconf->hostmask, cli_sockhost(cptr))) continue; *status = 1; res = 0; if ((host == NULL) && (sconf->flags & SHFLAG_AUTOAPPLY)) { *status = 0; return sconf; } if (EmptyString(passwd) && !EmptyString(sconf->passwd)) continue; if (!EmptyString(passwd) && EmptyString(sconf->passwd)) continue; if (!EmptyString(passwd) && !EmptyString(sconf->passwd)) { crypted = ircd_crypt(passwd, sconf->passwd); if (!crypted) continue; res = strcmp(crypted, sconf->passwd); MyFree(crypted); } if (0 == res) { *status = 0; return sconf; } } return 0; }
void *cidr_exe(searchCtx *ctx, struct searchNode *thenode, void *theinput) { nick *np = (nick *)theinput; struct cidr_localdata *c = thenode->localdata; if(!ipmask_check(&np->ipaddress, &c->ip, c->bits)) return (void *)0; return (void *)1; }
trusthost *th_getbyhostandmask(struct irc_in_addr *ip, uint32_t bits) { trustgroup *tg; trusthost *th; for(tg=tglist;tg;tg=tg->next) for(th=tg->hosts;th;th=th->next) if(ipmask_check(ip, &th->ip, 128) && th->bits == bits) return th; return NULL; }
/** Check local clients against a new Z-line. * If the Z-line is inactive, return immediately. * Otherwise, if any users match it, disconnect them. * @param[in] cptr Peer connect that sent the Z-line. * @param[in] sptr Client that originated the Z-line. * @param[in] zline New Z-line to check. * @return Zero, unless \a sptr Z-lined himself, in which case CPTR_KILLED. */ static int do_zline(struct Client *cptr, struct Client *sptr, struct Zline *zline) { struct Client *acptr; int fd, retval = 0, tval; if (feature_bool(FEAT_DISABLE_ZLINES)) return 0; /* Z-lines are disabled */ if (!ZlineIsActive(zline)) /* no action taken on inactive zlines */ return 0; for (fd = HighestFd; fd >= 0; --fd) { /* * get the users! */ if ((acptr = LocalClientArray[fd])) { if (!cli_user(acptr)) continue; if (find_except_conf(acptr, EFLAG_ZLINE)) continue; /* IP zline */ if (ZlineIsIpMask(zline)) { if (!irc_in_addr_type_cmp(&cli_ip(acptr), &zline->zl_addr) && zline->zl_bits) continue; if (!ipmask_check(&cli_ip(acptr), &zline->zl_addr, zline->zl_bits)) continue; } else { if (match(zline->zl_mask, cli_sock_ip(acptr)) != 0) continue; } /* ok, here's one that got Z-lined */ send_reply(acptr, SND_EXPLICIT | ERR_YOUREBANNEDCREEP, ":%s", zline->zl_reason); /* let the ops know about it */ sendto_opmask_butone_global(&me, SNO_GLINE, "Z-line active for %s", get_client_name(acptr, SHOW_IP)); /* and get rid of him */ if ((tval = exit_client_msg(cptr, acptr, &me, "Z-lined%s%s%s", (!feature_bool(FEAT_HIS_ZLINE_REASON) ? " (" : ""), (!feature_bool(FEAT_HIS_ZLINE_REASON) ? zline->zl_reason : ""), (!feature_bool(FEAT_HIS_ZLINE_REASON) ? ")" : "")))) retval = tval; /* retain killed status */ } } return retval; }
/** Find an IP registry entry if one exists for the IP address. * If \a ip looks like an IPv6 address, only consider the first 64 bits * of the address. Otherwise, only consider the final 32 bits. * @param[in] ip IP address to search for. * @return Matching registry entry, or NULL if none exists. */ static struct IPRegistryEntry* ip_registry_find(const struct irc_in_addr *ip) { struct irc_in_addr canon; struct IPRegistryEntry* entry; ip_registry_canonicalize(&canon, ip); entry = hashTable[ip_registry_hash(&canon)]; for ( ; entry; entry = entry->next) { int bits = (canon.in6_16[0] == htons(0x2002)) ? 48 : 64; if (ipmask_check(&canon, &entry->addr, bits)) break; } return entry; }
/** Check whether a client matches a target mask. * @param[in] from Client trying to send a message (ignored). * @param[in] one Client being considered as a target. * @param[in] mask Mask for matching against. * @param[in] addr IP address prefix to match against. * @param[in] nbits Number of bits in \a addr (> 128 if none valid). * @param[in] what Type of match (either MATCH_HOST or MATCH_SERVER). * @return Non-zero if \a one matches, zero if not. */ static int match_it(struct Client *from, struct Client *one, const char *mask, struct irc_in_addr *addr, unsigned char nbits, int what) { switch (what) { case MATCH_HOST: return ((nbits <= 128 && ipmask_check(&cli_ip(one), addr, nbits)) || match(mask, cli_user(one)->host) == 0 || (HasHiddenHost(one) && match(mask, cli_user(one)->realhost) == 0)); case MATCH_SERVER: default: return (match(mask, cli_name(cli_user(one)->server)) == 0); } }
/* returns the ip with the smallest prefix that is still a superset of the given host */ trusthost *th_getsmallestsupersetbyhost(struct irc_in_addr *ip, uint32_t bits) { trustgroup *tg; trusthost *th, *result = NULL; uint32_t sbits; for(tg=tglist;tg;tg=tg->next) { for(th=tg->hosts;th;th=th->next) { if(ipmask_check(ip, &th->ip, th->bits)) { if((th->bits < bits) && (!result || (th->bits > sbits))) { sbits = th->bits; result = th; } } } } return result; }
/** Get all the exception flags that apply to the client \a cptr * @param[in] cptr Client to find the exception flags for. * @return Bitmask of all the exception flags found to apply to \a cptr */ int get_except_flags(struct Client *cptr) { int flags = 0; struct ExceptConf *econf; for(econf = exceptConfList; econf; econf = econf->next) { if (econf->usermask && match(econf->usermask, cli_username(cptr))) continue; if (econf->bits > 0) { if (!ipmask_check(&cli_ip(cptr), &econf->address, econf->bits)) continue; } else if (econf->hostmask && match(econf->hostmask, cli_sockhost(cptr))) continue; flags |= econf->flags; } return flags; }
/** Find WebIRC configuration for \a cptr with password matching \a passwd * @param[in] cptr Client to match WebIRC configuration against. * @param[in] passwd Password to compare against WebIRC configuration. * @param[out] status 0 for Success, 1 for invalid password and 2 for no WebIRC configuration. * @return WebIRCConf struct of matching WebIRC configuration or 0 on error. */ struct WebIRCConf* find_webirc_conf(struct Client *cptr, char *passwd, int* status) { struct WebIRCConf *wconf; char *crypted; int res; *status = 2; if (!passwd) return 0; for(wconf = webircConfList; wconf; wconf = wconf->next) { if (wconf->usermask && match(wconf->usermask, cli_username(cptr))) continue; if (wconf->bits > 0) { if (!ipmask_check(&cli_ip(cptr), &wconf->address, wconf->bits)) continue; } else if (wconf->hostmask && match(wconf->hostmask, cli_sockhost(cptr))) continue; *status = 1; if (!wconf->passwd) { *status = 0; return wconf; } crypted = ircd_crypt(passwd, wconf->passwd); if (!crypted) continue; res = strcmp(crypted, wconf->passwd); MyFree(crypted); if (0 == res) { *status = 0; return wconf; } } return 0; }
/** Find the first (best) Client block to attach. * @param cptr Client for whom to check rules. * @return Authorization check result. */ enum AuthorizationCheckResult attach_iline(struct Client* cptr) { struct ConfItem* aconf; assert(0 != cptr); for (aconf = GlobalConfList; aconf; aconf = aconf->next) { if (aconf->status != CONF_CLIENT) continue; /* If you change any of this logic, please make corresponding * changes in conf_debug_iline() below. */ if (aconf->address.port && aconf->address.port != cli_listener(cptr)->addr.port) continue; if (aconf->username && match(aconf->username, cli_username(cptr))) continue; if (aconf->host && match(aconf->host, cli_sockhost(cptr))) continue; if (aconf->countrymask && match(aconf->countrymask, cli_countrycode(cptr))) continue; if (aconf->continentmask && match(aconf->continentmask, cli_continentcode(cptr))) continue; if ((aconf->addrbits >= 0) && !ipmask_check(&cli_ip(cptr), &aconf->address.addr, aconf->addrbits)) continue; if (IPcheck_nr(cptr) > aconf->maximum) return ACR_TOO_MANY_FROM_IP; if (aconf->redirserver && !EmptyString(aconf->redirserver)) { send_reply(cptr, RPL_BOUNCE, aconf->redirserver, aconf->redirport); return ACR_NO_AUTHORIZATION; } if (aconf->username && !IsWebIRCUserIdent(cptr) && (aconf->flags & CONF_NOIDENTTILDE)) SetFlag(cptr, FLAG_DOID); return attach_conf(cptr, aconf); } return ACR_NO_AUTHORIZATION; }
/** Find the first matching MOTD block for a user. * If the user is remote, always use remote MOTD. * Otherwise, if there is a hostmask- or class-based MOTD that matches * the user, use it. * Otherwise, use the local MOTD. * @param[in] cptr Client to find MOTD for. * @return Pointer to first matching MOTD for the client. */ static struct Motd * motd_lookup(struct Client *cptr) { struct Motd *ptr; char *c_class = NULL; assert(0 != cptr); if (!MyUser(cptr)) /* not my user, always return remote motd */ return MotdList.remote; c_class = get_client_class(cptr); assert(c_class != NULL); /* check the motd blocks first */ for (ptr = MotdList.other; ptr; ptr = ptr->next) { if (ptr->type == MOTD_CLASS && !match(ptr->hostmask, c_class)) return ptr; else if (ptr->type == MOTD_HOSTMASK && !match(ptr->hostmask, cli_sockhost(cptr))) return ptr; else if (ptr->type == MOTD_IPMASK && ipmask_check(&cli_ip(cptr), &ptr->address, ptr->addrbits)) return ptr; else if (ptr->type == MOTD_COUNTRY && !match(ptr->hostmask, cli_countrycode(cptr))) return ptr; else if (ptr->type == MOTD_CONTINENT && !match(ptr->hostmask, cli_continentcode(cptr))) return ptr; } return MotdList.local; /* Ok, return the default motd */ }
/* * m_who - generic message handler * * parv[0] = sender prefix * parv[1] = nickname mask list * parv[2] = additional selection flag, only 'o' for now. * and %flags to specify what fields to output * plus a ,querytype if the t flag is specified * so the final thing will be like o%tnchu,777 * parv[3] = _optional_ parameter that overrides parv[1] * This can be used as "/quote who foo % :The Black Hacker * to find me, parv[3] _can_ contain spaces !. */ int m_who(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { char *mask; /* The mask we are looking for */ char ch; /* Scratch char register */ struct Channel *chptr; /* Channel to show */ struct Client *acptr; /* Client to show */ int bitsel; /* Mask of selectors to apply */ int matchsel; /* Which fields the match should apply on */ int counter; /* Query size counter, initially used to count fields */ int commas; /* Does our mask contain any comma ? If so is a list.. */ int fields; /* Mask of fields to show */ int isthere = 0; /* When this set the user is member of chptr */ char *nick; /* Single element extracted from the mask list */ char *p; /* Scratch char pointer */ char *qrt; /* Pointer to the query type */ static char mymask[512]; /* To save the mask before corrupting it */ /* Let's find where is our mask, and if actually contains something */ mask = ((parc > 1) ? parv[1] : 0); if (parc > 3 && parv[3]) mask = parv[3]; if (mask && ((mask[0] == '\0') || (mask[1] == '\0' && ((mask[0] == '0') || (mask[0] == '*'))))) mask = 0; /* Evaluate the flags now, we consider the second parameter as "matchFlags%fieldsToInclude,querytype" */ bitsel = fields = counter = matchsel = 0; qrt = 0; if (parc > 2 && parv[2] && *parv[2]) { p = parv[2]; while (((ch = *(p++))) && (ch != '%') && (ch != ',')) switch (ch) { case 'd': case 'D': bitsel |= WHOSELECT_DELAY; continue; case 'o': case 'O': bitsel |= WHOSELECT_OPER; continue; case 'x': case 'X': bitsel |= WHOSELECT_EXTRA; if (HasPriv(sptr, PRIV_WHOX)) log_write(LS_WHO, L_INFO, LOG_NOSNOTICE, "%#C WHO %s %s", sptr, (BadPtr(parv[3]) ? parv[1] : parv[3]), parv[2]); continue; case 'n': case 'N': matchsel |= WHO_FIELD_NIC; continue; case 'u': case 'U': matchsel |= WHO_FIELD_UID; continue; case 'h': case 'H': matchsel |= WHO_FIELD_HOS; continue; case 'i': case 'I': matchsel |= WHO_FIELD_NIP; continue; case 's': case 'S': matchsel |= WHO_FIELD_SER; continue; case 'r': case 'R': matchsel |= WHO_FIELD_REN; continue; case 'a': case 'A': matchsel |= WHO_FIELD_ACC; continue; } if (ch == '%') while ((ch = *p++) && (ch != ',')) { counter++; switch (ch) { case 'c': case 'C': fields |= WHO_FIELD_CHA; break; case 'd': case 'D': fields |= WHO_FIELD_DIS; break; case 'f': case 'F': fields |= WHO_FIELD_FLA; break; case 'h': case 'H': fields |= WHO_FIELD_HOS; break; case 'i': case 'I': fields |= WHO_FIELD_NIP; break; case 'l': case 'L': fields |= WHO_FIELD_IDL; case 'n': case 'N': fields |= WHO_FIELD_NIC; break; case 'r': case 'R': fields |= WHO_FIELD_REN; break; case 's': case 'S': fields |= WHO_FIELD_SER; break; case 't': case 'T': fields |= WHO_FIELD_QTY; break; case 'u': case 'U': fields |= WHO_FIELD_UID; break; case 'a': case 'A': fields |= WHO_FIELD_ACC; break; case 'o': case 'O': fields |= WHO_FIELD_OPL; break; default: break; } }; if (ch) qrt = p; } if (!matchsel) matchsel = WHO_FIELD_DEF; if (!fields) counter = 7; if (feature_bool(FEAT_HIS_WHO_SERVERNAME) && !IsAnOper(sptr)) matchsel &= ~WHO_FIELD_SER; if (qrt && (fields & WHO_FIELD_QTY)) { p = qrt; if (!((*p > '9') || (*p < '0'))) p++; if (!((*p > '9') || (*p < '0'))) p++; if (!((*p > '9') || (*p < '0'))) p++; *p = '\0'; } else qrt = 0; /* I'd love to add also a check on the number of matches fields per time */ counter = (2048 / (counter + 4)); if (mask && (strlen(mask) > 510)) mask[510] = '\0'; move_marker(); commas = (mask && strchr(mask, ',')); /* First treat mask as a list of plain nicks/channels */ if (mask) { strcpy(mymask, mask); for (p = 0, nick = ircd_strtok(&p, mymask, ","); nick; nick = ircd_strtok(&p, 0, ",")) { if (IsChannelName(nick) && (chptr = FindChannel(nick))) { isthere = (find_channel_member(sptr, chptr) != 0); if (isthere || SEE_CHANNEL(sptr, chptr, bitsel)) { struct Membership* member; for (member = chptr->members; member; member = member->next_member) { acptr = member->user; if ((bitsel & WHOSELECT_OPER) && !SeeOper(sptr,acptr)) continue; if ((acptr != sptr) && ((member->status & CHFL_ZOMBIE) || ((member->status & CHFL_DELAYED) && !(bitsel & WHOSELECT_DELAY)))) continue; if (!(isthere || (SEE_USER(sptr, acptr, bitsel)))) continue; if (!Process(acptr)) /* This can't be moved before other checks */ continue; if (!(isthere || (SHOW_MORE(sptr, counter)))) break; do_who(sptr, acptr, chptr, fields, qrt); } } } else { if ((acptr = FindUser(nick)) && ((!(bitsel & WHOSELECT_OPER)) || SeeOper(sptr,acptr)) && Process(acptr) && SHOW_MORE(sptr, counter)) { do_who(sptr, acptr, 0, fields, qrt); } } } } /* If we didn't have any comma in the mask treat it as a real mask and try to match all relevant fields */ if (!(commas || (counter < 1))) { struct irc_in_addr imask; int minlen, cset; unsigned char ibits; if (mask) { matchcomp(mymask, &minlen, &cset, mask); if (!ipmask_parse(mask, &imask, &ibits)) matchsel &= ~WHO_FIELD_NIP; if ((minlen > NICKLEN) || !(cset & NTL_IRCNK)) matchsel &= ~WHO_FIELD_NIC; if ((matchsel & WHO_FIELD_SER) && ((minlen > HOSTLEN) || (!(cset & NTL_IRCHN)) || (!markMatchexServer(mymask, minlen)))) matchsel &= ~WHO_FIELD_SER; if ((minlen > USERLEN) || !(cset & NTL_IRCUI)) matchsel &= ~WHO_FIELD_UID; if ((minlen > HOSTLEN) || !(cset & NTL_IRCHN)) matchsel &= ~WHO_FIELD_HOS; if ((minlen > ACCOUNTLEN)) matchsel &= ~WHO_FIELD_ACC; } /* First of all loop through the clients in common channels */ if ((!(counter < 1)) && matchsel) { struct Membership* member; struct Membership* chan; for (chan = cli_user(sptr)->channel; chan; chan = chan->next_channel) { chptr = chan->channel; for (member = chptr->members; member; member = member->next_member) { acptr = member->user; if (!(IsUser(acptr) && Process(acptr))) continue; /* Now Process() is at the beginning, if we fail we'll never have to show this acptr in this query */ if ((bitsel & WHOSELECT_OPER) && !SeeOper(sptr,acptr)) continue; if ((mask) && ((!(matchsel & WHO_FIELD_NIC)) || matchexec(cli_name(acptr), mymask, minlen)) && ((!(matchsel & WHO_FIELD_UID)) || matchexec(cli_user(acptr)->username, mymask, minlen)) && ((!(matchsel & WHO_FIELD_SER)) || (!(HasFlag(cli_user(acptr)->server, FLAG_MAP)))) && ((!(matchsel & WHO_FIELD_HOS)) || matchexec(cli_user(acptr)->host, mymask, minlen)) && ((!(matchsel & WHO_FIELD_HOS)) || !HasHiddenHost(acptr) || !IsAnOper(sptr) || matchexec(cli_user(acptr)->realhost, mymask, minlen)) && ((!(matchsel & WHO_FIELD_REN)) || matchexec(cli_info(acptr), mymask, minlen)) && ((!(matchsel & WHO_FIELD_NIP)) || (HasHiddenHost(acptr) && !IsAnOper(sptr)) || !ipmask_check(&cli_ip(acptr), &imask, ibits)) && ((!(matchsel & WHO_FIELD_ACC)) || matchexec(cli_user(acptr)->account, mymask, minlen))) continue; if (!SHOW_MORE(sptr, counter)) break; do_who(sptr, acptr, chptr, fields, qrt); } } } /* Loop through all clients :-\, if we still have something to match to and we can show more clients */ if ((!(counter < 1)) && matchsel) for (acptr = cli_prev(&me); acptr; acptr = cli_prev(acptr)) { if (!(IsUser(acptr) && Process(acptr))) continue; if ((bitsel & WHOSELECT_OPER) && !SeeOper(sptr,acptr)) continue; if (!(SEE_USER(sptr, acptr, bitsel))) continue; if ((mask) && ((!(matchsel & WHO_FIELD_NIC)) || matchexec(cli_name(acptr), mymask, minlen)) && ((!(matchsel & WHO_FIELD_UID)) || matchexec(cli_user(acptr)->username, mymask, minlen)) && ((!(matchsel & WHO_FIELD_SER)) || (!(HasFlag(cli_user(acptr)->server, FLAG_MAP)))) && ((!(matchsel & WHO_FIELD_HOS)) || matchexec(cli_user(acptr)->host, mymask, minlen)) && ((!(matchsel & WHO_FIELD_HOS)) || !HasHiddenHost(acptr) || !IsAnOper(sptr) || matchexec(cli_user(acptr)->realhost, mymask, minlen)) && ((!(matchsel & WHO_FIELD_REN)) || matchexec(cli_info(acptr), mymask, minlen)) && ((!(matchsel & WHO_FIELD_NIP)) || (HasHiddenHost(acptr) && !IsAnOper(sptr)) || !ipmask_check(&cli_ip(acptr), &imask, ibits)) && ((!(matchsel & WHO_FIELD_ACC)) || matchexec(cli_user(acptr)->account, mymask, minlen))) continue; if (!SHOW_MORE(sptr, counter)) break; do_who(sptr, acptr, 0, fields, qrt); } } /* Make a clean mask suitable to be sent in the "end of" */ if (mask && (p = strchr(mask, ' '))) *p = '\0'; /* Notify the user if we decided that his query was too long */ if (counter < 0) send_reply(sptr, ERR_QUERYTOOLONG, BadPtr(mask) ? "*" : mask); send_reply(sptr, RPL_ENDOFWHO, BadPtr(mask) ? "*" : mask); return 0; }
/** Interpret \a client as a client specifier and show which Client * block(s) match that client. * * The client specifier may contain an IP address, hostname, listener * port, or a combination of those separated by commas. IP addresses * and hostnamese may be preceded by "username@"; the last given * username will be used for the match. * * @param[in] client Client specifier. * @return Matching Client block structure. */ struct ConfItem *conf_debug_iline(const char *client) { struct irc_in_addr address; struct ConfItem *aconf; struct DenyConf *deny; char *sep; unsigned short listener; char username[USERLEN+1], hostname[HOSTLEN+1], realname[REALLEN+1]; /* Initialize variables. */ listener = 0; memset(&address, 0, sizeof(address)); memset(&username, 0, sizeof(username)); memset(&hostname, 0, sizeof(hostname)); memset(&realname, 0, sizeof(realname)); /* Parse client specifier. */ while (*client) { struct irc_in_addr tmpaddr; long tmp; /* Try to parse as listener port number first. */ tmp = strtol(client, &sep, 10); if (tmp && (*sep == '\0' || *sep == ',')) { listener = tmp; client = sep + (*sep != '\0'); continue; } /* Maybe username@ before an IP address or hostname? */ tmp = strcspn(client, ",@"); if (client[tmp] == '@') { if (tmp > USERLEN) tmp = USERLEN; ircd_strncpy(username, client, tmp); /* and fall through */ client += tmp + 1; } /* Looks like an IP address? */ tmp = ircd_aton(&tmpaddr, client); if (tmp && (client[tmp] == '\0' || client[tmp] == ',')) { memcpy(&address, &tmpaddr, sizeof(address)); client += tmp + (client[tmp] != '\0'); continue; } /* Realname? */ if (client[0] == '$' && client[1] == 'R') { client += 2; for (tmp = 0; *client != '\0' && *client != ',' && tmp < REALLEN; ++client, ++tmp) { if (*client == '\\') realname[tmp] = *++client; else realname[tmp] = *client; } continue; } /* Else must be a hostname. */ tmp = strcspn(client, ","); if (tmp > HOSTLEN) tmp = HOSTLEN; ircd_strncpy(hostname, client, tmp); client += tmp + (client[tmp] != '\0'); } /* Walk configuration to find matching Client block. */ for (aconf = GlobalConfList; aconf; aconf = aconf->next) { if (aconf->status != CONF_CLIENT) continue; if (aconf->address.port && aconf->address.port != listener) { fprintf(stdout, "Listener port mismatch: %u != %u\n", aconf->address.port, listener); continue; } if (aconf->username && match(aconf->username, username)) { fprintf(stdout, "Username mismatch: %s != %s\n", aconf->username, username); continue; } if (aconf->host && match(aconf->host, hostname)) { fprintf(stdout, "Hostname mismatch: %s != %s\n", aconf->host, hostname); continue; } if ((aconf->addrbits >= 0) && !ipmask_check(&address, &aconf->address.addr, aconf->addrbits)) { fprintf(stdout, "IP address mismatch: %s != %s\n", aconf->name, ircd_ntoa(&address)); continue; } fprintf(stdout, "Match! username=%s host=%s ip=%s class=%s maxlinks=%u password=%s\n", (aconf->username ? aconf->username : "******"), (aconf->host ? aconf->host : "(null)"), (aconf->name ? aconf->name : "(null)"), ConfClass(aconf), aconf->maximum, (aconf->passwd ? aconf->passwd : "(null)")); break; } /* If no authorization, say so and exit. */ if (!aconf) { fprintf(stdout, "No authorization found.\n"); return NULL; } /* Look for a Kill block with the user's name on it. */ for (deny = denyConfList; deny; deny = deny->next) { if (deny->usermask && match(deny->usermask, username)) continue; if (deny->realmask && match(deny->realmask, realname)) continue; if (deny->bits > 0) { if (!ipmask_check(&address, &deny->address, deny->bits)) continue; } else if (deny->hostmask && match(deny->hostmask, hostname)) continue; /* Looks like a match; report it. */ fprintf(stdout, "Denied! usermask=%s realmask=\"%s\" hostmask=%s (bits=%u)\n", deny->usermask ? deny->usermask : "(null)", deny->realmask ? deny->realmask : "(null)", deny->hostmask ? deny->hostmask : "(null)", deny->bits); } return aconf; }
/** Searches for a K/G-line for a client. If one is found, notify the * user and disconnect them. * @param cptr Client to search for. * @return 0 if client is accepted; -1 if client was locally denied * (K-line); -2 if client was globally denied (G-line); -3 if client * was globally IP denied (Z-line). */ int find_kill(struct Client *cptr) { const char* host; const char* name; const char* realname; const char* country; const char* continent; const char* version; struct DenyConf* deny; struct Gline* agline = NULL; struct Zline* azline = NULL; assert(0 != cptr); if (!cli_user(cptr)) return 0; host = cli_sockhost(cptr); name = cli_user(cptr)->username; realname = cli_info(cptr); country = cli_countrycode(cptr); continent = cli_continentcode(cptr); version = cli_version(cptr); assert(strlen(host) <= HOSTLEN); assert((name ? strlen(name) : 0) <= HOSTLEN); assert((realname ? strlen(realname) : 0) <= REALLEN); assert((country ? strlen(country) : 0) <= 3); assert((continent ? strlen(continent) : 0) <= 3); assert((version ? strlen(version) : 0) <= VERSIONLEN); /* 2000-07-14: Rewrote this loop for massive speed increases. * -- Isomer */ if (!find_except_conf(cptr, EFLAG_KLINE)) { for (deny = denyConfList; deny; deny = deny->next) { if (deny->usermask && match(deny->usermask, name)) continue; if (deny->realmask && match(deny->realmask, realname)) continue; if (deny->countrymask && country && match(deny->countrymask, country)) continue; if (deny->continentmask && continent && match(deny->continentmask, continent)) continue; if (feature_bool(FEAT_CTCP_VERSIONING) && feature_bool(FEAT_CTCP_VERSIONING_KILL)) { if (deny->version && version && match(deny->version, version)) continue; } if (deny->bits > 0) { if (!ipmask_check(&cli_ip(cptr), &deny->address, deny->bits)) continue; } else if (deny->hostmask && match(deny->hostmask, host)) continue; if ((deny->flags & DENY_FLAGS_AUTHEX) && IsAccount(cptr)) { if (!EmptyString(deny->mark) && EmptyString(cli_killmark(cptr))) ircd_strncpy(cli_killmark(cptr), deny->mark, BUFSIZE); continue; } if (EmptyString(deny->message)) send_reply(cptr, SND_EXPLICIT | ERR_YOUREBANNEDCREEP, ":Connection from your host is refused on this server."); else { if (deny->flags & DENY_FLAGS_FILE) killcomment(cptr, deny->message); else send_reply(cptr, SND_EXPLICIT | ERR_YOUREBANNEDCREEP, ":%s.", deny->message); } return -1; } } /* Check Zlines here just in case a spoofed IP matches */ if (!feature_bool(FEAT_DISABLE_ZLINES) && (azline = zline_lookup(cptr, 0))) { /* * find active zlines * added a check against the user's IP address to find_zline() */ send_reply(cptr, SND_EXPLICIT | ERR_YOUREBANNEDCREEP, ":%s.", ZlineReason(azline)); return -3; } /* Don't need to do an except lookup here as it's done in gline_lookup() */ if (!feature_bool(FEAT_DISABLE_GLINES) && (agline = gline_lookup(cptr, 0))) { /* * find active glines * added a check against the user's IP address to find_gline() -Kev */ send_reply(cptr, SND_EXPLICIT | ERR_YOUREBANNEDCREEP, ":%s.", GlineReason(agline)); return -2; } return 0; }
void th_adjusthosts(trusthost *th, trusthost *superset, trusthost *subset) { struct irc_in_addr ipaddress_canonical; /* * First and foremost, CIDR doesn't allow hosts to cross boundaries, i.e. everything with a smaller prefix * is entirely contained with the prefix that is one smaller. * e.g. 0.0.0.0/23, 0.0.0.128/23, you can't have a single prefix for 0.0.0.64-0.0.0.192, instead * you have two, 0.0.0.64/26 and 0.0.0.128/26. * * This makes the code MUCH easier as the entire thing is one huge set/tree. * * Four cases here: * 1: host isn't covered by any existing hosts. * 2: host is covered by a less specific one only, e.g. adding 0.0.0.1/32, while 0.0.0.0/24 already exists. * 3: host is covered by a more specific one only, e.g. adding 0.0.0.0/24 while 0.0.0.1/32 already exists * (note there might be more than one more specific host, e.g. 0.0.0.1/32 and 0.0.0.2/32). * 4: covered by more and less specific cases, e.g. adding 0.0.0.0/24 to: { 0.0.0.1/32, 0.0.0.2/32, 0.0.0.0/16 }. * * CASE 1 * ------ * * !superset && !subset * * Scan through the host hash and add any clients which match our host, this is exactly the same as case 3 * but without needing to check (though checking doesn't hurt), so we'll just use the code for that. * * CASE 2 * ------ * * superset && !subset * * We have the less specific host in 'superset', we know it is the only one so pull out clients in it's * ->users list matching our new host. * No need to look for extra hosts in the main nick hash as they're all covered already. * * CASE 3 * ------ * * !superset && subset * * We have one host in 'subset', but there might be more than one, we don't care though! * We can scan the entire host hash and pull out any hosts that match us and don't have * a trust group already, this ignores any with a more specific prefix. * * CASE 4 * ------ * * superset && subset * * Here we first fix up the ones less specific then us, so we just perform what we did for case 2, * then we perform what we did for case 3. * * So in summary: * CASE 1: DO 3 * CASE 2: (work) * CASE 3: (work) * CASE 4: DO 2; DO 3 * Or: * if(2 || 4) : DO 2 * if(1 || 3 || 4): DO 3 */ /* we let the compiler do the boolean minimisation for clarity reasons */ if((superset && !subset) || (superset && subset)) { /* cases 2 and 4 */ nick *np, *nnp; for(np=superset->users;np;np=nnp) { nnp = nextbytrust(np); ip_canonicalize_tunnel(&ipaddress_canonical, &np->ipaddress); if(ipmask_check(&ipaddress_canonical, &th->ip, th->bits)) { trusts_lostnick(np, 1); trusts_newnick(np, 1); } } } if((!superset && !subset) || (!superset && subset) || (superset && subset)) { /* cases 1, 3 and 4 */ nick *np; int i; for(i=0;i<NICKHASHSIZE;i++) { for(np=nicktable[i];np;np=np->next) { ip_canonicalize_tunnel(&ipaddress_canonical, &np->ipaddress); if(!gettrusthost(np) && ipmask_check(&ipaddress_canonical, &th->ip, th->bits)) trusts_newnick(np, 1); } } } }