qemu/authz/listfile.c
<<
>>
Prefs
   1/*
   2 * QEMU access control list file authorization driver
   3 *
   4 * Copyright (c) 2018 Red Hat, Inc.
   5 *
   6 * This library is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU Lesser General Public
   8 * License as published by the Free Software Foundation; either
   9 * version 2 of the License, or (at your option) any later version.
  10 *
  11 * This library is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * Lesser General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU Lesser General Public
  17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  18 *
  19 */
  20
  21#include "qemu/osdep.h"
  22#include "authz/listfile.h"
  23#include "trace.h"
  24#include "qemu/error-report.h"
  25#include "qemu/main-loop.h"
  26#include "qemu/module.h"
  27#include "qemu/sockets.h"
  28#include "qemu/filemonitor.h"
  29#include "qom/object_interfaces.h"
  30#include "qapi/qapi-visit-authz.h"
  31#include "qapi/qmp/qjson.h"
  32#include "qapi/qmp/qobject.h"
  33#include "qapi/qmp/qerror.h"
  34#include "qapi/qobject-input-visitor.h"
  35
  36
  37static bool
  38qauthz_list_file_is_allowed(QAuthZ *authz,
  39                            const char *identity,
  40                            Error **errp)
  41{
  42    QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(authz);
  43    if (fauthz->list) {
  44        return qauthz_is_allowed(fauthz->list, identity, errp);
  45    }
  46
  47    return false;
  48}
  49
  50
  51static QAuthZ *
  52qauthz_list_file_load(QAuthZListFile *fauthz, Error **errp)
  53{
  54    GError *err = NULL;
  55    gchar *content = NULL;
  56    gsize len;
  57    QObject *obj = NULL;
  58    QDict *pdict;
  59    Visitor *v = NULL;
  60    QAuthZ *ret = NULL;
  61
  62    trace_qauthz_list_file_load(fauthz, fauthz->filename);
  63    if (!g_file_get_contents(fauthz->filename, &content, &len, &err)) {
  64        error_setg(errp, "Unable to read '%s': %s",
  65                   fauthz->filename, err->message);
  66        goto cleanup;
  67    }
  68
  69    obj = qobject_from_json(content, errp);
  70    if (!obj) {
  71        goto cleanup;
  72    }
  73
  74    pdict = qobject_to(QDict, obj);
  75    if (!pdict) {
  76        error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "obj", "dict");
  77        goto cleanup;
  78    }
  79
  80    v = qobject_input_visitor_new(obj);
  81
  82    ret = (QAuthZ *)user_creatable_add_type(TYPE_QAUTHZ_LIST,
  83                                            NULL, pdict, v, errp);
  84
  85 cleanup:
  86    visit_free(v);
  87    qobject_unref(obj);
  88    if (err) {
  89        g_error_free(err);
  90    }
  91    g_free(content);
  92    return ret;
  93}
  94
  95
  96static void
  97qauthz_list_file_event(int64_t wd G_GNUC_UNUSED,
  98                       QFileMonitorEvent ev G_GNUC_UNUSED,
  99                       const char *name G_GNUC_UNUSED,
 100                       void *opaque)
 101{
 102    QAuthZListFile *fauthz = opaque;
 103    Error *err = NULL;
 104
 105    if (ev != QFILE_MONITOR_EVENT_MODIFIED &&
 106        ev != QFILE_MONITOR_EVENT_CREATED) {
 107        return;
 108    }
 109
 110    object_unref(OBJECT(fauthz->list));
 111    fauthz->list = qauthz_list_file_load(fauthz, &err);
 112    trace_qauthz_list_file_refresh(fauthz,
 113                                   fauthz->filename, fauthz->list ? 1 : 0);
 114    if (!fauthz->list) {
 115        error_report_err(err);
 116    }
 117}
 118
 119static void
 120qauthz_list_file_complete(UserCreatable *uc, Error **errp)
 121{
 122    QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(uc);
 123    gchar *dir = NULL, *file = NULL;
 124
 125    fauthz->list = qauthz_list_file_load(fauthz, errp);
 126
 127    if (!fauthz->refresh) {
 128        return;
 129    }
 130
 131    fauthz->file_monitor = qemu_file_monitor_new(errp);
 132    if (!fauthz->file_monitor) {
 133        return;
 134    }
 135
 136    dir = g_path_get_dirname(fauthz->filename);
 137    if (g_str_equal(dir, ".")) {
 138        error_setg(errp, "Filename must be an absolute path");
 139        goto cleanup;
 140    }
 141    file = g_path_get_basename(fauthz->filename);
 142    if (g_str_equal(file, ".")) {
 143        error_setg(errp, "Path has no trailing filename component");
 144        goto cleanup;
 145    }
 146
 147    fauthz->file_watch = qemu_file_monitor_add_watch(
 148        fauthz->file_monitor, dir, file,
 149        qauthz_list_file_event, fauthz, errp);
 150    if (fauthz->file_watch < 0) {
 151        goto cleanup;
 152    }
 153
 154 cleanup:
 155    g_free(file);
 156    g_free(dir);
 157}
 158
 159
 160static void
 161qauthz_list_file_prop_set_filename(Object *obj,
 162                                   const char *value,
 163                                   Error **errp G_GNUC_UNUSED)
 164{
 165    QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj);
 166
 167    g_free(fauthz->filename);
 168    fauthz->filename = g_strdup(value);
 169}
 170
 171
 172static char *
 173qauthz_list_file_prop_get_filename(Object *obj,
 174                                   Error **errp G_GNUC_UNUSED)
 175{
 176    QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj);
 177
 178    return g_strdup(fauthz->filename);
 179}
 180
 181
 182static void
 183qauthz_list_file_prop_set_refresh(Object *obj,
 184                                  bool value,
 185                                  Error **errp G_GNUC_UNUSED)
 186{
 187    QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj);
 188
 189    fauthz->refresh = value;
 190}
 191
 192
 193static bool
 194qauthz_list_file_prop_get_refresh(Object *obj,
 195                                  Error **errp G_GNUC_UNUSED)
 196{
 197    QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj);
 198
 199    return fauthz->refresh;
 200}
 201
 202
 203static void
 204qauthz_list_file_finalize(Object *obj)
 205{
 206    QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj);
 207
 208    object_unref(OBJECT(fauthz->list));
 209    g_free(fauthz->filename);
 210    qemu_file_monitor_free(fauthz->file_monitor);
 211}
 212
 213
 214static void
 215qauthz_list_file_class_init(ObjectClass *oc, void *data)
 216{
 217    UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
 218    QAuthZClass *authz = QAUTHZ_CLASS(oc);
 219
 220    ucc->complete = qauthz_list_file_complete;
 221
 222    object_class_property_add_str(oc, "filename",
 223                                  qauthz_list_file_prop_get_filename,
 224                                  qauthz_list_file_prop_set_filename,
 225                                  NULL);
 226    object_class_property_add_bool(oc, "refresh",
 227                                   qauthz_list_file_prop_get_refresh,
 228                                   qauthz_list_file_prop_set_refresh,
 229                                   NULL);
 230
 231    authz->is_allowed = qauthz_list_file_is_allowed;
 232}
 233
 234
 235static void
 236qauthz_list_file_init(Object *obj)
 237{
 238    QAuthZListFile *authz = QAUTHZ_LIST_FILE(obj);
 239
 240    authz->file_watch = -1;
 241#ifdef CONFIG_INOTIFY1
 242    authz->refresh = TRUE;
 243#endif
 244}
 245
 246
 247QAuthZListFile *qauthz_list_file_new(const char *id,
 248                                     const char *filename,
 249                                     bool refresh,
 250                                     Error **errp)
 251{
 252    return QAUTHZ_LIST_FILE(
 253        object_new_with_props(TYPE_QAUTHZ_LIST_FILE,
 254                              object_get_objects_root(),
 255                              id, errp,
 256                              "filename", filename,
 257                              "refresh", refresh ? "yes" : "no",
 258                              NULL));
 259}
 260
 261
 262static const TypeInfo qauthz_list_file_info = {
 263    .parent = TYPE_QAUTHZ,
 264    .name = TYPE_QAUTHZ_LIST_FILE,
 265    .instance_init = qauthz_list_file_init,
 266    .instance_size = sizeof(QAuthZListFile),
 267    .instance_finalize = qauthz_list_file_finalize,
 268    .class_size = sizeof(QAuthZListFileClass),
 269    .class_init = qauthz_list_file_class_init,
 270    .interfaces = (InterfaceInfo[]) {
 271        { TYPE_USER_CREATABLE },
 272        { }
 273    }
 274};
 275
 276
 277static void
 278qauthz_list_file_register_types(void)
 279{
 280    type_register_static(&qauthz_list_file_info);
 281}
 282
 283
 284type_init(qauthz_list_file_register_types);
 285