Пример #1
0
pair<u8 *, size_t> setupFDRFloodControl(const vector<hwlmLiteral> &lits,
                                        const EngineDescription &eng) {
    vector<FDRFlood> tmpFlood(N_CHARS);
    u32 default_suffix = eng.getDefaultFloodSuffixLength();

    // zero everything to avoid spurious distinctions in the compares
    memset(&tmpFlood[0], 0, N_CHARS * sizeof(FDRFlood));

    for (u32 c = 0; c < N_CHARS; c++) {
        tmpFlood[c].suffix = default_suffix;
    }

    for (const auto &lit : lits) {
        DEBUG_PRINTF("lit: '%s'%s\n", escapeString(lit.s).c_str(),
                     lit.nocase ? " (nocase)" : "");
        u32 litSize = verify_u32(lit.s.size());
        u32 maskSize = (u32)lit.msk.size();
        u8 c = lit.s[litSize - 1];
        bool nocase = ourisalpha(c) ? lit.nocase : false;

        if (nocase && maskSize && (lit.msk[maskSize - 1] & CASE_BIT)) {
            c = (lit.cmp[maskSize - 1] & CASE_BIT) ? mytolower(c) : mytoupper(c);
            nocase = false;
        }

        u32 iEnd = MAX(litSize, maskSize);
        u32 upSuffix = iEnd; // upSuffix is used as an upper case suffix length
                             // for case-less, or as a suffix length for case-sensitive;
        u32 loSuffix = iEnd; // loSuffix used only for case-less as a lower case suffix
                             // length;

        for (u32 i = 0; i < iEnd; i++) {
            if (i < litSize) {
                if (isDifferent(c, lit.s[litSize - i - 1], lit.nocase)) {
                    DEBUG_PRINTF("non-flood char in literal[%u] %c != %c\n",
                                                i, c, lit.s[litSize - i - 1]);
                    upSuffix = MIN(upSuffix, i);
                    loSuffix = MIN(loSuffix, i); // makes sense only for case-less
                    break;
                }
            }
            if (i < maskSize) {
                u8 m = lit.msk[maskSize - i - 1];
                u8 cm = lit.cmp[maskSize - i - 1] & m;
                if(nocase) {
                    if ((mytoupper(c) & m) != cm) {
                        DEBUG_PRINTF("non-flood char in mask[%u] %c != %c\n",
                                                            i, mytoupper(c), cm);
                        upSuffix = MIN(upSuffix, i);
                    }
                    if ((mytolower(c) & m) != cm) {
                        DEBUG_PRINTF("non-flood char in mask[%u] %c != %c\n",
                                                            i, mytolower(c), cm);
                        loSuffix = MIN(loSuffix, i);
                    }
                    if (loSuffix != iEnd && upSuffix != iEnd) {
                        break;
                    }
                } else if ((c & m) != cm) {
                    DEBUG_PRINTF("non-flood char in mask[%u] %c != %c\n", i, c, cm);
                    upSuffix = MIN(upSuffix, i);
                    break;
                }
            }
        }
        if(upSuffix != iEnd) {
            updateFloodSuffix(tmpFlood, nocase ? mytoupper(c) : c, upSuffix);
        } else {
            addFlood(tmpFlood, nocase ? mytoupper(c) : c, lit, upSuffix);
        }
        if (nocase) {
            if(loSuffix != iEnd) {
                updateFloodSuffix(tmpFlood, mytolower(c), loSuffix);
            } else {
                addFlood(tmpFlood, mytolower(c), lit, loSuffix);
            }
        }
    }

#ifdef DEBUG
    for (u32 i = 0; i < N_CHARS; i++) {
        FDRFlood &fl = tmpFlood[i];
        if (!fl.idCount) {
            continue;
        }

        printf("i is %02x fl->idCount is %hd fl->suffix is %d fl->allGroups is "
               "%016llx\n", i, fl.idCount, fl.suffix, fl.allGroups);
        for (u32 j = 0; j < fl.idCount; j++) {
            printf("j is %d fl.groups[j] %016llx fl.len[j] %d \n", j,
                   fl.groups[j], fl.len[j]);
        }
    }
#endif

    map<FDRFlood, CharReach, FloodComparator> flood2chars;
    for (u32 i = 0; i < N_CHARS; i++) {
        FDRFlood fl = tmpFlood[i];
        flood2chars[fl].set(i);
    }

    u32 nDistinctFloods = flood2chars.size();
    size_t floodHeaderSize = sizeof(u32) * N_CHARS;
    size_t floodStructSize = sizeof(FDRFlood) * nDistinctFloods;
    size_t totalSize = ROUNDUP_16(floodHeaderSize + floodStructSize);
    u8 *buf = (u8 *)aligned_zmalloc(totalSize);
    assert(buf); // otherwise would have thrown std::bad_alloc

    u32 *floodHeader = (u32 *)buf;
    FDRFlood *layoutFlood = (FDRFlood * )(buf + floodHeaderSize);

    u32 currentFloodIndex = 0;
    for (const auto &m : flood2chars) {
        const FDRFlood &fl = m.first;
        const CharReach &cr = m.second;
        layoutFlood[currentFloodIndex] = fl;
        for (size_t c = cr.find_first(); c != cr.npos; c = cr.find_next(c)) {
            floodHeader[c] = currentFloodIndex;
        }
        currentFloodIndex++;
    }

    DEBUG_PRINTF("made a flood structure with %zu + %zu = %zu\n",
                 floodHeaderSize, floodStructSize, totalSize);

    return make_pair((u8 *)buf, totalSize);
}
Пример #2
0
/*
 * WARNING WARNING WARNING
 *
 *  This function is very ugly in terms of args handling, and it is
 *  very easy to inadvertently break something if you make small tweaks
 *  to it.
 *
 *  args and numargs do NOT always map together in this function,
 *  for example numargs = 3, means that args really has 3+3=6 elements
 *  in some points: numargs should be numargs2.
 *
 *  Basically, the bottom two elements of args[] are dropped
 * in this function when
 * it goes to args2 to call the particular handlers -Mysid
 */
