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