<?php include("nocache.php"); ?>
<html>
<head>
<title>
PASSWORD CHANGE PAGE
</title>
</head>
<body>
<link
rel = stylesheet
type = text/css
href = /style/mystyle.css
>
<h2>
Password change page for NIS, LDAP and NT accounts
</h2>
<p>
<?php
error_reporting(E_ALL);
define ("ALL", 1);
define ("NIS", 2);
define ("LDAP", 3);
define ("NT", 4);
define ("MAX_NIS_PASSLEN", 8);
define ("MAX_LDAP_PASSLEN", 12);
define ("MAX_NT_PASSLEN", 12);
define ("MAX_MAX_PASSLEN",
max(array(MAX_NIS_PASSLEN, MAX_LDAP_PASSLEN, MAX_NT_PASSLEN)));
define ("CRACKLIB_PREFIX", "/usr/lib/cracklib_dict");
$accounts = array(
NIS => array(
"name" => "NIS",
"what" => "Change " .
"NIS " .
"(Network Information Services)" .
"account",
"old" => "n_old",
"new1" => "n_new",
"new2" => "n_new_ver",
"validate_func" => "nis_validate",
"chpasswd_func" => "nis_chpasswd",
"description" => "Email account login. Also used to " .
"access all UNIX-based services, such " .
"as NFS exports."
),
LDAP => array(
"name" => "LDAP",
"what" => "Change " .
"LDAP " .
"(Lightweight Directory Access Protocol) " .
"account",
"old" => "l_old",
"new1" => "l_new",
"new2" => "l_new_ver",
"validate_func" => "ldap_validate",
"chpasswd_func" => "ldap_chpasswd",
"description" => "Used for Intranet portal and related " .
"functions, such as internal mailing " .
"lists and email aliases"
),
NT => array(
"name" => "Windows NT",
"what" => "Change " .
"NT " .
"(Windows NT domain) " .
"account",
"old" => "w_old",
"new1" => "w_new",
"new2" => "w_new_ver",
"validate_func" => "nt_validate",
"chpasswd_func" => "nt_chpasswd",
"description" => "Login required for Windows printing, " .
"networked files, home directory and VPN."
),
ALL => array(
"name" => "(All accounts)",
"what" => "Change All accounts at once",
"old" => "a_old",
"new1" => "a_new",
"new2" => "a_new_ver",
"validate_func" => "all_validate",
"chpasswd_func" => "all_chpasswd",
"description" => "Changes all three accounts at once. " .
"Requires that all old passwords are the " .
"same. If your accounts use more than " .
"one password you will be notified and " .
"must fill out each individual account " .
"below.<p><em>Using any of these fields " .
"causes the individual account fields " .
"below to be ignored. </em>",
"user" => " "
)
);
$errors = array();
$ld_host = "ldap.yourcompany.com";
$ld_base = "o=company,c=us";
$ld_port = 389;
if (!($lc = ldap_connect($ld_host, $ld_port)))
_die("unable to connect to LDAP server");
if (!($lb = ldap_bind($lc)))
_die("anonymous bind to LDAP server failed");
$accounts[LDAP]["user"] = $HTTP_SERVER_VARS["REMOTE_USER"];
$accounts[NT] ["user"] = $accounts[LDAP]["user"];
$accounts[NIS] ["user"] = ldap_get_attr($accounts[LDAP]["user"], "pop3user");
?>
<p>
This page will let you change your Company passwords.
<p>
The following accounts can be changed. Each account has fields next to it
which you can use to enter a new password for that account, and a field in
which you must enter your old account password to authorize the change. <em>
If you leave any of the fields blank for a given account, the remaining fields
will be ignored and the password for it will remain unchanged. </em>
<p>
Select the `submit' button once you have entered new and old passwords for all
the accounts you wish changed.
<p>
<?php
foreach (array(ALL, NIS, LDAP, NT) as $which) {
$account = &$accounts[$which];
sane_assign($account["oldpass"], $HTTP_POST_VARS[$account["old"]]);
sane_assign($account["newpass1"], $HTTP_POST_VARS[$account["new1"]]);
sane_assign($account["newpass2"], $HTTP_POST_VARS[$account["new2"]]);
}
if (isset($HTTP_POST_VARS["submit"])) {
foreach (array(ALL, NIS, LDAP, NT) as $which) {
$old = &$accounts[$which]["oldpass"];
$new1 = &$accounts[$which]["newpass1"];
$new2 = &$accounts[$which]["newpass2"];
if (!$old || !$new1 || !$new2)
continue;
if ($which == ALL)
$using_all = TRUE;
if (!verify($new1, $new2, $which) ||
!sanitize($new1, $which)) {
$new1 = $new2 = NULL;
}
if (!validate($accounts[$which]["user"], $old, $which)) {
$old = NULL;
}
if ($which == ALL)
break;
}
}
if (isset($errors[0])) {
echo("<br><hr>");
display_errors($errors);
}
?>
<hr>
<p>
<form method=post action=<?php echo(basename(__FILE__)) ?>>
<link
rel = stylesheet
type = text/css
href = /share/style/nicetable.css
>
<table
border = 0
cellspacing = 2
cellpadding = 10
width = 98%
align = center
>
<?php
foreach (array(ALL, LDAP, NIS, NT) as $which) {
$account = &$accounts[$which];
?>
<tr>
<td class=bigtablehead colspan=3>
<?php echo($account["what"])?>
<strong>
<em> <?php echo($account["user"])?> </em>
</strong>
</td>
<tr>
<td class=tablelabelcell colspan=3>
<?php echo($account["description"])?>
</td>
<tr>
<td class=tablecell> old password </td>
<td class=tablecell> new password </td>
<td class=tablecell> confirm new password </td>
<tr>
<?php
foreach (array(array("old", "oldpass"),
array("new1", "newpass1"),
array("new2", "newpass2")) as $inputs) {
?>
<td class=tablealtcell>
<input
type = password
size = <?php echo(MAX_MAX_PASSLEN . "\n")?>
maxlength = <?php echo(MAX_MAX_PASSLEN . "\n")?>
name = "<?php echo($account[$inputs[0]])?>"
value = "<?php echo($account[$inputs[1]])?>"
>
</td>
<?php
}
?>
<tr><td colspan=3></td></tr>
<?php
}
?>
</table>
<br>
<p>
<hr>
<p>
<input type=submit name=submit value=submit>
</form>
</html>
<?php
ldap_close($lc);
?>
<?php
function
_die($death_string)
{
$admin_mail = "admin@yourcompany.com";
die("$death_string, " . "please notify " . $admin_mail);
}
function
display_errors($errors)
{
global $errors;
echo("<br><p><strong>\n" .
"The following errors were found in your form data:\n".
"</strong><ul>\n");
foreach ($errors as $current_error)
echo("<li><em>$current_error</em>\n");
echo("</ul>\n" .
"<p>\n" .
"These errors must be corrected, and the form re-submitted, " .
"in order for your password changes to be processed. " .
"For assistance selecting a password, please read " .
"<a href=/XXX/TODO/FIXME> this document</a>. If you believe " .
"these errors are themselves incorrect, please report the " .
"error to <a href=admin@yourcompany.com> " .
"admin@yourcompany.com</a>\n");
}
?>
<?php
function
sane_assign(&$var, &$val)
{
global $errors;
if (strlen($val) > MAX_MAX_PASSLEN) {
array_push($errors,
"One of the form fields you input exceeds the " .
"absolute maximum of " . MAX_MAX_PASSLEN . " " .
"characters; clearing its input field to be safe. ");
$val = NULL;
}
if (ereg("[\"'` ]+", $val)) {
array_push($errors,
"One of your passwords uses characters which " .
"could be used maliciously (those from the set " .
"(\", ', `, space)). Clearing its input fields " .
"to be safe. ");
$val = NULL;
}
$var = $val;
}
XXXTODO
function
ldap_get_attr($uid, $attr)
{
global $ld_base;
global $lc;
if (!($ls = ldap_search($lc, $ld_base, "(uid=$uid)", array("$attr"))))
_die("your LDAP entry failed a search for the $attr attribute");
if (($ln = ldap_count_entries($lc, $ls)) != 1)
_die("your LDAP UID matched an invalid " . $ln . " " . "DNs");
$le = ldap_first_entry($lc, $ls);
$lf = ldap_first_attribute($lc, $le, $lr);
if (!($value = ldap_get_values($lc, $le, $lf)))
_die("unable to get first attribute value for NIS search");
return (array_shift($value));
}
function
verify_crypt_string($crypt_pw, $plain_pw)
{
$salt = substr($crypt_pw, 0, 2);
$crypted = crypt($plain_pw, $salt);
if (!strcmp($crypt_pw, $crypted))
return (TRUE);
else
return (FALSE);
}
function
make_badpass($whichbad)
{
global $errors;
global $using_all;
global $accounts;
$badpass = "old password for $whichbad ";
if ($using_all) $badpass .= " (from {$accounts[ALL]['name']}) ";
$badpass .= "is incorrect.";
return $badpass;
}
function
verify(&$s1, &$s2, $which)
{
global $errors;
global $accounts;
if (strcmp($s1, $s2)) {
array_push($errors, "new passwords given for " .
$accounts[$which]["name"] .
" account do not match");
$s1 = NULL;
return (FALSE);
}
return $s1;
}
?>
<?php
function
validate($u, $p, $which)
{
global $accounts;
if ($p == NULL)
return (FALSE);
return($accounts[$which]["validate_func"]($u, $p));
}
function
sanitize($p, $which)
{
global $errors;
global $accounts;
if ($p == NULL)
return (FALSE);
$dict = crack_opendict(CRACKLIB_PREFIX);
$ret = crack_check($dict, $p);
$ret = crack_getlastmessage();
crack_closedict($dict);
if (!strcmp($ret, "strong password"))
return (TRUE);
else {
array_push($errors, "the new password you supplied for your " .
$accounts[$which]["name"] .
" account is unacceptable (" . $ret . ")");
return (FALSE);
}
}
function
nis_validate($u, $p)
{
global $errors;
if (strlen($p) > MAX_NIS_PASSLEN) {
array_push($errors,
"NIS passwords are not significant after 8 chars");
return (NULL);
}
if (!($nis_domain = yp_get_default_domain()))
_die("couldn't get default NIS domain");
if (!($nis_match = yp_match($nis_domain, "passwd.byname", $u)))
_die("couldn't match NIS username $u in passwd.byname map");
XXXTODO
$crypt_string = explode(":", $nis_match, 3);
$crypt_string = $crypt_string[1];
if (!verify_crypt_string($crypt_string, $p)) {
array_push($errors, make_badpass("NIS"));
return (NULL);
}
return($p);
}
function
ldap_validate($u, $p)
{
global $ld_base;
global $lc;
global $accounts;
global $errors;
$lname = $accounts[LDAP]["user"];
$passvalue = ldap_get_attr($lname, "userPassword");
if (!eregi("^\{(crypt|sha)}(.*$)", $passvalue, $passarr))
_die("invalid LDAP password format encountered");
switch (strtolower($passarr[1])) {
case "crypt":
if (!verify_crypt_string($passarr[2], $p)) {
$err = make_badpass("LDAP-{$passarr[1]}");
array_push($errors, $err);
return(NULL);
}
break;
case "sha":
$hash_result = mhash(MHASH_SHA1, $p);
if ($passarr[2] != base64_encode($hash_result)) {
$err = make_badpass("LDAP-{$passarr[1]}");
array_push($errors, $err);
return(NULL);
}
break;
default:
_die("default switch reached in ldap_validate()");
}
return($p);
}
function
nt_validate($u, $p)
{
global $errors;
$user = escapeshellcmd($u);
$pass = escapeshellcmd($p);
system("/bin/bash -c 'echo -e \"$pass\\n$pass\\n$pass\" | " .
"/usr/local/bin/smbpasswd -U $user -r ro1-pdc -s &>/dev/null'",
$retval);
if ($retval == 0)
return TRUE;
else {
array_push($errors, make_badpass("NT"));
return FALSE;
}
}
function
all_validate($u, $p)
{
global $accounts;
$ret = TRUE;
$keys = array_keys($accounts);
$keys = array_slice($keys, 0, -1);
foreach ($keys as $key) {
$u = &$accounts[$key]["user"];
if (!($accounts[$key]["validate_func"]($u, $p)))
$ret = FALSE;
}
if (!$ret)
return FALSE;
else
return TRUE;
}
?>