Recently I decided to switch all my SMTP needs to msmtp, which is a
command-line SMTP client. To configure it most tutorials on the Internet
suggest to simply create ~/.msmtprc configuration file. However,
man 1 smtp
says that it’s also possible to keep configuration in
$XDG_CONFIG_HOME/msmtp/config (so in practice in ~/.config/msmtp/config),
which I’d very much prefer, because that’s where I store configuration files
for other programs.
So as always I created a config file in ~/config/mail/.config/msmtp/config and symlinked it with GNU Stow to ~/.config. Of course that didn’t work (otherwise I wouldn’t write this article) and msmtp repeatedly reported no configuration file available, even if it was there all the time.
Only blind luck directed me to Debian Bug Tracker which mentions AppArmor - a name which I heard before but I’m not very familiar with. In short, AppArmor offers per-application, profile-based Mandatory Access Control system. AppArmor’s profile for msmtp allows accessing only certain, specific files. For example msmtp can access only files under $HOME/.config/msmtp.
There’s one problem though. AppArmor resolves symbolic links for directories to their original paths. This is what GNU Stow creates by default - topmost symlink it can afford, in this case a symlink to msmtp config directory. So even if msmtp itself tries to read ~/.config/msmtp/config, AppArmor registers that as a request for access to ~/config/mail/.config/msmtp/config. And it leaves a syslog trace of denying such request:
kernel: [249329.035844] audit: type=1400 audit(1567152137.648:32): apparmor="DENIED" operation="open" profile="/usr/bin/msmtp" name="/home/mgoral/config/mail/.config/msmtp/config" pid=14000 comm="msmtp" requested_mask="r" denied_mask="r" fsuid=1000 ouid=1000
There are several ways to resolve this issue:
- disable AppArmor for msmtp (e.g.
sudo aa-disable msmtp);
- add local rules for msmtp in /etc/apparmor.d/local/usr.bin.msmtp;
- symlink individual files;
- use ~/.msmtprc;
- create alias for directory symlink.
I chose to simply use ~/.msmtprc, because that’s the simplest thing which works. All the other require root access, which is yet another password which blocks automatic deployment of my dotfiles.
AppArmor also caused a second problem.
Instead of storing password in plain text in configuration file, it can read it from the output of arbitrary command. As I use pass for all my password management needs and I already have a wrapper for querying certain fields from encrypted files (designed specifically for cases like that) it was no-brainer to use this script for msmtp as well. Didn’t work at all, of course. :)
The script is called pass-get. Thanks to AppArmor I can’t use it, because msmtp’s profile restricts access only to few external executables. Fortunately pass command is on the list, as well as head, so I just had to partially duplicate my pass-get command. Which is counter-productive, because if I ever have to change pass-get, I’m almost sure I’ll forget about that one small configuration file for a program which was installed, configured and forgotten.
Anyway, here’s the line:
passwordeval "pass my-email | head -1"