mirror of
https://salsa.debian.org/dskoll/remind.git
synced 2026-04-16 06:18:47 +02:00
Disable RUN in callbacks to ordx and subst_xxx functions.
This commit is contained in:
@@ -4308,7 +4308,7 @@ Returns a string that is the ordinal number \fInum\fR. For example,
|
||||
In order to help with localization, if you define a function called
|
||||
\fBordx\fR that takes a single parameter, then calling
|
||||
\fBord\fR(\fIn\fR) invokes \fBordx\fR(\fIn\fR) and returns whatever
|
||||
it does.
|
||||
it does. During the callback to \fBordx\fR, \fBRUN\fR will be disabled.
|
||||
.RE
|
||||
.TP
|
||||
.B orthodoxeaster([dqi_arg])
|
||||
@@ -6516,6 +6516,9 @@ If you use a \fB%{name}\fR sequence and the function \fBsubst_\fIname\fR is
|
||||
not defined or returns an error, then \fB%{name}\fR is replaced with the
|
||||
empty string.
|
||||
.PP
|
||||
Note that when \fBRemind\fR invokes any callback function for a
|
||||
substitution sequence, \fBRUN\fR will be disabled.
|
||||
.PP
|
||||
.SH THE TRANSLATION TABLE
|
||||
.PP
|
||||
To assist with localizing reminder files, \fBRemind\fR maintains a
|
||||
|
||||
@@ -145,7 +145,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig const *tt, int
|
||||
if (func && check_subst_args(func, 1)) {
|
||||
snprintf(s, sizeof(s), "subst_ampm(%d)", h);
|
||||
expr = (char const *) s;
|
||||
r = EvalExpr(&expr, &v, NULL);
|
||||
r = EvalExprRunDisabled(&expr, &v, NULL);
|
||||
if (r == OK) {
|
||||
if (!DoCoerce(STR_TYPE, &v)) {
|
||||
snprintf(mypm, sizeof(mypm), "%s", v.v.str);
|
||||
@@ -173,7 +173,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig const *tt, int
|
||||
if (func && check_subst_args(func, 1)) {
|
||||
snprintf(s, sizeof(s), "subst_ampm(%d)", ch);
|
||||
expr = (char const *) s;
|
||||
r = EvalExpr(&expr, &v, NULL);
|
||||
r = EvalExprRunDisabled(&expr, &v, NULL);
|
||||
if (r == OK) {
|
||||
if (!DoCoerce(STR_TYPE, &v)) {
|
||||
snprintf(mycpm, sizeof(mycpm), "%s", v.v.str);
|
||||
@@ -196,7 +196,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig const *tt, int
|
||||
if (func && check_subst_args(func, 1)) {
|
||||
snprintf(s, sizeof(s), "subst_ordinal(%d)", d);
|
||||
expr = (char const *) s;
|
||||
r = EvalExpr(&expr, &v, NULL);
|
||||
r = EvalExprRunDisabled(&expr, &v, NULL);
|
||||
if (r == OK) {
|
||||
if (!DoCoerce(STR_TYPE, &v)) {
|
||||
snprintf(myplu, sizeof(myplu), "%s", v.v.str);
|
||||
@@ -360,7 +360,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig const *tt, int
|
||||
snprintf(ss, sizeof(s) - (ss-s), "(%d,'%04d-%02d-%02d',%02d:%02d)",
|
||||
altmode ? 1 : 0, y, m+1, d, h, min);
|
||||
expr = (char const *) s;
|
||||
r = EvalExpr(&expr, &v, NULL);
|
||||
r = EvalExprRunDisabled(&expr, &v, NULL);
|
||||
if (r == OK) {
|
||||
if (!DoCoerce(STR_TYPE, &v)) {
|
||||
if (DBufPuts(dbuf, v.v.str) != OK) {
|
||||
@@ -383,7 +383,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig const *tt, int
|
||||
snprintf(s, sizeof(s), "%s(%d,'%04d-%02d-%02d',%02d:%02d)",
|
||||
substname, altmode ? 1 : 0, y, m+1, d, h, min);
|
||||
expr = (char const *) s;
|
||||
r = EvalExpr(&expr, &v, NULL);
|
||||
r = EvalExprRunDisabled(&expr, &v, NULL);
|
||||
if (r == OK) {
|
||||
if (v.type != INT_TYPE || v.v.val != 0) {
|
||||
if (!DoCoerce(STR_TYPE, &v)) {
|
||||
@@ -439,7 +439,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig const *tt, int
|
||||
snprintf(s, sizeof(s), "%s(%d,'%04d-%02d-%02d',%02d:%02d)",
|
||||
substname, altmode ? 1 : 0, y, m+1, d, h, min);
|
||||
expr = (char const *) s;
|
||||
r = EvalExpr(&expr, &v, NULL);
|
||||
r = EvalExprRunDisabled(&expr, &v, NULL);
|
||||
if (r == OK) {
|
||||
if (v.type != INT_TYPE || v.v.val != 0) {
|
||||
if (!DoCoerce(STR_TYPE, &v)) {
|
||||
|
||||
25
src/expr.c
25
src/expr.c
@@ -694,6 +694,7 @@ eval_userfunc(expr_node *node, Value *locals, Value *ans, int *nonconst)
|
||||
Value *new_locals = NULL;
|
||||
expr_node *kid;
|
||||
int i, r, j, pushed;
|
||||
int old_rundisabled;
|
||||
|
||||
/* If we have <= STACK_ARGS_MAX, store them on the stack here */
|
||||
Value stack_locals[STACK_ARGS_MAX];
|
||||
@@ -781,9 +782,15 @@ eval_userfunc(expr_node *node, Value *locals, Value *ans, int *nonconst)
|
||||
|
||||
DBG(debug_enter_userfunc(node, new_locals, f->nargs));
|
||||
|
||||
old_rundisabled = RunDisabled;
|
||||
if (f->run_disabled) {
|
||||
RunDisabled |= RUN_UF;
|
||||
}
|
||||
/* Evaluate the function's expr_node tree */
|
||||
r = evaluate_expr_node(f->node, new_locals, ans, nonconst);
|
||||
|
||||
RunDisabled = old_rundisabled;
|
||||
|
||||
DBG(debug_exit_userfunc(node, ans, r, new_locals, f->nargs));
|
||||
|
||||
if (r != OK) {
|
||||
@@ -2869,6 +2876,24 @@ static char const *get_operator_name(expr_node *node)
|
||||
else return "UNKNOWN_OPERATOR";
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* EvalExprRunDisabled - parse and evaluate an expression */
|
||||
/* Evaluate an expression. Return 0 if OK, non-zero if error */
|
||||
/* Put the result into value pointed to by v. During */
|
||||
/* evaluation, RUN will be disabled */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
int EvalExprRunDisabled(char const **e, Value *v, ParsePtr p)
|
||||
{
|
||||
int old_run_disabled = RunDisabled;
|
||||
int r;
|
||||
RunDisabled |= RUN_CB;
|
||||
r = EvalExpr(e, v, p);
|
||||
RunDisabled = old_run_disabled;
|
||||
return r;
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* EvalExpr - parse and evaluate an expression. */
|
||||
|
||||
19
src/funcs.c
19
src/funcs.c
@@ -1170,6 +1170,7 @@ static int FOrd(func_info *info)
|
||||
char const *e = buf;
|
||||
Value val;
|
||||
int nonconst;
|
||||
int old_rundisabled;
|
||||
|
||||
val.type = ERR_TYPE;
|
||||
snprintf(buf, sizeof(buf), "ordx(%d)", ARGV(0));
|
||||
@@ -1178,7 +1179,10 @@ static int FOrd(func_info *info)
|
||||
return r;
|
||||
}
|
||||
in_ford = 1;
|
||||
old_rundisabled = RunDisabled;
|
||||
RunDisabled |= RUN_CB;
|
||||
r = evaluate_expr_node(n, NULL, &val, &nonconst);
|
||||
RunDisabled = old_rundisabled;
|
||||
in_ford = 0;
|
||||
free_expr_tree(n);
|
||||
if (r != OK) {
|
||||
@@ -4156,7 +4160,7 @@ FEval(func_info *info)
|
||||
{
|
||||
expr_node *n;
|
||||
int r;
|
||||
int run_was_enabled = 0;
|
||||
int old_run_disabled;
|
||||
|
||||
ASSERT_TYPE(0, STR_TYPE);
|
||||
char const *e = ARGSTR(0);
|
||||
@@ -4168,14 +4172,13 @@ FEval(func_info *info)
|
||||
}
|
||||
|
||||
/* Disable shell() command in eval */
|
||||
if (! (RunDisabled & RUN_IN_EVAL)) {
|
||||
run_was_enabled = 1;
|
||||
RunDisabled |= RUN_IN_EVAL;
|
||||
}
|
||||
old_run_disabled = RunDisabled;
|
||||
RunDisabled |= RUN_IN_EVAL;
|
||||
|
||||
r = evaluate_expr_node(n, NULL, &(info->retval), &(info->nonconst));
|
||||
if (run_was_enabled) {
|
||||
RunDisabled &= ~RUN_IN_EVAL;
|
||||
}
|
||||
|
||||
RunDisabled = old_run_disabled;
|
||||
|
||||
free_expr_tree(n);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -66,6 +66,7 @@ void unlimit_execution_time(void);
|
||||
expr_node *free_expr_tree(expr_node *node);
|
||||
expr_node *clone_expr_tree(expr_node const *node, int *r);
|
||||
int EvalExpr (char const **e, Value *v, ParsePtr p);
|
||||
int EvalExprRunDisabled(char const **e, Value *v, ParsePtr p);
|
||||
int DoCoerce (char type, Value *v);
|
||||
char const *PrintValue (Value *v, FILE *fp);
|
||||
int CopyValue (Value *dest, const Value *src);
|
||||
|
||||
@@ -640,13 +640,15 @@ static int CalculateNextTimeUsingSched(QueuedRem *q)
|
||||
return NO_TIME;
|
||||
}
|
||||
|
||||
RunDisabled = q->RunDisabled; /* Don't want weird scheduling functions
|
||||
to be a security hole! */
|
||||
while(1) {
|
||||
char exprBuf[VAR_NAME_LEN+32];
|
||||
snprintf(exprBuf, sizeof(exprBuf), "%s(%d)", q->sched, q->ntrig);
|
||||
s = exprBuf;
|
||||
r = EvalExpr(&s, &v, NULL);
|
||||
if (q->RunDisabled) {
|
||||
r = EvalExprRunDisabled(&s, &v, NULL);
|
||||
} else {
|
||||
r = EvalExpr(&s, &v, NULL);
|
||||
}
|
||||
if (r) {
|
||||
q->sched[0] = 0;
|
||||
return NO_TIME;
|
||||
|
||||
@@ -263,6 +263,8 @@ typedef struct {
|
||||
#define RUN_SCRIPT 0x02
|
||||
#define RUN_NOTOWNER 0x04
|
||||
#define RUN_IN_EVAL 0x08
|
||||
#define RUN_UF 0x10 /* A user-function defined with RUN OFF */
|
||||
#define RUN_CB 0x20 /* A callback */
|
||||
|
||||
/* Flags for the SimpleCalendar format */
|
||||
#define SC_AMPM 0 /* Time shown as 3:00am, etc. */
|
||||
@@ -317,6 +319,7 @@ typedef struct udf_struct {
|
||||
int lineno_start;
|
||||
int recurse_flag;
|
||||
int been_pushed;
|
||||
int run_disabled;
|
||||
} UserFunc;
|
||||
|
||||
/* A pushed systtem variable */
|
||||
|
||||
@@ -275,6 +275,11 @@ int DoFset(ParsePtr p)
|
||||
func->lineno_start = LineNoStart;
|
||||
func->recurse_flag = 0;
|
||||
func->been_pushed = 0;
|
||||
if (RunDisabled) {
|
||||
func->run_disabled = 1;
|
||||
} else {
|
||||
func->run_disabled = 0;
|
||||
}
|
||||
if (in_constant_context()) {
|
||||
func->is_constant = 1;
|
||||
} else {
|
||||
|
||||
31
tests/safety.rem
Normal file
31
tests/safety.rem
Normal file
@@ -0,0 +1,31 @@
|
||||
BANNER %
|
||||
SET $AddBlankLines 0
|
||||
|
||||
FSET danger(x) shell("echo oops")
|
||||
|
||||
RUN OFF
|
||||
FSET safe(x) shell("echo nope")
|
||||
FSET safe2(x) danger(x)
|
||||
RUN ON
|
||||
|
||||
DEBUG +x
|
||||
set a danger(1)
|
||||
set b safe(1)
|
||||
set b safe2(1)
|
||||
|
||||
RUN OFF
|
||||
set a danger(1)
|
||||
set b safe(1)
|
||||
set b safe2(1)
|
||||
|
||||
RUN ON
|
||||
|
||||
DEBUG -x
|
||||
FSET subst_b(a, b, c) shell("echo nooooo....")
|
||||
|
||||
REM MSG [subst_b(1, 2, 3)]
|
||||
FLUSH
|
||||
REM MSG %b
|
||||
FLUSH
|
||||
REM MSG [subst_b(1, 2, 3)]
|
||||
FLUSH
|
||||
@@ -621,12 +621,17 @@ rm -f ../tests/once.timestamp
|
||||
grep -F -v '$SysInclude' < ../tests/test.out > ../tests/test.out.1 && mv -f ../tests/test.out.1 ../tests/test.out
|
||||
|
||||
# If "man" accepts the --warnings flag, test all the man pages.
|
||||
RUNMAN=0
|
||||
man man | grep -e --warnings > /dev/null 2>&1
|
||||
if test $? = 0 ; then
|
||||
for i in ../man/*.1 ; do
|
||||
man --warnings=w $i 2>>../tests/test.out 1>/dev/null
|
||||
done
|
||||
if test "$?" = 0 ; then
|
||||
RUNMAN=1
|
||||
fi
|
||||
for i in ../man/*.1 ; do
|
||||
echo "Checking $i..." >> ../tests/test.out
|
||||
if test "$RUNMAN" = 1 ; then
|
||||
man --warnings=w $i 2>>../tests/test.out 1>/dev/null
|
||||
fi
|
||||
done
|
||||
|
||||
# Test --print-tokens long option
|
||||
../src/remind --print-tokens < /dev/null >> ../tests/test.out 2>&1
|
||||
@@ -788,6 +793,8 @@ REM TODO 2025-08-13 COMPLETE-THROUGH 2025-08-13 MSG %(LANGID) Task3%:
|
||||
EOF
|
||||
done
|
||||
|
||||
../src/remind -q ../tests/safety.rem 2025-08-13 >> ../tests/test.out 2>&1
|
||||
|
||||
cmp -s ../tests/test.out ../tests/test.cmp
|
||||
if [ "$?" = "0" ]; then
|
||||
echo "Remind: Acceptance test PASSED"
|
||||
|
||||
@@ -24392,6 +24392,10 @@ with_time
|
||||
|
||||
foo
|
||||
bar
|
||||
Checking ../man/rem.1...
|
||||
Checking ../man/rem2ps.1...
|
||||
Checking ../man/remind.1...
|
||||
Checking ../man/tkremind.1...
|
||||
# Remind Tokens
|
||||
|
||||
addomit
|
||||
@@ -39678,3 +39682,44 @@ This is executed by the shell.
|
||||
2025/08/13 * * * * ro Task1
|
||||
2025/08/13 * * * * ro Task2
|
||||
2025/08/13 * * * * ro Task3 (finalizată)
|
||||
Entering UserFN danger(1)
|
||||
shell("echo oops") => "oops"
|
||||
Leaving UserFN danger(1) => "oops"
|
||||
Entering UserFN safe(1)
|
||||
shell("echo nope") => RUN disabled
|
||||
../tests/safety.rem(13): shell(): RUN disabled
|
||||
../tests/safety.rem(7): [#0] In function `safe'
|
||||
Leaving UserFN safe(1) => RUN disabled
|
||||
Entering UserFN safe2(1)
|
||||
x => 1
|
||||
Entering UserFN danger(1)
|
||||
shell("echo oops") => RUN disabled
|
||||
../tests/safety.rem(14): shell(): RUN disabled
|
||||
../tests/safety.rem(4): [#0] In function `danger'
|
||||
../tests/safety.rem(8): [#1] Called from function `safe2'
|
||||
Leaving UserFN danger(1) => RUN disabled
|
||||
Leaving UserFN safe2(1) => RUN disabled
|
||||
Entering UserFN danger(1)
|
||||
shell("echo oops") => RUN disabled
|
||||
../tests/safety.rem(17): shell(): RUN disabled
|
||||
../tests/safety.rem(4): [#0] In function `danger'
|
||||
Leaving UserFN danger(1) => RUN disabled
|
||||
Entering UserFN safe(1)
|
||||
shell("echo nope") => RUN disabled
|
||||
../tests/safety.rem(18): shell(): RUN disabled
|
||||
../tests/safety.rem(7): [#0] In function `safe'
|
||||
Leaving UserFN safe(1) => RUN disabled
|
||||
Entering UserFN safe2(1)
|
||||
x => 1
|
||||
Entering UserFN danger(1)
|
||||
shell("echo oops") => RUN disabled
|
||||
../tests/safety.rem(19): shell(): RUN disabled
|
||||
../tests/safety.rem(4): [#0] In function `danger'
|
||||
../tests/safety.rem(8): [#1] Called from function `safe2'
|
||||
Leaving UserFN danger(1) => RUN disabled
|
||||
Leaving UserFN safe2(1) => RUN disabled
|
||||
nooooo....
|
||||
../tests/safety.rem(28): shell(): RUN disabled
|
||||
../tests/safety.rem(24): [#0] In function `subst_b'
|
||||
today
|
||||
nooooo....
|
||||
|
||||
Reference in New Issue
Block a user