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

Contents of /imapfilter/passwd.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.15 - (show annotations)
Sun Aug 3 16:06:04 2003 UTC (20 years, 7 months ago) by lefcha
Branch: MAIN
CVS Tags: release-0_9
Branch point for: release-0_9-patches
Changes since 1.14: +37 -0 lines
File MIME type: text/plain
Moved store_passwords() from parse.c to passwd.c.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26