2009-02-26 20:57:38 +01:00
|
|
|
/*
|
|
|
|
* UFD routines for Wi-Fi Protected Setup
|
|
|
|
* Copyright (c) 2009, Masashi Honma <honma@ictec.co.jp>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* Alternatively, this software may be distributed under the terms of BSD
|
|
|
|
* license.
|
|
|
|
*
|
|
|
|
* See README and COPYING for more details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "includes.h"
|
|
|
|
#include "common.h"
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
|
|
|
|
#include "wps/wps.h"
|
|
|
|
|
2009-02-26 21:05:39 +01:00
|
|
|
#ifdef CONFIG_NATIVE_WINDOWS
|
|
|
|
#define UFD_DIR1 "%s\\SMRTNTKY"
|
|
|
|
#define UFD_DIR2 UFD_DIR1 "\\WFAWSC"
|
|
|
|
#define UFD_FILE UFD_DIR2 "\\%s"
|
|
|
|
#else /* CONFIG_NATIVE_WINDOWS */
|
|
|
|
#define UFD_DIR1 "%s/SMRTNTKY"
|
|
|
|
#define UFD_DIR2 UFD_DIR1 "/WFAWSC"
|
|
|
|
#define UFD_FILE UFD_DIR2 "/%s"
|
|
|
|
#endif /* CONFIG_NATIVE_WINDOWS */
|
|
|
|
|
|
|
|
|
2009-02-26 21:04:49 +01:00
|
|
|
struct wps_ufd_data {
|
|
|
|
int ufd_fd;
|
|
|
|
};
|
2009-02-26 20:57:38 +01:00
|
|
|
|
|
|
|
|
|
|
|
static int dev_pwd_e_file_filter(const struct dirent *entry)
|
|
|
|
{
|
|
|
|
unsigned int prefix;
|
|
|
|
char ext[5];
|
|
|
|
|
|
|
|
if (sscanf(entry->d_name, "%8x.%4s", &prefix, ext) != 2)
|
|
|
|
return 0;
|
|
|
|
if (prefix == 0)
|
|
|
|
return 0;
|
|
|
|
if (os_strcasecmp(ext, "WFA") != 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int wps_get_dev_pwd_e_file_name(char *path, char *file_name)
|
|
|
|
{
|
|
|
|
struct dirent **namelist;
|
|
|
|
int i, file_num;
|
|
|
|
|
|
|
|
file_num = scandir(path, &namelist, &dev_pwd_e_file_filter,
|
|
|
|
alphasort);
|
2009-02-26 21:06:11 +01:00
|
|
|
if (file_num < 0) {
|
|
|
|
wpa_printf(MSG_ERROR, "WPS: OOB file not found: %d (%s)",
|
|
|
|
errno, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (file_num == 0) {
|
2009-02-26 20:57:38 +01:00
|
|
|
wpa_printf(MSG_ERROR, "WPS: OOB file not found");
|
2009-02-26 21:06:11 +01:00
|
|
|
os_free(namelist);
|
2009-02-26 20:57:38 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
os_strlcpy(file_name, namelist[0]->d_name, 13);
|
|
|
|
for (i = 0; i < file_num; i++)
|
|
|
|
os_free(namelist[i]);
|
|
|
|
os_free(namelist);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int get_file_name(struct wps_context *wps, int registrar,
|
2009-02-26 21:07:55 +01:00
|
|
|
const char *path, char *file_name)
|
2009-02-26 20:57:38 +01:00
|
|
|
{
|
|
|
|
switch (wps->oob_conf.oob_method) {
|
|
|
|
case OOB_METHOD_CRED:
|
|
|
|
os_snprintf(file_name, 13, "00000000.WSC");
|
|
|
|
break;
|
|
|
|
case OOB_METHOD_DEV_PWD_E:
|
|
|
|
if (registrar) {
|
|
|
|
char temp[128];
|
2009-02-26 21:07:55 +01:00
|
|
|
os_snprintf(temp, sizeof(temp), UFD_DIR2, path);
|
2009-02-26 20:57:38 +01:00
|
|
|
if (wps_get_dev_pwd_e_file_name(temp, file_name) < 0)
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
u8 *mac_addr = wps->dev.mac_addr;
|
|
|
|
|
|
|
|
os_snprintf(file_name, 13, "%02X%02X%02X%02X.WFA",
|
|
|
|
mac_addr[2], mac_addr[3], mac_addr[4],
|
|
|
|
mac_addr[5]);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case OOB_METHOD_DEV_PWD_R:
|
|
|
|
os_snprintf(file_name, 13, "00000000.WFA");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
wpa_printf(MSG_ERROR, "WPS: Invalid USBA OOB method");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-02-26 21:00:29 +01:00
|
|
|
static int ufd_mkdir(const char *path)
|
|
|
|
{
|
|
|
|
if (mkdir(path, S_IRWXU) < 0 && errno != EEXIST) {
|
|
|
|
wpa_printf(MSG_ERROR, "WPS (UFD): Failed to create directory "
|
|
|
|
"'%s': %d (%s)", path, errno, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-02-26 21:07:55 +01:00
|
|
|
static void * init_ufd(struct wps_context *wps,
|
|
|
|
struct oob_device_data *oob_dev, int registrar)
|
2009-02-26 20:57:38 +01:00
|
|
|
{
|
|
|
|
int write_f;
|
|
|
|
char temp[128];
|
2009-02-26 21:07:55 +01:00
|
|
|
char *path = oob_dev->device_path;
|
2009-02-26 20:57:38 +01:00
|
|
|
char filename[13];
|
2009-02-26 21:04:49 +01:00
|
|
|
struct wps_ufd_data *data;
|
|
|
|
int ufd_fd;
|
|
|
|
|
|
|
|
if (path == NULL)
|
|
|
|
return NULL;
|
2009-02-26 20:57:38 +01:00
|
|
|
|
|
|
|
write_f = wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E ?
|
|
|
|
!registrar : registrar;
|
|
|
|
|
2009-02-26 21:07:55 +01:00
|
|
|
if (get_file_name(wps, registrar, path, filename) < 0) {
|
2009-02-26 20:57:38 +01:00
|
|
|
wpa_printf(MSG_ERROR, "WPS (UFD): Failed to get file name");
|
2009-02-26 21:04:49 +01:00
|
|
|
return NULL;
|
2009-02-26 20:57:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (write_f) {
|
2009-02-26 21:05:39 +01:00
|
|
|
os_snprintf(temp, sizeof(temp), UFD_DIR1, path);
|
2009-02-26 21:00:29 +01:00
|
|
|
if (ufd_mkdir(temp))
|
2009-02-26 21:04:49 +01:00
|
|
|
return NULL;
|
2009-02-26 21:05:39 +01:00
|
|
|
os_snprintf(temp, sizeof(temp), UFD_DIR2, path);
|
2009-02-26 21:00:29 +01:00
|
|
|
if (ufd_mkdir(temp))
|
2009-02-26 21:04:49 +01:00
|
|
|
return NULL;
|
2009-02-26 20:57:38 +01:00
|
|
|
}
|
|
|
|
|
2009-02-26 21:05:39 +01:00
|
|
|
os_snprintf(temp, sizeof(temp), UFD_FILE, path, filename);
|
2009-02-26 20:57:38 +01:00
|
|
|
if (write_f)
|
|
|
|
ufd_fd = open(temp, O_WRONLY | O_CREAT | O_TRUNC,
|
|
|
|
S_IRUSR | S_IWUSR);
|
|
|
|
else
|
|
|
|
ufd_fd = open(temp, O_RDONLY);
|
|
|
|
if (ufd_fd < 0) {
|
|
|
|
wpa_printf(MSG_ERROR, "WPS (UFD): Failed to open %s: %s",
|
|
|
|
temp, strerror(errno));
|
2009-02-26 21:04:49 +01:00
|
|
|
return NULL;
|
2009-02-26 20:57:38 +01:00
|
|
|
}
|
|
|
|
|
2009-02-26 21:04:49 +01:00
|
|
|
data = os_zalloc(sizeof(*data));
|
|
|
|
if (data == NULL)
|
|
|
|
return NULL;
|
|
|
|
data->ufd_fd = ufd_fd;
|
|
|
|
return data;
|
2009-02-26 20:57:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-02-26 21:04:49 +01:00
|
|
|
static struct wpabuf * read_ufd(void *priv)
|
2009-02-26 20:57:38 +01:00
|
|
|
{
|
2009-02-26 21:04:49 +01:00
|
|
|
struct wps_ufd_data *data = priv;
|
2009-02-26 20:57:38 +01:00
|
|
|
struct wpabuf *buf;
|
|
|
|
struct stat s;
|
|
|
|
size_t file_size;
|
|
|
|
|
2009-02-26 21:04:49 +01:00
|
|
|
if (fstat(data->ufd_fd, &s) < 0) {
|
2009-02-26 20:57:38 +01:00
|
|
|
wpa_printf(MSG_ERROR, "WPS (UFD): Failed to get file size");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
file_size = s.st_size;
|
|
|
|
buf = wpabuf_alloc(file_size);
|
|
|
|
if (buf == NULL) {
|
|
|
|
wpa_printf(MSG_ERROR, "WPS (UFD): Failed to alloc read "
|
|
|
|
"buffer");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-02-26 21:04:49 +01:00
|
|
|
if (read(data->ufd_fd, wpabuf_mhead(buf), file_size) !=
|
|
|
|
(int) file_size) {
|
2009-02-26 20:57:38 +01:00
|
|
|
wpabuf_free(buf);
|
|
|
|
wpa_printf(MSG_ERROR, "WPS (UFD): Failed to read");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
wpabuf_put(buf, file_size);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-02-26 21:04:49 +01:00
|
|
|
static int write_ufd(void *priv, struct wpabuf *buf)
|
2009-02-26 20:57:38 +01:00
|
|
|
{
|
2009-02-26 21:04:49 +01:00
|
|
|
struct wps_ufd_data *data = priv;
|
|
|
|
|
|
|
|
if (write(data->ufd_fd, wpabuf_mhead(buf), wpabuf_len(buf)) !=
|
2009-02-26 20:57:38 +01:00
|
|
|
(int) wpabuf_len(buf)) {
|
|
|
|
wpa_printf(MSG_ERROR, "WPS (UFD): Failed to write");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-02-26 21:04:49 +01:00
|
|
|
static void deinit_ufd(void *priv)
|
2009-02-26 20:57:38 +01:00
|
|
|
{
|
2009-02-26 21:04:49 +01:00
|
|
|
struct wps_ufd_data *data = priv;
|
|
|
|
close(data->ufd_fd);
|
|
|
|
os_free(data);
|
2009-02-26 20:57:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct oob_device_data oob_ufd_device_data = {
|
2009-03-06 15:16:22 +01:00
|
|
|
.device_name = NULL,
|
2009-02-26 20:57:38 +01:00
|
|
|
.device_path = NULL,
|
|
|
|
.init_func = init_ufd,
|
|
|
|
.read_func = read_ufd,
|
|
|
|
.write_func = write_ufd,
|
|
|
|
.deinit_func = deinit_ufd,
|
|
|
|
};
|