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

Annotation of /imapfilter/parse.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.4.2.1 - (hide 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 lefcha 1.1 #include <stdio.h>
2 lefcha 1.3 #include <stdlib.h>
3 lefcha 1.1 #include <string.h>
4 lefcha 1.4.2.1 #include <strings.h>
5 lefcha 1.1 #include <errno.h>
6 lefcha 1.4.2.1 #include <limits.h>
7 lefcha 1.1 #include <sys/stat.h>
8 lefcha 1.4.2.1 #include <regex.h>
9 lefcha 1.1
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 lefcha 1.4 * Signal SIGUSR1 received, destroy all data structures and reread the
211 lefcha 1.1 * configuration file.
212     */
213     void
214     reread_config(char *cfg)
215     {
216     destroy_all();
217     read_config(cfg);
218 lefcha 1.2 #ifdef ENCRYPTED_PASSWORDS
219 lefcha 1.1 read_passwords();
220 lefcha 1.2 #endif
221 lefcha 1.4 flags &= ~(FLAG_SIGUSR1_RECEIVED);
222 lefcha 1.1 }
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