How to block specific apps from opening in specific accounts

How to block certain applications from opening on certain accounts (eg: Stop account John from opening Firefox or Gimp). It is assumed this is for the GUI and not the terminal and would only apply to specific users, so for example user X can open Gimp but not Firefox, user Z can open Software Center but not VirtualBox.

What good and easy way is there to do this for a new user of Ubuntu.


Solution 1:

A. Configurational options

If the block is meant to block not-so-experienced users from using certain applications, editing (a local copy of) the application's desktop file (as described in [1]) is probably the fastest and easiest way.
Some additional things can be done to create an extra barrier and/or to prevent the fact that the user finds out too easily what we've done to block the application ([2] and [3]).

The set up is not fit for unattended situations with experienced users. In "home" situations with average users it will be sufficient in many cases.

1.Example for blocking gedit by editing (a local version of) the .desktop file

  • Copy the application's desktop file in /usr/share/applications to ~/.local/share/applications:

    cp /usr/share/applications/gedit.desktop ~/.local/share/applications/gedit.desktop
    
  • Edit the file: open it with gedit (while you still can :)) by dragging it over an open gedit window.

    • replace the line

      Exec=gedit %U
      

      by:

      Exec=zenity --info --text 'You are not allowed to use this application'
      
    • remove the (possible) shortcuts, to prevent starting the application from one of the shortcuts:

      remove the line (for the gedit example):

      Actions=Window;Document;
      

      and the section(s) like:

      [Desktop Action Window]
      Name=Open a New Window
      Exec=gedit --new-window
      OnlyShowIn=Unity;
      

    From then on (after log out / log in) the user will see this message if he or she tries to open gedit from Dash, or tries to open a file that is linked to the application:

    enter image description here

    • Hiding the application from Dash (optional measure)

      After we made the changes above, having the gedit.desktop file still open, we can add an additional line:

      NoDisplay=true
      

      By adding this line, gedit will not even show up in Dash.

    Undo

    To undo, simply remove the local .desktop file from ~/.local/share/applications

2.Making it a bit more difficult to find out

While, after editing the .desktop file, the application will not show up in Dash any more, Dash search will still show our newly created gedit.desktop file, which might unintentionally give a hint how to escape the application block.

enter image description here

To avoid that, we should exclude the directory ~/.local/share/applications from Dash search and clear the search history.
Open System Settings > "Security & Privacy" > "Files & Applications" (tab). Add the directory ~/.local/share/applications to the list to exclude from search.

enter image description here

3.(Not) using the terminal / command line

Redirecting the gedit command (1)

