I have several encrypted APFS volumes, some of which have their passphrases stored only in specific users' keychains so they can unlock and mount automatically for those users.
However, when the user logs out, the volume remains mounted. While this isn't strictly a problem (as I set mount points inside the user's home folder, and have volume ownership enabled), I would prefer for the volume to unmount and lock again automatically.
This behaviour differs compared to mounting an encrypted disk image, which is mounted as a specific user (when viewing the output of mount
) and which then (normally*) unmounts when the user logs out.
Is it possible to replicate the same behaviour with APFS volumes, i.e- mount automatically for user with the passphrase in their keychain when they login, and then unmount (and lock) automatically when they logout?
*I say normally, as macOS Catalina appears to have bugs related to cleaning up user processes when a user logs out, resulting in many processes still running for logged out users. This currently includes disk-image-helper, so it no longer unmounts automatically as it did under Mojave. I'm happy to accept any answer that replicates the disk image mounting/unmounting behaviour with the caveat that this currently doesn't always work for Catalina, on the basis that it should work if Apple ever fixes these bugs.
Update: I've tried doing the following in a script triggered by launchd, but launchd's kill signal doesn't appear to reach it:
#!/bin/bash
VOLUME=12345678-9012-3456-7890-123456789012
MOUNT_POINT=/Users/haravikk/Desktop/Foo
[ ! -e "${MOUNT_POINT}" ] && { mkdir "${MOUNT_POINT}" || exit 1; }
if echo -e "$(security find-generic-password -wa "${VOLUME}" | sed 's/../\\x&/g')" | diskutil apfs unlockVolume "${VOLUME}" -stdinpassphrase; then
cleanup() {
echo 'Unmounting'
attempts=5
while [[ ${attempts} -gt 0 ]]; do
diskutil apfs lockVolume "${VOLUME}" && break
[[ -n "${MOUNT_POINT}" ]] && umount "${MOUNT_POINT}" && break
attempts=$((${attempts} - 1))
sleep 5
done
if [[ ${attempts} = 0 ]]; then
if ! diskutil unmount force "${VOLUME}"; then
if [[ -z "${MOUNT_POINT}" ]] || ! umount -f "${MOUNT_POINT}"; then
echo 'All attempts to unmount failed' >&2
fi
fi
fi
}
trap 'cleanup' SIGINT SIGHUP SIGTERM EXIT
while true; do
sleep 86400 &
wait $!
done
fi
The idea was that when the user logs out, launchd
should send their processes a kill signal (SIGINT
) which will trigger the script's trap and allow it to unmount the volume. But this never seems to happen; the trap isn't triggered at all.
If anyone is interested in using the basics of this script, note that you will need to have an entry in your keychain for the volume (you can do this by mounting with Disk Utility and choosing to save when prompted for the password), and must make sure that security
has permission to access it.