Published on

bash script

Authors
  • Name
    Jackson Chen

How do I edit /etc/sudoers from a script? https://stackoverflow.com/questions/323957/how-do-i-edit-etc-sudoers-from-a-script

modify_sudoers_for_requiretty.sh

1. Take a backup of sudoers file and change the backup file.
sudo cp /etc/sudoers /tmp/sudoers.bak
sudo echo "$USER ALL=(ALL) NOPASSWD:ALL
Defaults:$USER !requiretty
" >> /tmp/sudoers.bak

2.  Check syntax of the backup file to make sure it is correct.
sudo visudo -cf /tmp/sudoers.bak
if [ $? -eq 0 ]; then
  # Replace the sudoers file with the new only if syntax is correct.
  sudo cp /tmp/sudoers.bak /etc/sudoers
else
  echo "Could not modify /etc/sudoers file. Please do this manually."
fi

What is Visudo? The sudo command is configured through a file located at /etc/sudoers.

Warning: Never edit this file (/etc/sudoers) with a normal text editor! Always use the visudo command instead!

How To Edit the Sudoers File https://www.digitalocean.com/community/tutorials/how-to-edit-the-sudoers-file

User Privilege Lines The fourth line, which dictates the root user’s sudo privileges, is different from the preceding lines. Let’s take a look at what the different fields mean:

root ALL=(ALL:ALL) ALL The first field indicates the username that the rule will apply to (root).
root ALL=(ALL:ALL) ALL The first “ALL” indicates that this rule applies to all hosts.
root ALL=(ALL:ALL) ALL This “ALL” indicates that the root user can run commands as all users.
root ALL=(ALL:ALL) ALL This “ALL” indicates that the root user can run commands as all groups.
root ALL=(ALL:ALL) ALL The last “ALL” indicates these rules apply to all commands.
sudo visudo
/etc/sudoers

%wheel ALL=(ALL) ALL
    Need to add "%Domain Admins" group and "%Linux Admin" groups

How to change /etc/ssh/sshd_config - bash script

file=/etc/ssh/sshd_config
cp -p $file $file.old &&
awk '
$1=="PasswordAuthentication" {$2="yes"}
$1=="PubkeyAuthentication" {$2="yes"}
{print}
' $file.old > $file

Edit sshd_config using a Bash script https://www.redhat.com/sysadmin/bash-script-configure-ssh

#!/bin/bash
if [[ "${UID}" -ne 0 ]]; then
    echo " You need to run this script as root"
    exit 1
fi

To directly modify sshd_config

sed -i 's/#\?\(Port\s*\).*$/\1 2231/' /etc/ssh/sshd_config
sed -i 's/#\?\(PermitRootLogin\s*\).*$/\1 no/' /etc/ssh/sshd_config
sed -i 's/#\?\(PubkeyAuthentication\s*\).*$/\1 yes/' /etc/ssh/sshd_config
sed -i 's/#\?\(PermitEmptyPasswords\s*\).*$/\1 no/' /etc/ssh/sshd_config
sed -i 's/#\?\(PasswordAuthentication\s*\).*$/\1 no/' /etc/ssh/sshd_config

# Check the exit status of the last command

if [[ "${?}" -ne 0 ]]; then
   echo "The sshd_config file was not modified successfully"
   exit 1
fi
/etc/init.d/ssh restart

exit 0

SED will replace the rules it finds. If a line is commented, it will remove the # and replace the value. This approach is less solid as it can lead to duplicate rules. I.E. A rule exists commented and uncommented. Also, if the rule wasn't there, it will not be written at all.

for rule in "${!rules[@]}"; do
  regex="s/#\?\(${rule}\s*\).*$/\1 ${rules[${rule}]}/"
  sed "${regex}" ./data.txt > temp.txt;
  mv -f temp.txt ./data.txt
done

AWK AWK is more solid in this situation. It yields better control. It will read line by line and replace the value if it exists without changing commented rules. If a rule wasn't found at the end of the file, it will append this rule to the file. This is much more solid than the SED approach. We can be sure there will be not duplicate rule and all rules are defined.

for rule in "${!rules[@]}"; do
awk -v key="${rule}" -v val="${rules[${rule}]}" \
  '$1==key {foundLine=1; print key " " val} $1!=key{print $0} END{if(foundLine!=1) print key " " val}' \
  ./data.txt > sshd_config.tmp && mv sshd_config.tmp ./data.txt
done
# Alternative
wk '$1=="PermitRootLogin"{foundLine=1; print "PermitRootLogin no"} $1!="PermitRootLogin"{print $0} END{if(foundLine!=1) print "PermitRootLogin no"}' sshd_config > sshd_config.tmp && mv sshd_config.tmp sshd_config

Disable ssh root login by modifying /etc/ssh/sshd_conf from within a script https://stackoverflow.com/questions/36070562/disable-ssh-root-login-by-modifying-etc-ssh-sshd-conf-from-within-a-script

Preparation

Showing the test data only once for better readability in the examples. It has been initialized for each approach the same way. It will define some rules in a test file and a dictionary of new rules that should replace the rules in the file or be written to the file.

echo 'LoginGraceTime 120' > ./data.txt
echo '#PermitRootLogin yes' >> ./data.txt
echo 'PermitRootLogin no' >> ./data.txt
echo 'PasswordAuthentication yes' >> ./data.txt

declare -A rules=( 
    ["LoginGraceTime"]="1m"
    ["PermitRootLogin"]="no"
    ["PasswordAuthentication"]="no"
    ["AllowUsers"]="blue"
)

SED SED will replace the rules it finds. If a line is commented, it will remove the # and replace the value. This approach is less solid as it can lead to duplicate rules. I.E. A rule exists commented and uncommented. Also, if the rule wasn't there, it will not be written at all.

for rule in "${!rules[@]}"; do
  regex="s/#\?\(${rule}\s*\).*$/\1 ${rules[${rule}]}/"
  sed "${regex}" ./data.txt > temp.txt;
  mv -f temp.txt ./data.txt
done
Result:

LoginGraceTime  1m
PermitRootLogin  no
PermitRootLogin  no
PasswordAuthentication  no

AWK AWK is more solid in this situation. It yields better control. It will read line by line and replace the value if it exists without changing commented rules. If a rule wasn't found at the end of the file, it will append this rule to the file. This is much more solid than the SED approach. We can be sure there will be not duplicate rule and all rules are defined.

for rule in "${!rules[@]}"; do
awk -v key="${rule}" -v val="${rules[${rule}]}" \
  '$1==key {foundLine=1; print key " " val} $1!=key{print $0} END{if(foundLine!=1) print key " " val}' \
  ./data.txt > sshd_config.tmp && mv sshd_config.tmp ./data.txt
done
Result:

LoginGraceTime 1m
#PermitRootLogin yes
PermitRootLogin no
PasswordAuthentication no
AllowUsers blue

Conclusion
AWK is clearly the better choice. It is more safe and can handle rules that are not in the file.

Bash date time format

https://www.tutorialkart.com/bash-shell-scripting/bash-date-format-options-examples/

Powerful Awk Built-in Variables – FS, OFS, RS, ORS, NR, NF, FILENAME, FNR

https://www.thegeekstuff.com/2010/01/8-powerful-awk-built-in-variables-fs-ofs-rs-ors-nr-nf-filename-fnr/

  1. FS - Input field separator variable Awk reads and parses each line from input based on whitespace character by default and set the variables $1,$2 and etc. Awk FS variable is used to set the field separator for each record. Awk FS can be set to any single character or regular expression. You can use input field separator using one of the following two options:

Awk FS is any single character or regular expression which you want to use as a input field separator.

Awk FS can be changed any number of times, it retains its values until it is explicitly changed. If you want to change the field separator, its better to change before you read the line. So that change affects the line what you read.

# Using -F command line option.
  $ awk -F 'FS' 'commands' inputfilename

# Awk FS can be set like normal variable
  $ awk 'BEGIN{FS="FS";}'
  1. OFS - Output Field Separator Variable Awk OFS is an output equivalent of awk FS variable. By default awk OFS is a single space character.
# Example
  $ awk -F':' '{print $3,$4;}' /etc/passwd
  $ awk -F':' 'BEGIN{OFS="=";} {print $3,$4;}' /etc/passwd
  1. RS - Record Separator variable Awk RS defines a line. Awk reads line by line by default.
# Example
  $cat student.awk
  BEGIN {
    RS="\n\n";
    FS="\n";

  }
  {
    print $1,$2;
  }
  1. ORS - Output Record Separator Variable Awk ORS is an Output equivalent of RS. Each record in the output will be printed with this delimiter.
# Example
$  awk 'BEGIN{ORS="=";} {print;}' student-marks
  1. NR - Number of Records Variable Awk NR gives you the total number of records being processed or line number.
# Example
  $ awk '{print "Processing Record - ",NR;}END {print NR, "Students Records are processed";}' student-marks
  1. NF - Number of Fields in a record Awk NF gives you the total number of fields in a record. Awk NF will be very useful for validating whether all the fields are exist in a record.
# Example
  $ awk '{print NR,"->",NF}' student-marks
  1. FILENAME - Name of the current input file FILENAME variable gives the name of the file being read. Awk can accept number of input files to process.
# Example
  $ awk '{print FILENAME}' student-marks
  1. FNR - Number of Records relative to the current input file When awk reads from the multiple input file, awk NR variable will give the total number of records relative to all the input file. Awk FNR will give you number of records for each input file.
# Example
  $ awk '{print FILENAME, FNR;}' student-marks bookdetails

Modify and Verify /etc/fstab

Making changes to /etc/fstab could render the system un-usable.

  1. Backup existing fstab
# Make backup before any changes
backupDate=`date +%M-%d-%m-%Y`

[ ! -d "/root/fstab_backup" ] && mkdir /root/fstab_backup
cat /etc/fstab > /root/fstab_backup/fstab.$backupDate.BACKUP
  1. Test and verify all the mounts or mounting the filesystems are mounted
# Verify all the fstab mounts
      mount -fav

-a    mount all
-f    fake  "test" mount the filesystems, useful in conjunction with -v flag
-v    verbose mode
  1. After the successful testing, then commit the changes to /etc/fstab
# Commit changes
      systemctl daemon-reload
      or reboot system