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