1
/* FIGARO'S PASSWORD MANAGER (FPM)
2
* Copyright (C) 2000 John Conneely
4
* FPM is open source / free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
9
* FPM is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18
* passfile.c -- Routines to save and load XML files with FPM data.
22
#include <libxml/parser.h>
23
#include <libxml/tree.h>
28
#include "fpm_crypt.h"
32
/* Variables for parsing tokens out of a string. */
33
static char *_s_token;
34
static char *_c_token_pos;
35
static int _token_end;
41
/* This routine goes through the entire password list and will decrypt the
42
* passwords with an old key and encrypt it again with a new key. This is
43
* needed in two situations: First, if the user changes a password. Secondly,
44
* (and much more common) if the salt changes. In practice, this routine gets
45
* called whenever we save a file.
50
gchar plaintext[FPM_PASSWORD_LEN+1] = {0};
56
// printf("XXX passfile_update_key being called\n");
57
if (old_context!=new_context)
59
// printf("XXX run through the list\n");
60
list=g_list_first(glb_pass_list);
64
ix = strlen(data->password) / 2;
65
fpm_decrypt_field(old_context, plaintext,
67
// printf("XXX passwd = %s\n", plaintext);
68
fpm_encrypt_field(new_context, data->password,
69
plaintext, FPM_PASSWORD_LEN);
70
list = g_list_next(list);
73
memset(plaintext, 0, FPM_PASSWORD_LEN);
74
bcopy(new_context, old_context , blowfish_contextsize());
77
// printf("XXX passfile_update_key exit\n");
81
move_backup(gchar* file_name)
82
/* In case of bugs, etc. I want to save old password files. If you would
83
* like to prevent this, you can set FPM_BACKUP_NUM to 0. This is
84
* HIGHLY UNRECOMMENDED while we are in beta!
92
for(i=glb_fpm_ini->number_backup_files;i>0;i--)
94
g_snprintf(file2, 512, "%s.%02d", file_name, i);
96
g_snprintf(file1, 512, "%s.%02d", file_name, i-1);
98
g_snprintf(file1, 512, "%s", file_name);
100
rename(file1, file2);
106
passfile_upd_attr(xmlNodePtr node, char *cond, char** data_ptr)
109
if (!strcmp((char *)node->name, cond))
112
if(node->xmlChildrenNode != NULL)
113
*data_ptr=g_strdup((char *)node->xmlChildrenNode->content);
115
*data_ptr=g_strdup("");
119
static void new_leaf(xmlDocPtr doc, xmlNodePtr item, const xmlChar *name, xmlChar *text)
123
tmp = xmlEncodeEntitiesReentrant(doc, text);
124
xmlNewChild(item, NULL, name, tmp);
128
static void new_leaf_encrypt
129
(xmlDocPtr doc, xmlNodePtr item, const xmlChar *name, char *text)
132
// printf("XXX calling new_leaf_encrypt: %s\n", text);
133
cipher_text=fpm_encrypt_field_var(new_context, text);
134
new_leaf(doc, item, name, (xmlChar *)cipher_text);
139
passfile_save(gchar* file_name)
142
xmlNodePtr nodelist, item;
144
fpm_launcher* launcher;
146
gchar* vstring_cipher;
147
gchar* vstring_plain;
154
if (glb_fpm_ini->create_backup)
155
move_backup(file_name);
156
passfile_update_key();
158
vstring_cipher=g_malloc0(17);
159
vstring_plain=g_malloc0(9);
161
doc = xmlNewDoc((xmlChar *)"1.0");
162
doc->xmlRootNode = xmlNewDocNode(doc, NULL, (xmlChar *)"FPM", NULL);
163
xmlSetProp(doc->xmlRootNode, (xmlChar *)"full_version", (xmlChar *)FULL_VERSION);
164
xmlSetProp(doc->xmlRootNode, (xmlChar *)"min_version", (xmlChar *)MIN_VERSION);
165
xmlSetProp(doc->xmlRootNode, (xmlChar *)"display_version", (xmlChar *)DISPLAY_VERSION);
166
item = xmlNewChild(doc->xmlRootNode, NULL, (xmlChar *)"KeyInfo", NULL);
167
xmlSetProp(item, (xmlChar *)"salt", (xmlChar *)new_salt);
168
strncpy(vstring_plain, "FIGARO", 8);
169
fpm_encrypt_field(new_context, vstring_cipher, vstring_plain, 8);
170
xmlSetProp(item, (xmlChar *)"vstring", (xmlChar *)vstring_cipher);
172
fpm_decrypt_field(new_context, vstring_plain, vstring_cipher, 8);
174
nodelist = xmlNewChild(doc->xmlRootNode, NULL, (xmlChar *)"LauncherList", NULL);
175
list = g_list_first(glb_launcher_list);
180
item=xmlNewChild(nodelist, NULL, (xmlChar *)"LauncerItem", NULL);
181
new_leaf(doc, item, (xmlChar *)"title", (xmlChar *)launcher->title);
182
new_leaf(doc, item, (xmlChar *)"cmdline", (xmlChar *)launcher->cmdline);
183
tmp=g_strdup_printf("%d", launcher->copy_user);
184
new_leaf(doc, item, (xmlChar *)"copy_user", (xmlChar *)tmp);
186
tmp=g_strdup_printf("%d", launcher->copy_password);
187
new_leaf(doc, item, (xmlChar *)"copy_password", (xmlChar *)tmp);
190
list=g_list_next(list);
193
nodelist = xmlNewChild(doc->xmlRootNode, NULL, (xmlChar *)"PasswordList", NULL);
194
list = g_list_first(glb_pass_list);
199
item = xmlNewChild(nodelist, NULL, (xmlChar *)"PasswordItem", NULL);
200
new_leaf_encrypt(doc, item, (xmlChar *)"title", data->title);
201
new_leaf_encrypt(doc, item, (xmlChar *)"user", data->user);
202
new_leaf_encrypt(doc, item, (xmlChar *)"url", data->arg);
203
new_leaf(doc, item, (xmlChar *)"password", (xmlChar *)data->password);
204
new_leaf_encrypt(doc, item, (xmlChar *)"notes", data->notes);
205
new_leaf_encrypt(doc, item, (xmlChar *)"category", data->category);
206
new_leaf_encrypt(doc, item, (xmlChar *)"launcher", data->launcher);
208
if (data->default_list) xmlNewChild(item, NULL, (xmlChar *)"default", NULL);
210
list=g_list_next(list);
214
file=fopen(file_name, "w");
215
xmlDocDump(file, doc);
217
cmd = g_strdup_printf("chmod 0600 %s", file_name);
218
fpm_execute_shell(cmd);
221
dia_str = g_strdup_printf(_("Saved %d password(s)."), i);
222
fpm_statusbar_push(dia_str);
224
printf("Saved %d password(s).\n", i);
226
g_free(vstring_plain);
227
g_free(vstring_cipher);
231
passfile_export(gchar* file_name)
234
xmlNodePtr nodelist, item;
236
fpm_launcher* launcher;
239
gchar* vstring_cipher;
240
gchar* vstring_plain;
245
gchar plaintext[FPM_PASSWORD_LEN+1] = {0};
246
gchar *new_file_name;
247
gchar *new_file_name2;
251
new_file_name = g_malloc0(strlen(file_name) + 10);
252
new_file_name2 = g_malloc0(strlen(file_name) + 15);
253
sprintf(new_file_name, "%s.export", file_name);
254
sprintf(new_file_name2, "%s.export.asc", file_name);
255
dia_str = g_malloc0(strlen(new_file_name) + strlen(new_file_name2) + 200);
257
printf("Export file %s\n", new_file_name);
259
// move_backup(file_name);
260
passfile_update_key();
262
vstring_cipher=g_malloc0(17);
263
vstring_plain=g_malloc0(9);
265
doc = xmlNewDoc((xmlChar *)"1.0");
266
doc->xmlRootNode = xmlNewDocNode(doc, NULL, (xmlChar *)"FPM", NULL);
267
xmlSetProp(doc->xmlRootNode, (xmlChar *)"full_version", (xmlChar *)FULL_VERSION);
268
xmlSetProp(doc->xmlRootNode, (xmlChar *)"min_version", (xmlChar *)MIN_VERSION);
269
xmlSetProp(doc->xmlRootNode, (xmlChar *)"display_version", (xmlChar *)DISPLAY_VERSION);
270
item = xmlNewChild(doc->xmlRootNode, NULL, (xmlChar *)"KeyInfo", NULL);
271
xmlSetProp(item, (xmlChar *)"salt", (xmlChar *)new_salt);
272
strncpy(vstring_plain, "FIGARO", 8);
273
fpm_encrypt_field(new_context, vstring_cipher, vstring_plain, 8);
274
xmlSetProp(item, (xmlChar *)"vstring", (xmlChar *)vstring_cipher);
276
fpm_decrypt_field(new_context, vstring_plain, vstring_cipher, 8);
278
nodelist = xmlNewChild(doc->xmlRootNode, NULL, (xmlChar *)"LauncherList", NULL);
279
list = g_list_first(glb_launcher_list);
284
item=xmlNewChild(nodelist, NULL, (xmlChar *)"LauncerItem", NULL);
285
new_leaf(doc, item, (xmlChar *)"title", (xmlChar *)launcher->title);
286
new_leaf(doc, item, (xmlChar *)"cmdline", (xmlChar *)launcher->cmdline);
287
tmp=g_strdup_printf("%d", launcher->copy_user);
288
new_leaf(doc, item, (xmlChar *)"copy_user", (xmlChar *)tmp);
290
tmp=g_strdup_printf("%d", launcher->copy_password);
291
new_leaf(doc, item, (xmlChar *)"copy_password", (xmlChar *)tmp);
294
list=g_list_next(list);
297
nodelist = xmlNewChild(doc->xmlRootNode, NULL, (xmlChar *)"PasswordList", NULL);
298
list = g_list_first(glb_pass_list);
300
if ( ( fp = fopen(new_file_name2, "w")) == NULL )
302
perror(new_file_name2);
308
item = xmlNewChild(nodelist, NULL, (xmlChar *)"PasswordItem", NULL);
309
new_leaf(doc, item, (xmlChar *)"title", (xmlChar *)data->title);
310
new_leaf(doc, item, (xmlChar *)"user", (xmlChar *)data->user);
311
new_leaf(doc, item, (xmlChar *)"url", (xmlChar *)data->arg);
312
fpm_decrypt_field(old_context, plaintext, data->password, FPM_PASSWORD_LEN);
313
new_leaf(doc, item, (xmlChar *)"password", (xmlChar *)plaintext);
314
new_leaf(doc, item, (xmlChar *)"notes", (xmlChar *)data->notes);
315
new_leaf(doc, item, (xmlChar *)"category", (xmlChar *)data->category);
316
new_leaf(doc, item, (xmlChar *)"launcher", (xmlChar *)data->launcher);
317
fprintf(fp, "title=%s\nuser=%s\npasswd=%s\nurl=%s\nnotes=%s\n\n", data->title, data->user, plaintext, data->arg, data->notes);
319
if (data->default_list) xmlNewChild(item, NULL, (xmlChar *)"default", NULL);
321
list=g_list_next(list);
326
file=fopen(new_file_name, "w");
327
xmlDocDump(file, doc);
329
cmd = g_strdup_printf("chmod 0600 %s", new_file_name);
330
fpm_execute_shell(cmd);
332
cmd = g_strdup_printf("chmod 0600 %s", new_file_name2);
333
fpm_execute_shell(cmd);
336
printf("Saved %d passwords.\n", i);
338
g_free(vstring_plain);
339
g_free(vstring_cipher);
340
sprintf(dia_str, _("Exported clear text passwords to\n %s and\n %s"), new_file_name, new_file_name2);
341
fpm_message(GTK_WINDOW(glb_win_app), dia_str, GTK_MESSAGE_INFO);
342
g_free(new_file_name);
343
g_free(new_file_name2);
345
/* Zero out plain text */
346
memset(plaintext, 0, FPM_PASSWORD_LEN);
352
passfile_load(gchar* file_name)
355
xmlNodePtr list, item, attr;
357
fpm_launcher* launcher;
359
//GtkStatusbar *entry;
363
/* Start from scratch */
364
if(glb_pass_list != NULL) fpm_clear_list();
367
xmlKeepBlanksDefault(0);
368
doc=xmlParseFile(file_name);
371
/* If we can't read the doc, then assume we are running for first time.*/
372
old_salt=get_new_salt();
376
fpm_init_launchers();
382
/* Check if document is one of ours */
383
g_return_val_if_fail(!xmlStrcmp(doc->xmlRootNode->name, (xmlChar *)"FPM"), -2);
385
file_version = (char *)xmlGetProp(doc->xmlRootNode, (xmlChar *)"min_version");
386
if (strcmp(file_version, FULL_VERSION) > 0)
388
g_error("Sorry, the password file cannot be read because it uses a future file format. Please download the latest version of FPM and try again.\n");
392
file_version = (char *)xmlGetProp(doc->xmlRootNode, (xmlChar *)"full_version");
394
/* Current versions of FPM encrypt all fields. Fields other than the
395
* password are decrypted when the program reads the password file,
396
* and the password is decrypted as it is needed (to try to prevent it
397
* from showing up in coredumps, etc.) The global variable glb_need_decrypt
398
* is set by the passfile loading routines to specify that the passfile
399
* was created with a version of FPM that requires this decryption.
400
* This allows backward compatibility with previous versions of FPM which
401
* only encrypted passwords.
405
glb_need_decrypt = (strcmp(file_version, ENCRYPT_VERSION) >= 0);
407
list=doc->xmlRootNode->xmlChildrenNode;
408
old_salt = (char *)xmlGetProp(list, (xmlChar *)"salt");
409
vstring = (char *)xmlGetProp(list, (xmlChar *)"vstring");
410
new_salt = get_new_salt();
411
glb_using_defaults=FALSE;
415
if (list==NULL || ( strcmp((char *)list->name, "PasswordList") && strcmp((char *)list->name, "LauncherList") ))
417
g_error("Invalid password file.");
421
if(!strcmp((char *)list->name, "LauncherList"))
423
printf("Loading launchers...\n");
424
glb_launcher_list=NULL;
425
item=list->xmlChildrenNode;
428
launcher=g_malloc0(sizeof(fpm_launcher));
429
launcher->title=g_strdup("");
430
launcher->cmdline=g_strdup("");
431
launcher->copy_user=0;
432
launcher->copy_password=0;
433
attr=item->xmlChildrenNode;
436
if(!strcmp((char *)attr->name, "title") && attr->xmlChildrenNode && attr->xmlChildrenNode->content)
438
g_free(launcher->title);
439
launcher->title=g_strdup((char *)attr->xmlChildrenNode->content);
441
if(!strcmp((char *)attr->name, "cmdline") && attr->xmlChildrenNode && attr->xmlChildrenNode->content)
443
g_free(launcher->cmdline);
444
launcher->cmdline=g_strdup((char *)attr->xmlChildrenNode->content);
446
if(!strcmp((char *)attr->name, "copy_user"))
448
if(!strcmp((char *)attr->xmlChildrenNode->content, "1")) launcher->copy_user=1;
449
if(!strcmp((char *)attr->xmlChildrenNode->content, "2")) launcher->copy_user=2;
451
if(!strcmp((char *)attr->name, "copy_password"))
453
if(!strcmp((char *)attr->xmlChildrenNode->content, "1")) launcher->copy_password=1;
454
if(!strcmp((char *)attr->xmlChildrenNode->content, "2")) launcher->copy_password=2;
458
glb_launcher_list=g_list_append(glb_launcher_list, launcher);
462
fpm_create_launcher_string_list();
464
/* Incurement top-level list from launcher list to password list. */
469
fpm_init_launchers();
472
if (list==NULL || strcmp((char *)list->name, "PasswordList"))
474
g_error("Invalid password file.");
481
item=list->xmlChildrenNode;
485
/* Start with blank data record */
486
data = g_malloc0(sizeof(fpm_data));
487
data->title=g_strdup("");
488
data->arg=g_strdup("");
489
data->user=g_strdup("");
490
data->notes=g_strdup("");
491
data->category=g_strdup("");
492
data->launcher=g_strdup("");
493
data->default_list=0;
495
/* Update data record with each type of attribute */
496
attr=item->xmlChildrenNode;
499
passfile_upd_attr(attr, "title", &data->title);
500
passfile_upd_attr(attr, "url", &data->arg);
501
// passfile_upd_attr(attr, "arg", &data->arg);
502
passfile_upd_attr(attr, "user", &data->user);
503
passfile_upd_attr(attr, "notes", &data->notes);
504
passfile_upd_attr(attr, "category", &data->category);
505
passfile_upd_attr(attr, "launcher", &data->launcher);
506
if(!strcmp((char *)attr->name, "default"))
508
data->default_list=1;
509
glb_using_defaults=TRUE;
512
if(!strcmp((char *)attr->name, "password"))
513
strncpy(data->password, (char *)attr->xmlChildrenNode->content, FPM_PASSWORD_LEN*2);
518
/* Insert item into GList */
520
glb_pass_list=g_list_append(glb_pass_list, data);
525
printf("Loaded %d password(s).\n", i);
527
dia_str = g_strdup_printf(_("Loaded %d password(s)."), i);
528
fpm_statusbar_push(dia_str);
537
set_token(char *tmps)
539
_s_token = strdup(tmps);
540
_c_token_pos = _s_token;
551
get_token(char *delim)
566
if ( index(delim, *cp) != NULL )
571
if ( strlen(scp) == 0 )
584
passfile_import(gchar *fname)
588
gchar plaintext[FPM_PASSWORD_LEN+1];
602
if ( ( fp = fopen(fname, "r")) != NULL )
604
while( fgets(tmps, 2048, fp) != NULL )
610
if ( (title = get_token("\t\n")) == NULL )
615
if ( (userid = get_token("\t\n")) == NULL )
620
if ( (passwd = get_token("\t\n")) == NULL )
625
if ( (url = get_token("\t\n")) == NULL )
630
if ( (category = get_token("\t\n")) == NULL )
636
/* Want at least 2 fields */
641
printf("%3d) (%d) title = [%s] ", row, no_data, title);
642
printf("userid = [%s] ", userid);
643
printf("passwd = [%s] ", passwd);
644
printf("url = [%s] ", url);
645
printf("category = [%s]\n", category);
646
END of debugging info */
648
printf("Not enough data on line %d\n", row);
654
/* Create new password entry */
655
new_data = g_malloc0(sizeof(fpm_data));
656
strncpy(plaintext, "", FPM_PASSWORD_LEN);
657
strcpy(plaintext, passwd);
658
fpm_encrypt_field( old_context, new_data->password,
659
plaintext, FPM_PASSWORD_LEN);
660
/* Zero out plain text */
661
memset(plaintext, 0, FPM_PASSWORD_LEN);
662
new_data->title=g_strdup(title);
663
new_data->arg=g_strdup(url);
664
new_data->user=g_strdup(userid);
665
new_data->notes=g_strdup("");
666
new_data->category=g_strdup(category);
667
new_data->launcher=g_strdup("");
668
glb_pass_list = g_list_append(glb_pass_list, new_data);
669
free_token(); /* Free up space for token parse */
674
dia_str = g_strdup_printf(_("Imported %d password(s)"), num_added);
675
fpm_message(GTK_WINDOW(glb_win_app), dia_str, GTK_MESSAGE_INFO);
677
printf("Imported %d entries\n", num_added);
678
passfile_save(glb_filename);
679
fpm_clist_populate_cat_list();
680
fpm_check_view(FPM_ALL_CAT_MSG);