listfile.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  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.1 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. #include "qemu/osdep.h"
  21. #include "authz/listfile.h"
  22. #include "trace.h"
  23. #include "qemu/error-report.h"
  24. #include "qemu/main-loop.h"
  25. #include "qemu/module.h"
  26. #include "qemu/sockets.h"
  27. #include "qemu/filemonitor.h"
  28. #include "qom/object_interfaces.h"
  29. #include "qapi/qapi-visit-authz.h"
  30. #include "qobject/qjson.h"
  31. #include "qobject/qobject.h"
  32. #include "qapi/qobject-input-visitor.h"
  33. static bool
  34. qauthz_list_file_is_allowed(QAuthZ *authz,
  35. const char *identity,
  36. Error **errp)
  37. {
  38. QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(authz);
  39. if (fauthz->list) {
  40. return qauthz_is_allowed(fauthz->list, identity, errp);
  41. }
  42. return false;
  43. }
  44. static QAuthZ *
  45. qauthz_list_file_load(QAuthZListFile *fauthz, Error **errp)
  46. {
  47. GError *err = NULL;
  48. gchar *content = NULL;
  49. gsize len;
  50. QObject *obj = NULL;
  51. QDict *pdict;
  52. Visitor *v = NULL;
  53. QAuthZ *ret = NULL;
  54. trace_qauthz_list_file_load(fauthz, fauthz->filename);
  55. if (!g_file_get_contents(fauthz->filename, &content, &len, &err)) {
  56. error_setg(errp, "Unable to read '%s': %s",
  57. fauthz->filename, err->message);
  58. goto cleanup;
  59. }
  60. obj = qobject_from_json(content, errp);
  61. if (!obj) {
  62. goto cleanup;
  63. }
  64. pdict = qobject_to(QDict, obj);
  65. if (!pdict) {
  66. error_setg(errp, "File '%s' must contain a JSON object",
  67. fauthz->filename);
  68. goto cleanup;
  69. }
  70. v = qobject_input_visitor_new(obj);
  71. ret = (QAuthZ *)user_creatable_add_type(TYPE_QAUTHZ_LIST,
  72. NULL, pdict, v, errp);
  73. cleanup:
  74. visit_free(v);
  75. qobject_unref(obj);
  76. if (err) {
  77. g_error_free(err);
  78. }
  79. g_free(content);
  80. return ret;
  81. }
  82. static void
  83. qauthz_list_file_event(int64_t wd G_GNUC_UNUSED,
  84. QFileMonitorEvent ev G_GNUC_UNUSED,
  85. const char *name G_GNUC_UNUSED,
  86. void *opaque)
  87. {
  88. QAuthZListFile *fauthz = opaque;
  89. Error *err = NULL;
  90. if (ev != QFILE_MONITOR_EVENT_MODIFIED &&
  91. ev != QFILE_MONITOR_EVENT_CREATED) {
  92. return;
  93. }
  94. object_unref(OBJECT(fauthz->list));
  95. fauthz->list = qauthz_list_file_load(fauthz, &err);
  96. trace_qauthz_list_file_refresh(fauthz,
  97. fauthz->filename, fauthz->list ? 1 : 0);
  98. if (!fauthz->list) {
  99. error_report_err(err);
  100. }
  101. }
  102. static void
  103. qauthz_list_file_complete(UserCreatable *uc, Error **errp)
  104. {
  105. QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(uc);
  106. gchar *dir = NULL, *file = NULL;
  107. if (!fauthz->filename) {
  108. error_setg(errp, "filename not provided");
  109. return;
  110. }
  111. fauthz->list = qauthz_list_file_load(fauthz, errp);
  112. if (!fauthz->list) {
  113. return;
  114. }
  115. if (!fauthz->refresh) {
  116. return;
  117. }
  118. fauthz->file_monitor = qemu_file_monitor_new(errp);
  119. if (!fauthz->file_monitor) {
  120. return;
  121. }
  122. dir = g_path_get_dirname(fauthz->filename);
  123. if (g_str_equal(dir, ".")) {
  124. error_setg(errp, "Filename must be an absolute path");
  125. goto cleanup;
  126. }
  127. file = g_path_get_basename(fauthz->filename);
  128. if (g_str_equal(file, ".")) {
  129. error_setg(errp, "Path has no trailing filename component");
  130. goto cleanup;
  131. }
  132. fauthz->file_watch = qemu_file_monitor_add_watch(
  133. fauthz->file_monitor, dir, file,
  134. qauthz_list_file_event, fauthz, errp);
  135. if (fauthz->file_watch < 0) {
  136. goto cleanup;
  137. }
  138. cleanup:
  139. g_free(file);
  140. g_free(dir);
  141. }
  142. static void
  143. qauthz_list_file_prop_set_filename(Object *obj,
  144. const char *value,
  145. Error **errp G_GNUC_UNUSED)
  146. {
  147. QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj);
  148. g_free(fauthz->filename);
  149. fauthz->filename = g_strdup(value);
  150. }
  151. static char *
  152. qauthz_list_file_prop_get_filename(Object *obj,
  153. Error **errp G_GNUC_UNUSED)
  154. {
  155. QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj);
  156. return g_strdup(fauthz->filename);
  157. }
  158. static void
  159. qauthz_list_file_prop_set_refresh(Object *obj,
  160. bool value,
  161. Error **errp G_GNUC_UNUSED)
  162. {
  163. QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj);
  164. fauthz->refresh = value;
  165. }
  166. static bool
  167. qauthz_list_file_prop_get_refresh(Object *obj,
  168. Error **errp G_GNUC_UNUSED)
  169. {
  170. QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj);
  171. return fauthz->refresh;
  172. }
  173. static void
  174. qauthz_list_file_finalize(Object *obj)
  175. {
  176. QAuthZListFile *fauthz = QAUTHZ_LIST_FILE(obj);
  177. object_unref(OBJECT(fauthz->list));
  178. g_free(fauthz->filename);
  179. qemu_file_monitor_free(fauthz->file_monitor);
  180. }
  181. static void
  182. qauthz_list_file_class_init(ObjectClass *oc, void *data)
  183. {
  184. UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
  185. QAuthZClass *authz = QAUTHZ_CLASS(oc);
  186. ucc->complete = qauthz_list_file_complete;
  187. object_class_property_add_str(oc, "filename",
  188. qauthz_list_file_prop_get_filename,
  189. qauthz_list_file_prop_set_filename);
  190. object_class_property_add_bool(oc, "refresh",
  191. qauthz_list_file_prop_get_refresh,
  192. qauthz_list_file_prop_set_refresh);
  193. authz->is_allowed = qauthz_list_file_is_allowed;
  194. }
  195. static void
  196. qauthz_list_file_init(Object *obj)
  197. {
  198. QAuthZListFile *authz = QAUTHZ_LIST_FILE(obj);
  199. authz->file_watch = -1;
  200. #ifdef CONFIG_INOTIFY1
  201. authz->refresh = true;
  202. #endif
  203. }
  204. QAuthZListFile *qauthz_list_file_new(const char *id,
  205. const char *filename,
  206. bool refresh,
  207. Error **errp)
  208. {
  209. return QAUTHZ_LIST_FILE(
  210. object_new_with_props(TYPE_QAUTHZ_LIST_FILE,
  211. object_get_objects_root(),
  212. id, errp,
  213. "filename", filename,
  214. "refresh", refresh ? "yes" : "no",
  215. NULL));
  216. }
  217. static const TypeInfo qauthz_list_file_info = {
  218. .parent = TYPE_QAUTHZ,
  219. .name = TYPE_QAUTHZ_LIST_FILE,
  220. .instance_init = qauthz_list_file_init,
  221. .instance_size = sizeof(QAuthZListFile),
  222. .instance_finalize = qauthz_list_file_finalize,
  223. .class_init = qauthz_list_file_class_init,
  224. .interfaces = (InterfaceInfo[]) {
  225. { TYPE_USER_CREATABLE },
  226. { }
  227. }
  228. };
  229. static void
  230. qauthz_list_file_register_types(void)
  231. {
  232. type_register_static(&qauthz_list_file_info);
  233. }
  234. type_init(qauthz_list_file_register_types);