prompt for input in a root session in a shell script - bash

I am trying to read input with read command within superuser privilege:
sudo read p
returns error:
sudo: read: command not found
And in the following:
sudo -s <<EOF
read p
EOF
read is being skipped.
So, How can I use read in a root session in a shell script or is there any alternatives? A little insight about why the above doesn't work would be appreciated.
EDIT:
I want the input to be stored in the variable p to be used later. Basically I want to do this inside the heredoc, i.e p should be usable inside the heredoc, outside the heredoc it's of no concern.

This could help:
$ my_tty=`tty`
$ sudo -s <<EOF
read -p "Some prompt: " p < $my_tty
echo "You supplied '\$p'"... #use $p
EOF
#Output
Some prompt: somevalue
You supplied 'somevalue'...
However, as I already said, this $p value is not visible outside sudo.
You could have rather used it like:
$ read -p "Some prompt: " p
$ sudo -s <<EOF
echo "You supplied '$p'"... #use $p
EOF

sudo -s read p
You can't use sudo for shell built-in commands since sudo doesn't create shell

Related

How can I request elevated permissions in a bash script's begin and let it go at the end?

I have a script (myscript.sh) which runs a few commands which need elevated privileges (i.e. needs to run with sudo).
Script is quite complex, but to demonstrate it is like below:
#!/bin/bash
echo "hello"
command1_which_needs_sudo
echo "hello2"
command2_which_needs_sudo
echo "hello3"
...
If I run it as a normal user without the required privileges:
$ ./myscript.sh
hello
must be super-user to perform this action
However if I run it with the correct privileges, it will work fine:
$ sudo ./myscript.sh
hello
hello2
hello3
Can I somehow achieve to run myscript.sh without sudo, and make the script requesting the elevated privileges only once in the beginning (and pass it back once it has finished)?
So obviously, sudo command1_which_needs_sudo will not be good, as command2 also need privileges.
How can I do this if I don't want to create another file, and due to script complexity I also don't want to do this with heredoc syntax?
If your main concern is code clarity, using wrapper functions can do a lot of good.
# call any named bash function under sudo with arbitrary arguments
run_escalated_function() {
local function_name args_q
function_name=$1; shift || return
printf -v args_q '%q ' "$#"
sudo bash -c "$(declare -f "$function_name"); $function_name $args_q"
}
privileged_bits() {
command1_which_needs_sudo
echo "hello2"
command2_which_needs_sudo
}
echo "hello"
run_escalated_function privileged_bits
echo "hello3"
If you want to run the script with root privileges without having to type sudo in the terminal nor having to type the password more than once then you can use:
#!/bin/bash
if [ "$EUID" -ne 0 ]
then
exec sudo -s "$0" "$#"
fi
echo "hello"
command1_which_needs_sudo
echo "hello2"
command2_which_needs_sudo
echo "hello3"
# ...
sudo -k
Update:
If your goal is to execute one part of the script with sudo rights then using a quoted here‑document is probably the easiest solution; there won't be any syntax issues because the current shell won't expand anything in it.
#!/bin/bash
echo "hello"
sudo -s var="hello2" <<'END_OF_SUDO'
command1_which_needs_sudo
echo "$var"
command2_which_needs_sudo
END_OF_SUDO
sudo -k
echo "hello3"
#...
remark: take notice that you can use external values in the here-document script by setting varname=value in the sudo command.

Create and write systemd service from Shell script Failed [duplicate]

