static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len) { int auth = read_u32(data, 0); if (auth != vs->vd->subauth) { VNC_DEBUG("Rejecting auth %d\n", auth); vnc_write_u8(vs, 0); /* Reject auth */ vnc_flush(vs); vnc_client_error(vs); } else { VNC_DEBUG("Accepting auth %d, setting up TLS for handshake\n", auth); vnc_write_u8(vs, 1); /* Accept auth */ vnc_flush(vs); if (vnc_tls_client_setup(vs, NEED_X509_AUTH(vs)) < 0) { VNC_DEBUG("Failed to setup TLS\n"); return 0; } VNC_DEBUG("Start TLS VeNCrypt handshake process\n"); if (vnc_start_vencrypt_handshake(vs) < 0) { VNC_DEBUG("Failed to start TLS handshake\n"); return 0; } } return 0; }
static int vnc_auth_sasl_check_access(VncState *vs) { const void *val; int err; int allow; err = sasl_getprop(vs->sasl.conn, SASL_USERNAME, &val); if (err != SASL_OK) { VNC_DEBUG("cannot query SASL username on connection %d (%s), denying access\n", err, sasl_errstring(err, NULL, NULL)); return -1; } if (val == NULL) { VNC_DEBUG("no client username was found, denying access\n"); return -1; } VNC_DEBUG("SASL client username %s\n", (const char *)val); vs->sasl.username = g_strdup((const char*)val); if (vs->vd->sasl.acl == NULL) { VNC_DEBUG("no ACL activated, allowing access\n"); return 0; } allow = qemu_acl_party_is_allowed(vs->vd->sasl.acl, vs->sasl.username); VNC_DEBUG("SASL client %s %s by ACL\n", vs->sasl.username, allow ? "allowed" : "denied"); return allow ? 0 : -1; }
static int vnc_start_vencrypt_handshake(struct VncState *vs) { int ret; if ((ret = gnutls_handshake(vs->tls.session)) < 0) { if (!gnutls_error_is_fatal(ret)) { VNC_DEBUG("Handshake interrupted (blocking)\n"); if (!gnutls_record_get_direction(vs->tls.session)) qemu_set_fd_handler(vs->csock, vnc_tls_handshake_io, NULL, vs); else qemu_set_fd_handler(vs->csock, NULL, vnc_tls_handshake_io, vs); return 0; } VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret)); vnc_client_error(vs); return -1; } if (vs->vd->tls.x509verify) { if (vnc_tls_validate_certificate(vs) < 0) { VNC_DEBUG("Client verification failed\n"); vnc_client_error(vs); return -1; } else { VNC_DEBUG("Client verification passed\n"); } } VNC_DEBUG("Handshake done, switching to TLS data mode\n"); vs->tls.wiremode = VNC_WIREMODE_TLS; qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs); start_auth_vencrypt_subauth(vs); return 0; }
static void start_auth_vencrypt_subauth(VncState *vs) { switch (vs->subauth) { case VNC_AUTH_VENCRYPT_TLSNONE: case VNC_AUTH_VENCRYPT_X509NONE: VNC_DEBUG("Accept TLS auth none\n"); vnc_write_u32(vs, 0); /* Accept auth completion */ start_client_init(vs); break; case VNC_AUTH_VENCRYPT_TLSVNC: case VNC_AUTH_VENCRYPT_X509VNC: VNC_DEBUG("Start TLS auth VNC\n"); start_auth_vnc(vs); break; #ifdef CONFIG_VNC_SASL case VNC_AUTH_VENCRYPT_TLSSASL: case VNC_AUTH_VENCRYPT_X509SASL: VNC_DEBUG("Start TLS auth SASL\n"); start_auth_sasl(vs); break; #endif /* CONFIG_VNC_SASL */ default: /* Should not be possible, but just in case */ VNC_DEBUG("Reject subauth %d server bug\n", vs->auth); vnc_write_u8(vs, 1); if (vs->minor >= 8) { static const char err[] = "Unsupported authentication type"; vnc_write_u32(vs, sizeof(err)); vnc_write(vs, err, sizeof(err)); } vnc_client_error(vs); } }
static int vncws_start_tls_handshake(struct VncState *vs) { int ret = gnutls_handshake(vs->ws_tls.session); if (ret < 0) { if (!gnutls_error_is_fatal(ret)) { VNC_DEBUG("Handshake interrupted (blocking)\n"); if (!gnutls_record_get_direction(vs->ws_tls.session)) { qemu_set_fd_handler(vs->csock, vncws_tls_handshake_io, NULL, vs); } else { qemu_set_fd_handler(vs->csock, NULL, vncws_tls_handshake_io, vs); } return 0; } VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret)); vnc_client_error(vs); return -1; } VNC_DEBUG("Handshake done, switching to TLS data mode\n"); vs->ws_tls.wiremode = VNC_WIREMODE_TLS; qemu_set_fd_handler2(vs->csock, NULL, vncws_handshake_read, NULL, vs); return 0; }
void vncws_tls_handshake_io(void *opaque) { VncState *vs = (VncState *)opaque; Error *err = NULL; vs->tls = qcrypto_tls_session_new(vs->vd->tlscreds, NULL, vs->vd->tlsaclname, QCRYPTO_TLS_CREDS_ENDPOINT_SERVER, &err); if (!vs->tls) { VNC_DEBUG("Failed to setup TLS %s\n", error_get_pretty(err)); error_free(err); vnc_client_error(vs); return; } qcrypto_tls_session_set_callbacks(vs->tls, vnc_tls_push, vnc_tls_pull, vs); VNC_DEBUG("Start TLS WS handshake process\n"); vncws_start_tls_handshake(vs); }
void vncws_tls_handshake_io(void *opaque) { struct VncState *vs = (struct VncState *)opaque; if (!vs->tls.session) { VNC_DEBUG("TLS Websocket setup\n"); if (vnc_tls_client_setup(vs, vs->vd->tls.x509cert != NULL) < 0) { return; } } VNC_DEBUG("Handshake IO continue\n"); vncws_start_tls_handshake(vs); }
static void vncws_tls_handshake_done(Object *source, Error *err, gpointer user_data) { VncState *vs = user_data; if (err) { VNC_DEBUG("Handshake failed %s\n", error_get_pretty(err)); vnc_client_error(vs); } else { VNC_DEBUG("TLS handshake complete, starting websocket handshake\n"); vs->ioc_tag = qio_channel_add_watch( QIO_CHANNEL(vs->ioc), G_IO_IN, vncws_handshake_io, vs, NULL); } }
static void vncws_send_handshake_response(VncState *vs, const char* key) { char combined_key[WS_CLIENT_KEY_LEN + WS_GUID_LEN + 1]; unsigned char hash[SHA1_DIGEST_LEN]; size_t hash_size = sizeof(hash); char *accept = NULL, *response = NULL; gnutls_datum_t in; int ret; g_strlcpy(combined_key, key, WS_CLIENT_KEY_LEN + 1); g_strlcat(combined_key, WS_GUID, WS_CLIENT_KEY_LEN + WS_GUID_LEN + 1); /* hash and encode it */ in.data = (void *)combined_key; in.size = WS_CLIENT_KEY_LEN + WS_GUID_LEN; ret = gnutls_fingerprint(GNUTLS_DIG_SHA1, &in, hash, &hash_size); if (ret == GNUTLS_E_SUCCESS && hash_size <= SHA1_DIGEST_LEN) { accept = g_base64_encode(hash, hash_size); } if (accept == NULL) { VNC_DEBUG("Hashing Websocket combined key failed\n"); vnc_client_error(vs); return; } response = g_strdup_printf(WS_HANDSHAKE, accept); vnc_client_write_buf(vs, (const uint8_t *)response, strlen(response)); g_free(accept); g_free(response); vs->encode_ws = 1; vnc_init_state(vs); }
static void vnc_tls_handshake_io(void *opaque) { VncState *vs = (VncState *)opaque; VNC_DEBUG("Handshake IO continue\n"); vnc_start_vencrypt_handshake(vs); }
static void vncws_tls_handshake_io(void *opaque) { struct VncState *vs = (struct VncState *)opaque; VNC_DEBUG("Handshake IO continue\n"); vncws_start_tls_handshake(vs); }
long vnc_client_read_ws(VncState *vs) { int ret, err; uint8_t *payload; size_t payload_size, frame_size; VNC_DEBUG("Read websocket %p size %zd offset %zd\n", vs->ws_input.buffer, vs->ws_input.capacity, vs->ws_input.offset); buffer_reserve(&vs->ws_input, 4096); ret = vnc_client_read_buf(vs, buffer_end(&vs->ws_input), 4096); if (!ret) { return 0; } vs->ws_input.offset += ret; /* make sure that nothing is left in the ws_input buffer */ do { err = vncws_decode_frame(&vs->ws_input, &payload, &payload_size, &frame_size); if (err <= 0) { return err; } buffer_reserve(&vs->input, payload_size); buffer_append(&vs->input, payload, payload_size); buffer_advance(&vs->ws_input, frame_size); } while (vs->ws_input.offset > 0); return ret; }
void vncws_handshake_read(void *opaque) { VncState *vs = opaque; uint8_t *handshake_end; long ret; /* Typical HTTP headers from novnc are 512 bytes, so limiting * total header size to 4096 is easily enough. */ size_t want = 4096 - vs->ws_input.offset; buffer_reserve(&vs->ws_input, want); ret = vnc_client_read_buf(vs, buffer_end(&vs->ws_input), want); if (!ret) { if (vs->csock == -1) { vnc_disconnect_finish(vs); } return; } vs->ws_input.offset += ret; handshake_end = (uint8_t *)g_strstr_len((char *)vs->ws_input.buffer, vs->ws_input.offset, WS_HANDSHAKE_END); if (handshake_end) { qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); vncws_process_handshake(vs, vs->ws_input.buffer, vs->ws_input.offset); buffer_advance(&vs->ws_input, handshake_end - vs->ws_input.buffer + strlen(WS_HANDSHAKE_END)); } else if (vs->ws_input.offset >= 4096) { VNC_DEBUG("End of headers not found in first 4096 bytes\n"); vnc_client_error(vs); } }
static int vnc_set_x509_credential(VncDisplay *vd, const char *certdir, const char *filename, char **cred, int ignoreMissing) { struct stat sb; if (*cred) { g_free(*cred); *cred = NULL; } *cred = g_malloc(strlen(certdir) + strlen(filename) + 2); strcpy(*cred, certdir); strcat(*cred, "/"); strcat(*cred, filename); VNC_DEBUG("Check %s\n", *cred); if (stat(*cred, &sb) < 0) { g_free(*cred); *cred = NULL; if (ignoreMissing && errno == ENOENT) return 0; return -1; } return 0; }
static void vncws_send_handshake_response(VncState *vs, const char* key) { char combined_key[WS_CLIENT_KEY_LEN + WS_GUID_LEN + 1]; char *accept = NULL, *response = NULL; Error *err = NULL; g_strlcpy(combined_key, key, WS_CLIENT_KEY_LEN + 1); g_strlcat(combined_key, WS_GUID, WS_CLIENT_KEY_LEN + WS_GUID_LEN + 1); /* hash and encode it */ if (qcrypto_hash_base64(QCRYPTO_HASH_ALG_SHA1, combined_key, WS_CLIENT_KEY_LEN + WS_GUID_LEN, &accept, &err) < 0) { VNC_DEBUG("Hashing Websocket combined key failed %s\n", error_get_pretty(err)); error_free(err); vnc_client_error(vs); return; } response = g_strdup_printf(WS_HANDSHAKE, accept); vnc_client_write_buf(vs, (const uint8_t *)response, strlen(response)); g_free(accept); g_free(response); vs->encode_ws = 1; vnc_init_state(vs); }
static int protocol_client_auth_sasl_start_len(VncState *vs, uint8_t *data, size_t len) { uint32_t startlen = read_u32(data, 0); VNC_DEBUG("Got client start len %d\n", startlen); if (startlen > SASL_DATA_MAX_LEN) { VNC_DEBUG("Too much SASL data %d\n", startlen); vnc_client_error(vs); return -1; } if (startlen == 0) return protocol_client_auth_sasl_start(vs, NULL, 0); vnc_read_when(vs, protocol_client_auth_sasl_start, startlen); return 0; }
static int vnc_auth_sasl_check_ssf(VncState *vs) { const void *val; int err, ssf; if (!vs->sasl.wantSSF) return 1; err = sasl_getprop(vs->sasl.conn, SASL_SSF, &val); if (err != SASL_OK) return 0; ssf = *(const int *)val; VNC_DEBUG("negotiated an SSF of %d\n", ssf); if (ssf < 56) return 0; /* 56 is good for Kerberos */ /* Only setup for read initially, because we're about to send an RPC * reply which must be in plain text. When the next incoming RPC * arrives, we'll switch on writes too * * cf qemudClientReadSASL in qemud.c */ vs->sasl.runSSF = 1; /* We have a SSF that's good enough */ return 1; }
static int protocol_client_auth_sasl_mechname_len(VncState *vs, uint8_t *data, size_t len) { uint32_t mechlen = read_u32(data, 0); VNC_DEBUG("Got client mechname len %d\n", mechlen); if (mechlen > 100) { VNC_DEBUG("Too long SASL mechname data %d\n", mechlen); vnc_client_error(vs); return -1; } if (mechlen < 1) { VNC_DEBUG("Too short SASL mechname %d\n", mechlen); vnc_client_error(vs); return -1; } vnc_read_when(vs, protocol_client_auth_sasl_mechname,mechlen); return 0; }
static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len) { int auth = read_u32(data, 0); if (auth != vs->subauth) { VNC_DEBUG("Rejecting auth %d\n", auth); vnc_write_u8(vs, 0); /* Reject auth */ vnc_flush(vs); vnc_client_error(vs); } else { Error *err = NULL; QIOChannelTLS *tls; VNC_DEBUG("Accepting auth %d, setting up TLS for handshake\n", auth); vnc_write_u8(vs, 1); /* Accept auth */ vnc_flush(vs); if (vs->ioc_tag) { g_source_remove(vs->ioc_tag); vs->ioc_tag = 0; } tls = qio_channel_tls_new_server( vs->ioc, vs->vd->tlscreds, vs->vd->tlsaclname, &err); if (!tls) { VNC_DEBUG("Failed to setup TLS %s\n", error_get_pretty(err)); error_free(err); vnc_client_error(vs); return 0; } VNC_DEBUG("Start TLS VeNCrypt handshake process\n"); object_unref(OBJECT(vs->ioc)); vs->ioc = QIO_CHANNEL(tls); vs->tls = qio_channel_tls_get_session(tls); qio_channel_tls_handshake(tls, vnc_tls_handshake_done, vs, NULL); } return 0; }
static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len) { if (data[0] != 0 || data[1] != 2) { VNC_DEBUG("Unsupported VeNCrypt protocol %d.%d\n", (int)data[0], (int)data[1]); vnc_write_u8(vs, 1); /* Reject version */ vnc_flush(vs); vnc_client_error(vs); } else { VNC_DEBUG("Sending allowed auth %d\n", vs->subauth); vnc_write_u8(vs, 0); /* Accept version */ vnc_write_u8(vs, 1); /* Number of sub-auths */ vnc_write_u32(vs, vs->subauth); /* The supported auth */ vnc_flush(vs); vnc_read_when(vs, protocol_client_vencrypt_auth, 4); } return 0; }
static void vncws_tls_handshake_done(QIOTask *task, gpointer user_data) { VncState *vs = user_data; Error *err = NULL; if (qio_task_propagate_error(task, &err)) { VNC_DEBUG("Handshake failed %s\n", error_get_pretty(err)); vnc_client_error(vs); error_free(err); } else { VNC_DEBUG("TLS handshake complete, starting websocket handshake\n"); if (vs->ioc_tag) { g_source_remove(vs->ioc_tag); } vs->ioc_tag = qio_channel_add_watch( QIO_CHANNEL(vs->ioc), G_IO_IN, vncws_handshake_io, vs, NULL); } }
int vncws_decode_frame_header(Buffer *input, size_t *header_size, size_t *payload_remain, WsMask *payload_mask) { unsigned char opcode = 0, fin = 0, has_mask = 0; size_t payload_len; WsHeader *header = (WsHeader *)input->buffer; if (input->offset < WS_HEAD_MIN_LEN + 4) { /* header not complete */ return 0; } fin = (header->b0 & 0x80) >> 7; opcode = header->b0 & 0x0f; has_mask = (header->b1 & 0x80) >> 7; payload_len = header->b1 & 0x7f; if (opcode == WS_OPCODE_CLOSE) { /* disconnect */ return -1; } /* Websocket frame sanity check: * * Websocket fragmentation is not supported. * * All websockets frames sent by a client have to be masked. * * Only binary encoding is supported. */ if (!fin || !has_mask || opcode != WS_OPCODE_BINARY_FRAME) { VNC_DEBUG("Received faulty/unsupported Websocket frame\n"); return -2; } if (payload_len < 126) { *payload_remain = payload_len; *header_size = 6; *payload_mask = header->u.m; } else if (payload_len == 126 && input->offset >= 8) { *payload_remain = be16_to_cpu(header->u.s16.l16); *header_size = 8; *payload_mask = header->u.s16.m16; } else if (payload_len == 127 && input->offset >= 14) { *payload_remain = be64_to_cpu(header->u.s64.l64); *header_size = 14; *payload_mask = header->u.s64.m64; } else { /* header not complete */ return 0; } return 1; }
static int protocol_client_auth_sasl_mechname(VncState *vs, uint8_t *data, size_t len) { char *mechname = g_malloc(len + 1); strncpy(mechname, (char*)data, len); mechname[len] = '\0'; VNC_DEBUG("Got client mechname '%s' check against '%s'\n", mechname, vs->sasl.mechlist); if (strncmp(vs->sasl.mechlist, mechname, len) == 0) { if (vs->sasl.mechlist[len] != '\0' && vs->sasl.mechlist[len] != ',') { VNC_DEBUG("One %d", vs->sasl.mechlist[len]); goto fail; } } else { char *offset = strstr(vs->sasl.mechlist, mechname); VNC_DEBUG("Two %p\n", offset); if (!offset) { goto fail; } VNC_DEBUG("Two '%s'\n", offset); if (offset[-1] != ',' || (offset[len] != '\0'&& offset[len] != ',')) { goto fail; } } g_free(vs->sasl.mechlist); vs->sasl.mechlist = mechname; VNC_DEBUG("Validated mechname '%s'\n", mechname); vnc_read_when(vs, protocol_client_auth_sasl_start_len, 4); return 0; fail: vnc_client_error(vs); g_free(mechname); return -1; }
long vnc_client_read_ws(VncState *vs) { int ret, err; uint8_t *payload; size_t payload_size, header_size; VNC_DEBUG("Read websocket %p size %zd offset %zd\n", vs->ws_input.buffer, vs->ws_input.capacity, vs->ws_input.offset); buffer_reserve(&vs->ws_input, 4096); ret = vnc_client_read_buf(vs, buffer_end(&vs->ws_input), 4096); if (!ret) { return 0; } vs->ws_input.offset += ret; ret = 0; /* consume as much of ws_input buffer as possible */ do { if (vs->ws_payload_remain == 0) { err = vncws_decode_frame_header(&vs->ws_input, &header_size, &vs->ws_payload_remain, &vs->ws_payload_mask); if (err <= 0) { return err; } buffer_advance(&vs->ws_input, header_size); } if (vs->ws_payload_remain != 0) { err = vncws_decode_frame_payload(&vs->ws_input, &vs->ws_payload_remain, &vs->ws_payload_mask, &payload, &payload_size); if (err < 0) { return err; } if (err == 0) { return ret; } ret += err; buffer_reserve(&vs->input, payload_size); buffer_append(&vs->input, payload, payload_size); buffer_advance(&vs->ws_input, payload_size); } } while (vs->ws_input.offset > 0); return ret; }
static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncDisplay *vd) { gnutls_certificate_credentials_t x509_cred; int ret; if (!vd->tls.x509cacert) { VNC_DEBUG("No CA x509 certificate specified\n"); return NULL; } if (!vd->tls.x509cert) { VNC_DEBUG("No server x509 certificate specified\n"); return NULL; } if (!vd->tls.x509key) { VNC_DEBUG("No server private key specified\n"); return NULL; } if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) { VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret)); return NULL; } if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred, vd->tls.x509cacert, GNUTLS_X509_FMT_PEM)) < 0) { VNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret)); gnutls_certificate_free_credentials(x509_cred); return NULL; } if ((ret = gnutls_certificate_set_x509_key_file (x509_cred, vd->tls.x509cert, vd->tls.x509key, GNUTLS_X509_FMT_PEM)) < 0) { VNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret)); gnutls_certificate_free_credentials(x509_cred); return NULL; } if (vd->tls.x509cacrl) { if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred, vd->tls.x509cacrl, GNUTLS_X509_FMT_PEM)) < 0) { VNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret)); gnutls_certificate_free_credentials(x509_cred); return NULL; } } gnutls_certificate_set_dh_params (x509_cred, dh_params); return x509_cred; }
static gnutls_anon_server_credentials_t vnc_tls_initialize_anon_cred(void) { gnutls_anon_server_credentials_t anon_cred; int ret; if ((ret = gnutls_anon_allocate_server_credentials(&anon_cred)) < 0) { VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret)); return NULL; } gnutls_anon_set_server_dh_params(anon_cred, dh_params); return anon_cred; }
long vnc_client_write_sasl(VncState *vs) { long ret; VNC_DEBUG("Write SASL: Pending output %p size %zd offset %zd " "Encoded: %p size %d offset %d\n", vs->output.buffer, vs->output.capacity, vs->output.offset, vs->sasl.encoded, vs->sasl.encodedLength, vs->sasl.encodedOffset); if (!vs->sasl.encoded) { int err; err = sasl_encode(vs->sasl.conn, (char *)vs->output.buffer, vs->output.offset, (const char **)&vs->sasl.encoded, &vs->sasl.encodedLength); if (err != SASL_OK) return vnc_client_io_error(vs, -1, NULL); vs->sasl.encodedOffset = 0; } ret = vnc_client_write_buf(vs, vs->sasl.encoded + vs->sasl.encodedOffset, vs->sasl.encodedLength - vs->sasl.encodedOffset); if (!ret) return 0; vs->sasl.encodedOffset += ret; if (vs->sasl.encodedOffset == vs->sasl.encodedLength) { vs->output.offset = 0; vs->sasl.encoded = NULL; vs->sasl.encodedOffset = vs->sasl.encodedLength = 0; } /* Can't merge this block with one above, because * someone might have written more unencrypted * data in vs->output while we were processing * SASL encoded output */ if (vs->output.offset == 0) { if (vs->ioc_tag) { g_source_remove(vs->ioc_tag); } vs->ioc_tag = qio_channel_add_watch( vs->ioc, G_IO_IN, vnc_client_io, vs, NULL); } return ret; }
static int vncws_start_tls_handshake(VncState *vs) { Error *err = NULL; if (qcrypto_tls_session_handshake(vs->tls, &err) < 0) { goto error; } switch (qcrypto_tls_session_get_handshake_status(vs->tls)) { case QCRYPTO_TLS_HANDSHAKE_COMPLETE: VNC_DEBUG("Handshake done, checking credentials\n"); if (qcrypto_tls_session_check_credentials(vs->tls, &err) < 0) { goto error; } VNC_DEBUG("Client verification passed, starting TLS I/O\n"); qemu_set_fd_handler(vs->csock, vncws_handshake_read, NULL, vs); break; case QCRYPTO_TLS_HANDSHAKE_RECVING: VNC_DEBUG("Handshake interrupted (blocking read)\n"); qemu_set_fd_handler(vs->csock, vncws_tls_handshake_io, NULL, vs); break; case QCRYPTO_TLS_HANDSHAKE_SENDING: VNC_DEBUG("Handshake interrupted (blocking write)\n"); qemu_set_fd_handler(vs->csock, NULL, vncws_tls_handshake_io, vs); break; } return 0; error: VNC_DEBUG("Handshake failed %s\n", error_get_pretty(err)); error_free(err); vnc_client_error(vs); return -1; }
static int vncws_start_tls_handshake(struct VncState *vs) { int ret = gnutls_handshake(vs->tls.session); if (ret < 0) { if (!gnutls_error_is_fatal(ret)) { VNC_DEBUG("Handshake interrupted (blocking)\n"); if (!gnutls_record_get_direction(vs->tls.session)) { qemu_set_fd_handler(vs->csock, vncws_tls_handshake_io, NULL, vs); } else { qemu_set_fd_handler(vs->csock, NULL, vncws_tls_handshake_io, vs); } return 0; } VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret)); vnc_client_error(vs); return -1; } if (vs->vd->tls.x509verify) { if (vnc_tls_validate_certificate(vs) < 0) { VNC_DEBUG("Client verification failed\n"); vnc_client_error(vs); return -1; } else { VNC_DEBUG("Client verification passed\n"); } } VNC_DEBUG("Handshake done, switching to TLS data mode\n"); qemu_set_fd_handler2(vs->csock, NULL, vncws_handshake_read, NULL, vs); return 0; }
static void vnc_tls_handshake_done(Object *source, Error *err, gpointer user_data) { VncState *vs = user_data; if (err) { VNC_DEBUG("Handshake failed %s\n", error_get_pretty(err)); vnc_client_error(vs); } else { vs->ioc_tag = qio_channel_add_watch( vs->ioc, G_IO_IN | G_IO_OUT, vnc_client_io, vs, NULL); start_auth_vencrypt_subauth(vs); } }