Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 18 Jan 2015 12:01:19 +0000 (UTC)
From:      Alexey Dokuchaev <danfe@FreeBSD.org>
To:        ports-committers@freebsd.org, svn-ports-all@freebsd.org, svn-ports-head@freebsd.org
Subject:   svn commit: r377324 - in head/www/thttpd: . files
Message-ID:  <201501181201.t0IC1JLq093944@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: danfe
Date: Sun Jan 18 12:01:18 2015
New Revision: 377324
URL: https://svnweb.freebsd.org/changeset/ports/377324
QAT: https://qat.redports.org/buildarchive/r377324/

Log:
  Bring another several patches from Gentoo and Red Hat (also relevant to the
  upcoming 2.26):
  
  - Fix potential buffer overflow in expand_symlinks() function of libhttpd.c
  - Better handling of tempfile and additional input validation in htpasswd(1)
  - Make sure that the logfile is created or reopened as read/write by thttpd
    (www) user only (modified to allow group read access as well so web admin
    won't have to su(1) to super-user or "www" to be able to read logs) [1]
  
  Bump port revision to account for these and previous changes.
  
  Gentoo bug:	458896 [1]
  Security:	CVE-2013-0348 [1]

Added:
  head/www/thttpd/files/patch-extras_htpasswd.c   (contents, props changed)
Modified:
  head/www/thttpd/Makefile
  head/www/thttpd/files/patch-libhttpd.c
  head/www/thttpd/files/patch-thttpd.c

Modified: head/www/thttpd/Makefile
==============================================================================
--- head/www/thttpd/Makefile	Sun Jan 18 11:40:01 2015	(r377323)
+++ head/www/thttpd/Makefile	Sun Jan 18 12:01:18 2015	(r377324)
@@ -3,7 +3,7 @@
 
 PORTNAME=	thttpd
 PORTVERSION=	2.25b
-PORTREVISION=	5
+PORTREVISION=	6
 CATEGORIES=	www ipv6
 MASTER_SITES=	http://www.acme.com/software/thttpd/ \
 		http://atreides.freenix.no/~anders/

Added: head/www/thttpd/files/patch-extras_htpasswd.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/www/thttpd/files/patch-extras_htpasswd.c	Sun Jan 18 12:01:18 2015	(r377324)
@@ -0,0 +1,201 @@
+--- extras/htpasswd.c.orig	2001-12-19 00:08:08 UTC
++++ extras/htpasswd.c
+@@ -21,7 +21,12 @@ extern char *crypt(const char *key, cons
+ #define LF 10
+ #define CR 13
+ 
++#define CPW_LEN 13
++
++/* ie 'string' + '\0' */
+ #define MAX_STRING_LEN 256
++/* ie 'maxstring' + ':' + cpassword */
++#define MAX_LINE_LEN MAX_STRING_LEN+1+CPW_LEN
+ 
+ int tfd;
+ char temp_template[] = "/tmp/htp.XXXXXX";
+@@ -137,8 +142,9 @@ add_password( char* user, FILE* f )
+     }
+ 
+ static void usage(void) {
+-    fprintf(stderr,"Usage: htpasswd [-c] passwordfile username\n");
+-    fprintf(stderr,"The -c flag creates a new file.\n");
++    fprintf(stderr,"Usage: htpasswd [-c] passwordfile username\n"
++                   "The -c flag creates a new file.\n"
++                   "Will prompt for password, unless given on stdin.\n");
+     exit(1);
+ }
+ 
+@@ -151,51 +157,131 @@ void interrupted(int signo) {
+ int main(int argc, char *argv[]) {
+     FILE *tfp,*f;
+     char user[MAX_STRING_LEN];
+-    char line[MAX_STRING_LEN];
+-    char l[MAX_STRING_LEN];
++    char pwfilename[MAX_STRING_LEN];
++    char line[MAX_LINE_LEN];
++    char l[MAX_LINE_LEN];
+     char w[MAX_STRING_LEN];
+     char command[MAX_STRING_LEN];
+-    int found;
++    int found,u;
+ 
+     tfd = -1;
++    u = 2; /* argv[u] is username, unless...  */
+     signal(SIGINT,(void (*)(int))interrupted);
+     if(argc == 4) {
++        u = 3;
+         if(strcmp(argv[1],"-c"))
+             usage();
++        if((f=fopen(argv[2],"r")) != NULL) {
++            fclose(f);
++            fprintf(stderr,
++                "Password file %s already exists.\n"
++                "Delete it first, if you really want to overwrite it.\n",
++                argv[2]);
++            exit(1);
++        }
++    } else if(argc != 3) usage();
++    /* check uname length; underlying system will take care of pwdfile
++       name too long */
++    if (strlen(argv[u]) >= MAX_STRING_LEN) {
++      fprintf(stderr,"Username too long (max %i): %s\n",
++              MAX_STRING_LEN-1, argv[u]);
++      exit(1);
++    }
++    
++    if(argc == 4) {
+         if(!(tfp = fopen(argv[2],"w"))) {
+             fprintf(stderr,"Could not open passwd file %s for writing.\n",
+                     argv[2]);
+             perror("fopen");
+             exit(1);
+         }
++        if (strlen(argv[2]) > (sizeof(pwfilename) - 1)) {
++            fprintf(stderr, "%s: filename is too long\n", argv[0]);
++	    exit(1);
++        }
++        if (((strchr(argv[2], ';')) != NULL) || ((strchr(argv[2], '>')) != NULL)) {
++	    fprintf(stderr, "%s: filename contains an illegal character\n",
++		argv[0]);
++	    exit(1);
++        }
++        if (strlen(argv[3]) > (sizeof(user) - 1)) {
++	    fprintf(stderr, "%s: username is too long\n", argv[0],
++		sizeof(user) - 1);
++	    exit(1);
++        }
++        if ((strchr(argv[3], ':')) != NULL) {
++            fprintf(stderr, "%s: username contains an illegal character\n",
++                argv[0]);
++            exit(1);
++        }
+         printf("Adding password for %s.\n",argv[3]);
+         add_password(argv[3],tfp);
+         fclose(tfp);
+         exit(0);
+-    } else if(argc != 3) usage();
++    }
+ 
+-    tfd = mkstemp(temp_template);
+-    if(!(tfp = fdopen(tfd,"w"))) {
+-        fprintf(stderr,"Could not open temp file.\n");
++    if (strlen(argv[1]) > (sizeof(pwfilename) - 1)) {
++        fprintf(stderr, "%s: filename is too long\n", argv[0]);
++        exit(1);
++    }
++    if (((strchr(argv[1], ';')) != NULL) || ((strchr(argv[1], '>')) != NULL)) {
++        fprintf(stderr, "%s: filename contains an illegal character\n",
++                argv[0]);
++        exit(1);
++    }
++    if (strlen(argv[2]) > (sizeof(user) - 1)) {
++        fprintf(stderr, "%s: username is too long\n", argv[0],
++                sizeof(user) - 1);
++        exit(1);
++    }
++    if ((strchr(argv[2], ':')) != NULL) {
++        fprintf(stderr, "%s: username contains an illegal character\n",
++                argv[0]);
+         exit(1);
+     }
+-
+     if(!(f = fopen(argv[1],"r"))) {
+         fprintf(stderr,
+                 "Could not open passwd file %s for reading.\n",argv[1]);
+         fprintf(stderr,"Use -c option to create new one.\n");
+         exit(1);
+     }
++    if(freopen(argv[1],"a",f) == NULL) {
++        fprintf(stderr,
++                "Could not open passwd file %s for writing!.\n"
++                "Changes would be lost.\n",argv[1]);
++        exit(1);
++    }
++    f = freopen(argv[1],"r",f);
++    
++    /* pwdfile is there, go on with tempfile now ... */
++    tfd = mkstemp(temp_template);
++    if(!(tfp = fdopen(tfd,"w"))) {
++        fprintf(stderr,"Could not open temp file.\n");
++        exit(1);
++    }
++    /* already checked for boflw ... */
+     strcpy(user,argv[2]);
+ 
+     found = 0;
+-    while(!(getline(line,MAX_STRING_LEN,f))) {
++    /* line we get is username:pwd, or possibly any other cruft */
++    while(!(getline(line,MAX_LINE_LEN,f))) {
++        char *i;
++
+         if(found || (line[0] == '#') || (!line[0])) {
+             putline(tfp,line);
+             continue;
+         }
+-        strcpy(l,line);
+-        getword(w,l,':');
++        i = index(line,':');
++        w[0] = '\0';
++        /* actually, cpw is CPW_LEN chars and never null, hence ':' should 
++           always be at line[strlen(line)-CPW_LEN-1] in a valid user:cpw line
++           Here though we may allow for pre-hancrafted pwdfile (!)...
++           But still need to check for length limits.
++         */
++        if (i != 0 && i-line <= MAX_STRING_LEN-1) {
++            strcpy(l,line);
++            getword(w,l,':');
++        }
+         if(strcmp(user,w)) {
+             putline(tfp,line);
+             continue;
+@@ -210,10 +296,28 @@ int main(int argc, char *argv[]) {
+         printf("Adding user %s\n",user);
+         add_password(user,tfp);
+     }
++    /* close, rewind & copy */
++    fclose(f);
++    fclose(tfp);
++    f = fopen(argv[1],"w");    
++    if(f==NULL) {
++      fprintf(stderr,"Failed re-opening %s!?\n",argv[1]);
++      exit(1);
++    }
++    tfp = fopen(temp_template,"r");
++    if(tfp==NULL) {
++      fprintf(stderr,"Failed re-opening tempfile!?\n");
++      exit(1);
++    }
++    {
++      int c;
++      while((c=fgetc(tfp))!=EOF && !feof(tfp))  {
++        fputc(c,f);
++        /* fputc(c,stderr); */
++      }
++    }
+     fclose(f);
+     fclose(tfp);
+-    sprintf(command,"cp %s %s",temp_template,argv[1]);
+-    system(command);
+     unlink(temp_template);
+     exit(0);
+ }

Modified: head/www/thttpd/files/patch-libhttpd.c
==============================================================================
--- head/www/thttpd/files/patch-libhttpd.c	Sun Jan 18 11:40:01 2015	(r377323)
+++ head/www/thttpd/files/patch-libhttpd.c	Sun Jan 18 12:01:18 2015	(r377324)
@@ -1,6 +1,24 @@
 --- libhttpd.c.orig	Mon May 27 01:22:26 2002
 +++ libhttpd.c	Sun Oct 20 23:49:58 2002
-@@ -3816,6 +3816,9 @@
+@@ -1483,7 +1483,7 @@
+ 	    httpd_realloc_str( &checked, &maxchecked, checkedlen );
+ 	    (void) strcpy( checked, path );
+ 	    /* Trim trailing slashes. */
+-	    while ( checked[checkedlen - 1] == '/' )
++	    while ( checkedlen && checked[checkedlen - 1] == '/' )
+ 		{
+ 		checked[checkedlen - 1] = '\0';
+ 		--checkedlen;
+@@ -1502,7 +1502,7 @@
+     restlen = strlen( path );
+     httpd_realloc_str( &rest, &maxrest, restlen );
+     (void) strcpy( rest, path );
+-    if ( rest[restlen - 1] == '/' )
++    if ( restlen && rest[restlen - 1] == '/' )
+ 	rest[--restlen] = '\0';         /* trim trailing slash */
+     if ( ! tildemapped )
+ 	/* Remove any leading slashes. */
+@@ -3889,6 +3889,9 @@
  	    httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl );
  	    return -1;
  	    }

Modified: head/www/thttpd/files/patch-thttpd.c
==============================================================================
--- head/www/thttpd/files/patch-thttpd.c	Sun Jan 18 11:40:01 2015	(r377323)
+++ head/www/thttpd/files/patch-thttpd.c	Sun Jan 18 12:01:18 2015	(r377324)
@@ -1,6 +1,42 @@
 --- thttpd.c.orig	Wed Jun 29 19:50:59 2005
 +++ thttpd.c	Sun Jun 17 21:30:11 2007
-@@ -1723,12 +1723,45 @@
+@@ -331,6 +331,7 @@
+ re_open_logfile( void )
+     {
+     FILE* logfp;
++    int retchmod;
+ 
+     if ( no_log || hs == (httpd_server*) 0 )
+ 	return;
+@@ -340,7 +341,8 @@
+ 	{
+ 	syslog( LOG_NOTICE, "re-opening logfile" );
+ 	logfp = fopen( logfile, "a" );
+-	if ( logfp == (FILE*) 0 )
++	retchmod = chmod( logfile, S_IRUSR|S_IWUSR );
++	if ( logfp == (FILE*) 0 || retchmod != 0 )
+ 	    {
+ 	    syslog( LOG_CRIT, "re-opening %.80s - %m", logfile );
+ 	    return;
+@@ -360,6 +362,7 @@
+     gid_t gid = 32767;
+     char cwd[MAXPATHLEN+1];
+     FILE* logfp;
++    int retchmod;
+     int num_ready;
+     int cnum;
+     connecttab* c;
+@@ -429,7 +432,8 @@
+ 	else
+ 	    {
+ 	    logfp = fopen( logfile, "a" );
+-	    if ( logfp == (FILE*) 0 )
++	    retchmod = chmod( logfile, S_IRUSR|S_IWUSR|S_IRGRP );
++	    if ( logfp == (FILE*) 0 || retchmod != 0 )
+ 		{
+ 		syslog( LOG_CRIT, "%.80s - %m", logfile );
+ 		perror( logfile );
+@@ -1714,12 +1718,45 @@
      if ( hc->responselen == 0 )
  	{
  	/* No, just write the file. */
@@ -46,7 +82,7 @@
  	/* Yes.  We'll combine headers and file into a single writev(),
  	** hoping that this generates a single packet.
  	*/
-@@ -1739,6 +1772,7 @@
+@@ -1730,6 +1767,7 @@
  	iv[1].iov_base = &(hc->file_address[c->next_byte_index]);
  	iv[1].iov_len = MIN( c->end_byte_index - c->next_byte_index, max_bytes );
  	sz = writev( hc->conn_fd, iv, 2 );
@@ -54,7 +90,7 @@
  	}
  
      if ( sz < 0 && errno == EINTR )
-@@ -1786,7 +1820,11 @@
+@@ -1777,7 +1815,11 @@
  	**
  	** And ECONNRESET isn't interesting either.
  	*/



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201501181201.t0IC1JLq093944>