1/*
2 * External backend for file-backed passwords
3 * Copyright (c) 2021, Patrick Steinhardt <ps@pks.im>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9#include "includes.h"
10
11#include "utils/common.h"
12#include "utils/config.h"
13#include "ext_password_i.h"
14
15
16/**
17 * Data structure for the file-backed password backend.
18 */
19struct ext_password_file_data {
20	char *path; /* path of the password file */
21};
22
23
24/**
25 * ext_password_file_init - Initialize file-backed password backend
26 * @params: Parameters passed by the user.
27 * Returns: Pointer to the initialized backend.
28 *
29 * This function initializes a new file-backed password backend. The user is
30 * expected to initialize this backend with the parameters being the path of
31 * the file that contains the passwords.
32 */
33static void * ext_password_file_init(const char *params)
34{
35	struct ext_password_file_data *data;
36
37	if (!params) {
38		wpa_printf(MSG_ERROR, "EXT PW FILE: no path given");
39		return NULL;
40	}
41
42	data = os_zalloc(sizeof(*data));
43	if (!data)
44		return NULL;
45
46	data->path = os_strdup(params);
47	if (!data->path) {
48		os_free(data);
49		return NULL;
50	}
51
52	return data;
53}
54
55
56/**
57 * ext_password_file_deinit - Deinitialize file-backed password backend
58 * @ctx: The file-backed password backend
59 *
60 * This function frees all data associated with the file-backed password
61 * backend.
62 */
63static void ext_password_file_deinit(void *ctx)
64{
65	struct ext_password_file_data *data = ctx;
66
67	str_clear_free(data->path);
68	os_free(data);
69}
70
71/**
72 * ext_password_file_get - Retrieve password from the file-backed password backend
73 * @ctx: The file-backed password backend
74 * @name: Name of the password to retrieve
75 * Returns: Buffer containing the password if one was found or %NULL.
76 *
77 * This function tries to find a password identified by name in the password
78 * file. The password is expected to be stored in `NAME=PASSWORD` format.
79 * Comments and empty lines in the file are ignored. Invalid lines will cause
80 * an error message, but will not cause the function to fail.
81 */
82static struct wpabuf * ext_password_file_get(void *ctx, const char *name)
83{
84	struct ext_password_file_data *data = ctx;
85	struct wpabuf *password = NULL;
86	char buf[512], *pos;
87	int line = 0;
88	FILE *f;
89
90	f = fopen(data->path, "r");
91	if (!f) {
92		wpa_printf(MSG_ERROR,
93			   "EXT PW FILE: could not open file '%s': %s",
94			   data->path, strerror(errno));
95		return NULL;
96	}
97
98	wpa_printf(MSG_DEBUG, "EXT PW FILE: get(%s)", name);
99
100	while (wpa_config_get_line(buf, sizeof(buf), f, &line, &pos)) {
101		char *sep = os_strchr(pos, '=');
102
103		if (!sep) {
104			wpa_printf(MSG_ERROR, "Invalid password line %d.",
105				   line);
106			continue;
107		}
108
109		if (!sep[1]) {
110			wpa_printf(MSG_ERROR, "No password for line %d.", line);
111			continue;
112
113		}
114
115		if (os_strncmp(name, pos, sep - pos) != 0)
116			continue;
117
118		password = wpabuf_alloc_copy(sep + 1, os_strlen(sep + 1));
119		goto done;
120	}
121
122	wpa_printf(MSG_ERROR, "Password for '%s' was not found.", name);
123
124done:
125	forced_memzero(buf, sizeof(buf));
126	fclose(f);
127	return password;
128}
129
130
131const struct ext_password_backend ext_password_file = {
132	.name = "file",
133	.init = ext_password_file_init,
134	.deinit = ext_password_file_deinit,
135	.get = ext_password_file_get,
136};
137