OSDN Git Service

44ac2fae633a00f22981cfb2d6c55e1c1d6a4c60
[qmiga/qemu.git] / ui / vnc-auth-vencrypt.c
1 /*
2  * QEMU VNC display driver: VeNCrypt authentication setup
3  *
4  * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
5  * Copyright (C) 2006 Fabrice Bellard
6  * Copyright (C) 2009 Red Hat, Inc
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to deal
10  * in the Software without restriction, including without limitation the rights
11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12  * copies of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24  * THE SOFTWARE.
25  */
26
27 #include "vnc.h"
28 #include "qemu/main-loop.h"
29
30 static void start_auth_vencrypt_subauth(VncState *vs)
31 {
32     switch (vs->subauth) {
33     case VNC_AUTH_VENCRYPT_TLSNONE:
34     case VNC_AUTH_VENCRYPT_X509NONE:
35        VNC_DEBUG("Accept TLS auth none\n");
36        vnc_write_u32(vs, 0); /* Accept auth completion */
37        start_client_init(vs);
38        break;
39
40     case VNC_AUTH_VENCRYPT_TLSVNC:
41     case VNC_AUTH_VENCRYPT_X509VNC:
42        VNC_DEBUG("Start TLS auth VNC\n");
43        start_auth_vnc(vs);
44        break;
45
46 #ifdef CONFIG_VNC_SASL
47     case VNC_AUTH_VENCRYPT_TLSSASL:
48     case VNC_AUTH_VENCRYPT_X509SASL:
49       VNC_DEBUG("Start TLS auth SASL\n");
50       start_auth_sasl(vs);
51       break;
52 #endif /* CONFIG_VNC_SASL */
53
54     default: /* Should not be possible, but just in case */
55        VNC_DEBUG("Reject subauth %d server bug\n", vs->auth);
56        vnc_write_u8(vs, 1);
57        if (vs->minor >= 8) {
58            static const char err[] = "Unsupported authentication type";
59            vnc_write_u32(vs, sizeof(err));
60            vnc_write(vs, err, sizeof(err));
61        }
62        vnc_client_error(vs);
63     }
64 }
65
66 static void vnc_tls_handshake_io(void *opaque);
67
68 static int vnc_start_vencrypt_handshake(VncState *vs)
69 {
70     Error *err = NULL;
71
72     if (qcrypto_tls_session_handshake(vs->tls, &err) < 0) {
73         goto error;
74     }
75
76     switch (qcrypto_tls_session_get_handshake_status(vs->tls)) {
77     case QCRYPTO_TLS_HANDSHAKE_COMPLETE:
78         VNC_DEBUG("Handshake done, checking credentials\n");
79         if (qcrypto_tls_session_check_credentials(vs->tls, &err) < 0) {
80             goto error;
81         }
82         VNC_DEBUG("Client verification passed, starting TLS I/O\n");
83         qemu_set_fd_handler(vs->csock, vnc_client_read, vnc_client_write, vs);
84
85         start_auth_vencrypt_subauth(vs);
86         break;
87
88     case QCRYPTO_TLS_HANDSHAKE_RECVING:
89         VNC_DEBUG("Handshake interrupted (blocking read)\n");
90         qemu_set_fd_handler(vs->csock, vnc_tls_handshake_io, NULL, vs);
91         break;
92
93     case QCRYPTO_TLS_HANDSHAKE_SENDING:
94         VNC_DEBUG("Handshake interrupted (blocking write)\n");
95         qemu_set_fd_handler(vs->csock, NULL, vnc_tls_handshake_io, vs);
96         break;
97     }
98
99     return 0;
100
101  error:
102     VNC_DEBUG("Handshake failed %s\n", error_get_pretty(err));
103     error_free(err);
104     vnc_client_error(vs);
105     return -1;
106 }
107
108 static void vnc_tls_handshake_io(void *opaque)
109 {
110     VncState *vs = (VncState *)opaque;
111
112     VNC_DEBUG("Handshake IO continue\n");
113     vnc_start_vencrypt_handshake(vs);
114 }
115
116
117 static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len)
118 {
119     int auth = read_u32(data, 0);
120
121     if (auth != vs->subauth) {
122         VNC_DEBUG("Rejecting auth %d\n", auth);
123         vnc_write_u8(vs, 0); /* Reject auth */
124         vnc_flush(vs);
125         vnc_client_error(vs);
126     } else {
127         Error *err = NULL;
128         VNC_DEBUG("Accepting auth %d, setting up TLS for handshake\n", auth);
129         vnc_write_u8(vs, 1); /* Accept auth */
130         vnc_flush(vs);
131
132         vs->tls = qcrypto_tls_session_new(vs->vd->tlscreds,
133                                           NULL,
134                                           vs->vd->tlsaclname,
135                                           QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
136                                           &err);
137         if (!vs->tls) {
138             VNC_DEBUG("Failed to setup TLS %s\n",
139                       error_get_pretty(err));
140             error_free(err);
141             vnc_client_error(vs);
142             return 0;
143         }
144
145         qcrypto_tls_session_set_callbacks(vs->tls,
146                                           vnc_tls_push,
147                                           vnc_tls_pull,
148                                           vs);
149
150         VNC_DEBUG("Start TLS VeNCrypt handshake process\n");
151         if (vnc_start_vencrypt_handshake(vs) < 0) {
152             VNC_DEBUG("Failed to start TLS handshake\n");
153             return 0;
154         }
155     }
156     return 0;
157 }
158
159 static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len)
160 {
161     if (data[0] != 0 ||
162         data[1] != 2) {
163         VNC_DEBUG("Unsupported VeNCrypt protocol %d.%d\n", (int)data[0], (int)data[1]);
164         vnc_write_u8(vs, 1); /* Reject version */
165         vnc_flush(vs);
166         vnc_client_error(vs);
167     } else {
168         VNC_DEBUG("Sending allowed auth %d\n", vs->subauth);
169         vnc_write_u8(vs, 0); /* Accept version */
170         vnc_write_u8(vs, 1); /* Number of sub-auths */
171         vnc_write_u32(vs, vs->subauth); /* The supported auth */
172         vnc_flush(vs);
173         vnc_read_when(vs, protocol_client_vencrypt_auth, 4);
174     }
175     return 0;
176 }
177
178
179 void start_auth_vencrypt(VncState *vs)
180 {
181     /* Send VeNCrypt version 0.2 */
182     vnc_write_u8(vs, 0);
183     vnc_write_u8(vs, 2);
184
185     vnc_read_when(vs, protocol_client_vencrypt_init, 2);
186 }
187