3 * rcfile_y.y -- Run control file parser for fetchmail
5 * For license terms, see the file COPYING in this directory.
10 #include <sys/types.h>
15 #if defined(STDC_HEADERS)
18 #if defined(HAVE_UNISTD_H)
23 #include "fetchmail.h"
25 struct query cmd_opts; /* where to put command-line info */
26 struct query *querylist; /* head of server list (globally visible) */
28 int yydebug; /* in case we didn't generate with -- debug */
30 static struct query current; /* current server record */
31 static int prc_errflag;
33 static void record_current();
34 static void user_reset();
43 %token DEFAULTS POLL SKIP AKA LOCALDOMAINS PROTOCOL
44 %token AUTHENTICATE TIMEOUT KPOP KERBEROS
45 %token ENVELOPE USERNAME PASSWORD FOLDER SMTPHOST MDA PRECONNECT LIMIT
46 %token IS HERE THERE TO MAP WILDCARD
47 %token SET BATCHLIMIT FETCHLIMIT LOGFILE DAEMON INTERFACE MONITOR
50 %token <number> NUMBER
51 %token NO KEEP FLUSH FETCHALL REWRITE FORCECR STRIPCR DNS PORT UIDL
59 statement_list : statement
60 | statement_list statement
63 /* future global options should also have the form SET <name> <value> */
64 statement : SET LOGFILE MAP STRING {logfile = xstrdup($4);}
65 | SET DAEMON NUMBER {poll_interval = $3;}
68 * The way the next two productions are written depends on the fact that
69 * userspecs cannot be empty. It's a kluge to deal with files that set
70 * up a load of defaults and then have poll statements following with no
71 * user options at all.
73 | define_server serverspecs {record_current();}
74 | define_server serverspecs userspecs
77 define_server : POLL STRING {memset(¤t,'\0',sizeof(current));
78 save_str(¤t.server.names, -1,$2);
79 current.server.skip = FALSE;}
80 | SKIP STRING {memset(¤t,'\0',sizeof(current));
81 save_str(¤t.server.names, -1,$2);
82 current.server.skip = TRUE;}
83 | DEFAULTS {memset(¤t,'\0',sizeof(current));
84 save_str(¤t.server.names, -1,"defaults");}
87 serverspecs : /* EMPTY */
88 | serverspecs serv_option
91 alias_list : STRING {save_str(¤t.server.names,-1,$1);}
92 | alias_list STRING {save_str(¤t.server.names,-1,$2);}
95 domain_list : STRING {save_str(¤t.server.localdomains,-1,$1);}
96 | domain_list STRING {save_str(¤t.server.localdomains,-1,$2);}
99 serv_option : AKA alias_list
100 | LOCALDOMAINS domain_list
101 | PROTOCOL PROTO {current.server.protocol = $2;}
103 current.server.protocol = P_POP3;
104 current.server.authenticate = A_KERBEROS;
105 current.server.port = KPOP_PORT;
107 | UIDL {current.server.uidl = FLAG_TRUE;}
108 | NO UIDL {current.server.uidl = FLAG_FALSE;}
109 | PORT NUMBER {current.server.port = $2;}
110 | AUTHENTICATE PASSWORD {current.server.authenticate = A_PASSWORD;}
111 | AUTHENTICATE KERBEROS {current.server.authenticate = A_KERBEROS;}
112 | TIMEOUT NUMBER {current.server.timeout = $2;}
113 | ENVELOPE STRING {current.server.envelope = xstrdup($2);}
116 interface_parse($2, ¤t.server);
118 fprintf(stderr, "fetchmail: interface option is only supported under Linux\n");
123 current.server.monitor = xstrdup($2);
125 fprintf(stderr, "fetchmail: monitor option is only supported under Linux\n");
128 | DNS {current.server.dns = FLAG_TRUE;}
129 | NO DNS {current.server.dns = FLAG_FALSE;}
130 | NO ENVELOPE {current.server.envelope = STRING_DISABLED;}
134 * The first and only the first user spec may omit the USERNAME part.
135 * This is a backward-compatibility kluge to allow old popclient files
138 userspecs : user1opts {record_current(); user_reset();}
139 | user1opts explicits
141 record_current(); user_reset();
142 fprintf(stderr, "Warning: user entry with no `user' keyword\n");
147 explicits : explicitdef {record_current(); user_reset();}
148 | explicits explicitdef {record_current(); user_reset();}
151 explicitdef : userdef user0opts
154 userdef : USERNAME STRING {current.remotename = xstrdup($2);}
155 | USERNAME mapping_list HERE
156 | USERNAME STRING THERE {current.remotename = xstrdup($2);}
159 user0opts : /* EMPTY */
160 | user0opts user_option
163 user1opts : user_option
164 | user1opts user_option
167 localnames : WILDCARD {current.wildcard = TRUE;}
168 | mapping_list {current.wildcard = FALSE;}
169 | mapping_list WILDCARD {current.wildcard = TRUE;}
172 mapping_list : mapping
173 | mapping_list mapping
177 {save_str_pair(¤t.localnames, $1, NULL);}
179 {save_str_pair(¤t.localnames, $1, $3);}
182 smtphunt : STRING {save_str(¤t.smtphunt, -1, $1);}
183 | smtphunt STRING {save_str(¤t.smtphunt, -1, $2);}
186 user_option : TO localnames HERE
191 | IS STRING THERE {current.remotename = xstrdup($2);}
192 | PASSWORD STRING {current.password = xstrdup($2);}
193 | FOLDER STRING {current.mailbox = xstrdup($2);}
195 | MDA STRING {current.mda = xstrdup($2);}
196 | PRECONNECT STRING {current.preconnect = xstrdup($2);}
198 | KEEP {current.keep = FLAG_TRUE;}
199 | FLUSH {current.flush = FLAG_TRUE;}
200 | FETCHALL {current.fetchall = FLAG_TRUE;}
201 | REWRITE {current.rewrite = FLAG_TRUE;}
202 | FORCECR {current.forcecr = FLAG_TRUE;}
203 | STRIPCR {current.stripcr = FLAG_TRUE;}
205 | NO KEEP {current.keep = FLAG_FALSE;}
206 | NO FLUSH {current.flush = FLAG_FALSE;}
207 | NO FETCHALL {current.fetchall = FLAG_FALSE;}
208 | NO REWRITE {current.rewrite = FLAG_FALSE;}
209 | NO FORCECR {current.forcecr = FLAG_FALSE;}
210 | NO STRIPCR {current.stripcr = FLAG_FALSE;}
212 | LIMIT NUMBER {current.limit = $2;}
213 | FETCHLIMIT NUMBER {current.fetchlimit = $2;}
214 | BATCHLIMIT NUMBER {current.batchlimit = $2;}
218 /* lexer interface */
220 extern int prc_lineno;
224 static struct query *hosttail; /* where to add new elements */
226 void yyerror (const char *s)
227 /* report a syntax error */
229 error_at_line( 0, 0, rcfile, prc_lineno, "%s at %s", s, yytext );
233 int prc_filecheck(pathname)
234 /* check that a configuration file is secure */
235 const char *pathname; /* pathname for the configuration file */
239 /* special case, useful for debugging purposes */
240 if (strcmp("/dev/null", pathname) == 0)
243 /* the run control file must have the same uid as the REAL uid of this
244 process, it must have permissions no greater than 600, and it must not
245 be a symbolic link. We check these conditions here. */
248 if (lstat(pathname, &statbuf) < 0) {
252 error(0, errno, "lstat: %s", pathname);
257 if ((statbuf.st_mode & S_IFLNK) == S_IFLNK) {
258 fprintf(stderr, "File %s must not be a symbolic link.\n", pathname);
262 if (statbuf.st_mode & ~(S_IFREG | S_IREAD | S_IWRITE)) {
263 fprintf(stderr, "File %s must have no more than -rw------ (0600) permissions.\n",
268 if (statbuf.st_uid != getuid()) {
269 fprintf(stderr, "File %s must be owned by you.\n", pathname);
276 int prc_parse_file (pathname)
277 /* digest the configuration into a linked list of host records */
278 const char *pathname; /* pathname for the configuration file */
281 querylist = hosttail = (struct query *)NULL;
283 /* Check that the file is secure */
284 if ((prc_errflag = prc_filecheck(pathname)) != 0)
290 /* Open the configuration and feed it to the lexer. */
291 if ((yyin = fopen(pathname,"r")) == (FILE *)NULL) {
292 error(0, errno, "open: %s", pathname);
296 yyparse(); /* parse entire file */
306 static void user_reset(void)
307 /* clear the global current record (server parameters) used by the parser */
309 struct hostdata save;
312 * Purpose of this code is to initialize the new server block, but
313 * preserve whatever server name was previously set. Also
314 * preserve server options unless the command-line explicitly
317 save = current.server;
319 memset(¤t, '\0', sizeof(current));
321 current.server = save;
324 struct query *hostalloc(init)
325 /* append a host record to the host list */
326 struct query *init; /* pointer to block containing initial values */
330 /* allocate new node */
331 node = (struct query *) xmalloc(sizeof(struct query));
334 memcpy(node, init, sizeof(struct query));
336 /* append to end of list */
337 if (hosttail != (struct query *) 0)
338 hosttail->next = node; /* list contains at least one element */
340 querylist = node; /* list is empty */
345 static void record_current(void)
346 /* register current parameters and append to the host list */
348 #define FLAG_FORCE(fld) if (cmd_opts.fld) current.fld = cmd_opts.fld
349 FLAG_FORCE(server.protocol);
350 FLAG_FORCE(server.port);
351 FLAG_FORCE(server.authenticate);
352 FLAG_FORCE(server.timeout);
353 FLAG_FORCE(server.envelope);
354 FLAG_FORCE(server.skip);
355 FLAG_FORCE(server.dns);
358 FLAG_FORCE(server.interface);
359 FLAG_FORCE(server.monitor);
360 FLAG_FORCE(server.interface_pair);
363 FLAG_FORCE(remotename);
364 FLAG_FORCE(password);
366 if (cmd_opts.smtphunt)
367 save_str(¤t.smtphunt, -1, cmd_opts.smtphunt->id);
369 FLAG_FORCE(preconnect);
373 FLAG_FORCE(fetchall);
378 FLAG_FORCE(fetchlimit);
379 FLAG_FORCE(batchlimit);
383 (void) hostalloc(¤t);
386 void optmerge(struct query *h2, struct query *h1)
387 /* merge two options records; empty fields in h2 are filled in from h1 */
389 append_str_list(&h2->server.localdomains, &h1->server.localdomains);
390 append_str_list(&h2->localnames, &h1->localnames);
391 append_str_list(&h2->smtphunt, &h1->smtphunt);
393 #define FLAG_MERGE(fld) if (!h2->fld) h2->fld = h1->fld
394 FLAG_MERGE(server.protocol);
395 FLAG_MERGE(server.port);
396 FLAG_MERGE(server.authenticate);
397 FLAG_MERGE(server.timeout);
398 FLAG_MERGE(server.envelope);
399 FLAG_MERGE(server.skip);
400 FLAG_MERGE(server.dns);
403 FLAG_MERGE(server.interface);
404 FLAG_MERGE(server.monitor);
405 FLAG_MERGE(server.interface_pair);
408 FLAG_MERGE(remotename);
409 FLAG_MERGE(password);
412 FLAG_MERGE(preconnect);
416 FLAG_MERGE(fetchall);
421 FLAG_MERGE(fetchlimit);
422 FLAG_MERGE(batchlimit);
426 /* easier to do this than cope with variations in where the library lives */
427 int yywrap(void) {return 1;}
429 /* rcfile_y.y ends here */