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

Annotation of /imapfilter/passwd.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.15 - (hide annotations)
Sun Aug 3 16:06:04 2003 UTC (20 years, 8 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 lefcha 1.1 #include <stdio.h>
2     #include <string.h>
3 lefcha 1.15 #include <errno.h>
4 lefcha 1.2 #include <stdlib.h>
5     #include <limits.h>
6 lefcha 1.15 #include <sys/types.h>
7     #include <sys/stat.h>
8     #include <fcntl.h>
9 lefcha 1.1
10 lefcha 1.2 #include "config.h"
11 lefcha 1.1 #include "imapfilter.h"
12 lefcha 1.15 #include "pathnames.h"
13 lefcha 1.1
14 lefcha 1.2 #ifdef ENCRYPTED_PASSWORDS
15     #include <openssl/evp.h>
16     #endif
17 lefcha 1.1
18    
19 lefcha 1.5 extern unsigned int flags;
20 lefcha 1.2 extern account_t *accounts;
21 lefcha 1.15 extern char *home;
22 lefcha 1.2
23     #ifdef ENCRYPTED_PASSWORDS
24 lefcha 1.3 extern char *passphr;
25 lefcha 1.2 #endif
26 lefcha 1.1
27 lefcha 1.15
28     int store_passwords(account_t ** accts);
29    
30    
31 lefcha 1.1 /*
32     * Get password from user interactively.
33     */
34 lefcha 1.9 void
35     get_password(char *passwd, size_t pwlen)
36 lefcha 1.1 {
37 lefcha 1.9 char *c;
38 lefcha 1.2
39 lefcha 1.9 tty_disable_echo();
40 lefcha 1.8
41 lefcha 1.9 if (fgets(passwd, pwlen, stdin))
42     if ((c = strchr(passwd, '\n')))
43     *c = '\0';
44 lefcha 1.2
45 lefcha 1.9 tty_restore();
46 lefcha 1.1
47 lefcha 1.9 putchar('\n');
48 lefcha 1.1 }
49    
50    
51 lefcha 1.2 #ifdef ENCRYPTED_PASSWORDS
52 lefcha 1.1 /*
53 lefcha 1.9 * Encrypt and Base64 encode passwords. Append the MD5 checksum of the
54     * passwords before encrypting them.
55 lefcha 1.1 */
56 lefcha 1.9 int
57 lefcha 1.12 encrypt_passwords(FILE * fd, account_t ** accts)
58 lefcha 1.1 {
59 lefcha 1.13 int i, n;
60 lefcha 1.9 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 lefcha 1.13 n = 1 + random() % 100000000, 10;
77     snprintf(iv, EVP_MAX_IV_LENGTH, "%08d", n);
78 lefcha 1.11 fprintf(fd, "%s\n", iv);
79 lefcha 1.9
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 lefcha 1.2
96 lefcha 1.9 fwrite(bbuf, sizeof(char), bbufl, fd);
97     }
98 lefcha 1.6
99 lefcha 1.9 EVP_DigestFinal(&mdctx, mdv, &mdl);
100 lefcha 1.2
101 lefcha 1.9 xstrncpy(buf, ".\n", ENCRYPTION_BUF - 1);
102 lefcha 1.8
103 lefcha 1.9 /* MD5 checksum of data. */
104     for (i = 0; i < mdl; i++)
105 lefcha 1.11 snprintf(2 + buf + i * 2, ENCRYPTION_BUF - 3 - i * 2, "%02x",
106 lefcha 1.9 mdv[i]);
107 lefcha 1.8
108 lefcha 1.9 EVP_EncryptUpdate(&ctx, ebuf, &ebufl, buf, strlen(buf));
109     EVP_EncodeUpdate(&bctx, bbuf, &bbufl, ebuf, ebufl);
110     fwrite(bbuf, sizeof(char), bbufl, fd);
111 lefcha 1.8
112 lefcha 1.9 EVP_EncryptFinal(&ctx, ebuf, &ebufl);
113 lefcha 1.11
114 lefcha 1.9 EVP_EncodeUpdate(&bctx, bbuf, &bbufl, ebuf, ebufl);
115 lefcha 1.11 fwrite(bbuf, sizeof(char), bbufl, fd);
116    
117 lefcha 1.9 EVP_EncodeFinal(&bctx, bbuf, &bbufl);
118     fwrite(bbuf, sizeof(char), bbufl, fd);
119 lefcha 1.8
120 lefcha 1.9 EVP_CIPHER_CTX_cleanup(&ctx);
121 lefcha 1.2
122 lefcha 1.9 return 0;
123 lefcha 1.1 }
124    
125    
126     /*
127 lefcha 1.3 * Decode (Base64) passwords, decrypt them and verify the MD5 checksum.
128 lefcha 1.1 */
129 lefcha 1.9 int
130     decrypt_passwords(unsigned char **buf, FILE * fd)
131 lefcha 1.1 {
132 lefcha 1.9 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 lefcha 1.6 }
178 lefcha 1.8
179 lefcha 1.9 EVP_DecodeFinal(&bctx, ebuf, &ebufl);
180     if (!EVP_DecryptFinal(ctx, c, &bufl))
181     goto fail;
182 lefcha 1.2
183 lefcha 1.9 c += bufl;
184     *c = '\0';
185 lefcha 1.6
186 lefcha 1.9 /* Calculate the MD5 checksum and check if it is correct. */
187     if (!(c = strstr(*buf, "\n.\n")))
188     goto fail;
189 lefcha 1.6
190 lefcha 1.9 EVP_DigestInit(&mdctx, EVP_md5());
191     EVP_DigestUpdate(&mdctx, *buf, c - *buf + 1);
192     EVP_DigestFinal(&mdctx, mdv, &mdl);
193 lefcha 1.8
194 lefcha 1.9 for (i = 0; i < mdl; i++)
195     snprintf(mdc + i * 2, EVP_MAX_MD_SIZE * 2 + 1 - i * 2, "%02x",
196     mdv[i]);
197 lefcha 1.8
198 lefcha 1.9 c += 3;
199 lefcha 1.6
200 lefcha 1.9 if (strncmp(c, mdc, 32))
201     goto fail;
202 lefcha 1.2
203 lefcha 1.9 EVP_CIPHER_CTX_cleanup(ctx);
204 lefcha 1.8
205 lefcha 1.9 sfree(key);
206     sfree(ctx);
207 lefcha 1.8
208 lefcha 1.9 return 0;
209 lefcha 1.6
210     fail:
211 lefcha 1.9 error("Wrong master passphrase.\n");
212     EVP_CIPHER_CTX_cleanup(ctx);
213     sfree(*buf);
214     sfree(key);
215     sfree(ctx);
216 lefcha 1.8
217 lefcha 1.9 return ERROR_DECRYPT;
218 lefcha 1.15 }
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 lefcha 1.2 }
246    
247    
248     /*
249     * Interactive encrypted passwords editor.
250     */
251 lefcha 1.9 void
252     password_editor(void)
253 lefcha 1.2 {
254 lefcha 1.12 int i, q, n, pn;
255 lefcha 1.9 char buf[LINE_MAX];
256     char *c;
257     char *p[2];
258 lefcha 1.12 account_t *a, **accts;
259 lefcha 1.9
260     if (!(flags & FLAG_BLANK_PASSWORD)) {
261     error("no candidate passwords for encryption found\n");
262     return;
263 lefcha 1.2 }
264 lefcha 1.12 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 lefcha 1.9
273 lefcha 1.12 memset(accts, 0, (pn + 1) * sizeof(account_t *));
274 lefcha 1.9
275 lefcha 1.12 for (i = 0, a = accounts; a != NULL; a = a->next) {
276 lefcha 1.9 if (a->passwdattr == PASSWORD_NONE ||
277     a->passwdattr == PASSWORD_ENCRYPTED)
278     accts[i++] = a;
279     }
280    
281     do {
282 lefcha 1.10 printf("cmd: ");
283 lefcha 1.9 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 lefcha 1.12 "w\tsave changes\n"
296 lefcha 1.9 "x\tsave and exit\n");
297     else if (*c == 'q')
298     q = 1;
299     else if (*c == 'l')
300 lefcha 1.12 for (i = 0; i < pn; i++)
301 lefcha 1.9 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 lefcha 1.11 if (n == 0 || n < 1 ||
308 lefcha 1.12 n > pn ||
309 lefcha 1.9 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 lefcha 1.11 if (n == 0 || n < 1 ||
320 lefcha 1.12 n > pn ||
321 lefcha 1.9 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 lefcha 1.12 } else if (*c == 'w' || *c == 's') {
340 lefcha 1.9 store_passwords(accts);
341     } else if (*c == 'x') {
342     store_passwords(accts);
343     q = 1;
344     } else
345     break;
346     }
347     } while (!q);
348 lefcha 1.1 }
349 lefcha 1.9 #endif /* ENCRYPTED_PASSWORDS */

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26