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  */
19 struct 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  */
33 static 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  */
63 static 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  */
82 static 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 
124 done:
125 	forced_memzero(buf, sizeof(buf));
126 	fclose(f);
127 	return password;
128 }
129 
130 
131 const 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