Fix various problems with adding and removing module DCC bindings

Change remove_all_dcc_binds() so that it only removes DCC binds for the module supplied, as it's supposed to.

get_dcc_type() should ignore the first entry in dcc_types[] ("<none>") otherwise the client will try to
respond to DCC requests with that name.

Explicitly track the number of entries in the dcc_types[] array rather than using a NULL terminator.  This
allows us to change dcc_types[] to use NULL entries to mark unused slots in the array, rather than pointers
to entries with a NULL .name element.  Together, this means that the dcc_types[] array is only resized when it
actually needs to be grown and removal works correctly (without eg. prematurely marking the end of the array).

Make add_dcc_bind() fail if the requested DCC type has already been bound by a module (this still allows one
module at a time to rebind a built-in DCC type).  Previously the behaviour was ill-defined in this case.
This commit is contained in:
Kevin Easton 2018-02-20 23:27:32 +11:00
parent 5ae42802ec
commit 9e7fc85ae1
4 changed files with 84 additions and 42 deletions

View File

@ -1,5 +1,10 @@
[Changes 1.2.2]
* Fix various problems with adding and removing module DCC bindings. The
same DCC type cannot be bound by more than one module simultaneously. The
remove_all_dcc_binds() function now only removes all DCC bindings for the
given module. (caf)
* Fix crash when unloading the arcfour module. (caf)
* Change add_dcc_bind() to collect all function pointer arguments into a

View File

