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