5

I am working on Linux Ubuntu 16.04.
In this challenge I want to remove some commands from the Linux shell.

Specifically, I want to remove the exit command.
I want that if a user will try to exit the shell with this command, it won't be possible or maybe even send some message instead.

Any idea how can I do it ?
I searched for a file named exit:
find / -name exit

But it found only directories:

/usr/src/linux-headers-4.13.0-41-generic/include/config/have/exit
/usr/src/linux-headers-4.13.0-41-generic/include/config/have/irq/exit
/usr/src/linux-headers-4.13.0-43-generic/include/config/have/exit
/usr/src/linux-headers-4.13.0-43-generic/include/config/have/irq/exit
/usr/src/linux-headers-4.13.0-36-generic/include/config/have/exit
/usr/src/linux-headers-4.13.0-36-generic/include/config/have/irq/exit
/usr/src/linux-headers-4.15.0-43-generic/include/config/have/exit
/usr/src/linux-headers-4.15.0-43-generic/include/config/have/irq/exit

EDIT:
I read here about using trap like this trap "ENTER-COMMAND-HERE" EXIT and I tried trap "sh" EXIT but it still existing the shell.

E235
  • 363
  • 7
  • 19
  • 2
    As far as I know, `exit` is a builtin (part of the shell itself, not an external application). You'd probably have to modify the source code for the shell in question. Why would you want to do such a thing as preventing a user exiting a shell session, though? (perhaps it would be better to *not* have `exit` be an alias for `logout` in interactive sessions, rather than remove the `exit` functionality.) – Agi Hammerthief Jan 08 '19 at 10:40
  • 1
    A bit pointless IMHO to remove the `exit` command, considering that one could send `^D` signal, either via keyboard or via `printf`, or kill the shell process. A challenge though IMHO without a satisfactory solution – Sergiy Kolodyazhnyy Jan 08 '19 at 10:44
  • 1
    There's so many ways to exit a shell session though, so I don't know what purpose disabling `exit` would serve. – Kusalananda Jan 08 '19 at 11:02
  • While it's an odd request, I don't feel it's overly broad and could be answered (perhaps with diff/patches) if the shell(s) were specified. E235: what shells are you concerned about here? – Jeff Schaller Jan 08 '19 at 17:18
  • @SergiyKolodyazhnyy `^D` (`VEOF`) doesn't send a signal, like `^C` (`VINTR`). It's causing the data already written to the tty to be immediately made available at the other end; if there's no such data, a read at the other end with return 0 (EOF). Also, could you please explain how you could send a `^D` to the shell from within the shell with `printf`? –  Jan 09 '19 at 20:23
  • @UncleBilly `^D` is actually End of Transmission, EOT, character. See [Wikipedia article](https://en.wikipedia.org/wiki/End-of-Transmission_character) about it. So it's a matter of `echo` or `printf` the hex value for it. Or merely `$'\04'` in shell. As for an example, feel free to see one of my older answers: https://askubuntu.com/a/725208/295286 – Sergiy Kolodyazhnyy Jan 09 '19 at 20:31
  • @SergiyKolodyazhnyy Nope. It's exactly as I told you. Go read the termios(3) and stty(1) manpages. You can easily change it -- `stty eof z` will cause an EOF when you enter `z` twice (or once at the beginning of the line). And the question about `printf` was rhetorical; of course you cannot send an EOF to the shell from within the shell. –  Jan 09 '19 at 20:35
  • @UncleBilly Please re-read `termios(3)`: "(004, EOT, Ctrl-D) End-of-file character (EOF)" , and this is exactly what `$'\04'` sequence is. As for `stty eof z` , the `stty` man page says: "eof CHAR: CHAR will send an end of file (terminate the input)" It merely binds CHAR to sending EOF, not redefines or changes it. And of course we can send EOF from within the shell, just like we can send other control characters that change color or title of the terminal. Feel free to ask a question here on U&L about it if you don't believe me. – Sergiy Kolodyazhnyy Jan 09 '19 at 20:42
  • @SergiyKolodyazhnyy I do not mean to play the smartass or humiliate you; please take some time to **test** and correct your misconceptions -- and also correct that answer you're proudly pointing to ;-) –  Jan 09 '19 at 20:50
  • @UncleBilly I'm always open to learning, so if you have something better to point to, feel free to do so. – Sergiy Kolodyazhnyy Jan 09 '19 at 20:53
  • @SergiyKolodyazhnyy start with **testing** your false assumption that a `printf '\004'` will terminate the shell in the way a `printf '\033[31m'` will make the text red. –  Jan 09 '19 at 21:00
  • @UncleBilly OK, admittedly that didn't work. Nonetheless my point still stands, shell can be closed in more ways than just `exit` and even from within itself – Sergiy Kolodyazhnyy Jan 09 '19 at 23:46

2 Answers2

16

In addition to what terdon said (basically overriding the special built-in exit command with an alias, or a function for that matter), the bash shell also allows you to disable built-in commands.

To disable the exit built-in command:

enable -n exit

To disallow enabling it again, also disable the enable built-in command:

enable -n enable

Note that, just as with terdon's answer, this only affects the current shell session, unless it is implemented as part of a system-wide shell startup file.

Personally, I almost exclusively use Ctrl+D to exit interactive shell sessions. To circumvent this in bash, set IGNOREEOF to some large integer and make it read-only:

readonly IGNOREEOF=1000

This makes the shell exit after pressing Ctrl+D 1000 times.

You could still kill the shell with e.g. kill -s HUP "$$". You can make the shell ignore the hangup signal with

trap '' HUP

There is no way to prevent the user from forcefully killing the shell with a KILL signal though, but you can remove the built-in kill command as above and install an overriding shell function or alias, but it would still be easy to use /bin/kill:

enable -n kill
kill () { echo 'kill: Operation not permitted' >&2; }

You could also exit the shell through

set -e
false

... unless you disable the set built-in, obviously, but that may be taking it too far, as would trying to prevent exiting by several other less obvious means (some of which, would you want to prevent them, would require modifications to the bash source code).


The issue with

trap 'bash' EXIT

is that it will spawn a new shell when the current shell exits. That new shell is easy to exit though, because it hasn't got the trap set up, unless you install the trap as part of the shell's startup files.

This also does not prevent you from exiting the shell, because strictly speaking, the trap doesn't execute until the shell actually exits. What it gives you is a new shell.

Kusalananda
  • 320,670
  • 36
  • 633
  • 936
  • The two `enable` commands probably could be placed into `/etc/bash.bashrc` or user's personal config file to avoid setting it for each and every shell session. – Sergiy Kolodyazhnyy Jan 09 '19 at 18:24
  • 3
    `exec true` would also effectively terminate the shell. So would setting some low limits with `ulimit`, or set `TMOUT=1`... – Stéphane Chazelas Jan 09 '19 at 19:56
14

There is no exit executable, that is one of the shell's (you don't say what shell, so I am assuming bash) builtin commands. As such, the only way to remove it completely is to edit the source code of the shell and recompile it (but look at @Kusalananda's answer for a better approach).

As an alternative, you could add something like this to /etc/bash.bashrc:

alias exit='echo "You can check-out any time you like, but you can never leave!"'

But this is trivially easy to circumvent by anyone who knows even a little bit about *nix.

terdon
  • 234,489
  • 66
  • 447
  • 667