Mike Jagdis
2010-06-06 21:26:27 UTC
[Resending to callweaver-users as well as callweaver-dev]
That latest series of changes, up to r5713, includes a pretty
comprehensive rework of dialplan substitution, expression evaluation and
the dial command.
Previously dialplan was NOT secure and COULD NOT be written to be
secure. And that was true of all implementations, not just callweaver.
If you don't see the problem experiment by setting variables that
contain ',', '"' and '&' then use them in ${...}, "${...}", $[ ... ],
"$[ ... ]" and Dial and see just how often things break in ways that
allow other bits of the variable to be treated as something totally
unrelated. Then bear in mind that you probably cannot have anything but
the most trivial dialplan _without_ expanding variables such as EXTEN or
CALLERID(...) that come from external sources. And that's half the
point of 99.99% of implementations, right? Receiving calls from other
people?
So.
As of r5713 of callweaver trunk there is a fairly major rewrite of the
dialplan guts that provides:
1. Correct handling of quoted elements and \-escaped characters
'...' enclose literal strings, "..." enclose strings which are
subject to substitution but not argument splitting.
Expansion of things containing '"' works correctly, e.g.:
Set(x='a"b')
Verbose(0, "${x}")
prints a"b rather than erroring.
As with bash (or any POSIX shell) you can put a double quote in a
double quoted string using a \-escape, e.g. "...\"...". To put a
single quote in a single quoted string you have to terminate the
first quote, \-escape a quote, then reopen the quoting, e.g.
'...'\''...'.
Also ${...} and $[...] are like $(...) in bash in that they escape
the surrounding quote context and do their own thing. So to read
something like:
Set(x="${ENUMLOOKUP("${EXTEN}", ALL, 'result%d', e164.arpa)")
ignore what is outside the ${...} initially in order to understand
the quoting. But note that the surrounding quotes DO matter. WITH
them the expansion is correctly escaped so that it is a single
argument. WITHOUT them the expansion will potentially be treated as
a list of arguments and split where ever a comma occurs.
If you DO NOT quote things you get the old, broken behaviour as you
might expect. You SHOULD quote things. *Every* thing. If you need
to construct strings and then split them consider embedding quotes
and then using EVAL() on them (see the Dial() examples below).
I'll say that again just to be sure you heard.
QUOTE EVERYTHING!
2. A new, alternative syntax for Dial()
The old syntax is still present and still works. STOP USING IT AS
SOON AS POSSIBLE.
The new syntax allows the list of devices to dial to be specified
as a set of arguments enclosed in {...}, e.g.:
Dial({ "DAHDI/g1/${number}", "SIP/${name}" })
If you use the new syntax you can also place commas between dial
options so each option is a separate argument and thus you can be
sure that what dial sees is what you intended, e.g.:
Dial({ "SIP/${name}" }, T, A("${announcefile}"), W)
If you need to build lists of devices to dial dynamically DO NOT be
tempted to fall back on the old syntax. Instead embed quotes and
use EVAL() to reparse the string back into a list of arguments (you
can use the same technique any other time you need to construct
lists of arguments), e.g.:
Set(devs="'DAHDI/g1/${number}'")
Set(devs="${devs}, 'SIP/${name}'")
Dial({ ${EVAL("${devs}")} }, ...)
Please clean up your dialplans and let me know (with debug/verbose logs)
of anything that doesn't seem to work. And ask questions if anything
doesn't seem clear :-).
Mike
That latest series of changes, up to r5713, includes a pretty
comprehensive rework of dialplan substitution, expression evaluation and
the dial command.
Previously dialplan was NOT secure and COULD NOT be written to be
secure. And that was true of all implementations, not just callweaver.
If you don't see the problem experiment by setting variables that
contain ',', '"' and '&' then use them in ${...}, "${...}", $[ ... ],
"$[ ... ]" and Dial and see just how often things break in ways that
allow other bits of the variable to be treated as something totally
unrelated. Then bear in mind that you probably cannot have anything but
the most trivial dialplan _without_ expanding variables such as EXTEN or
CALLERID(...) that come from external sources. And that's half the
point of 99.99% of implementations, right? Receiving calls from other
people?
So.
As of r5713 of callweaver trunk there is a fairly major rewrite of the
dialplan guts that provides:
1. Correct handling of quoted elements and \-escaped characters
'...' enclose literal strings, "..." enclose strings which are
subject to substitution but not argument splitting.
Expansion of things containing '"' works correctly, e.g.:
Set(x='a"b')
Verbose(0, "${x}")
prints a"b rather than erroring.
As with bash (or any POSIX shell) you can put a double quote in a
double quoted string using a \-escape, e.g. "...\"...". To put a
single quote in a single quoted string you have to terminate the
first quote, \-escape a quote, then reopen the quoting, e.g.
'...'\''...'.
Also ${...} and $[...] are like $(...) in bash in that they escape
the surrounding quote context and do their own thing. So to read
something like:
Set(x="${ENUMLOOKUP("${EXTEN}", ALL, 'result%d', e164.arpa)")
ignore what is outside the ${...} initially in order to understand
the quoting. But note that the surrounding quotes DO matter. WITH
them the expansion is correctly escaped so that it is a single
argument. WITHOUT them the expansion will potentially be treated as
a list of arguments and split where ever a comma occurs.
If you DO NOT quote things you get the old, broken behaviour as you
might expect. You SHOULD quote things. *Every* thing. If you need
to construct strings and then split them consider embedding quotes
and then using EVAL() on them (see the Dial() examples below).
I'll say that again just to be sure you heard.
QUOTE EVERYTHING!
2. A new, alternative syntax for Dial()
The old syntax is still present and still works. STOP USING IT AS
SOON AS POSSIBLE.
The new syntax allows the list of devices to dial to be specified
as a set of arguments enclosed in {...}, e.g.:
Dial({ "DAHDI/g1/${number}", "SIP/${name}" })
If you use the new syntax you can also place commas between dial
options so each option is a separate argument and thus you can be
sure that what dial sees is what you intended, e.g.:
Dial({ "SIP/${name}" }, T, A("${announcefile}"), W)
If you need to build lists of devices to dial dynamically DO NOT be
tempted to fall back on the old syntax. Instead embed quotes and
use EVAL() to reparse the string back into a list of arguments (you
can use the same technique any other time you need to construct
lists of arguments), e.g.:
Set(devs="'DAHDI/g1/${number}'")
Set(devs="${devs}, 'SIP/${name}'")
Dial({ ${EVAL("${devs}")} }, ...)
Please clean up your dialplans and let me know (with debug/verbose logs)
of anything that doesn't seem to work. And ask questions if anything
doesn't seem clear :-).
Mike
--
Mike Jagdis Web: http://www.eris-associates.co.uk
Eris Associates Limited Tel: +44 7780 608 368
Reading, England Fax: +44 118 926 6974
Mike Jagdis Web: http://www.eris-associates.co.uk
Eris Associates Limited Tel: +44 7780 608 368
Reading, England Fax: +44 118 926 6974