diff options
Diffstat (limited to 'third_party/rust/authenticator/src/transport/linux/hidraw.rs')
-rw-r--r-- | third_party/rust/authenticator/src/transport/linux/hidraw.rs | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/third_party/rust/authenticator/src/transport/linux/hidraw.rs b/third_party/rust/authenticator/src/transport/linux/hidraw.rs new file mode 100644 index 0000000000..16d687f358 --- /dev/null +++ b/third_party/rust/authenticator/src/transport/linux/hidraw.rs @@ -0,0 +1,80 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#![cfg_attr(feature = "cargo-clippy", allow(clippy::cast_lossless))] + +extern crate libc; + +use std::io; +use std::os::unix::io::RawFd; + +use super::hidwrapper::{_HIDIOCGRDESC, _HIDIOCGRDESCSIZE}; +use crate::consts::MAX_HID_RPT_SIZE; +use crate::transport::hidproto::*; +use crate::util::{from_unix_result, io_err}; + +#[allow(non_camel_case_types)] +#[repr(C)] +pub struct LinuxReportDescriptor { + size: ::libc::c_int, + value: [u8; 4096], +} + +const HID_MAX_DESCRIPTOR_SIZE: usize = 4096; + +#[cfg(not(target_env = "musl"))] +type IocType = libc::c_ulong; +#[cfg(target_env = "musl")] +type IocType = libc::c_int; + +pub unsafe fn hidiocgrdescsize( + fd: libc::c_int, + val: *mut ::libc::c_int, +) -> io::Result<libc::c_int> { + from_unix_result(libc::ioctl(fd, _HIDIOCGRDESCSIZE as IocType, val)) +} + +pub unsafe fn hidiocgrdesc( + fd: libc::c_int, + val: *mut LinuxReportDescriptor, +) -> io::Result<libc::c_int> { + from_unix_result(libc::ioctl(fd, _HIDIOCGRDESC as IocType, val)) +} + +pub fn is_u2f_device(fd: RawFd) -> bool { + match read_report_descriptor(fd) { + Ok(desc) => has_fido_usage(desc), + Err(_) => false, // Upon failure, just say it's not a U2F device. + } +} + +pub fn read_hid_rpt_sizes_or_defaults(fd: RawFd) -> (usize, usize) { + let default_rpt_sizes = (MAX_HID_RPT_SIZE, MAX_HID_RPT_SIZE); + let desc = read_report_descriptor(fd); + if let Ok(desc) = desc { + if let Ok(rpt_sizes) = read_hid_rpt_sizes(desc) { + rpt_sizes + } else { + default_rpt_sizes + } + } else { + default_rpt_sizes + } +} + +fn read_report_descriptor(fd: RawFd) -> io::Result<ReportDescriptor> { + let mut desc = LinuxReportDescriptor { + size: 0, + value: [0; HID_MAX_DESCRIPTOR_SIZE], + }; + + let _ = unsafe { hidiocgrdescsize(fd, &mut desc.size)? }; + if desc.size == 0 || desc.size as usize > desc.value.len() { + return Err(io_err("unexpected hidiocgrdescsize() result")); + } + + let _ = unsafe { hidiocgrdesc(fd, &mut desc)? }; + let mut value = Vec::from(&desc.value[..]); + value.truncate(desc.size as usize); + Ok(ReportDescriptor { value }) +} |