main: add SystemdEncrypt option, and initialize key

Recently systemd added the ability to pass secret credentials to
services via LoadCredentialEncrypted/SetCredentialEncrypted. Once
set up the service is able to read the decrypted credentials from
a file. The file path is found in the environment variable
CREDENTIALS_DIRECTORY + an identifier. The value of SystemdEncrypt
should be set to the systemd key ID used when the credential was
created.

When SystemdEncrypt is set IWD will attempt to read the decrypted
secret from systemd. If at any point this fails warnings will be
printed but IWD will continue normally. Its expected that any failures
will result in the inability to connect to any networks which have
previously encrypted the passphrase/PSK without re-entering
the passphrase manually. This could happen, for example, if the
systemd secret was changed.

Once the secret is read in it is set into storage to be used for
profile encryption/decryption.
This commit is contained in:
James Prestwood 2022-02-15 13:41:31 -08:00 committed by Denis Kenzior
parent 64f225df6e
commit e8e9c68dea
1 changed files with 76 additions and 0 deletions

View File

@ -29,6 +29,10 @@
#include <errno.h>
#include <getopt.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <ell/ell.h>
#include <ell/useful.h>
@ -45,6 +49,7 @@
#include "src/storage.h"
#include "src/anqp.h"
#include "src/netconfig.h"
#include "src/crypto.h"
#include "src/backtrace.h"
@ -397,6 +402,71 @@ done:
return r;
}
/*
* Initialize a systemd encryption key for encrypting/decrypting credentials.
*/
static bool setup_system_key(void)
{
int fd;
struct stat st;
const char *cred_dir;
void *key = NULL;
_auto_(l_free) char *path = NULL;
_auto_(l_free) char *key_id = NULL;
bool r = false;
key_id = l_settings_get_string(iwd_config, "General",
"SystemdEncrypt");
if (!key_id)
return true;
cred_dir = getenv("CREDENTIALS_DIRECTORY");
if (!cred_dir) {
l_warn("SystemdEncrypt enabled but CREDENTIALS_DIRECTORY not "
"set, check iwd.service file");
return false;
}
path = l_strdup_printf("%s/%s", cred_dir, key_id);
if (stat(path, &st) < 0) {
l_warn("SystemdEncrypt: Could not stat %s", path);
return false;
}
fd = open(path, O_RDONLY, 0);
if (fd < 0) {
l_warn("SystemdEncrypt: Cannot open secret: %s (%d)",
strerror(errno), errno);
return false;
}
if (fstat(fd, &st) < 0 || st.st_size == 0)
goto close_fd;
key = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (key == MAP_FAILED) {
l_warn("SystemdEncrypt: can't mmap secret: %s (%d)",
strerror(errno), errno);
goto close_fd;
}
if (mlock(key, st.st_size) < 0) {
l_warn("SystemdEncrypt: Failed to mlock secrets file");
goto unmap;
}
r = storage_init(key, st.st_size);
munlock(key, st.st_size);
unmap:
munmap(key, st.st_size);
close_fd:
close(fd);
return r;
}
int main(int argc, char *argv[])
{
int exit_status;
@ -529,9 +599,15 @@ int main(int argc, char *argv[])
l_dbus_set_disconnect_handler(dbus, dbus_disconnected, NULL, NULL);
dbus_init(dbus);
if (!setup_system_key())
goto failed_storage;
exit_status = l_main_run_with_signal(signal_handler, NULL);
iwd_modules_exit();
storage_exit();
failed_storage:
dbus_exit();
l_dbus_destroy(dbus);