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

Annotation of /imapfilter/file.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.44 - (hide annotations)
Tue Aug 20 14:54:01 2002 UTC (21 years, 7 months ago) by lefcha
Branch: MAIN
Changes since 1.43: +8 -2 lines
File MIME type: text/plain
Variable to control if errors are written to logfile.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26