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

Annotation of /imapfilter/file.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.34 - (hide annotations)
Thu Jan 31 17:08:13 2002 UTC (22 years, 2 months ago) by lefcha
Branch: MAIN
Changes since 1.33: +13 -1 lines
File MIME type: text/plain
Added daemon mode.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26