diff options
Diffstat (limited to 'authz')
-rw-r--r-- | authz/Makefile.objs | 1 | ||||
-rw-r--r-- | authz/listfile.c | 283 | ||||
-rw-r--r-- | authz/trace-events | 4 |
3 files changed, 288 insertions, 0 deletions
diff --git a/authz/Makefile.objs b/authz/Makefile.objs index 921fa624d7..8351bf181d 100644 --- a/authz/Makefile.objs +++ b/authz/Makefile.objs @@ -1,3 +1,4 @@ authz-obj-y += base.o authz-obj-y += simple.o authz-obj-y += list.o +authz-obj-y += listfile.o diff --git a/authz/listfile.c b/authz/listfile.c new file mode 100644 index 0000000000..d4579767e7 --- /dev/null +++ b/authz/listfile.c @@ -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); diff --git a/authz/trace-events b/authz/trace-events index a896d876e8..fb65349a90 100644 --- a/authz/trace-events +++ b/authz/trace-events @@ -9,3 +9,7 @@ qauthz_simple_is_allowed(void *authz, const char *wantidentity, const char *goti # 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" |