Allow non-root users to run init.d

Some companies do not allow usage of sudo or su – root due to security reasons. E.g.:

I have written a cron job for CentOS Linux that allows non-root users to trigger different init.d executables on their own without using sudo.

User just adds a token (e.g.: httpd graceful) to a trigger file within their home directory and waits for the root cron job. The root cron job picks up the token every two minutes, validates it and then runs the desired init.d script.

This method works on all System V systems and is useful for Apache, MySQL, Samba and many other middleware that has to be installed by root, but used by non-root or unprivileged application administrators. Ok admin, first put following files to the non-root users home directory:

  • Configuration file
  • Empty trigger file
  • Empty log file
  • Cron job as bash script file

The administrator has to ensure, that file permissions and ownership is set properly to avoid abuse. Here is an example from the view of the non-root user peter:

[peter ~]$ ls -l service-ctrl.*
-rw-r--r-- 1 root peter   511 Sep 11 22:22 service-ctrl.cfg
-rw-r--r-- 1 root peter   511 Sep 11 22:22 service-ctrl.cfg.bak
-rw-r--r-- 1 root peter   167 Sep 11 22:22 service-ctrl.log
-rwxr--r-- 1 root root   2828 Sep 11 22:22 service-ctrl.sh
-rw-rw-r-- 1 root peter     0 Sep 11 22:22 service-ctrl.trigger

The configuration file contains a list of services and their options. E.g.:

[peter ~]$ grep ^srvlst service-ctrl.cfg
srvlst+=("httpd start stop restart graceful status")
srvlst+=("iptables status")

The configuration file allows the administrator (=root) to enable the usage of specific services and options on a per-user basis. The default service for testing purposes is: /etc/init.d/ntpd status

[peter ~]$ grep ^srvlst service-ctrl.sh
srvlst+=("ntpd status") # Default service for testing.

The root cron job is quite simple:

[root ~]# crontab -l | grep service-ctrl
*/2 * * * * /home/users/peter/service-ctrl.sh >/dev/null 2>&1 # Service controller

The trigger file is used by the non-root user to add the token. E.g.:

[peter ~]$ echo "ntpd status" > service-ctrl.trigger

Once triggered, user has to wait for the root cron job which picks up the token:

[peter ~]$ tail -f service-ctrl.log
2015-09-11 22:33:01 Trigger: ntpd status
2015-09-11 22:33:01 Running: /etc/init.d/ntpd status
ntpd (pid 4164) is running...

After execution, cron job clears the token file to avoid any loops.

Configuration file

#!/bin/bash
##########################################
# service-ctrl.cfg
#
# This file is sourced by service-ctrl.sh
##########################################
# Peter Wellmann
# Version 11.09.2015
# https://denken24.de/?p=526
##########################################
# Define service and options here:
#srvlst+=("fail2ban start stop restart status")
#srvlst+=("httpd start stop restart graceful status")
##########################################

Cron job (bash script)

#!/bin/bash
##########################################
# service-ctrl.sh
##########################################
# Run service scripts for non-root users.
#
# This script is triggerd by a root cron job.
#
# Activate/Trigger:
# echo "<service> <option>" > service-ctrl.trigger
##########################################
# (c) Peter Wellmann
# Version 11.09.2015
# https://denken24.de/?p=526
##########################################
# Set globals
timestamp="%Y-%m-%d %T"
cfgfile="service-ctrl.cfg"
trigger="service-ctrl.trigger"
logfile="service-ctrl.log"
# Check file permissions an ownership
cd `dirname $0` 2>/dev/null
if [ $? -ne 0 ]; then echo "Error! Invald script directory: `dirname $0`"; exit 1; fi
/usr/bin/stat -c "%A %G" "${trigger}" 2>/dev/null | grep "^-...rw-.--" | grep -v "root$" -q
if [ $? -ne 0 ]; then echo "Error! Invalid permission or ownership assigned to: ${trigger}"; exit 1; fi
/usr/bin/stat -c "%A %G" "${logfile}" 2>/dev/null | grep "^-...r--.--" | grep -v "root$" -q
if [ $? -ne 0 ]; then echo "Error! Invalid permission or ownership assigned to: ${logfile}"; exit 1; fi
/usr/bin/stat -c "%A %U" "${cfgfile}" 2>/dev/null | grep "^-rw-r--.--\ root$" -q
if [ $? -ne 0 ]; then echo "Error! Invalid permission or ownership assigned to: ${cfgfile}"; exit 1; fi
##########################################
# Prepare service array
srvlst=() # Init empty service array
srvlst+=("ntpd status") # Default service for testing. See service-ctrl.cfg for additional services!
source ${cfgfile} # load additional services from cfg file
##########################################
# Anything todo?
if [ ! -s "${trigger}" ]; then exit 0; fi
# Redirect all output to log file
exec >> "${logfile}" 2>&1
# Common functions
log() {
    if [[ -n "$1" ]]; then echo "$(date +"${timestamp}") $1"; fi; return 0
}
error() {
    if [[ -n "$1" ]]; then log "Error! $1"; exit 1; fi; return 0
}
# Main loop
triggerary=(`grep ^[a-z] "${trigger}" -m 1`)
log "Trigger: ${triggerary[0]} ${triggerary[1]}"
# Check service script
if [ -x "/etc/init.d/${triggerary[0]}" ]; then
    # walk through allowed services
    for srvid in "${!srvlst[@]}"; do
        srvary=(${srvlst[$srvid]}) # srvary[0]-->service  srvary[>=1]-->options
        for((i=1; i<${#srvary[@]}; i++)); do
            if [[ "${triggerary[0]} ${triggerary[1]}" == "${srvary[0]} ${srvary[$i]}" ]]; then
                log "Running: /etc/init.d/${triggerary[0]} ${triggerary[1]}"
                /etc/init.d/${triggerary[0]} ${triggerary[1]}
            fi
        done
    done
else
    log "Service script not executable: /etc/init.d/${triggerary[0]}"
fi
# Clear trigger file while keeping ownership
echo -n > "${trigger}"
# Cleanup (shorten) log file to 1000 lines
/bin/sed -i -e :a -e '$q;N;1001,$D;ba' ${logfile}
exit 0
#EOF
Veröffentlicht in Technik Getagged mit: , ,

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

*