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

Diff of /imapfilter/passwd.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.8.2.2 by lefcha, Mon May 26 08:14:17 2003 UTC revision 1.19 by lefcha, Sat Feb 14 19:14:43 2004 UTC
# Line 1  Line 1 
1  #include <stdio.h>  #include <stdio.h>
 #include <string.h>  
2  #include <stdlib.h>  #include <stdlib.h>
3    #include <string.h>
4    #include <errno.h>
5  #include <limits.h>  #include <limits.h>
6    #include <sys/stat.h>
7    #include <time.h>
8    
9  #include "config.h"  #include "config.h"
10  #include "imapfilter.h"  #include "imapfilter.h"
11  #include "data.h"  #include "pathnames.h"
12    
13  #ifdef ENCRYPTED_PASSWORDS  #ifdef ENCRYPTED_PASSWORDS
14  #include <openssl/evp.h>  #include <openssl/evp.h>
# Line 14  Line 17 
17    
18  extern unsigned int flags;  extern unsigned int flags;
19  extern account_t *accounts;  extern account_t *accounts;
20    extern char *home;
21    
22  #ifdef ENCRYPTED_PASSWORDS  #ifdef ENCRYPTED_PASSWORDS
23  extern char *passphr;  extern char *passphr;
24  #endif  #endif
25    
26    
27    int store_passwords(account_t ** accts);
28    
29    
30  /*  /*
31   * Get password from user interactively.   * Get password from user interactively.
32   */   */
33  void get_password(char *passwd, size_t pwlen)  void
34    get_password(char *passwd, size_t pwlen)
35  {  {
36      char *c;          char *c;
37    
38      tty_disable_echo();          tty_noecho();
39    
40      if (fgets(passwd, pwlen, stdin))          if (fgets(passwd, pwlen, stdin))
41          if ((c = strchr(passwd, '\n')))                  if ((c = strchr(passwd, '\n')))
42              *c = 0;                          *c = '\0';
43    
44      tty_restore();          tty_restore();
45    
46      putchar('\n');          putchar('\n');
47  }  }
48    
49    
50  #ifdef ENCRYPTED_PASSWORDS  #ifdef ENCRYPTED_PASSWORDS
51  /*  /*
52   * Encrypt and Base64 encode passwords.  Append the MD5 checksum of the passwords   * Encrypt and Base64 encode passwords.  Append the MD5 checksum of the
53   * before encrypting them.   * passwords before encrypting them.
54   */   */
55  int encrypt_passwords(FILE * fd, account_t * accts[])  int
56    encrypt_passwords(FILE * fd, account_t ** accts)
57  {  {
58      int i;          int i, n;
59      char *c;          unsigned char iv[EVP_MAX_IV_LENGTH];
60      unsigned char iv[EVP_MAX_IV_LENGTH];          unsigned char *key;
61      unsigned char *key;          unsigned char buf[ENCRYPT_BUF];
62      unsigned char buf[ENCRYPTION_BUF];          unsigned char ebuf[ENCRYPT_BUF];
63      unsigned char ebuf[ENCRYPTION_BUF];          unsigned char bbuf[ENCRYPT_BUF];
64      unsigned char bbuf[ENCRYPTION_BUF];          unsigned char mdv[EVP_MAX_MD_SIZE];
65      unsigned char mdv[EVP_MAX_MD_SIZE];          int mdl, ebufl, bbufl;
66      int mdl, ebufl, bbufl;          EVP_CIPHER_CTX ctx;
67      EVP_CIPHER_CTX ctx;          EVP_MD_CTX mdctx;
68      EVP_MD_CTX mdctx;          EVP_ENCODE_CTX bctx;
69      EVP_ENCODE_CTX bctx;  
70            key = (unsigned char *)smalloc(EVP_MAX_KEY_LENGTH);
71      key = (unsigned char *)smalloc(EVP_MAX_KEY_LENGTH);  
72            srandom(time(NULL));
73      srandom(time(NULL));  
74            /* Initialization vector. */
75      /* Initialization vector. */          n = 1 + random() % 100000000, 10;
76      c = ultostr(1 + random() % 100000000, 10);          snprintf(iv, EVP_MAX_IV_LENGTH, "%08d", n);
77      snprintf(iv, EVP_MAX_IV_LENGTH, "%08s", c);          fprintf(fd, "%s\n", iv);
78      fprintf(fd, "%s\n", iv);  
79            EVP_CIPHER_CTX_init(&ctx);
80      EVP_CIPHER_CTX_init(&ctx);  
81            EVP_BytesToKey(EVP_bf_cbc(), EVP_md5(), NULL, passphr,
82      EVP_BytesToKey(EVP_bf_cbc(), EVP_md5(), NULL, passphr, strlen(passphr), 1,              strlen(passphr), 1, key, NULL);
83                     key, NULL);  
84            EVP_DigestInit(&mdctx, EVP_md5());
85      EVP_DigestInit(&mdctx, EVP_md5());          EVP_EncryptInit(&ctx, EVP_bf_cbc(), key, iv);
86      EVP_EncryptInit(&ctx, EVP_bf_cbc(), key, iv);          EVP_EncodeInit(&bctx);
87      EVP_EncodeInit(&bctx);  
88            for (i = 0; accts[i] != NULL; i++) {
89      for (i = 0; accts[i]; i++) {                  snprintf(buf, ENCRYPT_BUF, "%s %s %s\n", accts[i]->server,
90          snprintf(buf, ENCRYPTION_BUF, "%s %s %s\n", accts[i]->server, accts[i]->username,                      accts[i]->user, accts[i]->pass);
91                   accts[i]->password);                  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          EVP_DigestUpdate(&mdctx, buf, strlen(buf));                  fwrite(bbuf, sizeof(char), bbufl, fd);
96          EVP_EncryptUpdate(&ctx, ebuf, &ebufl, buf, strlen(buf));          }
         EVP_EncodeUpdate(&bctx, bbuf, &bbufl, ebuf, ebufl);  
   
         fwrite(bbuf, sizeof(char), bbufl, fd);  
     }  
97    
98      EVP_DigestFinal(&mdctx, mdv, &mdl);          EVP_DigestFinal(&mdctx, mdv, &mdl);
99    
100      xstrncpy(buf, ".\n", ENCRYPTION_BUF - 1);          xstrncpy(buf, ".\n", ENCRYPT_BUF - 1);
101    
102      /* MD5 checksum of data. */          /* MD5 checksum of data. */
103      for (i = 0; i < mdl; i++)          for (i = 0; i < mdl; i++)
104          snprintf(2 + buf + i * 2, ENCRYPTION_BUF - 3 - i * 2, "%02x", mdv[i]);                  snprintf(2 + buf + i * 2, ENCRYPT_BUF - 3 - i * 2, "%02x",
105                        mdv[i]);
106    
107      EVP_EncryptUpdate(&ctx, ebuf, &ebufl, buf, strlen(buf));          EVP_EncryptUpdate(&ctx, ebuf, &ebufl, buf, strlen(buf));
108      EVP_EncodeUpdate(&bctx, bbuf, &bbufl, ebuf, ebufl);          EVP_EncodeUpdate(&bctx, bbuf, &bbufl, ebuf, ebufl);
109      fwrite(bbuf, sizeof(char), bbufl, fd);          fwrite(bbuf, sizeof(char), bbufl, fd);
110    
111      EVP_EncryptFinal(&ctx, ebuf, &ebufl);          EVP_EncryptFinal(&ctx, ebuf, &ebufl);
112    
113      EVP_EncodeUpdate(&bctx, bbuf, &bbufl, ebuf, ebufl);          EVP_EncodeUpdate(&bctx, bbuf, &bbufl, ebuf, ebufl);
114      fwrite(bbuf, sizeof(char), bbufl, fd);          fwrite(bbuf, sizeof(char), bbufl, fd);
115    
116      EVP_EncodeFinal(&bctx, bbuf, &bbufl);          EVP_EncodeFinal(&bctx, bbuf, &bbufl);
117      fwrite(bbuf, sizeof(char), bbufl, fd);          fwrite(bbuf, sizeof(char), bbufl, fd);
118    
119      EVP_CIPHER_CTX_cleanup(&ctx);          EVP_CIPHER_CTX_cleanup(&ctx);
120    
121      return 0;          return 0;
122  }  }
123    
124    
125  /*  /*
126   * Decode (Base64) passwords, decrypt them and verify the MD5 checksum.   * Decode (Base64) passwords, decrypt them and verify the MD5 checksum.
127   */   */
128  int decrypt_passwords(unsigned char **buf, FILE * fd)  int
129    decrypt_passwords(unsigned char **buf, FILE * fd)
130  {  {
131      int i, j = 1;          int i, j;
132      unsigned char iv[EVP_MAX_IV_LENGTH];          unsigned char iv[EVP_MAX_IV_LENGTH];
133      unsigned char *key;          unsigned char *key;
134      unsigned char *c;          unsigned char *c;
135      unsigned char ebuf[LINE_MAX];          unsigned char ebuf[LINE_MAX];
136      unsigned char bbuf[LINE_MAX];          unsigned char bbuf[LINE_MAX];
137      unsigned char mdv[EVP_MAX_MD_SIZE];          unsigned char mdv[EVP_MAX_MD_SIZE];
138      unsigned char mdc[EVP_MAX_MD_SIZE * 2 + 1];          unsigned char mdc[EVP_MAX_MD_SIZE * 2 + 1];
139      int mdl, bufl, ebufl;          int mdl, bufl, ebufl;
140      EVP_CIPHER_CTX *ctx;          EVP_CIPHER_CTX *ctx;
141      EVP_MD_CTX mdctx;          EVP_MD_CTX mdctx;
142      EVP_ENCODE_CTX bctx;          EVP_ENCODE_CTX bctx;
143    
144      c = *buf = (unsigned char *)smalloc(DECRYPTION_BUF * sizeof(char));          j = 1;
145      key = (unsigned char *)smalloc(EVP_MAX_KEY_LENGTH);  
146      ctx = (EVP_CIPHER_CTX *) smalloc(sizeof(EVP_CIPHER_CTX));          c = *buf = (unsigned char *)smalloc(DECRYPT_BUF * sizeof(char));
147            key = (unsigned char *)smalloc(EVP_MAX_KEY_LENGTH);
148      fgets(bbuf, LINE_MAX, fd);          ctx = (EVP_CIPHER_CTX *) smalloc(sizeof(EVP_CIPHER_CTX));
149    
150      memcpy(iv, bbuf, EVP_MAX_IV_LENGTH);          fgets(bbuf, LINE_MAX, fd);
151    
152      EVP_CIPHER_CTX_init(ctx);          memcpy(iv, bbuf, EVP_MAX_IV_LENGTH);
153    
154      EVP_BytesToKey(EVP_bf_cbc(), EVP_md5(), NULL, passphr, strlen(passphr),          EVP_CIPHER_CTX_init(ctx);
155                     1, key, NULL);  
156            EVP_BytesToKey(EVP_bf_cbc(), EVP_md5(), NULL, passphr, strlen(passphr),
157      EVP_DecryptInit(ctx, EVP_bf_cbc(), key, iv);              1, key, NULL);
158      EVP_DecodeInit(&bctx);  
159            EVP_DecryptInit(ctx, EVP_bf_cbc(), key, iv);
160      while (fgets(bbuf, LINE_MAX, fd)) {          EVP_DecodeInit(&bctx);
161          EVP_DecodeUpdate(&bctx, ebuf, &ebufl, bbuf, strlen(bbuf));  
162          if (!EVP_DecryptUpdate(ctx, c, &bufl, ebuf, ebufl))          while (fgets(bbuf, LINE_MAX, fd)) {
163              goto fail;                  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;          c += bufl;
183          *c = 0;          *c = '\0';
184    
185          if (c - *buf > DECRYPTION_BUF * j - 64) {          /* Calculate the MD5 checksum and check if it is correct. */
186              i = c - *buf;          if (!(c = strstr(*buf, "\n.\n")))
187              *buf = (char *)srealloc(*buf, DECRYPTION_BUF * ++j);                  goto fail;
             c = *buf + i;  
             *c = 0;  
         }  
     }  
188    
189      EVP_DecodeFinal(&bctx, ebuf, &ebufl);          EVP_DigestInit(&mdctx, EVP_md5());
190      if (!EVP_DecryptFinal(ctx, c, &bufl))          EVP_DigestUpdate(&mdctx, *buf, c - *buf + 1);
191          goto fail;          EVP_DigestFinal(&mdctx, mdv, &mdl);
192    
193      c += bufl;          for (i = 0; i < mdl; i++)
194      *c = 0;                  snprintf(mdc + i * 2, EVP_MAX_MD_SIZE * 2 + 1 - i * 2, "%02x",
195                        mdv[i]);
196    
197      /* Calculate the MD5 checksum and check if it is correct. */          c += 3;
     if (!(c = strstr(*buf, "\n.\n")))  
         goto fail;  
198    
199      EVP_DigestInit(&mdctx, EVP_md5());          if (strncmp(c, mdc, 32))
200      EVP_DigestUpdate(&mdctx, *buf, c - *buf + 1);                  goto fail;
     EVP_DigestFinal(&mdctx, mdv, &mdl);  
201    
202      for (i = 0; i < mdl; i++)          EVP_CIPHER_CTX_cleanup(ctx);
         snprintf(mdc + i * 2, EVP_MAX_MD_SIZE * 2 + 1 - i * 2, "%02x", mdv[i]);  
203    
204      c += 3;          sfree(key);
205            sfree(ctx);
206    
207      if (strncmp(c, mdc, 32))          return 0;
         goto fail;  
208    
209      EVP_CIPHER_CTX_cleanup(ctx);  fail:
210            error("Wrong master passphrase.\n");
211            EVP_CIPHER_CTX_cleanup(ctx);
212            sfree(*buf);
213            sfree(key);
214            sfree(ctx);
215    
216      sfree(key);          return ERROR_DECRYPT;
217      sfree(ctx);  }
218    
     return 0;  
219    
220  fail:  /*
221      error("Wrong master passphrase.\n");   * Store encrypted passwords to file.
222      EVP_CIPHER_CTX_cleanup(ctx);   */
223      sfree(*buf);  int
224      sfree(key);  store_passwords(account_t ** accts)
225      sfree(ctx);  {
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      return ERROR_DECRYPT;          fclose(fd);
242    
243            return 0;
244  }  }
245    
246    
247  /*  /*
248   * Interactive encrypted passwords editor.   * Interactive encrypted passwords editor.
249   */   */
250  void password_editor(void)  void
251    password_editor(void)
252  {  {
253      int i, q, n;          int i, q, n, pn;
254      char buf[LINE_MAX];          char buf[LINE_MAX];
255      char *c;          char *c;
256      char *p[2];          char *p[2];
257      account_t *a, *accts[EDITOR_PASSWORDS_MAX + 1];          account_t *a, **accts;
258    
259      if (!(flags & FLAG_BLANK_PASSWORD)) {          if (!(flags & FLAG_BLANKPASS)) {
260          error("imapfilter: no candidate passwords for encryption found\n");                  error("no candidate passwords for encryption found\n");
261          return;                  return;
     }  
     q = 0;  
   
     memset(accts, 0, (EDITOR_PASSWORDS_MAX + 1) * sizeof(account_t *));  
   
     for (i = 0, a = accounts; i < EDITOR_PASSWORDS_MAX && a; a = a->next) {  
         if (a->passwdattr == PASSWORD_NONE ||  
             a->passwdattr == PASSWORD_ENCRYPTED)  
             accts[i++] = a;  
     }  
   
     do {  
         printf("command: ");  
         fgets(buf, LINE_MAX, stdin);  
         c = buf;  
         for (;; c++) {  
             if (*c == ' ' || *c == '\t')  
                 continue;  
             else if (*c == '?' || *c == 'h')  
                 printf("c       clear a password entry\n"  
                        "e       edit a password entry\n"  
                        "h       help\n"  
                        "l       list entries\n"  
                        "p       change master password\n"  
                        "q       quit without saving\n"  
                        "s       save changes\n"  
                        "x       save and exit\n");  
             else if (*c == 'q')  
                 q = 1;  
             else if (*c == 'l')  
                 for (i = 0; accts[i]; i++)  
                     printf("%d %s %s %s\n", i + 1, accts[i]->server,  
                            accts[i]->username, accts[i]->password);  
             else if (*c == 'e') {  
                 n = atoi(++c);  
                 if (!n || n < 1 || n > EDITOR_PASSWORDS_MAX || !accts[n - 1])  
                     break;  
                 accts[n - 1]->password[0] = 0;  
                 printf("Enter new password: ");  
                 if (fgets(accts[n - 1]->password, PASSWORD_LEN, stdin))  
                     if ((c = strchr(accts[n - 1]->password, '\n')))  
                         *c = 0;  
             } else if (*c == 'c') {  
                 n = atoi(++c);  
                 if (!n || n < 1 || n > EDITOR_PASSWORDS_MAX || !accts[n - 1])  
                     break;  
                 accts[n - 1]->password[0] = 0;  
             } else if (*c == 'p') {  
                 p[0] = (char *)smalloc(PASSPHRASE_LEN);  
                 p[1] = (char *)smalloc(PASSPHRASE_LEN);  
                 do {  
                     for (i = 0; i < 2; i++) {  
                         printf("Enter %snew master password: ",  
                                i ? "again " : "");  
                         get_password(p[i], PASSPHRASE_LEN);  
                     }  
                 } while (strcmp(p[0], p[1]));  
                 xstrncpy(passphr, p[0], PASSPHRASE_LEN - 1);  
                 sfree(p[0]);  
                 sfree(p[1]);  
             } else if (*c == 's') {  
                 store_passwords(accts);  
             } else if (*c == 'x') {  
                 store_passwords(accts);  
                 q = 1;  
             } else  
                 break;  
262          }          }
263      } while (!q);          q = pn = 0;
 }  
264    
265  #endif          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 */

Legend:
Removed from v.1.8.2.2  
changed lines
  Added in v.1.19

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26