mirror of
https://github.com/osmarks/ngircd.git
synced 2025-02-24 05:00:01 +00:00
Fix use-after-free on Lists_CheckReason()
Change Lists_CheckReason() to receive a buffer where the reason will be stored and its length. Change callers accordingly. Change Class_GetMemberReason() (and its callers) in a similar way so it doesn't rely on a global buffer for the rejected reason.
This commit is contained in:
parent
528c8fc244
commit
cde2e8a277
@ -33,8 +33,6 @@
|
|||||||
|
|
||||||
struct list_head My_Classes[CLASS_COUNT];
|
struct list_head My_Classes[CLASS_COUNT];
|
||||||
|
|
||||||
char Reject_Reason[COMMAND_LEN];
|
|
||||||
|
|
||||||
GLOBAL void
|
GLOBAL void
|
||||||
Class_Init(void)
|
Class_Init(void)
|
||||||
{
|
{
|
||||||
@ -49,32 +47,29 @@ Class_Exit(void)
|
|||||||
for (i = 0; i < CLASS_COUNT; Lists_Free(&My_Classes[i++]));
|
for (i = 0; i < CLASS_COUNT; Lists_Free(&My_Classes[i++]));
|
||||||
}
|
}
|
||||||
|
|
||||||
GLOBAL char *
|
GLOBAL bool
|
||||||
Class_GetMemberReason(const int Class, CLIENT *Client)
|
Class_GetMemberReason(const int Class, CLIENT *Client, char *reason, size_t len)
|
||||||
{
|
{
|
||||||
char *reason;
|
char str[COMMAND_LEN] = "listed";
|
||||||
|
|
||||||
assert(Class < CLASS_COUNT);
|
assert(Class < CLASS_COUNT);
|
||||||
assert(Client != NULL);
|
assert(Client != NULL);
|
||||||
|
|
||||||
reason = Lists_CheckReason(&My_Classes[Class], Client);
|
if (!Lists_CheckReason(&My_Classes[Class], Client, str, sizeof(str)))
|
||||||
if (!reason)
|
return false;
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (!*reason)
|
|
||||||
reason = "listed";
|
|
||||||
|
|
||||||
switch(Class) {
|
switch(Class) {
|
||||||
case CLASS_GLINE:
|
case CLASS_GLINE:
|
||||||
snprintf(Reject_Reason, sizeof(Reject_Reason),
|
snprintf(reason, len, "\"%s\" (G-Line)", str);
|
||||||
"\"%s\" (G-Line)", reason);
|
break;
|
||||||
return Reject_Reason;
|
|
||||||
case CLASS_KLINE:
|
case CLASS_KLINE:
|
||||||
snprintf(Reject_Reason, sizeof(Reject_Reason),
|
snprintf(reason, len, "\"%s\" (K-Line)", str);
|
||||||
"\"%s\" (K-Line)", reason);
|
break;
|
||||||
return Reject_Reason;
|
default:
|
||||||
|
snprintf(reason, len, "%s", str);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return reason;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -88,15 +83,13 @@ Class_GetMemberReason(const int Class, CLIENT *Client)
|
|||||||
GLOBAL bool
|
GLOBAL bool
|
||||||
Class_HandleServerBans(CLIENT *Client)
|
Class_HandleServerBans(CLIENT *Client)
|
||||||
{
|
{
|
||||||
char *rejectptr;
|
char reject[COMMAND_LEN];
|
||||||
|
|
||||||
assert(Client != NULL);
|
assert(Client != NULL);
|
||||||
|
|
||||||
rejectptr = Class_GetMemberReason(CLASS_GLINE, Client);
|
if (Class_GetMemberReason(CLASS_GLINE, Client, reject, sizeof(reject)) ||
|
||||||
if (!rejectptr)
|
Class_GetMemberReason(CLASS_KLINE, Client, reject, sizeof(reject))) {
|
||||||
rejectptr = Class_GetMemberReason(CLASS_KLINE, Client);
|
Client_Reject(Client, reject, true);
|
||||||
if (rejectptr) {
|
|
||||||
Client_Reject(Client, rejectptr, true);
|
|
||||||
return DISCONNECTED;
|
return DISCONNECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,8 @@ GLOBAL bool Class_AddMask PARAMS((const int Class, const char *Mask,
|
|||||||
const time_t ValidUntil, const char *Reason));
|
const time_t ValidUntil, const char *Reason));
|
||||||
GLOBAL void Class_DeleteMask PARAMS((const int Class, const char *Mask));
|
GLOBAL void Class_DeleteMask PARAMS((const int Class, const char *Mask));
|
||||||
|
|
||||||
GLOBAL char *Class_GetMemberReason PARAMS((const int Class, CLIENT *Client));
|
GLOBAL bool Class_GetMemberReason PARAMS((const int Class, CLIENT *Client,
|
||||||
|
char *reason, size_t len));
|
||||||
GLOBAL bool Class_HandleServerBans PARAMS((CLIENT *Client));
|
GLOBAL bool Class_HandleServerBans PARAMS((CLIENT *Client));
|
||||||
|
|
||||||
GLOBAL struct list_head *Class_GetList PARAMS((const int Class));
|
GLOBAL struct list_head *Class_GetList PARAMS((const int Class));
|
||||||
|
@ -130,7 +130,8 @@ Lists_Add(struct list_head *h, const char *Mask, time_t ValidUntil,
|
|||||||
if (e) {
|
if (e) {
|
||||||
e->valid_until = ValidUntil;
|
e->valid_until = ValidUntil;
|
||||||
if (Reason) {
|
if (Reason) {
|
||||||
free(e->reason);
|
if (e->reason)
|
||||||
|
free(e->reason);
|
||||||
e->reason = strdup(Reason);
|
e->reason = strdup(Reason);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -320,18 +321,21 @@ Lists_MakeMask(const char *Pattern)
|
|||||||
bool
|
bool
|
||||||
Lists_Check(struct list_head *h, CLIENT *Client)
|
Lists_Check(struct list_head *h, CLIENT *Client)
|
||||||
{
|
{
|
||||||
return Lists_CheckReason(h, Client) != NULL;
|
return Lists_CheckReason(h, Client, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a client is listed in a list and return the "reason".
|
* Check if a client is listed in a list and store the reason if a buffer
|
||||||
|
* is provided.
|
||||||
*
|
*
|
||||||
* @param h List head.
|
* @param h List head.
|
||||||
* @param Client Client to check.
|
* @param Client Client to check.
|
||||||
|
* @param reason Result buffer to store the reason.
|
||||||
|
* @param len Size of the buffer.
|
||||||
* @return true if client is listed, false if not.
|
* @return true if client is listed, false if not.
|
||||||
*/
|
*/
|
||||||
char *
|
bool
|
||||||
Lists_CheckReason(struct list_head *h, CLIENT *Client)
|
Lists_CheckReason(struct list_head *h, CLIENT *Client, char *reason, size_t len)
|
||||||
{
|
{
|
||||||
struct list_elem *e, *last, *next;
|
struct list_elem *e, *last, *next;
|
||||||
|
|
||||||
@ -343,19 +347,21 @@ Lists_CheckReason(struct list_head *h, CLIENT *Client)
|
|||||||
while (e) {
|
while (e) {
|
||||||
next = e->next;
|
next = e->next;
|
||||||
if (Match(e->mask, Client_MaskCloaked(Client))) {
|
if (Match(e->mask, Client_MaskCloaked(Client))) {
|
||||||
|
if (len && e->reason)
|
||||||
|
strlcpy(reason, e->reason, len);
|
||||||
if (e->valid_until == 1) {
|
if (e->valid_until == 1) {
|
||||||
/* Entry is valid only once, delete it */
|
/* Entry is valid only once, delete it */
|
||||||
LogDebug("Deleted \"%s\" from list (used).",
|
LogDebug("Deleted \"%s\" from list (used).",
|
||||||
e->mask);
|
e->mask);
|
||||||
Lists_Unlink(h, last, e);
|
Lists_Unlink(h, last, e);
|
||||||
}
|
}
|
||||||
return e->reason ? e->reason : "";
|
return true;
|
||||||
}
|
}
|
||||||
last = e;
|
last = e;
|
||||||
e = next;
|
e = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,7 +30,8 @@ GLOBAL struct list_elem *Lists_GetFirst PARAMS((const struct list_head *));
|
|||||||
GLOBAL struct list_elem *Lists_GetNext PARAMS((const struct list_elem *));
|
GLOBAL struct list_elem *Lists_GetNext PARAMS((const struct list_elem *));
|
||||||
|
|
||||||
GLOBAL bool Lists_Check PARAMS((struct list_head *head, CLIENT *client));
|
GLOBAL bool Lists_Check PARAMS((struct list_head *head, CLIENT *client));
|
||||||
GLOBAL char *Lists_CheckReason PARAMS((struct list_head *head, CLIENT *client));
|
GLOBAL bool Lists_CheckReason PARAMS((struct list_head *head, CLIENT *client,
|
||||||
|
char *reason, size_t len));
|
||||||
GLOBAL struct list_elem *Lists_CheckDupeMask PARAMS((const struct list_head *head,
|
GLOBAL struct list_elem *Lists_CheckDupeMask PARAMS((const struct list_head *head,
|
||||||
const char *mask));
|
const char *mask));
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user