authz: delete existing ACL implementation
The 'qemu_acl' type was a previous non-QOM based attempt to provide an authorization facility in QEMU. Because it is non-QOM based it cannot be created via the command line and requires special monitor commands to manipulate it. The new QAuthZ subclasses provide a superset of the functionality in qemu_acl, so the latter can now be deleted. The HMP 'acl_*' monitor commands are converted to use the new QAuthZSimple data type instead in order to provide temporary backwards compatibility. Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
parent
8953caf3cd
commit
b76806d4ec
17
configure
vendored
17
configure
vendored
@ -3205,20 +3205,6 @@ if test "$xkbcommon" != "no" ; then
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# fnmatch() probe, used for ACL routines
|
||||
fnmatch="no"
|
||||
cat > $TMPC << EOF
|
||||
#include <fnmatch.h>
|
||||
int main(void)
|
||||
{
|
||||
fnmatch("foo", "foo", 0);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if compile_prog "" "" ; then
|
||||
fnmatch="yes"
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# xfsctl() probe, used for file-posix.c
|
||||
@ -6416,9 +6402,6 @@ if test "$xkbcommon" = "yes" ; then
|
||||
echo "XKBCOMMON_CFLAGS=$xkbcommon_cflags" >> $config_host_mak
|
||||
echo "XKBCOMMON_LIBS=$xkbcommon_libs" >> $config_host_mak
|
||||
fi
|
||||
if test "$fnmatch" = "yes" ; then
|
||||
echo "CONFIG_FNMATCH=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$xfs" = "yes" ; then
|
||||
echo "CONFIG_XFS=y" >> $config_host_mak
|
||||
fi
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include "crypto/tlscredspsk.h"
|
||||
#include "crypto/tlscredsx509.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/acl.h"
|
||||
#include "authz/base.h"
|
||||
#include "trace.h"
|
||||
|
||||
#ifdef CONFIG_GNUTLS
|
||||
@ -37,7 +37,7 @@ struct QCryptoTLSSession {
|
||||
QCryptoTLSCreds *creds;
|
||||
gnutls_session_t handle;
|
||||
char *hostname;
|
||||
char *aclname;
|
||||
char *authzid;
|
||||
bool handshakeComplete;
|
||||
QCryptoTLSSessionWriteFunc writeFunc;
|
||||
QCryptoTLSSessionReadFunc readFunc;
|
||||
@ -56,7 +56,7 @@ qcrypto_tls_session_free(QCryptoTLSSession *session)
|
||||
gnutls_deinit(session->handle);
|
||||
g_free(session->hostname);
|
||||
g_free(session->peername);
|
||||
g_free(session->aclname);
|
||||
g_free(session->authzid);
|
||||
object_unref(OBJECT(session->creds));
|
||||
g_free(session);
|
||||
}
|
||||
@ -95,7 +95,7 @@ qcrypto_tls_session_pull(void *opaque, void *buf, size_t len)
|
||||
QCryptoTLSSession *
|
||||
qcrypto_tls_session_new(QCryptoTLSCreds *creds,
|
||||
const char *hostname,
|
||||
const char *aclname,
|
||||
const char *authzid,
|
||||
QCryptoTLSCredsEndpoint endpoint,
|
||||
Error **errp)
|
||||
{
|
||||
@ -105,13 +105,13 @@ qcrypto_tls_session_new(QCryptoTLSCreds *creds,
|
||||
session = g_new0(QCryptoTLSSession, 1);
|
||||
trace_qcrypto_tls_session_new(
|
||||
session, creds, hostname ? hostname : "<none>",
|
||||
aclname ? aclname : "<none>", endpoint);
|
||||
authzid ? authzid : "<none>", endpoint);
|
||||
|
||||
if (hostname) {
|
||||
session->hostname = g_strdup(hostname);
|
||||
}
|
||||
if (aclname) {
|
||||
session->aclname = g_strdup(aclname);
|
||||
if (authzid) {
|
||||
session->authzid = g_strdup(authzid);
|
||||
}
|
||||
session->creds = creds;
|
||||
object_ref(OBJECT(creds));
|
||||
@ -262,6 +262,7 @@ qcrypto_tls_session_check_certificate(QCryptoTLSSession *session,
|
||||
unsigned int nCerts, i;
|
||||
time_t now;
|
||||
gnutls_x509_crt_t cert = NULL;
|
||||
Error *err = NULL;
|
||||
|
||||
now = time(NULL);
|
||||
if (now == ((time_t)-1)) {
|
||||
@ -349,19 +350,17 @@ qcrypto_tls_session_check_certificate(QCryptoTLSSession *session,
|
||||
gnutls_strerror(ret));
|
||||
goto error;
|
||||
}
|
||||
if (session->aclname) {
|
||||
qemu_acl *acl = qemu_acl_find(session->aclname);
|
||||
int allow;
|
||||
if (!acl) {
|
||||
error_setg(errp, "Cannot find ACL %s",
|
||||
session->aclname);
|
||||
if (session->authzid) {
|
||||
bool allow;
|
||||
|
||||
allow = qauthz_is_allowed_by_id(session->authzid,
|
||||
session->peername, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
goto error;
|
||||
}
|
||||
|
||||
allow = qemu_acl_party_is_allowed(acl, session->peername);
|
||||
|
||||
if (!allow) {
|
||||
error_setg(errp, "TLS x509 ACL check for %s is denied",
|
||||
error_setg(errp, "TLS x509 authz check for %s is denied",
|
||||
session->peername);
|
||||
goto error;
|
||||
}
|
||||
@ -555,7 +554,7 @@ qcrypto_tls_session_get_peer_name(QCryptoTLSSession *session)
|
||||
QCryptoTLSSession *
|
||||
qcrypto_tls_session_new(QCryptoTLSCreds *creds G_GNUC_UNUSED,
|
||||
const char *hostname G_GNUC_UNUSED,
|
||||
const char *aclname G_GNUC_UNUSED,
|
||||
const char *authzid G_GNUC_UNUSED,
|
||||
QCryptoTLSCredsEndpoint endpoint G_GNUC_UNUSED,
|
||||
Error **errp)
|
||||
{
|
||||
|
@ -19,5 +19,5 @@ qcrypto_tls_creds_x509_load_cert(void *creds, int isServer, const char *file) "T
|
||||
qcrypto_tls_creds_x509_load_cert_list(void *creds, const char *file) "TLS creds x509 load cert list creds=%p file=%s"
|
||||
|
||||
# crypto/tlssession.c
|
||||
qcrypto_tls_session_new(void *session, void *creds, const char *hostname, const char *aclname, int endpoint) "TLS session new session=%p creds=%p hostname=%s aclname=%s endpoint=%d"
|
||||
qcrypto_tls_session_new(void *session, void *creds, const char *hostname, const char *authzid, int endpoint) "TLS session new session=%p creds=%p hostname=%s authzid=%s endpoint=%d"
|
||||
qcrypto_tls_session_check_creds(void *session, const char *status) "TLS session check creds session=%p status=%s"
|
||||
|
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* QEMU access control list management
|
||||
*
|
||||
* Copyright (C) 2009 Red Hat, Inc
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QEMU_ACL_H
|
||||
#define QEMU_ACL_H
|
||||
|
||||
#include "qemu/queue.h"
|
||||
|
||||
typedef struct qemu_acl_entry qemu_acl_entry;
|
||||
typedef struct qemu_acl qemu_acl;
|
||||
|
||||
struct qemu_acl_entry {
|
||||
char *match;
|
||||
int deny;
|
||||
|
||||
QTAILQ_ENTRY(qemu_acl_entry) next;
|
||||
};
|
||||
|
||||
struct qemu_acl {
|
||||
char *aclname;
|
||||
unsigned int nentries;
|
||||
QTAILQ_HEAD(,qemu_acl_entry) entries;
|
||||
int defaultDeny;
|
||||
};
|
||||
|
||||
qemu_acl *qemu_acl_init(const char *aclname);
|
||||
|
||||
qemu_acl *qemu_acl_find(const char *aclname);
|
||||
|
||||
int qemu_acl_party_is_allowed(qemu_acl *acl,
|
||||
const char *party);
|
||||
|
||||
void qemu_acl_reset(qemu_acl *acl);
|
||||
|
||||
int qemu_acl_append(qemu_acl *acl,
|
||||
int deny,
|
||||
const char *match);
|
||||
int qemu_acl_insert(qemu_acl *acl,
|
||||
int deny,
|
||||
const char *match,
|
||||
int index);
|
||||
int qemu_acl_remove(qemu_acl *acl,
|
||||
const char *match);
|
||||
|
||||
#endif /* QEMU_ACL_H */
|
175
monitor.c
175
monitor.c
@ -51,7 +51,8 @@
|
||||
#include "sysemu/balloon.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "sysemu/hw_accel.h"
|
||||
#include "qemu/acl.h"
|
||||
#include "authz/list.h"
|
||||
#include "qapi/util.h"
|
||||
#include "sysemu/tpm.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
@ -2016,93 +2017,148 @@ static void hmp_wavcapture(Monitor *mon, const QDict *qdict)
|
||||
QLIST_INSERT_HEAD (&capture_head, s, entries);
|
||||
}
|
||||
|
||||
static qemu_acl *find_acl(Monitor *mon, const char *name)
|
||||
static QAuthZList *find_auth(Monitor *mon, const char *name)
|
||||
{
|
||||
qemu_acl *acl = qemu_acl_find(name);
|
||||
Object *obj;
|
||||
Object *container;
|
||||
|
||||
if (!acl) {
|
||||
container = object_get_objects_root();
|
||||
obj = object_resolve_path_component(container, name);
|
||||
if (!obj) {
|
||||
monitor_printf(mon, "acl: unknown list '%s'\n", name);
|
||||
return NULL;
|
||||
}
|
||||
return acl;
|
||||
|
||||
return QAUTHZ_LIST(obj);
|
||||
}
|
||||
|
||||
static void hmp_acl_show(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
const char *aclname = qdict_get_str(qdict, "aclname");
|
||||
qemu_acl *acl = find_acl(mon, aclname);
|
||||
qemu_acl_entry *entry;
|
||||
int i = 0;
|
||||
QAuthZList *auth = find_auth(mon, aclname);
|
||||
QAuthZListRuleList *rules;
|
||||
size_t i = 0;
|
||||
|
||||
if (acl) {
|
||||
monitor_printf(mon, "policy: %s\n",
|
||||
acl->defaultDeny ? "deny" : "allow");
|
||||
QTAILQ_FOREACH(entry, &acl->entries, next) {
|
||||
i++;
|
||||
monitor_printf(mon, "%d: %s %s\n", i,
|
||||
entry->deny ? "deny" : "allow", entry->match);
|
||||
}
|
||||
if (!auth) {
|
||||
return;
|
||||
}
|
||||
|
||||
monitor_printf(mon, "policy: %s\n",
|
||||
QAuthZListPolicy_str(auth->policy));
|
||||
|
||||
rules = auth->rules;
|
||||
while (rules) {
|
||||
QAuthZListRule *rule = rules->value;
|
||||
i++;
|
||||
monitor_printf(mon, "%zu: %s %s\n", i,
|
||||
QAuthZListPolicy_str(rule->policy),
|
||||
rule->match);
|
||||
rules = rules->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void hmp_acl_reset(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
const char *aclname = qdict_get_str(qdict, "aclname");
|
||||
qemu_acl *acl = find_acl(mon, aclname);
|
||||
QAuthZList *auth = find_auth(mon, aclname);
|
||||
|
||||
if (acl) {
|
||||
qemu_acl_reset(acl);
|
||||
monitor_printf(mon, "acl: removed all rules\n");
|
||||
if (!auth) {
|
||||
return;
|
||||
}
|
||||
|
||||
auth->policy = QAUTHZ_LIST_POLICY_DENY;
|
||||
qapi_free_QAuthZListRuleList(auth->rules);
|
||||
auth->rules = NULL;
|
||||
monitor_printf(mon, "acl: removed all rules\n");
|
||||
}
|
||||
|
||||
static void hmp_acl_policy(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
const char *aclname = qdict_get_str(qdict, "aclname");
|
||||
const char *policy = qdict_get_str(qdict, "policy");
|
||||
qemu_acl *acl = find_acl(mon, aclname);
|
||||
QAuthZList *auth = find_auth(mon, aclname);
|
||||
int val;
|
||||
Error *err = NULL;
|
||||
|
||||
if (acl) {
|
||||
if (strcmp(policy, "allow") == 0) {
|
||||
acl->defaultDeny = 0;
|
||||
if (!auth) {
|
||||
return;
|
||||
}
|
||||
|
||||
val = qapi_enum_parse(&QAuthZListPolicy_lookup,
|
||||
policy,
|
||||
QAUTHZ_LIST_POLICY_DENY,
|
||||
&err);
|
||||
if (err) {
|
||||
error_free(err);
|
||||
monitor_printf(mon, "acl: unknown policy '%s', "
|
||||
"expected 'deny' or 'allow'\n", policy);
|
||||
} else {
|
||||
auth->policy = val;
|
||||
if (auth->policy == QAUTHZ_LIST_POLICY_ALLOW) {
|
||||
monitor_printf(mon, "acl: policy set to 'allow'\n");
|
||||
} else if (strcmp(policy, "deny") == 0) {
|
||||
acl->defaultDeny = 1;
|
||||
monitor_printf(mon, "acl: policy set to 'deny'\n");
|
||||
} else {
|
||||
monitor_printf(mon, "acl: unknown policy '%s', "
|
||||
"expected 'deny' or 'allow'\n", policy);
|
||||
monitor_printf(mon, "acl: policy set to 'deny'\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static QAuthZListFormat hmp_acl_get_format(const char *match)
|
||||
{
|
||||
if (strchr(match, '*')) {
|
||||
return QAUTHZ_LIST_FORMAT_GLOB;
|
||||
} else {
|
||||
return QAUTHZ_LIST_FORMAT_EXACT;
|
||||
}
|
||||
}
|
||||
|
||||
static void hmp_acl_add(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
const char *aclname = qdict_get_str(qdict, "aclname");
|
||||
const char *match = qdict_get_str(qdict, "match");
|
||||
const char *policy = qdict_get_str(qdict, "policy");
|
||||
const char *policystr = qdict_get_str(qdict, "policy");
|
||||
int has_index = qdict_haskey(qdict, "index");
|
||||
int index = qdict_get_try_int(qdict, "index", -1);
|
||||
qemu_acl *acl = find_acl(mon, aclname);
|
||||
int deny, ret;
|
||||
QAuthZList *auth = find_auth(mon, aclname);
|
||||
Error *err = NULL;
|
||||
QAuthZListPolicy policy;
|
||||
QAuthZListFormat format;
|
||||
size_t i = 0;
|
||||
|
||||
if (acl) {
|
||||
if (strcmp(policy, "allow") == 0) {
|
||||
deny = 0;
|
||||
} else if (strcmp(policy, "deny") == 0) {
|
||||
deny = 1;
|
||||
} else {
|
||||
monitor_printf(mon, "acl: unknown policy '%s', "
|
||||
"expected 'deny' or 'allow'\n", policy);
|
||||
return;
|
||||
}
|
||||
if (has_index)
|
||||
ret = qemu_acl_insert(acl, deny, match, index);
|
||||
else
|
||||
ret = qemu_acl_append(acl, deny, match);
|
||||
if (ret < 0)
|
||||
monitor_printf(mon, "acl: unable to add acl entry\n");
|
||||
else
|
||||
monitor_printf(mon, "acl: added rule at position %d\n", ret);
|
||||
if (!auth) {
|
||||
return;
|
||||
}
|
||||
|
||||
policy = qapi_enum_parse(&QAuthZListPolicy_lookup,
|
||||
policystr,
|
||||
QAUTHZ_LIST_POLICY_DENY,
|
||||
&err);
|
||||
if (err) {
|
||||
error_free(err);
|
||||
monitor_printf(mon, "acl: unknown policy '%s', "
|
||||
"expected 'deny' or 'allow'\n", policystr);
|
||||
return;
|
||||
}
|
||||
|
||||
format = hmp_acl_get_format(match);
|
||||
|
||||
if (has_index && index == 0) {
|
||||
monitor_printf(mon, "acl: unable to add acl entry\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (has_index) {
|
||||
i = qauthz_list_insert_rule(auth, match, policy,
|
||||
format, index - 1, &err);
|
||||
} else {
|
||||
i = qauthz_list_append_rule(auth, match, policy,
|
||||
format, &err);
|
||||
}
|
||||
if (err) {
|
||||
monitor_printf(mon, "acl: unable to add rule: %s",
|
||||
error_get_pretty(err));
|
||||
error_free(err);
|
||||
} else {
|
||||
monitor_printf(mon, "acl: added rule at position %zu\n", i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2110,15 +2166,18 @@ static void hmp_acl_remove(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
const char *aclname = qdict_get_str(qdict, "aclname");
|
||||
const char *match = qdict_get_str(qdict, "match");
|
||||
qemu_acl *acl = find_acl(mon, aclname);
|
||||
int ret;
|
||||
QAuthZList *auth = find_auth(mon, aclname);
|
||||
ssize_t i = 0;
|
||||
|
||||
if (acl) {
|
||||
ret = qemu_acl_remove(acl, match);
|
||||
if (ret < 0)
|
||||
monitor_printf(mon, "acl: no matching acl entry\n");
|
||||
else
|
||||
monitor_printf(mon, "acl: removed rule at position %d\n", ret);
|
||||
if (!auth) {
|
||||
return;
|
||||
}
|
||||
|
||||
i = qauthz_list_delete_rule(auth, match);
|
||||
if (i >= 0) {
|
||||
monitor_printf(mon, "acl: removed rule at position %zu\n", i + 1);
|
||||
} else {
|
||||
monitor_printf(mon, "acl: no matching acl entry\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -537,8 +537,8 @@ test-qom-obj-y = $(qom-obj-y) $(test-util-obj-y)
|
||||
test-qapi-obj-y = tests/test-qapi-visit.o tests/test-qapi-types.o \
|
||||
tests/test-qapi-introspect.o \
|
||||
$(test-qom-obj-y)
|
||||
benchmark-crypto-obj-y = $(crypto-obj-y) $(test-qom-obj-y)
|
||||
test-crypto-obj-y = $(crypto-obj-y) $(test-qom-obj-y)
|
||||
benchmark-crypto-obj-y = $(authz-obj-y) $(crypto-obj-y) $(test-qom-obj-y)
|
||||
test-crypto-obj-y = $(authz-obj-y) $(crypto-obj-y) $(test-qom-obj-y)
|
||||
test-io-obj-y = $(io-obj-y) $(test-crypto-obj-y)
|
||||
test-authz-obj-y = $(test-qom-obj-y) $(authz-obj-y)
|
||||
test-block-obj-y = $(block-obj-y) $(test-io-obj-y) tests/iothread.o
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "qom/object_interfaces.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/sockets.h"
|
||||
#include "qemu/acl.h"
|
||||
#include "authz/list.h"
|
||||
|
||||
#ifdef QCRYPTO_HAVE_TLS_TEST_SUPPORT
|
||||
|
||||
@ -229,7 +229,7 @@ static void test_crypto_tls_session_x509(const void *opaque)
|
||||
QCryptoTLSCreds *serverCreds;
|
||||
QCryptoTLSSession *clientSess = NULL;
|
||||
QCryptoTLSSession *serverSess = NULL;
|
||||
qemu_acl *acl;
|
||||
QAuthZList *auth;
|
||||
const char * const *wildcards;
|
||||
int channel[2];
|
||||
bool clientShake = false;
|
||||
@ -285,11 +285,15 @@ static void test_crypto_tls_session_x509(const void *opaque)
|
||||
SERVER_CERT_DIR);
|
||||
g_assert(serverCreds != NULL);
|
||||
|
||||
acl = qemu_acl_init("tlssessionacl");
|
||||
qemu_acl_reset(acl);
|
||||
auth = qauthz_list_new("tlssessionacl",
|
||||
QAUTHZ_LIST_POLICY_DENY,
|
||||
&error_abort);
|
||||
wildcards = data->wildcards;
|
||||
while (wildcards && *wildcards) {
|
||||
qemu_acl_append(acl, 0, *wildcards);
|
||||
qauthz_list_append_rule(auth, *wildcards,
|
||||
QAUTHZ_LIST_POLICY_ALLOW,
|
||||
QAUTHZ_LIST_FORMAT_GLOB,
|
||||
&error_abort);
|
||||
wildcards++;
|
||||
}
|
||||
|
||||
@ -377,6 +381,7 @@ static void test_crypto_tls_session_x509(const void *opaque)
|
||||
|
||||
object_unparent(OBJECT(serverCreds));
|
||||
object_unparent(OBJECT(clientCreds));
|
||||
object_unparent(OBJECT(auth));
|
||||
|
||||
qcrypto_tls_session_free(serverSess);
|
||||
qcrypto_tls_session_free(clientSess);
|
||||
|
@ -29,8 +29,8 @@
|
||||
#include "io-channel-helpers.h"
|
||||
#include "crypto/init.h"
|
||||
#include "crypto/tlscredsx509.h"
|
||||
#include "qemu/acl.h"
|
||||
#include "qapi/error.h"
|
||||
#include "authz/list.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
|
||||
#ifdef QCRYPTO_HAVE_TLS_TEST_SUPPORT
|
||||
@ -113,7 +113,7 @@ static void test_io_channel_tls(const void *opaque)
|
||||
QIOChannelTLS *serverChanTLS;
|
||||
QIOChannelSocket *clientChanSock;
|
||||
QIOChannelSocket *serverChanSock;
|
||||
qemu_acl *acl;
|
||||
QAuthZList *auth;
|
||||
const char * const *wildcards;
|
||||
int channel[2];
|
||||
struct QIOChannelTLSHandshakeData clientHandshake = { false, false };
|
||||
@ -161,11 +161,15 @@ static void test_io_channel_tls(const void *opaque)
|
||||
SERVER_CERT_DIR);
|
||||
g_assert(serverCreds != NULL);
|
||||
|
||||
acl = qemu_acl_init("channeltlsacl");
|
||||
qemu_acl_reset(acl);
|
||||
auth = qauthz_list_new("channeltlsacl",
|
||||
QAUTHZ_LIST_POLICY_DENY,
|
||||
&error_abort);
|
||||
wildcards = data->wildcards;
|
||||
while (wildcards && *wildcards) {
|
||||
qemu_acl_append(acl, 0, *wildcards);
|
||||
qauthz_list_append_rule(auth, *wildcards,
|
||||
QAUTHZ_LIST_POLICY_ALLOW,
|
||||
QAUTHZ_LIST_FORMAT_GLOB,
|
||||
&error_abort);
|
||||
wildcards++;
|
||||
}
|
||||
|
||||
@ -253,6 +257,8 @@ static void test_io_channel_tls(const void *opaque)
|
||||
object_unref(OBJECT(serverChanSock));
|
||||
object_unref(OBJECT(clientChanSock));
|
||||
|
||||
object_unparent(OBJECT(auth));
|
||||
|
||||
close(channel[0]);
|
||||
close(channel[1]);
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "authz/base.h"
|
||||
#include "vnc.h"
|
||||
#include "trace.h"
|
||||
|
||||
@ -146,13 +147,14 @@ size_t vnc_client_read_sasl(VncState *vs)
|
||||
static int vnc_auth_sasl_check_access(VncState *vs)
|
||||
{
|
||||
const void *val;
|
||||
int err;
|
||||
int allow;
|
||||
int rv;
|
||||
Error *err = NULL;
|
||||
bool allow;
|
||||
|
||||
err = sasl_getprop(vs->sasl.conn, SASL_USERNAME, &val);
|
||||
if (err != SASL_OK) {
|
||||
rv = sasl_getprop(vs->sasl.conn, SASL_USERNAME, &val);
|
||||
if (rv != SASL_OK) {
|
||||
trace_vnc_auth_fail(vs, vs->auth, "Cannot fetch SASL username",
|
||||
sasl_errstring(err, NULL, NULL));
|
||||
sasl_errstring(rv, NULL, NULL));
|
||||
return -1;
|
||||
}
|
||||
if (val == NULL) {
|
||||
@ -163,12 +165,19 @@ static int vnc_auth_sasl_check_access(VncState *vs)
|
||||
vs->sasl.username = g_strdup((const char*)val);
|
||||
trace_vnc_auth_sasl_username(vs, vs->sasl.username);
|
||||
|
||||
if (vs->vd->sasl.acl == NULL) {
|
||||
if (vs->vd->sasl.authzid == NULL) {
|
||||
trace_vnc_auth_sasl_acl(vs, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
allow = qemu_acl_party_is_allowed(vs->vd->sasl.acl, vs->sasl.username);
|
||||
allow = qauthz_is_allowed_by_id(vs->vd->sasl.authzid,
|
||||
vs->sasl.username, &err);
|
||||
if (err) {
|
||||
trace_vnc_auth_fail(vs, vs->auth, "Error from authz",
|
||||
error_get_pretty(err));
|
||||
error_free(err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
trace_vnc_auth_sasl_acl(vs, allow);
|
||||
return allow ? 0 : -1;
|
||||
|
@ -30,8 +30,8 @@
|
||||
typedef struct VncStateSASL VncStateSASL;
|
||||
typedef struct VncDisplaySASL VncDisplaySASL;
|
||||
|
||||
#include "qemu/acl.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "authz/base.h"
|
||||
|
||||
struct VncStateSASL {
|
||||
sasl_conn_t *conn;
|
||||
@ -60,7 +60,8 @@ struct VncStateSASL {
|
||||
};
|
||||
|
||||
struct VncDisplaySASL {
|
||||
qemu_acl *acl;
|
||||
QAuthZ *authz;
|
||||
char *authzid;
|
||||
};
|
||||
|
||||
void vnc_sasl_client_cleanup(VncState *vs);
|
||||
|
@ -109,7 +109,7 @@ static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len
|
||||
tls = qio_channel_tls_new_server(
|
||||
vs->ioc,
|
||||
vs->vd->tlscreds,
|
||||
vs->vd->tlsaclname,
|
||||
vs->vd->tlsauthzid,
|
||||
&err);
|
||||
if (!tls) {
|
||||
trace_vnc_auth_fail(vs, vs->auth, "TLS setup failed",
|
||||
|
@ -62,7 +62,7 @@ gboolean vncws_tls_handshake_io(QIOChannel *ioc G_GNUC_UNUSED,
|
||||
tls = qio_channel_tls_new_server(
|
||||
vs->ioc,
|
||||
vs->vd->tlscreds,
|
||||
vs->vd->tlsaclname,
|
||||
vs->vd->tlsauthzid,
|
||||
&err);
|
||||
if (!tls) {
|
||||
VNC_DEBUG("Failed to setup TLS %s\n", error_get_pretty(err));
|
||||
|
37
ui/vnc.c
37
ui/vnc.c
@ -33,7 +33,7 @@
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/sockets.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/acl.h"
|
||||
#include "authz/list.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "qapi/qapi-emit-events.h"
|
||||
#include "qapi/qapi-events-ui.h"
|
||||
@ -3229,12 +3229,24 @@ static void vnc_display_close(VncDisplay *vd)
|
||||
object_unparent(OBJECT(vd->tlscreds));
|
||||
vd->tlscreds = NULL;
|
||||
}
|
||||
g_free(vd->tlsaclname);
|
||||
vd->tlsaclname = NULL;
|
||||
if (vd->tlsauthz) {
|
||||
object_unparent(OBJECT(vd->tlsauthz));
|
||||
vd->tlsauthz = NULL;
|
||||
}
|
||||
g_free(vd->tlsauthzid);
|
||||
vd->tlsauthzid = NULL;
|
||||
if (vd->lock_key_sync) {
|
||||
qemu_remove_led_event_handler(vd->led);
|
||||
vd->led = NULL;
|
||||
}
|
||||
#ifdef CONFIG_VNC_SASL
|
||||
if (vd->sasl.authz) {
|
||||
object_unparent(OBJECT(vd->sasl.authz));
|
||||
vd->sasl.authz = NULL;
|
||||
}
|
||||
g_free(vd->sasl.authzid);
|
||||
vd->sasl.authzid = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
int vnc_display_password(const char *id, const char *password)
|
||||
@ -3887,23 +3899,24 @@ void vnc_display_open(const char *id, Error **errp)
|
||||
|
||||
if (acl) {
|
||||
if (strcmp(vd->id, "default") == 0) {
|
||||
vd->tlsaclname = g_strdup("vnc.x509dname");
|
||||
vd->tlsauthzid = g_strdup("vnc.x509dname");
|
||||
} else {
|
||||
vd->tlsaclname = g_strdup_printf("vnc.%s.x509dname", vd->id);
|
||||
vd->tlsauthzid = g_strdup_printf("vnc.%s.x509dname", vd->id);
|
||||
}
|
||||
qemu_acl_init(vd->tlsaclname);
|
||||
vd->tlsauthz = QAUTHZ(qauthz_list_new(vd->tlsauthzid,
|
||||
QAUTHZ_LIST_POLICY_DENY,
|
||||
&error_abort));
|
||||
}
|
||||
#ifdef CONFIG_VNC_SASL
|
||||
if (acl && sasl) {
|
||||
char *aclname;
|
||||
|
||||
if (strcmp(vd->id, "default") == 0) {
|
||||
aclname = g_strdup("vnc.username");
|
||||
vd->sasl.authzid = g_strdup("vnc.username");
|
||||
} else {
|
||||
aclname = g_strdup_printf("vnc.%s.username", vd->id);
|
||||
vd->sasl.authzid = g_strdup_printf("vnc.%s.username", vd->id);
|
||||
}
|
||||
vd->sasl.acl = qemu_acl_init(aclname);
|
||||
g_free(aclname);
|
||||
vd->sasl.authz = QAUTHZ(qauthz_list_new(vd->sasl.authzid,
|
||||
QAUTHZ_LIST_POLICY_DENY,
|
||||
&error_abort));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
4
ui/vnc.h
4
ui/vnc.h
@ -39,6 +39,7 @@
|
||||
#include "io/channel-socket.h"
|
||||
#include "io/channel-tls.h"
|
||||
#include "io/net-listener.h"
|
||||
#include "authz/base.h"
|
||||
#include <zlib.h>
|
||||
|
||||
#include "keymaps.h"
|
||||
@ -178,7 +179,8 @@ struct VncDisplay
|
||||
bool lossy;
|
||||
bool non_adaptive;
|
||||
QCryptoTLSCreds *tlscreds;
|
||||
char *tlsaclname;
|
||||
QAuthZ *tlsauthz;
|
||||
char *tlsauthzid;
|
||||
#ifdef CONFIG_VNC_SASL
|
||||
VncDisplaySASL sasl;
|
||||
#endif
|
||||
|
@ -20,7 +20,6 @@ util-obj-y += envlist.o path.o module.o
|
||||
util-obj-y += host-utils.o
|
||||
util-obj-y += bitmap.o bitops.o hbitmap.o
|
||||
util-obj-y += fifo8.o
|
||||
util-obj-y += acl.o
|
||||
util-obj-y += cacheinfo.o
|
||||
util-obj-y += error.o qemu-error.o
|
||||
util-obj-y += id.o
|
||||
|
179
util/acl.c
179
util/acl.c
@ -1,179 +0,0 @@
|
||||
/*
|
||||
* QEMU access control list management
|
||||
*
|
||||
* Copyright (C) 2009 Red Hat, Inc
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/acl.h"
|
||||
|
||||
#ifdef CONFIG_FNMATCH
|
||||
#include <fnmatch.h>
|
||||
#endif
|
||||
|
||||
|
||||
static unsigned int nacls = 0;
|
||||
static qemu_acl **acls = NULL;
|
||||
|
||||
|
||||
|
||||
qemu_acl *qemu_acl_find(const char *aclname)
|
||||
{
|
||||
int i;
|
||||
for (i = 0 ; i < nacls ; i++) {
|
||||
if (strcmp(acls[i]->aclname, aclname) == 0)
|
||||
return acls[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qemu_acl *qemu_acl_init(const char *aclname)
|
||||
{
|
||||
qemu_acl *acl;
|
||||
|
||||
acl = qemu_acl_find(aclname);
|
||||
if (acl)
|
||||
return acl;
|
||||
|
||||
acl = g_malloc(sizeof(*acl));
|
||||
acl->aclname = g_strdup(aclname);
|
||||
/* Deny by default, so there is no window of "open
|
||||
* access" between QEMU starting, and the user setting
|
||||
* up ACLs in the monitor */
|
||||
acl->defaultDeny = 1;
|
||||
|
||||
acl->nentries = 0;
|
||||
QTAILQ_INIT(&acl->entries);
|
||||
|
||||
acls = g_realloc(acls, sizeof(*acls) * (nacls +1));
|
||||
acls[nacls] = acl;
|
||||
nacls++;
|
||||
|
||||
return acl;
|
||||
}
|
||||
|
||||
int qemu_acl_party_is_allowed(qemu_acl *acl,
|
||||
const char *party)
|
||||
{
|
||||
qemu_acl_entry *entry;
|
||||
|
||||
QTAILQ_FOREACH(entry, &acl->entries, next) {
|
||||
#ifdef CONFIG_FNMATCH
|
||||
if (fnmatch(entry->match, party, 0) == 0)
|
||||
return entry->deny ? 0 : 1;
|
||||
#else
|
||||
/* No fnmatch, so fallback to exact string matching
|
||||
* instead of allowing wildcards */
|
||||
if (strcmp(entry->match, party) == 0)
|
||||
return entry->deny ? 0 : 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
return acl->defaultDeny ? 0 : 1;
|
||||
}
|
||||
|
||||
|
||||
void qemu_acl_reset(qemu_acl *acl)
|
||||
{
|
||||
qemu_acl_entry *entry, *next_entry;
|
||||
|
||||
/* Put back to deny by default, so there is no window
|
||||
* of "open access" while the user re-initializes the
|
||||
* access control list */
|
||||
acl->defaultDeny = 1;
|
||||
QTAILQ_FOREACH_SAFE(entry, &acl->entries, next, next_entry) {
|
||||
QTAILQ_REMOVE(&acl->entries, entry, next);
|
||||
g_free(entry->match);
|
||||
g_free(entry);
|
||||
}
|
||||
acl->nentries = 0;
|
||||
}
|
||||
|
||||
|
||||
int qemu_acl_append(qemu_acl *acl,
|
||||
int deny,
|
||||
const char *match)
|
||||
{
|
||||
qemu_acl_entry *entry;
|
||||
|
||||
entry = g_malloc(sizeof(*entry));
|
||||
entry->match = g_strdup(match);
|
||||
entry->deny = deny;
|
||||
|
||||
QTAILQ_INSERT_TAIL(&acl->entries, entry, next);
|
||||
acl->nentries++;
|
||||
|
||||
return acl->nentries;
|
||||
}
|
||||
|
||||
|
||||
int qemu_acl_insert(qemu_acl *acl,
|
||||
int deny,
|
||||
const char *match,
|
||||
int index)
|
||||
{
|
||||
qemu_acl_entry *tmp;
|
||||
int i = 0;
|
||||
|
||||
if (index <= 0)
|
||||
return -1;
|
||||
if (index > acl->nentries) {
|
||||
return qemu_acl_append(acl, deny, match);
|
||||
}
|
||||
|
||||
QTAILQ_FOREACH(tmp, &acl->entries, next) {
|
||||
i++;
|
||||
if (i == index) {
|
||||
qemu_acl_entry *entry;
|
||||
entry = g_malloc(sizeof(*entry));
|
||||
entry->match = g_strdup(match);
|
||||
entry->deny = deny;
|
||||
|
||||
QTAILQ_INSERT_BEFORE(tmp, entry, next);
|
||||
acl->nentries++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int qemu_acl_remove(qemu_acl *acl,
|
||||
const char *match)
|
||||
{
|
||||
qemu_acl_entry *entry;
|
||||
int i = 0;
|
||||
|
||||
QTAILQ_FOREACH(entry, &acl->entries, next) {
|
||||
i++;
|
||||
if (strcmp(entry->match, match) == 0) {
|
||||
QTAILQ_REMOVE(&acl->entries, entry, next);
|
||||
acl->nentries--;
|
||||
g_free(entry->match);
|
||||
g_free(entry);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
Loading…
Reference in New Issue
Block a user