_rootUser = $rootUser; $this->_rootPass = $rootPass; $this->_host = $host; } /** * @return ObjectUserLdap */ public function getUser($userName) { $usrLdap = UsersLdapHelper::getUser($userName, true); if (empty($usrLdap[0])) return null; DBG::_('DBG_SU', true, 'usrLdap', $usrLdap[0], __CLASS__, __FUNCTION__, __LINE__); $user = $this->_buildUserFromLdap($usrLdap[0]); return $user; } private function _buildUserFromLdap($usrLdap) { $user = new ObjectUserLdap($this); $user->primaryKey = V::get('uidNumber', '', $usrLdap); $user->login = V::get('uid', '', $usrLdap); $user->password = ''; $user->name = V::get('cn', '', $usrLdap); $user->email = V::get('mail', '', $usrLdap); $user->phone = V::get('telephoneNumber', '', $usrLdap); $user->homeEmail = V::get('carLicense', '', $usrLdap); $user->homePhone = V::get('homePhone', '', $usrLdap); $user->employeeType = V::get('employeeType', '', $usrLdap); return $user; } /** * @return ObjectGroupLdap $group */ public function getGroup($groupID) { return $this->_getGroup($groupID, $fetchNested = true); } private function _getGroup($groupID, $fetchNested = false) { if ($groupID <= 0) return false; $group = null; $groups = UsersLdapHelper::getGroupsByID($groupID); if (count($groups) == 1) { $group = reset($groups); if(V::get('DBG_SU', 0, $_GET, 'int') > 2){echo'
groupLdap (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($group);echo'';}
$group = $this->_buildGroupFromLdap($group, $fetchNested);
if(V::get('DBG_SU', 0, $_GET, 'int') > 2){echo'group (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($group);echo'';}
} else if (count($groups) > 1) {
if(V::get('DBG_SU', 0, $_GET, 'int') > 0){echo''."Too much groups in ldap by ID {$groupID}".' (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($groups);echo'';}
trigger_error("Too much groups in ldap by ID {$groupID}", E_USER_WARNING);
}
return $group;
}
public function getParentGroups(ObjectGroup $group) {
$parentGroups = array();
$parentGroupsLdap = UsersLdapHelper::getParentGroupsByAppleUID($group->getLdapUID());
foreach ($parentGroupsLdap as $groupLdap) {
$group = $this->_buildGroupFromLdap($groupLdap);
if ($group->zasobID > 0) {
$parentGroups[$group->zasobID] = $group;
}
}
return $parentGroups;
}
/**
* @return bool
*/
public function isDisabled($usr) {
if (!$usr) throw new Exception("Błąd podczas sprawdzania statusu blokady - nie podano użytkownika!");
if (null === $usr->isDisabled) {
$allGroups = $this->_fetchAllUserGroups($usr->login);
$usr->isDisabled = in_array('com.apple.access_disabled', $allGroups);
DBG::_('DBG_SU', '>1', "usr->isDisabled(" . (($usr->isDisabled)? 'true' : 'false') . ") ", null, __CLASS__, __FUNCTION__, __LINE__);
}
return $usr->isDisabled;
}
/**
* @return bool
*/
public function setDisabled($usrLogin, $isDisabled) {
// pwpolicy -a diradmin -u t1 -disableuser
// pwpolicy -a diradmin -u t1 -enableuser
if (empty($usrLogin) || null === $isDisabled) {
return false;
}
$cmdDisabled = ($isDisabled)? ' -disableuser' : ' -enableuser';
$cmd = "pwpolicy -a {$this->_rootUser} -p {$this->_rootPass} -u {$usrLogin} {$cmdDisabled} 2>&1 ";
$cmdOut = null; $cmdRet = null;
exec($cmd, $cmdOut, $cmdRet);
DBG::_('DBG_SU', '>1', "cmd(" . str_replace($this->_rootPass, '***', $cmd) . ") ret({$cmdRet}) ", $cmdOut, __CLASS__, __FUNCTION__, __LINE__);
if ($cmdRet !== 0) {
return false;
}
return true;
}
/**
* @param $usr - user object @see UserStorageBase::getUser()
* $usr->employeeType: Pracownik, Kandydat, Partner, Anonymous
* Pracownik - all access
* Kandydat - no access
* Partner - access: smb/afp, TODO: calendar?, addressbook?
* Anonymous - no access
*/
public function createUser($usr) {
DBG::_('DBG_SU', '>1', 'usr', $usr, __CLASS__, __FUNCTION__, __LINE__);
$cmdDsclAuth = "dscl -u {$this->_rootUser} -P {$this->_rootPass} /LDAPv3/127.0.0.1 ";
$login = $this->_cleanUid($usr->login);
$name = $this->_cleanText($usr->name);
$type = $usr->employeeType;
$email = $usr->email;
$pass = $usr->password;
$uniqueID = 0;
// test user login and pass by searching for $uniqueID for new user
$cmd = "{$cmdDsclAuth} -list /Users > /dev/null && {$cmdDsclAuth} -list /Users UniqueID|awk '{print \$2}'|sort -n|tail -1 ";
$cmdOut = null; $cmdRet = null;
exec($cmd, $cmdOut, $cmdRet);
if ($cmdRet == 0 && !empty($cmdOut[0])) {
$uniqueID = intval($cmdOut[0]);
if ($uniqueID > 0) {
$uniqueID += 1;
}
}
if ($uniqueID <= 0) {
throw new Exception("Error: dscl auth - check login and password in ldap config");
}
if (empty($name)) {
$name = $login;
} else {
// TODO: replace bad signs str_replace($_SESSION['CONFIG']['BAD_FILE_SIGNS_LETTERS'],$_SESSION['CONFIG']['OK_FILE_SIGNS_LETTERS'],$ADM_NAME)
}
if (empty($pass)) {
$pass = $login;
}
$cmds = array();
//$cmds[] = "{$cmdDsclAuth} -create /Users/{$login} HomeDirectory \"groupsAll (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($groupsAll);echo'';
echo'groups (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($groups);echo'';
}
return $groups;
}
private function _groupNameRemoveID($groupName) {
if (substr($groupName, 0, 1) == '[' && strpos($groupName, ']')) {
$groupName = substr($groupName, strpos($groupName, ']') + 1);
$groupName = trim($groupName);
}
return $groupName;
}
private function _generateGroupName($id, $groupName) {
$groupNameShort = $groupName;
$groupNameShort = $this->_groupNameRemoveID($groupNameShort);
// TODO: polish chars - replace to ascii?
$groupNameShort = preg_replace('/[^a-zA-Z0-9_-]+/', '_', $groupNameShort);
// TODO: skrócić nazwę bo nie widać w aplikacji Server, np.
// RealName: [5] Typowe_stanowisko_obs_uguj_ce_Obieg_Dokument_w_do_implementacji_po_instalacji_systemu
// w apliakcji Server pokauje tylko "[5] ", tak samo w edycji
return "[{$id}] {$groupNameShort}";
}
private function _generateGroupUid($id, $groupName) {
$groupNameShort = $groupName;
$groupNameShort = $this->_groupNameRemoveID($groupNameShort);
$groupNameShort = str_replace(' ', '_', $groupNameShort);
$groupNameShort = preg_replace('/[^a-zA-Z0-9_-]+/', '_', $groupNameShort);
if (strlen($groupNameShort) > 30) {
$groupNameShort = substr($groupNameShort, 0, 30);
}
return "{$id}_{$groupNameShort}";
}
/**
* Create group.
*
* @param object $group @see getGroup
* @return bool
*
* @require $group->zasobID - Allowed only network group based on Zasob.
*/
public function createGroup(ObjectGroup $group) {
// TEST: $ dscl /LDAPv3/127.0.0.1 -list /Groups PrimaryGroupID
if ($group->zasobID <= 0) {
throw new Exception("Nie udało się utworzyć grupy sieciowej '{$group->primaryKey}' '{$group->realName}' - brak numery zasobu");
}
$groupName = $this->_generateGroupName($group->zasobID, $group->realName);
$groupUidGenerated = $this->_generateGroupUid($group->zasobID, $group->realName);
/*
* dseditgroup -o create -n /LDAPv3/ldap.company.com -u {$this->_rootUser} -P {$this->_rootPass} -r "Extra Group" -c "a nice comment" -k "some keyword" extragroup
* The group extragroup is created from the node /LDAPv3/ldap.company.com with the realname, comment,
* timetolive (instead of default of 14400 = 4 hours), and keyword atttribute values given above if the user
* myusername has supplied a correct password and has write access.
*
* -r realname
* This is a simple text string.
*
* -t recordtype
* The type of the record to be added to or deleted from the group specified by groupname. Valid values are user, computer, group, or computergroup.
*
*/
$cmd = "dseditgroup -o create -n /LDAPv3/127.0.0.1 -u {$this->_rootUser} -P {$this->_rootPass} -r \"{$groupName}\" {$groupUidGenerated}";
$cmdOut = null; $cmdRet = null;
exec($cmd, $cmdOut, $cmdRet);
DBG::_('DBG_SU', '>1', "create group cmd(" . str_replace($this->_rootPass, '***', $cmd) . ") ret({$cmdRet})", $cmdOut, __CLASS__, __FUNCTION__, __LINE__);
if ($cmdRet !== 0) {
throw new Exception("Nie udało się utworzyć grupy sieciowej '{$group->primaryKey}' '{$group->realName}'");
}
//$command8 = "dscl -u {$user} -P {$pass} /LDAPv3/127.0.0.1 -append /Groups/{$groupUid} GroupMembership {$ACCOUNT} ";
//$command8 = "dscl -u {$user} -P {$pass} /LDAPv3/127.0.0.1 -delete /Groups/{$groupUid} GroupMembership {$ACCOUNT} ";
//$command1 = "dscl -u {$user} -P {$pass} /LDAPv3/127.0.0.1 -create /Groups/{$groupUid} PrimaryGroupID {$PrimaryGroupID} ";
//$command2 = "dscl -u {$user} -P {$pass} /LDAPv3/127.0.0.1 -create /Groups/{$groupUid} RealName \"{$groupName}\" ";
}
private function _isGroupLocal($groupUid) {
$localGroups = array();
$localGroups[] = 'com.apple.access_mail';
$localGroups[] = 'com.apple.access_addressbook';
$localGroups[] = 'com.apple.access_calendar';
$localGroups[] = 'com.apple.access_smb';
$localGroups[] = 'com.apple.access_afp';
$localGroups[] = 'com.apple.access_vpn';
$localGroups[] = 'com.apple.access_chat';
//$localGroups[] = 'workgroup'; - Network Group
return in_array($groupUid, $localGroups);
}
/**
* Add local group member.
*
* @param string $usrLogin - user login
* @param object $group - @see getGroup
* @return bool
*
* @require sudoers dla _www
*
* cat /etc/sudoers |grep "'.$ADMIN_USERNAME.' ALL = NOPASSWD: /usr/bin/su" || echo "'.$ADMIN_USERNAME.' ALL = NOPASSWD: /usr/bin/su " >> /etc/sudoers;
* cat /etc/sudoers |grep "'.$ADMIN_USERNAME.' ALL = NOPASSWD: /usr/bin/su"
* cat /etc/sudoers |grep "_www ALL = NOPASSWD: /Applications/Server.app/Contents/ServerRoot/usr/sbin/calendarserver_manage_principals" || echo "_www ALL = NOPASSWD: /Applications/Server.app/Contents/ServerRoot/usr/sbin/calendarserver_manage_principals " >> /etc/sudoers;
* cat /etc/sudoers |grep "_www ALL = NOPASSWD: /Applications/Server.app/Contents/ServerRoot/usr/sbin/calendarserver_manage_principals"';
* cat /etc/sudoers |grep "_www ALL = NOPASSWD: /usr/bin/dscl" || echo "_www ALL = NOPASSWD: /usr/bin/dscl " >> /etc/sudoers;
* cat /etc/sudoers |grep "_www ALL = NOPASSWD: /usr/bin/dscl";
* cat /etc/sudoers |grep "_www ALL = NOPASSWD: /usr/bin/pwpolicy" || echo "_www ALL = NOPASSWD: /usr/bin/pwpolicy" >> /etc/sudoers;
* cat /etc/sudoers |grep "_www ALL = NOPASSWD: /usr/bin/pwpolicy";
* cat /etc/sudoers |grep "_www ALL = NOPASSWD: /usr/sbin/createhomedir" || echo "_www ALL = NOPASSWD: /usr/sbin/createhomedir" >> /etc/sudoers;
* cat /etc/sudoers |grep "_www ALL = NOPASSWD: /usr/sbin/createhomedir";
*
* cat /etc/sudoers |grep "_www ALL = NOPASSWD: /usr/sbin/dseditgroup" || echo "_www ALL = NOPASSWD: /usr/sbin/dseditgroup" >> /etc/sudoers;
* cat /etc/sudoers |grep "_www ALL = NOPASSWD: /usr/sbin/dseditgroup";
*/
private function _addUserGroupLocal($usrLogin, $group) {
if (!$group || empty($group->primaryKey) || empty($usrLogin)) return false;
$groupUid = $group->primaryKey;
$cmd = "sudo dscl /Local/Default -append /Groups/{$groupUid} GroupMembership {$usrLogin} ";
$cmdOut = null; $cmdRet = null;
exec($cmd, $cmdOut, $cmdRet);
if ($cmdRet != 0) {
throw new Exception("Nie udało się dodać usera '{$usrLogin}' do grupy lokalnej '{$groupUid}'");
}
}
/**
* Remove local group member.
*
* @param string $usrLogin - user login
* @param object $group - @see getGroup
* @return bool
*/
private function _removeUserGroupLocal($usrLogin, $group) {
if (!$group || empty($group->primaryKey) || empty($usrLogin)) return false;
$groupUid = $group->primaryKey;
//$cmd = "sudo dscl /Local/Default -delete /Groups/{$groupUid} GroupMembership {$usrLogin} 2>&1 ";
//$cmd = "dseditgroup -o edit -n /Local/Default -u diradmin -p ... -d username -t user {$groupUid} ";
$cmd = "sudo dseditgroup -o edit -n /Local/Default -d {$usrLogin} -t user {$groupUid} 2>&1 ";
// The group extragroup from the node /LDAPv3/ldap.company.com will have the username deleted if the correct
// password is presented interactively for the user myusername which also need to have write access.
// -t recordtype type of the record to add or delete
// -d recordname name of the record to delete
$cmdOut = null; $cmdRet = null;
exec($cmd, $cmdOut, $cmdRet);
DBG::_('DBG_SU', '>1', "cmd({$cmd}) ret({$cmdRet})", $cmdOut, __CLASS__, __FUNCTION__, __LINE__);
if ($cmdRet != 0) {
throw new Exception("Nie udało się dodać usera '{$usrLogin}' z grupy lokalnej '{$groupUid}'");
}
}
public function findGroupUidDscl($groupUid) {// not used @see findGroupUid
$groupRealUid = null;
$cmd = "dscl /LDAPv3/127.0.0.1 -list /Groups | grep '^{$groupUid}' ";
$cmdOut = null; $cmdRet = null;
exec($cmd, $cmdOut, $cmdRet);
if ($cmdRet != 0) {
$this->setError(1, "cmd failed - search for group by uid", '(' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . ')');
return false;
}
if (!empty($cmdOut)) {
foreach ($cmdOut as $vGroupUid) {
$vGroupID = $this->_getGroupIdFromUid($vGroupUid);
if (!empty($vGroupID) && $vGroupID == $groupUid) {
$groupRealUid = $vGroupUid;
break;
}
}
}
return $groupRealUid;
}
public function findGroupUidLdap($groupUid) {
$groupRealUid = null;
$groups = UsersLdapHelper::getGroupsByID($groupUid);
if (count($groups) == 1) {
$groupRealUid = reset($groups)->cn;
}
return $groupRealUid;
}
public function findGroupUid($groupUid) {
return $this->findGroupUidLdap($groupUid);
}
/**
* Add network group member.
*
* @param string $usrLogin - user login
* @param object $group - @see getGroup
* @return bool
*/
private function _addUserGroupNetwork($usrLogin, $group) {
if (!$group || empty($group->primaryKey) || empty($usrLogin)) return false;
$groupUid = $group->primaryKey;
$groupName = $group->realName;
$groupRealUid = '';
if ($group->type == 'network') {
$groupRealUid = $group->primaryKey;// workgroup
}
else if (is_numeric($groupUid)) {
$groupRealUid = $this->findGroupUid($groupUid);
}
if (!$groupRealUid) {
if ($group->type == 'network') {
throw new Exception("Brak dostępu do utworzenia grupy sieciowej '{$group->primaryKey}'");
} else if ($group->type == 'local') {
throw new Exception("Brak dostępu do utworzenia grupy lokalnej '{$group->primaryKey}'");
}
$this->createGroup($group);
}
$cmdDsclAuth = "dscl -u {$this->_rootUser} -P {$this->_rootPass} /LDAPv3/127.0.0.1 ";
$cmd = "{$cmdDsclAuth} -append /Groups/{$groupRealUid} GroupMembership {$usrLogin} ";
$cmdOut = null; $cmdRet = null;
exec($cmd, $cmdOut, $cmdRet);
if ($cmdRet != 0) {// TODO: may return 62 - user already in this group
throw new Exception("Nie udało się dodać usera '{$usrLogin}' do grupy sieciowej '{$groupUid}'");
}
}
/**
* Remove network group member.
*
* @param string $usrLogin - user login
* @param object $group - @see getGroup
* @return bool
*/
private function _removeUserGroupNetwork($usrLogin, $group) {
if (!$group || empty($group->primaryKey) || empty($usrLogin)) return false;
$groupUid = $group->primaryKey;
$cmdDsclAuth = "dscl -u {$this->_rootUser} -P {$this->_rootPass} /LDAPv3/127.0.0.1 ";
$cmd = "{$cmdDsclAuth} -delete /Groups/{$groupUid} GroupMembership {$usrLogin} ";
$cmdOut = null; $cmdRet = null;
exec($cmd, $cmdOut, $cmdRet);
DBG::_('DBG_SU', '>1', "cmd({$cmd}) ret({$cmdRet})", $cmdOut, __CLASS__, __FUNCTION__, __LINE__);
if ($cmdRet != 0) {
throw new Exception("Nie udało się dodać usera '{$usrLogin}' z grupy sieciowej '{$groupUid}'");
}
}
private function _removeUserUidFromGroupNetwork($usrAppleUid, $group) {
if (!$group || empty($group->primaryKey) || empty($usrAppleUid)) return false;
$groupUid = $group->primaryKey;
$cmdDsclAuth = "dscl -u {$this->_rootUser} -P {$this->_rootPass} /LDAPv3/127.0.0.1 ";
$cmd = "{$cmdDsclAuth} -delete /Groups/{$groupUid} GroupMembers {$usrAppleUid} ";
$cmdOut = null; $cmdRet = null;
exec($cmd, $cmdOut, $cmdRet);
DBG::_('DBG_SU', '>1', "cmd({$cmd}) ret({$cmdRet})", $cmdOut, __CLASS__, __FUNCTION__, __LINE__);
if ($cmdRet != 0) {
throw new Exception("Nie udało się usunąć uid '{$usrAppleUid}' z grupy sieciowej '{$groupUid}'");
}
}
/**
* Add group member.
*
* @param string $usrLogin - user login
* @param object $group - @see getGroup
* @return bool
*/
public function addUserGroup($usrLogin, $group) {
// $groupUid, $groupName
if ($group->type == 'local') {
return $this->_addUserGroupLocal($usrLogin, $group);
} else {
return $this->_addUserGroupNetwork($usrLogin, $group);
}
}
/**
* Remove group member.
*
* @param string $usrLogin - user login
* @param object $group - @see getGroup
* @return bool
*/
public function removeUserGroup($usrLogin, $group) {
if ($group->type == 'local') {
return $this->_removeUserGroupLocal($usrLogin, $group);
} else {
return $this->_removeUserGroupNetwork($usrLogin, $group);
}
}
public function removeUserUidFromGroup($usrLogin, $group) {
$rawUsrLdap = UsersLdapHelper::getUser($usrLogin, true);
$rawUsrLdap = (!empty($rawUsrLdap))? $rawUsrLdap[0] : null;
if (!$rawUsrLdap) throw new Exception("Cannot find user '{$usrLogin}'");
$usrAppleUid = V::get('apple-generateduid', '', $rawUsrLdap);
if (empty($usrAppleUid)) throw new Exception("Cannot find uid for user '{$usrLogin}'");
DBG::_('DBG_SU', '>0', "CleanupAppleMemberUidTodoList user apple-generateduid({$usrAppleUid})", $group, __CLASS__, __FUNCTION__, __LINE__);
if ($group->type == 'local') {
//return $this->_removeUserGroupLocal($usrLogin, $group);
} else {
return $this->_removeUserUidFromGroupNetwork($usrAppleUid, $group);
}
}
public function addNestedGroup($groupID, $nestedGroupID) {
if ($groupID <= 0) return false;
if ($nestedGroupID <= 0) return false;
$group = $this->_getGroup($groupID);
$groupNested = $this->_getGroup($nestedGroupID);
if (!$group || !$groupNested) {
return false;
}
$groupToAdd = $groupNested->primaryKey;
$groupName = $group->primaryKey;
// put a group called {$groupToAdd} into the {$groupName} group
$cmd = "dseditgroup -o edit -n /LDAPv3/127.0.0.1 -u {$this->_rootUser} -P {$this->_rootPass} -a {$groupToAdd} -t group {$groupName}";
$cmdOut = null; $cmdRet = null;
exec($cmd, $cmdOut, $cmdRet);
if ($cmdRet != 0) {
DBG::_('DBG_SU', '>1', "cmd(" . str_replace($this->_rootPass, '***', $cmd) . ") ret({$cmdRet})", $cmdOut, __CLASS__, __FUNCTION__, __LINE__);
$this->setError(1, "Nie udało się dodać grupy nadrzędnej '{$groupToAdd}' do grupy '{$groupName}' ", '(' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . ')');
return false;
}
return true;
}
public function removeNestedGroup($groupID, $nestedGroupID) {
if ($groupID <= 0) return false;
if ($nestedGroupID <= 0) return false;
$group = $this->_getGroup($groupID);
$groupNested = $this->_getGroup($nestedGroupID);
if (!$group || !$groupNested) {
return false;
}
$groupToRemove = $groupNested->primaryKey;
$groupName = $group->primaryKey;
// put a group called {$groupToAdd} into the {$groupName} group
$cmd = "dseditgroup -o edit -n /LDAPv3/127.0.0.1 -u {$this->_rootUser} -P {$this->_rootPass} -d {$groupToRemove} -t group {$groupName}";
$cmdOut = null; $cmdRet = null;
exec($cmd, $cmdOut, $cmdRet);
if ($cmdRet != 0) {
DBG::_('DBG_SU', '>1', "cmd(" . str_replace($this->_rootPass, '***', $cmd) . ") ret({$cmdRet})", $cmdOut, __CLASS__, __FUNCTION__, __LINE__);
$this->setError(1, "Nie udało się usunąć grupy podrzędnej '{$groupToRemove}' z grupy '{$groupName}' ", '(' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . ')');
return false;
}
return true;
}
public function changePassword($usrLogin, $passwd) {
$cmdDsclAuth = "dscl -u {$this->_rootUser} -P {$this->_rootPass} /LDAPv3/127.0.0.1 ";
$cmd = "{$cmdDsclAuth} -passwd /Users/{$usrLogin} \"{$passwd}\" ";
$cmdOut = null; $cmdRet = null;
exec($cmd, $cmdOut, $cmdRet);
if ($cmdRet != 0) {
return false;
}
return true;
}
}