#include <stdio.h>
#include <sys/types.h>
#include <sys/file.h>
-#if defined(HAVE_SYS_WAIT_H)
#include <sys/wait.h>
-#endif
#include <sys/stat.h>
#include <errno.h>
-#if defined(STDC_HEADERS)
#include <stdlib.h>
-#endif
-#if defined(HAVE_UNISTD_H)
#include <unistd.h>
-#endif
#include <string.h>
-#if NET_SECURITY
-#include <net/security.h>
-#endif /* NET_SECURITY */
+#if defined(__CYGWIN__)
+#include <sys/cygwin.h>
+#endif /* __CYGWIN__ */
#include "fetchmail.h"
-#include "i18n.h"
+#include "gettext.h"
/* parser reads these */
char *rcfile; /* path name of rc file */
static void user_reset(void);
static void reset_server(const char *name, int skip);
+/* these should be of size PATH_MAX */
+char currentwd[1024] = "", rcfiledir[1024] = "";
+
/* using Bison, this arranges that yydebug messages will show actual tokens */
extern char * yytext;
#define YYPRINT(fp, type, val) fprintf(fp, " = \"%s\"", yytext)
%token DEFAULTS POLL SKIP VIA AKA LOCALDOMAINS PROTOCOL
%token AUTHENTICATE TIMEOUT KPOP SDPS ENVELOPE QVIRTUAL
+%token PINENTRY_TIMEOUT PWMD_SOCKET PWMD_FILE
%token USERNAME PASSWORD FOLDER SMTPHOST FETCHDOMAINS MDA BSMTP LMTP
%token SMTPADDRESS SMTPNAME SPAMRESPONSE PRECONNECT POSTCONNECT LIMIT WARNINGS
-%token NETSEC INTERFACE MONITOR PLUGIN PLUGOUT
-%token IS HERE THERE TO MAP WILDCARD
-%token BATCHLIMIT FETCHLIMIT EXPUNGE PROPERTIES
-%token SET LOGFILE DAEMON SYSLOG IDFILE INVISIBLE POSTMASTER BOUNCEMAIL
-%token SPAMBOUNCE SHOWDOTS
+%token INTERFACE MONITOR PLUGIN PLUGOUT
+%token IS HERE THERE TO MAP
+%token BATCHLIMIT FETCHLIMIT FETCHSIZELIMIT FASTUIDL EXPUNGE PROPERTIES
+%token SET LOGFILE DAEMON SYSLOG IDFILE PIDFILE INVISIBLE POSTMASTER BOUNCEMAIL
+%token SPAMBOUNCE SOFTBOUNCE SHOWDOTS
+%token BADHEADER ACCEPT REJECT_
+%token RETRIEVEERROR ABORT CONTINUE MARKSEEN
%token <proto> PROTO AUTHTYPE
%token <sval> STRING
%token <number> NUMBER
-%token NO KEEP FLUSH FETCHALL REWRITE FORCECR STRIPCR PASS8BITS
+%token NO KEEP FLUSH LIMITFLUSH FETCHALL REWRITE FORCECR STRIPCR PASS8BITS
%token DROPSTATUS DROPDELIVERED
%token DNS SERVICE PORT UIDL INTERVAL MIMEDECODE IDLE CHECKALIAS
-%token SSL SSLKEY SSLCERT SSLPROTO SSLCERTCK SSLCERTPATH SSLFINGERPRINT
-%token PRINCIPAL
+%token SSL SSLKEY SSLCERT SSLPROTO SSLCERTCK SSLCERTFILE SSLCERTPATH SSLCOMMONNAME SSLFINGERPRINT
+%token PRINCIPAL ESMTPNAME ESMTPPASSWORD
%token TRACEPOLLS
+%expect 2
+
+%destructor { free ($$); } STRING
+
%%
rcfile : /* empty */
optmap : MAP | /* EMPTY */;
/* future global options should also have the form SET <name> optmap <value> */
-statement : SET LOGFILE optmap STRING {run.logfile = xstrdup($4);}
- | SET IDFILE optmap STRING {run.idfile = xstrdup($4);}
+statement : SET LOGFILE optmap STRING {run.logfile = prependdir ($4, rcfiledir); free($4);}
+ | SET IDFILE optmap STRING {run.idfile = prependdir ($4, rcfiledir); free($4);}
+ | SET PIDFILE optmap STRING {run.pidfile = prependdir ($4, rcfiledir); free($4);}
| SET DAEMON optmap NUMBER {run.poll_interval = $4;}
- | SET POSTMASTER optmap STRING {run.postmaster = xstrdup($4);}
+ | SET POSTMASTER optmap STRING {run.postmaster = $4;}
| SET BOUNCEMAIL {run.bouncemail = TRUE;}
| SET NO BOUNCEMAIL {run.bouncemail = FALSE;}
| SET SPAMBOUNCE {run.spambounce = TRUE;}
| SET NO SPAMBOUNCE {run.spambounce = FALSE;}
- | SET PROPERTIES optmap STRING {run.properties =xstrdup($4);}
+ | SET SOFTBOUNCE {run.softbounce = TRUE;}
+ | SET NO SOFTBOUNCE {run.softbounce = FALSE;}
+ | SET PROPERTIES optmap STRING {run.properties = $4;}
| SET SYSLOG {run.use_syslog = TRUE;}
| SET NO SYSLOG {run.use_syslog = FALSE;}
| SET INVISIBLE {run.invisible = TRUE;}
| SET NO INVISIBLE {run.invisible = FALSE;}
- | SET SHOWDOTS {run.showdots = TRUE;}
- | SET NO SHOWDOTS {run.showdots = FALSE;}
+ | SET SHOWDOTS {run.showdots = FLAG_TRUE;}
+ | SET NO SHOWDOTS {run.showdots = FLAG_FALSE;}
+ | SET PINENTRY_TIMEOUT optmap NUMBER {
+#ifdef HAVE_LIBPWMD
+ run.pinentry_timeout = $4;
+#else
+ yyerror(GT_("pwmd not enabled"));
+#endif
+ }
/*
* The way the next two productions are written depends on the fact that
{yyerror(GT_("server option after user options"));}
;
-define_server : POLL STRING {reset_server($2, FALSE);}
- | SKIP STRING {reset_server($2, TRUE);}
+define_server : POLL STRING {reset_server($2, FALSE); free($2);}
+ | SKIP STRING {reset_server($2, TRUE); free($2);}
| DEFAULTS {reset_server("defaults", FALSE);}
;
| serverspecs serv_option
;
-alias_list : STRING {save_str(¤t.server.akalist,$1,0);}
- | alias_list STRING {save_str(¤t.server.akalist,$2,0);}
+alias_list : STRING {save_str(¤t.server.akalist,$1,0); free($1);}
+ | alias_list STRING {save_str(¤t.server.akalist,$2,0); free($2);}
;
-domain_list : STRING {save_str(¤t.server.localdomains,$1,0);}
- | domain_list STRING {save_str(¤t.server.localdomains,$2,0);}
+domain_list : STRING {save_str(¤t.server.localdomains,$1,0); free($1);}
+ | domain_list STRING {save_str(¤t.server.localdomains,$2,0); free($2);}
;
serv_option : AKA alias_list
- | VIA STRING {current.server.via = xstrdup($2);}
+ | VIA STRING {current.server.via = $2;}
| LOCALDOMAINS domain_list
| PROTOCOL PROTO {current.server.protocol = $2;}
| PROTOCOL KPOP {
current.server.protocol = P_POP3;
-
- if (current.server.authenticate == A_PASSWORD)
#ifdef KERBEROS_V5
+ if (current.server.authenticate == A_PASSWORD)
current.server.authenticate = A_KERBEROS_V5;
-#else
- current.server.authenticate = A_KERBEROS_V4;
-#endif /* KERBEROS_V5 */
-#if INET6_ENABLE
current.server.service = KPOP_PORT;
-#else /* INET6_ENABLE */
- current.server.port = KPOP_PORT;
-#endif /* INET6_ENABLE */
+#else
+ yyerror(GT_("Kerberos not enabled."));
+#endif
}
- | PRINCIPAL STRING {current.server.principal = xstrdup($2);}
+ | PRINCIPAL STRING {current.server.principal = $2;}
+ | ESMTPNAME STRING {current.server.esmtp_name = $2;}
+ | ESMTPPASSWORD STRING {current.server.esmtp_password = $2;}
| PROTOCOL SDPS {
#ifdef SDPS_ENABLE
current.server.protocol = P_POP3;
yyerror(GT_("SDPS not enabled."));
#endif /* SDPS_ENABLE */
}
- | UIDL {current.server.uidl = FLAG_TRUE;}
- | NO UIDL {current.server.uidl = FLAG_FALSE;}
+ | UIDL {/* EMPTY - removed in 7.0.0 */}
+ | NO UIDL {/* EMPTY - removed in 7.0.0 */}
| CHECKALIAS {current.server.checkalias = FLAG_TRUE;}
| NO CHECKALIAS {current.server.checkalias = FLAG_FALSE;}
| SERVICE STRING {
-#if INET6_ENABLE
current.server.service = $2;
-#endif /* INET6_ENABLE */
}
+ | SERVICE NUMBER {
+ int port = $2;
+ char buf[10];
+ snprintf(buf, sizeof buf, "%d", port);
+ current.server.service = xstrdup(buf);
+ }
| PORT NUMBER {
-#if INET6_ENABLE
int port = $2;
char buf[10];
- sprintf(buf, "%d", port);
+ snprintf(buf, sizeof buf, "%d", port);
current.server.service = xstrdup(buf);
-#else
- current.server.port = $2;
-#endif /* INET6_ENABLE */
}
| INTERVAL NUMBER
{current.server.interval = $2;}
{current.server.authenticate = $2;}
| TIMEOUT NUMBER
{current.server.timeout = $2;}
- | ENVELOPE NUMBER STRING
+ | ENVELOPE NUMBER STRING
{
- current.server.envelope =
- xstrdup($3);
+ current.server.envelope = $3;
current.server.envskip = $2;
}
| ENVELOPE STRING
{
- current.server.envelope =
- xstrdup($2);
+ current.server.envelope = $2;
current.server.envskip = 0;
}
- | QVIRTUAL STRING {current.server.qvirtual=xstrdup($2);}
- | NETSEC STRING {
-#ifdef NET_SECURITY
- void *request;
- int requestlen;
-
- if (net_security_strtorequest($2, &request, &requestlen))
- yyerror(GT_("invalid security request"));
- else {
- current.server.netsec = xstrdup($2);
- free(request);
- }
-#else
- yyerror(GT_("network-security support disabled"));
-#endif /* NET_SECURITY */
- }
+ | QVIRTUAL STRING {current.server.qvirtual = $2;}
| INTERFACE STRING {
-#if (defined(linux) && !defined(INET6_ENABLE)) || defined(__FreeBSD__)
+#ifdef CAN_MONITOR
interface_parse($2, ¤t.server);
-#else /* (defined(linux) && !defined(INET6_ENABLE)) || defined(__FreeBSD__) */
+#else
fprintf(stderr, GT_("fetchmail: interface option is only supported under Linux (without IPv6) and FreeBSD\n"));
-#endif /* (defined(linux) && !defined(INET6_ENABLE)) || defined(__FreeBSD__) */
+#endif
+ free($2);
}
| MONITOR STRING {
-#if (defined(linux) && !defined(INET6_ENABLE)) || defined(__FreeBSD__)
- current.server.monitor = xstrdup($2);
-#else /* (defined(linux) && !defined(INET6_ENABLE)) || defined(__FreeBSD__) */
+#ifdef CAN_MONITOR
+ current.server.monitor = $2;
+#else
fprintf(stderr, GT_("fetchmail: monitor option is only supported under Linux (without IPv6) and FreeBSD\n"));
-#endif /* (defined(linux) && !defined(INET6_ENABLE) || defined(__FreeBSD__)) */
+ free($2);
+#endif
}
- | PLUGIN STRING { current.server.plugin = xstrdup($2); }
- | PLUGOUT STRING { current.server.plugout = xstrdup($2); }
+ | PLUGIN STRING { current.server.plugin = $2; }
+ | PLUGOUT STRING { current.server.plugout = $2; }
| DNS {current.server.dns = FLAG_TRUE;}
| NO DNS {current.server.dns = FLAG_FALSE;}
| NO ENVELOPE {current.server.envelope = STRING_DISABLED;}
- | TRACEPOLLS {current.tracepolls = FLAG_TRUE;}
- | NO TRACEPOLLS {current.tracepolls = FLAG_FALSE;}
+ | TRACEPOLLS {current.server.tracepolls = FLAG_TRUE;}
+ | NO TRACEPOLLS {current.server.tracepolls = FLAG_FALSE;}
+ | BADHEADER ACCEPT {current.server.badheader = BHACCEPT;}
+ | BADHEADER REJECT_ {current.server.badheader = BHREJECT;}
+ | RETRIEVEERROR ABORT {current.server.retrieveerror = RE_ABORT;}
+ | RETRIEVEERROR CONTINUE {current.server.retrieveerror = RE_CONTINUE;}
+ | RETRIEVEERROR MARKSEEN {current.server.retrieveerror = RE_MARKSEEN;}
;
userspecs : user1opts {record_current(); user_reset();}
explicitdef : userdef user0opts
;
-userdef : USERNAME STRING {current.remotename = xstrdup($2);}
+userdef : USERNAME STRING {current.remotename = $2;}
| USERNAME mapping_list HERE
- | USERNAME STRING THERE {current.remotename = xstrdup($2);}
+ | USERNAME STRING THERE {current.remotename = $2;}
;
user0opts : /* EMPTY */
| user1opts user_option
;
-localnames : WILDCARD {current.wildcard = TRUE;}
- | mapping_list {current.wildcard = FALSE;}
- | mapping_list WILDCARD {current.wildcard = TRUE;}
- ;
-
mapping_list : mapping
| mapping_list mapping
;
-mapping : STRING
- {save_str_pair(¤t.localnames, $1, NULL);}
- | STRING MAP STRING
- {save_str_pair(¤t.localnames, $1, $3);}
+mapping : STRING {if (0 == strcmp($1, "*")) {
+ current.wildcard = TRUE;
+ } else {
+ save_str_pair(¤t.localnames, $1, NULL);
+ }
+ free($1);}
+ | STRING MAP STRING {save_str_pair(¤t.localnames, $1, $3); free($1); free($3);}
;
-folder_list : STRING {save_str(¤t.mailboxes,$1,0);}
- | folder_list STRING {save_str(¤t.mailboxes,$2,0);}
+folder_list : STRING {save_str(¤t.mailboxes,$1,0); free($1);}
+ | folder_list STRING {save_str(¤t.mailboxes,$2,0); free($2);}
;
-smtp_list : STRING {save_str(¤t.smtphunt, $1,TRUE);}
- | smtp_list STRING {save_str(¤t.smtphunt, $2,TRUE);}
+smtp_list : STRING {save_str(¤t.smtphunt, $1,TRUE); free($1);}
+ | smtp_list STRING {save_str(¤t.smtphunt, $2,TRUE); free($2);}
;
-fetch_list : STRING {save_str(¤t.domainlist, $1,TRUE);}
- | fetch_list STRING {save_str(¤t.domainlist, $2,TRUE);}
+fetch_list : STRING {save_str(¤t.domainlist, $1,TRUE); free($1);}
+ | fetch_list STRING {save_str(¤t.domainlist, $2,TRUE); free($2);}
;
num_list : NUMBER
{
struct idlist *id;
- id=save_str(¤t.antispam,STRING_DUMMY,0);
+ 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 = save_str(¤t.antispam,STRING_DUMMY,0);
id->val.status.num = $2;
}
;
-user_option : TO localnames HERE
- | TO localnames
- | IS localnames HERE
- | IS localnames
+user_option : TO mapping_list HERE
+ | TO mapping_list
+ | IS mapping_list HERE
+ | IS mapping_list
- | IS STRING THERE {current.remotename = xstrdup($2);}
- | PASSWORD STRING {current.password = xstrdup($2);}
+ | IS STRING THERE {current.remotename = $2;}
+ | PASSWORD STRING {current.password = $2;}
| FOLDER folder_list
| SMTPHOST smtp_list
| FETCHDOMAINS fetch_list
- | SMTPADDRESS STRING {current.smtpaddress = xstrdup($2);}
- | SMTPNAME STRING {current.smtpname = xstrdup($2);}
+ | SMTPADDRESS STRING {current.smtpaddress = $2;}
+ | SMTPNAME STRING {current.smtpname = $2;}
| SPAMRESPONSE num_list
- | MDA STRING {current.mda = xstrdup($2);}
- | BSMTP STRING {current.bsmtp = xstrdup($2);}
+ | MDA STRING {current.mda = $2;}
+ | BSMTP STRING {current.bsmtp = prependdir ($2, rcfiledir); free($2);}
| LMTP {current.listener = LMTP_MODE;}
- | PRECONNECT STRING {current.preconnect = xstrdup($2);}
- | POSTCONNECT STRING {current.postconnect = xstrdup($2);}
+ | PRECONNECT STRING {current.preconnect = $2;}
+ | POSTCONNECT STRING {current.postconnect = $2;}
| KEEP {current.keep = FLAG_TRUE;}
| FLUSH {current.flush = FLAG_TRUE;}
+ | LIMITFLUSH {current.limitflush = FLAG_TRUE;}
| FETCHALL {current.fetchall = FLAG_TRUE;}
| REWRITE {current.rewrite = FLAG_TRUE;}
| FORCECR {current.forcecr = FLAG_TRUE;}
yyerror(GT_("SSL is not enabled"));
#endif
}
- | SSLKEY STRING {current.sslkey = xstrdup($2);}
- | SSLCERT STRING {current.sslcert = xstrdup($2);}
- | SSLPROTO STRING {current.sslproto = xstrdup($2);}
+ | SSLKEY STRING {current.sslkey = prependdir ($2, rcfiledir); free($2);}
+ | SSLCERT STRING {current.sslcert = prependdir ($2, rcfiledir); free($2);}
+ | SSLPROTO STRING {current.sslproto = $2;}
| SSLCERTCK {current.sslcertck = FLAG_TRUE;}
- | SSLCERTPATH STRING {current.sslcertpath = xstrdup($2);}
- | SSLFINGERPRINT STRING {current.sslfingerprint = xstrdup($2);}
+ | SSLCERTFILE STRING {current.sslcertfile = prependdir($2, rcfiledir); free($2);}
+ | SSLCERTPATH STRING {current.sslcertpath = prependdir($2, rcfiledir); free($2);}
+ | SSLCOMMONNAME STRING {current.sslcommonname = $2;}
+ | SSLFINGERPRINT STRING {current.sslfingerprint = $2;}
| NO KEEP {current.keep = FLAG_FALSE;}
| NO FLUSH {current.flush = FLAG_FALSE;}
+ | NO LIMITFLUSH {current.limitflush = FLAG_FALSE;}
| NO FETCHALL {current.fetchall = FLAG_FALSE;}
| NO REWRITE {current.rewrite = FLAG_FALSE;}
| NO FORCECR {current.forcecr = FLAG_FALSE;}
| NO MIMEDECODE {current.mimedecode = FLAG_FALSE;}
| NO IDLE {current.idle = FLAG_FALSE;}
- | NO SSL {
-#ifdef SSL_ENABLE
- current.use_ssl = FLAG_FALSE;
-#else
- yyerror(GT_("SSL is not enabled"))
-#endif
- }
+ | 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);}
+ | FETCHSIZELIMIT NUMBER {current.fetchsizelimit = NUM_VALUE_IN($2);}
+ | FASTUIDL NUMBER {current.fastuidl = 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);}
+ | PROPERTIES STRING {current.properties = $2;}
+
+ | PWMD_SOCKET STRING {
+#ifdef HAVE_LIBPWMD
+ current.pwmd_socket = xstrdup($2);
+#else
+ yyerror(GT_("pwmd not enabled"));
+#endif
+ }
+
+ | PWMD_FILE STRING {
+#ifdef HAVE_LIBPWMD
+ current.pwmd_file = xstrdup($2);
+#else
+ yyerror(GT_("pwmd not enabled"));
+#endif
+ }
;
%%
prc_errflag++;
}
-int prc_filecheck(const char *pathname, const flag securecheck)
-/* check that a configuration file is secure */
+/** check that a configuration file is secure, returns PS_* status codes */
+int prc_filecheck(const char *pathname,
+ const flag securecheck /** shortcuts permission, filetype and uid tests if false */)
{
-#ifndef __EMX__
struct stat statbuf;
errno = 0;
process, it must have permissions no greater than 600, and it must not
be a symbolic link. We check these conditions here. */
- if (lstat(pathname, &statbuf) < 0) {
+ if (stat(pathname, &statbuf) < 0) {
if (errno == ENOENT)
return(PS_SUCCESS);
else {
if (!securecheck) return PS_SUCCESS;
- if ((statbuf.st_mode & S_IFLNK) == S_IFLNK)
+ if (!S_ISREG(statbuf.st_mode))
{
- fprintf(stderr, GT_("File %s must not be a symbolic link.\n"), pathname);
+ fprintf(stderr, GT_("File %s must be a regular file.\n"), pathname);
return(PS_IOERR);
}
-#ifndef __BEOS__
- if (statbuf.st_mode & ~(S_IFREG | S_IREAD | S_IWRITE | S_IEXEC | S_IXGRP))
+#ifdef __CYGWIN__
+ if (cygwin_internal(CW_CHECK_NTSEC, pathname))
+#endif /* __CYGWIN__ */
+ if (statbuf.st_mode & (S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH | S_IXOTH))
{
- fprintf(stderr, GT_("File %s must have no more than -rwx--x--- (0710) permissions.\n"),
+ fprintf(stderr, GT_("File %s must have no more than -rwx------ (0700) permissions.\n"),
pathname);
return(PS_IOERR);
}
-#endif /* __BEOS__ */
-#ifdef HAVE_GETEUID
if (statbuf.st_uid != geteuid())
-#else
- if (statbuf.st_uid != getuid())
-#endif /* HAVE_GETEUID */
{
fprintf(stderr, GT_("File %s must be owned by you.\n"), pathname);
return(PS_IOERR);
}
-#endif
return(PS_SUCCESS);
}
current.server = save;
}
-struct query *hostalloc(init)
-/* append a host record to the host list */
-struct query *init; /* pointer to block containing initial values */
+/** append a host record to the host list */
+struct query *hostalloc(struct query *init /** pointer to block containing
+ initial values */)
{
struct query *node;
trailer = TRUE;
}
-/* easier to do this than cope with variations in where the library lives */
-int yywrap(void) {return 1;}
+char *prependdir (const char *file, const char *dir)
+/* if a filename is relative to dir, convert it to an absolute path */
+{
+ char *newfile;
+ if (!file[0] || /* null path */
+ file[0] == '/' || /* absolute path */
+ strcmp(file, "-") == 0 || /* stdin/stdout */
+ !dir[0]) /* we don't HAVE_GETCWD */
+ return xstrdup (file);
+ newfile = (char *)xmalloc (strlen (dir) + 1 + strlen (file) + 1);
+ if (dir[strlen(dir) - 1] != '/')
+ sprintf (newfile, "%s/%s", dir, file);
+ else
+ sprintf (newfile, "%s%s", dir, file);
+ return newfile;
+}
/* rcfile_y.y ends here */
-
-