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

Diff of /imapfilter/file.c

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

revision 1.43.2.2 by lefcha, Mon Aug 26 20:18:14 2002 UTC revision 1.63 by lefcha, Fri Feb 13 12:17:15 2004 UTC
# Line 1  Line 1 
1  #include <stdio.h>  #include <stdio.h>
2  #include <unistd.h>  #include <unistd.h>
 #include <errno.h>  
 #include <sys/types.h>  
 #include <regex.h>  
3  #include <string.h>  #include <string.h>
4  #include <stdlib.h>  #include <errno.h>
5  #include <limits.h>  #include <limits.h>
6    #include <sys/types.h>
7  #include <sys/stat.h>  #include <sys/stat.h>
8  #include <fcntl.h>  #include <fcntl.h>
 #include <time.h>  
9    
10  #include "config.h"  #include "config.h"
11  #include "imapfilter.h"  #include "imapfilter.h"
12  #include "data.h"  #include "pathnames.h"
13    
14    
 extern char logfile[PATH_MAX];  
 extern unsigned int options;  
 extern unsigned int flags;  
 extern unsigned int interval;  
 extern long timeout;  
15  extern char *home;  extern char *home;
16    extern options_t opts;
 #ifdef ENCRYPTED_PASSWORDS  
 char *passphr;                  /* Master password to access the passwords  
                                    file. */  
 #endif  
   
   
 /*  
  * Find the path to configuration file, open it and call parse_config().  
  */  
 int read_config(char *cfg)  
 {  
     int r;  
     FILE *fd;  
     char *c = NULL;  
   
     if (!cfg) {  
         cfg = c = (char *)xmalloc(PATH_MAX * sizeof(char));  
         snprintf(cfg, PATH_MAX, "%s/%s", home, ".imapfilterrc");  
     }  
 #ifdef DEBUG  
     printf("debug: configuration file: '%s'\n", cfg);  
 #endif  
 #ifdef CHECK_PERMISSIONS  
     check_file_perms(cfg, S_IRUSR | S_IWUSR);  
 #endif  
     fd = fopen(cfg, "r");  
   
     if (!fd)  
         fatal(ERROR_FILE_OPEN, "imapfilter: opening config file %s; %s\n",  
               cfg, strerror(errno));  
   
     if (c)  
         xfree(c);  
   
     if ((r = parse_config(fd)))  
         fatal(ERROR_CONFIG_PARSE,  
               "imapfilter: parse error in config file at row %d\n", r);  
   
     fclose(fd);  
   
 #ifdef DEBUG  
     printf("debug: options: %0#10x\n", options);  
 #endif  
   
     return 0;  
 }  
   
   
 /*  
  * Parse configuration file.  
  */  
 int parse_config(FILE * fd)  
 {  
     int i, r = 0;  
     unsigned int row = 0;  
     char line[LINE_MAX];  
     regex_t creg[13];  
     regmatch_t match[11];  
     const char *reg[13] = {  
         "^([[:blank:]]*\n|#.*\n)$",  
   
         "^[[:blank:]]*ACCOUNT[[:blank:]]+([[:alnum:]_-]+)[[:blank:]]+"  
         "(([[:graph:]]+):([[:graph:]]*)|([[:graph:]]+))@([[:alnum:].-]+)"  
         "(:[[:digit:]]+)?[[:blank:]]*([[:blank:]]SSL|[[:blank:]]SSL2|"  
         "[[:blank:]]SSL3|[[:blank:]]TLS1)?[[:blank:]]*\n$",  
   
         "^[[:blank:]]*FOLDER[[:blank:]]+([[:alnum:]_-]+)[[:blank:]]+"  
         "([[:print:]]+)[[:blank:]]*\n$",  
   
         "^[[:blank:]]*FILTER[[:blank:]]+([[:alnum:]_-]+)[[:blank:]]*"  
         "([[:blank:]]OR|[[:blank:]]AND)?[[:blank:]]*\n$",  
   
         "^[[:blank:]]*ACTION[[:blank:]]+(DELETE|"  
         "COPY[[:blank:]]+(\"[[:print:]]*\"|[[:graph:]]+)|"  
         "MOVE[[:blank:]]+(\"[[:print:]]*\"|[[:graph:]]+)|"  
         "RCOPY[[:blank:]]+([[:alnum:]_-]+)[[:blank:]]+"  
         "(\"[[:print:]]*\"|[[:graph:]]+)|"  
         "RMOVE[[:blank:]]+([[:alnum:]_-]+)[[:blank:]]+"  
         "(\"[[:print:]]*\"|[[:graph:]]+)|"  
         "FLAG[[:blank:]]+(REPLACE|ADD|REMOVE)[[:blank:]]+"  
         "([[:alpha:],]+)|"  
         "LIST)[[:blank:]]*([[:graph:]]*)[[:blank:]]*\n$",  
   
         "^[[:blank:]]*(MASK[[:blank:]])?[[:blank:]]*(OR[[:blank:]]|"  
         "AND[[:blank:]])?[[:blank:]]*(NOT[[:blank:]])?[[:blank:]]*"  
         "(ANSWERED|DELETED|DRAFT|FLAGGED|NEW|OLD|RECENT|SEEN|UNANSWERED|"  
         "UNDELETED|UNDRAFT|UNFLAGGED|UNSEEN)[[:blank:]]*\n$",  
   
         "^[[:blank:]]*(MASK[[:blank:]])?[[:blank:]]*(OR[[:blank:]]|"  
         "AND[[:blank:]])?[[:blank:]]*(NOT[[:blank:]])?[[:blank:]]*"  
         "(BCC|BODY|CC|FROM|SUBJECT|TEXT|TO)[[:blank:]]+(\"[[:print:]]*\"|"  
         "[[:graph:]]+)[[:blank:]]*\n$",  
   
         "^[[:blank:]]*(MASK[[:blank:]])?[[:blank:]]*(OR[[:blank:]]|"  
         "AND[[:blank:]])?[[:blank:]]*(NOT[[:blank:]])?[[:blank:]]*"  
         "(HEADER)[[:blank:]]+(\"[[:print:]]*\"|[[:graph:]]+)[[:blank:]]+"  
         "(\"[[:print:]]*\"|[[:graph:]]+)[[:blank:]]*\n$",  
   
         "^[[:blank:]]*(MASK[[:blank:]])?[[:blank:]]*(OR[[:blank:]]|"  
         "AND[[:blank:]])?[[:blank:]]*(NOT[[:blank:]])?[[:blank:]]*"  
         "(LARGER|SMALLER|OLDER|NEWER)[[:blank:]]+([[:digit:]]+)"  
         "[[:blank:]]*\n$",  
   
         "^[[:blank:]]*JOB[[:blank:]]+([[:alnum:],_-]+)[[:blank:]]+"  
         "([[:alnum:],_-]+)[[:blank:]]*\n$",  
   
         "^[[:blank:]]*(SET[[:blank:]])?[[:blank:]]*(LOGFILE)"  
         "[[:blank:]]*=[[:blank:]]*([[:print:]]+)\n$",  
   
         "^[[:blank:]]*(SET[[:blank:]])?[[:blank:]]*(ERRORS|EXPUNGE|HEADERS|"  
         "NAMESPACE|SUBSCRIBE|WARNING)[[:blank:]]*=[[:blank:]]*(YES|NO)"  
         "[[:blank:]]*\n$",  
   
         "^[[:blank:]]*(SET[[:blank:]])?[[:blank:]]*(DAEMON|TIMEOUT)"  
         "[[:blank:]]*=[[:blank:]]*([[:digit:]]+)\n$"  
     };  
   
     for (i = 0; i < 13; i++)  
         regcomp(&creg[i], reg[i], REG_EXTENDED | REG_ICASE);  
   
     /* First process all the variables.  This is done because some variables'  
        arguments are used before the other commands are processed. */  
     while (fgets(line, LINE_MAX - 1, fd))  
         if (!regexec(&creg[10], line, 4, match, 0) ||  
             !regexec(&creg[11], line, 4, match, 0) ||  
             !regexec(&creg[12], line, 4, match, 0))  
             set_options(line, match);  
   
     /* Then rewind and process everything else. */  
     fseek(fd, 0L, SEEK_SET);  
     while (fgets(line, LINE_MAX - 1, fd)) {  
         row++;  
         if (!regexec(&creg[0], line, 0, match, 0))  
             continue;  
         else if (!regexec(&creg[1], line, 9, match, 0))  
             set_account(line, match);  
         else if (!regexec(&creg[2], line, 3, match, 0))  
             r = set_mboxgrp(line, match);  
         else if (!regexec(&creg[3], line, 3, match, 0))  
             r = set_filter(line, match);  
         else if (!regexec(&creg[4], line, 11, match, 0))  
             r = set_action(line, match);  
         else if (!regexec(&creg[5], line, 5, match, 0))  
             r = set_mask(line, match, MASK_MATCH_1);  
         else if (!regexec(&creg[6], line, 6, match, 0))  
             r = set_mask(line, match, MASK_MATCH_2);  
         else if (!regexec(&creg[7], line, 7, match, 0))  
             r = set_mask(line, match, MASK_MATCH_3);  
         else if (!regexec(&creg[8], line, 6, match, 0))  
             r = set_mask(line, match, MASK_MATCH_4);  
         else if (!regexec(&creg[9], line, 3, match, 0))  
             r = set_job(line, match);  
         /* Skip variable processing. */  
         else if (!regexec(&creg[10], line, 4, match, 0) ||  
                  !regexec(&creg[11], line, 4, match, 0) ||  
                  !regexec(&creg[12], line, 4, match, 0));  
         else  
             return row;  
   
         if (r == ERROR_CONFIG_PARSE)  
             return row;  
     }  
   
     for (i = 0; i < 13; i++)  
         regfree(&creg[i]);  
   
     destroy_data();  
   
     return 0;  
 }  
