]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/udev/fido_id/fido_id.c
license: LGPL-2.1+ -> LGPL-2.1-or-later
[thirdparty/systemd.git] / src / udev / fido_id / fido_id.c
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-internal.h"
18 #include "device-private.h"
19 #include "device-util.h"
20 #include "fd-util.h"
21 #include "fido_id_desc.h"
22 #include "log.h"
23 #include "macro.h"
24 #include "main-func.h"
25 #include "path-util.h"
26 #include "string-util.h"
27 #include "udev-util.h"
28
29 static int run(int argc, char **argv) {
30 _cleanup_(sd_device_unrefp) struct sd_device *device = NULL;
31 _cleanup_free_ char *desc_path = NULL;
32 _cleanup_close_ int fd = -1;
33
34 struct sd_device *hid_device;
35 const char *sys_path;
36 uint8_t desc[HID_MAX_DESCRIPTOR_SIZE];
37 ssize_t desc_len;
38
39 int r;
40
41 log_set_target(LOG_TARGET_AUTO);
42 udev_parse_config();
43 log_parse_environment();
44 log_open();
45
46 if (argc > 2)
47 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Usage: %s [SYSFS_PATH]", program_invocation_short_name);
48
49 if (argc == 1) {
50 r = device_new_from_strv(&device, environ);
51 if (r < 0)
52 return log_error_errno(r, "Failed to get current device from environment: %m");
53 } else {
54 r = sd_device_new_from_syspath(&device, argv[1]);
55 if (r < 0)
56 return log_error_errno(r, "Failed to get device from syspath: %m");
57 }
58
59 r = sd_device_get_parent(device, &hid_device);
60 if (r < 0)
61 return log_device_error_errno(device, r, "Failed to get parent HID device: %m");
62
63 r = sd_device_get_syspath(hid_device, &sys_path);
64 if (r < 0)
65 return log_device_error_errno(hid_device, r, "Failed to get syspath for HID device: %m");
66
67 desc_path = path_join(sys_path, "report_descriptor");
68 if (!desc_path)
69 return log_oom();
70
71 fd = open(desc_path, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
72 if (fd < 0)
73 return log_device_error_errno(hid_device, errno,
74 "Failed to open report descriptor at '%s': %m", desc_path);
75
76 desc_len = read(fd, desc, sizeof(desc));
77 if (desc_len < 0)
78 return log_device_error_errno(hid_device, errno,
79 "Failed to read report descriptor at '%s': %m", desc_path);
80 if (desc_len == 0)
81 return log_device_debug_errno(hid_device, SYNTHETIC_ERRNO(EINVAL),
82 "Empty report descriptor at '%s'.", desc_path);
83
84 r = is_fido_security_token_desc(desc, desc_len);
85 if (r < 0)
86 return log_device_debug_errno(hid_device, r,
87 "Failed to parse report descriptor at '%s'.", desc_path);
88 if (r > 0) {
89 printf("ID_FIDO_TOKEN=1\n");
90 printf("ID_SECURITY_TOKEN=1\n");
91 }
92
93 return 0;
94 }
95
96 DEFINE_MAIN_FUNCTION(run);