aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric S. Raymond <esr@thyrsus.com>1996-10-13 15:51:19 +0000
committerEric S. Raymond <esr@thyrsus.com>1996-10-13 15:51:19 +0000
commit3fb4233b2db4486b6e593546798604bbdaf45613 (patch)
tree2e061580a48736a6ea10f6124988ea296de2d4c3
parent7c01a0bb7d66715319fa94626a963e8389375858 (diff)
downloadfetchmail-3fb4233b2db4486b6e593546798604bbdaf45613.tar.gz
fetchmail-3fb4233b2db4486b6e593546798604bbdaf45613.tar.bz2
fetchmail-3fb4233b2db4486b6e593546798604bbdaf45613.zip
Simplified rcfile-parsing code.
svn path=/trunk/; revision=324
-rw-r--r--Makefile.in8
-rw-r--r--rcfile_y.y314
2 files changed, 287 insertions, 35 deletions
diff --git a/Makefile.in b/Makefile.in
index c3e2ba4e..d62d7440 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -72,16 +72,16 @@ ETAGS = etags -tw
CTAGS = ctags -tw
popobjs = socket.o getpass.o pop2.o pop3.o imap.o fetchmail.o options.o \
- rcfile_l.o rcfile_y.o rcfile.o daemon.o driver.o smtp.o xmalloc.o \
+ rcfile_l.o rcfile_y.o daemon.o driver.o smtp.o xmalloc.o \
uid.o md5c.o md5ify.o
objs = $(popobjs) $(extras) $(EXTRAOBJ)
srcs = $(srcdir)/socket.c $(srcdir)/getpass.c $(srcdir)/pop2.c \
$(srcdir)/pop3.c $(srcdir)/imap.c $(srcdir)/fetchmail.c \
- $(srcdir)/options.c $(srcdir)/rcfile.c $(srcdir)/daemon.c \
- $(srcdir)/driver.c $(srcdir)/smtp.c $(srcdir)/xmalloc.c \
- $(srcdir)/uid.c $(srcdir)/md5c.c $(srcdir)/md5ify.c
+ $(srcdir)/options.c $(srcdir)/daemon.c $(srcdir)/driver.c \
+ $(srcdir)/smtp.c $(srcdir)/xmalloc.c $(srcdir)/uid.c \
+ $(srcdir)/md5c.c $(srcdir)/md5ify.c
.SUFFIXES:
.SUFFIXES: .o .c .h .y .l .ps .dvi .info .texi
diff --git a/rcfile_y.y b/rcfile_y.y
index b3650880..2985fc6c 100644
--- a/rcfile_y.y
+++ b/rcfile_y.y
@@ -13,14 +13,20 @@
#include <config.h>
#include <stdio.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <errno.h>
#include "fetchmail.h"
-extern char *rcfile;
-extern int prc_lineno;
-extern int prc_errflag;
-extern char *yytext;
+struct hostrec cmd_opts; /* where to put command-line info */
+struct hostrec *hostlist; /* head of server list (globally visible) */
int yydebug; /* in case we didn't generate with -- debug */
+
+static struct hostrec current; /* current server record */
+static int prc_errflag;
%}
%union {
@@ -52,26 +58,26 @@ statement_list : statement
statement : define_server serverspecs userspecs
;
-define_server : SERVER STRING {prc_setserver($2);}
- | SKIP SERVER STRING {prc_setserver($3);
- prc_setskip($1==FLAG_TRUE);}
- | DEFAULTS {prc_setserver("defaults");}
+define_server : SERVER STRING {strcpy(current.servername, $2);}
+ | SKIP SERVER STRING {strcpy(current.servername, $3);
+ current.skip=($1==FLAG_TRUE);}
+ | DEFAULTS {strcpy(current.servername,"defaults");}
;
serverspecs : /* EMPTY */
| serverspecs serv_option
;
-serv_option : PROTOCOL PROTO {prc_setproto($2);}
+serv_option : PROTOCOL PROTO {current.protocol = $2;}
| PROTOCOL KPOP {
- prc_setproto(P_POP3);
- prc_setauth(A_KERBEROS);
- prc_setport(KPOP_PORT);
+ current.protocol = P_POP3;
+ current.authenticate = A_KERBEROS;
+ current.port = KPOP_PORT;
}
- | PORT STRING {prc_setport(atoi($2));}
- | SKIP {prc_setskip($1==FLAG_TRUE);}
- | AUTHENTICATE PASSWORD {prc_setauth(A_PASSWORD);}
- | AUTHENTICATE KERBEROS {prc_setauth(A_KERBEROS);}
+ | PORT STRING {current.port = atoi($2);}
+ | SKIP {current.skip = ($1==FLAG_TRUE);}
+ | AUTHENTICATE PASSWORD {current.authenticate = A_PASSWORD;}
+ | AUTHENTICATE KERBEROS {current.authenticate = A_KERBEROS;}
;
/* the first and only the first user spec may omit the USERNAME part */
@@ -87,9 +93,9 @@ explicits : explicitdef {prc_register(); prc_reset();}
explicitdef : userdef user0opts
;
-userdef : USERNAME STRING {prc_setremote($2);}
- | USERNAME STRING HERE {prc_setlocal($2);}
- | USERNAME STRING THERE {prc_setremote($2);}
+userdef : USERNAME STRING {strcpy(current.remotename, $2);}
+ | USERNAME STRING HERE {strcpy(current.localname, $2);}
+ | USERNAME STRING THERE {strcpy(current.remotename, $2);}
;
user0opts : /* EMPTY */
@@ -100,24 +106,270 @@ user1opts : user_option
| user1opts user_option
;
-user_option : IS STRING {prc_setlocal($2);}
- | IS STRING HERE {prc_setlocal($2);}
- | IS STRING THERE {prc_setremote($2);}
- | PASSWORD STRING {prc_setpassword($2);}
- | FOLDER STRING {prc_setfolder($2);}
- | SMTPHOST STRING {prc_setsmtphost($2);}
- | MDA STRING {prc_setmda($2);}
-
- | KEEP {prc_setkeep($1==FLAG_TRUE);}
- | FLUSH {prc_setflush($1==FLAG_TRUE);}
- | FETCHALL {prc_setfetchall($1==FLAG_TRUE);}
- | REWRITE {prc_setrewrite($1==FLAG_TRUE);}
+user_option : IS STRING {strcpy(current.localname, $2);}
+ | IS STRING HERE {strcpy(current.localname, $2);}
+ | IS STRING THERE {strcpy(current.remotename, $2);}
+ | PASSWORD STRING {strcpy(current.password, $2);}
+ | FOLDER STRING {strcpy(current.mailbox, $2);}
+ | SMTPHOST STRING {strcpy(current.smtphost, $2);}
+ | MDA STRING {strcpy(current.mda, $2);}
+
+ | KEEP {current.keep = ($1==FLAG_TRUE);}
+ | FLUSH {current.flush = ($1==FLAG_TRUE);}
+ | FETCHALL {current.fetchall = ($1==FLAG_TRUE);}
+ | REWRITE {current.norewrite = ($1==FLAG_TRUE);}
;
%%
+/* lexer interface */
+extern char *rcfile;
+extern int prc_lineno;
+extern char *yytext;
+extern FILE *yyin;
+
+static struct hostrec *hosttail; /* where to add new elements */
+
+/******************************************************************
+ function: yyerror
+ description: report a syntax error
+ arguments:
+ s error string
+
+ ret. value: none
+ globals: none
+ *****************************************************************/
+
yyerror (s)
char *s;
{
fprintf(stderr,"%s line %d: %s at %s\n", rcfile, prc_lineno, s, yytext);
prc_errflag++;
}
+
+/******************************************************************
+ function: prc_filecheck
+ description: Check that a configuration file is secure
+ arguments:
+ pathname pathname for the configuration file
+
+ ret. value: error code.
+ globals: none
+ *****************************************************************/
+
+int prc_filecheck(pathname)
+char *pathname;
+{
+ struct stat statbuf;
+
+ /* 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
+ be a symbolic link. We check these conditions here. */
+
+ errno = 0;
+ if (lstat(pathname, &statbuf) < 0) {
+ if (errno == ENOENT)
+ return(0);
+ else {
+ perror(pathname);
+ return(PS_IOERR);
+ }
+ }
+
+ if ((statbuf.st_mode & S_IFLNK) == S_IFLNK) {
+ fprintf(stderr, "File %s must not be a symbolic link.\n", pathname);
+ return(PS_AUTHFAIL);
+ }
+
+ if (statbuf.st_mode & ~(S_IFREG | S_IREAD | S_IWRITE)) {
+ fprintf(stderr, "File %s must have no more than -rw------ permissions.\n",
+ pathname);
+ return(PS_AUTHFAIL);
+ }
+
+ if (statbuf.st_uid != getuid()) {
+ fprintf(stderr, "File %s must be owned by you.\n", pathname);
+ return(PS_AUTHFAIL);
+ }
+
+ return(0);
+}
+
+/******************************************************************
+ function: prc_parse_file
+ description: Read the contents of the configuration file, storing
+ each parsed record in a linked list.
+ arguments:
+ pathname pathname for the configuration file
+
+ ret. value: error code.
+ globals: writes sp_head, writes hosttail, writes yyin,
+ writes rcfile, writes prc_errflag.
+ calls: prc_reset, yyparse.
+ *****************************************************************/
+
+prc_parse_file (pathname)
+char *pathname;
+{
+ prc_errflag = 0;
+ hostlist = hosttail = (struct hostrec *)NULL;
+ prc_reset();
+
+ /* Check that the file is secure */
+ if ((prc_errflag = prc_filecheck(pathname)) != 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) {
+ perror(pathname);
+ return(PS_IOERR);
+ }
+
+ yyparse(); /* parse entire file */
+
+ fclose(yyin);
+
+ if (prc_errflag)
+ return(PS_SYNTAX);
+ else
+ return(0);
+}
+
+/******************************************************************
+ function: prc_reset
+ description: clear the global current record (server parameters)
+ used by the parser.
+ arguments: none.
+ ret. value: none.
+ globals: writes current.
+ calls: none.
+ *****************************************************************/
+
+prc_reset()
+{
+ char savename[HOSTLEN+1];
+ int saveport, saveproto, saveauth;
+
+ /*
+ * Purpose of this code is to initialize the new server block with
+ * the command-line data, but preserve whatever server name was
+ * previously set. Also preserve server options unless the
+ * command-line explicitly overrides them.
+ */
+ (void) strcpy(savename, current.servername);
+ saveport = current.port;
+ saveproto = current.protocol;
+ saveauth = current.authenticate;
+
+ memset(&current, '\0', sizeof(current));
+
+ (void) strcpy(current.servername, savename);
+ current.protocol = saveproto;
+ current.authenticate = saveauth;
+}
+
+/******************************************************************
+ function: hostalloc
+ description: append a host record to the host list
+ arguments:
+ init pointer to block containing initial values
+ ret. value: new record.
+ calls: none.
+ *****************************************************************/
+
+struct hostrec *hostalloc(init)
+struct hostrec *init;
+{
+ struct hostrec *node;
+
+ /* allocate new node */
+ node = (struct hostrec *) xmalloc(sizeof(struct hostrec));
+
+ /* initialize it */
+ memcpy(node, init, sizeof(struct hostrec));
+
+ /* append to end of list */
+ if (hosttail != (struct hostrec *) 0)
+ hosttail->next = node; /* list contains at least one element */
+ else
+ hostlist = node; /* list is empty */
+ hosttail = node;
+ return(node);
+}
+
+/******************************************************************
+ function: hostalloc
+ description: register the parsed server params by appending
+ them to a linked list of server param records.
+ arguments: none
+ ret. value: none
+ globals: reads current.
+ calls: hostalloc.
+ *****************************************************************/
+
+int prc_register()
+{
+#define STR_FORCE(fld, len) if (cmd_opts.fld[0]) \
+ strcpy(current.fld, cmd_opts.fld)
+ STR_FORCE(localname, USERNAMELEN);
+ STR_FORCE(remotename, USERNAMELEN);
+ STR_FORCE(password, PASSWORDLEN);
+ STR_FORCE(mailbox, FOLDERLEN);
+ STR_FORCE(smtphost, HOSTLEN);
+ STR_FORCE(mda, MDALEN);
+#undef STR_FORCE
+
+#define FLAG_FORCE(fld) if (cmd_opts.fld) current.fld = cmd_opts.fld
+ FLAG_FORCE(protocol);
+ FLAG_FORCE(keep);
+ FLAG_FORCE(flush);
+ FLAG_FORCE(fetchall);
+ FLAG_FORCE(norewrite);
+ FLAG_FORCE(skip);
+ FLAG_FORCE(port);
+ FLAG_FORCE(authenticate);
+#undef FLAG_FORCE
+
+ (void) hostalloc(&current);
+}
+
+/******************************************************************
+ function: optmerge
+ description: Merge two options records.
+ Empty fields in h2 are filled in from h1.
+ arguments
+ h1 h2 the records
+
+ ret. value: none.
+ globals: reads current_head.
+ calls: none.
+
+ *****************************************************************/
+
+void optmerge(h2, h1)
+struct hostrec *h1;
+struct hostrec *h2;
+{
+#define STR_MERGE(fld, len) if (*(h2->fld) == '\0') strcpy(h2->fld, h1->fld)
+ STR_MERGE(localname, USERNAMELEN);
+ STR_MERGE(remotename, USERNAMELEN);
+ STR_MERGE(password, PASSWORDLEN);
+ STR_MERGE(mailbox, FOLDERLEN);
+ STR_MERGE(smtphost, HOSTLEN);
+ STR_MERGE(mda, MDALEN);
+#undef STR_MERGE
+
+#define FLAG_MERGE(fld) if (!h2->fld) h2->fld = h1->fld
+ FLAG_MERGE(protocol);
+ FLAG_MERGE(keep);
+ FLAG_MERGE(flush);
+ FLAG_MERGE(fetchall);
+ FLAG_MERGE(norewrite);
+ FLAG_MERGE(skip);
+ FLAG_MERGE(port);
+ FLAG_MERGE(authenticate);
+#undef FLAG_MERGE
+}
+