/[imapfilter]/imapfilter/passwd.c
ViewVC logotype

Contents of /imapfilter/passwd.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.19 - (show annotations)
Sat Feb 14 19:14:43 2004 UTC (20 years, 1 month ago) by lefcha
Branch: MAIN
CVS Tags: HEAD
Changes since 1.18: +1 -1 lines
File MIME type: text/plain
Indentation.

1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <limits.h>
6 #include <sys/stat.h>
7 #include <time.h>
8
9 #include "config.h"
10 #include "imapfilter.h"
11 #include "pathnames.h"
12
13 #ifdef ENCRYPTED_PASSWORDS
14 #include <openssl/evp.h>
15 #endif
16
17
18 extern unsigned int flags;
19 extern account_t *accounts;
20 extern char *home;
21
22 #ifdef ENCRYPTED_PASSWORDS
23 extern char *passphr;
24 #endif
25
26
27 int store_passwords(account_t ** accts);
28
29
30 /*
31 * Get password from user interactively.
32 */
33 void
34 get_password(char *passwd, size_t pwlen)
35 {
36 char *c;
37
38 tty_noecho();
39
40 if (fgets(passwd, pwlen, stdin))
41 if ((c = strchr(passwd, '\n')))
42 *c = '\0';
43
44 tty_restore();
45
46 putchar('\n');
47 }
48
49
50 #ifdef ENCRYPTED_PASSWORDS
51 /*
52 * Encrypt and Base64 encode passwords. Append the MD5 checksum of the
53 * passwords before encrypting them.
54 */
55 int
56 encrypt_passwords(FILE * fd, account_t ** accts)
57 {
58 int i, n;
59 unsigned char iv[EVP_MAX_IV_LENGTH];
60 unsigned char *key;
61 unsigned char buf[ENCRYPT_BUF];
62 unsigned char ebuf[ENCRYPT_BUF];
63 unsigned char bbuf[ENCRYPT_BUF];
64 unsigned char mdv[EVP_MAX_MD_SIZE];
65 int mdl, ebufl, bbufl;
66 EVP_CIPHER_CTX ctx;
67 EVP_MD_CTX mdctx;
68 EVP_ENCODE_CTX bctx;
69
70 key = (unsigned char *)smalloc(EVP_MAX_KEY_LENGTH);
71
72 srandom(time(NULL));
73
74 /* Initialization vector. */
75 n = 1 + random() % 100000000, 10;
76 snprintf(iv, EVP_MAX_IV_LENGTH, "%08d", n);
77 fprintf(fd, "%s\n", iv);
78
79 EVP_CIPHER_CTX_init(&ctx);
80
81 EVP_BytesToKey(EVP_bf_cbc(), EVP_md5(), NULL, passphr,
82 strlen(passphr), 1, key, NULL);
83
84 EVP_DigestInit(&mdctx, EVP_md5());
85 EVP_EncryptInit(&ctx, EVP_bf_cbc(), key, iv);
86 EVP_EncodeInit(&bctx);
87
88 for (i = 0; accts[i] != NULL; i++) {
89 snprintf(buf, ENCRYPT_BUF, "%s %s %s\n", accts[i]->server,
90 accts[i]->user, accts[i]->pass);
91 EVP_DigestUpdate(&mdctx, buf, strlen(buf));
92 EVP_EncryptUpdate(&ctx, ebuf, &ebufl, buf, strlen(buf));
93 EVP_EncodeUpdate(&bctx, bbuf, &bbufl, ebuf, ebufl);
94
95 fwrite(bbuf, sizeof(char), bbufl, fd);
96 }
97
98 EVP_DigestFinal(&mdctx, mdv, &mdl);
99
100 xstrncpy(buf, ".\n", ENCRYPT_BUF - 1);
101
102 /* MD5 checksum of data. */
103 for (i = 0; i < mdl; i++)
104 snprintf(2 + buf + i * 2, ENCRYPT_BUF - 3 - i * 2, "%02x",
105 mdv[i]);
106
107 EVP_EncryptUpdate(&ctx, ebuf, &ebufl, buf, strlen(buf));
108 EVP_EncodeUpdate(&bctx, bbuf, &bbufl, ebuf, ebufl);
109 fwrite(bbuf, sizeof(char), bbufl, fd);
110
111 EVP_EncryptFinal(&ctx, ebuf, &ebufl);
112
113 EVP_EncodeUpdate(&bctx, bbuf, &bbufl, ebuf, ebufl);
114 fwrite(bbuf, sizeof(char), bbufl, fd);
115
116 EVP_EncodeFinal(&bctx, bbuf, &bbufl);
117 fwrite(bbuf, sizeof(char), bbufl, fd);
118
119 EVP_CIPHER_CTX_cleanup(&ctx);
120
121 return 0;
122 }
123
124
125 /*
126 * Decode (Base64) passwords, decrypt them and verify the MD5 checksum.
127 */
128 int
129 decrypt_passwords(unsigned char **buf, FILE * fd)
130 {
131 int i, j;
132 unsigned char iv[EVP_MAX_IV_LENGTH];
133 unsigned char *key;
134 unsigned char *c;
135 unsigned char ebuf[LINE_MAX];
136 unsigned char bbuf[LINE_MAX];
137 unsigned char mdv[EVP_MAX_MD_SIZE];
138 unsigned char mdc[EVP_MAX_MD_SIZE * 2 + 1];
139 int mdl, bufl, ebufl;
140 EVP_CIPHER_CTX *ctx;
141 EVP_MD_CTX mdctx;
142 EVP_ENCODE_CTX bctx;
143
144 j = 1;
145
146 c = *buf = (unsigned char *)smalloc(DECRYPT_BUF * sizeof(char));
147 key = (unsigned char *)smalloc(EVP_MAX_KEY_LENGTH);
148 ctx = (EVP_CIPHER_CTX *) smalloc(sizeof(EVP_CIPHER_CTX));
149
150 fgets(bbuf, LINE_MAX, fd);
151
152 memcpy(iv, bbuf, EVP_MAX_IV_LENGTH);
153
154 EVP_CIPHER_CTX_init(ctx);
155
156 EVP_BytesToKey(EVP_bf_cbc(), EVP_md5(), NULL, passphr, strlen(passphr),
157 1, key, NULL);
158
159 EVP_DecryptInit(ctx, EVP_bf_cbc(), key, iv);
160 EVP_DecodeInit(&bctx);
161
162 while (fgets(bbuf, LINE_MAX, fd)) {
163 EVP_DecodeUpdate(&bctx, ebuf, &ebufl, bbuf, strlen(bbuf));
164 if (!EVP_DecryptUpdate(ctx, c, &bufl, ebuf, ebufl))
165 goto fail;
166
167 c += bufl;
168 *c = '\0';
169
170 if (c - *buf > DECRYPT_BUF * j - 64) {
171 i = c - *buf;
172 *buf = (char *)srealloc(*buf, DECRYPT_BUF * ++j);
173 c = *buf + i;
174 *c = '\0';
175 }
176 }
177
178 EVP_DecodeFinal(&bctx, ebuf, &ebufl);
179 if (!EVP_DecryptFinal(ctx, c, &bufl))
180 goto fail;
181
182 c += bufl;
183 *c = '\0';
184
185 /* Calculate the MD5 checksum and check if it is correct. */
186 if (!(c = strstr(*buf, "\n.\n")))
187 goto fail;
188
189 EVP_DigestInit(&mdctx, EVP_md5());
190 EVP_DigestUpdate(&mdctx, *buf, c - *buf + 1);
191 EVP_DigestFinal(&mdctx, mdv, &mdl);
192
193 for (i = 0; i < mdl; i++)
194 snprintf(mdc + i * 2, EVP_MAX_MD_SIZE * 2 + 1 - i * 2, "%02x",
195 mdv[i]);
196
197 c += 3;
198
199 if (strncmp(c, mdc, 32))
200 goto fail;
201
202 EVP_CIPHER_CTX_cleanup(ctx);
203
204 sfree(key);
205 sfree(ctx);
206
207 return 0;
208
209 fail:
210 error("Wrong master passphrase.\n");
211 EVP_CIPHER_CTX_cleanup(ctx);
212 sfree(*buf);
213 sfree(key);
214 sfree(ctx);
215
216 return ERROR_DECRYPT;
217 }
218
219
220 /*
221 * Store encrypted passwords to file.
222 */
223 int
224 store_passwords(account_t ** accts)
225 {
226 char pwfile[PATH_MAX];
227 FILE *fd;
228
229 snprintf(pwfile, PATH_MAX, "%s/%s", home, PATHNAME_PASSWORDS);
230
231 create_file(pwfile, S_IRUSR | S_IWUSR);
232
233 fd = fopen(pwfile, "w");
234
235 if (fd == NULL)
236 fatal(ERROR_FILEOPEN, "opening passwords file %s; %s\n",
237 pwfile, strerror(errno));
238
239 encrypt_passwords(fd, accts);
240
241 fclose(fd);
242
243 return 0;
244 }
245
246
247 /*
248 * Interactive encrypted passwords editor.
249 */
250 void
251 password_editor(void)
252 {
253 int i, q, n, pn;
254 char buf[LINE_MAX];
255 char *c;
256 char *p[2];
257 account_t *a, **accts;
258
259 if (!(flags & FLAG_BLANKPASS)) {
260 error("no candidate passwords for encryption found\n");
261 return;
262 }
263 q = pn = 0;
264
265 for (a = accounts; a != NULL; a = a->next)
266 if (a->pass_attr != PASS_ATTR_PLAIN)
267 pn++;
268
269 accts = (account_t **) xmalloc((pn + 1) * sizeof(account_t *));
270
271 memset(accts, 0, (pn + 1) * sizeof(account_t *));
272
273 for (i = 0, a = accounts; a != NULL; a = a->next) {
274 if (a->pass_attr != PASS_ATTR_PLAIN)
275 accts[i++] = a;
276 }
277
278 do {
279 printf("cmd: ");
280 fgets(buf, LINE_MAX, stdin);
281 c = buf;
282 for (;; c++) {
283 if (*c == ' ' || *c == '\t')
284 continue;
285 else if (*c == '?' || *c == 'h')
286 printf("c\tclear a password entry\n"
287 "e\tedit a password entry\n"
288 "h\thelp\n"
289 "l\tlist entries\n"
290 "p\tchange master password\n"
291 "q\tquit without saving\n"
292 "w\tsave changes\n"
293 "x\tsave and exit\n");
294 else if (*c == 'q')
295 q = 1;
296 else if (*c == 'l')
297 for (i = 0; i < pn; i++)
298 printf("%d %s %s %s\n", i + 1,
299 accts[i]->server,
300 accts[i]->user,
301 accts[i]->pass);
302 else if (*c == 'e') {
303 n = atoi(++c);
304 if (n == 0 || n < 1 ||
305 n > pn ||
306 accts[n - 1] == NULL)
307 break;
308 accts[n - 1]->pass[0] = '\0';
309 printf("Enter new password: ");
310 if (fgets(accts[n - 1]->pass, PASS_LEN,
311 stdin) &&
312 (c = strchr(accts[n - 1]->pass, '\n')))
313 *c = '\0';
314 } else if (*c == 'c') {
315 n = atoi(++c);
316 if (n == 0 || n < 1 ||
317 n > pn ||
318 accts[n - 1] == NULL)
319 break;
320 accts[n - 1]->pass[0] = '\0';
321 } else if (*c == 'p') {
322 p[0] = (char *)smalloc(PASSPHRASE_LEN);
323 p[1] = (char *)smalloc(PASSPHRASE_LEN);
324 do {
325 for (i = 0; i < 2; i++) {
326 printf("Enter %snew master "
327 "password: ",
328 i ? "again " : "");
329 get_password(p[i],
330 PASSPHRASE_LEN);
331 }
332 } while (strcmp(p[0], p[1]));
333 xstrncpy(passphr, p[0], PASSPHRASE_LEN - 1);
334 sfree(p[0]);
335 sfree(p[1]);
336 } else if (*c == 'w' || *c == 's') {
337 store_passwords(accts);
338 } else if (*c == 'x') {
339 store_passwords(accts);
340 q = 1;
341 } else
342 break;
343 }
344 } while (!q);
345 }
346 #endif /* ENCRYPTED_PASSWORDS */

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26