• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * UFD routines for Wi-Fi Protected Setup
3  * Copyright (c) 2009-2012, Masashi Honma <masashi.honma@gmail.com>
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 #include "common.h"
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14 #include <dirent.h>
15 
16 #include "wps/wps.h"
17 #include "wps/wps_i.h"
18 
19 #ifdef CONFIG_NATIVE_WINDOWS
20 #define UFD_DIR1 "%s\\SMRTNTKY"
21 #define UFD_DIR2 UFD_DIR1 "\\WFAWSC"
22 #define UFD_FILE UFD_DIR2 "\\%s"
23 #else /* CONFIG_NATIVE_WINDOWS */
24 #define UFD_DIR1 "%s/SMRTNTKY"
25 #define UFD_DIR2 UFD_DIR1 "/WFAWSC"
26 #define UFD_FILE UFD_DIR2 "/%s"
27 #endif /* CONFIG_NATIVE_WINDOWS */
28 
29 
30 struct wps_ufd_data {
31 	int ufd_fd;
32 };
33 
34 
dev_pwd_e_file_filter(const struct dirent * entry)35 static int dev_pwd_e_file_filter(const struct dirent *entry)
36 {
37 	unsigned int prefix;
38 	char ext[5];
39 
40 	if (sscanf(entry->d_name, "%8x.%4s", &prefix, ext) != 2)
41 		return 0;
42 	if (prefix == 0)
43 		return 0;
44 	if (os_strcasecmp(ext, "WFA") != 0)
45 		return 0;
46 
47 	return 1;
48 }
49 
50 
wps_get_dev_pwd_e_file_name(char * path,char * file_name)51 static int wps_get_dev_pwd_e_file_name(char *path, char *file_name)
52 {
53 	struct dirent **namelist;
54 	int i, file_num;
55 
56 	file_num = scandir(path, &namelist, &dev_pwd_e_file_filter,
57 			   alphasort);
58 	if (file_num < 0) {
59 		wpa_printf(MSG_ERROR, "WPS: OOB file not found: %d (%s)",
60 			   errno, strerror(errno));
61 		return -1;
62 	}
63 	if (file_num == 0) {
64 		wpa_printf(MSG_ERROR, "WPS: OOB file not found");
65 		os_free(namelist);
66 		return -1;
67 	}
68 	os_strlcpy(file_name, namelist[0]->d_name, 13);
69 	for (i = 0; i < file_num; i++)
70 		os_free(namelist[i]);
71 	os_free(namelist);
72 	return 0;
73 }
74 
75 
get_file_name(struct wps_context * wps,int registrar,const char * path,char * file_name)76 static int get_file_name(struct wps_context *wps, int registrar,
77 			 const char *path, char *file_name)
78 {
79 	switch (wps->oob_conf.oob_method) {
80 	case OOB_METHOD_CRED:
81 		os_snprintf(file_name, 13, "00000000.WSC");
82 		break;
83 	case OOB_METHOD_DEV_PWD_E:
84 		if (registrar) {
85 			char temp[128];
86 			os_snprintf(temp, sizeof(temp), UFD_DIR2, path);
87 			if (wps_get_dev_pwd_e_file_name(temp, file_name) < 0)
88 				return -1;
89 		} else {
90 			u8 *mac_addr = wps->dev.mac_addr;
91 
92 			os_snprintf(file_name, 13, "%02X%02X%02X%02X.WFA",
93 				    mac_addr[2], mac_addr[3], mac_addr[4],
94 				    mac_addr[5]);
95 		}
96 		break;
97 	case OOB_METHOD_DEV_PWD_R:
98 		os_snprintf(file_name, 13, "00000000.WFA");
99 		break;
100 	default:
101 		wpa_printf(MSG_ERROR, "WPS: Invalid USBA OOB method");
102 		return -1;
103 	}
104 	return 0;
105 }
106 
107 
ufd_mkdir(const char * path)108 static int ufd_mkdir(const char *path)
109 {
110 	if (mkdir(path, S_IRWXU) < 0 && errno != EEXIST) {
111 		wpa_printf(MSG_ERROR, "WPS (UFD): Failed to create directory "
112 			   "'%s': %d (%s)", path, errno, strerror(errno));
113 		return -1;
114 	}
115 	return 0;
116 }
117 
118 
init_ufd(struct wps_context * wps,struct oob_device_data * oob_dev,int registrar)119 static void * init_ufd(struct wps_context *wps,
120 		       struct oob_device_data *oob_dev, int registrar)
121 {
122 	int write_f;
123 	char temp[128];
124 	char *path = oob_dev->device_path;
125 	char filename[13];
126 	struct wps_ufd_data *data;
127 	int ufd_fd;
128 
129 	if (path == NULL)
130 		return NULL;
131 
132 	write_f = wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E ?
133 		!registrar : registrar;
134 
135 	if (get_file_name(wps, registrar, path, filename) < 0) {
136 		wpa_printf(MSG_ERROR, "WPS (UFD): Failed to get file name");
137 		return NULL;
138 	}
139 
140 	if (write_f) {
141 		os_snprintf(temp, sizeof(temp), UFD_DIR1, path);
142 		if (ufd_mkdir(temp))
143 			return NULL;
144 		os_snprintf(temp, sizeof(temp), UFD_DIR2, path);
145 		if (ufd_mkdir(temp))
146 			return NULL;
147 	}
148 
149 	os_snprintf(temp, sizeof(temp), UFD_FILE, path, filename);
150 	if (write_f)
151 		ufd_fd = open(temp, O_WRONLY | O_CREAT | O_TRUNC,
152 			      S_IRUSR | S_IWUSR);
153 	else
154 		ufd_fd = open(temp, O_RDONLY);
155 	if (ufd_fd < 0) {
156 		wpa_printf(MSG_ERROR, "WPS (UFD): Failed to open %s: %s",
157 			   temp, strerror(errno));
158 		return NULL;
159 	}
160 
161 	data = os_zalloc(sizeof(*data));
162 	if (data == NULL) {
163 		close(ufd_fd);
164 		return NULL;
165 	}
166 	data->ufd_fd = ufd_fd;
167 	return data;
168 }
169 
170 
read_ufd(void * priv)171 static struct wpabuf * read_ufd(void *priv)
172 {
173 	struct wps_ufd_data *data = priv;
174 	struct wpabuf *buf;
175 	struct stat s;
176 	size_t file_size;
177 
178 	if (fstat(data->ufd_fd, &s) < 0) {
179 		wpa_printf(MSG_ERROR, "WPS (UFD): Failed to get file size");
180 		return NULL;
181 	}
182 
183 	file_size = s.st_size;
184 	buf = wpabuf_alloc(file_size);
185 	if (buf == NULL) {
186 		wpa_printf(MSG_ERROR, "WPS (UFD): Failed to alloc read "
187 			   "buffer");
188 		return NULL;
189 	}
190 
191 	if (read(data->ufd_fd, wpabuf_mhead(buf), file_size) !=
192 	    (int) file_size) {
193 		wpabuf_free(buf);
194 		wpa_printf(MSG_ERROR, "WPS (UFD): Failed to read");
195 		return NULL;
196 	}
197 	wpabuf_put(buf, file_size);
198 	return buf;
199 }
200 
201 
write_ufd(void * priv,struct wpabuf * buf)202 static int write_ufd(void *priv, struct wpabuf *buf)
203 {
204 	struct wps_ufd_data *data = priv;
205 
206 	if (write(data->ufd_fd, wpabuf_mhead(buf), wpabuf_len(buf)) !=
207 	    (int) wpabuf_len(buf)) {
208 		wpa_printf(MSG_ERROR, "WPS (UFD): Failed to write");
209 		return -1;
210 	}
211 	return 0;
212 }
213 
214 
deinit_ufd(void * priv)215 static void deinit_ufd(void *priv)
216 {
217 	struct wps_ufd_data *data = priv;
218 	close(data->ufd_fd);
219 	os_free(data);
220 }
221 
222 
223 struct oob_device_data oob_ufd_device_data = {
224 	.device_name	= NULL,
225 	.device_path	= NULL,
226 	.init_func	= init_ufd,
227 	.read_func	= read_ufd,
228 	.write_func	= write_ufd,
229 	.deinit_func	= deinit_ufd,
230 };
231