From 69d1af357b9a62e588590d24798ee1ce6c17777c Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Sat, 29 Apr 2006 09:58:17 +0000 Subject: [PATCH] use MHash to generate NT password hash --- lam/HISTORY | 2 + lam/docs/devel/mod_ext.htm | 55 +++++++ lam/docs/devel/mod_index.htm | 2 + lam/docs/devel/modules-specification.htm | 26 +++- lam/lib/baseModule.inc | 13 ++ lam/lib/createntlm.inc | 187 +---------------------- lam/lib/modules.inc | 21 +++ lam/lib/modules/posixAccount.inc | 19 ++- lam/lib/modules/sambaAccount.inc | 2 + lam/lib/modules/sambaSamAccount.inc | 2 + lam/templates/login.php | 11 +- 11 files changed, 140 insertions(+), 200 deletions(-) create mode 100644 lam/docs/devel/mod_ext.htm diff --git a/lam/HISTORY b/lam/HISTORY index 6e5a53ba..ced3adda 100644 --- a/lam/HISTORY +++ b/lam/HISTORY @@ -2,6 +2,8 @@ - security enhancements: session timeout, logging, host restrictions - fixed bugs: -> PDF creation bug when GID translation is activated (1477111) + -> allow "@" in passwords (1477878) + -> Samba 2/3: fixed NT hashes 12.04.2006 1.0.1 diff --git a/lam/docs/devel/mod_ext.htm b/lam/docs/devel/mod_ext.htm new file mode 100644 index 00000000..a0a84cd7 --- /dev/null +++ b/lam/docs/devel/mod_ext.htm @@ -0,0 +1,55 @@ + + + + Module HowTo - Defining required extensions + + + +
+

Module HowTo - Defining required extensions
+

+

