struct query cmd_opts; /* where to put command-line info */
/* parser sets these */
-int poll_interval; /* poll interval in seconds */
-char *logfile; /* log file for daemon mode */
-flag errors_to_syslog; /* if syslog was set */
-flag use_invisible; /* if invisible was set */
struct query *querylist; /* head of server list (globally visible) */
int yydebug; /* in case we didn't generate with -- debug */
static struct hostdata *leadentry;
static flag trailer;
-static void record_current();
-static void user_reset();
-static void reset_server(char *name, int skip);
+static void record_current(void);
+static void user_reset(void);
+static void reset_server(const char *name, int skip);
/* using Bison, this arranges that yydebug messages will show actual tokens */
extern char * yytext;
}
%token DEFAULTS POLL SKIP VIA AKA LOCALDOMAINS PROTOCOL
-%token AUTHENTICATE TIMEOUT KPOP KERBEROS4 KERBEROS5 KERBEROS
-%token ENVELOPE QVIRTUAL USERNAME PASSWORD FOLDER SMTPHOST MDA SMTPADDRESS
-%token SPAMRESPONSE PRECONNECT POSTCONNECT LIMIT
+%token PREAUTHENTICATE TIMEOUT KPOP SDPS KERBEROS4 KERBEROS5 KERBEROS SSH
+%token ENVELOPE QVIRTUAL USERNAME PASSWORD FOLDER SMTPHOST MDA BSMTP LMTP
+%token SMTPADDRESS SPAMRESPONSE PRECONNECT POSTCONNECT LIMIT WARNINGS
+%token NETSEC INTERFACE MONITOR PLUGIN PLUGOUT
%token IS HERE THERE TO MAP WILDCARD
-%token BATCHLIMIT FETCHLIMIT EXPUNGE
-%token SET LOGFILE DAEMON SYSLOG IDFILE INVISIBLE NETSEC INTERFACE MONITOR
+%token BATCHLIMIT FETCHLIMIT EXPUNGE PROPERTIES
+%token SET LOGFILE DAEMON SYSLOG IDFILE INVISIBLE POSTMASTER BOUNCEMAIL
%token <proto> PROTO
%token <sval> STRING
%token <number> NUMBER
-%token NO KEEP FLUSH FETCHALL REWRITE FORCECR STRIPCR PASS8BITS DROPSTATUS
-%token DNS SERVICE PORT UIDL INTERVAL MIMEDECODE
+%token NO KEEP FLUSH FETCHALL REWRITE FORCECR STRIPCR PASS8BITS
+%token DROPSTATUS DROPDELIVERED
+%token DNS SERVICE PORT UIDL INTERVAL MIMEDECODE IDLE CHECKALIAS
+%token SSL SSLKEY SSLCERT
%%
statement : SET LOGFILE optmap STRING {run.logfile = xstrdup($4);}
| SET IDFILE optmap STRING {run.idfile = xstrdup($4);}
| SET DAEMON optmap NUMBER {run.poll_interval = $4;}
+ | SET POSTMASTER optmap STRING {run.postmaster = xstrdup($4);}
+ | SET BOUNCEMAIL {run.bouncemail = TRUE;}
+ | SET NO BOUNCEMAIL {run.bouncemail = FALSE;}
+ | SET PROPERTIES optmap STRING {run.properties =xstrdup($4);}
| SET SYSLOG {run.use_syslog = TRUE;}
| SET INVISIBLE {run.invisible = TRUE;}
| PROTOCOL PROTO {current.server.protocol = $2;}
| PROTOCOL KPOP {
current.server.protocol = P_POP3;
+
+ if (current.server.preauthenticate == A_PASSWORD)
#ifdef KERBEROS_V5
- current.server.preauthenticate = A_KERBEROS_V5;
+ current.server.preauthenticate = A_KERBEROS_V5;
#else
- current.server.preauthenticate = A_KERBEROS_V4;
+ current.server.preauthenticate = A_KERBEROS_V4;
#endif /* KERBEROS_V5 */
-#if INET6
+#if INET6_ENABLE
current.server.service = KPOP_PORT;
-#else /* INET6 */
+#else /* INET6_ENABLE */
current.server.port = KPOP_PORT;
-#endif /* INET6 */
+#endif /* INET6_ENABLE */
+ }
+ | PROTOCOL SDPS {
+#ifdef SDPS_ENABLE
+ current.server.protocol = P_POP3;
+ current.server.sdps = TRUE;
+#else
+ yyerror("SDPS not enabled.");
+#endif /* SDPS_ENABLE */
}
| UIDL {current.server.uidl = FLAG_TRUE;}
| NO UIDL {current.server.uidl = FLAG_FALSE;}
+ | CHECKALIAS {current.server.checkalias = FLAG_TRUE;}
+ | NO CHECKALIAS {current.server.checkalias = FLAG_FALSE;}
| SERVICE STRING {
-#if INET6
+#if INET6_ENABLE
current.server.service = $2;
-#endif /* INET6 */
+#endif /* INET6_ENABLE */
}
| PORT NUMBER {
-#if !INET6
+#if INET6_ENABLE
+ int port = $2;
+ char buf[10];
+ sprintf(buf, "%d", port);
+ current.server.service = xstrdup(buf);
+#else
current.server.port = $2;
-#endif /* !INET6 */
- }
+#endif /* INET6_ENABLE */
+ }
| INTERVAL NUMBER {current.server.interval = $2;}
- | AUTHENTICATE PASSWORD {current.server.preauthenticate = A_PASSWORD;}
- | AUTHENTICATE KERBEROS4 {current.server.preauthenticate = A_KERBEROS_V4;}
- | AUTHENTICATE KERBEROS5 {current.server.preauthenticate = A_KERBEROS_V5;}
- | AUTHENTICATE KERBEROS {
+ | PREAUTHENTICATE PASSWORD {current.server.preauthenticate = A_PASSWORD;}
+ | PREAUTHENTICATE KERBEROS4 {current.server.preauthenticate = A_KERBEROS_V4;}
+ | PREAUTHENTICATE KERBEROS5 {current.server.preauthenticate = A_KERBEROS_V5;}
+ | PREAUTHENTICATE KERBEROS {
#ifdef KERBEROS_V5
current.server.preauthenticate = A_KERBEROS_V5;
#else
current.server.preauthenticate = A_KERBEROS_V4;
#endif /* KERBEROS_V5 */
}
+ | PREAUTHENTICATE SSH {current.server.preauthenticate = A_SSH;}
| TIMEOUT NUMBER {current.server.timeout = $2;}
| ENVELOPE NUMBER STRING
#endif /* NET_SECURITY */
}
| INTERFACE STRING {
-#if defined(linux) && !defined(INET6)
+#if (defined(linux) && !defined(INET6_ENABLE)) || defined(__FreeBSD__)
interface_parse($2, ¤t.server);
-#else /* defined(linux) && !defined(INET6) */
- fprintf(stderr, "fetchmail: interface option is only supported under Linux\n");
-#endif /* defined(linux) && !defined(INET6) */
+#else /* (defined(linux) && !defined(INET6_ENABLE)) || defined(__FreeBSD__) */
+ fprintf(stderr, "fetchmail: interface option is only supported under Linux and FreeBSD\n");
+#endif /* (defined(linux) && !defined(INET6_ENABLE)) || defined(__FreeBSD__) */
}
| MONITOR STRING {
-#if defined(linux) && !defined(INET6)
+#if (defined(linux) && !defined(INET6_ENABLE)) || defined(__FreeBSD__)
current.server.monitor = xstrdup($2);
-#else /* defined(linux) && !defined(INET6) */
+#else /* (defined(linux) && !defined(INET6_ENABLE)) || defined(__FreeBSD__) */
fprintf(stderr, "fetchmail: monitor option is only supported under Linux\n");
-#endif /* defined(linux) && !defined(INET6) */
+#endif /* (defined(linux) && !defined(INET6_ENABLE) || defined(__FreeBSD__)) */
}
+ | PLUGIN STRING { current.server.plugin = xstrdup($2); }
+ | PLUGOUT STRING { current.server.plugout = xstrdup($2); }
| DNS {current.server.dns = FLAG_TRUE;}
| NO DNS {current.server.dns = FLAG_FALSE;}
| NO ENVELOPE {current.server.envelope = STRING_DISABLED;}
| smtp_list STRING {save_str(¤t.smtphunt, $2,TRUE);}
;
+num_list : NUMBER
+ {
+ struct idlist *id;
+ id=save_str(¤t.antispam,STRING_DUMMY,0);
+ id->val.status.num = $1;
+ }
+ | num_list NUMBER
+ {
+ struct idlist *id;
+ id=save_str(¤t.antispam,STRING_DUMMY,0);
+ id->val.status.num = $2;
+ }
+ ;
+
user_option : TO localnames HERE
| TO localnames
| IS localnames HERE
| IS localnames
- | IS STRING THERE {current.remotename = xstrdup($2);}
- | PASSWORD STRING {current.password = xstrdup($2);}
+ | IS STRING THERE {current.remotename = xstrdup($2);}
+ | PASSWORD STRING {current.password = xstrdup($2);}
| FOLDER folder_list
| SMTPHOST smtp_list
| SMTPADDRESS STRING {current.smtpaddress = xstrdup($2);}
- | SPAMRESPONSE NUMBER {current.antispam = $2;}
- | MDA STRING {current.mda = xstrdup($2);}
- | PRECONNECT STRING {current.preconnect = xstrdup($2);}
+ | SPAMRESPONSE num_list
+ | MDA STRING {current.mda = xstrdup($2);}
+ | BSMTP STRING {current.bsmtp = xstrdup($2);}
+ | LMTP {current.listener = LMTP_MODE;}
+ | PRECONNECT STRING {current.preconnect = xstrdup($2);}
| POSTCONNECT STRING {current.postconnect = xstrdup($2);}
- | KEEP {current.keep = FLAG_TRUE;}
- | FLUSH {current.flush = FLAG_TRUE;}
- | FETCHALL {current.fetchall = FLAG_TRUE;}
- | REWRITE {current.rewrite = FLAG_TRUE;}
- | FORCECR {current.forcecr = FLAG_TRUE;}
- | STRIPCR {current.stripcr = FLAG_TRUE;}
- | PASS8BITS {current.pass8bits = FLAG_TRUE;}
- | DROPSTATUS {current.dropstatus = FLAG_TRUE;}
- | MIMEDECODE {current.mimedecode = FLAG_TRUE;}
-
- | NO KEEP {current.keep = FLAG_FALSE;}
- | NO FLUSH {current.flush = FLAG_FALSE;}
- | NO FETCHALL {current.fetchall = FLAG_FALSE;}
- | NO REWRITE {current.rewrite = FLAG_FALSE;}
- | NO FORCECR {current.forcecr = FLAG_FALSE;}
- | NO STRIPCR {current.stripcr = FLAG_FALSE;}
- | NO PASS8BITS {current.pass8bits = FLAG_FALSE;}
- | NO DROPSTATUS {current.dropstatus = FLAG_FALSE;}
- | NO MIMEDECODE {current.mimedecode = FLAG_FALSE;}
-
- | LIMIT NUMBER {current.limit = NUM_VALUE($2);}
- | FETCHLIMIT NUMBER {current.fetchlimit = NUM_VALUE($2);}
- | BATCHLIMIT NUMBER {current.batchlimit = NUM_VALUE($2);}
- | EXPUNGE NUMBER {current.expunge = NUM_VALUE($2);}
+ | KEEP {current.keep = FLAG_TRUE;}
+ | FLUSH {current.flush = FLAG_TRUE;}
+ | FETCHALL {current.fetchall = FLAG_TRUE;}
+ | REWRITE {current.rewrite = FLAG_TRUE;}
+ | FORCECR {current.forcecr = FLAG_TRUE;}
+ | STRIPCR {current.stripcr = FLAG_TRUE;}
+ | PASS8BITS {current.pass8bits = FLAG_TRUE;}
+ | DROPSTATUS {current.dropstatus = FLAG_TRUE;}
+ | DROPDELIVERED {current.dropdelivered = FLAG_TRUE;}
+ | MIMEDECODE {current.mimedecode = FLAG_TRUE;}
+ | IDLE {current.idle = FLAG_TRUE;}
+
+ | SSL {current.use_ssl = FLAG_TRUE;}
+ | SSLKEY STRING {current.sslkey = xstrdup($2);}
+ | SSLCERT STRING {current.sslcert = xstrdup($2);}
+
+ | NO KEEP {current.keep = FLAG_FALSE;}
+ | NO FLUSH {current.flush = FLAG_FALSE;}
+ | NO FETCHALL {current.fetchall = FLAG_FALSE;}
+ | NO REWRITE {current.rewrite = FLAG_FALSE;}
+ | NO FORCECR {current.forcecr = FLAG_FALSE;}
+ | NO STRIPCR {current.stripcr = FLAG_FALSE;}
+ | NO PASS8BITS {current.pass8bits = FLAG_FALSE;}
+ | NO DROPSTATUS {current.dropstatus = FLAG_FALSE;}
+ | NO DROPDELIVERED {current.dropdelivered = FLAG_FALSE;}
+ | NO MIMEDECODE {current.mimedecode = FLAG_FALSE;}
+ | NO IDLE {current.idle = FLAG_FALSE;}
+
+ | NO SSL {current.use_ssl = FLAG_FALSE;}
+
+ | LIMIT NUMBER {current.limit = NUM_VALUE_IN($2);}
+ | WARNINGS NUMBER {current.warnings = NUM_VALUE_IN($2);}
+ | FETCHLIMIT NUMBER {current.fetchlimit = NUM_VALUE_IN($2);}
+ | BATCHLIMIT NUMBER {current.batchlimit = NUM_VALUE_IN($2);}
+ | EXPUNGE NUMBER {current.expunge = NUM_VALUE_IN($2);}
+
+ | PROPERTIES STRING {current.properties = xstrdup($2);}
;
%%
void yyerror (const char *s)
/* report a syntax error */
{
- error_at_line( 0, 0, rcfile, prc_lineno, "%s at %s", s,
+ report_at_line(stderr, 0, rcfile, prc_lineno, "%s at %s", s,
(yytext && yytext[0]) ? yytext : "end of input");
prc_errflag++;
}
-int prc_filecheck(pathname, securecheck)
+int prc_filecheck(const char *pathname, const flag securecheck)
/* check that a configuration file is secure */
-const char *pathname; /* pathname for the configuration file */
-const flag securecheck;
{
#ifndef __EMX__
struct stat statbuf;
errno = 0;
- /* special cases useful for debugging purposes */
+ /* special case useful for debugging purposes */
if (strcmp("/dev/null", pathname) == 0)
- return(0);
+ return(PS_SUCCESS);
+
+ /* pass through the special name for stdin */
+ if (strcmp("-", pathname) == 0)
+ return(PS_SUCCESS);
/* the run control file must have the same uid as the REAL uid of this
process, it must have permissions no greater than 600, and it must not
if (lstat(pathname, &statbuf) < 0) {
if (errno == ENOENT)
- return(0);
+ return(PS_SUCCESS);
else {
- error(0, errno, "lstat: %s", pathname);
+ report(stderr, "lstat: %s: %s\n", pathname, strerror(errno));
return(PS_IOERR);
}
}
- if (!securecheck) return 0;
+ if (!securecheck) return PS_SUCCESS;
- if ((statbuf.st_mode & S_IFLNK) == S_IFLNK) {
+ if ((statbuf.st_mode & S_IFLNK) == S_IFLNK)
+ {
fprintf(stderr, "File %s must not be a symbolic link.\n", pathname);
- return(PS_AUTHFAIL);
+ return(PS_IOERR);
}
- if (statbuf.st_mode & ~(S_IFREG | S_IREAD | S_IWRITE)) {
- fprintf(stderr, "File %s must have no more than -rw------ (0600) permissions.\n",
+#ifndef __BEOS__
+ if (statbuf.st_mode & ~(S_IFREG | S_IREAD | S_IWRITE | S_IEXEC | S_IXGRP))
+ {
+ fprintf(stderr, "File %s must have no more than -rwx--x--- (0710) permissions.\n",
pathname);
- return(PS_AUTHFAIL);
+ return(PS_IOERR);
}
+#endif /* __BEOS__ */
- if (statbuf.st_uid != getuid()) {
+#ifdef HAVE_GETEUID
+ if (statbuf.st_uid != geteuid())
+#else
+ if (statbuf.st_uid != getuid())
+#endif /* HAVE_GETEUID */
+ {
fprintf(stderr, "File %s must be owned by you.\n", pathname);
- return(PS_AUTHFAIL);
+ return(PS_IOERR);
}
#endif
- return(0);
+ return(PS_SUCCESS);
}
int prc_parse_file (const char *pathname, const flag securecheck)
if ( (prc_errflag = prc_filecheck(pathname, securecheck)) != 0 )
return(prc_errflag);
- if (errno == ENOENT)
- return(0);
-
- /* Open the configuration and feed it to the lexer. */
- if ((yyin = fopen(pathname,"r")) == (FILE *)NULL) {
- error(0, errno, "open: %s", pathname);
+ /*
+ * Croak if the configuration directory does not exist.
+ * This probably means an NFS mount failed and we can't
+ * see a configuration file that ought to be there.
+ * Question: is this a portable check? It's not clear
+ * that all implementations of lstat() will return ENOTDIR
+ * rather than plain ENOENT in this case...
+ */
+ if (errno == ENOTDIR)
+ return(PS_IOERR);
+ else if (errno == ENOENT)
+ return(PS_SUCCESS);
+
+ /* Open the configuration file and feed it to the lexer. */
+ if (strcmp(pathname, "-") == 0)
+ yyin = stdin;
+ else if ((yyin = fopen(pathname,"r")) == (FILE *)NULL) {
+ report(stderr, "open: %s: %s\n", pathname, strerror(errno));
return(PS_IOERR);
}
yyparse(); /* parse entire file */
- fclose(yyin);
+ fclose(yyin); /* not checking this should be safe, file mode was r */
if (prc_errflag)
return(PS_SYNTAX);
else
- return(0);
+ return(PS_SUCCESS);
}
-static void reset_server(char *name, int skip)
+static void reset_server(const char *name, int skip)
/* clear the entire global record and initialize it with a new name */
{
trailer = FALSE;