1 /* 2 * Copyright (c) 2019-2022 Yubico AB. All rights reserved. 3 * Use of this source code is governed by a BSD-style 4 * license that can be found in the LICENSE file. 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8 #include <sys/types.h> 9 #include <sys/file.h> 10 #include <sys/ioctl.h> 11 12 #include <linux/hidraw.h> 13 #include <linux/input.h> 14 15 #include <errno.h> 16 #include <libudev.h> 17 #include <time.h> 18 #include <unistd.h> 19 20 #include "fido.h" 21 22 struct hid_linux { 23 int fd; 24 size_t report_in_len; 25 size_t report_out_len; 26 sigset_t sigmask; 27 const sigset_t *sigmaskp; 28 }; 29 30 static int 31 get_report_descriptor(int fd, struct hidraw_report_descriptor *hrd) 32 { 33 int s = -1; 34 35 if (ioctl(fd, IOCTL_REQ(HIDIOCGRDESCSIZE), &s) == -1) { 36 fido_log_error(errno, "%s: ioctl HIDIOCGRDESCSIZE", __func__); 37 return (-1); 38 } 39 40 if (s < 0 || (unsigned)s > HID_MAX_DESCRIPTOR_SIZE) { 41 fido_log_debug("%s: HIDIOCGRDESCSIZE %d", __func__, s); 42 return (-1); 43 } 44 45 hrd->size = (unsigned)s; 46 47 if (ioctl(fd, IOCTL_REQ(HIDIOCGRDESC), hrd) == -1) { 48 fido_log_error(errno, "%s: ioctl HIDIOCGRDESC", __func__); 49 return (-1); 50 } 51 52 return (0); 53 } 54 55 static bool 56 is_fido(const char *path) 57 { 58 int fd = -1; 59 uint32_t usage_page = 0; 60 struct hidraw_report_descriptor *hrd = NULL; 61 62 if ((hrd = calloc(1, sizeof(*hrd))) == NULL || 63 (fd = fido_hid_unix_open(path)) == -1) 64 goto out; 65 if (get_report_descriptor(fd, hrd) < 0 || 66 fido_hid_get_usage(hrd->value, hrd->size, &usage_page) < 0) 67 usage_page = 0; 68 69 out: 70 free(hrd); 71 72 if (fd != -1 && close(fd) == -1) 73 fido_log_error(errno, "%s: close", __func__); 74 75 return (usage_page == 0xf1d0); 76 } 77 78 static int 79 parse_uevent(const char *uevent, int *bus, int16_t *vendor_id, 80 int16_t *product_id) 81 { 82 char *cp; 83 char *p; 84 char *s; 85 int ok = -1; 86 short unsigned int x; 87 short unsigned int y; 88 short unsigned int z; 89 90 if ((s = cp = strdup(uevent)) == NULL) 91 return (-1); 92 93 while ((p = strsep(&cp, "\n")) != NULL && *p != '\0') { 94 if (strncmp(p, "HID_ID=", 7) == 0) { 95 if (sscanf(p + 7, "%hx:%hx:%hx", &x, &y, &z) == 3) { 96 *bus = (int)x; 97 *vendor_id = (int16_t)y; 98 *product_id = (int16_t)z; 99 ok = 0; 100 break; 101 } 102 } 103 } 104 105 free(s); 106 107 return (ok); 108 } 109 110 static char * 111 get_parent_attr(struct udev_device *dev, const char *subsystem, 112 const char *devtype, const char *attr) 113 { 114 struct udev_device *parent; 115 const char *value; 116 117 if ((parent = udev_device_get_parent_with_subsystem_devtype(dev, 118 subsystem, devtype)) == NULL || (value = 119 udev_device_get_sysattr_value(parent, attr)) == NULL) 120 return (NULL); 121 122 return (strdup(value)); 123 } 124 125 static char * 126 get_usb_attr(struct udev_device *dev, const char *attr) 127 { 128 return (get_parent_attr(dev, "usb", "usb_device", attr)); 129 } 130 131 static int 132 copy_info(fido_dev_info_t *di, struct udev *udev, 133 struct udev_list_entry *udev_entry) 134 { 135 const char *name; 136 const char *path; 137 char *uevent = NULL; 138 struct udev_device *dev = NULL; 139 int bus = 0; 140 int ok = -1; 141 142 memset(di, 0, sizeof(*di)); 143 144 if ((name = udev_list_entry_get_name(udev_entry)) == NULL || 145 (dev = udev_device_new_from_syspath(udev, name)) == NULL || 146 (path = udev_device_get_devnode(dev)) == NULL || 147 is_fido(path) == 0) 148 goto fail; 149 150 if ((uevent = get_parent_attr(dev, "hid", NULL, "uevent")) == NULL || 151 parse_uevent(uevent, &bus, &di->vendor_id, &di->product_id) < 0) { 152 fido_log_debug("%s: uevent", __func__); 153 goto fail; 154 } 155 156 #ifndef FIDO_HID_ANY 157 if (bus != BUS_USB) { 158 fido_log_debug("%s: bus", __func__); 159 goto fail; 160 } 161 #endif 162 163 di->path = strdup(path); 164 if ((di->manufacturer = get_usb_attr(dev, "manufacturer")) == NULL) 165 di->manufacturer = strdup(""); 166 if ((di->product = get_usb_attr(dev, "product")) == NULL) 167 di->product = strdup(""); 168 if (di->path == NULL || di->manufacturer == NULL || di->product == NULL) 169 goto fail; 170 171 ok = 0; 172 fail: 173 if (dev != NULL) 174 udev_device_unref(dev); 175 176 free(uevent); 177 178 if (ok < 0) { 179 free(di->path); 180 free(di->manufacturer); 181 free(di->product); 182 explicit_bzero(di, sizeof(*di)); 183 } 184 185 return (ok); 186 } 187 188 int 189 fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) 190 { 191 struct udev *udev = NULL; 192 struct udev_enumerate *udev_enum = NULL; 193 struct udev_list_entry *udev_list; 194 struct udev_list_entry *udev_entry; 195 int r = FIDO_ERR_INTERNAL; 196 197 *olen = 0; 198 199 if (ilen == 0) 200 return (FIDO_OK); /* nothing to do */ 201 202 if (devlist == NULL) 203 return (FIDO_ERR_INVALID_ARGUMENT); 204 205 if ((udev = udev_new()) == NULL || 206 (udev_enum = udev_enumerate_new(udev)) == NULL) 207 goto fail; 208 209 if (udev_enumerate_add_match_subsystem(udev_enum, "hidraw") < 0 || 210 udev_enumerate_scan_devices(udev_enum) < 0) 211 goto fail; 212 213 if ((udev_list = udev_enumerate_get_list_entry(udev_enum)) == NULL) { 214 r = FIDO_OK; /* zero hidraw devices */ 215 goto fail; 216 } 217 218 udev_list_entry_foreach(udev_entry, udev_list) { 219 if (copy_info(&devlist[*olen], udev, udev_entry) == 0) { 220 devlist[*olen].io = (fido_dev_io_t) { 221 fido_hid_open, 222 fido_hid_close, 223 fido_hid_read, 224 fido_hid_write, 225 }; 226 if (++(*olen) == ilen) 227 break; 228 } 229 } 230 231 r = FIDO_OK; 232 fail: 233 if (udev_enum != NULL) 234 udev_enumerate_unref(udev_enum); 235 if (udev != NULL) 236 udev_unref(udev); 237 238 return (r); 239 } 240 241 void * 242 fido_hid_open(const char *path) 243 { 244 struct hid_linux *ctx; 245 struct hidraw_report_descriptor *hrd; 246 struct timespec tv_pause; 247 long interval_ms, retries = 0; 248 bool looped; 249 250 retry: 251 looped = false; 252 253 if ((ctx = calloc(1, sizeof(*ctx))) == NULL || 254 (ctx->fd = fido_hid_unix_open(path)) == -1) { 255 free(ctx); 256 return (NULL); 257 } 258 259 while (flock(ctx->fd, LOCK_EX|LOCK_NB) == -1) { 260 if (errno != EWOULDBLOCK) { 261 fido_log_error(errno, "%s: flock", __func__); 262 fido_hid_close(ctx); 263 return (NULL); 264 } 265 looped = true; 266 if (retries++ >= 20) { 267 fido_log_debug("%s: flock timeout", __func__); 268 fido_hid_close(ctx); 269 return (NULL); 270 } 271 interval_ms = retries * 100000000L; 272 tv_pause.tv_sec = interval_ms / 1000000000L; 273 tv_pause.tv_nsec = interval_ms % 1000000000L; 274 if (nanosleep(&tv_pause, NULL) == -1) { 275 fido_log_error(errno, "%s: nanosleep", __func__); 276 fido_hid_close(ctx); 277 return (NULL); 278 } 279 } 280 281 if (looped) { 282 fido_log_debug("%s: retrying", __func__); 283 fido_hid_close(ctx); 284 goto retry; 285 } 286 287 if ((hrd = calloc(1, sizeof(*hrd))) == NULL || 288 get_report_descriptor(ctx->fd, hrd) < 0 || 289 fido_hid_get_report_len(hrd->value, hrd->size, &ctx->report_in_len, 290 &ctx->report_out_len) < 0 || ctx->report_in_len == 0 || 291 ctx->report_out_len == 0) { 292 fido_log_debug("%s: using default report sizes", __func__); 293 ctx->report_in_len = CTAP_MAX_REPORT_LEN; 294 ctx->report_out_len = CTAP_MAX_REPORT_LEN; 295 } 296 297 free(hrd); 298 299 return (ctx); 300 } 301 302 void 303 fido_hid_close(void *handle) 304 { 305 struct hid_linux *ctx = handle; 306 307 if (close(ctx->fd) == -1) 308 fido_log_error(errno, "%s: close", __func__); 309 310 free(ctx); 311 } 312 313 int 314 fido_hid_set_sigmask(void *handle, const fido_sigset_t *sigmask) 315 { 316 struct hid_linux *ctx = handle; 317 318 ctx->sigmask = *sigmask; 319 ctx->sigmaskp = &ctx->sigmask; 320 321 return (FIDO_OK); 322 } 323 324 int 325 fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms) 326 { 327 struct hid_linux *ctx = handle; 328 ssize_t r; 329 330 if (len != ctx->report_in_len) { 331 fido_log_debug("%s: len %zu", __func__, len); 332 return (-1); 333 } 334 335 if (fido_hid_unix_wait(ctx->fd, ms, ctx->sigmaskp) < 0) { 336 fido_log_debug("%s: fd not ready", __func__); 337 return (-1); 338 } 339 340 if ((r = read(ctx->fd, buf, len)) == -1) { 341 fido_log_error(errno, "%s: read", __func__); 342 return (-1); 343 } 344 345 if (r < 0 || (size_t)r != len) { 346 fido_log_debug("%s: %zd != %zu", __func__, r, len); 347 return (-1); 348 } 349 350 return ((int)r); 351 } 352 353 int 354 fido_hid_write(void *handle, const unsigned char *buf, size_t len) 355 { 356 struct hid_linux *ctx = handle; 357 ssize_t r; 358 359 if (len != ctx->report_out_len + 1) { 360 fido_log_debug("%s: len %zu", __func__, len); 361 return (-1); 362 } 363 364 if ((r = write(ctx->fd, buf, len)) == -1) { 365 fido_log_error(errno, "%s: write", __func__); 366 return (-1); 367 } 368 369 if (r < 0 || (size_t)r != len) { 370 fido_log_debug("%s: %zd != %zu", __func__, r, len); 371 return (-1); 372 } 373 374 return ((int)r); 375 } 376 377 size_t 378 fido_hid_report_in_len(void *handle) 379 { 380 struct hid_linux *ctx = handle; 381 382 return (ctx->report_in_len); 383 } 384 385 size_t 386 fido_hid_report_out_len(void *handle) 387 { 388 struct hid_linux *ctx = handle; 389 390 return (ctx->report_out_len); 391 } 392