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

Contents of /imapfilter/file.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.31 - (show annotations)
Tue Jan 29 21:23:41 2002 UTC (22 years, 2 months ago) by lefcha
Branch: MAIN
Changes since 1.30: +156 -153 lines
File MIME type: text/plain
Added secure memory allocation subsystem.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26