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

Contents of /imapfilter/file.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.36 - (show annotations)
Tue Jun 18 21:04:38 2002 UTC (21 years, 9 months ago) by lefcha
Branch: MAIN
Changes since 1.35: +68 -37 lines
File MIME type: text/plain
Change of the regex indentation.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26