Windows: Map network drives from csv

Even back in my olden days of using a non-free operating system, I was automating my tasks. The non-persistent sessions at the computer science lab required that I script my tasks. This is what I came up with for mapping network drives.

You can set a csv file with the following contents:


So it’s not a real csv file; it’s got headers delineated by “SERVER” and a server name. The script will operate on the following lines, until the next “SERVER” line. It will mount the drive letter, from the following CIFS share, using a username and password or prompting if blank, and a pretty name. It will only mount those entries, if the SERVER actually is reachable. So it fails safely if you are on a different network than the requested server at the time.

The script is available on my gitlab. And that example csv is also there.

I eventually scrapped this script when I deployed an Active Directory domain and I used group policy to define a number of mounts to define.

Devuan freeipa domain users control local devices

The Debian method of granting access to devices like the network cards, audio output, printers, etc., is to add a user to the appropriate system group. For domain users, however, do I have to add every single domain user to the local group? I have sought an answer to this problem for a long time. After a lot of research, and coming back to the problem, I finally have a solution I find acceptable for general use and for sharing.


You have to adjust pam, nsswitch, and the local groups themselves. However, no additional packages should be needed!


I did this with lightdm display manager, which calls pam. During my research, I read on one of those pages somewhere that not all DMs use pam. Just make sure yours does.
You have domain groups named netdev, plugdev, audio, etc. Making extra groups in the directory, with either nested groups or direct members, is a small price to pay for this goal!

The steps

Configure pam

You have to configure pam to include the pam_group library.

sudo touch "${tf}" ; sudo chmod 0644 "${tf}" ; sudo chown root.root "${tf}"
cat <<EOF | sudo tee "${tf}" 1>/dev/null
Name: activate /etc/security/group.conf
Default: yes
Priority: 900
Auth-Type: Primary
        required               use_first_pass

And run the debian pam-auth-update program. Obviously there is not a EL equivalent, but then you can’t have this problem on a EL derivative.


And select the option that we just wrote, “Activate /etc/security/group.conf”

Configure nsswitch.conf

Change the group: line in nsswitch.conf to the following:

group:      compat [SUCCESS=merge] sss

You can accomplish that with a sed oneliner:

sed -i -r -e '/^\s*group:/s/(compat|files) sss/\1 [SUCCESS=merge] sss/;' /etc/nsswitch.conf

Change the local groups

To take advantage of the glibc group merging, you have to be using glibc 2.24 or higher, and Devuan Ceres has 2.28 so we’re good. Also, the GIDs have to match exactly. Of course your GID range will be different from mine, but I wrote a general solution.

