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

Contents of /imapfilter/file.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.34 - (show 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 #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
43 snprintf(cfg, PATH_MAX, "%s/%s", home, ".imapfilterrc");
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[8];
84 const char *reg[13] = {
85 "^([[:blank:]]*\n|#.*\n)$",
86 #ifndef SSL_TLS
87 "^[[:blank:]]*ACCOUNT[[:blank:]]+(([[:graph:]]+):([[:graph:]]*)|([[:graph:]]+))@([[:alnum:].-]+)(:[[:digit:]]+)?[[:blank:]]*\n$",
88 #else
89 "^[[:blank:]]*ACCOUNT[[:blank:]]+(([[:graph:]]+):([[:graph:]]*)|([[:graph:]]+))@([[:alnum:].-]+)(:[[:digit:]]+)?[[:blank:]]*([[:blank:]]SSL|[[:blank:]]SSL2|[[:blank:]]SSL3|[[:blank:]]TLS1)?[[:blank:]]*\n$",
90 #endif
91 "^[[:blank:]]*FOLDER[[:blank:]]+([[:alnum:]_-]+)[[:blank:]]+([[:print:]]+)[[:blank:]]*\n$",
92 "^[[:blank:]]*FILTER[[:blank:]]+([[:alnum:]_-]+)[[:blank:]]*([[:blank:]]OR|[[:blank:]]AND)?[[:blank:]]*\n$",
93 "^[[:blank:]]*ACTION[[:blank:]]+(DELETE|COPY[[:blank:]]+(\"[[:print:]]*\"|[[:graph:]]+)|MOVE[[:blank:]]+(\"[[:print:]]*\"|[[:graph:]]+)|LIST)[[:blank:]]*([[:graph:]]*)[[:blank:]]*\n$",
94 "^[[: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 "^[[:blank:]]*(MASK[[:blank:]])?[[:blank:]]*(OR[[:blank:]]|AND[[:blank:]])?[[:blank:]]*(NOT[[:blank:]])?[[:blank:]]*(LARGER|SMALLER|OLDER|NEWER)[[:blank:]]+([[:digit:]]+)[[:blank:]]*\n$",
98 "^[[:blank:]]*JOB[[:blank:]]+([[:alnum:],_-]+)[[:blank:]]+([[:alnum:],_-]+)[[:blank:]]*\n$",
99 "^[[:blank:]]*(SET[[:blank:]])?[[:blank:]]*(LOGFILE)[[:blank:]]*=[[:blank:]]*([[:print:]]+)\n$",
100 "^[[:blank:]]*(SET[[:blank:]])?[[:blank:]]*(HEADERS|NAMESPACE)[[:blank:]]*=[[:blank:]]*(YES|NO)[[:blank:]]*\n$",
101 "^[[:blank:]]*(SET[[:blank:]])?[[:blank:]]*(DAEMON|TIMEOUT)[[:blank:]]*=[[:blank:]]*([[:digit:]]+)\n$"
102 };
103
104 for (i = 0; i < 13; i++)
105 regcomp(&creg[i], reg[i], REG_EXTENDED | REG_ICASE);
106
107 while (fgets(line, LINE_MAX - 1, fd)) {
108 row++;
109 if (!regexec(&creg[0], line, 0, match, 0))
110 continue;
111 #ifndef SSL_TLS
112 else if (!regexec(&creg[1], line, 7, match, 0))
113 #else
114 else if (!regexec(&creg[1], line, 8, match, 0))
115 #endif
116 set_account(line, match);
117 else if (!regexec(&creg[2], line, 3, match, 0))
118 r = set_mboxgrp(line, match);
119 else if (!regexec(&creg[3], line, 3, match, 0))
120 r = set_filter(line, match);
121 else if (!regexec(&creg[4], line, 5, match, 0))
122 r = set_action(line, match);
123 else if (!regexec(&creg[5], line, 7, match, 0) ||
124 !regexec(&creg[6], line, 7, match, 0) ||
125 !regexec(&creg[7], line, 7, match, 0) ||
126 !regexec(&creg[8], line, 7, match, 0))
127 r = set_mask(line, match);
128 else if (!regexec(&creg[9], line, 3, match, 0))
129 r = set_job(line, match);
130 else if (!regexec(&creg[10], line, 4, match, 0) ||
131 !regexec(&creg[11], line, 4, match, 0) ||
132 !regexec(&creg[12], line, 4, match, 0))
133 set_options(line, match);
134 else
135 return row;
136
137 if (r == ERROR_CONFIG_PARSE)
138 return row;
139 }
140
141 for (i = 0; i < 13; i++)
142 regfree(&creg[i]);
143
144 destroy_data();
145
146 return 0;
147 }
148
149
150 /*
151 * Set other options found in config file.
152 */
153 void set_options(char *line, regmatch_t * match)
154 {
155 if (!strncasecmp(line + match[2].rm_so, "logfile", 7)) {
156 if (!*logfile)
157 strncat(logfile, line + match[3].rm_so,
158 min((match[3].rm_eo - match[3].rm_so), PATH_MAX - 1));
159 } else if (!strncasecmp(line + match[2].rm_so, "header", 6)) {
160 if (!strncasecmp(line + match[3].rm_so, "yes", 3))
161 options |= OPTION_HEADERS;
162 else
163 options &= ~(OPTION_HEADERS);
164 } 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 } 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 } 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 }
182 }
183
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
194 if (!(flags & FLAG_BLANK_PASSWORD))
195 return 1;
196
197 passphr = (char *) smalloc(PASSPHRASE_LEN);
198
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 } while (decrypt_passwords(&buf, fd) && --t);
243
244 if (!t)
245 return ERROR_PASSPHRASE;
246
247 c = cp = sstrdup(buf);
248
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 sfree(cp);
267 sfree(buf);
268
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
283 create_file(pwfile, S_IRUSR | S_IWUSR);
284
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
299
300 /*
301 * Create $HOME/.imapfilter directory.
302 */
303 int create_homedir(void)
304 {
305 char *hdn = ".imapfilter";
306
307 if (home)
308 if (chdir(home))
309 error("imapfilter: could not change directory; %s\n",
310 strerror(errno));
311
312 create_dir(hdn, S_IRUSR | S_IWUSR | S_IXUSR);
313
314 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 if (!exists_file(fname)) {
366 fd = open(fname, O_CREAT | O_WRONLY | O_TRUNC, mode);
367 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 }
374
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
446
447

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26