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

Annotation of /imapfilter/file.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.33 - (hide annotations)
Wed Jan 30 19:19:00 2002 UTC (22 years, 2 months ago) by lefcha
Branch: MAIN
Changes since 1.32: +8 -5 lines
File MIME type: text/plain
Added lockfile to prevent many imapfilters from running simultaneously.

1 lefcha 1.1 #include <stdio.h>
2 lefcha 1.28 #include <unistd.h>
3 lefcha 1.1 #include <errno.h>
4 lefcha 1.5 #include <sys/types.h>
5 lefcha 1.1 #include <regex.h>
6     #include <string.h>
7     #include <stdlib.h>
8     #include <limits.h>
9 lefcha 1.10 #include <sys/stat.h>
10 lefcha 1.28 #include <fcntl.h>
11 lefcha 1.29 #include <time.h>
12 lefcha 1.1
13     #include "config.h"
14     #include "imapfilter.h"
15 lefcha 1.13 #include "data.h"
16 lefcha 1.1
17    
18 lefcha 1.6 extern char logfile[PATH_MAX];
19 lefcha 1.11 extern unsigned int options;
20 lefcha 1.28 extern long timeout;
21 lefcha 1.29 extern char *home;
22    
23     #ifdef ENCRYPTED_PASSWORDS
24 lefcha 1.31 char *passphr; /* Master password to access the
25     passwords file. */
26 lefcha 1.28 #endif
27 lefcha 1.27
28 lefcha 1.1
29     /*
30 lefcha 1.13 * Find the path to configuration file, open it and call parse_config().
31 lefcha 1.1 */
32     int read_config(char *cfg)
33     {
34     int r;
35 lefcha 1.29 FILE *fd;
36 lefcha 1.23 char *c = NULL;
37 lefcha 1.24
38 lefcha 1.1 if (!cfg) {
39 lefcha 1.23 cfg = c = (char *) xmalloc(PATH_MAX * sizeof(char));
40 lefcha 1.8
41 lefcha 1.1 snprintf(cfg, PATH_MAX, "%s/%s", home, ".imapfilterrc");
42     }
43     #ifdef DEBUG
44 lefcha 1.11 printf("debug: configuration file: '%s'\n", cfg);
45 lefcha 1.1 #endif
46 lefcha 1.13 #ifdef CHECK_PERMISSIONS
47 lefcha 1.28 check_file_perms(cfg, S_IRUSR | S_IWUSR);
48 lefcha 1.12 #endif
49 lefcha 1.29 fd = fopen(cfg, "r");
50 lefcha 1.1
51 lefcha 1.29 if (!fd)
52 lefcha 1.17 fatal(ERROR_FILE_OPEN, "imapfilter: opening config file %s; %s\n",
53 lefcha 1.11 cfg, strerror(errno));
54 lefcha 1.1
55 lefcha 1.23 if (c)
56 lefcha 1.29 xfree(c);
57 lefcha 1.23
58 lefcha 1.29 if ((r = parse_config(fd)))
59 lefcha 1.17 fatal(ERROR_CONFIG_PARSE,
60     "imapfilter: parse error in config file at row %d\n", r);
61 lefcha 1.1
62 lefcha 1.29 fclose(fd);
63 lefcha 1.1
64 lefcha 1.11 #ifdef DEBUG
65     printf("debug: options: %0#10x\n", options);
66     #endif
67    
68 lefcha 1.17 return 0;
69 lefcha 1.1 }
70    
71 lefcha 1.6
72 lefcha 1.10 /*
73 lefcha 1.13 * Parse configuration file.
74 lefcha 1.1 */
75 lefcha 1.29 int parse_config(FILE * fd)
76 lefcha 1.1 {
77 lefcha 1.17 int i, r = 0;
78 lefcha 1.1 unsigned int row = 0;
79     char line[LINE_MAX];
80 lefcha 1.27 regex_t creg[13];
81 lefcha 1.28 regmatch_t match[8];
82 lefcha 1.27 const char *reg[13] = {
83 lefcha 1.15 "^([[:blank:]]*\n|#.*\n)$",
84 lefcha 1.25 #ifndef SSL_TLS
85 lefcha 1.28 "^[[:blank:]]*ACCOUNT[[:blank:]]+(([[:graph:]]+):([[:graph:]]*)|([[:graph:]]+))@([[:alnum:].-]+)(:[[:digit:]]+)?[[:blank:]]*\n$",
86 lefcha 1.25 #else
87 lefcha 1.28 "^[[:blank:]]*ACCOUNT[[:blank:]]+(([[:graph:]]+):([[:graph:]]*)|([[:graph:]]+))@([[:alnum:].-]+)(:[[:digit:]]+)?[[:blank:]]*([[:blank:]]SSL|[[:blank:]]SSL2|[[:blank:]]SSL3|[[:blank:]]TLS1)?[[:blank:]]*\n$",
88 lefcha 1.25 #endif
89 lefcha 1.31 "^[[:blank:]]*FOLDER[[:blank:]]+([[:alnum:]_-]+)[[:blank:]]+([[:print:]]+)[[:blank:]]*\n$",
90 lefcha 1.13 "^[[:blank:]]*FILTER[[:blank:]]+([[:alnum:]_-]+)[[:blank:]]*([[:blank:]]OR|[[:blank:]]AND)?[[:blank:]]*\n$",
91 lefcha 1.30 "^[[:blank:]]*ACTION[[:blank:]]+(DELETE|COPY[[:blank:]]+(\"[[:print:]]*\"|[[:graph:]]+)|MOVE[[:blank:]]+(\"[[:print:]]*\"|[[:graph:]]+)|LIST)[[:blank:]]*([[:graph:]]*)[[:blank:]]*\n$",
92 lefcha 1.17 "^[[: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$",
93     "^[[:blank:]]*(MASK[[:blank:]])?[[:blank:]]*(OR[[:blank:]]|AND[[:blank:]])?[[:blank:]]*(NOT[[:blank:]])?[[:blank:]]*(BCC|BODY|CC|FROM|SUBJECT|TEXT|TO)[[:blank:]]+(\"[[:print:]]*\"|[[:graph:]]+)[[:blank:]]*\n$",
94     "^[[:blank:]]*(MASK[[:blank:]])?[[:blank:]]*(OR[[:blank:]]|AND[[:blank:]])?[[:blank:]]*(NOT[[:blank:]])?[[:blank:]]*(HEADER)[[:blank:]]+(\"[[:print:]]*\"|[[:graph:]]+)[[:blank:]]+(\"[[:print:]]*\"|[[:graph:]]+)[[:blank:]]*\n$",
95 lefcha 1.26 "^[[:blank:]]*(MASK[[:blank:]])?[[:blank:]]*(OR[[:blank:]]|AND[[:blank:]])?[[:blank:]]*(NOT[[:blank:]])?[[:blank:]]*(LARGER|SMALLER|OLDER|NEWER)[[:blank:]]+([[:digit:]]+)[[:blank:]]*\n$",
96 lefcha 1.13 "^[[:blank:]]*JOB[[:blank:]]+([[:alnum:],_-]+)[[:blank:]]+([[:alnum:],_-]+)[[:blank:]]*\n$",
97 lefcha 1.26 "^[[:blank:]]*(SET[[:blank:]])?[[:blank:]]*(LOGFILE)[[:blank:]]*=[[:blank:]]*([[:print:]]+)\n$",
98 lefcha 1.28 "^[[:blank:]]*(SET[[:blank:]])?[[:blank:]]*(HEADERS|NAMESPACE)[[:blank:]]*=[[:blank:]]*(YES|NO)[[:blank:]]*\n$",
99 lefcha 1.27 "^[[:blank:]]*(SET[[:blank:]])?[[:blank:]]*(TIMEOUT)[[:blank:]]*=[[:blank:]]*(-?[[:digit:]]+)\n$"
100 lefcha 1.1 };
101    
102 lefcha 1.27 for (i = 0; i < 13; i++)
103 lefcha 1.14 regcomp(&creg[i], reg[i], REG_EXTENDED | REG_ICASE);
104 lefcha 1.1
105 lefcha 1.29 while (fgets(line, LINE_MAX - 1, fd)) {
106 lefcha 1.1 row++;
107 lefcha 1.15 if (!regexec(&creg[0], line, 0, match, 0))
108     continue;
109 lefcha 1.26 #ifndef SSL_TLS
110 lefcha 1.28 else if (!regexec(&creg[1], line, 7, match, 0))
111 lefcha 1.25 #else
112 lefcha 1.28 else if (!regexec(&creg[1], line, 8, match, 0))
113 lefcha 1.25 #endif
114 lefcha 1.13 set_account(line, match);
115 lefcha 1.15 else if (!regexec(&creg[2], line, 3, match, 0))
116 lefcha 1.17 r = set_mboxgrp(line, match);
117 lefcha 1.15 else if (!regexec(&creg[3], line, 3, match, 0))
118 lefcha 1.17 r = set_filter(line, match);
119     else if (!regexec(&creg[4], line, 5, match, 0))
120     r = set_action(line, match);
121 lefcha 1.15 else if (!regexec(&creg[5], line, 7, match, 0) ||
122 lefcha 1.18 !regexec(&creg[6], line, 7, match, 0) ||
123     !regexec(&creg[7], line, 7, match, 0) ||
124     !regexec(&creg[8], line, 7, match, 0))
125 lefcha 1.17 r = set_mask(line, match);
126 lefcha 1.15 else if (!regexec(&creg[9], line, 3, match, 0))
127 lefcha 1.17 r = set_job(line, match);
128 lefcha 1.26 else if (!regexec(&creg[10], line, 4, match, 0) ||
129 lefcha 1.27 !regexec(&creg[11], line, 4, match, 0) ||
130     !regexec(&creg[12], line, 4, match, 0))
131 lefcha 1.15 set_options(line, match);
132 lefcha 1.17 else
133 lefcha 1.18 return row;
134    
135 lefcha 1.17 if (r == ERROR_CONFIG_PARSE)
136     return row;
137 lefcha 1.1 }
138 lefcha 1.3
139 lefcha 1.27 for (i = 0; i < 13; i++)
140 lefcha 1.12 regfree(&creg[i]);
141 lefcha 1.18
142 lefcha 1.15 destroy_data();
143 lefcha 1.6
144 lefcha 1.8 return 0;
145 lefcha 1.1 }
146    
147    
148     /*
149 lefcha 1.13 * Set other options found in config file.
150 lefcha 1.11 */
151     void set_options(char *line, regmatch_t * match)
152     {
153 lefcha 1.26 if (!strncasecmp(line + match[2].rm_so, "logfile", 7)) {
154 lefcha 1.19 if (!*logfile)
155 lefcha 1.26 strncat(logfile, line + match[3].rm_so,
156     min((match[3].rm_eo - match[3].rm_so), PATH_MAX - 1));
157 lefcha 1.27 } else if (!strncasecmp(line + match[2].rm_so, "header", 6)) {
158 lefcha 1.26 if (!strncasecmp(line + match[3].rm_so, "yes", 3))
159 lefcha 1.19 options |= OPTION_HEADERS;
160 lefcha 1.25 else
161     options &= ~(OPTION_HEADERS);
162 lefcha 1.28 } else if (!strncasecmp(line + match[2].rm_so, "namespace", 9)) {
163     if (!strncasecmp(line + match[3].rm_so, "yes", 3))
164     options |= OPTION_NAMESPACE;
165     else
166     options &= ~(OPTION_NAMESPACE);
167 lefcha 1.27 } else if (!strncasecmp(line + match[2].rm_so, "timeout", 7)) {
168     errno = 0;
169     timeout = strtol(line + match[3].rm_so, NULL, 10);
170     if (errno)
171     timeout = 0;
172 lefcha 1.19 }
173 lefcha 1.1 }
174 lefcha 1.29
175    
176     #ifdef ENCRYPTED_PASSWORDS
177     /*
178     * Open password file and call parse_passwords().
179     */
180     int read_passwords(void)
181     {
182     FILE *fd;
183     char pwfile[PATH_MAX];
184 lefcha 1.31
185     passphr = (char *) smalloc(PASSPHRASE_LEN);
186 lefcha 1.29
187     snprintf(pwfile, PATH_MAX, "%s/%s", home, ".imapfilter/passwords");
188     #ifdef DEBUG
189     printf("debug: passwords file: '%s'\n", pwfile);
190     #endif
191    
192     if (!exists_file(pwfile))
193     return 1;
194    
195     #ifdef CHECK_PERMISSIONS
196     check_file_perms(pwfile, S_IRUSR | S_IWUSR);
197     #endif
198    
199     fd = fopen(pwfile, "r");
200    
201     if (!fd)
202     fatal(ERROR_FILE_OPEN, "imapfilter: opening passwords file %s; %s\n",
203     pwfile, strerror(errno));
204    
205     parse_passwords(fd);
206    
207     fclose(fd);
208    
209     return 0;
210     }
211    
212    
213     /*
214     * Parse unencrypted password file.
215     */
216     int parse_passwords(FILE * fd)
217     {
218     int t = 3;
219     char *pe = NULL;
220     char user[USERNAME_LEN], serv[SERVER_LEN];
221     unsigned char *buf;
222     char *c, *cp, *line;
223     regex_t creg;
224     regmatch_t match[4];
225     const char *reg = "([[:alnum:].-]+) ([[:graph:]]+) ([[:graph:]]+)";
226    
227     do {
228     printf("Enter master passphrase: ");
229     get_password(passphr, PASSPHRASE_LEN);
230 lefcha 1.31 } while (decrypt_passwords(&buf, fd) && --t);
231 lefcha 1.29
232     if (!t)
233     return ERROR_PASSPHRASE;
234    
235 lefcha 1.31 c = cp = sstrdup(buf);
236 lefcha 1.29
237     regcomp(&creg, reg, REG_EXTENDED | REG_ICASE);
238    
239     while ((line = strsep(&c, "\n")) &&
240     !regexec(&creg, line, 4, match, 0)) {
241     user[0] = serv[0] = 0;
242    
243     strncat(serv, line + match[1].rm_so,
244     min(match[1].rm_eo - match[1].rm_so, SERVER_LEN - 1));
245     strncat(user, line + match[2].rm_so,
246     min(match[2].rm_eo - match[2].rm_so, USERNAME_LEN - 1));
247    
248     if ((pe = (char *) find_password(user, serv)))
249     strncat(pe, line + match[3].rm_so,
250     min(match[3].rm_eo - match[3].rm_so, PASSWORD_LEN - 1));
251     }
252    
253     regfree(&creg);
254 lefcha 1.31 sfree(cp);
255     sfree(buf);
256 lefcha 1.29
257     return 0;
258     }
259    
260    
261     /*
262     * Store encrypted passwords to file.
263     */
264     int store_passwords(account_t * accts[])
265     {
266     char pwfile[PATH_MAX];
267     FILE *fd;
268    
269     snprintf(pwfile, PATH_MAX, "%s/%s", home, ".imapfilter/passwords");
270 lefcha 1.32
271     create_file(pwfile, S_IRUSR | S_IWUSR);
272 lefcha 1.29
273     fd = fopen(pwfile, "w");
274    
275     if (!fd)
276     fatal(ERROR_FILE_OPEN, "imapfilter: opening passwords file %s; %s\n",
277     pwfile, strerror(errno));
278    
279     encrypt_passwords(fd, accts);
280    
281     fclose(fd);
282    
283     return 0;
284     }
285     #endif
286 lefcha 1.31
287    
288     /*
289     * Create $HOME/.imapfilter directory.
290     */
291     int create_homedir(void)
292     {
293 lefcha 1.33 char *hdn = ".imapfilter";
294 lefcha 1.31
295     if (home)
296     if (chdir(home))
297     error("imapfilter: could not change directory; %s\n",
298     strerror(errno));
299    
300 lefcha 1.33 create_dir(hdn, S_IRUSR | S_IWUSR | S_IXUSR);
301    
302 lefcha 1.31 return 0;
303     }
304    
305    
306     /*
307     * Check if a file exists.
308     */
309     int exists_file(char *fname)
310     {
311     struct stat fs;
312    
313     if (access(fname, F_OK))
314     return 0;
315    
316     stat(fname, &fs);
317     if (!S_ISREG(fs.st_mode)) {
318     error("imapfilter: file %s not a regular file\n", fname);
319     return ERROR_FILE_OPEN;
320     }
321    
322     return 1;
323     }
324    
325    
326     /*
327     * Check if a directory exists.
328     */
329     int exists_dir(char *dname)
330     {
331     struct stat ds;
332    
333     if (access(dname, F_OK))
334     return 0;
335    
336     stat(dname, &ds);
337     if (!S_ISDIR(ds.st_mode)) {
338     error("imapfilter: file %s not a directory\n", dname);
339     return ERROR_FILE_OPEN;
340     }
341    
342     return 1;
343     }
344    
345    
346     /*
347     * Create a file.
348     */
349     int create_file(char *fname, mode_t mode)
350     {
351     int fd = 0;
352    
353 lefcha 1.33 if (!exists_file(fname)) {
354     fd = open(fname, O_CREAT | O_WRONLY | O_TRUNC, mode);
355 lefcha 1.31 if (fd == -1) {
356     error("imapfilter: could not create file %s; %s\n", fname,
357     strerror(errno));
358     return ERROR_FILE_OPEN;
359     }
360     close(fd);
361 lefcha 1.33 }
362 lefcha 1.31
363     return 0;
364     }
365    
366    
367     /*
368     * Create a directory.
369     */
370     int create_dir(char *dname, mode_t mode)
371     {
372     if (!exists_dir(dname))
373     if (mkdir(dname, mode))
374     error("imapfilter: could not create directory %s; %s\n", dname,
375     strerror(errno));
376    
377     return 0;
378     }
379    
380    
381     #ifdef CHECK_PERMISSIONS
382     /*
383     * Check the permissions of a file.
384     */
385     int check_file_perms(char *fname, mode_t mode)
386     {
387     struct stat fs;
388    
389     if (stat(fname, &fs)) {
390     error("imapfilter: getting file %s status; %s\n", fname,
391     strerror(errno));
392     return ERROR_TRIVIAL;
393     }
394     if (!S_ISREG(fs.st_mode)) {
395     error("imapfilter: file %s not a regular file\n", fname);
396     return ERROR_TRIVIAL;
397     }
398     if ((fs.st_mode & 00777) != mode) {
399     error("imapfilter: warning: improper file %s permissions\n"
400     "imapfilter: warning: file's mode should be %o not %o\n",
401     fname, mode, fs.st_mode & 00777);
402     return ERROR_TRIVIAL;
403     }
404     return 0;
405     }
406    
407    
408     /*
409     * Check the permissions of a directory.
410     */
411     int check_dir_perms(char *dname, mode_t mode)
412     {
413     struct stat ds;
414    
415     if (stat(dname, &ds)) {
416     error("imapfilter: getting file %s status; %s\n", dname,
417     strerror(errno));
418     return ERROR_TRIVIAL;
419     }
420     if (!S_ISDIR(ds.st_mode)) {
421     error("imapfilter: file %s not a directory\n", dname);
422     return ERROR_TRIVIAL;
423     }
424     if ((ds.st_mode & 00777) != mode) {
425     error("imapfilter: warning: improper dir %s permissions\n"
426     "imapfilter: warning: file's mode should be %o not %o\n",
427     dname, mode, ds.st_mode & 00777);
428     return ERROR_TRIVIAL;
429     }
430     return 0;
431     }
432     #endif
433 lefcha 1.33
434    
435 lefcha 1.31

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26