qemu_command_builder/
vnc.rs

1use crate::common::OnOff;
2use crate::to_command::ToArg;
3use crate::to_command::ToCommand;
4use bon::Builder;
5use std::path::PathBuf;
6
7pub enum VNCDisplay {
8    To(usize),
9    Host(usize),
10    Unix(PathBuf),
11    None,
12}
13
14pub enum AllowExclusiveForceSharedIgnore {
15    AllowExclusive,
16    ForceShared,
17    Ignore,
18}
19
20impl ToArg for AllowExclusiveForceSharedIgnore {
21    fn to_arg(&self) -> &str {
22        match self {
23            AllowExclusiveForceSharedIgnore::AllowExclusive => "allow-exclusive",
24            AllowExclusiveForceSharedIgnore::ForceShared => "force-shared",
25            AllowExclusiveForceSharedIgnore::Ignore => "ignore",
26        }
27    }
28}
29#[derive(Builder)]
30pub struct VNC {
31    display: VNCDisplay,
32
33    /// Connect to a listening VNC client via a "reverse" connection.
34    /// The client is specified by the display. For reverse network
35    /// connections (host:d,``reverse``), the d argument is a TCP port
36    /// number, not a display number.    
37    reverse: Option<OnOff>,
38
39    /// Opens an additional TCP listening port dedicated to VNC
40    /// Websocket connections. If a bare websocket option is given, the
41    /// Websocket port is 5700+display. An alternative port can be
42    /// specified with the syntax ``websocket``\ =port.
43    ///
44    /// If host is specified connections will only be allowed from this
45    /// host. It is possible to control the websocket listen address
46    /// independently, using the syntax ``websocket``\ =host:port.
47    ///
48    /// Websocket could be allowed over UNIX domain socket, using the syntax
49    /// ``websocket``\ =unix:path, where path is the location of a unix socket
50    /// to listen for connections on.
51    ///
52    /// If no TLS credentials are provided, the websocket connection
53    /// runs in unencrypted mode. If TLS credentials are provided, the
54    /// websocket connection requires encrypted client connections.
55    websocket: Option<OnOff>,
56
57    /// Require that password based authentication is used for client
58    /// connections.
59    ///
60    /// The password must be set separately using the ``set_password``
61    /// command in the :ref:`QEMU monitor`. The
62    /// syntax to change your password is:
63    /// ``set_password <protocol> <password>`` where <protocol> could be
64    /// either "vnc" or "spice".
65    ///
66    /// If you would like to change <protocol> password expiration, you
67    /// should use ``expire_password <protocol> <expiration-time>``
68    /// where expiration time could be one of the following options:
69    ///     now, never, +seconds or UNIX time of expiration, e.g. +60 to
70    /// make password expire in 60 seconds, or 1335196800 to make
71    /// password expire on "Mon Apr 23 12:00:00 EDT 2012" (UNIX time for
72    /// this date and time).
73    ///
74    /// You can also use keywords "now" or "never" for the expiration
75    /// time to allow <protocol> password to expire immediately or never
76    /// expire.
77    password: Option<OnOff>,
78
79    /// Require that password based authentication is used for client
80    /// connections, using the password provided by the ``secret``
81    /// object identified by ``secret-id``.
82    password_secret: Option<String>,
83
84    /// Provides the ID of a set of TLS credentials to use to secure the
85    /// VNC server. They will apply to both the normal VNC server socket
86    /// and the websocket socket (if enabled). Setting TLS credentials
87    /// will cause the VNC server socket to enable the VeNCrypt auth
88    /// mechanism. The credentials should have been previously created
89    /// using the ``-object tls-creds`` argument.
90    tls_creds: Option<String>,
91
92    /// Provides the ID of the QAuthZ authorization object against which
93    /// the client's x509 distinguished name will validated. This object
94    /// is only resolved at time of use, so can be deleted and recreated
95    /// on the fly while the VNC server is active. If missing, it will
96    /// default to denying access.
97    tls_authz: Option<String>,
98
99    /// Require that the client use SASL to authenticate with the VNC
100    /// server. The exact choice of authentication method used is
101    /// controlled from the system / user's SASL configuration file for
102    /// the 'qemu' service. This is typically found in
103    /// /etc/sasl2/qemu.conf. If running QEMU as an unprivileged user,
104    /// an environment variable SASL\_CONF\_PATH can be used to make it
105    /// search alternate locations for the service config. While some
106    /// SASL auth methods can also provide data encryption (eg GSSAPI),
107    /// it is recommended that SASL always be combined with the 'tls'
108    /// and 'x509' settings to enable use of SSL and server
109    /// certificates. This ensures a data encryption preventing
110    /// compromise of authentication credentials. See the
111    /// :ref:`VNC security` section in the System Emulation Users Guide
112    /// for details on using SASL authentication.    
113    sasl: Option<OnOff>,
114
115    /// Provides the ID of the QAuthZ authorization object against which
116    /// the client's SASL username will validated. This object is only
117    /// resolved at time of use, so can be deleted and recreated on the
118    /// fly while the VNC server is active. If missing, it will default
119    /// to denying access.
120    sasl_authz: Option<String>,
121
122    /// Legacy method for enabling authorization of clients against the
123    /// x509 distinguished name and SASL username. It results in the
124    /// creation of two ``authz-list`` objects with IDs of
125    /// ``vnc.username`` and ``vnc.x509dname``. The rules for these
126    /// objects must be configured with the HMP ACL commands.
127    ///
128    /// This option is deprecated and should no longer be used. The new
129    /// ``sasl-authz`` and ``tls-authz`` options are a replacement.
130    acl: Option<OnOff>,
131
132    /// Enable lossy compression methods (gradient, JPEG, ...). If this
133    /// option is set, VNC client may receive lossy framebuffer updates
134    /// depending on its encoding settings. Enabling this option can
135    /// save a lot of bandwidth at the expense of quality.   
136    lossy: Option<OnOff>,
137
138    /// Disable adaptive encodings. Adaptive encodings are enabled by
139    /// default. An adaptive encoding will try to detect frequently
140    /// updated screen regions, and send updates in these regions using
141    /// a lossy encoding (like JPEG). This can be really helpful to save
142    /// bandwidth when playing videos. Disabling adaptive encodings
143    /// restores the original static behavior of encodings like Tight.
144    non_adaptive: Option<OnOff>,
145
146    /// Set display sharing policy. 'allow-exclusive' allows clients to
147    /// ask for exclusive access. As suggested by the rfb spec this is
148    /// implemented by dropping other connections. Connecting multiple
149    /// clients in parallel requires all clients asking for a shared
150    /// session (vncviewer: -shared switch). This is the default.
151    /// 'force-shared' disables exclusive client access. Useful for
152    /// shared desktop sessions, where you don't want someone forgetting
153    /// specify -shared disconnect everybody else. 'ignore' completely
154    /// ignores the shared flag and allows everybody connect
155    /// unconditionally. Doesn't conform to the rfb spec but is
156    /// traditional QEMU behavior.
157    share: Option<AllowExclusiveForceSharedIgnore>,
158
159    /// Set keyboard delay, for key down and key up events, in
160    /// milliseconds. Default is 10. Keyboards are low-bandwidth
161    /// devices, so this slowdown can help the device and guest to keep
162    /// up and not lose events in case events are arriving in bulk.
163    /// Possible causes for the latter are flaky network connections, or
164    /// scripts for automated testing.
165    key_delay_ms: Option<usize>,
166
167    /// Use the specified audiodev when the VNC client requests audio
168    /// transmission. When not using an -audiodev argument, this option
169    /// must be omitted, otherwise is must be present and specify a
170    /// valid audiodev.
171    audiodev: Option<String>,
172
173    /// Permit the remote client to issue shutdown, reboot or reset power
174    /// control requests.
175    power_control: Option<OnOff>,
176}
177
178impl ToCommand for VNC {
179    fn to_command(&self) -> Vec<String> {
180        let mut cmd = vec![];
181
182        cmd.push("-vnc".to_string());
183
184        let mut args = vec![];
185        match &self.display {
186            VNCDisplay::To(l) => {
187                args.push(format!("to={}", l));
188            }
189            VNCDisplay::Host(d) => {
190                args.push(format!("host={}", d));
191            }
192            VNCDisplay::Unix(path) => {
193                args.push(format!("unix={}", path.display()));
194            }
195            VNCDisplay::None => {
196                args.push("none".to_string());
197            }
198        }
199
200        if let Some(reverse) = &self.reverse {
201            args.push(format!("reverse={}", reverse.to_arg()));
202        }
203        if let Some(websocket) = &self.websocket {
204            args.push(format!("websocket={}", websocket.to_arg()));
205        }
206        if let Some(password) = &self.password {
207            args.push(format!("password={}", password.to_arg()));
208        }
209        if let Some(password_secret) = &self.password_secret {
210            args.push(format!("password-secret={}", password_secret));
211        }
212        if let Some(tls_creds) = &self.tls_creds {
213            args.push(format!("tls-creds={}", tls_creds));
214        }
215        if let Some(tls_authz) = &self.tls_authz {
216            args.push(format!("tls-authz={}", tls_authz));
217        }
218        if let Some(sasl) = &self.sasl {
219            args.push(format!("sasl={}", sasl.to_arg()));
220        }
221        if let Some(sasl_authz) = &self.sasl_authz {
222            args.push(format!("sasl-authz={}", sasl_authz));
223        }
224        if let Some(acl) = &self.acl {
225            args.push(format!("acl={}", acl.to_arg()));
226        }
227        if let Some(lossy) = &self.lossy {
228            args.push(format!("lossy={}", lossy.to_arg()));
229        }
230        if let Some(non_adaptive) = &self.non_adaptive {
231            args.push(format!("non-adaptive={}", non_adaptive.to_arg()));
232        }
233        if let Some(share) = &self.share {
234            args.push(format!("share={}", share.to_arg()));
235        }
236        if let Some(key_delay_ms) = &self.key_delay_ms {
237            args.push(format!("key-delay-ms={}", key_delay_ms));
238        }
239        if let Some(audiodev) = &self.audiodev {
240            args.push(format!("audiodev={}", audiodev));
241        }
242        if let Some(power_control) = &self.power_control {
243            args.push(format!("power-control={}", power_control.to_arg()));
244        }
245
246        cmd.push(args.join(","));
247
248        cmd
249    }
250}