ac8fe5032a5c9371b717e14154c2b7241f33bc51
[claws.git] / src / password.c
1 /*
2  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 2016 The Claws Mail Team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program 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
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #include "claws-features.h"
23 #endif
24
25 #ifdef PASSWORD_CRYPTO_GNUTLS
26 # include <gnutls/gnutls.h>
27 # include <gnutls/crypto.h>
28 #endif
29
30 #include <glib.h>
31 #include <glib/gi18n.h>
32
33 #if defined G_OS_UNIX
34 #include <fcntl.h>
35 #include <unistd.h>
36 #elif defined G_OS_WIN32
37 #include <windows.h>
38 #include <wincrypt.h>
39 #endif
40
41 #include "common/passcrypt.h"
42 #include "common/plugin.h"
43 #include "common/pkcs5_pbkdf2.h"
44 #include "common/utils.h"
45 #include "account.h"
46 #include "alertpanel.h"
47 #include "inputdialog.h"
48 #include "password.h"
49 #include "passwordstore.h"
50 #include "prefs_common.h"
51
52 #ifndef PASSWORD_CRYPTO_OLD
53 static gchar *_master_passphrase = NULL;
54
55 /* Length of stored key derivation, before base64. */
56 #define KD_LENGTH 64
57
58 /* Length of randomly generated and saved salt, used for key derivation.
59  * Also before base64. */
60 #define KD_SALT_LENGTH 64
61
62 static void _generate_salt()
63 {
64 #if defined G_OS_UNIX
65         int rnd;
66 #elif defined G_OS_WIN32
67         HCRYPTPROV rnd;
68 #endif
69         gint ret;
70         guchar salt[KD_SALT_LENGTH];
71
72         if (prefs_common_get_prefs()->master_passphrase_salt != NULL) {
73                 g_free(prefs_common_get_prefs()->master_passphrase_salt);
74         }
75
76         /* Prepare our source of random data. */
77 #if defined G_OS_UNIX
78         rnd = open("/dev/urandom", O_RDONLY);
79         if (rnd == -1) {
80                 perror("fopen on /dev/urandom");
81 #elif defined G_OS_WIN32
82         if (!CryptAcquireContext(&rnd, NULL, NULL, PROV_RSA_FULL, 0) &&
83                         !CryptAcquireContext(&rnd, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) {
84                 debug_print("Could not acquire a CSP handle.\n");
85 #endif
86                 return;
87         }
88
89 #if defined G_OS_UNIX
90         ret = read(rnd, salt, KD_SALT_LENGTH);
91         if (ret != KD_SALT_LENGTH) {
92                 perror("read into salt");
93                 close(rnd);
94 #elif defined G_OS_WIN32
95         if (!CryptGenRandom(rnd, KD_SALT_LENGTH, salt)) {
96                 debug_print("Could not read random data for salt\n");
97                 CryptReleaseContext(rnd, 0);
98 #endif
99                 return;
100         }
101
102         prefs_common_get_prefs()->master_passphrase_salt =
103                 g_base64_encode(salt, KD_SALT_LENGTH);
104 }
105
106 #undef KD_SALT_LENGTH
107
108 static guchar *_make_key_deriv(const gchar *passphrase, guint rounds)
109 {
110         guchar *kd, *salt;
111         gchar *saltpref = prefs_common_get_prefs()->master_passphrase_salt;
112         gsize saltlen;
113         gint ret;
114
115         /* Grab our salt, generating and saving a new random one if needed. */
116         if (saltpref == NULL || strlen(saltpref) == 0) {
117                 _generate_salt();
118                 saltpref = prefs_common_get_prefs()->master_passphrase_salt;
119         }
120         salt = g_base64_decode(saltpref, &saltlen);
121         kd = g_malloc0(KD_LENGTH);
122
123         ret = pkcs5_pbkdf2(passphrase, strlen(passphrase), salt, saltlen,
124                         kd, KD_LENGTH, rounds);
125
126         g_free(salt);
127
128         if (ret == 0) {
129                 return kd;
130         }
131
132         g_free(kd);
133         return NULL;
134 }
135
136 static const gchar *master_passphrase()
137 {
138         gchar *input;
139         gboolean end = FALSE;
140
141         if (!prefs_common_get_prefs()->use_master_passphrase) {
142                 return PASSCRYPT_KEY;
143         }
144
145         if (_master_passphrase != NULL) {
146                 debug_print("Master passphrase is in memory, offering it.\n");
147                 return _master_passphrase;
148         }
149
150         while (!end) {
151                 input = input_dialog_with_invisible(_("Input master passphrase"),
152                                 _("Input master passphrase"), NULL);
153
154                 if (input == NULL) {
155                         debug_print("Cancel pressed at master passphrase dialog.\n");
156                         break;
157                 }
158
159                 if (master_passphrase_is_correct(input)) {
160                         debug_print("Entered master passphrase seems to be correct, remembering it.\n");
161                         _master_passphrase = input;
162                         end = TRUE;
163                 } else {
164                         alertpanel_error(_("Incorrect master passphrase."));
165                 }
166         }
167
168         return _master_passphrase;
169 }
170
171 const gboolean master_passphrase_is_set()
172 {
173         if (prefs_common_get_prefs()->master_passphrase == NULL
174                         || strlen(prefs_common_get_prefs()->master_passphrase) == 0)
175                 return FALSE;
176
177         return TRUE;
178 }
179
180 const gboolean master_passphrase_is_correct(const gchar *input)
181 {
182         guchar *kd, *input_kd;
183         gchar **tokens;
184         gchar *stored_kd = prefs_common_get_prefs()->master_passphrase;
185         gsize kd_len;
186         guint rounds = 0;
187         gint ret;
188
189         g_return_val_if_fail(stored_kd != NULL && strlen(stored_kd) > 0, FALSE);
190         g_return_val_if_fail(input != NULL, FALSE);
191
192         if (stored_kd == NULL)
193                 return FALSE;
194
195         tokens = g_strsplit_set(stored_kd, "{}", 3);
196         if (tokens[0] == NULL ||
197                         strlen(tokens[0]) != 0 || /* nothing before { */
198                         tokens[1] == NULL ||
199                         strncmp(tokens[1], "PBKDF2-HMAC-SHA1,", 17) || /* correct tag */
200                         strlen(tokens[1]) <= 17 || /* something after , */
201                         (rounds = atoi(tokens[1] + 17)) <= 0 || /* valid rounds # */
202                         tokens[2] == NULL ||
203                         strlen(tokens[2]) == 0) { /* string continues after } */
204                 debug_print("Mangled master_passphrase format in config, can not use it.\n");
205                 g_strfreev(tokens);
206                 return FALSE;
207         }
208
209         stored_kd = tokens[2];
210         kd = g_base64_decode(stored_kd, &kd_len); /* should be 64 */
211         g_strfreev(tokens);
212
213         if (kd_len != KD_LENGTH) {
214                 debug_print("master_passphrase is %ld bytes long, should be %d.\n",
215                                 kd_len, KD_LENGTH);
216                 g_free(kd);
217                 return FALSE;
218         }
219
220         input_kd = _make_key_deriv(input, rounds);
221         ret = memcmp(kd, input_kd, kd_len);
222
223         g_free(input_kd);
224         g_free(kd);
225
226         if (ret == 0)
227                 return TRUE;
228
229         return FALSE;
230 }
231
232 gboolean master_passphrase_is_entered()
233 {
234         return (_master_passphrase == NULL) ? FALSE : TRUE;
235 }
236
237 void master_passphrase_forget()
238 {
239         /* If master passphrase is currently in memory (entered by user),
240          * get rid of it. User will have to enter the new one again. */
241         if (_master_passphrase != NULL) {
242                 memset(_master_passphrase, 0, strlen(_master_passphrase));
243                 g_free(_master_passphrase);
244                 _master_passphrase = NULL;
245         }
246 }
247
248 void master_passphrase_change(const gchar *oldp, const gchar *newp)
249 {
250         guchar *kd;
251         gchar *base64_kd;
252         guint rounds = prefs_common_get_prefs()->master_passphrase_pbkdf2_rounds;
253
254         g_return_if_fail(rounds > 0);
255
256         if (oldp == NULL) {
257                 /* If oldp is NULL, make sure the user has to enter the
258                  * current master passphrase before being able to change it. */
259                 master_passphrase_forget();
260                 oldp = master_passphrase();
261         }
262         g_return_if_fail(oldp != NULL);
263
264         /* Update master passphrase hash in prefs */
265         if (prefs_common_get_prefs()->master_passphrase != NULL)
266                 g_free(prefs_common_get_prefs()->master_passphrase);
267
268         if (newp != NULL) {
269                 debug_print("Storing key derivation of new master passphrase\n");
270                 kd = _make_key_deriv(newp, rounds);
271                 base64_kd = g_base64_encode(kd, 64);
272                 prefs_common_get_prefs()->master_passphrase =
273                         g_strdup_printf("{PBKDF2-HMAC-SHA1,%d}%s", rounds, base64_kd);
274                 g_free(kd);
275                 g_free(base64_kd);
276         } else {
277                 debug_print("Setting master_passphrase to NULL\n");
278                 prefs_common_get_prefs()->master_passphrase = NULL;
279         }
280
281         /* Now go over all accounts, reencrypting their passwords using
282          * the new master passphrase. */
283
284         if (oldp == NULL)
285                 oldp = PASSCRYPT_KEY;
286         if (newp == NULL)
287                 newp = PASSCRYPT_KEY;
288
289         debug_print("Reencrypting all account passwords...\n");
290         passwd_store_reencrypt_all(oldp, newp);
291
292         /* Now reencrypt all plugins passwords fields 
293          * FIXME: Unloaded plugins won't be able to update their stored passwords
294          */
295         plugins_master_passphrase_change(oldp, newp);
296
297         master_passphrase_forget();
298 }
299 #endif
300
301 gchar *password_encrypt_old(const gchar *password)
302 {
303         if (!password || strlen(password) == 0) {
304                 return NULL;
305         }
306
307         gchar *encrypted = g_strdup(password);
308         gchar *encoded, *result;
309         gsize len = strlen(password);
310
311         passcrypt_encrypt(encrypted, len);
312         encoded = g_base64_encode(encrypted, len);
313         g_free(encrypted);
314         result = g_strconcat("!", encoded, NULL);
315         g_free(encoded);
316
317         return result;
318 }
319
320 gchar *password_decrypt_old(const gchar *password)
321 {
322         if (!password || strlen(password) == 0) {
323                 return NULL;
324         }
325
326         if (*password != '!' || strlen(password) < 2) {
327                 return NULL;
328         }
329
330         gsize len;
331         gchar *decrypted = g_base64_decode(password + 1, &len);
332
333         passcrypt_decrypt(decrypted, len);
334         return decrypted;
335 }
336
337 #ifdef PASSWORD_CRYPTO_GNUTLS
338 #define BUFSIZE 128
339
340 /* Since we can't count on having GnuTLS new enough to have
341  * gnutls_cipher_get_iv_size(), we hardcode the IV length for now. */
342 #define IVLEN 16
343
344 gchar *password_encrypt_gnutls(const gchar *password,
345                 const gchar *encryption_passphrase)
346 {
347         /* Another, slightly inferior combination is AES-128-CBC + SHA-256.
348          * Any block cipher in CBC mode with keysize N and a hash algo with
349          * digest length 2*N would do. */
350         gnutls_cipher_algorithm_t algo = GNUTLS_CIPHER_AES_256_CBC;
351         gnutls_digest_algorithm_t digest = GNUTLS_DIG_SHA512;
352         gnutls_cipher_hd_t handle;
353         gnutls_datum_t key, iv;
354         int keylen, digestlen, blocklen, ret, i;
355         unsigned char hashbuf[BUFSIZE], *buf, *encbuf, *base, *output;
356 #if defined G_OS_UNIX
357         int rnd;
358 #elif defined G_OS_WIN32
359         HCRYPTPROV rnd;
360 #endif
361
362         g_return_val_if_fail(password != NULL, NULL);
363         g_return_val_if_fail(encryption_passphrase != NULL, NULL);
364
365 /*      ivlen = gnutls_cipher_get_iv_size(algo);*/
366         keylen = gnutls_cipher_get_key_size(algo);
367         blocklen = gnutls_cipher_get_block_size(algo);
368         digestlen = gnutls_hash_get_len(digest);
369
370         /* Prepare key for cipher - first half of hash of passkey XORed with
371          * the second. */
372         memset(&hashbuf, 0, BUFSIZE);
373         if ((ret = gnutls_hash_fast(digest, encryption_passphrase,
374                                         strlen(encryption_passphrase), &hashbuf)) < 0) {
375                 debug_print("Hashing passkey failed: %s\n", gnutls_strerror(ret));
376                 return NULL;
377         }
378         for (i = 0; i < digestlen/2; i++) {
379                 hashbuf[i] = hashbuf[i] ^ hashbuf[i+digestlen/2];
380         }
381
382         key.data = malloc(keylen);
383         memcpy(key.data, &hashbuf, keylen);
384         key.size = keylen;
385
386         /* Prepare our source of random data. */
387 #if defined G_OS_UNIX
388         rnd = open("/dev/urandom", O_RDONLY);
389         if (rnd == -1) {
390                 perror("fopen on /dev/urandom");
391 #elif defined G_OS_WIN32
392         if (!CryptAcquireContext(&rnd, NULL, NULL, PROV_RSA_FULL, 0) &&
393                         !CryptAcquireContext(&rnd, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) {
394                 debug_print("Could not acquire a CSP handle.\n");
395 #endif
396                 g_free(key.data);
397                 return NULL;
398         }
399
400         /* Prepare random IV for cipher */
401         iv.data = malloc(IVLEN);
402         iv.size = IVLEN;
403 #if defined G_OS_UNIX
404         ret = read(rnd, iv.data, IVLEN);
405         if (ret != IVLEN) {
406                 perror("read into iv");
407                 close(rnd);
408 #elif defined G_OS_WIN32
409         if (!CryptGenRandom(rnd, IVLEN, iv.data)) {
410                 debug_print("Could not read random data for IV\n");
411                 CryptReleaseContext(rnd, 0);
412 #endif
413                 g_free(key.data);
414                 g_free(iv.data);
415                 return NULL;
416         }
417
418         /* Initialize the encryption */
419         ret = gnutls_cipher_init(&handle, algo, &key, &iv);
420         if (ret < 0) {
421                 g_free(key.data);
422                 g_free(iv.data);
423 #if defined G_OS_UNIX
424                 close(rnd);
425 #elif defined G_OS_WIN32
426                 CryptReleaseContext(rnd, 0);
427 #endif
428                 return NULL;
429         }
430
431         /* Fill buf with one block of random data, our password, pad the
432          * rest with zero bytes. */
433         buf = malloc(BUFSIZE + blocklen);
434         memset(buf, 0, BUFSIZE);
435 #if defined G_OS_UNIX
436         ret = read(rnd, buf, blocklen);
437         if (ret != blocklen) {
438                 perror("read into buffer");
439                 close(rnd);
440 #elif defined G_OS_WIN32
441         if (!CryptGenRandom(rnd, blocklen, buf)) {
442                 debug_print("Could not read random data for IV\n");
443                 CryptReleaseContext(rnd, 0);
444 #endif
445                 g_free(buf);
446                 g_free(key.data);
447                 g_free(iv.data);
448                 gnutls_cipher_deinit(handle);
449                 return NULL;
450         }
451
452         /* We don't need any more random data. */
453 #if defined G_OS_UNIX
454         close(rnd);
455 #elif defined G_OS_WIN32
456         CryptReleaseContext(rnd, 0);
457 #endif
458
459         memcpy(buf + blocklen, password, strlen(password));
460
461         /* Encrypt into encbuf */
462         encbuf = malloc(BUFSIZE + blocklen);
463         memset(encbuf, 0, BUFSIZE + blocklen);
464         ret = gnutls_cipher_encrypt2(handle, buf, BUFSIZE + blocklen,
465                         encbuf, BUFSIZE + blocklen);
466         if (ret < 0) {
467                 g_free(key.data);
468                 g_free(iv.data);
469                 g_free(buf);
470                 g_free(encbuf);
471                 gnutls_cipher_deinit(handle);
472                 return NULL;
473         }
474
475         /* Cleanup */
476         gnutls_cipher_deinit(handle);
477         g_free(key.data);
478         g_free(iv.data);
479         g_free(buf);
480
481         /* And finally prepare the resulting string:
482          * "{algorithm}base64encodedciphertext" */
483         base = g_base64_encode(encbuf, BUFSIZE);
484         g_free(encbuf);
485         output = g_strdup_printf("{%s}%s", gnutls_cipher_get_name(algo), base);
486         g_free(base);
487
488         return output;
489 }
490
491 gchar *password_decrypt_gnutls(const gchar *password,
492                 const gchar *decryption_passphrase)
493 {
494         gchar **tokens, *tmp;
495         gnutls_cipher_algorithm_t algo;
496         gnutls_digest_algorithm_t digest = GNUTLS_DIG_UNKNOWN;
497         gnutls_cipher_hd_t handle;
498         gnutls_datum_t key, iv;
499         int keylen, digestlen, blocklen, ret, i;
500         gsize len;
501         unsigned char hashbuf[BUFSIZE], *buf;
502 #if defined G_OS_UNIX
503         int rnd;
504 #elif defined G_OS_WIN32
505         HCRYPTPROV rnd;
506 #endif
507
508         g_return_val_if_fail(password != NULL, NULL);
509         g_return_val_if_fail(decryption_passphrase != NULL, NULL);
510
511         tokens = g_strsplit_set(password, "{}", 3);
512
513         /* Parse the string, retrieving algorithm and encrypted data.
514          * We expect "{algorithm}base64encodedciphertext". */
515         if (strlen(tokens[0]) != 0 ||
516                         (algo = gnutls_cipher_get_id(tokens[1])) == GNUTLS_CIPHER_UNKNOWN ||
517                         strlen(tokens[2]) == 0)
518                 return NULL;
519
520         /* Our hash algo needs to have digest length twice as long as our
521          * cipher algo's key length. */
522         if (algo == GNUTLS_CIPHER_AES_256_CBC) {
523                 debug_print("Using AES-256-CBC + SHA-512 for decryption\n");
524                 digest = GNUTLS_DIG_SHA512;
525         } else if (algo == GNUTLS_CIPHER_AES_128_CBC) {
526                 debug_print("Using AES-128-CBC + SHA-256 for decryption\n");
527                 digest = GNUTLS_DIG_SHA256;
528         }
529         if (digest == GNUTLS_DIG_UNKNOWN) {
530                 debug_print("Password is encrypted with unsupported cipher, giving up.\n");
531                 g_strfreev(tokens);
532                 return NULL;
533         }
534
535 /*      ivlen = gnutls_cipher_get_iv_size(algo); */
536         keylen = gnutls_cipher_get_key_size(algo);
537         blocklen = gnutls_cipher_get_block_size(algo);
538         digestlen = gnutls_hash_get_len(digest);
539
540         /* Prepare key for cipher - first half of hash of passkey XORed with
541          * the second. AES-256 has key length 32 and length of SHA-512 hash
542          * is exactly twice that, 64. */
543         memset(&hashbuf, 0, BUFSIZE);
544         if ((ret = gnutls_hash_fast(digest, decryption_passphrase,
545                                         strlen(decryption_passphrase), &hashbuf)) < 0) {
546                 debug_print("Hashing passkey failed: %s\n", gnutls_strerror(ret));
547                 g_strfreev(tokens);
548                 return NULL;
549         }
550         for (i = 0; i < digestlen/2; i++) {
551                 hashbuf[i] = hashbuf[i] ^ hashbuf[i+digestlen/2];
552         }
553
554         key.data = malloc(keylen);
555         memcpy(key.data, &hashbuf, keylen);
556         key.size = keylen;
557
558         /* Prepare our source of random data. */
559 #if defined G_OS_UNIX
560         rnd = open("/dev/urandom", O_RDONLY);
561         if (rnd == -1) {
562                 perror("fopen on /dev/urandom");
563 #elif defined G_OS_WIN32
564         if (!CryptAcquireContext(&rnd, NULL, NULL, PROV_RSA_FULL, 0) &&
565                         !CryptAcquireContext(&rnd, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) {
566                 debug_print("Could not acquire a CSP handle.\n");
567 #endif
568                 g_free(key.data);
569                 g_strfreev(tokens);
570                 return NULL;
571         }
572
573         /* Prepare random IV for cipher */
574         iv.data = malloc(IVLEN);
575         iv.size = IVLEN;
576 #if defined G_OS_UNIX
577         ret = read(rnd, iv.data, IVLEN);
578         if (ret != IVLEN) {
579                 perror("read into iv");
580                 close(rnd);
581 #elif defined G_OS_WIN32
582         if (!CryptGenRandom(rnd, IVLEN, iv.data)) {
583                 debug_print("Could not read random data for IV\n");
584                 CryptReleaseContext(rnd, 0);
585 #endif
586                 g_free(key.data);
587                 g_free(iv.data);
588                 g_strfreev(tokens);
589                 return NULL;
590         }
591
592         /* We don't need any more random data. */
593 #if defined G_OS_UNIX
594         close(rnd);
595 #elif defined G_OS_WIN32
596         CryptReleaseContext(rnd, 0);
597 #endif
598
599         /* Prepare encrypted password string for decryption. */
600         tmp = g_base64_decode(tokens[2], &len);
601         g_strfreev(tokens);
602
603         /* Initialize the decryption */
604         ret = gnutls_cipher_init(&handle, algo, &key, &iv);
605         if (ret < 0) {
606                 debug_print("Cipher init failed: %s\n", gnutls_strerror(ret));
607                 g_free(key.data);
608                 g_free(iv.data);
609                 return NULL;
610         }
611
612         buf = malloc(BUFSIZE + blocklen);
613         memset(buf, 0, BUFSIZE + blocklen);
614         ret = gnutls_cipher_decrypt2(handle, tmp, len,
615                         buf, BUFSIZE + blocklen);
616         if (ret < 0) {
617                 debug_print("Decryption failed: %s\n", gnutls_strerror(ret));
618                 g_free(key.data);
619                 g_free(iv.data);
620                 g_free(buf);
621                 gnutls_cipher_deinit(handle);
622                 return NULL;
623         }
624
625         /* Cleanup */
626         gnutls_cipher_deinit(handle);
627         g_free(key.data);
628         g_free(iv.data);
629
630         tmp = g_strndup(buf + blocklen, MIN(strlen(buf + blocklen), BUFSIZE));
631         g_free(buf);
632         return tmp;
633 }
634
635 #undef BUFSIZE
636
637 #endif
638
639 gchar *password_encrypt(const gchar *password,
640                 const gchar *encryption_passphrase)
641 {
642         if (password == NULL || strlen(password) == 0) {
643                 return NULL;
644         }
645
646 #ifndef PASSWORD_CRYPTO_OLD
647         if (encryption_passphrase == NULL)
648                 encryption_passphrase = master_passphrase();
649
650         return password_encrypt_real(password, encryption_passphrase);
651 #else
652         return password_encrypt_old(password);
653 #endif
654 }
655
656 gchar *password_decrypt(const gchar *password,
657                 const gchar *decryption_passphrase)
658 {
659         if (password == NULL || strlen(password) == 0) {
660                 return NULL;
661         }
662
663         /* First, check if the password was possibly decrypted using old,
664          * obsolete method */
665         if (*password == '!') {
666                 debug_print("Trying to decrypt password using the old method...\n");
667                 return password_decrypt_old(password);
668         }
669
670         /* Try available crypto backend */
671 #ifndef PASSWORD_CRYPTO_OLD
672         if (decryption_passphrase == NULL)
673                 decryption_passphrase = master_passphrase();
674
675         if (*password == '{') {
676                 debug_print("Trying to decrypt password...\n");
677                 return password_decrypt_real(password, decryption_passphrase);
678         }
679 #endif
680
681         /* Fallback, in case the configuration is really old and
682          * stored password in plaintext */
683         debug_print("Assuming password was stored plaintext, returning it unchanged\n");
684         return g_strdup(password);
685 }