@ -156,7 +156,7 @@ struct dcc_offer {
int check_dcc_socket(int);
char *get_dcc_info(SocketList *, DCC_int *, int);
void init_dcc_table(void);
int BX_remove_all_dcc_binds(char *);
int BX_remove_all_dcc_binds(const char *);
int BX_remove_dcc_bind(char *, int);
/* Function pointers for the operations implementing a DCC type.

View File

@ -606,7 +606,7 @@ extern Function_ptr *global;
#define erase_dcc_info (*(void (*)(int, int, char *, ...))global[ERASE_DCC_INFO])
#define add_dcc_bind (*(int (*)(char *, char *, const struct dcc_ops *))global[ADD_DCC_BIND])
#define remove_dcc_bind (*(int (*)(char *, int ))global[REMOVE_DCC_BIND])
#define remove_all_dcc_binds (*(int (*)(char *))global[REMOVE_ALL_DCC_BINDS])
#define remove_all_dcc_binds (*(int (*)(const char *))global[REMOVE_ALL_DCC_BINDS])
#define get_active_count (*(int (*)(void ))global[GET_ACTIVE_COUNT])
#define get_num_queue (*(int (*)(void ))global[GET_NUM_QUEUE])
#define add_to_queue (*(int (*)(char *, char *, pack *))global[ADD_TO_QUEUE])

View File

@ -74,7 +74,7 @@ extern int use_socks;
#define DCC_HASHSIZE 11
static HashEntry dcc_no_flood[DCC_HASHSIZE];
struct _dcc_types_
struct dcc_type
{
char *name;
char *module;
@ -84,7 +84,7 @@ struct _dcc_types_
static const struct dcc_ops null_ops = { NULL, NULL, NULL, NULL, NULL };
static struct _dcc_types_ _dcc_types[] =
static struct dcc_type builtin_dcc_types[] =
{
{"<none>", NULL, 0, NULL},
{"CHAT", NULL, DCC_CHAT, &null_ops},
@ -98,10 +98,11 @@ static struct _dcc_types_ _dcc_types[] =
{"FTP", NULL, DCC_FTPOPEN, &null_ops},
{"FTPGET", NULL, DCC_FTPGET, &null_ops},
{"FTPSEND", NULL, DCC_FTPSEND, &null_ops},
{NULL, NULL, 0, NULL}
};
static struct _dcc_types_ **dcc_types = NULL;
static const size_t n_builtin_dcc_types = sizeof builtin_dcc_types / sizeof builtin_dcc_types[0];
static struct dcc_type **dcc_types = NULL;
static size_t n_dcc_types = 0;
static char DCC_current_transfer_buffer[BIG_BUFFER_SIZE/4];
unsigned int send_count_stat = 0;
@ -286,9 +287,10 @@ static int get_dcc_type(const char *name)
{
int i;
for (i = 0; dcc_types[i]->name; i++)
/* Start at 1 to ignore the <none> type */
for (i = 1; i < n_dcc_types; i++)
{
if (!my_stricmp(name, dcc_types[i]->name))
if (dcc_types[i] && !my_stricmp(name, dcc_types[i]->name))
return i;
}
@ -4255,53 +4257,89 @@ char *nick,
}
}
/* add_dcc_bind()
*
* Bind a new set of DCC operations to a DCC name. This can either be a completely new DCC type,
* or a new set of operations for a builtin DCC type. This fails if the given DCC name is already
* bound by another module.
*/
int BX_add_dcc_bind(char *name, char *module, const struct dcc_ops *dcc_ops)
{
int i;
for (i = 0; dcc_types[i]->name; i++)
int i;
i = get_dcc_type(name);
if (i < 0)
{
if (!my_stricmp(dcc_types[i]->name, name))
break;
}
if (i >= 0xfe) return 0;
if (!dcc_types[i])
{
RESIZE(dcc_types, struct _dcc_types_ *, i + 2);
dcc_types[i] = new_malloc(sizeof(struct _dcc_types_));
}
if (!dcc_types[i]->name)
/* New DCC type, requires a new entry in the list */
for (i = 0; i < n_dcc_types; i++)
{
if (!dcc_types[i])
break;
}
if (i & ~DCC_TYPES)
{
yell("Failed to add DCC binding [%s] for module [%s], too many DCC bindings.",
name, module);
return 0;
}
if (i >= n_dcc_types)
{
n_dcc_types = i + 1;
RESIZE(dcc_types, struct dcc_type *, n_dcc_types);
}
dcc_types[i] = new_malloc(sizeof(struct dcc_type));
malloc_strcpy(&dcc_types[i]->name, name);
dcc_types[i]->type = i;
}
else
{
if (dcc_types[i]->module)
{
yell("Failed to add DCC binding [%s] for module [%s], already bound by module [%s].",
name, module, dcc_types[i]->module);
return 0;
}
}
malloc_strcpy(&dcc_types[i]->module, module);
dcc_types[i]->dcc_ops = dcc_ops;
dcc_types[i]->type = i;
return i;
}
int BX_remove_dcc_bind(char *name, int type)
{
int i = type & DCC_TYPES;
if (!dcc_types[i]->module)
if (type >= n_dcc_types || !dcc_types[type] || !dcc_types[type]->module)
return 0;
new_free(&dcc_types[i]->module);
dcc_types[i]->dcc_ops = &null_ops;
if (i > DCC_FTPSEND)
new_free(&dcc_types[type]->module);
dcc_types[type]->dcc_ops = &null_ops;
if (type >= n_builtin_dcc_types)
{
new_free(&dcc_types[i]->name);
new_free(&dcc_types[i]);
/* RESIZE(dcc_types, struct _dcc_types *, i - 1);*/
new_free(&dcc_types[type]->name);
new_free(&dcc_types[type]);
}
return 1;
}
int BX_remove_all_dcc_binds(char *name)
/* remove_all_dcc_binds()
*
* Remove all DCC bindings added by a given module.
*/
int BX_remove_all_dcc_binds(const char *module)
{
int ret = 0;
int i, j;
/* scan to end of list */
for (i = 0; dcc_types[i]->name; i++);
i--;
for (j = i; j > 0; j--)
ret += remove_dcc_bind(dcc_types[j]->name, dcc_types[j]->type);
int ret = 0;
int i;
for (i = 0; i < n_dcc_types; i++)
{
if (dcc_types[i] && dcc_types[i]->module && !strcasecmp(dcc_types[i]->module, module))
ret += remove_dcc_bind(dcc_types[i]->name, i);
}
return ret;
}
@ -4309,13 +4347,12 @@ void init_dcc_table(void)
{
int i;
for (i = 0; _dcc_types[i].name; i++);
RESIZE(dcc_types, struct _dcc_types_ *, i + 1);
for (i = 0; _dcc_types[i].name; i++)
n_dcc_types = n_builtin_dcc_types;
RESIZE(dcc_types, struct dcc_type *, n_dcc_types);
for (i = 0; i < n_dcc_types; i++)
{
dcc_types[i] = &_dcc_types[i];
dcc_types[i] = &builtin_dcc_types[i];
}
dcc_types[i] = new_malloc(sizeof(struct _dcc_types_));
}
char *get_dcc_info(SocketList *s, DCC_int *n, int i)