]> Pileus Git - ~andy/fetchmail/blob - rcfile_y.y
Dave Bodenstab's fixes.
[~andy/fetchmail] / rcfile_y.y
1 %{
2 /*
3  * rcfile_y.y -- Run control file parser for fetchmail
4  *
5  * For license terms, see the file COPYING in this directory.
6  */
7
8 #include <config.h>
9 #include <stdio.h>
10 #include <sys/types.h>
11 #include <sys/file.h>
12 #include <sys/wait.h>
13 #include <sys/stat.h>
14 #include <errno.h>
15 #if defined(STDC_HEADERS)
16 #include <stdlib.h>
17 #endif
18 #if defined(HAVE_UNISTD_H)
19 #include <unistd.h>
20 #endif
21 #include <string.h>
22
23 #include "fetchmail.h"
24
25 struct query cmd_opts;  /* where to put command-line info */
26 struct query *querylist;        /* head of server list (globally visible) */
27
28 int yydebug;    /* in case we didn't generate with -- debug */
29
30 static struct query current;            /* current server record */
31 static int prc_errflag;
32
33 static void prc_register();
34 static void prc_reset();
35 %}
36
37 %union {
38   int proto;
39   int flag;
40   int number;
41   char *sval;
42 }
43
44 %token DEFAULTS POLL SKIP AKA LOCALDOMAINS PROTOCOL
45 %token AUTHENTICATE TIMEOUT KPOP KERBEROS
46 %token ENVELOPE USERNAME PASSWORD FOLDER SMTPHOST MDA PRECONNECT LIMIT
47 %token IS HERE THERE TO MAP WILDCARD
48 %token SET BATCHLIMIT FETCHLIMIT LOGFILE INTERFACE MONITOR
49 %token <proto> PROTO
50 %token <sval>  STRING
51 %token <number> NUMBER
52 %token <flag>  KEEP FLUSH FETCHALL REWRITE STRIPCR DNS PORT
53
54 /* these are actually used by the lexer */
55 %token FLAG_TRUE        2
56 %token FLAG_FALSE       1
57
58 %%
59
60 rcfile          : /* empty */
61                 | statement_list
62                 ;
63
64 statement_list  : statement
65                 | statement_list statement
66                 ;
67
68 /* future global options should also have the form SET <name> <value> */
69 statement       : SET LOGFILE MAP STRING        {logfile = xstrdup($4);}
70
71 /* 
72  * The way the next two productions are written depends on the fact that
73  * userspecs cannot be empty.  It's a kluge to deal with files that set
74  * up a load of defaults and then have poll statements following with no
75  * user options at all. 
76  */
77                 | define_server serverspecs     {prc_register(); prc_reset();}
78                 | define_server serverspecs userspecs
79                                 {
80                                         memset(&current,'\0',sizeof(current));
81                                         current.stripcr = -1;
82                                 }
83                 ;
84
85 define_server   : POLL STRING   {current.server.names = (struct idlist *)NULL;
86                                         save_str(&current.server.names, -1,$2);
87                                         current.server.skip = FALSE;}
88                 | SKIP STRING   {current.server.names = (struct idlist *)NULL;
89                                         save_str(&current.server.names, -1,$2);
90                                         current.server.skip = TRUE;}
91                 | DEFAULTS      {current.server.names = (struct idlist *)NULL;
92                                         save_str(&current.server.names, -1,"defaults");}
93                 ;
94
95 serverspecs     : /* EMPTY */
96                 | serverspecs serv_option
97                 ;
98
99 alias_list      : STRING                {save_str(&current.server.names,-1,$1);}
100                 | alias_list STRING     {save_str(&current.server.names,-1,$2);}
101                 ;
102
103 domain_list     : STRING                {save_str(&current.server.localdomains,-1,$1);}
104                 | domain_list STRING    {save_str(&current.server.localdomains,-1,$2);}
105                 ;
106
107 serv_option     : AKA alias_list
108                 | LOCALDOMAINS domain_list
109                 | PROTOCOL PROTO        {current.server.protocol = $2;}
110                 | PROTOCOL KPOP         {
111                                             current.server.protocol = P_POP3;
112                                             current.server.authenticate = A_KERBEROS;
113                                             current.server.port = KPOP_PORT;
114                                         }
115                 | PORT NUMBER           {current.server.port = $2;}
116                 | AUTHENTICATE PASSWORD {current.server.authenticate = A_PASSWORD;}
117                 | AUTHENTICATE KERBEROS {current.server.authenticate = A_KERBEROS;}
118                 | TIMEOUT NUMBER        {current.server.timeout = $2;}
119                 | ENVELOPE STRING       {current.server.envelope = xstrdup($2);}
120                 | INTERFACE STRING      {
121 #ifdef linux
122                                         interface_parse($2, &current.server);
123 #else
124                                         fprintf(stderr, "fetchmail: interface option is only supported under Linux\n");
125 #endif /* linux */
126                                         }
127                 | MONITOR STRING        {
128 #ifdef linux
129                                         current.server.monitor = xstrdup($2);
130 #else
131                                         fprintf(stderr, "fetchmail: monitor option is only supported under Linux\n");
132 #endif /* linux */
133                                         }
134                 | DNS                   {current.server.no_dns = ($1==FLAG_FALSE);}
135                 ;
136
137 /*
138  * The first and only the first user spec may omit the USERNAME part.
139  * This is a backward-compatibility kluge to allow old popclient files
140  * to keep working.
141  */
142 userspecs       : user1opts             {prc_register(); prc_reset();}
143                 | user1opts explicits   {prc_register(); prc_reset();}
144                 | explicits
145                 ;
146
147 explicits       : explicitdef           {prc_register(); prc_reset();}
148                 | explicits explicitdef {prc_register(); prc_reset();}
149                 ;
150
151 explicitdef     : userdef user0opts
152                 ;
153
154 userdef         : USERNAME STRING       {current.remotename = xstrdup($2);}
155                 | USERNAME mapping_list HERE
156                 | USERNAME STRING THERE {current.remotename = xstrdup($2);}
157                 ;
158
159 user0opts       : /* EMPTY */
160                 | user0opts user_option
161                 ;
162
163 user1opts       : user_option
164                 | user1opts user_option
165                 ;
166
167 localnames      : WILDCARD              {current.wildcard =  TRUE;}
168                 | mapping_list          {current.wildcard =  FALSE;}
169                 | mapping_list WILDCARD {current.wildcard =  TRUE;}
170                 ;
171
172 mapping_list    : mapping               
173                 | mapping_list mapping
174                 ;
175
176 mapping         : STRING        
177                                 {save_str_pair(&current.localnames, $1, NULL);}
178                 | STRING MAP STRING
179                                 {save_str_pair(&current.localnames, $1, $3);}
180                 ;
181
182 user_option     : TO localnames HERE
183                 | TO localnames
184                 | IS localnames HERE
185                 | IS localnames
186
187                 | IS STRING THERE       {current.remotename = xstrdup($2);}
188                 | PASSWORD STRING       {current.password = xstrdup($2);}
189                 | FOLDER STRING         {current.mailbox = xstrdup($2);}
190                 | SMTPHOST STRING       {current.smtphost = xstrdup($2);}
191                 | MDA STRING            {current.mda = xstrdup($2);}
192                 | PRECONNECT STRING     {current.preconnect = xstrdup($2);}
193
194                 | KEEP                  {current.keep = ($1==FLAG_TRUE);}
195                 | FLUSH                 {current.flush = ($1==FLAG_TRUE);}
196                 | FETCHALL              {current.fetchall = ($1==FLAG_TRUE);}
197                 | REWRITE               {current.no_rewrite =($1==FLAG_FALSE);}
198                 | STRIPCR               {current.stripcr = ($1==FLAG_TRUE);}
199                 | LIMIT NUMBER          {current.limit = $2;}
200                 | FETCHLIMIT NUMBER     {current.fetchlimit = $2;}
201                 | BATCHLIMIT NUMBER     {current.batchlimit = $2;}
202                 ;
203 %%
204
205 /* lexer interface */
206 extern char *rcfile;
207 extern int prc_lineno;
208 extern char *yytext;
209 extern FILE *yyin;
210
211 static struct query *hosttail;  /* where to add new elements */
212
213 void yyerror (const char *s)
214 /* report a syntax error */
215 {
216     fprintf(stderr,"%s line %d: %s at %s\n", rcfile, prc_lineno, s, yytext);
217     prc_errflag++;
218 }
219
220 int prc_filecheck(pathname)
221 /* check that a configuration file is secure */
222 const char *pathname;           /* pathname for the configuration file */
223 {
224     struct stat statbuf;
225
226     /* the run control file must have the same uid as the REAL uid of this 
227        process, it must have permissions no greater than 600, and it must not 
228        be a symbolic link.  We check these conditions here. */
229
230     errno = 0;
231     if (lstat(pathname, &statbuf) < 0) {
232         if (errno == ENOENT) 
233             return(0);
234         else {
235             error(0, errno, "lstat: %s", pathname);
236             return(PS_IOERR);
237         }
238     }
239
240     if ((statbuf.st_mode & S_IFLNK) == S_IFLNK) {
241         fprintf(stderr, "File %s must not be a symbolic link.\n", pathname);
242         return(PS_AUTHFAIL);
243     }
244
245     if (statbuf.st_mode & ~(S_IFREG | S_IREAD | S_IWRITE)) {
246         fprintf(stderr, "File %s must have no more than -rw------ permissions.\n", 
247                 pathname);
248         return(PS_AUTHFAIL);
249     }
250
251     if (statbuf.st_uid != getuid()) {
252         fprintf(stderr, "File %s must be owned by you.\n", pathname);
253         return(PS_AUTHFAIL);
254     }
255
256     return(0);
257 }
258
259 int prc_parse_file (pathname)
260 /* digest the configuration into a linked list of host records */
261 const char *pathname;           /* pathname for the configuration file */
262 {
263     prc_errflag = 0;
264     querylist = hosttail = (struct query *)NULL;
265     prc_reset();
266
267     /* Check that the file is secure */
268     if ((prc_errflag = prc_filecheck(pathname)) != 0)
269         return(prc_errflag);
270
271     if (errno == ENOENT)
272         return(0);
273
274     /* Open the configuration and feed it to the lexer. */
275     if ((yyin = fopen(pathname,"r")) == (FILE *)NULL) {
276         error(0, errno, "open: %s", pathname);
277         return(PS_IOERR);
278     }
279
280     yyparse();          /* parse entire file */
281
282     fclose(yyin);
283
284     if (prc_errflag) 
285         return(PS_SYNTAX);
286     else
287         return(0);
288 }
289
290 static void prc_reset(void)
291 /* clear the global current record (server parameters) used by the parser */
292 {
293     struct hostdata save;
294
295     /*
296      * Purpose of this code is to initialize the new server block, but
297      * preserve whatever server name was previously set.  Also
298      * preserve server options unless the command-line explicitly
299      * overrides them.
300      */
301     save = current.server;
302
303     memset(&current, '\0', sizeof(current));
304
305     current.server = save;
306 }
307
308 struct query *hostalloc(init)
309 /* append a host record to the host list */
310 struct query *init;     /* pointer to block containing initial values */
311 {
312     struct query *node;
313
314     /* allocate new node */
315     node = (struct query *) xmalloc(sizeof(struct query));
316
317     /* initialize it */
318     memcpy(node, init, sizeof(struct query));
319
320     /* append to end of list */
321     if (hosttail != (struct query *) 0)
322         hosttail->next = node;  /* list contains at least one element */
323     else
324         querylist = node;       /* list is empty */
325     hosttail = node;
326     return(node);
327 }
328
329 static void prc_register(void)
330 /* register current parameters and append to the host list */
331 {
332 #define FLAG_FORCE(fld) if (cmd_opts.fld) current.fld = cmd_opts.fld
333     FLAG_FORCE(server.protocol);
334     FLAG_FORCE(server.port);
335     FLAG_FORCE(server.authenticate);
336     FLAG_FORCE(server.timeout);
337     FLAG_FORCE(server.envelope);
338     FLAG_FORCE(server.skip);
339     FLAG_FORCE(server.no_dns);
340
341 #ifdef linux
342     FLAG_FORCE(server.interface);
343     FLAG_FORCE(server.monitor);
344     FLAG_FORCE(server.interface_pair);
345 #endif /* linux */
346
347     FLAG_FORCE(remotename);
348     FLAG_FORCE(password);
349     FLAG_FORCE(mailbox);
350     FLAG_FORCE(smtphost);
351     FLAG_FORCE(mda);
352     FLAG_FORCE(preconnect);
353
354     FLAG_FORCE(keep);
355     FLAG_FORCE(flush);
356     FLAG_FORCE(fetchall);
357     FLAG_FORCE(no_rewrite);
358     FLAG_FORCE(stripcr);
359     FLAG_FORCE(limit);
360     FLAG_FORCE(fetchlimit);
361     FLAG_FORCE(batchlimit);
362
363 #undef FLAG_FORCE
364
365     (void) hostalloc(&current);
366 }
367
368 void optmerge(struct query *h2, struct query *h1)
369 /* merge two options records; empty fields in h2 are filled in from h1 */
370 {
371     append_str_list(&h2->server.localdomains, &h1->server.localdomains);
372     append_str_list(&h2->localnames, &h1->localnames);
373
374 #define FLAG_MERGE(fld) if (!h2->fld) h2->fld = h1->fld
375     FLAG_MERGE(server.protocol);
376     FLAG_MERGE(server.port);
377     FLAG_MERGE(server.authenticate);
378     FLAG_MERGE(server.timeout);
379     FLAG_MERGE(server.envelope);
380     FLAG_MERGE(server.skip);
381     FLAG_MERGE(server.no_dns);
382
383 #ifdef linux
384     FLAG_MERGE(server.interface);
385     FLAG_MERGE(server.monitor);
386     FLAG_MERGE(server.interface_pair);
387 #endif /* linux */
388
389     FLAG_MERGE(remotename);
390     FLAG_MERGE(password);
391     FLAG_MERGE(mailbox);
392     FLAG_MERGE(smtphost);
393     FLAG_MERGE(mda);
394     FLAG_MERGE(preconnect);
395
396     FLAG_MERGE(keep);
397     FLAG_MERGE(flush);
398     FLAG_MERGE(fetchall);
399     FLAG_MERGE(no_rewrite);
400     FLAG_MERGE(stripcr);
401     FLAG_MERGE(limit);
402     FLAG_MERGE(fetchlimit);
403     FLAG_MERGE(batchlimit);
404 #undef FLAG_MERGE
405 }
406
407 /* easier to do this than cope with variations in where the library lives */
408 int yywrap(void) {return 1;}
409
410 /* rcfile_y.y ends here */