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-attributes.h"
24 #define DEBUG_FLAG GKM_DEBUG_OBJECT
25 #include "gkm-debug.h"
26 #include "gkm-object.h"
27 #include "gkm-store.h"
28 #include "gkm-transaction.h"
29 #include "gkm-util.h"
30
31 typedef struct _Schema {
32 CK_ATTRIBUTE_TYPE type;
33 gpointer default_value;
34 gsize default_length;
35 GkmStoreValidator validator;
36 guint flags;
37 } Schema;
38
39 struct _GkmStorePrivate {
40 GHashTable *schemas;
41 };
42
43 G_DEFINE_TYPE_WITH_PRIVATE (GkmStore, gkm_store, G_TYPE_OBJECT);
44
45 /* -----------------------------------------------------------------------------
46 * INTERNAL
47 */
48
49 static void
schema_free(gpointer data)50 schema_free (gpointer data)
51 {
52 Schema *schema;
53
54 if (data == NULL)
55 return;
56
57 schema = data;
58 g_free (schema->default_value);
59 g_slice_free (Schema, schema);
60 }
61
62 /* -----------------------------------------------------------------------------
63 * OBJECT
64 */
65
66 static GObject*
gkm_store_constructor(GType type,guint n_props,GObjectConstructParam * props)67 gkm_store_constructor (GType type, guint n_props, GObjectConstructParam *props)
68 {
69 GkmStore *self = GKM_STORE (G_OBJECT_CLASS (gkm_store_parent_class)->constructor(type, n_props, props));
70 g_return_val_if_fail (self, NULL);
71
72 return G_OBJECT (self);
73 }
74
75 static void
gkm_store_init(GkmStore * self)76 gkm_store_init (GkmStore *self)
77 {
78 self->pv = gkm_store_get_instance_private (self);
79 self->pv->schemas = g_hash_table_new_full (gkm_util_ulong_hash, gkm_util_ulong_equal,
80 NULL, schema_free);
81 }
82
83 static void
gkm_store_dispose(GObject * obj)84 gkm_store_dispose (GObject *obj)
85 {
86 GkmStore *self = GKM_STORE (obj);
87
88 g_hash_table_remove_all (self->pv->schemas);
89
90 G_OBJECT_CLASS (gkm_store_parent_class)->dispose (obj);
91 }
92
93 static void
gkm_store_finalize(GObject * obj)94 gkm_store_finalize (GObject *obj)
95 {
96 GkmStore *self = GKM_STORE (obj);
97
98 g_hash_table_destroy (self->pv->schemas);
99
100 G_OBJECT_CLASS (gkm_store_parent_class)->finalize (obj);
101 }
102
103 static void
gkm_store_set_property(GObject * obj,guint prop_id,const GValue * value,GParamSpec * pspec)104 gkm_store_set_property (GObject *obj, guint prop_id, const GValue *value,
105 GParamSpec *pspec)
106 {
107 switch (prop_id) {
108 default:
109 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
110 break;
111 }
112 }
113
114 static void
gkm_store_get_property(GObject * obj,guint prop_id,GValue * value,GParamSpec * pspec)115 gkm_store_get_property (GObject *obj, guint prop_id, GValue *value,
116 GParamSpec *pspec)
117 {
118 switch (prop_id) {
119 default:
120 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
121 break;
122 }
123 }
124
125 static void
gkm_store_class_init(GkmStoreClass * klass)126 gkm_store_class_init (GkmStoreClass *klass)
127 {
128 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
129
130 gobject_class->constructor = gkm_store_constructor;
131 gobject_class->dispose = gkm_store_dispose;
132 gobject_class->finalize = gkm_store_finalize;
133 gobject_class->set_property = gkm_store_set_property;
134 gobject_class->get_property = gkm_store_get_property;
135 }
136
137 /* -----------------------------------------------------------------------------
138 * PUBLIC
139 */
140
141 gconstpointer
gkm_store_read_value(GkmStore * self,GkmObject * object,CK_ATTRIBUTE_TYPE type,gsize * n_value)142 gkm_store_read_value (GkmStore *self, GkmObject *object,
143 CK_ATTRIBUTE_TYPE type, gsize *n_value)
144 {
145 CK_ATTRIBUTE at;
146 Schema *schema;
147 CK_RV rv;
148
149 g_return_val_if_fail (GKM_IS_STORE (self), NULL);
150 g_return_val_if_fail (GKM_IS_OBJECT (object), NULL);
151 g_return_val_if_fail (n_value, NULL);
152
153 g_assert (GKM_STORE_GET_CLASS (self)->read_value);
154
155 schema = g_hash_table_lookup (self->pv->schemas, &type);
156 if (schema == NULL)
157 return NULL;
158
159 at.type = type;
160 at.pValue = NULL;
161 at.ulValueLen = 0;
162
163 rv = GKM_STORE_GET_CLASS (self)->read_value (self, object, &at);
164 if (rv == CKR_ATTRIBUTE_TYPE_INVALID || rv == CKR_USER_NOT_LOGGED_IN) {
165 at.pValue = schema->default_value;
166 at.ulValueLen = schema->default_length;
167 } else if (rv != CKR_OK) {
168 g_return_val_if_reached (NULL);
169 }
170
171 *n_value = at.ulValueLen;
172 return at.pValue;
173 }
174
175 gchar*
gkm_store_read_string(GkmStore * self,GkmObject * object,CK_ATTRIBUTE_TYPE type)176 gkm_store_read_string (GkmStore *self, GkmObject *object, CK_ATTRIBUTE_TYPE type)
177 {
178 gconstpointer value;
179 gsize n_value;
180
181 g_return_val_if_fail (GKM_IS_STORE (self), NULL);
182 g_return_val_if_fail (GKM_IS_OBJECT (object), NULL);
183
184 value = gkm_store_read_value (self, object, type, &n_value);
185 if (!value)
186 return NULL;
187
188 return g_strndup (value, n_value);
189 }
190
191 CK_RV
gkm_store_get_attribute(GkmStore * self,GkmObject * object,CK_ATTRIBUTE_PTR attr)192 gkm_store_get_attribute (GkmStore *self, GkmObject *object, CK_ATTRIBUTE_PTR attr)
193 {
194 CK_ATTRIBUTE at;
195 Schema *schema;
196 CK_RV rv;
197
198 g_return_val_if_fail (GKM_IS_STORE (self), CKR_GENERAL_ERROR);
199 g_return_val_if_fail (GKM_IS_OBJECT (object), CKR_GENERAL_ERROR);
200 g_return_val_if_fail (attr, CKR_GENERAL_ERROR);
201
202 g_assert (GKM_STORE_GET_CLASS (self)->read_value);
203
204 schema = g_hash_table_lookup (self->pv->schemas, &(attr->type));
205 if (schema == NULL) {
206 gkm_debug ("CKR_ATTRIBUTE_TYPE_INVALID: %s not in schema",
207 gkm_log_attr_type (attr->type));
208 return CKR_ATTRIBUTE_TYPE_INVALID;
209 }
210
211 if (schema->flags & GKM_STORE_IS_INTERNAL) {
212 gkm_debug ("CKR_ATTRIBUTE_TYPE_INVALID: %s is an internal attribute",
213 gkm_log_attr_type (attr->type));
214 return CKR_ATTRIBUTE_TYPE_INVALID;
215 }
216
217 if (schema->flags & GKM_STORE_IS_SENSITIVE)
218 return CKR_ATTRIBUTE_SENSITIVE;
219
220 at.type = attr->type;
221 at.pValue = NULL;
222 at.ulValueLen = 0;
223
224 rv = GKM_STORE_GET_CLASS (self)->read_value (self, object, &at);
225 if (rv == CKR_ATTRIBUTE_TYPE_INVALID) {
226 at.pValue = schema->default_value;
227 at.ulValueLen = schema->default_length;
228 } else if (rv != CKR_OK) {
229 return rv;
230 }
231
232 /*
233 * If we get an assert here, then the derived class is probably
234 * trying to fill the buffer in the attribute passed. It should
235 * actually just be setting the pValue to its own buffers.
236 */
237 g_assert (at.pValue || !at.ulValueLen);
238
239 return gkm_attribute_set_data (attr, at.pValue, at.ulValueLen);
240 }
241
242 void
gkm_store_write_value(GkmStore * self,GkmTransaction * transaction,GkmObject * object,CK_ATTRIBUTE_PTR attr)243 gkm_store_write_value (GkmStore *self, GkmTransaction *transaction,
244 GkmObject *object, CK_ATTRIBUTE_PTR attr)
245 {
246 Schema *schema;
247
248 g_return_if_fail (GKM_IS_STORE (self));
249 g_return_if_fail (GKM_IS_TRANSACTION (transaction));
250 g_return_if_fail (GKM_IS_OBJECT (object));
251 g_return_if_fail (attr);
252
253 g_return_if_fail (!gkm_transaction_get_failed (transaction));
254 g_assert (GKM_STORE_GET_CLASS (self)->write_value);
255
256 schema = g_hash_table_lookup (self->pv->schemas, &(attr->type));
257 if (schema == NULL) {
258 gkm_debug ("CKR_ATTRIBUTE_TYPE_INVALID: %s not in schema",
259 gkm_log_attr_type (attr->type));
260 gkm_transaction_fail (transaction, CKR_ATTRIBUTE_TYPE_INVALID);
261 return;
262 }
263
264 GKM_STORE_GET_CLASS (self)->write_value (self, transaction, object, attr);
265 }
266
267 void
gkm_store_set_attribute(GkmStore * self,GkmTransaction * transaction,GkmObject * object,CK_ATTRIBUTE_PTR attr)268 gkm_store_set_attribute (GkmStore *self, GkmTransaction *transaction,
269 GkmObject *object, CK_ATTRIBUTE_PTR attr)
270 {
271 Schema *schema;
272 CK_RV rv = CKR_OK;
273
274 g_return_if_fail (GKM_IS_STORE (self));
275 g_return_if_fail (GKM_IS_TRANSACTION (transaction));
276 g_return_if_fail (GKM_IS_OBJECT (object));
277 g_return_if_fail (attr);
278
279 g_return_if_fail (!gkm_transaction_get_failed (transaction));
280 g_assert (GKM_STORE_GET_CLASS (self)->write_value);
281
282 schema = g_hash_table_lookup (self->pv->schemas, &(attr->type));
283 if (schema == NULL) {
284 gkm_debug ("CKR_ATTRIBUTE_TYPE_INVALID: %s not in schema",
285 gkm_log_attr_type (attr->type));
286 rv = CKR_ATTRIBUTE_TYPE_INVALID;
287 } else if (schema->flags & GKM_STORE_IS_INTERNAL) {
288 gkm_debug ("CKR_ATTRIBUTE_TYPE_INVALID: %s is internal",
289 gkm_log_attr_type (attr->type));
290 rv = CKR_ATTRIBUTE_TYPE_INVALID;
291 } else if (schema->validator) {
292 rv = (schema->validator) (object, attr);
293 }
294
295 if (rv != CKR_OK) {
296 gkm_transaction_fail (transaction, rv);
297 return;
298 }
299
300 GKM_STORE_GET_CLASS (self)->write_value (self, transaction, object, attr);
301 }
302
303 void
gkm_store_register_schema(GkmStore * self,CK_ATTRIBUTE_PTR attr,GkmStoreValidator validator,guint flags)304 gkm_store_register_schema (GkmStore *self, CK_ATTRIBUTE_PTR attr,
305 GkmStoreValidator validator, guint flags)
306 {
307 Schema *schema;
308
309 g_return_if_fail (GKM_IS_STORE (self));
310 g_return_if_fail (g_hash_table_lookup (self->pv->schemas, &(attr->type)) == NULL);
311 g_return_if_fail (!attr->ulValueLen || attr->pValue);
312 g_return_if_fail (attr->ulValueLen != (CK_ULONG)-1);
313
314 schema = g_slice_new0 (Schema);
315 schema->type = attr->type;
316 schema->flags = flags;
317 schema->validator = validator;
318 schema->default_value = attr->pValue;
319 schema->default_length = attr->ulValueLen;
320 if (schema->default_value)
321 schema->default_value = g_memdup (schema->default_value,
322 schema->default_length);
323
324 g_hash_table_insert (self->pv->schemas, &(schema->type), schema);
325 }
326
327 gboolean
gkm_store_lookup_schema(GkmStore * self,CK_ATTRIBUTE_TYPE type,guint * flags)328 gkm_store_lookup_schema (GkmStore *self, CK_ATTRIBUTE_TYPE type, guint *flags)
329 {
330 Schema *schema;
331
332 g_return_val_if_fail (GKM_IS_STORE (self), FALSE);
333
334 schema = g_hash_table_lookup (self->pv->schemas, &type);
335 if (!schema)
336 return FALSE;
337 if (flags)
338 *flags = schema->flags;
339 return TRUE;
340 }
341