Split the GCR and GCK libraries out of gnome-keyring
[platform/upstream/gcr.git] / gck / gck-uri.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /* gck-uri.c - the GObject PKCS#11 wrapper library
3
4    Copyright (C) 2010, Stefan Walter
5
6    The Gnome Keyring Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    License, or (at your option) any later version.
10
11    The Gnome Keyring Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public
17    License along with the Gnome Library; see the file COPYING.LIB.  If not,
18    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.
20
21    Author: Stef Walter <stef@memberwebs.com>
22 */
23
24 #include "config.h"
25
26 #include "gck.h"
27 #include "gck-private.h"
28 #include "gck-marshal.h"
29
30 #include <glib/gi18n-lib.h>
31
32 #include <p11-kit/uri.h>
33
34 #include <string.h>
35 #include <stdlib.h>
36
37 /**
38  * SECTION:gck-uri
39  * @title: PKCS11 URIs
40  * @short_description: Parsing and building PKCS\#11 URIs.
41  *
42  * <ulink href='http://tools.ietf.org/html/draft-pechanec-pkcs11uri-03'>PKCS\#11 URIs</ulink>
43  * are a standard for referring to PKCS\#11 modules, tokens, or objects. What the
44  * PKCS\#11 URI refers to depends on the context in which it is used.
45  *
46  * A PKCS\#11 URI can always resolve to more than one object, token or module. A
47  * PKCS\#11 URI that refers to a token, would (when used in a context that expects
48  * objects) refer to all the token on that module.
49  *
50  * In most cases the parsing or building of URIs is handled elsewhere in the GCK
51  * library. For example to enumerate objects that match a PKCS\#11 URI use the
52  * gck_modules_enumerate_uri() function.
53  *
54  * To parse a PKCS\#11 URI use the gck_uri_parse() function passing in the type of
55  * context in which you're using the URI. To build a URI use the gck_uri_build()
56  * function.
57  **/
58
59 /**
60  * GckUriData:
61  * @any_unrecognized: whether any parts of the PKCS\#11 URI were unsupported or unrecognized.
62  * @module_info: information about the PKCS\#11 modules matching the URI.
63  * @token_info: information about the PKCS\#11 tokens matching the URI.
64  * @attributes: information about the PKCS\#11 objects matching the URI.
65  *
66  * Information about the contents of a PKCS\#11 URI. Various fields may be %NULL
67  * depending on the context that the URI was parsed for.
68  *
69  * Since PKCS\#11 URIs represent a set which results from the intersections of
70  * all of the URI parts, if @any_recognized is set to %TRUE then usually the URI
71  * should be treated as not matching anything.
72  */
73
74 /**
75  * GckUriFlags:
76  * @GCK_URI_FOR_MODULE: the URI will be used to match modules.
77  * @GCK_URI_FOR_TOKEN: the URI will be used to match tokens.
78  * @GCK_URI_FOR_OBJECT: the URI will be used to match objects.
79  * @GCK_URI_WITH_VERSION: the URI has specific version numbers for module and/or token
80  * @GCK_URI_FOR_ANY: parse all recognized components of the URI.
81  *
82  * Which parts of the PKCS\#11 URI will be parsed or formatted. These can be
83  * combined.
84  */
85
86 /**
87  * GCK_URI_FOR_MODULE_WITH_VERSION:
88  *
89  * The URI will match specific version of modules. To be used as a GckUriFlags argument.
90  */
91
92 /**
93  * GCK_URI_FOR_OBJECT_ON_TOKEN:
94  *
95  * The URI will match objects on a specific token. To be used as a GckUriFlags argument.
96  */
97
98 /**
99  * GCK_URI_FOR_OBJECT_ON_TOKEN_AND_MODULE:
100  *
101  * The token inserted into a device with a specific module.
102  */
103
104 /**
105  * GckUriError:
106  * @GCK_URI_BAD_SCHEME: invalid URI scheme
107  * @GCK_URI_BAD_ENCODING: bad URI encoding
108  * @GCK_URI_BAD_SYNTAX: bad URI syntax
109  * @GCK_URI_BAD_VERSION: bad URI version component
110  * @GCK_URI_NOT_FOUND: piece of the URI was not found
111  *
112  * Various error codes used with PKCS\#11 URIs
113  */
114
115 /**
116  * GCK_URI_ERROR:
117  *
118  * Error domain for URI errors.
119  */
120
121 /**
122  * GCK_URI_BAD_PREFIX:
123  *
124  * Use %GCK_URI_BAD_SCHEME instead.
125  *
126  * Deprecated: Since 3.2
127  */
128
129 /**
130  * CKR_GCK_MODULE_PROBLEM:
131  *
132  * Use %GCK_ERROR_MODULE_PROBLEM instead.
133  *
134  * Deprecated: Since 3.4
135  */
136
137 #define URI_PREFIX "pkcs11:"
138 #define N_URI_PREFIX 7
139
140 struct _GckUri {
141         gboolean any_unrecognized;
142         GckModuleInfo *module_info;
143         GckTokenInfo *token_info;
144         GckAttributes *attributes;
145 };
146
147 GQuark
148 gck_uri_get_error_quark (void)
149 {
150         /* This is deprecated version */
151         return gck_uri_get_error_quark ();
152 }
153
154 GQuark
155 gck_uri_error_get_quark (void)
156 {
157         static GQuark domain = 0;
158         static volatile gsize quark_inited = 0;
159
160         if (g_once_init_enter (&quark_inited)) {
161                 domain = g_quark_from_static_string ("gck-uri-error");
162                 g_once_init_leave (&quark_inited, 1);
163         }
164
165         return domain;
166 }
167
168 /**
169  * gck_uri_data_new:
170  *
171  * Allocate a new GckUriData structure. None of the fields
172  * will be set.
173  *
174  * Returns: (transfer full): a newly allocated GckUriData, free with
175  *          gck_uri_data_free()
176  */
177 GckUriData *
178 gck_uri_data_new (void)
179 {
180         return g_slice_new0 (GckUriData);
181 }
182
183 /**
184  * gck_uri_parse:
185  * @string: the URI to parse.
186  * @flags: the context in which the URI will be used.
187  * @error: a #GError, or %NULL.
188  *
189  * Parse a PKCS\#11 URI for use in a given context.
190  *
191  * The result will contain the fields that are relevant for
192  * the given context. See #GckUriData  for more info.
193  * Other fields will be set to %NULL.
194  *
195  * Returns: (transfer full): a newly allocated #GckUriData; which should be
196  *          freed with gck_uri_data_free()
197  */
198 GckUriData*
199 gck_uri_parse (const gchar *string, GckUriFlags flags, GError **error)
200 {
201         GckUriData *uri_data = NULL;
202         CK_ATTRIBUTE_PTR attrs;
203         CK_ULONG i, n_attrs;
204         P11KitUri *p11_uri;
205         gint res;
206
207         g_return_val_if_fail (string, FALSE);
208         g_return_val_if_fail (!error || !*error, FALSE);
209
210         p11_uri = p11_kit_uri_new ();
211         if (!p11_uri)
212                 g_error ("failed to allocate P11KitUri");
213
214         res = p11_kit_uri_parse (string, flags, p11_uri);
215         if (res != P11_KIT_URI_OK) {
216                 p11_kit_uri_free (p11_uri);
217                 switch (res) {
218                 case P11_KIT_URI_NO_MEMORY:
219                         g_error ("failed to allocate memory in p11_kit_uri_parse()");
220                         break;
221                 case P11_KIT_URI_BAD_ENCODING:
222                         g_set_error (error, GCK_URI_ERROR, GCK_URI_BAD_ENCODING,
223                                      _("The URI has invalid encoding."));
224                         break;
225                 case P11_KIT_URI_BAD_SCHEME:
226                         g_set_error_literal (error, GCK_URI_ERROR, GCK_URI_BAD_SCHEME,
227                                              _("The URI does not have the 'pkcs11' scheme."));
228                         break;
229                 case P11_KIT_URI_BAD_SYNTAX:
230                         g_set_error_literal (error, GCK_URI_ERROR, GCK_URI_BAD_SYNTAX,
231                                              _("The URI has bad syntax."));
232                         break;
233                 case P11_KIT_URI_BAD_VERSION:
234                         g_set_error_literal (error, GCK_URI_ERROR, GCK_URI_BAD_SYNTAX,
235                                              _("The URI has a bad version number."));
236                         break;
237                 case P11_KIT_URI_NOT_FOUND:
238                         g_assert_not_reached ();
239                         break;
240                 };
241                 return NULL;
242         }
243
244         /* Convert it to a GckUri */
245         uri_data = gck_uri_data_new ();
246         if (flags & GCK_URI_FOR_MODULE_WITH_VERSION)
247                 uri_data->module_info = _gck_module_info_from_pkcs11 (p11_kit_uri_get_module_info (p11_uri));
248         if (flags & GCK_URI_FOR_TOKEN)
249                 uri_data->token_info = _gck_token_info_from_pkcs11 (p11_kit_uri_get_token_info (p11_uri));
250         if (flags & GCK_URI_FOR_OBJECT) {
251                 attrs = p11_kit_uri_get_attributes (p11_uri, &n_attrs);
252                 uri_data->attributes = gck_attributes_new ();
253                 for (i = 0; i < n_attrs; ++i)
254                         gck_attributes_add (uri_data->attributes, (GckAttribute*)&attrs[i]);
255         }
256         uri_data->any_unrecognized = p11_kit_uri_any_unrecognized (p11_uri);
257
258         p11_kit_uri_free (p11_uri);
259         return uri_data;
260 }
261
262 /**
263  * gck_uri_build:
264  * @uri_data: the info to build the URI from.
265  * @flags: The context that the URI is for
266  *
267  * Build a PKCS\#11 URI. The various parts relevant to the flags
268  * specified will be used to build the URI.
269  *
270  * Return value: a newly allocated string containing a PKCS\#11 URI.
271  */
272 gchar*
273 gck_uri_build (GckUriData *uri_data, GckUriFlags flags)
274 {
275         GckAttribute *attr;
276         P11KitUri *p11_uri = 0;
277         gchar *string;
278         int res;
279         guint i;
280
281         g_return_val_if_fail (uri_data != NULL, NULL);
282
283         p11_uri = p11_kit_uri_new ();
284
285         if ((flags & GCK_URI_FOR_MODULE_WITH_VERSION) && uri_data->module_info)
286                 _gck_module_info_to_pkcs11 (uri_data->module_info,
287                                             p11_kit_uri_get_module_info (p11_uri));
288         if ((flags & GCK_URI_FOR_TOKEN) && uri_data->token_info)
289                 _gck_token_info_to_pkcs11 (uri_data->token_info,
290                                            p11_kit_uri_get_token_info (p11_uri));
291         if ((flags & GCK_URI_FOR_OBJECT) && uri_data->attributes) {
292                 for (i = 0; i < gck_attributes_count (uri_data->attributes); ++i) {
293                         attr = gck_attributes_at (uri_data->attributes, i);
294                         res = p11_kit_uri_set_attribute (p11_uri, (CK_ATTRIBUTE_PTR)attr);
295                         if (res == P11_KIT_URI_NO_MEMORY)
296                                 g_error ("failed to allocate memory in p11_kit_uri_set_attribute()");
297                         else if (res != P11_KIT_URI_NOT_FOUND && res != P11_KIT_URI_OK)
298                                 g_return_val_if_reached (NULL);
299                 }
300         }
301
302         res = p11_kit_uri_format (p11_uri, flags & GCK_URI_FOR_ANY, &string);
303         if (res == P11_KIT_URI_NO_MEMORY)
304                 g_error ("failed to allocate memory in p11_kit_uri_format()");
305         else if (res != P11_KIT_URI_OK)
306                 g_return_val_if_reached (NULL);
307
308         p11_kit_uri_free (p11_uri);
309         return string;
310 }
311
312 GType
313 gck_uri_data_get_type (void)
314 {
315         static volatile gsize initialized = 0;
316         static GType type = 0;
317         if (g_once_init_enter (&initialized)) {
318                 type = g_boxed_type_register_static ("GckUriData",
319                                                      (GBoxedCopyFunc)gck_uri_data_copy,
320                                                      (GBoxedFreeFunc)gck_uri_data_free);
321                 g_once_init_leave (&initialized, 1);
322         }
323         return type;
324 }
325
326 /**
327  * gck_uri_data_copy:
328  * @uri_data: URI data to copy
329  *
330  * Copy a #GckUriData
331  *
332  * Returns: (transfer full): newly allocated copy of the uri data
333  */
334 GckUriData *
335 gck_uri_data_copy (GckUriData *uri_data)
336 {
337         GckUriData *copy;
338
339         copy = g_memdup (uri_data, sizeof (GckUriData));
340         copy->attributes = gck_attributes_new ();
341         gck_attributes_add_all (copy->attributes, uri_data->attributes);
342         copy->module_info = gck_module_info_copy (copy->module_info);
343         copy->token_info = gck_token_info_copy (copy->token_info);
344         return copy;
345 }
346
347 /**
348  * gck_uri_data_free:
349  * @uri_data: URI data to free.
350  *
351  * Free a #GckUriData.
352  */
353 void
354 gck_uri_data_free (GckUriData *uri_data)
355 {
356         if (uri_data) {
357                 if (uri_data->attributes)
358                         gck_attributes_unref (uri_data->attributes);
359                 if (uri_data->module_info)
360                         gck_module_info_free (uri_data->module_info);
361                 if (uri_data->token_info)
362                         gck_token_info_free (uri_data->token_info);
363                 g_slice_free (GckUriData, uri_data);
364         }
365 }