]> git.proxmox.com Git - mirror_qemu.git/blob - io/channel-tls.c
audio: fix audio timer rate conversion bug
[mirror_qemu.git] / io / channel-tls.c
1 /*
2 * QEMU I/O channels TLS driver
3 *
4 * Copyright (c) 2015 Red Hat, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 #include "qemu/osdep.h"
22 #include "qapi/error.h"
23 #include "io/channel-tls.h"
24 #include "trace.h"
25
26
27 static ssize_t qio_channel_tls_write_handler(const char *buf,
28 size_t len,
29 void *opaque)
30 {
31 QIOChannelTLS *tioc = QIO_CHANNEL_TLS(opaque);
32 ssize_t ret;
33
34 ret = qio_channel_write(tioc->master, buf, len, NULL);
35 if (ret == QIO_CHANNEL_ERR_BLOCK) {
36 errno = EAGAIN;
37 return -1;
38 } else if (ret < 0) {
39 errno = EIO;
40 return -1;
41 }
42 return ret;
43 }
44
45 static ssize_t qio_channel_tls_read_handler(char *buf,
46 size_t len,
47 void *opaque)
48 {
49 QIOChannelTLS *tioc = QIO_CHANNEL_TLS(opaque);
50 ssize_t ret;
51
52 ret = qio_channel_read(tioc->master, buf, len, NULL);
53 if (ret == QIO_CHANNEL_ERR_BLOCK) {
54 errno = EAGAIN;
55 return -1;
56 } else if (ret < 0) {
57 errno = EIO;
58 return -1;
59 }
60 return ret;
61 }
62
63
64 QIOChannelTLS *
65 qio_channel_tls_new_server(QIOChannel *master,
66 QCryptoTLSCreds *creds,
67 const char *aclname,
68 Error **errp)
69 {
70 QIOChannelTLS *ioc;
71
72 ioc = QIO_CHANNEL_TLS(object_new(TYPE_QIO_CHANNEL_TLS));
73
74 ioc->master = master;
75 object_ref(OBJECT(master));
76
77 ioc->session = qcrypto_tls_session_new(
78 creds,
79 NULL,
80 aclname,
81 QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
82 errp);
83 if (!ioc->session) {
84 goto error;
85 }
86
87 qcrypto_tls_session_set_callbacks(
88 ioc->session,
89 qio_channel_tls_write_handler,
90 qio_channel_tls_read_handler,
91 ioc);
92
93 trace_qio_channel_tls_new_server(ioc, master, creds, aclname);
94 return ioc;
95
96 error:
97 object_unref(OBJECT(ioc));
98 return NULL;
99 }
100
101 QIOChannelTLS *
102 qio_channel_tls_new_client(QIOChannel *master,
103 QCryptoTLSCreds *creds,
104 const char *hostname,
105 Error **errp)
106 {
107 QIOChannelTLS *tioc;
108 QIOChannel *ioc;
109
110 tioc = QIO_CHANNEL_TLS(object_new(TYPE_QIO_CHANNEL_TLS));
111 ioc = QIO_CHANNEL(tioc);
112
113 tioc->master = master;
114 if (qio_channel_has_feature(master, QIO_CHANNEL_FEATURE_SHUTDOWN)) {
115 qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_SHUTDOWN);
116 }
117 object_ref(OBJECT(master));
118
119 tioc->session = qcrypto_tls_session_new(
120 creds,
121 hostname,
122 NULL,
123 QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT,
124 errp);
125 if (!tioc->session) {
126 goto error;
127 }
128
129 qcrypto_tls_session_set_callbacks(
130 tioc->session,
131 qio_channel_tls_write_handler,
132 qio_channel_tls_read_handler,
133 tioc);
134
135 trace_qio_channel_tls_new_client(tioc, master, creds, hostname);
136 return tioc;
137
138 error:
139 object_unref(OBJECT(tioc));
140 return NULL;
141 }
142
143 struct QIOChannelTLSData {
144 QIOTask *task;
145 GMainContext *context;
146 };
147 typedef struct QIOChannelTLSData QIOChannelTLSData;
148
149 static gboolean qio_channel_tls_handshake_io(QIOChannel *ioc,
150 GIOCondition condition,
151 gpointer user_data);
152
153 static void qio_channel_tls_handshake_task(QIOChannelTLS *ioc,
154 QIOTask *task,
155 GMainContext *context)
156 {
157 Error *err = NULL;
158 QCryptoTLSSessionHandshakeStatus status;
159
160 if (qcrypto_tls_session_handshake(ioc->session, &err) < 0) {
161 trace_qio_channel_tls_handshake_fail(ioc);
162 qio_task_set_error(task, err);
163 qio_task_complete(task);
164 return;
165 }
166
167 status = qcrypto_tls_session_get_handshake_status(ioc->session);
168 if (status == QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
169 trace_qio_channel_tls_handshake_complete(ioc);
170 if (qcrypto_tls_session_check_credentials(ioc->session,
171 &err) < 0) {
172 trace_qio_channel_tls_credentials_deny(ioc);
173 qio_task_set_error(task, err);
174 } else {
175 trace_qio_channel_tls_credentials_allow(ioc);
176 }
177 qio_task_complete(task);
178 } else {
179 GIOCondition condition;
180 QIOChannelTLSData *data = g_new0(typeof(*data), 1);
181
182 data->task = task;
183 data->context = context;
184
185 if (context) {
186 g_main_context_ref(context);
187 }
188
189 if (status == QCRYPTO_TLS_HANDSHAKE_SENDING) {
190 condition = G_IO_OUT;
191 } else {
192 condition = G_IO_IN;
193 }
194
195 trace_qio_channel_tls_handshake_pending(ioc, status);
196 qio_channel_add_watch_full(ioc->master,
197 condition,
198 qio_channel_tls_handshake_io,
199 data,
200 NULL,
201 context);
202 }
203 }
204
205
206 static gboolean qio_channel_tls_handshake_io(QIOChannel *ioc,
207 GIOCondition condition,
208 gpointer user_data)
209 {
210 QIOChannelTLSData *data = user_data;
211 QIOTask *task = data->task;
212 GMainContext *context = data->context;
213 QIOChannelTLS *tioc = QIO_CHANNEL_TLS(
214 qio_task_get_source(task));
215
216 g_free(data);
217 qio_channel_tls_handshake_task(tioc, task, context);
218
219 if (context) {
220 g_main_context_unref(context);
221 }
222
223 return FALSE;
224 }
225
226 void qio_channel_tls_handshake(QIOChannelTLS *ioc,
227 QIOTaskFunc func,
228 gpointer opaque,
229 GDestroyNotify destroy,
230 GMainContext *context)
231 {
232 QIOTask *task;
233
234 task = qio_task_new(OBJECT(ioc),
235 func, opaque, destroy);
236
237 trace_qio_channel_tls_handshake_start(ioc);
238 qio_channel_tls_handshake_task(ioc, task, context);
239 }
240
241
242 static void qio_channel_tls_init(Object *obj G_GNUC_UNUSED)
243 {
244 }
245
246
247 static void qio_channel_tls_finalize(Object *obj)
248 {
249 QIOChannelTLS *ioc = QIO_CHANNEL_TLS(obj);
250
251 object_unref(OBJECT(ioc->master));
252 qcrypto_tls_session_free(ioc->session);
253 }
254
255
256 static ssize_t qio_channel_tls_readv(QIOChannel *ioc,
257 const struct iovec *iov,
258 size_t niov,
259 int **fds,
260 size_t *nfds,
261 Error **errp)
262 {
263 QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
264 size_t i;
265 ssize_t got = 0;
266
267 for (i = 0 ; i < niov ; i++) {
268 ssize_t ret = qcrypto_tls_session_read(tioc->session,
269 iov[i].iov_base,
270 iov[i].iov_len);
271 if (ret < 0) {
272 if (errno == EAGAIN) {
273 if (got) {
274 return got;
275 } else {
276 return QIO_CHANNEL_ERR_BLOCK;
277 }
278 } else if (errno == ECONNABORTED &&
279 (tioc->shutdown & QIO_CHANNEL_SHUTDOWN_READ)) {
280 return 0;
281 }
282
283 error_setg_errno(errp, errno,
284 "Cannot read from TLS channel");
285 return -1;
286 }
287 got += ret;
288 if (ret < iov[i].iov_len) {
289 break;
290 }
291 }
292 return got;
293 }
294
295
296 static ssize_t qio_channel_tls_writev(QIOChannel *ioc,
297 const struct iovec *iov,
298 size_t niov,
299 int *fds,
300 size_t nfds,
301 Error **errp)
302 {
303 QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
304 size_t i;
305 ssize_t done = 0;
306
307 for (i = 0 ; i < niov ; i++) {
308 ssize_t ret = qcrypto_tls_session_write(tioc->session,
309 iov[i].iov_base,
310 iov[i].iov_len);
311 if (ret <= 0) {
312 if (errno == EAGAIN) {
313 if (done) {
314 return done;
315 } else {
316 return QIO_CHANNEL_ERR_BLOCK;
317 }
318 }
319
320 error_setg_errno(errp, errno,
321 "Cannot write to TLS channel");
322 return -1;
323 }
324 done += ret;
325 if (ret < iov[i].iov_len) {
326 break;
327 }
328 }
329 return done;
330 }
331
332 static int qio_channel_tls_set_blocking(QIOChannel *ioc,
333 bool enabled,
334 Error **errp)
335 {
336 QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
337
338 return qio_channel_set_blocking(tioc->master, enabled, errp);
339 }
340
341 static void qio_channel_tls_set_delay(QIOChannel *ioc,
342 bool enabled)
343 {
344 QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
345
346 qio_channel_set_delay(tioc->master, enabled);
347 }
348
349 static void qio_channel_tls_set_cork(QIOChannel *ioc,
350 bool enabled)
351 {
352 QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
353
354 qio_channel_set_cork(tioc->master, enabled);
355 }
356
357 static int qio_channel_tls_shutdown(QIOChannel *ioc,
358 QIOChannelShutdown how,
359 Error **errp)
360 {
361 QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
362
363 tioc->shutdown |= how;
364
365 return qio_channel_shutdown(tioc->master, how, errp);
366 }
367
368 static int qio_channel_tls_close(QIOChannel *ioc,
369 Error **errp)
370 {
371 QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
372
373 return qio_channel_close(tioc->master, errp);
374 }
375
376 static void qio_channel_tls_set_aio_fd_handler(QIOChannel *ioc,
377 AioContext *ctx,
378 IOHandler *io_read,
379 IOHandler *io_write,
380 void *opaque)
381 {
382 QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
383
384 qio_channel_set_aio_fd_handler(tioc->master, ctx, io_read, io_write, opaque);
385 }
386
387 static GSource *qio_channel_tls_create_watch(QIOChannel *ioc,
388 GIOCondition condition)
389 {
390 QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
391
392 return qio_channel_create_watch(tioc->master, condition);
393 }
394
395 QCryptoTLSSession *
396 qio_channel_tls_get_session(QIOChannelTLS *ioc)
397 {
398 return ioc->session;
399 }
400
401 static void qio_channel_tls_class_init(ObjectClass *klass,
402 void *class_data G_GNUC_UNUSED)
403 {
404 QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
405
406 ioc_klass->io_writev = qio_channel_tls_writev;
407 ioc_klass->io_readv = qio_channel_tls_readv;
408 ioc_klass->io_set_blocking = qio_channel_tls_set_blocking;
409 ioc_klass->io_set_delay = qio_channel_tls_set_delay;
410 ioc_klass->io_set_cork = qio_channel_tls_set_cork;
411 ioc_klass->io_close = qio_channel_tls_close;
412 ioc_klass->io_shutdown = qio_channel_tls_shutdown;
413 ioc_klass->io_create_watch = qio_channel_tls_create_watch;
414 ioc_klass->io_set_aio_fd_handler = qio_channel_tls_set_aio_fd_handler;
415 }
416
417 static const TypeInfo qio_channel_tls_info = {
418 .parent = TYPE_QIO_CHANNEL,
419 .name = TYPE_QIO_CHANNEL_TLS,
420 .instance_size = sizeof(QIOChannelTLS),
421 .instance_init = qio_channel_tls_init,
422 .instance_finalize = qio_channel_tls_finalize,
423 .class_init = qio_channel_tls_class_init,
424 };
425
426 static void qio_channel_tls_register_types(void)
427 {
428 type_register_static(&qio_channel_tls_info);
429 }
430
431 type_init(qio_channel_tls_register_types);