Branch data Line data Source code
1 : : /* libsecret - GLib wrapper for Secret Service
2 : : *
3 : : * Copyright 2011 Collabora Ltd.
4 : : *
5 : : * This program is free software: you can redistribute it and/or modify
6 : : * it under the terms of the GNU Lesser General Public License as published
7 : : * by the Free Software Foundation; either version 2.1 of the licence or (at
8 : : * your option) any later version.
9 : : *
10 : : * See the included COPYING file for more information.
11 : : *
12 : : * Author: Stef Walter <stefw@gnome.org>
13 : : */
14 : :
15 : : #include "config.h"
16 : :
17 : : #include "secret-private.h"
18 : : #include "secret-value.h"
19 : :
20 : : #include "egg/egg-secure-memory.h"
21 : :
22 : : #include <string.h>
23 : :
24 : : /**
25 : : * SecretValue:
26 : : *
27 : : * A value containing a secret
28 : : *
29 : : * A #SecretValue contains a password or other secret value.
30 : : *
31 : : * Use [method@Value.get] to get the actual secret data, such as a password.
32 : : * The secret data is not necessarily null-terminated, unless the content type
33 : : * is "text/plain".
34 : : *
35 : : * Each #SecretValue has a content type. For passwords, this is `text/plain`.
36 : : * Use [method@Value.get_content_type] to look at the content type.
37 : : *
38 : : * #SecretValue is reference counted and immutable. The secret data is only
39 : : * freed when all references have been released via [method@Value.unref].
40 : : *
41 : : * Stability: Stable
42 : : */
43 : :
44 : : static gboolean is_password_value (SecretValue *value);
45 : :
46 : 64 : EGG_SECURE_DECLARE (secret_value);
47 : :
48 : : struct _SecretValue {
49 : : gint refs;
50 : : gpointer secret;
51 : : gsize length;
52 : : GDestroyNotify destroy;
53 : : gchar *content_type;
54 : : };
55 : :
56 : : GType
57 : 28 : secret_value_get_type (void)
58 : : {
59 : : static gsize initialized = 0;
60 : : static GType type = 0;
61 : :
62 [ + + + - : 28 : if (g_once_init_enter (&initialized)) {
+ + ]
63 : 15 : type = g_boxed_type_register_static ("SecretValue",
64 : : (GBoxedCopyFunc)secret_value_ref,
65 : : (GBoxedFreeFunc)secret_value_unref);
66 : 15 : g_once_init_leave (&initialized, 1);
67 : : }
68 : :
69 : 28 : return type;
70 : : }
71 : :
72 : : /**
73 : : * secret_value_new:
74 : : * @secret: the secret data
75 : : * @length: the length of the data
76 : : * @content_type: the content type of the data
77 : : *
78 : : * Create a #SecretValue for the secret data passed in.
79 : : *
80 : : * The secret data is copied into non-pageable 'secure' memory.
81 : : *
82 : : * If the length is less than zero, then @secret is assumed to be
83 : : * null-terminated.
84 : : *
85 : : * Returns: (transfer full): the new #SecretValue
86 : : */
87 : : SecretValue *
88 : 62 : secret_value_new (const gchar *secret,
89 : : gssize length,
90 : : const gchar *content_type)
91 : : {
92 : : gchar *copy;
93 : :
94 [ + + - + ]: 62 : g_return_val_if_fail (length == 0 || secret != NULL, NULL);
95 [ - + ]: 62 : g_return_val_if_fail (content_type, NULL);
96 : :
97 [ + + ]: 62 : if (length < 0)
98 : 39 : length = strlen (secret);
99 : :
100 : 62 : copy = egg_secure_alloc (length + 1);
101 [ + + ]: 62 : if (secret)
102 : 61 : memcpy (copy, secret, length);
103 : 62 : copy[length] = 0;
104 : 62 : return secret_value_new_full (copy, length, content_type, egg_secure_free);
105 : : }
106 : :
107 : : /**
108 : : * secret_value_new_full:
109 : : * @secret: the secret data
110 : : * @length: the length of the data
111 : : * @content_type: the content type of the data
112 : : * @destroy: function to call to free the secret data
113 : : *
114 : : * Create a #SecretValue for the secret data passed in.
115 : : *
116 : : * The secret data is not copied, and will later be freed with the @destroy
117 : : * function.
118 : : *
119 : : * If the length is less than zero, then @secret is assumed to be
120 : : * null-terminated.
121 : : *
122 : : * Returns: (transfer full): the new #SecretValue
123 : : */
124 : : SecretValue *
125 : 110 : secret_value_new_full (gchar *secret,
126 : : gssize length,
127 : : const gchar *content_type,
128 : : GDestroyNotify destroy)
129 : : {
130 : : SecretValue *value;
131 : :
132 [ - + ]: 110 : g_return_val_if_fail (content_type, NULL);
133 : :
134 [ + + ]: 110 : if (length < 0)
135 : 5 : length = strlen (secret);
136 : :
137 : 110 : value = g_new0 (SecretValue, 1);
138 : 110 : value->refs = 1;
139 : 110 : value->content_type = g_strdup (content_type);
140 : 110 : value->destroy = destroy;
141 : 110 : value->length = length;
142 : 110 : value->secret = secret;
143 : :
144 : 110 : return value;
145 : : }
146 : :
147 : : /**
148 : : * secret_value_get:
149 : : * @value: the value
150 : : * @length: the length of the secret
151 : : *
152 : : * Get the secret data in the #SecretValue.
153 : : *
154 : : * The value is not necessarily null-terminated unless it was created with
155 : : * [ctor@Value.new] or a null-terminated string was passed to
156 : : * [ctor@Value.new_full].
157 : : *
158 : : * Returns: (array length=length) (element-type guint8): the secret data
159 : : */
160 : : const gchar *
161 : 95 : secret_value_get (SecretValue *value,
162 : : gsize *length)
163 : : {
164 [ - + ]: 95 : g_return_val_if_fail (value, NULL);
165 [ + + ]: 95 : if (length)
166 : 90 : *length = value->length;
167 : 95 : return value->secret;
168 : : }
169 : :
170 : : /**
171 : : * secret_value_get_text:
172 : : * @value: the value
173 : : *
174 : : * Get the secret data in the #SecretValue if it contains a textual
175 : : * value.
176 : : *
177 : : * The content type must be `text/plain`.
178 : : *
179 : : * Returns: (nullable): the content type
180 : : */
181 : : const gchar *
182 : 3 : secret_value_get_text (SecretValue *value)
183 : : {
184 [ - + ]: 3 : g_return_val_if_fail (value, NULL);
185 : :
186 [ - + ]: 3 : if (!is_password_value (value))
187 : 0 : return NULL;
188 : :
189 : 3 : return value->secret;
190 : : }
191 : :
192 : : /**
193 : : * secret_value_get_content_type:
194 : : * @value: the value
195 : : *
196 : : * Get the content type of the secret value, such as
197 : : * `text/plain`.
198 : : *
199 : : * Returns: the content type
200 : : */
201 : : const gchar *
202 : 25 : secret_value_get_content_type (SecretValue *value)
203 : : {
204 [ - + ]: 25 : g_return_val_if_fail (value, NULL);
205 : 25 : return value->content_type;
206 : : }
207 : :
208 : : /**
209 : : * secret_value_ref:
210 : : * @value: value to reference
211 : : *
212 : : * Add another reference to the #SecretValue.
213 : : *
214 : : * For each reference [method@Value.unref] should be called to unreference the
215 : : * value.
216 : : *
217 : : * Returns: (transfer full): the value
218 : : */
219 : : SecretValue *
220 : 118 : secret_value_ref (SecretValue *value)
221 : : {
222 [ - + ]: 118 : g_return_val_if_fail (value, NULL);
223 : 118 : g_atomic_int_inc (&value->refs);
224 : 118 : return value;
225 : : }
226 : :
227 : : /**
228 : : * secret_value_unref:
229 : : * @value: (type Secret.Value): value to unreference
230 : : *
231 : : * Unreference a #SecretValue.
232 : : *
233 : : * When the last reference is gone, then the value will be freed.
234 : : */
235 : : void
236 : 202 : secret_value_unref (gpointer value)
237 : : {
238 : 202 : SecretValue *val = value;
239 : :
240 [ - + ]: 202 : g_return_if_fail (value != NULL);
241 : :
242 [ + + ]: 202 : if (g_atomic_int_dec_and_test (&val->refs)) {
243 : 85 : g_free (val->content_type);
244 [ + - ]: 85 : if (val->destroy)
245 : 85 : (val->destroy) (val->secret);
246 : 85 : g_free (val);
247 : : }
248 : : }
249 : :
250 : : static gboolean
251 : 18 : is_password_value (SecretValue *value)
252 : : {
253 [ + - + + ]: 18 : if (value->content_type && g_str_equal (value->content_type, "text/plain"))
254 : 17 : return TRUE;
255 : :
256 : : /* gnome-keyring-daemon used to return passwords like this, so support this, but validate */
257 [ + - + - ]: 1 : if (!value->content_type || g_str_equal (value->content_type, "application/octet-stream"))
258 : 1 : return g_utf8_validate (value->secret, value->length, NULL);
259 : :
260 : 0 : return FALSE;
261 : : }
262 : :
263 : : /**
264 : : * secret_value_unref_to_password:
265 : : * @value: the value
266 : : * @length: (inout): the length of the secret
267 : : *
268 : : * Unreference a #SecretValue and steal the secret data in
269 : : * #SecretValue as nonpageable memory.
270 : : *
271 : : * Returns: (transfer full): a new password string stored in nonpageable memory
272 : : * which must be freed with [func@password_free] when done
273 : : *
274 : : * Since: 0.19.0
275 : : */
276 : : gchar *
277 : 8 : secret_value_unref_to_password (SecretValue *value,
278 : : gsize *length)
279 : : {
280 : 8 : SecretValue *val = value;
281 : : gchar *result;
282 : :
283 [ - + ]: 8 : g_return_val_if_fail (value != NULL, NULL);
284 : :
285 [ + + ]: 8 : if (g_atomic_int_dec_and_test (&val->refs)) {
286 [ + + ]: 7 : if (val->destroy == egg_secure_free) {
287 : 6 : result = val->secret;
288 [ - + ]: 6 : if (length)
289 : 0 : *length = val->length;
290 : :
291 : : } else {
292 : 1 : result = egg_secure_strndup (val->secret, val->length);
293 [ + - ]: 1 : if (val->destroy)
294 : 1 : (val->destroy) (val->secret);
295 [ - + ]: 1 : if (length)
296 : 0 : *length = val->length;
297 : : }
298 : 7 : g_free (val->content_type);
299 : 7 : g_free (val);
300 : :
301 : : } else {
302 : 1 : result = egg_secure_strndup (val->secret, val->length);
303 [ - + ]: 1 : if (length)
304 : 0 : *length = val->length;
305 : : }
306 : :
307 : 8 : return result;
308 : : }
309 : :
310 : : gchar *
311 : 9 : _secret_value_unref_to_password (SecretValue *value)
312 : : {
313 [ - + ]: 9 : g_return_val_if_fail (value != NULL, NULL);
314 : :
315 [ + + ]: 9 : if (!is_password_value (value)) {
316 : 1 : secret_value_unref (value);
317 : 1 : return NULL;
318 : : }
319 : :
320 : 8 : return secret_value_unref_to_password (value, NULL);
321 : : }
322 : :
323 : : gchar *
324 : 6 : _secret_value_unref_to_string (SecretValue *value)
325 : : {
326 : 6 : SecretValue *val = value;
327 : : gchar *result;
328 : :
329 [ - + ]: 6 : g_return_val_if_fail (value != NULL, NULL);
330 : :
331 [ - + ]: 6 : if (!is_password_value (value)) {
332 : 0 : secret_value_unref (value);
333 : 0 : return NULL;
334 : : }
335 : :
336 [ + - ]: 6 : if (g_atomic_int_dec_and_test (&val->refs)) {
337 [ - + ]: 6 : if (val->destroy == g_free) {
338 : 0 : result = val->secret;
339 : :
340 : : } else {
341 : 6 : result = g_strndup (val->secret, val->length);
342 [ + - ]: 6 : if (val->destroy)
343 : 6 : (val->destroy) (val->secret);
344 : : }
345 : 6 : g_free (val->content_type);
346 : 6 : g_free (val);
347 : :
348 : : } else {
349 : 0 : result = g_strndup (val->secret, val->length);
350 : : }
351 : :
352 : 6 : return result;
353 : : }
|