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 void 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
93 /* detect and complain about the most common user error */
94 | define_server serverspecs userspecs serv_option
95 {yyerror("server option after user options");}
98 define_server : POLL STRING {reset_server($2, FALSE);}
99 | SKIP STRING {reset_server($2, TRUE);}
100 | DEFAULTS {reset_server("defaults", FALSE);}
103 serverspecs : /* EMPTY */
104 | serverspecs serv_option
107 alias_list : STRING {save_str(¤t.server.akalist,-1,$1);}
108 | alias_list STRING {save_str(¤t.server.akalist,-1,$2);}
111 domain_list : STRING {save_str(¤t.server.localdomains,-1,$1);}
112 | domain_list STRING {save_str(¤t.server.localdomains,-1,$2);}
115 serv_option : AKA alias_list
116 | VIA STRING {current.server.via = xstrdup($2);}
117 | LOCALDOMAINS domain_list
118 | PROTOCOL PROTO {current.server.protocol = $2;}
120 current.server.protocol = P_POP3;
121 current.server.preauthenticate = A_KERBEROS_V4;
122 current.server.port = KPOP_PORT;
124 | UIDL {current.server.uidl = FLAG_TRUE;}
125 | NO UIDL {current.server.uidl = FLAG_FALSE;}
126 | PORT NUMBER {current.server.port = $2;}
127 | INTERVAL NUMBER {current.server.interval = $2;}
128 | AUTHENTICATE PASSWORD {current.server.preauthenticate = A_PASSWORD;}
129 | AUTHENTICATE KERBEROS4 {current.server.preauthenticate = A_KERBEROS_V4;}
130 | TIMEOUT NUMBER {current.server.timeout = $2;}
131 | ENVELOPE STRING {current.server.envelope = xstrdup($2);}
134 interface_parse($2, ¤t.server);
136 fprintf(stderr, "fetchmail: interface option is only supported under Linux\n");
141 current.server.monitor = xstrdup($2);
143 fprintf(stderr, "fetchmail: monitor option is only supported under Linux\n");
146 | DNS {current.server.dns = FLAG_TRUE;}
147 | NO DNS {current.server.dns = FLAG_FALSE;}
148 | NO ENVELOPE {current.server.envelope = STRING_DISABLED;}
151 userspecs : user1opts {record_current(); user_reset();}
155 explicits : explicitdef {record_current(); user_reset();}
156 | explicits explicitdef {record_current(); user_reset();}
159 explicitdef : userdef user0opts
162 userdef : USERNAME STRING {current.remotename = xstrdup($2);}
163 | USERNAME mapping_list HERE
164 | USERNAME STRING THERE {current.remotename = xstrdup($2);}
167 user0opts : /* EMPTY */
168 | user0opts user_option
171 user1opts : user_option
172 | user1opts user_option
175 localnames : WILDCARD {current.wildcard = TRUE;}
176 | mapping_list {current.wildcard = FALSE;}
177 | mapping_list WILDCARD {current.wildcard = TRUE;}
180 mapping_list : mapping
181 | mapping_list mapping
185 {save_str_pair(¤t.localnames, $1, NULL);}
187 {save_str_pair(¤t.localnames, $1, $3);}
190 folder_list : STRING {save_str(¤t.mailboxes,-1,$1);}
191 | folder_list STRING {save_str(¤t.mailboxes,-1,$2);}
194 smtp_list : STRING {save_str(¤t.smtphunt, TRUE,$1);}
195 | smtp_list STRING {save_str(¤t.smtphunt, TRUE,$2);}
198 user_option : TO localnames HERE
203 | IS STRING THERE {current.remotename = xstrdup($2);}
204 | PASSWORD STRING {current.password = xstrdup($2);}
207 | MDA STRING {current.mda = xstrdup($2);}
208 | PRECONNECT STRING {current.preconnect = xstrdup($2);}
209 | POSTCONNECT STRING {current.postconnect = xstrdup($2);}
211 | KEEP {current.keep = FLAG_TRUE;}
212 | FLUSH {current.flush = FLAG_TRUE;}
213 | FETCHALL {current.fetchall = FLAG_TRUE;}
214 | REWRITE {current.rewrite = FLAG_TRUE;}
215 | FORCECR {current.forcecr = FLAG_TRUE;}
216 | STRIPCR {current.stripcr = FLAG_TRUE;}
217 | PASS8BITS {current.pass8bits = FLAG_TRUE;}
218 | DROPSTATUS {current.dropstatus = FLAG_TRUE;}
220 | NO KEEP {current.keep = FLAG_FALSE;}
221 | NO FLUSH {current.flush = FLAG_FALSE;}
222 | NO FETCHALL {current.fetchall = FLAG_FALSE;}
223 | NO REWRITE {current.rewrite = FLAG_FALSE;}
224 | NO FORCECR {current.forcecr = FLAG_FALSE;}
225 | NO STRIPCR {current.stripcr = FLAG_FALSE;}
226 | NO PASS8BITS {current.pass8bits = FLAG_FALSE;}
227 | NO DROPSTATUS {current.dropstatus = FLAG_FALSE;}
229 | LIMIT NUMBER {current.limit = $2;}
230 | FETCHLIMIT NUMBER {current.fetchlimit = $2;}
231 | BATCHLIMIT NUMBER {current.batchlimit = $2;}
235 /* lexer interface */
237 extern int prc_lineno;
241 static struct query *hosttail; /* where to add new elements */
243 void yyerror (const char *s)
244 /* report a syntax error */
246 error_at_line( 0, 0, rcfile, prc_lineno, "%s at %s", s,
247 (yytext && yytext[0]) ? yytext : "end of input");
251 int prc_filecheck(pathname)
252 /* check that a configuration file is secure */
253 const char *pathname; /* pathname for the configuration file */
259 /* special cases useful for debugging purposes */
260 if (strcmp("/dev/null", pathname) == 0)
263 /* the run control file must have the same uid as the REAL uid of this
264 process, it must have permissions no greater than 600, and it must not
265 be a symbolic link. We check these conditions here. */
267 if (lstat(pathname, &statbuf) < 0) {
271 error(0, errno, "lstat: %s", pathname);
276 if ((statbuf.st_mode & S_IFLNK) == S_IFLNK) {
277 fprintf(stderr, "File %s must not be a symbolic link.\n", pathname);
281 if (statbuf.st_mode & ~(S_IFREG | S_IREAD | S_IWRITE)) {
282 fprintf(stderr, "File %s must have no more than -rw------ (0600) permissions.\n",
287 if (statbuf.st_uid != getuid()) {
288 fprintf(stderr, "File %s must be owned by you.\n", pathname);
295 int prc_parse_file (const char *pathname, const flag securecheck)
296 /* digest the configuration into a linked list of host records */
299 querylist = hosttail = (struct query *)NULL;
303 /* Check that the file is secure */
304 if (securecheck && (prc_errflag = prc_filecheck(pathname)) != 0)
310 /* Open the configuration and feed it to the lexer. */
311 if ((yyin = fopen(pathname,"r")) == (FILE *)NULL) {
312 error(0, errno, "open: %s", pathname);
316 yyparse(); /* parse entire file */
326 static void reset_server(char *name, int skip)
327 /* clear the entire global record and initialize it with a new name */
330 memset(¤t,'\0',sizeof(current));
331 current.smtp_socket = -1;
332 current.server.pollname = xstrdup(name);
333 current.server.skip = skip;
337 static void user_reset(void)
338 /* clear the global current record (user parameters) used by the parser */
340 struct hostdata save;
343 * Purpose of this code is to initialize the new server block, but
344 * preserve whatever server name was previously set. Also
345 * preserve server options unless the command-line explicitly
348 save = current.server;
350 memset(¤t, '\0', sizeof(current));
351 current.smtp_socket = -1;
353 current.server = save;
356 struct query *hostalloc(init)
357 /* append a host record to the host list */
358 struct query *init; /* pointer to block containing initial values */
362 /* allocate new node */
363 node = (struct query *) xmalloc(sizeof(struct query));
366 memcpy(node, init, sizeof(struct query));
368 /* append to end of list */
369 if (hosttail != (struct query *) 0)
370 hosttail->next = node; /* list contains at least one element */
372 querylist = node; /* list is empty */
376 node->server.lead_server = leadentry;
379 node->server.lead_server = NULL;
380 leadentry = &node->server;
386 static void record_current(void)
387 /* register current parameters and append to the host list */
389 #define FLAG_FORCE(fld) if (cmd_opts.fld) current.fld = cmd_opts.fld
390 FLAG_FORCE(server.via);
391 FLAG_FORCE(server.protocol);
392 FLAG_FORCE(server.port);
393 FLAG_FORCE(server.interval);
394 FLAG_FORCE(server.preauthenticate);
395 FLAG_FORCE(server.timeout);
396 FLAG_FORCE(server.envelope);
397 FLAG_FORCE(server.skip);
398 FLAG_FORCE(server.dns);
399 FLAG_FORCE(server.uidl);
402 FLAG_FORCE(server.interface);
403 FLAG_FORCE(server.monitor);
404 FLAG_FORCE(server.interface_pair);
407 FLAG_FORCE(remotename);
408 FLAG_FORCE(password);
409 if (cmd_opts.mailboxes)
410 save_str(¤t.mailboxes, -1, cmd_opts.mailboxes->id);
411 if (cmd_opts.smtphunt)
412 save_str(¤t.smtphunt, -1, cmd_opts.smtphunt->id);
414 FLAG_FORCE(preconnect);
415 FLAG_FORCE(postconnect);
419 FLAG_FORCE(fetchall);
423 FLAG_FORCE(pass8bits);
424 FLAG_FORCE(dropstatus);
426 FLAG_FORCE(fetchlimit);
427 FLAG_FORCE(batchlimit);
431 (void) hostalloc(¤t);
436 void optmerge(struct query *h2, struct query *h1)
437 /* merge two options records; empty fields in h2 are filled in from h1 */
439 append_str_list(&h2->server.localdomains, &h1->server.localdomains);
440 append_str_list(&h2->localnames, &h1->localnames);
441 append_str_list(&h2->mailboxes, &h1->mailboxes);
442 append_str_list(&h2->smtphunt, &h1->smtphunt);
444 #define FLAG_MERGE(fld) if (!h2->fld) h2->fld = h1->fld
445 FLAG_MERGE(server.via);
446 FLAG_MERGE(server.protocol);
447 FLAG_MERGE(server.port);
448 FLAG_MERGE(server.interval);
449 FLAG_MERGE(server.preauthenticate);
450 FLAG_MERGE(server.timeout);
451 FLAG_MERGE(server.envelope);
452 FLAG_MERGE(server.skip);
453 FLAG_MERGE(server.dns);
454 FLAG_MERGE(server.uidl);
457 FLAG_MERGE(server.interface);
458 FLAG_MERGE(server.monitor);
459 FLAG_MERGE(server.interface_pair);
462 FLAG_MERGE(remotename);
463 FLAG_MERGE(password);
465 FLAG_MERGE(preconnect);
469 FLAG_MERGE(fetchall);
473 FLAG_MERGE(pass8bits);
474 FLAG_MERGE(dropstatus);
476 FLAG_MERGE(fetchlimit);
477 FLAG_MERGE(batchlimit);
481 /* easier to do this than cope with variations in where the library lives */
482 int yywrap(void) {return 1;}
484 /* rcfile_y.y ends here */