From c1f599f48c1190c58f90cafd0edbeb9282d19192 Mon Sep 17 00:00:00 2001
From: Jared Hancock <jared@osticket.com>
Date: Mon, 31 Mar 2014 17:34:10 -0500
Subject: [PATCH] Add flag to forbid passwd changes by user

Useful if the staff members administratively configure a static password
that the user should never change.
---
 include/class.client.php                      |  8 +----
 include/class.user.php                        | 32 +++++++++++--------
 include/client/profile.inc.php                |  2 ++
 include/staff/templates/user-account.tmpl.php |  3 ++
 pwreset.php                                   |  4 +++
 5 files changed, 29 insertions(+), 20 deletions(-)

diff --git a/include/class.client.php b/include/class.client.php
index 707418456..3ad25fa39 100644
--- a/include/class.client.php
+++ b/include/class.client.php
@@ -306,12 +306,6 @@ class ClientAccount extends UserAccount {
         unset($_SESSION['_client']['reset-token']);
     }
 
-    function getInfo() {
-        $base = parent::getInfo();
-        $base['tz_offset'] = $this->timezone;
-        return $base;
-    }
-
     function update($vars, &$errors) {
         $rtoken = $_SESSION['_client']['reset-token'];
         if ($vars['passwd1'] || $vars['passwd2'] || $vars['cpasswd'] || $rtoken) {
@@ -362,7 +356,7 @@ class ClientAccount extends UserAccount {
             $info = array('password' => $vars['passwd1']);
             Signal::send('auth.pwchange', $this, $info);
             $this->cancelResetTokens();
-            $this->_clearStatus(self::PASSWD_RESET_REQUIRED);
+            $this->clearStatus(self::REQUIRE_PASSWD_RESET);
         }
 
         return $this->save();
diff --git a/include/class.user.php b/include/class.user.php
index ba4a19401..97335063c 100644
--- a/include/class.user.php
+++ b/include/class.user.php
@@ -547,7 +547,8 @@ class UserAccount extends UserAccountModel {
 
     const CONFIRMED             = 0x0001;
     const LOCKED                = 0x0002;
-    const PASSWD_RESET_REQUIRED = 0x0004;
+    const REQUIRE_PASSWD_RESET  = 0x0004;
+    const FORBID_PASSWD_RESET   = 0x0008;
 
     protected function hasStatus($flag) {
         return 0 !== ($this->get('status') & $flag);
@@ -580,12 +581,16 @@ class UserAccount extends UserAccountModel {
     }
 
     function forcePasswdReset() {
-        $this->setStatus(self::PASSWD_RESET_REQUIRED);
+        $this->setStatus(self::REQUIRE_PASSWD_RESET);
         return $this->save();
     }
 
     function isPasswdResetForced() {
-        return $this->hasStatus(self::PASSWD_RESET_REQUIRED);
+        return $this->hasStatus(self::REQUIRE_PASSWD_RESET);
+    }
+
+    function isPasswdResetEnabled() {
+        return !$this->hasStatus(self::FORBID_PASSWD_RESET);
     }
 
     function hasPassword() {
@@ -737,15 +742,16 @@ class UserAccount extends UserAccountModel {
         }
 
         // Set flags
-        if ($vars['pwreset-flag'])
-            $this->setStatus(self::PASSWD_RESET_REQUIRED);
-        else
-            $this->clearStatus(self::PASSWD_RESET_REQUIRED);
-
-        if ($vars['locked-flag'])
-            $this->setStatus(self::LOCKED);
-        else
-            $this->clearStatus(self::LOCKED);
+        foreach (array(
+                'pwreset-flag'=>        self::REQUIRE_PASSWD_RESET,
+                'locked-flag'=>         self::LOCKED,
+                'forbid-pwchange-flag'=> self::FORBID_PASSWD_RESET
+        ) as $ck=>$flag) {
+            if ($vars[$ck])
+                $this->setStatus($flag);
+            else
+                $this->clearStatus($flag);
+        }
 
         return $this->save(true);
     }
@@ -794,7 +800,7 @@ class UserAccount extends UserAccountModel {
             $account->set('passwd', Password::hash($vars['passwd1']));
             $account->setStatus(self::CONFIRMED);
             if ($vars['pwreset-flag'])
-                $account->setStatus(self::PASSWD_RESET_REQUIRED);
+                $account->setStatus(self::REQUIRE_PASSWD_RESET);
         }
 
         $account->save(true);
diff --git a/include/client/profile.inc.php b/include/client/profile.inc.php
index d5651031c..8586c3976 100644
--- a/include/client/profile.inc.php
+++ b/include/client/profile.inc.php
@@ -50,6 +50,7 @@ if ($acct = $thisclient->getAccount()) {
         <em>(Current Time: <strong><?php echo Format::date($cfg->getDateTimeFormat(),Misc::gmtime(),$info['tz_offset'],$info['dst']); ?></strong>)</em>
     </td>
 </tr>
+<?php if ($acct->isPasswdResetEnabled()) { ?>
 <tr>
     <td colspan=2">
         <div><hr><h3>Access Credentials</h3></div>
@@ -85,6 +86,7 @@ if ($acct = $thisclient->getAccount()) {
     </td>
 </tr>
 <?php } ?>
+<?php } ?>
 </table>
 <hr>
 <p style="text-align: center;">
diff --git a/include/staff/templates/user-account.tmpl.php b/include/staff/templates/user-account.tmpl.php
index 5a08e8e4c..8304d8afa 100644
--- a/include/staff/templates/user-account.tmpl.php
+++ b/include/staff/templates/user-account.tmpl.php
@@ -143,6 +143,9 @@ if ($info['error']) {
                    <div><input type="checkbox" name="pwreset-flag" value="1" <?php
                     echo $account->isPasswdResetForced() ?
                     'checked="checked"' : ''; ?>> Password Reset Required</div>
+                   <div><input type="checkbox" name="forbid-pwchange-flag" value="1" <?php
+                    echo !$account->isPasswdResetEnabled() ?
+                    'checked="checked"' : ''; ?>> User Cannot Change Password</div>
                 </td>
             </tr>
         </tbody>
diff --git a/pwreset.php b/pwreset.php
index 6fb51b487..7b2a636e5 100644
--- a/pwreset.php
+++ b/pwreset.php
@@ -19,6 +19,10 @@ if($_POST) {
                 if (!$acct->hasPassword()) {
                     $banner = 'Unable to reset password. Contact your administrator';
                 }
+                elseif (!$acct->isPasswdResetEnabled()) {
+                    $banner = 'Password reset is not enabled for your account. '
+                        .'Contact your administrator';
+                }
                 elseif (!$acct->sendResetEmail()) {
                     $inc = 'pwreset.sent.php';
                 }
-- 
GitLab