Added da to list of languages
[platform/upstream/libsecret.git] / libsecret / secret-value.c
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  * SECTION:secret-value
26  * @title: SecretValue
27  * @short_description: a value containing a secret
28  *
29  * A #SecretValue contains a password or other secret value.
30  *
31  * Use secret_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 secret_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 secret_value_unref().
40  *
41  * These functions have an unstable API and may change across versions. Use
42  * <literal>libsecret-unstable</literal> package to access them.
43  *
44  * Stability: Unstable
45  */
46
47 static gboolean     is_password_value    (SecretValue *value);
48
49 /**
50  * SecretValue:
51  *
52  * A secret value, like a password or other binary secret.
53  */
54
55 EGG_SECURE_DECLARE (secret_value);
56
57 struct _SecretValue {
58         gint refs;
59         gpointer secret;
60         gsize length;
61         GDestroyNotify destroy;
62         gchar *content_type;
63 };
64
65 GType
66 secret_value_get_type (void)
67 {
68         static gsize initialized = 0;
69         static GType type = 0;
70
71         if (g_once_init_enter (&initialized)) {
72                 type = g_boxed_type_register_static ("SecretValue",
73                                                      (GBoxedCopyFunc)secret_value_ref,
74                                                      (GBoxedFreeFunc)secret_value_unref);
75                 g_once_init_leave (&initialized, 1);
76         }
77
78         return type;
79 }
80
81 /**
82  * secret_value_new:
83  * @secret: the secret data
84  * @length: the length of the data
85  * @content_type: the content type of the data
86  *
87  * Create a #SecretValue for the secret data passed in. The secret data is
88  * copied into non-pageable 'secure' memory.
89  *
90  * If the length is less than zero, then @secret is assumed to be
91  * null-terminated.
92  *
93  * Returns: (transfer full): the new #SecretValue
94  */
95 SecretValue *
96 secret_value_new (const gchar *secret,
97                   gssize length,
98                   const gchar *content_type)
99 {
100         gchar *copy;
101
102         g_return_val_if_fail (length == 0 || secret != NULL, NULL);
103         g_return_val_if_fail (content_type, NULL);
104
105         if (length < 0)
106                 length = strlen (secret);
107
108         copy = egg_secure_alloc (length + 1);
109         if (secret)
110                 memcpy (copy, secret, length);
111         copy[length] = 0;
112         return secret_value_new_full (copy, length, content_type, egg_secure_free);
113 }
114
115 /**
116  * secret_value_new_full:
117  * @secret: the secret data
118  * @length: the length of the data
119  * @content_type: the content type of the data
120  * @destroy: function to call to free the secret data
121  *
122  * Create a #SecretValue for the secret data passed in. The secret data is
123  * not copied, and will later be freed with the @destroy function.
124  *
125  * If the length is less than zero, then @secret is assumed to be
126  * null-terminated.
127  *
128  * Returns: (transfer full): the new #SecretValue
129  */
130 SecretValue *
131 secret_value_new_full (gchar *secret,
132                        gssize length,
133                        const gchar *content_type,
134                        GDestroyNotify destroy)
135 {
136         SecretValue *value;
137
138         g_return_val_if_fail (content_type, NULL);
139
140         if (length < 0)
141                 length = strlen (secret);
142
143         value = g_slice_new0 (SecretValue);
144         value->refs = 1;
145         value->content_type = g_strdup (content_type);
146         value->destroy = destroy;
147         value->length = length;
148         value->secret = secret;
149
150         return value;
151 }
152
153 /**
154  * secret_value_get:
155  * @value: the value
156  * @length: the length of the secret
157  *
158  * Get the secret data in the #SecretValue. The value is not necessarily
159  * null-terminated unless it was created with secret_value_new() or a
160  * null-terminated string was passed to secret_value_new_full().
161  *
162  * Returns: (array length=length) (element-type guint8): the secret data
163  */
164 const gchar *
165 secret_value_get (SecretValue *value,
166                   gsize *length)
167 {
168         g_return_val_if_fail (value, NULL);
169         if (length)
170                 *length = value->length;
171         return value->secret;
172 }
173
174 /**
175  * secret_value_get_text:
176  * @value: the value
177  *
178  * Get the secret data in the #SecretValue if it contains a textual
179  * value. The content type must be <literal>text/plain</literal>.
180  *
181  * Returns: (allow-none): the content type
182  */
183 const gchar *
184 secret_value_get_text (SecretValue *value)
185 {
186         g_return_val_if_fail (value, NULL);
187
188         if (!is_password_value (value))
189                 return NULL;
190
191         return value->secret;
192 }
193
194 /**
195  * secret_value_get_content_type:
196  * @value: the value
197  *
198  * Get the content type of the secret value, such as
199  * <literal>text/plain</literal>.
200  *
201  * Returns: the content type
202  */
203 const gchar *
204 secret_value_get_content_type (SecretValue *value)
205 {
206         g_return_val_if_fail (value, NULL);
207         return value->content_type;
208 }
209
210 /**
211  * secret_value_ref:
212  * @value: value to reference
213  *
214  * Add another reference to the #SecretValue. For each reference
215  * secret_value_unref() should be called to unreference the value.
216  *
217  * Returns: (transfer full): the value
218  */
219 SecretValue *
220 secret_value_ref (SecretValue *value)
221 {
222         g_return_val_if_fail (value, NULL);
223         g_atomic_int_inc (&value->refs);
224         return value;
225 }
226
227 /**
228  * secret_value_unref:
229  * @value: (type SecretUnstable.Value) (allow-none): value to unreference
230  *
231  * Unreference a #SecretValue. When the last reference is gone, then
232  * the value will be freed.
233  */
234 void
235 secret_value_unref (gpointer value)
236 {
237         SecretValue *val = value;
238
239         g_return_if_fail (value != NULL);
240
241         if (g_atomic_int_dec_and_test (&val->refs)) {
242                 g_free (val->content_type);
243                 if (val->destroy)
244                         (val->destroy) (val->secret);
245                 g_slice_free (SecretValue, val);
246         }
247 }
248
249 static gboolean
250 is_password_value (SecretValue *value)
251 {
252         if (value->content_type && g_str_equal (value->content_type, "text/plain"))
253                 return TRUE;
254
255         /* gnome-keyring-daemon used to return passwords like this, so support this, but validate */
256         if (!value->content_type || g_str_equal (value->content_type, "application/octet-stream"))
257                 return g_utf8_validate (value->secret, value->length, NULL);
258
259         return FALSE;
260 }
261
262 gchar *
263 _secret_value_unref_to_password (SecretValue *value)
264 {
265         SecretValue *val = value;
266         gchar *result;
267
268         g_return_val_if_fail (value != NULL, NULL);
269
270         if (!is_password_value (value)) {
271                 secret_value_unref (value);
272                 return NULL;
273         }
274
275         if (g_atomic_int_dec_and_test (&val->refs)) {
276                 if (val->destroy == egg_secure_free) {
277                         result = val->secret;
278
279                 } else {
280                         result = egg_secure_strndup (val->secret, val->length);
281                         if (val->destroy)
282                                 (val->destroy) (val->secret);
283                 }
284                 g_free (val->content_type);
285                 g_slice_free (SecretValue, val);
286
287         } else {
288                 result = egg_secure_strndup (val->secret, val->length);
289         }
290
291         return result;
292 }
293
294 gchar *
295 _secret_value_unref_to_string (SecretValue *value)
296 {
297         SecretValue *val = value;
298         gchar *result;
299
300         g_return_val_if_fail (value != NULL, NULL);
301
302         if (!is_password_value (value)) {
303                 secret_value_unref (value);
304                 return NULL;
305         }
306
307         if (g_atomic_int_dec_and_test (&val->refs)) {
308                 if (val->destroy == g_free) {
309                         result = val->secret;
310
311                 } else {
312                         result = g_strndup (val->secret, val->length);
313                         if (val->destroy)
314                                 (val->destroy) (val->secret);
315                 }
316                 g_free (val->content_type);
317                 g_slice_free (SecretValue, val);
318
319         } else {
320                 result = g_strndup (val->secret, val->length);
321         }
322
323         return result;
324 }