summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES5
-rw-r--r--build/apr_common.m453
-rw-r--r--configure.in4
-rw-r--r--passwd/apr_md5.c21
4 files changed, 83 insertions, 0 deletions
diff --git a/CHANGES b/CHANGES
index 3aff062cc..61480d2d5 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,10 @@
Changes with APR b1
+ *) Linux, AIX: Use crypt_r() instead of crypt() because the native
+ crypt() is not thread-safe. The misuse of crypt() led to
+ intermittent failures with Apache basic authentication when crypt
+ passwords were being used. [Jeff Trawick]
+
*) AIX: Global mutexes don't need an intraprocess mutex when SysV
sems are used for the crossprocess mutex.
Darwin: The same optimization was applied for Posix sems.
diff --git a/build/apr_common.m4 b/build/apr_common.m4
index 7ec02223a..876396af2 100644
--- a/build/apr_common.m4
+++ b/build/apr_common.m4
@@ -459,6 +459,59 @@ fi
AC_MSG_RESULT([$msg])
] )
dnl
+dnl APR_CHECK_CRYPT_R_STYLE
+dnl
+dnl Decide which of a couple of flavors of crypt_r() is necessary for
+dnl this platform.
+dnl
+AC_DEFUN(APR_CHECK_CRYPT_R_STYLE,[
+AC_CACHE_CHECK(style of crypt_r, ac_cv_crypt_r_style,[
+dnl
+ac_cv_crypt_r_style=none
+dnl
+AC_TRY_COMPILE([
+#include <crypt.h>
+],[
+CRYPTD buffer;
+crypt_r("passwd", "hash", &buffer);
+], ac_cv_crypt_r_style=cryptd)
+dnl
+if test "$ac_cv_crypt_r_style" = "none"; then
+AC_TRY_COMPILE([
+#include <crypt.h>
+],[
+struct crypt_data buffer;
+crypt_r("passwd", "hash", &buffer);
+], ac_cv_crypt_r_style=struct_crypt_data)
+fi
+dnl
+if test "$ac_cv_crypt_r_style" = "none"; then
+dnl same as previous test, but see if defining _GNU_SOURCE helps
+AC_TRY_COMPILE([
+#define _GNU_SOURCE
+#include <crypt.h>
+],[
+struct crypt_data buffer;
+crypt_r("passwd", "hash", &buffer);
+], ac_cv_crypt_r_style=struct_crypt_data_gnu_source)
+fi
+dnl
+])
+if test "$ac_cv_crypt_r_style" = "cryptd"; then
+ AC_DEFINE(CRYPT_R_CRYPTD, 1, [Define if crypt_r has uses CRYPTD])
+fi
+dnl if we don't combine these conditions, CRYPT_R_STRUCT_CRYPT_DATA
+dnl will end up defined twice
+if test "$ac_cv_crypt_r_style" = "struct_crypt_data" -o \
+ "$ac_cv_crypt_r_style" = "struct_crypt_data_gnu_source"; then
+ AC_DEFINE(CRYPT_R_STRUCT_CRYPT_DATA, 1, [Define if crypt_r uses struct crypt_data])
+fi
+if test "$ac_cv_crypt_r_style" = "struct_crypt_data_gnu_source"; then
+ APR_ADDTO(CPPFLAGS, [-D_GNU_SOURCE])
+fi
+])
+
+dnl
dnl APR_CHECK_ICONV_INBUF
dnl
dnl Decide whether or not the inbuf parameter to iconv() is const.
diff --git a/configure.in b/configure.in
index c0b293a20..b484e701f 100644
--- a/configure.in
+++ b/configure.in
@@ -830,6 +830,10 @@ AC_CHECK_FUNCS(strerror_r, [ strerror_r="1" ], [ strerror_r="0" ])
if test "$strerror_r" = "1"; then
APR_CHECK_STRERROR_R_RC
fi
+AC_CHECK_FUNCS(crypt_r, [ crypt_r="1" ], [ crypt_r="0" ])
+if test "$crypt_r" = "1"; then
+ APR_CHECK_CRYPT_R_STYLE
+fi
AC_CHECK_FUNCS(iconv, [ iconv="1" ], [ iconv="0" ])
if test "$iconv" = "1"; then
APR_CHECK_ICONV_INBUF
diff --git a/passwd/apr_md5.c b/passwd/apr_md5.c
index 2c21eee8e..76a16b494 100644
--- a/passwd/apr_md5.c
+++ b/passwd/apr_md5.c
@@ -699,7 +699,28 @@ APR_DECLARE(apr_status_t) apr_password_validate(const char *passwd,
*/
#if defined(WIN32) || defined(BEOS) || defined(NETWARE)
apr_cpystrn(sample, passwd, sizeof(sample) - 1);
+#elif defined(CRYPT_R_CRYPTD)
+ CRYPTD buffer;
+
+ crypt_pw = crypt_r(passwd, hash, &buffer);
+ apr_cpystrn(sample, crypt_pw, sizeof(sample) - 1);
+#elif defined(CRYPT_R_STRUCT_CRYPT_DATA)
+ struct crypt_data buffer;
+
+ /* having to clear this seems bogus... GNU doc is
+ * confusing... user report found from google says
+ * the crypt_data struct had to be cleared to get
+ * the same result as plain crypt()
+ */
+ memset(&buffer, 0, sizeof(buffer));
+ crypt_pw = crypt_r(passwd, hash, &buffer);
+ apr_cpystrn(sample, crypt_pw, sizeof(sample) - 1);
#else
+ /* XXX if this is a threaded build, we should hold a mutex
+ * around the next two lines... but note that on some
+ * platforms (e.g., Solaris, HP-UX) crypt() returns a
+ * pointer to thread-specific data
+ */
crypt_pw = crypt(passwd, hash);
apr_cpystrn(sample, crypt_pw, sizeof(sample) - 1);
#endif