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