mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/berrange/tags/authz-core-pull-request' into staging
Add a standard authorization framework The current network services now support encryption via TLS and in some cases support authentication via SASL. In cases where SASL is not available, x509 client certificates can be used as a crude authorization scheme, but using a sub-CA and controlling who you give certs to. In general this is not very flexible though, so this series introduces a new standard authorization framework. It comes with four initial authorization mechanisms - Simple - an exact username match. This is useful when there is exactly one user that is known to connect. For example when live migrating from one QEMU to another with TLS, libvirt would use the simple scheme to whitelist the TLS cert of the source QEMU. - List - an full access control list, with optional regex matching. This is more flexible and is used to provide 100% backcompat with the existing HMP ACL commands. The caveat is that we can't create these via the CLI -object arg yet. - ListFile - the same as List, but with the rules stored in JSON format in an external file. This avoids the -object limitation while also allowing the admin to change list entries on the file. QEMU uses inotify to notice these changes and auto-reload the file contents. This is likely a good default choice for most network services, if the "simple" mechanism isn't sufficient. - PAM - delegate the username lookup to a PAM module, which opens the door to many options including things like SQL/LDAP lookups. # gpg: Signature made Tue 26 Feb 2019 15:33:46 GMT # gpg: using RSA key BE86EBB415104FDF # gpg: Good signature from "Daniel P. Berrange <dan@berrange.com>" [full] # gpg: aka "Daniel P. Berrange <berrange@redhat.com>" [full] # Primary key fingerprint: DAF3 A6FD B26B 6291 2D0E 8E3F BE86 EBB4 1510 4FDF * remotes/berrange/tags/authz-core-pull-request: authz: delete existing ACL implementation authz: add QAuthZPAM object type for authorizing using PAM authz: add QAuthZListFile object type for a file access control list authz: add QAuthZList object type for an access control list authz: add QAuthZSimple object type for easy whitelist auth checks authz: add QAuthZ object as an authorization base class hw/usb: switch MTP to use new inotify APIs hw/usb: fix const-ness for string params in MTP driver hw/usb: don't set IN_ISDIR for inotify watch in MTP driver qom: don't require user creatable objects to be registered util: add helper APIs for dealing with inotify in portable manner Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
+15
@@ -2079,6 +2079,14 @@ F: io/
|
||||
F: include/io/
|
||||
F: tests/test-io-*
|
||||
|
||||
User authorization
|
||||
M: Daniel P. Berrange <berrange@redhat.com>
|
||||
S: Maintained
|
||||
F: authz/
|
||||
F: qapi/authz.json
|
||||
F: include/authz/
|
||||
F: tests/test-authz-*
|
||||
|
||||
Sockets
|
||||
M: Daniel P. Berrange <berrange@redhat.com>
|
||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||
@@ -2087,6 +2095,13 @@ F: include/qemu/sockets.h
|
||||
F: util/qemu-sockets.c
|
||||
F: qapi/sockets.json
|
||||
|
||||
File monitor
|
||||
M: Daniel P. Berrange <berrange@redhat.com>
|
||||
S: Odd fixes
|
||||
F: util/filemonitor*.c
|
||||
F: include/qemu/filemonitor.h
|
||||
F: tests/test-util-filemonitor.c
|
||||
|
||||
Throttling infrastructure
|
||||
M: Alberto Garcia <berto@igalia.com>
|
||||
S: Supported
|
||||
|
||||
@@ -359,6 +359,7 @@ endif
|
||||
|
||||
dummy := $(call unnest-vars,, \
|
||||
stub-obj-y \
|
||||
authz-obj-y \
|
||||
chardev-obj-y \
|
||||
util-obj-y \
|
||||
qga-obj-y \
|
||||
@@ -423,6 +424,7 @@ qemu-options.def: $(SRC_PATH)/qemu-options.hx $(SRC_PATH)/scripts/hxtool
|
||||
SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
|
||||
SOFTMMU_SUBDIR_RULES=$(filter %-softmmu,$(SUBDIR_RULES))
|
||||
|
||||
$(SOFTMMU_SUBDIR_RULES): $(authz-obj-y)
|
||||
$(SOFTMMU_SUBDIR_RULES): $(block-obj-y)
|
||||
$(SOFTMMU_SUBDIR_RULES): $(crypto-obj-y)
|
||||
$(SOFTMMU_SUBDIR_RULES): $(io-obj-y)
|
||||
@@ -485,9 +487,9 @@ COMMON_LDADDS = libqemuutil.a
|
||||
|
||||
qemu-img.o: qemu-img-cmds.h
|
||||
|
||||
qemu-img$(EXESUF): qemu-img.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
|
||||
qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
|
||||
qemu-io$(EXESUF): qemu-io.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
|
||||
qemu-img$(EXESUF): qemu-img.o $(authz-obj-y) $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
|
||||
qemu-nbd$(EXESUF): qemu-nbd.o $(authz-obj-y) $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
|
||||
qemu-io$(EXESUF): qemu-io.o $(authz-obj-y) $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
|
||||
|
||||
qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o $(COMMON_LDADDS)
|
||||
|
||||
@@ -498,7 +500,7 @@ qemu-edid$(EXESUF): qemu-edid.o hw/display/edid-generate.o $(COMMON_LDADDS)
|
||||
fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/9p-marshal.o fsdev/9p-iov-marshal.o $(COMMON_LDADDS)
|
||||
fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
|
||||
|
||||
scsi/qemu-pr-helper$(EXESUF): scsi/qemu-pr-helper.o scsi/utils.o $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
|
||||
scsi/qemu-pr-helper$(EXESUF): scsi/qemu-pr-helper.o scsi/utils.o $(authz-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
|
||||
ifdef CONFIG_MPATH
|
||||
scsi/qemu-pr-helper$(EXESUF): LIBS += -ludev -lmultipath -lmpathpersist
|
||||
endif
|
||||
|
||||
+7
-1
@@ -1,11 +1,16 @@
|
||||
#######################################################################
|
||||
# Common libraries for tools and emulators
|
||||
stub-obj-y = stubs/ crypto/
|
||||
stub-obj-y = stubs/ util/ crypto/
|
||||
util-obj-y = util/ qobject/ qapi/
|
||||
|
||||
chardev-obj-y = chardev/
|
||||
slirp-obj-$(CONFIG_SLIRP) = slirp/
|
||||
|
||||
#######################################################################
|
||||
# authz-obj-y is code used by both qemu system emulation and qemu-img
|
||||
|
||||
authz-obj-y = authz/
|
||||
|
||||
#######################################################################
|
||||
# block-obj-y is code used by both qemu system emulation and qemu-img
|
||||
|
||||
@@ -125,6 +130,7 @@ trace-events-subdirs =
|
||||
trace-events-subdirs += accel/kvm
|
||||
trace-events-subdirs += accel/tcg
|
||||
trace-events-subdirs += audio
|
||||
trace-events-subdirs += authz
|
||||
trace-events-subdirs += block
|
||||
trace-events-subdirs += chardev
|
||||
trace-events-subdirs += crypto
|
||||
|
||||
@@ -179,6 +179,7 @@ include $(SRC_PATH)/Makefile.objs
|
||||
dummy := $(call unnest-vars,,target-obj-y)
|
||||
target-obj-y-save := $(target-obj-y)
|
||||
dummy := $(call unnest-vars,.., \
|
||||
authz-obj-y \
|
||||
block-obj-y \
|
||||
block-obj-m \
|
||||
chardev-obj-y \
|
||||
@@ -193,6 +194,7 @@ target-obj-y := $(target-obj-y-save)
|
||||
all-obj-y += $(common-obj-y)
|
||||
all-obj-y += $(target-obj-y)
|
||||
all-obj-y += $(qom-obj-y)
|
||||
all-obj-$(CONFIG_SOFTMMU) += $(authz-obj-y)
|
||||
all-obj-$(CONFIG_SOFTMMU) += $(block-obj-y) $(chardev-obj-y)
|
||||
all-obj-$(CONFIG_USER_ONLY) += $(crypto-aes-obj-y)
|
||||
all-obj-$(CONFIG_SOFTMMU) += $(crypto-obj-y)
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
authz-obj-y += base.o
|
||||
authz-obj-y += simple.o
|
||||
authz-obj-y += list.o
|
||||
authz-obj-y += listfile.o
|
||||
authz-obj-$(CONFIG_AUTH_PAM) += pamacct.o
|
||||
|
||||
pamacct.o-libs = -lpam
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* QEMU authorization framework base class
|
||||
*
|
||||
* Copyright (c) 2018 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "authz/base.h"
|
||||
#include "authz/trace.h"
|
||||
|
||||
bool qauthz_is_allowed(QAuthZ *authz,
|
||||
const char *identity,
|
||||
Error **errp)
|
||||
{
|
||||
QAuthZClass *cls = QAUTHZ_GET_CLASS(authz);
|
||||
bool allowed;
|
||||
|
||||
allowed = cls->is_allowed(authz, identity, errp);
|
||||
trace_qauthz_is_allowed(authz, identity, allowed);
|
||||
|
||||
return allowed;
|
||||
}
|
||||
|
||||
|
||||
bool qauthz_is_allowed_by_id(const char *authzid,
|
||||
const char *identity,
|
||||
Error **errp)
|
||||
{
|
||||
QAuthZ *authz;
|
||||
Object *obj;
|
||||
Object *container;
|
||||
|
||||
container = object_get_objects_root();
|
||||
obj = object_resolve_path_component(container,
|
||||
authzid);
|
||||
if (!obj) {
|
||||
error_setg(errp, "Cannot find QAuthZ object ID %s",
|
||||
authzid);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!object_dynamic_cast(obj, TYPE_QAUTHZ)) {
|
||||
error_setg(errp, "Object '%s' is not a QAuthZ subclass",
|
||||
authzid);
|
||||
return false;
|
||||
}
|
||||
|
||||
authz = QAUTHZ(obj);
|
||||
|
||||
return qauthz_is_allowed(authz, identity, errp);
|
||||
}
|
||||
|
||||
|
||||
static const TypeInfo authz_info = {
|
||||
.parent = TYPE_OBJECT,
|
||||
.name = TYPE_QAUTHZ,
|
||||
.instance_size = sizeof(QAuthZ),
|
||||
.class_size = sizeof(QAuthZClass),
|
||||
.abstract = true,
|
||||
};
|
||||
|
||||
static void qauthz_register_types(void)
|
||||
{
|
||||
type_register_static(&authz_info);
|
||||
}
|
||||
|
||||
type_init(qauthz_register_types)
|
||||
|
||||
+271
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* QEMU access control list authorization driver
|
||||
*
|
||||
* Copyright (c) 2018 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "authz/list.h"
|
||||
#include "authz/trace.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
#include "qapi/qapi-visit-authz.h"
|
||||
|
||||
static bool qauthz_list_is_allowed(QAuthZ *authz,
|
||||
const char *identity,
|
||||
Error **errp)
|
||||
{
|
||||
QAuthZList *lauthz = QAUTHZ_LIST(authz);
|
||||
QAuthZListRuleList *rules = lauthz->rules;
|
||||
|
||||
while (rules) {
|
||||
QAuthZListRule *rule = rules->value;
|
||||
QAuthZListFormat format = rule->has_format ? rule->format :
|
||||
QAUTHZ_LIST_FORMAT_EXACT;
|
||||
|
||||
trace_qauthz_list_check_rule(authz, rule->match, identity,
|
||||
format, rule->policy);
|
||||
switch (format) {
|
||||
case QAUTHZ_LIST_FORMAT_EXACT:
|
||||
if (g_str_equal(rule->match, identity)) {
|
||||
return rule->policy == QAUTHZ_LIST_POLICY_ALLOW;
|
||||
}
|
||||
break;
|
||||
case QAUTHZ_LIST_FORMAT_GLOB:
|
||||
if (g_pattern_match_simple(rule->match, identity)) {
|
||||
return rule->policy == QAUTHZ_LIST_POLICY_ALLOW;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_warn_if_reached();
|
||||
return false;
|
||||
}
|
||||
rules = rules->next;
|
||||
}
|
||||
|
||||
trace_qauthz_list_default_policy(authz, identity, lauthz->policy);
|
||||
return lauthz->policy == QAUTHZ_LIST_POLICY_ALLOW;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qauthz_list_prop_set_policy(Object *obj,
|
||||
int value,
|
||||
Error **errp G_GNUC_UNUSED)
|
||||
{
|
||||
QAuthZList *lauthz = QAUTHZ_LIST(obj);
|
||||
|
||||
lauthz->policy = value;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qauthz_list_prop_get_policy(Object *obj,
|
||||
Error **errp G_GNUC_UNUSED)
|
||||
{
|
||||
QAuthZList *lauthz = QAUTHZ_LIST(obj);
|
||||
|
||||
return lauthz->policy;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qauthz_list_prop_get_rules(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
QAuthZList *lauthz = QAUTHZ_LIST(obj);
|
||||
|
||||
visit_type_QAuthZListRuleList(v, name, &lauthz->rules, errp);
|
||||
}
|
||||
|
||||
static void
|
||||
qauthz_list_prop_set_rules(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
QAuthZList *lauthz = QAUTHZ_LIST(obj);
|
||||
QAuthZListRuleList *oldrules;
|
||||
|
||||
oldrules = lauthz->rules;
|
||||
visit_type_QAuthZListRuleList(v, name, &lauthz->rules, errp);
|
||||
|
||||
qapi_free_QAuthZListRuleList(oldrules);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qauthz_list_finalize(Object *obj)
|
||||
{
|
||||
QAuthZList *lauthz = QAUTHZ_LIST(obj);
|
||||
|
||||
qapi_free_QAuthZListRuleList(lauthz->rules);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qauthz_list_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
QAuthZClass *authz = QAUTHZ_CLASS(oc);
|
||||
|
||||
object_class_property_add_enum(oc, "policy",
|
||||
"QAuthZListPolicy",
|
||||
&QAuthZListPolicy_lookup,
|
||||
qauthz_list_prop_get_policy,
|
||||
qauthz_list_prop_set_policy,
|
||||
NULL);
|
||||
|
||||
object_class_property_add(oc, "rules", "QAuthZListRule",
|
||||
qauthz_list_prop_get_rules,
|
||||
qauthz_list_prop_set_rules,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
authz->is_allowed = qauthz_list_is_allowed;
|
||||
}
|
||||
|
||||
|
||||
QAuthZList *qauthz_list_new(const char *id,
|
||||
QAuthZListPolicy policy,
|
||||
Error **errp)
|
||||
{
|
||||
return QAUTHZ_LIST(
|
||||
object_new_with_props(TYPE_QAUTHZ_LIST,
|
||||
object_get_objects_root(),
|
||||
id, errp,
|
||||
"policy", QAuthZListPolicy_str(policy),
|
||||
NULL));
|
||||
}
|
||||
|
||||
ssize_t qauthz_list_append_rule(QAuthZList *auth,
|
||||
const char *match,
|
||||
QAuthZListPolicy policy,
|
||||
QAuthZListFormat format,
|
||||
Error **errp)
|
||||
{
|
||||
QAuthZListRule *rule;
|
||||
QAuthZListRuleList *rules, *tmp;
|
||||
size_t i = 0;
|
||||
|
||||
rule = g_new0(QAuthZListRule, 1);
|
||||
rule->policy = policy;
|
||||
rule->match = g_strdup(match);
|
||||
rule->format = format;
|
||||
rule->has_format = true;
|
||||
|
||||
tmp = g_new0(QAuthZListRuleList, 1);
|
||||
tmp->value = rule;
|
||||
|
||||
rules = auth->rules;
|
||||
if (rules) {
|
||||
while (rules->next) {
|
||||
i++;
|
||||
rules = rules->next;
|
||||
}
|
||||
rules->next = tmp;
|
||||
return i + 1;
|
||||
} else {
|
||||
auth->rules = tmp;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ssize_t qauthz_list_insert_rule(QAuthZList *auth,
|
||||
const char *match,
|
||||
QAuthZListPolicy policy,
|
||||
QAuthZListFormat format,
|
||||
size_t index,
|
||||
Error **errp)
|
||||
{
|
||||
QAuthZListRule *rule;
|
||||
QAuthZListRuleList *rules, *tmp;
|
||||
size_t i = 0;
|
||||
|
||||
rule = g_new0(QAuthZListRule, 1);
|
||||
rule->policy = policy;
|
||||
rule->match = g_strdup(match);
|
||||
rule->format = format;
|
||||
rule->has_format = true;
|
||||
|
||||
tmp = g_new0(QAuthZListRuleList, 1);
|
||||
tmp->value = rule;
|
||||
|
||||
rules = auth->rules;
|
||||
if (rules && index > 0) {
|
||||
while (rules->next && i < (index - 1)) {
|
||||
i++;
|
||||
rules = rules->next;
|
||||
}
|
||||
tmp->next = rules->next;
|
||||
rules->next = tmp;
|
||||
return i + 1;
|
||||
} else {
|
||||
tmp->next = auth->rules;
|
||||
auth->rules = tmp;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ssize_t qauthz_list_delete_rule(QAuthZList *auth, const char *match)
|
||||
{
|
||||
QAuthZListRule *rule;
|
||||
QAuthZListRuleList *rules, *prev;
|
||||
size_t i = 0;
|
||||
|
||||
prev = NULL;
|
||||
rules = auth->rules;
|
||||
while (rules) {
|
||||
rule = rules->value;
|
||||
if (g_str_equal(rule->match, match)) {
|
||||
if (prev) {
|
||||
prev->next = rules->next;
|
||||
} else {
|
||||
auth->rules = rules->next;
|
||||
}
|
||||
rules->next = NULL;
|
||||
qapi_free_QAuthZListRuleList(rules);
|
||||
return i;
|
||||
}
|
||||
prev = rules;
|
||||
rules = rules->next;
|
||||
i++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static const TypeInfo qauthz_list_info = {
|
||||
.parent = TYPE_QAUTHZ,
|
||||
.name = TYPE_QAUTHZ_LIST,
|
||||
.instance_size = sizeof(QAuthZList),
|
||||
.instance_finalize = qauthz_list_finalize,
|
||||
.class_size = sizeof(QAuthZListClass),
|
||||
.class_init = qauthz_list_class_init,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ TYPE_USER_CREATABLE },
|
||||
{ }
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
qauthz_list_register_types(void)
|
||||
{
|
||||
type_register_static(&qauthz_list_info);
|
||||
}
|
||||
|
||||
|
||||
type_init(qauthz_list_register_types);
|
||||
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* QEMU access control list file authorization driver
|
||||
*
|
||||
* Copyright (c) 2018 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "authz/listfile.h"
|
||||
#include "authz/trace.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "qemu/sockets.h"
|
||||
#include "qemu/filemonitor.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
#include "qapi/qapi-visit-authz.h"
|
||||
#include "qapi/qmp/qjson.h"
|
||||
#include "qapi/qmp/qobject.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qapi/qobject-input-visitor.h"
|
||||
|
||||
|
||||
static bool
|
||||
qauthz_list_file_is_allowed(QAuthZ *authz,
|
||||
const char *identity,
|
||||
Error **errp)
|
||||
{
|
||||
QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(authz);
|
||||
if (fauthz->list) {
|
||||
return qauthz_is_allowed(fauthz->list, identity, errp);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static QAuthZ *
|
||||
qauthz_list_file_load(QAuthZListFile *fauthz, Error **errp)
|
||||
{
|
||||
GError *err = NULL;
|
||||
gchar *content = NULL;
|
||||
gsize len;
|
||||
QObject *obj = NULL;
|
||||
QDict *pdict;
|
||||
Visitor *v = NULL;
|
||||
QAuthZ *ret = NULL;
|
||||
|
||||
trace_qauthz_list_file_load(fauthz, fauthz->filename);
|
||||
if (!g_file_get_contents(fauthz->filename, &content, &len, &err)) {
|
||||
error_setg(errp, "Unable to read '%s': %s",
|
||||
fauthz->filename, err->message);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
obj = qobject_from_json(content, errp);
|
||||
if (!obj) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
pdict = qobject_to(QDict, obj);
|
||||
if (!pdict) {
|
||||
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "obj", "dict");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
v = qobject_input_visitor_new(obj);
|
||||
|
||||
ret = (QAuthZ *)user_creatable_add_type(TYPE_QAUTHZ_LIST,
|
||||
NULL, pdict, v, errp);
|
||||
|
||||
cleanup:
|
||||
visit_free(v);
|
||||
qobject_unref(obj);
|
||||
if (err) {
|
||||
g_error_free(err);
|
||||
}
|
||||
g_free(content);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qauthz_list_file_event(int wd G_GNUC_UNUSED,
|
||||
QFileMonitorEvent ev G_GNUC_UNUSED,
|
||||
const char *name G_GNUC_UNUSED,
|
||||
void *opaque)
|
||||
{
|
||||
QAuthZListFile *fauthz = opaque;
|
||||
Error *err = NULL;
|
||||
|
||||
if (ev != QFILE_MONITOR_EVENT_MODIFIED &&
|
||||
ev != QFILE_MONITOR_EVENT_CREATED) {
|
||||
return;
|
||||
}
|
||||
|
||||
object_unref(OBJECT(fauthz->list));
|
||||
fauthz->list = qauthz_list_file_load(fauthz, &err);
|
||||
trace_qauthz_list_file_refresh(fauthz,
|
||||
fauthz->filename, fauthz->list ? 1 : 0);
|
||||
if (!fauthz->list) {
|
||||
error_report_err(err);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
qauthz_list_file_complete(UserCreatable *uc, Error **errp)
|
||||
{
|
||||
QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(uc);
|
||||
gchar *dir = NULL, *file = NULL;
|
||||
|
||||
fauthz->list = qauthz_list_file_load(fauthz, errp);
|
||||
|
||||
if (!fauthz->refresh) {
|
||||
return;
|
||||
}
|
||||
|
||||
fauthz->file_monitor = qemu_file_monitor_new(errp);
|
||||
if (!fauthz->file_monitor) {
|
||||
return;
|
||||
}
|
||||
|
||||
dir = g_path_get_dirname(fauthz->filename);
|
||||
if (g_str_equal(dir, ".")) {
|
||||
error_setg(errp, "Filename must be an absolute path");
|
||||
goto cleanup;
|
||||
}
|
||||
file = g_path_get_basename(fauthz->filename);
|
||||
if (g_str_equal(file, ".")) {
|
||||
error_setg(errp, "Path has no trailing filename component");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
fauthz->file_watch = qemu_file_monitor_add_watch(
|
||||
fauthz->file_monitor, dir, file,
|
||||
qauthz_list_file_event, fauthz, errp);
|
||||
if (fauthz->file_watch < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
g_free(file);
|
||||
g_free(dir);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qauthz_list_file_prop_set_filename(Object *obj,
|
||||
const char *value,
|
||||
Error **errp G_GNUC_UNUSED)
|
||||
{
|
||||
QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj);
|
||||
|
||||
g_free(fauthz->filename);
|
||||
fauthz->filename = g_strdup(value);
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
qauthz_list_file_prop_get_filename(Object *obj,
|
||||
Error **errp G_GNUC_UNUSED)
|
||||
{
|
||||
QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj);
|
||||
|
||||
return g_strdup(fauthz->filename);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qauthz_list_file_prop_set_refresh(Object *obj,
|
||||
bool value,
|
||||
Error **errp G_GNUC_UNUSED)
|
||||
{
|
||||
QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj);
|
||||
|
||||
fauthz->refresh = value;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
qauthz_list_file_prop_get_refresh(Object *obj,
|
||||
Error **errp G_GNUC_UNUSED)
|
||||
{
|
||||
QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj);
|
||||
|
||||
return fauthz->refresh;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qauthz_list_file_finalize(Object *obj)
|
||||
{
|
||||
QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj);
|
||||
|
||||
object_unref(OBJECT(fauthz->list));
|
||||
g_free(fauthz->filename);
|
||||
qemu_file_monitor_free(fauthz->file_monitor);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qauthz_list_file_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
|
||||
QAuthZClass *authz = QAUTHZ_CLASS(oc);
|
||||
|
||||
ucc->complete = qauthz_list_file_complete;
|
||||
|
||||
object_class_property_add_str(oc, "filename",
|
||||
qauthz_list_file_prop_get_filename,
|
||||
qauthz_list_file_prop_set_filename,
|
||||
NULL);
|
||||
object_class_property_add_bool(oc, "refresh",
|
||||
qauthz_list_file_prop_get_refresh,
|
||||
qauthz_list_file_prop_set_refresh,
|
||||
NULL);
|
||||
|
||||
authz->is_allowed = qauthz_list_file_is_allowed;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qauthz_list_file_init(Object *obj)
|
||||
{
|
||||
QAuthZListFile *authz = QAUTHZ_LIST_FILE(obj);
|
||||
|
||||
authz->file_watch = -1;
|
||||
#ifdef CONFIG_INOTIFY1
|
||||
authz->refresh = TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
QAuthZListFile *qauthz_list_file_new(const char *id,
|
||||
const char *filename,
|
||||
bool refresh,
|
||||
Error **errp)
|
||||
{
|
||||
return QAUTHZ_LIST_FILE(
|
||||
object_new_with_props(TYPE_QAUTHZ_LIST_FILE,
|
||||
object_get_objects_root(),
|
||||
id, errp,
|
||||
"filename", filename,
|
||||
"refresh", refresh ? "yes" : "no",
|
||||
NULL));
|
||||
}
|
||||
|
||||
|
||||
static const TypeInfo qauthz_list_file_info = {
|
||||
.parent = TYPE_QAUTHZ,
|
||||
.name = TYPE_QAUTHZ_LIST_FILE,
|
||||
.instance_init = qauthz_list_file_init,
|
||||
.instance_size = sizeof(QAuthZListFile),
|
||||
.instance_finalize = qauthz_list_file_finalize,
|
||||
.class_size = sizeof(QAuthZListFileClass),
|
||||
.class_init = qauthz_list_file_class_init,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ TYPE_USER_CREATABLE },
|
||||
{ }
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
qauthz_list_file_register_types(void)
|
||||
{
|
||||
type_register_static(&qauthz_list_file_info);
|
||||
}
|
||||
|
||||
|
||||
type_init(qauthz_list_file_register_types);
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* QEMU PAM authorization driver
|
||||
*
|
||||
* Copyright (c) 2018 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "authz/pamacct.h"
|
||||
#include "authz/trace.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
|
||||
#include <security/pam_appl.h>
|
||||
|
||||
|
||||
static bool qauthz_pam_is_allowed(QAuthZ *authz,
|
||||
const char *identity,
|
||||
Error **errp)
|
||||
{
|
||||
QAuthZPAM *pauthz = QAUTHZ_PAM(authz);
|
||||
const struct pam_conv pam_conversation = { 0 };
|
||||
pam_handle_t *pamh = NULL;
|
||||
int ret;
|
||||
|
||||
trace_qauthz_pam_check(authz, identity, pauthz->service);
|
||||
ret = pam_start(pauthz->service,
|
||||
identity,
|
||||
&pam_conversation,
|
||||
&pamh);
|
||||
if (ret != PAM_SUCCESS) {
|
||||
error_setg(errp, "Unable to start PAM transaction: %s",
|
||||
pam_strerror(NULL, ret));
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = pam_acct_mgmt(pamh, PAM_SILENT);
|
||||
pam_end(pamh, ret);
|
||||
if (ret != PAM_SUCCESS) {
|
||||
error_setg(errp, "Unable to authorize user '%s': %s",
|
||||
identity, pam_strerror(pamh, ret));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qauthz_pam_prop_set_service(Object *obj,
|
||||
const char *service,
|
||||
Error **errp G_GNUC_UNUSED)
|
||||
{
|
||||
QAuthZPAM *pauthz = QAUTHZ_PAM(obj);
|
||||
|
||||
g_free(pauthz->service);
|
||||
pauthz->service = g_strdup(service);
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
qauthz_pam_prop_get_service(Object *obj,
|
||||
Error **errp G_GNUC_UNUSED)
|
||||
{
|
||||
QAuthZPAM *pauthz = QAUTHZ_PAM(obj);
|
||||
|
||||
return g_strdup(pauthz->service);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qauthz_pam_complete(UserCreatable *uc, Error **errp)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qauthz_pam_finalize(Object *obj)
|
||||
{
|
||||
QAuthZPAM *pauthz = QAUTHZ_PAM(obj);
|
||||
|
||||
g_free(pauthz->service);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qauthz_pam_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
|
||||
QAuthZClass *authz = QAUTHZ_CLASS(oc);
|
||||
|
||||
ucc->complete = qauthz_pam_complete;
|
||||
authz->is_allowed = qauthz_pam_is_allowed;
|
||||
|
||||
object_class_property_add_str(oc, "service",
|
||||
qauthz_pam_prop_get_service,
|
||||
qauthz_pam_prop_set_service,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
QAuthZPAM *qauthz_pam_new(const char *id,
|
||||
const char *service,
|
||||
Error **errp)
|
||||
{
|
||||
return QAUTHZ_PAM(
|
||||
object_new_with_props(TYPE_QAUTHZ_PAM,
|
||||
object_get_objects_root(),
|
||||
id, errp,
|
||||
"service", service,
|
||||
NULL));
|
||||
}
|
||||
|
||||
|
||||
static const TypeInfo qauthz_pam_info = {
|
||||
.parent = TYPE_QAUTHZ,
|
||||
.name = TYPE_QAUTHZ_PAM,
|
||||
.instance_size = sizeof(QAuthZPAM),
|
||||
.instance_finalize = qauthz_pam_finalize,
|
||||
.class_size = sizeof(QAuthZPAMClass),
|
||||
.class_init = qauthz_pam_class_init,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ TYPE_USER_CREATABLE },
|
||||
{ }
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
qauthz_pam_register_types(void)
|
||||
{
|
||||
type_register_static(&qauthz_pam_info);
|
||||
}
|
||||
|
||||
|
||||
type_init(qauthz_pam_register_types);
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* QEMU simple authorization driver
|
||||
*
|
||||
* Copyright (c) 2018 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "authz/simple.h"
|
||||
#include "authz/trace.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
|
||||
static bool qauthz_simple_is_allowed(QAuthZ *authz,
|
||||
const char *identity,
|
||||
Error **errp)
|
||||
{
|
||||
QAuthZSimple *sauthz = QAUTHZ_SIMPLE(authz);
|
||||
|
||||
trace_qauthz_simple_is_allowed(authz, sauthz->identity, identity);
|
||||
return g_str_equal(identity, sauthz->identity);
|
||||
}
|
||||
|
||||
static void
|
||||
qauthz_simple_prop_set_identity(Object *obj,
|
||||
const char *value,
|
||||
Error **errp G_GNUC_UNUSED)
|
||||
{
|
||||
QAuthZSimple *sauthz = QAUTHZ_SIMPLE(obj);
|
||||
|
||||
g_free(sauthz->identity);
|
||||
sauthz->identity = g_strdup(value);
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
qauthz_simple_prop_get_identity(Object *obj,
|
||||
Error **errp G_GNUC_UNUSED)
|
||||
{
|
||||
QAuthZSimple *sauthz = QAUTHZ_SIMPLE(obj);
|
||||
|
||||
return g_strdup(sauthz->identity);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qauthz_simple_finalize(Object *obj)
|
||||
{
|
||||
QAuthZSimple *sauthz = QAUTHZ_SIMPLE(obj);
|
||||
|
||||
g_free(sauthz->identity);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qauthz_simple_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
QAuthZClass *authz = QAUTHZ_CLASS(oc);
|
||||
|
||||
authz->is_allowed = qauthz_simple_is_allowed;
|
||||
|
||||
object_class_property_add_str(oc, "identity",
|
||||
qauthz_simple_prop_get_identity,
|
||||
qauthz_simple_prop_set_identity,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
QAuthZSimple *qauthz_simple_new(const char *id,
|
||||
const char *identity,
|
||||
Error **errp)
|
||||
{
|
||||
return QAUTHZ_SIMPLE(
|
||||
object_new_with_props(TYPE_QAUTHZ_SIMPLE,
|
||||
object_get_objects_root(),
|
||||
id, errp,
|
||||
"identity", identity,
|
||||
NULL));
|
||||
}
|
||||
|
||||
|
||||
static const TypeInfo qauthz_simple_info = {
|
||||
.parent = TYPE_QAUTHZ,
|
||||
.name = TYPE_QAUTHZ_SIMPLE,
|
||||
.instance_size = sizeof(QAuthZSimple),
|
||||
.instance_finalize = qauthz_simple_finalize,
|
||||
.class_size = sizeof(QAuthZSimpleClass),
|
||||
.class_init = qauthz_simple_class_init,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ TYPE_USER_CREATABLE },
|
||||
{ }
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
qauthz_simple_register_types(void)
|
||||
{
|
||||
type_register_static(&qauthz_simple_info);
|
||||
}
|
||||
|
||||
|
||||
type_init(qauthz_simple_register_types);
|
||||
@@ -0,0 +1,18 @@
|
||||
# See docs/devel/tracing.txt for syntax documentation.
|
||||
|
||||
# authz/base.c
|
||||
qauthz_is_allowed(void *authz, const char *identity, bool allowed) "AuthZ %p check identity=%s allowed=%d"
|
||||
|
||||
# auth/simple.c
|
||||
qauthz_simple_is_allowed(void *authz, const char *wantidentity, const char *gotidentity) "AuthZ simple %p check want identity=%s got identity=%s"
|
||||
|
||||
# auth/list.c
|
||||
qauthz_list_check_rule(void *authz, const char *identity, const char *rule, int format, int policy) "AuthZ list %p check rule=%s identity=%s format=%d policy=%d"
|
||||
qauthz_list_default_policy(void *authz, const char *identity, int policy) "AuthZ list %p default identity=%s policy=%d"
|
||||
|
||||
# auth/listfile.c
|
||||
qauthz_list_file_load(void *authz, const char *filename) "AuthZ file %p load filename=%s"
|
||||
qauthz_list_file_refresh(void *authz, const char *filename, int success) "AuthZ file %p load filename=%s success=%d"
|
||||
|
||||
# auth/pam.c
|
||||
qauthz_pam_check(void *authz, const char *identity, const char *service) "AuthZ PAM %p identity=%s service=%s"
|
||||
@@ -463,6 +463,7 @@ gnutls=""
|
||||
nettle=""
|
||||
gcrypt=""
|
||||
gcrypt_hmac="no"
|
||||
auth_pam=""
|
||||
vte=""
|
||||
virglrenderer=""
|
||||
tpm="yes"
|
||||
@@ -1381,6 +1382,10 @@ for opt do
|
||||
;;
|
||||
--enable-gcrypt) gcrypt="yes"
|
||||
;;
|
||||
--disable-auth-pam) auth_pam="no"
|
||||
;;
|
||||
--enable-auth-pam) auth_pam="yes"
|
||||
;;
|
||||
--enable-rdma) rdma="yes"
|
||||
;;
|
||||
--disable-rdma) rdma="no"
|
||||
@@ -1707,6 +1712,7 @@ disabled with --disable-FEATURE, default is enabled if available:
|
||||
gnutls GNUTLS cryptography support
|
||||
nettle nettle cryptography support
|
||||
gcrypt libgcrypt cryptography support
|
||||
auth-pam PAM access control
|
||||
sdl SDL UI
|
||||
sdl_image SDL Image support for icons
|
||||
gtk gtk UI
|
||||
@@ -2864,6 +2870,33 @@ else
|
||||
fi
|
||||
|
||||
|
||||
##########################################
|
||||
# PAM probe
|
||||
|
||||
if test "$auth_pam" != "no"; then
|
||||
cat > $TMPC <<EOF
|
||||
#include <security/pam_appl.h>
|
||||
#include <stdio.h>
|
||||
int main(void) {
|
||||
const char *service_name = "qemu";
|
||||
const char *user = "frank";
|
||||
const struct pam_conv *pam_conv = NULL;
|
||||
pam_handle_t *pamh = NULL;
|
||||
pam_start(service_name, user, pam_conv, &pamh);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if compile_prog "" "-lpam" ; then
|
||||
auth_pam=yes
|
||||
else
|
||||
if test "$auth_pam" = "yes"; then
|
||||
feature_not_found "PAM" "Install PAM development package"
|
||||
else
|
||||
auth_pam=no
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# getifaddrs (for tests/test-io-channel-socket )
|
||||
|
||||
@@ -3172,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
|
||||
@@ -6091,6 +6110,7 @@ echo "GNUTLS support $gnutls"
|
||||
echo "libgcrypt $gcrypt"
|
||||
echo "nettle $nettle $(echo_version $nettle $nettle_version)"
|
||||
echo "libtasn1 $tasn1"
|
||||
echo "PAM $auth_pam"
|
||||
echo "curses support $curses"
|
||||
echo "virgl support $virglrenderer $(echo_version $virglrenderer $virgl_version)"
|
||||
echo "curl support $curl"
|
||||
@@ -6382,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
|
||||
@@ -6550,6 +6567,9 @@ fi
|
||||
if test "$tasn1" = "yes" ; then
|
||||
echo "CONFIG_TASN1=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$auth_pam" = "yes" ; then
|
||||
echo "CONFIG_AUTH_PAM=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$have_ifaddrs_h" = "yes" ; then
|
||||
echo "HAVE_IFADDRS_H=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
+17
-18
@@ -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)
|
||||
{
|
||||
|
||||
+1
-1
@@ -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"
|
||||
|
||||
+124
-179
@@ -11,17 +11,16 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include <wchar.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include <sys/statvfs.h>
|
||||
#ifdef CONFIG_INOTIFY1
|
||||
#include <sys/inotify.h>
|
||||
#include "qemu/main-loop.h"
|
||||
#endif
|
||||
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/iov.h"
|
||||
#include "qemu/filemonitor.h"
|
||||
#include "trace.h"
|
||||
#include "hw/usb.h"
|
||||
#include "desc.h"
|
||||
@@ -132,7 +131,6 @@ enum {
|
||||
EP_EVENT,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_INOTIFY1
|
||||
typedef struct MTPMonEntry MTPMonEntry;
|
||||
|
||||
struct MTPMonEntry {
|
||||
@@ -141,7 +139,6 @@ struct MTPMonEntry {
|
||||
|
||||
QTAILQ_ENTRY(MTPMonEntry) next;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct MTPControl {
|
||||
uint16_t code;
|
||||
@@ -172,10 +169,8 @@ struct MTPObject {
|
||||
char *name;
|
||||
char *path;
|
||||
struct stat stat;
|
||||
#ifdef CONFIG_INOTIFY1
|
||||
/* inotify watch cookie */
|
||||
int watchfd;
|
||||
#endif
|
||||
/* file monitor watch id */
|
||||
int watchid;
|
||||
MTPObject *parent;
|
||||
uint32_t nchildren;
|
||||
QLIST_HEAD(, MTPObject) children;
|
||||
@@ -198,11 +193,8 @@ struct MTPState {
|
||||
bool readonly;
|
||||
|
||||
QTAILQ_HEAD(, MTPObject) objects;
|
||||
#ifdef CONFIG_INOTIFY1
|
||||
/* inotify descriptor */
|
||||
int inotifyfd;
|
||||
QFileMonitor *file_monitor;
|
||||
QTAILQ_HEAD(, MTPMonEntry) events;
|
||||
#endif
|
||||
/* Responder is expecting a write operation */
|
||||
bool write_pending;
|
||||
struct {
|
||||
@@ -383,7 +375,7 @@ static const USBDesc desc = {
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static MTPObject *usb_mtp_object_alloc(MTPState *s, uint32_t handle,
|
||||
MTPObject *parent, char *name)
|
||||
MTPObject *parent, const char *name)
|
||||
{
|
||||
MTPObject *o = g_new0(MTPObject, 1);
|
||||
|
||||
@@ -391,6 +383,7 @@ static MTPObject *usb_mtp_object_alloc(MTPState *s, uint32_t handle,
|
||||
goto ignore;
|
||||
}
|
||||
|
||||
o->watchid = -1;
|
||||
o->handle = handle;
|
||||
o->parent = parent;
|
||||
o->name = g_strdup(name);
|
||||
@@ -437,6 +430,10 @@ static void usb_mtp_object_free(MTPState *s, MTPObject *o)
|
||||
|
||||
trace_usb_mtp_object_free(s->dev.addr, o->handle, o->path);
|
||||
|
||||
if (o->watchid != -1 && s->file_monitor) {
|
||||
qemu_file_monitor_remove_watch(s->file_monitor, o->path, o->watchid);
|
||||
}
|
||||
|
||||
QTAILQ_REMOVE(&s->objects, o, next);
|
||||
if (o->parent) {
|
||||
QLIST_REMOVE(o, list);
|
||||
@@ -465,7 +462,7 @@ static MTPObject *usb_mtp_object_lookup(MTPState *s, uint32_t handle)
|
||||
}
|
||||
|
||||
static MTPObject *usb_mtp_add_child(MTPState *s, MTPObject *o,
|
||||
char *name)
|
||||
const char *name)
|
||||
{
|
||||
MTPObject *child =
|
||||
usb_mtp_object_alloc(s, s->next_handle++, o, name);
|
||||
@@ -484,10 +481,14 @@ static MTPObject *usb_mtp_add_child(MTPState *s, MTPObject *o,
|
||||
}
|
||||
|
||||
static MTPObject *usb_mtp_object_lookup_name(MTPObject *parent,
|
||||
char *name, int len)
|
||||
const char *name, int len)
|
||||
{
|
||||
MTPObject *iter;
|
||||
|
||||
if (len == -1) {
|
||||
len = strlen(name);
|
||||
}
|
||||
|
||||
QLIST_FOREACH(iter, &parent->children, list) {
|
||||
if (strncmp(iter->name, name, len) == 0) {
|
||||
return iter;
|
||||
@@ -497,13 +498,12 @@ static MTPObject *usb_mtp_object_lookup_name(MTPObject *parent,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_INOTIFY1
|
||||
static MTPObject *usb_mtp_object_lookup_wd(MTPState *s, int wd)
|
||||
static MTPObject *usb_mtp_object_lookup_id(MTPState *s, int id)
|
||||
{
|
||||
MTPObject *iter;
|
||||
|
||||
QTAILQ_FOREACH(iter, &s->objects, next) {
|
||||
if (iter->watchfd == wd) {
|
||||
if (iter->watchid == id) {
|
||||
return iter;
|
||||
}
|
||||
}
|
||||
@@ -511,160 +511,103 @@ static MTPObject *usb_mtp_object_lookup_wd(MTPState *s, int wd)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void inotify_watchfn(void *arg)
|
||||
static void file_monitor_event(int id,
|
||||
QFileMonitorEvent ev,
|
||||
const char *name,
|
||||
void *opaque)
|
||||
{
|
||||
MTPState *s = arg;
|
||||
ssize_t bytes;
|
||||
/* From the man page: atleast one event can be read */
|
||||
int pos;
|
||||
char buf[sizeof(struct inotify_event) + NAME_MAX + 1];
|
||||
MTPState *s = opaque;
|
||||
MTPObject *parent = usb_mtp_object_lookup_id(s, id);
|
||||
MTPMonEntry *entry = NULL;
|
||||
MTPObject *o;
|
||||
|
||||
for (;;) {
|
||||
bytes = read(s->inotifyfd, buf, sizeof(buf));
|
||||
pos = 0;
|
||||
|
||||
if (bytes <= 0) {
|
||||
/* Better luck next time */
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: Ignore initiator initiated events.
|
||||
* For now we are good because the store is RO
|
||||
*/
|
||||
while (bytes > 0) {
|
||||
char *p = buf + pos;
|
||||
struct inotify_event *event = (struct inotify_event *)p;
|
||||
int watchfd = 0;
|
||||
uint32_t mask = event->mask & (IN_CREATE | IN_DELETE |
|
||||
IN_MODIFY | IN_IGNORED);
|
||||
MTPObject *parent = usb_mtp_object_lookup_wd(s, event->wd);
|
||||
MTPMonEntry *entry = NULL;
|
||||
MTPObject *o;
|
||||
|
||||
pos = pos + sizeof(struct inotify_event) + event->len;
|
||||
bytes = bytes - pos;
|
||||
|
||||
if (!parent) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (mask) {
|
||||
case IN_CREATE:
|
||||
if (usb_mtp_object_lookup_name
|
||||
(parent, event->name, event->len)) {
|
||||
/* Duplicate create event */
|
||||
continue;
|
||||
}
|
||||
entry = g_new0(MTPMonEntry, 1);
|
||||
entry->handle = s->next_handle;
|
||||
entry->event = EVT_OBJ_ADDED;
|
||||
o = usb_mtp_add_child(s, parent, event->name);
|
||||
if (!o) {
|
||||
g_free(entry);
|
||||
continue;
|
||||
}
|
||||
o->watchfd = watchfd;
|
||||
trace_usb_mtp_inotify_event(s->dev.addr, event->name,
|
||||
event->mask, "Obj Added");
|
||||
break;
|
||||
|
||||
case IN_DELETE:
|
||||
/*
|
||||
* The kernel issues a IN_IGNORED event
|
||||
* when a dir containing a watchpoint is
|
||||
* deleted, so we don't have to delete the
|
||||
* watchpoint
|
||||
*/
|
||||
o = usb_mtp_object_lookup_name(parent, event->name, event->len);
|
||||
if (!o) {
|
||||
continue;
|
||||
}
|
||||
entry = g_new0(MTPMonEntry, 1);
|
||||
entry->handle = o->handle;
|
||||
entry->event = EVT_OBJ_REMOVED;
|
||||
trace_usb_mtp_inotify_event(s->dev.addr, o->path,
|
||||
event->mask, "Obj Deleted");
|
||||
usb_mtp_object_free(s, o);
|
||||
break;
|
||||
|
||||
case IN_MODIFY:
|
||||
o = usb_mtp_object_lookup_name(parent, event->name, event->len);
|
||||
if (!o) {
|
||||
continue;
|
||||
}
|
||||
entry = g_new0(MTPMonEntry, 1);
|
||||
entry->handle = o->handle;
|
||||
entry->event = EVT_OBJ_INFO_CHANGED;
|
||||
trace_usb_mtp_inotify_event(s->dev.addr, o->path,
|
||||
event->mask, "Obj Modified");
|
||||
break;
|
||||
|
||||
case IN_IGNORED:
|
||||
trace_usb_mtp_inotify_event(s->dev.addr, parent->path,
|
||||
event->mask, "Obj parent dir ignored");
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "usb-mtp: failed to parse inotify event\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry) {
|
||||
QTAILQ_INSERT_HEAD(&s->events, entry, next);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int usb_mtp_inotify_init(MTPState *s)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = inotify_init1(IN_NONBLOCK);
|
||||
if (fd == -1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
QTAILQ_INIT(&s->events);
|
||||
s->inotifyfd = fd;
|
||||
|
||||
qemu_set_fd_handler(fd, inotify_watchfn, NULL, s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usb_mtp_inotify_cleanup(MTPState *s)
|
||||
{
|
||||
MTPMonEntry *e, *p;
|
||||
|
||||
if (!s->inotifyfd) {
|
||||
if (!parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_set_fd_handler(s->inotifyfd, NULL, NULL, s);
|
||||
close(s->inotifyfd);
|
||||
switch (ev) {
|
||||
case QFILE_MONITOR_EVENT_CREATED:
|
||||
if (usb_mtp_object_lookup_name(parent, name, -1)) {
|
||||
/* Duplicate create event */
|
||||
return;
|
||||
}
|
||||
entry = g_new0(MTPMonEntry, 1);
|
||||
entry->handle = s->next_handle;
|
||||
entry->event = EVT_OBJ_ADDED;
|
||||
o = usb_mtp_add_child(s, parent, name);
|
||||
if (!o) {
|
||||
g_free(entry);
|
||||
return;
|
||||
}
|
||||
trace_usb_mtp_file_monitor_event(s->dev.addr, name, "Obj Added");
|
||||
break;
|
||||
|
||||
case QFILE_MONITOR_EVENT_DELETED:
|
||||
/*
|
||||
* The kernel issues a IN_IGNORED event
|
||||
* when a dir containing a watchpoint is
|
||||
* deleted, so we don't have to delete the
|
||||
* watchpoint
|
||||
*/
|
||||
o = usb_mtp_object_lookup_name(parent, name, -1);
|
||||
if (!o) {
|
||||
return;
|
||||
}
|
||||
entry = g_new0(MTPMonEntry, 1);
|
||||
entry->handle = o->handle;
|
||||
entry->event = EVT_OBJ_REMOVED;
|
||||
trace_usb_mtp_file_monitor_event(s->dev.addr, o->path, "Obj Deleted");
|
||||
usb_mtp_object_free(s, o);
|
||||
break;
|
||||
|
||||
case QFILE_MONITOR_EVENT_MODIFIED:
|
||||
o = usb_mtp_object_lookup_name(parent, name, -1);
|
||||
if (!o) {
|
||||
return;
|
||||
}
|
||||
entry = g_new0(MTPMonEntry, 1);
|
||||
entry->handle = o->handle;
|
||||
entry->event = EVT_OBJ_INFO_CHANGED;
|
||||
trace_usb_mtp_file_monitor_event(s->dev.addr, o->path, "Obj Modified");
|
||||
break;
|
||||
|
||||
case QFILE_MONITOR_EVENT_IGNORED:
|
||||
trace_usb_mtp_file_monitor_event(s->dev.addr, parent->path,
|
||||
"Obj parent dir ignored");
|
||||
break;
|
||||
|
||||
case QFILE_MONITOR_EVENT_ATTRIBUTES:
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
if (entry) {
|
||||
QTAILQ_INSERT_HEAD(&s->events, entry, next);
|
||||
}
|
||||
}
|
||||
|
||||
static void usb_mtp_file_monitor_cleanup(MTPState *s)
|
||||
{
|
||||
MTPMonEntry *e, *p;
|
||||
|
||||
QTAILQ_FOREACH_SAFE(e, &s->events, next, p) {
|
||||
QTAILQ_REMOVE(&s->events, e, next);
|
||||
g_free(e);
|
||||
}
|
||||
|
||||
qemu_file_monitor_free(s->file_monitor);
|
||||
s->file_monitor = NULL;
|
||||
}
|
||||
|
||||
static int usb_mtp_add_watch(int inotifyfd, char *path)
|
||||
{
|
||||
uint32_t mask = IN_CREATE | IN_DELETE | IN_MODIFY |
|
||||
IN_ISDIR;
|
||||
|
||||
return inotify_add_watch(inotifyfd, path, mask);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void usb_mtp_object_readdir(MTPState *s, MTPObject *o)
|
||||
{
|
||||
struct dirent *entry;
|
||||
DIR *dir;
|
||||
int fd;
|
||||
Error *err = NULL;
|
||||
|
||||
if (o->have_children) {
|
||||
return;
|
||||
@@ -680,16 +623,21 @@ static void usb_mtp_object_readdir(MTPState *s, MTPObject *o)
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
#ifdef CONFIG_INOTIFY1
|
||||
int watchfd = usb_mtp_add_watch(s->inotifyfd, o->path);
|
||||
if (watchfd == -1) {
|
||||
fprintf(stderr, "usb-mtp: failed to add watch for %s\n", o->path);
|
||||
} else {
|
||||
trace_usb_mtp_inotify_event(s->dev.addr, o->path,
|
||||
0, "Watch Added");
|
||||
o->watchfd = watchfd;
|
||||
|
||||
if (s->file_monitor) {
|
||||
int id = qemu_file_monitor_add_watch(s->file_monitor, o->path, NULL,
|
||||
file_monitor_event, s, &err);
|
||||
if (id == -1) {
|
||||
error_report("usb-mtp: failed to add watch for %s: %s", o->path,
|
||||
error_get_pretty(err));
|
||||
error_free(err);
|
||||
} else {
|
||||
trace_usb_mtp_file_monitor_event(s->dev.addr, o->path,
|
||||
"Watch Added");
|
||||
o->watchid = id;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
usb_mtp_add_child(s, o, entry->d_name);
|
||||
}
|
||||
@@ -1197,13 +1145,11 @@ enum {
|
||||
/* Assumes that children, if any, have been already freed */
|
||||
static void usb_mtp_object_free_one(MTPState *s, MTPObject *o)
|
||||
{
|
||||
#ifndef CONFIG_INOTIFY1
|
||||
assert(o->nchildren == 0);
|
||||
QTAILQ_REMOVE(&s->objects, o, next);
|
||||
g_free(o->name);
|
||||
g_free(o->path);
|
||||
g_free(o);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int usb_mtp_deletefn(MTPState *s, MTPObject *o, uint32_t trans)
|
||||
@@ -1302,6 +1248,7 @@ static void usb_mtp_command(MTPState *s, MTPControl *c)
|
||||
MTPData *data_in = NULL;
|
||||
MTPObject *o = NULL;
|
||||
uint32_t nres = 0, res0 = 0;
|
||||
Error *err = NULL;
|
||||
|
||||
/* sanity checks */
|
||||
if (c->code >= CMD_CLOSE_SESSION && s->session == 0) {
|
||||
@@ -1329,19 +1276,21 @@ static void usb_mtp_command(MTPState *s, MTPControl *c)
|
||||
trace_usb_mtp_op_open_session(s->dev.addr);
|
||||
s->session = c->argv[0];
|
||||
usb_mtp_object_alloc(s, s->next_handle++, NULL, s->root);
|
||||
#ifdef CONFIG_INOTIFY1
|
||||
if (usb_mtp_inotify_init(s)) {
|
||||
fprintf(stderr, "usb-mtp: file monitoring init failed\n");
|
||||
|
||||
s->file_monitor = qemu_file_monitor_new(&err);
|
||||
if (err) {
|
||||
error_report("usb-mtp: file monitoring init failed: %s",
|
||||
error_get_pretty(err));
|
||||
error_free(err);
|
||||
} else {
|
||||
QTAILQ_INIT(&s->events);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case CMD_CLOSE_SESSION:
|
||||
trace_usb_mtp_op_close_session(s->dev.addr);
|
||||
s->session = 0;
|
||||
s->next_handle = 0;
|
||||
#ifdef CONFIG_INOTIFY1
|
||||
usb_mtp_inotify_cleanup(s);
|
||||
#endif
|
||||
usb_mtp_file_monitor_cleanup(s);
|
||||
usb_mtp_object_free(s, QTAILQ_FIRST(&s->objects));
|
||||
assert(QTAILQ_EMPTY(&s->objects));
|
||||
break;
|
||||
@@ -1554,9 +1503,7 @@ static void usb_mtp_handle_reset(USBDevice *dev)
|
||||
|
||||
trace_usb_mtp_reset(s->dev.addr);
|
||||
|
||||
#ifdef CONFIG_INOTIFY1
|
||||
usb_mtp_inotify_cleanup(s);
|
||||
#endif
|
||||
usb_mtp_file_monitor_cleanup(s);
|
||||
usb_mtp_object_free(s, QTAILQ_FIRST(&s->objects));
|
||||
s->session = 0;
|
||||
usb_mtp_data_free(s->data_in);
|
||||
@@ -2027,7 +1974,6 @@ static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p)
|
||||
}
|
||||
break;
|
||||
case EP_EVENT:
|
||||
#ifdef CONFIG_INOTIFY1
|
||||
if (!QTAILQ_EMPTY(&s->events)) {
|
||||
struct MTPMonEntry *e = QTAILQ_LAST(&s->events);
|
||||
uint32_t handle;
|
||||
@@ -2051,7 +1997,6 @@ static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p)
|
||||
g_free(e);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
p->status = USB_RET_NAK;
|
||||
return;
|
||||
default:
|
||||
|
||||
+1
-1
@@ -237,7 +237,7 @@ usb_mtp_op_unknown(int dev, uint32_t code) "dev %d, command code 0x%x"
|
||||
usb_mtp_object_alloc(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s"
|
||||
usb_mtp_object_free(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s"
|
||||
usb_mtp_add_child(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s"
|
||||
usb_mtp_inotify_event(int dev, const char *path, uint32_t mask, const char *s) "dev %d, path %s mask 0x%x event %s"
|
||||
usb_mtp_file_monitor_event(int dev, const char *path, const char *s) "dev %d, path %s event %s"
|
||||
|
||||
# hw/usb/host-libusb.c
|
||||
usb_host_open_started(int bus, int addr) "dev %d:%d"
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* QEMU authorization framework base class
|
||||
*
|
||||
* Copyright (c) 2018 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QAUTHZ_BASE_H__
|
||||
#define QAUTHZ_BASE_H__
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
|
||||
#define TYPE_QAUTHZ "authz"
|
||||
|
||||
#define QAUTHZ_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(QAuthZClass, (klass), \
|
||||
TYPE_QAUTHZ)
|
||||
#define QAUTHZ_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(QAuthZClass, (obj), \
|
||||
TYPE_QAUTHZ)
|
||||
#define QAUTHZ(obj) \
|
||||
INTERFACE_CHECK(QAuthZ, (obj), \
|
||||
TYPE_QAUTHZ)
|
||||
|
||||
typedef struct QAuthZ QAuthZ;
|
||||
typedef struct QAuthZClass QAuthZClass;
|
||||
|
||||
/**
|
||||
* QAuthZ:
|
||||
*
|
||||
* The QAuthZ class defines an API contract to be used
|
||||
* for providing an authorization driver for services
|
||||
* with user identities.
|
||||
*/
|
||||
|
||||
struct QAuthZ {
|
||||
Object parent_obj;
|
||||
};
|
||||
|
||||
|
||||
struct QAuthZClass {
|
||||
ObjectClass parent_class;
|
||||
|
||||
bool (*is_allowed)(QAuthZ *authz,
|
||||
const char *identity,
|
||||
Error **errp);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* qauthz_is_allowed:
|
||||
* @authz: the authorization object
|
||||
* @identity: the user identity to authorize
|
||||
* @errp: pointer to a NULL initialized error object
|
||||
*
|
||||
* Check if a user @identity is authorized. If an error
|
||||
* occurs this method will return false to indicate
|
||||
* denial, as well as setting @errp to contain the details.
|
||||
* Callers are recommended to treat the denial and error
|
||||
* scenarios identically. Specifically the error info in
|
||||
* @errp should never be fed back to the user being
|
||||
* authorized, it is merely for benefit of administrator
|
||||
* debugging.
|
||||
*
|
||||
* Returns: true if @identity is authorized, false if denied or if
|
||||
* an error occurred.
|
||||
*/
|
||||
bool qauthz_is_allowed(QAuthZ *authz,
|
||||
const char *identity,
|
||||
Error **errp);
|
||||
|
||||
|
||||
/**
|
||||
* qauthz_is_allowed_by_id:
|
||||
* @authzid: ID of the authorization object
|
||||
* @identity: the user identity to authorize
|
||||
* @errp: pointer to a NULL initialized error object
|
||||
*
|
||||
* Check if a user @identity is authorized. If an error
|
||||
* occurs this method will return false to indicate
|
||||
* denial, as well as setting @errp to contain the details.
|
||||
* Callers are recommended to treat the denial and error
|
||||
* scenarios identically. Specifically the error info in
|
||||
* @errp should never be fed back to the user being
|
||||
* authorized, it is merely for benefit of administrator
|
||||
* debugging.
|
||||
*
|
||||
* Returns: true if @identity is authorized, false if denied or if
|
||||
* an error occurred.
|
||||
*/
|
||||
bool qauthz_is_allowed_by_id(const char *authzid,
|
||||
const char *identity,
|
||||
Error **errp);
|
||||
|
||||
#endif /* QAUTHZ_BASE_H__ */
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* QEMU list authorization driver
|
||||
*
|
||||
* Copyright (c) 2018 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QAUTHZ_LIST_H__
|
||||
#define QAUTHZ_LIST_H__
|
||||
|
||||
#include "authz/base.h"
|
||||
#include "qapi/qapi-types-authz.h"
|
||||
|
||||
#define TYPE_QAUTHZ_LIST "authz-list"
|
||||
|
||||
#define QAUTHZ_LIST_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(QAuthZListClass, (klass), \
|
||||
TYPE_QAUTHZ_LIST)
|
||||
#define QAUTHZ_LIST_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(QAuthZListClass, (obj), \
|
||||
TYPE_QAUTHZ_LIST)
|
||||
#define QAUTHZ_LIST(obj) \
|
||||
INTERFACE_CHECK(QAuthZList, (obj), \
|
||||
TYPE_QAUTHZ_LIST)
|
||||
|
||||
typedef struct QAuthZList QAuthZList;
|
||||
typedef struct QAuthZListClass QAuthZListClass;
|
||||
|
||||
|
||||
/**
|
||||
* QAuthZList:
|
||||
*
|
||||
* This authorization driver provides a list mechanism
|
||||
* for granting access by matching user names against a
|
||||
* list of globs. Each match rule has an associated policy
|
||||
* and a catch all policy applies if no rule matches
|
||||
*
|
||||
* To create an instance of this class via QMP:
|
||||
*
|
||||
* {
|
||||
* "execute": "object-add",
|
||||
* "arguments": {
|
||||
* "qom-type": "authz-list",
|
||||
* "id": "authz0",
|
||||
* "props": {
|
||||
* "rules": [
|
||||
* { "match": "fred", "policy": "allow", "format": "exact" },
|
||||
* { "match": "bob", "policy": "allow", "format": "exact" },
|
||||
* { "match": "danb", "policy": "deny", "format": "exact" },
|
||||
* { "match": "dan*", "policy": "allow", "format": "glob" }
|
||||
* ],
|
||||
* "policy": "deny"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*
|
||||
*/
|
||||
struct QAuthZList {
|
||||
QAuthZ parent_obj;
|
||||
|
||||
QAuthZListPolicy policy;
|
||||
QAuthZListRuleList *rules;
|
||||
};
|
||||
|
||||
|
||||
struct QAuthZListClass {
|
||||
QAuthZClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
QAuthZList *qauthz_list_new(const char *id,
|
||||
QAuthZListPolicy policy,
|
||||
Error **errp);
|
||||
|
||||
ssize_t qauthz_list_append_rule(QAuthZList *auth,
|
||||
const char *match,
|
||||
QAuthZListPolicy policy,
|
||||
QAuthZListFormat format,
|
||||
Error **errp);
|
||||
|
||||
ssize_t qauthz_list_insert_rule(QAuthZList *auth,
|
||||
const char *match,
|
||||
QAuthZListPolicy policy,
|
||||
QAuthZListFormat format,
|
||||
size_t index,
|
||||
Error **errp);
|
||||
|
||||
ssize_t qauthz_list_delete_rule(QAuthZList *auth,
|
||||
const char *match);
|
||||
|
||||
|
||||
#endif /* QAUTHZ_LIST_H__ */
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* QEMU list file authorization driver
|
||||
*
|
||||
* Copyright (c) 2018 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QAUTHZ_LIST_FILE_H__
|
||||
#define QAUTHZ_LIST_FILE_H__
|
||||
|
||||
#include "authz/list.h"
|
||||
#include "qapi/qapi-types-authz.h"
|
||||
#include "qemu/filemonitor.h"
|
||||
|
||||
#define TYPE_QAUTHZ_LIST_FILE "authz-list-file"
|
||||
|
||||
#define QAUTHZ_LIST_FILE_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(QAuthZListFileClass, (klass), \
|
||||
TYPE_QAUTHZ_LIST_FILE)
|
||||
#define QAUTHZ_LIST_FILE_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(QAuthZListFileClass, (obj), \
|
||||
TYPE_QAUTHZ_LIST_FILE)
|
||||
#define QAUTHZ_LIST_FILE(obj) \
|
||||
INTERFACE_CHECK(QAuthZListFile, (obj), \
|
||||
TYPE_QAUTHZ_LIST_FILE)
|
||||
|
||||
typedef struct QAuthZListFile QAuthZListFile;
|
||||
typedef struct QAuthZListFileClass QAuthZListFileClass;
|
||||
|
||||
|
||||
/**
|
||||
* QAuthZListFile:
|
||||
*
|
||||
* This authorization driver provides a file mechanism
|
||||
* for granting access by matching user names against a
|
||||
* file of globs. Each match rule has an associated policy
|
||||
* and a catch all policy applies if no rule matches
|
||||
*
|
||||
* To create an instance of this class via QMP:
|
||||
*
|
||||
* {
|
||||
* "execute": "object-add",
|
||||
* "arguments": {
|
||||
* "qom-type": "authz-list-file",
|
||||
* "id": "authz0",
|
||||
* "props": {
|
||||
* "filename": "/etc/qemu/myvm-vnc.acl",
|
||||
* "refresh": true
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* If 'refresh' is 'yes', inotify is used to monitor for changes
|
||||
* to the file and auto-reload the rules.
|
||||
*
|
||||
* The myvm-vnc.acl file should contain the parameters for
|
||||
* the QAuthZList object in JSON format:
|
||||
*
|
||||
* {
|
||||
* "rules": [
|
||||
* { "match": "fred", "policy": "allow", "format": "exact" },
|
||||
* { "match": "bob", "policy": "allow", "format": "exact" },
|
||||
* { "match": "danb", "policy": "deny", "format": "exact" },
|
||||
* { "match": "dan*", "policy": "allow", "format": "glob" }
|
||||
* ],
|
||||
* "policy": "deny"
|
||||
* }
|
||||
*
|
||||
* The object can be created on the command line using
|
||||
*
|
||||
* -object authz-list-file,id=authz0,\
|
||||
* filename=/etc/qemu/myvm-vnc.acl,refresh=yes
|
||||
*
|
||||
*/
|
||||
struct QAuthZListFile {
|
||||
QAuthZ parent_obj;
|
||||
|
||||
QAuthZ *list;
|
||||
char *filename;
|
||||
bool refresh;
|
||||
QFileMonitor *file_monitor;
|
||||
int file_watch;
|
||||
};
|
||||
|
||||
|
||||
struct QAuthZListFileClass {
|
||||
QAuthZClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
QAuthZListFile *qauthz_list_file_new(const char *id,
|
||||
const char *filename,
|
||||
bool refresh,
|
||||
Error **errp);
|
||||
|
||||
|
||||
#endif /* QAUTHZ_LIST_FILE_H__ */
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* QEMU PAM authorization driver
|
||||
*
|
||||
* Copyright (c) 2018 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QAUTHZ_PAM_H__
|
||||
#define QAUTHZ_PAM_H__
|
||||
|
||||
#include "authz/base.h"
|
||||
|
||||
|
||||
#define TYPE_QAUTHZ_PAM "authz-pam"
|
||||
|
||||
#define QAUTHZ_PAM_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(QAuthZPAMClass, (klass), \
|
||||
TYPE_QAUTHZ_PAM)
|
||||
#define QAUTHZ_PAM_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(QAuthZPAMClass, (obj), \
|
||||
TYPE_QAUTHZ_PAM)
|
||||
#define QAUTHZ_PAM(obj) \
|
||||
INTERFACE_CHECK(QAuthZPAM, (obj), \
|
||||
TYPE_QAUTHZ_PAM)
|
||||
|
||||
typedef struct QAuthZPAM QAuthZPAM;
|
||||
typedef struct QAuthZPAMClass QAuthZPAMClass;
|
||||
|
||||
|
||||
/**
|
||||
* QAuthZPAM:
|
||||
*
|
||||
* This authorization driver provides a PAM mechanism
|
||||
* for granting access by matching user names against a
|
||||
* list of globs. Each match rule has an associated policy
|
||||
* and a catch all policy applies if no rule matches
|
||||
*
|
||||
* To create an instance of this class via QMP:
|
||||
*
|
||||
* {
|
||||
* "execute": "object-add",
|
||||
* "arguments": {
|
||||
* "qom-type": "authz-pam",
|
||||
* "id": "authz0",
|
||||
* "parameters": {
|
||||
* "service": "qemu-vnc-tls"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* The driver only uses the PAM "account" verification
|
||||
* subsystem. The above config would require a config
|
||||
* file /etc/pam.d/qemu-vnc-tls. For a simple file
|
||||
* lookup it would contain
|
||||
*
|
||||
* account requisite pam_listfile.so item=user sense=allow \
|
||||
* file=/etc/qemu/vnc.allow
|
||||
*
|
||||
* The external file would then contain a list of usernames.
|
||||
* If x509 cert was being used as the username, a suitable
|
||||
* entry would match the distinguish name:
|
||||
*
|
||||
* CN=laptop.berrange.com,O=Berrange Home,L=London,ST=London,C=GB
|
||||
*
|
||||
* On the command line it can be created using
|
||||
*
|
||||
* -object authz-pam,id=authz0,service=qemu-vnc-tls
|
||||
*
|
||||
*/
|
||||
struct QAuthZPAM {
|
||||
QAuthZ parent_obj;
|
||||
|
||||
char *service;
|
||||
};
|
||||
|
||||
|
||||
struct QAuthZPAMClass {
|
||||
QAuthZClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
QAuthZPAM *qauthz_pam_new(const char *id,
|
||||
const char *service,
|
||||
Error **errp);
|
||||
|
||||
|
||||
#endif /* QAUTHZ_PAM_H__ */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user