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 "ext_password_i.h"
13 
14 
15 /**
16  * Data structure for the file-backed password backend.
17  */
18 struct ext_password_file_data {
19 	char *path; /* path of the password file */
20 };
21 
22 
23 /**
24  * ext_password_file_init - Initialize file-backed password backend
25  * @params: Parameters passed by the user.
26  * Returns: Pointer to the initialized backend.
27  *
28  * This function initializes a new file-backed password backend. The user is
29  * expected to initialize this backend with the parameters being the path of
30  * the file that contains the passwords.
31  */
ext_password_file_init(const char * params)32 static void * ext_password_file_init(const char *params)
33 {
34 	struct ext_password_file_data *data;
35 
36 	if (!params) {
37 		wpa_printf(MSG_ERROR, "EXT PW FILE: no path given");
38 		return NULL;
39 	}
40 
41 	data = os_zalloc(sizeof(*data));
42 	if (!data)
43 		return NULL;
44 
45 	data->path = os_strdup(params);
46 	if (!data->path) {
47 		os_free(data);
48 		return NULL;
49 	}
50 
51 	return data;
52 }
53 
54 
55 /**
56  * ext_password_file_deinit - Deinitialize file-backed password backend
57  * @ctx: The file-backed password backend
58  *
59  * This function frees all data associated with the file-backed password
60  * backend.
61  */
ext_password_file_deinit(void * ctx)62 static void ext_password_file_deinit(void *ctx)
63 {
64 	struct ext_password_file_data *data = ctx;
65 
66 	str_clear_free(data->path);
67 	os_free(data);
68 }
69 
70 /**
71  * ext_password_file_get - Retrieve password from the file-backed password backend
72  * @ctx: The file-backed password backend
73  * @name: Name of the password to retrieve
74  * Returns: Buffer containing the password if one was found or %NULL.
75  *
76  * This function tries to find a password identified by name in the password
77  * file. The password is expected to be stored in `NAME=PASSWORD` format.
78  * Comments and empty lines in the file are ignored. Invalid lines will cause
79  * an error message, but will not cause the function to fail.
80  */
ext_password_file_get(void * ctx,const char * name)81 static struct wpabuf * ext_password_file_get(void *ctx, const char *name)
82 {
83 	struct ext_password_file_data *data = ctx;
84 	struct wpabuf *password = NULL;
85 	char buf[512], *pos;
86 	size_t name_len;
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 	name_len = os_strlen(name);
99 
100 	wpa_printf(MSG_DEBUG, "EXT PW FILE: get(%s)", name);
101 
102 	while ((pos = fgets(buf, sizeof(buf), f))) {
103 		char *sep;
104 
105 		line++;
106 
107 		/* Strip newline characters */
108 		pos[strcspn(pos, "\r\n")] = 0;
109 
110 		/* Skip comments and empty lines */
111 		if (*pos == '#' || *pos == '\0')
112 			continue;
113 
114 		sep = os_strchr(pos, '=');
115 		if (!sep) {
116 			wpa_printf(MSG_ERROR, "Invalid password line %d.",
117 				   line);
118 			continue;
119 		}
120 
121 		if (!sep[1]) {
122 			wpa_printf(MSG_ERROR, "No password for line %d.", line);
123 			continue;
124 
125 		}
126 
127 		if (name_len != (size_t) (sep - pos) ||
128 		    os_strncmp(name, pos, sep - pos) != 0)
129 			continue;
130 
131 		password = wpabuf_alloc_copy(sep + 1, os_strlen(sep + 1));
132 		goto done;
133 	}
134 
135 	wpa_printf(MSG_ERROR, "Password for '%s' was not found.", name);
136 
137 done:
138 	forced_memzero(buf, sizeof(buf));
139 	fclose(f);
140 	return password;
141 }
142 
143 
144 const struct ext_password_backend ext_password_file = {
145 	.name = "file",
146 	.init = ext_password_file_init,
147 	.deinit = ext_password_file_deinit,
148 	.get = ext_password_file_get,
149 };
150