Allow restriction of module command arguments

The module commands now support an optional flag for arguments that when
enabled checks that the argument module name matches the registered domain
name. This can be used to enforce argument type validity for arguments
that are given to modules that expect objects of a certain type.

For example, this is used by the cache and dbfwfilter to prevent valid
filters but of the wrong type being given as arguments.
This commit is contained in:
Markus Mäkelä 2017-01-13 14:12:38 +02:00
parent 265e5c0593
commit 60d4e17996
6 changed files with 66 additions and 40 deletions

View File

@ -43,7 +43,7 @@ MXS_BEGIN_DECLS
*/
typedef struct
{
uint64_t type; /**< The argument type */
uint64_t type; /**< The argument type and options */
const char *description; /**< The argument description */
} modulecmd_arg_type_t;
@ -68,13 +68,15 @@ typedef struct
/**
* Options for arguments, bits 9 through 32
*/
#define MODULECMD_ARG_OPTIONAL (1 << 8) /**< The argument is optional */
#define MODULECMD_ARG_OPTIONAL (1 << 8) /**< The argument is optional */
#define MODULECMD_ARG_NAME_MATCHES_DOMAIN (1 << 9) /**< Argument module name must match domain name */
/**
* Helper macros
*/
#define MODULECMD_GET_TYPE(t) ((t)->type & 0xff)
#define MODULECMD_ARG_IS_REQUIRED(t) (((t)->type & MODULECMD_ARG_OPTIONAL) == 0)
#define MODULECMD_ALLOW_NAME_MISMATCH(t) (((t)->type & MODULECMD_ARG_NAME_MATCHES_DOMAIN) == 0)
#define MODULECMD_ARG_PRESENT(t) (MODULECMD_GET_TYPE(t) != MODULECMD_ARG_NONE)
/** Argument list node */

View File

@ -205,7 +205,7 @@ static bool domain_has_command(MODULECMD_DOMAIN *dm, const char *id)
return false;
}
static bool process_argument(modulecmd_arg_type_t *type, const void* value,
static bool process_argument(const MODULECMD *cmd, modulecmd_arg_type_t *type, const void* value,
struct arg_node *arg, const char **err)
{
bool rval = false;
@ -255,8 +255,16 @@ static bool process_argument(modulecmd_arg_type_t *type, const void* value,
case MODULECMD_ARG_SERVICE:
if ((arg->value.service = service_find((char*)value)))
{
arg->type.type = MODULECMD_ARG_SERVICE;
rval = true;
if (MODULECMD_ALLOW_NAME_MISMATCH(type) ||
strcmp(cmd->domain, arg->value.service->routerModule) == 0)
{
arg->type.type = MODULECMD_ARG_SERVICE;
rval = true;
}
else
{
*err = "router and domain names don't match";
}
}
else
{
@ -267,8 +275,16 @@ static bool process_argument(modulecmd_arg_type_t *type, const void* value,
case MODULECMD_ARG_SERVER:
if ((arg->value.server = server_find_by_unique_name((char*)value)))
{
arg->type.type = MODULECMD_ARG_SERVER;
rval = true;
if (MODULECMD_ALLOW_NAME_MISMATCH(type) ||
strcmp(cmd->domain, arg->value.server->protocol) == 0)
{
arg->type.type = MODULECMD_ARG_SERVER;
rval = true;
}
else
{
*err = "server and domain names don't match";
}
}
else
{
@ -293,8 +309,16 @@ static bool process_argument(modulecmd_arg_type_t *type, const void* value,
case MODULECMD_ARG_MONITOR:
if ((arg->value.monitor = monitor_find((char*)value)))
{
arg->type.type = MODULECMD_ARG_MONITOR;
rval = true;
if (MODULECMD_ALLOW_NAME_MISMATCH(type) ||
strcmp(cmd->domain, arg->value.monitor->module_name) == 0)
{
arg->type.type = MODULECMD_ARG_MONITOR;
rval = true;
}
else
{
*err = "monitor and domain names don't match";
}
}
else
{
@ -305,8 +329,16 @@ static bool process_argument(modulecmd_arg_type_t *type, const void* value,
case MODULECMD_ARG_FILTER:
if ((arg->value.filter = filter_def_find((char*)value)))
{
arg->type.type = MODULECMD_ARG_FILTER;
rval = true;
if (MODULECMD_ALLOW_NAME_MISMATCH(type) ||
strcmp(cmd->domain, arg->value.filter->module) == 0)
{
arg->type.type = MODULECMD_ARG_FILTER;
rval = true;
}
else
{
*err = "filter and domain names don't match";
}
}
else
{
@ -459,7 +491,7 @@ MODULECMD_ARG* modulecmd_arg_parse(const MODULECMD *cmd, int argc, const void **
{
const char *err = "";
if (!process_argument(&cmd->arg_types[i], argv[i], &arg->argv[i], &err))
if (!process_argument(cmd, &cmd->arg_types[i], argv[i], &arg->argv[i], &err))
{
error = true;
modulecmd_set_error("Argument %d, %s: %s", i + 1, err, argv[i] ? argv[i] : "No argument given");

View File

@ -93,17 +93,11 @@ bool cache_command_show(const MODULECMD_ARG* pArgs)
const MXS_FILTER_DEF* pFilterDef = pArgs->argv[1].value.filter;
ss_dassert(pFilterDef);
ss_dassert(strcmp(pFilterDef->module, MXS_MODULE_NAME) == 0);
if (strcmp(pFilterDef->module, "cache") == 0)
{
CacheFilter* pFilter = reinterpret_cast<CacheFilter*>(pFilterDef->filter);
CacheFilter* pFilter = reinterpret_cast<CacheFilter*>(pFilterDef->filter);
pFilter->cache().show(pDcb);
}
else
{
dcb_printf(pDcb, "Filter %s exists, but it is not a cache.", pFilterDef->name);
}
pFilter->cache().show(pDcb);
return true;
}
@ -127,10 +121,10 @@ extern "C" MXS_MODULE* MXS_CREATE_MODULE()
static modulecmd_arg_type_t show_argv[] =
{
{ MODULECMD_ARG_OUTPUT, "The output dcb" },
{ MODULECMD_ARG_FILTER, "Cache name" }
{ MODULECMD_ARG_FILTER | MODULECMD_ARG_NAME_MATCHES_DOMAIN, "Cache name" }
};
modulecmd_register_command("cache", "show", cache_command_show,
modulecmd_register_command(MXS_MODULE_NAME, "show", cache_command_show,
MXS_ARRAY_NELEMS(show_argv), show_argv);
MXS_NOTICE("Initialized cache module %s.\n", VERSION_STRING);

View File

@ -60,6 +60,7 @@
*@endcode
*/
#define MXS_MODULE_NAME "dbfwfilter"
#include <maxscale/cdefs.h>
#include <stdio.h>
@ -791,19 +792,19 @@ MXS_MODULE* MXS_CREATE_MODULE()
{
modulecmd_arg_type_t args_rules_reload[] =
{
{MODULECMD_ARG_FILTER, "Filter to reload"},
{MODULECMD_ARG_FILTER | MODULECMD_ARG_NAME_MATCHES_DOMAIN, "Filter to reload"},
{MODULECMD_ARG_STRING | MODULECMD_ARG_OPTIONAL, "Path to rule file"}
};
modulecmd_register_command("dbfwfilter", "rules/reload", dbfw_reload_rules, 2, args_rules_reload);
modulecmd_register_command(MXS_MODULE_NAME, "rules/reload", dbfw_reload_rules, 2, args_rules_reload);
modulecmd_arg_type_t args_rules_show[] =
{
{MODULECMD_ARG_OUTPUT, "DCB where result is written"},
{MODULECMD_ARG_FILTER, "Filter to inspect"}
{MODULECMD_ARG_FILTER | MODULECMD_ARG_NAME_MATCHES_DOMAIN, "Filter to inspect"}
};
modulecmd_register_command("dbfwfilter", "rules", dbfw_show_rules, 2, args_rules_show);
modulecmd_register_command(MXS_MODULE_NAME, "rules", dbfw_show_rules, 2, args_rules_show);
static MXS_FILTER_OBJECT MyObject =
{

View File

@ -43,17 +43,11 @@ bool masking_command_reload(const MODULECMD_ARG* pArgs)
const MXS_FILTER_DEF* pFilterDef = pArgs->argv[1].value.filter;
ss_dassert(pFilterDef);
ss_dassert(strcmp(pFilterDef->module, MXS_MODULE_NAME) == 0);
if (strcmp(pFilterDef->module, "masking") == 0)
{
MaskingFilter* pFilter = reinterpret_cast<MaskingFilter*>(pFilterDef->filter);
MaskingFilter* pFilter = reinterpret_cast<MaskingFilter*>(pFilterDef->filter);
MXS_EXCEPTION_GUARD(pFilter->reload(pDcb));
}
else
{
dcb_printf(pDcb, "Filter %s exists, but it is not a masking filter.", pFilterDef->name);
}
MXS_EXCEPTION_GUARD(pFilter->reload(pDcb));
return true;
}
@ -69,10 +63,10 @@ extern "C" MXS_MODULE* MXS_CREATE_MODULE()
static modulecmd_arg_type_t reload_argv[] =
{
{ MODULECMD_ARG_OUTPUT, "The output dcb" },
{ MODULECMD_ARG_FILTER, "Masking name" }
{ MODULECMD_ARG_FILTER | MODULECMD_ARG_NAME_MATCHES_DOMAIN, "Masking name" }
};
modulecmd_register_command("masking", "reload", masking_command_reload,
modulecmd_register_command(MXS_MODULE_NAME, "reload", masking_command_reload,
MXS_ARRAY_NELEMS(reload_argv), reload_argv);
MXS_NOTICE("Masking module %s initialized.", VERSION_STRING);

View File

@ -24,6 +24,9 @@
* @endverbatim
*/
#define MXS_MODULE_NAME "avrorouter"
#include <maxscale/cdefs.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -134,10 +137,10 @@ MXS_MODULE* MXS_CREATE_MODULE()
static modulecmd_arg_type_t args[] =
{
{ MODULECMD_ARG_SERVICE, "The avrorouter service" },
{ MODULECMD_ARG_SERVICE | MODULECMD_ARG_NAME_MATCHES_DOMAIN, "The avrorouter service" },
{ MODULECMD_ARG_STRING, "Action, whether to 'start' or 'stop' the conversion process" }
};
modulecmd_register_command("avrorouter", "convert", avro_handle_convert, 2, args);
modulecmd_register_command(MXS_MODULE_NAME, "convert", avro_handle_convert, 2, args);
static ROUTER_OBJECT MyObject =
{