1

I would like to allow a user to run any of a collection of scripts and write the output a designated directory but to not allow that designated directory to be written to with any other script or command for that user.

The intent is to rsync that designated directory out of the system but only for approved scripts. The user can run other scripts unrestricted but is prevented from exporting the output outside of the environment except for approved scripts.

Attempt to solve the issue

I have tried setting up two users 'normal' and 'restricted' with the output directory and approved scripts owned by 'restricted' so 'normal' run the scripts as 'restricted' allowing the output to go to the restricted directory and this works but there is nothing to stop 'normal' running an unapporved script as 'restricted' allowing the output to go to 'restricted' directory which is what I wish to prevent.

3
  • 2
    You leave out important information like the relevant OS etc. Plese add this. Nevertheless, my first two ideas to look into are sudo wrappers and SELinux.
    – Sven
    Commented Nov 8, 2016 at 16:43
  • 2
    If you use sudo, you can allow your user to only execute certain commands/scripts as the specified user. Also, Ubuntu uses AppArmor instead of SELinux IIRC.
    – Sven
    Commented Nov 8, 2016 at 17:32
  • If it's linux, sudo can do that.
    – mzhaase
    Commented Nov 15, 2016 at 16:16

3 Answers 3

4
+50

Here is what you can do:

You will need two users 'normal' and 'restricted' but don't give the password for restricted user to normal user. Then call:

visudo 

And add all the scripts that you want to let the normal user to execute as restricted user like this:

normal ALL=(restricted) NOPASSWD: scriptDir/script.sh

Then let user normal calling the scripts like:

su -c scriptDir/script.sh restricted

In this way you can control what script you want the user normal to execute as restricted

9
  • I think this is promising. Is there a way to redirect the output of the script into the restricted directory only ffor those scripts: sudo -u restricted scriptDir/script.sh > scriptDir/command.out
    – DavidC
    Commented Nov 16, 2016 at 17:31
  • 1
    @DavidC you give permissions to the output folder to the user 'restricted'. Then you have your script direct writes to that folder.
    – Jeter-work
    Commented Nov 16, 2016 at 23:16
  • 1
    @DavidC If you hash the script(s), then in sudoers you can explicitly give permission on those scripts with the hash. This will prevent the user/group from executing any of the scripts that have a hash different from what is listed in sudoers. See here: sudo.ws/man/1.8.17/sudoers.man.html
    – Jeter-work
    Commented Nov 16, 2016 at 23:37
  • 1
    I can confirm that this method works - we use this for a junior tech who needs to run specific scripts on a few servers. Commented Nov 17, 2016 at 7:01
  • 1
    @DavidC you can redirect the output from inside the script don't let it print output to the stdout make it print it to the file in the file inside the restricted area directly Commented Nov 17, 2016 at 8:09
1

Set up ACL - Access Control list by installing the utilities (getfacl and setfacl).

You can set per-user ACLs, but it's often easier to put users who should have the same rights on a part of the filesystem in a group and set ACLs for that group. For example, if the users in the group html-writers should have read-write access to the tree under /var/www/html

You could use setfacl:

setfacl -m group:html-writers u:username:rwx myfolder

This sets permissions for specific users, without changing the ownership of the directory.

1
  • Doesn't prevent the end user from modifying items in the folder when not running the script. OP wants the end user to be able to run a script that writes to a folder, but the end user can only modify that folder through the script.
    – Jeter-work
    Commented Nov 16, 2016 at 23:21
1

Sounds like you're trying to solve a problem using tools that don't allow you to do what you want. If you rely on ACLs or Unix permissions, then the permissions regarding the directory, depend on the user that is trying to change them. So regardless of how you cut it, if a user can write to the directory, they can create files in addition to those you want them to create.

However, if the user can't write to the directory, but you wish for a script to be able to, then you must run that script as a user that can. This can be done 2 ways, if you must use a script, then as mentioned by @Wissam Al-Roujoulah, you can use sudo. If you can get the intended behaviour into a binary, rather than a script, then you can use setuid on it, and configure it so that any member of a group can run the binary, but that binary will run as a different user.

The issue with sudo on scripts is the same as the reason why you can't use setuid on a script. It's simply too easy for someone to pervert the behaviour of a script, using shell variables, so act with caution.

I solved my own version of your problem by writing a very basic .c file which runs system commands like a script, then have the compiled binary, setuid to allow users to use it. In my case I wanted to clear cache folders from various locations, where the binary needs run as root, but I wanted non-privileged users to be able to run it.

I've cut the file down a lot, as my original included options for clearing multiple different types of cache, in different locations, but you get the idea. I've also included the code I used to audit log, as it shows how to put info in the syslog, if you want to use that rather than a file.

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <syslog.h>

int has_root_euid()
{
  if (geteuid()==0) {
    return 1;
  }
  return 0;
}

int main (int argc, char * argv[])
{
  int retval;
  uid_t uid;

  uid = getuid();

  openlog (argv[0], LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
  syslog (LOG_NOTICE, "UID %d ran clearcache", uid);
  closelog();

  if (!has_root_euid()) {
    printf("Insufficient permissions to clear WSDL cache.\n");
  } else {
    printf("Clearing WSDL cache: rm -f /tmp/wsdl*\n");
    setuid(0);
    retval = system("rm -f /tmp/wsdl*");
    setuid(uid);
    printf("System returns (%d). \n", retval);
  }
  return 0;
}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .