summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGlenn Strauss <gstrauss@gluelogic.com>2016-08-20 20:55:17 -0400
committerGlenn Strauss <gstrauss@gluelogic.com>2016-08-21 01:49:09 -0400
commit65efc2eda8419e4bba016df1b77783bb55c2b269 (patch)
tree7f4b3595927bdccb304e4e865b18bbb2f25f78cd
parent9e7083582df55e2d2fd0e4173adc11a637f2f376 (diff)
downloadlighttpd-git-65efc2eda8419e4bba016df1b77783bb55c2b269.tar.gz
[mod_auth] support CRYPT-MD5-NTLM algorithm (fixes #1743)
(based on patch submitted in #1743) (minimally tested using example in #1743 with password 'test') x-ref: "[PATCH] Add support for CRYPT-MD5-NTLM" https://redmine.lighttpd.net/issues/1743
-rw-r--r--src/mod_authn_file.c69
1 files changed, 63 insertions, 6 deletions
diff --git a/src/mod_authn_file.c b/src/mod_authn_file.c
index 9609764f..33c6d48e 100644
--- a/src/mod_authn_file.c
+++ b/src/mod_authn_file.c
@@ -18,6 +18,7 @@
#ifdef USE_OPENSSL
#include "base64.h"
+#include <openssl/md4.h>
#include <openssl/sha.h>
#endif
@@ -623,7 +624,7 @@ static handler_t mod_authn_file_htpasswd_basic(server *srv, connection *con, voi
mod_authn_file_patch_connection(srv, con, p);
rc = mod_authn_file_htpasswd_get(srv, p->conf.auth_htpasswd_userfile, username, password);
if (0 == rc) {
- char sample[120];
+ char sample[256];
rc = -1;
if (!strncmp(password->ptr, APR1_ID, strlen(APR1_ID))) {
/*
@@ -645,12 +646,68 @@ static handler_t mod_authn_file_htpasswd_basic(server *srv, connection *con, voi
#if defined(HAVE_CRYPT_R)
struct crypt_data crypt_tmp_data;
crypt_tmp_data.initialized = 0;
- crypted = crypt_r(pw, password->ptr, &crypt_tmp_data);
- #else
- crypted = crypt(pw, password->ptr);
#endif
- if (NULL != crypted) {
- rc = strcmp(password->ptr, crypted);
+ #ifdef USE_OPENSSL /* (for MD4_*() (e.g. MD4_Update())) */
+ if (0 == memcmp(password->ptr, CONST_STR_LEN("$1+ntlm$"))) {
+ /* CRYPT-MD5-NTLM algorithm
+ * This algorithm allows for the construction of (slight more)
+ * secure, salted password hashes from an environment where only
+ * legacy NTLM hashes are available and where it is not feasible
+ * to re-hash all the passwords with the MD5-based crypt(). */
+ /* Note: originally, LM password were limited to 14 chars.
+ * NTLM passwords limited to 127 chars, and encoding to UCS-2LE
+ * requires double that, so sample[256] buf is large enough.
+ * Prior sample[120] size likely taken from apr_md5_encode(). */
+ char *b = password->ptr+sizeof("$1+ntlm$")-1;
+ char *e = strchr(b, '$');
+ size_t slen = (NULL != e) ? (size_t)(e - b) : sizeof(sample);
+ size_t pwlen = strlen(pw) * 2;
+ if (slen < sizeof(sample) - (sizeof("$1$")-1)
+ && pwlen < sizeof(sample)) {
+ /* compute NTLM hash and convert to lowercase hex chars
+ * (require lc hex chars from li_tohex()) */
+ char ntlmhash[16];
+ char ntlmhex[33]; /*(sizeof(ntlmhash)*2 + 1)*/
+ MD4_CTX c;
+ MD4_Init(&c);
+ if (pwlen) {
+ /*(reuse sample buffer to encode pw into UCS-2LE)
+ *(Note: assumes pw input in ISO-8859-1) */
+ /*(buffer sizes checked above)*/
+ for (int i=0; i < (int)pwlen; i+=2) {
+ sample[i] = pw[(i >> 1)];
+ sample[i+1] = 0;
+ }
+ MD4_Update(&c, (unsigned char *)sample, pwlen);
+ }
+ MD4_Final((unsigned char *)ntlmhash, &c);
+ li_tohex(ntlmhex,sizeof(ntlmhex),ntlmhash,sizeof(ntlmhash));
+
+ /*(reuse sample buffer for salt (FYI: expect slen == 8))*/
+ memcpy(sample, CONST_STR_LEN("$1$"));
+ memcpy(sample+sizeof("$1$")-1, b, slen);
+ #if defined(HAVE_CRYPT_R)
+ crypted = crypt_r(ntlmhex, sample, &crypt_tmp_data);
+ #else
+ crypted = crypt(ntlmhex, sample);
+ #endif
+ if (NULL != crypted
+ && 0 == strncmp(crypted, "$1$", sizeof("$1$")-1)) {
+ rc = strcmp(b, crypted+3); /*skip crypted "$1$" prefix*/
+ }
+ }
+ }
+ else
+ #endif
+ {
+ #if defined(HAVE_CRYPT_R)
+ crypted = crypt_r(pw, password->ptr, &crypt_tmp_data);
+ #else
+ crypted = crypt(pw, password->ptr);
+ #endif
+ if (NULL != crypted) {
+ rc = strcmp(password->ptr, crypted);
+ }
}
}
#endif