Ubuntu: Changing the Crypt (Plymouth) Login Screen

So, with all of this customisation of my Ubuntu machine going on, there had to be something else that I could configure, right? Well, there’s a lot, actually, but from the purely aesthetical point of view, the crypt screen was the next logical choice.

For those of you who may not be aware, and haven’t implemented encryption via Yubikey and LUKS, you can encrypt your volume and are forced to enter it on boot to get into the system. Think of it like BitLocker™ for Windows™®, only better.

celtic-come-at-me-bro

Oh, yeah, that’s right: I said it…

Anyways, the first thing that you’ll want to do is find a Plymoth theme. There’s actually a site full of them, here, and there’s – arguably – hundreds (if not thousands) more that you could find across the internet.

So, first things first, we download the theme. In my case it was the Paw Ubuntu/Mint Floral theme, just for the sake of proof-of-concept and the aesthetic appeals to me. YYMV. However, this is the them being used in this haphazard “how-to”.

Once the file is downloaded, extract it. (NOTE: Make sure that the script’s name matches the folder name; otherwise, the later regex will fail.) Move the contents of the inner parent to the shared directory on Ubuntu:

$ sudo mv Paw-Ubuntu-Floral /usr/share/plymouth/themes/

Now that it’s copied, we need to tell Ubuntu to build a new boot screen with the one we just copied over. This is fairly easy to do (kind of) in all of three commands:

$ sudo update-alternatives --install /usr/share/plymouth/themes/default.plymouth default.plymouth /usr/share/plymouth/themes/Paw-Ubuntu-Floral/paw-ubuntu-floral.plymouth 100 $ sudo update-alternatives --config default.plymouth
Det finns 2 val för alternativet default.plymouth (som tillhandahåller /usr/share/plymouth/themes/default.plymouth).

  Val          Sökväg                                                                 Prioritet  Status
------------------------------------------------------------
* 0            /usr/share/plymouth/themes/ubuntu-logo/ubuntu-logo.plymouth               100       automatiskt läge
  1            /usr/share/plymouth/themes/Paw-Ubuntu-Floral/paw-ubuntu-floral.plymouth   100       manuellt läge
  2            /usr/share/plymouth/themes/ubuntu-logo/ubuntu-logo.plymouth               100       manuellt läge

Tryck  för att behålla nuvarande val[*], eller ange urvalsnummer: 1       
update-alternatives: använder /usr/share/plymouth/themes/Paw-Ubuntu-Floral/paw-ubuntu-floral.plymouth för att tillhandahålla /usr/share/plymouth/themes/default.plymouth (default.plymouth) i manuellt läge

$ sudo update-initramfs -u
update-initramfs: Generating /boot/initrd.img-4.15.0-46-generic

If you receive the following error, you probably didn’t verify the file name of the script, like I suggested in the section above:

