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

Contents of /imapfilter/parse.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.4.2.1 - (show annotations)
Fri Aug 8 00:28:03 2003 UTC (20 years, 7 months ago) by lefcha
Branch: release-0_9-patches
Changes since 1.4: +3 -3 lines
File MIME type: text/plain
Corrected headers includes.

1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <strings.h>
5 #include <errno.h>
6 #include <limits.h>
7 #include <sys/stat.h>
8 #include <regex.h>
9
10 #include "config.h"
11 #include "imapfilter.h"
12 #include "pathnames.h"
13
14
15 extern char logfile[PATH_MAX];
16 extern unsigned int options;
17 extern char charset[CHARSET_LEN];
18 extern unsigned int flags;
19 extern unsigned int interval;
20 extern long timeout;
21 extern char *home;
22
23 #ifdef ENCRYPTED_PASSWORDS
24 char *passphr = NULL; /* Master password to access the passwords
25 * file. */
26 #endif
27
28
29 int parse_config(FILE * fd);
30 void set_options(char *line, regmatch_t * match);
31
32 int parse_passwords(FILE * fd);
33
34
35 /*
36 * Find the path to configuration file, open it and call parse_config().
37 */
38 int
39 read_config(char *cfg)
40 {
41 int r;
42 FILE *fd;
43 char *c;
44
45 c = NULL;
46
47 if (cfg == NULL) {
48 cfg = c = (char *)xmalloc(PATH_MAX * sizeof(char));
49 snprintf(cfg, PATH_MAX, "%s/%s", home, PATHNAME_CONFIG_FILE);
50 }
51 #ifdef DEBUG
52 fprintf(stderr, "debug: configuration file: '%s'\n", cfg);
53 #endif
54 #ifdef CHECK_PERMISSIONS
55 check_file_perms(cfg, S_IRUSR | S_IWUSR);
56 #endif
57 fd = fopen(cfg, "r");
58 if (fd == NULL)
59 fatal(ERROR_FILE_OPEN, "opening config file %s; %s\n", cfg,
60 strerror(errno));
61
62 if (c != NULL)
63 xfree(c);
64
65 if ((r = parse_config(fd)))
66 fatal(ERROR_CONFIG_PARSE,
67 "parse error in config file at row %d\n", r);
68
69 fclose(fd);
70
71 #ifdef DEBUG
72 fprintf(stderr, "debug: options: %0#10x '%s'\n", options, charset);
73 #endif
74
75 return 0;
76 }
77
78
79 /*
80 * Parse configuration file.
81 */
82 int
83 parse_config(FILE * fd)
84 {
85 int i, r;
86 unsigned int row;
87 char line[LINE_MAX];
88 regex_t creg[13];
89 regmatch_t match[11];
90 const char *reg[13] = {
91 "^([[:blank:]]*\n|#.*\n)$",
92
93 "^[[:blank:]]*ACCOUNT[[:blank:]]+([[:alnum:]_-]+)[[:blank:]]+"
94 "(([[:graph:]]+):([[:graph:]]*)|([[:graph:]]+))@"
95 "([[:alnum:].-]+)(:[[:digit:]]+)?[[:blank:]]*"
96 "([[:blank:]]SSL2|[[:blank:]]SSL3|[[:blank:]]TLS1)?"
97 "[[:blank:]]*\n$",
98
99 "^[[:blank:]]*FOLDER[[:blank:]]+([[:alnum:]_-]+)[[:blank:]]+"
100 "([[:print:]]+)[[:blank:]]*\n$",
101
102 "^[[:blank:]]*FILTER[[:blank:]]+([[:alnum:]_-]+)[[:blank:]]*"
103 "([[:blank:]]OR|[[:blank:]]AND)?[[:blank:]]*\n$",
104
105 "^[[:blank:]]*ACTION[[:blank:]]+(DELETE|"
106 "COPY[[:blank:]]+(\"[[:print:]]*\"|[[:graph:]]+)|"
107 "MOVE[[:blank:]]+(\"[[:print:]]*\"|[[:graph:]]+)|"
108 "RCOPY[[:blank:]]+([[:alnum:]_-]+)[[:blank:]]+"
109 "(\"[[:print:]]*\"|[[:graph:]]+)|"
110 "RMOVE[[:blank:]]+([[:alnum:]_-]+)[[:blank:]]+"
111 "(\"[[:print:]]*\"|[[:graph:]]+)|"
112 "FLAG[[:blank:]]+(REPLACE|ADD|REMOVE)[[:blank:]]+"
113 "([[:alpha:],]+)|"
114 "LIST)[[:blank:]]*([[:graph:]]*)[[:blank:]]*\n$",
115
116 "^[[:blank:]]*(MASK[[:blank:]])?[[:blank:]]*(OR[[:blank:]]|"
117 "AND[[:blank:]])?[[:blank:]]*(NOT[[:blank:]])?[[:blank:]]*"
118 "(ANSWERED|DELETED|DRAFT|FLAGGED|NEW|OLD|RECENT|SEEN|"
119 "UNANSWERED|UNDELETED|UNDRAFT|UNFLAGGED|UNSEEN)[[:blank:]]*\n$",
120
121 "^[[:blank:]]*(MASK[[:blank:]])?[[:blank:]]*(OR[[:blank:]]|"
122 "AND[[:blank:]])?[[:blank:]]*(NOT[[:blank:]])?[[:blank:]]*"
123 "(BCC|BODY|CC|FROM|SUBJECT|TEXT|TO)[[:blank:]]+"
124 "(\"[[:print:]]*\"|[[:graph:]]+)[[:blank:]]*\n$",
125
126 "^[[:blank:]]*(MASK[[:blank:]])?[[:blank:]]*(OR[[:blank:]]|"
127 "AND[[:blank:]])?[[:blank:]]*(NOT[[:blank:]])?[[:blank:]]*"
128 "(HEADER)[[:blank:]]+(\"[[:print:]]*\"|[[:graph:]]+)"
129 "[[:blank:]]+(\"[[:print:]]*\"|[[:graph:]]+)[[:blank:]]*\n$",
130
131 "^[[:blank:]]*(MASK[[:blank:]])?[[:blank:]]*(OR[[:blank:]]|"
132 "AND[[:blank:]])?[[:blank:]]*(NOT[[:blank:]])?[[:blank:]]*"
133 "(LARGER|SMALLER|OLDER|NEWER)[[:blank:]]+([[:digit:]]+)"
134 "[[:blank:]]*\n$",
135
136 "^[[:blank:]]*JOB[[:blank:]]+([[:alnum:],_-]+)[[:blank:]]+"
137 "([[:alnum:],_-]+)[[:blank:]]*\n$",
138
139 "^[[:blank:]]*(SET[[:blank:]])?[[:blank:]]*(LOGFILE|CHARSET)"
140 "[[:blank:]]*=[[:blank:]]*(\"[[:print:]]*\"|[[:graph:]]+)"
141 "[[:blank:]]*\n$",
142
143 "^[[:blank:]]*(SET[[:blank:]])?[[:blank:]]*(ERRORS|EXPUNGE|"
144 "HEADERS|NAMESPACE|SUBSCRIBE)[[:blank:]]*=[[:blank:]]*"
145 "(YES|NO)[[:blank:]]*\n$",
146
147 "^[[:blank:]]*(SET[[:blank:]])?[[:blank:]]*(DAEMON|TIMEOUT)"
148 "[[:blank:]]*=[[:blank:]]*([[:digit:]]+)\n$"
149 };
150
151 r = row = 0;
152
153 for (i = 0; i < 13; i++)
154 regcomp(&creg[i], reg[i], REG_EXTENDED | REG_ICASE);
155
156 /* First process all the variables. This is done because some
157 * variables' arguments are used before the other commands are
158 * processed. */
159 while (fgets(line, LINE_MAX - 1, fd))
160 if (!regexec(&creg[10], line, 4, match, 0) ||
161 !regexec(&creg[11], line, 4, match, 0) ||
162 !regexec(&creg[12], line, 4, match, 0))
163 set_options(line, match);
164
165 /* Then rewind and process everything else. */
166 fseek(fd, 0L, SEEK_SET);
167 while (fgets(line, LINE_MAX - 1, fd)) {
168 row++;
169 if (!regexec(&creg[0], line, 0, match, 0))
170 continue;
171 else if (!regexec(&creg[1], line, 9, match, 0))
172 set_account(line, match);
173 else if (!regexec(&creg[2], line, 3, match, 0))
174 r = set_mboxgrp(line, match);
175 else if (!regexec(&creg[3], line, 3, match, 0))
176 r = set_filter(line, match);
177 else if (!regexec(&creg[4], line, 11, match, 0))
178 r = set_action(line, match);
179 else if (!regexec(&creg[5], line, 5, match, 0))
180 r = set_mask(line, match, MASK_MATCH_1);
181 else if (!regexec(&creg[6], line, 6, match, 0))
182 r = set_mask(line, match, MASK_MATCH_2);
183 else if (!regexec(&creg[7], line, 7, match, 0))
184 r = set_mask(line, match, MASK_MATCH_3);
185 else if (!regexec(&creg[8], line, 6, match, 0))
186 r = set_mask(line, match, MASK_MATCH_4);
187 else if (!regexec(&creg[9], line, 3, match, 0))
188 r = set_job(line, match);
189 /* Skip variable processing. */
190 else if (!regexec(&creg[10], line, 4, match, 0) ||
191 !regexec(&creg[11], line, 4, match, 0) ||
192 !regexec(&creg[12], line, 4, match, 0));
193 else
194 return row;
195
196 if (r == ERROR_CONFIG_PARSE)
197 return row;
198 }
199
200 for (i = 0; i < 13; i++)
201 regfree(&creg[i]);
202
203 destroy_unneeded();
204
205 return 0;
206 }
207
208
209 /*
210 * Signal SIGUSR1 received, destroy all data structures and reread the
211 * configuration file.
212 */
213 void
214 reread_config(char *cfg)
215 {
216 destroy_all();
217 read_config(cfg);
218 #ifdef ENCRYPTED_PASSWORDS
219 read_passwords();
220 #endif
221 flags &= ~(FLAG_SIGUSR1_RECEIVED);
222 }
223
224
225 /*
226 * Set other options found in config file.
227 */
228 void
229 set_options(char *line, regmatch_t * m)
230 {
231 if (!strncasecmp(line + m[2].rm_so, "logfile", 7)) {
232 if (*logfile == '\0') {
233 if (*(line + m[3].rm_so) == '"' &&
234 *(line + m[3].rm_eo - 1) == '"')
235 strncat(logfile, line + m[3].rm_so + 1,
236 min((m[3].rm_eo - m[3].rm_so - 2),
237 PATH_MAX - 1));
238 else
239 strncat(logfile, line + m[3].rm_so,
240 min((m[3].rm_eo - m[3].rm_so),
241 PATH_MAX - 1));
242 }
243 } else if (!strncasecmp(line + m[2].rm_so, "charset", 7)) {
244 if (*(line + m[3].rm_so) == '"' &&
245 *(line + m[3].rm_eo - 1) == '"')
246 strncat(charset, line + m[3].rm_so + 1,
247 min((m[3].rm_eo - m[3].rm_so - 2),
248 CHARSET_LEN - 1));
249 else
250 strncat(charset, line + m[3].rm_so,
251 min((m[3].rm_eo - m[3].rm_so), CHARSET_LEN - 1));
252 } else if (!strncasecmp(line + m[2].rm_so, "errors", 6)) {
253 if (!strncasecmp(line + m[3].rm_so, "yes", 3))
254 options |= OPTION_ERRORS;
255 else
256 options &= ~(OPTION_ERRORS);
257 } else if (!strncasecmp(line + m[2].rm_so, "expunge", 7)) {
258 if (!strncasecmp(line + m[3].rm_so, "yes", 3))
259 options |= OPTION_EXPUNGE;
260 else
261 options &= ~(OPTION_EXPUNGE);
262 } else if (!strncasecmp(line + m[2].rm_so, "header", 6)) {
263 if (!strncasecmp(line + m[3].rm_so, "yes", 3))
264 options |= OPTION_HEADERS;
265 else
266 options &= ~(OPTION_HEADERS);
267 } else if (!strncasecmp(line + m[2].rm_so, "namespace", 9)) {
268 if (!strncasecmp(line + m[3].rm_so, "yes", 3))
269 options |= OPTION_NAMESPACE;
270 else
271 options &= ~(OPTION_NAMESPACE);
272 } else if (!strncasecmp(line + m[2].rm_so, "subscribe", 9)) {
273 if (!strncasecmp(line + m[3].rm_so, "yes", 3))
274 options |= OPTION_SUBSCRIBE;
275 else
276 options &= ~(OPTION_SUBSCRIBE);
277 } else if (!strncasecmp(line + m[2].rm_so, "timeout", 7)) {
278 errno = 0;
279 timeout = strtol(line + m[3].rm_so, NULL, 10);
280 if (errno)
281 timeout = 0;
282 } else if (!strncasecmp(line + m[2].rm_so, "daemon", 6) &&
283 !(options & OPTION_DAEMON_MODE)) {
284 options |= OPTION_DAEMON_MODE;
285 errno = 0;
286 interval = strtoul(line + m[3].rm_so, NULL, 10);
287 if (errno)
288 interval = 0;
289 }
290 }
291
292
293 #ifdef ENCRYPTED_PASSWORDS
294 /*
295 * Open password file and call parse_passwords().
296 */
297 int
298 read_passwords(void)
299 {
300 FILE *fd;
301 char pwfile[PATH_MAX];
302
303 if (!(flags & FLAG_BLANK_PASSWORD))
304 return ERROR_CONFIG_PARSE;
305
306 if (!passphr) {
307 passphr = (char *)smalloc(PASSPHRASE_LEN);
308 *passphr = '\0';
309 }
310 snprintf(pwfile, PATH_MAX, "%s/%s", home, PATHNAME_PASSWORD_FILE);
311 #ifdef DEBUG
312 fprintf(stderr, "debug: passwords file: '%s'\n", pwfile);
313 #endif
314
315 if (!exists_file(pwfile))
316 return ERROR_FILE_OPEN;
317
318 #ifdef CHECK_PERMISSIONS
319 check_file_perms(pwfile, S_IRUSR | S_IWUSR);
320 #endif
321
322 fd = fopen(pwfile, "r");
323 if (fd == NULL)
324 fatal(ERROR_FILE_OPEN, "opening passwords file %s; %s\n",
325 pwfile, strerror(errno));
326
327 parse_passwords(fd);
328
329 fclose(fd);
330
331 return 0;
332 }
333
334
335 /*
336 * Parse unencrypted password file.
337 */
338 int
339 parse_passwords(FILE * fd)
340 {
341 int t;
342 char *pe;
343 char user[USERNAME_LEN], serv[SERVER_LEN];
344 unsigned char *buf;
345 char *c, *cp, *line;
346 regex_t creg;
347 regmatch_t match[4];
348 const char *reg;
349
350 t = 3;
351 pe = NULL;
352 reg = "([[:alnum:].-]+) ([[:graph:]]+) ([[:graph:]]+)";
353
354 if (!(flags & FLAG_DAEMON_MODE)) {
355 do {
356 fseek(fd, 0L, SEEK_SET);
357 printf("Enter master passphrase: ");
358 get_password(passphr, PASSPHRASE_LEN);
359 } while (decrypt_passwords(&buf, fd) && --t != 0);
360
361 if (!t)
362 return ERROR_PASSPHRASE;
363 } else if (decrypt_passwords(&buf, fd))
364 fatal(ERROR_DECRYPT,
365 "failed decrypting passwords in daemon mode\n");
366
367 c = cp = sstrdup(buf);
368
369 regcomp(&creg, reg, REG_EXTENDED | REG_ICASE);
370
371 line = strtok_r(c, "\n", &c);
372 while (line != NULL && !regexec(&creg, line, 4, match, 0)) {
373 user[0] = serv[0] = '\0';
374
375 strncat(serv, line + match[1].rm_so,
376 min(match[1].rm_eo - match[1].rm_so, SERVER_LEN - 1));
377 strncat(user, line + match[2].rm_so,
378 min(match[2].rm_eo - match[2].rm_so, USERNAME_LEN - 1));
379
380 if ((pe = (char *)find_password(user, serv)))
381 strncat(pe, line + match[3].rm_so,
382 min(match[3].rm_eo - match[3].rm_so,
383 PASSWORD_LEN - 1));
384
385 line = strtok_r(NULL, "\n", &c);
386 }
387
388 regfree(&creg);
389 sfree(cp);
390 sfree(buf);
391
392 return 0;
393 }
394 #endif /* ENCRYPTED_PASSWORDS */

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26