aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hmp-commands.hx54
-rw-r--r--monitor.c100
-rw-r--r--qmp-commands.hx57
-rw-r--r--ui/qemu-spice.h5
-rw-r--r--ui/spice-core.c35
5 files changed, 251 insertions, 0 deletions
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 23024ba6f2..f0ae3b9fd8 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1135,6 +1135,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 1047ceea97..b13a363131 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"
@@ -1075,6 +1076,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 b4e601751f..1d71711f2e 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 8b23ac9d04..48239c3dbd 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 d29d20359d..27a1ced430 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);