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

Annotation of /imapfilter/passwd.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.19 - (hide 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 lefcha 1.1 #include <stdio.h>
2 lefcha 1.16 #include <stdlib.h>
3 lefcha 1.1 #include <string.h>
4 lefcha 1.15 #include <errno.h>
5 lefcha 1.2 #include <limits.h>
6 lefcha 1.15 #include <sys/stat.h>
7 lefcha 1.16 #include <time.h>
8 lefcha 1.1
9 lefcha 1.2 #include "config.h"
10 lefcha 1.1 #include "imapfilter.h"
11 lefcha 1.15 #include "pathnames.h"
12 lefcha 1.1
13 lefcha 1.2 #ifdef ENCRYPTED_PASSWORDS
14     #include <openssl/evp.h>
15     #endif
16 lefcha 1.1
17    
18 lefcha 1.5 extern unsigned int flags;
19 lefcha 1.2 extern account_t *accounts;
20 lefcha 1.15 extern char *home;
21 lefcha 1.2
22     #ifdef ENCRYPTED_PASSWORDS
23 lefcha 1.3 extern char *passphr;
24 lefcha 1.2 #endif
25 lefcha 1.1
26 lefcha 1.15
27     int store_passwords(account_t ** accts);
28    
29    
30 lefcha 1.1 /*
31     * Get password from user interactively.
32     */
33 lefcha 1.9 void
34     get_password(char *passwd, size_t pwlen)
35 lefcha 1.1 {
36 lefcha 1.9 char *c;
37 lefcha 1.2
38 lefcha 1.18 tty_noecho();
39 lefcha 1.8
40 lefcha 1.9 if (fgets(passwd, pwlen, stdin))
41     if ((c = strchr(passwd, '\n')))
42     *c = '\0';
43 lefcha 1.2
44 lefcha 1.9 tty_restore();
45 lefcha 1.1
46 lefcha 1.9 putchar('\n');
47 lefcha 1.1 }
48    
49    
50 lefcha 1.2 #ifdef ENCRYPTED_PASSWORDS
51 lefcha 1.1 /*
52 lefcha 1.9 * Encrypt and Base64 encode passwords. Append the MD5 checksum of the
53     * passwords before encrypting them.
54 lefcha 1.1 */
55 lefcha 1.9 int
56 lefcha 1.12 encrypt_passwords(FILE * fd, account_t ** accts)
57 lefcha 1.1 {
58 lefcha 1.13 int i, n;
59 lefcha 1.9 unsigned char iv[EVP_MAX_IV_LENGTH];
60     unsigned char *key;
61 lefcha 1.18 unsigned char buf[ENCRYPT_BUF];
62     unsigned char ebuf[ENCRYPT_BUF];
63     unsigned char bbuf[ENCRYPT_BUF];
64 lefcha 1.9 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 lefcha 1.13 n = 1 + random() % 100000000, 10;
76     snprintf(iv, EVP_MAX_IV_LENGTH, "%08d", n);
77 lefcha 1.11 fprintf(fd, "%s\n", iv);
78 lefcha 1.9
79     EVP_CIPHER_CTX_init(&ctx);
80    
81 lefcha 1.17 EVP_BytesToKey(EVP_bf_cbc(), EVP_md5(), NULL, passphr,
82     strlen(passphr), 1, key, NULL);
83 lefcha 1.9
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 lefcha 1.18 snprintf(buf, ENCRYPT_BUF, "%s %s %s\n", accts[i]->server,
90     accts[i]->user, accts[i]->pass);
91 lefcha 1.9 EVP_DigestUpdate(&mdctx, buf, strlen(buf));
92     EVP_EncryptUpdate(&ctx, ebuf, &ebufl, buf, strlen(buf));
93     EVP_EncodeUpdate(&bctx, bbuf, &bbufl, ebuf, ebufl);
94 lefcha 1.2
95 lefcha 1.9 fwrite(bbuf, sizeof(char), bbufl, fd);
96     }
97 lefcha 1.6
98 lefcha 1.9 EVP_DigestFinal(&mdctx, mdv, &mdl);
99 lefcha 1.2
100 lefcha 1.18 xstrncpy(buf, ".\n", ENCRYPT_BUF - 1);
101 lefcha 1.8
102 lefcha 1.9 /* MD5 checksum of data. */
103     for (i = 0; i < mdl; i++)
104 lefcha 1.18 snprintf(2 + buf + i * 2, ENCRYPT_BUF - 3 - i * 2, "%02x",
105 lefcha 1.9 mdv[i]);
106 lefcha 1.8
107 lefcha 1.9 EVP_EncryptUpdate(&ctx, ebuf, &ebufl, buf, strlen(buf));
108     EVP_EncodeUpdate(&bctx, bbuf, &bbufl, ebuf, ebufl);
109     fwrite(bbuf, sizeof(char), bbufl, fd);
110 lefcha 1.8
111 lefcha 1.9 EVP_EncryptFinal(&ctx, ebuf, &ebufl);
112 lefcha 1.11
113 lefcha 1.9 EVP_EncodeUpdate(&bctx, bbuf, &bbufl, ebuf, ebufl);
114 lefcha 1.11 fwrite(bbuf, sizeof(char), bbufl, fd);
115    
116 lefcha 1.9 EVP_EncodeFinal(&bctx, bbuf, &bbufl);
117     fwrite(bbuf, sizeof(char), bbufl, fd);
118 lefcha 1.8
119 lefcha 1.9 EVP_CIPHER_CTX_cleanup(&ctx);
120 lefcha 1.2
121 lefcha 1.9 return 0;
122 lefcha 1.1 }
123    
124    
125     /*
126 lefcha 1.3 * Decode (Base64) passwords, decrypt them and verify the MD5 checksum.
127 lefcha 1.1 */
128 lefcha 1.9 int
129     decrypt_passwords(unsigned char **buf, FILE * fd)
130 lefcha 1.1 {
131 lefcha 1.9 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 lefcha 1.18 c = *buf = (unsigned char *)smalloc(DECRYPT_BUF * sizeof(char));
147 lefcha 1.9 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 lefcha 1.18 if (c - *buf > DECRYPT_BUF * j - 64) {
171 lefcha 1.9 i = c - *buf;
172 lefcha 1.18 *buf = (char *)srealloc(*buf, DECRYPT_BUF * ++j);
173 lefcha 1.9 c = *buf + i;
174     *c = '\0';
175     }
176 lefcha 1.6 }
177 lefcha 1.8
178 lefcha 1.9 EVP_DecodeFinal(&bctx, ebuf, &ebufl);
179     if (!EVP_DecryptFinal(ctx, c, &bufl))
180     goto fail;
181 lefcha 1.2
182 lefcha 1.9 c += bufl;
183     *c = '\0';
184 lefcha 1.6
185 lefcha 1.9 /* Calculate the MD5 checksum and check if it is correct. */
186     if (!(c = strstr(*buf, "\n.\n")))
187     goto fail;
188 lefcha 1.6
189 lefcha 1.9 EVP_DigestInit(&mdctx, EVP_md5());
190     EVP_DigestUpdate(&mdctx, *buf, c - *buf + 1);
191     EVP_DigestFinal(&mdctx, mdv, &mdl);
192 lefcha 1.8
193 lefcha 1.9 for (i = 0; i < mdl; i++)
194     snprintf(mdc + i * 2, EVP_MAX_MD_SIZE * 2 + 1 - i * 2, "%02x",
195     mdv[i]);
196 lefcha 1.8
197 lefcha 1.9 c += 3;
198 lefcha 1.6
199 lefcha 1.9 if (strncmp(c, mdc, 32))
200     goto fail;
201 lefcha 1.2
202 lefcha 1.9 EVP_CIPHER_CTX_cleanup(ctx);
203 lefcha 1.8
204 lefcha 1.9 sfree(key);
205     sfree(ctx);
206 lefcha 1.8
207 lefcha 1.9 return 0;
208 lefcha 1.6
209     fail:
210 lefcha 1.9 error("Wrong master passphrase.\n");
211     EVP_CIPHER_CTX_cleanup(ctx);
212     sfree(*buf);
213     sfree(key);
214     sfree(ctx);
215 lefcha 1.8
216 lefcha 1.9 return ERROR_DECRYPT;
217 lefcha 1.15 }
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 lefcha 1.18 snprintf(pwfile, PATH_MAX, "%s/%s", home, PATHNAME_PASSWORDS);
230 lefcha 1.15
231     create_file(pwfile, S_IRUSR | S_IWUSR);
232    
233     fd = fopen(pwfile, "w");
234    
235     if (fd == NULL)
236 lefcha 1.18 fatal(ERROR_FILEOPEN, "opening passwords file %s; %s\n",
237 lefcha 1.15 pwfile, strerror(errno));
238    
239     encrypt_passwords(fd, accts);
240    
241     fclose(fd);
242    
243     return 0;
244 lefcha 1.2 }
245    
246    
247     /*
248     * Interactive encrypted passwords editor.
249     */
250 lefcha 1.9 void
251     password_editor(void)
252 lefcha 1.2 {
253 lefcha 1.12 int i, q, n, pn;
254 lefcha 1.9 char buf[LINE_MAX];
255     char *c;
256     char *p[2];
257 lefcha 1.12 account_t *a, **accts;
258 lefcha 1.9
259 lefcha 1.18 if (!(flags & FLAG_BLANKPASS)) {
260 lefcha 1.9 error("no candidate passwords for encryption found\n");
261     return;
262 lefcha 1.2 }
263 lefcha 1.12 q = pn = 0;
264    
265     for (a = accounts; a != NULL; a = a->next)
266 lefcha 1.18 if (a->pass_attr != PASS_ATTR_PLAIN)
267 lefcha 1.12 pn++;
268    
269     accts = (account_t **) xmalloc((pn + 1) * sizeof(account_t *));
270 lefcha 1.9
271 lefcha 1.12 memset(accts, 0, (pn + 1) * sizeof(account_t *));
272 lefcha 1.9
273 lefcha 1.12 for (i = 0, a = accounts; a != NULL; a = a->next) {
274 lefcha 1.18 if (a->pass_attr != PASS_ATTR_PLAIN)
275 lefcha 1.9 accts[i++] = a;
276     }
277    
278     do {
279 lefcha 1.10 printf("cmd: ");
280 lefcha 1.9 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 lefcha 1.12 "w\tsave changes\n"
293 lefcha 1.9 "x\tsave and exit\n");
294     else if (*c == 'q')
295     q = 1;
296     else if (*c == 'l')
297 lefcha 1.12 for (i = 0; i < pn; i++)
298 lefcha 1.9 printf("%d %s %s %s\n", i + 1,
299     accts[i]->server,
300 lefcha 1.18 accts[i]->user,
301     accts[i]->pass);
302 lefcha 1.9 else if (*c == 'e') {
303     n = atoi(++c);
304 lefcha 1.11 if (n == 0 || n < 1 ||
305 lefcha 1.12 n > pn ||
306 lefcha 1.9 accts[n - 1] == NULL)
307     break;
308 lefcha 1.18 accts[n - 1]->pass[0] = '\0';
309 lefcha 1.9 printf("Enter new password: ");
310 lefcha 1.18 if (fgets(accts[n - 1]->pass, PASS_LEN,
311 lefcha 1.19 stdin) &&
312 lefcha 1.18 (c = strchr(accts[n - 1]->pass, '\n')))
313 lefcha 1.9 *c = '\0';
314     } else if (*c == 'c') {
315     n = atoi(++c);
316 lefcha 1.11 if (n == 0 || n < 1 ||
317 lefcha 1.12 n > pn ||
318 lefcha 1.9 accts[n - 1] == NULL)
319     break;
320 lefcha 1.18 accts[n - 1]->pass[0] = '\0';
321 lefcha 1.9 } 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 lefcha 1.12 } else if (*c == 'w' || *c == 's') {
337 lefcha 1.9 store_passwords(accts);
338     } else if (*c == 'x') {
339     store_passwords(accts);
340     q = 1;
341     } else
342     break;
343     }
344     } while (!q);
345 lefcha 1.1 }
346 lefcha 1.9 #endif /* ENCRYPTED_PASSWORDS */

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26