17    
18    
19  /*  /*
20   * Set other options found in config file.   * Create imapfilter's home directory.
21   */   */
22  void set_options(char *line, regmatch_t * match)  int
23    create_homedir(void)
24  {  {
25      if (!strncasecmp(line + match[2].rm_so, "logfile", 7)) {          char hd[PATH_MAX];
         if (!*logfile)  
             strncat(logfile, line + match[3].rm_so,  
                     min((match[3].rm_eo - match[3].rm_so), PATH_MAX - 1));  
     } else if (!strncasecmp(line + match[2].rm_so, "errors", 6)) {  
         if (!strncasecmp(line + match[3].rm_so, "yes", 3))  
             options |= OPTION_ERRORS;  
         else  
             options &= ~(OPTION_ERRORS);  
     } else if (!strncasecmp(line + match[2].rm_so, "expunge", 7)) {  
         if (!strncasecmp(line + match[3].rm_so, "yes", 3))  
             options |= OPTION_EXPUNGE;  
         else  
             options &= ~(OPTION_EXPUNGE);  
     } else if (!strncasecmp(line + match[2].rm_so, "header", 6)) {  
         if (!strncasecmp(line + match[3].rm_so, "yes", 3))  
             options |= OPTION_HEADERS;  
         else  
             options &= ~(OPTION_HEADERS);  
     } else if (!strncasecmp(line + match[2].rm_so, "namespace", 9)) {  
         if (!strncasecmp(line + match[3].rm_so, "yes", 3))  
             options |= OPTION_NAMESPACE;  
         else  
             options &= ~(OPTION_NAMESPACE);  
     } else if (!strncasecmp(line + match[2].rm_so, "subscribe", 9)) {  
         if (!strncasecmp(line + match[3].rm_so, "yes", 3))  
             options |= OPTION_SUBSCRIBE;  
         else  
             options &= ~(OPTION_SUBSCRIBE);  
     } else if (!strncasecmp(line + match[2].rm_so, "warning", 7)) {  
         if (!strncasecmp(line + match[3].rm_so, "yes", 3))  
             options |= OPTION_WARNING;  
         else  
             options &= ~(OPTION_WARNING);  
     } else if (!strncasecmp(line + match[2].rm_so, "timeout", 7)) {  
         errno = 0;  
         timeout = strtol(line + match[3].rm_so, NULL, 10);  
         if (errno)  
             timeout = 0;  
     } else if (!strncasecmp(line + match[2].rm_so, "daemon", 6) &&  
                !(options & OPTION_DAEMON_MODE)) {  
         options |= OPTION_DAEMON_MODE;  
         errno = 0;  
         interval = strtoul(line + match[3].rm_so, NULL, 10);  
         if (errno)  
             interval = 0;  
     }  
 }  
   
   
 #ifdef ENCRYPTED_PASSWORDS  
 /*  
  * Open password file and call parse_passwords().  
  */  
 int read_passwords(void)  
 {  
     FILE *fd;  
     char pwfile[PATH_MAX];  
   
     if (!(flags & FLAG_BLANK_PASSWORD))  
         return ERROR_CONFIG_PARSE;  
   
     passphr = (char *)smalloc(PASSPHRASE_LEN);  
     *passphr = 0;  
   
     snprintf(pwfile, PATH_MAX, "%s/%s", home, ".imapfilter/passwords");  
 #ifdef DEBUG  
     printf("debug: passwords file: '%s'\n", pwfile);  
 #endif  
   
     if (!exists_file(pwfile))  
         return ERROR_FILE_OPEN;  
   
 #ifdef CHECK_PERMISSIONS  
     check_file_perms(pwfile, S_IRUSR | S_IWUSR);  
 #endif  
26    
27      fd = fopen(pwfile, "r");          snprintf(hd, PATH_MAX, "%s/%s", home, PATHNAME_HOME);
   
     if (!fd)  
         fatal(ERROR_FILE_OPEN, "imapfilter: opening passwords file %s; %s\n",  
               pwfile, strerror(errno));  
   
     parse_passwords(fd);  
   
     fclose(fd);  
   
     return 0;  
 }  
   
   
 /*  
  *  Parse unencrypted password file.  
  */  
 int parse_passwords(FILE * fd)  
 {  
     int t = 3;  
     char *pe = NULL;  
     char user[USERNAME_LEN], serv[SERVER_LEN];  
     unsigned char *buf;  
     char *c, *cp, *line;  
     regex_t creg;  
     regmatch_t match[4];  
     const char *reg = "([[:alnum:].-]+) ([[:graph:]]+) ([[:graph:]]+)";  
     int r;  
   
     do {  
         fseek(fd, 0L, SEEK_SET);  
         printf("Enter master passphrase: ");  
         get_password(passphr, PASSPHRASE_LEN);  
     } while ((r = decrypt_passwords(&buf, fd)) && --t);  
   
     if (!t)  
         return ERROR_PASSPHRASE;  
   
     c = cp = sstrdup(buf);  
   
     regcomp(&creg, reg, REG_EXTENDED | REG_ICASE);  
   
     line = strtok_r(c, "\n", &c);  
     while (line && !regexec(&creg, line, 4, match, 0)) {  
         user[0] = serv[0] = 0;  
   
         strncat(serv, line + match[1].rm_so,  
                 min(match[1].rm_eo - match[1].rm_so, SERVER_LEN - 1));  
         strncat(user, line + match[2].rm_so,  
                 min(match[2].rm_eo - match[2].rm_so, USERNAME_LEN - 1));  
   
         if ((pe = (char *)find_password(user, serv)))  
             strncat(pe, line + match[3].rm_so,  
                     min(match[3].rm_eo - match[3].rm_so, PASSWORD_LEN - 1));  
   
         line = strtok_r(NULL, "\n", &c);  
     }  
   
     regfree(&creg);  
     sfree(cp);  
     sfree(buf);  
28    
29      return 0;          if (!exists_dir(hd)) {
30  }                  if (mkdir(hd, S_IRUSR | S_IWUSR | S_IXUSR))
31                            error("could not create directory %s; %s\n", hd,
32                                strerror(errno));
33  /*          } else {
34   * Store encrypted passwords to file.                  check_dir_perms(hd, S_IRUSR | S_IWUSR | S_IXUSR);
35   */          }
36  int store_passwords(account_t * accts[])          return 0;
 {  
     char pwfile[PATH_MAX];  
     FILE *fd;  
   
     snprintf(pwfile, PATH_MAX, "%s/%s", home, ".imapfilter/passwords");  
   
     create_file(pwfile, S_IRUSR | S_IWUSR);  
   
     fd = fopen(pwfile, "w");  
   
     if (!fd)  
         fatal(ERROR_FILE_OPEN, "imapfilter: opening passwords file %s; %s\n",  
               pwfile, strerror(errno));  
   
     encrypt_passwords(fd, accts);  
   
     fclose(fd);  
   
     return 0;  
 }  
   
 #endif  
   
   
 /*  
  * Create $HOME/.imapfilter directory.  
  */  
 int create_homedir(void)  
 {  
     char *hdn = ".imapfilter";  
   
     if (home)  
         if (chdir(home))  
             error("imapfilter: could not change directory; %s\n",  
                   strerror(errno));  
   
     if (!exists_dir(hdn))  
         if (mkdir(hdn, S_IRUSR | S_IWUSR | S_IXUSR))  
             error("imapfilter: could not create directory %s; %s\n", hdn,  
                   strerror(errno));  
   
     return 0;  
37  }  }
38    
39    
40  /*  /*
41   * Check if a file exists.   * Check if a file exists.
42   */   */
43  int exists_file(char *fname)  int
44    exists_file(char *fname)
45  {  {
46      struct stat fs;          struct stat fs;
47    
48      if (access(fname, F_OK))          if (access(fname, F_OK))
49          return 0;                  return 0;
50    
51      stat(fname, &fs);          stat(fname, &fs);
52      if (!S_ISREG(fs.st_mode)) {          if (!S_ISREG(fs.st_mode)) {
53          error("imapfilter: file %s not a regular file\n", fname);                  error("file %s not a regular file\n", fname);
54          return ERROR_FILE_OPEN;                  return ERROR_FILEOPEN;
55      }          }
56      return 1;          return 1;
57  }  }
58    
59    
60  /*  /*
61   * Check if a directory exists.   * Check if a directory exists.
62   */   */
63  int exists_dir(char *dname)  int
64    exists_dir(char *dname)
65  {  {
66      struct stat ds;          struct stat ds;
67    
68      if (access(dname, F_OK))          if (access(dname, F_OK))
69          return 0;                  return 0;
70    
71      stat(dname, &ds);          stat(dname, &ds);
72      if (!S_ISDIR(ds.st_mode)) {          if (!S_ISDIR(ds.st_mode)) {
73          error("imapfilter: file %s not a directory\n", dname);                  error("file %s not a directory\n", dname);
74          return ERROR_FILE_OPEN;                  return ERROR_FILEOPEN;
75      }          }
76      return 1;          return 1;
77  }  }
78    
79    
80  /*  /*
81   * Create a file with the specified permissions.   * Create a file with the specified permissions.
82   */   */
83  int create_file(char *fname, mode_t mode)  int
84    create_file(char *fname, mode_t mode)
85  {  {
86      int fd = 0;          int fd;
87    
88            fd = 0;
89    
90      if (!exists_file(fname)) {          if (!exists_file(fname)) {
91          fd = open(fname, O_CREAT | O_WRONLY | O_TRUNC, mode);                  fd = open(fname, O_CREAT | O_WRONLY | O_TRUNC, mode);
92          if (fd == -1) {                  if (fd == -1) {
93              error("imapfilter: could not create file %s; %s\n", fname,                          error("could not create file %s; %s\n", fname,
94                    strerror(errno));                              strerror(errno));
95              return ERROR_FILE_OPEN;                          return ERROR_FILEOPEN;
96                    }
97                    close(fd);
98          }          }
99          close(fd);          return 0;
     }  
     return 0;  
100  }  }
101    
102    
 #ifdef CHECK_PERMISSIONS  
