1 /*
2 * Copyright (C) 2010 Stefan Walter
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as
6 * published by the Free Software Foundation; either version 2.1 of
7 * the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "config.h"
19
20 #include "gcr-key-mechanisms.h"
21
22 #include <glib/gi18n-lib.h>
23
24 static gboolean
check_have_attributes(GckAttributes * attrs,const gulong * types,gsize n_types)25 check_have_attributes (GckAttributes *attrs,
26 const gulong *types,
27 gsize n_types)
28 {
29 gsize i;
30
31 for (i = 0; i < n_types; i++) {
32 if (!gck_attributes_find (attrs, types[i]))
33 return FALSE;
34 }
35
36 return TRUE;
37 }
38
39 static gulong
find_first_usable_mechanism(GckObject * key,GckAttributes * attrs,const gulong * mechanisms,gsize n_mechanisms,gulong action_attr_type)40 find_first_usable_mechanism (GckObject *key,
41 GckAttributes *attrs,
42 const gulong *mechanisms,
43 gsize n_mechanisms,
44 gulong action_attr_type)
45 {
46 GckSession *session;
47 GckSlot *slot;
48 GArray *mechs;
49 gboolean can;
50 gsize i;
51
52 if (gck_attributes_find_boolean (attrs, action_attr_type, &can) && !can) {
53 g_debug ("key not capable of needed action");
54 return GCK_INVALID;
55 }
56
57 session = gck_object_get_session (key);
58 slot = gck_session_get_slot (session);
59 mechs = gck_slot_get_mechanisms (slot);
60 g_object_unref (slot);
61 g_object_unref (session);
62
63 if (!mechs) {
64 g_debug ("couldn't get slot mechanisms");
65 return GCK_INVALID;
66 }
67
68 for (i = 0; i < n_mechanisms; i++) {
69 if (gck_mechanisms_check (mechs, mechanisms[i], GCK_INVALID))
70 break;
71 }
72
73 gck_mechanisms_free (mechs);
74
75 if (i < n_mechanisms)
76 return mechanisms[i];
77 return GCK_INVALID;
78 }
79
80 gulong
_gcr_key_mechanisms_check(GckObject * key,const gulong * mechanisms,gsize n_mechanisms,gulong action_attr_type,GCancellable * cancellable,GError ** error)81 _gcr_key_mechanisms_check (GckObject *key,
82 const gulong *mechanisms,
83 gsize n_mechanisms,
84 gulong action_attr_type,
85 GCancellable *cancellable,
86 GError **error)
87 {
88 gulong attr_types[] = { action_attr_type };
89 GckAttributes *attrs = NULL;
90 gulong result;
91
92 g_return_val_if_fail (GCK_IS_OBJECT (key), GCK_INVALID);
93 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), GCK_INVALID);
94 g_return_val_if_fail (error == NULL || *error == NULL, GCK_INVALID);
95
96 if (GCK_IS_OBJECT_CACHE (key)) {
97 attrs = gck_object_cache_get_attributes (GCK_OBJECT_CACHE (key));
98 if (!check_have_attributes (attrs, attr_types, G_N_ELEMENTS (attr_types))) {
99 gck_attributes_unref (attrs);
100 attrs = NULL;
101 }
102 }
103
104 if (attrs == NULL) {
105 attrs = gck_object_get_full (key, attr_types, G_N_ELEMENTS (attr_types),
106 cancellable, error);
107 }
108
109 if (!attrs)
110 return GCK_INVALID;
111
112 result = find_first_usable_mechanism (key, attrs, mechanisms, n_mechanisms, action_attr_type);
113 gck_attributes_unref (attrs);
114 return result;
115 }
116
117 typedef struct {
118 gulong *mechanisms;
119 gsize n_mechanisms;
120 gulong action_attr_type;
121 } CheckClosure;
122
123 static void
check_closure_free(gpointer data)124 check_closure_free (gpointer data)
125 {
126 CheckClosure *closure = data;
127 g_free (closure->mechanisms);
128 g_free (closure);
129 }
130
131 static void
on_check_get_attributes(GObject * source,GAsyncResult * result,gpointer user_data)132 on_check_get_attributes (GObject *source,
133 GAsyncResult *result,
134 gpointer user_data)
135 {
136 GTask *task = G_TASK (user_data);
137 GckAttributes *attrs;
138 GError *error = NULL;
139
140 attrs = gck_object_cache_lookup_finish (GCK_OBJECT (source), result, &error);
141 if (error != NULL)
142 g_task_return_error (task, g_steal_pointer (&error));
143 else
144 g_task_return_pointer (task, attrs, gck_attributes_unref);
145
146 g_clear_object (&task);
147 }
148
149 void
_gcr_key_mechanisms_check_async(GckObject * key,const gulong * mechanisms,gsize n_mechanisms,gulong action_attr_type,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)150 _gcr_key_mechanisms_check_async (GckObject *key,
151 const gulong *mechanisms,
152 gsize n_mechanisms,
153 gulong action_attr_type,
154 GCancellable *cancellable,
155 GAsyncReadyCallback callback,
156 gpointer user_data)
157 {
158 gulong attr_types[] = { action_attr_type };
159 CheckClosure *closure;
160 GTask *task;
161
162 g_return_if_fail (GCK_IS_OBJECT (key));
163 g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
164
165 task = g_task_new (key, cancellable, callback, user_data);
166 g_task_set_source_tag (task, _gcr_key_mechanisms_check_async);
167 closure = g_new0 (CheckClosure, 1);
168 closure->mechanisms = g_memdup (mechanisms, n_mechanisms * sizeof (gulong));
169 closure->n_mechanisms = n_mechanisms;
170 closure->action_attr_type = action_attr_type;
171 g_task_set_task_data (task, closure, check_closure_free);
172
173 gck_object_cache_lookup_async (key, attr_types, G_N_ELEMENTS (attr_types),
174 cancellable, on_check_get_attributes,
175 g_steal_pointer (&task));
176
177 g_clear_object (&task);
178 }
179
180 gulong
_gcr_key_mechanisms_check_finish(GckObject * key,GAsyncResult * result,GError ** error)181 _gcr_key_mechanisms_check_finish (GckObject *key,
182 GAsyncResult *result,
183 GError **error)
184 {
185 CheckClosure *closure;
186 GckAttributes *attrs;
187 gulong ret = GCK_INVALID;
188
189 g_return_val_if_fail (GCK_IS_OBJECT (key), GCK_INVALID);
190 g_return_val_if_fail (error == NULL || *error == NULL, GCK_INVALID);
191
192 g_return_val_if_fail (g_task_is_valid (result, key), GCK_INVALID);
193 g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) ==
194 _gcr_key_mechanisms_check_async, GCK_INVALID);
195
196 closure = g_task_get_task_data (G_TASK (result));
197
198 attrs = g_task_propagate_pointer (G_TASK (result), error);
199 if (!attrs)
200 return GCK_INVALID;
201
202 ret = find_first_usable_mechanism (GCK_OBJECT (key), attrs,
203 closure->mechanisms, closure->n_mechanisms,
204 closure->action_attr_type);
205
206 gck_attributes_unref (attrs);
207 return ret;
208 }
209