?? vnc.c
字號:
if (NEED_X509_AUTH(vs)) { gnutls_certificate_server_credentials x509_cred = vnc_tls_initialize_x509_cred(vs); if (!x509_cred) { gnutls_deinit(vs->tls_session); vs->tls_session = NULL; vnc_client_error(vs); return -1; } if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) { gnutls_deinit(vs->tls_session); vs->tls_session = NULL; gnutls_certificate_free_credentials(x509_cred); vnc_client_error(vs); return -1; } if (vs->x509verify) { VNC_DEBUG("Requesting a client certificate\n"); gnutls_certificate_server_set_request (vs->tls_session, GNUTLS_CERT_REQUEST); } } else { gnutls_anon_server_credentials anon_cred = vnc_tls_initialize_anon_cred(); if (!anon_cred) { gnutls_deinit(vs->tls_session); vs->tls_session = NULL; vnc_client_error(vs); return -1; } if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_ANON, anon_cred) < 0) { gnutls_deinit(vs->tls_session); vs->tls_session = NULL; gnutls_anon_free_server_credentials(anon_cred); vnc_client_error(vs); return -1; } } gnutls_transport_set_ptr(vs->tls_session, (gnutls_transport_ptr_t)vs); gnutls_transport_set_push_function(vs->tls_session, vnc_tls_push); gnutls_transport_set_pull_function(vs->tls_session, vnc_tls_pull); } VNC_DEBUG("Start TLS handshake process\n"); return vnc_continue_handshake(vs);}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 { VNC_DEBUG("Accepting auth %d, starting handshake\n", auth); vnc_write_u8(vs, 1); /* Accept auth */ vnc_flush(vs); if (vnc_start_tls(vs) < 0) { VNC_DEBUG("Failed to complete TLS\n"); return 0; } if (vs->wiremode == VNC_WIREMODE_TLS) { VNC_DEBUG("Starting VeNCrypt subauth\n"); return start_auth_vencrypt_subauth(vs); } else { VNC_DEBUG("TLS handshake blocked\n"); return 0; } } 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 int start_auth_vencrypt(VncState *vs){ /* Send VeNCrypt version 0.2 */ vnc_write_u8(vs, 0); vnc_write_u8(vs, 2); vnc_read_when(vs, protocol_client_vencrypt_init, 2); return 0;}#endif /* CONFIG_VNC_TLS */static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len){ /* We only advertise 1 auth scheme at a time, so client * must pick the one we sent. Verify this */ if (data[0] != vs->auth) { /* Reject auth */ VNC_DEBUG("Reject auth %d\n", (int)data[0]); vnc_write_u32(vs, 1); if (vs->minor >= 8) { static const char err[] = "Authentication failed"; vnc_write_u32(vs, sizeof(err)); vnc_write(vs, err, sizeof(err)); } vnc_client_error(vs); } else { /* Accept requested auth */ VNC_DEBUG("Client requested auth %d\n", (int)data[0]); switch (vs->auth) { case VNC_AUTH_NONE: VNC_DEBUG("Accept auth none\n"); if (vs->minor >= 8) { vnc_write_u32(vs, 0); /* Accept auth completion */ vnc_flush(vs); } vnc_read_when(vs, protocol_client_init, 1); break; case VNC_AUTH_VNC: VNC_DEBUG("Start VNC auth\n"); return start_auth_vnc(vs);#if CONFIG_VNC_TLS case VNC_AUTH_VENCRYPT: VNC_DEBUG("Accept VeNCrypt auth\n");; return start_auth_vencrypt(vs);#endif /* CONFIG_VNC_TLS */ default: /* Should not be possible, but just in case */ VNC_DEBUG("Reject auth %d\n", vs->auth); vnc_write_u8(vs, 1); if (vs->minor >= 8) { static const char err[] = "Authentication failed"; vnc_write_u32(vs, sizeof(err)); vnc_write(vs, err, sizeof(err)); } vnc_client_error(vs); } } return 0;}static int protocol_version(VncState *vs, uint8_t *version, size_t len){ char local[13]; memcpy(local, version, 12); local[12] = 0; if (sscanf(local, "RFB %03d.%03d\n", &vs->major, &vs->minor) != 2) { VNC_DEBUG("Malformed protocol version %s\n", local); vnc_client_error(vs); return 0; } VNC_DEBUG("Client request protocol version %d.%d\n", vs->major, vs->minor); if (vs->major != 3 || (vs->minor != 3 && vs->minor != 4 && vs->minor != 5 && vs->minor != 7 && vs->minor != 8)) { VNC_DEBUG("Unsupported client version\n"); vnc_write_u32(vs, VNC_AUTH_INVALID); vnc_flush(vs); vnc_client_error(vs); return 0; } /* Some broken clients report v3.4 or v3.5, which spec requires to be treated * as equivalent to v3.3 by servers */ if (vs->minor == 4 || vs->minor == 5) vs->minor = 3; if (vs->minor == 3) { if (vs->auth == VNC_AUTH_NONE) { VNC_DEBUG("Tell client auth none\n"); vnc_write_u32(vs, vs->auth); vnc_flush(vs); vnc_read_when(vs, protocol_client_init, 1); } else if (vs->auth == VNC_AUTH_VNC) { VNC_DEBUG("Tell client VNC auth\n"); vnc_write_u32(vs, vs->auth); vnc_flush(vs); start_auth_vnc(vs); } else { VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->auth); vnc_write_u32(vs, VNC_AUTH_INVALID); vnc_flush(vs); vnc_client_error(vs); } } else { VNC_DEBUG("Telling client we support auth %d\n", vs->auth); vnc_write_u8(vs, 1); /* num auth */ vnc_write_u8(vs, vs->auth); vnc_read_when(vs, protocol_client_auth, 1); vnc_flush(vs); } return 0;}static void vnc_listen_read(void *opaque){ VncState *vs = opaque; struct sockaddr_in addr; socklen_t addrlen = sizeof(addr); vs->csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen); if (vs->csock != -1) { VNC_DEBUG("New client on socket %d\n", vs->csock); socket_set_nonblock(vs->csock); qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, opaque); vnc_write(vs, "RFB 003.008\n", 12); vnc_flush(vs); vnc_read_when(vs, protocol_version, 12); memset(vs->old_data, 0, vs->ds->linesize * vs->ds->height); memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row)); vs->has_resize = 0; vs->has_hextile = 0; vs->ds->dpy_copy = NULL; }}extern int parse_host_port(struct sockaddr_in *saddr, const char *str);void vnc_display_init(DisplayState *ds){ VncState *vs; vs = qemu_mallocz(sizeof(VncState)); if (!vs) exit(1); ds->opaque = vs; vnc_state = vs; vs->display = NULL; vs->password = NULL; vs->lsock = -1; vs->csock = -1; vs->depth = 4; vs->last_x = -1; vs->last_y = -1; vs->ds = ds; if (!keyboard_layout) keyboard_layout = "en-us"; vs->kbd_layout = init_keyboard_layout(keyboard_layout); if (!vs->kbd_layout) exit(1); vs->ds->data = NULL; vs->ds->dpy_update = vnc_dpy_update; vs->ds->dpy_resize = vnc_dpy_resize; vs->ds->dpy_refresh = vnc_dpy_refresh; memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row)); vnc_dpy_resize(vs->ds, 640, 400);}#if CONFIG_VNC_TLSstatic int vnc_set_x509_credential(VncState *vs, const char *certdir, const char *filename, char **cred, int ignoreMissing){ struct stat sb; if (*cred) { qemu_free(*cred); *cred = NULL; } if (!(*cred = qemu_malloc(strlen(certdir) + strlen(filename) + 2))) return -1; strcpy(*cred, certdir); strcat(*cred, "/"); strcat(*cred, filename); VNC_DEBUG("Check %s\n", *cred); if (stat(*cred, &sb) < 0) { qemu_free(*cred); *cred = NULL; if (ignoreMissing && errno == ENOENT) return 0; return -1; } return 0;}static int vnc_set_x509_credential_dir(VncState *vs, const char *certdir){ if (vnc_set_x509_credential(vs, certdir, X509_CA_CERT_FILE, &vs->x509cacert, 0) < 0) goto cleanup; if (vnc_set_x509_credential(vs, certdir, X509_CA_CRL_FILE, &vs->x509cacrl, 1) < 0) goto cleanup; if (vnc_set_x509_credential(vs, certdir, X509_SERVER_CERT_FILE, &vs->x509cert, 0) < 0) goto cleanup; if (vnc_set_x509_credential(vs, certdir, X509_SERVER_KEY_FILE, &vs->x509key, 0) < 0) goto cleanup; return 0; cleanup: qemu_free(vs->x509cacert); qemu_free(vs->x509cacrl); qemu_free(vs->x509cert); qemu_free(vs->x509key); vs->x509cacert = vs->x509cacrl = vs->x509cert = vs->x509key = NULL; return -1;}#endif /* CONFIG_VNC_TLS */void vnc_display_close(DisplayState *ds){ VncState *vs = ds ? (VncState *)ds->opaque : vnc_state; if (vs->display) { qemu_free(vs->display); vs->display = NULL; } if (vs->lsock != -1) { qemu_set_fd_handler2(vs->lsock, NULL, NULL, NULL, NULL); close(vs->lsock); vs->lsock = -1; } if (vs->csock != -1) { qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL); closesocket(vs->csock); vs->csock = -1; buffer_reset(&vs->input); buffer_reset(&vs->output); vs->need_update = 0;#if CONFIG_VNC_TLS if (vs->tls_session) { gnutls_deinit(vs->tls_session); vs->tls_session = NULL; } vs->wiremode = VNC_WIREMODE_CLEAR;#endif /* CONFIG_VNC_TLS */ } vs->auth = VNC_AUTH_INVALID;#if CONFIG_VNC_TLS vs->subauth = VNC_AUTH_INVALID; vs->x509verify = 0;#endif}int vnc_display_password(DisplayState *ds, const char *password){ VncState *vs = ds ? (VncState *)ds->opaque : vnc_state; if (vs->password) { qemu_free(vs->password); vs->password = NULL; } if (password && password[0]) { if (!(vs->password = qemu_strdup(password))) return -1; } return 0;}int vnc_display_open(DisplayState *ds, const char *display){ struct sockaddr *addr; struct sockaddr_in iaddr;#ifndef _WIN32 struct sockaddr_un uaddr;#endif int reuse_addr, ret; socklen_t addrlen; const char *p; VncState *vs = ds ? (VncState *)ds->opaque : vnc_state; const char *options; int password = 0;#if CONFIG_VNC_TLS int tls = 0, x509 = 0;#endif vnc_display_close(ds); if (strcmp(display, "none") == 0) return 0; if (!(vs->display = strdup(display))) return -1; options = display; while ((options = strchr(options, ','))) { options++; if (strncmp(options, "password", 8) == 0) { password = 1; /* Require password auth */#if CONFIG_VNC_TLS } else if (strncmp(options, "tls", 3) == 0) { tls = 1; /* Require TLS */ } else if (strncmp(options, "x509", 4) == 0) { char *start, *end; x509 = 1; /* Require x509 certificates */ if (strncmp(options, "x509verify", 10) == 0) vs->x509verify = 1; /* ...and verify client certs */ /* Now check for 'x509=/some/path' postfix * and use that to setup x509 certificate/key paths */ start = strchr(options, '='); end = strchr(options, ','); if (start && (!end || (start < end))) { int len = end ? end-(start+1) : strlen(start+1); char *path = qemu_malloc(len+1); strncpy(path, start+1, len); path[len] = '\0'; VNC_DEBUG("Trying certificate path '%s'\n", path); if (vnc_set_x509_credential_dir(vs, path) < 0) { fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path); qemu_free(path); qemu_free(vs->display); vs->display = NULL; return -1; } qemu_free(path); } else { fprintf(stderr, "No certificate path provided\n"); qemu_free(vs->display); vs->display = NULL; return -1; }#endif } } if (password) {#if CONFIG_VNC_TLS if (tls) { vs->auth = VNC_AUTH_VENCRYPT; if (x509) { VNC_DEBUG("Initializing VNC server with x509 password auth\n"); vs->subauth = VNC_AUTH_VENCRYPT_X509VNC; } else { VNC_DEBUG("Initializing VNC server with TLS password auth\n"); vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC; } } else {#endif VNC_DEBUG("Initializing VNC server with password auth\n"); vs->auth = VNC_AUTH_VNC;#if CONFIG_VNC_TLS vs->subauth = VNC_AUTH_INVALID; }#endif } else {#if CONFIG_VNC_TLS if (tls) { vs->auth = VNC_AUTH_VENCRYPT; if (x509) { VNC_DEBUG("Initializing VNC server with x509 no auth\n"); vs->subauth = VNC_AUTH_VENCRYPT_X509NONE; } else { VNC_DEBUG("Initializing VNC server with TLS no auth\n"); vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE; } } else {#endif VNC_DEBUG("Initializing VNC server with no auth\n"); vs->auth = VNC_AUTH_NONE;#if CONFIG_VNC_TLS vs->subauth = VNC_AUTH_INVALID; }#endif }#ifndef _WIN32 if (strstart(display, "unix:", &p)) { addr = (struct sockaddr *)&uaddr; addrlen = sizeof(uaddr); vs->lsock = socket(PF_UNIX, SOCK_STREAM, 0); if (vs->lsock == -1) { fprintf(stderr, "Could not create socket\n"); free(vs->display); vs->display = NULL; return -1; } uaddr.sun_family = AF_UNIX; memset(uaddr.sun_path, 0, 108); snprintf(uaddr.sun_path, 108, "%s", p); unlink(uaddr.sun_path); } else#endif { addr = (struct sockaddr *)&iaddr; addrlen = sizeof(iaddr); if (parse_host_port(&iaddr, display) < 0) { fprintf(stderr, "Could not parse VNC address\n"); free(vs->display); vs->display = NULL; return -1; } iaddr.sin_port = htons(ntohs(iaddr.sin_port) + 5900); vs->lsock = socket(PF_INET, SOCK_STREAM, 0); if (vs->lsock == -1) { fprintf(stderr, "Could not create socket\n"); free(vs->display); vs->display = NULL; return -1; } reuse_addr = 1; ret = setsockopt(vs->lsock, SOL_SOCKET, SO_REUSEADDR, (const char *)&reuse_addr, sizeof(reuse_addr)); if (ret == -1) { fprintf(stderr, "setsockopt() failed\n"); close(vs->lsock); vs->lsock = -1; free(vs->display); vs->display = NULL; return -1; } } if (bind(vs->lsock, addr, addrlen) == -1) { fprintf(stderr, "bind() failed\n"); close(vs->lsock); vs->lsock = -1; free(vs->display); vs->display = NULL; return -1; } if (listen(vs->lsock, 1) == -1) { fprintf(stderr, "listen() failed\n"); close(vs->lsock); vs->lsock = -1; free(vs->display); vs->display = NULL; return -1; } return qemu_set_fd_handler2(vs->lsock, vnc_listen_poll, vnc_listen_read, NULL, vs);}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -