summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosé Fonseca <jrfonseca@users.sourceforge.net>2005-02-15 17:15:38 +0000
committerJosé Fonseca <jrfonseca@users.sourceforge.net>2005-02-15 17:15:38 +0000
commit7bbad4f8de74ef60f19137230c38100787fd982b (patch)
treeea43d78ac094e7b3e929779b4823fa647632dae6
parent5482ddc6be9ab5e1bdf9d7fb78208190a8c74f8b (diff)
Enforce strict permissions on configuration file (Tiago Macambira).
-rw-r--r--NEWS4
-rw-r--r--configure.ac2
-rw-r--r--parser.y80
3 files changed, 84 insertions, 2 deletions
diff --git a/NEWS b/NEWS
index 13d47c9..729de80 100644
--- a/NEWS
+++ b/NEWS
@@ -8,7 +8,9 @@ News
* Do not attempt to authenticate if no username/password is given.
- * Several configuration enhancements (SASAJIMA, Dirk Tilger).
+ * Several configuration fixes/enhancements (SASAJIMA and Dirk Tilger).
+
+ * Enforce strict permissions on configuration file (Tiago Macambira).
* Version 0.5.0 (2003-11-14):
diff --git a/configure.ac b/configure.ac
index a752f73..30aea20 100644
--- a/configure.ac
+++ b/configure.ac
@@ -44,5 +44,7 @@ AC_SUBST( sysconfdir )
jrf_FUNC_GETOPT
+AC_CHECK_FUNCS([getuid geteuid])
+
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
diff --git a/parser.y b/parser.y
index 437adbf..a13a200 100644
--- a/parser.y
+++ b/parser.y
@@ -7,10 +7,18 @@
*/
+#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>
@@ -125,6 +133,73 @@ void yyerror (const char *s)
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
@@ -157,8 +232,11 @@ void rcfile_parse(const char *_rcfile)
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)