diff options
-rw-r--r-- | Makefile.in | 8 | ||||
-rw-r--r-- | rcfile_y.y | 314 |
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 @@ -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(¤t, '\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(¤t); +} + +/****************************************************************** + 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 +} + |