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