Home | History | Annotate | Download | only in wps
      1 /*
      2  * UFD routines for Wi-Fi Protected Setup
      3  * Copyright (c) 2009-2012, Masashi Honma <masashi.honma (at) 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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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