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