155d86984SDaniel P. Berrangé /* 255d86984SDaniel P. Berrangé * QEMU access control list file authorization driver 355d86984SDaniel P. Berrangé * 455d86984SDaniel P. Berrangé * Copyright (c) 2018 Red Hat, Inc. 555d86984SDaniel P. Berrangé * 655d86984SDaniel P. Berrangé * This library is free software; you can redistribute it and/or 755d86984SDaniel P. Berrangé * modify it under the terms of the GNU Lesser General Public 855d86984SDaniel P. Berrangé * License as published by the Free Software Foundation; either 9036a80cdSChetan Pant * version 2.1 of the License, or (at your option) any later version. 1055d86984SDaniel P. Berrangé * 1155d86984SDaniel P. Berrangé * This library is distributed in the hope that it will be useful, 1255d86984SDaniel P. Berrangé * but WITHOUT ANY WARRANTY; without even the implied warranty of 1355d86984SDaniel P. Berrangé * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1455d86984SDaniel P. Berrangé * Lesser General Public License for more details. 1555d86984SDaniel P. Berrangé * 1655d86984SDaniel P. Berrangé * You should have received a copy of the GNU Lesser General Public 1755d86984SDaniel P. Berrangé * License along with this library; if not, see <http://www.gnu.org/licenses/>. 1855d86984SDaniel P. Berrangé * 1955d86984SDaniel P. Berrangé */ 2055d86984SDaniel P. Berrangé 2155d86984SDaniel P. Berrangé #include "qemu/osdep.h" 2255d86984SDaniel P. Berrangé #include "authz/listfile.h" 2345b1f68cSMarkus Armbruster #include "trace.h" 2455d86984SDaniel P. Berrangé #include "qemu/error-report.h" 2555d86984SDaniel P. Berrangé #include "qemu/main-loop.h" 260b8fa32fSMarkus Armbruster #include "qemu/module.h" 2755d86984SDaniel P. Berrangé #include "qemu/sockets.h" 2855d86984SDaniel P. Berrangé #include "qemu/filemonitor.h" 2955d86984SDaniel P. Berrangé #include "qom/object_interfaces.h" 3055d86984SDaniel P. Berrangé #include "qapi/qapi-visit-authz.h" 3155d86984SDaniel P. Berrangé #include "qapi/qmp/qjson.h" 3255d86984SDaniel P. Berrangé #include "qapi/qmp/qobject.h" 3355d86984SDaniel P. Berrangé #include "qapi/qmp/qerror.h" 3455d86984SDaniel P. Berrangé #include "qapi/qobject-input-visitor.h" 3555d86984SDaniel P. Berrangé 3655d86984SDaniel P. Berrangé 3755d86984SDaniel P. Berrangé static bool 3855d86984SDaniel P. Berrangé qauthz_list_file_is_allowed(QAuthZ *authz, 3955d86984SDaniel P. Berrangé const char *identity, 4055d86984SDaniel P. Berrangé Error **errp) 4155d86984SDaniel P. Berrangé { 4255d86984SDaniel P. Berrangé QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(authz); 4355d86984SDaniel P. Berrangé if (fauthz->list) { 4455d86984SDaniel P. Berrangé return qauthz_is_allowed(fauthz->list, identity, errp); 4555d86984SDaniel P. Berrangé } 4655d86984SDaniel P. Berrangé 4755d86984SDaniel P. Berrangé return false; 4855d86984SDaniel P. Berrangé } 4955d86984SDaniel P. Berrangé 5055d86984SDaniel P. Berrangé 5155d86984SDaniel P. Berrangé static QAuthZ * 5255d86984SDaniel P. Berrangé qauthz_list_file_load(QAuthZListFile *fauthz, Error **errp) 5355d86984SDaniel P. Berrangé { 5455d86984SDaniel P. Berrangé GError *err = NULL; 5555d86984SDaniel P. Berrangé gchar *content = NULL; 5655d86984SDaniel P. Berrangé gsize len; 5755d86984SDaniel P. Berrangé QObject *obj = NULL; 5855d86984SDaniel P. Berrangé QDict *pdict; 5955d86984SDaniel P. Berrangé Visitor *v = NULL; 6055d86984SDaniel P. Berrangé QAuthZ *ret = NULL; 6155d86984SDaniel P. Berrangé 6255d86984SDaniel P. Berrangé trace_qauthz_list_file_load(fauthz, fauthz->filename); 6355d86984SDaniel P. Berrangé if (!g_file_get_contents(fauthz->filename, &content, &len, &err)) { 6455d86984SDaniel P. Berrangé error_setg(errp, "Unable to read '%s': %s", 6555d86984SDaniel P. Berrangé fauthz->filename, err->message); 6655d86984SDaniel P. Berrangé goto cleanup; 6755d86984SDaniel P. Berrangé } 6855d86984SDaniel P. Berrangé 6955d86984SDaniel P. Berrangé obj = qobject_from_json(content, errp); 7055d86984SDaniel P. Berrangé if (!obj) { 7155d86984SDaniel P. Berrangé goto cleanup; 7255d86984SDaniel P. Berrangé } 7355d86984SDaniel P. Berrangé 7455d86984SDaniel P. Berrangé pdict = qobject_to(QDict, obj); 7555d86984SDaniel P. Berrangé if (!pdict) { 7655d86984SDaniel P. Berrangé error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "obj", "dict"); 7755d86984SDaniel P. Berrangé goto cleanup; 7855d86984SDaniel P. Berrangé } 7955d86984SDaniel P. Berrangé 8055d86984SDaniel P. Berrangé v = qobject_input_visitor_new(obj); 8155d86984SDaniel P. Berrangé 8255d86984SDaniel P. Berrangé ret = (QAuthZ *)user_creatable_add_type(TYPE_QAUTHZ_LIST, 8355d86984SDaniel P. Berrangé NULL, pdict, v, errp); 8455d86984SDaniel P. Berrangé 8555d86984SDaniel P. Berrangé cleanup: 8655d86984SDaniel P. Berrangé visit_free(v); 8755d86984SDaniel P. Berrangé qobject_unref(obj); 8855d86984SDaniel P. Berrangé if (err) { 8955d86984SDaniel P. Berrangé g_error_free(err); 9055d86984SDaniel P. Berrangé } 9155d86984SDaniel P. Berrangé g_free(content); 9255d86984SDaniel P. Berrangé return ret; 9355d86984SDaniel P. Berrangé } 9455d86984SDaniel P. Berrangé 9555d86984SDaniel P. Berrangé 9655d86984SDaniel P. Berrangé static void 97b4682a63SDaniel P. Berrangé qauthz_list_file_event(int64_t wd G_GNUC_UNUSED, 9855d86984SDaniel P. Berrangé QFileMonitorEvent ev G_GNUC_UNUSED, 9955d86984SDaniel P. Berrangé const char *name G_GNUC_UNUSED, 10055d86984SDaniel P. Berrangé void *opaque) 10155d86984SDaniel P. Berrangé { 10255d86984SDaniel P. Berrangé QAuthZListFile *fauthz = opaque; 10355d86984SDaniel P. Berrangé Error *err = NULL; 10455d86984SDaniel P. Berrangé 10555d86984SDaniel P. Berrangé if (ev != QFILE_MONITOR_EVENT_MODIFIED && 10655d86984SDaniel P. Berrangé ev != QFILE_MONITOR_EVENT_CREATED) { 10755d86984SDaniel P. Berrangé return; 10855d86984SDaniel P. Berrangé } 10955d86984SDaniel P. Berrangé 11055d86984SDaniel P. Berrangé object_unref(OBJECT(fauthz->list)); 11155d86984SDaniel P. Berrangé fauthz->list = qauthz_list_file_load(fauthz, &err); 11255d86984SDaniel P. Berrangé trace_qauthz_list_file_refresh(fauthz, 11355d86984SDaniel P. Berrangé fauthz->filename, fauthz->list ? 1 : 0); 11455d86984SDaniel P. Berrangé if (!fauthz->list) { 11555d86984SDaniel P. Berrangé error_report_err(err); 11655d86984SDaniel P. Berrangé } 11755d86984SDaniel P. Berrangé } 11855d86984SDaniel P. Berrangé 11955d86984SDaniel P. Berrangé static void 12055d86984SDaniel P. Berrangé qauthz_list_file_complete(UserCreatable *uc, Error **errp) 12155d86984SDaniel P. Berrangé { 12255d86984SDaniel P. Berrangé QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(uc); 12355d86984SDaniel P. Berrangé gchar *dir = NULL, *file = NULL; 12455d86984SDaniel P. Berrangé 12514b39485SEduardo Habkost if (!fauthz->filename) { 12614b39485SEduardo Habkost error_setg(errp, "filename not provided"); 12714b39485SEduardo Habkost return; 12814b39485SEduardo Habkost } 12914b39485SEduardo Habkost 13055d86984SDaniel P. Berrangé fauthz->list = qauthz_list_file_load(fauthz, errp); 131*2b37e9f8SMarkus Armbruster if (!fauthz->list) { 132*2b37e9f8SMarkus Armbruster return; 133*2b37e9f8SMarkus Armbruster } 13455d86984SDaniel P. Berrangé 13555d86984SDaniel P. Berrangé if (!fauthz->refresh) { 13655d86984SDaniel P. Berrangé return; 13755d86984SDaniel P. Berrangé } 13855d86984SDaniel P. Berrangé 13955d86984SDaniel P. Berrangé fauthz->file_monitor = qemu_file_monitor_new(errp); 14055d86984SDaniel P. Berrangé if (!fauthz->file_monitor) { 14155d86984SDaniel P. Berrangé return; 14255d86984SDaniel P. Berrangé } 14355d86984SDaniel P. Berrangé 14455d86984SDaniel P. Berrangé dir = g_path_get_dirname(fauthz->filename); 14555d86984SDaniel P. Berrangé if (g_str_equal(dir, ".")) { 14655d86984SDaniel P. Berrangé error_setg(errp, "Filename must be an absolute path"); 14755d86984SDaniel P. Berrangé goto cleanup; 14855d86984SDaniel P. Berrangé } 14955d86984SDaniel P. Berrangé file = g_path_get_basename(fauthz->filename); 15055d86984SDaniel P. Berrangé if (g_str_equal(file, ".")) { 15155d86984SDaniel P. Berrangé error_setg(errp, "Path has no trailing filename component"); 15255d86984SDaniel P. Berrangé goto cleanup; 15355d86984SDaniel P. Berrangé } 15455d86984SDaniel P. Berrangé 15555d86984SDaniel P. Berrangé fauthz->file_watch = qemu_file_monitor_add_watch( 15655d86984SDaniel P. Berrangé fauthz->file_monitor, dir, file, 15755d86984SDaniel P. Berrangé qauthz_list_file_event, fauthz, errp); 15855d86984SDaniel P. Berrangé if (fauthz->file_watch < 0) { 15955d86984SDaniel P. Berrangé goto cleanup; 16055d86984SDaniel P. Berrangé } 16155d86984SDaniel P. Berrangé 16255d86984SDaniel P. Berrangé cleanup: 16355d86984SDaniel P. Berrangé g_free(file); 16455d86984SDaniel P. Berrangé g_free(dir); 16555d86984SDaniel P. Berrangé } 16655d86984SDaniel P. Berrangé 16755d86984SDaniel P. Berrangé 16855d86984SDaniel P. Berrangé static void 16955d86984SDaniel P. Berrangé qauthz_list_file_prop_set_filename(Object *obj, 17055d86984SDaniel P. Berrangé const char *value, 17155d86984SDaniel P. Berrangé Error **errp G_GNUC_UNUSED) 17255d86984SDaniel P. Berrangé { 17355d86984SDaniel P. Berrangé QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj); 17455d86984SDaniel P. Berrangé 17555d86984SDaniel P. Berrangé g_free(fauthz->filename); 17655d86984SDaniel P. Berrangé fauthz->filename = g_strdup(value); 17755d86984SDaniel P. Berrangé } 17855d86984SDaniel P. Berrangé 17955d86984SDaniel P. Berrangé 18055d86984SDaniel P. Berrangé static char * 18155d86984SDaniel P. Berrangé qauthz_list_file_prop_get_filename(Object *obj, 18255d86984SDaniel P. Berrangé Error **errp G_GNUC_UNUSED) 18355d86984SDaniel P. Berrangé { 18455d86984SDaniel P. Berrangé QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj); 18555d86984SDaniel P. Berrangé 18655d86984SDaniel P. Berrangé return g_strdup(fauthz->filename); 18755d86984SDaniel P. Berrangé } 18855d86984SDaniel P. Berrangé 18955d86984SDaniel P. Berrangé 19055d86984SDaniel P. Berrangé static void 19155d86984SDaniel P. Berrangé qauthz_list_file_prop_set_refresh(Object *obj, 19255d86984SDaniel P. Berrangé bool value, 19355d86984SDaniel P. Berrangé Error **errp G_GNUC_UNUSED) 19455d86984SDaniel P. Berrangé { 19555d86984SDaniel P. Berrangé QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj); 19655d86984SDaniel P. Berrangé 19755d86984SDaniel P. Berrangé fauthz->refresh = value; 19855d86984SDaniel P. Berrangé } 19955d86984SDaniel P. Berrangé 20055d86984SDaniel P. Berrangé 20155d86984SDaniel P. Berrangé static bool 20255d86984SDaniel P. Berrangé qauthz_list_file_prop_get_refresh(Object *obj, 20355d86984SDaniel P. Berrangé Error **errp G_GNUC_UNUSED) 20455d86984SDaniel P. Berrangé { 20555d86984SDaniel P. Berrangé QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj); 20655d86984SDaniel P. Berrangé 20755d86984SDaniel P. Berrangé return fauthz->refresh; 20855d86984SDaniel P. Berrangé } 20955d86984SDaniel P. Berrangé 21055d86984SDaniel P. Berrangé 21155d86984SDaniel P. Berrangé static void 21255d86984SDaniel P. Berrangé qauthz_list_file_finalize(Object *obj) 21355d86984SDaniel P. Berrangé { 21455d86984SDaniel P. Berrangé QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj); 21555d86984SDaniel P. Berrangé 21655d86984SDaniel P. Berrangé object_unref(OBJECT(fauthz->list)); 21755d86984SDaniel P. Berrangé g_free(fauthz->filename); 21855d86984SDaniel P. Berrangé qemu_file_monitor_free(fauthz->file_monitor); 21955d86984SDaniel P. Berrangé } 22055d86984SDaniel P. Berrangé 22155d86984SDaniel P. Berrangé 22255d86984SDaniel P. Berrangé static void 22355d86984SDaniel P. Berrangé qauthz_list_file_class_init(ObjectClass *oc, void *data) 22455d86984SDaniel P. Berrangé { 22555d86984SDaniel P. Berrangé UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); 22655d86984SDaniel P. Berrangé QAuthZClass *authz = QAUTHZ_CLASS(oc); 22755d86984SDaniel P. Berrangé 22855d86984SDaniel P. Berrangé ucc->complete = qauthz_list_file_complete; 22955d86984SDaniel P. Berrangé 23055d86984SDaniel P. Berrangé object_class_property_add_str(oc, "filename", 23155d86984SDaniel P. Berrangé qauthz_list_file_prop_get_filename, 232d2623129SMarkus Armbruster qauthz_list_file_prop_set_filename); 23355d86984SDaniel P. Berrangé object_class_property_add_bool(oc, "refresh", 23455d86984SDaniel P. Berrangé qauthz_list_file_prop_get_refresh, 235d2623129SMarkus Armbruster qauthz_list_file_prop_set_refresh); 23655d86984SDaniel P. Berrangé 23755d86984SDaniel P. Berrangé authz->is_allowed = qauthz_list_file_is_allowed; 23855d86984SDaniel P. Berrangé } 23955d86984SDaniel P. Berrangé 24055d86984SDaniel P. Berrangé 24155d86984SDaniel P. Berrangé static void 24255d86984SDaniel P. Berrangé qauthz_list_file_init(Object *obj) 24355d86984SDaniel P. Berrangé { 24455d86984SDaniel P. Berrangé QAuthZListFile *authz = QAUTHZ_LIST_FILE(obj); 24555d86984SDaniel P. Berrangé 24655d86984SDaniel P. Berrangé authz->file_watch = -1; 24755d86984SDaniel P. Berrangé #ifdef CONFIG_INOTIFY1 248834e8bf1SJafar Abdi authz->refresh = true; 24955d86984SDaniel P. Berrangé #endif 25055d86984SDaniel P. Berrangé } 25155d86984SDaniel P. Berrangé 25255d86984SDaniel P. Berrangé 25355d86984SDaniel P. Berrangé QAuthZListFile *qauthz_list_file_new(const char *id, 25455d86984SDaniel P. Berrangé const char *filename, 25555d86984SDaniel P. Berrangé bool refresh, 25655d86984SDaniel P. Berrangé Error **errp) 25755d86984SDaniel P. Berrangé { 25855d86984SDaniel P. Berrangé return QAUTHZ_LIST_FILE( 25955d86984SDaniel P. Berrangé object_new_with_props(TYPE_QAUTHZ_LIST_FILE, 26055d86984SDaniel P. Berrangé object_get_objects_root(), 26155d86984SDaniel P. Berrangé id, errp, 26255d86984SDaniel P. Berrangé "filename", filename, 26355d86984SDaniel P. Berrangé "refresh", refresh ? "yes" : "no", 26455d86984SDaniel P. Berrangé NULL)); 26555d86984SDaniel P. Berrangé } 26655d86984SDaniel P. Berrangé 26755d86984SDaniel P. Berrangé 26855d86984SDaniel P. Berrangé static const TypeInfo qauthz_list_file_info = { 26955d86984SDaniel P. Berrangé .parent = TYPE_QAUTHZ, 27055d86984SDaniel P. Berrangé .name = TYPE_QAUTHZ_LIST_FILE, 27155d86984SDaniel P. Berrangé .instance_init = qauthz_list_file_init, 27255d86984SDaniel P. Berrangé .instance_size = sizeof(QAuthZListFile), 27355d86984SDaniel P. Berrangé .instance_finalize = qauthz_list_file_finalize, 27455d86984SDaniel P. Berrangé .class_init = qauthz_list_file_class_init, 27555d86984SDaniel P. Berrangé .interfaces = (InterfaceInfo[]) { 27655d86984SDaniel P. Berrangé { TYPE_USER_CREATABLE }, 27755d86984SDaniel P. Berrangé { } 27855d86984SDaniel P. Berrangé } 27955d86984SDaniel P. Berrangé }; 28055d86984SDaniel P. Berrangé 28155d86984SDaniel P. Berrangé 28255d86984SDaniel P. Berrangé static void 28355d86984SDaniel P. Berrangé qauthz_list_file_register_types(void) 28455d86984SDaniel P. Berrangé { 28555d86984SDaniel P. Berrangé type_register_static(&qauthz_list_file_info); 28655d86984SDaniel P. Berrangé } 28755d86984SDaniel P. Berrangé 28855d86984SDaniel P. Berrangé 28955d86984SDaniel P. Berrangé type_init(qauthz_list_file_register_types); 290