103  /*  /*
104   * Check the permissions of a file.   * Check the permissions of a file.
105   */   */
106  int check_file_perms(char *fname, mode_t mode)  int
107    check_file_perms(char *fname, mode_t mode)
108  {  {
109      struct stat fs;          struct stat fs;
110    
111            if (opts.verbosity <= -1)
112                    return 0;
113    
114      if (stat(fname, &fs)) {          if (stat(fname, &fs)) {
115          error("imapfilter: getting file %s status; %s\n", fname,                  error("getting file %s status; %s\n", fname,
116                strerror(errno));                      strerror(errno));
117          return ERROR_TRIVIAL;                  return ERROR_TRIVIAL;
118      }          }
119      if (!S_ISREG(fs.st_mode)) {          if (!S_ISREG(fs.st_mode)) {
120          error("imapfilter: file %s not a regular file\n", fname);                  error("file %s not a regular file\n", fname);
121          return ERROR_TRIVIAL;                  return ERROR_TRIVIAL;
122      }          }
123      if ((fs.st_mode & 00777) != mode) {          if ((fs.st_mode & 00777) != mode) {
124          error("imapfilter: warning: improper file %s permissions\n"                  error("warning: file's %s mode should be %o not %o\n", fname,
125                "imapfilter: warning: file's mode should be %o not %o\n",                      mode, fs.st_mode & 00777);
126                fname, mode, fs.st_mode & 00777);                  return ERROR_TRIVIAL;
127          return ERROR_TRIVIAL;          }
128      }          return 0;
     return 0;  
129  }  }
130    
131    
132  /*  /*
133   * Check the permissions of a directory.   * Check the permissions of a directory.
134   */   */
135  int check_dir_perms(char *dname, mode_t mode)  int
136    check_dir_perms(char *dname, mode_t mode)
137  {  {
138      struct stat ds;          struct stat ds;
139    
140      if (stat(dname, &ds)) {          if (opts.verbosity <= -1)
141          error("imapfilter: getting file %s status; %s\n", dname,                  return 0;
               strerror(errno));  
         return ERROR_TRIVIAL;  
     }  
     if (!S_ISDIR(ds.st_mode)) {  
         error("imapfilter: file %s not a directory\n", dname);  
         return ERROR_TRIVIAL;  
     }  
     if ((ds.st_mode & 00777) != mode) {  
         error("imapfilter: warning: improper dir %s permissions\n"  
               "imapfilter: warning: file's mode should be %o not %o\n",  
               dname, mode, ds.st_mode & 00777);  
         return ERROR_TRIVIAL;  
     }  
     return 0;  
 }  
142    
143  #endif          if (stat(dname, &ds)) {
144                    error("getting file %s status; %s\n", dname,
145                        strerror(errno));
146                    return ERROR_TRIVIAL;
147            }
148            if (!S_ISDIR(ds.st_mode)) {
149                    error("file %s not a directory\n", dname);
150                    return ERROR_TRIVIAL;
151            }
152            if ((ds.st_mode & 00777) != mode) {
153                    error("warning: dir's %s mode should be %o not %o\n", dname,
154                        mode, ds.st_mode & 00777);
155                    return ERROR_TRIVIAL;
156            }
157            return 0;
158    }

Legend:
Removed from v.1.43.2.2  
changed lines
  Added in v.1.63

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26