1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2  *
3  * Copyright (C) 2016 Peter Hatina <phatina@redhat.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  *
19  */
20 
21 #include "config.h"
22 
23 #include <string.h>
24 #include <ctype.h>
25 
26 #include "udiskslogging.h"
27 #include "udisksdaemontypes.h"
28 #include "udisksconfigmanager.h"
29 
30 struct _UDisksConfigManager {
31   GObject parent_instance;
32 
33   gboolean uninstalled;
34 
35   UDisksModuleLoadPreference load_preference;
36 
37   const gchar *encryption;
38   gchar *config_dir;
39 };
40 
41 struct _UDisksConfigManagerClass {
42   GObjectClass parent_class;
43 };
44 
45 G_DEFINE_TYPE (UDisksConfigManager, udisks_config_manager, G_TYPE_OBJECT)
46 
47 enum
48 {
49   PROP_0,
50   PROP_UNINSTALLED,
51   PROP_PREFERENCE,
52   PROP_ENCRYPTION,
53   PROP_N
54 };
55 
56 #define MODULES_GROUP_NAME  PACKAGE_NAME_UDISKS2
57 #define MODULES_KEY "modules"
58 #define MODULES_LOAD_PREFERENCE_KEY "modules_load_preference"
59 
60 #define DEFAULTS_GROUP_NAME "defaults"
61 #define DEFAULTS_ENCRYPTION_KEY "encryption"
62 
63 static void
udisks_config_manager_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)64 udisks_config_manager_get_property (GObject    *object,
65                                     guint       property_id,
66                                     GValue     *value,
67                                     GParamSpec *pspec)
68 {
69   UDisksConfigManager *manager = UDISKS_CONFIG_MANAGER (object);
70 
71   switch (property_id)
72     {
73     case PROP_UNINSTALLED:
74       g_value_set_boolean (value, udisks_config_manager_get_uninstalled (manager));
75       break;
76 
77     case PROP_PREFERENCE:
78       g_value_set_int (value, udisks_config_manager_get_load_preference (manager));
79       break;
80 
81     case PROP_ENCRYPTION:
82       g_value_set_string (value, udisks_config_manager_get_encryption (manager));
83       break;
84 
85     default:
86       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
87       break;
88     }
89 }
90 
91 static const gchar *
get_encryption_config(const gchar * encryption)92 get_encryption_config (const gchar *encryption)
93 {
94   if (g_strcmp0 (encryption, UDISKS_ENCRYPTION_LUKS1) == 0)
95     {
96       return UDISKS_ENCRYPTION_LUKS1;
97     }
98   else if (g_strcmp0 (encryption, UDISKS_ENCRYPTION_LUKS2) == 0)
99     {
100       return UDISKS_ENCRYPTION_LUKS2;
101     }
102   else
103     {
104       udisks_warning ("Unknown value used for 'encryption': %s; defaulting to '%s'",
105                       encryption, UDISKS_ENCRYPTION_DEFAULT);
106       return UDISKS_ENCRYPTION_DEFAULT;
107     }
108 }
109 
110 static void
udisks_config_manager_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)111 udisks_config_manager_set_property (GObject      *object,
112                                     guint         property_id,
113                                     const GValue *value,
114                                     GParamSpec   *pspec)
115 {
116   UDisksConfigManager *manager = UDISKS_CONFIG_MANAGER (object);
117 
118   switch (property_id)
119     {
120     case PROP_UNINSTALLED:
121       manager->uninstalled = g_value_get_boolean (value);
122       break;
123 
124     case PROP_PREFERENCE:
125       manager->load_preference = g_value_get_int (value);
126       break;
127 
128     case PROP_ENCRYPTION:
129       manager->encryption = get_encryption_config (g_value_get_string (value));
130       break;
131 
132     default:
133       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
134       break;
135     }
136 }
137 
138 static void
parse_config_file(UDisksConfigManager * manager,UDisksModuleLoadPreference * out_load_preference,const gchar ** out_encryption,GList ** out_modules)139 parse_config_file (UDisksConfigManager         *manager,
140                    UDisksModuleLoadPreference  *out_load_preference,
141                    const gchar                **out_encryption,
142                    GList                      **out_modules)
143 {
144   GKeyFile *config_file;
145   gchar *conf_filename;
146   gchar *load_preference;
147   gchar *encryption;
148   gchar *module_i;
149   gchar **modules;
150   gchar **modules_tmp;
151 
152   /* Get modules and means of loading */
153   conf_filename = g_build_filename (G_DIR_SEPARATOR_S,
154                                     manager->config_dir,
155                                     PACKAGE_NAME_UDISKS2 ".conf",
156                                     NULL);
157 
158   udisks_debug ("Loading configuration file: %s", conf_filename);
159 
160   /* Load config */
161   config_file = g_key_file_new ();
162   g_key_file_set_list_separator (config_file, ',');
163   if (g_key_file_load_from_file (config_file, conf_filename, G_KEY_FILE_NONE, NULL))
164     {
165       if (out_modules != NULL)
166         {
167           modules = g_key_file_get_string_list (config_file, MODULES_GROUP_NAME, MODULES_KEY, NULL, NULL);
168           /* Read the list of modules to load. */
169           if (modules)
170             {
171               modules_tmp = modules;
172               for (module_i = *modules_tmp; module_i; module_i = *++modules_tmp)
173                 *out_modules = g_list_append (*out_modules, g_strdup (g_strstrip (module_i)));
174               g_strfreev (modules);
175             }
176         }
177 
178       if (out_load_preference != NULL)
179         {
180           /* Read the load preference configuration option. */
181           load_preference = g_key_file_get_string (config_file, MODULES_GROUP_NAME, MODULES_LOAD_PREFERENCE_KEY, NULL);
182           if (load_preference)
183             {
184               /* Check the key value */
185               if (g_ascii_strcasecmp (load_preference, "ondemand") == 0)
186                 {
187                   *out_load_preference = UDISKS_MODULE_LOAD_ONDEMAND;
188                 }
189               else if (g_ascii_strcasecmp (load_preference, "onstartup") == 0)
190                 {
191                   *out_load_preference = UDISKS_MODULE_LOAD_ONSTARTUP;
192                 }
193               else
194                 {
195                   udisks_warning ("Unknown value used for 'modules_load_preference': %s; defaulting to 'ondemand'",
196                                   load_preference);
197                 }
198 
199               g_free (load_preference);
200             }
201         }
202 
203       if (out_encryption != NULL)
204         {
205           /* Read the load preference configuration option. */
206           encryption = g_key_file_get_string (config_file, DEFAULTS_GROUP_NAME, DEFAULTS_ENCRYPTION_KEY, NULL);
207           if (encryption)
208             {
209               *out_encryption = get_encryption_config (encryption);
210               g_free (encryption);
211             }
212         }
213     }
214   else
215     {
216       udisks_warning ("Can't load configuration file %s", conf_filename);
217     }
218 
219   g_key_file_free (config_file);
220   g_free (conf_filename);
221 }
222 
223 static void
udisks_config_manager_constructed(GObject * object)224 udisks_config_manager_constructed (GObject *object)
225 {
226   UDisksConfigManager *manager = UDISKS_CONFIG_MANAGER (object);
227 
228   /* Build a path to the config directory */
229   manager->config_dir = g_build_path (G_DIR_SEPARATOR_S,
230                                       manager->uninstalled ? BUILD_DIR : PACKAGE_SYSCONF_DIR,
231                                       manager->uninstalled ? "udisks" : PROJECT_SYSCONF_DIR,
232                                       NULL);
233 
234   /* Make sure the config dir exists, UDisksLinuxDrive may store some data there */
235   if (g_mkdir_with_parents (manager->config_dir, 0755) != 0)
236     {
237       /* don't abort the daemon, the config dir may point to a readonly filesystem */
238       udisks_warning ("Error creating directory %s: %m", manager->config_dir);
239     }
240 
241   parse_config_file (manager, &manager->load_preference, &manager->encryption, NULL);
242 
243   if (G_OBJECT_CLASS (udisks_config_manager_parent_class))
244     G_OBJECT_CLASS (udisks_config_manager_parent_class)->constructed (object);
245 }
246 
247 static void
udisks_config_manager_dispose(GObject * object)248 udisks_config_manager_dispose (GObject *object)
249 {
250   if (G_OBJECT_CLASS (udisks_config_manager_parent_class))
251     G_OBJECT_CLASS (udisks_config_manager_parent_class)->dispose (object);
252 }
253 
254 static void
udisks_config_manager_finalize(GObject * object)255 udisks_config_manager_finalize (GObject *object)
256 {
257   UDisksConfigManager *manager = UDISKS_CONFIG_MANAGER (object);
258 
259   g_free (manager->config_dir);
260 
261   if (G_OBJECT_CLASS (udisks_config_manager_parent_class))
262     G_OBJECT_CLASS (udisks_config_manager_parent_class)->finalize (object);
263 }
264 
265 static void
udisks_config_manager_class_init(UDisksConfigManagerClass * klass)266 udisks_config_manager_class_init (UDisksConfigManagerClass *klass)
267 {
268   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
269 
270   gobject_class->constructed  = udisks_config_manager_constructed;
271   gobject_class->get_property = udisks_config_manager_get_property;
272   gobject_class->set_property = udisks_config_manager_set_property;
273   gobject_class->dispose = udisks_config_manager_dispose;
274   gobject_class->finalize = udisks_config_manager_finalize;
275 
276   /**
277    * UDisksConfigManager:uninstalled:
278    *
279    * Loads modules from the build directory.
280    */
281   g_object_class_install_property (gobject_class,
282                                    PROP_UNINSTALLED,
283                                    g_param_spec_boolean ("uninstalled",
284                                                          "Load modules from the build directory",
285                                                          "Whether the modules should be loaded from the build directory",
286                                                          FALSE,
287                                                          G_PARAM_READABLE |
288                                                          G_PARAM_WRITABLE |
289                                                          G_PARAM_STATIC_STRINGS |
290                                                          G_PARAM_CONSTRUCT_ONLY));
291 
292   /**
293    * UDisksConfigManager:preference:
294    *
295    * Module load preference.
296    */
297   g_object_class_install_property (gobject_class,
298                                    PROP_PREFERENCE,
299                                    g_param_spec_int ("preference",
300                                                      "Module load preference",
301                                                      "When to load the additional modules",
302                                                      UDISKS_MODULE_LOAD_ONDEMAND,
303                                                      UDISKS_MODULE_LOAD_ONSTARTUP,
304                                                      UDISKS_MODULE_LOAD_ONDEMAND,
305                                                      G_PARAM_READABLE |
306                                                      G_PARAM_WRITABLE |
307                                                      G_PARAM_STATIC_STRINGS |
308                                                      G_PARAM_CONSTRUCT_ONLY));
309 
310   /**
311    * UDisksConfigManager:encryption:
312    *
313    * Default encryption technolog.
314    */
315   g_object_class_install_property (gobject_class,
316                                    PROP_ENCRYPTION,
317                                    g_param_spec_string ("encryption",
318                                                         "Default encryption technology",
319                                                         "Encryption technology used when creating encrypted filesystems",
320                                                         UDISKS_ENCRYPTION_DEFAULT,
321                                                         G_PARAM_READABLE |
322                                                         G_PARAM_WRITABLE |
323                                                         G_PARAM_STATIC_STRINGS |
324                                                         G_PARAM_CONSTRUCT_ONLY));
325 
326 }
327 
328 static void
udisks_config_manager_init(UDisksConfigManager * manager)329 udisks_config_manager_init (UDisksConfigManager *manager)
330 {
331   manager->load_preference = UDISKS_MODULE_LOAD_ONDEMAND;
332   manager->encryption = UDISKS_ENCRYPTION_DEFAULT;
333 }
334 
335 UDisksConfigManager *
udisks_config_manager_new(void)336 udisks_config_manager_new (void)
337 {
338   return UDISKS_CONFIG_MANAGER (g_object_new (UDISKS_TYPE_CONFIG_MANAGER,
339                                 "uninstalled", FALSE,
340                                 NULL));
341 }
342 
343 UDisksConfigManager *
udisks_config_manager_new_uninstalled(void)344 udisks_config_manager_new_uninstalled (void)
345 {
346   return UDISKS_CONFIG_MANAGER (g_object_new (UDISKS_TYPE_CONFIG_MANAGER,
347                                 "uninstalled", TRUE,
348                                 NULL));
349 }
350 
351 gboolean
udisks_config_manager_get_uninstalled(UDisksConfigManager * manager)352 udisks_config_manager_get_uninstalled (UDisksConfigManager *manager)
353 {
354   g_return_val_if_fail (UDISKS_IS_CONFIG_MANAGER (manager), FALSE);
355   return manager->uninstalled;
356 }
357 
358 /**
359  * udisks_config_manager_get_modules:
360  * @manager: A #UDisksConfigManager.
361  *
362  * Reads the udisks2.conf file and retrieves a list of module names to load.
363  * A special '*' placeholder may be present as a first item as specified
364  * in the config file.
365  *
366  * Returns: (transfer full) (nullable) (element-type gchar*): A list of strings
367  *          or %NULL if no specific configuration has been found in the config file.
368  *          Free the elements with g_free().
369  */
370 GList *
udisks_config_manager_get_modules(UDisksConfigManager * manager)371 udisks_config_manager_get_modules (UDisksConfigManager *manager)
372 {
373   GList *modules = NULL;
374 
375   g_return_val_if_fail (UDISKS_IS_CONFIG_MANAGER (manager), NULL);
376 
377   parse_config_file (manager, NULL, NULL, &modules);
378   return modules;
379 }
380 
381 /**
382  * udisks_config_manager_get_modules_all:
383  * @manager: A #UDisksConfigManager.
384  *
385  * Reads the udisks2.conf file and returns whether to load all modules or not.
386  * This corresponds to a special '*' placeholder in the config file.
387  *
388  * Returns: %TRUE when the daemon runs from a source tree, %FALSE otherwise.
389  */
390 gboolean
udisks_config_manager_get_modules_all(UDisksConfigManager * manager)391 udisks_config_manager_get_modules_all (UDisksConfigManager *manager)
392 {
393   GList *modules = NULL;
394   gboolean ret;
395 
396   g_return_val_if_fail (UDISKS_IS_CONFIG_MANAGER (manager), FALSE);
397 
398   parse_config_file (manager, NULL, NULL, &modules);
399 
400   ret = !modules || (g_strcmp0 (modules->data, "*") == 0 && g_list_length (modules) == 1);
401 
402   g_list_free_full (modules, (GDestroyNotify) g_free);
403 
404   return ret;
405 }
406 
407 UDisksModuleLoadPreference
udisks_config_manager_get_load_preference(UDisksConfigManager * manager)408 udisks_config_manager_get_load_preference (UDisksConfigManager *manager)
409 {
410   g_return_val_if_fail (UDISKS_IS_CONFIG_MANAGER (manager),
411                         UDISKS_MODULE_LOAD_ONDEMAND);
412   return manager->load_preference;
413 }
414 
415 const gchar *
udisks_config_manager_get_encryption(UDisksConfigManager * manager)416 udisks_config_manager_get_encryption (UDisksConfigManager *manager)
417 {
418   g_return_val_if_fail (UDISKS_IS_CONFIG_MANAGER (manager),
419                         UDISKS_ENCRYPTION_DEFAULT);
420   return manager->encryption;
421 }
422 
423 /**
424  * udisks_config_manager_get_config_dir:
425  * @manager: A #UDisksConfigManager.
426  *
427  * Gets path to the actual directory where global UDisks configuration files are
428  * stored. Takes in account the flag whether the UDisks daemon is running from
429  * a source code tree ("uninstalled") or whether it is a properly installed package.
430  *
431  * Returns: (transfer none): path to the global UDisks configuration directory.
432  */
433 const gchar *
udisks_config_manager_get_config_dir(UDisksConfigManager * manager)434 udisks_config_manager_get_config_dir (UDisksConfigManager *manager)
435 {
436   g_return_val_if_fail (UDISKS_IS_CONFIG_MANAGER (manager), NULL);
437   g_warn_if_fail (manager->config_dir != NULL);
438   return manager->config_dir;
439 }
440