So far, hidraw_id detects U2F tokens and sets: ID_U2F_TOKEN=1 ID_SECURITY_TOKEN=1
This causes the uaccess rules to apply to U2F devices. --- I've never written any udev code before. Feedback welcome. If you think this doesn't belong in udev, I can try to find it another home. .gitignore | 1 + Makefile.am | 11 ++++ rules/60-hidraw.rules | 7 ++ src/udev/hidraw_id/Makefile | 1 + src/udev/hidraw_id/hidraw_id.c | 144 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 164 insertions(+) create mode 100644 rules/60-hidraw.rules create mode 120000 src/udev/hidraw_id/Makefile create mode 100644 src/udev/hidraw_id/hidraw_id.c diff --git a/.gitignore b/.gitignore index f119b574c777..4bd3cdf08f0d 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,7 @@ /exported /exported-* /gtk-doc.make +/hidraw_id /hostnamectl /install-tree /journalctl diff --git a/Makefile.am b/Makefile.am index fae946a388af..9f64687d32b1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3542,6 +3542,17 @@ udevlibexec_PROGRAMS += \ ata_id # ------------------------------------------------------------------------------ +hidraw_id_SOURCES = \ + src/udev/hidraw_id/hidraw_id.c + +hidraw_id_LDADD = \ + libudev-internal.la \ + libsystemd-shared.la + +udevlibexec_PROGRAMS += \ + hidraw_id + +# ------------------------------------------------------------------------------ cdrom_id_SOURCES = \ src/udev/cdrom_id/cdrom_id.c diff --git a/rules/60-hidraw.rules b/rules/60-hidraw.rules new file mode 100644 index 000000000000..1ee9c812f711 --- /dev/null +++ b/rules/60-hidraw.rules @@ -0,0 +1,7 @@ +# do not edit this file, it will be overwritten on update + +ACTION=="remove", GOTO="hidraw_end" + +SUBSYSTEM=="hidraw", IMPORT{program}="hidraw_id --udev" + +LABEL="keyboard_end" diff --git a/src/udev/hidraw_id/Makefile b/src/udev/hidraw_id/Makefile new file mode 120000 index 000000000000..d0b0e8e0086f --- /dev/null +++ b/src/udev/hidraw_id/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/udev/hidraw_id/hidraw_id.c b/src/udev/hidraw_id/hidraw_id.c new file mode 100644 index 000000000000..e32f222f22f9 --- /dev/null +++ b/src/udev/hidraw_id/hidraw_id.c @@ -0,0 +1,144 @@ +/* + * Copyright (c) Andrew Lutomirski, 2014 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include "libudev.h" +#include "libudev-private.h" + +_printf_(6,0) +static void log_fn(struct udev *udev, int priority, + const char *file, int line, const char *fn, + const char *format, va_list args) +{ + log_metav(priority, file, line, fn, format, args); +} + +int main(int argc, char **argv) +{ + struct udev *udev; + struct udev_device *dev, *hiddev; + char path[4096]; + unsigned char desc[4096]; + int desclen; + int fd = -1; + int i; + int ret = 1; + unsigned int usage_page = 0; + int is_u2f_token = 0; + + if (argc != 2) { + fprintf(stderr, "Usage: hidraw_id SYSFS_PATH|--udev\n"); + return 1; + } + + log_parse_environment(); + log_open(); + + udev = udev_new(); + + udev_set_log_fn(udev, log_fn); + + if (!strcmp(argv[1], "--udev")) + dev = udev_device_new_from_environment(udev); + else + dev = udev_device_new_from_syspath(udev, argv[1]); + + if (!dev) + goto out; + + hiddev = udev_device_get_parent(dev); + if (!hiddev) + goto out; + + if (snprintf(path, sizeof(path), "%s/report_descriptor", + udev_device_get_syspath(hiddev)) > (int)sizeof(path)) + return 1; + + fd = open(path, O_RDONLY | O_NOFOLLOW); + if (fd == -1) + goto out; + + desclen = read(fd, desc, sizeof(desc)); + if (desclen <= 0) + goto out; + + /* Parse the report descriptor. */ + for (i = 0; i < desclen; ) { + unsigned char tag = desc[i] >> 4; + unsigned char type = (desc[i] >> 2) & 0x3; + unsigned char sizecode = desc[i] & 0x3; + int size, j; + unsigned int value = 0; + + if (desc[i] == 0xfe) { + /* Long item; skip it. */ + if (i + 1 >= desclen) { + log_error("bad report_descriptor"); + goto out; + } + i += (desc[i+1] + 3); /* Can't overflow. */ + continue; + } + + size = (sizecode < 3 ? sizecode : 4); + if (i + 1 + size > desclen) { + log_error("bad report_descriptor"); + goto out; + } + + for (j = 0; j < size; j++) + value |= (desc[i + 1 + j] << 8*j); + + if (type == 1 && tag == 0) + usage_page = value; + + /* + * Detect U2F tokens. See: + * https://fidoalliance.org/specs/fido-u2f-HID-protocol-v1.0-rd-20141008.pdf + * http://www.usb.org/developers/hidpage/HUTRR48.pdf + */ + + if (type == 2 && tag == 0) { + if (usage_page == 0xf1d0 && value == 0x1) + is_u2f_token = 1; + } + + i += 1 + size; + } + + if (is_u2f_token) + printf("ID_U2F_TOKEN=1\nID_SECURITY_TOKEN=1\n"); + + ret = 0; + +out: + if (fd != -1) + close(fd); + if (dev) + udev_device_unref(dev); + udev_unref(udev); + + log_close(); + + return ret; +} -- 1.9.3 _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel