How to Run a Script as a Non-Shell User (/sbin/nologin) on RedHat Linux: Solutions for su and setuid Issues


39 views

When working with system accounts on RedHat Linux (or any Linux system), you'll often encounter users with /sbin/nologin as their shell. These accounts are typically used for services and daemons that shouldn't have interactive login capabilities. However, this becomes problematic when you need to execute scripts as these users.

The standard approach using su fails because the account is locked for interactive use:


su myuser -c /home/myuser/script.sh
# Results in: "This account is currently not available"

This happens because su attempts to start a login shell, which is explicitly prohibited by the /sbin/nologin setting.

The setuid approach doesn't work as expected either:


chown myuser:mygroup /home/myuser/script.sh
chmod +s /home/myuser/script.sh
/home/myuser/script.sh  # Still executes as current user (root)

This occurs because setuid is ignored for scripts due to security reasons - it only works with compiled binaries.

Option 1: Using sudo

Configure sudo to allow specific commands without a shell:


# In /etc/sudoers:
myrunner ALL=(myuser) NOPASSWD: /home/myuser/script.sh

# Then execute:
sudo -u myuser /home/myuser/script.sh

Option 2: Using runuser

RedHat's runuser command can bypass the shell requirement:


runuser -u myuser -- /home/myuser/script.sh

Option 3: Temporary Shell Modification

For one-time executions, temporarily change the shell:


usermod -s /bin/bash myuser
su myuser -c "/home/myuser/script.sh"
usermod -s /sbin/nologin myuser

Note: This approach has security implications and should be used cautiously.

Option 4: Using a Wrapper Binary

Create a simple C wrapper:


// compile with: gcc -o wrapper wrapper.c
#include 
#include 

int main() {
    setuid(1001);  // UID of myuser
    system("/home/myuser/script.sh");
    return 0;
}

Then set the setuid bit on the compiled binary.

When implementing these solutions:

  • Always prefer sudo over permanent shell changes
  • Audit scripts being run as system users
  • Limit sudo permissions to specific commands
  • Consider using proper service management (systemd units) for persistent operations

When dealing with system accounts configured with /sbin/nologin as their shell in /etc/passwd, traditional methods like su or sudo won't work because these accounts are explicitly restricted from interactive login. Here's why your attempts failed:

# This fails because nologin accounts block shell access
su myuser -c /home/myuser/script.sh

The setuid bit approach failed because:

  • Linux ignores setuid on interpreted scripts for security reasons
  • Even with proper ownership, the kernel won't execute scripts with elevated privileges

Method 1: Using sudo with nologin override

# In /etc/sudoers add:
myuser ALL=(root) NOPASSWD: /home/myuser/script.sh

# Then execute with:
sudo -u myuser /home/myuser/script.sh

Method 2: Wrapper in C (for setuid functionality)

Compile this as a binary and set proper permissions:

#include <unistd.h>
#include <sys/types.h>

int main() {
    setuid(1001);  // Replace with myuser's UID
    system("/home/myuser/script.sh");
    return 0;
}

Then:

gcc wrapper.c -o script_wrapper
chown myuser:mygroup script_wrapper
chmod 4750 script_wrapper

Method 3: Using runuser with --shell override

runuser -u myuser --shell=/bin/bash /home/myuser/script.sh

When implementing these solutions:

  • Always validate paths in scripts
  • Limit sudo permissions to specific commands
  • Audit scripts for potential privilege escalation vectors

For systemd-based systems, consider creating a service unit:

[Unit]
Description=MyUser Script Service

[Service]
User=myuser
ExecStart=/home/myuser/script.sh

[Install]
WantedBy=multi-user.target