vnc/spice: add set_passwd monitor command.
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>
This commit is contained in:
		| @@ -1132,6 +1132,60 @@ STEXI | ||||
| @item block_passwd @var{device} @var{password} | ||||
| @findex block_passwd | ||||
| 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 | ||||
|  | ||||
|     { | ||||
|   | ||||
							
								
								
									
										100
									
								
								monitor.c
									
									
									
									
									
								
							
							
						
						
									
										100
									
								
								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")); | ||||
|   | ||||
| @@ -735,6 +735,63 @@ Example: | ||||
|                                                "password": "12345" } } | ||||
| <- { "return": {} } | ||||
|  | ||||
| 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 | ||||
|  | ||||
|     { | ||||
|   | ||||
| @@ -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 */ | ||||
|  | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user