storage: relocate and protect secret storage through group access
[platform/upstream/gsignond.git] / src / extensions / tizen / tizen-storage-manager.c
1 /* vi: set et sw=4 ts=4 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /*
4  * This file is part of gsignond
5  *
6  * Copyright (C) 2013 Intel Corporation.
7  *
8  * Contact: Jussi Laako <jussi.laako@linux.intel.com>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23  * 02110-1301 USA
24  */
25
26 #include <errno.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <sys/types.h>
30 #include <sys/mount.h>
31 #include <glib.h>
32 #include <glib/gstdio.h>
33 #include <mntent.h>
34 #include <ecryptfs.h>
35
36 #include "tizen-storage-manager.h"
37 #include "gsignond/gsignond-log.h"
38 #include "gsignond/gsignond-utils.h"
39
40 #define EXTENSION_TIZEN_STORAGE_MANAGER_GET_PRIVATE(obj) \
41     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
42                                   EXTENSION_TYPE_TIZEN_STORAGE_MANAGER, \
43                                   ExtensionTizenStorageManagerPrivate))
44
45 /* these are limited by ecryptfs */
46 #define KEY_BYTES 16
47 #define KEY_CIPHER "aes"
48
49 struct _ExtensionTizenStorageManagerPrivate
50 {
51     gchar *cdir;
52     gchar fekey[ECRYPTFS_MAX_PASSPHRASE_BYTES + 1];
53     gchar fesalt[ECRYPTFS_SALT_SIZE + 1];
54     gchar ksig[ECRYPTFS_SIG_SIZE_HEX + 1];
55 };
56
57 enum
58 {
59     PROP_0,
60     PROP_FEKEY,
61     PROP_FESALT,
62     N_PROPERTIES,
63     PROP_CONFIG
64 };
65
66 static GParamSpec *properties[N_PROPERTIES] = { NULL, };
67
68 G_DEFINE_TYPE (ExtensionTizenStorageManager,
69                extension_tizen_storage_manager,
70                GSIGNOND_TYPE_STORAGE_MANAGER);
71
72 static void
73 _set_config (ExtensionTizenStorageManager *self, GSignondConfig *config)
74 {
75     GSignondStorageManager *parent = GSIGNOND_STORAGE_MANAGER (self);
76     g_assert (parent->config == NULL);
77     g_assert (self->priv->cdir == NULL);
78     parent->config = config;
79
80     gchar *user_dir = g_strdup_printf ("gsignond.%s", g_get_user_name ());
81     const gchar *secure_dir = gsignond_config_get_string (
82                                          config,
83                                          GSIGNOND_CONFIG_GENERAL_SECURE_DIR);
84     if (parent->location)
85         parent->location = g_build_filename (secure_dir,
86                                              user_dir,
87                                              NULL);
88     else
89         parent->location = g_build_filename ("/var/db",
90                                              user_dir,
91                                              NULL);
92     g_free (user_dir);
93     self->priv->cdir = g_strdup_printf ("%s.efs", parent->location);
94     DBG ("location %s encryption point %s", parent->location, self->priv->cdir);
95 }
96
97 static void
98 _set_property (GObject *object, guint prop_id, const GValue *value,
99                GParamSpec *pspec)
100 {
101     ExtensionTizenStorageManager *self =
102         EXTENSION_TIZEN_STORAGE_MANAGER (object);
103     ExtensionTizenStorageManagerPrivate *priv = self->priv;
104
105     switch (prop_id) {
106         case PROP_CONFIG:
107             _set_config (self, GSIGNOND_CONFIG (g_value_dup_object (value)));
108             break;
109         case PROP_FEKEY:
110             g_strlcpy (priv->fekey,
111                        g_value_get_string (value),
112                        sizeof(priv->fekey));
113             break;
114         case PROP_FESALT:
115             g_strlcpy (priv->fesalt,
116                        g_value_get_string (value),
117                        sizeof(priv->fesalt));
118             break;
119         default:
120             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
121     }
122 }
123
124 static void
125 _get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
126 {
127     ExtensionTizenStorageManager *self =
128         EXTENSION_TIZEN_STORAGE_MANAGER (object);
129     ExtensionTizenStorageManagerPrivate *priv = self->priv;
130
131     switch (prop_id) {
132         case PROP_CONFIG:
133             g_value_set_object (value,
134                                 GSIGNOND_STORAGE_MANAGER (self)->config);
135             break;
136         case PROP_FEKEY:
137             g_value_set_string (value, priv->fekey);
138             break;
139         case PROP_FESALT:
140             g_value_set_string (value, priv->fesalt);
141             break;
142         default:
143             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
144     }
145 }
146
147 static void
148 _dispose (GObject *object)
149 {
150     G_OBJECT_CLASS (extension_tizen_storage_manager_parent_class)->dispose (object);
151 }
152
153 static void
154 _finalize (GObject *object)
155 {
156     ExtensionTizenStorageManager *self =
157         EXTENSION_TIZEN_STORAGE_MANAGER (object);
158     ExtensionTizenStorageManagerPrivate *priv = self->priv;
159
160     if (priv)
161         memset(priv->ksig, 0x00, sizeof(priv->ksig));
162     g_free (priv->cdir);
163
164     G_OBJECT_CLASS (extension_tizen_storage_manager_parent_class)->finalize (object);
165 }
166
167 static gboolean
168 _initialize_storage (GSignondStorageManager *parent)
169 {
170     ExtensionTizenStorageManager *self =
171         EXTENSION_TIZEN_STORAGE_MANAGER (parent);
172     ExtensionTizenStorageManagerPrivate *priv = self->priv;
173
174     g_return_val_if_fail (parent->location, FALSE);
175     g_return_val_if_fail (priv->cdir, FALSE);
176
177     if (g_access (parent->location, R_OK) == 0 &&
178         g_access (priv->cdir, R_OK) == 0)
179         return TRUE;
180
181     gboolean res = FALSE;
182
183     uid_t uid = getuid ();
184     if (seteuid (0))
185         WARN ("seteuid() failed");
186
187     DBG ("create mount point %s", parent->location);
188     if (g_mkdir_with_parents (parent->location, S_IRWXU | S_IRWXG))
189         goto init_exit;
190
191     DBG ("create storage point %s", priv->cdir);
192     if (g_mkdir_with_parents (priv->cdir, S_IRWXU | S_IRWXG))
193         goto init_exit;
194
195     if (chown (parent->location, 0, getegid ()))
196         WARN ("chown() failed");
197     if (chmod (parent->location, S_IRWXU | S_IRWXG))
198         WARN ("chmod() failed");
199     if (chown (priv->cdir, 0, getegid ()))
200         WARN ("chown() failed");
201     if (chmod (priv->cdir, S_IRWXU | S_IRWXG))
202         WARN ("chmod() failed");
203     res = TRUE;
204
205 init_exit:
206     if (seteuid (uid))
207         WARN ("seteuid() failed");
208
209     return res;
210 }
211
212 static gboolean
213 _storage_is_initialized (GSignondStorageManager *parent)
214 {
215     ExtensionTizenStorageManager *self =
216         EXTENSION_TIZEN_STORAGE_MANAGER (parent);
217     ExtensionTizenStorageManagerPrivate *priv = self->priv;
218
219     g_return_val_if_fail (priv->cdir, FALSE);
220
221     if (g_access (priv->cdir, 0) || g_access (parent->location, 0))
222         return FALSE;
223
224     return TRUE;
225 }
226
227 static const gchar *
228 _mount_filesystem (GSignondStorageManager *parent)
229 {
230     gchar *retval = NULL;
231     ExtensionTizenStorageManager *self =
232         EXTENSION_TIZEN_STORAGE_MANAGER (parent);
233     ExtensionTizenStorageManagerPrivate *priv = self->priv;
234
235     DBG ("add passphrase to kernel keyring");
236     if (ecryptfs_add_passphrase_key_to_keyring (priv->ksig,
237                                                 priv->fekey,
238                                                 priv->fesalt) < 0)
239         return NULL;
240
241     gchar *mntopts = g_strdup_printf (
242                                       "ecryptfs_check_dev_ruid" \
243                                       ",ecryptfs_cipher=%s" \
244                                       ",ecryptfs_key_bytes=%d" \
245                                       ",ecryptfs_unlink_sigs" \
246                                       ",ecryptfs_sig=%s",
247                                       KEY_CIPHER, KEY_BYTES,
248                                       priv->ksig);
249     DBG ("mount options: %s", mntopts);
250     uid_t uid = getuid ();
251     if (seteuid (0))
252         WARN ("seteuid() failed");
253     DBG ("perform mount %s -> %s", priv->cdir, parent->location);
254     if (mount (priv->cdir, parent->location,
255                "ecryptfs", MS_NOSUID | MS_NODEV, mntopts)) {
256         INFO ("mount failed %d: %s", errno, strerror(errno));
257         goto _mount_exit;
258     }
259
260     DBG ("mount succeeded at %s", parent->location);
261     retval = parent->location;
262
263 _mount_exit:
264     g_free (mntopts);
265     if (seteuid (uid))
266         WARN ("seteuid() failed");
267
268     return retval;
269 }
270
271 static gboolean
272 _unmount_filesystem (GSignondStorageManager *parent)
273 {
274     g_return_val_if_fail (parent != NULL, FALSE);
275
276     uid_t uid = getuid ();
277     if (seteuid (0))
278         WARN ("seteuid() failed");
279     umount (parent->location);
280     if (seteuid (uid))
281         WARN ("seteuid() failed");
282
283     return TRUE;
284 }
285
286 static gboolean
287 _filesystem_is_mounted (GSignondStorageManager *parent)
288 {
289     gboolean retval = FALSE;
290     FILE *mntf = setmntent("/proc/mounts", "r");
291     g_return_val_if_fail (mntf != NULL, FALSE);
292     
293     struct mntent *me;
294     while ((me = getmntent(mntf))) {
295         if (g_strcmp0 (parent->location, me->mnt_dir) == 0) {
296             retval = TRUE;
297             break;
298         }
299     }
300
301     endmntent(mntf);
302
303     return retval;
304 }
305
306 static gboolean
307 _delete_storage (GSignondStorageManager *parent)
308 {
309     ExtensionTizenStorageManager *self =
310         EXTENSION_TIZEN_STORAGE_MANAGER (parent);
311     ExtensionTizenStorageManagerPrivate *priv = self->priv;
312
313     g_return_val_if_fail (priv->cdir, FALSE);
314     g_return_val_if_fail (!_filesystem_is_mounted(parent), FALSE);
315
316     return (gsignond_wipe_directory (priv->cdir) &&
317             gsignond_wipe_directory (parent->location));
318 }
319
320 static void
321 extension_tizen_storage_manager_class_init (
322                                       ExtensionTizenStorageManagerClass *klass)
323 {
324     GObjectClass *base = G_OBJECT_CLASS (klass);
325
326     base->set_property = _set_property;
327     base->get_property = _get_property;
328     base->dispose = _dispose;
329     base->finalize = _finalize;
330
331     properties[PROP_FEKEY] = g_param_spec_string ("fekey",
332                                                   "fekey",
333                                                   "File encryption key",
334                                                   "0123456789",
335                                                   G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
336     properties[PROP_FESALT] = g_param_spec_string ("fesalt",
337                                                    "fesalt",
338                                                    "File encryption salt",
339                                                    "9876543210",
340                                                    G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
341     g_object_class_install_properties (base, N_PROPERTIES, properties);
342     g_object_class_override_property (base, PROP_CONFIG, "config");
343
344     g_type_class_add_private (klass,
345                               sizeof(ExtensionTizenStorageManagerPrivate));
346
347     GSignondStorageManagerClass *parent_class =
348         GSIGNOND_STORAGE_MANAGER_CLASS (klass);
349     parent_class->initialize_storage = _initialize_storage;
350     parent_class->delete_storage = _delete_storage;
351     parent_class->storage_is_initialized = _storage_is_initialized;
352     parent_class->mount_filesystem = _mount_filesystem;
353     parent_class->unmount_filesystem = _unmount_filesystem;
354     parent_class->filesystem_is_mounted = _filesystem_is_mounted;
355 }
356
357 static void
358 extension_tizen_storage_manager_init (ExtensionTizenStorageManager *self)
359 {
360     ExtensionTizenStorageManagerPrivate *priv =
361         EXTENSION_TIZEN_STORAGE_MANAGER_GET_PRIVATE (self);
362     self->priv = priv;
363
364     g_strlcpy (priv->fekey, "1234567890", sizeof(priv->fekey));
365     g_strlcpy (priv->fesalt, "0987654321", sizeof(priv->fesalt));
366 }
367