Addsudoers: A script to add users or groups into /etc/sudoers

Well, sudo is a great tool for delegating permissions among admins. But, it's really hard to find a great tool which would give an interactive way of editing /etc/sudoers file. Now, when I say "editing", I really refer to add new groups, users, aliases in the /etc/sudoers file. visudo is great tool, but again, we gotta edit the raw sudoers file. So, I was thinking of having some kind of a script which would simply prompt me what to enter and the script will take care of rest of the things like how to enter that information in the sudoers file.

So, here I want to share my work. It's not really a robust script. There is a lot of things to be implemented (details are mentioned in the script itself) yet.

So script gurus, grab the code, test it on different *nixes, modify it, play with it, and make it better. And yes, don't forget to distribute the code :slight_smile:

===========
addsudoers.sh

#! /bin/bash

# ============================================================================
# This script securely and accurately adds users into the /etc/sudoers file
# It's for those who don't have the fancy GUI to add users in sudoers list
# or simply do not want to use a GUI (like me ;-D)
# Created by Admin_XOR; however, anyone is free to modify and re-distribute it
# Thanks to the indepth manual on /etc/sudoers available at:
# http://www.gratisoft.us/sudo/sudoers.man.html
# ============================================================================

## I guess I'm only a half way of entire implementation of sudoers file
## Things that I haven't implemented yet are:
## NOPASSWD, run as a group like (: wheel), changing deafult values, and
## the rest is waiting to be figured out by you folks ;-)

## check if the user executing the script has an effective user id 0
if [ "$EUID" -ne 0 ]; then
    echo "ERROR: You should be root or your EUID should be 0"
    exit 1
fi

## check if there's /etc/sudoers.tmp file; this is created by visudo
## if it's there, we will not execute the script as someone might be accessing
## sudoers file

## *** WARNING *** uncomment the next line at your own risk :-P
#sudoers=/etc/sudoers

## just for testing: a fake sudoers file
sudoers=~/sudoers

## we dont need to check if sudoers file exists; do we?? 

if [ -f "$sudoers.tmp" ]; then
    echo "ERROR: sudoers file is in use"
    ## gives a hint who might be using it
    /sbin/fuser -u $sudoers
    exit 2
else 
    # create a fake lock file recognizable by visudo
    # this will prevent visudo from opening sudoers while we are working
    touch $sudoers.tmp
fi

## we should keep a backup of the original sudoers file with appropriate
## timestamp even before we access the file and make any changes to it

tstmp=$( date +%F-%H-%M-%S )
cp $sudoers $sudoers.$tstmp.bak

## now, we are good to go ahead and do the changes in sudoers



## important global vairiables
## some of them have not been used. But, I'm half way to implement full
## features of sudoers file. So, who knows!! I may need them tomorrow ;-)

usr_name=""
grp_name=""
sys_name=""
rusr_name=""
rgrp_name=""
cmd_name=""

## here we define the functions

## writes the users specification part in the sudoers file in the form of
## USER_OR_GROUP        SYSTEM = (RUNAS_USER_OR_GROUP) COMMANDS

function func_write {
    echo "# =================" >>$sudoers
    me=$( logname )
    d=$( date +%F )
    t=$( date +%T )
    echo -n "Write the changes? [y/n]: "
    read ans
    if [ "$ans" == "n" ] || [ "$ans" == "N" ]; then
        return
    else
        echo "# modified by $me on $d at $t" >>$sudoers
        tmp="$1        $2 = ($3) $4"
        echo $tmp >>$sudoers
    fi
}

## writes the aliases created

function func_commit {
    echo "# =================" >>$sudoers
    me=$( logname )
    d=$( date +%F )
    t=$( date +%T )
    echo -n "Write the changes? [y/n]: "
    read ans
    if [ "$ans" == "n" ] || [ "$ans" == "N" ]; then
        return
    else
        echo "# modified by $me on $d at $t" >>$sudoers
        tmp="$1        $2 = $3"
        echo $tmp >>$sudoers
    fi
}

