1f4476bd9SJan Schumann<?php 20489c64bSMoisés Braga Ribeirouse dokuwiki\Utf8\Sort; 3f4476bd9SJan Schumann 4f4476bd9SJan Schumann/** 5f4476bd9SJan Schumann * Plaintext authentication backend 6f4476bd9SJan Schumann * 7f4476bd9SJan Schumann * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 8f4476bd9SJan Schumann * @author Andreas Gohr <andi@splitbrain.org> 9f4476bd9SJan Schumann * @author Chris Smith <chris@jalakai.co.uk> 10f4476bd9SJan Schumann * @author Jan Schumann <js@schumann-it.com> 11f4476bd9SJan Schumann */ 125aa905e9SAndreas Gohrclass auth_plugin_authplain extends DokuWiki_Auth_Plugin 135aa905e9SAndreas Gohr{ 14311f4603SAndreas Gohr /** @var array user cache */ 15311f4603SAndreas Gohr protected $users = null; 16311f4603SAndreas Gohr 17311f4603SAndreas Gohr /** @var array filter pattern */ 185aa905e9SAndreas Gohr protected $pattern = array(); 19f4476bd9SJan Schumann 206c8c1f46SChristopher Smith /** @var bool safe version of preg_split */ 215aa905e9SAndreas Gohr protected $pregsplit_safe = false; 226c8c1f46SChristopher Smith 23f4476bd9SJan Schumann /** 24f4476bd9SJan Schumann * Constructor 25f4476bd9SJan Schumann * 26f4476bd9SJan Schumann * Carry out sanity checks to ensure the object is 27f4476bd9SJan Schumann * able to operate. Set capabilities. 28f4476bd9SJan Schumann * 29f4476bd9SJan Schumann * @author Christopher Smith <chris@jalakai.co.uk> 30f4476bd9SJan Schumann */ 315aa905e9SAndreas Gohr public function __construct() 325aa905e9SAndreas Gohr { 33454d868bSAndreas Gohr parent::__construct(); 34f4476bd9SJan Schumann global $config_cascade; 35f4476bd9SJan Schumann 36f4476bd9SJan Schumann if (!@is_readable($config_cascade['plainauth.users']['default'])) { 37f4476bd9SJan Schumann $this->success = false; 38f4476bd9SJan Schumann } else { 39f4476bd9SJan Schumann if (@is_writable($config_cascade['plainauth.users']['default'])) { 40f4476bd9SJan Schumann $this->cando['addUser'] = true; 41f4476bd9SJan Schumann $this->cando['delUser'] = true; 42f4476bd9SJan Schumann $this->cando['modLogin'] = true; 43f4476bd9SJan Schumann $this->cando['modPass'] = true; 44f4476bd9SJan Schumann $this->cando['modName'] = true; 45f4476bd9SJan Schumann $this->cando['modMail'] = true; 46f4476bd9SJan Schumann $this->cando['modGroups'] = true; 47f4476bd9SJan Schumann } 48f4476bd9SJan Schumann $this->cando['getUsers'] = true; 49f4476bd9SJan Schumann $this->cando['getUserCount'] = true; 50b2fcc742SAnna Dabrowska $this->cando['getGroups'] = true; 51f4476bd9SJan Schumann } 526c8c1f46SChristopher Smith 535aa905e9SAndreas Gohr $this->pregsplit_safe = version_compare(PCRE_VERSION, '6.7', '>='); 54f4476bd9SJan Schumann } 55f4476bd9SJan Schumann 56f4476bd9SJan Schumann /** 57311f4603SAndreas Gohr * Check user+password 58f4476bd9SJan Schumann * 59f4476bd9SJan Schumann * Checks if the given user exists and the given 60f4476bd9SJan Schumann * plaintext password is correct 61f4476bd9SJan Schumann * 62f4476bd9SJan Schumann * @author Andreas Gohr <andi@splitbrain.org> 63311f4603SAndreas Gohr * @param string $user 64311f4603SAndreas Gohr * @param string $pass 65f4476bd9SJan Schumann * @return bool 66f4476bd9SJan Schumann */ 675aa905e9SAndreas Gohr public function checkPass($user, $pass) 685aa905e9SAndreas Gohr { 69f4476bd9SJan Schumann $userinfo = $this->getUserData($user); 70f4476bd9SJan Schumann if ($userinfo === false) return false; 71f4476bd9SJan Schumann 72f4476bd9SJan Schumann return auth_verifyPassword($pass, $this->users[$user]['pass']); 73f4476bd9SJan Schumann } 74f4476bd9SJan Schumann 75f4476bd9SJan Schumann /** 76f4476bd9SJan Schumann * Return user info 77f4476bd9SJan Schumann * 78f4476bd9SJan Schumann * Returns info about the given user needs to contain 79f4476bd9SJan Schumann * at least these fields: 80f4476bd9SJan Schumann * 81f4476bd9SJan Schumann * name string full name of the user 82f4476bd9SJan Schumann * mail string email addres of the user 83f4476bd9SJan Schumann * grps array list of groups the user is in 84f4476bd9SJan Schumann * 85f4476bd9SJan Schumann * @author Andreas Gohr <andi@splitbrain.org> 86311f4603SAndreas Gohr * @param string $user 872046a654SChristopher Smith * @param bool $requireGroups (optional) ignored by this plugin, grps info always supplied 88253d4b48SGerrit Uitslag * @return array|false 89f4476bd9SJan Schumann */ 905aa905e9SAndreas Gohr public function getUserData($user, $requireGroups = true) 915aa905e9SAndreas Gohr { 925aa905e9SAndreas Gohr if ($this->users === null) $this->loadUserData(); 93f4476bd9SJan Schumann return isset($this->users[$user]) ? $this->users[$user] : false; 94f4476bd9SJan Schumann } 95f4476bd9SJan Schumann 96f4476bd9SJan Schumann /** 97f95ecbbfSAngus Gratton * Creates a string suitable for saving as a line 98f95ecbbfSAngus Gratton * in the file database 99f95ecbbfSAngus Gratton * (delimiters escaped, etc.) 100f95ecbbfSAngus Gratton * 101f95ecbbfSAngus Gratton * @param string $user 102f95ecbbfSAngus Gratton * @param string $pass 103f95ecbbfSAngus Gratton * @param string $name 104f95ecbbfSAngus Gratton * @param string $mail 105f95ecbbfSAngus Gratton * @param array $grps list of groups the user is in 106f95ecbbfSAngus Gratton * @return string 107f95ecbbfSAngus Gratton */ 1085aa905e9SAndreas Gohr protected function createUserLine($user, $pass, $name, $mail, $grps) 1095aa905e9SAndreas Gohr { 110f95ecbbfSAngus Gratton $groups = join(',', $grps); 111f95ecbbfSAngus Gratton $userline = array($user, $pass, $name, $mail, $groups); 112f95ecbbfSAngus Gratton $userline = str_replace('\\', '\\\\', $userline); // escape \ as \\ 113f95ecbbfSAngus Gratton $userline = str_replace(':', '\\:', $userline); // escape : as \: 114f95ecbbfSAngus Gratton $userline = join(':', $userline)."\n"; 115f95ecbbfSAngus Gratton return $userline; 116f95ecbbfSAngus Gratton } 117f95ecbbfSAngus Gratton 118f95ecbbfSAngus Gratton /** 119f4476bd9SJan Schumann * Create a new User 120f4476bd9SJan Schumann * 121f4476bd9SJan Schumann * Returns false if the user already exists, null when an error 122f4476bd9SJan Schumann * occurred and true if everything went well. 123f4476bd9SJan Schumann * 124f4476bd9SJan Schumann * The new user will be added to the default group by this 125f4476bd9SJan Schumann * function if grps are not specified (default behaviour). 126f4476bd9SJan Schumann * 127f4476bd9SJan Schumann * @author Andreas Gohr <andi@splitbrain.org> 128f4476bd9SJan Schumann * @author Chris Smith <chris@jalakai.co.uk> 129311f4603SAndreas Gohr * 130311f4603SAndreas Gohr * @param string $user 131311f4603SAndreas Gohr * @param string $pwd 132311f4603SAndreas Gohr * @param string $name 133311f4603SAndreas Gohr * @param string $mail 134311f4603SAndreas Gohr * @param array $grps 135311f4603SAndreas Gohr * @return bool|null|string 136f4476bd9SJan Schumann */ 1375aa905e9SAndreas Gohr public function createUser($user, $pwd, $name, $mail, $grps = null) 1385aa905e9SAndreas Gohr { 139f4476bd9SJan Schumann global $conf; 140f4476bd9SJan Schumann global $config_cascade; 141f4476bd9SJan Schumann 142f4476bd9SJan Schumann // user mustn't already exist 143db9faf02SPatrick Brown if ($this->getUserData($user) !== false) { 144db9faf02SPatrick Brown msg($this->getLang('userexists'), -1); 145db9faf02SPatrick Brown return false; 146db9faf02SPatrick Brown } 147f4476bd9SJan Schumann 148f4476bd9SJan Schumann $pass = auth_cryptPassword($pwd); 149f4476bd9SJan Schumann 150f4476bd9SJan Schumann // set default group if no groups specified 151f4476bd9SJan Schumann if (!is_array($grps)) $grps = array($conf['defaultgroup']); 152f4476bd9SJan Schumann 153f4476bd9SJan Schumann // prepare user line 1545aa905e9SAndreas Gohr $userline = $this->createUserLine($user, $pass, $name, $mail, $grps); 155f4476bd9SJan Schumann 156db9faf02SPatrick Brown if (!io_saveFile($config_cascade['plainauth.users']['default'], $userline, true)) { 157db9faf02SPatrick Brown msg($this->getLang('writefail'), -1); 158db9faf02SPatrick Brown return null; 159f4476bd9SJan Schumann } 160f4476bd9SJan Schumann 161db9faf02SPatrick Brown $this->users[$user] = compact('pass', 'name', 'mail', 'grps'); 162db9faf02SPatrick Brown return $pwd; 163f4476bd9SJan Schumann } 164f4476bd9SJan Schumann 165f4476bd9SJan Schumann /** 166f4476bd9SJan Schumann * Modify user data 167f4476bd9SJan Schumann * 168f4476bd9SJan Schumann * @author Chris Smith <chris@jalakai.co.uk> 169311f4603SAndreas Gohr * @param string $user nick of the user to be changed 170311f4603SAndreas Gohr * @param array $changes array of field/value pairs to be changed (password will be clear text) 171f4476bd9SJan Schumann * @return bool 172f4476bd9SJan Schumann */ 1735aa905e9SAndreas Gohr public function modifyUser($user, $changes) 1745aa905e9SAndreas Gohr { 175f4476bd9SJan Schumann global $ACT; 176f4476bd9SJan Schumann global $config_cascade; 177f4476bd9SJan Schumann 178f4476bd9SJan Schumann // sanity checks, user must already exist and there must be something to change 179db9faf02SPatrick Brown if (($userinfo = $this->getUserData($user)) === false) { 180db9faf02SPatrick Brown msg($this->getLang('usernotexists'), -1); 181db9faf02SPatrick Brown return false; 182db9faf02SPatrick Brown } 18342cbd322SAndreas Gohr 18442cbd322SAndreas Gohr // don't modify protected users 18542cbd322SAndreas Gohr if (!empty($userinfo['protected'])) { 18642cbd322SAndreas Gohr msg(sprintf($this->getLang('protected'), hsc($user)), -1); 18742cbd322SAndreas Gohr return false; 18842cbd322SAndreas Gohr } 18942cbd322SAndreas Gohr 190f4476bd9SJan Schumann if (!is_array($changes) || !count($changes)) return true; 191f4476bd9SJan Schumann 192f4476bd9SJan Schumann // update userinfo with new data, remembering to encrypt any password 193f4476bd9SJan Schumann $newuser = $user; 194f4476bd9SJan Schumann foreach ($changes as $field => $value) { 195f4476bd9SJan Schumann if ($field == 'user') { 196f4476bd9SJan Schumann $newuser = $value; 197f4476bd9SJan Schumann continue; 198f4476bd9SJan Schumann } 199f4476bd9SJan Schumann if ($field == 'pass') $value = auth_cryptPassword($value); 200f4476bd9SJan Schumann $userinfo[$field] = $value; 201f4476bd9SJan Schumann } 202f4476bd9SJan Schumann 2035aa905e9SAndreas Gohr $userline = $this->createUserLine( 20464159a61SAndreas Gohr $newuser, 20564159a61SAndreas Gohr $userinfo['pass'], 20664159a61SAndreas Gohr $userinfo['name'], 20764159a61SAndreas Gohr $userinfo['mail'], 20864159a61SAndreas Gohr $userinfo['grps'] 20964159a61SAndreas Gohr ); 210f4476bd9SJan Schumann 211699e3c49SPatrick Brown if (!io_replaceInFile($config_cascade['plainauth.users']['default'], '/^'.$user.':/', $userline, true)) { 212699e3c49SPatrick Brown msg('There was an error modifying your user data. You may need to register again.', -1); 213699e3c49SPatrick Brown // FIXME, io functions should be fail-safe so existing data isn't lost 214311f4603SAndreas Gohr $ACT = 'register'; 215f4476bd9SJan Schumann return false; 216f4476bd9SJan Schumann } 217f4476bd9SJan Schumann 21859440086SAndreas Gohr if(isset($this->users[$user])) unset($this->users[$user]); 219f4476bd9SJan Schumann $this->users[$newuser] = $userinfo; 220f4476bd9SJan Schumann return true; 221f4476bd9SJan Schumann } 222f4476bd9SJan Schumann 223f4476bd9SJan Schumann /** 224f4476bd9SJan Schumann * Remove one or more users from the list of registered users 225f4476bd9SJan Schumann * 226f4476bd9SJan Schumann * @author Christopher Smith <chris@jalakai.co.uk> 227f4476bd9SJan Schumann * @param array $users array of users to be deleted 228f4476bd9SJan Schumann * @return int the number of users deleted 229f4476bd9SJan Schumann */ 2305aa905e9SAndreas Gohr public function deleteUsers($users) 2315aa905e9SAndreas Gohr { 232f4476bd9SJan Schumann global $config_cascade; 233f4476bd9SJan Schumann 234f4476bd9SJan Schumann if (!is_array($users) || empty($users)) return 0; 235f4476bd9SJan Schumann 2365aa905e9SAndreas Gohr if ($this->users === null) $this->loadUserData(); 237f4476bd9SJan Schumann 238f4476bd9SJan Schumann $deleted = array(); 239f4476bd9SJan Schumann foreach ($users as $user) { 24042cbd322SAndreas Gohr // don't delete protected users 24142cbd322SAndreas Gohr if (!empty($this->users[$user]['protected'])) { 24242cbd322SAndreas Gohr msg(sprintf($this->getLang('protected'), hsc($user)), -1); 24342cbd322SAndreas Gohr continue; 24442cbd322SAndreas Gohr } 245f4476bd9SJan Schumann if (isset($this->users[$user])) $deleted[] = preg_quote($user, '/'); 246f4476bd9SJan Schumann } 247f4476bd9SJan Schumann 248f4476bd9SJan Schumann if (empty($deleted)) return 0; 249f4476bd9SJan Schumann 250f4476bd9SJan Schumann $pattern = '/^('.join('|', $deleted).'):/'; 251db9faf02SPatrick Brown if (!io_deleteFromFile($config_cascade['plainauth.users']['default'], $pattern, true)) { 252db9faf02SPatrick Brown msg($this->getLang('writefail'), -1); 253db9faf02SPatrick Brown return 0; 254db9faf02SPatrick Brown } 255f4476bd9SJan Schumann 2569d24536dSAndreas Gohr // reload the user list and count the difference 257f4476bd9SJan Schumann $count = count($this->users); 2585aa905e9SAndreas Gohr $this->loadUserData(); 259f4476bd9SJan Schumann $count -= count($this->users); 260f4476bd9SJan Schumann return $count; 261f4476bd9SJan Schumann } 262f4476bd9SJan Schumann 263f4476bd9SJan Schumann /** 264f4476bd9SJan Schumann * Return a count of the number of user which meet $filter criteria 265f4476bd9SJan Schumann * 266f4476bd9SJan Schumann * @author Chris Smith <chris@jalakai.co.uk> 267311f4603SAndreas Gohr * 268311f4603SAndreas Gohr * @param array $filter 269311f4603SAndreas Gohr * @return int 270f4476bd9SJan Schumann */ 2715aa905e9SAndreas Gohr public function getUserCount($filter = array()) 2725aa905e9SAndreas Gohr { 273f4476bd9SJan Schumann 2745aa905e9SAndreas Gohr if ($this->users === null) $this->loadUserData(); 275f4476bd9SJan Schumann 276f4476bd9SJan Schumann if (!count($filter)) return count($this->users); 277f4476bd9SJan Schumann 278f4476bd9SJan Schumann $count = 0; 2795aa905e9SAndreas Gohr $this->constructPattern($filter); 280f4476bd9SJan Schumann 281f4476bd9SJan Schumann foreach ($this->users as $user => $info) { 2825aa905e9SAndreas Gohr $count += $this->filter($user, $info); 283f4476bd9SJan Schumann } 284f4476bd9SJan Schumann 285f4476bd9SJan Schumann return $count; 286f4476bd9SJan Schumann } 287f4476bd9SJan Schumann 288f4476bd9SJan Schumann /** 289f4476bd9SJan Schumann * Bulk retrieval of user data 290f4476bd9SJan Schumann * 291f4476bd9SJan Schumann * @author Chris Smith <chris@jalakai.co.uk> 292311f4603SAndreas Gohr * 293311f4603SAndreas Gohr * @param int $start index of first user to be returned 294311f4603SAndreas Gohr * @param int $limit max number of users to be returned 295311f4603SAndreas Gohr * @param array $filter array of field/pattern pairs 296311f4603SAndreas Gohr * @return array userinfo (refer getUserData for internal userinfo details) 297f4476bd9SJan Schumann */ 2985aa905e9SAndreas Gohr public function retrieveUsers($start = 0, $limit = 0, $filter = array()) 2995aa905e9SAndreas Gohr { 300f4476bd9SJan Schumann 3015aa905e9SAndreas Gohr if ($this->users === null) $this->loadUserData(); 302f4476bd9SJan Schumann 3030489c64bSMoisés Braga Ribeiro Sort::ksort($this->users); 304f4476bd9SJan Schumann 305f4476bd9SJan Schumann $i = 0; 306f4476bd9SJan Schumann $count = 0; 307f4476bd9SJan Schumann $out = array(); 3085aa905e9SAndreas Gohr $this->constructPattern($filter); 309f4476bd9SJan Schumann 310f4476bd9SJan Schumann foreach ($this->users as $user => $info) { 3115aa905e9SAndreas Gohr if ($this->filter($user, $info)) { 312f4476bd9SJan Schumann if ($i >= $start) { 313f4476bd9SJan Schumann $out[$user] = $info; 314f4476bd9SJan Schumann $count++; 315f4476bd9SJan Schumann if (($limit > 0) && ($count >= $limit)) break; 316f4476bd9SJan Schumann } 317f4476bd9SJan Schumann $i++; 318f4476bd9SJan Schumann } 319f4476bd9SJan Schumann } 320f4476bd9SJan Schumann 321f4476bd9SJan Schumann return $out; 322f4476bd9SJan Schumann } 323f4476bd9SJan Schumann 324f4476bd9SJan Schumann /** 325b2fcc742SAnna Dabrowska * Retrieves groups. 326b2fcc742SAnna Dabrowska * Loads complete user data into memory before searching for groups. 327b2fcc742SAnna Dabrowska * 328b2fcc742SAnna Dabrowska * @param int $start index of first group to be returned 329b2fcc742SAnna Dabrowska * @param int $limit max number of groups to be returned 330b2fcc742SAnna Dabrowska * @return array 331b2fcc742SAnna Dabrowska */ 332b2fcc742SAnna Dabrowska public function retrieveGroups($start = 0, $limit = 0) 333b2fcc742SAnna Dabrowska { 334b2fcc742SAnna Dabrowska $groups = []; 335b2fcc742SAnna Dabrowska 33642c62e55SAndreas Gohr if ($this->users === null) $this->loadUserData(); 337b2fcc742SAnna Dabrowska foreach($this->users as $user => $info) { 338b2fcc742SAnna Dabrowska $groups = array_merge($groups, array_diff($info['grps'], $groups)); 339b2fcc742SAnna Dabrowska } 3400489c64bSMoisés Braga Ribeiro Sort::ksort($groups); 341b2fcc742SAnna Dabrowska 342b2fcc742SAnna Dabrowska if($limit > 0) { 343b2fcc742SAnna Dabrowska return array_splice($groups, $start, $limit); 344b2fcc742SAnna Dabrowska } 345b2fcc742SAnna Dabrowska return array_splice($groups, $start); 346b2fcc742SAnna Dabrowska } 347b2fcc742SAnna Dabrowska 348b2fcc742SAnna Dabrowska /** 349f4476bd9SJan Schumann * Only valid pageid's (no namespaces) for usernames 350311f4603SAndreas Gohr * 351311f4603SAndreas Gohr * @param string $user 352311f4603SAndreas Gohr * @return string 353f4476bd9SJan Schumann */ 3545aa905e9SAndreas Gohr public function cleanUser($user) 3555aa905e9SAndreas Gohr { 356f4476bd9SJan Schumann global $conf; 357*5f18fdf3SAndreas Gohr 358*5f18fdf3SAndreas Gohr return cleanID(str_replace([':', '/', ';'], $conf['sepchar'], $user)); 359f4476bd9SJan Schumann } 360f4476bd9SJan Schumann 361f4476bd9SJan Schumann /** 362f4476bd9SJan Schumann * Only valid pageid's (no namespaces) for groupnames 363311f4603SAndreas Gohr * 364311f4603SAndreas Gohr * @param string $group 365311f4603SAndreas Gohr * @return string 366f4476bd9SJan Schumann */ 3675aa905e9SAndreas Gohr public function cleanGroup($group) 3685aa905e9SAndreas Gohr { 369f4476bd9SJan Schumann global $conf; 370*5f18fdf3SAndreas Gohr 371*5f18fdf3SAndreas Gohr return cleanID(str_replace([':', '/', ';'], $conf['sepchar'], $group)); 372f4476bd9SJan Schumann } 373f4476bd9SJan Schumann 374f4476bd9SJan Schumann /** 375f4476bd9SJan Schumann * Load all user data 376f4476bd9SJan Schumann * 377f4476bd9SJan Schumann * loads the user file into a datastructure 378f4476bd9SJan Schumann * 379f4476bd9SJan Schumann * @author Andreas Gohr <andi@splitbrain.org> 380f4476bd9SJan Schumann */ 3815aa905e9SAndreas Gohr protected function loadUserData() 3825aa905e9SAndreas Gohr { 383f4476bd9SJan Schumann global $config_cascade; 384f4476bd9SJan Schumann 3855aa905e9SAndreas Gohr $this->users = $this->readUserFile($config_cascade['plainauth.users']['default']); 386f4476bd9SJan Schumann 38742cbd322SAndreas Gohr // support protected users 38842cbd322SAndreas Gohr if (!empty($config_cascade['plainauth.users']['protected'])) { 3895aa905e9SAndreas Gohr $protected = $this->readUserFile($config_cascade['plainauth.users']['protected']); 39042cbd322SAndreas Gohr foreach (array_keys($protected) as $key) { 39142cbd322SAndreas Gohr $protected[$key]['protected'] = true; 39242cbd322SAndreas Gohr } 39342cbd322SAndreas Gohr $this->users = array_merge($this->users, $protected); 39442cbd322SAndreas Gohr } 39542cbd322SAndreas Gohr } 396f4476bd9SJan Schumann 39742cbd322SAndreas Gohr /** 39842cbd322SAndreas Gohr * Read user data from given file 39942cbd322SAndreas Gohr * 40042cbd322SAndreas Gohr * ignores non existing files 40142cbd322SAndreas Gohr * 40242cbd322SAndreas Gohr * @param string $file the file to load data from 40342cbd322SAndreas Gohr * @return array 40442cbd322SAndreas Gohr */ 4055aa905e9SAndreas Gohr protected function readUserFile($file) 4065aa905e9SAndreas Gohr { 40742cbd322SAndreas Gohr $users = array(); 40842cbd322SAndreas Gohr if (!file_exists($file)) return $users; 40942cbd322SAndreas Gohr 41042cbd322SAndreas Gohr $lines = file($file); 411f4476bd9SJan Schumann foreach ($lines as $line) { 412f4476bd9SJan Schumann $line = preg_replace('/#.*$/', '', $line); //ignore comments 413f4476bd9SJan Schumann $line = trim($line); 414f4476bd9SJan Schumann if (empty($line)) continue; 415f4476bd9SJan Schumann 4165aa905e9SAndreas Gohr $row = $this->splitUserData($line); 417f95ecbbfSAngus Gratton $row = str_replace('\\:', ':', $row); 418f95ecbbfSAngus Gratton $row = str_replace('\\\\', '\\', $row); 419f95ecbbfSAngus Gratton 420f4476bd9SJan Schumann $groups = array_values(array_filter(explode(",", $row[4]))); 421f4476bd9SJan Schumann 42242cbd322SAndreas Gohr $users[$row[0]]['pass'] = $row[1]; 42342cbd322SAndreas Gohr $users[$row[0]]['name'] = urldecode($row[2]); 42442cbd322SAndreas Gohr $users[$row[0]]['mail'] = $row[3]; 42542cbd322SAndreas Gohr $users[$row[0]]['grps'] = $groups; 426f4476bd9SJan Schumann } 42742cbd322SAndreas Gohr return $users; 428f4476bd9SJan Schumann } 429f4476bd9SJan Schumann 4305aa905e9SAndreas Gohr /** 4315aa905e9SAndreas Gohr * Get the user line split into it's parts 4325aa905e9SAndreas Gohr * 4335aa905e9SAndreas Gohr * @param string $line 4345aa905e9SAndreas Gohr * @return string[] 4355aa905e9SAndreas Gohr */ 4365aa905e9SAndreas Gohr protected function splitUserData($line) 4375aa905e9SAndreas Gohr { 4386c8c1f46SChristopher Smith // due to a bug in PCRE 6.6, preg_split will fail with the regex we use here 4396c8c1f46SChristopher Smith // refer github issues 877 & 885 4405aa905e9SAndreas Gohr if ($this->pregsplit_safe) { 4416c8c1f46SChristopher Smith return preg_split('/(?<![^\\\\]\\\\)\:/', $line, 5); // allow for : escaped as \: 4426c8c1f46SChristopher Smith } 4436c8c1f46SChristopher Smith 4446c8c1f46SChristopher Smith $row = array(); 4456c8c1f46SChristopher Smith $piece = ''; 4469d846ff4SChristopher Smith $len = strlen($line); 4479d846ff4SChristopher Smith for ($i=0; $i<$len; $i++) { 4486c8c1f46SChristopher Smith if ($line[$i]=='\\') { 4499d846ff4SChristopher Smith $piece .= $line[$i]; 4506c8c1f46SChristopher Smith $i++; 4519d846ff4SChristopher Smith if ($i>=$len) break; 4526c8c1f46SChristopher Smith } elseif ($line[$i]==':') { 4536c8c1f46SChristopher Smith $row[] = $piece; 4546c8c1f46SChristopher Smith $piece = ''; 4556c8c1f46SChristopher Smith continue; 4566c8c1f46SChristopher Smith } 4576c8c1f46SChristopher Smith $piece .= $line[$i]; 4586c8c1f46SChristopher Smith } 4596c8c1f46SChristopher Smith $row[] = $piece; 4606c8c1f46SChristopher Smith 4616c8c1f46SChristopher Smith return $row; 4626c8c1f46SChristopher Smith } 4636c8c1f46SChristopher Smith 464f4476bd9SJan Schumann /** 465311f4603SAndreas Gohr * return true if $user + $info match $filter criteria, false otherwise 466f4476bd9SJan Schumann * 467f4476bd9SJan Schumann * @author Chris Smith <chris@jalakai.co.uk> 468311f4603SAndreas Gohr * 469311f4603SAndreas Gohr * @param string $user User login 470311f4603SAndreas Gohr * @param array $info User's userinfo array 471311f4603SAndreas Gohr * @return bool 472f4476bd9SJan Schumann */ 4735aa905e9SAndreas Gohr protected function filter($user, $info) 4745aa905e9SAndreas Gohr { 4755aa905e9SAndreas Gohr foreach ($this->pattern as $item => $pattern) { 476f4476bd9SJan Schumann if ($item == 'user') { 477311f4603SAndreas Gohr if (!preg_match($pattern, $user)) return false; 478f4476bd9SJan Schumann } elseif ($item == 'grps') { 479311f4603SAndreas Gohr if (!count(preg_grep($pattern, $info['grps']))) return false; 480f4476bd9SJan Schumann } else { 481311f4603SAndreas Gohr if (!preg_match($pattern, $info[$item])) return false; 482f4476bd9SJan Schumann } 483f4476bd9SJan Schumann } 484311f4603SAndreas Gohr return true; 485f4476bd9SJan Schumann } 486f4476bd9SJan Schumann 487311f4603SAndreas Gohr /** 488311f4603SAndreas Gohr * construct a filter pattern 489311f4603SAndreas Gohr * 490311f4603SAndreas Gohr * @param array $filter 491311f4603SAndreas Gohr */ 4925aa905e9SAndreas Gohr protected function constructPattern($filter) 4935aa905e9SAndreas Gohr { 4945aa905e9SAndreas Gohr $this->pattern = array(); 495f4476bd9SJan Schumann foreach ($filter as $item => $pattern) { 4965aa905e9SAndreas Gohr $this->pattern[$item] = '/'.str_replace('/', '\/', $pattern).'/i'; // allow regex characters 497f4476bd9SJan Schumann } 498f4476bd9SJan Schumann } 499f4476bd9SJan Schumann} 500