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

Contents of /imapfilter/file.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.38 - (show annotations)
Sat Jul 13 14:11:08 2002 UTC (21 years, 9 months ago) by lefcha
Branch: MAIN
Changes since 1.37: +35 -35 lines
File MIME type: text/plain
Added variable to enable direct expunge of marked deleted mail.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26