[tpop3d-discuss] 1.4.2 auth_mysql patch
Stephen Friedl
steve at unixwiz.net
Sun, 29 Dec 2002 22:02:02 -0800
Hello list,
This is a patch to tpop3d-1.4.2 to fix a fatal error in the mySQL
module. The current code does not check to insure that the data from
either of:
auth-mysql-pass-query
auth-mysql-apop-query
are not NULL - if this happens, tpop3d simply exits with a SIGSEGV,
and this is not very helpful (no logging is done). I've added a
"valid_mysql_params()" function that checks the four params in both
places and logs a more helpful message when NULL is found. I also added
local temp variables for row[0] .. row[3] so their purpose was a bit
more clear.
Both these two routines (APOP and PASS) share a large amount of common
code, so it probably makes sense to do some merging. But I decided this
was outside my portfolio for the evening.
Also a trivial addition to signals.c (added <memory.h>)
Hope this fits in the proper tpo3pd style...
---
Stephen J Friedl | Software Consultant | Tustin, CA | +1 714 544-6561
www.unixwiz.net | I speak for me only | KA8CMY | steve@unixwiz.net
Patch created: Sun Dec 29 21:59:30 PST 2002
Working dir..: /source/tpop3d-1.4.2
Patch created with:
=======================================================
{
cat ../tpop3d-patch-header
echo ""
echo "Patch created: " `date`
echo "Working dir..: " `pwd`
echo ""
echo "Patch created with:"
echo "======================================================="
cat ../make-tpop3d-patch
echo "======================================================="
echo ""
LC_ALL=C TZ=UTC0 diff -Naur auth_mysql.c.orig auth_mysql.c
LC_ALL=C TZ=UTC0 diff -Naur signals.c.orig signals.c
}
=======================================================
--- auth_mysql.c.orig Mon Dec 30 04:32:34 2002
+++ auth_mysql.c Mon Dec 30 05:41:56 2002
@@ -210,6 +210,56 @@
/* MD5 crypt(3) routines end. */
+/*
+ * valid_mysql_params()
+ *
+ * Given the four parameters fetched from mysql for a user, either
+ * for regular or APOP passwords, make sure none is NULL. Return
+ * TRUE if all is well or FALSE if not, but we take care to output
+ * a message indicating what's wrong. The first param is the name
+ * of the
+ */
+
+static int valid_mysql_params(const char *caller, const char *name,
+ const char *ROW_mboxpath,
+ const char *ROW_passhash,
+ const char *ROW_unixuser,
+ const char *ROW_mboxtype )
+{
+ if ( ROW_mboxpath == 0 )
+ {
+ log_print(LOG_WARNING,
+ _("%s: mboxpath is NULL for user {%s}"),
+ caller, name);
+ return 0;
+ }
+
+ if ( ROW_passhash == 0 )
+ {
+ log_print(LOG_WARNING,
+ _("%s: passhash is NULL for user '%s'"),
+ caller, name);
+ return 0;
+ }
+
+ if ( ROW_unixuser == 0 )
+ {
+ log_print(LOG_WARNING,
+ _("%s: unixuser is NULL for user '%s'"),
+ caller, name);
+ return 0;
+ }
+
+ if ( ROW_mboxtype == 0 )
+ {
+ log_print(LOG_WARNING,
+ _("%s: mboxtype is NULL for user '%s'"),
+ caller, name);
+ return 0;
+ }
+ return 1;
+}
+
/* MySQL PASSWORD() routines. This is here so that you can use the MySQL
* proprietary password-hashing routine with tpop3d. The code is inserted here
@@ -399,13 +449,26 @@
unsigned char this_digest[16];
MD5_CTX ctx;
uid_t uid;
+ const char *ROW_mboxpath; /* full path of mailbox */
+ const char *ROW_passhash; /* hashed password */
+ const char *ROW_unixuser; /* UNIX user name/number */
+ const char *ROW_mboxtype; /* 'maildir' or 'bsd' */
row = mysql_fetch_row(result);
/* These are "can't happen" errors */
if (!row || !(lengths = mysql_fetch_lengths(result))) break;
+ if ( ! valid_mysql_params("auth_mysql_new_apop", who,
+ ROW_mboxpath = row[0],
+ ROW_passhash = row[1],
+ ROW_unixuser = row[2],
+ ROW_mboxtype = row[3]) )
+ {
+ break;
+ }
+
/* Verify that this user has a plaintext password. */
- if (strncmp(row[1], "{plaintext}", 11) != 0) {
+ if (strncmp(ROW_passhash, "{plaintext}", 11) != 0) {
log_print(LOG_WARNING, _("auth_mysql_new_apop: attempted APOP login by %s, who does not have a plaintext password"), who);
break;
}
@@ -413,7 +476,7 @@
/* Calculate our idea of the digest */
MD5Init(&ctx);
MD5Update(&ctx, (unsigned char*)timestamp, strlen(timestamp));
- MD5Update(&ctx, (unsigned char*)row[1] + 11, lengths[1] - 11);
+ MD5Update(&ctx, (unsigned char*)ROW_passhash + 11, lengths[1] - 11);
MD5Final(this_digest, &ctx);
/* User was lying */
@@ -423,8 +486,8 @@
}
/* User was not lying (about her password) */
- if (!parse_uid((const char*)row[2], &uid)) {
- log_print(LOG_ERR, _("auth_mysql_new_apop: unix user `%s' for %s does not make sense"), row[3], who);
+ if (!parse_uid(ROW_unixuser, &uid)) {
+ log_print(LOG_ERR, _("auth_mysql_new_apop: unix user `%s' for %s does not make sense"), ROW_unixuser, who);
break;
}
@@ -435,7 +498,7 @@
break;
}
- a = authcontext_new(pw->pw_uid, use_gid ? mail_gid : pw->pw_gid, row[3], row[0], pw->pw_dir);
+ a = authcontext_new(pw->pw_uid, use_gid ? mail_gid : pw->pw_gid, ROW_mboxtype, ROW_mboxpath, pw->pw_dir);
break;
}
@@ -501,25 +564,38 @@
case 1: {
MYSQL_ROW row;
unsigned long *lengths;
- char *pwhash;
+ const char *pwhash;
struct passwd *pw;
int authok = 0;
uid_t uid;
+ const char *ROW_mboxpath; /* full path of mailbox */
+ const char *ROW_passhash; /* hashed password */
+ const char *ROW_unixuser; /* UNIX user name/number */
+ const char *ROW_mboxtype; /* 'maildir' or 'bsd' */
row = mysql_fetch_row(result);
/* These are "can't happen" errors */
if (!row || !(lengths = mysql_fetch_lengths(result))) break;
+ if ( ! valid_mysql_params("auth_mysql_new_user_pass", who,
+ ROW_mboxpath = row[0],
+ ROW_passhash = row[1],
+ ROW_unixuser = row[2],
+ ROW_mboxtype = row[3]) )
+ {
+ break;
+ }
+
/* Verify the password. There are several possibilities here. */
- pwhash = (char*)row[1];
+ pwhash = ROW_passhash;
if (strncmp(pwhash, "{crypt}", 7) == 0) {
/* Password hashed by system crypt function. */
if (strcmp(crypt(pass, pwhash + 7), pwhash + 7) == 0) authok = 1;
} else if (strncmp(pwhash, "{crypt_md5}", 11) == 0) {
/* Password hashed by crypt_md5. */
- if (strcmp(crypt_md5(pass, pwhash + 11), pwhash + 11) == 0) authok = 1;
+ if (strcmp(crypt_md5(pass, pwhash + 10), pwhash + 11) == 0) authok = 1;
} else if (strncmp(pwhash, "{plaintext}", 11) == 0) {
/* Plain text password, as used for APOP. */
if (strcmp(pass, pwhash + 11) == 0) authok = 1;
@@ -571,8 +647,8 @@
break;
}
- if (!parse_uid((const char*)row[2], &uid)) {
- log_print(LOG_ERR, _("auth_mysql_new_user_pass: unix user `%s' for %s does not make sense"), row[3], who);
+ if (!parse_uid((const char*)ROW_unixuser, &uid)) {
+ log_print(LOG_ERR, _("auth_mysql_new_user_pass: unix user `%s' for %s does not make sense"), ROW_unixuser, who);
break;
}
@@ -583,7 +659,7 @@
break;
}
- a = authcontext_new(pw->pw_uid, use_gid ? mail_gid : pw->pw_gid, row[3], row[0], pw->pw_dir);
+ a = authcontext_new(pw->pw_uid, use_gid ? mail_gid : pw->pw_gid, ROW_mboxtype, ROW_mboxpath, pw->pw_dir);
break;
}
--- signals.c.orig Mon Dec 30 04:22:35 2002
+++ signals.c Mon Dec 30 04:54:52 2002
@@ -15,6 +15,7 @@
#include <errno.h>
#include <signal.h>
#include <syslog.h>
+#include <memory.h>
#include <sys/wait.h>