This question already has answers here:
How do I use sudo to redirect output to a location I don't have permission to write to? [closed]
(15 answers)
sudo cat << EOF > File doesn't work, sudo su does [duplicate]
(5 answers)
Closed 1 year ago.
I am trying to automate the addition of a repository source in my arch's pacman.conf file but using the echo command in my shell script. However, it fails like this:-
sudo echo "[archlinuxfr]" >> /etc/pacman.conf
sudo echo "Server = http://repo.archlinux.fr/\$arch" >> /etc/pacman.conf
sudo echo " " >> /etc/pacman.conf
-bash: /etc/pacman.conf: Permission denied
If I make changes to /etc/pacman.conf manually using vim, by doing
sudo vim /etc/pacman.conf
and quiting vim with :wq, everything works fine and my pacman.conf has been manually updated without "Permission denied" complaints.
Why is this so? And how do I get sudo echo to work? (btw, I tried using sudo cat too but that failed with Permission denied as well)
As #geekosaur explained, the shell does the redirection before running the command. When you type this:
sudo foo >/some/file
Your current shell process makes a copy of itself that first tries to open /some/file for writing, then if that succeeds it makes that file descriptor its standard output, and only if that succeeds does it execute sudo. This is failing at the first step.
If you're allowed (sudoer configs often preclude running shells), you can do something like this:
sudo bash -c 'foo >/some/file'
But I find a good solution in general is to use | sudo tee instead of > and | sudo tee -a instead of >>. That's especially useful if the redirection is the only reason I need sudo in the first place; after all, needlessly running processes as root is precisely what sudo was created to avoid. And running echo as root is just silly.
echo '[archlinuxfr]' | sudo tee -a /etc/pacman.conf >/dev/null
echo 'Server = http://repo.archlinux.fr/$arch' | sudo tee -a /etc/pacman.conf >/dev/null
echo ' ' | sudo tee -a /etc/pacman.conf >/dev/null
I added > /dev/null on the end because tee sends its output to both the named file and its own standard output, and I don't need to see it on my terminal. (The tee command acts like a "T" connector in a physical pipeline, which is where it gets its name.) And I switched to single quotes ('...') instead of doubles ("...") so that everything is literal and I didn't have to put a backslash in front of the $ in $arch. (Without the quotes or backslash, $arch would get replaced by the value of the shell parameter arch, which probably doesn't exist, in which case the $arch is replaced by nothing and just vanishes.)
So that takes care of writing to files as root using sudo. Now for a lengthy digression on ways to output newline-containing text in a shell script. :)
To BLUF it, as they say, my preferred solution would be to just feed a here-document into the above sudo tee command; then there is no need for cat or echo or printf or any other commands at all. The single quotation marks have moved to the sentinel introduction <<'EOF', but they have the same effect there: the body is treated as literal text, so $arch is left alone:
sudo tee -a /etc/pacman.conf >/dev/null <<'EOF'
[archlinuxfr]
Server = http://repo.archlinux.fr/$arch
EOF
But while that's how I'd do it, there are alternatives. Here are a few:
You can stick with one echo per line, but group all of them together in a subshell, so you only have to append to the file once:
(echo '[archlinuxfr]'
echo 'Server = http://repo.archlinux.fr/$arch'
echo ' ') | sudo tee -a /etc/pacman.conf >/dev/null
If you add -e to the echo (and you're using a shell that supports that non-POSIX extension), you can embed newlines directly into the string using \n:
# NON-POSIX - NOT RECOMMENDED
echo -e '[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n ' |
sudo tee -a /etc/pacman.conf >/dev/null
But as it says above, that's not POSIX-specified behavior; your shell might just echo a literal -e followed by a string with a bunch of literal \ns instead. The POSIX way of doing that is to use printf instead of echo; it automatically treats its argument like echo -e does, but doesn't automatically append a newline at the end, so you have to stick an extra \n there, too:
printf '[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n \n' |
sudo tee -a /etc/pacman.conf >/dev/null
With either of those solutions, what the command gets as an argument string contains the two-character sequence \n, and it's up to the command program itself (the code inside printf or echo) to translate that into a newline. In many modern shells, you have the option of using ANSI quotes $'...', which will translate sequences like \n into literal newlines before the command program ever sees the string. That means such strings work with any command whatsoever, including plain old -e-less echo:
echo $'[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n ' |
sudo tee -a /etc/pacman.conf >/dev/null
But, while more portable than echo -e, ANSI quotes are still a non-POSIX extension.
And again, while those are all options, I prefer the straight tee <<EOF solution above.
The problem is that the redirection is being processed by your original shell, not by sudo. Shells are not capable of reading minds and do not know that that particular >> is meant for the sudo and not for it.
You need to:
quote the redirection ( so it is passed on to sudo)
and use sudo -s (so that sudo uses a shell to process the quoted redirection.)
http://www.innovationsts.com/blog/?p=2758
As the instructions are not that clear above I am using the instructions from that blog post. With examples so it is easier to see what you need to do.
$ sudo cat /root/example.txt | gzip > /root/example.gz
-bash: /root/example.gz: Permission denied
Notice that it’s the second command (the gzip command) in the pipeline that causes the error. That’s where our technique of using bash with the -c option comes in.
$ sudo bash -c 'cat /root/example.txt | gzip > /root/example.gz'
$ sudo ls /root/example.gz
/root/example.gz
We can see form the ls command’s output that the compressed file creation succeeded.
The second method is similar to the first in that we’re passing a command string to bash, but we’re doing it in a pipeline via sudo.
$ sudo rm /root/example.gz
$ echo "cat /root/example.txt | gzip > /root/example.gz" | sudo bash
$ sudo ls /root/example.gz
/root/example.gz
sudo bash -c 'echo "[archlinuxfr]" >> /etc/pacman.conf'
STEP 1 create a function in a bash file (write_pacman.sh)
#!/bin/bash
function write_pacman {
tee -a /etc/pacman.conf > /dev/null << 'EOF'
[archlinuxfr]
Server = http://repo.archlinux.fr/\$arch
EOF
}
'EOF' will not interpret $arch variable.
STE2 source bash file
$ source write_pacman.sh
STEP 3 execute function
$ write_pacman
append files (sudo cat):
cat <origin-file> | sudo tee -a <target-file>
append echo to file (sudo echo):
echo <origin> | sudo tee -a <target-file>
(EXTRA) disregard the ouput:
echo >origin> | sudo tee -a <target-file> >/dev/null

Want to find status of sudo su - in multiple servers

I have a bash script, hostlist file and an expect script:
Below is the bash script to take inputs from hostlist file and keep looping ssh for multiple servers.
for x in $(cat hostlist); do
./sudoscript.exp $x
done
Below is the expect cum bash script I want to tun and collect outputs of sudo su - command. I just need to get outputs as '0 or non zero values in a file for successful run/execution of 'sudo su - '. I just need to simulate the execution and check if the command runs successfully or not with out actually changing user to admin by doing sudo su -.
#!/bin/bash
#!/usr/bin/expect
spawn ssh [lindex $argv 0]
expect "$"
send "sudo su -\r" exit ; echo $server:$? >> output
Can someone please suggest to complete the script above.
What exactly are you trying to do?
Maybe you're trying to see if it is possible to become root without a password? If that's the case, try:
for x in $(cat hostlist); do
echo $x
ssh $x sudo -l |egrep -w 'NOPASSWD:.*(ALL|/su)'
echo
done
sudo -l will list what you can run. It requires your password unless you have one or more commands that do not require your password (ssh won't run interactively when called with a command and without the -t flag. This is intentional since we don't want that).
The egrep command limits the results to just what can be done without a password as well as either ALL commands or else su itself. (Note, this won't find su if it's in an alias.)

Why can't I redirect text to a text file?

I'm writing a bash shell script that has to be run with admin permissions (sudo).
I'm running the following commands
sudo -u $SUDO_USER touch /home/$SUDO_USER/.kde/share/config/kcmfonts > /dev/null
sudo -u $SUDO_USER echo "[General]\ndontChangeAASettings=true\nforceFontDPI=96" >> /home/$SUDO_USER/.kde/share/config/kcmfonts
The first command succeeds and creates the file. However the second command keeps erroring with the following:
cannot create /home/username/.kde/share/config/kcmfonts: Permission denied
I can't understand why this keeps erroring on permissions. I'm running the command as the user who invoked sudo so I should have access to write to this file. The kcmfonts file is created successfully.
Can someone help me out?
Consider doing this:
echo "some text" | sudo -u $SUDO_USER tee -a /home/$SUDO_USER/filename
The tee command can assist you with directing the output to the file. tee's -a option is for append (like >>) without it you'll clobber the file (like >).
You don't need to execute the left side with elevated privs (although it is just echo, this is a good thing to form as a habit), you only need the elevated privs for writing to the file. So with this command you're only elevating permissions for tee.
sudo -u $SUDO_USER echo "some text" >> /home/$SUDO_USER/filename
sudo executes the command echo "some text" as `$SUDO_USER".
But the redirection is done under your account, not under the $SUDO_USER account. Redirection is handled by the shell process, which is yours and is not under the control of sudo.
Try this:
sudo -u $SUDO_USER sh -c 'echo "some text" >> /home/$SUDO_USER/filename'
That way, the sh process will be executed by $SUDO_USER, and that's the process that will handle the redirection (and will write to the output file).
Depending on the complexity of the command, you may need to play some games with escaping quotation marks and other special characters. If that's too complex (which it may well be), you can create a script:
$ cat foo.sh
#!/bin/sh
echo "some text" >> /home/$SUDO_USER/filename
$ sudo -u $SUDO_USER ./foo.sh
Now it's the ./foo.sh command (which executes as /bin/sh ./foo.sh) that will run under the $SUDO_USER account, and it should have permission to write to the output file.

sudo cat << EOF > File doesn't work, sudo su does [duplicate]

This question already has answers here:
How do I use sudo to redirect output to a location I don't have permission to write to? [closed]
(15 answers)
Closed 6 months ago.
I tried the following on the command prompt in bash:
sudo cat << EOF > /etc/yum.repos.d/some-name.repo
#Content
#....
#...
EOF
It complained :
-bash: /etc/yum.repos.d/some-name.repo: Permission denied
Then I did sudo su and tried the exact same thing except the sudo before cat, and it worked without any problem. What am I missing in the above ?
Output redirection (e.g., >) is performed by bash, not by cat, while running with your UID. To run with root's UID use sudo:
sudo bash -c 'cat << EOF > /etc/yum.repos.d/some-name.repo
line1
line2
line3
EOF'
Another option is tee.
cat << EOF | sudo tee -a /etc/yum.repos.d/some-name.repo
...
EOF
As a variation to #Yuriy Nazarov's answer, only the piped output needs to be elevated thru sudo. The piped input can stay un-elevated:
sudo bash -c 'cat > /etc/yum.repos.d/some-name.repo' << EOF
line1
line2
line3
EOF
This means a much smaller portion of the command needs to be quoted and sent thru to sudo.
As others have pointed out the shell redirection is done by the current shell not by cat. sudo only changes the permission of the program that is executed not of the shell doing the redirect. My solution to this is to avoid the redirect:
sudo dd of=/etc/yum.repos.d/some-name.repo << EOF
if you are using ' inside the text then you may use:
$ sudo bash -c "cat > /etc/postfix/mysql-virtual_forwardings.cf << EOF
user = mail_admin
password = password
dbname = mail
query = SELECT destination FROM forwardings WHERE source='%s'
hosts = 127.0.0.1
EOF
"
this is tested on google cloud's virtual server centos 7.0

Resources