packages/ssoinabox-webui/root/usr/local/share/ssoinabox/htdocs/lostpw.php
changeset 3 a044870a9d3d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/packages/ssoinabox-webui/root/usr/local/share/ssoinabox/htdocs/lostpw.php	Fri Jan 11 00:32:54 2013 -0500
@@ -0,0 +1,135 @@
+<?php
+
+require('includes/starthere.php');
+
+if ( !empty($_SERVER['PATH_INFO']) )
+{
+	if ( count($params = explode('/', $_SERVER['PATH_INFO'])) !== 4 )
+	{
+		redirect('/lostpw');
+	}
+	
+	list(,$uid,$timestamp,$token) = $params;
+	
+	try
+	{
+		$do_redirect = true;
+		if ( !preg_match('/^[a-z0-9]{3,32}$/', $uid) ||
+			 !preg_match('/^[a-f0-9]{8}$/', $timestamp) ||
+		  	 !preg_match('/^[a-f0-9]{40}$/', $token) )
+			throw new Exception("Request format is invalid");
+		
+		$ts_dec = hexdec($timestamp);
+		
+		if ( hash_hmac('sha1', "$uid%$ts_dec", $hmac_secret) !== $token )
+			throw new Exception("Request token is invalid");
+		
+		if ( abs(time() - $ts_dec) > (12 * 3600) )
+			throw new Exception("This link has expired. Please request another password reset.");
+		
+		$userinfo = ldap_get_user($uid);
+		
+		// handle a submit?
+		$do_redirect = false;
+		if ( !empty($_POST['password']) )
+		{
+			if ( ($result = test_password($_POST['password'])) !== true )
+				throw new Exception("Your new password $result.");
+			
+			if ( $_POST['password'] !== $_POST['password_confirm'] )
+				throw new Exception("The passwords you entered did not match.");
+			
+			if ( reset_password($uid, $_POST['password']) )
+			{
+				queue_message(E_NOTICE, "Your password has been reset. You can now log into the control panel.");
+				redirect('/lostpw');
+			}
+			else
+			{
+				throw new Exception("Internal error when performing password reset.");
+			}
+		}
+	}
+	catch ( Exception $e )
+	{
+		queue_message(E_ERROR, $e->getMessage());
+		if ( $do_redirect )
+			redirect('/lostpw');
+	}
+	
+	display_template('resetpw', array(
+			'userinfo' => $userinfo
+		));
+	
+	exit;
+}
+
+if ( !empty($_POST['email_or_username']) )
+{
+	try
+	{
+		global $_ldapconn, $ldap_user_basedn;
+		
+		$field = strstr($_POST['email_or_username'], '@') ? 'mail' : 'uid';
+		if ( $field == 'uid' && !preg_match('/^[a-z0-9]{3,32}$/', $_POST['email_or_username']) )
+		{
+			throw new Exception("Invalid username. Usernames can only contain 3-32 a-z and 0-9 (all lowercase) characters.");
+		}
+		
+		$search_filter = sprintf('(&(%s=%s)(objectClass=posixAccount))', $field, ldap_escape($_POST['email_or_username']));
+		$search_result = ldap_search($_ldapconn, $ldap_user_basedn, $search_filter);
+		
+		if ( !$search_result )
+		{
+			throw new Exception(ldap_error($_ldapconn));
+		}
+		
+		if ( ldap_count_entries($_ldapconn, $search_result) == 0 )
+		{
+			throw new Exception("Could not find any accounts that matched that $field.");
+		}
+		else if ( ldap_count_entries($_ldapconn, $search_result) > 1 )
+		{
+			throw new Exception("LDAP search query erroneously returned multiple results.");
+		}
+		
+		$userinfo = ldap_array_cleanup(ldap_get_attributes($_ldapconn, ldap_first_entry($_ldapconn, $search_result)));
+		
+		if ( !isset($userinfo['mail']) )
+		{
+			throw new Exception("No e-mail address is registered to your account. Please contact the administrator to request a password reset.");
+		}
+		
+		$mail_censored = $mail = is_array($userinfo['mail']) ? $userinfo['mail'][ count($userinfo['mail']) - 1 ] : $userinfo['mail'];
+		
+		// smtp_mail($from, $to, $subject, $body, $headers = '')
+		$reset_link = sprintf('http://%s/lostpw/%s/%08x/%s', gethostname(), $userinfo['uid'], time(), hash_hmac('sha1', "{$userinfo['uid']}%" . time(), $hmac_secret));
+		$email_body = parse_template('emails/lostpw', array(
+				'userinfo' => $userinfo
+				, 'reset_link' => $reset_link
+				, 'ip' => $_SERVER['REMOTE_ADDR']
+			));
+			
+		$domainname = strtolower(get_default_kerberos_realm());
+		$mail_result = smtp_mail("accounts@$domainname", $mail, "$domainname password reset", $email_body, "From: $domainname accounts <accounts@$domainname>\r\nTo: {$userinfo['cn']} <$mail>");
+		
+		// censor e-mail address to keep deviants from scraping for it
+		if ( $field == 'uid' && preg_match('/^(.)(.*?)(.)@([a-z\.]+)$/', $mail, $match) )
+			$mail_censored = sprintf('%s%s%s@%s', $match[1], str_repeat('.', strlen($match[2])), $match[3], $match[4]);
+		
+		if ( $mail_result )
+		{
+			queue_message(E_NOTICE, "Password reset instructions have been mailed to $mail_censored.");
+		}
+		else
+		{
+			throw new Exception("Failed to send e-mail.");
+		}
+	}
+	catch ( Exception $e )
+	{
+		queue_message(E_ERROR, $e->getMessage());
+	}
+}
+
+display_template('lostpw');