Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libfido2/examples/select.c
39536 views
1
/*
2
* Copyright (c) 2020-2022 Yubico AB. All rights reserved.
3
* Use of this source code is governed by a BSD-style
4
* license that can be found in the LICENSE file.
5
* SPDX-License-Identifier: BSD-2-Clause
6
*/
7
8
#include <errno.h>
9
#include <fido.h>
10
#include <stdio.h>
11
#include <stdlib.h>
12
#include <time.h>
13
14
#include "../openbsd-compat/openbsd-compat.h"
15
16
#define FIDO_POLL_MS 50
17
18
#if defined(_MSC_VER)
19
static int
20
nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
21
{
22
if (rmtp != NULL) {
23
errno = EINVAL;
24
return (-1);
25
}
26
27
Sleep((DWORD)(rqtp->tv_sec * 1000) + (DWORD)(rqtp->tv_nsec / 1000000));
28
29
return (0);
30
}
31
#endif
32
33
static fido_dev_t *
34
open_dev(const fido_dev_info_t *di)
35
{
36
fido_dev_t *dev;
37
int r;
38
39
if ((dev = fido_dev_new()) == NULL) {
40
warnx("%s: fido_dev_new", __func__);
41
return (NULL);
42
}
43
44
if ((r = fido_dev_open(dev, fido_dev_info_path(di))) != FIDO_OK) {
45
warnx("%s: fido_dev_open %s: %s", __func__,
46
fido_dev_info_path(di), fido_strerr(r));
47
fido_dev_free(&dev);
48
return (NULL);
49
}
50
51
printf("%s (0x%04x:0x%04x) is %s\n", fido_dev_info_path(di),
52
fido_dev_info_vendor(di), fido_dev_info_product(di),
53
fido_dev_is_fido2(dev) ? "fido2" : "u2f");
54
55
return (dev);
56
}
57
58
static int
59
select_dev(const fido_dev_info_t *devlist, size_t ndevs, fido_dev_t **dev,
60
size_t *idx, int secs)
61
{
62
const fido_dev_info_t *di;
63
fido_dev_t **devtab;
64
struct timespec ts_start;
65
struct timespec ts_now;
66
struct timespec ts_delta;
67
struct timespec ts_pause;
68
size_t nopen = 0;
69
int touched;
70
int r;
71
long ms_remain;
72
73
*dev = NULL;
74
*idx = 0;
75
76
printf("%u authenticator(s) detected\n", (unsigned)ndevs);
77
78
if (ndevs == 0)
79
return (0); /* nothing to do */
80
81
if ((devtab = calloc(ndevs, sizeof(*devtab))) == NULL) {
82
warn("%s: calloc", __func__);
83
return (-1);
84
}
85
86
for (size_t i = 0; i < ndevs; i++) {
87
di = fido_dev_info_ptr(devlist, i);
88
if ((devtab[i] = open_dev(di)) != NULL) {
89
*idx = i;
90
nopen++;
91
}
92
}
93
94
printf("%u authenticator(s) opened\n", (unsigned)nopen);
95
96
if (nopen < 2) {
97
if (nopen == 1)
98
*dev = devtab[*idx]; /* single candidate */
99
r = 0;
100
goto out;
101
}
102
103
for (size_t i = 0; i < ndevs; i++) {
104
di = fido_dev_info_ptr(devlist, i);
105
if (devtab[i] == NULL)
106
continue; /* failed to open */
107
if ((r = fido_dev_get_touch_begin(devtab[i])) != FIDO_OK) {
108
warnx("%s: fido_dev_get_touch_begin %s: %s", __func__,
109
fido_dev_info_path(di), fido_strerr(r));
110
r = -1;
111
goto out;
112
}
113
}
114
115
if (clock_gettime(CLOCK_MONOTONIC, &ts_start) != 0) {
116
warn("%s: clock_gettime", __func__);
117
r = -1;
118
goto out;
119
}
120
121
ts_pause.tv_sec = 0;
122
ts_pause.tv_nsec = 200000000; /* 200ms */
123
124
do {
125
nanosleep(&ts_pause, NULL);
126
127
for (size_t i = 0; i < ndevs; i++) {
128
di = fido_dev_info_ptr(devlist, i);
129
if (devtab[i] == NULL) {
130
/* failed to open or discarded */
131
continue;
132
}
133
if ((r = fido_dev_get_touch_status(devtab[i], &touched,
134
FIDO_POLL_MS)) != FIDO_OK) {
135
warnx("%s: fido_dev_get_touch_status %s: %s",
136
__func__, fido_dev_info_path(di),
137
fido_strerr(r));
138
fido_dev_close(devtab[i]);
139
fido_dev_free(&devtab[i]);
140
continue; /* discard */
141
}
142
if (touched) {
143
*dev = devtab[i];
144
*idx = i;
145
r = 0;
146
goto out;
147
}
148
}
149
150
if (clock_gettime(CLOCK_MONOTONIC, &ts_now) != 0) {
151
warn("%s: clock_gettime", __func__);
152
r = -1;
153
goto out;
154
}
155
156
timespecsub(&ts_now, &ts_start, &ts_delta);
157
ms_remain = (secs * 1000) - ((long)ts_delta.tv_sec * 1000) +
158
((long)ts_delta.tv_nsec / 1000000);
159
} while (ms_remain > FIDO_POLL_MS);
160
161
printf("timeout after %d seconds\n", secs);
162
r = -1;
163
out:
164
if (r != 0) {
165
*dev = NULL;
166
*idx = 0;
167
}
168
169
for (size_t i = 0; i < ndevs; i++) {
170
if (devtab[i] && devtab[i] != *dev) {
171
fido_dev_cancel(devtab[i]);
172
fido_dev_close(devtab[i]);
173
fido_dev_free(&devtab[i]);
174
}
175
}
176
177
free(devtab);
178
179
return (r);
180
}
181
182
int
183
main(void)
184
{
185
const fido_dev_info_t *di;
186
fido_dev_info_t *devlist;
187
fido_dev_t *dev;
188
size_t idx;
189
size_t ndevs;
190
int r;
191
192
fido_init(0);
193
194
if ((devlist = fido_dev_info_new(64)) == NULL)
195
errx(1, "fido_dev_info_new");
196
197
if ((r = fido_dev_info_manifest(devlist, 64, &ndevs)) != FIDO_OK)
198
errx(1, "fido_dev_info_manifest: %s (0x%x)", fido_strerr(r), r);
199
if (select_dev(devlist, ndevs, &dev, &idx, 15) != 0)
200
errx(1, "select_dev");
201
if (dev == NULL)
202
errx(1, "no authenticator found");
203
204
di = fido_dev_info_ptr(devlist, idx);
205
printf("%s: %s by %s (PIN %sset)\n", fido_dev_info_path(di),
206
fido_dev_info_product_string(di),
207
fido_dev_info_manufacturer_string(di),
208
fido_dev_has_pin(dev) ? "" : "un");
209
210
fido_dev_close(dev);
211
fido_dev_free(&dev);
212
fido_dev_info_free(&devlist, ndevs);
213
214
exit(0);
215
}
216
217