]> Pileus Git - ~andy/fetchmail/blob - rcfile_y.y
Implement batchlimit option.
[~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 PROTOCOL AUTHENTICATE TIMEOUT KPOP KERBEROS
45 %token USERNAME PASSWORD FOLDER SMTPHOST MDA IS HERE THERE TO MAP LIMIT
46 %token SET BATCHLIMIT 
47 %token <proto> PROTO
48 %token <sval>  STRING
49 %token <number> NUMBER
50 %token <flag>  KEEP FLUSH FETCHALL REWRITE PORT SKIP
51
52 /* these are actually used by the lexer */
53 %token FLAG_TRUE        2
54 %token FLAG_FALSE       1
55
56 %%
57
58 rcfile          : /* empty */
59                 | statement_list
60                 ;
61
62 statement_list  : statement
63                 | statement_list statement
64                 ;
65
66 /* future global options should also have the form SET <name> <value> */
67 statement       : define_server serverspecs userspecs
68                 | SET BATCHLIMIT MAP NUMBER     {batchlimit = $4;}
69                 ;
70
71 define_server   : POLL STRING   {strcpy(current.servername, $2);}
72                 | SKIP STRING   {strcpy(current.servername, $2);
73                                                 current.skip=($1==FLAG_TRUE);}
74                 | DEFAULTS      {strcpy(current.servername,"defaults");}
75                 ;
76
77 serverspecs     : /* EMPTY */
78                 | serverspecs serv_option
79                 ;
80
81 serv_option     : PROTOCOL PROTO        {current.protocol = $2;}
82                 | PROTOCOL KPOP         {
83                                             current.protocol = P_POP3;
84                                             current.authenticate = A_KERBEROS;
85                                             current.port = KPOP_PORT;
86                                         }
87                 | PORT NUMBER           {current.port = $2;}
88                 | AUTHENTICATE PASSWORD {current.authenticate = A_PASSWORD;}
89                 | AUTHENTICATE KERBEROS {current.authenticate = A_KERBEROS;}
90                 | TIMEOUT NUMBER        {current.timeout = $2;}
91                 ;
92
93 /* the first and only the first user spec may omit the USERNAME part */
94 userspecs       : /* EMPTY */
95                 | user1opts             {prc_register(); prc_reset();}
96                 | user1opts explicits   {prc_register(); prc_reset();}
97                 | explicits
98                 ;
99
100 explicits       : explicitdef           {prc_register(); prc_reset();}
101                 | explicits explicitdef {prc_register(); prc_reset();}
102                 ;
103
104 explicitdef     : userdef user0opts
105                 ;
106
107 userdef         : USERNAME STRING       {strcpy(current.remotename, $2);}
108                 | USERNAME mapping_list HERE
109                 | USERNAME STRING THERE {strcpy(current.remotename, $2);}
110                 ;
111
112 user0opts       : /* EMPTY */
113                 | user0opts user_option
114                 ;
115
116 user1opts       : user_option
117                 | user1opts user_option
118                 ;
119
120 mapping_list    : mapping               
121                 | mapping_list mapping
122                 ;
123
124 mapping         : STRING        
125                                 {save_id_pair(&current.localnames, $1, NULL);}
126                 | STRING MAP STRING
127                                 {save_id_pair(&current.localnames, $1, $3);}
128                 ;
129
130 user_option     : TO mapping_list HERE
131                 | TO mapping_list
132                 | IS mapping_list HERE
133                 | IS mapping_list
134                 | IS STRING THERE       {strcpy(current.remotename, $2);}
135                 | PASSWORD STRING       {strcpy(current.password, $2);}
136                 | FOLDER STRING         {strcpy(current.mailbox, $2);}
137                 | SMTPHOST STRING       {strcpy(current.smtphost, $2);}
138                 | MDA STRING            {strcpy(current.mda, $2);}
139
140                 | KEEP                  {current.keep = ($1==FLAG_TRUE);}
141                 | FLUSH                 {current.flush = ($1==FLAG_TRUE);}
142                 | FETCHALL              {current.fetchall = ($1==FLAG_TRUE);}
143                 | REWRITE               {current.norewrite = ($1==FLAG_TRUE);}
144                 | LIMIT NUMBER          {current.limit = $2;}
145                 ;
146 %%
147
148 /* lexer interface */
149 extern char *rcfile;
150 extern int prc_lineno;
151 extern char *yytext;
152 extern FILE *yyin;
153
154 static struct query *hosttail;  /* where to add new elements */
155
156 void yyerror (s)
157 /* report a syntax error */
158 char *s;        /* error string */
159 {
160     fprintf(stderr,"%s line %d: %s at %s\n", rcfile, prc_lineno, s, yytext);
161     prc_errflag++;
162 }
163
164 int prc_filecheck(pathname)
165 /* check that a configuration file is secure */
166 const char *pathname;           /* pathname for the configuration file */
167 {
168     struct stat statbuf;
169
170     /* the run control file must have the same uid as the REAL uid of this 
171        process, it must have permissions no greater than 600, and it must not 
172        be a symbolic link.  We check these conditions here. */
173
174     errno = 0;
175     if (lstat(pathname, &statbuf) < 0) {
176         if (errno == ENOENT) 
177             return(0);
178         else {
179             perror(pathname);
180             return(PS_IOERR);
181         }
182     }
183
184     if ((statbuf.st_mode & S_IFLNK) == S_IFLNK) {
185         fprintf(stderr, "File %s must not be a symbolic link.\n", pathname);
186         return(PS_AUTHFAIL);
187     }
188
189     if (statbuf.st_mode & ~(S_IFREG | S_IREAD | S_IWRITE)) {
190         fprintf(stderr, "File %s must have no more than -rw------ permissions.\n", 
191                 pathname);
192         return(PS_AUTHFAIL);
193     }
194
195     if (statbuf.st_uid != getuid()) {
196         fprintf(stderr, "File %s must be owned by you.\n", pathname);
197         return(PS_AUTHFAIL);
198     }
199
200     return(0);
201 }
202
203 int prc_parse_file (pathname)
204 /* digest the configuration into a linked list of host records */
205 const char *pathname;           /* pathname for the configuration file */
206 {
207     prc_errflag = 0;
208     querylist = hosttail = (struct query *)NULL;
209     prc_reset();
210
211     /* Check that the file is secure */
212     if ((prc_errflag = prc_filecheck(pathname)) != 0)
213         return(prc_errflag);
214
215     if (errno == ENOENT)
216         return(0);
217
218     /* Open the configuration and feed it to the lexer. */
219     if ((yyin = fopen(pathname,"r")) == (FILE *)NULL) {
220         perror(pathname);
221         return(PS_IOERR);
222     }
223
224     yyparse();          /* parse entire file */
225
226     fclose(yyin);
227
228     if (prc_errflag) 
229         return(PS_SYNTAX);
230     else
231         return(0);
232 }
233
234 static void prc_reset()
235 /* clear the global current record (server parameters) used by the parser */
236 {
237     char        savename[HOSTLEN+1];
238     int         saveport, saveproto, saveauth, saveskip;
239
240     /*
241      * Purpose of this code is to initialize the new server block, but
242      * preserve whatever server name was previously set.  Also
243      * preserve server options unless the command-line explicitly
244      * overrides them.
245      */
246     (void) strcpy(savename, current.servername);
247     saveport = current.port;
248     saveproto = current.protocol;
249     saveauth = current.authenticate;
250     saveskip = current.skip;
251
252     memset(&current, '\0', sizeof(current));
253
254     (void) strcpy(current.servername, savename);
255     current.protocol = saveproto;
256     current.authenticate = saveauth;
257     current.skip = saveskip;
258 }
259
260 struct query *hostalloc(init)
261 /* append a host record to the host list */
262 struct query *init;     /* pointer to block containing initial values */
263 {
264     struct query *node;
265
266     /* allocate new node */
267     node = (struct query *) xmalloc(sizeof(struct query));
268
269     /* initialize it */
270     memcpy(node, init, sizeof(struct query));
271
272     /* append to end of list */
273     if (hosttail != (struct query *) 0)
274         hosttail->next = node;  /* list contains at least one element */
275     else
276         querylist = node;       /* list is empty */
277     hosttail = node;
278     return(node);
279 }
280
281 static void prc_register()
282 /* register current parameters and append to the host list */
283 {
284 #define STR_FORCE(fld, len) if (cmd_opts.fld[0]) \
285                                         strcpy(current.fld, cmd_opts.fld)
286     STR_FORCE(remotename, USERNAMELEN);
287     STR_FORCE(password, PASSWORDLEN);
288     STR_FORCE(mailbox, FOLDERLEN);
289     STR_FORCE(smtphost, HOSTLEN);
290     STR_FORCE(mda, MDALEN);
291 #undef STR_FORCE
292     
293 #define FLAG_FORCE(fld) if (cmd_opts.fld) current.fld = cmd_opts.fld
294     FLAG_FORCE(protocol);
295     FLAG_FORCE(keep);
296     FLAG_FORCE(flush);
297     FLAG_FORCE(fetchall);
298     FLAG_FORCE(norewrite);
299     FLAG_FORCE(skip);
300     FLAG_FORCE(port);
301     FLAG_FORCE(authenticate);
302     FLAG_FORCE(timeout);
303     FLAG_FORCE(limit);
304 #undef FLAG_FORCE
305
306     (void) hostalloc(&current);
307 }
308
309 void optmerge(h2, h1)
310 /* merge two options records; empty fields in h2 are filled in from h1 */
311 struct query *h1;
312 struct query *h2;
313 {
314     append_uid_list(&h2->localnames, &h1->localnames);
315
316 #define STR_MERGE(fld, len) if (*(h2->fld) == '\0') strcpy(h2->fld, h1->fld)
317     STR_MERGE(remotename, USERNAMELEN);
318     STR_MERGE(password, PASSWORDLEN);
319     STR_MERGE(mailbox, FOLDERLEN);
320     STR_MERGE(smtphost, HOSTLEN);
321     STR_MERGE(mda, MDALEN);
322 #undef STR_MERGE
323
324 #define FLAG_MERGE(fld) if (!h2->fld) h2->fld = h1->fld
325     FLAG_MERGE(protocol);
326     FLAG_MERGE(keep);
327     FLAG_MERGE(flush);
328     FLAG_MERGE(fetchall);
329     FLAG_MERGE(norewrite);
330     FLAG_MERGE(skip);
331     FLAG_MERGE(port);
332     FLAG_MERGE(authenticate);
333     FLAG_MERGE(timeout);
334     FLAG_MERGE(limit);
335 #undef FLAG_MERGE
336
337 }
338
339 /* easier to do this than cope with variations in where the library lives */
340 int yywrap() {return 1;}
341
342 /* rcfile_y.y ends here */