test -z "${LOGFILE}" && LOGFILE=/root/deploy.log
for word in netdev video audio dip ;
      tgid="$( getent group -s  sss  "${word}" | awk -F':' '{print $3}' )"
      ogid="$( getent group -s files "${word}" | awk -F':' '{print $3}' )"
   } 2>/dev/null
   # if group exists locally and in domain
   test -n "${ogid}" && test -n "${tgid}" && test ${ogid} -ne ${tgid} && {
      # use sed because groupmod fails because the new GID already exists
      sed -i -r -e "/^${word}:/s/:${ogid}:/:${tgid}:/;" /etc/group
      # log to stdout and logfile
      printf '%s %s\n' "$( date -u "+%FT%TZ" )" "Change ${word} from gid ${ogid} to ${tgid}" | tee -a "${LOGFILE}"

This snippet changes the gid of the requested local groups, to match the gid of the netgroups. A reboot is required to get the updated permissions on the device special files.


Web searches

pam_group add domain user to netdev


  1. pam – Add all network users to local group for specific hosts in CentOS7 – Server Fault
  2. OpenLDAP/SSSD Automatically Add User to Local Group – Server Fault
  3. LDAPClientAuthentication – Community Help Wiki []
  4. Proposals/GroupMerging – glibc wiki
  5. SystemGroups – Debian Wiki
  6. My question from a few months ago Grant domain user access like he is in netdev group []

Devuan join freeipa domain

FreeIPA is a great identity management domain for GNU/Linux systems. This post explains how to join a Devuan installation as a client to FreeIPA so that you can use centralized users, sudo policies, certificates, and everything else that is managed by freeipa.


Running Devuan Ceres

You must be running Devuan ceres (unstable) to make the freeipa packages available. To get there, you need these exact apt sources:

deb ceres main contrib non-free
deb-src ceres main contrib non-free

To use the packages from these repos, you should do the normal update, upgrade, and dist-upgrade. Here is my full command for an unattended upgrade.

mkdir -p ~/log ; sudo apt-get update ;
_myact() {
   sudo DEBIAN_FRONTEND=noninteractive apt-get -q -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" -o Dpkg::Options::="--force-overwrite" upgrade ;
   sudo DEBIAN_FRONTEND=noninteractive apt-get -q -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" -o Dpkg::Options::="--force-overwrite" dist-upgrade ;
} ;
time _myact 2>&1 | tee -a ~/log/apt-get.upgrade.$( date "+%F" ).log

After a reboot, you are ready for the next steps.

Building custom oddjob-mkhomedir

You need a custom package, because in Devuan package oddjob is banned (because of systemd dependencies). I built a dummy package, which you can install from my OBS account.
I will briefly describe the build process so you can do this in your environment. My build resources are in version control on my gitlab in two directories.

  1. Build a dummy source tarball
    mkdir -p ~/deb/oddjob-mkhomedir-0.0.1/ ; cd ~/deb/oddjob-mkhomedir ; echo "Dummy package" >>
  2. Build a debian/ directory

    I modifed the debian control files to make it an all-architecture deb so I didn’t have to recompile for i686 and x86_64, but for a one-off package for yourself, don’t bother.

  3. Compile the package
    debuild -us -uc

    In the parent directory, which in my example is ~/deb, there should be the oddjob-mkhomedir_0.0.1-1_amd64.deb
    Loading it into an apt repository is beyond the scope of this conversation.

  4. Install the package
    apt-get install ~/deb/oddjob-mkhomedir_0.0.1-1_amd64.deb

Because of this fake mkhomedir package, we will have to take steps to enable the mkhomedir behavior farther ahead.

Install packages and files

Install the client software.

sudo apt-get -y install freeipa-client

You will need to have a dummy file for systemctl and for hostnamectl. Some components of freeipa are hardcoded to use that. Maybe we should recompile the freeipa package for Devuan instead of just using the debian one. But that sounds way beyond my capacity. So let’s just keep hacking.

sudo touch "${tf}" ; sudo chmod 0755 "${tf}"
sudo tee "${tf}" <<EOF /dev/null

sudo touch "${tf}" ; sudo chmod 0755 "${tf}"
sudo tee "${tf}" <<EOF /dev/null

Configure freeipa client

Now we are ready to do the main work! I found that I had to disable ntp so the script could do its thing, which recently has been installing chronyd. I guess I don’t care; I just don’t want drift. I picked my battles, and ntp clients is not the battle I will fight today.

sudo service ntp stop

The script does not make a few important directories, so just make these yourself, and then run the install script.

sudo mkdir -p /etc/ipa /var/lib/ipa-client/pki
sudo ipa-client-install --hostname="$( hostname --fqdn )" --mkhomedir --configure-firefox

Of course if you don’t want those options, remove them. I think the configure-firefox step is broken anyway. I forget what it’s supposed to do; maybe load the ipa CA cert into the nss database.
I found that I always have to restart sssd after my initial client configuration. It’s a small price to pay for domain user resolution, so just do it. In this case, actually stop it and then start it.

sudo service sssd stop ; sudo service sssd start

That should be the bare minimum to get freeipa domain user auth working.

Followup and extra goodies

For the quality-of-life improvements, you need a few extra steps.

Add mkhomedir

Now is the time to add pam_mkhomedir to the pam stack.

# add pam_mkhomedir
tf=/etc/pam.d/common-session ; ! grep -q 'mkhomedir' "${tf}" && { thisline="$(( $( grep -nE 'session\s+optional' "${tf}" | head -n1 | awk -F':' '{print $1}' ) - 0 ))" ; awk -v thisline="$thisline" 'NR == (thisline) {print "session optional"; } {print;}' "${tf}" > "${tf}.2" ; test -f "${tf}.2" && mv "${tf}.2" "${tf}" ; }

This one-liner checks for the existence of the string “mkhomedir” in the common-session file and then adds the lib to the pam session stack if it was absent. It cleverly sticks it at the beginning of the “session optional” section, because the order of pam statements is important. So if you have heavily customized your pam configuration, you need to be careful. This line works with a bog-standard pam config straight from the ISO. If you want to stick it in there yourself, you need this line:

session optional

Kerberos trust dns

If you want to just use short hostnames to access other systems, you need to tell kerberos to trust dns.
If you have bgscripts package installed, you can use the updateval command in a oneliner.

sudo updateval -a /etc/krb5.conf -s '[libdefaults]' '^(\s*dns_canonicalize_hostname\s*=\s*).*' '  dns_canonicalize_hostname = true'

Basically, in /etc/krb5.conf change dns_canonicalize_hostname to true.


If the install fails for any reason, before you reinstall it, you have to run ipa-client-install –uninstall. And in order for that second command to succeed, you probably have to run “certmonger” first. I don’t really know why running that allows it to uninstall, but just take it under advisement.


Original research

Run init script as SELinux type other than initrc_t

To run a custom init script as SELinux context other than initrc_t, you can use an SELinux policy that adds a new type for you to use.

# Filename: general-local.te
# License: CC-BY-SA 4.0
# Author: bgstack15
# Startdate: 2019-09-19 16:45
# Title: SELinux Policy for Custom Process Types from Init Scripts
# Purpose: SELinux policy to allow an init script to run a process as a selinux type other than initrc_t
# History:
# Usage:
#    When installed, you can run the following command to have the daemon process transition to type unconfined_t:
#    chcon -t 'local_initrc_exec_t' /etc/init.d/myscript
# Reference:
#    liberal use of tail -n45000 /var/log/audit/audit.log | audit2allow
# Improve:
# Documentation:
#    Change an init script to context local_initrc_exec_t and then the process will transition to unconfined_t which of course is insecure, but it satisfies the scan that is looking for daemons running as initrc_t.
module general-local 1.0;

require {
        type fs_t;
        type initrc_exec_t;
        type init_t;
        type unconfined_t;
        class file { append create entrypoint execmod execute execute_no_trans getattr ioctl link lock mounton open quotaon read relabelfrom relabelto rename setattr swapon unlink write };
        class filesystem associate;
        class process { unconfined transition };
        class service { start status };

type local_initrc_exec_t;
type_transition init_t local_initrc_exec_t:process unconfined_t ;

#============= init_t ==============
allow init_t local_initrc_exec_t:file *;
allow init_t unconfined_t:process transition;
#============= local_initrc_exec_t ==============
allow local_initrc_exec_t fs_t:filesystem associate;
#============= unconfined_t ==============
allow unconfined_t local_initrc_exec_t:file *;
allow unconfined_t local_initrc_exec_t:service { start status };

To compile and install this module, you can run the following oneliner.

checkmodule -M -m -o general_local.mod general_local.te && semodule_package -m general_local.mod -o general_local.pp && semodule -v -i general_local.pp

Should you run daemons as unconfined_t? Of course not. But it’s different than running it as initrc_t.



  1. ObjectClassesPerms – SELinux Wiki
  2. SELinux Policy Concepts and Overview: Security Policy Development Primer for Security Enhanced Linux
  3. Writing a targeted policy module for SELinux (howto tutorial slides)
  4. PackagingDrafts/SELinux – Fedora Project Wiki#Creating_new_types
  5. HowTos/SELinux – CentOS Wiki
  6. Logrotate, audit.log, selinux, cron, and ansible | Knowledge Base


How I run Artemis Spaceship Bridge Simulator on Devuan ceres

I like to play Artemis Spaceship Bridge Simulator with my friends.

To install my licensed Artemis 2.7.0 game on Devuan using Wine, I use the official Debian instructions for installing the Buster version of winehq-devel.

sudo su -
dpkg --add-architecture i386 # needed for packages
wget -O- -nc | apt-key add -
   echo "# And for Debian Buster this one:"
   echo "deb buster main"
} >> /etc/apt/sources.list.d/winehq.list
apt-get update
apt-get install -y winehq-devel winetricks

I was having a problem getting the game to run, and after much Internet searching I found what I think is the working solution!

wine regedit

Set this value:


I was warned that this is very experimental and might break wine in unintended ways, so be very careful when applying this. If Artemis works without setting this registry key, then do not set the registry key.



  1. Useful Registry Keys – WineHQ Wiki
  2. 2.7 Crash / Wineskin – Artemis SBS Forums
  3. View Single Post – Running Artemis on Mac? – Artemis SBS Forums
  4. Debian – WineHQ Wiki

Change photo on AD user account from Linux shell

You need a photo, with a suitable small size, probably 100×100 or smaller. I heard a size limit, 10KB, but my reference photo was 2KB.

Install openldap-clients, or the appropriate package to get ldapmodify command.

You will need the reference photo, which I will call input.jpg.

$ file input.jpg
input.jpg: JPEG image data, JFIF standard 1.01

Convert it with base64 with no wrapping.

$ base64 -w0 < input.jpg > photo.ldif

And now, add the ldif commands to the photo.ldif file:

dn: CN=Example user,OU=Users,DC=example,DC=com
changetype: modify
add: thumbnailPhoto

Observe that there is a blank line after the attribute being modified.

If you’re using kerberos auth, make sure you have a ticket with kinit $LDAPUSER. Run the ldapmodif command!

ldapmodify -v -f photo.ldif -H ldaps:// -O maxssf=0 -Y gssapi

To use simple binding, you would want a command more like this:

ldapmodify -v -f photo.ldif -H ldaps:// -O maxssf=0 -x -W -D 'CN=Example user,OU=Users,DC=example,DC=com'

This works because in Active Directory a user has the permissions (NTACLs) to update certain attributes for himself.


Original research
Refresher on ldif syntax:

xfreerdp client cannot connect to xrdp session

You might get this kind of error when using xfreerdp to connect to xrdp.

[07:56:20:443] [11212:11213] [ERROR][com.freerdp.core.update] - [0x03] Cache Glyph - SERVER BUG: The support for this feature was not announced! Use /relax-order-checks to ignore
[07:56:20:443] [11212:11213] [ERROR][com.freerdp.core.update] - order flags 03 failed
[07:56:20:443] [11212:11213] [ERROR][com.freerdp.core.fastpath] - Fastpath update Orders [0] failed, status 0
[07:56:20:443] [11212:11213] [ERROR][com.freerdp.core.fastpath] - fastpath_recv_update() - -1
[07:56:20:443] [11212:11213] [ERROR][com.freerdp.core.fastpath] - fastpath_recv_update_data() fail
[07:56:20:443] [11212:11213] [ERROR][com.freerdp.core.transport] - transport_check_fds: transport->ReceiveCallback() - -3
[07:56:20:443] [11212:11213] [ERROR][com.freerdp.core] - freerdp_check_fds() failed - 0
[07:56:20:443] [11212:11213] [INFO][com.freerdp.client.common] - Network disconnect!
[07:56:20:443] [11212:11213] [ERROR][com.freerdp.client.x11] - Failed to check FreeRDP file descriptor

To work around the problem, add +glyph-cache to your command.

xfreerdp /v:remote-host3 /size:"1520x820" /u:bgstack15 /wallpaper /sec-rdp /sound +glyph-cache



Cannot connect with XFreeRDP version 2.0.0-rc4 · Issue #1266 · neutrinolabs/xrdp

Run spice-vdagent with X11

On Devuan beowulf/ceres, for some reason spice-vdagent is not started when X11 is started. I found what appears to be a proper way to do it: write file /etc/X11/Xsession.d/60spice-vdagent.

# -*- sh -*-
# Xsession.d script to start spice-vdagent
# This file is sourced by Xsession(5), not executed.

__AGENT="$( which spice-vdagent 2>/dev/null )"
test -x "${__AGENT}" && "${__AGENT}" &

Maybe this should be included in the spice-vdagent package…

Compare two files in hexadecimal view

Just a quick and dirty list for myself. When I was looking for hexeditors with a file-compare view, these came up. All three of these options seem useful in slightly different ways.
vimdiff and :%!xxd
Vimdiff just calls vim with a bunch of preset options.

vimdiff file1 file2

Once inside, you have to convert each file with :%!xxd and then after making any changes, convert back with :%!xxd -r before saving. Slightly clunky, and I’m sure there’s a way to automate all that. But I was only making select changes. And a few keystrokes isn’t so bad.