--- /dev/null
+/*
+ * External backend for file-backed passwords
+ * Copyright (c) 2021, Patrick Steinhardt <ps@pks.im>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "utils/common.h"
+#include "utils/config.h"
+#include "ext_password_i.h"
+
+
+/**
+ * Data structure for the file-backed password backend.
+ */
+struct ext_password_file_data {
+ char *path; /* path of the password file */
+};
+
+
+/**
+ * ext_password_file_init - Initialize file-backed password backend
+ * @params: Parameters passed by the user.
+ * Returns: Pointer to the initialized backend.
+ *
+ * This function initializes a new file-backed password backend. The user is
+ * expected to initialize this backend with the parameters being the path of
+ * the file that contains the passwords.
+ */
+static void * ext_password_file_init(const char *params)
+{
+ struct ext_password_file_data *data;
+
+ if (!params) {
+ wpa_printf(MSG_ERROR, "EXT PW FILE: no path given");
+ return NULL;
+ }
+
+ data = os_zalloc(sizeof(*data));
+ if (!data)
+ return NULL;
+
+ data->path = os_strdup(params);
+ if (!data->path) {
+ os_free(data);
+ return NULL;
+ }
+
+ return data;
+}
+
+
+/**
+ * ext_password_file_deinit - Deinitialize file-backed password backend
+ * @ctx: The file-backed password backend
+ *
+ * This function frees all data associated with the file-backed password
+ * backend.
+ */
+static void ext_password_file_deinit(void *ctx)
+{
+ struct ext_password_file_data *data = ctx;
+
+ str_clear_free(data->path);
+ os_free(data);
+}
+
+/**
+ * ext_password_file_get - Retrieve password from the file-backed password backend
+ * @ctx: The file-backed password backend
+ * @name: Name of the password to retrieve
+ * Returns: Buffer containing the password if one was found or %NULL.
+ *
+ * This function tries to find a password identified by name in the password
+ * file. The password is expected to be stored in `NAME=PASSWORD` format.
+ * Comments and empty lines in the file are ignored. Invalid lines will cause
+ * an error message, but will not cause the function to fail.
+ */
+static struct wpabuf * ext_password_file_get(void *ctx, const char *name)
+{
+ struct ext_password_file_data *data = ctx;
+ struct wpabuf *password = NULL;
+ char buf[512], *pos;
+ int line = 0;
+ FILE *f;
+
+ f = fopen(data->path, "r");
+ if (!f) {
+ wpa_printf(MSG_ERROR,
+ "EXT PW FILE: could not open file '%s': %s",
+ data->path, strerror(errno));
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "EXT PW FILE: get(%s)", name);
+
+ while (wpa_config_get_line(buf, sizeof(buf), f, &line, &pos)) {
+ char *sep = os_strchr(pos, '=');
+
+ if (!sep) {
+ wpa_printf(MSG_ERROR, "Invalid password line %d.",
+ line);
+ continue;
+ }
+
+ if (!sep[1]) {
+ wpa_printf(MSG_ERROR, "No password for line %d.", line);
+ continue;
+
+ }
+
+ if (os_strncmp(name, pos, sep - pos) != 0)
+ continue;
+
+ password = wpabuf_alloc_copy(sep + 1, os_strlen(sep + 1));
+ goto done;
+ }
+
+ wpa_printf(MSG_ERROR, "Password for '%s' was not found.", name);
+
+done:
+ forced_memzero(buf, sizeof(buf));
+ fclose(f);
+ return password;
+}
+
+
+const struct ext_password_backend ext_password_file = {
+ .name = "file",
+ .init = ext_password_file_init,
+ .deinit = ext_password_file_deinit,
+ .get = ext_password_file_get,
+};