summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--monitor.c23
-rw-r--r--qemu-deprecated.texi11
-rw-r--r--qemu-options.hx35
-rw-r--r--ui/curses.c79
-rw-r--r--ui/curses_keys.h113
-rw-r--r--ui/vnc.c64
6 files changed, 243 insertions, 82 deletions
diff --git a/monitor.c b/monitor.c
index defa129319..72061d5bae 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2032,6 +2032,19 @@ static QAuthZList *find_auth(Monitor *mon, const char *name)
     return QAUTHZ_LIST(obj);
 }
 
+static bool warn_acl;
+static void hmp_warn_acl(void)
+{
+    if (warn_acl) {
+        return;
+    }
+    error_report("The acl_show, acl_reset, acl_policy, acl_add, acl_remove "
+                 "commands are deprecated with no replacement. Authorization "
+                 "for VNC should be performed using the pluggable QAuthZ "
+                 "objects");
+    warn_acl = true;
+}
+
 static void hmp_acl_show(Monitor *mon, const QDict *qdict)
 {
     const char *aclname = qdict_get_str(qdict, "aclname");
@@ -2039,6 +2052,8 @@ static void hmp_acl_show(Monitor *mon, const QDict *qdict)
     QAuthZListRuleList *rules;
     size_t i = 0;
 
+    hmp_warn_acl();
+
     if (!auth) {
         return;
     }
@@ -2062,6 +2077,8 @@ static void hmp_acl_reset(Monitor *mon, const QDict *qdict)
     const char *aclname = qdict_get_str(qdict, "aclname");
     QAuthZList *auth = find_auth(mon, aclname);
 
+    hmp_warn_acl();
+
     if (!auth) {
         return;
     }
@@ -2080,6 +2097,8 @@ static void hmp_acl_policy(Monitor *mon, const QDict *qdict)
     int val;
     Error *err = NULL;
 
+    hmp_warn_acl();
+
     if (!auth) {
         return;
     }
@@ -2124,6 +2143,8 @@ static void hmp_acl_add(Monitor *mon, const QDict *qdict)
     QAuthZListFormat format;
     size_t i = 0;
 
+    hmp_warn_acl();
+
     if (!auth) {
         return;
     }
@@ -2169,6 +2190,8 @@ static void hmp_acl_remove(Monitor *mon, const QDict *qdict)
     QAuthZList *auth = find_auth(mon, aclname);
     ssize_t i = 0;
 
+    hmp_warn_acl();
+
     if (!auth) {
         return;
     }
diff --git a/qemu-deprecated.texi b/qemu-deprecated.texi
index 45c57952da..1e15f57e9c 100644
--- a/qemu-deprecated.texi
+++ b/qemu-deprecated.texi
@@ -60,6 +60,11 @@ Support for invalid topologies will be removed, the user must ensure
 topologies described with -smp include all possible cpus, i.e.
   @math{@var{sockets} * @var{cores} * @var{threads} = @var{maxcpus}}.
 
+@subsection -vnc acl (since 4.0.0)
+
+The @code{acl} option to the @code{-vnc} argument has been replaced
+by the @code{tls-authz} and @code{sasl-authz} options.
+
 @section QEMU Machine Protocol (QMP) commands
 
 @subsection block-dirty-bitmap-add "autoload" parameter (since 2.12.0)
@@ -99,6 +104,12 @@ The @option{[hub_id name]} parameter tuple of the 'hostfwd_add' and
 Use ``device_add'' for hotplugging vCPUs instead of ``cpu-add''.  See
 documentation of ``query-hotpluggable-cpus'' for additional details.
 
+@subsection acl_show, acl_reset, acl_policy, acl_add, acl_remove (since 4.0.0)
+
+The ``acl_show'', ``acl_reset'', ``acl_policy'', ``acl_add'', and
+``acl_remove'' commands are deprecated with no replacement. Authorization
+for VNC should be performed using the pluggable QAuthZ objects.
+
 @section System emulator devices
 
 @subsection bluetooth (since 3.1)
diff --git a/qemu-options.hx b/qemu-options.hx
index 1cf9aac1fe..c74f99b265 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1624,6 +1624,14 @@ will cause the VNC server socket to enable the VeNCrypt auth
 mechanism.  The credentials should have been previously created
 using the @option{-object tls-creds} argument.
 
+@item tls-authz=@var{ID}
+
+Provides the ID of the QAuthZ authorization object against which
+the client's x509 distinguished name will validated. This object is
+only resolved at time of use, so can be deleted and recreated on the
+fly while the VNC server is active. If missing, it will default
+to denying access.
+
 @item sasl
 
 Require that the client use SASL to authenticate with the VNC server.
@@ -1639,18 +1647,25 @@ ensures a data encryption preventing compromise of authentication
 credentials. See the @ref{vnc_security} section for details on using
 SASL authentication.
 
+@item sasl-authz=@var{ID}
+
+Provides the ID of the QAuthZ authorization object against which
+the client's SASL username will validated. This object is
+only resolved at time of use, so can be deleted and recreated on the
+fly while the VNC server is active. If missing, it will default
+to denying access.
+
 @item acl
 
-Turn on access control lists for checking of the x509 client certificate
-and SASL party. For x509 certs, the ACL check is made against the
-certificate's distinguished name. This is something that looks like
-@code{C=GB,O=ACME,L=Boston,CN=bob}. For SASL party, the ACL check is
-made against the username, which depending on the SASL plugin, may
-include a realm component, eg @code{bob} or @code{bob@@EXAMPLE.COM}.
-When the @option{acl} flag is set, the initial access list will be
-empty, with a @code{deny} policy. Thus no one will be allowed to
-use the VNC server until the ACLs have been loaded. This can be
-achieved using the @code{acl} monitor command.
+Legacy method for enabling authorization of clients against the
+x509 distinguished name and SASL username. It results in the creation
+of two @code{authz-list} objects with IDs of @code{vnc.username} and
+@code{vnc.x509dname}. The rules for these objects must be configured
+with the HMP ACL commands.
+
+This option is deprecated and should no longer be used. The new
+@option{sasl-authz} and @option{tls-authz} options are a
+replacement.
 
 @item lossy
 
diff --git a/ui/curses.c b/ui/curses.c
index 6e0091c3b2..37954ce1b0 100644
--- a/ui/curses.c
+++ b/ui/curses.c
@@ -42,6 +42,12 @@
 #define FONT_HEIGHT 16
 #define FONT_WIDTH 8
 
+enum maybe_keycode {
+    CURSES_KEYCODE,
+    CURSES_CHAR,
+    CURSES_CHAR_OR_KEYCODE,
+};
+
 static DisplayChangeListener *dcl;
 static console_ch_t screen[160 * 100];
 static WINDOW *screenpad = NULL;
@@ -194,9 +200,54 @@ static void curses_cursor_position(DisplayChangeListener *dcl,
 
 static kbd_layout_t *kbd_layout = NULL;
 
+static wint_t console_getch(enum maybe_keycode *maybe_keycode)
+{
+    wint_t ret;
+    switch (get_wch(&ret)) {
+    case KEY_CODE_YES:
+        *maybe_keycode = CURSES_KEYCODE;
+        break;
+    case OK:
+        *maybe_keycode = CURSES_CHAR;
+        break;
+    case ERR:
+        ret = -1;
+        break;
+    }
+    return ret;
+}
+
+static int curses2foo(const int _curses2foo[], const int _curseskey2foo[],
+                      int chr, enum maybe_keycode maybe_keycode)
+{
+    int ret = -1;
+    if (maybe_keycode == CURSES_CHAR) {
+        if (chr < CURSES_CHARS) {
+            ret = _curses2foo[chr];
+        }
+    } else {
+        if (chr < CURSES_KEYS) {
+            ret = _curseskey2foo[chr];
+        }
+        if (ret == -1 && maybe_keycode == CURSES_CHAR_OR_KEYCODE &&
+            chr < CURSES_CHARS) {
+            ret = _curses2foo[chr];
+        }
+    }
+    return ret;
+}
+
+#define curses2keycode(chr, maybe_keycode) \
+    curses2foo(_curses2keycode, _curseskey2keycode, chr, maybe_keycode)
+#define curses2keysym(chr, maybe_keycode) \
+    curses2foo(_curses2keysym, _curseskey2keysym, chr, maybe_keycode)
+#define curses2qemu(chr, maybe_keycode) \
+    curses2foo(_curses2qemu, _curseskey2qemu, chr, maybe_keycode)
+
 static void curses_refresh(DisplayChangeListener *dcl)
 {
     int chr, keysym, keycode, keycode_alt;
+    enum maybe_keycode maybe_keycode;
 
     curses_winch_check();
 
@@ -212,14 +263,14 @@ static void curses_refresh(DisplayChangeListener *dcl)
 
     while (1) {
         /* while there are any pending key strokes to process */
-        chr = getch();
+        chr = console_getch(&maybe_keycode);
 
-        if (chr == ERR)
+        if (chr == -1)
             break;
 
 #ifdef KEY_RESIZE
         /* this shouldn't occur when we use a custom SIGWINCH handler */
-        if (chr == KEY_RESIZE) {
+        if (maybe_keycode != CURSES_CHAR && chr == KEY_RESIZE) {
             clear();
             refresh();
             curses_calc_pad();
@@ -228,17 +279,19 @@ static void curses_refresh(DisplayChangeListener *dcl)
         }
 #endif
 
-        keycode = curses2keycode[chr];
+        keycode = curses2keycode(chr, maybe_keycode);
         keycode_alt = 0;
 
-        /* alt key */
+        /* alt or esc key */
         if (keycode == 1) {
-            int nextchr = getch();
+            enum maybe_keycode next_maybe_keycode;
+            int nextchr = console_getch(&next_maybe_keycode);
 
-            if (nextchr != ERR) {
+            if (nextchr != -1) {
                 chr = nextchr;
+                maybe_keycode = next_maybe_keycode;
                 keycode_alt = ALT;
-                keycode = curses2keycode[chr];
+                keycode = curses2keycode(chr, maybe_keycode);
 
                 if (keycode != -1) {
                     keycode |= ALT;
@@ -258,9 +311,7 @@ static void curses_refresh(DisplayChangeListener *dcl)
         }
 
         if (kbd_layout) {
-            keysym = -1;
-            if (chr < CURSES_KEYS)
-                keysym = curses2keysym[chr];
+            keysym = curses2keysym(chr, maybe_keycode);
 
             if (keysym == -1) {
                 if (chr < ' ') {
@@ -326,10 +377,7 @@ static void curses_refresh(DisplayChangeListener *dcl)
                 qemu_input_event_send_key_delay(0);
             }
         } else {
-            keysym = -1;
-            if (chr < CURSES_KEYS) {
-                keysym = curses2qemu[chr];
-            }
+            keysym = curses2qemu(chr, maybe_keycode);
             if (keysym == -1)
                 keysym = chr;
 
@@ -361,6 +409,7 @@ static void curses_setup(void)
     initscr(); noecho(); intrflush(stdscr, FALSE);
     nodelay(stdscr, TRUE); nonl(); keypad(stdscr, TRUE);
     start_color(); raw(); scrollok(stdscr, FALSE);
+    set_escdelay(25);
 
     /* Make color pair to match color format (3bits bg:3bits fg) */
     for (i = 0; i < 64; i++) {
diff --git a/ui/curses_keys.h b/ui/curses_keys.h
index e9195a1671..71e04acdc7 100644
--- a/ui/curses_keys.h
+++ b/ui/curses_keys.h
@@ -49,22 +49,28 @@
 /* curses won't detect a Control + Alt + 1, so use Alt + 1 */
 #define QEMU_KEY_CONSOLE0   (2 | ALT)   /* (curses2keycode['1'] | ALT) */
 
+#define CURSES_CHARS        0x100       /* Support latin1 only */
 #define CURSES_KEYS         KEY_MAX     /* KEY_MAX defined in <curses.h> */
 
-static const int curses2keysym[CURSES_KEYS] = {
-    [0 ... (CURSES_KEYS - 1)] = -1,
+static const int _curses2keysym[CURSES_CHARS] = {
+    [0 ... (CURSES_CHARS - 1)] = -1,
 
     [0x7f] = KEY_BACKSPACE,
     ['\r'] = KEY_ENTER,
     ['\n'] = KEY_ENTER,
     [27] = 27,
+};
+
+static const int _curseskey2keysym[CURSES_KEYS] = {
+    [0 ... (CURSES_KEYS - 1)] = -1,
+
     [KEY_BTAB] = '\t' | KEYSYM_SHIFT,
     [KEY_SPREVIOUS] = KEY_PPAGE | KEYSYM_SHIFT,
     [KEY_SNEXT] = KEY_NPAGE | KEYSYM_SHIFT,
 };
 
-static const int curses2keycode[CURSES_KEYS] = {
-    [0 ... (CURSES_KEYS - 1)] = -1,
+static const int _curses2keycode[CURSES_CHARS] = {
+    [0 ... (CURSES_CHARS - 1)] = -1,
 
     [0x01b] = 1, /* Escape */
     ['1'] = 2,
@@ -80,7 +86,6 @@ static const int curses2keycode[CURSES_KEYS] = {
     ['-'] = 12,
     ['='] = 13,
     [0x07f] = 14, /* Backspace */
-    [KEY_BACKSPACE] = 14, /* Backspace */
 
     ['\t'] = 15, /* Tab */
     ['q'] = 16,
@@ -97,7 +102,6 @@ static const int curses2keycode[CURSES_KEYS] = {
     [']'] = 27,
     ['\n'] = 28, /* Return */
     ['\r'] = 28, /* Return */
-    [KEY_ENTER] = 28, /* Return */
 
     ['a'] = 30,
     ['s'] = 31,
@@ -126,33 +130,6 @@ static const int curses2keycode[CURSES_KEYS] = {
 
     [' '] = 57,
 
-    [KEY_F(1)] = 59, /* Function Key 1 */
-    [KEY_F(2)] = 60, /* Function Key 2 */
-    [KEY_F(3)] = 61, /* Function Key 3 */
-    [KEY_F(4)] = 62, /* Function Key 4 */
-    [KEY_F(5)] = 63, /* Function Key 5 */
-    [KEY_F(6)] = 64, /* Function Key 6 */
-    [KEY_F(7)] = 65, /* Function Key 7 */
-    [KEY_F(8)] = 66, /* Function Key 8 */
-    [KEY_F(9)] = 67, /* Function Key 9 */
-    [KEY_F(10)] = 68, /* Function Key 10 */
-    [KEY_F(11)] = 87, /* Function Key 11 */
-    [KEY_F(12)] = 88, /* Function Key 12 */
-
-    [KEY_HOME] = 71 | GREY, /* Home */
-    [KEY_UP] = 72 | GREY, /* Up Arrow */
-    [KEY_PPAGE] = 73 | GREY, /* Page Up */
-    [KEY_LEFT] = 75 | GREY, /* Left Arrow */
-    [KEY_RIGHT] = 77 | GREY, /* Right Arrow */
-    [KEY_END] = 79 | GREY, /* End */
-    [KEY_DOWN] = 80 | GREY, /* Down Arrow */
-    [KEY_NPAGE] = 81 | GREY, /* Page Down */
-    [KEY_IC] = 82 | GREY, /* Insert */
-    [KEY_DC] = 83 | GREY, /* Delete */
-
-    [KEY_SPREVIOUS] = 73 | GREY | SHIFT, /* Shift + Page Up */
-    [KEY_SNEXT] = 81 | GREY | SHIFT, /* Shift + Page Down */
-
     ['!'] = 2 | SHIFT,
     ['@'] = 3 | SHIFT,
     ['#'] = 4 | SHIFT,
@@ -166,7 +143,6 @@ static const int curses2keycode[CURSES_KEYS] = {
     ['_'] = 12 | SHIFT,
     ['+'] = 13 | SHIFT,
 
-    [KEY_BTAB] = 15 | SHIFT, /* Shift + Tab */
     ['Q'] = 16 | SHIFT,
     ['W'] = 17 | SHIFT,
     ['E'] = 18 | SHIFT,
@@ -205,19 +181,6 @@ static const int curses2keycode[CURSES_KEYS] = {
     ['>'] = 52 | SHIFT,
     ['?'] = 53 | SHIFT,
 
-    [KEY_F(13)] = 59 | SHIFT, /* Shift + Function Key 1 */
-    [KEY_F(14)] = 60 | SHIFT, /* Shift + Function Key 2 */
-    [KEY_F(15)] = 61 | SHIFT, /* Shift + Function Key 3 */
-    [KEY_F(16)] = 62 | SHIFT, /* Shift + Function Key 4 */
-    [KEY_F(17)] = 63 | SHIFT, /* Shift + Function Key 5 */
-    [KEY_F(18)] = 64 | SHIFT, /* Shift + Function Key 6 */
-    [KEY_F(19)] = 65 | SHIFT, /* Shift + Function Key 7 */
-    [KEY_F(20)] = 66 | SHIFT, /* Shift + Function Key 8 */
-    [KEY_F(21)] = 67 | SHIFT, /* Shift + Function Key 9 */
-    [KEY_F(22)] = 68 | SHIFT, /* Shift + Function Key 10 */
-    [KEY_F(23)] = 69 | SHIFT, /* Shift + Function Key 11 */
-    [KEY_F(24)] = 70 | SHIFT, /* Shift + Function Key 12 */
-
     ['Q' - '@'] = 16 | CNTRL, /* Control + q */
     ['W' - '@'] = 17 | CNTRL, /* Control + w */
     ['E' - '@'] = 18 | CNTRL, /* Control + e */
@@ -249,13 +212,67 @@ static const int curses2keycode[CURSES_KEYS] = {
 
 };
 
-static const int curses2qemu[CURSES_KEYS] = {
+static const int _curseskey2keycode[CURSES_KEYS] = {
     [0 ... (CURSES_KEYS - 1)] = -1,
 
+    [KEY_BACKSPACE] = 14, /* Backspace */
+
+    [KEY_ENTER] = 28, /* Return */
+
+    [KEY_F(1)] = 59, /* Function Key 1 */
+    [KEY_F(2)] = 60, /* Function Key 2 */
+    [KEY_F(3)] = 61, /* Function Key 3 */
+    [KEY_F(4)] = 62, /* Function Key 4 */
+    [KEY_F(5)] = 63, /* Function Key 5 */
+    [KEY_F(6)] = 64, /* Function Key 6 */
+    [KEY_F(7)] = 65, /* Function Key 7 */
+    [KEY_F(8)] = 66, /* Function Key 8 */
+    [KEY_F(9)] = 67, /* Function Key 9 */
+    [KEY_F(10)] = 68, /* Function Key 10 */
+    [KEY_F(11)] = 87, /* Function Key 11 */
+    [KEY_F(12)] = 88, /* Function Key 12 */
+
+    [KEY_HOME] = 71 | GREY, /* Home */
+    [KEY_UP] = 72 | GREY, /* Up Arrow */
+    [KEY_PPAGE] = 73 | GREY, /* Page Up */
+    [KEY_LEFT] = 75 | GREY, /* Left Arrow */
+    [KEY_RIGHT] = 77 | GREY, /* Right Arrow */
+    [KEY_END] = 79 | GREY, /* End */
+    [KEY_DOWN] = 80 | GREY, /* Down Arrow */
+    [KEY_NPAGE] = 81 | GREY, /* Page Down */
+    [KEY_IC] = 82 | GREY, /* Insert */
+    [KEY_DC] = 83 | GREY, /* Delete */
+
+    [KEY_SPREVIOUS] = 73 | GREY | SHIFT, /* Shift + Page Up */
+    [KEY_SNEXT] = 81 | GREY | SHIFT, /* Shift + Page Down */
+
+    [KEY_BTAB] = 15 | SHIFT, /* Shift + Tab */
+
+    [KEY_F(13)] = 59 | SHIFT, /* Shift + Function Key 1 */
+    [KEY_F(14)] = 60 | SHIFT, /* Shift + Function Key 2 */
+    [KEY_F(15)] = 61 | SHIFT, /* Shift + Function Key 3 */
+    [KEY_F(16)] = 62 | SHIFT, /* Shift + Function Key 4 */
+    [KEY_F(17)] = 63 | SHIFT, /* Shift + Function Key 5 */
+    [KEY_F(18)] = 64 | SHIFT, /* Shift + Function Key 6 */
+    [KEY_F(19)] = 65 | SHIFT, /* Shift + Function Key 7 */
+    [KEY_F(20)] = 66 | SHIFT, /* Shift + Function Key 8 */
+    [KEY_F(21)] = 67 | SHIFT, /* Shift + Function Key 9 */
+    [KEY_F(22)] = 68 | SHIFT, /* Shift + Function Key 10 */
+    [KEY_F(23)] = 69 | SHIFT, /* Shift + Function Key 11 */
+    [KEY_F(24)] = 70 | SHIFT, /* Shift + Function Key 12 */
+};
+
+static const int _curses2qemu[CURSES_CHARS] = {
+    [0 ... (CURSES_CHARS - 1)] = -1,
+
     ['\n'] = '\n',
     ['\r'] = '\n',
 
     [0x07f] = QEMU_KEY_BACKSPACE,
+};
+
+static const int _curseskey2qemu[CURSES_KEYS] = {
+    [0 ... (CURSES_KEYS - 1)] = -1,
 
     [KEY_DOWN] = QEMU_KEY_DOWN,
     [KEY_UP] = QEMU_KEY_UP,
diff --git a/ui/vnc.c b/ui/vnc.c
index da4a21d4ce..2d9e8f43b0 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -700,6 +700,12 @@ static void vnc_abort_display_jobs(VncDisplay *vd)
     }
     QTAILQ_FOREACH(vs, &vd->clients, next) {
         vnc_lock_output(vs);
+        if (vs->update == VNC_STATE_UPDATE_NONE &&
+            vs->job_update != VNC_STATE_UPDATE_NONE) {
+            /* job aborted before completion */
+            vs->update = vs->job_update;
+            vs->job_update = VNC_STATE_UPDATE_NONE;
+        }
         vs->abort = false;
         vnc_unlock_output(vs);
     }
@@ -3358,6 +3364,12 @@ static QemuOptsList qemu_vnc_opts = {
             .name = "acl",
             .type = QEMU_OPT_BOOL,
         },{
+            .name = "tls-authz",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "sasl-authz",
+            .type = QEMU_OPT_STRING,
+        },{
             .name = "lossy",
             .type = QEMU_OPT_BOOL,
         },{
@@ -3796,6 +3808,8 @@ void vnc_display_open(const char *id, Error **errp)
     const char *credid;
     bool sasl = false;
     int acl = 0;
+    const char *tlsauthz;
+    const char *saslauthz;
     int lock_key_sync = 1;
     int key_delay_ms;
 
@@ -3867,7 +3881,33 @@ void vnc_display_open(const char *id, Error **errp)
             goto fail;
         }
     }
+    if (qemu_opt_get(opts, "acl")) {
+        error_report("The 'acl' option to -vnc is deprecated. "
+                     "Please use the 'tls-authz' and 'sasl-authz' "
+                     "options instead");
+    }
     acl = qemu_opt_get_bool(opts, "acl", false);
+    tlsauthz = qemu_opt_get(opts, "tls-authz");
+    if (acl && tlsauthz) {
+        error_setg(errp, "'acl' option is mutually exclusive with the "
+                   "'tls-authz' option");
+        goto fail;
+    }
+    if (tlsauthz && !vd->tlscreds) {
+        error_setg(errp, "'tls-authz' provided but TLS is not enabled");
+        goto fail;
+    }
+
+    saslauthz = qemu_opt_get(opts, "sasl-authz");
+    if (acl && saslauthz) {
+        error_setg(errp, "'acl' option is mutually exclusive with the "
+                   "'sasl-authz' option");
+        goto fail;
+    }
+    if (saslauthz && !sasl) {
+        error_setg(errp, "'sasl-authz' provided but SASL auth is not enabled");
+        goto fail;
+    }
 
     share = qemu_opt_get(opts, "share");
     if (share) {
@@ -3897,7 +3937,9 @@ void vnc_display_open(const char *id, Error **errp)
         vd->non_adaptive = true;
     }
 
-    if (acl) {
+    if (tlsauthz) {
+        vd->tlsauthzid = g_strdup(tlsauthz);
+    } else if (acl) {
         if (strcmp(vd->id, "default") == 0) {
             vd->tlsauthzid = g_strdup("vnc.x509dname");
         } else {
@@ -3908,15 +3950,19 @@ void vnc_display_open(const char *id, Error **errp)
                                               &error_abort));
     }
 #ifdef CONFIG_VNC_SASL
-    if (acl && sasl) {
-        if (strcmp(vd->id, "default") == 0) {
-            vd->sasl.authzid = g_strdup("vnc.username");
-        } else {
-            vd->sasl.authzid = g_strdup_printf("vnc.%s.username", vd->id);
+    if (sasl) {
+        if (saslauthz) {
+            vd->sasl.authzid = g_strdup(saslauthz);
+        } else if (acl) {
+            if (strcmp(vd->id, "default") == 0) {
+                vd->sasl.authzid = g_strdup("vnc.username");
+            } else {
+                vd->sasl.authzid = g_strdup_printf("vnc.%s.username", vd->id);
+            }
+            vd->sasl.authz = QAUTHZ(qauthz_list_new(vd->sasl.authzid,
+                                                    QAUTHZ_LIST_POLICY_DENY,
+                                                    &error_abort));
         }
-        vd->sasl.authz = QAUTHZ(qauthz_list_new(vd->sasl.authzid,
-                                                QAUTHZ_LIST_POLICY_DENY,
-                                                &error_abort));
     }
 #endif