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 errors_to_syslog; /* if syslog was set */
33 flag use_invisible; /* if invisible was set */
34 struct query *querylist; /* head of server list (globally visible) */
36 int yydebug; /* in case we didn't generate with -- debug */
38 static struct query current; /* current server record */
39 static int prc_errflag;
40 static struct hostdata *leadentry;
43 static void record_current();
44 static void user_reset();
45 static void reset_server(char *name, int skip);
47 /* using Bison, this arranges that yydebug messages will show actual tokens */
49 #define YYPRINT(fp, type, val) fprintf(fp, " = \"%s\"", yytext)
58 %token DEFAULTS POLL SKIP VIA AKA LOCALDOMAINS PROTOCOL
59 %token AUTHENTICATE TIMEOUT KPOP KERBEROS4
60 %token ENVELOPE QVIRTUAL USERNAME PASSWORD FOLDER SMTPHOST MDA
61 %token PRECONNECT POSTCONNECT LIMIT
62 %token IS HERE THERE TO MAP WILDCARD
63 %token BATCHLIMIT FETCHLIMIT EXPUNGE
64 %token SET LOGFILE DAEMON SYSLOG INVISIBLE INTERFACE MONITOR
67 %token <number> NUMBER
68 %token NO KEEP FLUSH FETCHALL REWRITE FORCECR STRIPCR PASS8BITS DROPSTATUS
69 %token DNS PORT UIDL INTERVAL
77 statement_list : statement
78 | statement_list statement
81 optmap : MAP | /* EMPTY */;
83 /* future global options should also have the form SET <name> optmap <value> */
84 statement : SET LOGFILE optmap STRING {logfile = xstrdup($4);}
85 | SET DAEMON optmap NUMBER {poll_interval = $4;}
86 | SET SYSLOG {errors_to_syslog = TRUE;}
87 | SET INVISIBLE {use_invisible = TRUE;}
90 * The way the next two productions are written depends on the fact that
91 * userspecs cannot be empty. It's a kluge to deal with files that set
92 * up a load of defaults and then have poll statements following with no
93 * user options at all.
95 | define_server serverspecs {record_current();}
96 | define_server serverspecs userspecs
98 /* detect and complain about the most common user error */
99 | define_server serverspecs userspecs serv_option
100 {yyerror("server option after user options");}
103 define_server : POLL STRING {reset_server($2, FALSE);}
104 | SKIP STRING {reset_server($2, TRUE);}
105 | DEFAULTS {reset_server("defaults", FALSE);}
108 serverspecs : /* EMPTY */
109 | serverspecs serv_option
112 alias_list : STRING {save_str(¤t.server.akalist,-1,$1);}
113 | alias_list STRING {save_str(¤t.server.akalist,-1,$2);}
116 domain_list : STRING {save_str(¤t.server.localdomains,-1,$1);}
117 | domain_list STRING {save_str(¤t.server.localdomains,-1,$2);}
120 serv_option : AKA alias_list
121 | VIA STRING {current.server.via = xstrdup($2);}
122 | LOCALDOMAINS domain_list
123 | PROTOCOL PROTO {current.server.protocol = $2;}
125 current.server.protocol = P_POP3;
126 current.server.preauthenticate = A_KERBEROS_V4;
127 current.server.port = KPOP_PORT;
129 | UIDL {current.server.uidl = FLAG_TRUE;}
130 | NO UIDL {current.server.uidl = FLAG_FALSE;}
131 | PORT NUMBER {current.server.port = $2;}
132 | INTERVAL NUMBER {current.server.interval = $2;}
133 | AUTHENTICATE PASSWORD {current.server.preauthenticate = A_PASSWORD;}
134 | AUTHENTICATE KERBEROS4 {current.server.preauthenticate = A_KERBEROS_V4;}
135 | TIMEOUT NUMBER {current.server.timeout = $2;}
137 | ENVELOPE NUMBER STRING
139 current.server.envelope =
141 current.server.envskip = $2;
145 current.server.envelope =
147 current.server.envskip = 0;
150 | QVIRTUAL STRING {current.server.qvirtual = xstrdup($2);}
153 interface_parse($2, ¤t.server);
155 fprintf(stderr, "fetchmail: interface option is only supported under Linux\n");
160 current.server.monitor = xstrdup($2);
162 fprintf(stderr, "fetchmail: monitor option is only supported under Linux\n");
165 | DNS {current.server.dns = FLAG_TRUE;}
166 | NO DNS {current.server.dns = FLAG_FALSE;}
167 | NO ENVELOPE {current.server.envelope = STRING_DISABLED;}
170 userspecs : user1opts {record_current(); user_reset();}
174 explicits : explicitdef {record_current(); user_reset();}
175 | explicits explicitdef {record_current(); user_reset();}
178 explicitdef : userdef user0opts
181 userdef : USERNAME STRING {current.remotename = xstrdup($2);}
182 | USERNAME mapping_list HERE
183 | USERNAME STRING THERE {current.remotename = xstrdup($2);}
186 user0opts : /* EMPTY */
187 | user0opts user_option
190 user1opts : user_option
191 | user1opts user_option
194 localnames : WILDCARD {current.wildcard = TRUE;}
195 | mapping_list {current.wildcard = FALSE;}
196 | mapping_list WILDCARD {current.wildcard = TRUE;}
199 mapping_list : mapping
200 | mapping_list mapping
204 {save_str_pair(¤t.localnames, $1, NULL);}
206 {save_str_pair(¤t.localnames, $1, $3);}
209 folder_list : STRING {save_str(¤t.mailboxes,-1,$1);}
210 | folder_list STRING {save_str(¤t.mailboxes,-1,$2);}
213 smtp_list : STRING {save_str(¤t.smtphunt, TRUE,$1);}
214 | smtp_list STRING {save_str(¤t.smtphunt, TRUE,$2);}
217 user_option : TO localnames HERE
222 | IS STRING THERE {current.remotename = xstrdup($2);}
223 | PASSWORD STRING {current.password = xstrdup($2);}
226 | MDA STRING {current.mda = xstrdup($2);}
227 | PRECONNECT STRING {current.preconnect = xstrdup($2);}
228 | POSTCONNECT STRING {current.postconnect = xstrdup($2);}
230 | KEEP {current.keep = FLAG_TRUE;}
231 | FLUSH {current.flush = FLAG_TRUE;}
232 | FETCHALL {current.fetchall = FLAG_TRUE;}
233 | REWRITE {current.rewrite = FLAG_TRUE;}
234 | FORCECR {current.forcecr = FLAG_TRUE;}
235 | STRIPCR {current.stripcr = FLAG_TRUE;}
236 | PASS8BITS {current.pass8bits = FLAG_TRUE;}
237 | DROPSTATUS {current.dropstatus = FLAG_TRUE;}
239 | NO KEEP {current.keep = FLAG_FALSE;}
240 | NO FLUSH {current.flush = FLAG_FALSE;}
241 | NO FETCHALL {current.fetchall = FLAG_FALSE;}
242 | NO REWRITE {current.rewrite = FLAG_FALSE;}
243 | NO FORCECR {current.forcecr = FLAG_FALSE;}
244 | NO STRIPCR {current.stripcr = FLAG_FALSE;}
245 | NO PASS8BITS {current.pass8bits = FLAG_FALSE;}
246 | NO DROPSTATUS {current.dropstatus = FLAG_FALSE;}
248 | LIMIT NUMBER {current.limit = NUM_VALUE($2);}
249 | FETCHLIMIT NUMBER {current.fetchlimit = NUM_VALUE($2);}
250 | BATCHLIMIT NUMBER {current.batchlimit = NUM_VALUE($2);}
251 | EXPUNGE NUMBER {current.expunge = NUM_VALUE($2);}
255 /* lexer interface */
257 extern int prc_lineno;
261 static struct query *hosttail; /* where to add new elements */
263 void yyerror (const char *s)
264 /* report a syntax error */
266 error_at_line( 0, 0, rcfile, prc_lineno, "%s at %s", s,
267 (yytext && yytext[0]) ? yytext : "end of input");
271 int prc_filecheck(pathname)
272 /* check that a configuration file is secure */
273 const char *pathname; /* pathname for the configuration file */
279 /* special cases useful for debugging purposes */
280 if (strcmp("/dev/null", pathname) == 0)
283 /* the run control file must have the same uid as the REAL uid of this
284 process, it must have permissions no greater than 600, and it must not
285 be a symbolic link. We check these conditions here. */
287 if (lstat(pathname, &statbuf) < 0) {
291 error(0, errno, "lstat: %s", pathname);
296 if ((statbuf.st_mode & S_IFLNK) == S_IFLNK) {
297 fprintf(stderr, "File %s must not be a symbolic link.\n", pathname);
301 if (statbuf.st_mode & ~(S_IFREG | S_IREAD | S_IWRITE)) {
302 fprintf(stderr, "File %s must have no more than -rw------ (0600) permissions.\n",
307 if (statbuf.st_uid != getuid()) {
308 fprintf(stderr, "File %s must be owned by you.\n", pathname);
315 int prc_parse_file (const char *pathname, const flag securecheck)
316 /* digest the configuration into a linked list of host records */
319 querylist = hosttail = (struct query *)NULL;
323 /* Check that the file is secure */
324 if (securecheck && (prc_errflag = prc_filecheck(pathname)) != 0)
330 /* Open the configuration and feed it to the lexer. */
331 if ((yyin = fopen(pathname,"r")) == (FILE *)NULL) {
332 error(0, errno, "open: %s", pathname);
336 yyparse(); /* parse entire file */
346 static void reset_server(char *name, int skip)
347 /* clear the entire global record and initialize it with a new name */
350 memset(¤t,'\0',sizeof(current));
351 current.smtp_socket = -1;
352 current.server.pollname = xstrdup(name);
353 current.server.skip = skip;
357 static void user_reset(void)
358 /* clear the global current record (user parameters) used by the parser */
360 struct hostdata save;
363 * Purpose of this code is to initialize the new server block, but
364 * preserve whatever server name was previously set. Also
365 * preserve server options unless the command-line explicitly
368 save = current.server;
370 memset(¤t, '\0', sizeof(current));
371 current.smtp_socket = -1;
373 current.server = save;
376 struct query *hostalloc(init)
377 /* append a host record to the host list */
378 struct query *init; /* pointer to block containing initial values */
382 /* allocate new node */
383 node = (struct query *) xmalloc(sizeof(struct query));
386 memcpy(node, init, sizeof(struct query));
388 /* append to end of list */
389 if (hosttail != (struct query *) 0)
390 hosttail->next = node; /* list contains at least one element */
392 querylist = node; /* list is empty */
396 node->server.lead_server = leadentry;
399 node->server.lead_server = NULL;
400 leadentry = &node->server;
406 static void record_current(void)
407 /* register current parameters and append to the host list */
409 #define FLAG_FORCE(fld) if (cmd_opts.fld) current.fld = cmd_opts.fld
410 FLAG_FORCE(server.via);
411 FLAG_FORCE(server.protocol);
412 FLAG_FORCE(server.port);
413 FLAG_FORCE(server.interval);
414 FLAG_FORCE(server.preauthenticate);
415 FLAG_FORCE(server.timeout);
416 FLAG_FORCE(server.envelope);
417 FLAG_FORCE(server.envskip);
418 FLAG_FORCE(server.qvirtual);
419 FLAG_FORCE(server.skip);
420 FLAG_FORCE(server.dns);
421 FLAG_FORCE(server.uidl);
424 FLAG_FORCE(server.interface);
425 FLAG_FORCE(server.monitor);
426 FLAG_FORCE(server.interface_pair);
429 FLAG_FORCE(remotename);
430 FLAG_FORCE(password);
431 if (cmd_opts.mailboxes)
432 current.mailboxes = cmd_opts.mailboxes;
433 if (cmd_opts.smtphunt)
434 current.smtphunt = cmd_opts.smtphunt;
436 FLAG_FORCE(preconnect);
437 FLAG_FORCE(postconnect);
441 FLAG_FORCE(fetchall);
445 FLAG_FORCE(pass8bits);
446 FLAG_FORCE(dropstatus);
448 FLAG_FORCE(fetchlimit);
449 FLAG_FORCE(batchlimit);
454 (void) hostalloc(¤t);
459 void optmerge(struct query *h2, struct query *h1)
460 /* merge two options records; empty fields in h2 are filled in from h1 */
462 append_str_list(&h2->server.localdomains, &h1->server.localdomains);
463 append_str_list(&h2->localnames, &h1->localnames);
464 append_str_list(&h2->mailboxes, &h1->mailboxes);
465 append_str_list(&h2->smtphunt, &h1->smtphunt);
467 #define FLAG_MERGE(fld) if (!h2->fld) h2->fld = h1->fld
468 FLAG_MERGE(server.via);
469 FLAG_MERGE(server.protocol);
470 FLAG_MERGE(server.port);
471 FLAG_MERGE(server.interval);
472 FLAG_MERGE(server.preauthenticate);
473 FLAG_MERGE(server.timeout);
474 FLAG_MERGE(server.envelope);
475 FLAG_MERGE(server.envskip);
476 FLAG_MERGE(server.qvirtual);
477 FLAG_MERGE(server.skip);
478 FLAG_MERGE(server.dns);
479 FLAG_MERGE(server.uidl);
482 FLAG_MERGE(server.interface);
483 FLAG_MERGE(server.monitor);
484 FLAG_MERGE(server.interface_pair);
487 FLAG_MERGE(remotename);
488 FLAG_MERGE(password);
490 FLAG_MERGE(preconnect);
494 FLAG_MERGE(fetchall);
498 FLAG_MERGE(pass8bits);
499 FLAG_MERGE(dropstatus);
501 FLAG_MERGE(fetchlimit);
502 FLAG_MERGE(batchlimit);
507 /* easier to do this than cope with variations in where the library lives */
508 int yywrap(void) {return 1;}
510 /* rcfile_y.y ends here */