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]
This commit is contained in:
Alexey Dokuchaev 2015-01-18 12:01:18 +00:00
parent 14b98461cf
commit 31b51c9317
Notes: svn2git 2021-03-31 03:12:20 +00:00
svn path=/head/; revision=377324
4 changed files with 260 additions and 5 deletions

View file

@ -3,7 +3,7 @@
PORTNAME= thttpd PORTNAME= thttpd
PORTVERSION= 2.25b PORTVERSION= 2.25b
PORTREVISION= 5 PORTREVISION= 6
CATEGORIES= www ipv6 CATEGORIES= www ipv6
MASTER_SITES= http://www.acme.com/software/thttpd/ \ MASTER_SITES= http://www.acme.com/software/thttpd/ \
http://atreides.freenix.no/~anders/ http://atreides.freenix.no/~anders/

View file

@ -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);
}

View file

@ -1,6 +1,24 @@
--- libhttpd.c.orig Mon May 27 01:22:26 2002 --- libhttpd.c.orig Mon May 27 01:22:26 2002
+++ libhttpd.c Sun Oct 20 23:49:58 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 ); httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl );
return -1; return -1;
} }

View file

@ -1,6 +1,42 @@
--- thttpd.c.orig Wed Jun 29 19:50:59 2005 --- thttpd.c.orig Wed Jun 29 19:50:59 2005
+++ thttpd.c Sun Jun 17 21:30:11 2007 +++ 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 ) if ( hc->responselen == 0 )
{ {
/* No, just write the file. */ /* No, just write the file. */
@ -46,7 +82,7 @@
/* Yes. We'll combine headers and file into a single writev(), /* Yes. We'll combine headers and file into a single writev(),
** hoping that this generates a single packet. ** 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_base = &(hc->file_address[c->next_byte_index]);
iv[1].iov_len = MIN( c->end_byte_index - c->next_byte_index, max_bytes ); iv[1].iov_len = MIN( c->end_byte_index - c->next_byte_index, max_bytes );
sz = writev( hc->conn_fd, iv, 2 ); sz = writev( hc->conn_fd, iv, 2 );
@ -54,7 +90,7 @@
} }
if ( sz < 0 && errno == EINTR ) if ( sz < 0 && errno == EINTR )
@@ -1786,7 +1820,11 @@ @@ -1777,7 +1815,11 @@
** **
** And ECONNRESET isn't interesting either. ** And ECONNRESET isn't interesting either.
*/ */