+Your account module might require special PHP extensions. LAM can check +this for you and display an error message at the login page.
+
+
+
You will need to implement the function getRequiredExtensions() or use meta['extensions'].
+
+Example:
+
+The posixAccount module needs +to generate password hashes. Therefore it needs the MHash extension.
+
+ + + + + + +
    /**
+    * Returns meta data that is interpreted by parent +class
+    *
+    * @return array array with meta data
+    */
+    function +get_metaData() {
+        $return = array();
+        // PHP extensions
+        $return["extensions"] = +array("mhash");
+        [...]
+
+
+
+
+ +

+
+
+ + diff --git a/lam/docs/devel/mod_index.htm b/lam/docs/devel/mod_index.htm index 4d6d0fd4..64958a61 100644 --- a/lam/docs/devel/mod_index.htm +++ b/lam/docs/devel/mod_index.htm @@ -51,6 +51,8 @@ existing modules.

4. Defining the RDN


+

5. Defining required PHP extensions

+

diff --git a/lam/docs/devel/modules-specification.htm b/lam/docs/devel/modules-specification.htm index 24777678..d7fa132d 100644 --- a/lam/docs/devel/modules-specification.htm +++ b/lam/docs/devel/modules-specification.htm @@ -515,8 +515,22 @@ internal data structures.
is an hash array (identifier => array(values))  with all values of an account profile.

-


-

+

2.1.20. getRequiredExtensions*

+
+ + + + + + +
function getRequiredExtensions()
+
+
+This function returns a list of PHP extensions (e.g. mhash) which are +needed by this module.
+
+


2.2. Functions which are called inside of an account container
@@ -1442,6 +1456,14 @@ return value of get_uploadColumns().
the return value of get_uploadPreDepends().

+

6.15 getRequiredExtensions()
+

+"extensions" => array()
+
+
Example: array('mhash')
+
attributes); for ($i=0; $imeta['objectClasses']) && is_array($this->meta['objectClasses'])) return $this->meta['objectClasses']; else return array(); } + + /** + * Returns a list of required PHP extensions. + * + * @return array extensions + */ + function getRequiredExtensions() { + if (isset($this->meta['extensions']) && is_array($this->meta['extensions'])) return $this->meta['extensions']; + else return array(); + } } diff --git a/lam/lib/createntlm.inc b/lam/lib/createntlm.inc index 0cf2ecbe..d3e81b39 100644 --- a/lam/lib/createntlm.inc +++ b/lam/lib/createntlm.inc @@ -329,192 +329,7 @@ var $sbox = array(array(array(14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5 * @return string hash value */ function nthash($password = "") { - $password = substr($password,0,128); - $password2 = ""; - for ($i = 0; $i < strlen($password); $i++) $password2 .= $password[$i] . chr(0); - $password = $password2; - $hex = $this->mdfour($password); - for ($i = 0; $i < sizeof($hex); $i++) { - $hex[$i] = sprintf("%02X", $hex[$i]); - } - return join("", $hex); - } - - # Support functions - # Ported from SAMBA/source/lib/md4.c:F,G and H respectfully - function F($X, $Y, $Z) { - $ret = (($X&$Y) | ((~((int)$X))&$Z)); - if ($this->x($ret) > 4294967296) { - $ret = (2*4294967296) - $this->x($ret); - } - return $ret; - } - - function G($X, $Y, $Z) { - return ($X&$Y) | ($X&$Z) | ($Y&$Z); - } - - function H($X, $Y, $Z) { - return $X^$Y^$Z; - } - - # Ported from SAMBA/source/lib/md4.c:mdfour - function mdfour($in) { - $in = unpack("C*",$in); - $in = array_values($in); - $b = sizeof($in) * 8; - $A = array(0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476); - while (sizeof($in) > 64 ) { - $M = $this->copy64($in); - $this->mdfour64($A[0], $A[1], $A[2], $A[3], $M); - $new_in = array(); - for ($i = 64; $i < sizeof($in); $i++) $new_in[] = $in[$i]; - $in = $new_in; - } - $buf = $in; - $buf[] = 0x80; - for ($i = sizeof($buf) - 1; $i < 127; $i++) $buf[] = 0; - if ( sizeof($in) <= 55 ) { - $temp = $this->copy4($b); - $buf[56] = $temp[0]; - $buf[57] = $temp[1]; - $buf[58] = $temp[2]; - $buf[59] = $temp[3]; - $M = $this->copy64($buf); - $this->mdfour64($A[0], $A[1], $A[2], $A[3], $M); - } - else { - $temp = $this->copy4($b); - $buf[120] = $temp[0]; - $buf[121] = $temp[1]; - $buf[122] = $temp[2]; - $buf[123] = $temp[3]; - $M = $this->copy64($buf); - $this->mdfour64($A[0], $A[1], $A[2], $A[3], $M); - $temp = array(); - for ($i = 64; $i < sizeof($buf); $i++) $temp[] = $buf[$i]; - $M = $this->copy64($temp); - $this->mdfour64($A[0], $A[1], $A[2], $A[3], $M); - } - $out = array(); - $temp = $this->copy4($A[0]); - for ($i = 0; $i < 4; $i++) $out[] = $temp[$i]; - $temp = $this->copy4($A[1]); - for ($i = 0; $i < 4; $i++) $out[] = $temp[$i]; - $temp = $this->copy4($A[2]); - for ($i = 0; $i < 4; $i++) $out[] = $temp[$i]; - $temp = $this->copy4($A[3]); - for ($i = 0; $i < 4; $i++) $out[] = $temp[$i]; - return $out; - } - - # Ported from SAMBA/source/lib/md4.c:copy4 - function copy4($x) { - $out = array(); - $out[0] = $x&0xFF; - $out[1] = $this->unsigned_shift_r($x, 8)&0xFF; - $out[2] = $this->unsigned_shift_r($x, 16)&0xFF; - $out[3] = $this->unsigned_shift_r($x, 24)&0xFF; - return $out; - } - - # Ported from SAMBA/source/lib/md4.c:copy64 - function copy64($in) { - for ($i = 0; $i < 16; $i++) { - $M[$i] = ($in[$i*4+3]<<24) | ($in[$i*4+2]<<16) | ($in[$i*4+1]<<8) | ($in[$i*4+0]<<0); - } - return $M; - } - - # Ported from SAMBA/source/lib/md4.c:mdfour64 - function mdfour64(&$A, &$B, &$C, &$D, $M) { - $X = array(); - for ($i = 0; $i < 16; $i++) $X[] = $M[$i]; - $AA=$A; - $BB=$B; - $CC=$C; - $DD=$D; - $this->ROUND1($A,$B,$C,$D, 0, 3, $X); - $this->ROUND1($D,$A,$B,$C, 1, 7, $X); - $this->ROUND1($C,$D,$A,$B, 2, 11, $X); - $this->ROUND1($B,$C,$D,$A, 3, 19, $X); - $this->ROUND1($A,$B,$C,$D, 4, 3, $X); $this->ROUND1($D,$A,$B,$C, 5, 7, $X); - $this->ROUND1($C,$D,$A,$B, 6, 11, $X); $this->ROUND1($B,$C,$D,$A, 7, 19, $X); - $this->ROUND1($A,$B,$C,$D, 8, 3, $X); $this->ROUND1($D,$A,$B,$C, 9, 7, $X); - $this->ROUND1($C,$D,$A,$B, 10, 11, $X); $this->ROUND1($B,$C,$D,$A, 11, 19, $X); - $this->ROUND1($A,$B,$C,$D, 12, 3, $X); $this->ROUND1($D,$A,$B,$C, 13, 7, $X); - $this->ROUND1($C,$D,$A,$B, 14, 11, $X); $this->ROUND1($B,$C,$D,$A, 15, 19, $X); - $this->ROUND2($A,$B,$C,$D, 0, 3, $X); $this->ROUND2($D,$A,$B,$C, 4, 5, $X); - $this->ROUND2($C,$D,$A,$B, 8, 9, $X); $this->ROUND2($B,$C,$D,$A, 12, 13, $X); - $this->ROUND2($A,$B,$C,$D, 1, 3, $X); $this->ROUND2($D,$A,$B,$C, 5, 5, $X); - $this->ROUND2($C,$D,$A,$B, 9, 9, $X); $this->ROUND2($B,$C,$D,$A, 13, 13, $X); - $this->ROUND2($A,$B,$C,$D, 2, 3, $X); $this->ROUND2($D,$A,$B,$C, 6, 5, $X); - $this->ROUND2($C,$D,$A,$B, 10, 9, $X); $this->ROUND2($B,$C,$D,$A, 14, 13, $X); - $this->ROUND2($A,$B,$C,$D, 3, 3, $X); $this->ROUND2($D,$A,$B,$C, 7, 5, $X); - $this->ROUND2($C,$D,$A,$B, 11, 9, $X); $this->ROUND2($B,$C,$D,$A, 15, 13, $X); - $this->ROUND3($A,$B,$C,$D, 0, 3, $X); $this->ROUND3($D,$A,$B,$C, 8, 9, $X); - $this->ROUND3($C,$D,$A,$B, 4, 11, $X); $this->ROUND3($B,$C,$D,$A, 12, 15, $X); - $this->ROUND3($A,$B,$C,$D, 2, 3, $X); $this->ROUND3($D,$A,$B,$C, 10, 9, $X); - $this->ROUND3($C,$D,$A,$B, 6, 11, $X); $this->ROUND3($B,$C,$D,$A, 14, 15, $X); - $this->ROUND3($A,$B,$C,$D, 1, 3, $X); $this->ROUND3($D,$A,$B,$C, 9, 9, $X); - $this->ROUND3($C,$D,$A,$B, 5, 11, $X); $this->ROUND3($B,$C,$D,$A, 13, 15, $X); - $this->ROUND3($A,$B,$C,$D, 3, 3, $X); $this->ROUND3($D,$A,$B,$C, 11, 9, $X); - $this->ROUND3($C,$D,$A,$B, 7, 11, $X); $this->ROUND3($B,$C,$D,$A, 15, 15, $X); - - $A = $this->add32(array($A, $AA)); $B = $this->add32(array($B, $BB)); - $C = $this->add32(array($C, $CC)); $D = $this->add32(array($D, $DD)); - } - - # Needed? because perl seems to choke on overflowing when doing bitwise - # operations on numbers larger than 32 bits. Well, it did on my machine =) - function add32($v) { - for ($i = 0; $i < sizeof($v); $i++) { - $v[$i] = array($this->unsigned_shift_r(($v[$i]&0xffff0000), 16), ($v[$i]&0xffff)); - } - for ($i = 0; $i < sizeof($v); $i++) { - $sum[0] += $v[$i][0]; - $sum[1] += $v[$i][1]; - } - $sum[0] += ($sum[1]&0xffff0000)>>16; - $sum[1] &= 0xffff; - $sum[0] &= 0xffff; - $ret = ($sum[0]<<16) | $sum[1]; - if ($this->x($ret) > 4294967296) { - $ret = (2*4294967296) - $this->x($ret); - } - return $ret; - } - - # Ported from SAMBA/source/lib/md4.c:ROUND1 - function ROUND1(&$a,$b,$c,$d,$k,$s,$X) { - $a = $this->md4lshift($this->add32(array($a, $this->F($b,$c,$d), $X[$k])), $s); - return $a; - } - - # Ported from SAMBA/source/lib/md4.c:ROUND2 - function ROUND2(&$a,$b,$c,$d,$k,$s,$X) { - $a = $this->md4lshift($this->add32(array($a, $this->G($b,$c,$d), $X[$k] + 0x5A827999)), $s); - return $a; - } - - # Ported from SAMBA/source/lib/md4.c:ROUND3 - function ROUND3(&$a,$b,$c,$d,$k,$s,$X) { - $a = $this->md4lshift($this->add32(array($a + $this->H($b,$c,$d) + $X[$k] + 0x6ED9EBA1)), $s); - return $a; - } - - # Ported from SAMBA/source/lib/md4.c:lshift - # Renamed to prevent clash with SAMBA/source/libsmb/smbdes.c:lshift - function md4lshift($x, $s) { - $x &= 0xFFFFFFFF; - if ($this->x($x) > 4294967296) { - $x = (2*4294967296) - $this->x($x); - } - $ret = ((($x<<$s)&0xFFFFFFFF) | $this->unsigned_shift_r($x, (32-$s))); - if ($this->x($ret) > 4294967296) { - $ret = (2*4294967296) - $this->x($ret); - } - return $ret; + return strtoupper(bin2hex(mhash(MHASH_MD4, iconv("UTF-8","UTF-16LE",$password)))); } /** diff --git a/lam/lib/modules.inc b/lam/lib/modules.inc index d5a01033..d50fa8af 100644 --- a/lam/lib/modules.inc +++ b/lam/lib/modules.inc @@ -528,6 +528,27 @@ function doUploadPostActions($scope, $data, $ids, $failed) { return $return; } +/** +* Returns true if the module is a base module +* +* @return array required extensions +*/ +function getRequiredExtensions() { + $extList = array(); + $scopes = $_SESSION['config']->get_ActiveTypes(); + for ($i = 0; $i < sizeof($scopes); $i++) { + $mods = $_SESSION['config']->get_AccountModules($scopes[$i]); + for ($m = 0; $m < sizeof($mods); $m++) { + $module = new $mods[$m]($scopes[$i]); + $ext = $module->getRequiredExtensions(); + for ($e = 0; $e < sizeof($ext); $e++) { + if (!in_array($ext[$e], $extList)) $extList[] = $ext[$e]; + } + } + } + return $extList; +} + /** * Takes a list of meta-HTML elements and prints the equivalent HTML output. * diff --git a/lam/lib/modules/posixAccount.inc b/lam/lib/modules/posixAccount.inc index bba40c9a..27b6dcfd 100644 --- a/lam/lib/modules/posixAccount.inc +++ b/lam/lib/modules/posixAccount.inc @@ -125,6 +125,8 @@ class posixAccount extends baseModule { $return["RDN"] = array("uid" => "normal", "cn" => "low"); // managed object classes $return['objectClasses'] = array('posixAccount'); + // PHP extensions + $return['extensions'] = array('mhash'); // profile checks $return['profile_checks']['posixAccount_homeDirectory'] = array('type' => 'ext_preg', 'regex' => 'homeDirectory', 'error_message' => $this->messages['homeDirectory'][0]); @@ -583,7 +585,7 @@ class posixAccount extends baseModule { $this->attributes['homeDirectory'][0] = $post['homeDirectory']; $this->attributes['loginShell'][0] = $post['loginShell']; if (isset($post['gecos'])) $this->attributes['gecos'][0] = $post['gecos']; - if ($post['createhomedir']) $this->createhomedir = true; + if (isset($post['createhomedir'])) $this->createhomedir = true; else $this->createhomedir = false; if ($this->orig['uid'][0]!='' && $post['uid']!=$this->attributes['uid'][0]) $triggered_messages['uid'][] = $this->messages['uid'][0]; @@ -672,30 +674,31 @@ class posixAccount extends baseModule { if ( !get_preg($this->attributes['homeDirectory'][0], 'homeDirectory' )) $triggered_messages['homeDirecotry'][] = $this->messages['homeDirectory'][0]; } - if (($post['userPassword_lock'] && $post['userPassword_invalid']) || ($post['userPassword_nopassword'] && $post['userPassword_invalid'])) { + if ((isset($post['userPassword_lock']) && isset($post['userPassword_invalid'])) || + (isset($post['userPassword_nopassword']) && isset($post['userPassword_invalid']))) { // found invalid password parameter combination $triggered_messages['userPassword'][] = $this->messages['userPassword'][3]; } else { - if ($post['userPassword_nopassword']) { + if (isset($post['userPassword_nopassword'])) { $this->userPassword_nopassword=true; $this->userPassword_invalid=false; $this->attributes['userPassword'][0] = ''; $post['userPassword2'] = ''; - if ($post['userPassword_lock']) + if (isset($post['userPassword_lock'])) $this->userPassword_lock=true; else $this->userPassword_lock=false; } else { $this->userPassword_nopassword=false; - if ($post['userPassword_invalid']) { + if (isset($post['userPassword_invalid'])) { $this->userPassword_invalid=true; $this->userPassword_lock=false; $post['userPassword2'] = ''; } else { $this->userPassword_invalid=false; - if ($post['genpass']) $this->attributes['userPassword'][0] = genpasswd(); + if (isset($post['genpass'])) $this->attributes['userPassword'][0] = genpasswd(); elseif ($_SESSION[$this->base]->isNewAccount) { if ($post['userPassword'] != $post['userPassword2']) $triggered_messages['userPassword'][] = $this->messages['userPassword'][0]; @@ -703,7 +706,7 @@ class posixAccount extends baseModule { if (!get_preg($this->attributes['userPassword'][0], 'password')) $triggered_messages['userPassword'][] = $this->messages['userPassword'][1]; } - if ($post['userPassword_lock']) $this->userPassword_lock=true; + if (isset($post['userPassword_lock'])) $this->userPassword_lock=true; else $this->userPassword_lock=false; } } @@ -841,7 +844,7 @@ class posixAccount extends baseModule { function display_html_attributes(&$post) { // check password format if called the first time if (!isset($this->userPassword_invalid)) { - if ($this->attributes['userPassword'][0]) { + if (isset($this->attributes['userPassword'][0])) { if ($this->attributes['userPassword'][0] == '*') $this->userPassword_invalid = true; else $this->userPassword_invalid = false; if (pwd_is_enabled($this->attributes['userPassword'][0])) $this->userPassword_lock = false; diff --git a/lam/lib/modules/sambaAccount.inc b/lam/lib/modules/sambaAccount.inc index a7dc75fb..d9d63fa3 100644 --- a/lam/lib/modules/sambaAccount.inc +++ b/lam/lib/modules/sambaAccount.inc @@ -107,6 +107,8 @@ class sambaAccount extends baseModule { $return['dependencies'] = array('depends' => array('posixAccount'), 'conflicts' => array()); // managed object classes $return['objectClasses'] = array('sambaAccount'); + // PHP extensions + $return['extensions'] = array('mhash'); // profile options if ($this->get_scope() == 'user') { // set Unix password for Samba diff --git a/lam/lib/modules/sambaSamAccount.inc b/lam/lib/modules/sambaSamAccount.inc index 9c8d08b6..31872930 100644 --- a/lam/lib/modules/sambaSamAccount.inc +++ b/lam/lib/modules/sambaSamAccount.inc @@ -126,6 +126,8 @@ class sambaSamAccount extends baseModule { $return['dependencies'] = array('depends' => array('posixAccount'), 'conflicts' => array()); // managed object classes $return['objectClasses'] = array('sambaSamAccount'); + // PHP extensions + $return['extensions'] = array('mhash'); // profile checks $return['profile_checks']['sambaSamAccount_smbhome'] = array( 'type' => 'ext_preg', diff --git a/lam/templates/login.php b/lam/templates/login.php index c18e31cb..5ebcd929 100644 --- a/lam/templates/login.php +++ b/lam/templates/login.php @@ -179,10 +179,13 @@ function display_LoginPage($config_object) {


4.3."); - echo "

"; + // check extensions + $extList = getRequiredExtensions(); + for ($i = 0; $i < sizeof($extList); $i++) { + if (!extension_loaded($extList[$i])) { + StatusMessage("ERROR", _("A required extension is missing!"), $extList[$i]); + echo "
"; + } } ?>