Problem with exec shell_escape option
I'm trying to get exec to pass a string as an argument without any shell quoting, but not succeeding. This is with freeradius 3.0.12 under Ubuntu 16.04. [Aside: what I'm actually trying to do is invoke an external change password program using an exec expansion in local_cpw in rlm_mschap, following the example given: # local_cpw = "%{exec:/path/to/script %{mschap:User-Name} %{MS-CHAP-New-Cleartext-Password}}" But I'm finding that passwords with special characters are being mangled] I can reproduce this using exec by itself. Here are 4 combinations: shell_escape = {yes,no} and expansion argument quoted/not quoted. # mods-available/exec - I left the original exec in there and added: exec exec1 { wait = yes input_pairs = request shell_escape = no timeout = 10 } exec exec2 { wait = yes input_pairs = request shell_escape = yes timeout = 10 } # policy.d/testpolicy testpolicy { update request { &Tmp-String-0 := " foo ' bar \" baz \\ qux " &Tmp-String-1 := "%{exec1:/usr/local/bin/showarg %{Tmp-String-0}}" &Tmp-String-2 := "%{exec1:/usr/local/bin/showarg '%{Tmp-String-0}'}" &Tmp-String-3 := "%{exec2:/usr/local/bin/showarg %{Tmp-String-0}}" &Tmp-String-4 := "%{exec2:/usr/local/bin/showarg '%{Tmp-String-0}'}" } } # /usr/local/bin/showarg #!/bin/sh echo "Arg is <$1>" >>/tmp/exec.log Results: - 1 and 3 fail with "rad_expand_xlat: Invalid string passed as argument" - 2 and 4 both apply shell quoting to the argument # cat /tmp/exec.log Arg is <\ foo\ \'\ bar\ "\ baz\ \ qux\ > Arg is <\ foo\ \'\ bar\ "\ baz\ \ qux\ > Debug output: (0) policy testpolicy { (0) update request { (0) &Tmp-String-0 := " foo ' bar \" baz \\ qux " (0) Executing: /usr/local/bin/showarg \ foo\ \'\ bar\ "\ baz\ \\ qux\ : rad_expand_xlat: Invalid string passed as argument invalid command line '/usr/local/bin/showarg \ foo\ \'\ bar\ "\ baz\ \\ qux\ '. (0) EXPAND %{exec1:/usr/local/bin/showarg %{Tmp-String-0}} (0) --> (0) &Tmp-String-1 := (0) Executing: /usr/local/bin/showarg '\ foo\ \'\ bar\ "\ baz\ \\ qux\ ': (0) Program returned code (0) and output '' (0) EXPAND %{exec1:/usr/local/bin/showarg '%{Tmp-String-0}'} (0) --> (0) &Tmp-String-2 := (0) Executing: /usr/local/bin/showarg \ foo\ \'\ bar\ "\ baz\ \\ qux\ : rad_expand_xlat: Invalid string passed as argument invalid command line '/usr/local/bin/showarg \ foo\ \'\ bar\ "\ baz\ \\ qux\ '. (0) EXPAND %{exec2:/usr/local/bin/showarg %{Tmp-String-0}} (0) --> (0) &Tmp-String-3 := (0) Executing: /usr/local/bin/showarg '\ foo\ \'\ bar\ "\ baz\ \\ qux\ ': (0) Program returned code (0) and output '' (0) EXPAND %{exec2:/usr/local/bin/showarg '%{Tmp-String-0}'} (0) --> (0) &Tmp-String-4 := (0) } # update request = noop (0) } # policy testpolicy = noop So it looks like the shell_escape setting isn't doing anything. What am I missing? Thanks, Brian. P.S. There is something else confusing. In raddb/mods-available/exec it says: # Execute external programs # # This module is useful only for 'xlat'. To use it, # put 'exec' into the 'instantiate' section. You can then # do dynamic translation of attributes like: # # Attribute-Name = `%{exec:/path/to/program args}` However, I can see from the source that it has hooks for the various module lifecycle stages; indeed, the sites-available/default config invokes it in the accounting and post-auth stages: # For Exec-Program and Exec-Program-Wait exec So is the comment that exec is "useful only for 'xlat'" incorrect? I've checked the obvious places for documentation with no luck: - http://wiki.freeradius.org/search?q=exec - man rlm_exec (not found) But in any case, it doesn't affect the main issue here, since local_cpw has to use a string expansion anyway.
On Dec 21, 2016, at 1:42 PM, Brian Candler <b.candler@pobox.com> wrote:
I'm trying to get exec to pass a string as an argument without any shell quoting, but not succeeding. This is with freeradius 3.0.12 under Ubuntu 16.04.
Strings are escaped when passed to the shell. That's a security requirement, and can't be changed. The strings *should* be escaped properly. So that the shell can un-escape them and use them, though.
testpolicy { update request { &Tmp-String-0 := " foo ' bar \" baz \\ qux " &Tmp-String-1 := "%{exec1:/usr/local/bin/showarg %{Tmp-String-0}}" &Tmp-String-2 := "%{exec1:/usr/local/bin/showarg '%{Tmp-String-0}'}" &Tmp-String-3 := "%{exec2:/usr/local/bin/showarg %{Tmp-String-0}}" &Tmp-String-4 := "%{exec2:/usr/local/bin/showarg '%{Tmp-String-0}'}" } }
# /usr/local/bin/showarg
#!/bin/sh echo "Arg is <$1>" >>/tmp/exec.log
Results:
- 1 and 3 fail with "rad_expand_xlat: Invalid string passed as argument"
- 2 and 4 both apply shell quoting to the argument
# cat /tmp/exec.log Arg is <\ foo\ \'\ bar\ "\ baz\ \ qux\ > Arg is <\ foo\ \'\ bar\ "\ baz\ \ qux\ >
Debug output:
(0) policy testpolicy { (0) update request { (0) &Tmp-String-0 := " foo ' bar \" baz \\ qux " (0) Executing: /usr/local/bin/showarg \ foo\ \'\ bar\ "\ baz\ \\ qux\ : rad_expand_xlat: Invalid string passed as argument
Hmm... the string expansion looks OK. i.e. there are enough backslashes. The issue seems to be that the string un-expansion is expecting "\ " only here, and is getting upset over the \'
So it looks like the shell_escape setting isn't doing anything. What am I missing?
It should work. I'll see if I can add some tests. But in general, passing user input to an exec'd program is a bad idea. It's useful, but there are just too many opportunities for the user to do something bad.
However, I can see from the source that it has hooks for the various module lifecycle stages; indeed, the sites-available/default config invokes it in the accounting and post-auth stages:
# For Exec-Program and Exec-Program-Wait exec
That's historical.
So is the comment that exec is "useful only for 'xlat'" incorrect?
It's mostly correct. The Exec-Program and Exec-Program-Wait functionality should be removed in v4. Alan DeKok.
On 21/12/2016 18:51, Alan DeKok wrote:
It should work. I'll see if I can add some tests. Thank you. But in general, passing user input to an exec'd program is a bad idea. It's useful, but there are just too many opportunities for the user to do something bad.
Sure. The external password change program I've written isn't a shell script. As far as I can tell from source: the 'exec' xlat expansion ultimately calls execve(prog, args), i.e. it doesn't invoke a shell itself. Is that right? Cheers, Brian.
participants (2)
-
Alan DeKok -
Brian Candler