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