void vnc_display_open(DisplayState *ds, const char *display, Error **errp)
{
    VncDisplay *vs = vnc_display;
    const char *options;
    int password = 0;
    int reverse = 0;
#ifdef CONFIG_VNC_TLS
    int tls = 0, x509 = 0;
#endif
#ifdef CONFIG_VNC_SASL
    int sasl = 0;
    int saslErr;
#endif
#if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
    int acl = 0;
#endif
    int lock_key_sync = 1;

    if (!vnc_display) {
        error_setg(errp, "VNC display not active");
        return;
    }
    vnc_display_close(ds);
    if (strcmp(display, "none") == 0)
        return;

    vs->display = g_strdup(display);
    vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;

    options = display;
    while ((options = strchr(options, ','))) {
        options++;
        if (strncmp(options, "password", 8) == 0) {
            if (fips_get_state()) {
                error_setg(errp,
                           "VNC password auth disabled due to FIPS mode, "
                           "consider using the VeNCrypt or SASL authentication "
                           "methods as an alternative");
                goto fail;
            }
            password = 1; /* Require password auth */
        } else if (strncmp(options, "reverse", 7) == 0) {
            reverse = 1;
        } else if (strncmp(options, "no-lock-key-sync", 16) == 0) {
            lock_key_sync = 0;
#ifdef CONFIG_VNC_SASL
        } else if (strncmp(options, "sasl", 4) == 0) {
            sasl = 1; /* Require SASL auth */
#endif
#ifdef CONFIG_VNC_WS
        } else if (strncmp(options, "websocket", 9) == 0) {
            char *start, *end;
            vs->websocket = 1;

            /* Check for 'websocket=<port>' */
            start = strchr(options, '=');
            end = strchr(options, ',');
            if (start && (!end || (start < end))) {
                int len = end ? end-(start+1) : strlen(start+1);
                if (len < 6) {
                    /* extract the host specification from display */
                    char  *host = NULL, *port = NULL, *host_end = NULL;
                    port = g_strndup(start + 1, len);

                    /* ipv6 hosts have colons */
                    end = strchr(display, ',');
                    host_end = g_strrstr_len(display, end - display, ":");

                    if (host_end) {
                        host = g_strndup(display, host_end - display + 1);
                    } else {
                        host = g_strndup(":", 1);
                    }
                    vs->ws_display = g_strconcat(host, port, NULL);
                    g_free(host);
                    g_free(port);
                }
            }
#endif /* CONFIG_VNC_WS */
#ifdef 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->tls.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 = g_strndup(start + 1, len);

                VNC_DEBUG("Trying certificate path '%s'\n", path);
                if (vnc_tls_set_x509_creds_dir(vs, path) < 0) {
                    error_setg(errp, "Failed to find x509 certificates/keys in %s", path);
                    g_free(path);
                    goto fail;
                }
                g_free(path);
            } else {
                error_setg(errp, "No certificate path provided");
                goto fail;
            }
#endif
#if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
        } else if (strncmp(options, "acl", 3) == 0) {
            acl = 1;
#endif
        } else if (strncmp(options, "lossy", 5) == 0) {
#ifdef CONFIG_VNC_JPEG
            vs->lossy = true;
#endif
        } else if (strncmp(options, "non-adaptive", 12) == 0) {
            vs->non_adaptive = true;
        } else if (strncmp(options, "share=", 6) == 0) {
            if (strncmp(options+6, "ignore", 6) == 0) {
                vs->share_policy = VNC_SHARE_POLICY_IGNORE;
            } else if (strncmp(options+6, "allow-exclusive", 15) == 0) {
                vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
            } else if (strncmp(options+6, "force-shared", 12) == 0) {
                vs->share_policy = VNC_SHARE_POLICY_FORCE_SHARED;
            } else {
                error_setg(errp, "unknown vnc share= option");
                goto fail;
            }
        }
    }

    /* adaptive updates are only used with tight encoding and
     * if lossy updates are enabled so we can disable all the
     * calculations otherwise */
    if (!vs->lossy) {
        vs->non_adaptive = true;
    }

#ifdef CONFIG_VNC_TLS
    if (acl && x509 && vs->tls.x509verify) {
        if (!(vs->tls.acl = qemu_acl_init("vnc.x509dname"))) {
            fprintf(stderr, "Failed to create x509 dname ACL\n");
            exit(1);
        }
    }
#endif
#ifdef CONFIG_VNC_SASL
    if (acl && sasl) {
        if (!(vs->sasl.acl = qemu_acl_init("vnc.username"))) {
            fprintf(stderr, "Failed to create username ACL\n");
            exit(1);
        }
    }
#endif

    /*
     * Combinations we support here:
     *
     *  - no-auth                (clear text, no auth)
     *  - password               (clear text, weak auth)
     *  - sasl                   (encrypt, good auth *IF* using Kerberos via GSSAPI)
     *  - tls                    (encrypt, weak anonymous creds, no auth)
     *  - tls + password         (encrypt, weak anonymous creds, weak auth)
     *  - tls + sasl             (encrypt, weak anonymous creds, good auth)
     *  - tls + x509             (encrypt, good x509 creds, no auth)
     *  - tls + x509 + password  (encrypt, good x509 creds, weak auth)
     *  - tls + x509 + sasl      (encrypt, good x509 creds, good auth)
     *
     * NB1. TLS is a stackable auth scheme.
     * NB2. the x509 schemes have option to validate a client cert dname
     */
    if (password) {
#ifdef 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 /* CONFIG_VNC_TLS */
            VNC_DEBUG("Initializing VNC server with password auth\n");
            vs->auth = VNC_AUTH_VNC;
#ifdef CONFIG_VNC_TLS
            vs->subauth = VNC_AUTH_INVALID;
        }
#endif /* CONFIG_VNC_TLS */
#ifdef CONFIG_VNC_SASL
    } else if (sasl) {
#ifdef CONFIG_VNC_TLS
        if (tls) {
            vs->auth = VNC_AUTH_VENCRYPT;
            if (x509) {
                VNC_DEBUG("Initializing VNC server with x509 SASL auth\n");
                vs->subauth = VNC_AUTH_VENCRYPT_X509SASL;
            } else {
                VNC_DEBUG("Initializing VNC server with TLS SASL auth\n");
                vs->subauth = VNC_AUTH_VENCRYPT_TLSSASL;
            }
        } else {
#endif /* CONFIG_VNC_TLS */
            VNC_DEBUG("Initializing VNC server with SASL auth\n");
            vs->auth = VNC_AUTH_SASL;
#ifdef CONFIG_VNC_TLS
            vs->subauth = VNC_AUTH_INVALID;
        }
#endif /* CONFIG_VNC_TLS */
#endif /* CONFIG_VNC_SASL */
    } else {
#ifdef 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;
#ifdef CONFIG_VNC_TLS
            vs->subauth = VNC_AUTH_INVALID;
        }
#endif
    }

#ifdef CONFIG_VNC_SASL
    if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) {
        error_setg(errp, "Failed to initialize SASL auth: %s",
                   sasl_errstring(saslErr, NULL, NULL));
        goto fail;
    }
#endif
    vs->lock_key_sync = lock_key_sync;

    if (reverse) {
        /* connect to viewer */
        int csock;
        vs->lsock = -1;
#ifdef CONFIG_VNC_WS
        vs->lwebsock = -1;
#endif
        if (strncmp(display, "unix:", 5) == 0) {
            csock = unix_connect(display+5, errp);
        } else {
            csock = inet_connect(display, errp);
        }
        if (csock < 0) {
            goto fail;
        }
        vnc_connect(vs, csock, false, false);
    } else {
        /* listen for connects */
        char *dpy;
        dpy = g_malloc(256);
        if (strncmp(display, "unix:", 5) == 0) {
            pstrcpy(dpy, 256, "unix:");
            vs->lsock = unix_listen(display+5, dpy+5, 256-5, errp);
        } else {
            vs->lsock = inet_listen(display, dpy, 256,
                                    SOCK_STREAM, 5900, errp);
            if (vs->lsock < 0) {
                g_free(dpy);
                goto fail;
            }
#ifdef CONFIG_VNC_WS
            if (vs->websocket) {
                if (vs->ws_display) {
                    vs->lwebsock = inet_listen(vs->ws_display, NULL, 256,
                        SOCK_STREAM, 0, errp);
                } else {
                    vs->lwebsock = inet_listen(vs->display, NULL, 256,
                        SOCK_STREAM, 5700, errp);
                }

                if (vs->lwebsock < 0) {
                    if (vs->lsock) {
                        close(vs->lsock);
                        vs->lsock = -1;
                    }
                    g_free(dpy);
                    goto fail;
                }
            }
#endif /* CONFIG_VNC_WS */
        }
        g_free(vs->display);
        vs->display = dpy;
        qemu_set_fd_handler2(vs->lsock, NULL,
                vnc_listen_regular_read, NULL, vs);
#ifdef CONFIG_VNC_WS
        if (vs->websocket) {
            qemu_set_fd_handler2(vs->lwebsock, NULL,
                    vnc_listen_websocket_read, NULL, vs);
        }
#endif /* CONFIG_VNC_WS */
    }
    return;

fail:
    g_free(vs->display);
    vs->display = NULL;
#ifdef CONFIG_VNC_WS
    g_free(vs->ws_display);
    vs->ws_display = NULL;
#endif /* CONFIG_VNC_WS */
}