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