#include "ircd_alloc.h"
#include "ircd_chattr.h"
#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_snprintf.h"
#include "ircd_string.h"
#include "list.h"
#include "listener.h"
struct tm motd_tm;
-/*
- * is the K line field an interval or a comment? - Mmmm
- */
-static int is_comment(const char *comment)
-{
- unsigned int i;
- unsigned int len = strlen(comment);
- for (i = 0; i < len; ++i) {
- if (!IsKTimeChar(comment[i]))
- return 1;
- }
- return 0;
-}
-
-/*
- * check against a set of time intervals
- */
-static int check_time_interval(char *interval, char *reply)
-{
- struct tm* tptr;
- char* p;
- int perm_min_hours;
- int perm_min_minutes;
- int perm_max_hours;
- int perm_max_minutes;
- int nowm;
- int perm_min;
- int perm_max;
-
- tptr = localtime(&CurrentTime);
- nowm = tptr->tm_hour * 60 + tptr->tm_min;
-
- while (interval) {
- p = strchr(interval, ',');
- if (p)
- *p = '\0';
- if (sscanf(interval, "%2d%2d-%2d%2d", &perm_min_hours, &perm_min_minutes,
- &perm_max_hours, &perm_max_minutes) != 4)
- {
- if (p)
- *p = ',';
- return 0;
- }
- if (p)
- *(p++) = ',';
- perm_min = 60 * perm_min_hours + perm_min_minutes;
- perm_max = 60 * perm_max_hours + perm_max_minutes;
- /*
- * The following check allows intervals over midnight ...
- */
- if ((perm_min < perm_max)
- ? (perm_min <= nowm && nowm <= perm_max)
- : (perm_min <= nowm || nowm <= perm_max))
- {
- sprintf_irc(reply, ":%%s %%d %%s :%s %d:%02d to %d:%02d.",
- "You are not allowed to connect from",
- perm_min_hours, perm_min_minutes,
- perm_max_hours, perm_max_minutes);
- return (ERR_YOUREBANNEDCREEP);
- }
- if ((perm_min < perm_max)
- ? (perm_min <= nowm + 5 && nowm + 5 <= perm_max)
- : (perm_min <= nowm + 5 || nowm + 5 <= perm_max))
- {
- sprintf_irc(reply, ":%%s %%d %%s :%d minute%s%s",
- perm_min - nowm, (perm_min - nowm) > 1 ? "s " : " ",
- "and you will be denied for further access");
- return (ERR_YOUWILLBEBANNED);
- }
- interval = p;
- }
- return 0;
-}
-
/*
* output the reason for being k lined from a file - Mmmm
* sptr is server
{
FBFILE* file = NULL;
char line[80];
- char* tmp;
+ char* tmp = NULL;
struct stat sb;
struct tm* tm;
if (NULL == (file = fbopen(filename, "r"))) {
- sendto_one(sptr, err_str(ERR_NOMOTD), me.name, parv);
- sendto_one(sptr,
- ":%s %d %s :Connection from your host is refused on this server.",
- me.name, ERR_YOUREBANNEDCREEP, parv);
+ send_reply(sptr, ERR_NOMOTD);
+ send_reply(sptr, SND_EXPLICIT | ERR_YOUREBANNEDCREEP,
+ ":Connection from your host is refused on this server.");
return;
}
fbstat(&sb, file);
*tmp = '\0';
if ((tmp = strchr(line, '\r')))
*tmp = '\0';
- /* sendto_one(sptr,
- * ":%s %d %s : %s.",
- * me.name, ERR_YOUREBANNEDCREEP, parv,line); */
- sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv, line);
+ send_reply(sptr, RPL_MOTD, line);
}
- sendto_one(sptr,
- ":%s %d %s :Connection from your host is refused on this server.",
- me.name, ERR_YOUREBANNEDCREEP, parv);
+ send_reply(sptr, SND_EXPLICIT | ERR_YOUREBANNEDCREEP,
+ ":Connection from your host is refused on this server.");
fbclose(file);
}
/*
* check_limit_and_attach - check client limits and attach I:line
+ *
+ * Made it accept 1 charactor, and 2 charactor limits (0->99 now),
+ * and dislallow more than 255 people here as well as in ipcheck.
+ * removed the old "ONE" scheme too.
+ * -- Isomer 2000-06-22
*/
-static int check_limit_and_attach(struct Client* cptr, struct ConfItem* aconf)
+static enum AuthorizationCheckResult
+check_limit_and_attach(struct Client* cptr, struct ConfItem* aconf)
{
+ int number = 255;
+
if (aconf->passwd) {
- /* Special case: exactly one digit */
- if (IsDigit(*aconf->passwd) && !aconf->passwd[1]) {
- /*
- * Refuse connections when there are already <digit>
- * clients connected with the same IP number
- */
- unsigned short nr = *aconf->passwd - '0';
- if (IPcheck_nr(cptr) > nr)
- return ACR_TOO_MANY_FROM_IP; /* Already got nr with that ip# */
- }
-#ifdef USEONE
- else if (0 == strcmp(aconf->passwd, "ONE")) {
- int i;
- for (i = HighestFd; i > -1; --i) {
- if (LocalClientArray[i] && MyUser(LocalClientArray[i]) &&
- LocalClientArray[i]->ip.s_addr == cptr->ip.s_addr)
- return ACR_TOO_MANY_FROM_IP; /* Already got one with that ip# */
- }
- }
-#endif
+ if (IsDigit(*aconf->passwd) && !aconf->passwd[1])
+ number = *aconf->passwd-'0';
+ else if (IsDigit(*aconf->passwd) && IsDigit(aconf->passwd[1]) &&
+ !aconf->passwd[2])
+ number = (*aconf->passwd-'0')*10+(aconf->passwd[1]-'0');
}
+ if (ip_registry_count(cptr->ip.s_addr) > number)
+ return ACR_TOO_MANY_FROM_IP;
return attach_conf(cptr, aconf);
}
/*
* Find the first (best) I line to attach.
*/
-int attach_iline(struct Client* cptr)
+enum AuthorizationCheckResult attach_iline(struct Client* cptr)
{
struct ConfItem* aconf;
const char* hname;
* connection). Note, that this automaticly changes the
* attachment if there was an old one...
*/
-int attach_conf(struct Client *cptr, struct ConfItem *aconf)
+enum AuthorizationCheckResult attach_conf(struct Client *cptr, struct ConfItem *aconf)
{
struct SLink *lp;
struct ConfItem *tmp;
char userhost[USERLEN + HOSTLEN + 3];
- /*
- * XXX - buffer overflow possible, unchecked variables
- */
if (user)
- sprintf_irc(userhost, "%s@%s", user, host);
+ ircd_snprintf(0, userhost, sizeof(userhost), "%s@%s", user, host);
else
ircd_strncpy(userhost, host, sizeof(userhost) - 1);
struct ConfItem* find_conf_byhost(struct SLink* lp, const char* host,
int statmask)
{
- struct ConfItem* tmp;
+ struct ConfItem* tmp = NULL;
assert(0 != host);
if (HOSTLEN < strlen(host))
int found_g = 0;
if (1 == sig)
- sendto_ops("Got signal SIGHUP, reloading ircd conf. file");
+ sendto_opmask_butone(0, SNO_OLDSNO,
+ "Got signal SIGHUP, reloading ircd conf. file");
while ((tmp2 = *tmp)) {
if (tmp2->clients) {
attach_confs_byname(acptr, acptr->name,
CONF_HUB | CONF_LEAF | CONF_UWORLD);
}
+ /* Because admin's are getting so uppity about people managing to
+ * get past K/G's etc, we'll "fix" the bug by actually explaining
+ * whats going on.
+ */
if ((found_g = find_kill(acptr))) {
- sendto_op_mask(found_g == -2 ? SNO_GLINE : SNO_OPERKILL,
- found_g == -2 ? "G-line active for %s" : "K-line active for %s",
- get_client_name(acptr, HIDE_IP));
+ sendto_opmask_butone(0, found_g == -2 ? SNO_GLINE : SNO_OPERKILL,
+ found_g == -2 ? "G-line active for %s%s" :
+ "K-line active for %s%s",
+ IsUnknown(acptr) ? "Unregistered Client ":"",
+ get_client_name(acptr, HIDE_IP));
if (exit_client(cptr, acptr, &me, found_g == -2 ? "G-lined" :
"K-lined") == CPTR_KILLED)
ret = CPTR_KILLED;
/* Could we test if it's conf line at all? -Vesa */
if (line[1] != ':') {
Debug((DEBUG_ERROR, "Bad config line: %s", line));
+ sendto_op_mask(SNO_OLDSNO,"Bad Config line");
continue;
}
if (aconf)
break;
default:
Debug((DEBUG_ERROR, "Error in config file: %s", line));
+ sendto_op_mask(SNO_OLDSNO,"Unknown prefix in config file: %c",*tmp);
break;
}
if (IsIllegal(aconf))
if (aconf->status & CONF_ME) {
if (!tmp) {
Debug((DEBUG_FATAL, "Your M: line must have the Numeric, "
- "assigned to you by routing-com, behind the port number!\n"));
+ "assigned to you by routing-com!\n"));
ircd_log(L_WARNING, "Your M: line must have the Numeric, "
- "assigned to you by routing-com, behind the port number!\n");
+ "assigned to you by routing-com!\n");
exit(-1);
}
SetYXXServerName(&me, atoi(tmp)); /* Our Numeric Nick */
len += strlen(aconf->host);
newhost = (char*) MyMalloc(len);
assert(0 != newhost);
- sprintf_irc(newhost, "*@%s", aconf->host);
+ ircd_snprintf(0, newhost, len, "*@%s", aconf->host);
MyFree(aconf->host);
aconf->host = newhost;
}
if (aconf->status == CONF_ME) {
ircd_strncpy(me.info, aconf->name, REALLEN);
}
+
+ if (aconf->status == CONF_IPKILL) {
+ /*
+ * Here we use the same kludge as in listener.c to parse
+ * a.b.c.d, or a.b.c.*, or a.b.c.d/e.
+ */
+ int class;
+ char ipname[16];
+ int ad[4] = { 0 };
+ int bits2=0;
+ class=sscanf(aconf->host,"%d.%d.%d.%d/%d",
+ &ad[0], &ad[1], &ad[2], &ad[3], &bits2);
+ if (class!=5) {
+ aconf->bits=class*8;
+ }
+ else {
+ aconf->bits=bits2;
+ }
+ sprintf_irc(ipname,"%d.%d.%d.%d",ad[0], ad[1], ad[2], ad[3]);
+
+ /* This ensures endian correctness */
+ aconf->ipnum.s_addr = inet_addr(ipname);
+ Debug((DEBUG_DEBUG,"IPkill: %s = %08x/%i (%08x)",ipname,
+ aconf->ipnum.s_addr,aconf->bits,NETMASK(aconf->bits)));
+ }
/*
* Juped nicks are listed in the 'password' field of U:lines,
}
}
+/*
+ * find_kill
+ * input:
+ * client pointer
+ * returns:
+ * 0: Client may continue to try and connect
+ * -1: Client was K/k:'d - sideeffect: reason was sent.
+ * -2: Client was G/g:'d - sideeffect: reason was sent.
+ * sideeffects:
+ * Client may have been sent a reason why they are denied, as above.
+ */
int find_kill(struct Client *cptr)
{
- char reply[256];
const char* host;
const char* name;
struct ConfItem* tmp;
host = cptr->sockhost;
name = cptr->user->username;
-#if 0
- /*
- * whee :)
- * XXX - if this ever happens, we're already screwed
+ assert(strlen(host) <= HOSTLEN);
+ assert((name ? strlen(name) : 0) <= HOSTLEN);
+
+ /* 2000-07-14: Rewrote this loop for massive speed increases.
+ * -- Isomer
*/
- if (strlen(host) > HOSTLEN ||
- (name ? strlen(name) : 0) > HOSTLEN)
- return (0);
-#endif
-
- reply[0] = '\0';
-
for (tmp = GlobalConfList; tmp; tmp = tmp->next) {
- /* Added a check against the user's IP address as well.
- * If the line is either CONF_KILL or CONF_IPKILL, check it; if and only
- * if it's CONF_IPKILL, check the IP address as well (the && below will
- * short circuit and the match won't even get run) -Kev
+
+ if ((tmp->status & CONF_KLINE) == 0)
+ continue;
+
+ /*
+ * What is this for? You can K: by port?!
+ * -- Isomer
*/
- if ((tmp->status & CONF_KLINE) && tmp->host && tmp->name &&
- (match(tmp->host, host) == 0 ||
- ((tmp->status == CONF_IPKILL) &&
- match(tmp->host, ircd_ntoa((const char*) &cptr->ip)) == 0)) &&
- (!name || match(tmp->name, name) == 0) &&
- (!tmp->port || (tmp->port == cptr->listener->port)))
- {
- /*
- * Can short-circuit evaluation - not taking chances
- * because check_time_interval destroys tmp->passwd
- * - Mmmm
- */
- if (EmptyString(tmp->passwd))
- break;
- else if (is_comment(tmp->passwd))
- break;
- else if (check_time_interval(tmp->passwd, reply))
- break;
+ if (tmp->port && tmp->port != cptr->listener->port)
+ continue;
+
+ if (!tmp->name || match(tmp->name, name) != 0)
+ continue;
+
+ if (!tmp->host)
+ break;
+
+ if (tmp->status != CONF_IPKILL) {
+ if (match(tmp->host, host) == 0)
+ break;
+ }
+ else { /* k: by IP */
+ Debug((DEBUG_DEBUG, "ip: %08x network: %08x/%i mask: %08x",
+ cptr->ip.s_addr, tmp->ipnum.s_addr, tmp->bits,
+ NETMASK(tmp->bits)));
+ if ((cptr->ip.s_addr & NETMASK(tmp->bits)) == tmp->ipnum.s_addr)
+ break;
}
}
- if (reply[0])
- sendto_one(cptr, reply, me.name, ERR_YOUREBANNEDCREEP, cptr->name);
- else if (tmp) {
+ if (tmp) {
if (EmptyString(tmp->passwd))
- sendto_one(cptr,
- ":%s %d %s :Connection from your host is refused on this server.",
- me.name, ERR_YOUREBANNEDCREEP, cptr->name);
+ send_reply(cptr, SND_EXPLICIT | ERR_YOUREBANNEDCREEP,
+ ":Connection from your host is refused on this server.");
else {
if (*tmp->passwd == '"') {
- char *sbuf =
- sprintf_irc(sendbuf, ":%s %d %s :%s", me.name, ERR_YOUREBANNEDCREEP,
- cptr->name, &tmp->passwd[1]);
- sbuf[-1] = '.'; /* Overwrite last quote with a dot */
- sendbufto_one(cptr);
+ send_reply(cptr, SND_EXPLICIT | ERR_YOUREBANNEDCREEP, ":%*s.",
+ strlen(tmp->passwd + 1) - 1, tmp->passwd + 1);
}
else if (*tmp->passwd == '!')
killcomment(cptr, cptr->name, &tmp->passwd[1]);
#ifdef COMMENT_IS_FILE
killcomment(cptr, cptr->name, tmp->passwd);
#else
- sendto_one(cptr, ":%s %d %s :%s.", me.name, ERR_YOUREBANNEDCREEP,
- cptr->name, tmp->passwd);
+ send_reply(cptr, SND_EXPLICIT | ERR_YOUREBANNEDCREEP, ":%s.",
+ tmp->passwd);
#endif
}
}
/* find active glines */
/* added a check against the user's IP address to find_gline() -Kev */
- else if ((agline = find_gline(cptr, NULL)) && GlineIsActive(agline))
- sendto_one(cptr, ":%s %d %s :%s.", me.name, ERR_YOUREBANNEDCREEP,
- cptr->name, agline->reason);
+ else if ((agline = gline_lookup(cptr, 0)) && GlineIsActive(agline))
+ send_reply(cptr, SND_EXPLICIT | ERR_YOUREBANNEDCREEP, ":%s.",
+ GlineReason(agline));
else
agline = NULL; /* if a gline was found, it was inactive */
- return (tmp ? -1 : (agline ? -2 : 0));
+ if (tmp)
+ return -1;
+ if (agline)
+ return -2;
+
+ return 0;
}
struct MotdItem* read_motd(const char* motdfile)
*/
enum AuthorizationCheckResult conf_check_client(struct Client *cptr)
{
- int acr;
+ enum AuthorizationCheckResult acr = ACR_OK;
ClearAccess(cptr);
if (IsConnecting(cptr) || IsHandshake(cptr)) {
c_conf = find_conf_byname(lp, cptr->name, CONF_SERVER);
if (!c_conf) {
- sendto_ops("Connect Error: lost C:line for %s", cptr->name);
+ sendto_opmask_butone(0, SNO_OLDSNO, "Connect Error: lost C:line for %s",
+ cptr->name);
det_confs_butmask(cptr, 0);
return -1;
}