Command arguments handling + cleanups
Fix bug #185 - Args of !commands lost/damaged. All string arguments were incorrectly freed after being added to the argument list for a command. Instead this fix makes sure it is properly copied into a new string, and by doing so this requires a new API for dealing with hub command arguments in a type safe manner, and also allows for each argument to be cleaned up properly when the command is no longer needed. This also fixes issues with parse errors for certain types, and optional arguments (previously it was impossible to tell the difference for an integer with value 0 or if no integer was given). All arguments can now be accessed through the new functions hub_command_arg_reset() and hub_command_arg_next(). These functions are also exposed to plug-ins. The argument type notations for 'n' has changed to mean nick (string), and 'u' is used for a user (struct hub_user - must be online).
This commit is contained in:
parent
390b63e80a
commit
df7bbc094f
@ -298,7 +298,7 @@ $(admin_BINARY): $(admin_OBJECTS) $(libuhub_OBJECTS) $(libutils_OBJECTS) $(libad
|
|||||||
$(uhub_BINARY): $(uhub_OBJECTS) $(libuhub_OBJECTS) $(libutils_OBJECTS) $(libadc_common_OBJECTS)
|
$(uhub_BINARY): $(uhub_OBJECTS) $(libuhub_OBJECTS) $(libutils_OBJECTS) $(libadc_common_OBJECTS)
|
||||||
$(MSG_LD) $(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS)
|
$(MSG_LD) $(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS)
|
||||||
|
|
||||||
$(uhub-passwd_BINARY): $(uhub-passwd_OBJECTS)
|
$(uhub-passwd_BINARY): $(uhub-passwd_OBJECTS) src/util/misc.o src/util/list.o src/util/memory.o src/util/log.o
|
||||||
$(MSG_LD) $(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS) $(uhub-passwd_LIBS)
|
$(MSG_LD) $(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS) $(uhub-passwd_LIBS)
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ EXO_TEST(setup, {
|
|||||||
|
|
||||||
static int test_handler(struct command_base* cbase, struct hub_user* user, struct hub_command* hcmd)
|
static int test_handler(struct command_base* cbase, struct hub_user* user, struct hub_command* hcmd)
|
||||||
{
|
{
|
||||||
|
printf("test_handler\n");
|
||||||
result = 1;
|
result = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -35,7 +36,7 @@ static struct command_handle* create_handler(const char* prefix, const char* arg
|
|||||||
c->cred = cred;
|
c->cred = cred;
|
||||||
c->handler = test_handler;
|
c->handler = test_handler;
|
||||||
c->description = "A handler added by autotest.";
|
c->description = "A handler added by autotest.";
|
||||||
c->description = "exotic";
|
c->origin = "exotic test";
|
||||||
c->ptr = &c->ptr;
|
c->ptr = &c->ptr;
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
@ -67,7 +68,7 @@ EXO_TEST(command_create, {
|
|||||||
ADD_TEST(c_test1, "test1", "", auth_cred_guest);
|
ADD_TEST(c_test1, "test1", "", auth_cred_guest);
|
||||||
ADD_TEST(c_test2, "test2", "", auth_cred_operator);
|
ADD_TEST(c_test2, "test2", "", auth_cred_operator);
|
||||||
ADD_TEST(c_test3, "test3", "N?N?N", auth_cred_guest);
|
ADD_TEST(c_test3, "test3", "N?N?N", auth_cred_guest);
|
||||||
ADD_TEST(c_test4, "test4", "n", auth_cred_guest);
|
ADD_TEST(c_test4, "test4", "u", auth_cred_guest);
|
||||||
ADD_TEST(c_test5, "test5", "i", auth_cred_guest);
|
ADD_TEST(c_test5, "test5", "i", auth_cred_guest);
|
||||||
ADD_TEST(c_test6, "test6", "?c", auth_cred_guest);
|
ADD_TEST(c_test6, "test6", "?c", auth_cred_guest);
|
||||||
ADD_TEST(c_test6, "test7", "C", auth_cred_guest);
|
ADD_TEST(c_test6, "test7", "C", auth_cred_guest);
|
||||||
@ -84,6 +85,30 @@ static int verify(const char* str, enum command_parse_status expected)
|
|||||||
return status == expected;
|
return status == expected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct hub_command_arg_data* verify_argument(struct hub_command* cmd, enum hub_command_arg_type type)
|
||||||
|
{
|
||||||
|
return hub_command_arg_next(cmd, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int verify_arg_integer(struct hub_command* cmd, int expected)
|
||||||
|
{
|
||||||
|
struct hub_command_arg_data* data = verify_argument(cmd, type_integer);
|
||||||
|
return data->data.integer == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int verify_arg_user(struct hub_command* cmd, struct hub_user* expected)
|
||||||
|
{
|
||||||
|
struct hub_command_arg_data* data = verify_argument(cmd, type_user);
|
||||||
|
return data->data.user == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int verify_arg_cred(struct hub_command* cmd, enum auth_credentials cred)
|
||||||
|
{
|
||||||
|
struct hub_command_arg_data* data = verify_argument(cmd, type_credentials);
|
||||||
|
return data->data.credentials == cred;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
EXO_TEST(command_access_1, { return verify("!test1", cmd_status_ok); });
|
EXO_TEST(command_access_1, { return verify("!test1", cmd_status_ok); });
|
||||||
EXO_TEST(command_access_2, { return verify("!test2", cmd_status_access_error); });
|
EXO_TEST(command_access_2, { return verify("!test2", cmd_status_access_error); });
|
||||||
EXO_TEST(command_access_3, { user.credentials = auth_cred_operator; return verify("!test2", cmd_status_ok); });
|
EXO_TEST(command_access_3, { user.credentials = auth_cred_operator; return verify("!test2", cmd_status_ok); });
|
||||||
@ -134,7 +159,67 @@ EXO_TEST(command_parse_3, { return verify("!fail", cmd_status_not_found); });
|
|||||||
// built-in command
|
// built-in command
|
||||||
EXO_TEST(command_parse_4, { return verify("!help", cmd_status_ok); });
|
EXO_TEST(command_parse_4, { return verify("!help", cmd_status_ok); });
|
||||||
|
|
||||||
|
|
||||||
|
EXO_TEST(command_argument_integer_1, {
|
||||||
|
struct hub_command* cmd = command_parse(cbase, &user, "!test3");
|
||||||
|
return verify_argument(cmd, type_integer) == NULL;
|
||||||
|
});
|
||||||
|
|
||||||
|
EXO_TEST(command_argument_integer_2, {
|
||||||
|
struct hub_command* cmd = command_parse(cbase, &user, "!test3 10 42");
|
||||||
|
return verify_arg_integer(cmd, 10) && verify_arg_integer(cmd, 42) && verify_argument(cmd, type_integer) == NULL;
|
||||||
|
});
|
||||||
|
|
||||||
|
EXO_TEST(command_argument_integer_3, {
|
||||||
|
struct hub_command* cmd = command_parse(cbase, &user, "!test3 10 42 6784");
|
||||||
|
return verify_arg_integer(cmd, 10) && verify_arg_integer(cmd, 42) && verify_arg_integer(cmd, 6784);
|
||||||
|
});
|
||||||
|
|
||||||
|
EXO_TEST(command_argument_user_1, {
|
||||||
|
struct hub_command* cmd = command_parse(cbase, &user, "!test4 tester");
|
||||||
|
return verify_arg_user(cmd, &user) ;
|
||||||
|
});
|
||||||
|
|
||||||
|
EXO_TEST(command_argument_cid_1, {
|
||||||
|
struct hub_command* cmd = command_parse(cbase, &user, "!test5 3AGHMAASJA2RFNM22AA6753V7B7DYEPNTIWHBAY");
|
||||||
|
return verify_arg_user(cmd, &user) ;
|
||||||
|
});
|
||||||
|
|
||||||
|
EXO_TEST(command_argument_cred_1, {
|
||||||
|
struct hub_command* cmd = command_parse(cbase, &user, "!test7 admin");
|
||||||
|
return verify_arg_cred(cmd, auth_cred_admin);;
|
||||||
|
});
|
||||||
|
|
||||||
|
EXO_TEST(command_argument_cred_2, {
|
||||||
|
struct hub_command* cmd = command_parse(cbase, &user, "!test7 op");
|
||||||
|
return verify_arg_cred(cmd, auth_cred_operator);;
|
||||||
|
});
|
||||||
|
|
||||||
|
EXO_TEST(command_argument_cred_3, {
|
||||||
|
struct hub_command* cmd = command_parse(cbase, &user, "!test7 operator");
|
||||||
|
return verify_arg_cred(cmd, auth_cred_operator);
|
||||||
|
});
|
||||||
|
|
||||||
|
EXO_TEST(command_argument_cred_4, {
|
||||||
|
struct hub_command* cmd = command_parse(cbase, &user, "!test7 super");
|
||||||
|
return verify_arg_cred(cmd, auth_cred_super);
|
||||||
|
});
|
||||||
|
|
||||||
|
EXO_TEST(command_argument_cred_5, {
|
||||||
|
struct hub_command* cmd = command_parse(cbase, &user, "!test7 guest");
|
||||||
|
return verify_arg_cred(cmd, auth_cred_guest);
|
||||||
|
});
|
||||||
|
|
||||||
|
EXO_TEST(command_argument_cred_6, {
|
||||||
|
struct hub_command* cmd = command_parse(cbase, &user, "!test7 user");
|
||||||
|
return verify_arg_cred(cmd, auth_cred_user);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
EXO_TEST(command_user_destroy, { return uman_remove(hub, &user) == 0; });
|
||||||
|
|
||||||
EXO_TEST(command_destroy, {
|
EXO_TEST(command_destroy, {
|
||||||
|
|
||||||
DEL_TEST(c_test1);
|
DEL_TEST(c_test1);
|
||||||
DEL_TEST(c_test2);
|
DEL_TEST(c_test2);
|
||||||
DEL_TEST(c_test3);
|
DEL_TEST(c_test3);
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
#include "uhub.h"
|
#include "uhub.h"
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
// #define CRASH_DEBUG
|
|
||||||
// #define DEBUG_UNLOAD_PLUGINS
|
// #define DEBUG_UNLOAD_PLUGINS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -95,16 +94,36 @@ static int command_is_available(struct command_handle* handle, const struct hub_
|
|||||||
return handle->cred <= user->credentials;
|
return handle->cred <= user->credentials;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hub_command_args_free(struct hub_command* cmd)
|
||||||
|
{
|
||||||
|
struct hub_command_arg_data* data = NULL;
|
||||||
|
|
||||||
|
if (!cmd->args)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (data = (struct hub_command_arg_data*) list_get_first(cmd->args); data; data = (struct hub_command_arg_data*) list_get_next(cmd->args))
|
||||||
|
{
|
||||||
|
switch (data->type)
|
||||||
|
{
|
||||||
|
case type_string:
|
||||||
|
hub_free(data->data.string);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
list_clear(cmd->args, hub_free);
|
||||||
|
list_destroy(cmd->args);
|
||||||
|
cmd->args = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void command_free(struct hub_command* cmd)
|
void command_free(struct hub_command* cmd)
|
||||||
{
|
{
|
||||||
if (!cmd) return;
|
if (!cmd) return;
|
||||||
|
|
||||||
hub_free(cmd->prefix);
|
hub_free(cmd->prefix);
|
||||||
if (cmd->args)
|
hub_command_args_free(cmd);
|
||||||
{
|
|
||||||
list_clear(cmd->args, &null_free);
|
|
||||||
list_destroy(cmd->args);
|
|
||||||
}
|
|
||||||
hub_free(cmd);
|
hub_free(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,33 +143,27 @@ static struct command_handle* command_handler_lookup(struct command_base* cbase,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum command_parse_status command_extract_arguments(struct command_base* cbase, const struct hub_user* user, struct command_handle* command, struct linked_list* tokens, struct linked_list** args)
|
|
||||||
|
static enum command_parse_status command_extract_arguments(struct command_base* cbase, const struct hub_user* user, struct command_handle* command, struct linked_list* tokens, struct linked_list* args)
|
||||||
{
|
{
|
||||||
int arg = 0;
|
int arg = 0;
|
||||||
int opt = 0;
|
int opt = 0;
|
||||||
char arg_code;
|
char arg_code;
|
||||||
char* token = NULL;
|
char* token = NULL;
|
||||||
struct hub_user* target = NULL;
|
struct hub_command_arg_data* data = NULL;
|
||||||
struct command_handle* target_command = NULL;
|
|
||||||
enum auth_credentials cred;
|
|
||||||
enum command_parse_status status = cmd_status_ok;
|
enum command_parse_status status = cmd_status_ok;
|
||||||
int args_addr_range = 0;
|
|
||||||
int temp_num;
|
|
||||||
|
|
||||||
// Ignore the first token since it is the prefix.
|
// Ignore the first token since it is the prefix.
|
||||||
token = list_get_first(tokens);
|
token = list_get_first(tokens);
|
||||||
list_remove(tokens, token);
|
list_remove(tokens, token);
|
||||||
hub_free(token);
|
hub_free(token);
|
||||||
|
|
||||||
uhub_assert(args);
|
while (status == cmd_status_ok && (arg_code = command->args[arg++]))
|
||||||
*args = list_create();
|
|
||||||
|
|
||||||
while ((arg_code = command->args[arg++]))
|
|
||||||
{
|
{
|
||||||
token = list_get_first(tokens);
|
token = list_get_first(tokens);
|
||||||
if (!token || !*token)
|
if (!token || !*token)
|
||||||
{
|
{
|
||||||
status = (arg_code == '?') ? cmd_status_ok : cmd_status_missing_args;
|
status = (arg_code == '?' ? cmd_status_ok : cmd_status_missing_args);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,91 +173,116 @@ static enum command_parse_status command_extract_arguments(struct command_base*
|
|||||||
opt = 1;
|
opt = 1;
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case 'n':
|
case 'u':
|
||||||
target = uman_get_user_by_nick(cbase->hub, token);
|
data = hub_malloc(sizeof(*data));
|
||||||
if (!target)
|
data->type = type_user;
|
||||||
|
data->data.user = uman_get_user_by_nick(cbase->hub, token);
|
||||||
|
if (!data->data.user)
|
||||||
{
|
{
|
||||||
|
hub_free(data);
|
||||||
|
data = NULL;
|
||||||
status = cmd_status_arg_nick;
|
status = cmd_status_arg_nick;
|
||||||
goto parse_arguments_error;
|
|
||||||
}
|
}
|
||||||
list_append(*args, target);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'i':
|
case 'i':
|
||||||
target = uman_get_user_by_cid(cbase->hub, token);
|
data = hub_malloc(sizeof(*data));
|
||||||
if (!target)
|
data->type = type_user;
|
||||||
|
data->data.user = uman_get_user_by_cid(cbase->hub, token);
|
||||||
|
if (!data->data.user)
|
||||||
{
|
{
|
||||||
|
hub_free(data);
|
||||||
|
data = NULL;
|
||||||
status = cmd_status_arg_cid;
|
status = cmd_status_arg_cid;
|
||||||
goto parse_arguments_error;
|
|
||||||
}
|
}
|
||||||
list_append(*args, target);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'a':
|
case 'a':
|
||||||
uhub_assert(args_addr_range == 0 || !"BUG: Can only be one address range argument per command!");
|
data = hub_malloc(sizeof(*data));
|
||||||
if (!ip_convert_address_to_range(token, &cbase->range))
|
data->type = type_address;
|
||||||
|
if (ip_convert_to_binary(token, data->data.address) == -1)
|
||||||
{
|
{
|
||||||
|
hub_free(data);
|
||||||
|
data = NULL;
|
||||||
status = cmd_status_arg_address;
|
status = cmd_status_arg_address;
|
||||||
goto parse_arguments_error;
|
|
||||||
}
|
}
|
||||||
list_append(*args, &cbase->range);
|
|
||||||
args_addr_range++;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'r':
|
||||||
|
data = hub_malloc(sizeof(*data));
|
||||||
|
data->type = type_range;
|
||||||
|
if (!ip_convert_address_to_range(token, data->data.range))
|
||||||
|
{
|
||||||
|
hub_free(data);
|
||||||
|
data = NULL;
|
||||||
|
status = cmd_status_arg_address;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'n':
|
||||||
case 'm':
|
case 'm':
|
||||||
case 'p':
|
case 'p':
|
||||||
list_append(*args, token);
|
data = hub_malloc(sizeof(*data));
|
||||||
|
data->type = type_string;
|
||||||
|
data->data.string = strdup(token);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'c':
|
case 'c':
|
||||||
target_command = command_handler_lookup(cbase, token);
|
data = hub_malloc(sizeof(*data));
|
||||||
if (!target_command)
|
data->type = type_command;
|
||||||
|
data->data.command = command_handler_lookup(cbase, token);
|
||||||
|
if (!data->data.command)
|
||||||
{
|
{
|
||||||
|
hub_free(data);
|
||||||
|
data = NULL;
|
||||||
status = cmd_status_arg_command;
|
status = cmd_status_arg_command;
|
||||||
goto parse_arguments_error;
|
|
||||||
}
|
}
|
||||||
list_append(*args, target_command);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'C':
|
case 'C':
|
||||||
if (!auth_string_to_cred(token, &cred))
|
data = hub_malloc(sizeof(*data));
|
||||||
|
data->type = type_credentials;
|
||||||
|
if (!auth_string_to_cred(token, &data->data.credentials))
|
||||||
{
|
{
|
||||||
|
hub_free(data);
|
||||||
|
data = NULL;
|
||||||
status = cmd_status_arg_cred;
|
status = cmd_status_arg_cred;
|
||||||
goto parse_arguments_error;
|
|
||||||
}
|
}
|
||||||
list_append(*args, (void*) cred);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'N':
|
case 'N':
|
||||||
if (!is_number(token, &temp_num))
|
data = hub_malloc(sizeof(*data));
|
||||||
|
data->type = type_integer;
|
||||||
|
if (!is_number(token, &data->data.integer))
|
||||||
{
|
{
|
||||||
status = cmd_status_arg_number;
|
hub_free(data);
|
||||||
goto parse_arguments_error;
|
data = NULL;
|
||||||
|
return cmd_status_arg_number;
|
||||||
}
|
}
|
||||||
list_append(*args, (void*) (int*) (intptr_t) temp_num);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '\0':
|
case '\0':
|
||||||
if (!opt)
|
if (!opt)
|
||||||
{
|
{
|
||||||
status = cmd_status_missing_args;
|
status = cmd_status_missing_args;
|
||||||
goto parse_arguments_error;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
status = cmd_status_ok;
|
status = cmd_status_ok;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data)
|
||||||
|
{
|
||||||
|
list_append(args, data);
|
||||||
|
data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
list_remove(tokens, token);
|
list_remove(tokens, token);
|
||||||
hub_free(token);
|
hub_free(token);
|
||||||
}
|
}
|
||||||
return status;
|
|
||||||
|
|
||||||
parse_arguments_error:
|
hub_free(data);
|
||||||
list_clear(*args, &null_free);
|
|
||||||
list_destroy(*args);
|
|
||||||
*args = NULL;
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,7 +325,7 @@ struct hub_command* command_parse(struct command_base* cbase, const struct hub_u
|
|||||||
cmd->status = cmd_status_ok;
|
cmd->status = cmd_status_ok;
|
||||||
cmd->message = message;
|
cmd->message = message;
|
||||||
cmd->prefix = NULL;
|
cmd->prefix = NULL;
|
||||||
cmd->args = NULL;
|
cmd->args = list_create();
|
||||||
cmd->user = user;
|
cmd->user = user;
|
||||||
|
|
||||||
if (split_string(message, " ", tokens, 0) <= 0)
|
if (split_string(message, " ", tokens, 0) <= 0)
|
||||||
@ -305,7 +343,7 @@ struct hub_command* command_parse(struct command_base* cbase, const struct hub_u
|
|||||||
goto command_parse_cleanup;
|
goto command_parse_cleanup;
|
||||||
|
|
||||||
// Parse arguments
|
// Parse arguments
|
||||||
cmd->status = command_extract_arguments(cbase, user, handle, tokens, &cmd->args);
|
cmd->status = command_extract_arguments(cbase, user, handle, tokens, cmd->args);
|
||||||
goto command_parse_cleanup;
|
goto command_parse_cleanup;
|
||||||
|
|
||||||
command_parse_cleanup:
|
command_parse_cleanup:
|
||||||
@ -327,8 +365,10 @@ void command_get_syntax(struct command_handle* handler, struct cbuffer* buf)
|
|||||||
{
|
{
|
||||||
case '?': cbuf_append(buf, "["); opt = 1; continue;
|
case '?': cbuf_append(buf, "["); opt = 1; continue;
|
||||||
case 'n': cbuf_append(buf, "<nick>"); break;
|
case 'n': cbuf_append(buf, "<nick>"); break;
|
||||||
|
case 'u': cbuf_append(buf, "<user>"); break;
|
||||||
case 'i': cbuf_append(buf, "<cid>"); break;
|
case 'i': cbuf_append(buf, "<cid>"); break;
|
||||||
case 'a': cbuf_append(buf, "<addr>"); break;
|
case 'a': cbuf_append(buf, "<addr>"); break;
|
||||||
|
case 'r': cbuf_append(buf, "<addr range>"); break;
|
||||||
case 'm': cbuf_append(buf, "<message>"); break;
|
case 'm': cbuf_append(buf, "<message>"); break;
|
||||||
case 'p': cbuf_append(buf, "<password>"); break;
|
case 'p': cbuf_append(buf, "<password>"); break;
|
||||||
case 'C': cbuf_append(buf, "<credentials>"); break;
|
case 'C': cbuf_append(buf, "<credentials>"); break;
|
||||||
@ -452,6 +492,25 @@ int command_invoke(struct command_base* cbase, struct hub_user* user, const char
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t hub_command_arg_reset(struct hub_command* cmd)
|
||||||
|
{
|
||||||
|
cmd->args->iterator = NULL;
|
||||||
|
return list_size(cmd->args);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct hub_command_arg_data* hub_command_arg_next(struct hub_command* cmd, enum hub_command_arg_type type)
|
||||||
|
{
|
||||||
|
struct hub_command_arg_data* ptr = (struct hub_command_arg_data*) list_get_next(cmd->args);
|
||||||
|
if (!ptr)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
uhub_assert(ptr->type == type);
|
||||||
|
if (ptr->type != type)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
static int command_status(struct command_base* cbase, struct hub_user* user, struct hub_command* cmd, struct cbuffer* msg)
|
static int command_status(struct command_base* cbase, struct hub_user* user, struct hub_command* cmd, struct cbuffer* msg)
|
||||||
{
|
{
|
||||||
struct cbuffer* buf = cbuf_create(cbuf_size(msg) + strlen(cmd->prefix) + 8);
|
struct cbuffer* buf = cbuf_create(cbuf_size(msg) + strlen(cmd->prefix) + 8);
|
||||||
@ -465,9 +524,10 @@ static int command_help(struct command_base* cbase, struct hub_user* user, struc
|
|||||||
{
|
{
|
||||||
size_t n;
|
size_t n;
|
||||||
struct cbuffer* buf = cbuf_create(MAX_HELP_LINE);
|
struct cbuffer* buf = cbuf_create(MAX_HELP_LINE);
|
||||||
struct command_handle* command = list_get_first(cmd->args);
|
struct hub_command_arg_data* data = hub_command_arg_next(cmd, type_command);
|
||||||
|
struct command_handle* command;
|
||||||
|
|
||||||
if (!command)
|
if (!data)
|
||||||
{
|
{
|
||||||
cbuf_append(buf, "Available commands:\n");
|
cbuf_append(buf, "Available commands:\n");
|
||||||
|
|
||||||
@ -484,6 +544,7 @@ static int command_help(struct command_base* cbase, struct hub_user* user, struc
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
command = data->data.command;
|
||||||
if (command_is_available(command, user))
|
if (command_is_available(command, user))
|
||||||
{
|
{
|
||||||
cbuf_append_format(buf, "Usage: !%s ", command->prefix);
|
cbuf_append_format(buf, "Usage: !%s ", command->prefix);
|
||||||
@ -521,7 +582,8 @@ static int command_uptime(struct command_base* cbase, struct hub_user* user, str
|
|||||||
static int command_kick(struct command_base* cbase, struct hub_user* user, struct hub_command* cmd)
|
static int command_kick(struct command_base* cbase, struct hub_user* user, struct hub_command* cmd)
|
||||||
{
|
{
|
||||||
struct cbuffer* buf;
|
struct cbuffer* buf;
|
||||||
struct hub_user* target = list_get_first(cmd->args);
|
struct hub_command_arg_data* arg = hub_command_arg_next(cmd, type_user);
|
||||||
|
struct hub_user* target = arg->data.user;
|
||||||
|
|
||||||
buf = cbuf_create(128);
|
buf = cbuf_create(128);
|
||||||
if (target == user)
|
if (target == user)
|
||||||
@ -536,49 +598,6 @@ static int command_kick(struct command_base* cbase, struct hub_user* user, struc
|
|||||||
return command_status(cbase, user, cmd, buf);
|
return command_status(cbase, user, cmd, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int command_ban(struct command_base* cbase, struct hub_user* user, struct hub_command* cmd)
|
|
||||||
{
|
|
||||||
struct cbuffer* buf = cbuf_create(128);
|
|
||||||
struct hub_user* target = list_get_first(cmd->args);
|
|
||||||
|
|
||||||
if (target == user)
|
|
||||||
{
|
|
||||||
cbuf_append(buf, "Cannot kick/ban yourself");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cbuf_append_format(buf, "Banning user \"%s\"", target->id.nick);
|
|
||||||
|
|
||||||
hub_disconnect_user(cbase->hub, target, quit_kicked);
|
|
||||||
acl_user_ban_nick(cbase->hub->acl, target->id.nick);
|
|
||||||
acl_user_ban_cid(cbase->hub->acl, target->id.cid);
|
|
||||||
}
|
|
||||||
return command_status(cbase, user, cmd, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int command_unban(struct command_base* cbase, struct hub_user* user, struct hub_command* cmd)
|
|
||||||
{
|
|
||||||
return command_status(cbase, user, cmd, cbuf_create_const("Not implemented"));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int command_mute(struct command_base* cbase, struct hub_user* user, struct hub_command* cmd)
|
|
||||||
{
|
|
||||||
struct hub_user* target = list_get_first(cmd->args);
|
|
||||||
struct cbuffer* buf = cbuf_create(128);
|
|
||||||
|
|
||||||
if (strlen(cmd->prefix) == 4)
|
|
||||||
{
|
|
||||||
cbuf_append_format(buf, "Muted \"%s\"", target->id.nick);
|
|
||||||
user_flag_set(target, flag_muted);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cbuf_append_format(buf, "Unmuted \"%s\"", target->id.nick);
|
|
||||||
user_flag_unset(target, flag_muted);
|
|
||||||
}
|
|
||||||
return command_status(cbase, user, cmd, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int command_reload(struct command_base* cbase, struct hub_user* user, struct hub_command* cmd)
|
static int command_reload(struct command_base* cbase, struct hub_user* user, struct hub_command* cmd)
|
||||||
{
|
{
|
||||||
cbase->hub->status = hub_status_restart;
|
cbase->hub->status = hub_status_restart;
|
||||||
@ -628,20 +647,20 @@ static int command_myip(struct command_base* cbase, struct hub_user* user, struc
|
|||||||
static int command_getip(struct command_base* cbase, struct hub_user* user, struct hub_command* cmd)
|
static int command_getip(struct command_base* cbase, struct hub_user* user, struct hub_command* cmd)
|
||||||
{
|
{
|
||||||
struct cbuffer* buf = cbuf_create(128);
|
struct cbuffer* buf = cbuf_create(128);
|
||||||
struct hub_user* target = list_get_first(cmd->args);
|
struct hub_command_arg_data* arg = hub_command_arg_next(cmd, type_user);
|
||||||
cbuf_append_format(buf, "\"%s\" has address \"%s\"", target->id.nick, user_get_address(target));
|
cbuf_append_format(buf, "\"%s\" has address \"%s\"", arg->data.user->id.nick, user_get_address(arg->data.user));
|
||||||
return command_status(cbase, user, cmd, buf);
|
return command_status(cbase, user, cmd, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int command_whoip(struct command_base* cbase, struct hub_user* user, struct hub_command* cmd)
|
static int command_whoip(struct command_base* cbase, struct hub_user* user, struct hub_command* cmd)
|
||||||
{
|
{
|
||||||
struct cbuffer* buf;
|
struct cbuffer* buf;
|
||||||
struct ip_range* range = list_get_first(cmd->args);
|
struct hub_command_arg_data* arg = hub_command_arg_next(cmd, type_range);
|
||||||
struct linked_list* users = (struct linked_list*) list_create();
|
struct linked_list* users = (struct linked_list*) list_create();
|
||||||
struct hub_user* u;
|
struct hub_user* u;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
ret = uman_get_user_by_addr(cbase->hub, users, range);
|
ret = uman_get_user_by_addr(cbase->hub, users, arg->data.range);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
{
|
{
|
||||||
list_clear(users, &null_free);
|
list_clear(users, &null_free);
|
||||||
@ -712,10 +731,11 @@ static int command_broadcast(struct command_base* cbase, struct hub_user* user,
|
|||||||
static int command_log(struct command_base* cbase, struct hub_user* user, struct hub_command* cmd)
|
static int command_log(struct command_base* cbase, struct hub_user* user, struct hub_command* cmd)
|
||||||
{
|
{
|
||||||
struct cbuffer* buf;
|
struct cbuffer* buf;
|
||||||
|
struct hub_command_arg_data* arg = hub_command_arg_next(cmd, type_string);
|
||||||
struct linked_list* messages = cbase->hub->logout_info;
|
struct linked_list* messages = cbase->hub->logout_info;
|
||||||
struct hub_logout_info* log;
|
struct hub_logout_info* log;
|
||||||
char* search = 0;
|
char* search = arg ? arg->data.string : "";
|
||||||
size_t search_len = 0;
|
size_t search_len = strlen(search);
|
||||||
size_t search_hits = 0;
|
size_t search_hits = 0;
|
||||||
|
|
||||||
if (!list_size(messages))
|
if (!list_size(messages))
|
||||||
@ -724,19 +744,11 @@ static int command_log(struct command_base* cbase, struct hub_user* user, struct
|
|||||||
}
|
}
|
||||||
|
|
||||||
buf = cbuf_create(128);
|
buf = cbuf_create(128);
|
||||||
search = list_get_first(cmd->args);
|
cbuf_append_format(buf, "Logged entries: " PRINTF_SIZE_T, list_size(messages));
|
||||||
if (search)
|
|
||||||
{
|
|
||||||
search_len = strlen(search);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (search_len)
|
if (search_len)
|
||||||
{
|
{
|
||||||
cbuf_append_format(buf, "Logged entries: " PRINTF_SIZE_T ", searching for \"%s\"", list_size(messages), search);
|
cbuf_append_format(buf, ", searching for \"%s\"", search);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cbuf_append_format(buf, "Logged entries: " PRINTF_SIZE_T, list_size(messages));
|
|
||||||
}
|
}
|
||||||
command_status(cbase, user, cmd, buf);
|
command_status(cbase, user, cmd, buf);
|
||||||
|
|
||||||
@ -781,113 +793,6 @@ static int command_log(struct command_base* cbase, struct hub_user* user, struct
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int command_register(struct command_base* cbase, struct hub_user* user, struct hub_command* cmd)
|
|
||||||
{
|
|
||||||
struct cbuffer* buf = cbuf_create(128);
|
|
||||||
struct auth_info data;
|
|
||||||
char* password = list_get_first(cmd->args);
|
|
||||||
|
|
||||||
strncpy(data.nickname, user->id.nick, MAX_NICK_LEN);
|
|
||||||
strncpy(data.password, password, MAX_PASS_LEN);
|
|
||||||
data.nickname[MAX_NICK_LEN] = '\0';
|
|
||||||
data.password[MAX_PASS_LEN] = '\0';
|
|
||||||
data.credentials = auth_cred_user;
|
|
||||||
|
|
||||||
if (acl_register_user(cbase->hub, &data))
|
|
||||||
{
|
|
||||||
cbuf_append_format(buf, "User \"%s\" registered.", user->id.nick);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cbuf_append_format(buf, "Unable to register user \"%s\".", user->id.nick);
|
|
||||||
}
|
|
||||||
return command_status(cbase, user, cmd, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int command_password(struct command_base* cbase, struct hub_user* user, struct hub_command* cmd)
|
|
||||||
{
|
|
||||||
struct cbuffer* buf = cbuf_create(128);
|
|
||||||
struct auth_info data;
|
|
||||||
char* password = list_get_first(cmd->args);
|
|
||||||
|
|
||||||
strncpy(data.nickname, user->id.nick, MAX_NICK_LEN);
|
|
||||||
strncpy(data.password, password, MAX_PASS_LEN);
|
|
||||||
data.nickname[MAX_NICK_LEN] = '\0';
|
|
||||||
data.password[MAX_PASS_LEN] = '\0';
|
|
||||||
data.credentials = user->credentials;
|
|
||||||
|
|
||||||
if (acl_update_user(cbase->hub, &data))
|
|
||||||
{
|
|
||||||
cbuf_append(buf, "Password changed.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cbuf_append_format(buf, "Unable to change password for user \"%s\".", user->id.nick);
|
|
||||||
}
|
|
||||||
return command_status(cbase, user, cmd, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int command_useradd(struct command_base* cbase, struct hub_user* user, struct hub_command* cmd)
|
|
||||||
{
|
|
||||||
struct cbuffer* buf = cbuf_create(128);
|
|
||||||
struct auth_info data;
|
|
||||||
char* nick = list_get_first(cmd->args);
|
|
||||||
char* pass = list_get_next(cmd->args);
|
|
||||||
char* cred = list_get_next(cmd->args);
|
|
||||||
enum auth_credentials credentials;
|
|
||||||
|
|
||||||
if (!(cred && auth_string_to_cred(cred, &credentials)))
|
|
||||||
credentials = auth_cred_user;
|
|
||||||
|
|
||||||
strncpy(data.nickname, nick, MAX_NICK_LEN);
|
|
||||||
strncpy(data.password, pass, MAX_PASS_LEN);
|
|
||||||
data.nickname[MAX_NICK_LEN] = '\0';
|
|
||||||
data.password[MAX_PASS_LEN] = '\0';
|
|
||||||
data.credentials = credentials;
|
|
||||||
|
|
||||||
if (acl_register_user(cbase->hub, &data))
|
|
||||||
cbuf_append_format(buf, "User \"%s\" registered.", nick);
|
|
||||||
else
|
|
||||||
cbuf_append_format(buf, "Unable to register user \"%s\".", nick);
|
|
||||||
return command_status(cbase, user, cmd, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int command_userdel(struct command_base* cbase, struct hub_user* user, struct hub_command* cmd)
|
|
||||||
{
|
|
||||||
struct cbuffer* buf = cbuf_create(128);
|
|
||||||
char* nick = list_get_first(cmd->args);
|
|
||||||
|
|
||||||
if (acl_delete_user(cbase->hub, nick))
|
|
||||||
cbuf_append_format(buf, "User \"%s\" is deleted.", nick);
|
|
||||||
else
|
|
||||||
cbuf_append_format(buf, "Unable to delete user \"%s\".", nick);
|
|
||||||
return command_status(cbase, user, cmd, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int command_usermod(struct command_base* cbase, struct hub_user* user, struct hub_command* cmd)
|
|
||||||
{
|
|
||||||
return command_status(cbase, user, cmd, cbuf_create_const("Not implemented!"));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int command_userinfo(struct command_base* cbase, struct hub_user* user, struct hub_command* cmd)
|
|
||||||
{
|
|
||||||
return command_status(cbase, user, cmd, cbuf_create_const("Not implemented!"));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int command_userpass(struct command_base* cbase, struct hub_user* user, struct hub_command* cmd)
|
|
||||||
{
|
|
||||||
return command_status(cbase, user, cmd, cbuf_create_const("Not implemented!"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CRASH_DEBUG
|
|
||||||
static int command_crash(struct command_base* cbase, struct hub_user* user, struct hub_command* cmd)
|
|
||||||
{
|
|
||||||
void (*crash)(void) = NULL;
|
|
||||||
crash();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int command_stats(struct command_base* cbase, struct hub_user* user, struct hub_command* cmd)
|
static int command_stats(struct command_base* cbase, struct hub_user* user, struct hub_command* cmd)
|
||||||
{
|
{
|
||||||
struct cbuffer* buf = cbuf_create(128);
|
struct cbuffer* buf = cbuf_create(128);
|
||||||
@ -922,32 +827,18 @@ static struct command_handle* add_builtin(struct command_base* cbase, const char
|
|||||||
|
|
||||||
void commands_builtin_add(struct command_base* cbase)
|
void commands_builtin_add(struct command_base* cbase)
|
||||||
{
|
{
|
||||||
ADD_COMMAND("ban", 3, "n", auth_cred_operator, command_ban, "Ban a user" );
|
|
||||||
ADD_COMMAND("broadcast", 9, "m", auth_cred_operator, command_broadcast,"Send a message to all users" );
|
ADD_COMMAND("broadcast", 9, "m", auth_cred_operator, command_broadcast,"Send a message to all users" );
|
||||||
#ifdef CRASH_DEBUG
|
ADD_COMMAND("getip", 5, "u", auth_cred_operator, command_getip, "Show IP address for a user" );
|
||||||
ADD_COMMAND("crash", 5, "", auth_cred_admin, command_crash, "Crash the hub (DEBUG)." );
|
|
||||||
#endif
|
|
||||||
ADD_COMMAND("getip", 5, "n", auth_cred_operator, command_getip, "Show IP address for a user" );
|
|
||||||
ADD_COMMAND("help", 4, "?c",auth_cred_guest, command_help, "Show this help message." );
|
ADD_COMMAND("help", 4, "?c",auth_cred_guest, command_help, "Show this help message." );
|
||||||
ADD_COMMAND("kick", 4, "n", auth_cred_operator, command_kick, "Kick a user" );
|
ADD_COMMAND("kick", 4, "u", auth_cred_operator, command_kick, "Kick a user" );
|
||||||
ADD_COMMAND("log", 3, "", auth_cred_operator, command_log, "Display log" );
|
ADD_COMMAND("log", 3, "?m", auth_cred_operator, command_log, "Display log" ); // fail
|
||||||
ADD_COMMAND("mute", 4, "n", auth_cred_operator, command_mute, "Mute user" );
|
|
||||||
ADD_COMMAND("myip", 4, "", auth_cred_guest, command_myip, "Show your own IP." );
|
ADD_COMMAND("myip", 4, "", auth_cred_guest, command_myip, "Show your own IP." );
|
||||||
ADD_COMMAND("register", 8, "p", auth_cred_guest, command_register, "Register your username." );
|
|
||||||
ADD_COMMAND("reload", 6, "", auth_cred_admin, command_reload, "Reload configuration files." );
|
ADD_COMMAND("reload", 6, "", auth_cred_admin, command_reload, "Reload configuration files." );
|
||||||
ADD_COMMAND("password", 8, "p", auth_cred_user, command_password, "Change your own password." );
|
|
||||||
ADD_COMMAND("shutdown", 8, "", auth_cred_admin, command_shutdown_hub, "Shutdown hub." );
|
ADD_COMMAND("shutdown", 8, "", auth_cred_admin, command_shutdown_hub, "Shutdown hub." );
|
||||||
ADD_COMMAND("stats", 5, "", auth_cred_super, command_stats, "Show hub statistics." );
|
ADD_COMMAND("stats", 5, "", auth_cred_super, command_stats, "Show hub statistics." );
|
||||||
ADD_COMMAND("unban", 5, "n", auth_cred_operator, command_unban, "Lift ban on a user" );
|
|
||||||
ADD_COMMAND("unmute", 6, "n", auth_cred_operator, command_mute, "Unmute user" );
|
|
||||||
ADD_COMMAND("uptime", 6, "", auth_cred_guest, command_uptime, "Display hub uptime info." );
|
ADD_COMMAND("uptime", 6, "", auth_cred_guest, command_uptime, "Display hub uptime info." );
|
||||||
ADD_COMMAND("useradd", 7, "np",auth_cred_operator, command_useradd, "Register a new user." );
|
|
||||||
ADD_COMMAND("userdel", 7, "n", auth_cred_operator, command_userdel, "Delete a registered user." );
|
|
||||||
ADD_COMMAND("userinfo", 8, "n", auth_cred_operator, command_userinfo, "Show registered user info." );
|
|
||||||
ADD_COMMAND("usermod", 7, "nC",auth_cred_admin, command_usermod, "Modify user credentials." );
|
|
||||||
ADD_COMMAND("userpass", 8, "np",auth_cred_operator, command_userpass, "Change password for a user." );
|
|
||||||
ADD_COMMAND("version", 7, "", auth_cred_guest, command_version, "Show hub version info." );
|
ADD_COMMAND("version", 7, "", auth_cred_guest, command_version, "Show hub version info." );
|
||||||
ADD_COMMAND("whoip", 5, "a", auth_cred_operator, command_whoip, "Show users matching IP range" );
|
ADD_COMMAND("whoip", 5, "r", auth_cred_operator, command_whoip, "Show users matching IP range" );
|
||||||
|
|
||||||
#ifdef DEBUG_UNLOAD_PLUGINS
|
#ifdef DEBUG_UNLOAD_PLUGINS
|
||||||
ADD_COMMAND("load", 4, "", auth_cred_admin, command_load, "Load plugins." );
|
ADD_COMMAND("load", 4, "", auth_cred_admin, command_load, "Load plugins." );
|
||||||
|
@ -41,6 +41,33 @@ enum command_parse_status
|
|||||||
cmd_status_arg_command, /** <<< "A command argument is not valid ('c')" */
|
cmd_status_arg_command, /** <<< "A command argument is not valid ('c')" */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum hub_command_arg_type
|
||||||
|
{
|
||||||
|
type_integer,
|
||||||
|
type_string,
|
||||||
|
type_user,
|
||||||
|
type_address,
|
||||||
|
type_range,
|
||||||
|
type_credentials,
|
||||||
|
type_command
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hub_command_arg_data
|
||||||
|
{
|
||||||
|
enum hub_command_arg_type type;
|
||||||
|
union {
|
||||||
|
int integer;
|
||||||
|
char* string;
|
||||||
|
struct hub_user* user;
|
||||||
|
struct ip_addr_encap* address;
|
||||||
|
struct ip_range* range;
|
||||||
|
enum auth_credentials credentials;
|
||||||
|
struct command_handle* command;
|
||||||
|
} data;
|
||||||
|
};
|
||||||
|
|
||||||
|
void hub_command_args_free(struct hub_command* command);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This struct contains all information needed to invoke
|
* This struct contains all information needed to invoke
|
||||||
* a command, which includes the whole message, the prefix,
|
* a command, which includes the whole message, the prefix,
|
||||||
@ -63,13 +90,37 @@ struct hub_command
|
|||||||
void* ptr; /**<<< "A pointer of data which came from struct command_handler" */
|
void* ptr; /**<<< "A pointer of data which came from struct command_handler" */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the command argument iterator and return the number of arguments
|
||||||
|
* that can be extracted from a parsed command.
|
||||||
|
*
|
||||||
|
* @param cmd the command to start iterating arguments
|
||||||
|
* @return returns the number of arguments provided for the command
|
||||||
|
*/
|
||||||
|
extern size_t hub_command_arg_reset(struct hub_command* cmd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain the current argument and place it in data and increments the iterator.
|
||||||
|
* If no argument exists, or the argument is of a different type than \param type, then 0 is returned.
|
||||||
|
*
|
||||||
|
* NOTE: when calling hub_command_arg_next the first time during a command callback it is safe to assume
|
||||||
|
* that the first argument will be extracted. Thus you don't need to call hub_command_arg_reset().
|
||||||
|
*
|
||||||
|
* @param cmd the command used for iterating arguments.
|
||||||
|
* @param type the expected type of this argument
|
||||||
|
* @return NULL if no argument is found or if the argument found does not match the expected type.
|
||||||
|
*/
|
||||||
|
extern struct hub_command_arg_data* hub_command_arg_next(struct hub_command* cmd, enum hub_command_arg_type type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Argument codes are used to automatically parse arguments
|
* Argument codes are used to automatically parse arguments
|
||||||
* for a a hub command.
|
* for a a hub command.
|
||||||
*
|
*
|
||||||
* n = nick name (must exist in hub session)
|
* u = user (must exist in hub session, or will cause error)
|
||||||
|
* n = nick name (string)
|
||||||
* i = CID (must exist in hub)
|
* i = CID (must exist in hub)
|
||||||
* a = (IP) address (must be a valid IPv4 or IPv6 address)
|
* a = (IP) address (must be a valid IPv4 or IPv6 address)
|
||||||
|
* r = (IP) address range (either: IP-IP or IP/mask, both IPv4 or IPv6 work)
|
||||||
* m = message (string)
|
* m = message (string)
|
||||||
* p = password (string)
|
* p = password (string)
|
||||||
* C = credentials (see auth_string_to_cred).
|
* C = credentials (see auth_string_to_cred).
|
||||||
|
@ -147,6 +147,17 @@ static int cbfunc_command_del(struct plugin_handle* plugin, struct plugin_comman
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t cbfunc_command_arg_reset(struct plugin_handle* plugin, struct plugin_command* cmd)
|
||||||
|
{
|
||||||
|
// TODO: Use proper function for rewriting for plugin_command -> hub_command
|
||||||
|
return hub_command_arg_reset((struct hub_command*) cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct plugin_command_arg_data* cbfunc_command_arg_next(struct plugin_handle* plugin, struct plugin_command* cmd, enum plugin_command_arg_type t)
|
||||||
|
{
|
||||||
|
// TODO: Use proper function for rewriting for plugin_command -> hub_command
|
||||||
|
return (struct plugin_command_arg_data*) hub_command_arg_next((struct hub_command*) cmd, (enum hub_command_arg_type) t);
|
||||||
|
}
|
||||||
|
|
||||||
void plugin_register_callback_functions(struct plugin_handle* handle)
|
void plugin_register_callback_functions(struct plugin_handle* handle)
|
||||||
{
|
{
|
||||||
@ -155,6 +166,8 @@ void plugin_register_callback_functions(struct plugin_handle* handle)
|
|||||||
handle->hub.user_disconnect = cbfunc_user_disconnect;
|
handle->hub.user_disconnect = cbfunc_user_disconnect;
|
||||||
handle->hub.command_add = cbfunc_command_add;
|
handle->hub.command_add = cbfunc_command_add;
|
||||||
handle->hub.command_del = cbfunc_command_del;
|
handle->hub.command_del = cbfunc_command_del;
|
||||||
|
handle->hub.command_arg_reset = cbfunc_command_arg_reset;
|
||||||
|
handle->hub.command_arg_next = cbfunc_command_arg_next;
|
||||||
}
|
}
|
||||||
|
|
||||||
void plugin_unregister_callback_functions(struct plugin_handle* handle)
|
void plugin_unregister_callback_functions(struct plugin_handle* handle)
|
||||||
|
@ -531,6 +531,7 @@ const char* net_address_to_string(int af, const void* src, char* dst, socklen_t
|
|||||||
sin6.sin6_family = AF_INET6;
|
sin6.sin6_family = AF_INET6;
|
||||||
sin6.sin6_port = 0;
|
sin6.sin6_port = 0;
|
||||||
sin6.sin6_addr = *addr6;
|
sin6.sin6_addr = *addr6;
|
||||||
|
sin6.sin6_scope_id = 0;
|
||||||
size = sizeof(sin6);
|
size = sizeof(sin6);
|
||||||
addr = (LPSOCKADDR) &sin6;
|
addr = (LPSOCKADDR) &sin6;
|
||||||
break;
|
break;
|
||||||
|
@ -35,6 +35,19 @@ struct plugin_command
|
|||||||
struct linked_list* args;
|
struct linked_list* args;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct plugin_command_arg_data
|
||||||
|
{
|
||||||
|
enum plugin_command_arg_type type;
|
||||||
|
union {
|
||||||
|
int integer;
|
||||||
|
char* string;
|
||||||
|
struct plugin_user* user;
|
||||||
|
struct ip_addr_encap* address;
|
||||||
|
struct ip_range* range;
|
||||||
|
enum auth_credentials credentials;
|
||||||
|
} data;
|
||||||
|
};
|
||||||
|
|
||||||
typedef int (*plugin_command_handler)(struct plugin_handle*, struct plugin_user* to, struct plugin_command*);
|
typedef int (*plugin_command_handler)(struct plugin_handle*, struct plugin_user* to, struct plugin_command*);
|
||||||
|
|
||||||
struct plugin_command_handle
|
struct plugin_command_handle
|
||||||
@ -62,18 +75,5 @@ struct plugin_command_handle
|
|||||||
PTR->description = DESC; \
|
PTR->description = DESC; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
extern int plugin_command_add(struct plugin_handle*, struct plugin_command_handle*);
|
|
||||||
extern int plugin_command_del(struct plugin_handle*, struct plugin_command_handle*);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a message to a user.
|
|
||||||
* From the user's perspective the message will originate from the hub.
|
|
||||||
*/
|
|
||||||
extern int plugin_command_send_message(struct plugin_handle*, struct plugin_user* to, const char* message);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a reply to a command.
|
|
||||||
*/
|
|
||||||
extern int plugin_command_send_reply(struct plugin_handle*, struct plugin_user* user, struct plugin_command* command, const char* message);
|
|
||||||
|
|
||||||
#endif /* HAVE_UHUB_PLUGIN_API_H */
|
#endif /* HAVE_UHUB_PLUGIN_API_H */
|
||||||
|
@ -106,6 +106,8 @@ struct plugin_funcs
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct plugin_command_handle;
|
struct plugin_command_handle;
|
||||||
|
struct plugin_command;
|
||||||
|
struct plugin_command_arg_data;
|
||||||
|
|
||||||
typedef int (*hfunc_send_message)(struct plugin_handle*, struct plugin_user* user, const char* message);
|
typedef int (*hfunc_send_message)(struct plugin_handle*, struct plugin_user* user, const char* message);
|
||||||
typedef int (*hfunc_send_status)(struct plugin_handle*, struct plugin_user* to, int code, const char* message);
|
typedef int (*hfunc_send_status)(struct plugin_handle*, struct plugin_user* to, int code, const char* message);
|
||||||
@ -113,6 +115,9 @@ typedef int (*hfunc_user_disconnect)(struct plugin_handle*, struct plugin_user*
|
|||||||
typedef int (*hfunc_command_add)(struct plugin_handle*, struct plugin_command_handle*);
|
typedef int (*hfunc_command_add)(struct plugin_handle*, struct plugin_command_handle*);
|
||||||
typedef int (*hfunc_command_del)(struct plugin_handle*, struct plugin_command_handle*);
|
typedef int (*hfunc_command_del)(struct plugin_handle*, struct plugin_command_handle*);
|
||||||
|
|
||||||
|
typedef size_t (*hfunc_command_arg_reset)(struct plugin_handle*, struct plugin_command*);
|
||||||
|
typedef struct plugin_command_arg_data* (*hfunc_command_arg_next)(struct plugin_handle*, struct plugin_command*, enum plugin_command_arg_type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* These are functions created and initialized by the hub and which can be used
|
* These are functions created and initialized by the hub and which can be used
|
||||||
* by plugins to access functionality internal to the hub.
|
* by plugins to access functionality internal to the hub.
|
||||||
@ -124,9 +129,10 @@ struct plugin_hub_funcs
|
|||||||
hfunc_user_disconnect user_disconnect;
|
hfunc_user_disconnect user_disconnect;
|
||||||
hfunc_command_add command_add;
|
hfunc_command_add command_add;
|
||||||
hfunc_command_del command_del;
|
hfunc_command_del command_del;
|
||||||
|
hfunc_command_arg_reset command_arg_reset;
|
||||||
|
hfunc_command_arg_next command_arg_next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct plugin_handle
|
struct plugin_handle
|
||||||
{
|
{
|
||||||
struct uhub_plugin* handle; /* Must NOT be modified by the plugin */
|
struct uhub_plugin* handle; /* Must NOT be modified by the plugin */
|
||||||
|
@ -93,4 +93,15 @@ struct ban_info
|
|||||||
time_t expiry; /* Time when the ban record expires */
|
time_t expiry; /* Time when the ban record expires */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum plugin_command_arg_type
|
||||||
|
{
|
||||||
|
plugin_cmd_arg_type_integer,
|
||||||
|
plugin_cmd_arg_type_string,
|
||||||
|
plugin_cmd_arg_type_user,
|
||||||
|
plugin_cmd_arg_type_address,
|
||||||
|
plugin_cmd_arg_type_range,
|
||||||
|
plugin_cmd_arg_type_credentials,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif /* HAVE_UHUB_PLUGIN_TYPES_H */
|
#endif /* HAVE_UHUB_PLUGIN_TYPES_H */
|
||||||
|
@ -39,6 +39,37 @@ struct sql_data
|
|||||||
sqlite3* db;
|
sqlite3* db;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int null_callback(void* ptr, int argc, char **argv, char **colName) { return 0; }
|
||||||
|
|
||||||
|
static int sql_execute(struct sql_data* sql, int (*callback)(void* ptr, int argc, char **argv, char **colName), void* ptr, const char* sql_fmt, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
char query[1024];
|
||||||
|
char* errMsg;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
va_start(args, sql_fmt);
|
||||||
|
vsnprintf(query, sizeof(query), sql_fmt, args);
|
||||||
|
|
||||||
|
#ifdef DEBUG_SQL
|
||||||
|
printf("SQL: %s\n", query);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
rc = sqlite3_exec(sql->db, query, callback, ptr, &errMsg);
|
||||||
|
if (rc != SQLITE_OK)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG_SQL
|
||||||
|
fprintf(stderr, "ERROR: %s\n", errMsg);
|
||||||
|
#endif
|
||||||
|
sqlite3_free(errMsg);
|
||||||
|
return -rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = sqlite3_changes(sql->db);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct sql_data* parse_config(const char* line, struct plugin_handle* plugin)
|
static struct sql_data* parse_config(const char* line, struct plugin_handle* plugin)
|
||||||
{
|
{
|
||||||
struct sql_data* data = (struct sql_data*) hub_malloc_zero(sizeof(struct sql_data));
|
struct sql_data* data = (struct sql_data*) hub_malloc_zero(sizeof(struct sql_data));
|
||||||
@ -178,17 +209,42 @@ static plugin_st get_user(struct plugin_handle* plugin, const char* nickname, st
|
|||||||
static plugin_st register_user(struct plugin_handle* plugin, struct auth_info* user)
|
static plugin_st register_user(struct plugin_handle* plugin, struct auth_info* user)
|
||||||
{
|
{
|
||||||
struct sql_data* sql = (struct sql_data*) plugin->ptr;
|
struct sql_data* sql = (struct sql_data*) plugin->ptr;
|
||||||
if (sql->exclusive)
|
char* nick = strdup(sql_escape_string(user->nickname));
|
||||||
|
char* pass = strdup(sql_escape_string(user->password));
|
||||||
|
const char* cred = auth_cred_to_string(user->credentials);
|
||||||
|
int rc = sql_execute(sql, null_callback, NULL, "INSERT INTO users (nickname, password, credentials) VALUES('%s', '%s', '%s');", nick, pass, cred);
|
||||||
|
|
||||||
|
free(nick);
|
||||||
|
free(pass);
|
||||||
|
|
||||||
|
if (rc <= 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Unable to add user \"%s\"\n", user->nickname);
|
||||||
return st_deny;
|
return st_deny;
|
||||||
return st_default;
|
}
|
||||||
|
return st_allow;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_st update_user(struct plugin_handle* plugin, struct auth_info* user)
|
static plugin_st update_user(struct plugin_handle* plugin, struct auth_info* user)
|
||||||
{
|
{
|
||||||
struct sql_data* sql = (struct sql_data*) plugin->ptr;
|
struct sql_data* sql = (struct sql_data*) plugin->ptr;
|
||||||
if (sql->exclusive)
|
|
||||||
|
char* nick = strdup(sql_escape_string(user->nickname));
|
||||||
|
char* pass = strdup(sql_escape_string(user->password));
|
||||||
|
const char* cred = auth_cred_to_string(user->credentials);
|
||||||
|
int rc = sql_execute(sql, null_callback, NULL, "INSERT INTO users (nickname, password, credentials) VALUES('%s', '%s', '%s');", nick, pass, cred);
|
||||||
|
|
||||||
|
free(nick);
|
||||||
|
free(pass);
|
||||||
|
|
||||||
|
if (rc <= 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Unable to add user \"%s\"\n", user->nickname);
|
||||||
return st_deny;
|
return st_deny;
|
||||||
return st_default;
|
}
|
||||||
|
return st_allow;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_st delete_user(struct plugin_handle* plugin, struct auth_info* user)
|
static plugin_st delete_user(struct plugin_handle* plugin, struct auth_info* user)
|
||||||
@ -201,7 +257,7 @@ static plugin_st delete_user(struct plugin_handle* plugin, struct auth_info* use
|
|||||||
|
|
||||||
int plugin_register(struct plugin_handle* plugin, const char* config)
|
int plugin_register(struct plugin_handle* plugin, const char* config)
|
||||||
{
|
{
|
||||||
PLUGIN_INITIALIZE(plugin, "SQLite authentication plugin", "0.1", "Authenticate users based on a SQLite database.");
|
PLUGIN_INITIALIZE(plugin, "SQLite authentication plugin", "1.0", "Authenticate users based on a SQLite database.");
|
||||||
|
|
||||||
// Authentication actions.
|
// Authentication actions.
|
||||||
plugin->funcs.auth_get_user = get_user;
|
plugin->funcs.auth_get_user = get_user;
|
||||||
|
@ -129,13 +129,14 @@ static int command_history(struct plugin_handle* plugin, struct plugin_user* use
|
|||||||
{
|
{
|
||||||
struct cbuffer* buf;
|
struct cbuffer* buf;
|
||||||
struct chat_history_data* data = (struct chat_history_data*) plugin->ptr;
|
struct chat_history_data* data = (struct chat_history_data*) plugin->ptr;
|
||||||
int maxlines = 0;
|
struct plugin_command_arg_data* arg = plugin->hub.command_arg_next(plugin, cmd, plugin_cmd_arg_type_integer);
|
||||||
|
int maxlines;
|
||||||
|
|
||||||
if (!list_size(data->chat_history))
|
if (!list_size(data->chat_history))
|
||||||
return command_status(plugin, user, cmd, cbuf_create_const("No messages."));
|
return command_status(plugin, user, cmd, cbuf_create_const("No messages."));
|
||||||
|
|
||||||
if (list_size(cmd->args) > 0)
|
if (arg)
|
||||||
maxlines = (int) (intptr_t) ((intptr_t*) (void*) list_get_first(cmd->args));
|
maxlines = arg->data.integer;
|
||||||
else
|
else
|
||||||
maxlines = data->history_default;
|
maxlines = data->history_default;
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* uhub - A tiny ADC p2p connection hub
|
* uhub - A tiny ADC p2p connection hub
|
||||||
* Copyright (C) 2007-2011, Jan Vidar Krey
|
* Copyright (C) 2007-2012, Jan Vidar Krey
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "uhub.h"
|
#include "uhub.h"
|
||||||
|
#include "util/misc.h"
|
||||||
#include <sqlite3.h>
|
#include <sqlite3.h>
|
||||||
|
|
||||||
// #define DEBUG_SQL
|
// #define DEBUG_SQL
|
||||||
@ -104,6 +105,59 @@ static const char* validate_cred(const char* cred_str)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char* validate_username(const char* username)
|
||||||
|
{
|
||||||
|
const char* tmp;
|
||||||
|
|
||||||
|
// verify length
|
||||||
|
if (strlen(username) > MAX_NICK_LEN)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "User name is too long.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Nick must not start with a space */
|
||||||
|
if (is_white_space(username[0]))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "User name cannot start with white space.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for ASCII values below 32 */
|
||||||
|
for (tmp = username; *tmp; tmp++)
|
||||||
|
if ((*tmp < 32) && (*tmp > 0))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "User name contains illegal characters.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_valid_utf8(username))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "User name must be utf-8 encoded.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char* validate_password(const char* password)
|
||||||
|
{
|
||||||
|
// verify length
|
||||||
|
if (strlen(password) > MAX_PASS_LEN)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Password is too long.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_valid_utf8(password))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Password must be utf-8 encoded.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
static void open_database()
|
static void open_database()
|
||||||
{
|
{
|
||||||
@ -202,8 +256,8 @@ static int add(size_t argc, const char** argv)
|
|||||||
if (argc < 2)
|
if (argc < 2)
|
||||||
print_usage("username password [credentials = user]");
|
print_usage("username password [credentials = user]");
|
||||||
|
|
||||||
user = sql_escape_string(argv[0]);
|
user = sql_escape_string(validate_username(argv[0]));
|
||||||
pass = sql_escape_string(argv[1]);
|
pass = sql_escape_string(validate_password(argv[1]));
|
||||||
cred = validate_cred(argv[2] ? argv[2] : "user");
|
cred = validate_cred(argv[2] ? argv[2] : "user");
|
||||||
|
|
||||||
rc = sql_execute("INSERT INTO users (nickname, password, credentials) VALUES('%s', '%s', '%s');", user, pass, cred);
|
rc = sql_execute("INSERT INTO users (nickname, password, credentials) VALUES('%s', '%s', '%s');", user, pass, cred);
|
||||||
@ -253,7 +307,7 @@ static int pass(size_t argc, const char** argv)
|
|||||||
print_usage("username password");
|
print_usage("username password");
|
||||||
|
|
||||||
user = sql_escape_string(argv[0]);
|
user = sql_escape_string(argv[0]);
|
||||||
pass = sql_escape_string(argv[1]);
|
pass = sql_escape_string(validate_password(argv[1]));
|
||||||
|
|
||||||
rc = sql_execute("UPDATE users SET password = '%s' WHERE nickname = '%s';", pass, user);
|
rc = sql_execute("UPDATE users SET password = '%s' WHERE nickname = '%s';", pass, user);
|
||||||
|
|
||||||
@ -275,7 +329,7 @@ static int del(size_t argc, const char** argv)
|
|||||||
char* user = NULL;
|
char* user = NULL;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (argc < 2)
|
if (argc < 1)
|
||||||
print_usage("username");
|
print_usage("username");
|
||||||
|
|
||||||
user = sql_escape_string(argv[0]);
|
user = sql_escape_string(argv[0]);
|
||||||
@ -307,11 +361,11 @@ void main_usage(const char* binary)
|
|||||||
"\n"
|
"\n"
|
||||||
"Parameters:\n"
|
"Parameters:\n"
|
||||||
" 'filename' is a database file\n"
|
" 'filename' is a database file\n"
|
||||||
" 'username' is a nickname (UTF-8, up to 64 bytes)\n"
|
" 'username' is a nickname (UTF-8, up to %i bytes)\n"
|
||||||
" 'password' is a password (UTF-8, up to 64 bytes)\n"
|
" 'password' is a password (UTF-8, up to %i bytes)\n"
|
||||||
" 'credentials' is one of 'admin', 'super', 'op', 'user'\n"
|
" 'credentials' is one of 'admin', 'super', 'op', 'user'\n"
|
||||||
"\n"
|
"\n"
|
||||||
, binary);
|
, binary, MAX_NICK_LEN, MAX_PASS_LEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
@ -330,7 +384,7 @@ int main(int argc, char** argv)
|
|||||||
for (; n < sizeof(COMMANDS) / sizeof(COMMANDS[0]); n++)
|
for (; n < sizeof(COMMANDS) / sizeof(COMMANDS[0]); n++)
|
||||||
{
|
{
|
||||||
if (!strcmp(command, COMMANDS[n].command))
|
if (!strcmp(command, COMMANDS[n].command))
|
||||||
return COMMANDS[n].handle(argc - 2, (const char**) &argv[3]);
|
return COMMANDS[n].handle(argc - 3, (const char**) &argv[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unknown command!
|
// Unknown command!
|
||||||
|
Loading…
Reference in New Issue
Block a user