What is the error I get with login
?
When searching trough the source code of login
, we see this passage:
amroot = (getuid () == 0);
[...]
utent = get_current_utmp ();
/*
* Be picky if run by normal users (possible if installed setuid
* root), but not if run by root. This way it still allows logins
* even if your getty is broken, or if something corrupts utmp,
* but users must "exec login" which will use the existing utmp
* entry (will not overwrite remote hostname). --marekm
*/
if (!amroot && (NULL == utent)) {
(void) puts (_("No utmp entry. You must exec \"login\" from the lowest level \"sh\""));
exit (1);
}
The interessting part is the if clause at the end. The error message appears when getuid()
is not 0 and if there is no utmp entry. getuid()
returns the real user ID of the calling process. If you invoke login
with the setuid flag set, the real uid and effective uid differ. login
is, as the comment in the source snippet suggest, "picky" in such cases: it fails and throws the mentioned error.
Why does login
work with sudo
?
sudo
itself has the setuid bit set, thus euid and ruid differ. But, sudo executes the binary of login
and sets both the real and the effective uid to the target user. It will therefore not fail anymore.
Why my simple script to run whoami
doesn't work?
Your script has a shebang line (#!
) in it (I assume). What happens is the following: the kernel opens the executable (in your case a text file) and observes a #!
. Instead of the text file, the interpreter given in the shebang line is invoked (for example /bin/bash
or /bin/sh
) with the scripts name as first argument. Most unix and linux operating systems ignore the setuid bit when set on a script, because it is a security issue.
Imagine a script with setuid set. The attacker can then create a symbolic link to this script, invoke that script, and then change the symbolic link to his script, right before the interpreter opens the script behind the symbolic link (which is the evil one then).