Editing the .desktop file prevents using the application from Dash, but if the user knows the AltF2combination and the command to run the application, he or she will still be able to start the application, just like with the terminal. A nice and easy to set up extra measure is to create (if it doesn't exist yet) the directory ~/bin and create a small script in the directory:

#!/bin/bash
zenity --info --text 'You are not allowed to use this application'

Make it executable and name it after the application; gedit in this case.

Since ~/bin is in PATH, running the command will call the script instead of the "real" gedit application. As a result, the same You are not allowed to use this application -message will appear

Redirecting the gedit command (2)

Another way (with more limited effect, see note) of redirecting the application's command is to add an alias to the .bashrc file:

gedit ~/.bashrc

add the line (gedit example):

alias gedit='zenity --info --text "You are not allowed to use this application"'

Note: this is only to be used as an extra measure, since it only prevents the application to be called from the terminal directly. Double clicking on a (e.g.) .txt file will however still open the application.

Make the use of terminal difficult or impossible at all

To prevent the use of the terminal, you can also do the same trick on the gnome-terminal.desktop - file as in [1], and/or change the default shortcut key combination to run the terminal (System Settings > "Keyboard" > "Shortcuts" > "Starters")


4. A small tool to automatically create (or undo) an edited version of the .desktop file (as in 1.)

If you run the script below with either the argument block or unblock (you must run it with either one), you will be presented a list with (global) desktop files, representing your installed applications:

enter image description here

Pick one, and your application is blocked or unblocked, depending on the argument you run it with.

Note

You may have to log out / log in to make it work.

The script

#!/usr/bin/env python3

import os
import shutil
import sys

mode = sys.argv[1]

home = os.environ["HOME"]
global_dir = "/usr/share/applications/"

files = [file for file in os.listdir(global_dir) if file.endswith(".desktop")]
relevant = []
for i in range(len(files)):
    file = files[i]
    with open(global_dir+file) as src:
        text = src.read()
    if not "NoDisplay=true" in text:
        relevant.append((file))
for i in range (len(relevant)):
    print(str(i+1)+".", relevant[i])

choice = int(input("\nplease enter the number of the corresponding .desktop file: "))
filename = relevant[choice-1]

local_file = home+"/"+".local/share/applications/"+filename
global_file = global_dir+filename

def block_application(filename):
    if not os.path.exists(local_file):
        shutil.copyfile(global_file, local_file)
    with open(local_file) as src:
        lines = src.readlines()
    shortcuts_section = [i for i in range(len(lines)) if lines[i].startswith("Actions=")]
    if len(shortcuts_section) != 0:
        lines = lines[:shortcuts_section[0]]
    command = [i for i in range(len(lines)) if lines[i].startswith("Exec=")]
    if len(command) != 0:
        lines[command[0]] = 'Exec=zenity --info --text "You are not allowed to use this application"\n'
    with open(local_file, "wt") as out:
        for line in lines:
            out.write(line)

if mode == "block":
    block_application(filename)
elif mode == "unblock":
    os.remove(local_file)

Copy the script into an empty file, save it as block_apps.py and run it by either:

python3 /path/to/block_apps.py block

or

python3 /path/to/block_apps.py unblock

B. Scripted option(s)

Blocking certain applications can also be done by running a script in the background. The script would have to take certain actions if one of the "forbidden" applications is run.

1. Script to manipulate the screen when forbidden applications are used.

The script below offers a flexible way to block user defined applications. It runs with a simple command, with the forbidden applications as an argument, e.g. (assuming you made the script executable):

    /path/to/block_apps.py firefox gedit gnome-terminal

The advantage of blocking applications like this is that it is flexible; even within one account, different settings can be used, simply by using other applications as argument.

What it does

By un- commenting one of the lines:

# action = "xrandr --output "+screen+" --brightness 0"

or

# action = "xrandr --output "+screen+" --rotate inverted"

The script either:

blacks the screen (action = "xrandr --output "+screen+" --brightness 0"):

enter image description here

or turns it upside down (action = "xrandr --output "+screen+" --rotate inverted"):
(who said Unity doesn't allow to put the launcher on the right?)

enter image description here

The script

#!/usr/bin/env python3
import subprocess
import getpass
import sys
import time

applications = []
i = 1

while True:
    try:
        applications.append(sys.argv[i])
        i = i+1
    except IndexError:
        break

cmd1 = "xrandr"
get = subprocess.check_output(["/bin/bash", "-c", cmd1]).decode("utf-8").split()
screen = [get[i-1] for i in range(len(get)) if get[i] == "connected"][0]

#-- uncomment (only) one of the options below
# action = "xrandr --output "+screen+" --brightness 0"
action = "xrandr --output "+screen+" --rotate inverted"
#--

while True:
    cmd2 = "ps -u "+getpass.getuser()
    applist = subprocess.check_output(["/bin/bash", "-c", cmd2]).decode("utf-8")
    for application in applications:
        if application in applist:
            subprocess.Popen(["/bin/bash", "-c", action])
    time.sleep(5)

How to use

  • Copy the script into an empty file, save it as block_apps.py, make it executable
  • run it by the command:

    /path/to/block_apps.py <application_1> <application_2> <application_3> etc...
    
  • Important
    To kill the block_apps.py script and restore "normal" settings, use the script below (make it available under a shortcut key combination):

#!/usr/bin/env python3
import subprocess

cmd = "ps -ef | grep block_apps.py"
run = subprocess.check_output(["/bin/bash", "-c", cmd]).decode("utf-8").split("\n")
match = [line for line in run if "block_apps.py" in line]
command = "kill "+match[0].split()[1]
subprocess.Popen(["/bin/bash", "-c", command])

cmd1 = "xrandr"
get = subprocess.check_output(["/bin/bash", "-c", cmd1]).decode("utf-8").split()
screen = [get[i-1] for i in range(len(get)) if get[i] == "connected"][0]

restore_1 = "xrandr --output "+screen+" --brightness 1"
restore_2 = "xrandr --output "+screen+" --rotate normal"

for item in [restore_1, restore_2]:
    subprocess.Popen(["/bin/bash", "-c", item])

As always with scripts, copy it into an empty file, save it as kill_blockapps.py, make it executable and run it by:

/path/to/kill_blockapps.py

You will probably want to have this one under a shortcut key: Choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command as above.