_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); DBG::_('DBG_SU', '>2', "groupLdap", $group, __CLASS__, __FUNCTION__, __LINE__); $group = $this->_buildGroupFromLdap($group, $fetchNested); DBG::_('DBG_SU', '>2', "group", $group, __CLASS__, __FUNCTION__, __LINE__); } else if (count($groups) > 1) { DBG::_('DBG_SU', '>2', "Too much groups in ldap by ID {$groupID}", $groups, __CLASS__, __FUNCTION__, __LINE__); throw new Exception("Za dużo grup w bazie Ldap pasujących do grupy nr {$groupID}!"); } 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 \"afp://{$this->_host}/Users{$login}\" "; //$cmds[] = "{$cmdDsclAuth} -create /Users/{$login} NFSHomeDirectory /Network/Servers/{$this->_host}/Users/{$login} "; $cmds[] = "{$cmdDsclAuth} -create /Users/{$login} NFSHomeDirectory /Users/{$login} "; $cmds[] = "{$cmdDsclAuth} -create /Users/{$login} UserShell /bin/bash ";// TODO: bash? $cmds[] = "{$cmdDsclAuth} -create /Users/{$login} UniqueID {$uniqueID} "; $cmds[] = "{$cmdDsclAuth} -create /Users/{$login} PrimaryGroupID 20 ";// TODO: 20 maja domyslnie inne konta? $cmds[] = "{$cmdDsclAuth} -create /Users/{$login} RealName \"{$name}\" "; if (!empty($email)) $cmds[] = "{$cmdDsclAuth} -create /Users/{$login} EMailAddress {$email} "; $cmds[] = "{$cmdDsclAuth} -passwd /Users/{$login} \"{$pass}\" "; $cmds[] = "sudo /usr/sbin/createhomedir -c -u {$login} 2>&1 ";// TODO:INSTALATOR: add to sudoers _www ALL = NOPASSWD: /usr/sbin/createhomedir foreach ($cmds as $cmd) { $cmdOut = null; $cmdRet = null; exec($cmd, $cmdOut, $cmdRet); if ($cmdRet != 0) { DBG::_('DBG_SU', '>1', "cmd failed: " . str_replace($cmdDsclAuth, "dscl __auth__ ", $cmd), $cmdOut, __CLASS__, __FUNCTION__, __LINE__); throw new Exception("Wystąpił błąd podczas tworzenia użytwkonika '{$usrLogin}' w bazie Ldap"); } } } private function _getAdminLdap() { if (!$this->_ldapRoot) { $this->_ldapRoot = LDAP::getInstance(); if (!$this->_ldapRoot->bindDiradmin($errorMsg)) { // $errorMsg? $this->setError(1, "cant bind as diradmin", '(' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . ')'); return null; } } return $this->_ldapRoot; } public function updateUser($userName, $updateData) { if (empty($updateData)) return true; foreach ($updateData as $fldName => $val) { $val = trim($val); switch ($fldName) { case 'email': $ldap = $this->_getAdminLdap(); if ($ldap) { $attr = array(); $attr['mail'] = $val; $ldap->mod_replace($userName, $attr); } break; case 'name': $ldap = $this->_getAdminLdap(); if ($ldap) { $attr = array(); $attr['cn'] = $val; $ldap->mod_replace($userName, $attr); } break; case 'phone': $ldap = $this->_getAdminLdap(); if ($ldap) { $attr = array(); $attr['telephoneNumber'] = $val; $ldap->mod_replace($userName, $attr); } break; case 'employeeType': $ldap = $this->_getAdminLdap(); if ($ldap) { $attr = array(); $attr['employeeType'] = $val; $ldap->mod_replace($userName, $attr); } break; case 'password': if (!empty($val) && !$this->changePassword($userName, $val)) { $this->setError(1, "Nie udało się zmienić hasła dla usera '{$userName}'", '(' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . ')'); } break; case 'homeEmail': $ldap = $this->_getAdminLdap(); if ($ldap) { $attr = array(); $attr['carLicense'] = $val; if (!$ldap->mod_replace($userName, $attr)) { if (!$ldap->mod_add($userName, $attr)) { //$this->setError(1, "TODO: update homeEmail failed " . $ldap->error(), '(' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . ')'); } } } break; default: $this->setError(1, "TODO: update user {$userName} field {$fldName} to value '{$val}'", '(' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . ')'); } } if ($this->hasErrors()) { $this->setError(1, "Nie udało się zaktualizować danych usera '{$userName}'", '(' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . ')'); return false; } return true; } public function updateGroup($group, $updateData) { if (!$group) return false; if (empty($updateData)) return true; foreach ($updateData as $fldName => $val) { switch ($fldName) { case 'realName': $ldap = $this->_getAdminLdap(); if ($ldap) { $attr = array(); $attr['apple-group-realname'] = $val; $ldap->groupAttrUpdate($group->primaryKey, $attr); } break; default: $this->setError(1, "Błąd podczas aktulizacji grupy '{$group->primaryKey}' - pole '{$fldName}' watość '{$val}'", '#L' . __LINE__); } } return true; } private function _getGroupIdFromUid($groupUid) { if (empty($groupUid)) return null; if (!is_numeric(substr($groupUid, 0, 1))) return null; $tmp = str_replace(array('-', '_'), '_', $groupUid); $tmp = explode('_', $tmp); $tmp = reset($tmp); if (!empty($tmp) && is_numeric($tmp)) { return $tmp; } return null; } /** * User group list by id. * * @param bool $fetchNested - contain all groups below connected groups and group PODMIOT from above. * * @return array with group objects @see getGroup */ public function getUserGroups($usrLogin, $fetchNested = false) { $groups = array(); $groupsNetwork = $this->_getUserGroupsNetwork($usrLogin); $groupsLocal = $this->_getUserGroupsLocal($usrLogin); foreach ($groupsLocal as $kGroupUid => $vGroup) { $groups[$kGroupUid] = $vGroup; } foreach ($groupsNetwork as $kGroupUid => $vGroupNetwork) { if ($vGroupNetwork->primaryKey == 'workgroup') { $groups[$vGroupNetwork->primaryKey] = $vGroupNetwork; } else if ($vGroupNetwork->zasobID > 0) { $groups[$vGroupNetwork->zasobID] = $vGroupNetwork; } } DBG::_('DBG_SU', '>2', "groupsNetwork", array_keys($groupsNetwork), __CLASS__, __FUNCTION__, __LINE__); DBG::_('DBG_SU', '>2', "groupsLocal", array_keys($groupsLocal), __CLASS__, __FUNCTION__, __LINE__); return $groups; } /** * Build network group object. * * @param object $groupDB {ID, DESC} @see _getUserGroupsAll * @return object $group @see getGroup * * Example: _buildGroupFromLdap($groupLdap) => {@see getGroup} */ private function _buildGroupFromLdap($groupLdap, $fetchNested = false) { $group = new ObjectGroupLdap('MacOSX'); $group->primaryKey = $groupLdap->cn; $group->realName = V::get('realName', '', $groupLdap); $group->zasobID = $this->_getGroupIdFromUid($groupLdap->cn); $group->type = 'unknown';// TODO: try to fetch from name or from ldap attribute if ($groupLdap->cn == 'workgroup') $group->type = 'network'; if ($fetchNested && !empty($groupLdap->nestedGroups)) { $group->nestedGroups = $this->_fetchNestedGroupsByAppleUids($groupLdap->nestedGroups); } $group->setLdapUID($groupLdap->appleUID); return $group; } public function getGroupsByUserUid($usrLogin) { $groups = array(); $rawUsrLdap = UsersLdapHelper::getUser($usrLogin, true); $rawUsrLdap = (!empty($rawUsrLdap))? $rawUsrLdap[0] : null; if (!$rawUsrLdap) return $groups; $usrAppleUid = V::get('apple-generateduid', '', $rawUsrLdap); DBG::_('DBG_SU', '>0', "CleanupAppleMemberUidTodoList user apple-generateduid({$usrAppleUid})", $rawUsrLdap, __CLASS__, __FUNCTION__, __LINE__); if (empty($usrAppleUid)) return $groups; $groupsLdap = UsersLdapHelper::getUserGroupsByAppleUid($usrAppleUid, 0); foreach ($groupsLdap as $groupLdap) { $group = $this->_buildGroupFromLdap($groupLdap); if ($group->zasobID > 0) { $groups[$group->zasobID] = $group; } } return $groups; } private function _fetchNestedGroupsByAppleUids($appleUids) { $groups = array(); if (!is_array($appleUids)) $appleUids = array($appleUids); $groupsLdap = UsersLdapHelper::getGroupsByAppleUids($appleUids); foreach ($groupsLdap as $vGroupLdap) { $group = $this->_buildGroupFromLdap($vGroupLdap, $fetchNested = false); if ($group && $group->zasobID > 0) { $groups[$group->zasobID] = $group; } } return $groups; } /** * @param string $usrLogin - user login * @return array of group objects @see getGroup */ private function _getUserGroupsNetwork($usrLogin) { $groups = array(); $groupsNetwork = UsersLdapHelper::getUserGroups($usrLogin, 0); foreach ($groupsNetwork as $vGroupNetwork) { $groups[$vGroupNetwork->cn] = $this->_buildGroupFromLdap($vGroupNetwork); } return $groups; } /** * @param string $usrLogin - user login * @return array of group objects @see getGroup */ private function _getUserGroupsLocal($usrLogin) { $groups = array(); $allGroups = $this->_fetchAllUserGroups($usrLogin); foreach ($allGroups as $groupName) { if ($this->_isGroupLocal($groupName)) { $groups[$groupName] = $this->_buildGroupLocal($groupName); } } DBG::_('DBG_SU', '>1', "User '{$usrLogin}' GroupsLocal:", $groups, __CLASS__, __FUNCTION__, __LINE__); return $groups; } private function _fetchAllUserGroups($usrLogin) { $groups = array(); $cmd = "groups {$usrLogin}"; $cmdOut = null; $cmdRet = null; exec($cmd, $cmdOut, $cmdRet); if ($cmdRet == 0 && !empty($cmdOut[0])) { $groupsCmd = explode(' ', $cmdOut[0]); foreach ($groupsCmd as $groupName) { if (!empty($groupName)) { $groups[] = $groupName; } } } DBG::_('DBG_SU', '>1', "User '{$usrLogin}' all groups:", $groups, __CLASS__, __FUNCTION__, __LINE__); return $groups; } public function getUserGroupsWithNested($usrLogin) {// TODO: NOT USED $groups = array(); $groupsAll = array(); $cmd = "groups {$usrLogin}"; $cmdOut = null; $cmdRet = null; exec($cmd, $cmdOut, $cmdRet); if ($cmdRet == 0 && !empty($cmdOut[0])) { $pominGrupy = array('staff','everyone','netaccounts'); $groupsCmd = explode(' ', $cmdOut[0]); foreach ($groupsCmd as $group) { $groupsAll[] = $group; $groupID = $this->_getGroupIdFromUid($group); if (!empty($groupID)) { $groups[$groupID] = $group; } else if ('workgroup' == $group) { $groups[$group] = $group; } else if (substr($group, 0, strlen('com.apple.access_')) == 'com.apple.access_') { $groups[$group] = $group; } } } DBG::_('DBG_SU', '>1', "groupsAll", $groupsAll, __CLASS__, __FUNCTION__, __LINE__); DBG::_('DBG_SU', '>1', "groups", $groups, __CLASS__, __FUNCTION__, __LINE__); 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; } }