You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
calculate-utils-3-client/pym/client/client_cache.py

747 lines
28 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# -*- coding: utf-8 -*-
# Copyright 2012-2016 Mir Calculate. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import sys
import time
from calculate.lib.utils.files import getModeFile
from calculate.lib.cl_ldap import ldapUser
from calculate.lib.cl_lang import setLocalTranslate
_ = lambda x: x
setLocalTranslate('cl_client3', sys.modules[__name__])
class Printable(object):
def __init__(self, parent):
if isinstance(parent, Printable):
self.parent = parent.parent
self.parent = parent
def printERROR(self, s):
self.parent.printERROR(s)
class _shareData(Printable):
"""Share class"""
fileName = ""
template = ""
lenData = 0
data = []
def getDataInFile(self, fileName='', lenData=0):
"""Get data list from file"""
return filter(lambda x: len(x) == lenData,
map(lambda x: x.rstrip().split(":"), open(fileName)))
def getFileAccess(self, perm="READ"):
if perm == "READ":
if os.access(self.fileName, os.R_OK):
return True
else:
self.printERROR(_("Failed to read the file") + _(": ") +
self.fileName)
return False
elif perm == "WRITE":
if os.access(self.fileName, os.W_OK):
return True
else:
self.printERROR(_("Failed to write to file") + _(": ") +
self.fileName)
return False
def getData(self):
if id(_shareData.data) == id(self.data):
self.data = self.data[:]
if self.data:
return self.data
elif self.getFileAccess(perm="READ"):
self.data = self.getDataInFile(fileName=self.fileName,
lenData=self.lenData)
return self.data
else:
return False
def save(self):
if self.getFileAccess(perm="WRITE"):
buff = "\n".join(map(lambda x: ":".join(x), self.data)) + "\n"
FD = open(self.fileName, "w+")
FD.write(buff)
FD.close()
return True
else:
return False
def delete(self, name):
if self.getData() is False:
return False
else:
self.data = filter(lambda x: x[0] != name, self.data)
return True
def replace(self, name, listData):
if self.getData() is False:
return False
else:
flagFound = False
for index, listDataOld in enumerate(self.data):
if name == listDataOld[0]:
flagFound = True
if not self.equally(listData, self.data[index]):
self.data[index] = listData
if flagFound:
return True
else:
return None
def equally(self, listDataA, listDataB):
if set(listDataA) == set(listDataB):
return True
else:
return False
def get(self, name):
if self.getData() is False:
return False
else:
listData = filter(lambda x: x[0] == name, self.data)
if listData:
return listData[0]
else:
return []
class passwd(_shareData):
'''Class for working with the file /etc/passwd'''
fileName = "/etc/passwd"
template = "%(login)s:x:%(uid)s:%(gid)s:%(gecos)s:%(directory)s:%(shell)s"
lenData = 7
def add(self, name, uid, gid, gecos="", directory="", shell="/bin/bash"):
if not directory:
directory = "/home/%s" % name
userData = self.template % {'login': name, 'uid': uid, 'gid': gid,
'gecos': gecos, 'directory': directory,
'shell': shell}
userList = userData.split(":")
if self.getData() is False:
return False
else:
ret = self.replace(name, userList)
if ret is False:
return False
elif ret is None:
self.data.append(userList)
return True
class group(_shareData):
'''Class for working with the file /etc/group'''
fileName = "/etc/group"
template = "%(group_name)s:x:%(gid)s:%(user_list)s"
lenData = 4
def add(self, name, gid, userList=()):
groupData = self.template % {'group_name': name, 'gid': gid,
'user_list': ','.join(userList)}
groupList = groupData.split(":")
if self.getData() is False:
return False
else:
ret = self.replace(name, groupList)
if ret is False:
return False
elif ret is None:
self.data.append(groupList)
return True
def replace(self, name, listData):
if self.getData() is False:
return False
else:
delEmpty = lambda y: filter(lambda x: x.strip(), y)
flagFound = False
for index, listDataOld in enumerate(self.data):
if name == listDataOld[0]:
flagFound = True
if not self.equally(listData, self.data[index]):
listDataWork = listData[:]
listDataWork[1] = self.data[index][1]
# Constant gid
listDataWork[2] = self.data[index][2]
# Join user list
userList = delEmpty(self.data[index][3].split(',') +
listDataWork[3].split(','))
# unique list
userList = reduce(lambda x, y: \
(y in x and x) or x + [y],
userList, [])
listDataWork[3] = ','.join(userList)
self.data[index] = listDataWork
if flagFound:
return True
else:
return None
def equally(self, listDataA, listDataB):
getData = lambda x: x[:1] + x[3:]
return _shareData.equally(self, getData(listDataA),
getData(listDataB))
def getSecondUserGroups(self, userName):
"""get all second user groups"""
if self.getData() is False:
return False
else:
userGroups = []
for group, x, gid, userList in self.data:
usersInGroup = userList.split(",")
if userName in usersInGroup:
userGroups.append(group)
return userGroups
def getUsersInGroup(self, name):
if self.getData() is False:
return False
else:
dataGroup = map(lambda x: x[3].split(","),
filter(lambda x: x[0] == name, self.data))
if dataGroup:
return dataGroup[0]
else:
return []
def deleteUserInGroups(self, userName, groups):
if self.getData() is False:
return False
else:
data = []
for dataList in self.data:
groupName, x, gid, userList = dataList
if groupName in groups:
usersList = ",".join(filter(lambda x: x != userName,
userList.split(",")))
dataList[3] = usersList
data.append(dataList)
self.data = data
return self.data
class shadow(_shareData):
'''Class for working with the file /etc/shadow'''
fileName = "/etc/shadow"
template = ("%(login)s:%(hash)s:%(shadowLastChange)s:"
"%(shadowMin)s:%(shadowMax)s:%(shadowWarning)s:::")
lenData = 9
def add(self, name, pwdHash,
shadowLastChange=str(int(time.time() / 86400)), shadowMin="0",
shadowMax="99999", shadowWarning="7"):
shadowData = self.template % {'login': name, 'hash': pwdHash,
'shadowLastChange': shadowLastChange,
'shadowMin': shadowMin,
'shadowMax': shadowMax,
'shadowWarning': shadowWarning}
shadowList = shadowData.split(":")
if self.getData() is False:
return False
else:
ret = self.replace(name, shadowList)
if ret is False:
return False
elif ret is None:
self.data.append(shadowList)
return True
def equally(self, listDataA, listDataB):
getData = lambda x: x[:1] + x[2:]
return _shareData.equally(self, getData(listDataA),
getData(listDataB))
class _shareCache(_shareData):
def save(self):
path = os.path.dirname(self.fileName)
if not os.path.exists(path):
try:
os.makedirs(path)
except OSError:
self.printERROR(_("Failed to create directory %s") % path)
return False
if not os.path.exists(self.fileName):
try:
open(self.fileName, "w").close()
except IOError:
self.printERROR(_("Failed to create file %s") % self.fileName)
return False
if self.getFileAccess(perm="WRITE"):
modeFile = 0600
if getModeFile(self.fileName, mode="mode") != modeFile:
os.chmod(self.fileName, modeFile)
buff = "\n".join(map(lambda x: ":".join(x), self.data)) + "\n"
FD = open(self.fileName, "w+")
FD.write(buff)
FD.close()
return True
else:
return False
def getData(self):
if id(_shareData.data) == id(self.data):
self.data = self.data[:]
if self.data:
return self.data
elif not os.path.exists(self.fileName):
return self.data
elif self.getFileAccess(perm="READ"):
self.data = self.getDataInFile(fileName=self.fileName,
lenData=self.lenData)
return self.data
else:
return False
class cachePasswd(_shareCache, passwd):
fileName = "/var/lib/calculate/calculate-client/cache/passwd"
class cacheGroup(_shareCache, group):
fileName = "/var/lib/calculate/calculate-client/cache/group"
def replace(self, name, listData):
return _shareData.replace(self, name, listData)
def equally(self, listDataA, listDataB):
return _shareData.equally(self, listDataA, listDataB)
class cacheShadow(_shareCache, shadow):
fileName = "/var/lib/calculate/calculate-client/cache/shadow"
class cacheCreateGroup(cacheGroup):
fileName = "/var/lib/calculate/calculate-client/cache/create_group"
class cacheCreatePasswd(cachePasswd):
fileName = "/var/lib/calculate/calculate-client/cache/create_passwd"
class userCache(Printable):
ldapObj = ldapUser()
def addUserToCache(self, userName, pwdHash):
'''Add LDAP user to cache'''
ldapData = self.ldapObj.getUserLdapInfo(userName, shadowAttr=True)
if not ldapData:
self.printERROR(_("User %s not found in LDAP") % userName)
return False
groupName = ldapData['group']
# Add user
cachePasswdObj = cachePasswd(self)
if not cachePasswdObj.add(userName, ldapData['uid'], ldapData['gid'],
gecos=ldapData['fullName'],
directory=ldapData['home'],
shell=ldapData['loginShell']):
return False
if not cachePasswdObj.save():
return False
cacheGroupObj = cacheGroup(self)
# Add primary group
if not cacheGroupObj.add(groupName, ldapData['gid']):
return False
# Add second groups
secondGroupsData = ldapData['groups']
cacheSecondUserGroups = cacheGroupObj.getSecondUserGroups(userName)
deleteSecondGroups = cacheSecondUserGroups
if secondGroupsData:
allUsersSecondGroups = []
for groupName, gid in secondGroupsData:
usersInGroup = cacheGroupObj.getUsersInGroup(groupName)
if usersInGroup is False:
return False
if not userName in usersInGroup:
usersInGroup.append(userName)
if not cacheGroupObj.add(groupName, gid, usersInGroup):
return False
allUsersSecondGroups.append(groupName)
deleteSecondGroups = list(set(cacheSecondUserGroups) - \
set(allUsersSecondGroups))
if not cacheGroupObj.deleteUserInGroups(userName, deleteSecondGroups):
return False
if not cacheGroupObj.save():
return False
# Add shadow user
cacheShadowObj = cacheShadow(self)
if not cacheShadowObj.add(userName, pwdHash,
shadowLastChange=ldapData['shadowLastChange'],
shadowMin=ldapData['shadowMin'],
shadowMax=ldapData['shadowMax'],
shadowWarning=ldapData['shadowWarning']):
return False
if not cacheShadowObj.save():
return False
return True
def delUserFromCacheCreate(self, userName):
'''Delete LDAP user from createCache'''
cacheCreatePasswdObj = cacheCreatePasswd(self)
cacheUserData = cacheCreatePasswdObj.get(userName)
if cacheUserData is False:
return False
if not cacheUserData:
return True
gid = cacheUserData[3]
cacheCreateGroupObj = cacheCreateGroup(self)
cacheSecondGroups = cacheCreateGroupObj.getSecondUserGroups(userName)
if cacheSecondGroups is False:
return False
# delete user in second groups
if not cacheCreateGroupObj.deleteUserInGroups(userName,
cacheSecondGroups):
return False
# delete user
if not cacheCreatePasswdObj.delete(userName):
return False
if not cacheCreatePasswdObj.save():
return False
# delete groups
usersGids = map(lambda x: x[3], cacheCreatePasswdObj.data)
deleteGroups = map(lambda x: x[0],
filter(lambda x: not x[2] in usersGids and not x[3],
cacheCreateGroupObj.data))
for delGroupName in deleteGroups:
if not cacheCreateGroupObj.delete(delGroupName):
return False
if not cacheCreateGroupObj.save():
return False
return True
def delUserFromCache(self, userName):
'''Delete LDAP user from cache'''
cachePasswdObj = cachePasswd(self)
cacheUserData = cachePasswdObj.get(userName)
if cacheUserData is False:
return False
if not cacheUserData:
return True
gid = cacheUserData[3]
cacheGroupObj = cacheGroup(self)
cacheSecondGroups = cacheGroupObj.getSecondUserGroups(userName)
if cacheSecondGroups is False:
return False
# delete user in second groups
if not cacheGroupObj.deleteUserInGroups(userName, cacheSecondGroups):
return False
# delete user
if not cachePasswdObj.delete(userName):
return False
if not cachePasswdObj.save():
return False
# delete groups
usersGids = map(lambda x: x[3], cachePasswdObj.data)
deleteGroups = map(lambda x: x[0],
filter(lambda x: not x[2] in usersGids and not x[3],
cacheGroupObj.data))
for delGroupName in deleteGroups:
if not cacheGroupObj.delete(delGroupName):
return False
if not cacheGroupObj.save():
return False
# delete shadow user
cacheShadowObj = cacheShadow(self)
if not cacheShadowObj.delete(userName):
return False
if not cacheShadowObj.save():
return False
return True
def delUserFromSystem(self, userName):
'''Delete LDAP user from system files ( passwd, group, shadow )'''
cacheCreatePasswdObj = cacheCreatePasswd(self)
cacheCreatePasswdData = cacheCreatePasswdObj.get(userName)
if cacheCreatePasswdData is False:
return False
if not cacheCreatePasswdData:
return True
passwdObj = passwd(self)
userData = passwdObj.get(userName)
if userData is False:
return False
# delete user
if not userData:
return True
if not passwdObj.delete(userName):
return False
if not passwdObj.save():
return False
# delete user group
groupObj = group(self)
listGroupData = groupObj.getData()
if listGroupData is False:
return False
cacheCreateGroupObj = cacheCreateGroup(self)
secondUsersGroups = groupObj.getSecondUserGroups(userName)
usersGids = map(lambda x: x[3], passwdObj.data)
listGroupDataWork = []
for index, groupData in enumerate(listGroupData):
groupName, x, gid, listUsers = groupData
listUsers = filter(lambda x: x.strip(), listUsers.split(','))
listUsers = ",".join(filter(lambda x: x != userName, listUsers))
cacheCreateGroupData = cacheCreateGroupObj.get(groupName)
if cacheCreateGroupData is False:
return False
if groupName in cacheCreateGroupData:
if not gid in usersGids and not listUsers:
continue
listGroupDataWork.append([groupName, x, gid, listUsers])
groupObj.data = listGroupDataWork
if not groupObj.save():
return False
# delete user shadow
shadowObj = shadow(self)
shadowData = shadowObj.get(userName)
if shadowData is False:
return False
if not shadowData:
return True
if not shadowObj.delete(userName):
return False
if not shadowObj.save():
return False
if not self.delUserFromCacheCreate(userName):
return False
return True
def isConnectToLdap(self):
connectData = self.ldapObj.getBindConnectData()
if not connectData:
return {}
bindDn, bindPw, host = connectData
usersDN = self.ldapObj.getUsersDN()
groupsDNs = self.ldapObj.getGroupsDN()
# Соединяемся с LDAP
if not self.ldapObj.ldapConnect(bindDn, bindPw, host):
return False
return True
def deleteCacheUsersFromSystem(self):
'''Delete cache users from system'''
cacheCreatePasswdObj = cacheCreatePasswd(self)
cacheCreateListPasswdData = cacheCreatePasswdObj.getData()
if cacheCreateListPasswdData is False:
return False
delUsersPasswd = map(lambda x: x[0], cacheCreateListPasswdData)
for delUser in delUsersPasswd:
if not self.delUserFromSystem(delUser):
return False
return True
def getLoginDomainUsers(self):
'''Get all domain login users'''
cacheCreatePasswdObj = cacheCreatePasswd(self)
cacheListCreatePasswdData = cacheCreatePasswdObj.getData()
if cacheListCreatePasswdData is False:
return False
return cacheListCreatePasswdData
def addCacheUsersFromSystem(self):
'''Add cache users from system'''
cachePasswdObj = cachePasswd(self)
cacheListPasswdData = cachePasswdObj.getData()
if not isinstance(cacheListPasswdData, (list, tuple)):
return False
# Add cache passwd users to system
passwdObj = passwd(self)
cacheCreatePasswdObj = cacheCreatePasswd(self)
cacheListCreatePasswdData = cacheCreatePasswdObj.getData()
if cacheListCreatePasswdData is False:
return False
# remove deleted users
cacheUsers = map(lambda x: x[0], cacheListPasswdData)
createUsers = map(lambda x: x[0], cacheListCreatePasswdData)
deletedUsers = list(set(createUsers) - set(cacheUsers))
for delUser in deletedUsers:
if not self.delUserFromSystem(delUser):
return False
if not self.delUserFromCache(delUser):
return False
addUsers = []
addUsersGid = []
notAddUsers = []
for cachePasswdData in cacheListPasswdData:
userName, x, uid, gid, gecos, directory, shell = cachePasswdData
retPasswd = passwdObj.get(userName)
if retPasswd is False:
return False
if not retPasswd:
if not cacheCreatePasswdObj.add(userName, uid, gid,
gecos=gecos,
directory=directory,
shell=shell):
return False
retCacheCreate = cacheCreatePasswdObj.get(userName)
if retCacheCreate is False:
return False
if retCacheCreate:
if not passwdObj.add(userName, uid, gid,
gecos=gecos,
directory=directory,
shell=shell):
return False
addUsers.append(userName)
addUsersGid.append(gid)
else:
notAddUsers.append(userName)
if passwdObj.data:
if not passwdObj.save():
return False
if not cacheCreatePasswdObj.save():
return False
cacheShadowObj = cacheShadow(self)
cacheListShadowData = cacheShadowObj.getData()
if not isinstance(cacheListShadowData, (list, tuple)):
return False
# Add cache shadow users to system
shadowObj = shadow(self)
for cacheShadowData in cacheListShadowData:
userName, pwdHash, shadowLastChange, shadowMin, shadowMax, \
shadowWarning, x, x, x = cacheShadowData
if userName in addUsers:
if not shadowObj.add(userName, pwdHash,
shadowLastChange=shadowLastChange,
shadowMin=shadowMin,
shadowMax=shadowMax,
shadowWarning=shadowWarning):
return False
if shadowObj.data:
if not shadowObj.save():
return False
cacheGroupObj = cacheGroup(self)
cacheListGroupData = cacheGroupObj.getData()
if not isinstance(cacheListGroupData, (list, tuple)):
return False
cacheCreateGroupObj = cacheCreateGroup(self)
# Add cache group users to system
groupObj = group(self)
setAddUsers = set(addUsers)
for cacheGroupData in cacheListGroupData:
groupName, x, gid, listUsers = cacheGroupData
retGroup = groupObj.get(groupName)
if retGroup is False:
return False
listUsers = filter(lambda x: x.strip(), listUsers.split(','))
if setAddUsers & set(listUsers) or gid in addUsersGid:
listUsers = filter(lambda x: not x in notAddUsers, listUsers)
if not retGroup:
if not cacheCreateGroupObj.add(groupName, gid, listUsers):
return False
if not groupObj.add(groupName, gid, listUsers):
return False
if groupObj.data:
if not groupObj.save():
return False
if cacheCreateGroupObj.data:
if not cacheCreateGroupObj.save():
return False
return True
def syncCacheToLdap(self):
'''Compare cache users to LDAP users.
Deleting a user from the cache when the differences'''
if not self.isConnectToLdap():
self.printERROR(_("Failed to connect to the LDAP server"))
return False
cachePasswdObj = cachePasswd(self)
cacheListPasswdData = cachePasswdObj.getData()
if cacheListPasswdData is False:
return False
if (not isinstance(cacheListPasswdData, (tuple, list)) or
not cacheListPasswdData):
return True
cacheGroupObj = cacheGroup(self)
cacheListGroupData = cacheGroupObj.getData()
if cacheListGroupData is False:
return False
cacheShadowObj = cacheShadow(self)
deletedCacheUsers = []
for cachePasswdData in cacheListPasswdData:
userName, x, uid, gid, gecos, directory, shell = cachePasswdData
ldapData = self.ldapObj.getUserLdapInfo(userName, shadowAttr=True)
if not ldapData:
deletedCacheUsers.append(userName)
continue
cacheGroupData = map(lambda x: x[0], filter(lambda x: x[2] == gid,
cacheListGroupData))
if not cacheGroupData:
deletedCacheUsers.append(userName)
continue
groupName = cacheGroupData[0]
cacheShadowData = cacheShadowObj.get(userName)
if cacheShadowData is False:
return False
if not cacheShadowData:
deletedCacheUsers.append(userName)
continue
x, x, shadowLastChange, shadowMin, shadowMax, shadowWarning, \
x, x, x = cacheShadowData
groups = cacheGroupObj.getSecondUserGroups(userName)
gidsGroups = map(lambda x: x[2],
filter(lambda x: x[0] in groups,
cacheGroupObj.data))
userShadowDict = {'uid': uid,
'gid': gid,
'fullName': gecos,
'home': directory,
'group': groupName,
'groups': (groups, gidsGroups),
'loginShell': shell,
'shadowLastChange': shadowLastChange,
'shadowMin': shadowMin,
'shadowMax': shadowMax,
'shadowWarning': shadowWarning}
flagDeleteUser = False
for attr, value in userShadowDict.items():
if attr == "groups":
for index, val in enumerate(value):
if set(map(lambda x: x[index],
ldapData[attr])) != set(val):
flagDeleteUser = True
break
else:
if ldapData[attr] != value:
flagDeleteUser = True
break
if flagDeleteUser:
deletedCacheUsers.append(userName)
continue
# Deleted cache users
for delUserName in deletedCacheUsers:
if not self.delUserFromCache(delUserName):
return False
return True
def clearCache(self):
'''Clear cache files'''
cacheObjs = (cachePasswd(self), cacheShadow(self), cacheGroup(self),
cacheCreateGroup(self), cacheCreatePasswd(self))
for cacheObj in cacheObjs:
if not cacheObj.save():
return False
return True