Line data Source code
1 : /*
2 : * gnome-keyring
3 : *
4 : * Copyright (C) 2008 Stefan Walter
5 : *
6 : * This program is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU Lesser General Public License as
8 : * published by the Free Software Foundation; either version 2.1 of
9 : * the License, or (at your option) any later version.
10 : *
11 : * This program is distributed in the hope that it will be useful, but
12 : * 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 program; if not, see
18 : * <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "config.h"
22 :
23 : #include "gkm-ssh-module.h"
24 : #include "gkm-ssh-private-key.h"
25 : #include "gkm-ssh-public-key.h"
26 :
27 : #include "egg/egg-error.h"
28 : #include "egg/egg-file-tracker.h"
29 :
30 : #include <string.h>
31 :
32 : struct _GkmSshModule {
33 : GkmModule parent;
34 : EggFileTracker *tracker;
35 : gchar *directory;
36 : GHashTable *keys_by_path;
37 : };
38 :
39 : static const CK_SLOT_INFO gkm_ssh_module_slot_info = {
40 : "SSH Keys",
41 : "Gnome Keyring",
42 : CKF_TOKEN_PRESENT,
43 : { 0, 0 },
44 : { 0, 0 }
45 : };
46 :
47 : static const CK_TOKEN_INFO gkm_ssh_module_token_info = {
48 : "SSH Keys",
49 : "Gnome Keyring",
50 : "1.0",
51 : "1:SSH:HOME", /* Unique serial number for manufacturer */
52 : CKF_TOKEN_INITIALIZED | CKF_WRITE_PROTECTED | CKF_USER_PIN_INITIALIZED | CKF_LOGIN_REQUIRED,
53 : CK_EFFECTIVELY_INFINITE,
54 : CK_EFFECTIVELY_INFINITE,
55 : CK_EFFECTIVELY_INFINITE,
56 : CK_EFFECTIVELY_INFINITE,
57 : 1024,
58 : 1,
59 : CK_UNAVAILABLE_INFORMATION,
60 : CK_UNAVAILABLE_INFORMATION,
61 : CK_UNAVAILABLE_INFORMATION,
62 : CK_UNAVAILABLE_INFORMATION,
63 : { 0, 0 },
64 : { 0, 0 },
65 : ""
66 : };
67 :
68 :
69 247 : G_DEFINE_TYPE (GkmSshModule, gkm_ssh_module, GKM_TYPE_MODULE);
70 :
71 : GkmModule* _gkm_ssh_store_get_module_for_testing (void);
72 :
73 : /* -----------------------------------------------------------------------------
74 : * ACTUAL PKCS#11 Module Implementation
75 : */
76 :
77 : /* Include all the module entry points */
78 : #include "gkm/gkm-module-ep.h"
79 32 : GKM_DEFINE_MODULE (gkm_ssh_module, GKM_TYPE_SSH_MODULE);
80 :
81 : /* -----------------------------------------------------------------------------
82 : * INTERNAL
83 : */
84 :
85 : static gchar*
86 0 : private_path_for_public (const gchar *public_path)
87 : {
88 : gsize length;
89 :
90 0 : g_assert (public_path);
91 :
92 0 : length = strlen (public_path);
93 0 : if (length > 4 && g_str_equal (public_path + (length - 4), ".pub"))
94 0 : return g_strndup (public_path, length - 4);
95 :
96 0 : return NULL;
97 : }
98 :
99 : static void
100 0 : file_load (EggFileTracker *tracker,
101 : const gchar *path,
102 : GkmSshModule *self)
103 : {
104 : GkmSshPrivateKey *key;
105 : gchar *private_path;
106 0 : GError *error = NULL;
107 : gchar *unique;
108 :
109 0 : g_return_if_fail (path);
110 0 : g_return_if_fail (GKM_IS_SSH_MODULE (self));
111 :
112 0 : private_path = private_path_for_public (path);
113 0 : if (!private_path || !g_file_test (private_path, G_FILE_TEST_IS_REGULAR)) {
114 0 : g_message ("no private key present for public key: %s", path);
115 0 : g_free (private_path);
116 0 : return;
117 : }
118 :
119 : /* Create a key if necessary */
120 0 : key = g_hash_table_lookup (self->keys_by_path, path);
121 0 : if (key == NULL) {
122 0 : unique = g_strdup_printf ("ssh-store:%s", private_path);
123 0 : key = gkm_ssh_private_key_new (GKM_MODULE (self), unique);
124 0 : g_free (unique);
125 :
126 0 : g_hash_table_replace (self->keys_by_path, g_strdup (path), key);
127 : }
128 :
129 : /* Parse the data into the key */
130 0 : if (!gkm_ssh_private_key_parse (key, path, private_path, &error)) {
131 0 : if (error) {
132 0 : g_message ("couldn't parse data: %s: %s", path, egg_error_message (error));
133 0 : g_clear_error (&error);
134 : }
135 0 : gkm_object_expose (GKM_OBJECT (key), FALSE);
136 :
137 : /* When successful register with the object manager */
138 : } else {
139 0 : gkm_object_expose (GKM_OBJECT (key), TRUE);
140 : }
141 :
142 0 : g_free (private_path);
143 : }
144 :
145 : static void
146 0 : file_remove (EggFileTracker *tracker,
147 : const gchar *path,
148 : GkmSshModule *self)
149 : {
150 0 : g_return_if_fail (path);
151 0 : g_return_if_fail (GKM_IS_SSH_MODULE (self));
152 0 : g_hash_table_remove (self->keys_by_path, path);
153 : }
154 :
155 :
156 : /* -----------------------------------------------------------------------------
157 : * OBJECT
158 : */
159 :
160 : static const CK_SLOT_INFO*
161 66 : gkm_ssh_module_real_get_slot_info (GkmModule *self)
162 : {
163 66 : return &gkm_ssh_module_slot_info;
164 : }
165 :
166 : static const CK_TOKEN_INFO*
167 29 : gkm_ssh_module_real_get_token_info (GkmModule *self)
168 : {
169 29 : return &gkm_ssh_module_token_info;
170 : }
171 :
172 : static void
173 27 : gkm_ssh_module_real_parse_argument (GkmModule *base, const gchar *name, const gchar *value)
174 : {
175 27 : GkmSshModule *self = GKM_SSH_MODULE (base);
176 27 : if (g_str_equal (name, "directory")) {
177 27 : g_free (self->directory);
178 27 : self->directory = g_strdup (value);
179 : }
180 27 : }
181 :
182 : static CK_RV
183 4 : gkm_ssh_module_real_refresh_token (GkmModule *base)
184 : {
185 4 : GkmSshModule *self = GKM_SSH_MODULE (base);
186 4 : egg_file_tracker_refresh (self->tracker, FALSE);
187 4 : return CKR_OK;
188 : }
189 :
190 : static GObject*
191 32 : gkm_ssh_module_constructor (GType type, guint n_props, GObjectConstructParam *props)
192 : {
193 32 : GkmSshModule *self = GKM_SSH_MODULE (G_OBJECT_CLASS (gkm_ssh_module_parent_class)->constructor(type, n_props, props));
194 32 : g_return_val_if_fail (self, NULL);
195 :
196 32 : if (!self->directory)
197 5 : self->directory = g_strdup ("~/.ssh");
198 32 : self->tracker = egg_file_tracker_new (self->directory, "*.pub", NULL);
199 32 : g_signal_connect (self->tracker, "file-added", G_CALLBACK (file_load), self);
200 32 : g_signal_connect (self->tracker, "file-changed", G_CALLBACK (file_load), self);
201 32 : g_signal_connect (self->tracker, "file-removed", G_CALLBACK (file_remove), self);
202 :
203 32 : return G_OBJECT (self);
204 : }
205 :
206 : static void
207 32 : gkm_ssh_module_init (GkmSshModule *self)
208 : {
209 32 : self->keys_by_path = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
210 32 : }
211 :
212 : static void
213 64 : gkm_ssh_module_dispose (GObject *obj)
214 : {
215 64 : GkmSshModule *self = GKM_SSH_MODULE (obj);
216 :
217 64 : if (self->tracker)
218 32 : g_object_unref (self->tracker);
219 64 : self->tracker = NULL;
220 :
221 64 : g_hash_table_remove_all (self->keys_by_path);
222 :
223 64 : G_OBJECT_CLASS (gkm_ssh_module_parent_class)->dispose (obj);
224 64 : }
225 :
226 : static void
227 32 : gkm_ssh_module_finalize (GObject *obj)
228 : {
229 32 : GkmSshModule *self = GKM_SSH_MODULE (obj);
230 :
231 32 : g_assert (self->tracker == NULL);
232 :
233 32 : g_hash_table_destroy (self->keys_by_path);
234 32 : self->keys_by_path = NULL;
235 :
236 32 : g_free (self->directory);
237 32 : self->directory = NULL;
238 :
239 32 : G_OBJECT_CLASS (gkm_ssh_module_parent_class)->finalize (obj);
240 32 : }
241 :
242 : static void
243 28 : gkm_ssh_module_class_init (GkmSshModuleClass *klass)
244 : {
245 28 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
246 28 : GkmModuleClass *module_class = GKM_MODULE_CLASS (klass);
247 :
248 28 : gobject_class->constructor = gkm_ssh_module_constructor;
249 28 : gobject_class->dispose = gkm_ssh_module_dispose;
250 28 : gobject_class->finalize = gkm_ssh_module_finalize;
251 :
252 28 : module_class->get_slot_info = gkm_ssh_module_real_get_slot_info;
253 28 : module_class->get_token_info = gkm_ssh_module_real_get_token_info;
254 28 : module_class->parse_argument = gkm_ssh_module_real_parse_argument;
255 28 : module_class->refresh_token = gkm_ssh_module_real_refresh_token;
256 28 : }
257 :
258 : /* ----------------------------------------------------------------------------
259 : * PUBLIC
260 : */
261 :
262 : CK_FUNCTION_LIST_PTR
263 37 : gkm_ssh_store_get_functions (void)
264 : {
265 37 : gkm_crypto_initialize ();
266 37 : return gkm_ssh_module_function_list;
267 : }
268 :
269 : GkmModule*
270 10 : _gkm_ssh_store_get_module_for_testing (void)
271 : {
272 10 : return pkcs11_module;
273 : }
|