@@ -59,6 +59,7 @@ typedef struct {
QIONetListener *listener;
GSource *hup_source;
QCryptoTLSCreds *tls_creds;
+ char *tls_authz;
TCPChardevState state;
int max_size;
int do_telnetopt;
@@ -807,7 +808,7 @@ static void tcp_chr_tls_init(Chardev *chr)
if (s->is_listen) {
tioc = qio_channel_tls_new_server(
s->ioc, s->tls_creds,
- NULL, /* XXX Use an ACL */
+ s->tls_authz,
&err);
} else {
tioc = qio_channel_tls_new_client(
@@ -1055,6 +1056,7 @@ static void char_socket_finalize(Object *obj)
if (s->tls_creds) {
object_unref(OBJECT(s->tls_creds));
}
+ g_free(s->tls_authz);
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
}
@@ -1320,6 +1322,7 @@ static void qmp_chardev_open_socket(Chardev *chr,
}
}
}
+ s->tls_authz = g_strdup(sock->tls_authz);
s->addr = addr = socket_address_flatten(sock->addr);
@@ -1358,6 +1361,7 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
const char *port = qemu_opt_get(opts, "port");
const char *fd = qemu_opt_get(opts, "fd");
SocketAddressLegacy *addr;
+ const char *tls_authz = qemu_opt_get(opts, "tls-authz");
ChardevSocket *sock;
if ((!!path + !!fd + !!host) != 1) {
@@ -1370,6 +1374,10 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
error_setg(errp, "chardev: socket: no port given");
return;
}
+ if (tls_authz && !tls_creds) {
+ error_setg(errp, "Authorization can only be used when TLS is enabled");
+ return;
+ }
backend->type = CHARDEV_BACKEND_KIND_SOCKET;
sock = backend->u.socket.data = g_new0(ChardevSocket, 1);
@@ -1399,6 +1407,8 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
sock->reconnect = qemu_opt_get_number(opts, "reconnect", 0);
sock->has_tls_creds = qemu_opt_get(opts, "tls-creds");
sock->tls_creds = g_strdup(qemu_opt_get(opts, "tls-creds"));
+ sock->has_tls_authz = qemu_opt_get(opts, "tls-authz");
+ sock->tls_authz = g_strdup(qemu_opt_get(opts, "tls-authz"));
addr = g_new0(SocketAddressLegacy, 1);
if (path) {
@@ -880,6 +880,9 @@ QemuOptsList qemu_chardev_opts = {
},{
.name = "tls-creds",
.type = QEMU_OPT_STRING,
+ },{
+ .name = "tls-authz",
+ .type = QEMU_OPT_STRING,
},{
.name = "websocket",
.type = QEMU_OPT_BOOL,
@@ -248,6 +248,11 @@
# @addr: socket address to listen on (server=true)
# or connect to (server=false)
# @tls-creds: the ID of the TLS credentials object (since 2.6)
+# @tls-authz: the ID of the QAuthZ authorization object against which
+# the client's x509 distinguished name will validated. This
+# object is only resolved at time of use, so can be deleted
+# and recreated on the fly while the chardev server is active.
+# If missing, it will default to denying access (since 4.0)
# @server: create server socket (default: true)
# @wait: wait for incoming connection on server
# sockets (default: false).
@@ -268,6 +273,7 @@
{ 'struct': 'ChardevSocket',
'data': { 'addr': 'SocketAddressLegacy',
'*tls-creds': 'str',
+ '*tls-authz' : 'str',
'*server': 'bool',
'*wait': 'bool',
'*nodelay': 'bool',
@@ -2408,7 +2408,7 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev,
"-chardev null,id=id[,mux=on|off][,logfile=PATH][,logappend=on|off]\n"
"-chardev socket,id=id[,host=host],port=port[,to=to][,ipv4][,ipv6][,nodelay][,reconnect=seconds]\n"
" [,server][,nowait][,telnet][,websocket][,reconnect=seconds][,mux=on|off]\n"
- " [,logfile=PATH][,logappend=on|off][,tls-creds=ID] (tcp)\n"
+ " [,logfile=PATH][,logappend=on|off][,tls-creds=ID][,tls-authz=ID] (tcp)\n"
"-chardev socket,id=id,path=path[,server][,nowait][,telnet][,websocket][,reconnect=seconds]\n"
" [,mux=on|off][,logfile=PATH][,logappend=on|off] (unix)\n"
"-chardev udp,id=id[,host=host],port=port[,localaddr=localaddr]\n"
@@ -2537,7 +2537,7 @@ The available backends are:
A void device. This device will not emit any data, and will drop any data it
receives. The null backend does not take any options.
-@item -chardev socket,id=@var{id}[,@var{TCP options} or @var{unix options}][,server][,nowait][,telnet][,websocket][,reconnect=@var{seconds}][,tls-creds=@var{id}]
+@item -chardev socket,id=@var{id}[,@var{TCP options} or @var{unix options}][,server][,nowait][,telnet][,websocket][,reconnect=@var{seconds}][,tls-creds=@var{id}][,tls-authz=@var{id}]
Create a two-way stream socket, which can be either a TCP or a unix socket. A
unix socket will be created if @option{path} is specified. Behaviour is
@@ -2563,6 +2563,11 @@ and specifies the id of the TLS credentials to use for the handshake. The
credentials must be previously created with the @option{-object tls-creds}
argument.
+@option{tls-auth} provides the ID of the QAuthZ authorization object against
+which the client's x509 distinguished name will validated. This object is only
+resolved at time of use, so can be deleted and recreated on the fly while the
+chardev server is active. If missing, it will default to denying access.
+
TCP and unix socket options are given below:
@table @option