void
parseLine(char *line)
{
	int i = 0, a = 0, x = 0, prefixed = 0;
	char *args2[MAX_IRC_LINE_LEN + 5];
	char *args[MAX_IRC_LINE_LEN + 5];
	char realargs[151][151];
	u_int16_t numargs = 0;
	/* 
	 * Seems Ok to me ^^^ 
	 * sizes may be off(?)
	 */

	/* Yes, your sizes were off.. -Mysid */

	strncpyzt(coreBuffer, line, MAX_IRC_LINE_LEN);
#ifdef DEBUG
	printf("Read: %s\n", coreBuffer);
#endif

	CTime = time(NULL);

	while (*line && x < 150) {
		while (*line != ' ' && *line && a < 150) {
			realargs[x][a] = *line;
			a++;
			line++;
		}
		realargs[x][a] = 0;
		args[x] = realargs[x];
		x++;
		numargs++;
		while (*line == ' ')
			line++;
		a = 0;
	}

	/* ensure the next item is null so we can check it later */
	realargs[x][0] = 0;
	args[x] = realargs[x];

	if (args[0][0] == ':') {
		prefixed = 1;
				 /** \bug old lame bugfix, what would be better is to use a 'from'
                    value and args++'ing it, if there's no prefix then
                    have from set to the uplink -Mysid */
		args[0]++;
	} else
		prefixed = 0;

	if (!strcmp(args[0], "PING") && !prefixed) {
		sSend("PONG :%s", myname);
		return;
	}

	else if (!strcmp(args[0], "ERROR") && !strcmp(args[1], ":Closing"))
		sshutdown(0);

	else if (!strcmp(args[0], "NICK") && !prefixed) {
		if (strchr(args[4], '*') || strchr(args[4], '?')
			|| strchr(args[4], '!') || strchr(args[4], '@')) {
			char nick[NICKLEN];

			strncpyzt(nick, args[1], NICKLEN);
			sSend
				(":%s KILL %s :%s!%s (Your ident reply contains either a *, !, @, or ?. Please remove this before returning.)",
				 services[1].name, nick, services[1].host,
				 services[1].name);
			addGhost(nick);
			timer(15, delTimedGhost, strdup(nick));
			return;
		}

		addNewUser(args, numargs);	/* nickserv.c, add new user. */
		return;
	}


	if (!strcmp(args[1], "PRIVMSG")) {
		UserList *tmp = getNickData(args[0]);


		if (strchr(args[2], '#') || strchr(args[2], '$'))
			return;

		if (!strcasecmp(args[0], NickServ)
			|| !strcasecmp(args[0], GameServ)
			|| !strcasecmp(args[0], OperServ)
			|| !strcasecmp(args[0], ChanServ)
			|| !strcasecmp(args[0], MemoServ)
			|| !strcasecmp(args[0], InfoServ)) return;

		if (tmp && tmp->reg && tmp->reg->flags & NBANISH) {
			sSend(":%s NOTICE %s :This nickname is banished."
			      "  You cannot use services until you change"
			      " nicknames.",
			      NickServ, args[0]);
			return;
		}

		if (!tmp) {
			nDesynch(args[0], "PRIVMSG");
			return;
		}

		if (addFlood(tmp, 1))
			return;

		if (getBanInfo(tmp->nick, tmp->user, tmp->host, A_IGNORE) != NULL) {
			if (tmp->floodlevel.GetLev() < 2)
				sSend
					(":%s NOTICE %s :You are on services ignore, you may not use any Service",
					 NickServ, tmp->nick);
			if (!isOper(tmp) || tmp->caccess < ACC_RECOGNIZED || !tmp->reg
				|| !(tmp->reg->opflags & OROOT))
				return;
		}

		args[3]++;
		while (*args[3] == ' ')
			args[3]++;

		for (i = 3; i < numargs; i++)
			args2[i - 3] = args[i];
		numargs -= 3;

		/* Handle pings before even going to the services */
		if (!strcasecmp(args2[0], "\001PING")) {
			if (addFlood(tmp, 3))
				return;
			if (numargs < 3)
				sSend(":%s NOTICE %s :\001PING %s", args[2], args[0],
					  args2[1]);
			else
				sSend(":%s NOTICE %s :\001PING %s %s", args[2], args[0],
					  args2[1], args2[2]);
			return;
		}

		/* NOTE: numargs maps to args2 not args at this point */
		if (!strncasecmp(args[2], OperServ, strlen(OperServ)))
			sendToOperServ(tmp, args2, numargs);
		else if (!strncasecmp(args[2], NickServ, strlen(NickServ)))
			sendToNickServ(tmp, args2, numargs);
		else if (!strncasecmp(args[2], ChanServ, strlen(ChanServ)))
			sendToChanServ(tmp, args2, numargs);
		else if (!strncasecmp(args[2], MemoServ, strlen(MemoServ)))
			sendToMemoServ(tmp, args2, numargs);
		else if (!strncasecmp(args[2], InfoServ, strlen(InfoServ)))
			sendToInfoServ(tmp, args2, numargs);
		else if (!strncasecmp(args[2], GameServ, strlen(GameServ)))
			sendToGameServ(tmp, args2, numargs);
		else if (isGhost(args[2])) {
			sSend
				(":%s NOTICE %s :This is a NickServ registered nick enforcer, and not a real user.",
				 args[2], args[0]);
		}
		/* Note, the below should be correct. */
		else if ((numargs >= 1) && adCheck(tmp, args[2], args2, numargs))
			return;
		return;
	}

	else if (!strcmp(args[1], "QUIT")) {
		remUser(args[0], 0);
		return;
	} else if (!strcmp(args[1], "NICK")) {
		UserList *tmp = getNickData(args[0]);
		if (addFlood(tmp, 5))
			return;
		changeNick(args[0], args[2], args[3]);
		return;
	} else if (!strcmp(args[1], "MODE") && !strcmp(args[0], args[2])) {
		setMode(args[0], args[3]);
		return;
	} else if (!strcmp(args[1], "MODE")) {
		setChanMode(args, numargs);
		return;
	} else if (!strcmp(args[1], "TOPIC")) {
		setChanTopic(args, numargs);
		return;
	} else if (!strcmp(args[1], "AWAY")) {
		if (numargs < 3) {
			setFlags(args[0], NISAWAY, '-');
			checkMemos(getNickData(args[0]));
		} else
			setFlags(args[0], NISAWAY, '+');
		return;
	}

	else if (!strcmp(args[1], "JOIN")) {
		addUserToChan(getNickData(args[0]), args[2]);
		return;
	} else if (!strcmp(args[1], "PART")) {
		remUserFromChan(getNickData(args[0]), args[2]);
		return;
	} else if (!strcmp(args[1], "KICK")) {
		remUserFromChan(getNickData(args[3]), args[2]);
		return;
	}

	else if (!strcmp(args[1], "KILL")) {
		int i;
		for (i = 0; i < NUMSERVS; i++) {
			if (!strcasecmp(args[2], services[i].name)) {
				addUser(services[i].name, services[i].uname,
						services[i].host, services[i].rname,
						services[i].mode);
				sSend(":%s KILL %s :%s!%s (services kill protection)",
					  services[i].name, args[0], services[i].host,
					  services[i].name);
				sSend(":%s GLOBOPS :%s just killed me!", services[i].name,
					  args[0]);
				remUser(args[0], 0);
				return;
			}
		}

		if (isGhost(args[2])) {
			delGhost(args[2]);
			return;
		}

		else
			remUser(args[2], 1);
		return;
	} else if (!strcmp(args[1], "MOTD")) {
		UserList *tmp = getNickData(args[0]);
		if (addFlood(tmp, 1))
			return;
		motd(args[0]);
		return;
	}

	else if (!strcmp(args[1], "INFO")) {
		UserList *tmp = getNickData(args[0]);
		if (!tmp || addFlood(tmp, 3))
			return;
		sendInfoReply(tmp);
		return;
	}

	else if (!strcmp(args[1], "VERSION")) {
		UserList *tmp = getNickData(args[0]);
		if (addFlood(tmp, 1))
			return;
		sSend(":%s 351 %s %s %s :%s", myname, args[0], VERSION_STRING,
			  myname, VERSION_QUOTE);
		return;
	} else if ((!strcmp(args[1], "GNOTICE") || !strcmp(args[1], "GLOBOPS"))
			   && !strcmp(args[2], ":Link") && !strcmp(args[3], "with")
			   && !strncmp(args[4], myname, strlen(myname))) {
		sSend(":%s GNOTICE :Link with %s[services@%s] established.",
			  myname, args[0], hostname);
		strncpyzt(hostname, args[0], sizeof(hostname));

		expireNicks(NULL);
		expireChans(NULL);
		sync_cfg("1");
		checkTusers(NULL);
		flushLogs(NULL);
		nextNsync = (SYNCTIME + CTime);
		nextCsync = ((SYNCTIME * 2) + CTime);
		nextMsync = ((SYNCTIME * 3) + CTime);
		loadakills();
		return;
	}
#ifdef IRCD_HURTSET
	else if (!strcmp(args[1], "HURTSET") && (numargs >= 4)) {
		UserList *hurtwho;
		if ((hurtwho = getNickData(args[2]))) {
			if (args[3] && *args[3] == '-')
				hurtwho->oflags &= ~(NISAHURT);
			else if (args[3] && atoi(args[3]) == 4) {
				hurtwho->oflags |= (NISAHURT);
			}
			else if (args[3] && isdigit(*args[3])
					 && (getBanInfo(hurtwho->nick, hurtwho->user,
							hurtwho->host, A_AHURT) != NULL)) 
			    hurtwho->oflags |= (NISAHURT);
		}
	}
#endif
	else if (!strcmp(args[1], "SQUIT")) {
		time_t jupe;
		jupe = time(NULL);
		if (strchr(args[2], '.'))
			return;
		sSend(":%s WALLOPS :%s Un-jupitered by %s at %s", myname, args[2],
			  args[0], ctime(&(jupe)));
		return;
	}

	else if (!strcmp(args[1], "STATS") && numargs > 3) {
		const char* from = args[0];

		if (args[2] && !strcasecmp(args[2], "OPTS"))
		{
			sSend(":%s NOTICE %s :Network name: %s", InfoServ, from, NETWORK);


#ifdef AKILLMAILTO
		        sSend(":%s NOTICE %s :Akill log address: %s", InfoServ, from,
		                AKILLMAILTO);
#endif

#ifdef ENABLE_GRPOPS
		        sSend(":%s NOTICE %s :GRPops enabled.",  InfoServ, from);
#endif

#ifdef MD5_AUTH
		        sSend(":%s NOTICE %s :MD5 authentication available.",  InfoServ, from);
#endif

		}
		else if (args[2] && !strcasecmp(args[2], "V$"))
		{
			sSend(":%s NOTICE %s :Based on sn services1.4.", InfoServ, from);
		}
	}

	/* "No N-line" error */
	else if (!strcmp(args[0], "ERROR") && !strcmp(args[1], ":No")) {
		fprintf(stderr, "Error connecting to server: No N-line\n");
		sshutdown(2);
	}
}