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>
12 #if defined(HAVE_SYS_WAIT_H)
17 #if defined(STDC_HEADERS)
20 #if defined(HAVE_UNISTD_H)
25 #include "fetchmail.h"
27 /* parser reads these */
28 char *rcfile; /* path name of rc file */
29 struct query cmd_opts; /* where to put command-line info */
31 /* parser sets these */
32 int poll_interval; /* poll interval in seconds */
33 char *logfile; /* log file for daemon mode */
34 flag errors_to_syslog; /* if syslog was set */
35 flag use_invisible; /* if invisible was set */
36 struct query *querylist; /* head of server list (globally visible) */
38 int yydebug; /* in case we didn't generate with -- debug */
40 static struct query current; /* current server record */
41 static int prc_errflag;
42 static struct hostdata *leadentry;
45 static void record_current();
46 static void user_reset();
47 static void reset_server(char *name, int skip);
49 /* using Bison, this arranges that yydebug messages will show actual tokens */
51 #define YYPRINT(fp, type, val) fprintf(fp, " = \"%s\"", yytext)
60 %token DEFAULTS POLL SKIP VIA AKA LOCALDOMAINS PROTOCOL
61 %token AUTHENTICATE TIMEOUT KPOP KERBEROS4
62 %token ENVELOPE QVIRTUAL USERNAME PASSWORD FOLDER SMTPHOST MDA SMTPADDRESS
63 %token PRECONNECT POSTCONNECT LIMIT
64 %token IS HERE THERE TO MAP WILDCARD
65 %token BATCHLIMIT FETCHLIMIT EXPUNGE
66 %token SET LOGFILE DAEMON SYSLOG INVISIBLE INTERFACE MONITOR
69 %token <number> NUMBER
70 %token NO KEEP FLUSH FETCHALL REWRITE FORCECR STRIPCR PASS8BITS DROPSTATUS
71 %token DNS PORT UIDL INTERVAL
79 statement_list : statement
80 | statement_list statement
83 optmap : MAP | /* EMPTY */;
85 /* future global options should also have the form SET <name> optmap <value> */
86 statement : SET LOGFILE optmap STRING {logfile = xstrdup($4);}
87 | SET DAEMON optmap NUMBER {poll_interval = $4;}
88 | SET SYSLOG {errors_to_syslog = TRUE;}
89 | SET INVISIBLE {use_invisible = TRUE;}
92 * The way the next two productions are written depends on the fact that
93 * userspecs cannot be empty. It's a kluge to deal with files that set
94 * up a load of defaults and then have poll statements following with no
95 * user options at all.
97 | define_server serverspecs {record_current();}
98 | define_server serverspecs userspecs
100 /* detect and complain about the most common user error */
101 | define_server serverspecs userspecs serv_option
102 {yyerror("server option after user options");}
105 define_server : POLL STRING {reset_server($2, FALSE);}
106 | SKIP STRING {reset_server($2, TRUE);}
107 | DEFAULTS {reset_server("defaults", FALSE);}
110 serverspecs : /* EMPTY */
111 | serverspecs serv_option
114 alias_list : STRING {save_str(¤t.server.akalist,-1,$1);}
115 | alias_list STRING {save_str(¤t.server.akalist,-1,$2);}
118 domain_list : STRING {save_str(¤t.server.localdomains,-1,$1);}
119 | domain_list STRING {save_str(¤t.server.localdomains,-1,$2);}
122 serv_option : AKA alias_list
123 | VIA STRING {current.server.via = xstrdup($2);}
124 | LOCALDOMAINS domain_list
125 | PROTOCOL PROTO {current.server.protocol = $2;}
127 current.server.protocol = P_POP3;
128 current.server.preauthenticate = A_KERBEROS_V4;
129 current.server.port = KPOP_PORT;
131 | UIDL {current.server.uidl = FLAG_TRUE;}
132 | NO UIDL {current.server.uidl = FLAG_FALSE;}
133 | PORT NUMBER {current.server.port = $2;}
134 | INTERVAL NUMBER {current.server.interval = $2;}
135 | AUTHENTICATE PASSWORD {current.server.preauthenticate = A_PASSWORD;}
136 | AUTHENTICATE KERBEROS4 {current.server.preauthenticate = A_KERBEROS_V4;}
137 | TIMEOUT NUMBER {current.server.timeout = $2;}
139 | ENVELOPE NUMBER STRING
141 current.server.envelope =
143 current.server.envskip = $2;
147 current.server.envelope =
149 current.server.envskip = 0;
152 | QVIRTUAL STRING {current.server.qvirtual = xstrdup($2);}
155 interface_parse($2, ¤t.server);
157 fprintf(stderr, "fetchmail: interface option is only supported under Linux\n");
162 current.server.monitor = xstrdup($2);
164 fprintf(stderr, "fetchmail: monitor option is only supported under Linux\n");
167 | DNS {current.server.dns = FLAG_TRUE;}
168 | NO DNS {current.server.dns = FLAG_FALSE;}
169 | NO ENVELOPE {current.server.envelope = STRING_DISABLED;}
172 userspecs : user1opts {record_current(); user_reset();}
176 explicits : explicitdef {record_current(); user_reset();}
177 | explicits explicitdef {record_current(); user_reset();}
180 explicitdef : userdef user0opts
183 userdef : USERNAME STRING {current.remotename = xstrdup($2);}
184 | USERNAME mapping_list HERE
185 | USERNAME STRING THERE {current.remotename = xstrdup($2);}
188 user0opts : /* EMPTY */
189 | user0opts user_option
192 user1opts : user_option
193 | user1opts user_option
196 localnames : WILDCARD {current.wildcard = TRUE;}
197 | mapping_list {current.wildcard = FALSE;}
198 | mapping_list WILDCARD {current.wildcard = TRUE;}
201 mapping_list : mapping
202 | mapping_list mapping
206 {save_str_pair(¤t.localnames, $1, NULL);}
208 {save_str_pair(¤t.localnames, $1, $3);}
211 folder_list : STRING {save_str(¤t.mailboxes,-1,$1);}
212 | folder_list STRING {save_str(¤t.mailboxes,-1,$2);}
215 smtp_list : STRING {save_str(¤t.smtphunt, TRUE,$1);}
216 | smtp_list STRING {save_str(¤t.smtphunt, TRUE,$2);}
219 user_option : TO localnames HERE
224 | IS STRING THERE {current.remotename = xstrdup($2);}
225 | PASSWORD STRING {current.password = xstrdup($2);}
228 | SMTPADDRESS STRING {current.smtpaddress = xstrdup($2);}
229 | MDA STRING {current.mda = xstrdup($2);}
230 | PRECONNECT STRING {current.preconnect = xstrdup($2);}
231 | POSTCONNECT STRING {current.postconnect = xstrdup($2);}
233 | KEEP {current.keep = FLAG_TRUE;}
234 | FLUSH {current.flush = FLAG_TRUE;}
235 | FETCHALL {current.fetchall = FLAG_TRUE;}
236 | REWRITE {current.rewrite = FLAG_TRUE;}
237 | FORCECR {current.forcecr = FLAG_TRUE;}
238 | STRIPCR {current.stripcr = FLAG_TRUE;}
239 | PASS8BITS {current.pass8bits = FLAG_TRUE;}
240 | DROPSTATUS {current.dropstatus = FLAG_TRUE;}
242 | NO KEEP {current.keep = FLAG_FALSE;}
243 | NO FLUSH {current.flush = FLAG_FALSE;}
244 | NO FETCHALL {current.fetchall = FLAG_FALSE;}
245 | NO REWRITE {current.rewrite = FLAG_FALSE;}
246 | NO FORCECR {current.forcecr = FLAG_FALSE;}
247 | NO STRIPCR {current.stripcr = FLAG_FALSE;}
248 | NO PASS8BITS {current.pass8bits = FLAG_FALSE;}
249 | NO DROPSTATUS {current.dropstatus = FLAG_FALSE;}
251 | LIMIT NUMBER {current.limit = NUM_VALUE($2);}
252 | FETCHLIMIT NUMBER {current.fetchlimit = NUM_VALUE($2);}
253 | BATCHLIMIT NUMBER {current.batchlimit = NUM_VALUE($2);}
254 | EXPUNGE NUMBER {current.expunge = NUM_VALUE($2);}
258 /* lexer interface */
260 extern int prc_lineno;
264 static struct query *hosttail; /* where to add new elements */
266 void yyerror (const char *s)
267 /* report a syntax error */
269 error_at_line( 0, 0, rcfile, prc_lineno, "%s at %s", s,
270 (yytext && yytext[0]) ? yytext : "end of input");
274 int prc_filecheck(pathname)
275 /* check that a configuration file is secure */
276 const char *pathname; /* pathname for the configuration file */
282 /* special cases useful for debugging purposes */
283 if (strcmp("/dev/null", pathname) == 0)
286 /* the run control file must have the same uid as the REAL uid of this
287 process, it must have permissions no greater than 600, and it must not
288 be a symbolic link. We check these conditions here. */
290 if (lstat(pathname, &statbuf) < 0) {
294 error(0, errno, "lstat: %s", pathname);
299 if ((statbuf.st_mode & S_IFLNK) == S_IFLNK) {
300 fprintf(stderr, "File %s must not be a symbolic link.\n", pathname);
304 if (statbuf.st_mode & ~(S_IFREG | S_IREAD | S_IWRITE)) {
305 fprintf(stderr, "File %s must have no more than -rw------ (0600) permissions.\n",
310 if (statbuf.st_uid != getuid()) {
311 fprintf(stderr, "File %s must be owned by you.\n", pathname);
318 int prc_parse_file (const char *pathname, const flag securecheck)
319 /* digest the configuration into a linked list of host records */
322 querylist = hosttail = (struct query *)NULL;
326 /* Check that the file is secure */
327 if (securecheck && (prc_errflag = prc_filecheck(pathname)) != 0)
333 /* Open the configuration and feed it to the lexer. */
334 if ((yyin = fopen(pathname,"r")) == (FILE *)NULL) {
335 error(0, errno, "open: %s", pathname);
339 yyparse(); /* parse entire file */
349 static void reset_server(char *name, int skip)
350 /* clear the entire global record and initialize it with a new name */
353 memset(¤t,'\0',sizeof(current));
354 current.smtp_socket = -1;
355 current.server.pollname = xstrdup(name);
356 current.server.skip = skip;
360 static void user_reset(void)
361 /* clear the global current record (user parameters) used by the parser */
363 struct hostdata save;
366 * Purpose of this code is to initialize the new server block, but
367 * preserve whatever server name was previously set. Also
368 * preserve server options unless the command-line explicitly
371 save = current.server;
373 memset(¤t, '\0', sizeof(current));
374 current.smtp_socket = -1;
376 current.server = save;
379 struct query *hostalloc(init)
380 /* append a host record to the host list */
381 struct query *init; /* pointer to block containing initial values */
385 /* allocate new node */
386 node = (struct query *) xmalloc(sizeof(struct query));
389 memcpy(node, init, sizeof(struct query));
391 /* append to end of list */
392 if (hosttail != (struct query *) 0)
393 hosttail->next = node; /* list contains at least one element */
395 querylist = node; /* list is empty */
399 node->server.lead_server = leadentry;
402 node->server.lead_server = NULL;
403 leadentry = &node->server;
409 static void record_current(void)
410 /* register current parameters and append to the host list */
412 #define FLAG_FORCE(fld) if (cmd_opts.fld) current.fld = cmd_opts.fld
413 FLAG_FORCE(server.via);
414 FLAG_FORCE(server.protocol);
415 FLAG_FORCE(server.port);
416 FLAG_FORCE(server.interval);
417 FLAG_FORCE(server.preauthenticate);
418 FLAG_FORCE(server.timeout);
419 FLAG_FORCE(server.envelope);
420 FLAG_FORCE(server.envskip);
421 FLAG_FORCE(server.qvirtual);
422 FLAG_FORCE(server.skip);
423 FLAG_FORCE(server.dns);
424 FLAG_FORCE(server.uidl);
427 FLAG_FORCE(server.interface);
428 FLAG_FORCE(server.monitor);
429 FLAG_FORCE(server.interface_pair);
432 FLAG_FORCE(remotename);
433 FLAG_FORCE(password);
434 if (cmd_opts.mailboxes)
435 current.mailboxes = cmd_opts.mailboxes;
436 if (cmd_opts.smtphunt)
437 current.smtphunt = cmd_opts.smtphunt;
439 FLAG_FORCE(smtpaddress);
440 FLAG_FORCE(preconnect);
441 FLAG_FORCE(postconnect);
445 FLAG_FORCE(fetchall);
449 FLAG_FORCE(pass8bits);
450 FLAG_FORCE(dropstatus);
452 FLAG_FORCE(fetchlimit);
453 FLAG_FORCE(batchlimit);
458 (void) hostalloc(¤t);
463 void optmerge(struct query *h2, struct query *h1)
464 /* merge two options records; empty fields in h2 are filled in from h1 */
466 append_str_list(&h2->server.localdomains, &h1->server.localdomains);
467 append_str_list(&h2->localnames, &h1->localnames);
468 append_str_list(&h2->mailboxes, &h1->mailboxes);
469 append_str_list(&h2->smtphunt, &h1->smtphunt);
471 #define FLAG_MERGE(fld) if (!h2->fld) h2->fld = h1->fld
472 FLAG_MERGE(server.via);
473 FLAG_MERGE(server.protocol);
474 FLAG_MERGE(server.port);
475 FLAG_MERGE(server.interval);
476 FLAG_MERGE(server.preauthenticate);
477 FLAG_MERGE(server.timeout);
478 FLAG_MERGE(server.envelope);
479 FLAG_MERGE(server.envskip);
480 FLAG_MERGE(server.qvirtual);
481 FLAG_MERGE(server.skip);
482 FLAG_MERGE(server.dns);
483 FLAG_MERGE(server.uidl);
486 FLAG_MERGE(server.interface);
487 FLAG_MERGE(server.monitor);
488 FLAG_MERGE(server.interface_pair);
491 FLAG_MERGE(remotename);
492 FLAG_MERGE(password);
494 FLAG_MERGE(smtpaddress);
495 FLAG_MERGE(preconnect);
499 FLAG_MERGE(fetchall);
503 FLAG_MERGE(pass8bits);
504 FLAG_MERGE(dropstatus);
506 FLAG_MERGE(fetchlimit);
507 FLAG_MERGE(batchlimit);
512 /* easier to do this than cope with variations in where the library lives */
513 int yywrap(void) {return 1;}
515 /* rcfile_y.y ends here */