Help with cfexecute and sh with sudo commands

I’m still in the process of learing linux/ubuntu. I came across a problem that I would appreciate some advice on how to safely cfexecute scipting files with commands that needs sudo. I’ve found some examples on how to do it with PHP, but I still don’t feel safe doing it.

I am running Lucee 5.3.3.62 with lucees default none-root user “cfml” on Ubuntu 18.04. I just want to open/close the SSH ports using a simple button on a cfm-page with the use of cfexecute.

So I created two very simple scripts:

/opt/myscripts/openSSHport.sh

#!/bin/sh
ufw allow 22

and for closing
/opt/myscripts/closeSSHport.sh

#!/bin/sh
ufw deny 22

I can run both scripts successfully in a terminal with:
$ sudo sh /opt/myscripts/closeSSHport.sh

However, when using cfexecute I receive an error as expected because of cfml being non root user:
sudo: no tty present and no askpass program specified

What is the best way to approach this? I don’t like the idea of giving “cfml” free sudo privilege. How can I give CFML the privilege to run those scripts only by doing:

<cfscript>                
        cfexecute( 
        name="sudo", 
        arguments="sh /opt/myscripts/closeSSHPort.sh", 
        variable="standardOut" , 
         errorVariable="errorOut" );
</cfscript>

Should I really set up passwordless sudo for user “cfml” in visudo? What would be the safest way to get those scripts running with cfexecute without giving cfml all over access to ufw?

I would appreciate some insight a lot.

First, ensure that your /opt/myscripts/ and all the scripts within are owned by root, but can be read and executed by CFML. Likely you’ll use CFML’s group for this, or a supplemental group. For sake of illustration let’s create a supplemental group.

groupadd -r cfscript
usermod -a -G cfscript cfml
chown -R root.cfscript /opt/myscripts
chmod 750 /opt/myscripts /opt/myscripts/*.sh

Here’s what this does.

  1. Creates a new group called cfscript.
  2. Adds the user “cfml” to the group
  3. Sets ownership of /opt/myscripts/ to user root, group cfscript
  4. Sets permissions such that only root and cfscript members can enter the directory, and execute scripts.

If you then run id cfml you’ll see all the groups that cfml is a member of. You should restart lucee. It’s probably also worth running cfexecute id to verify that the lucee server has the supplemental group cfscript. If it doesn’t, nothing else is going to work - you’d need to look into how the service is started, specifically how it runs at cfml - things initiated from a root systemd need to set the user of the service somehow. If it’s systemd, you should be fine or can set additional groups in the .service file… If it’s su, you’re probably fine. If it’s setuidgid, it only does primary groups, if it’s chpst, it’ll set what you tell it to so you need to tweak command line options.

But I digress let’s assume you’ve run cfexecute id, and you HAVE the cfscript supplemental group, and all is well. If it isn’t then we’ll have to dig down the rabbit hole further.

The reason we set the ownership to root is because we want to ensure only root can modify these files. We want “root” to decide what the delegated access to the cfscript group is - so only root should modify the files, and root should make it possible for cfscript group to execute the files. If they’re owned by… cfml, for instance, cfml could just change the script and do whatever they want.

Since you have a shebang line as line 1 of your scripts, you don’t need to run sh explicitly, that, in combination with the executable bits applied earlier means we can run them as /opt/myscripts/closeSSHPort.sh directly, without calling sh first.

Now we’ll tell sudo that passwordless is fine, but ONLY for these scripts.

If your distro supports it you can create a new file in /etc/sudoers.d/, perhaps called cfscript. Otherwise you’d have to modify the main /etc/sudoers file, but you’ll want to add something like this:

%cfscript ALL=NOPASSWD:/opt/myscripts/closeSSHPort.sh
%cfscript ALL=NOPASSWD:/opt/myscripts/openSSHPort.sh

This tells sudo that members of the cfscript group, can run the /opt/myscripts/closeSSHPort.sh and /opt/myscripts/closeSSHPort.sh scripts, without requiring a password, as any user they want (but ultimately as root, I just don’t bother to specify)

This opens the smallest security “hole” possible to enable what you want to do.

You can now test this from the shell as the cfml user.

First id to make sure you have the cfscript group. Adding the group to a user only takes effect after restarting the service, or reconnecting to the ssh console, or restarting your X11 session.

Assuming you HAVE the cfscript group

sudo /opt/myscripts/closeSSHPort.sh

It should complete without asking for a password.

During testing it may be useful to echo the commands executed - if /bin/sh is bash, you can just add “set -x” to your script, i.e. on line 2 before your ufw line, and it’ll echo the commands as they’re run to STDERR.

You may also have to explicitly reference ufw - i.e. /sbin/ufw or /usr/sbin/ufw (use which ufw as root to figure out where it is) because the user’s PATH argument won’t include those directories, and/or just to be specific about what you want to execute.

From CF, then you just execute name=“sudo” arguments=“/opt/myscripts/closeSSHPort.sh”

1 Like

Dear Joseph @joe.gooch,

just wanted to say that your answer is by far more than I’ve expected!!! Hooray!!! Thanks for taking your time to do this detailied step by step instructions with the supplemental group cfscript. I’m going to bookmark this Thread-URL and try it right away.

Have a very nice day!!!

Thanks, @joe.gooch for such a useful and comprehensive answer.

FYI 5.3.8 adds a directory parameter to <cfexecute> thanks to @isapir

https://luceeserver.atlassian.net/browse/LDEV-2912

1 Like