1 /* GIO - GLib Input, Output and Streaming Library
2 *
3 * Copyright (C) 2011 Collabora, Ltd.
4 *
5 * SPDX-License-Identifier: LGPL-2.1-or-later
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General
18 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 *
20 * Author: Stef Walter <stefw@collabora.co.uk>
21 */
22
23 #include "config.h"
24 #include "glib.h"
25 #include "glibintl.h"
26
27 #include "gioenumtypes.h"
28 #include "gtlspassword.h"
29
30 #include <string.h>
31
32 /**
33 * GTlsPassword:
34 *
35 * An abstract interface representing a password used in TLS. Often used in
36 * user interaction such as unlocking a key storage token.
37 *
38 * Since: 2.30
39 */
40
41 enum
42 {
43 PROP_0,
44 PROP_FLAGS,
45 PROP_DESCRIPTION,
46 PROP_WARNING
47 };
48
49 struct _GTlsPasswordPrivate
50 {
51 guchar *value;
52 gsize length;
53 GDestroyNotify destroy;
54 GTlsPasswordFlags flags;
55 gchar *description;
56 gchar *warning;
57 };
58
59 G_DEFINE_TYPE_WITH_PRIVATE (GTlsPassword, g_tls_password, G_TYPE_OBJECT)
60
61 static void
62 g_tls_password_init (GTlsPassword *password)
63 {
64 password->priv = g_tls_password_get_instance_private (password);
65 }
66
67 static const guchar *
68 g_tls_password_real_get_value (GTlsPassword *password,
69 gsize *length)
70 {
71 if (length)
72 *length = password->priv->length;
73 return password->priv->value;
74 }
75
76 static void
77 g_tls_password_real_set_value (GTlsPassword *password,
78 guchar *value,
79 gssize length,
80 GDestroyNotify destroy)
81 {
82 if (password->priv->destroy)
83 (password->priv->destroy) (password->priv->value);
84 password->priv->destroy = NULL;
85 password->priv->value = NULL;
86 password->priv->length = 0;
87
88 if (length < 0)
89 length = strlen ((gchar*) value);
90
91 password->priv->value = value;
92 password->priv->length = length;
93 password->priv->destroy = destroy;
94 }
95
96 static const gchar*
97 g_tls_password_real_get_default_warning (GTlsPassword *password)
98 {
99 GTlsPasswordFlags flags;
100
101 flags = g_tls_password_get_flags (password);
102
103 if (flags & G_TLS_PASSWORD_FINAL_TRY)
104 return _("This is the last chance to enter the password correctly before your access is locked out.");
105 if (flags & G_TLS_PASSWORD_MANY_TRIES)
106 /* Translators: This is not the 'This is the last chance' string. It is
107 * displayed when more than one attempt is allowed. */
108 return _("Several passwords entered have been incorrect, and your access will be locked out after further failures.");
109 if (flags & G_TLS_PASSWORD_RETRY)
110 return _("The password entered is incorrect.");
111
112 return NULL;
113 }
114
115 static void
116 g_tls_password_get_property (GObject *object,
117 guint prop_id,
118 GValue *value,
119 GParamSpec *pspec)
120 {
121 GTlsPassword *password = G_TLS_PASSWORD (object);
122
123 switch (prop_id)
124 {
125 case PROP_FLAGS:
126 g_value_set_flags (value, g_tls_password_get_flags (password));
127 break;
128 case PROP_WARNING:
129 g_value_set_string (value, g_tls_password_get_warning (password));
130 break;
131 case PROP_DESCRIPTION:
132 g_value_set_string (value, g_tls_password_get_description (password));
133 break;
134 default:
135 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
136 break;
137 }
138 }
139
140 static void
141 g_tls_password_set_property (GObject *object,
142 guint prop_id,
143 const GValue *value,
144 GParamSpec *pspec)
145 {
146 GTlsPassword *password = G_TLS_PASSWORD (object);
147
148 switch (prop_id)
149 {
150 case PROP_FLAGS:
151 g_tls_password_set_flags (password, g_value_get_flags (value));
152 break;
153 case PROP_WARNING:
154 g_tls_password_set_warning (password, g_value_get_string (value));
155 break;
156 case PROP_DESCRIPTION:
157 g_tls_password_set_description (password, g_value_get_string (value));
158 break;
159 default:
160 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
161 break;
162 }
163 }
164
165 static void
166 g_tls_password_finalize (GObject *object)
167 {
168 GTlsPassword *password = G_TLS_PASSWORD (object);
169
170 g_tls_password_real_set_value (password, NULL, 0, NULL);
171 g_free (password->priv->warning);
172 g_free (password->priv->description);
173
174 G_OBJECT_CLASS (g_tls_password_parent_class)->finalize (object);
175 }
176
177 static void
178 g_tls_password_class_init (GTlsPasswordClass *klass)
179 {
180 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
181
182 klass->get_value = g_tls_password_real_get_value;
183 klass->set_value = g_tls_password_real_set_value;
184 klass->get_default_warning = g_tls_password_real_get_default_warning;
185
186 gobject_class->get_property = g_tls_password_get_property;
187 gobject_class->set_property = g_tls_password_set_property;
188 gobject_class->finalize = g_tls_password_finalize;
189
190 /**
191 * GTlsPassword:flags:
192 *
193 * Flags about the password.
194 *
195 * Since: 2.30
196 */
197 g_object_class_install_property (gobject_class, PROP_FLAGS,
198 g_param_spec_flags ("flags", NULL, NULL,
199 G_TYPE_TLS_PASSWORD_FLAGS,
200 G_TLS_PASSWORD_NONE,
201 G_PARAM_READWRITE |
202 G_PARAM_STATIC_STRINGS));
203
204 /**
205 * GTlsPassword:description:
206 *
207 * Description of what the password is for.
208 *
209 * Since: 2.30
210 */
211 g_object_class_install_property (gobject_class, PROP_DESCRIPTION,
212 g_param_spec_string ("description", NULL, NULL,
213 NULL,
214 G_PARAM_READWRITE |
215 G_PARAM_STATIC_STRINGS));
216
217 /**
218 * GTlsPassword:warning:
219 *
220 * Warning about the password.
221 *
222 * Since: 2.30
223 */
224 g_object_class_install_property (gobject_class, PROP_WARNING,
225 g_param_spec_string ("warning", NULL, NULL,
226 NULL,
227 G_PARAM_READWRITE |
228 G_PARAM_STATIC_STRINGS));
229
230 }
231
232 /**
233 * g_tls_password_new:
234 * @flags: the password flags
235 * @description: description of what the password is for
236 *
237 * Create a new #GTlsPassword object.
238 *
239 * Returns: (transfer full): The newly allocated password object
240 */
241 GTlsPassword *
242 g_tls_password_new (GTlsPasswordFlags flags,
243 const gchar *description)
244 {
245 return g_object_new (G_TYPE_TLS_PASSWORD,
246 "flags", flags,
247 "description", description,
248 NULL);
249 }
250
251 /**
252 * g_tls_password_get_value: (virtual get_value)
253 * @password: a #GTlsPassword object
254 * @length: (optional) (out caller-allocates): location to place the length of the password.
255 *
256 * Get the password value. If @length is not %NULL then it will be
257 * filled in with the length of the password value. (Note that the
258 * password value is not nul-terminated, so you can only pass %NULL
259 * for @length in contexts where you know the password will have a
260 * certain fixed length.)
261 *
262 * Returns: (array length=length): The password value (owned by the password object).
263 *
264 * Since: 2.30
265 */
266 const guchar *
267 g_tls_password_get_value (GTlsPassword *password,
268 gsize *length)
269 {
270 g_return_val_if_fail (G_IS_TLS_PASSWORD (password), NULL);
271 return G_TLS_PASSWORD_GET_CLASS (password)->get_value (password, length);
272 }
273
274 /**
275 * g_tls_password_set_value:
276 * @password: a #GTlsPassword object
277 * @value: (array length=length): the new password value
278 * @length: the length of the password, or -1
279 *
280 * Set the value for this password. The @value will be copied by the password
281 * object.
282 *
283 * Specify the @length, for a non-nul-terminated password. Pass -1 as
284 * @length if using a nul-terminated password, and @length will be
285 * calculated automatically. (Note that the terminating nul is not
286 * considered part of the password in this case.)
287 *
288 * Since: 2.30
289 */
290 void
291 g_tls_password_set_value (GTlsPassword *password,
292 const guchar *value,
293 gssize length)
294 {
295 g_return_if_fail (G_IS_TLS_PASSWORD (password));
296
297 if (length < 0)
298 {
299 /* FIXME: g_tls_password_set_value_full() doesn’t support unsigned gsize */
300 gsize length_unsigned = strlen ((gchar *) value);
301 g_return_if_fail (length_unsigned <= G_MAXSSIZE);
302 length = (gssize) length_unsigned;
303 }
304
305 g_tls_password_set_value_full (password, g_memdup2 (value, (gsize) length), length, g_free);
306 }
307
308 /**
309 * g_tls_password_set_value_full: (virtual set_value)
310 * @password: a #GTlsPassword object
311 * @value: (array length=length): the value for the password
312 * @length: the length of the password, or -1
313 * @destroy: (nullable): a function to use to free the password.
314 *
315 * Provide the value for this password.
316 *
317 * The @value will be owned by the password object, and later freed using
318 * the @destroy function callback.
319 *
320 * Specify the @length, for a non-nul-terminated password. Pass -1 as
321 * @length if using a nul-terminated password, and @length will be
322 * calculated automatically. (Note that the terminating nul is not
323 * considered part of the password in this case.)
324 *
325 * Since: 2.30
326 */
327 void
328 g_tls_password_set_value_full (GTlsPassword *password,
329 guchar *value,
330 gssize length,
331 GDestroyNotify destroy)
332 {
333 g_return_if_fail (G_IS_TLS_PASSWORD (password));
334 G_TLS_PASSWORD_GET_CLASS (password)->set_value (password, value,
335 length, destroy);
336 }
337
338 /**
339 * g_tls_password_get_flags:
340 * @password: a #GTlsPassword object
341 *
342 * Get flags about the password.
343 *
344 * Returns: The flags about the password.
345 *
346 * Since: 2.30
347 */
348 GTlsPasswordFlags
349 g_tls_password_get_flags (GTlsPassword *password)
350 {
351 g_return_val_if_fail (G_IS_TLS_PASSWORD (password), G_TLS_PASSWORD_NONE);
352 return password->priv->flags;
353 }
354
355 /**
356 * g_tls_password_set_flags:
357 * @password: a #GTlsPassword object
358 * @flags: The flags about the password
359 *
360 * Set flags about the password.
361 *
362 * Since: 2.30
363 */
364 void
365 g_tls_password_set_flags (GTlsPassword *password,
366 GTlsPasswordFlags flags)
367 {
368 g_return_if_fail (G_IS_TLS_PASSWORD (password));
369
370 password->priv->flags = flags;
371
372 g_object_notify (G_OBJECT (password), "flags");
373 }
374
375 /**
376 * g_tls_password_get_description:
377 * @password: a #GTlsPassword object
378 *
379 * Get a description string about what the password will be used for.
380 *
381 * Returns: The description of the password.
382 *
383 * Since: 2.30
384 */
385 const gchar*
386 g_tls_password_get_description (GTlsPassword *password)
387 {
388 g_return_val_if_fail (G_IS_TLS_PASSWORD (password), NULL);
389 return password->priv->description;
390 }
391
392 /**
393 * g_tls_password_set_description:
394 * @password: a #GTlsPassword object
395 * @description: The description of the password
396 *
397 * Set a description string about what the password will be used for.
398 *
399 * Since: 2.30
400 */
401 void
402 g_tls_password_set_description (GTlsPassword *password,
403 const gchar *description)
404 {
405 gchar *copy;
406
407 g_return_if_fail (G_IS_TLS_PASSWORD (password));
408
409 copy = g_strdup (description);
410 g_free (password->priv->description);
411 password->priv->description = copy;
412
413 g_object_notify (G_OBJECT (password), "description");
414 }
415
416 /**
417 * g_tls_password_get_warning:
418 * @password: a #GTlsPassword object
419 *
420 * Get a user readable translated warning. Usually this warning is a
421 * representation of the password flags returned from
422 * g_tls_password_get_flags().
423 *
424 * Returns: The warning.
425 *
426 * Since: 2.30
427 */
428 const gchar *
429 g_tls_password_get_warning (GTlsPassword *password)
430 {
431 g_return_val_if_fail (G_IS_TLS_PASSWORD (password), NULL);
432
433 if (password->priv->warning == NULL)
434 return G_TLS_PASSWORD_GET_CLASS (password)->get_default_warning (password);
435
436 return password->priv->warning;
437 }
438
439 /**
440 * g_tls_password_set_warning:
441 * @password: a #GTlsPassword object
442 * @warning: The user readable warning
443 *
444 * Set a user readable translated warning. Usually this warning is a
445 * representation of the password flags returned from
446 * g_tls_password_get_flags().
447 *
448 * Since: 2.30
449 */
450 void
451 g_tls_password_set_warning (GTlsPassword *password,
452 const gchar *warning)
453 {
454 gchar *copy;
455
456 g_return_if_fail (G_IS_TLS_PASSWORD (password));
457
458 copy = g_strdup (warning);
459 g_free (password->priv->warning);
460 password->priv->warning = copy;
461
462 g_object_notify (G_OBJECT (password), "warning");
463 }