From 241924a673f2460ce179239447e972a8202eef1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=B0=D0=BC=D0=BE=D1=83=D0=BA=D0=B8=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B9?= Date: Wed, 1 Sep 2010 14:03:21 +0400 Subject: [PATCH] Added caching of domain users. --- pym/cl_client.py | 236 +++++++++++++++++++---- pym/cl_client_cache.py | 421 ++++++++++++++++++++++++++++------------- 2 files changed, 489 insertions(+), 168 deletions(-) diff --git a/pym/cl_client.py b/pym/cl_client.py index 27705d8..a8de14f 100644 --- a/pym/cl_client.py +++ b/pym/cl_client.py @@ -41,6 +41,8 @@ from cl_utils import runOsCommand, getpathenv, getModeFile, removeDir, isMount,\ from _cl_keys import getKey, clearKey from convertenv import convertEnv from encrypt import encrypt +from cl_client_cache import userCache +from shutil import copy2 lang().setLanguage(sys.modules[__name__]) @@ -341,6 +343,10 @@ class client(share, commandServer, encrypt): # объект конвертирования из старого remote env файла convObj = None + # Приватный файлы пользователя + privateFiles = ['.kde4/share/apps/kwallet/kdewallet.kwl', configFileServer] + # Приватные директории пользователя + privateDirs = [".ssh"] def removeVars(self): @@ -815,6 +821,34 @@ class client(share, commandServer, encrypt): FD.close() return True + def getDateObjClientConf(self, fileConfig): + """Возващает объект времени из конфигурационного файла + .calculate/desktop.env""" + if os.path.exists(fileConfig): + objConfig = iniParser(fileConfig) + data = self.getDataInConfig("main", ["date", "date_logout"], + objConfig) + timeLogout = data["date_logout"] + timeConfig = data["date"] + timeLogoutObj = False + if timeLogout: + try: + timeLogoutObj = time.strptime(timeLogout, + "%Y-%m-%d %H:%M:%S") + except: + pass + timeConfigObj = False + if timeConfig: + try: + timeConfigObj = time.strptime(timeConfig, + "%Y-%m-%d %H:%M:%S") + except: + pass + listDataObj = filter(lambda x: x, (timeLogoutObj, timeConfigObj)) + if listDataObj: + return max(listDataObj) + return False + def mountUserResAndSync(self, userName, sync=True, progress=False): """Монтирование пользовательских ресурсов и синхронизация настроек""" # Проверяем на root @@ -839,11 +873,19 @@ class client(share, commandServer, encrypt): return False if userName in passwdUsers: try: - pwd.getpwnam(userName) + pwdObj = pwd.getpwnam(userName) except: self.printERROR(_("Can not found user %s")%userName) self.umountUserRes() return False + homeDir = pwdObj.pw_dir + uid = pwdObj.pw_uid + gid = pwdObj.pw_gid + configFileName = os.path.join(homeDir, self.configFileDesktop) + # записываем в конфигурационный файл статус "локальный режим" + # Write to the configuration file status of "local mode" + self.setVarToConfig("main", {"status_sync":"local"}, + configFileName, uid, gid) self.printWARNING(_("We use user information from /etc/passwd")) return True # Проверим что компьютер в домене и смонтирован [remote] @@ -862,11 +904,10 @@ class client(share, commandServer, encrypt): self.printERROR(_("Can not found user %s in LDAP") %userName) self.umountUserRes() return False - rootPath = self.clVars.Get('cl_root_path') - # Реальный путь к домашней директории - homeDir = os.path.join(rootPath, homeDir[1:]) # Файл хранения настроек пакета configFileName = os.path.join(homeDir, self.configFileDesktop) + # объект времени для текущего профиля + currentTimeObj = self.getDateObjClientConf(configFileName) # При отсуствии создаем домашнюю директорию if not os.path.exists(homeDir): os.makedirs(homeDir) @@ -882,6 +923,9 @@ class client(share, commandServer, encrypt): # Отмонтируем пользовательские ресурсы в случае ошибки self.umountUserRes(homeDir) return False + # Кеширование пользователя + if not self.cAddUserToCache(userName, userPwd): + return False # Флаг ошибки flagError = False # Имя удаленного сервера @@ -909,7 +953,9 @@ class client(share, commandServer, encrypt): # Статус синхронизации syncStatus = True osLinuxShort = self.clVars.Get("os_linux_shortname") - + # Флаг копирования приватных файлов с сервера в случае + # устаревшей даты профиля + flagCopyPrivateFiles = False # Если профиль на удаленном сервере if remoteServer and replOn: # имя файла архива в процессе архивации @@ -967,6 +1013,19 @@ class client(share, commandServer, encrypt): homeTemplate = os.path.join(path, osLinuxShort) if not os.path.exists(homeTemplate): homeTemplate = os.path.join(path, "." + osLinuxShort) + # Проверка на дату профиля на удаленном сервере + if name == "remote_profile": + fileConfigRemote = os.path.join(homeTemplate, + self.configFileDesktop) + # объект времени для удаленного сервера + remoteTimeObj = self.getDateObjClientConf(fileConfigRemote) + if remoteTimeObj and currentTimeObj: + if currentTimeObj > remoteTimeObj: + sync = False + flagCopyPrivateFiles = True + # Если нет синхронизации отменяем обработку + if not sync: + continue # Примонтирована директория профиля с текущего сервера if name == "profile": # Перенос профиля на сервере в директорию без точки @@ -1000,7 +1059,9 @@ class client(share, commandServer, encrypt): flagError = True break pathTemplateCurr = dictRes["profile"]["path"] - homeTemplateCurr = os.path.join(pathTemplateCurr,osLinuxShort) + homeTemplateCurr = os.path.join(pathTemplateCurr, + osLinuxShort) + # Синхронизация профиля с текущего сервера hostConnect = defaultHost if not self.syncLoginTemplate(hostConnect, userName,homeDir, @@ -1098,17 +1159,26 @@ class client(share, commandServer, encrypt): # Отмонтируем пользовательские ресурсы в случае ошибки self.umountUserRes(homeDir) return False - + if not flagError and flagCopyPrivateFiles: + configFileName = os.path.join(homeDir, self.configFileDesktop) + # записываем в конфигурационный файл статус "локальный режим" + # Write to the configuration file status of "local mode" + self.setVarToConfig("main", {"status_sync":"local"}, + configFileName, uid, gid) + # Копируем приватные файлы с сервера + # Copy private files from the server + self.copyPrivateFiles(homeTemplate, homeDir) # Отмонтируем директорию профиля пользователя на удаленном сервере if sync and "remote_profile" in dictRes: umountPath = dictRes["remote_profile"]["path"] - textLine = self.umountSleepPath(umountPath) - if not textLine: - # Отмонтируем пользовательские ресурсы в случае ошибки - self.umountUserRes(homeDir) - return False + if isMount(umountPath): + textLine = self.umountSleepPath(umountPath) + if not textLine: + # Отмонтируем пользовательские ресурсы в случае ошибки + self.umountUserRes(homeDir) + return False # Удаляем директорию удаленного профиля у клиента - if os.path.exists(umountPath): + if os.path.exists(umountPath) and not os.listdir(umountPath): os.rmdir(umountPath) # Если профиль на текущем сервере @@ -1152,6 +1222,17 @@ class client(share, commandServer, encrypt): break # Директория профиля homeTemplate = os.path.join(path, osLinuxShort) + # Проверка на дату профиля на текущем сервере + fileConfigThis = os.path.join(homeTemplate, + self.configFileDesktop) + thisTimeObj = self.getDateObjClientConf(fileConfigThis) + if thisTimeObj and currentTimeObj: + if currentTimeObj > thisTimeObj: + sync = False + flagCopyPrivateFiles = True + # Если нет синхронизации отменяем обработку + if not sync: + continue # Синхронизация профиля пользователя с текущего сервера hostConnect = defaultHost if not self.syncLoginTemplate(hostConnect, userName, homeDir, @@ -1160,7 +1241,16 @@ class client(share, commandServer, encrypt): # Отмонтируем пользовательские ресурсы в случае ошибки self.umountUserRes(homeDir) return False - + if not flagError and flagCopyPrivateFiles: + configFileName = os.path.join(homeDir, self.configFileDesktop) + # записываем в конфигурационный файл статус "локальный режим" + # Write to the configuration file status of "local mode" + self.setVarToConfig("main", {"status_sync":"local"}, + configFileName, uid, gid) + # Копируем приватные файлы с сервера + # Copy private files from the server + self.copyPrivateFiles(homeTemplate, homeDir) + if flagError: # Отмонтируем пользовательские ресурсы в случае ошибки self.umountUserRes(homeDir) @@ -1272,25 +1362,53 @@ class client(share, commandServer, encrypt): os.remove(rmFile) return True + def getPrivateFiles(self, userHome): + """Все приватные файлы пользователя относительно директории userHome""" + privateFiles = [] + for privateHomeDir in self.privateDirs: + privateDir = os.path.join(userHome,privateHomeDir) + if os.path.isdir(privateDir): + # .ssh файлы относительно домашней директории пользователя + privateFiles += map(lambda x:os.path.join(privateHomeDir,x), + filter(lambda x:\ + os.path.isfile(os.path.join(privateDir,x)), + os.listdir(privateDir))) + return self.privateFiles + privateFiles + def removePrivateFiles(self, userHome): """Удаление приватных файлов""" - privateFiles = ['.kde4/share/apps/kwallet/kdewallet.kwl', - self.configFileServer] - # файлы в .ssh - sshHome = ".ssh" - sshPath = os.path.join(userHome,sshHome) - if os.path.isdir(sshPath): - # .ssh файлы относительно домашней директории пользователя - privateFiles += map(lambda x:os.path.join(sshHome,x),\ - filter(lambda x:\ - os.path.isfile(os.path.join(sshPath,x)),\ - os.listdir(sshPath))) + privateFiles = self.getPrivateFiles(userHome) for prFile in privateFiles: rmFile = os.path.join(userHome, prFile) if os.path.exists(rmFile): os.remove(rmFile) return True + def copyPrivateFiles(self, serverProfileDir, userHomeDir): + """Копирование приватных файлов c сервера в домашнюю директорию""" + privateFiles = self.getPrivateFiles(serverProfileDir) + for prFile in privateFiles: + src = os.path.join(serverProfileDir, prFile) + dst = os.path.join(userHomeDir, prFile) + if os.path.exists(src): + dstPath = os.path.dirname(dst) + if not os.path.exists(dstPath): + listElPath = [] + for el in filter(lambda x: x, + dstPath.partition(userHomeDir)[2].split("/")): + listElPath.append(el) + joinPath = "/".join(listElPath) + dPath = os.path.join(userHomeDir, joinPath) + if not os.path.exists(dPath): + sPath = os.path.join(serverProfileDir, joinPath) + sMode, sUid, sGid = getModeFile(sPath) + os.mkdir(dPath,sMode) + os.chown(dPath, sUid, sGid) + copy2(src, dst) + sUid, sGid = getModeFile(src, mode="owner") + os.chown(dst, sUid, sGid) + return True + def scanDirectory(self, scanDir, listFiles, skipPath=[], prefix=False, flagDir=False): """Генерация списка файлов и директорий""" @@ -1388,12 +1506,6 @@ class client(share, commandServer, encrypt): # Проверяем на root if not self.isRoot(): return False - domain = self.clVars.Get("cl_remote_host") - hostAuth = self.clVars.Get("os_remote_auth") - # В случае компьютера вне домена - if not hostAuth or not domain: - self.printSUCCESS(_("To be used local profile")) - return True try: passwdUsers = map(lambda x: x[0], map(lambda x: x.split(':'), @@ -1402,14 +1514,28 @@ class client(share, commandServer, encrypt): except: self.printERROR(_("Can not open /etc/passwd")) return False + currentDateStr = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) if userName in passwdUsers: try: - pwd.getpwnam(userName) + pwdObj = pwd.getpwnam(userName) except: self.printERROR(_("Can not found user %s")%userName) self.umountUserRes() return False + homeDir = pwdObj.pw_dir + uid = pwdObj.pw_uid + gid = pwdObj.pw_gid + configFileName = os.path.join(homeDir, self.configFileDesktop) + self.setVarToConfig("main", {"date_logout":currentDateStr}, + configFileName, uid, gid) self.printWARNING(_("We use user information from /etc/passwd")) + self.printSUCCESS(_("To be used local profile")) + return True + domain = self.clVars.Get("cl_remote_host") + hostAuth = self.clVars.Get("os_remote_auth") + # В случае компьютера вне домена + if not hostAuth or not domain: + self.printSUCCESS(_("To be used local profile")) return True connectDomain = self.isDomain() if not connectDomain: @@ -1433,6 +1559,8 @@ class client(share, commandServer, encrypt): return False # Файл хранения настроек пакета configFileName = os.path.join(homeDir, self.configFileDesktop) + self.setVarToConfig("main", {"date_logout":currentDateStr}, + configFileName, uid, gid) if os.path.exists(homeDir): self.moveHomeDir(homeDir) else: @@ -1665,6 +1793,9 @@ class client(share, commandServer, encrypt): if not self.applyTemplatesFromSystem(): self.printERROR(_("Can not apply undomain templates")) return False + # Delete LDAP users from system and clear cache + if not self.cDelLdapSysUsersAndClearCache(): + return False # Рестартуем dbus self.restartDBus() self.printSUCCESS(_("Apply undomain templates")) @@ -1891,6 +2022,39 @@ you need to remove it from the previous domain")) self.clVars.Delete("os_remote_client") return True + def cDelLdapSysUsersAndSyncCache(self): + """Delete LDAP users from system and synchronize cache""" + cacheObj = userCache() + if not cacheObj.deleteCacheUsersFromSystem(): + return False + if not cacheObj.syncCacheToLdap(): + return False + return True + + def cAddCacheUsersFromSystem(self): + """Add cache users from system""" + cacheObj = userCache() + if not cacheObj.addCacheUsersFromSystem(): + return False + return True + + def cAddUserToCache(self, userName, userPwd): + """Add user to cache""" + cacheObj = userCache() + pwdHash = self.getHashPasswd(userPwd, "shadow_ssha256") + if not cacheObj.addUserToCache(userName, pwdHash): + return False + return True + + def cDelLdapSysUsersAndClearCache(self): + """Delete LDAP users from system and clear cache""" + cacheObj = userCache() + if not cacheObj.deleteCacheUsersFromSystem(): + return False + if not cacheObj.clearCache(): + return False + return True + def mountRemote(self): """Монтирование remote если компьютер в домене @@ -1916,6 +2080,9 @@ you need to remove it from the previous domain")) self.clVars.flIniFile() if not self.applyRelevanceTemplates(domain): return False + # Delete LDAP users from system and synchronize cache + if not self.cDelLdapSysUsersAndSyncCache(): + return False return True else: pathRemote = "/var/calculate/remote" @@ -1936,6 +2103,8 @@ you need to remove it from the previous domain")) # Если шаблоны не актуальны накладываем новую версию шаблонов if not self.applyRelevanceTemplates(): return False + if not self.cAddCacheUsersFromSystem(): + return False if beforeRemoteAuth != self.clVars.Get('os_remote_auth'): self.restartDBus() return True @@ -1947,6 +2116,9 @@ you need to remove it from the previous domain")) beforeRemoteAuth = self.clVars.Get('os_remote_auth') if not self.applyRelevanceTemplates(domain): return False + # Delete LDAP users from system and synchronize cache + if not self.cDelLdapSysUsersAndSyncCache(): + return False if beforeRemoteAuth != self.clVars.Get('os_remote_auth'): self.restartDBus() return True diff --git a/pym/cl_client_cache.py b/pym/cl_client_cache.py index cada195..77f4a2e 100644 --- a/pym/cl_client_cache.py +++ b/pym/cl_client_cache.py @@ -53,7 +53,7 @@ class _shareData(color_print): elif self.getFileAccess(perm="READ"): self.data = self.getDataInFile(fileName=self.fileName, lenData=self.lenData) - return self.data + return self.data else: return False @@ -82,12 +82,19 @@ class _shareData(color_print): for index, listDataOld in enumerate(self.data): if name == listDataOld[0]: flagFound = True - self.data[index] = listData + 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 @@ -141,6 +148,77 @@ class group(_shareData): 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" @@ -167,6 +245,10 @@ class shadow(_shareData): 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(): @@ -186,7 +268,7 @@ class _shareCache(): return False if self.getFileAccess(perm="WRITE"): modeFile = 0600 - if getModeFile(self.fileName, mode=="mode") != modeFile: + 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+") @@ -216,9 +298,21 @@ class cachePasswd(_shareCache, 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(color_print): ldapObj = ldapUser() @@ -228,24 +322,7 @@ class userCache(color_print): if not ldapData: self.printERROR(_("Can not found user %s in LDAP")%userName) return False - passwdObj = passwd() - userData = passwdObj.get(userName) - if userData is False: - return False - elif userData: - self.printWARNING(_("User %s found in /etc/passwd")%userName) - self.printWARNING(\ - _("User Account will not be recorded in the cache")) - return True - groupName = ldapData['group'] - groupObj = group() - # is cached group? - flagCacheGroup = True - groupData = groupObj.get(groupName) - if groupData is False: - return False - elif groupData: - flagCacheGroup = False + groupName = ldapData['group'] # Add user cachePasswdObj = cachePasswd() if not cachePasswdObj.add(userName, ldapData['uid'], ldapData['gid'], @@ -255,13 +332,31 @@ class userCache(color_print): return False if not cachePasswdObj.save(): return False - # Add group - if flagCacheGroup: - cacheGroupObj = cacheGroup() - if not cacheGroupObj.add(groupName,ldapData['gid']): - return False - if not cacheGroupObj.save(): - return False + cacheGroupObj = cacheGroup() + # 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() if not cacheShadowObj.add(userName, pwdHash, @@ -274,6 +369,40 @@ class userCache(color_print): return False return True + def delUserFromCacheCreate(self, userName): + '''Delete LDAP user from createCache''' + cacheCreatePasswdObj = cacheCreatePasswd() + cacheUserData = cacheCreatePasswdObj.get(userName) + if cacheUserData is False: + return False + if not cacheUserData: + return True + gid = cacheUserData[3] + cacheCreateGroupObj = cacheCreateGroup() + 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() @@ -283,42 +412,43 @@ class userCache(color_print): if not cacheUserData: return True gid = cacheUserData[3] - flagDeleteGroup = len(filter(lambda x:x[3]==gid,cachePasswdObj.data))==1 + cacheGroupObj = cacheGroup() + 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() if not cacheShadowObj.delete(userName): return False if not cacheShadowObj.save(): return False - # delete group - if flagDeleteGroup: - cacheGroupObj = cacheGroup() - cacheListGroupData = cacheGroupObj.getData() - if cacheListGroupData is False: - return False - cacheGroupData = map(lambda x: x[0], filter(lambda x: x[2]==gid, - cacheListGroupData)) - # delete group - if cacheGroupData: - groupName = cacheGroupData[0] - if not cacheGroupObj.delete(groupName): - return False - if not cacheGroupObj.save(): - return False return True def delUserFromSystem(self, userName): '''Delete LDAP user from system files ( passwd, group, shadow )''' - cachePasswdObj = cachePasswd() - cacheUserData = cachePasswdObj.get(userName) - if cacheUserData is False: + cacheCreatePasswdObj = cacheCreatePasswd() + cacheCreateUserData = cacheCreatePasswdObj.get(userName) + if cacheCreateUserData is False: return False - if not cacheUserData: + if not cacheCreateUserData: return True passwdObj = passwd() userData = passwdObj.get(userName) @@ -331,24 +461,29 @@ class userCache(color_print): return False if not passwdObj.save(): return False - gid = userData[3] - cacheGroupObj = cacheGroup() - cacheListGroupData = cacheGroupObj.getData() - if cacheListGroupData is False: - return False - cacheGroupData = map(lambda x: x[0], filter(lambda x: x[2]==gid, - cacheListGroupData)) - # delete group - if cacheGroupData: - groupName = cacheGroupData[0] - groupObj = group() - groupData = groupObj.get(groupName) - if groupData is False: - return False - if not groupObj.delete(groupName): - return False - if not groupObj.save(): + # delete user group + groupObj = group() + listGroupData = groupObj.getData() + if listGroupData is False: + return False + cacheCreateGroupObj = cacheCreateGroup() + 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() shadowData = shadowObj.get(userName) @@ -360,6 +495,8 @@ class userCache(color_print): return False if not shadowObj.save(): return False + if not self.delUserFromCacheCreate(userName): + return False return True def isConnectToLdap(self): @@ -376,41 +513,13 @@ class userCache(color_print): def deleteCacheUsersFromSystem(self): '''Delete cache users from system''' - cachePasswdObj = cachePasswd() - cacheListPasswdData = cachePasswdObj.getData() - if cacheListPasswdData is False: + cacheCreatePasswdObj = cacheCreatePasswd() + cacheCreateListPasswdData = cacheCreatePasswdObj.getData() + if cacheCreateListPasswdData is False: return False - delUsersPasswd = map(lambda x: x[0], cacheListPasswdData) - passwdObj = passwd() + delUsersPasswd = map(lambda x: x[0], cacheCreateListPasswdData) for delUser in delUsersPasswd: - if not passwdObj.delete(delUser): - return False - if delUsersPasswd: - if not passwdObj.save(): - return False - cacheShadowObj = cacheShadow() - cacheListShadowData = cacheShadowObj.getData() - if cacheListShadowData is False: - return False - delUsersShadow = map(lambda x: x[0], cacheListShadowData) - shadowObj = shadow() - for delUser in delUsersShadow: - if not shadowObj.delete(delUser): - return False - if delUsersShadow: - if not shadowObj.save(): - return False - cacheGroupObj = cacheGroup() - cacheListGroupData = cacheGroupObj.getData() - if cacheListGroupData is False: - return False - delGroups = map(lambda x: x[0], cacheListGroupData) - groupObj = group() - for delGroup in delGroups: - if not groupObj.delete(delGroup): - return False - if delGroups: - if not groupObj.save(): + if not self.delUserFromSystem(delUser): return False return True @@ -422,16 +531,51 @@ class userCache(color_print): return False # Add cache passwd users to system passwdObj = passwd() + cacheCreatePasswdObj = cacheCreatePasswd() + cacheListCreatePasswdData = cacheCreatePasswdObj.getData() + if cacheListPasswdData 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 - if not passwdObj.add(userName, uid, gid, - gecos=gecos, - directory=directory, - shell=shell): + 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 cacheListPasswdData: + 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() cacheListShadowData = cacheShadowObj.getData() if cacheListShadowData is False: @@ -441,28 +585,43 @@ class userCache(color_print): for cacheShadowData in cacheListShadowData: userName, pwdHash, shadowLastChange, shadowMin, shadowMax,\ shadowWarning, x,x,x = cacheShadowData - if not shadowObj.add(userName, pwdHash, + if userName in addUsers: + if not shadowObj.add(userName, pwdHash, shadowLastChange=shadowLastChange, shadowMin=shadowMin, shadowMax=shadowMax, shadowWarning=shadowWarning): - return False - if cacheListShadowData: + return False + if shadowObj.data: if not shadowObj.save(): return False cacheGroupObj = cacheGroup() cacheListGroupData = cacheGroupObj.getData() if cacheListGroupData is False: return False + cacheCreateGroupObj = cacheCreateGroup() # Add cache group users to system groupObj = group() + setAddUsers = set(addUsers) for cacheGroupData in cacheListGroupData: - groupName, x, gid, x = cacheGroupData - if not groupObj.add(groupName, gid): + groupName, x, gid, listUsers = cacheGroupData + retGroup = groupObj.get(groupName) + if retGroup is False: return False - if cacheListGroupData: + 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): @@ -504,11 +663,16 @@ class userCache(color_print): 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, @@ -516,9 +680,16 @@ class userCache(color_print): 'shadowWarning':shadowWarning} flagDeleteUser = False for attr, value in userShadowDict.items(): - if ldapData[attr] != value: - flagDeleteUser = True - break + 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 @@ -526,34 +697,12 @@ class userCache(color_print): for delUserName in deletedCacheUsers: if not self.delUserFromCache(delUserName): return False - # sync groups - cachePasswdObj = cachePasswd() - cacheListPasswdData = cachePasswdObj.getData() - if cacheListPasswdData is False: - return False - if not cacheListPasswdData: - return True - cacheGroupObj = cacheGroup() - cacheListGroupData = cacheGroupObj.getData() - if cacheListGroupData is False: - return False - deletedCacheGroups = [] - for cacheGroupData in cacheListGroupData: - groupName, x , gid, x = cacheGroupData - if not filter(lambda x: x[3]==gid, cacheListPasswdData): - deletedCacheGroups.append(groupName) - # Delete groups - for delGroupName in deletedCacheGroups: - if not cacheGroupObj.delete(cacheGroupObj): - return False - if deletedCacheGroups: - if not cacheGroupObj.save(): - return False return True def clearCache(self): '''Clear cache files''' - cacheObjs = (cachePasswd(), cacheShadow(), cacheGroup()) + cacheObjs = (cachePasswd(), cacheShadow(), cacheGroup(), + cacheCreateGroup(), cacheCreateUser()) for cacheObj in cacheObjs: if not cacheObj.save(): return False