[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#129104: bug 129104 (buffer overflow + template reading in cgiemail)



On Sun, Jan 20, 2002 at 11:54:06PM -0500, Thomas Smith wrote:
> On Thu, Jan 17, 2002 at 04:42:42PM +0000, Colin Watson wrote:
> > Yes, with the current design there really isn't any way to do it well
> > (including backwards compatibility), only patch it up. I suggest a
> > simple 'templatedir="/foo/bar/baz"' in a trusted place like
> > /etc/cgiemail.conf. That has the advantage that it can be parsed by the
> > shell, so you can easily set it with debconf and not clobber the old
> > setting on upgrades.
> 
> Ok, that sounds as good as anything can be.  Go ahead and write the code
> (or does there need to be more planning?); I'll do the debconf stuff +
> make up a sane default template telling people what to do when cgiemail
> stops working.  Templates should live in /usr/share/cgiemail, right?
> 'Cause they're architecture-independent.
> 
> Don't forget not to let people do something like "GET
> /cgi-bin/cgiemail/../../../etc/passwd" :-)

OK, here's some code which I believe does the job. The parser is hardly
elegant, but, as the configuration file is presumably in a trusted
location, that isn't a security problem. Please try this out and see how
it goes.

Sorry for the delay in putting this together.

--- cgiemail-1.6.orig/cgilib.c
+++ cgiemail-1.6/cgilib.c
@@ -461,6 +461,59 @@
 }
 
 int
+cgi_read_configuration(formp, templatedir, templatedirlen)
+     cgi_form *formp;
+     char *templatedir;
+     int templatedirlen;
+{
+  FILE *cfp;
+  char *linebuf;
+  int linebuflen;
+  char *directive = "templatedir=\"";
+  int directivelen = strlen(directive);
+
+  cfp = fopen(TEMPLATECONF, "r");
+  if (!cfp)
+    {
+      formp->errcond = 1;
+      strcpy(formp->errmsg, "500 Could not open configuration file");
+      cgi_concat_errno(formp->errmsg);
+#ifdef DISCLOSE_PATHS
+      strncpy(formp->errinfo, TEMPLATECONF, CGI_ERRMSG_MAX);
+#else
+      strcpy(formp->errinfo, "Configuration file could not be accessed.");
+#endif /* DISCLOSE_PATHS */
+      return(1);
+    }
+
+  linebuflen = templatedirlen + directivelen + 2;
+  linebuf = (char *) malloc(linebuflen + 1);
+  while (fgets(linebuf, linebuflen - 1, cfp))
+    {
+      if (!strncmp(linebuf, directive, directivelen))
+	{
+	  char *inquotes = linebuf + directivelen;
+	  char *endquotes = strchr(inquotes, '"');
+	  if (endquotes)
+	    {
+	      strncpy(templatedir, inquotes, endquotes - inquotes);
+	      return(0);
+	    }
+	}
+    }
+
+  formp->errcond = 1;
+  strcpy(formp->errmsg,
+	 "500 Could not find templatedir in configuration file");
+#ifdef DISCLOSE_PATHS
+  strncpy(formp->errinfo, TEMPLATECONF, CGI_ERRMSG_MAX);
+#else
+  strcpy(formp->errinfo, "No templatedir=\"...\" line in configuration file.");
+#endif /* DISCLOSE_PATHS */
+  return(1);
+}
+
+int
 cgi_template_fill(formp, templatefile)
      cgi_form *formp;
      char *templatefile;
@@ -468,6 +521,7 @@
   FILE *tfp;
   char varname[CGI_VARNAME_MAX];
   char formatstr[CGI_VARNAME_MAX];
+  char templatedir[CGI_VARNAME_MAX];
   int varnamelen=0, formatlen=0, nfound=0, substitutions=0;
   int inchar, parse_state=0;
 
@@ -475,6 +529,22 @@
 
   char *envval;
 #endif /* ENABLE_CGIENV */
+
+  if (cgi_read_configuration(formp, templatedir, CGI_VARNAME_MAX - 1))
+    return(1);
+
+  if (strncmp(templatefile, templatedir, strlen(templatedir)) ||
+      strstr(templatefile, "/../"))
+    {
+      formp->errcond=1;
+      strcpy(formp->errmsg, "403 Template not in valid directory");
+#ifdef DISCLOSE_PATHS
+      strncpy(formp->errinfo, templatefile, CGI_ERRMSG_MAX);
+#else
+      strcpy(formp->errinfo, "Template file could not be accessed.");
+#endif /* DISCLOSE_PATHS */
+      return(1);
+    }
 
   /* open template file */
   tfp = fopen(templatefile, "r");
--- cgiemail-1.6.orig/debian/rules
+++ cgiemail-1.6/debian/rules
@@ -38,7 +38,7 @@
 configure-stamp:
 	dh_testdir
 	# Add here commands to configure the package.
-	./configure --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info
+	./configure --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info --sysconfdir=/etc
 
 	touch configure-stamp
 
--- cgiemail-1.6.orig/Makefile.in
+++ cgiemail-1.6/Makefile.in
@@ -4,6 +4,11 @@
 RELEASE=@CGIEMAIL_RELEASE@
 CC=@CC@
 
+prefix=@prefix@
+sysconfdir=@sysconfdir@
+TEMPLATECONF=$(sysconfdir)/cgiemail.conf
+CFLAGS := $(CFLAGS) -DTEMPLATECONF="\"$(TEMPLATECONF)\""
+
 PROG=cgiemail cgiecho cgifile cgicso
 
 DISTFILES=README ChangeLog *.[ch] configure *.in testce.txt

Cheers,

-- 
Colin Watson                                  [cjwatson@flatline.org.uk]



Reply to: