Jump to content
limetech

Plugin Authors: Changes for 6.1 release

44 posts in this topic Last Reply

Recommended Posts

Plugin Authors:

 

A primary goal of 6.1 is to button up some security holes; hopefully, you have followed along with the 6.1-rc release series.  In particular, we have made some changes having to do with commands passed in the 'cmd' (for update.htm) and '#command' (for update.php) query variables.  In addition we have eliminated and/or moved around certain command utilities.  These changes may or may not affect your plugin (probably they will).

 

Here we will outline the changes that should be made.  Please reply in this thread with questions/comments.

 

Command Execution

 

Here we're referring to a mechanism whereby a "command" can be passed in http GET or POST via query variable.  In the past, these commands could be anything, including for example, things that could display the passwd file or delete arbitrary files.  In an untrusted network of course this is undesirable.  If you define a root password then authentication is necessary to successfully execute http GET/POST and up until now that was "good enough" - but no longer.  Here we describe some methods we've seen plugins employ and how to fix.

 

Note: update.php features an #include argument which also must follow the below rules.

 

There are basically 4 ways a command string can be passed:

 

1) An absolute path which whose root is like a “/usr/local/emhttp” (docroot) jail:

 

cmd=/webGui/scripts/mycmd
cmd=/plugins/<plugin-name>/scripts/mycmd

 

When the command is actually executed the server will prepend “/usr/local/emhttp” to form the real path of the command passed to exec().  This is now the “best practice” for all such command strings.

 

2) An absolute path where docroot is explicitly included:

 

cmd=/usr/local/emhttp/webGui/scripts/mycmd
cmd=/usr/local/emhttp/plugins/<plugin-name>/scripts/mycmd

 

This will work but we will generate syslog message similar to:

 

“Deprecated absolute path:”

 

In 6.1 ‘stable’ this will be an error.  There are no uses of this form in the 6.1 webGui.

 

3) A relative path:

 

cmd=webGui/scripts/mycmd
cmd=plugins/<plugin-name>/scripts/mycmd
cmd=rm file

 

This will work but we will generate syslog message similar to:

 

“Deprecated relative path:”

 

In 6.1 ‘stable’ this will be an error.  There are no uses of this form in the 6.1 webGui.

 

4) An absolute path outside our docroot:

 

cmd=/usr/sbin/rm file

 

This will not work at all and will generate an error message in the syslog.

 

Once 6.1 stable is released, we’ll use realpath() function to verify commands do not get outside /usr/local/emhttp but this is not enforced completely yet.  Note this precludes the use of common shell commands such as 'cp', 'mv', etc.  For doing such operations you must create a wrapper script.  Wrapper scripts should be in your plugin/scripts directory.

 

Commands executed with exec()/shell_exec()

 

The “best practice” is to specify an absolute path:

 

exec(“/usr/local/emhttp/plugins/dynamix.plugin.manager/scripts/plugin $args”);

 

though this will work (but watch out: no leading ‘/’):

 

exec(“plugins/dynamix.plugin.manager/scripts/plugin $args”);

 

and one could also use:

 

exec(“$docroot/plugins/dynamix.plugin.manager/scripts/plugin $args”);

 

Use of built-in commands

 

Command that used to be in /root have been moved to /usr/local/sbin (in particular 'mdcmd').  If one of these is used please use the new absolute path, eg., "/usr/local/sbin/mdcmd".

 

Plugins that define scripts should put them in the plugin-specific ./scripts directory.  If your plugin defines a script that would be useful for someone at the console, it's ok for it to generate a symlink to the script in /usr/local/sbin.  See for example, the 'plugin' command.

 

Command arguments

 

Arguments for commands passed via 'cmd' or '#command' must be specified using separate query variables.

 

For example, with 'update.htm':

GET /update.htm?cmd=/plugins/dynamix.plugin.manager/scripts/plugin&arg1=version

 

For 'update.php':

POST /update.php

<post body>

#command=<mycommand>