W: plymouth module (/usr/lib/x86_64-linux-gnu/plymouth//.so) missing, skipping that theme.

If so, go back and change the name of the script and restart this entire process over from the beginning. (Yes, I know, which is why I cautioned you about it, before…)

Alright, assuming all went well, all you need to do, now, is to reboot and you’ll see your newfound plymouth theme when you’re prompted to input your credentials for the disk’s encryption.

Thanks for coming to this NERDTalk™ and happy Ubuntuing!

Mass-Configuring OVPN in NetworkManager (on Ubuntu 18.04LTS)

So, I had a pretty large problem to figure out: How to configure 170+ different OVPN (Swedish/English) configurations in NetworkManager, without having to enter my username and password over 170 friggin’, fraggin’ times.

(NOTE: If you’re highly security conscious, then this probably isn’t going to be very palatable for you. You have been warned.)

I use [REDACTED] VPN service and they offer a zip file that you can download with containing multiple OVPN configuration files; a unique file for each server that you can use. After filtering the list down to my targets, I had a resultant list to import into Network Manager.

In order to have NetworkManager leverage ovpn, though, you need to install two packages, first.

sudo apt-get install network-manager-openvpn network-manager-openvpn-gnome

Bes sure to restart NetworkManager, afterwards, so you don’t end-up in a dissonant state.

sudo service network-manager restart

So, how do we do that? Well, it’s not as complicated as one my think and you needn’t go crafting anyting in Python or the like to do so.

for i in <location of your ovpn files>; do sudo nmcli connection import type openvpn file "$i"; done

Now that we have the files imported, we need to modify them. To do this, the easiest way is to use Python to read in the files and write our changes. Modify the script below to include your username and password.

#!/usr/bin/env python
"""Changes the exported OVPN configurations in NetworkManager to contain the username and password and autoconnect.

When mass-importing OVPN configuration files, it's necessary to overcome the hurdle of the prompt for passwords. This
script looks for the exported configuration files in NetworkManager. It writes the password configuration and the
username/password to the file. You will need to restart NetworkManager for the changes to be imported; however, it's
easier/better just to bounce the machine. (sudo init 6)

TO RUN:
    sudo python3 ModifyOvpnConfigurations.py
"""

__author__ = "felsokning"
__copyright__ = "Copyright 2019"
__license__ = "MIT"

import os
import re

source_directory = "/etc/NetworkManager/system-connections"
ovpn_files = os.listdir(source_directory)
i = 0
for ovpn in ovpn_files:
    opened_file = open(source_directory + "/" + ovpn, "r+")
    file_content = opened_file.read()
    if file_content.__contains__("mssfix=1450\n"):
        output = re.sub(r"mssfix=1450", r"mssfix=1450\npassword-flags=0", file_content)
        # TODO: Change '*' to be your username
        output2 = re.sub(r"tunnel-mtu=1500", "tunnel-mtu=1500\nusername=*", output)
        output3 = re.sub(r"service-type=org.freedesktop.NetworkManager.openvpn", r"service-type=org."
                                                                                 r"freedesktop.NetworkManager."
                                                                                 r"openvpn\n\n[vpn-secrets]\n"
                                                                                 # TODO: Change '*' to your VPN password
                                                                                 r"password=*\n",
                         output2)
        output4 = re.sub(r"password-flags=1", r"", output3)

        # Indents are important, m'kay? Without them, you do things like overwrite your wireless config files.
        # Take it from me: You do NOT want to do that.
        opened_file.truncate(0)
        opened_file.seek(0)
        opened_file.write(output4)
        opened_file.close()
        print(ovpn)

Now that the files are modified, we need to restart NetworkManager to allow the configurations to be re-read on the connection’s instantiation.

sudo service network-manager restart

(Personally, bouncing the machine was more of a formidable option, here, but that’s because I messed-up the initial script – due to indenting – and wiped all of my configuration files; thus, the warning in the script.)

Now that this has been configured, I needed a way to randomly choose which VPN connection to use, so as to not always land on a static connection. To do this, I used Python again and randomised the choice of which VPN server to connect to. (You’ll note that I’m using a pretty large seed and that’s because the default random.random() method isn’t random in a secure manner [read: it’s predictable].)

#!/usr/bin/env python
"""Randomly connections to a random VPN profile (if any are found).

Uses NetworkManager (https://developer.gnome.org/NetworkManager/stable/gdbus-org.freedesktop.NetworkManager.html#) to
enumerate the devices and connections. First, we enumerate the wireless devices to ensure that we have one. Next, we
enumerate the VPN connections and put them into a list. After that, we randomly select one of the VPN connections to
connect to. Once we've accomplished this, we disconnect the current VPN connection (if one is found) and connect to
the randomly chosen VPN connection.

REQUIREMENTS:
    python-networkmanager

TO RUN:
    python NetworkManager_VPN.py
"""

__author__ = "felsokning"
__copyright__ = "Copyright 2019"
__license__ = "MIT"

import os
import random
import time
# Externals
import NetworkManager

# Find all of the VPN connections on the machine.
vpns = list()
current_vpn = None
wireless_device = None
connections = NetworkManager.Settings.ListConnections()
for c in connections:
    if "vpn" in c.GetSettings()['connection']['type']:
        path = c.object_path
        vpns.append(path)

# If there are no VPN connections, there's no point in proceeding.
if vpns.__len__() > 0:
    # We find the Wireless Network Interface.
    # If you're running some kind of weird, three wireless network cards situation, then...
    # Change this code to work in your use-case scenario.
    devices = NetworkManager.Device.all()
    for d in devices:
        if "wifi" in d.Driver:
            wireless_device = d

    # Validate that we found a wireless network interface
    if wireless_device is not None:
        # Get the currently active VPN connection.
        # If you're running some kind of weird, three active VPNs scenario, then...
        # Change this code to work in your use-case.
        active = NetworkManager.NetworkManager.ActiveConnections
        for a in active:
            if "vpn" in a.Type:
                current_vpn = a

        # Choose a random one to connect to. We use the far more secure random method, with a larger seed,
        # to try and prevent the random generation from being a predictable pattern (well, to try to make
        # it far less predictable with our sample, at least).
        rand = random.SystemRandom(os.urandom(99999999))
        random_int = rand.randint(0, (vpns.__len__() - 1))
        random_vpn = vpns.__getitem__(random_int)
        new_connection = NetworkManager.Connection(random_vpn)

        # Validate that we have a current VPN connection to disconnect from before we do.
        if current_vpn is not None:

            # Disconnect the old & busted.
            NetworkManager.NetworkManager.DeactivateConnection(current_vpn)

            # To prevent collision in NetworkManager, we allow background clean-up before reconnecting.
            time.sleep(10)

        # Connect the new hotness.
        print("Connecting to: {}".format(random_vpn))
        NetworkManager.NetworkManager.ActivateConnection(new_connection, wireless_device, "/")

    # No wireless interfaces were found, so let's abort.
    else:
        raise Exception("No wireless interfaces were found.")

# No VPN connections were found, so let's abort.
else:
    raise Exception("The hull has been breached and the science is leaking out! "
                    "(We didn't find any valid VPN connections on this machine via NetworkManager.)")

That should just about do it. …but WAIT! That’s not all! If you act now…

I’ve also written a script to remove all of the OVPN configurations from NetworkManager, in case you made a mistake somewhere (I know that I did and this came in pretty useful.)

#!/usr/bin/env python
"""Removes all VPN profiles found in NetworkManager.

Uses NetworkManager (https://developer.gnome.org/NetworkManager/stable/gdbus-org.freedesktop.NetworkManager.html#) to
enumerate the connections that are specifically VPN connections. Then, we delete them, with righteous retribution and
indignation.

REQUIREMENTS:
    python-networkmanager

TO RUN:
    python3 RemoveVPNs.py
"""

__author__ = "felsokning"
__copyright__ = "Copyright 2019"
__license__ = "MIT"

import NetworkManager

# Find all of the VPN connections on the machine.
vpn_list = list()
connections = NetworkManager.Settings.ListConnections()
for c in connections:
    if "vpn" in c.GetSettings()['connection']['type']:
        vpn_list.append(c)

# We make sure we'e not spinning our wheels and/or calling delete on null.
if len(vpn_list) > 0:
    for v in vpn_list:
        print("Deleting: {}".format(v.object_path))
        v.Delete()

Now, you should have of the tools you need to mass-configure OVPN on your *nix (debian-based, probably) machine. 🙂

Happy coding!