2007-08-28 10:18:04 +02:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* User administration code.
|
|
|
|
*
|
|
|
|
* @author Jan Dittberner <jan@dittberner.info>
|
|
|
|
* @version $Id$
|
|
|
|
* @license GPL
|
2007-11-26 09:49:33 +01:00
|
|
|
* @package DAVAdmin
|
2007-08-28 10:18:04 +02:00
|
|
|
*
|
|
|
|
* Copyright (c) 2007 Jan Dittberner
|
|
|
|
*
|
2007-11-26 09:49:33 +01:00
|
|
|
* This file is part of DAVAdmin.
|
2007-08-28 10:18:04 +02:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License as
|
|
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
|
|
* License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
|
|
* 02110-1301 USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/** Include common code. */
|
|
|
|
include_once('common.inc.php');
|
|
|
|
|
2007-11-26 10:44:23 +01:00
|
|
|
/**
|
|
|
|
* Gets the names of the given users's groups from the group file.
|
|
|
|
*
|
|
|
|
* @param string $username user name
|
2007-12-03 15:11:35 +01:00
|
|
|
* @return array array of group names
|
2007-11-26 10:44:23 +01:00
|
|
|
* @access private
|
|
|
|
*/
|
|
|
|
function _getGroupNames($username) {
|
2007-11-22 00:00:58 +01:00
|
|
|
$groupdata = file($GLOBALS['davconfig']['group.file']);
|
|
|
|
$retval = array();
|
|
|
|
foreach ($groupdata as $line) {
|
2007-11-22 08:41:30 +01:00
|
|
|
list($group, $users) = explode(":", $line);
|
|
|
|
$group = trim($group);
|
|
|
|
$users = explode(" ", $users);
|
|
|
|
foreach ($users as $user) {
|
|
|
|
if (trim($user) == $username) {
|
|
|
|
array_push($retval, $group);
|
2007-11-22 00:00:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-12-03 16:01:45 +01:00
|
|
|
asort($retval);
|
2007-11-22 00:00:58 +01:00
|
|
|
return $retval;
|
|
|
|
}
|
|
|
|
|
2007-08-28 10:18:04 +02:00
|
|
|
/**
|
|
|
|
* Gets XML encoded data for a user.
|
|
|
|
*
|
|
|
|
* @param int $uid user id
|
2007-12-03 15:11:35 +01:00
|
|
|
* @return string XML string
|
2007-08-28 10:18:04 +02:00
|
|
|
*/
|
|
|
|
function getUserData($uid) {
|
2007-11-22 00:00:58 +01:00
|
|
|
if (!(is_numeric($uid) && array_key_exists($uid, $GLOBALS['namemap']))) {
|
2007-08-28 10:18:04 +02:00
|
|
|
errorAsXml(sprintf(_("Invalid user id %s"), $uid));
|
|
|
|
}
|
|
|
|
|
2007-11-22 00:00:58 +01:00
|
|
|
$row = $GLOBALS['namemap'][$uid];
|
2007-11-26 10:44:23 +01:00
|
|
|
$groups = _getGroupNames($row['username']);
|
2007-11-22 00:00:58 +01:00
|
|
|
$retval = sprintf('<?xml version="1.0" encoding="utf8"?><userdata><uid>%d</uid><username>%s</username><firstname>%s</firstname><lastname>%s</lastname><groups>%s</groups><loggedin>0</loggedin></userdata>',
|
|
|
|
$uid, $row['username'], $row['firstname'],
|
|
|
|
$row['lastname'], implode(", ", $groups));
|
2007-08-28 10:18:04 +02:00
|
|
|
header("Content-Type: text/xml; charset=UTF-8");
|
|
|
|
return $retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets XML encoded data for a deleted user.
|
|
|
|
*
|
|
|
|
* @param int $uid user id
|
2007-12-03 15:11:35 +01:00
|
|
|
* @return string XML string
|
2007-08-28 10:18:04 +02:00
|
|
|
*/
|
|
|
|
function getDeletedUserData($uid) {
|
|
|
|
if (!is_numeric($uid)) {
|
|
|
|
errorAsXml(sprintf(_("Invalid user id %s"), $uid));
|
|
|
|
}
|
|
|
|
return sprintf('<?xml version="1.0" encoding="utf8"?><userdata><uid>%d</uid></userdata>', $uid);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Validates the given user data array for correctness.
|
|
|
|
*
|
|
|
|
* @param array &$userdata reference to an user data array
|
|
|
|
* @param boolean $forinsert if this is true the check skips field
|
|
|
|
* that will be created during insert
|
2007-12-03 15:11:35 +01:00
|
|
|
* @return array an array with validation error messages or an empty
|
|
|
|
* array
|
2007-08-28 10:18:04 +02:00
|
|
|
*/
|
|
|
|
function validateUserData(&$userdata, $forinsert) {
|
|
|
|
$errormsgs = array();
|
|
|
|
// normalize the user data array
|
|
|
|
foreach ($userdata as $key => $value) {
|
|
|
|
$userdata[$key] = trim($value);
|
|
|
|
}
|
|
|
|
if (!$forinsert) {
|
|
|
|
if (!is_numeric($userdata['uid'])) {
|
|
|
|
array_push($errormsgs, _("Uid must be numeric."));
|
|
|
|
}
|
|
|
|
if (!empty($userdata['password']) && strlen($userdata['password']) < 8) {
|
|
|
|
array_push($errormsgs, _("Password must be at least 8 characters long."));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!preg_match('/^[a-zA-Z0-9]{2,}$/', $userdata['username'])) {
|
|
|
|
array_push($errormsgs, _("Username must be at least 2 characters long and must contain letters and digits only."));
|
|
|
|
}
|
|
|
|
if (empty($userdata['password']) || strlen($userdata['password']) < 8) {
|
|
|
|
array_push($errormsgs, _("Password must be at least 8 characters long."));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (empty($userdata['firstname'])) {
|
|
|
|
$userdata['firstname'] = null;
|
|
|
|
}
|
|
|
|
if (empty($userdata['lastname'])) {
|
|
|
|
$userdata['lastname'] = null;
|
|
|
|
}
|
2008-11-16 17:54:08 +01:00
|
|
|
if (!preg_match('/^[0-9a-zA-z]+(\s*,\s*[0-9a-zA-z]+)*$/', $userdata['groups'])) {
|
2007-08-28 10:18:04 +02:00
|
|
|
array_push($errormsgs, _('Groups must be a list of group names separated by commas. Group names must consist of letters and digits.'));
|
|
|
|
}
|
|
|
|
return $errormsgs;
|
|
|
|
}
|
|
|
|
|
2007-11-22 08:41:30 +01:00
|
|
|
/**
|
2007-11-26 10:44:23 +01:00
|
|
|
* Create an entry for a digest authentication file.
|
2007-11-22 08:41:30 +01:00
|
|
|
*
|
|
|
|
* @param string $username user name
|
|
|
|
* @param string $realm realm name
|
|
|
|
* @param string $password password
|
|
|
|
* @return string digest entry
|
|
|
|
*/
|
2007-11-22 00:00:58 +01:00
|
|
|
function createDigest($username, $realm, $password) {
|
|
|
|
return sprintf("%s:%s:%s", $username, $realm,
|
|
|
|
md5(sprintf("%s:%s:%s", $username, $realm, $password)));
|
|
|
|
}
|
|
|
|
|
2007-11-26 10:44:23 +01:00
|
|
|
/**
|
|
|
|
* Update the user to name mapping file.
|
|
|
|
*/
|
2007-11-22 08:41:30 +01:00
|
|
|
function updateNameMap() {
|
|
|
|
$fh = fopen($GLOBALS['davconfig']['namemap.file'], 'w');
|
|
|
|
fwrite($fh, json_encode($GLOBALS['namemap']));
|
|
|
|
fclose($fh);
|
|
|
|
}
|
|
|
|
|
2007-11-26 10:44:23 +01:00
|
|
|
/**
|
|
|
|
* Update the digest file with the user information.
|
|
|
|
*
|
|
|
|
* @param &array reference to an associative array of user data
|
|
|
|
*/
|
2007-11-22 08:41:30 +01:00
|
|
|
function updateDigest(&$userdata) {
|
|
|
|
if ($userdata['password']) {
|
|
|
|
$digests = file($GLOBALS['davconfig']['digest.file']);
|
|
|
|
$written = false;
|
|
|
|
$fh = fopen($GLOBALS['davconfig']['digest.file'], 'w');
|
|
|
|
foreach ($digests as $digest) {
|
|
|
|
list($username, $realm, $data) = explode(":", $digest);
|
|
|
|
if ($username == $userdata['username']
|
|
|
|
&& $realm == $GLOBALS['davconfig']['dav.realm']) {
|
|
|
|
fwrite($fh, createDigest($userdata['username'],
|
|
|
|
$GLOBALS['davconfig']['dav.realm'],
|
|
|
|
$userdata['password']) . "\n");
|
|
|
|
$written = true;
|
|
|
|
} else {
|
|
|
|
fwrite($fh, $digest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!$written) {
|
|
|
|
fwrite($fh, createDigest($userdata['username'],
|
|
|
|
$GLOBALS['davconfig']['dav.realm'],
|
|
|
|
$userdata['password']) . "\n");
|
|
|
|
}
|
|
|
|
fclose($fh);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-11-26 10:44:23 +01:00
|
|
|
/**
|
|
|
|
* Update the group file with the group assignments of the user.
|
|
|
|
*
|
|
|
|
* @param &array reference to an associative array of user data
|
|
|
|
*/
|
2007-11-22 08:41:30 +01:00
|
|
|
function updateGroups(&$userdata) {
|
|
|
|
if ($userdata['groups']) {
|
|
|
|
$written = array();
|
|
|
|
foreach (explode(",", $userdata['groups']) as $group) {
|
|
|
|
$written[trim($group)] = false;
|
|
|
|
}
|
|
|
|
$groupdata = file($GLOBALS['davconfig']['group.file']);
|
|
|
|
$fh = fopen($GLOBALS['davconfig']['group.file'], 'w');
|
|
|
|
foreach ($groupdata as $groupline) {
|
|
|
|
list ($group, $users) = explode(":", $groupline);
|
|
|
|
$group = trim($group);
|
|
|
|
$users = explode(" ", trim($users));
|
|
|
|
foreach ($users as $key => $user) {
|
|
|
|
$users[$key] = trim($user);
|
|
|
|
}
|
|
|
|
if (array_key_exists($group, $written)) {
|
|
|
|
if (!in_array($userdata['username'], $users)) {
|
|
|
|
array_push($users, $userdata['username']);
|
|
|
|
}
|
|
|
|
fprintf($fh, "%s: %s\n", $group, implode(" ", $users));
|
|
|
|
$written[$group] = true;
|
|
|
|
} else {
|
2008-11-16 17:54:08 +01:00
|
|
|
if (in_array($userdata['username'], $users)) {
|
|
|
|
array_splice($users, array_search($userdata['username'], $users),1);
|
|
|
|
}
|
|
|
|
if (count($users) > 0 ) {
|
|
|
|
fprintf($fh, "%s: %s\n", $group, implode(" ", $users));
|
|
|
|
}
|
2007-11-22 08:41:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
foreach ($written as $group => $done) {
|
|
|
|
if (!$done) {
|
|
|
|
fprintf($fh, "%s: %s\n", $group, $userdata['username']);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fclose($fh);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-08-28 10:18:04 +02:00
|
|
|
/**
|
|
|
|
* Updates the data of a user in the database.
|
|
|
|
*
|
|
|
|
* @param array &$userdata reference to a user data array
|
|
|
|
*/
|
|
|
|
function updateUser(&$userdata) {
|
|
|
|
$validation = validateUserData($userdata, false);
|
|
|
|
if (!empty($validation)) {
|
|
|
|
errorAsXml(implode("\n", $validation));
|
|
|
|
}
|
2007-11-22 08:41:30 +01:00
|
|
|
$GLOBALS['namemap'][$userdata['uid']] =
|
|
|
|
array('uid' => $userdata['uid'],
|
|
|
|
'username' => $userdata['username'],
|
|
|
|
'firstname' => $userdata['firstname'],
|
|
|
|
'lastname' => $userdata['lastname']);
|
|
|
|
// write name mapping data
|
|
|
|
updateNameMap();
|
|
|
|
// write digest data
|
|
|
|
updateDigest($userdata);
|
|
|
|
// update group file
|
|
|
|
updateGroups($userdata);
|
2007-08-28 10:18:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Inserts a new user and its group assignments into the database.
|
|
|
|
*
|
|
|
|
* @param array &$userdata reference to an user data array
|
|
|
|
*/
|
|
|
|
function insertUser(&$userdata) {
|
|
|
|
$validation = validateUserData($userdata, true);
|
|
|
|
if (!empty($validation)) {
|
|
|
|
errorAsXml(implode("\n", $validation));
|
|
|
|
}
|
2007-11-22 08:41:30 +01:00
|
|
|
$uids = array_keys($GLOBALS['namemap']);
|
|
|
|
if (empty($uids)) {
|
|
|
|
$uid = 1;
|
|
|
|
} else {
|
2007-11-23 21:28:53 +01:00
|
|
|
foreach ($uids as $currentuid) {
|
|
|
|
$uid = max($uid, $currentuid);
|
|
|
|
}
|
|
|
|
$uid += 1;
|
2007-11-22 08:41:30 +01:00
|
|
|
}
|
|
|
|
$GLOBALS['namemap'][$uid] =
|
|
|
|
array('uid' => $uid,
|
|
|
|
'username' => $userdata['username'],
|
|
|
|
'firstname' => $userdata['firstname'],
|
|
|
|
'lastname' => $userdata['lastname']);
|
|
|
|
// write name mapping data
|
|
|
|
updateNameMap();
|
|
|
|
// write digest data
|
|
|
|
updateDigest($userdata);
|
|
|
|
// update group file
|
|
|
|
updateGroups($userdata);
|
|
|
|
return $uid;
|
|
|
|
}
|
|
|
|
|
2007-11-26 10:44:23 +01:00
|
|
|
/**
|
|
|
|
* Remove the digest entries of the given user from the digest file.
|
|
|
|
*
|
|
|
|
* @param string $username
|
|
|
|
*/
|
2007-11-22 08:41:30 +01:00
|
|
|
function removeDigest($username) {
|
|
|
|
$digests = file($GLOBALS['davconfig']['digest.file']);
|
|
|
|
$fh = fopen($GLOBALS['davconfig']['digest.file'], 'w');
|
|
|
|
foreach ($digests as $digest) {
|
2008-11-16 17:54:08 +01:00
|
|
|
list($user, $realm, $data) = explode(":", $digest);
|
|
|
|
if (!($user == $username
|
2007-11-22 08:41:30 +01:00
|
|
|
&& $realm == $GLOBALS['davconfig']['dav.realm'])) {
|
|
|
|
fwrite($fh, $digest);
|
2007-08-28 10:18:04 +02:00
|
|
|
}
|
2007-11-22 08:41:30 +01:00
|
|
|
}
|
|
|
|
fclose($fh);
|
|
|
|
}
|
|
|
|
|
2007-11-26 10:44:23 +01:00
|
|
|
/**
|
|
|
|
* Remove the given user from all groups in the group file.
|
|
|
|
*
|
|
|
|
* @param string $username
|
|
|
|
*/
|
2007-11-22 08:41:30 +01:00
|
|
|
function removeFromGroups($username) {
|
|
|
|
$groupdata = file($GLOBALS['davconfig']['group.file']);
|
|
|
|
$fh = fopen($GLOBALS['davconfig']['group.file'], 'w');
|
|
|
|
foreach ($groupdata as $groupline) {
|
|
|
|
list ($group, $users) = explode(":", $groupline);
|
|
|
|
$group = trim($group);
|
|
|
|
$users = explode(" ", trim($users));
|
|
|
|
foreach ($users as $key => $user) {
|
|
|
|
$users[$key] = trim($user);
|
|
|
|
}
|
|
|
|
if (in_array($username, $users)) {
|
2008-11-16 17:54:08 +01:00
|
|
|
array_splice($users, array_search($username, $users),1);
|
|
|
|
}
|
|
|
|
if (count($users) > 0 ) {
|
|
|
|
fprintf($fh, "%s: %s\n", $group, implode(" ", $users));
|
2007-08-28 10:18:04 +02:00
|
|
|
}
|
|
|
|
}
|
2007-11-22 08:41:30 +01:00
|
|
|
fclose($fh);
|
2007-08-28 10:18:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Delete the user with the given user id and its group assignments
|
|
|
|
* from the database.
|
|
|
|
*
|
|
|
|
* @param int $uid user id
|
|
|
|
*/
|
|
|
|
function deleteUser($uid) {
|
2007-11-22 08:41:30 +01:00
|
|
|
if (!(is_numeric($uid) && array_key_exists($uid, $GLOBALS['namemap']))) {
|
2007-08-28 10:18:04 +02:00
|
|
|
errorAsXml(sprintf(_("Invalid user id %s"), $uid));
|
|
|
|
}
|
2007-11-22 08:41:30 +01:00
|
|
|
removeDigest($GLOBALS['namemap'][$uid]['username']);
|
|
|
|
removeFromGroups($GLOBALS['namemap'][$uid]['username']);
|
|
|
|
unset($GLOBALS['namemap'][$uid]);
|
|
|
|
updateNameMap();
|
2007-08-28 10:18:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if ($_GET) {
|
|
|
|
if ($_GET['method']) {
|
|
|
|
switch ($_GET['method']) {
|
|
|
|
case 'getuserdata':
|
|
|
|
if ($_GET['uid']) {
|
|
|
|
print getUserData($_GET['uid']);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
errorAsXml(sprintf(_("Unexpected values %s!"), serialize($_GET)));
|
|
|
|
}
|
2007-12-02 22:23:20 +01:00
|
|
|
} else if (isset($_GET['language'])) {
|
|
|
|
header("Content-Type: text/html; charset=UTF-8");
|
|
|
|
$smarty->assign("users", $namemap);
|
|
|
|
$smarty->display("users.html");
|
2007-08-28 10:18:04 +02:00
|
|
|
} else {
|
|
|
|
invalidCall();
|
|
|
|
}
|
|
|
|
} elseif ($_POST) {
|
|
|
|
if ($_POST['method']) {
|
|
|
|
switch ($_POST['method']) {
|
|
|
|
case 'submituser':
|
|
|
|
if ($_POST['uid']) {
|
|
|
|
updateUser($_POST);
|
|
|
|
print getUserData($_POST['uid']);
|
|
|
|
} else {
|
|
|
|
print getUserData(insertUser($_POST));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'deleteuser':
|
|
|
|
if ($_POST['uid']) {
|
|
|
|
deleteUser($_POST['uid']);
|
|
|
|
print getDeletedUserData($_POST['uid']);
|
|
|
|
} else {
|
|
|
|
errorAsXml(sprintf(_("Unexpected values %s!"), serialize($_POST)));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
errorAsXml(sprintf(_("Unexpected values %s!"), serialize($_POST)));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
invalidCall();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
header("Content-Type: text/html; charset=UTF-8");
|
2007-11-22 00:00:58 +01:00
|
|
|
$smarty->assign("users", $namemap);
|
|
|
|
$smarty->display("users.html");
|
2007-08-28 10:18:04 +02:00
|
|
|
}
|
|
|
|
?>
|