1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 /*
3 * Identifies FIDO CTAP1 ("U2F")/CTAP2 security tokens based on the usage declared in their report
4 * descriptor and outputs suitable environment variables.
5 *
6 * Inspired by Andrew Lutomirski's 'u2f-hidraw-policy.c'
7 */
8
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <linux/hid.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <sys/types.h>
15 #include <unistd.h>
16
17 #include "device-private.h"
18 #include "device-util.h"
19 #include "fd-util.h"
20 #include "fido_id_desc.h"
21 #include "log.h"
22 #include "macro.h"
23 #include "main-func.h"
24 #include "path-util.h"
25 #include "string-util.h"
26 #include "udev-util.h"
27
run(int argc,char ** argv)28 static int run(int argc, char **argv) {
29 _cleanup_(sd_device_unrefp) struct sd_device *device = NULL;
30 _cleanup_free_ char *desc_path = NULL;
31 _cleanup_close_ int fd = -1;
32
33 struct sd_device *hid_device;
34 const char *sys_path;
35 uint8_t desc[HID_MAX_DESCRIPTOR_SIZE];
36 ssize_t desc_len;
37
38 int r;
39
40 log_set_target(LOG_TARGET_AUTO);
41 udev_parse_config();
42 log_parse_environment();
43 log_open();
44
45 if (argc > 2)
46 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Usage: %s [SYSFS_PATH]", program_invocation_short_name);
47
48 if (argc == 1) {
49 r = device_new_from_strv(&device, environ);
50 if (r < 0)
51 return log_error_errno(r, "Failed to get current device from environment: %m");
52 } else {
53 r = sd_device_new_from_syspath(&device, argv[1]);
54 if (r < 0)
55 return log_error_errno(r, "Failed to get device from syspath: %m");
56 }
57
58 r = sd_device_get_parent(device, &hid_device);
59 if (r < 0)
60 return log_device_error_errno(device, r, "Failed to get parent HID device: %m");
61
62 r = sd_device_get_syspath(hid_device, &sys_path);
63 if (r < 0)
64 return log_device_error_errno(hid_device, r, "Failed to get syspath for HID device: %m");
65
66 desc_path = path_join(sys_path, "report_descriptor");
67 if (!desc_path)
68 return log_oom();
69
70 fd = open(desc_path, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
71 if (fd < 0)
72 return log_device_error_errno(hid_device, errno,
73 "Failed to open report descriptor at '%s': %m", desc_path);
74
75 desc_len = read(fd, desc, sizeof(desc));
76 if (desc_len < 0)
77 return log_device_error_errno(hid_device, errno,
78 "Failed to read report descriptor at '%s': %m", desc_path);
79 if (desc_len == 0)
80 return log_device_debug_errno(hid_device, SYNTHETIC_ERRNO(EINVAL),
81 "Empty report descriptor at '%s'.", desc_path);
82
83 r = is_fido_security_token_desc(desc, desc_len);
84 if (r < 0)
85 return log_device_debug_errno(hid_device, r,
86 "Failed to parse report descriptor at '%s'.", desc_path);
87 if (r > 0) {
88 printf("ID_FIDO_TOKEN=1\n");
89 printf("ID_SECURITY_TOKEN=1\n");
90 }
91
92 return 0;
93 }
94
95 DEFINE_MAIN_FUNCTION(run);
96