## this function gets existing alias names for a specified alias type
## from sudoers

function func_get_alias_name {
    ali=$1
    echo "Existing $ali is(are): "
    grep ^$ali $sudoers | cut -d " " -f 2 -
}

## takes the user name

function func_user {
    echo -n "Enter a valid user name: "
    read usr
    if [ "$usr" == "" ]; then
        echo "User name cannot be empty"
        return
    fi
    
    usr_name=$usr
}

## takes the group name

function func_group {
    echo -n "Enter a valid group name: "
    read grp
    if [ "$grp" == "" ]; then
        echo "Group name cannot be empty"
        return
    fi
    
    grp_name=%$grp
}

## function to take input for aliases or direct entries

function func_input {
    nam=$1
    plac=""

    if [ "$nam" == "h" ]; then
        plc="host"
    elif [ "$nam" == "r" ]; then
        plc="runas user"
    elif [ "$nam" == "c" ]; then
        plc="command"
    else
        return
    fi

    echo
    echo "Please select: "
    echo "1 Enter $plc name(s) manually"
    echo "2 Select from an existing $plc Alias"
    echo -n "Enter your choice: "
    read choi
    
    mach=ALL

    case $choi in
        1 )    
        echo "Enter a $plc name; if more than one, then in comma separated -"
        echo -n "format; if empty ALL will be used: "
        read sys
        if [ "$sys" != "" ]; then
            mach=$sys
        fi
        ;;

        2 )
        if [ "$plc" == "host" ]; then
            func_get_alias_name "Host_Alias"
            echo -n "Enter your selection from above alias: "
                    read sys
                    if [ "$sys" != "" ]; then
                            mach=$sys
                    fi
        elif [ "$plc" == "runas user" ]; then
            func_get_alias_name "Runas_Alias"
            echo -n "Enter your selection from above alias: "
                    read sys    
                    if [ "$sys" != "" ]; then
                            mach=$sys
                    fi
        elif [ "$plc" == "command" ]; then
            func_get_alias_name "Cmnd_Alias"
            echo -n "Enter your selection from above alias: "
                    read sys
                    if [ "$sys" != "" ]; then
                            mach=$sys
                    fi
        else 
            [ ] # do nothing
        fi
        ;;
        
        * )
        echo "Error: Incorrect choice" ;;
    esac
    
    if [ "$plc" == "host" ]; then
        sys_name=$mach
    elif [ "$plc" == "runas user" ]; then
        rusr_name=$mach
    elif [ "$plc" == "command" ]; then
        cmd_name=$mach
    else 
        [ ] # do nothing
    fi
}

## wrapper function for func_input

function func_mrc {    
    func_input "h"
    func_input "r"
    func_input "c"
}

## function to create User_Alias

function func_create_user_alias {
    echo -n "Enter user alias name: "
    read ali
    if [ "$ali" == "" ]; then
        echo "User Alias name should not be empty"
        return
    fi
    
    echo -n "Enter # of users to be added in $ali: "
    read num
    if [ "$num" == "" ] || [ "$num" -eq 0 ]; then
        echo "Number of users should not be empty or 0"
        return
    fi
    
    usr_list=""
    list=$( seq $num )
    for i in $list; do
        echo -n "Enter user $i: "
        read usr
        if [ "$i" -eq 1 ]; then
            usr_list="$usr"
        else
            usr_list="$usr_list, $usr"
        fi
    done

    ## now, it's time to write this in sudoers file
    
    func_commit "User_Alias" $ali "$usr_list"
}

## this function creates a runas alias

function func_create_runas_alias {
        echo -n "Enter runas alias name: "
        read ali
        if [ "$ali" == "" ]; then
                echo "Runas Alias name should not be empty"
                return
        fi

        echo -n "Enter # of users to be added in $ali: "
        read num
        if [ "$num" == "" ] || [ "$num" -eq 0 ]; then
                echo "Number of users should not be empty or 0"
                return
        fi

        usr_list=""
        list=$( seq $num )
        for i in $list; do
                echo -n "Enter user $i: "
                read usr
                if [ "$i" -eq 1 ]; then
                        usr_list="$usr"
                else
                        usr_list="$usr_list, $usr"
                fi
        done

        ## now, it's time to write this in sudoers file

    func_commit "Runas_Alias" $ali "$usr_list"
}

## this function creates a host alias

function func_create_host_alias {
        echo -n "Enter host alias name: "
        read ali
        if [ "$ali" == "" ]; then
                echo "Host Alias name should not be empty"
                return
        fi

        echo -n "Enter # of hosts to be added in $ali: "
        read num
        if [ "$num" == "" ] || [ "$num" -eq 0 ]; then
                echo "Number of hosts should not be empty or 0"
                return
        fi

        usr_list=""
        list=$( seq $num )
        for i in $list; do
                echo -n "Enter host $i: "
                read usr
                if [ "$i" -eq 1 ]; then
                        usr_list="$usr"
                else
                        usr_list="$usr_list, $usr"
                fi
        done

        ## now, it's time to write this in sudoers file
    
    func_commit "Host_Alias" $ali "$usr_list"
}

## this function creates a command alias

function func_create_cmnd_alias {
        echo -n "Enter command alias name: "
        read ali
        if [ "$ali" == "" ]; then
                echo "Command Alias name should not be empty"
                return
        fi

        echo -n "Enter # of commands to be added in $ali: "
        read num
        if [ "$num" == "" ] || [ "$num" -eq 0 ]; then
                echo "Number of commands should not be empty or 0"
                return
        fi

        usr_list=""
        list=$( seq $num )
        for i in $list; do
                echo -n "Enter command $i: "
                read usr
                if [ "$i" -eq 1 ]; then
                        usr_list="$usr"
                else
                        usr_list="$usr_list, $usr"
                fi
        done

        ## now, it's time to write this in sudoers file
    func_commit "Cmnd_Alias" $ali "$usr_list"
}


# =============================
# the main user friendly interface
# =============================

echo "========================================================================"
echo "The utility will ask you to input entries; please enter them accordingly"
echo "WARNING!! Please make sure that you do know about $sudoers file and"
echo "you know what you are doing; sudo will not work if entries in $sudoers"
echo "are incorrect and that might lead to a security hole in your system"
echo "========================================================================"
# the big while loop

while : ; do
    echo
    echo "Please enter an appropriate number corresponding to the operation"
    echo "1 Add a User to sudoers"
    echo "2 Add a Group to sudoers"
    echo "3 Create a User Alias"
    echo "4 Create a Runas Alias"
    echo "5 Create a Host Alias"
    echo "6 Create a Command Alias"
    echo "7 Exit out of this wizard"
    echo ; echo -n "Enter: "
    read hit

    case $hit in
        1 ) 
        func_user
        func_mrc
        func_write $usr_name $sys_name $rusr_name $cmd_name;;

        2 ) 
        func_group
        func_mrc
        func_write $grp_name $sys_name $rusr_name $cmd_name;;

        3 )
        func_create_user_alias;;

        4 )
        func_create_runas_alias;;
        
        5 )
        func_create_host_alias;;
        
        6 )
        func_create_cmnd_alias;;

        7 ) break;;

        * ) echo "Error: wrong number";;
    esac
done

## dont forget to remove the lock file we created long back ;-)
rm -f $sudoers.tmp
exit 0

Why edit groups into sudoers instead of adding users to groups? Let the login system do the legwork.

Uhhh...Well, we do not edit "groups" into sudoers. What we do is that we create an alias which is in turn a simple variable that holds a list of users. Thus, gives you extra flexibility on grouping your users depending on how they are going to use the system.

You can create a separate group of user, then assign that group in sudoers file with the commands and other stuffs. Or, you can create a User_Alias and add the users in that alias. It's upto you and your organization's policy. Both are possible.

Correct me if I'm wrong. :slight_smile: