1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304
|
%{
/**
* \file parser.y
* Parser for the rcfile.
*
* \author Adapted from fetchmail's rcfile_y.y by José Fonseca
*/
#include "config.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#include <libesmtp.h>
#include "main.h"
#include "smtp.h"
#include "local.h"
#include "xmalloc.h"
extern int yylex (void);
/** Path name of dot file */
static const char *rcfile = NULL;
int yydebug; /**< in case we didn't generate with -- debug */
static identity_t *identity = NULL;
/**
* Utility macro to set the default identity, if one isn't set yet.
*
* It's necessary for compatability with older configurations files where the
* default identity was defined in a global section, instead of defined by the
* 'default' or the first defined identity, if no 'default' keyword is given.
*/
#define SET_DEFAULT_IDENTITY \
do { \
if(!default_identity) \
default_identity = identity; \
} while(0)
/* using Bison, this arranges that yydebug messages will show actual tokens */
extern char * yytext;
#define YYPRINT(fp, type, val) fprintf(fp, " = \"%s\"", yytext)
void yyerror (const char *s);
%}
%union {
int number;
char *sval;
}
%token IDENTITY DEFAULT HOSTNAME USERNAME PASSWORD STARTTLS CERTIFICATE_PASSPHRASE PRECONNECT POSTCONNECT MDA QUALIFYDOMAIN HELO FORCE SENDER MSGID REVERSE_PATH FORCE_MDA
%token MAP
%token DISABLED ENABLED REQUIRED
%token <sval> STRING
%token <number> NUMBER
%%
rcfile : /* empty */
| statement_list
| statement_list identity_list
| identity_list
;
identity_list : identity
| identity statement_list
| identity_list identity statement_list
;
map : /* empty */
| MAP
;
identity : IDENTITY map STRING
{
identity = identity_new();
identity_add(identity);
identity->address = xstrdup($3);
}
;
statement_list : statement
| statement_list statement
;
/* future global options should also have the form SET <name> optmap <value> */
statement : HOSTNAME map STRING { identity->host = xstrdup($3); SET_DEFAULT_IDENTITY; }
| USERNAME map STRING { identity->user = xstrdup($3); SET_DEFAULT_IDENTITY; }
| PASSWORD map STRING { identity->pass = xstrdup($3); SET_DEFAULT_IDENTITY; }
| STARTTLS map DISABLED { identity->starttls = Starttls_DISABLED; SET_DEFAULT_IDENTITY; }
| STARTTLS map ENABLED { identity->starttls = Starttls_ENABLED; SET_DEFAULT_IDENTITY; }
| STARTTLS map REQUIRED { identity->starttls = Starttls_REQUIRED; SET_DEFAULT_IDENTITY; }
| CERTIFICATE_PASSPHRASE map STRING { identity->certificate_passphrase = xstrdup($3); SET_DEFAULT_IDENTITY; }
| PRECONNECT map STRING { identity->preconnect = xstrdup($3); SET_DEFAULT_IDENTITY; }
| POSTCONNECT map STRING { identity->postconnect = xstrdup($3); SET_DEFAULT_IDENTITY; }
| QUALIFYDOMAIN map STRING { identity->qualifydomain = xstrdup($3); SET_DEFAULT_IDENTITY; }
| HELO map STRING { identity->helo = xstrdup($3); SET_DEFAULT_IDENTITY; }
| FORCE REVERSE_PATH map STRING { identity->force_reverse_path = xstrdup($4); SET_DEFAULT_IDENTITY; }
| FORCE SENDER map STRING { identity->force_sender = xstrdup($4); SET_DEFAULT_IDENTITY; }
| MSGID map DISABLED { identity->prohibit_msgid = 1; SET_DEFAULT_IDENTITY; }
| MSGID map ENABLED { identity->prohibit_msgid = 0; SET_DEFAULT_IDENTITY; }
| MDA map STRING { mda = xstrdup($3); }
| FORCE_MDA map STRING { force_mda = xstrdup($3); }
| DEFAULT { default_identity = identity; }
;
%%
/* lexer interface */
extern int lineno;
extern char *yytext;
extern FILE *yyin;
/**
* Report a syntax error.
*/
void yyerror (const char *s)
{
fprintf(stderr, "%s:%d: %s at %s\n", rcfile, lineno, s,
(yytext && yytext[0]) ? yytext : "end of input");
exit(EX_CONFIG);
}
/**
* Check that a configuration file is secure.
*
* \param securecheck if set to 1 strict file permission tests will be run.
*
* \return 0 if everything is OK, -1 in case of error
*
*/
int rcfile_check(const char *pathname, const int securecheck)
{
#ifndef __EMX__
struct stat statbuf;
errno = 0;
/* special case useful for debugging purposes */
if (strcmp("/dev/null", pathname) == 0)
return 0;
/* pass through the special name for stdin */
if (strcmp("-", pathname) == 0)
return 0;
/* 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.
*/
if (lstat(pathname, &statbuf) < 0) {
if (errno == ENOENT)
return 0;
else {
fprintf(stderr, "lstat: %s: %s\n", pathname, strerror(errno));
return -1;
}
}
if (!securecheck)
return 0;
if (!S_ISREG(statbuf.st_mode))
{
fprintf(stderr, "File %s must be a regular file.\n", pathname);
return -1;
}
#ifndef __BEOS__
if (statbuf.st_mode & (S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH | S_IXOTH))
{
fprintf(stderr, "File %s must have no more than -rwx--x--- (0710) permissions.\n", pathname);
return -1;
}
#endif /* !__BEOS__ */
#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 -1;
}
#endif
return 0;
}
#define RCFILE "esmtprc"
#define DOT_RCFILE "." RCFILE
#define ETC_RCFILE SYSCONFDIR "/" RCFILE
void rcfile_parse(const char *_rcfile)
{
char *dot_rcfile = NULL;
if(_rcfile)
{
/* Configuration file specified on the command line */
rcfile = _rcfile;
if(!(yyin = fopen(rcfile, "r")))
goto failure;
goto success;
}
/* Search for the user configuration file */
do
{
char *home;
if (!(home = getenv("HOME")))
break;
dot_rcfile = xmalloc(strlen(home) + strlen(DOT_RCFILE) + 2);
strcpy(dot_rcfile, home);
if (dot_rcfile[strlen(dot_rcfile) - 1] != '/')
strcat(dot_rcfile, "/");
strcat(dot_rcfile, DOT_RCFILE);
rcfile = dot_rcfile;
if (rcfile_check(rcfile, 1) < 0)
goto failure;
if(!(yyin = fopen(rcfile, "r")))
{
if(errno == ENOENT)
break;
else
goto failure;
}
goto success;
}
while(0);
/* Search for the global configuration file */
do
{
rcfile = ETC_RCFILE;
if(!(yyin = fopen(rcfile, "r")))
{
if(errno == ENOENT)
break;
else
goto failure;
}
goto success;
}
while(0);
/* No configuration file found */
fprintf(stderr, "No configuration file found at %s or " ETC_RCFILE "\n", dot_rcfile);
exit(EX_CONFIG);
success:
/* Configuration file opened */
identity = identity_new();
identity_add(identity);
yyparse(); /* parse entire file */
SET_DEFAULT_IDENTITY;
fclose(yyin); /* not checking this should be safe, file mode was r */
rcfile = NULL;
if(dot_rcfile)
free(dot_rcfile);
return;
failure:
/* Failure to open the configuration file */
fprintf(stderr, "open: %s: %s\n", rcfile, strerror(errno));
exit(EX_CONFIG);
}
/* easier to do this than cope with variations in where the library lives */
int yywrap(void) { return 1; }
|