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

9 years ago
# -*- 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.
9 years ago
import os
import sys
import time
12 years ago
from calculate.lib.utils.files import getModeFile
9 years ago
from calculate.lib.cl_ldap import ldapUser
12 years ago
from calculate.lib.cl_lang import setLocalTranslate
9 years ago
_ = 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"""
9 years ago
fileName = ""
template = ""
lenData = 0
data = []
def getDataInFile(self, fileName='', lenData=0):
"""Get data list from file"""
9 years ago
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:
9 years ago
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:
9 years ago
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)
9 years ago
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"
9 years ago
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:
9 years ago
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:
9 years ago
listData = filter(lambda x: x[0] == name, self.data)
if listData:
return listData[0]
else:
return []
9 years ago
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:
9 years ago
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
9 years ago
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
9 years ago
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
9 years ago
userList = delEmpty(self.data[index][3].split(',') +
listDataWork[3].split(','))
# unique list
9 years ago
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(","),
9 years ago
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:
9 years ago
usersList = ",".join(filter(lambda x: x != userName,
userList.split(",")))
dataList[3] = usersList
data.append(dataList)
self.data = data
return self.data
9 years ago
class shadow(_shareData):
'''Class for working with the file /etc/shadow'''
fileName = "/etc/shadow"
9 years ago
template = ("%(login)s:%(hash)s:%(shadowLastChange)s:"
"%(shadowMin)s:%(shadowMax)s:%(shadowWarning)s:::")
lenData = 9
def add(self, name, pwdHash,
9 years ago
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):
9 years ago
getData = lambda x: x[:1] + x[2:]
return _shareData.equally(self, getData(listDataA),
getData(listDataB))
9 years ago
class _shareCache(_shareData):
def save(self):
path = os.path.dirname(self.fileName)
if not os.path.exists(path):
try:
os.makedirs(path)
9 years ago
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()
9 years ago
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"
9 years ago
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
9 years ago
class cachePasswd(_shareCache, passwd):
fileName = "/var/lib/calculate/calculate-client/cache/passwd"
9 years ago
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)
9 years ago
class cacheShadow(_shareCache, shadow):
fileName = "/var/lib/calculate/calculate-client/cache/shadow"
9 years ago
class cacheCreateGroup(cacheGroup):
fileName = "/var/lib/calculate/calculate-client/cache/create_group"
9 years ago
class cacheCreatePasswd(cachePasswd):
fileName = "/var/lib/calculate/calculate-client/cache/create_passwd"
9 years ago
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:
9 years ago
self.printERROR(_("User %s not found in LDAP") % userName)
return False
9 years ago
groupName = ldapData['group']
# Add user
9 years ago
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
9 years ago
cacheGroupObj = cacheGroup(self)
# Add primary group
9 years ago
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)
9 years ago
deleteSecondGroups = list(set(cacheSecondUserGroups) - \
set(allUsersSecondGroups))
if not cacheGroupObj.deleteUserInGroups(userName, deleteSecondGroups):
return False
if not cacheGroupObj.save():
return False
# Add shadow user
9 years ago
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'''
9 years ago
cacheCreatePasswdObj = cacheCreatePasswd(self)
cacheUserData = cacheCreatePasswdObj.get(userName)
if cacheUserData is False:
return False
if not cacheUserData:
return True
gid = cacheUserData[3]
9 years ago
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
9 years ago
# 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:
9 years ago
if not cacheCreateGroupObj.delete(delGroupName):
return False
if not cacheCreateGroupObj.save():
return False
return True
def delUserFromCache(self, userName):
'''Delete LDAP user from cache'''
9 years ago
cachePasswdObj = cachePasswd(self)
cacheUserData = cachePasswdObj.get(userName)
if cacheUserData is False:
return False
if not cacheUserData:
return True
gid = cacheUserData[3]
9 years ago
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
9 years ago
# 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:
9 years ago
if not cacheGroupObj.delete(delGroupName):
return False
if not cacheGroupObj.save():
return False
# delete shadow user
9 years ago
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 )'''
9 years ago
cacheCreatePasswdObj = cacheCreatePasswd(self)
14 years ago
cacheCreatePasswdData = cacheCreatePasswdObj.get(userName)
if cacheCreatePasswdData is False:
return False
14 years ago
if not cacheCreatePasswdData:
return True
9 years ago
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
9 years ago
groupObj = group(self)
listGroupData = groupObj.getData()
if listGroupData is False:
return False
9 years ago
cacheCreateGroupObj = cacheCreateGroup(self)
secondUsersGroups = groupObj.getSecondUserGroups(userName)
9 years ago
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(','))
9 years ago
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
9 years ago
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'''
9 years ago
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
14 years ago
def getLoginDomainUsers(self):
'''Get all domain login users'''
9 years ago
cacheCreatePasswdObj = cacheCreatePasswd(self)
14 years ago
cacheListCreatePasswdData = cacheCreatePasswdObj.getData()
if cacheListCreatePasswdData is False:
return False
return cacheListCreatePasswdData
def addCacheUsersFromSystem(self):
'''Add cache users from system'''
9 years ago
cachePasswdObj = cachePasswd(self)
cacheListPasswdData = cachePasswdObj.getData()
9 years ago
if not isinstance(cacheListPasswdData, (list, tuple)):
return False
# Add cache passwd users to system
9 years ago
passwdObj = passwd(self)
cacheCreatePasswdObj = cacheCreatePasswd(self)
cacheListCreatePasswdData = cacheCreatePasswdObj.getData()
14 years ago
if cacheListCreatePasswdData is False:
return False
# remove deleted users
cacheUsers = map(lambda x: x[0], cacheListPasswdData)
9 years ago
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,
9 years ago
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
9 years ago
cacheShadowObj = cacheShadow(self)
cacheListShadowData = cacheShadowObj.getData()
9 years ago
if not isinstance(cacheListShadowData, (list, tuple)):
return False
# Add cache shadow users to system
9 years ago
shadowObj = shadow(self)
for cacheShadowData in cacheListShadowData:
9 years ago
userName, pwdHash, shadowLastChange, shadowMin, shadowMax, \
shadowWarning, x, x, x = cacheShadowData
if userName in addUsers:
if not shadowObj.add(userName, pwdHash,
9 years ago
shadowLastChange=shadowLastChange,
shadowMin=shadowMin,
shadowMax=shadowMax,
shadowWarning=shadowWarning):
return False
if shadowObj.data:
if not shadowObj.save():
return False
9 years ago
cacheGroupObj = cacheGroup(self)
cacheListGroupData = cacheGroupObj.getData()
9 years ago
if not isinstance(cacheListGroupData, (list, tuple)):
return False
9 years ago
cacheCreateGroupObj = cacheCreateGroup(self)
# Add cache group users to system
9 years ago
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():
12 years ago
self.printERROR(_("Failed to connect to the LDAP server"))
return False
9 years ago
cachePasswdObj = cachePasswd(self)
cacheListPasswdData = cachePasswdObj.getData()
if cacheListPasswdData is False:
return False
9 years ago
if (not isinstance(cacheListPasswdData, (tuple, list)) or
not cacheListPasswdData):
return True
9 years ago
cacheGroupObj = cacheGroup(self)
cacheListGroupData = cacheGroupObj.getData()
if cacheListGroupData is False:
return False
9 years ago
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
9 years ago
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
9 years ago
x, x, shadowLastChange, shadowMin, shadowMax, shadowWarning, \
x, x, x = cacheShadowData
groups = cacheGroupObj.getSecondUserGroups(userName)
gidsGroups = map(lambda x: x[2],
9 years ago
filter(lambda x: x[0] in groups,
cacheGroupObj.data))
userShadowDict = {'uid': uid,
'gid': gid,
'fullName': gecos,
'home': directory,
'group': groupName,
9 years ago
'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],
9 years ago
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'''
9 years ago
cacheObjs = (cachePasswd(self), cacheShadow(self), cacheGroup(self),
cacheCreateGroup(self), cacheCreatePasswd(self))
for cacheObj in cacheObjs:
if not cacheObj.save():
return False
return True