Index: ChangeLog
===================================================================
RCS file: /cvsroot/vpopmail/vpopmail/ChangeLog,v
retrieving revision 1.103.2.22
retrieving revision 1.103.2.31
diff -u -r1.103.2.22 -r1.103.2.31
--- ChangeLog 1 Jul 2004 05:09:59 -0000 1.103.2.22
+++ ChangeLog 27 Aug 2004 17:57:44 -0000 1.103.2.31
@@ -1,17 +1,35 @@
Numbers in square brackets ([]) are tracker items on SourceForge with patch
or info related to the entry.
+5.4.7 - unreleased
+
+ Tom Collins
+ - Don't try to delete dir-control for domain unless users-big-dir
+ is enabled.
+ - Verify user exists before trying to set quota in vsetuserquota().
+ [984698]
+ - Update cdb/Makefile so you can 'make install' without doing
+ 'make' first.
+ - Fix size comparisons to MAX_PW_X (should be ">", not ">=").
+ - Fix possible buffer overflows in vsybase.c.
+ - Have vconvert reset dir_control and increment it for each user
+ added when converting from cdb to MySQL.
+ - If crypt() doesn't support MD5 passwords, fall back to using
+ a valid, non-MD5 salt even if MD5 passwords are enabled.
+
5.4.6 - released 30-Jun-04
[backport from 5.5.0]
- Consolidate table creation code in vmysql.c and vpgsql.c.
- Increase SQL_BUF_SIZE from 600 to 2048 for Oracle, Postgres
and Sybase.
+ - Multiple fixes to vpgsql.c related to freeing PGresults and
+ attempting to access NULL PGresults when reporting errors.
+ * These changes address SQL Injection vulnerability documented in
+ * Bugtraq ID 10990
- Add qnprintf() to vpopmail.c for escaping strings in SQL queries.
- Use qnprintf() when building queries in vmysql.c, vpgsql.c,
voracle.pc, and vsybase.c.
- - Multiple fixes to vpgsql.c related to freeing PGresults and
- attempting to access NULL PGresults when reporting errors.
5.4.5 - released 25-Jun-04
Index: vconvert.c
===================================================================
RCS file: /cvsroot/vpopmail/vpopmail/vconvert.c,v
retrieving revision 1.2.2.1
retrieving revision 1.2.2.2
diff -u -r1.2.2.1 -r1.2.2.2
--- vconvert.c 10 Mar 2004 15:18:50 -0000 1.2.2.1
+++ vconvert.c 24 Aug 2004 17:17:39 -0000 1.2.2.2
@@ -1,5 +1,5 @@
/*
- * $Id: vconvert.c,v 1.2.2.1 2004/03/10 15:18:50 tomcollins Exp $
+ * $Id: vconvert.c,v 1.2.2.2 2004/08/24 17:17:39 tomcollins Exp $
* Copyright (C) 1999-2002 Inter7 Internet Technologies, Inc.
*
* This program is free software; you can redistribute it and/or modify
@@ -188,6 +188,8 @@
int i, colon_count, dir_count;
int bFoundDomain = 0;
char assign_file[MAX_BUFF];
+ uid_t uid;
+ gid_t gid;
snprintf(assign_file, sizeof(assign_file), "%s/users/assign", QMAILDIR);
if ( (assign_fs=fopen(assign_file, "r"))==NULL ) {
@@ -227,9 +229,13 @@
fclose(assign_fs);
vauth_deldomain(domain);
+ vdel_dir_control(domain);
vauth_adddomain(domain);
- vget_assign(domain, Dir, sizeof(Dir), NULL, NULL );
+ vget_assign(domain, Dir, sizeof(Dir), &uid, &gid );
+#ifdef USERS_BIG_DIR
+ open_big_dir (domain, uid, gid);
+#endif
snprintf(tmpbuf, sizeof(tmpbuf), "%s/vpasswd", Dir);
fs = fopen(tmpbuf,"r");
if ( fs == NULL ) return(-1);
@@ -241,8 +247,14 @@
continue;
}
vauth_setpw(pw, domain);
+#ifdef USERS_BIG_DIR
+ next_big_dir (uid, gid); /* increment user count */
+#endif
}
fclose(fs);
+#ifdef USERS_BIG_DIR
+ close_big_dir (domain, uid, gid);
+#endif
#endif /* USE_SQL */
return(0);
}
Index: vpalias.c
===================================================================
RCS file: /cvsroot/vpopmail/vpopmail/vpalias.c,v
retrieving revision 1.6
retrieving revision 1.6.2.1
diff -u -r1.6 -r1.6.2.1
--- vpalias.c 14 Jan 2004 23:55:21 -0000 1.6
+++ vpalias.c 19 Aug 2004 05:42:34 -0000 1.6.2.1
@@ -1,6 +1,6 @@
#ifndef VALIAS
/*
- * $Id: vpalias.c,v 1.6 2004/01/14 23:55:21 tomcollins Exp $
+ * $Id: vpalias.c,v 1.6.2.1 2004/08/19 05:42:34 tomcollins Exp $
* Copyright (C) 2000-2002 Inter7 Internet Technologies, Inc.
*
* This program is free software; you can redistribute it and/or modify
@@ -59,12 +59,12 @@
return( NULL );
}
- if ( strlen(alias) >= MAX_PW_NAME ) {
+ if ( strlen(alias) > MAX_PW_NAME ) {
verrori = VA_USER_NAME_TOO_LONG;
return( NULL );
}
- if ( strlen(domain) >= MAX_PW_DOMAIN ) {
+ if ( strlen(domain) > MAX_PW_DOMAIN ) {
verrori = VA_DOMAIN_NAME_TOO_LONG;
return( NULL );
}
@@ -116,8 +116,8 @@
if ( alias == NULL ) return(VA_NULL_POINTER);
if ( domain == NULL ) return(VA_NULL_POINTER);
if ( alias_line == NULL ) return(VA_NULL_POINTER);
- if ( strlen(alias) >= MAX_PW_NAME ) return(VA_USER_NAME_TOO_LONG);
- if ( strlen(domain) >= MAX_PW_DOMAIN ) return(VA_DOMAIN_NAME_TOO_LONG);
+ if ( strlen(alias) > MAX_PW_NAME ) return(VA_USER_NAME_TOO_LONG);
+ if ( strlen(domain) > MAX_PW_DOMAIN ) return(VA_DOMAIN_NAME_TOO_LONG);
if ( strlen(alias_line) >= MAX_ALIAS_LINE ) return(VA_ALIAS_LINE_TOO_LONG);
if ((tmpstr = vget_assign(domain, Dir, sizeof(Dir), &uid, &gid )) == NULL) {
@@ -155,8 +155,8 @@
if ( alias == NULL ) return(VA_NULL_POINTER);
if ( domain == NULL ) return(VA_NULL_POINTER);
- if ( strlen(alias) >= MAX_PW_NAME ) return(VA_USER_NAME_TOO_LONG);
- if ( strlen(domain) >= MAX_PW_DOMAIN ) return(VA_DOMAIN_NAME_TOO_LONG);
+ if ( strlen(alias) > MAX_PW_NAME ) return(VA_USER_NAME_TOO_LONG);
+ if ( strlen(domain) > MAX_PW_DOMAIN ) return(VA_DOMAIN_NAME_TOO_LONG);
if ((tmpstr = vget_assign(domain, Dir, 156, &uid, &gid )) == NULL) {
printf("invalid domain, not in qmail assign file\n");
@@ -183,7 +183,7 @@
return( NULL );
}
- if ( strlen(domain) >= MAX_PW_DOMAIN ) {
+ if ( strlen(domain) > MAX_PW_DOMAIN ) {
verrori = VA_DOMAIN_NAME_TOO_LONG;
return( NULL );
}
Index: vpopmail.c
===================================================================
RCS file: /cvsroot/vpopmail/vpopmail/vpopmail.c,v
retrieving revision 1.28.2.4
retrieving revision 1.28.2.8
diff -u -r1.28.2.4 -r1.28.2.8
--- vpopmail.c 26 Jun 2004 02:20:56 -0000 1.28.2.4
+++ vpopmail.c 27 Aug 2004 17:57:45 -0000 1.28.2.8
@@ -1,5 +1,5 @@
/*
- * $Id: vpopmail.c,v 1.28.2.4 2004/06/26 02:20:56 tomcollins Exp $
+ * $Id: vpopmail.c,v 1.28.2.8 2004/08/27 17:57:45 tomcollins Exp $
* Copyright (C) 2000-2002 Inter7 Internet Technologies, Inc.
*
* This program is free software; you can redistribute it and/or modify
@@ -101,7 +101,7 @@
if ( strlen( domain) <3) return (VA_INVALID_DOMAIN_NAME);
/* reject domain names that exceed our max permitted/storable size */
- if ( strlen( domain ) >= MAX_PW_DOMAIN ) return(VA_DOMAIN_NAME_TOO_LONG);
+ if ( strlen( domain ) > MAX_PW_DOMAIN ) return(VA_DOMAIN_NAME_TOO_LONG);
/* check invalid email domain characters */
for(i=0;domain[i]!=0;++i) {
@@ -174,7 +174,7 @@
* We dont want to start creating dirs and putting entries in
* the assign file etc if the path is going to be too long
*/
- if (strlen(dir)+strlen(DOMAINS_DIR)+strlen(DomainSubDir) >= MAX_PW_DIR) {
+ if (strlen(dir)+strlen(DOMAINS_DIR)+strlen(DomainSubDir) > MAX_PW_DIR) {
/* back out of changes made so far */
dec_dir_control(dir_control_for_uid, uid, gid);
chdir(calling_dir);
@@ -262,9 +262,11 @@
fprintf(stderr, "Failed while attempting to delete domain from the qmail control files\n");
}
+#ifdef USERS_BIG_DIR
if (vdel_dir_control(domain) != 0) {
- fprintf (stderr, "Failed while attempting to delete domain from dir_control\n");
+ fprintf (stderr, "Warning: Failed to delete dir_control for %s\n", domain);
}
+#endif
/* send a HUP signal to qmail-send process to reread control files */
signal_process("qmail-send", SIGHUP);
@@ -311,7 +313,7 @@
* asking to del that domain, because such a domain
* wouldnt be able to exist in the 1st place
*/
- if (strlen(domain) >= MAX_PW_DOMAIN) return (VA_DOMAIN_NAME_TOO_LONG);
+ if (strlen(domain) > MAX_PW_DOMAIN) return (VA_DOMAIN_NAME_TOO_LONG);
/* now we want to check a couple for things :
* a) if the domain to del exists in the system
@@ -379,10 +381,12 @@
*/
vdel_limits(domain);
+#ifdef USERS_BIG_DIR
/* delete the dir control info for this domain */
if (vdel_dir_control(domain) != 0) {
fprintf (stderr, "Warning: Failed to delete dir_control for %s\n", domain);
}
+#endif
/* Now remove domain from filesystem */
/* if it's a symbolic link just remove the link */
@@ -447,15 +451,15 @@
/* check gecos for : characters - bad */
if ( strchr(gecos,':')!=0) return(VA_BAD_CHAR);
- if ( strlen(username) >= MAX_PW_NAME ) return(VA_USER_NAME_TOO_LONG);
+ if ( strlen(username) > MAX_PW_NAME ) return(VA_USER_NAME_TOO_LONG);
#ifdef USERS_BIG_DIR
if ( strlen(username) == 1 ) return(VA_ILLEGAL_USERNAME);
#endif
- if ( strlen(domain) >= MAX_PW_DOMAIN ) return(VA_DOMAIN_NAME_TOO_LONG);
+ if ( strlen(domain) > MAX_PW_DOMAIN ) return(VA_DOMAIN_NAME_TOO_LONG);
if ( strlen(domain) < 3) return(VA_INVALID_DOMAIN_NAME);
- if ( strlen(password) >= MAX_PW_CLEAR_PASSWD ) return(VA_PASSWD_TOO_LONG);
- if ( strlen(gecos) >= MAX_PW_GECOS ) return(VA_GECOS_TOO_LONG);
+ if ( strlen(password) > MAX_PW_CLEAR_PASSWD ) return(VA_PASSWD_TOO_LONG);
+ if ( strlen(gecos) > MAX_PW_GECOS ) return(VA_GECOS_TOO_LONG);
umask(VPOPMAIL_UMASK);
lowerit(username);
@@ -602,6 +606,19 @@
tmpstr = crypt(clearpass,salt);
if ( tmpstr == NULL ) return(VA_CRYPT_FAILED);
+#ifdef MD5_PASSWORDS
+ /* Make sure this host's crypt supports MD5 passwords. If not,
+ * fall back on old-style crypt
+ */
+ if (tmpstr[2] != '$') {
+ salt[0] = randltr();
+ salt[1] = randltr();
+ salt[2] = 0;
+ tmpstr = crypt(clearpass,salt);
+ if ( tmpstr == NULL ) return(VA_CRYPT_FAILED);
+ }
+#endif
+
strncpy(crypted,tmpstr, ssize);
return(VA_SUCCESS);
}
@@ -1321,12 +1338,12 @@
gid_t gid;
#endif
- if ( strlen(username) >= MAX_PW_NAME ) return(VA_USER_NAME_TOO_LONG);
+ if ( strlen(username) > MAX_PW_NAME ) return(VA_USER_NAME_TOO_LONG);
#ifdef USERS_BIG_DIR
if ( strlen(username) == 1 ) return(VA_ILLEGAL_USERNAME);
#endif
- if ( strlen(domain) >= MAX_PW_DOMAIN ) return(VA_DOMAIN_NAME_TOO_LONG);
- if ( strlen(password) >= MAX_PW_CLEAR_PASSWD ) return(VA_PASSWD_TOO_LONG);
+ if ( strlen(domain) > MAX_PW_DOMAIN ) return(VA_DOMAIN_NAME_TOO_LONG);
+ if ( strlen(password) > MAX_PW_CLEAR_PASSWD ) return(VA_PASSWD_TOO_LONG);
lowerit(username);
lowerit(domain);
@@ -1546,16 +1563,19 @@
char *formattedquota;
int ret;
- if ( strlen(username) >= MAX_PW_NAME ) return(VA_USER_NAME_TOO_LONG);
+ if ( strlen(username) > MAX_PW_NAME ) return(VA_USER_NAME_TOO_LONG);
#ifdef USERS_BIG_DIR
if ( strlen(username) == 1 ) return(VA_ILLEGAL_USERNAME);
#endif
- if ( strlen(domain) >= MAX_PW_DOMAIN ) return(VA_DOMAIN_NAME_TOO_LONG);
- if ( strlen(quota) >= MAX_PW_QUOTA ) return(VA_QUOTA_TOO_LONG);
+ if ( strlen(domain) > MAX_PW_DOMAIN ) return(VA_DOMAIN_NAME_TOO_LONG);
+ if ( strlen(quota) > MAX_PW_QUOTA ) return(VA_QUOTA_TOO_LONG);
lowerit(username);
lowerit(domain);
+ mypw = vauth_getpw( username, domain );
+ if (mypw == NULL) return VA_USER_DOES_NOT_EXIST;
+
/* correctly format the quota string,
* and then store the quota into the auth backend
*/
@@ -1563,7 +1583,6 @@
ret = vauth_setquota( username, domain, formattedquota);
if (ret != VA_SUCCESS ) return(ret);
- mypw = vauth_getpw( username, domain );
remove_maildirsize(mypw->pw_dir);
if (strcmp (quota, "NOQUOTA") != 0) {
uid_t uid;
@@ -1723,7 +1742,7 @@
#endif
/* check the length of the dir path to make sure it is not too
long to save back to the auth backend */
- if ((strlen(domain_dir)+strlen(user_hash)+strlen(username)) >= MAX_PW_DIR) {
+ if ((strlen(domain_dir)+strlen(user_hash)+strlen(username)) > MAX_PW_DIR) {
fprintf (stderr, "Error. Path exceeds maximum permitted length\n");
chdir(calling_dir);
return (NULL);
@@ -1764,11 +1783,11 @@
if ( mypw != NULL ) {
/* user does exist in the auth backend, so fill in the dir field */
- mypw->pw_dir = malloc(MAX_PW_DIR);
+ mypw->pw_dir = malloc(MAX_PW_DIR+1);
if ( strlen(user_hash) > 0 ) {
- snprintf(mypw->pw_dir, MAX_PW_DIR, "%s/%s/%s", domain_dir, user_hash, username);
+ snprintf(mypw->pw_dir, MAX_PW_DIR+1, "%s/%s/%s", domain_dir, user_hash, username);
} else {
- snprintf(mypw->pw_dir, MAX_PW_DIR, "%s/%s", domain_dir, username);
+ snprintf(mypw->pw_dir, MAX_PW_DIR+1, "%s/%s", domain_dir, username);
}
/* save these values to the auth backend */
vauth_setpw( mypw, domain );
@@ -1857,7 +1876,7 @@
char *default_domain()
{
static int init = 0;
- static char d[MAX_PW_DOMAIN];
+ static char d[MAX_PW_DOMAIN+1];
char path[MAX_BUFF];
int dlen;
FILE *fs;
@@ -1909,8 +1928,9 @@
/* Michael Bowe 14th August 2003
* How can we prevent possible buffer overflows here
* For the moment, stick with a conservative size of MAX_PW_DOMAIN
+ * (plus 1 for the NULL)
*/
- snprintf(domain, MAX_PW_DOMAIN, "%s", tmpstr);
+ snprintf(domain, MAX_PW_DOMAIN+1, "%s", tmpstr);
return;
}
@@ -1945,8 +1965,9 @@
/* Michael Bowe 14th August 2003
* How can we prevent possible buffer overflows here
* For the moment, stick with a conservative size of MAX_PW_DOMAIN
+ * (plus 1 for the NULL)
*/
- snprintf(domain, MAX_PW_DOMAIN, "%s", host);
+ snprintf(domain, MAX_PW_DOMAIN+1, "%s", host);
}
return;
}
@@ -1955,8 +1976,9 @@
/* Michael Bowe 14th August 2003
* How can we prevent possible buffer overflows here
* For the moment, stick with a conservative size of MAX_PW_DOMAIN
+ * (plus 1 for the NULL)
*/
- snprintf(domain, MAX_PW_DOMAIN, "%s", DEFAULT_DOMAIN);
+ snprintf(domain, MAX_PW_DOMAIN+1, "%s", DEFAULT_DOMAIN);
}
/************************************************************************/
@@ -2282,10 +2304,11 @@
*
* Michael Bowe 21st Aug 2003. Need to watch out for buffer overflows here.
* We dont know what size domain is, so stick with a conservative limit of MAX_PW_DOMAIN
+ * (plus 1 for the NULL)
* Not sure if this is our best option? the pw entry shouldnt contain any dirs larger
* than this.
*/
- snprintf(domain, MAX_PW_DOMAIN, "%s", in_domain);
+ snprintf(domain, MAX_PW_DOMAIN+1, "%s", in_domain);
} else {
free(in_domain);
@@ -2786,15 +2809,15 @@
/* when checking for excess size using strlen, the check needs use >= because you
* have to allow 1 char for null termination
*/
- if ( strlen(inpw->pw_name) >= MAX_PW_NAME ) return(VA_USER_NAME_TOO_LONG);
+ if ( strlen(inpw->pw_name) > MAX_PW_NAME ) return(VA_USER_NAME_TOO_LONG);
if ( strlen(inpw->pw_name) == 1 ) return(VA_ILLEGAL_USERNAME);
- if ( strlen(domain) >= MAX_PW_DOMAIN ) return(VA_DOMAIN_NAME_TOO_LONG);
- if ( strlen(inpw->pw_passwd) >= MAX_PW_PASS ) return(VA_PASSWD_TOO_LONG);
- if ( strlen(inpw->pw_gecos) >= MAX_PW_GECOS ) return(VA_GECOS_TOO_LONG);
- if ( strlen(inpw->pw_dir) >= MAX_PW_DIR ) return(VA_DIR_TOO_LONG);
- if ( strlen(inpw->pw_shell) >= MAX_PW_QUOTA ) return(VA_QUOTA_TOO_LONG);
+ if ( strlen(domain) > MAX_PW_DOMAIN ) return(VA_DOMAIN_NAME_TOO_LONG);
+ if ( strlen(inpw->pw_passwd) > MAX_PW_PASS ) return(VA_PASSWD_TOO_LONG);
+ if ( strlen(inpw->pw_gecos) > MAX_PW_GECOS ) return(VA_GECOS_TOO_LONG);
+ if ( strlen(inpw->pw_dir) > MAX_PW_DIR ) return(VA_DIR_TOO_LONG);
+ if ( strlen(inpw->pw_shell) > MAX_PW_QUOTA ) return(VA_QUOTA_TOO_LONG);
#ifdef CLEAR_PASS
- if ( strlen(inpw->pw_clear_passwd) >= MAX_PW_CLEAR_PASSWD )
+ if ( strlen(inpw->pw_clear_passwd) > MAX_PW_CLEAR_PASSWD )
return(VA_CLEAR_PASSWD_TOO_LONG);
#endif
return(VA_SUCCESS);
@@ -2928,7 +2951,7 @@
if ( (err=is_domain_valid(alias_domain)) != VA_SUCCESS ) return(err);
/* make sure the alias domain does not exceed the max storable size */
- if (strlen(alias_domain) >= MAX_PW_DOMAIN) {
+ if (strlen(alias_domain) > MAX_PW_DOMAIN) {
return(VA_DOMAIN_NAME_TOO_LONG);
}
Index: vsybase.c
===================================================================
RCS file: /cvsroot/vpopmail/vpopmail/vsybase.c,v
retrieving revision 1.9.2.1
retrieving revision 1.9.2.2
diff -u -r1.9.2.1 -r1.9.2.2
--- vsybase.c 26 Jun 2004 02:20:56 -0000 1.9.2.1
+++ vsybase.c 19 Aug 2004 16:32:35 -0000 1.9.2.2
@@ -1,5 +1,5 @@
/*
- * $Id: vsybase.c,v 1.9.2.1 2004/06/26 02:20:56 tomcollins Exp $
+ * $Id: vsybase.c,v 1.9.2.2 2004/08/19 16:32:35 tomcollins Exp $
* Copyright (C) 1999-2003 Inter7 Internet Technologies, Inc.
*
* This program is free software; you can redistribute it and/or modify
@@ -101,7 +101,7 @@
if ( dbuse(dbproc, SYBASE_DATABASE) == FAIL ) {
dbcancel(dbproc);
- sprintf( SqlBuf, "create database %s", SYBASE_DATABASE );
+ snprintf( SqlBuf, sizeof(SqlBuf), "create database %s", SYBASE_DATABASE );
dbcmd(dbproc, SqlBuf);
dbsqlexec(dbproc);
while(dbresults(dbproc) != NO_MORE_RESULTS)
@@ -126,10 +126,10 @@
if ( site_size == LARGE_SITE ) {
tmpstr = vauth_munch_domain( domain );
- sprintf( SqlBuf1, "create table %s ( %s )",
+ snprintf( SqlBuf1, sizeof (SqlBuf1), "create table %s ( %s )",
tmpstr, LARGE_TABLE_LAYOUT );
} else {
- sprintf( SqlBuf1, "create table %s ( %s )",
+ snprintf( SqlBuf1, sizeof (SqlBuf1), "create table %s ( %s )",
SYBASE_DEFAULT_TABLE, SMALL_TABLE_LAYOUT);
}
@@ -175,16 +175,16 @@
if ( strlen(domain) <= 0 ) {
if ( strlen(dir) > 0 ) {
- sprintf(dirbuf, "%s/users/%s/%s", VPOPMAILDIR, dir, user);
+ snprintf(dirbuf, sizeof(dirbuf), "%s/users/%s/%s", VPOPMAILDIR, dir, user);
} else {
- sprintf(dirbuf, "%s/users/%s", VPOPMAILDIR, user);
+ snprintf(dirbuf, sizeof(dirbuf), "%s/users/%s", VPOPMAILDIR, user);
}
} else {
vget_assign(domain, dom_dir, 156, &uid, &gid );
if ( strlen(dir) > 0 ) {
- sprintf(dirbuf,"%s/%s/%s", dom_dir,dir,user);
+ snprintf(dirbuf, sizeof(dirbuf), "%s/%s/%s", dom_dir, dir, user);
} else {
- sprintf(dirbuf, "%s/%s", dom_dir, user);
+ snprintf(dirbuf, sizeof(dirbuf), "%s/%s", dom_dir, user);
}
}
@@ -294,7 +294,7 @@
tmpstr = vauth_munch_domain( domain );
if ( site_size == LARGE_SITE ) {
- sprintf( SqlBuf, "drop table %s", tmpstr);
+ snprintf( SqlBuf, sizeof(SqlBuf), "drop table %s", tmpstr);
} else {
qnprintf( SqlBuf, sizeof(SqlBuf), "delete from %s where pw_domain = '%s'",
SYBASE_DEFAULT_TABLE, domain );