func_odbc: Introduce minargs config and expose ARGC in addition to ARGn.

minargs enables enforcing of minimum count of arguments to pass to
func_odbc, so if you're unconditionally using ARG1 through ARG4 then
this should be set to 4.  func_odbc will generate an error in this case,
so for example

[FOO]
minargs = 4

and ODBC_FOO(a,b,c) in dialplan will now error out instead of using a
potentially leaked ARG4 from Gosub().

ARGC is needed if you're using optional argument, to verify whether or
not an argument has been passed, else it's possible to use a leaked ARGn
from Gosub (app_stack).  So now you can safely do
${IF($[${ARGC}>3]?${ARGV}:default value)} kind of thing.

Change-Id: I6ca0b137d90b03f6aa9c496991f6cbf1518f6c24
Signed-off-by: Jaco Kroon <jaco@uls.co.za>
This commit is contained in:
Jaco Kroon
2021-02-17 22:51:17 +02:00
committed by George Joseph
parent 6e695c867f
commit b0f349a330
3 changed files with 60 additions and 2 deletions

View File

@@ -120,6 +120,7 @@ struct acf_odbc_query {
char *sql_insert;
unsigned int flags;
int rowlimit;
int minargs;
struct ast_custom_function *acf;
};
@@ -545,6 +546,14 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co
return -1;
}
AST_STANDARD_APP_ARGS(args, s);
if (args.argc < query->minargs) {
ast_log(LOG_ERROR, "%d arguments supplied to '%s' requiring minimum %d\n",
args.argc, cmd, query->minargs);
AST_RWLIST_UNLOCK(&queries);
return -1;
}
if (!chan) {
if (!(chan = ast_dummy_channel_alloc())) {
AST_RWLIST_UNLOCK(&queries);
@@ -578,7 +587,8 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co
return -1;
}
AST_STANDARD_APP_ARGS(args, s);
snprintf(varname, sizeof(varname), "%u", args.argc);
pbx_builtin_pushvar_helper(chan, "ARGC", varname);
for (i = 0; i < args.argc; i++) {
snprintf(varname, sizeof(varname), "ARG%d", i + 1);
pbx_builtin_pushvar_helper(chan, varname, args.field[i]);
@@ -603,6 +613,8 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co
chan = ast_channel_unref(chan);
} else {
/* Restore prior values */
pbx_builtin_setvar_helper(chan, "ARGC", NULL);
for (i = 0; i < args.argc; i++) {
snprintf(varname, sizeof(varname), "ARG%d", i + 1);
pbx_builtin_setvar_helper(chan, varname, NULL);
@@ -756,6 +768,14 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha
return -1;
}
AST_STANDARD_APP_ARGS(args, s);
if (args.argc < query->minargs) {
ast_log(LOG_ERROR, "%d arguments supplied to '%s' requiring minimum %d\n",
args.argc, cmd, query->minargs);
AST_RWLIST_UNLOCK(&queries);
return -1;
}
if (!chan) {
if (!(chan = ast_dummy_channel_alloc())) {
AST_RWLIST_UNLOCK(&queries);
@@ -768,7 +788,8 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha
ast_autoservice_start(chan);
}
AST_STANDARD_APP_ARGS(args, s);
snprintf(varname, sizeof(varname), "%u", args.argc);
pbx_builtin_pushvar_helper(chan, "ARGC", varname);
for (x = 0; x < args.argc; x++) {
snprintf(varname, sizeof(varname), "ARG%d", x + 1);
pbx_builtin_pushvar_helper(chan, varname, args.field[x]);
@@ -780,6 +801,8 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha
chan = ast_channel_unref(chan);
} else {
/* Restore prior values */
pbx_builtin_setvar_helper(chan, "ARGC", NULL);
for (x = 0; x < args.argc; x++) {
snprintf(varname, sizeof(varname), "ARG%d", x + 1);
pbx_builtin_setvar_helper(chan, varname, NULL);
@@ -1290,6 +1313,10 @@ static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_qu
sscanf(tmp, "%30d", &((*query)->rowlimit));
}
if ((tmp = ast_variable_retrieve(cfg, catg, "minargs"))) {
sscanf(tmp, "%30d", &((*query)->minargs));
}
(*query)->acf = ast_calloc(1, sizeof(struct ast_custom_function));
if (!(*query)->acf) {
free_acf_query(*query);