|
1 /* |
|
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
|
3 * |
|
4 * Copyright 2018 Olaf Wintermann. All rights reserved. |
|
5 * |
|
6 * Redistribution and use in source and binary forms, with or without |
|
7 * modification, are permitted provided that the following conditions are met: |
|
8 * |
|
9 * 1. Redistributions of source code must retain the above copyright |
|
10 * notice, this list of conditions and the following disclaimer. |
|
11 * |
|
12 * 2. Redistributions in binary form must reproduce the above copyright |
|
13 * notice, this list of conditions and the following disclaimer in the |
|
14 * documentation and/or other materials provided with the distribution. |
|
15 * |
|
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
|
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
|
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
26 * POSSIBILITY OF SUCH DAMAGE. |
|
27 */ |
|
28 |
|
29 #include <stdio.h> |
|
30 #include <stdlib.h> |
|
31 |
|
32 #include <netinet/in.h> |
|
33 |
|
34 #include "pwd.h" |
|
35 |
|
36 #include <ucx/buffer.h> |
|
37 #include <ucx/utils.h> |
|
38 |
|
39 |
|
40 |
|
41 PwdStore* pwdstore_open(const char *file) { |
|
42 FILE *in = fopen(file, "r"); |
|
43 if(!in) { |
|
44 return NULL; |
|
45 } |
|
46 |
|
47 UcxBuffer *buf = ucx_buffer_new(NULL, 2048, UCX_BUFFER_AUTOEXTEND); |
|
48 ucx_stream_copy(in, buf, (read_func)fread, (write_func)ucx_buffer_write); |
|
49 fclose(in); |
|
50 |
|
51 if(buf->size < PWDS_HEADER_SIZE || buf->space[0] != PWDS_MAGIC_CHAR) { |
|
52 ucx_buffer_free(buf); |
|
53 return NULL; |
|
54 } |
|
55 |
|
56 PwdStore *p = malloc(sizeof(PwdStore)); |
|
57 p->pwds = ucx_map_new(16); |
|
58 p->content = buf; |
|
59 p->key = NULL; |
|
60 p->isdecrypted = 0; |
|
61 |
|
62 return p; |
|
63 } |
|
64 |
|
65 PwdStore* pwdstore_new(void) { |
|
66 PwdStore *p = calloc(1, sizeof(PwdStore)); |
|
67 p->pwds = ucx_map_new(16); |
|
68 p->content = ucx_buffer_new(NULL, PWDS_HEADER_SIZE, UCX_BUFFER_AUTOEXTEND); |
|
69 PWDS_MAGIC(p) = PWDS_MAGIC_CHAR; |
|
70 PWDS_VERSION(p) = 1; |
|
71 PWDS_ENC(p) = DAV_KEY_AES256; |
|
72 PWDS_PWFUNC(p) = DAV_PWFUNC_PBKDF2_SHA256; |
|
73 dav_rand_bytes(p->content->space+4, 16); |
|
74 return p; |
|
75 } |
|
76 |
|
77 static int read_pwdentry(PwdStore *p, UcxBuffer *in) { |
|
78 int type = ucx_buffer_getc(in); |
|
79 if(type == EOF || type != 0) { |
|
80 // only type 0 supported yet |
|
81 return 0; |
|
82 } |
|
83 |
|
84 uint32_t ulen = 0; |
|
85 uint32_t plen = 0; |
|
86 |
|
87 if(ucx_buffer_read(&ulen, 1, sizeof(uint32_t), in) != sizeof(uint32_t)) { |
|
88 return 0; |
|
89 } |
|
90 ulen = ntohl(ulen); |
|
91 if(ulen == 0 || ulen > PWDSTORE_MAX_LEN) { |
|
92 return 0; |
|
93 } |
|
94 |
|
95 char *user = malloc(ulen+1); |
|
96 user[ulen] = 0; |
|
97 if(ucx_buffer_read(user, 1, ulen, in) != ulen) { |
|
98 free(user); |
|
99 return 0; |
|
100 } |
|
101 |
|
102 if(ucx_buffer_read(&plen, 1, sizeof(uint32_t), in) != sizeof(uint32_t)) { |
|
103 return 0; |
|
104 } |
|
105 plen = ntohl(plen); |
|
106 if(plen == 0 || plen > PWDSTORE_MAX_LEN) { |
|
107 return 0; |
|
108 } |
|
109 char *password = malloc(plen+1); |
|
110 password[plen] = 0; |
|
111 if(ucx_buffer_read(password, 1, plen, in) != plen) { |
|
112 free(user); |
|
113 free(password); |
|
114 return 0; |
|
115 } |
|
116 |
|
117 pwdstore_put(p, user, password); |
|
118 free(user); |
|
119 free(password); |
|
120 return 1; |
|
121 |
|
122 } |
|
123 |
|
124 int pwdstore_decrypt(PwdStore *p) { |
|
125 if(!p->key) { |
|
126 return 1; |
|
127 } |
|
128 |
|
129 // decrypt contet |
|
130 size_t encsz = p->content->size - PWDS_HEADER_SIZE; |
|
131 UcxBuffer *enc = ucx_buffer_new(p->content->space + PWDS_HEADER_SIZE, encsz, 0); |
|
132 enc->size = encsz; |
|
133 enc->size = p->content->size - PWDS_HEADER_SIZE; |
|
134 UcxBuffer *content = aes_decrypt_buffer(enc, p->key); |
|
135 ucx_buffer_free(enc); |
|
136 if(!content) { |
|
137 return 1; |
|
138 } |
|
139 |
|
140 while(read_pwdentry(p, content)) {} |
|
141 |
|
142 ucx_buffer_free(content); |
|
143 |
|
144 return 0; |
|
145 } |
|
146 |
|
147 int pwdstore_setpassword(PwdStore *p, const char *password) { |
|
148 DavKey *key = dav_pw2key( |
|
149 password, |
|
150 p->content->space + 4, |
|
151 16, |
|
152 PWDS_PWFUNC(p), |
|
153 PWDS_ENC(p)); |
|
154 if(!key) { |
|
155 return 1; |
|
156 } |
|
157 |
|
158 p->key = key; |
|
159 return 0; |
|
160 } |
|
161 |
|
162 void pwdstore_encsettings(PwdStore *p, uint8_t enc, uint8_t pwfunc) { |
|
163 PWDS_ENC(p) = enc; |
|
164 PWDS_PWFUNC(p) = pwfunc; |
|
165 } |
|
166 |
|
167 static void free_entry(PwdEntry *e) { |
|
168 free(e->user); |
|
169 free(e->password); |
|
170 free(e); |
|
171 } |
|
172 |
|
173 void pwdstore_free(PwdStore* p) { |
|
174 ucx_map_free_content(p->pwds, (ucx_destructor)free_entry); |
|
175 ucx_map_free(p->pwds); |
|
176 |
|
177 if(p->content) { |
|
178 ucx_buffer_free(p->content); |
|
179 } |
|
180 |
|
181 free(p); |
|
182 } |
|
183 |
|
184 PwdEntry* pwdstore_get(PwdStore *p, const char *username) { |
|
185 return ucx_map_cstr_get(p->pwds, username); |
|
186 } |
|
187 |
|
188 void pwdstore_put(PwdStore *p, const char *username, const char *password) { |
|
189 PwdEntry *entry = malloc(sizeof(PwdEntry)); |
|
190 entry->user = strdup(username); |
|
191 entry->password = strdup(password); |
|
192 ucx_map_cstr_put(p->pwds, entry->user, entry); |
|
193 } |
|
194 |
|
195 int pwdstore_store(PwdStore *p, const char *file) { |
|
196 if(!p->key) { |
|
197 return 1; |
|
198 } |
|
199 |
|
200 UcxBuffer *content = ucx_buffer_new(NULL, 2048, UCX_BUFFER_AUTOEXTEND); |
|
201 |
|
202 UcxMapIterator i = ucx_map_iterator(p->pwds); |
|
203 PwdEntry *value; |
|
204 UCX_MAP_FOREACH(key, value, i) { |
|
205 ucx_buffer_putc(content, 0); // type |
|
206 uint32_t ulen = strlen(value->user); |
|
207 uint32_t plen = strlen(value->password); |
|
208 uint32_t netulen = htonl(ulen); |
|
209 uint32_t netplen = htonl(plen); |
|
210 ucx_buffer_write(&netulen, 1, sizeof(uint32_t), content); |
|
211 ucx_buffer_write(value->user, 1, ulen, content); |
|
212 ucx_buffer_write(&netplen, 1, sizeof(uint32_t), content); |
|
213 ucx_buffer_write(value->password, 1, plen, content); |
|
214 } |
|
215 |
|
216 content->pos = 0; |
|
217 UcxBuffer *enc = aes_encrypt_buffer(content, p->key); |
|
218 |
|
219 p->content->pos = PWDS_HEADER_SIZE; |
|
220 p->content->size = PWDS_HEADER_SIZE; |
|
221 ucx_buffer_write(enc->space, 1, enc->size, p->content); |
|
222 |
|
223 ucx_buffer_free(enc); |
|
224 |
|
225 FILE *out = fopen(file, "w"); |
|
226 if(!out) { |
|
227 return 1; |
|
228 } |
|
229 fwrite(p->content->space, 1, p->content->size, out); |
|
230 fclose(out); |
|
231 |
|
232 return 0; |
|
233 } |