setuid bit result - bit

I have a shell script that I want to set uid bit.
I set the owner to root and set uid bit.
I added 'whoami'in the shell to check if it is working properly
but when I executed the script, whoami returned user's name, not root.
Then this is wrong, right? I should have gotten root if uid was set correctly, right?

No, the setuid bit does NOT change the logged in user, it changes the effective user (euid) the script runs as.
Furthermore, setuid bits do not work on scripts.
If you want a script to be executed as root by less privileged users, I recommend to look into "su" or "sudo".

You can't use the setuid bit with shell scripts. The shell parses the shebang line to determine the program to execute, then launches that program without caring the slightest about the setuid bit set on the script.
See https://serverfault.com/questions/8449/cannot-set-uid-on-shell-scripts.

Related

Reduce prompt for a password while executing shell scripts on macOS

I am writing an initial setup shell script for a Mac.
When I run the script, it asks for the password several times.
Is there any way to make this happen only once during script execution?
If possible, I would like to know how to actively ask for it at the beginning of the script, instead of asking for it when some command requires it.

Launch interactive Bash shell in Ruby script, with initial command

I'm working on an interactive Ruby script, which build and packages resources. In the middle of the process, I'd like to drop into an interactive shell, but pre-cd'd into a specific working directory, as well as with an explanatory message (CTRL-D to continue). The interactive bash + given initial command is what's problematic.
Per the answer for doing something like this in Bash, given at https://stackoverflow.com/a/36152028, I've tried
system '/bin/bash', '--init-file', '<(echo "cd ~/src/devops; pwd")'
However, bash runs interactively but completely ignores the '<(echo "cd ~/src/devops; pwd")' section.
Interestingly system '/bin/bash', '--init-file complains if no argument is given, but literally anything runs bash, but with no initial command.
*Note that (--rcfile instead of --init-file) has the same effect.
Change the working directory of the Ruby script first, so that bash inherits the correct working directory.
curr_dir = Dir.pwd
Dir.chdir("#{Dir.home}/src/devops")
system "/bin/bash"
Dir.chdir(curr_dir) # Restore the original working directory if desired
Oh, this is probably far better (you can probably guess how little familiarity I have with Ruby):
system("/bin/bash", :chdir=>"#{Dir.home}/src/devops")

understanding PATH variable export at the beginning of the bash script

I have fairly often seen that PATH variable is exported at the beginning of the script. For example in /etc/init.d/rc script in Debian Wheezy:
PATH=/sbin:/usr/sbin:/bin:/usr/bin
export PATH
While I understand that this ensures that executables used in the script are started from correct directories, I don't fully understand which shells are affected by this export statement. For example here I start the script named rc(PID 6582; command is "/bin/sh /etc/init.d/rc") in bash(PID 3987):
init(1)-+-acpid(1926)
|-sshd(2139)-+-sshd(2375)---bash(2448)---screen(3393)---screen(3394)-+-bash(3395)---vim(3974)
| | |-bash(3397)---pstree(6584)
| | `-bash(3987)---rc(6582)---sleep(6583)
Am I correct that this PATH export statement in rc script affects only the /bin/sh with PID 6582 because parent shells(bash with PID 3987 in my example) do not inherit variables from children? In addition, am I correct that all the commands executed in script rc are started under the /bin/sh with PID 6582 and thus use this PATH=/sbin:/usr/sbin:/bin:/usr/bin variable? If yes, then hasn't the simple PATH=/sbin:/usr/sbin:/bin:/usr/bin been enough?
The environment variables are inherited by all the processes run from the script. PATH in particular affects the behaviour of the C functions execlp() and execvp(), so all the processes launched by the init.d script that started sshd and their descendants are impacted, but only until the point where one of these descendants changes and exports it.
In particular, bash(2448) most probably changes it, as it is a login shell, to match the system's and the user's config, so all it descendans are impacted by this change.
Then when you run manually the /etc/init.d/rc script by hand, the change is inherited by the sleep command (but that one never tries to run anithing).
If yes, then hasn't the simple PATH=/sbin:/usr/sbin:/bin:/usr/bin been enough?
If you mean just setting the variable instead of also exporting it, it depends on what the rc script runs. If it launches anything that tries to run commands with any of those functions, then no, only after exporting PATH it affects the children.
PATH should already be exported by the parent shell when the script run, so indeed, there is no need.
I can imagine corner cases where the shell which runs your script might not be properly initialized, such as for a startup script running very early in the boot process, but for regular userspace scripts, things should be set up the way you want them already.

how can i test if my shell script was run directly by SMF or directly by user

how can i test in my shell script if my shell script was run by SMF or directly by user i want to block users running my start shell script while allowing only SMF to run it and if a user tries to run it directly to tell it it should run it with svcadm nice message...
thanks
Is it really SMF vs user or is it interactive vs non-interactive? (Unfortunately, I don't know much about SMF - it was init/.rc files in my day.)
http://tldp.org/LDP/abs/html/intandnonint.html
35.1. Interactive and non-interactive shells and scripts
... If a script needs to test whether it is running in an interactive shell ...
Probably you could check the caller's id? Or play with permissions, allowing only a certain user to run it.

chroot + execvp + bash

Update
Got it! See my solution (fifth comment)
Here is my problem:
I have created a small binary called "jail" and in /etc/password I have made it the default shell for a test user.
Here is the -- simplified -- source code:
#define HOME "/home/user"
#define SHELL "/bin/bash"
...
if(chdir(HOME) || chroot(HOME)) return -1;
...
char *shellargv[] = { SHELL, "-login", "-rcfile", "/bin/myscript", 0 };
execvp(SHELL, shellargv);
Well, no matter how hard I try, it seems that, when my test user logs in, /bin/myscript will never be sourced. Similarly, if I drop a .bashrc file in user's home directory, it will be ignored as well.
Why would bash snob these guys?
--
Some precisions, not necessarily relevant, but to clear out some of the points made in the comments:
The 'jail' binary is actually suid, thus allowing it to chroot() successfully.
I have used 'ln' to make the appropriate binaries available - my jail cell is nicely padded :)
The issue does not seem to be with chrooting the user...something else is remiss.
As Jason C says, the exec'ed shell isn't interactive.
His solution will force the shell to be interactive if it accepts -i to mean that (and bash does):
char *shellargv[] = { SHELL, "-i", "-login", ... };
execvp(SHELL, shellargv);
I want to add, though, that traditionally a shell will act as a login shell if ARGV[0] begins with a dash.
char *shellargv[] = {"-"SHELL, "-i", ...};
execvp(SHELL, shellargv);
Usually, though, Bash will autodetect whether it should run interactively or not. Its failure to in your case may be because of missing /dev/* nodes.
The shell isn't interactive. Try adding -i to the list of arguments.
I can identify with wanting to do this yourself, but if you haven't already, check out jail chroot project and jailkit for some drop in tools to create a jail shell.
By the time your user is logging in and their shell tries to source this file, it's running under their UID. The chroot() system call is only usable by root -- you'll need to be cleverer than this.
Also, chrooting to a user's home directory will make their shell useless, as (unless they have a lot of stuff in there) they won't have access to any binaries. Useful things like ls, for instance.
Thanks for your help, guys,
I figured it out:
I forgot to setuid()/setgid(), chroot(), setuid()/setgid() back, then pass a proper environment using execve()
Oh, and, if I pass no argument to bash, it will source ~/.bashrc
If I pass "-l" if will source /etc/profile
Cheers!

Resources