]>
Commit | Line | Data |
---|---|---|
f376b2b9 SR |
1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
2 | From: Stefan Reiter <s.reiter@proxmox.com> | |
3 | Date: Wed, 25 Aug 2021 11:14:13 +0200 | |
4 | Subject: [PATCH] monitor: refactor set/expire_password and allow VNC display | |
5 | id | |
6 | MIME-Version: 1.0 | |
7 | Content-Type: text/plain; charset=UTF-8 | |
8 | Content-Transfer-Encoding: 8bit | |
9 | ||
10 | It is possible to specify more than one VNC server on the command line, | |
11 | either with an explicit ID or the auto-generated ones à la "default", | |
12 | "vnc2", "vnc3", ... | |
13 | ||
14 | It is not possible to change the password on one of these extra VNC | |
15 | displays though. Fix this by adding a "display" parameter to the | |
16 | "set_password" and "expire_password" QMP and HMP commands. | |
17 | ||
18 | For HMP, the display is specified using the "-d" value flag. | |
19 | ||
20 | For QMP, the schema is updated to explicitly express the supported | |
21 | variants of the commands with protocol-discriminated unions. | |
22 | ||
23 | Suggested-by: Eric Blake <eblake@redhat.com> | |
24 | Suggested-by: Markus Armbruster <armbru@redhat.com> | |
25 | Signed-off-by: Stefan Reiter <s.reiter@proxmox.com> | |
ddbf7a87 | 26 | Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> |
4567474e | 27 | Signed-off-by: Fabian Ebner <f.ebner@proxmox.com> |
f376b2b9 | 28 | --- |
4567474e | 29 | hmp-commands.hx | 24 ++++--- |
f376b2b9 SR |
30 | monitor/hmp-cmds.c | 57 +++++++++++++++- |
31 | monitor/qmp-cmds.c | 62 ++++++----------- | |
ddbf7a87 | 32 | qapi/ui.json | 165 ++++++++++++++++++++++++++++++++++++++------- |
4567474e | 33 | 4 files changed, 231 insertions(+), 77 deletions(-) |
f376b2b9 SR |
34 | |
35 | diff --git a/hmp-commands.hx b/hmp-commands.hx | |
4567474e | 36 | index 70a9136ac2..5efb47fc32 100644 |
f376b2b9 SR |
37 | --- a/hmp-commands.hx |
38 | +++ b/hmp-commands.hx | |
4567474e | 39 | @@ -1514,33 +1514,35 @@ ERST |
f376b2b9 SR |
40 | |
41 | { | |
42 | .name = "set_password", | |
43 | - .args_type = "protocol:s,password:s,connected:s?", | |
44 | - .params = "protocol password action-if-connected", | |
45 | + .args_type = "protocol:s,password:s,display:-dS,connected:s?", | |
46 | + .params = "protocol password [-d display] [action-if-connected]", | |
47 | .help = "set spice/vnc password", | |
48 | .cmd = hmp_set_password, | |
49 | }, | |
50 | ||
51 | SRST | |
52 | -``set_password [ vnc | spice ] password [ action-if-connected ]`` | |
4567474e FE |
53 | - Change spice/vnc password. *action-if-connected* specifies what |
54 | - should happen in case a connection is established: *fail* makes the | |
55 | - password change fail. *disconnect* changes the password and | |
f376b2b9 SR |
56 | +``set_password [ vnc | spice ] password [ -d display ] [ action-if-connected ]`` |
57 | + Change spice/vnc password. *display* can be used with 'vnc' to specify | |
58 | + which display to set the password on. *action-if-connected* specifies | |
59 | + what should happen in case a connection is established: *fail* makes | |
60 | + the password change fail. *disconnect* changes the password and | |
4567474e FE |
61 | disconnects the client. *keep* changes the password and keeps the |
62 | connection up. *keep* is the default. | |
f376b2b9 SR |
63 | ERST |
64 | ||
65 | { | |
66 | .name = "expire_password", | |
67 | - .args_type = "protocol:s,time:s", | |
68 | - .params = "protocol time", | |
69 | + .args_type = "protocol:s,time:s,display:-dS", | |
70 | + .params = "protocol time [-d display]", | |
71 | .help = "set spice/vnc password expire-time", | |
72 | .cmd = hmp_expire_password, | |
73 | }, | |
74 | ||
75 | SRST | |
76 | -``expire_password [ vnc | spice ]`` *expire-time* | |
77 | - Specify when a password for spice/vnc becomes | |
78 | - invalid. *expire-time* accepts: | |
79 | +``expire_password [ vnc | spice ] expire-time [ -d display ]`` | |
80 | + Specify when a password for spice/vnc becomes invalid. | |
81 | + *display* behaves the same as in ``set_password``. | |
82 | + *expire-time* accepts: | |
83 | ||
84 | ``now`` | |
85 | Invalidate password instantly. | |
86 | diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c | |
4567474e | 87 | index 9c91bf93e9..2e91ccb738 100644 |
f376b2b9 SR |
88 | --- a/monitor/hmp-cmds.c |
89 | +++ b/monitor/hmp-cmds.c | |
4567474e | 90 | @@ -1384,10 +1384,41 @@ void hmp_set_password(Monitor *mon, const QDict *qdict) |
f376b2b9 SR |
91 | { |
92 | const char *protocol = qdict_get_str(qdict, "protocol"); | |
93 | const char *password = qdict_get_str(qdict, "password"); | |
94 | + const char *display = qdict_get_try_str(qdict, "display"); | |
95 | const char *connected = qdict_get_try_str(qdict, "connected"); | |
96 | Error *err = NULL; | |
97 | + DisplayProtocol proto; | |
98 | ||
99 | - qmp_set_password(protocol, password, !!connected, connected, &err); | |
100 | + SetPasswordOptions opts = { | |
101 | + .password = g_strdup(password), | |
102 | + .u.vnc.display = NULL, | |
103 | + }; | |
104 | + | |
105 | + proto = qapi_enum_parse(&DisplayProtocol_lookup, protocol, | |
106 | + DISPLAY_PROTOCOL_VNC, &err); | |
107 | + if (err) { | |
108 | + hmp_handle_error(mon, err); | |
109 | + return; | |
110 | + } | |
111 | + opts.protocol = proto; | |
112 | + | |
113 | + if (proto == DISPLAY_PROTOCOL_VNC) { | |
114 | + opts.u.vnc.has_display = !!display; | |
115 | + opts.u.vnc.display = g_strdup(display); | |
116 | + } else if (proto == DISPLAY_PROTOCOL_SPICE) { | |
117 | + opts.u.spice.has_connected = !!connected; | |
118 | + opts.u.spice.connected = | |
119 | + qapi_enum_parse(&SetPasswordAction_lookup, connected, | |
120 | + SET_PASSWORD_ACTION_KEEP, &err); | |
121 | + if (err) { | |
122 | + hmp_handle_error(mon, err); | |
123 | + return; | |
124 | + } | |
125 | + } | |
126 | + | |
127 | + qmp_set_password(&opts, &err); | |
128 | + g_free(opts.password); | |
129 | + g_free(opts.u.vnc.display); | |
130 | hmp_handle_error(mon, err); | |
131 | } | |
132 | ||
4567474e | 133 | @@ -1395,9 +1426,31 @@ void hmp_expire_password(Monitor *mon, const QDict *qdict) |
f376b2b9 SR |
134 | { |
135 | const char *protocol = qdict_get_str(qdict, "protocol"); | |
136 | const char *whenstr = qdict_get_str(qdict, "time"); | |
137 | + const char *display = qdict_get_try_str(qdict, "display"); | |
138 | Error *err = NULL; | |
139 | + DisplayProtocol proto; | |
ddbf7a87 TL |
140 | |
141 | - qmp_expire_password(protocol, whenstr, &err); | |
f376b2b9 SR |
142 | + ExpirePasswordOptions opts = { |
143 | + .time = g_strdup(whenstr), | |
144 | + .u.vnc.display = NULL, | |
145 | + }; | |
146 | + | |
147 | + proto = qapi_enum_parse(&DisplayProtocol_lookup, protocol, | |
148 | + DISPLAY_PROTOCOL_VNC, &err); | |
149 | + if (err) { | |
150 | + hmp_handle_error(mon, err); | |
151 | + return; | |
152 | + } | |
153 | + opts.protocol = proto; | |
154 | + | |
155 | + if (proto == DISPLAY_PROTOCOL_VNC) { | |
156 | + opts.u.vnc.has_display = !!display; | |
157 | + opts.u.vnc.display = g_strdup(display); | |
158 | + } | |
ddbf7a87 | 159 | + |
f376b2b9 SR |
160 | + qmp_expire_password(&opts, &err); |
161 | + g_free(opts.time); | |
162 | + g_free(opts.u.vnc.display); | |
163 | hmp_handle_error(mon, err); | |
164 | } | |
165 | ||
166 | diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c | |
4567474e | 167 | index 343353e27a..729ca7cceb 100644 |
f376b2b9 SR |
168 | --- a/monitor/qmp-cmds.c |
169 | +++ b/monitor/qmp-cmds.c | |
4567474e | 170 | @@ -167,45 +167,30 @@ void qmp_system_wakeup(Error **errp) |
f376b2b9 SR |
171 | qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, errp); |
172 | } | |
173 | ||
174 | -void qmp_set_password(const char *protocol, const char *password, | |
175 | - bool has_connected, const char *connected, Error **errp) | |
176 | +void qmp_set_password(SetPasswordOptions *opts, Error **errp) | |
177 | { | |
178 | - int disconnect_if_connected = 0; | |
179 | - int fail_if_connected = 0; | |
180 | - int rc; | |
ddbf7a87 TL |
181 | + bool disconnect_if_connected = false; |
182 | + bool fail_if_connected = false; | |
183 | + int rc = 0; | |
184 | ||
f376b2b9 SR |
185 | - if (has_connected) { |
186 | - if (strcmp(connected, "fail") == 0) { | |
187 | - fail_if_connected = 1; | |
188 | - } else if (strcmp(connected, "disconnect") == 0) { | |
189 | - disconnect_if_connected = 1; | |
190 | - } else if (strcmp(connected, "keep") == 0) { | |
191 | - /* nothing */ | |
192 | - } else { | |
193 | - error_setg(errp, QERR_INVALID_PARAMETER, "connected"); | |
194 | - return; | |
195 | - } | |
196 | - } | |
ddbf7a87 | 197 | - |
f376b2b9 SR |
198 | - if (strcmp(protocol, "spice") == 0) { |
199 | + if (opts->protocol == DISPLAY_PROTOCOL_SPICE) { | |
200 | if (!qemu_using_spice(errp)) { | |
201 | return; | |
202 | } | |
203 | - rc = qemu_spice.set_passwd(password, fail_if_connected, | |
f376b2b9 SR |
204 | + if (opts->u.spice.has_connected) { |
205 | + fail_if_connected = | |
206 | + opts->u.spice.connected == SET_PASSWORD_ACTION_FAIL; | |
207 | + disconnect_if_connected = | |
208 | + opts->u.spice.connected == SET_PASSWORD_ACTION_DISCONNECT; | |
ddbf7a87 | 209 | + } |
f376b2b9 | 210 | + rc = qemu_spice.set_passwd(opts->password, fail_if_connected, |
ddbf7a87 TL |
211 | disconnect_if_connected); |
212 | - } else if (strcmp(protocol, "vnc") == 0) { | |
213 | - if (fail_if_connected || disconnect_if_connected) { | |
214 | - /* vnc supports "connected=keep" only */ | |
215 | - error_setg(errp, QERR_INVALID_PARAMETER, "connected"); | |
216 | - return; | |
217 | - } | |
f376b2b9 SR |
218 | + } else if (opts->protocol == DISPLAY_PROTOCOL_VNC) { |
219 | /* Note that setting an empty password will not disable login through | |
220 | * this interface. */ | |
221 | - rc = vnc_display_password(NULL, password); | |
222 | - } else { | |
223 | - error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "protocol", | |
224 | - "'vnc' or 'spice'"); | |
225 | - return; | |
226 | + rc = vnc_display_password( | |
227 | + opts->u.vnc.has_display ? opts->u.vnc.display : NULL, | |
228 | + opts->password); | |
229 | } | |
230 | ||
231 | if (rc != 0) { | |
4567474e | 232 | @@ -213,11 +198,11 @@ void qmp_set_password(const char *protocol, const char *password, |
f376b2b9 SR |
233 | } |
234 | } | |
235 | ||
236 | -void qmp_expire_password(const char *protocol, const char *whenstr, | |
237 | - Error **errp) | |
238 | +void qmp_expire_password(ExpirePasswordOptions *opts, Error **errp) | |
239 | { | |
240 | time_t when; | |
241 | int rc; | |
242 | + const char* whenstr = opts->time; | |
243 | ||
244 | if (strcmp(whenstr, "now") == 0) { | |
245 | when = 0; | |
4567474e | 246 | @@ -229,17 +214,14 @@ void qmp_expire_password(const char *protocol, const char *whenstr, |
f376b2b9 SR |
247 | when = strtoull(whenstr, NULL, 10); |
248 | } | |
249 | ||
250 | - if (strcmp(protocol, "spice") == 0) { | |
251 | + if (opts->protocol == DISPLAY_PROTOCOL_SPICE) { | |
252 | if (!qemu_using_spice(errp)) { | |
253 | return; | |
254 | } | |
255 | rc = qemu_spice.set_pw_expire(when); | |
256 | - } else if (strcmp(protocol, "vnc") == 0) { | |
257 | - rc = vnc_display_pw_expire(NULL, when); | |
258 | - } else { | |
259 | - error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "protocol", | |
260 | - "'vnc' or 'spice'"); | |
261 | - return; | |
262 | + } else if (opts->protocol == DISPLAY_PROTOCOL_VNC) { | |
263 | + rc = vnc_display_pw_expire( | |
264 | + opts->u.vnc.has_display ? opts->u.vnc.display : NULL, when); | |
265 | } | |
266 | ||
267 | if (rc != 0) { | |
268 | diff --git a/qapi/ui.json b/qapi/ui.json | |
4567474e | 269 | index d7567ac866..4244c62c30 100644 |
f376b2b9 SR |
270 | --- a/qapi/ui.json |
271 | +++ b/qapi/ui.json | |
ddbf7a87 TL |
272 | @@ -9,22 +9,23 @@ |
273 | { 'include': 'common.json' } | |
f376b2b9 SR |
274 | { 'include': 'sockets.json' } |
275 | ||
ddbf7a87 | 276 | +## |
f376b2b9 | 277 | +# @DisplayProtocol: |
ddbf7a87 | 278 | +# |
f376b2b9 | 279 | +# Display protocols which support changing password options. |
ddbf7a87 | 280 | +# |
f376b2b9 | 281 | +# Since: 6.2 |
ddbf7a87 | 282 | +# |
f376b2b9 SR |
283 | +## |
284 | +{ 'enum': 'DisplayProtocol', | |
4567474e FE |
285 | + 'data': [ { 'name': 'vnc', 'if': 'CONFIG_VNC' }, |
286 | + { 'name': 'spice', 'if': 'CONFIG_SPICE' } ] } | |
f376b2b9 | 287 | + |
ddbf7a87 TL |
288 | ## |
289 | # @set_password: | |
f376b2b9 | 290 | # |
ddbf7a87 TL |
291 | # Sets the password of a remote display session. |
292 | # | |
293 | -# @protocol: - 'vnc' to modify the VNC server password | |
294 | -# - 'spice' to modify the Spice server password | |
295 | -# | |
296 | -# @password: the new password | |
297 | -# | |
f376b2b9 SR |
298 | -# @connected: how to handle existing clients when changing the |
299 | -# password. If nothing is specified, defaults to 'keep' | |
300 | -# 'fail' to fail the command if clients are connected | |
301 | -# 'disconnect' to disconnect existing clients | |
302 | -# 'keep' to maintain existing clients | |
ddbf7a87 | 303 | -# |
f376b2b9 SR |
304 | # Returns: - Nothing on success |
305 | # - If Spice is not enabled, DeviceNotFound | |
ddbf7a87 | 306 | # |
f376b2b9 SR |
307 | @@ -37,16 +38,123 @@ |
308 | # <- { "return": {} } | |
309 | # | |
310 | ## | |
311 | -{ 'command': 'set_password', | |
312 | - 'data': {'protocol': 'str', 'password': 'str', '*connected': 'str'} } | |
313 | +{ 'command': 'set_password', 'boxed': true, 'data': 'SetPasswordOptions' } | |
314 | + | |
315 | +## | |
316 | +# @SetPasswordOptions: | |
317 | +# | |
318 | +# Data required to set a new password on a display server protocol. | |
319 | +# | |
320 | +# @protocol: - 'vnc' to modify the VNC server password | |
321 | +# - 'spice' to modify the Spice server password | |
322 | +# | |
323 | +# @password: the new password | |
324 | +# | |
325 | +# Since: 6.2 | |
326 | +# | |
327 | +## | |
328 | +{ 'union': 'SetPasswordOptions', | |
329 | + 'base': { 'protocol': 'DisplayProtocol', | |
330 | + 'password': 'str' }, | |
331 | + 'discriminator': 'protocol', | |
332 | + 'data': { 'vnc': 'SetPasswordOptionsVnc', | |
333 | + 'spice': 'SetPasswordOptionsSpice' } } | |
334 | + | |
335 | +## | |
336 | +# @SetPasswordAction: | |
337 | +# | |
338 | +# An action to take on changing a password on a connection with active clients. | |
339 | +# | |
340 | +# @fail: fail the command if clients are connected | |
341 | +# | |
342 | +# @disconnect: disconnect existing clients | |
343 | +# | |
344 | +# @keep: maintain existing clients | |
345 | +# | |
346 | +# Since: 6.2 | |
347 | +# | |
348 | +## | |
349 | +{ 'enum': 'SetPasswordAction', | |
350 | + 'data': [ 'fail', 'disconnect', 'keep' ] } | |
351 | + | |
352 | +## | |
353 | +# @SetPasswordActionVnc: | |
354 | +# | |
355 | +# See @SetPasswordAction. VNC only supports the keep action. 'connection' | |
356 | +# should just be omitted for VNC, this is kept for backwards compatibility. | |
357 | +# | |
358 | +# @keep: maintain existing clients | |
359 | +# | |
360 | +# Since: 6.2 | |
361 | +# | |
362 | +## | |
363 | +{ 'enum': 'SetPasswordActionVnc', | |
364 | + 'data': [ 'keep' ] } | |
365 | + | |
366 | +## | |
367 | +# @SetPasswordOptionsSpice: | |
368 | +# | |
369 | +# Options for set_password specific to the VNC procotol. | |
370 | +# | |
371 | +# @connected: How to handle existing clients when changing the | |
372 | +# password. If nothing is specified, defaults to 'keep'. | |
373 | +# | |
374 | +# Since: 6.2 | |
375 | +# | |
376 | +## | |
377 | +{ 'struct': 'SetPasswordOptionsSpice', | |
378 | + 'data': { '*connected': 'SetPasswordAction' } } | |
379 | + | |
380 | +## | |
381 | +# @SetPasswordOptionsVnc: | |
382 | +# | |
383 | +# Options for set_password specific to the VNC procotol. | |
384 | +# | |
385 | +# @display: The id of the display where the password should be changed. | |
386 | +# Defaults to the first. | |
387 | +# | |
388 | +# @connected: How to handle existing clients when changing the | |
389 | +# password. | |
390 | +# | |
391 | +# Features: | |
392 | +# @deprecated: For VNC, @connected will always be 'keep', parameter should be | |
393 | +# omitted. | |
394 | +# | |
395 | +# Since: 6.2 | |
396 | +# | |
397 | +## | |
398 | +{ 'struct': 'SetPasswordOptionsVnc', | |
399 | + 'data': { '*display': 'str', | |
400 | + '*connected': { 'type': 'SetPasswordActionVnc', | |
401 | + 'features': ['deprecated'] } } } | |
402 | ||
403 | ## | |
404 | # @expire_password: | |
405 | # | |
406 | # Expire the password of a remote display server. | |
407 | # | |
408 | -# @protocol: the name of the remote display protocol 'vnc' or 'spice' | |
409 | +# Returns: - Nothing on success | |
410 | +# - If @protocol is 'spice' and Spice is not active, DeviceNotFound | |
ddbf7a87 | 411 | # |
f376b2b9 SR |
412 | +# Since: 0.14 |
413 | +# | |
414 | +# Example: | |
415 | +# | |
416 | +# -> { "execute": "expire_password", "arguments": { "protocol": "vnc", | |
417 | +# "time": "+60" } } | |
418 | +# <- { "return": {} } | |
419 | +# | |
420 | +## | |
421 | +{ 'command': 'expire_password', 'boxed': true, 'data': 'ExpirePasswordOptions' } | |
422 | + | |
423 | +## | |
424 | +# @ExpirePasswordOptions: | |
425 | +# | |
426 | +# Data required to set password expiration on a display server protocol. | |
ddbf7a87 | 427 | +# |
f376b2b9 SR |
428 | +# @protocol: - 'vnc' to modify the VNC server expiration |
429 | +# - 'spice' to modify the Spice server expiration | |
430 | + | |
431 | # @time: when to expire the password. | |
432 | # | |
433 | # - 'now' to expire the password immediately | |
434 | @@ -54,24 +162,33 @@ | |
435 | # - '+INT' where INT is the number of seconds from now (integer) | |
436 | # - 'INT' where INT is the absolute time in seconds | |
437 | # | |
438 | -# Returns: - Nothing on success | |
439 | -# - If @protocol is 'spice' and Spice is not active, DeviceNotFound | |
440 | -# | |
441 | -# Since: 0.14 | |
442 | -# | |
443 | # Notes: Time is relative to the server and currently there is no way to | |
444 | # coordinate server time with client time. It is not recommended to | |
445 | # use the absolute time version of the @time parameter unless you're | |
446 | # sure you are on the same machine as the QEMU instance. | |
447 | # | |
448 | -# Example: | |
449 | +# Since: 6.2 | |
450 | # | |
451 | -# -> { "execute": "expire_password", "arguments": { "protocol": "vnc", | |
452 | -# "time": "+60" } } | |
453 | -# <- { "return": {} } | |
454 | +## | |
455 | +{ 'union': 'ExpirePasswordOptions', | |
456 | + 'base': { 'protocol': 'DisplayProtocol', | |
457 | + 'time': 'str' }, | |
458 | + 'discriminator': 'protocol', | |
459 | + 'data': { 'vnc': 'ExpirePasswordOptionsVnc' } } | |
460 | + | |
461 | +## | |
462 | +# @ExpirePasswordOptionsVnc: | |
463 | +# | |
464 | +# Options for expire_password specific to the VNC procotol. | |
465 | +# | |
466 | +# @display: The id of the display where the expiration should be changed. | |
467 | +# Defaults to the first. | |
468 | +# | |
469 | +# Since: 6.2 | |
470 | # | |
471 | ## | |
472 | -{ 'command': 'expire_password', 'data': {'protocol': 'str', 'time': 'str'} } | |
473 | +{ 'struct': 'ExpirePasswordOptionsVnc', | |
474 | + 'data': { '*display': 'str' } } | |
475 | ||
476 | ## | |
477 | # @screendump: |