xref: /qemu/authz/listfile.c (revision 6f1e91f7)
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/qobject-input-visitor.h"
3455d86984SDaniel P. Berrangé 
3555d86984SDaniel P. Berrangé 
3655d86984SDaniel P. Berrangé static bool
qauthz_list_file_is_allowed(QAuthZ * authz,const char * identity,Error ** errp)3755d86984SDaniel P. Berrangé qauthz_list_file_is_allowed(QAuthZ *authz,
3855d86984SDaniel P. Berrangé                             const char *identity,
3955d86984SDaniel P. Berrangé                             Error **errp)
4055d86984SDaniel P. Berrangé {
4155d86984SDaniel P. Berrangé     QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(authz);
4255d86984SDaniel P. Berrangé     if (fauthz->list) {
4355d86984SDaniel P. Berrangé         return qauthz_is_allowed(fauthz->list, identity, errp);
4455d86984SDaniel P. Berrangé     }
4555d86984SDaniel P. Berrangé 
4655d86984SDaniel P. Berrangé     return false;
4755d86984SDaniel P. Berrangé }
4855d86984SDaniel P. Berrangé 
4955d86984SDaniel P. Berrangé 
5055d86984SDaniel P. Berrangé static QAuthZ *
qauthz_list_file_load(QAuthZListFile * fauthz,Error ** errp)5155d86984SDaniel P. Berrangé qauthz_list_file_load(QAuthZListFile *fauthz, Error **errp)
5255d86984SDaniel P. Berrangé {
5355d86984SDaniel P. Berrangé     GError *err = NULL;
5455d86984SDaniel P. Berrangé     gchar *content = NULL;
5555d86984SDaniel P. Berrangé     gsize len;
5655d86984SDaniel P. Berrangé     QObject *obj = NULL;
5755d86984SDaniel P. Berrangé     QDict *pdict;
5855d86984SDaniel P. Berrangé     Visitor *v = NULL;
5955d86984SDaniel P. Berrangé     QAuthZ *ret = NULL;
6055d86984SDaniel P. Berrangé 
6155d86984SDaniel P. Berrangé     trace_qauthz_list_file_load(fauthz, fauthz->filename);
6255d86984SDaniel P. Berrangé     if (!g_file_get_contents(fauthz->filename, &content, &len, &err)) {
6355d86984SDaniel P. Berrangé         error_setg(errp, "Unable to read '%s': %s",
6455d86984SDaniel P. Berrangé                    fauthz->filename, err->message);
6555d86984SDaniel P. Berrangé         goto cleanup;
6655d86984SDaniel P. Berrangé     }
6755d86984SDaniel P. Berrangé 
6855d86984SDaniel P. Berrangé     obj = qobject_from_json(content, errp);
6955d86984SDaniel P. Berrangé     if (!obj) {
7055d86984SDaniel P. Berrangé         goto cleanup;
7155d86984SDaniel P. Berrangé     }
7255d86984SDaniel P. Berrangé 
7355d86984SDaniel P. Berrangé     pdict = qobject_to(QDict, obj);
7455d86984SDaniel P. Berrangé     if (!pdict) {
75*8e26ae7bSMarkus Armbruster         error_setg(errp, "File '%s' must contain a JSON object",
76*8e26ae7bSMarkus Armbruster                    fauthz->filename);
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
qauthz_list_file_event(int64_t wd G_GNUC_UNUSED,QFileMonitorEvent ev G_GNUC_UNUSED,const char * name G_GNUC_UNUSED,void * opaque)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
qauthz_list_file_complete(UserCreatable * uc,Error ** errp)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);
1312b37e9f8SMarkus Armbruster     if (!fauthz->list) {
1322b37e9f8SMarkus Armbruster         return;
1332b37e9f8SMarkus 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
qauthz_list_file_prop_set_filename(Object * obj,const char * value,Error ** errp G_GNUC_UNUSED)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 *
qauthz_list_file_prop_get_filename(Object * obj,Error ** errp G_GNUC_UNUSED)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
qauthz_list_file_prop_set_refresh(Object * obj,bool value,Error ** errp G_GNUC_UNUSED)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
qauthz_list_file_prop_get_refresh(Object * obj,Error ** errp G_GNUC_UNUSED)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
qauthz_list_file_finalize(Object * obj)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
qauthz_list_file_class_init(ObjectClass * oc,void * data)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
qauthz_list_file_init(Object * obj)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é 
qauthz_list_file_new(const char * id,const char * filename,bool refresh,Error ** errp)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
qauthz_list_file_register_types(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