Exclude user from using systemwide installed programs

I recently created a new user. I want to allow this user to use only one or two programs, but I have lots of systemwide installed apps. Is there an easy way to exclude a specific user from using apps (without reinstalling everything again)?


Below a combination of measures you can take, to restrict users locally from using defined applications. They are not meant (nor fit) for unattended usage, in public spaces for example, but do create a usable restricted desktop. It is mainly the combination of measures that makes it more difficult to bypass. Furthermore if someone manages to launch a "forbidden" application, it will be logged.

The answer is a bit extensive. The setup is not, and you are assisted by two scripts.

What the setup exists of

  • A selection of software, made unavailable from the interface by editing their local desktop file by a script (further below)
  • Making the terminal only available via password, so running applications from the terminal is made more difficult.
  • Changing the default keycombination of opening the terminal, instead of ctrlaltt
  • Logging the usage of a "blacklist" of software you define, in case some smart user might surpass your setup

How to setup

Setting up a broad selection of software, unavailable from the interface.

  • Log in, to the user account you want to restrict
  • Make a (temporary) folder (no matter where, on the desktop for example) to edit some files.
  • Browse into the directory /usr/share/applications Select all (desktop files of) applications you want the user to be excluded from (don't select all of them without looking, some of them are necessary to set up your desktop)
  • Copy these desktop files into the temporary directory you created, for bulk-editing.
  • Copy the text below, paste it into an empty file, save it in the same temporary folder as no_openapp.py.
  • CD into the directory(!) and run it with the command: python3 no_openapp.py.

The script did a few things:

1] Create a blacklist of commands (for later use, see further below) 2] Edit the desktop files to show a message instead of running the application. If you move the desktop files to ~/.local/share/applications, on next login the applications will not run from Unity or Dash.

#!/usr/bin/python3

import os
import getpass
import subprocess


desktopfile_dir = os.getcwd()
file_list = os.listdir(os.getcwd())
edit_subjects = [desktopfile_dir+"/"+item for item in file_list]

def create_blacklist():
    command_list = []
    for item in edit_subjects:
        with open(item) as blacklist_source:
            searchlines = blacklist_source.readlines()
        try:
            native_command = [
                line for line in searchlines if line.startswith("Exec=")
                ][0].replace("Exec=", "").replace("\n", "")
            cleaned_command = native_command.split(" ")[0]
            command_list.append(cleaned_command)
        except IndexError:
            pass

    with open(desktopfile_dir+"/blacklist.txt", "wt") as created_blacklist:
        created_blacklist.write(str(command_list))

def make_unavailable():
    for item in edit_subjects:
        try:
            with open(item, "r") as make_unav:
                lines = make_unav.readlines()
                line_range = range(0, len(lines))
                for index in line_range:
                    if lines[index].startswith("Exec="):
                        lines[index] = 'Exec=zenity --info --text="You are not allowed to use this application"\n'
                    else:
                        pass
            with open(item, "wt") as make_unav:
                for line in lines:
                    make_unav.write(line)
        except (IsADirectoryError, IndexError, PermissionError):
            pass


create_blacklist()
make_unavailable()

Restrict the use of the terminal

  • make the terminal accesible with a password, like in this post.
  • if the user is familiar with the key combination of ctrlaltt, change the default combination:

    System>Preferences>Keyboard Shortcuts > key combinations (tab).

In case you have a wizzkid bypass your measures, catch him

  • In case a user manages to get a forbidden application running, make sure you catch him. for this, we use the blacklist, created in step one.
  • create a folder on a hidden location. Copy the "blacklist.txt", created in step one to the directory.
  • copy the text below, paste it into an empty textfile and save it to the same directory as the blacklist, as processes.py.
  • open a terminal window, type crontab -e. add the following line to the crontab file:

    * * * * * cd /path/to/script; python3 processes.py

The blacklist is a list of process names. The script checks every minute if one of the black-listed applications is running, and keeps record in a log file (in the same directory as where the script is located). The name of the log file is log.txt. Optionally, you can make the script kill the forbidden application (not the default). To make it kill the application(s), change the line kill_apps = "no" into kill_apps = "yes" (in the head section of the sript).

#!/usr/bin/python3

import os
import datetime
import subprocess
import getpass

curr_dir = os.getcwd()
curruser = getpass.getuser()

# should forbidden applications be killed?
kill_apps = "yes"

def produce_commands_ofapp():
    with open(curr_dir+"/blacklist.txt", "r") as blacklist:
        blacklist = eval(blacklist.read())
    return blacklist

def createlist_runningprocs():
    processesb = subprocess.Popen(["ps", "-u", curruser], stdout=subprocess.PIPE)
    process_listb = (processesb.communicate()[0].decode("utf-8")).split("\n")
    return process_listb

def runsornot():
    check_blacklist = produce_commands_ofapp()
    runningprocs_list = createlist_runningprocs()
    found_matches = [item for item in check_blacklist
                       if item[:15] in str(runningprocs_list)]
    if len(found_matches) != 0:
        with open(curr_dir+"/log.txt", "a+") as logfile:
            logfile.write(str(found_matches)+" "+str(datetime.datetime.now())+"\n")
    else:
        pass
    if kill_apps == "yes":
        for application in found_matches:
            kill_forbidden(application)
    else:
        pass

def kill_forbidden(app_command):
    # get the pid length of system
    get_size = subprocess.Popen(
        ["cat", "/proc/sys/kernel/pid_max"],
        stdout=subprocess.PIPE
        )
    size = len((get_size.communicate()[0].decode("utf-8")).replace("\n", ""))
    # get the appropriate pid line & pid
    process_list = createlist_runningprocs()
    appr_pid = [
        line for line in process_list if \
        app_command[:15] in line][0][:size+1].replace(" ", "")
    # kill the found process
    subprocess.Popen(["kill", "-9", appr_pid])

runsornot()

As said, the setup can be bypassed. However, the combination of measures, and the fact that you have to know what they are, make it a reasonable defence in case of an avarage usere with an average knowledge on how to manipulate the system.


Thanks for your answers. I have reached this already by manipulating the permissions of the programs bin-files. I installed the old gnome user-administration tool, which allows to manage groups. Unchecked group games for the user, which is not allowed to open certain programs. Then changed group and permissions of the bin-files:

sudo chgrp games /path/to/game

sudo chmod 750 /path/to/game

Now the user can see the desktop files in the Dash, but they won't run after click.

Greetings