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 /* parser reads these */
26 char *rcfile; /* path name of rc file */
27 struct query cmd_opts; /* where to put command-line info */
29 /* parser sets these */
30 int poll_interval; /* poll interval in seconds */
31 char *logfile; /* log file for daemon mode */
32 flag use_syslog; /* if syslog was set */
33 struct query *querylist; /* head of server list (globally visible) */
35 int yydebug; /* in case we didn't generate with -- debug */
37 static struct query current; /* current server record */
38 static int prc_errflag;
39 static struct hostdata *leadentry;
42 static void record_current();
43 static void user_reset();
44 static int reset_server(char *name, int skip);
46 /* using Bison, this arranges that yydebug messages will show actual tokens */
48 #define YYPRINT(fp, type, val) fprintf(fp, " = \"%s\"", yytext)
57 %token DEFAULTS POLL SKIP VIA AKA LOCALDOMAINS PROTOCOL
58 %token AUTHENTICATE TIMEOUT KPOP KERBEROS4
59 %token ENVELOPE USERNAME PASSWORD FOLDER SMTPHOST MDA
60 %token PRECONNECT POSTCONNECT LIMIT
61 %token IS HERE THERE TO MAP WILDCARD
62 %token SET BATCHLIMIT FETCHLIMIT LOGFILE DAEMON SYSLOG INTERFACE MONITOR
65 %token <number> NUMBER
66 %token NO KEEP FLUSH FETCHALL REWRITE FORCECR STRIPCR PASS8BITS DROPSTATUS
67 %token DNS PORT UIDL INTERVAL
75 statement_list : statement
76 | statement_list statement
79 /* future global options should also have the form SET <name> <value> */
80 statement : SET LOGFILE MAP STRING {logfile = xstrdup($4);}
81 | SET DAEMON NUMBER {poll_interval = $3;}
82 | SET SYSLOG {use_syslog = TRUE;}
85 * The way the next two productions are written depends on the fact that
86 * userspecs cannot be empty. It's a kluge to deal with files that set
87 * up a load of defaults and then have poll statements following with no
88 * user options at all.
90 | define_server serverspecs {record_current();}
91 | define_server serverspecs userspecs
94 define_server : POLL STRING {
95 if (!reset_server($2, FALSE))
97 yyerror("duplicate entry name not allowed");
102 if (!reset_server($2, TRUE))
104 yyerror("duplicate entry name not allowed");
109 if (!reset_server("defaults", FALSE))
111 yyerror("can't have two default entries");
117 serverspecs : /* EMPTY */
118 | serverspecs serv_option
121 alias_list : STRING {save_str(¤t.server.akalist,-1,$1);}
122 | alias_list STRING {save_str(¤t.server.akalist,-1,$2);}
125 domain_list : STRING {save_str(¤t.server.localdomains,-1,$1);}
126 | domain_list STRING {save_str(¤t.server.localdomains,-1,$2);}
129 serv_option : AKA alias_list
130 | VIA STRING {current.server.via = xstrdup($2);}
131 | LOCALDOMAINS domain_list
132 | PROTOCOL PROTO {current.server.protocol = $2;}
134 current.server.protocol = P_POP3;
135 current.server.preauthenticate = A_KERBEROS_V4;
136 current.server.port = KPOP_PORT;
138 | UIDL {current.server.uidl = FLAG_TRUE;}
139 | NO UIDL {current.server.uidl = FLAG_FALSE;}
140 | PORT NUMBER {current.server.port = $2;}
141 | INTERVAL NUMBER {current.server.interval = $2;}
142 | AUTHENTICATE PASSWORD {current.server.preauthenticate = A_PASSWORD;}
143 | AUTHENTICATE KERBEROS4 {current.server.preauthenticate = A_KERBEROS_V4;}
144 | TIMEOUT NUMBER {current.server.timeout = $2;}
145 | ENVELOPE STRING {current.server.envelope = xstrdup($2);}
148 interface_parse($2, ¤t.server);
150 fprintf(stderr, "fetchmail: interface option is only supported under Linux\n");
155 current.server.monitor = xstrdup($2);
157 fprintf(stderr, "fetchmail: monitor option is only supported under Linux\n");
160 | DNS {current.server.dns = FLAG_TRUE;}
161 | NO DNS {current.server.dns = FLAG_FALSE;}
162 | NO ENVELOPE {current.server.envelope = STRING_DISABLED;}
165 userspecs : user1opts {record_current(); user_reset();}
169 explicits : explicitdef {record_current(); user_reset();}
170 | explicits explicitdef {record_current(); user_reset();}
173 explicitdef : userdef user0opts
176 userdef : USERNAME STRING {current.remotename = xstrdup($2);}
177 | USERNAME mapping_list HERE
178 | USERNAME STRING THERE {current.remotename = xstrdup($2);}
181 user0opts : /* EMPTY */
182 | user0opts user_option
185 user1opts : user_option
186 | user1opts user_option
189 localnames : WILDCARD {current.wildcard = TRUE;}
190 | mapping_list {current.wildcard = FALSE;}
191 | mapping_list WILDCARD {current.wildcard = TRUE;}
194 mapping_list : mapping
195 | mapping_list mapping
199 {save_str_pair(¤t.localnames, $1, NULL);}
201 {save_str_pair(¤t.localnames, $1, $3);}
204 folder_list : STRING {save_str(¤t.mailboxes,-1,$1);}
205 | folder_list STRING {save_str(¤t.mailboxes,-1,$2);}
208 smtp_list : STRING {save_str(¤t.smtphunt, -1, $1);}
209 | smtp_list STRING {save_str(¤t.smtphunt, -1, $2);}
212 user_option : TO localnames HERE
217 | IS STRING THERE {current.remotename = xstrdup($2);}
218 | PASSWORD STRING {current.password = xstrdup($2);}
221 | MDA STRING {current.mda = xstrdup($2);}
222 | PRECONNECT STRING {current.preconnect = xstrdup($2);}
223 | POSTCONNECT STRING {current.postconnect = xstrdup($2);}
225 | KEEP {current.keep = FLAG_TRUE;}
226 | FLUSH {current.flush = FLAG_TRUE;}
227 | FETCHALL {current.fetchall = FLAG_TRUE;}
228 | REWRITE {current.rewrite = FLAG_TRUE;}
229 | FORCECR {current.forcecr = FLAG_TRUE;}
230 | STRIPCR {current.stripcr = FLAG_TRUE;}
231 | PASS8BITS {current.pass8bits = FLAG_TRUE;}
232 | DROPSTATUS {current.dropstatus = FLAG_TRUE;}
234 | NO KEEP {current.keep = FLAG_FALSE;}
235 | NO FLUSH {current.flush = FLAG_FALSE;}
236 | NO FETCHALL {current.fetchall = FLAG_FALSE;}
237 | NO REWRITE {current.rewrite = FLAG_FALSE;}
238 | NO FORCECR {current.forcecr = FLAG_FALSE;}
239 | NO STRIPCR {current.stripcr = FLAG_FALSE;}
240 | NO PASS8BITS {current.pass8bits = FLAG_FALSE;}
241 | NO DROPSTATUS {current.dropstatus = FLAG_FALSE;}
243 | LIMIT NUMBER {current.limit = $2;}
244 | FETCHLIMIT NUMBER {current.fetchlimit = $2;}
245 | BATCHLIMIT NUMBER {current.batchlimit = $2;}
249 /* lexer interface */
251 extern int prc_lineno;
255 static struct query *hosttail; /* where to add new elements */
257 void yyerror (const char *s)
258 /* report a syntax error */
260 error_at_line( 0, 0, rcfile, prc_lineno, "%s at %s", s,
261 (yytext && yytext[0]) ? yytext : "end of input");
265 int prc_filecheck(pathname)
266 /* check that a configuration file is secure */
267 const char *pathname; /* pathname for the configuration file */
273 /* special cases useful for debugging purposes */
274 if (strcmp("/dev/null", pathname) == 0)
277 /* the run control file must have the same uid as the REAL uid of this
278 process, it must have permissions no greater than 600, and it must not
279 be a symbolic link. We check these conditions here. */
281 if (lstat(pathname, &statbuf) < 0) {
285 error(0, errno, "lstat: %s", pathname);
290 if ((statbuf.st_mode & S_IFLNK) == S_IFLNK) {
291 fprintf(stderr, "File %s must not be a symbolic link.\n", pathname);
295 if (statbuf.st_mode & ~(S_IFREG | S_IREAD | S_IWRITE)) {
296 fprintf(stderr, "File %s must have no more than -rw------ (0600) permissions.\n",
301 if (statbuf.st_uid != getuid()) {
302 fprintf(stderr, "File %s must be owned by you.\n", pathname);
309 int prc_parse_file (pathname, securecheck)
310 /* digest the configuration into a linked list of host records */
311 const char *pathname; /* pathname for the configuration file */
312 const flag securecheck; /* check for a secure rc file? */
315 querylist = hosttail = (struct query *)NULL;
319 /* Check that the file is secure */
320 if (securecheck && (prc_errflag = prc_filecheck(pathname)) != 0)
326 /* Open the configuration and feed it to the lexer. */
327 if ((yyin = fopen(pathname,"r")) == (FILE *)NULL) {
328 error(0, errno, "open: %s", pathname);
332 yyparse(); /* parse entire file */
342 static int reset_server(char *name, int skip)
343 /* clear the entire global record and initialize it with a new name */
346 memset(¤t,'\0',sizeof(current));
347 current.smtp_socket = -1;
348 current.server.pollname = xstrdup(name);
349 current.server.skip = skip;
354 static void user_reset(void)
355 /* clear the global current record (user parameters) used by the parser */
357 struct hostdata save;
360 * Purpose of this code is to initialize the new server block, but
361 * preserve whatever server name was previously set. Also
362 * preserve server options unless the command-line explicitly
365 save = current.server;
367 memset(¤t, '\0', sizeof(current));
368 current.smtp_socket = -1;
370 current.server = save;
373 struct query *hostalloc(init)
374 /* append a host record to the host list */
375 struct query *init; /* pointer to block containing initial values */
379 /* allocate new node */
380 node = (struct query *) xmalloc(sizeof(struct query));
383 memcpy(node, init, sizeof(struct query));
385 /* append to end of list */
386 if (hosttail != (struct query *) 0)
387 hosttail->next = node; /* list contains at least one element */
389 querylist = node; /* list is empty */
393 node->server.lead_server = leadentry;
396 node->server.lead_server = NULL;
397 leadentry = &node->server;
403 static void record_current(void)
404 /* register current parameters and append to the host list */
406 #define FLAG_FORCE(fld) if (cmd_opts.fld) current.fld = cmd_opts.fld
407 FLAG_FORCE(server.via);
408 FLAG_FORCE(server.protocol);
409 FLAG_FORCE(server.port);
410 FLAG_FORCE(server.interval);
411 FLAG_FORCE(server.preauthenticate);
412 FLAG_FORCE(server.timeout);
413 FLAG_FORCE(server.envelope);
414 FLAG_FORCE(server.skip);
415 FLAG_FORCE(server.dns);
416 FLAG_FORCE(server.uidl);
419 FLAG_FORCE(server.interface);
420 FLAG_FORCE(server.monitor);
421 FLAG_FORCE(server.interface_pair);
424 FLAG_FORCE(remotename);
425 FLAG_FORCE(password);
426 if (cmd_opts.mailboxes)
427 save_str(¤t.mailboxes, -1, cmd_opts.mailboxes->id);
428 if (cmd_opts.smtphunt)
429 save_str(¤t.smtphunt, -1, cmd_opts.smtphunt->id);
431 FLAG_FORCE(preconnect);
432 FLAG_FORCE(postconnect);
436 FLAG_FORCE(fetchall);
440 FLAG_FORCE(pass8bits);
442 FLAG_FORCE(fetchlimit);
443 FLAG_FORCE(batchlimit);
447 (void) hostalloc(¤t);
452 void optmerge(struct query *h2, struct query *h1)
453 /* merge two options records; empty fields in h2 are filled in from h1 */
455 append_str_list(&h2->server.localdomains, &h1->server.localdomains);
456 append_str_list(&h2->localnames, &h1->localnames);
457 append_str_list(&h2->mailboxes, &h1->mailboxes);
458 append_str_list(&h2->smtphunt, &h1->smtphunt);
460 #define FLAG_MERGE(fld) if (!h2->fld) h2->fld = h1->fld
461 FLAG_MERGE(server.via);
462 FLAG_MERGE(server.protocol);
463 FLAG_MERGE(server.port);
464 FLAG_MERGE(server.interval);
465 FLAG_MERGE(server.preauthenticate);
466 FLAG_MERGE(server.timeout);
467 FLAG_MERGE(server.envelope);
468 FLAG_MERGE(server.skip);
469 FLAG_MERGE(server.dns);
470 FLAG_MERGE(server.uidl);
473 FLAG_MERGE(server.interface);
474 FLAG_MERGE(server.monitor);
475 FLAG_MERGE(server.interface_pair);
478 FLAG_MERGE(remotename);
479 FLAG_MERGE(password);
481 FLAG_MERGE(preconnect);
485 FLAG_MERGE(fetchall);
489 FLAG_MERGE(pass8bits);
491 FLAG_MERGE(fetchlimit);
492 FLAG_MERGE(batchlimit);
496 /* easier to do this than cope with variations in where the library lives */
497 int yywrap(void) {return 1;}
499 /* rcfile_y.y ends here */