summaryrefslogtreecommitdiff
path: root/examples/select.c
diff options
context:
space:
mode:
Diffstat (limited to 'examples/select.c')
-rw-r--r--examples/select.c215
1 files changed, 215 insertions, 0 deletions
diff --git a/examples/select.c b/examples/select.c
new file mode 100644
index 0000000..1fb2960
--- /dev/null
+++ b/examples/select.c
@@ -0,0 +1,215 @@
1/*
2 * Copyright (c) 2020 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 */
6
7#include <errno.h>
8#include <stdbool.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <time.h>
12
13#include "fido.h"
14#include "../openbsd-compat/openbsd-compat.h"
15
16#define FIDO_POLL_MS 50
17
18#if defined(_MSC_VER)
19static int
20nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
21{
22 if (rmtp != NULL) {
23 errno = EINVAL;
24 return (-1);
25 }
26
27 Sleep(rqtp->tv_nsec / 1000000);
28
29 return (0);
30}
31#endif
32
33static fido_dev_t *
34open_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
58static int
59select_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;
163out:
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
182int
183main(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}