#arg[1]=<argument 1>

#arg[2]=<argument 2>

etc

Share this post


Link to post

Perhaps also good to mention that plugins which have scripts defined to start and stop a service under /etc/rc.d are recommended to move to /usr/local/emhttp/plugins/<plugin name>/scripts as well.

 

For example

 

/etc/rc.d/rc.myService

 

becomes

 

/usr/local/emhttp/plugins/myPlugin/scripts/rc.myService

 

Share this post


Link to post

I really applaud the effort in closing any and all security holes in unRaid.

 

Community Applications is ready to go for 6.1 Final

 

Share this post


Link to post

Looks like Tom edited the OP with this:  (I got nailed by it)

 

Command arguments

 

Arguments for commands passed via 'cmd' or '#command' must be specified using separate query variables.

 

For example, with 'update.htm':

GET /update.htm?cmd=/plugins/dynamix.plugin.manager/scripts/plugin&arg1=version

 

For 'update.php':

POST /update.php

<post body>

#command=<mycommand>

#arg[1]=<argument 1>

#arg[2]=<argument 2>

etc

Share this post


Link to post

Looks like Tom edited the OP with this:  (I got nailed by it)

 

Command arguments

 

Arguments for commands passed via 'cmd' or '#command' must be specified using separate query variables.

 

For example, with 'update.htm':

GET /update.htm?cmd=/plugins/dynamix.plugin.manager/scripts/plugin&arg1=version

 

For 'update.php':

POST /update.php

<post body>

#command=<mycommand>

#arg[1]=<argument 1>

#arg[2]=<argument 2>

etc

 

That's what I was looking for.

Share this post


Link to post

I've been messing with the unassigned devices plugin to see if I can make it work for rc6 because rc5 broke it, then rc6 broke it again.  I have everything working but I can't figure out the syntax I need for this line;

 

var content= "<div class='switch-wrapper'><input type='checkbox' class='complete-switch'></div><button type='button' onclick='$.post(\"/update.php\",{\"#command\":\"/plugins/unassigned.devices/scripts/udevadm trigger --action=change\"}};' value='Rescan Disks'>Rescan Disks</button></div>";

 

Can anyone suggest how to code this line to get it to work with rc6 and pass the command and arg separately?

 

The scripts/udevadm is a symlink to /usr/sbin/udevadm, which may not be necessary because udevadm may be in the path.  I'll investigate that further once I get this working.

Share this post


Link to post

I've been messing with the unassigned devices plugin to see if I can make it work for rc6 because rc5 broke it, then rc6 broke it again.  I have everything working but I can't figure out the syntax I need for this line;

 

var content= "<div class='switch-wrapper'><input type='checkbox' class='complete-switch'></div><button type='button' onclick='$.post(\"/update.php\",{\"#command\":\"/plugins/unassigned.devices/scripts/udevadm trigger --action=change\"}};' value='Rescan Disks'>Rescan Disks</button></div>";

 

Can anyone suggest how to code this line to get it to work with rc6 and pass the command and arg separately?

 

The scripts/udevadm is a symlink to /usr/sbin/udevadm, which may not be necessary because udevadm may be in the path.  I'll investigate that further once I get this working.

 

Sure, the correct syntax is:

 

var content= "<div class='switch-wrapper'><input type='checkbox' class='complete-switch'></div><button type='button' onclick='$.post(\"/update.php\",{\"#command\":\"/plugins/unassigned.devices/scripts/udevadm\", \"#arg[1]\":\"trigger\", \"#arg[2]\":\"--action=change\"});' value='Rescan Disks'>Rescan Disks</button></div>";

 

Any parameters need to be passed as a separate array of arguments (#arg[1], #arg[2], etc). The line above is written in JSON notation.

 

Ps1. In the original string is a mistake with double '}}' it should be '})'

 

Ps2. It is also required that scripts are placed under the <plugin>/scripts location instead of /usr/local/sbin.

 

Share this post


Link to post

i have this code ....

 <form name="stop_openvpnserver" method="POST" action="/update.htm" target="progressFrame">
          <input type="hidden" name="cmd" value="/usr/local/emhttp/plugins/openvpnserver/scripts/rc.openvpnserver stop">
          <input type="submit" name="runCmd" value="Stop">
         </form>

 

I change the cmd line to ...

 

<input type="hidden" name="cmd" value="/plugins/openvpnserver/scripts/rc.openvpnserver stop">

 

but it still won't work? what have I missed ?

 

//Peter

 

Share this post


Link to post

Use:

 

<input type="hidden" name="cmd" value="/plugins/openvpnserver/scripts/rc.openvpnserver[color=red]&arg1=[/color]stop">

Share this post


Link to post

Use:

 

<input type="hidden" name="cmd" value="/plugins/openvpnserver/scripts/rc.openvpnserver[color=red]&arg1=[/color]stop">

 

Thanks, but where and how do I specify

&arg1

Share this post


Link to post

Use:

 

<input type="hidden" name="cmd" value="/plugins/openvpnserver/scripts/rc.openvpnserver[color=red]&arg1=[/color]stop">

 

Thanks, but where and how do I specify

&arg1

 

It is not allowed anymore to specify parameters directly in the command, instead they need to be given as separate arguments:

 

Incorrect:

 

/plugins/openvpnserver/scripts/rc.openvpnserver stop

 

Correct:

 

/plugins/openvpnserver/scripts/rc.openvpnserver&arg1=stop

 

Share this post


Link to post

Use:

 

<input type="hidden" name="cmd" value="/plugins/openvpnserver/scripts/rc.openvpnserver[color=red]&arg1=[/color]stop">

 

Thanks, but where and how do I specify

&arg1

You are specifying it by saying arg1=stop

Share this post


Link to post

 

 

Use:

 

<input type="hidden" name="cmd" value="/plugins/openvpnserver/scripts/rc.openvpnserver[color=red]&arg1=[/color]stop">

 

For some reason I could not get that to work. Log kept showing invalid command. I looked through update.php but couldn't figure out why $command === false. I didn't try too hard either. I just split the rc file into a start and stop script. Then tied those to event folder scripts also.

Share this post


Link to post

Posting this for another use who can't post in this subforum

A) I can't reply to the thread for whatever reason.

 

B) Relevant to the thread in question...

 

He might need to XML Encode the &args1= portion to be &args1= since it's inside HTML value node.

Share this post


Link to post

Posting this for another use who can't post in this subforum

A) I can't reply to the thread for whatever reason.

 

B) Relevant to the thread in question...

 

He might need to XML Encode the &args1= portion to be &args1= since it's inside HTML value node.

I'll try that with a different plugin. But truthfully it was just easier to split the rc script and remove the bash functions and case logic since I already was using javascript to update the post value anyway.

 

Edit: I figured it out. Since I was using update.php I needed something like this. But I will just split rc.script and make a start and stop script since its cleaner.

<code>

<form name="deluged_settings" method="POST" action="/update.php" target="progressFrame">

<input type="hidden" name="#file" value="<?=$deluged_cfgfile;?>" />

<input type="hidden" id="command" name="#command" value="/usr/local/emhttp/plugins/deluged/scripts/rc.deluged" />

<input type="hidden" id="arg" name="#arg[0]" value="start" />

</code>

Share this post


Link to post

Posting this for another use who can't post in this subforum

A) I can't reply to the thread for whatever reason.

 

B) Relevant to the thread in question...

 

He might need to XML Encode the &args1= portion to be &args1= since it's inside HTML value node.

I'll try that with a different plugin. But truthfully it was just easier to split the rc script and remove the bash functions and case logic since I already was using javascript to update the post value anyway.

 

Edit: I figured it out. Since I was using update.php I needed something like this. But I will just split rc.script and make a start and stop script since its cleaner.

<code>

<form name="deluged_settings" method="POST" action="/update.php" target="progressFrame">

<input type="hidden" name="#file" value="<?=$deluged_cfgfile;?>" />

<input type="hidden" id="command" name="#command" value="/usr/local/emhttp/plugins/deluged/scripts/rc.deluged" />

<input type="hidden" id="arg" name="#arg[0]" value="start" />

</code>

 

Yes this method is best practice.

Share this post


Link to post

Use:

 

<input type="hidden" name="cmd" value="/plugins/openvpnserver/scripts/rc.openvpnserver[color=red]&arg1=[/color]stop">

I'm using the update.htm file in my plugins and doing the above doesn't seem to work for me either. Here's my code currently:

 

<form name="app_install" method="POST" action="/update.htm" target="progressFrame">

<input type="hidden" name="cmd" value="/plugins/<?=$appname;?>/scripts/rc.<?=$appname;?>&arg1=install"/>         

<input type="submit" name="runCmd" id="STDSMBUTTON" value="Install"/>

</form>

 

$appname in this case is "Btsync"

 

by adding &arg1= above, it still doesn't actually pass that argument over to the script file. Is there another step I'm missing?

Share this post


Link to post

Hi! You can try this, I got info from Tom!

I have no time right now to test ......

 

Using update.php is preferred:

<tr>
          <td width="30%">
            <form name="start_openvpnserver" method="POST" action="/update.php" target="progressFrame">
                <input type="hidden" name="#command" value="/plugins/openvpnserver/scripts/rc.openvpnserver">
                <input type="hidden" name="#arg[1]" value="start">
                <input type="submit" value="start">
            </form>
            </td>
            <td> <span class="red-text">Start OpenVPN Server</span></td>
</tr>

Share this post


Link to post

Will update.php work on unraid 5 as well? My plugins are universal between the different unraid versions so I don't want to break the backwards compatibility on them. I'm guessing the cmd for update.htm is missing something (in my plugin) or broken in rc6...?

Share this post


Link to post

Will update.php work on unraid 5 as well? My plugins are universal between the different unraid versions so I don't want to break the backwards compatibility on them. I'm guessing the cmd for update.htm is missing something (in my plugin) or broken in rc6...?

 

No, update.php was introduced as part of Dynamix, which isn't present in unRAID v5.

 

It is still possible to use update.htm / cmd in v6.1 though syntax has changed so you need to take care of that between old and new unRAID versions (if you want to keep compatibility).

 

Share this post


Link to post

Use:

 

<input type="hidden" name="cmd" value="/plugins/openvpnserver/scripts/rc.openvpnserver[color=red]&arg1=[/color]stop">

I'm using the update.htm file in my plugins and doing the above doesn't seem to work for me either. Here's my code currently:

 

<form name="app_install" method="POST" action="/update.htm" target="progressFrame">

<input type="hidden" name="cmd" value="/plugins/<?=$appname;?>/scripts/rc.<?=$appname;?>&arg1=install"/>         

<input type="submit" name="runCmd" id="STDSMBUTTON" value="Install"/>

</form>

 

$appname in this case is "Btsync"

 

by adding &arg1= above, it still doesn't actually pass that argument over to the script file. Is there another step I'm missing?

Try the following

<form name="app_install" method="POST" action="/update.htm" target="progressFrame">
[b]	<input type="hidden" name="cmd" value="/plugins/<?=$appname;?>/scripts/rc.<?=$appname;?>&arg1=install"/>[/b]          
<input type="submit" id="STDSMBUTTON" value="Install"/>
</form>

 

Share this post


Link to post

Thanks, that didn't seem to resolve it. Pressing the install button still just flashes the screen and reloads the page but the command is never passed to the server it seems.

Share this post


Link to post

Is there any include required for update.htm like there is with update.php?

Share this post


Link to post

Thanks, that didn't seem to resolve it. Pressing the install button still just flashes the screen and reloads the page but the command is never passed to the server it seems.

 

When you execute the command, check the syslog to see if the command is rejected (no message should mean it is executed).

 

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now