Prevent all commands from being defined as an alias

Is there a way to prevent all commands from being defined as an alias?

For example a user shouldn't be able to define rm or any other command (Ubuntu default commands) as an alias name.


There is no way you can prevent a user from defining whatever aliases they prefer. Consider:

  1. You disable aliases in /etc/bash.bashrc. They enable it wherever they chose to.
  2. You delete all mentions of aliases in /etc/bash.bashrc, and all ~/.bashrc and ~/.bash_aliases via a script. They put their aliases in another file and source it.
  3. You run a command in PROMPT_COMMAND that disables certain aliases. They redefine or undefine PROMPT_COMMAND.
  4. You trap DEBUG and undefine aliases. They remove the trap.
  5. You chown all files sourced at invocation to root. They use another file and source it manually as the first command they run.
  6. You disable the builtins unset, builtin and enable; make alias a function; declare -rf alias to prevent users from modifying the function; and export the function. They run /bin/bash with --rcfile and --init-file to start a new shell, where said builtins are now enabled.
  7. ...

You could disable aliases at compile time, then it would be up to you to keep bash up-to-date and make sure you aren't affected by the next Shellshock. Of course, the users could build their own bash.


TL;DR

The only way to prevent a user from creating aliases is to provide them with a shell that doesn't support aliasing. This is generally an X/Y problem, where X is really a threat model that should be solved with appropriate controls or architectures rather than trying to solve the problem post-facto after a user is given a shell on a shared system.

Below, I provide a technically-correct answer, as well as some guidance on what problems this will and won't solve. I also provide some additional guidance on alternative controls.

Using the Bash Restricted Shell

You can use Bash's restricted shell by assigning rbash as the user's login shell. For example:

foo:x:2001:2001:restricted user:/home/foo:/bin/rbash

You must then disable the alias built-in for the user, preferably without breaking everyone else's shell too. As an example, you could add the following to a file such as /etc/profile.d/rbash.sh:

# Limit effect to users in a specific UID range.
if ((UID >= 2000)) && ((UID < 3000)); then
    # Check shell options; disable alias builtins when shell is restricted.
    if [[ $- =~ r ]]; then
        enable -n alias
        enable -n unalias
    fi
fi

Caveats

Unless you've placed the user into a chroot jail or provided them with a modified PATH that doesn't include access to other shells, there's nothing stopping the user from simply typing bash at the prompt and getting an unrestricted shell.

In addition, by design the restricted shell prevents many common activities such as changing directories:

$ cd /tmp
rbash: cd: restricted

but doesn't prevent other scripts or programs in the PATH from doing so. This means you have to carefully craft the user's environment, and specifically that you need to prevent them from being able to modify the PATH in their startup files, because even though rbash makes PATH read-only it does so after initialization.

Better Choices

Even if you use rbash, you need to do so as part of a broader set of controls. Some examples may include:

  • Prevent non-technical users from accidentally invoking dangerous commands by providing default aliases such as rm -i, mv -i, and cp -i in the /etc/bash.bashrc file.

    • Given your original example, this is probably the most sensible solution.
    • You can combine this with enable -n alias if you like.
    • This won't prevent knowledgable users from changing the aliases, but it may be sufficient to prevent non-technical users from doing whatever it is you're concerned about.
  • Traditional Unix permissions or POSIX ACLs to protect files and directories.

  • Logins that perform a single non-interactive command. For example:

    foo:x:2001:2001:run foo.sh:/home/foo:/usr/local/bin/foo.sh
    
  • Use per-key SSH forced commands. For example:

    # ~foo/.ssh/authorized_keys
    command="/usr/local/bin/foo.sh" [remainder of line]
    
  • Use the OpenSSH ForceCommand option with a conditional Match block.

  • Use special tools like gitolite or scponly designed for your specific use case.

  • Use a chroot jail.

  • Use virtualization such as Xen, OpenVZ, LXC, VMware, VirtualBox, or other technologies to provide a segregated environment.

Once you have accurately defined your threat model, you can identify the most appropriate controls for your use case. Without a more meaningful understanding of why you want to prevent aliasing (e.g. what real-world problem does it solve?) you can't select the most appropriate controls.


This is quite a pointless endeavor, as muru's answer shows. But there are some options, but they are not perfect.

According to bash manual, functions always take precedence over aliases, thus we could do the following:

xieerqi@eagle:~$ function alias { echo "Aliases are no-no" ; }
xieerqi@eagle:~$ alias TEST='rm'
Aliases are no-no

You could place function definition into the systemwide .bashrc , however as muru pointed out, smart users will find way to get aliases by sourcing a different bashrc file for example.

Another idea I've played with is enable built-in. alias is a shell built in, and bash has nice enable command that allows enabling or disabling builtins. For instance, here's me disabling alias.

xieerqi@eagle:~$ enable -n alias
xieerqi@eagle:~$ alias
No command 'alias' found, did you mean:
 Command '0alias' from package 'zeroinstall-injector' (universe)
alias: command not found
xieerqi@eagle:~$ alias TEST='rm'
No command 'alias' found, did you mean:
 Command '0alias' from package 'zeroinstall-injector' (universe)
alias: command not found
xieerqi@eagle:~$ enable alias
xieerqi@eagle:~$ alias
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l='ls -CF'
alias la='ls -A'
alias ll='ls -alF'
alias ls='ls --color=auto'
xieerqi@eagle:~$ 

Again, using systemwide bashrc is an option here.