Plugin Authors: Changes for 6.1 release


limetech

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

Link to comment

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

 

Link to comment

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

Link to comment

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.

Link to comment

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.

Link to comment

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.

 

Link to comment

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

 

Link to comment

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

 

Link to comment

 

 

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.

Link to comment

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>

Link to comment

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.

Link to comment

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?

Link to comment

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>

Link to comment

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...?

Link to comment

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).

 

Link to comment

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>

 

Link to comment

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).

 

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.