* [Qemu-devel] [PATCH v2 1/3] vnc: auth reject cleanup
2010-11-30 13:22 [Qemu-devel] [PATCH v2 0/3] vnc/spice: add monitor commands to change+expire passwords Gerd Hoffmann
@ 2010-11-30 13:22 ` Gerd Hoffmann
2010-11-30 13:22 ` [Qemu-devel] [PATCH v2 2/3] vnc: support password expire Gerd Hoffmann
` (2 subsequent siblings)
3 siblings, 0 replies; 7+ messages in thread
From: Gerd Hoffmann @ 2010-11-30 13:22 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
protocol_client_auth_vnc() has two places where the auth can fail,
with identical code sending the reject message to the client.
Move the common code to the end of the function and make both
error paths jump there. No functional change.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
ui/vnc.c | 30 +++++++++++++-----------------
1 files changed, 13 insertions(+), 17 deletions(-)
diff --git a/ui/vnc.c b/ui/vnc.c
index 864342e..da70757 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -2085,15 +2085,7 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
if (!vs->vd->password || !vs->vd->password[0]) {
VNC_DEBUG("No password configured on server");
- vnc_write_u32(vs, 1); /* Reject auth */
- if (vs->minor >= 8) {
- static const char err[] = "Authentication failed";
- vnc_write_u32(vs, sizeof(err));
- vnc_write(vs, err, sizeof(err));
- }
- vnc_flush(vs);
- vnc_client_error(vs);
- return 0;
+ goto reject;
}
memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE);
@@ -2109,14 +2101,7 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
/* Compare expected vs actual challenge response */
if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) {
VNC_DEBUG("Client challenge reponse did not match\n");
- vnc_write_u32(vs, 1); /* Reject auth */
- if (vs->minor >= 8) {
- static const char err[] = "Authentication failed";
- vnc_write_u32(vs, sizeof(err));
- vnc_write(vs, err, sizeof(err));
- }
- vnc_flush(vs);
- vnc_client_error(vs);
+ goto reject;
} else {
VNC_DEBUG("Accepting VNC challenge response\n");
vnc_write_u32(vs, 0); /* Accept auth */
@@ -2125,6 +2110,17 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
start_client_init(vs);
}
return 0;
+
+reject:
+ vnc_write_u32(vs, 1); /* Reject auth */
+ if (vs->minor >= 8) {
+ static const char err[] = "Authentication failed";
+ vnc_write_u32(vs, sizeof(err));
+ vnc_write(vs, err, sizeof(err));
+ }
+ vnc_flush(vs);
+ vnc_client_error(vs);
+ return 0;
}
void start_auth_vnc(VncState *vs)
--
1.7.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [Qemu-devel] [PATCH v2 2/3] vnc: support password expire
2010-11-30 13:22 [Qemu-devel] [PATCH v2 0/3] vnc/spice: add monitor commands to change+expire passwords Gerd Hoffmann
2010-11-30 13:22 ` [Qemu-devel] [PATCH v2 1/3] vnc: auth reject cleanup Gerd Hoffmann
@ 2010-11-30 13:22 ` Gerd Hoffmann
2010-11-30 13:22 ` [Qemu-devel] [PATCH v2 3/3] vnc/spice: add set_passwd monitor command Gerd Hoffmann
2010-12-01 14:10 ` [Qemu-devel] [PATCH v2 0/3] vnc/spice: add monitor commands to change+expire passwords Anthony Liguori
3 siblings, 0 replies; 7+ messages in thread
From: Gerd Hoffmann @ 2010-11-30 13:22 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
This patch adds support for expiring passwords to vnc. It adds a new
vnc_display_pw_expire() function which specifies the time when the
password will expire.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
console.h | 1 +
qemu-common.h | 3 +++
ui/vnc.c | 14 ++++++++++++++
ui/vnc.h | 1 +
4 files changed, 19 insertions(+), 0 deletions(-)
diff --git a/console.h b/console.h
index aafb031..b2fc908 100644
--- a/console.h
+++ b/console.h
@@ -369,6 +369,7 @@ void vnc_display_init(DisplayState *ds);
void vnc_display_close(DisplayState *ds);
int vnc_display_open(DisplayState *ds, const char *display);
int vnc_display_password(DisplayState *ds, const char *password);
+int vnc_display_pw_expire(DisplayState *ds, time_t expires);
void do_info_vnc_print(Monitor *mon, const QObject *data);
void do_info_vnc(Monitor *mon, QObject **ret_data);
char *vnc_display_local_addr(DisplayState *ds);
diff --git a/qemu-common.h b/qemu-common.h
index b3957f1..d0ab116 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -50,6 +50,9 @@ typedef struct DeviceState DeviceState;
#if !defined(ENOTSUP)
#define ENOTSUP 4096
#endif
+#ifndef TIME_MAX
+#define TIME_MAX LONG_MAX
+#endif
#ifndef CONFIG_IOVEC
#define CONFIG_IOVEC
diff --git a/ui/vnc.c b/ui/vnc.c
index da70757..495d6d6 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -2082,11 +2082,16 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
unsigned char response[VNC_AUTH_CHALLENGE_SIZE];
int i, j, pwlen;
unsigned char key[8];
+ time_t now = time(NULL);
if (!vs->vd->password || !vs->vd->password[0]) {
VNC_DEBUG("No password configured on server");
goto reject;
}
+ if (vs->vd->expires < now) {
+ VNC_DEBUG("Password is expired");
+ goto reject;
+ }
memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE);
@@ -2432,6 +2437,7 @@ void vnc_display_init(DisplayState *ds)
vs->ds = ds;
QTAILQ_INIT(&vs->clients);
+ vs->expires = TIME_MAX;
if (keyboard_layout)
vs->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
@@ -2503,6 +2509,14 @@ int vnc_display_password(DisplayState *ds, const char *password)
return 0;
}
+int vnc_display_pw_expire(DisplayState *ds, time_t expires)
+{
+ VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
+
+ vs->expires = expires;
+ return 0;
+}
+
char *vnc_display_local_addr(DisplayState *ds)
{
VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
diff --git a/ui/vnc.h b/ui/vnc.h
index 9619b24..4f895be 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -120,6 +120,7 @@ struct VncDisplay
char *display;
char *password;
+ time_t expires;
int auth;
bool lossy;
#ifdef CONFIG_VNC_TLS
--
1.7.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [Qemu-devel] [PATCH v2 3/3] vnc/spice: add set_passwd monitor command.
2010-11-30 13:22 [Qemu-devel] [PATCH v2 0/3] vnc/spice: add monitor commands to change+expire passwords Gerd Hoffmann
2010-11-30 13:22 ` [Qemu-devel] [PATCH v2 1/3] vnc: auth reject cleanup Gerd Hoffmann
2010-11-30 13:22 ` [Qemu-devel] [PATCH v2 2/3] vnc: support password expire Gerd Hoffmann
@ 2010-11-30 13:22 ` Gerd Hoffmann
2010-12-01 14:10 ` [Qemu-devel] [PATCH v2 0/3] vnc/spice: add monitor commands to change+expire passwords Anthony Liguori
3 siblings, 0 replies; 7+ messages in thread
From: Gerd Hoffmann @ 2010-11-30 13:22 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
This patch adds new set_password and expire_password monitor commands
which allows to change and expire the password for spice and vnc
connections. See the doc update patch chunk for details.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hmp-commands.hx | 54 +++++++++++++++++++++++++++++
monitor.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
qmp-commands.hx | 57 +++++++++++++++++++++++++++++++
ui/qemu-spice.h | 5 +++
ui/spice-core.c | 35 +++++++++++++++++++
5 files changed, 251 insertions(+), 0 deletions(-)
diff --git a/hmp-commands.hx b/hmp-commands.hx
index e5585ba..9632ee8 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1117,6 +1117,60 @@ Set the encrypted device @var{device} password to @var{password}
ETEXI
{
+ .name = "set_password",
+ .args_type = "protocol:s,password:s,connected:s?",
+ .params = "protocol password action-if-connected",
+ .help = "set spice/vnc password",
+ .user_print = monitor_user_noop,
+ .mhandler.cmd_new = set_password,
+ },
+
+STEXI
+@item set_password [ vnc | spice ] password [ action-if-connected ]
+@findex set_password
+
+Change spice/vnc password. Use zero to make the password stay valid
+forever. @var{action-if-connected} specifies what should happen in
+case a connection is established: @var{fail} makes the password change
+fail. @var{disconnect} changes the password and disconnects the
+client. @var{keep} changes the password and keeps the connection up.
+@var{keep} is the default.
+ETEXI
+
+ {
+ .name = "expire_password",
+ .args_type = "protocol:s,time:s",
+ .params = "protocol time",
+ .help = "set spice/vnc password expire-time",
+ .user_print = monitor_user_noop,
+ .mhandler.cmd_new = expire_password,
+ },
+
+STEXI
+@item expire_password [ vnc | spice ] expire-time
+@findex expire_password
+
+Specify when a password for spice/vnc becomes
+invalid. @var{expire-time} accepts:
+
+@table @var
+@item now
+Invalidate password instantly.
+
+@item never
+Password stays valid forever.
+
+@item +nsec
+Password stays valid for @var{nsec} seconds starting now.
+
+@item nsec
+Password is invalidated at the given time. @var{nsec} are the seconds
+passed since 1970, i.e. unix epoch.
+
+@end table
+ETEXI
+
+ {
.name = "info",
.args_type = "item:s?",
.params = "[subcommand]",
diff --git a/monitor.c b/monitor.c
index bfeec0f..7b68df6 100644
--- a/monitor.c
+++ b/monitor.c
@@ -34,6 +34,7 @@
#include "net.h"
#include "net/slirp.h"
#include "qemu-char.h"
+#include "ui/qemu-spice.h"
#include "sysemu.h"
#include "monitor.h"
#include "readline.h"
@@ -1037,6 +1038,105 @@ static int do_change(Monitor *mon, const QDict *qdict, QObject **ret_data)
return ret;
}
+static int set_password(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+ const char *protocol = qdict_get_str(qdict, "protocol");
+ const char *password = qdict_get_str(qdict, "password");
+ const char *connected = qdict_get_try_str(qdict, "connected");
+ int disconnect_if_connected = 0;
+ int fail_if_connected = 0;
+ int rc;
+
+ if (connected) {
+ if (strcmp(connected, "fail") == 0) {
+ fail_if_connected = 1;
+ } else if (strcmp(connected, "disconnect") == 0) {
+ disconnect_if_connected = 1;
+ } else if (strcmp(connected, "keep") == 0) {
+ /* nothing */
+ } else {
+ qerror_report(QERR_INVALID_PARAMETER, "connected");
+ return -1;
+ }
+ }
+
+ if (strcmp(protocol, "spice") == 0) {
+ if (!using_spice) {
+ /* correct one? spice isn't a device ,,, */
+ qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice");
+ return -1;
+ }
+ rc = qemu_spice_set_passwd(password, fail_if_connected,
+ disconnect_if_connected);
+ if (rc != 0) {
+ qerror_report(QERR_SET_PASSWD_FAILED);
+ return -1;
+ }
+ return 0;
+ }
+
+ if (strcmp(protocol, "vnc") == 0) {
+ if (fail_if_connected || disconnect_if_connected) {
+ /* vnc supports "connected=keep" only */
+ qerror_report(QERR_INVALID_PARAMETER, "connected");
+ return -1;
+ }
+ rc = vnc_display_password(NULL, password);
+ if (rc != 0) {
+ qerror_report(QERR_SET_PASSWD_FAILED);
+ return -1;
+ }
+ return 0;
+ }
+
+ qerror_report(QERR_INVALID_PARAMETER, "protocol");
+ return -1;
+}
+
+static int expire_password(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+ const char *protocol = qdict_get_str(qdict, "protocol");
+ const char *whenstr = qdict_get_str(qdict, "time");
+ time_t when;
+ int rc;
+
+ if (strcmp(whenstr, "now")) {
+ when = 0;
+ } else if (strcmp(whenstr, "never")) {
+ when = TIME_MAX;
+ } else if (whenstr[0] == '+') {
+ when = time(NULL) + strtoull(whenstr+1, NULL, 10);
+ } else {
+ when = strtoull(whenstr, NULL, 10);
+ }
+
+ if (strcmp(protocol, "spice") == 0) {
+ if (!using_spice) {
+ /* correct one? spice isn't a device ,,, */
+ qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice");
+ return -1;
+ }
+ rc = qemu_spice_set_pw_expire(when);
+ if (rc != 0) {
+ qerror_report(QERR_SET_PASSWD_FAILED);
+ return -1;
+ }
+ return 0;
+ }
+
+ if (strcmp(protocol, "vnc") == 0) {
+ rc = vnc_display_pw_expire(NULL, when);
+ if (rc != 0) {
+ qerror_report(QERR_SET_PASSWD_FAILED);
+ return -1;
+ }
+ return 0;
+ }
+
+ qerror_report(QERR_INVALID_PARAMETER, "protocol");
+ return -1;
+}
+
static int do_screen_dump(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
vga_hw_screen_dump(qdict_get_str(qdict, "filename"));
diff --git a/qmp-commands.hx b/qmp-commands.hx
index b2f4fe5..125e6e9 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -738,6 +738,63 @@ Example:
EQMP
{
+ .name = "set_password",
+ .args_type = "protocol:s,password:s,connected:s?",
+ .params = "protocol password action-if-connected",
+ .help = "set spice/vnc password",
+ .user_print = monitor_user_noop,
+ .mhandler.cmd_new = set_password,
+ },
+
+SQMP
+set_password
+------------
+
+Set the password for vnc/spice protocols.
+
+Arguments:
+
+- "protocol": protocol name (json-string)
+- "password": password (json-string)
+- "connected": [ keep | disconnect | fail ] (josn-string, optional)
+
+Example:
+
+-> { "execute": "set_password", "arguments": { "protocol": "vnc",
+ "password": "secret" } }
+<- { "return": {} }
+
+EQMP
+
+ {
+ .name = "expire_password",
+ .args_type = "protocol:s,time:s",
+ .params = "protocol time",
+ .help = "set spice/vnc password expire-time",
+ .user_print = monitor_user_noop,
+ .mhandler.cmd_new = expire_password,
+ },
+
+SQMP
+expire_password
+---------------
+
+Set the password expire time for vnc/spice protocols.
+
+Arguments:
+
+- "protocol": protocol name (json-string)
+- "time": [ now | never | +secs | secs ] (json-string)
+
+Example:
+
+-> { "execute": "expire_password", "arguments": { "protocol": "vnc",
+ "time": "+60" } }
+<- { "return": {} }
+
+EQMP
+
+ {
.name = "qmp_capabilities",
.args_type = "",
.params = "",
diff --git a/ui/qemu-spice.h b/ui/qemu-spice.h
index 8b23ac9..48239c3 100644
--- a/ui/qemu-spice.h
+++ b/ui/qemu-spice.h
@@ -32,6 +32,9 @@ void qemu_spice_input_init(void);
void qemu_spice_audio_init(void);
void qemu_spice_display_init(DisplayState *ds);
int qemu_spice_add_interface(SpiceBaseInstance *sin);
+int qemu_spice_set_passwd(const char *passwd,
+ bool fail_if_connected, bool disconnect_if_connected);
+int qemu_spice_set_pw_expire(time_t expires);
void do_info_spice_print(Monitor *mon, const QObject *data);
void do_info_spice(Monitor *mon, QObject **ret_data);
@@ -39,6 +42,8 @@ void do_info_spice(Monitor *mon, QObject **ret_data);
#else /* CONFIG_SPICE */
#define using_spice 0
+#define qemu_spice_set_passwd(_p, _f1, _f2) (-1)
+#define qemu_spice_set_pw_expire(_e) (-1)
#endif /* CONFIG_SPICE */
diff --git a/ui/spice-core.c b/ui/spice-core.c
index d29d203..27a1ced 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -36,6 +36,8 @@
static SpiceServer *spice_server;
static const char *auth = "spice";
+static char *auth_passwd;
+static time_t auth_expires = TIME_MAX;
int using_spice = 0;
struct SpiceTimer {
@@ -599,6 +601,39 @@ int qemu_spice_add_interface(SpiceBaseInstance *sin)
return spice_server_add_interface(spice_server, sin);
}
+static int qemu_spice_set_ticket(bool fail_if_conn, bool disconnect_if_conn)
+{
+ time_t lifetime, now = time(NULL);
+ char *passwd;
+
+ if (now < auth_expires) {
+ passwd = auth_passwd;
+ lifetime = (auth_expires - now);
+ if (lifetime > INT_MAX) {
+ lifetime = INT_MAX;
+ }
+ } else {
+ passwd = NULL;
+ lifetime = 1;
+ }
+ return spice_server_set_ticket(spice_server, passwd, lifetime,
+ fail_if_conn, disconnect_if_conn);
+}
+
+int qemu_spice_set_passwd(const char *passwd,
+ bool fail_if_conn, bool disconnect_if_conn)
+{
+ free(auth_passwd);
+ auth_passwd = strdup(passwd);
+ return qemu_spice_set_ticket(fail_if_conn, disconnect_if_conn);
+}
+
+int qemu_spice_set_pw_expire(time_t expires)
+{
+ auth_expires = expires;
+ return qemu_spice_set_ticket(false, false);
+}
+
static void spice_register_config(void)
{
qemu_add_opts(&qemu_spice_opts);
--
1.7.1
^ permalink raw reply related [flat|nested] 7+ messages in thread