annotate pws-file.c @ 13:2bb1bbac1d0a default tip

Added tag version-1.0.0 for changeset 1926dfc9feb0
author Guido Berhoerster <guido+libpws@berhoerster.name>
date Sun, 04 Aug 2019 21:37:56 +0200
parents ec5c1b653ee6
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1 /*
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
2 * Copyright (C) 2015 Guido Berhoerster <guido+libpws@berhoerster.name>
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
3 *
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
4 * Permission is hereby granted, free of charge, to any person obtaining
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
5 * a copy of this software and associated documentation files (the
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
6 * "Software"), to deal in the Software without restriction, including
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
7 * without limitation the rights to use, copy, modify, merge, publish,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
8 * distribute, sublicense, and/or sell copies of the Software, and to
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
9 * permit persons to whom the Software is furnished to do so, subject to
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
10 * the following conditions:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
11 *
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
12 * The above copyright notice and this permission notice shall be included
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
13 * in all copies or substantial portions of the Software.
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
14 *
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
22 */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
23
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
24 #include "compat.h"
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
25
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
26 #include <stdlib.h>
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
27 #include <unistd.h>
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
28 #include <string.h>
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
29 #include <stdarg.h>
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
30 #include <errno.h>
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
31 #ifdef HAVE_ENDIAN_H
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
32 #include <endian.h>
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
33 #endif /* HAVE_ENDIAN_H */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
34 #ifdef HAVE_SYS_ENDIAN_H
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
35 #include <sys/endian.h>
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
36 #endif /* HAVE_ENDIAN_H */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
37 #include <nettle/twofish.h>
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
38 #include <nettle/cbc.h>
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
39 #include <nettle/hmac.h>
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
40 #include <nettle/sha.h>
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
41
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
42 #include "pws-internal.h"
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
43
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
44 #define MAX_ITER (1 << 22)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
45 #define DEFAULT_ITER 10000
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
46 #define KEY_SIZE 32UL
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
47 #define SALT_SIZE 32UL
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
48 #define METADATA_SIZE (sizeof (psafe3_tag) + SALT_SIZE + 4 +\
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
49 SHA256_DIGEST_SIZE + KEY_SIZE + KEY_SIZE + TWOFISH_BLOCK_SIZE)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
50
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
51 static const unsigned char psafe3_tag[] = { 'P', 'W', 'S', '3' };
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
52 static const unsigned char eof_marker[] = { 'P', 'W', 'S', '3', '-', 'E', 'O',
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
53 'F', 'P', 'W', 'S', '3', '-', 'E', 'O', 'F' };
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
54
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
55 RB_HEAD(empty_groups_tree, pws3_field);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
56
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
57 RB_HEAD(records_tree, pws3_record);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
58
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
59 struct pws3_file {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
60 struct pws3_field *fields[256];
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
61 struct empty_groups_tree *empty_groups_tree;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
62 struct records_tree *records_tree;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
63 struct pws_file_error {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
64 enum pws_error_code code;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
65 int errnum;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
66 char *msg;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
67 } error;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
68 };
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
69
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
70 struct twofish_cbc_ctx CBC_CTX(struct twofish_ctx, TWOFISH_BLOCK_SIZE);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
71
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
72 struct pws_file_ctx {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
73 FILE *fp;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
74 unsigned char *mem;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
75 size_t mem_size;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
76 size_t mem_pos;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
77 struct twofish_cbc_ctx cipher_ctx;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
78 struct hmac_sha256_ctx hmac_ctx;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
79 struct pws3_file *pws_file;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
80 uint32_t n_iter;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
81 };
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
82
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
83 static int empty_groups_cmp(struct pws3_field *, struct pws3_field *);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
84 static int record_cmp(struct pws3_record *, struct pws3_record *);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
85 RB_PROTOTYPE_STATIC(empty_groups_tree, pws3_field, tree_entry, empty_groups_cmp)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
86 RB_PROTOTYPE_STATIC(records_tree, pws3_record, tree_entry, record_cmp)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
87
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
88 RB_GENERATE_STATIC(empty_groups_tree, pws3_field, tree_entry, empty_groups_cmp)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
89
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
90 RB_GENERATE_STATIC(records_tree, pws3_record, tree_entry, record_cmp)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
91
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
92 static int
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
93 empty_groups_cmp(struct pws3_field *field1, struct pws3_field *field2)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
94 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
95 PWS_ASSERT(pws3_field_is_header(field1) &&
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
96 pws3_field_is_header(field2));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
97 PWS_ASSERT((pws3_field_get_type(field1) ==
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
98 PWS3_HEADER_FIELD_EMPTY_GROUPS) &&
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
99 (pws3_field_get_type(field2) == PWS3_HEADER_FIELD_EMPTY_GROUPS));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
100
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
101 return (strcmp(pws3_field_get_text(field1),
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
102 pws3_field_get_text(field2)));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
103 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
104
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
105 static int
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
106 record_cmp(struct pws3_record *record1, struct pws3_record *record2)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
107 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
108 struct pws3_field *uuid_field1;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
109 struct pws3_field *uuid_field2;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
110
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
111 uuid_field1 = pws3_record_get_field(record1, PWS3_RECORD_FIELD_UUID);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
112 uuid_field2 = pws3_record_get_field(record2, PWS3_RECORD_FIELD_UUID);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
113 PWS_ASSERT((uuid_field1 != NULL) && (uuid_field2 != NULL));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
114
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
115 return (memcmp(pws3_field_get_uuid(uuid_field1),
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
116 pws3_field_get_uuid(uuid_field2), PWS3_UUID_SIZE));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
117 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
118
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
119 static void
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
120 pws_set_system_error(struct pws3_file *pws_file, enum pws_error_code code,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
121 int errnum, const char *fmt, ...)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
122 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
123 char system_error_buf[4096] = "";
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
124 size_t system_error_len;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
125 int error_len;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
126 va_list args;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
127 va_list args2;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
128
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
129 pws_file->error.code = code;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
130 pws_file->error.errnum = errnum;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
131
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
132 strerror_r(errnum, system_error_buf, sizeof (system_error_buf) - 1);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
133 system_error_len = strlen(system_error_buf);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
134
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
135 pws_free(pws_file->error.msg, (pws_file->error.msg != NULL) ?
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
136 strlen(pws_file->error.msg) + 1 : 0);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
137 if (fmt != NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
138 va_start(args, fmt);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
139 va_copy(args2, args);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
140 error_len = vsnprintf(NULL, 0, fmt, args);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
141 pws_file->error.msg = pws_alloc(error_len + 2 +
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
142 system_error_len + 1);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
143 if (pws_file->error.msg == NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
144 va_end(args2);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
145 va_end(args);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
146 return;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
147 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
148 vsnprintf(pws_file->error.msg, error_len + 1, fmt, args2);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
149 va_end(args2);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
150 va_end(args);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
151 strcpy(pws_file->error.msg + error_len, ": ");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
152 strcpy(pws_file->error.msg + error_len + 2, system_error_buf);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
153 } else {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
154 pws_file->error.msg = pws_alloc(system_error_len + 1);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
155 snprintf(pws_file->error.msg, system_error_len + 1, "%s",
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
156 system_error_buf);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
157 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
158 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
159
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
160 static void
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
161 pws_set_error(struct pws3_file *pws_file, enum pws_error_code code,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
162 const char *fmt, ...)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
163 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
164 va_list args;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
165 va_list args2;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
166 int error_len;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
167
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
168 pws_file->error.code = code;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
169 pws_file->error.errnum = 0;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
170
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
171 pws_free(pws_file->error.msg, (pws_file->error.msg != NULL) ?
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
172 strlen(pws_file->error.msg) + 1 : 0);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
173 va_start(args, fmt);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
174 va_copy(args2, args);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
175 error_len = vsnprintf(NULL, 0, fmt, args);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
176 pws_file->error.msg = pws_alloc(error_len + 1);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
177 if (pws_file->error.msg == NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
178 va_end(args2);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
179 va_end(args);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
180 return;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
181 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
182 vsnprintf(pws_file->error.msg, error_len + 1, fmt, args2);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
183 va_end(args2);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
184 va_end(args);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
185 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
186
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
187 static int
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
188 read_buf(struct pws_file_ctx *ctx, unsigned char *buf, size_t buf_size)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
189 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
190 if (ctx->fp != NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
191 if (fread(buf, 1, buf_size, ctx->fp) != buf_size) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
192 if (ferror(ctx->fp) != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
193 return (-1);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
194 } else if (feof(ctx->fp) != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
195 return (1);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
196 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
197 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
198 } else {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
199 PWS_ASSERT(ctx->mem != NULL);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
200 if (ctx->mem_size - ctx->mem_pos < buf_size) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
201 return (1);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
202 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
203 memcpy(buf, &ctx->mem[ctx->mem_pos], buf_size);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
204 ctx->mem_pos += buf_size;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
205 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
206
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
207 return (0);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
208 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
209
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
210 static int
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
211 write_buf(struct pws_file_ctx *ctx, const unsigned char *buf, size_t buf_size)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
212 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
213 size_t remaining;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
214 unsigned char *tmp;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
215
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
216 if (ctx->fp != NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
217 if (fwrite(buf, 1, buf_size, ctx->fp) != buf_size) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
218 return (-1);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
219 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
220 if (fflush(ctx->fp) != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
221 return (-1);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
222 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
223 } else {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
224 remaining = ctx->mem_size - ctx->mem_pos;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
225 if (remaining < buf_size) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
226 tmp = pws_realloc(ctx->mem, ctx->mem_size +
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
227 (buf_size - remaining));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
228 if (tmp == NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
229 return (-1);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
230 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
231 ctx->mem = tmp;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
232 ctx->mem_size += (buf_size - remaining);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
233 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
234 memcpy(&ctx->mem[ctx->mem_pos], buf, buf_size);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
235 ctx->mem_pos += buf_size;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
236 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
237
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
238 return (0);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
239 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
240
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
241 static void
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
242 pws_file_clear(struct pws3_file *pws_file)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
243 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
244 size_t i;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
245 struct pws3_field *empty_group_field;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
246 struct pws3_field *empty_group_field_tmp;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
247 struct pws3_record *record;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
248 struct pws3_record *record_tmp;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
249
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
250 for (i = 0x00; i <= 0xff; i++) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
251 pws3_field_destroy(pws_file->fields[i]);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
252 pws_file->fields[i] = NULL;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
253 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
254
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
255 RB_FOREACH_SAFE(empty_group_field, empty_groups_tree,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
256 pws_file->empty_groups_tree, empty_group_field_tmp) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
257 pws3_field_destroy(RB_REMOVE(empty_groups_tree,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
258 pws_file->empty_groups_tree, empty_group_field));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
259 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
260
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
261 RB_FOREACH_SAFE(record, records_tree, pws_file->records_tree,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
262 record_tmp) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
263 pws3_record_destroy(RB_REMOVE(records_tree,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
264 pws_file->records_tree, record));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
265 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
266 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
267
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
268 void
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
269 pws3_file_destroy(struct pws3_file *pws_file)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
270 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
271 if (pws_file == NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
272 return;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
273 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
274
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
275 pws_free(pws_file->error.msg, (pws_file->error.msg != NULL) ?
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
276 strlen(pws_file->error.msg) + 1 : 0);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
277 pws_file_clear(pws_file);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
278 pws_free(pws_file->empty_groups_tree,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
279 sizeof (struct empty_groups_tree));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
280 pws_free(pws_file->records_tree, sizeof (struct records_tree));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
281 pws_free(pws_file, sizeof (struct pws3_file));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
282 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
283
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
284 struct pws3_file *
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
285 pws3_file_create(void)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
286 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
287 struct pws3_field *version_field = NULL;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
288 struct pws3_file *pws_file = NULL;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
289 size_t i;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
290
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
291 /* version field is mandatory */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
292 version_field = pws3_field_create(1, PWS3_HEADER_FIELD_VERSION);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
293 if (version_field == NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
294 goto err;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
295 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
296 pws3_field_set_uint16(version_field, PWS3_VERSION);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
297
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
298 pws_file = pws_alloc(sizeof (struct pws3_file));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
299 if (pws_file == NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
300 goto err;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
301 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
302 for (i = 0x00; i <= 0xff; i++) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
303 pws_file->fields[i] = NULL;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
304 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
305 pws_file->empty_groups_tree = NULL;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
306 pws_file->records_tree = NULL;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
307 pws_file->error.errnum = 0;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
308 pws_file->error.code = 0;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
309 pws_file->error.msg = NULL;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
310
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
311 pws_file->empty_groups_tree =
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
312 pws_alloc(sizeof (struct empty_groups_tree));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
313 if (pws_file->empty_groups_tree == NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
314 goto err;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
315 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
316 RB_INIT(pws_file->empty_groups_tree);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
317
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
318 pws_file->records_tree = pws_alloc(sizeof (struct records_tree));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
319 if (pws_file->records_tree == NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
320 goto err;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
321 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
322 RB_INIT(pws_file->records_tree);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
323
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
324 pws3_file_set_header_field(pws_file, version_field);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
325
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
326 return (pws_file);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
327 err:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
328 pws3_field_destroy(version_field);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
329 if (pws_file != NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
330 pws_free(pws_file->records_tree, sizeof (struct records_tree));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
331 pws_free(pws_file->empty_groups_tree,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
332 sizeof (struct empty_groups_tree));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
333 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
334 pws_free(pws_file, sizeof (struct pws3_file));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
335
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
336 return (NULL);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
337 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
338
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
339 enum pws_error_code
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
340 pws3_file_get_error_code(struct pws3_file *pws_file)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
341 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
342 return (pws_file->error.code);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
343 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
344
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
345 const char *
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
346 pws3_file_get_error_message(struct pws3_file *pws_file)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
347 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
348 return ((pws_file->error.msg != NULL) ? pws_file->error.msg : "");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
349 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
350
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
351 static void
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
352 stretch_key(unsigned char *stretched_key, uint32_t n_iter, const char *key,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
353 size_t key_size, const unsigned char *salt, size_t salt_size)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
354 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
355 uint32_t i;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
356 struct sha256_ctx md_ctx;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
357
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
358 sha256_init(&md_ctx);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
359 sha256_update(&md_ctx, key_size, (uint8_t *)key);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
360 sha256_update(&md_ctx, salt_size, salt);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
361 sha256_digest(&md_ctx, SHA256_DIGEST_SIZE, stretched_key);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
362
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
363 for (i = 0; i < n_iter; i++) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
364 sha256_update(&md_ctx, SHA256_DIGEST_SIZE, stretched_key);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
365 sha256_digest(&md_ctx, SHA256_DIGEST_SIZE, stretched_key);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
366 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
367 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
368
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
369 static int
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
370 read_metadata(struct pws_file_ctx *ctx, const char *password)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
371 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
372 int retval = -1;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
373 unsigned char buf[METADATA_SIZE];
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
374 unsigned char *p = buf;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
375 unsigned char *stretched_key = NULL;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
376 unsigned char *key_k = NULL;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
377 unsigned char *key_l = NULL;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
378 int read_retval;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
379 unsigned char salt[SALT_SIZE];
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
380 unsigned char key_digest[SHA256_DIGEST_SIZE];
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
381 struct sha256_ctx md_ctx;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
382 struct twofish_ctx cipher_ctx;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
383
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
384 stretched_key = pws_secure_alloc(SHA256_DIGEST_SIZE);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
385 if (stretched_key == NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
386 pws_set_error(ctx->pws_file, PWS_ERR_NO_MEMORY,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
387 "out of memory");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
388 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
389 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
390
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
391 key_k = pws_secure_alloc(KEY_SIZE);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
392 if (key_k == NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
393 pws_set_error(ctx->pws_file, PWS_ERR_NO_MEMORY,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
394 "out of memory");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
395 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
396 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
397
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
398 key_l = pws_secure_alloc(KEY_SIZE);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
399 if (key_l == NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
400 pws_set_error(ctx->pws_file, PWS_ERR_NO_MEMORY,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
401 "out of memory");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
402 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
403 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
404
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
405 read_retval = read_buf(ctx, buf, sizeof (buf));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
406 if (read_retval == 1) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
407 pws_set_error(ctx->pws_file, PWS_ERR_TRUNCATED_FILE,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
408 "unexpected end of file");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
409 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
410 } else if (read_retval != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
411 pws_set_system_error(ctx->pws_file, PWS_ERR_IO_ERROR, errno,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
412 NULL);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
413 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
414 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
415
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
416 /* check tag */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
417 if (memcmp(p, psafe3_tag, sizeof (psafe3_tag)) != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
418 pws_set_error(ctx->pws_file, PWS_ERR_INVALID_HEADER,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
419 "unknown filetype");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
420 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
421 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
422 p += sizeof (psafe3_tag);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
423
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
424 /* salt */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
425 memcpy(salt, p, SALT_SIZE);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
426 p += SALT_SIZE;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
427
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
428 /* iterations */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
429 memcpy(&ctx->n_iter, p, 4);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
430 ctx->n_iter = le32toh(ctx->n_iter);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
431 if ((ctx->n_iter < 1) || (ctx->n_iter > MAX_ITER)) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
432 pws_set_error(ctx->pws_file, PWS_ERR_INVALID_HEADER,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
433 "invalid number of iterations: %d", ctx->n_iter);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
434 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
435 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
436 p += 4;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
437
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
438 /* verify password */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
439 stretch_key(stretched_key, ctx->n_iter, password, strlen(password),
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
440 salt, SALT_SIZE);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
441 sha256_init(&md_ctx);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
442 sha256_update(&md_ctx, SHA256_DIGEST_SIZE, stretched_key);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
443 sha256_digest(&md_ctx, SHA256_DIGEST_SIZE, key_digest);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
444 if (memcmp(key_digest, p, SHA256_DIGEST_SIZE) != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
445 pws_set_error(ctx->pws_file, PWS_ERR_INVALID_HEADER,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
446 "wrong password");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
447 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
448 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
449 p += SHA256_DIGEST_SIZE;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
450
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
451 /* decrypt keys */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
452 twofish_set_key(&cipher_ctx, KEY_SIZE, stretched_key);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
453 twofish_decrypt(&cipher_ctx, KEY_SIZE, key_k, p);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
454 p += KEY_SIZE;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
455 twofish_decrypt(&cipher_ctx, KEY_SIZE, key_l, p);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
456 p += KEY_SIZE;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
457
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
458 /* set key for decryption */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
459 twofish_set_key(&ctx->cipher_ctx.ctx, KEY_SIZE, key_k);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
460
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
461 /* set IV */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
462 CBC_SET_IV(&ctx->cipher_ctx, p);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
463
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
464 /* set key for HMAC */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
465 HMAC_SET_KEY(&ctx->hmac_ctx, &nettle_sha256, KEY_SIZE, key_l);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
466
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
467 retval = 0;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
468
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
469 out:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
470 pws_secure_free(stretched_key, (stretched_key != NULL) ?
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
471 SHA256_DIGEST_SIZE : 0);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
472 pws_secure_free(key_l, (key_l != NULL) ? KEY_SIZE : 0);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
473 pws_secure_free(key_k, (key_k != NULL) ? KEY_SIZE : 0);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
474
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
475 return (retval);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
476 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
477
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
478 static int
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
479 read_block(struct pws_file_ctx *ctx, unsigned char *block)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
480 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
481 unsigned char buf[TWOFISH_BLOCK_SIZE];
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
482 int read_retval;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
483
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
484 read_retval = read_buf(ctx, buf, sizeof (buf));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
485 if (read_retval == 1) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
486 pws_set_error(ctx->pws_file, PWS_ERR_TRUNCATED_FILE,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
487 "unexpected end of file");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
488 return (-1);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
489 } else if (read_retval != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
490 pws_set_system_error(ctx->pws_file, PWS_ERR_IO_ERROR, errno,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
491 NULL);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
492 return (-1);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
493 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
494
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
495 /* reached the EOF block marking the end of encrypted records */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
496 if (memcmp(buf, eof_marker, TWOFISH_BLOCK_SIZE) == 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
497 return (1);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
498 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
499
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
500 CBC_DECRYPT(&ctx->cipher_ctx, twofish_decrypt, TWOFISH_BLOCK_SIZE,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
501 block, buf);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
502
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
503 return (0);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
504 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
505
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
506 static int
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
507 read_field(struct pws_file_ctx *ctx, struct pws3_field **fieldp, int is_header)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
508 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
509 int retval = -1;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
510 enum pws_data_type data_type;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
511 struct pws3_field *field = NULL;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
512 unsigned char *block_buf = NULL;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
513 unsigned char *p;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
514 int read_retval;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
515 unsigned char *field_buf = NULL;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
516 uint32_t field_size;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
517 size_t remaining;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
518 size_t field_buf_size = 0;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
519 uint8_t field_type = 0xff;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
520 time_t data_time;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
521 uint32_t data_uint32;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
522 uint16_t data_uint16;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
523 uint8_t data_uint8;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
524
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
525 block_buf = pws_secure_alloc(TWOFISH_BLOCK_SIZE);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
526 if (block_buf == NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
527 pws_set_error(ctx->pws_file, PWS_ERR_NO_MEMORY,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
528 "out of memory");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
529 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
530 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
531
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
532 next_field:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
533 p = block_buf;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
534
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
535 /* read first block */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
536 read_retval = read_block(ctx, block_buf);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
537 if (read_retval != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
538 retval = read_retval;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
539 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
540 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
541
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
542 /* determine field length */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
543 memcpy(&field_size, p, 4);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
544 remaining = field_buf_size = field_size = le32toh(field_size);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
545 p += 4;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
546 /* determine field type */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
547 memcpy(&field_type, p, 1);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
548 p++;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
549
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
550 /* check for end of header fields or end of record */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
551 if ((is_header && (field_type == PWS3_HEADER_FIELD_END)) ||
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
552 (!is_header && (field_type == PWS3_RECORD_FIELD_END))) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
553 retval = 1;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
554 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
555 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
556
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
557 /* skip empty fields */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
558 if (field_size == 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
559 goto next_field;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
560 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
561
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
562 /* determine data type */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
563 data_type = pws3_field_get_data_type(&(struct pws3_field){ .is_header =
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
564 is_header, .field_type = field_type });
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
565
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
566 /* make room for a terminating \0 in text fields */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
567 if (data_type == PWS_DATA_TYPE_TEXT) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
568 field_buf_size++;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
569 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
570
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
571 /* validate field length */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
572 switch (data_type) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
573 case PWS_DATA_TYPE_UUID:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
574 if ((field_size != 0) && (field_size != PWS3_UUID_SIZE)) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
575 pws_set_error(ctx->pws_file, PWS_ERR_INVALID_HEADER,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
576 "invalid field length");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
577 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
578 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
579 break;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
580 case PWS_DATA_TYPE_TIME: /* FALLTHROUGH */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
581 case PWS_DATA_TYPE_UINT32:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
582 if ((field_size != 0) && (field_size != 4)) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
583 pws_set_error(ctx->pws_file, PWS_ERR_INVALID_HEADER,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
584 "invalid field length");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
585 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
586 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
587 break;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
588 case PWS_DATA_TYPE_UINT8:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
589 if ((field_size != 0) && (field_size != 1)) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
590 pws_set_error(ctx->pws_file, PWS_ERR_INVALID_HEADER,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
591 "invalid field length");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
592 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
593 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
594 break;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
595 case PWS_DATA_TYPE_UINT16:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
596 if ((field_size != 0) && (field_size != 2)) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
597 pws_set_error(ctx->pws_file, PWS_ERR_INVALID_HEADER,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
598 "invalid field length");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
599 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
600 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
601 break;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
602 default:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
603 /* text or bytes */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
604 if ((!is_header &&
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
605 (field_type == PWS3_RECORD_FIELD_PASSWORD) &&
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
606 (field_buf_size > PWS3_MAX_PASSWORD_LEN)) ||
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
607 (field_buf_size > PWS3_MAX_FIELD_SIZE)) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
608 pws_set_error(ctx->pws_file, PWS_ERR_INVALID_HEADER,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
609 "invalid field length");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
610 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
611 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
612 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
613
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
614 field = pws3_field_create(is_header, field_type);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
615 if (field == NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
616 pws_set_system_error(ctx->pws_file, PWS_ERR_NO_MEMORY, errno,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
617 NULL);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
618 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
619 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
620
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
621 /* create field */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
622 if (field_buf_size > 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
623 if (!is_header && (field_type == PWS3_RECORD_FIELD_PASSWORD)) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
624 field_buf = pws_secure_alloc(field_buf_size);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
625 } else {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
626 field_buf = pws_alloc(field_buf_size);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
627 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
628 if (field_buf == NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
629 pws_set_error(ctx->pws_file, PWS_ERR_NO_MEMORY,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
630 "out of memory");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
631 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
632 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
633 memset(field_buf, 0, field_buf_size);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
634
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
635 memcpy(field_buf, p, MIN(remaining,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
636 (size_t)TWOFISH_BLOCK_SIZE - (p - block_buf)));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
637 remaining -= MIN(remaining,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
638 (size_t)TWOFISH_BLOCK_SIZE - (p - block_buf));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
639
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
640 while (remaining > 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
641 read_retval = read_block(ctx, block_buf);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
642 if (read_retval != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
643 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
644 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
645 memcpy(field_buf + (field_size - remaining),
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
646 block_buf, MIN(remaining, TWOFISH_BLOCK_SIZE));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
647 remaining -= MIN(remaining, TWOFISH_BLOCK_SIZE);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
648 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
649
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
650 hmac_sha256_update(&ctx->hmac_ctx, field_size, field_buf);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
651
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
652 switch (data_type) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
653 case PWS_DATA_TYPE_UUID:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
654 retval = pws3_field_set_uuid(field, field_buf);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
655 break;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
656 case PWS_DATA_TYPE_TEXT:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
657 retval = pws3_field_set_text(field, (char *)field_buf);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
658 break;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
659 case PWS_DATA_TYPE_TIME:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
660 memcpy(&data_uint32, field_buf, 4);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
661 data_time = le32toh(data_uint32);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
662 retval = pws3_field_set_time(field, data_time);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
663 break;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
664 case PWS_DATA_TYPE_UINT8:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
665 memcpy(&data_uint8, field_buf, 1);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
666 retval = pws3_field_set_uint8(field, data_uint8);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
667 break;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
668 case PWS_DATA_TYPE_UINT16:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
669 memcpy(&data_uint16, field_buf, 2);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
670 data_uint16 = le16toh(data_uint16);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
671 retval = pws3_field_set_uint16(field, data_uint16);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
672 break;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
673 case PWS_DATA_TYPE_UINT32:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
674 memcpy(&data_uint32, field_buf, 4);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
675 data_uint32 = le32toh(data_uint32);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
676 retval = pws3_field_set_uint32(field, data_uint32);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
677 break;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
678 case PWS_DATA_TYPE_BYTES:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
679 retval = pws3_field_set_bytes(field, field_buf,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
680 field_buf_size);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
681 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
682 if (retval != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
683 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
684 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
685 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
686
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
687 retval = 0;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
688
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
689 out:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
690 if (!is_header && (field_type == PWS3_RECORD_FIELD_PASSWORD)) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
691 pws_secure_free(field_buf, field_buf_size);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
692 } else {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
693 pws_free(field_buf, field_buf_size);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
694 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
695 pws_secure_free(block_buf, (block_buf != NULL) ?
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
696 (size_t)TWOFISH_BLOCK_SIZE : 0);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
697
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
698 if (retval == 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
699 *fieldp = field;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
700 } else {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
701 pws3_field_destroy(field);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
702 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
703
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
704 return (retval);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
705 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
706
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
707 static int
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
708 read_header(struct pws_file_ctx *ctx)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
709 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
710 int retval;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
711 struct pws3_field *field = NULL;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
712
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
713 /* the header must start with a version field */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
714 retval = read_field(ctx, &field, 1);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
715 if (retval != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
716 /* error or end of headers */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
717 pws_set_error(ctx->pws_file, PWS_ERR_INVALID_HEADER,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
718 "header does not start with a version field");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
719 return (-1);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
720 } else if (field->field_type != PWS3_HEADER_FIELD_VERSION) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
721 /* header does not start with a version field */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
722 pws3_field_destroy(field);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
723 pws_set_error(ctx->pws_file, PWS_ERR_INVALID_HEADER,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
724 "header does not start with a version field");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
725 return (-1);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
726 } else if (field->value.uint16 > PWS3_VERSION) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
727 /* unsupported database version */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
728 pws3_field_destroy(field);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
729 pws_set_error(ctx->pws_file, PWS_ERR_UNSUPPORTED_VERSION,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
730 "unsupported database version");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
731 return (-1);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
732 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
733 pws3_file_set_header_field(ctx->pws_file, field);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
734
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
735 for (;;) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
736 retval = read_field(ctx, &field, 1);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
737 if (retval == 1) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
738 /* end of headers */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
739 pws_set_error(ctx->pws_file, PWS_ERR_INVALID_HEADER,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
740 "unexpected end of headers");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
741 break;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
742 } else if (retval != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
743 return (-1);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
744 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
745 pws3_file_set_header_field(ctx->pws_file, field);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
746 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
747
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
748 return (0);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
749 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
750
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
751 static int
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
752 read_records(struct pws_file_ctx *ctx)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
753 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
754 int retval;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
755 struct pws3_record *record = NULL;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
756 struct pws3_field *field = NULL;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
757
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
758 for (;;) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
759 /*
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
760 * a record must consist of at least three fields, instead of
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
761 * the first field there could also be an EOF marker
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
762 */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
763 retval = read_field(ctx, &field, 0);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
764 if (retval == 1) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
765 /* EOF marker */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
766 retval = 0;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
767 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
768 } else if (retval != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
769 /* read error */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
770 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
771 } else if (field->field_type == PWS3_RECORD_FIELD_END) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
772 /* empty record */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
773 retval = -1;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
774 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
775 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
776
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
777 record = pws3_record_create();
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
778 if (record == NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
779 pws_set_system_error(ctx->pws_file, PWS_ERR_NO_MEMORY,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
780 errno, NULL);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
781 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
782 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
783
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
784 pws3_record_set_field(record, field);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
785 field = NULL;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
786
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
787 /* read the remaining fileds */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
788 for (;;) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
789 retval = read_field(ctx, &field, 0);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
790 if (retval == 1) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
791 /* end of record */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
792 break;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
793 } else if (retval != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
794 /* read error */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
795 retval = -1;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
796 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
797 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
798 pws3_record_set_field(record, field);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
799 field = NULL;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
800 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
801
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
802 /* check whether UUID is not empty */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
803 if (pws3_record_get_field(record, PWS3_RECORD_FIELD_UUID) ==
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
804 NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
805 /* record is missing mandatory fields */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
806 pws_set_error(ctx->pws_file, PWS_ERR_INVALID_RECORD,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
807 "record is missing mandatory fields");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
808 pws3_record_destroy(record);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
809 retval = -1;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
810 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
811 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
812
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
813 pws3_file_insert_record(ctx->pws_file, record);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
814 record = NULL;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
815 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
816
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
817 out:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
818 if (retval != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
819 pws3_field_destroy(field);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
820 pws3_record_destroy(record);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
821 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
822
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
823 return (retval);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
824 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
825
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
826 static int
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
827 verify_checksum(struct pws_file_ctx *ctx)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
828 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
829 int retval;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
830 unsigned char hmac_file[SHA256_DIGEST_SIZE];
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
831 unsigned char hmac[SHA256_DIGEST_SIZE];
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
832
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
833 retval = read_buf(ctx, hmac_file, sizeof (hmac_file));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
834 if (retval == 1) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
835 pws_set_error(ctx->pws_file, PWS_ERR_TRUNCATED_FILE,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
836 "unexpected end of file");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
837 return (-1);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
838 } else if (retval != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
839 pws_set_system_error(ctx->pws_file, PWS_ERR_IO_ERROR, errno,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
840 NULL);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
841 return (-1);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
842 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
843
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
844 hmac_sha256_digest(&ctx->hmac_ctx, sizeof (hmac), hmac);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
845 if (memcmp(hmac_file, hmac, sizeof (hmac_file)) != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
846 /* inconsistent database */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
847 pws_set_error(ctx->pws_file, PWS_ERR_INVALID_CHECKSUM,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
848 "checksum failed");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
849 return (-1);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
850 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
851
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
852 return (0);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
853 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
854
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
855 static int
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
856 pws3_file_read(struct pws3_file *pws_file, const char *password,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
857 unsigned char *s, size_t n, FILE *fp)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
858 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
859 int retval = -1;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
860 struct pws_file_ctx ctx = {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
861 .fp = fp,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
862 .mem = s,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
863 .mem_size = n,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
864 .mem_pos = 0,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
865 .pws_file = pws_file,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
866 };
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
867
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
868 pws_file_clear(pws_file);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
869
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
870 retval = read_metadata(&ctx, password);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
871 if (retval != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
872 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
873 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
874
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
875 retval = read_header(&ctx);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
876 if (retval != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
877 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
878 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
879
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
880 retval = read_records(&ctx);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
881 if (retval != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
882 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
883 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
884
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
885 retval = verify_checksum(&ctx);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
886 if (retval != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
887 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
888 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
889
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
890 out:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
891 if (retval != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
892 pws_file_clear(ctx.pws_file);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
893 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
894
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
895 return (retval);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
896 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
897
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
898 int
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
899 pws3_file_read_mem(struct pws3_file *pws_file, const char *password,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
900 unsigned char *s, size_t n)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
901 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
902 return (pws3_file_read(pws_file, password, s, n, NULL));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
903 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
904
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
905 int
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
906 pws3_file_read_stream(struct pws3_file *pws_file, const char *password,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
907 FILE *fp)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
908 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
909 return (pws3_file_read(pws_file, password, NULL, 0, fp));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
910 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
911
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
912 static int
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
913 write_metadata(struct pws_file_ctx *ctx, const char *password)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
914 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
915 int retval = -1;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
916 unsigned char *stretched_key = NULL;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
917 unsigned char *key_k = NULL;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
918 unsigned char *key_l = NULL;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
919 unsigned char metadata[METADATA_SIZE];
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
920 unsigned char *p = metadata;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
921 unsigned char *salt;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
922 uint32_t n_iter_le;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
923 struct sha256_ctx md_ctx;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
924 unsigned char *b1;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
925 unsigned char *b3;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
926 unsigned char *iv;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
927 struct twofish_ctx cipher_ctx;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
928
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
929 stretched_key = pws_secure_alloc(SHA256_DIGEST_SIZE);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
930 if (stretched_key == NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
931 pws_set_error(ctx->pws_file, PWS_ERR_NO_MEMORY,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
932 "out of memory");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
933 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
934 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
935
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
936 key_k = pws_secure_alloc(KEY_SIZE);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
937 if (key_k == NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
938 pws_set_error(ctx->pws_file, PWS_ERR_NO_MEMORY,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
939 "out of memory");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
940 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
941 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
942
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
943 key_l = pws_secure_alloc(KEY_SIZE);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
944 if (key_l == NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
945 pws_set_error(ctx->pws_file, PWS_ERR_NO_MEMORY,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
946 "out of memory");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
947 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
948 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
949
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
950 /* generate new keys */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
951 if (pws_random_bytes(key_k, KEY_SIZE) != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
952 pws_set_error(ctx->pws_file, PWS_ERR_GENERIC_ERROR,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
953 "failed to generate key");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
954 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
955 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
956
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
957 if (pws_random_bytes(key_l, KEY_SIZE) != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
958 pws_set_error(ctx->pws_file, PWS_ERR_GENERIC_ERROR,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
959 "failed to generate key");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
960 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
961 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
962
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
963 /* tag */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
964 memcpy(p, psafe3_tag, sizeof (psafe3_tag));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
965 p += sizeof (psafe3_tag);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
966
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
967 /* generate new salt */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
968 salt = p;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
969 if (pws_random_bytes(salt, SALT_SIZE) != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
970 pws_set_error(ctx->pws_file, PWS_ERR_GENERIC_ERROR,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
971 "failed to generate salt");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
972 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
973 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
974 p += SALT_SIZE;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
975
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
976 /* number of iterations */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
977 n_iter_le = htole32(ctx->n_iter);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
978 memcpy(p, &n_iter_le, 4);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
979 p += 4;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
980
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
981 /* stretch, hash password */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
982 stretch_key(stretched_key, ctx->n_iter, password, strlen(password),
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
983 salt, SALT_SIZE);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
984 sha256_init(&md_ctx);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
985 sha256_update(&md_ctx, SHA256_DIGEST_SIZE, stretched_key);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
986 sha256_digest(&md_ctx, SHA256_DIGEST_SIZE, p);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
987 p += SHA256_DIGEST_SIZE;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
988
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
989 b1 = p;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
990 p += KEY_SIZE;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
991
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
992 b3 = p;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
993 p += KEY_SIZE;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
994
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
995 /* generate IV */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
996 iv = p;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
997 if (pws_random_bytes(iv, TWOFISH_BLOCK_SIZE) != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
998 pws_set_error(ctx->pws_file, PWS_ERR_GENERIC_ERROR,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
999 "failed to generate IV");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1000 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1001 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1002
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1003 /* encrypt keys */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1004 twofish_set_key(&cipher_ctx, KEY_SIZE, stretched_key);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1005 twofish_encrypt(&cipher_ctx, KEY_SIZE, b1, key_k);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1006 twofish_encrypt(&cipher_ctx, KEY_SIZE, b3, key_l);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1007
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1008 /* set key for decryption */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1009 twofish_set_key(&ctx->cipher_ctx.ctx, KEY_SIZE, key_k);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1010
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1011 /* set IV */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1012 CBC_SET_IV(&ctx->cipher_ctx, p);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1013
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1014 /* set key for HMAC */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1015 hmac_sha256_set_key(&ctx->hmac_ctx, KEY_SIZE, key_l);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1016
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1017 /* write metadata */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1018 if (write_buf(ctx, metadata, sizeof (metadata)) != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1019 pws_set_system_error(ctx->pws_file, PWS_ERR_IO_ERROR, errno,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1020 NULL);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1021 retval = -1;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1022 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1023 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1024
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1025 retval = 0;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1026
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1027 out:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1028 pws_secure_free(key_k, (key_k != NULL) ? KEY_SIZE : 0);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1029 pws_secure_free(key_l, (key_l != NULL) ? KEY_SIZE : 0);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1030 pws_secure_free(stretched_key, (stretched_key != NULL) ?
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1031 SHA256_DIGEST_SIZE : 0);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1032
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1033 return (retval);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1034 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1035
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1036 static int
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1037 write_block(struct pws_file_ctx *ctx, unsigned char *block)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1038 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1039 unsigned char buf[TWOFISH_BLOCK_SIZE];
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1040
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1041 CBC_ENCRYPT(&ctx->cipher_ctx, twofish_encrypt, sizeof (buf), buf,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1042 block);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1043
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1044 if (write_buf(ctx, buf, sizeof (buf)) != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1045 pws_set_system_error(ctx->pws_file, PWS_ERR_IO_ERROR, errno,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1046 NULL);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1047 return (-1);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1048 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1049
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1050 return (0);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1051 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1052
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1053 static int
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1054 write_field(struct pws_file_ctx *ctx, struct pws3_field *field)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1055 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1056 int retval = -1;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1057 unsigned char *buf = NULL;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1058 unsigned char *p;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1059 unsigned char *field_data;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1060 enum pws_data_type data_type;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1061 size_t blocks = (field->size + 4 + 1) / TWOFISH_BLOCK_SIZE +
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1062 ((field->size + 4 + 1) % TWOFISH_BLOCK_SIZE != 0);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1063 size_t i;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1064 size_t j;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1065 uint32_t len_le;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1066
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1067 buf = pws_secure_alloc(TWOFISH_BLOCK_SIZE);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1068 if (buf == NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1069 pws_set_error(ctx->pws_file, PWS_ERR_NO_MEMORY,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1070 "out of memory");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1071 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1072 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1073
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1074 data_type = pws3_field_get_data_type(field);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1075
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1076 for (i = 0, j = 0; i < blocks; i++) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1077 p = field_data = buf;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1078 if (pws_random_bytes(buf, TWOFISH_BLOCK_SIZE) != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1079 pws_set_error(ctx->pws_file, PWS_ERR_GENERIC_ERROR,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1080 "could not get random numbers");
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1081 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1082 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1083
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1084 /* the first block of the field contains the length and type */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1085 if (i == 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1086 len_le = htole32(field->size);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1087 memcpy(p, &len_le, 4);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1088 p += 4;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1089
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1090 *p = field->field_type;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1091 p++;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1092 field_data = p;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1093 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1094
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1095 while ((j < field->size) &&
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1096 (p - buf < (ptrdiff_t)TWOFISH_BLOCK_SIZE)) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1097 switch (data_type) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1098 case PWS_DATA_TYPE_UINT8:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1099 *p = field->value.uint8;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1100 break;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1101 case PWS_DATA_TYPE_UINT16:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1102 /* little endian */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1103 *p = (field->value.uint16 >> (8 * j)) & 0xff;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1104 break;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1105 case PWS_DATA_TYPE_TIME: /* FALLTHROUGH */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1106 case PWS_DATA_TYPE_UINT32:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1107 /* little endian */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1108 *p = (field->value.uint32 >> (8 * j)) & 0xff;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1109 break;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1110 case PWS_DATA_TYPE_TEXT:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1111 *p = field->value.text[j];
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1112 break;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1113 case PWS_DATA_TYPE_UUID:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1114 *p = field->value.uuid[j];
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1115 break;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1116 default:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1117 *p = field->value.bytes[j];
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1118 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1119
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1120 p++;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1121 j++;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1122 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1123
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1124 hmac_sha256_update(&ctx->hmac_ctx, p - field_data, field_data);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1125
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1126 retval = write_block(ctx, buf);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1127 if (retval != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1128 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1129 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1130 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1131
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1132 retval = 0;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1133
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1134 out:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1135 pws_secure_free(buf, (buf != NULL) ? TWOFISH_BLOCK_SIZE : 0);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1136
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1137 return (retval);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1138 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1139
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1140 static int
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1141 write_header(struct pws_file_ctx *ctx)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1142 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1143 int retval = -1;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1144 size_t i;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1145 struct pws3_field *version_field;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1146 struct pws3_field *field = NULL;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1147 struct pws3_field *end_field = NULL;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1148
9
ec5c1b653ee6 Prevent NULL pointer dereference
Guido Berhoerster <guido+libpws@berhoerster.name>
parents: 0
diff changeset
1149 end_field = pws3_field_create(1, PWS3_HEADER_FIELD_END);
ec5c1b653ee6 Prevent NULL pointer dereference
Guido Berhoerster <guido+libpws@berhoerster.name>
parents: 0
diff changeset
1150 if (end_field == NULL) {
ec5c1b653ee6 Prevent NULL pointer dereference
Guido Berhoerster <guido+libpws@berhoerster.name>
parents: 0
diff changeset
1151 pws_set_system_error(ctx->pws_file, PWS_ERR_NO_MEMORY, errno,
ec5c1b653ee6 Prevent NULL pointer dereference
Guido Berhoerster <guido+libpws@berhoerster.name>
parents: 0
diff changeset
1152 NULL);
ec5c1b653ee6 Prevent NULL pointer dereference
Guido Berhoerster <guido+libpws@berhoerster.name>
parents: 0
diff changeset
1153 goto out;
ec5c1b653ee6 Prevent NULL pointer dereference
Guido Berhoerster <guido+libpws@berhoerster.name>
parents: 0
diff changeset
1154 }
ec5c1b653ee6 Prevent NULL pointer dereference
Guido Berhoerster <guido+libpws@berhoerster.name>
parents: 0
diff changeset
1155
0
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1156 version_field = pws3_file_get_header_field(ctx->pws_file,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1157 PWS3_HEADER_FIELD_VERSION);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1158 if (version_field == NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1159 /* add mandatory version header version_field if necessary */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1160 version_field = pws3_field_create(1, PWS3_HEADER_FIELD_VERSION);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1161 if (version_field == NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1162 pws_set_system_error(ctx->pws_file, PWS_ERR_NO_MEMORY,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1163 errno, NULL);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1164 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1165 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1166 pws3_field_set_uint16(version_field, PWS3_VERSION);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1167 pws3_file_set_header_field(ctx->pws_file, version_field);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1168 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1169 retval = write_field(ctx, version_field);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1170 if (retval != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1171 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1172 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1173
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1174 for (i = 0x01; i < 0xff; i++) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1175 if (ctx->pws_file->fields[i] != NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1176 retval = write_field(ctx, ctx->pws_file->fields[i]);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1177 if (retval != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1178 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1179 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1180 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1181 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1182
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1183 RB_FOREACH(field, empty_groups_tree, ctx->pws_file->empty_groups_tree) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1184 retval = write_field(ctx, field);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1185 if (retval != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1186 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1187 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1188 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1189
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1190 retval = write_field(ctx, end_field);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1191 if (retval != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1192 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1193 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1194
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1195 out:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1196 pws3_field_destroy(end_field);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1197
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1198 return (retval);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1199 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1200
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1201 static int
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1202 write_records(struct pws_file_ctx *ctx)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1203 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1204 int retval = -1;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1205 struct pws3_field *end_field = NULL;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1206 size_t i;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1207 struct pws3_record *record;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1208
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1209 end_field = pws3_field_create(0, PWS3_RECORD_FIELD_END);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1210 if (end_field == NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1211 pws_set_system_error(ctx->pws_file, PWS_ERR_NO_MEMORY, errno,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1212 NULL);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1213 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1214 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1215
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1216 RB_FOREACH(record, records_tree, ctx->pws_file->records_tree) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1217 /* record fields */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1218 for (i = 0x01; i < 0xff; i++) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1219 if (record->fields[i] != NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1220 retval = write_field(ctx, record->fields[i]);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1221 if (retval != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1222 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1223 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1224 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1225 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1226
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1227 /* end of entry marker */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1228 retval = write_field(ctx, end_field);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1229 if (retval != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1230 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1231 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1232 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1233
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1234 /* end of file marker */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1235 if (write_buf(ctx, eof_marker, sizeof (eof_marker)) != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1236 pws_set_system_error(ctx->pws_file, PWS_ERR_IO_ERROR, errno,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1237 NULL);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1238 retval = -1;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1239 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1240 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1241
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1242 retval = 0;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1243
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1244 out:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1245 pws3_field_destroy(end_field);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1246
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1247 return (retval);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1248 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1249
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1250 static int
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1251 write_checksum(struct pws_file_ctx *ctx)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1252 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1253 unsigned char hmac[SHA256_DIGEST_SIZE];
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1254
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1255 hmac_sha256_digest(&ctx->hmac_ctx, sizeof (hmac), hmac);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1256
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1257 if (write_buf(ctx, hmac, sizeof (hmac)) != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1258 pws_set_system_error(ctx->pws_file, PWS_ERR_IO_ERROR, errno,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1259 NULL);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1260 return (-1);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1261 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1262
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1263 return (0);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1264 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1265
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1266 static int
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1267 pws3_file_write(struct pws3_file *pws_file, const char *password,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1268 uint32_t n_iter, unsigned char **memp, size_t *mem_sizep, FILE *fp)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1269 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1270 int retval = -1;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1271 struct pws_file_ctx ctx = {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1272 .fp = fp,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1273 .pws_file = pws_file,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1274 .n_iter = n_iter
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1275 };
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1276
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1277 retval = write_metadata(&ctx, password);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1278 if (retval != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1279 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1280 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1281
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1282 retval = write_header(&ctx);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1283 if (retval != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1284 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1285 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1286
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1287 retval = write_records(&ctx);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1288 if (retval != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1289 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1290 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1291
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1292 retval = write_checksum(&ctx);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1293 if (retval != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1294 goto out;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1295 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1296
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1297 if (memp != NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1298 *memp = ctx.mem;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1299 *mem_sizep = ctx.mem_size;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1300 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1301
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1302 out:
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1303 if (retval != 0) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1304 pws_free(ctx.mem, ctx.mem_size);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1305 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1306
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1307 return (retval);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1308 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1309
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1310 int
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1311 pws3_file_write_mem(struct pws3_file *pws_file, const char *password,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1312 uint32_t n_iter, unsigned char **memp, size_t *mem_sizep)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1313 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1314 PWS_ASSERT(memp != NULL);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1315 PWS_ASSERT(mem_sizep != NULL);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1316
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1317 return (pws3_file_write(pws_file, password, n_iter, memp, mem_sizep,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1318 NULL));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1319 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1320
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1321 int
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1322 pws3_file_write_stream(struct pws3_file *pws_file, const char *password,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1323 uint32_t n_iter, FILE *fp)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1324 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1325 PWS_ASSERT(fp != NULL);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1326
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1327 return (pws3_file_write(pws_file, password, n_iter, NULL, NULL, fp));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1328 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1329
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1330 void
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1331 pws3_file_set_header_field(struct pws3_file *pws_file, struct pws3_field *field)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1332 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1333 PWS_ASSERT(pws3_field_is_header(field));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1334 PWS_ASSERT((pws3_field_get_data_type(field) != PWS_DATA_TYPE_TEXT) ||
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1335 (field->value.text != NULL));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1336 PWS_ASSERT((pws3_field_get_data_type(field) != PWS_DATA_TYPE_BYTES) ||
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1337 (field->value.bytes != NULL));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1338
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1339 if (field->field_type == PWS3_HEADER_FIELD_EMPTY_GROUPS) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1340 pws3_file_insert_empty_group(pws_file, field);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1341 return;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1342 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1343
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1344 pws3_field_destroy(pws3_file_remove_header_field(pws_file,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1345 field->field_type));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1346 pws_file->fields[field->field_type] = field;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1347 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1348
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1349 struct pws3_field *
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1350 pws3_file_get_header_field(struct pws3_file *pws_file, uint8_t field_type)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1351 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1352 if (field_type == PWS3_HEADER_FIELD_EMPTY_GROUPS) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1353 return (pws3_file_first_empty_group(pws_file));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1354 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1355
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1356 return (pws_file->fields[field_type]);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1357 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1358
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1359 struct pws3_field *
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1360 pws3_file_remove_header_field(struct pws3_file *pws_file, uint8_t field_type)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1361 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1362 struct pws3_field *field;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1363
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1364 if (field_type == PWS3_HEADER_FIELD_EMPTY_GROUPS) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1365 return (NULL);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1366 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1367
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1368 field = pws3_file_get_header_field(pws_file, field_type);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1369 pws_file->fields[field_type] = NULL;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1370
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1371 return (field);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1372 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1373
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1374 void
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1375 pws3_file_insert_empty_group(struct pws3_file *pws_file,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1376 struct pws3_field *field)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1377 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1378 const char *group_name;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1379
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1380 PWS_ASSERT(pws3_field_is_header(field));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1381 PWS_ASSERT(pws3_field_get_type(field) ==
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1382 PWS3_HEADER_FIELD_EMPTY_GROUPS);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1383
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1384 group_name = pws3_field_get_text(field);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1385 pws3_field_destroy(pws3_file_remove_empty_group(pws_file, group_name));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1386 RB_INSERT(empty_groups_tree, pws_file->empty_groups_tree, field);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1387 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1388
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1389 struct pws3_field *
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1390 pws3_file_get_empty_group(struct pws3_file *pws_file, const char *group_name)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1391 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1392 return (RB_FIND(empty_groups_tree, pws_file->empty_groups_tree,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1393 (&(struct pws3_field){ .is_header = 1,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1394 .field_type = PWS3_HEADER_FIELD_EMPTY_GROUPS,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1395 .value.text = (char *)group_name })));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1396 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1397
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1398 struct pws3_field *
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1399 pws3_file_remove_empty_group(struct pws3_file *pws_file, const char *group_name)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1400 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1401 struct pws3_field *field;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1402
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1403 field = RB_FIND(empty_groups_tree, pws_file->empty_groups_tree,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1404 (&(struct pws3_field){ .is_header = 1,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1405 .field_type = PWS3_HEADER_FIELD_EMPTY_GROUPS,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1406 .value.text = (char *)group_name }));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1407 if (field != NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1408 RB_REMOVE(empty_groups_tree, pws_file->empty_groups_tree,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1409 field);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1410 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1411
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1412 return (field);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1413 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1414
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1415 struct pws3_field *
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1416 pws3_file_first_empty_group(struct pws3_file *pws_file)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1417 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1418 return (RB_MIN(empty_groups_tree, pws_file->empty_groups_tree));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1419 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1420
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1421 struct pws3_field *
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1422 pws3_file_last_empty_group(struct pws3_file *pws_file)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1423 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1424 return (RB_MAX(empty_groups_tree, pws_file->empty_groups_tree));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1425 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1426
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1427 struct pws3_field *
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1428 pws3_file_next_empty_group(struct pws3_file *pws_file, struct pws3_field *field)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1429 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1430 return (RB_NEXT(empty_groups_tree, pws_file->empty_groups_tree, field));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1431 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1432
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1433 struct pws3_field *
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1434 pws3_file_prev_empty_group(struct pws3_file *pws_file, struct pws3_field *field)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1435 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1436 return (RB_PREV(empty_groups_tree, pws_file->empty_groups_tree, field));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1437 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1438
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1439 void
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1440 pws3_file_insert_record(struct pws3_file *pws_file, struct pws3_record *record)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1441 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1442 struct pws3_field *uuid_field;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1443 const unsigned char *uuid;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1444
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1445 uuid_field = pws3_record_get_field(record, PWS3_RECORD_FIELD_UUID);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1446 PWS_ASSERT(uuid_field != NULL);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1447 uuid = pws3_field_get_uuid(uuid_field);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1448
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1449 /* replace existing record */
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1450 pws3_record_destroy(pws3_file_remove_record(pws_file, uuid));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1451
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1452 RB_INSERT(records_tree, pws_file->records_tree, record);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1453 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1454
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1455 struct pws3_record *
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1456 pws3_file_get_record(struct pws3_file *pws_file,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1457 const unsigned char uuid[static PWS3_UUID_SIZE])
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1458 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1459 struct pws3_field uuid_field = {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1460 .is_header = 0,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1461 .field_type = PWS3_RECORD_FIELD_UUID
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1462 };
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1463 struct pws3_record search_record = {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1464 .fields[PWS3_RECORD_FIELD_UUID] = &uuid_field
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1465 };
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1466
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1467 memcpy(uuid_field.value.uuid, uuid, PWS3_UUID_SIZE);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1468
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1469 return (RB_FIND(records_tree, pws_file->records_tree, &search_record));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1470 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1471
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1472 struct pws3_record *
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1473 pws3_file_remove_record(struct pws3_file *pws_file,
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1474 const unsigned char uuid[static PWS3_UUID_SIZE])
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1475 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1476 struct pws3_record *record;
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1477
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1478 record = pws3_file_get_record(pws_file, uuid);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1479 if (record != NULL) {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1480 RB_REMOVE(records_tree, pws_file->records_tree, record);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1481 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1482
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1483 return (record);
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1484 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1485
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1486 struct pws3_record *
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1487 pws3_file_first_record(struct pws3_file *pws_file)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1488 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1489 return (RB_MIN(records_tree, pws_file->records_tree));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1490 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1491
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1492 struct pws3_record *
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1493 pws3_file_last_record(struct pws3_file *pws_file)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1494 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1495 return (RB_MAX(records_tree, pws_file->records_tree));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1496 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1497
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1498 struct pws3_record *
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1499 pws3_file_next_record(struct pws3_file *pws_file, struct pws3_record *record)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1500 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1501 return (RB_NEXT(records_tree, pws_file->records_tree, record));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1502 }
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1503
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1504 struct pws3_record *
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1505 pws3_file_prev_record(struct pws3_file *pws_file, struct pws3_record *record)
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1506 {
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1507 return (RB_PREV(records_tree, pws_file->records_tree, record));
d541e748cfd8 Initial revision
Guido Berhoerster <guido+libpws@berhoerster.name>
parents:
diff changeset
1508 }