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