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