|
|
|
@ -45,6 +45,7 @@ tr.setLanguage(sys.modules[__name__])
|
|
|
|
|
|
|
|
|
|
pcs = cl_utils.prettyColumnStr
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def adminConnectLdap(fun):
|
|
|
|
|
"""Cоединение с LDAP администратором сервиса (декоратор)
|
|
|
|
|
|
|
|
|
@ -126,8 +127,38 @@ imp_cl_help = cl_utils2.cl_help
|
|
|
|
|
# Форматированный вывод
|
|
|
|
|
imp_cl_smcon = cl_utils2.cl_smartcon
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class shareLdap(imp_cl_err, imp_cl_xml, imp_cl_help, imp_cl_smcon):
|
|
|
|
|
"""Класс где храняться общие методы для всех сервисов"""
|
|
|
|
|
|
|
|
|
|
def addInfoGroup(self, name, gid, comment):
|
|
|
|
|
"""Добавляем информацию о группе"""
|
|
|
|
|
class group():
|
|
|
|
|
"""Информация о группе"""
|
|
|
|
|
name = ""
|
|
|
|
|
gid = ""
|
|
|
|
|
comment = ""
|
|
|
|
|
gr = group()
|
|
|
|
|
gr.name = name
|
|
|
|
|
gr.gid = gid
|
|
|
|
|
gr.comment = comment
|
|
|
|
|
return gr
|
|
|
|
|
|
|
|
|
|
def addInfoUser(self, name, uid, gid, comment):
|
|
|
|
|
"""Добавляем информацию о пользователе"""
|
|
|
|
|
class user():
|
|
|
|
|
"""Информация о пользователе"""
|
|
|
|
|
name = ""
|
|
|
|
|
uid = ""
|
|
|
|
|
gid = ""
|
|
|
|
|
comment = ""
|
|
|
|
|
us = user()
|
|
|
|
|
us.name = name
|
|
|
|
|
us.uid = uid
|
|
|
|
|
us.gid = gid
|
|
|
|
|
us.comment = comment
|
|
|
|
|
return us
|
|
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
# Переменная объект Vars
|
|
|
|
|
self.clVars = False
|
|
|
|
@ -139,89 +170,27 @@ class shareLdap(imp_cl_err, imp_cl_xml, imp_cl_help, imp_cl_smcon):
|
|
|
|
|
self.baseDN = False
|
|
|
|
|
# DN сервисов относительно базового
|
|
|
|
|
self.ServicesDN = "ou=Services"
|
|
|
|
|
|
|
|
|
|
def verifyPasswordInFile(self, userName, userPassword):
|
|
|
|
|
"""проверяет пароль пользователя
|
|
|
|
|
|
|
|
|
|
Данные из /etc/shadow
|
|
|
|
|
"""
|
|
|
|
|
def searchShadowUser(userName):
|
|
|
|
|
"""Ищет пользователей в /etc/shadow"""
|
|
|
|
|
fileShadow = "/etc/shadow"
|
|
|
|
|
return self.searchLineInFile(userName, fileShadow)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import md5
|
|
|
|
|
|
|
|
|
|
def md5crypt(password, salt, magic='$1$'):
|
|
|
|
|
"""Функция криптования"""
|
|
|
|
|
m = md5.new()
|
|
|
|
|
m.update(password + magic + salt)
|
|
|
|
|
|
|
|
|
|
mixin = md5.md5(password + salt + password).digest()
|
|
|
|
|
for i in range(0, len(password)):
|
|
|
|
|
m.update(mixin[i % 16])
|
|
|
|
|
|
|
|
|
|
i = len(password)
|
|
|
|
|
while i:
|
|
|
|
|
if i & 1:
|
|
|
|
|
m.update('\x00')
|
|
|
|
|
else:
|
|
|
|
|
m.update(password[0])
|
|
|
|
|
i >>= 1
|
|
|
|
|
|
|
|
|
|
final = m.digest()
|
|
|
|
|
|
|
|
|
|
for i in range(1000):
|
|
|
|
|
m2 = md5.md5()
|
|
|
|
|
if i & 1:
|
|
|
|
|
m2.update(password)
|
|
|
|
|
else:
|
|
|
|
|
m2.update(final)
|
|
|
|
|
|
|
|
|
|
if i % 3:
|
|
|
|
|
m2.update(salt)
|
|
|
|
|
|
|
|
|
|
if i % 7:
|
|
|
|
|
m2.update(password)
|
|
|
|
|
|
|
|
|
|
if i & 1:
|
|
|
|
|
m2.update(final)
|
|
|
|
|
else:
|
|
|
|
|
m2.update(password)
|
|
|
|
|
|
|
|
|
|
final = m2.digest()
|
|
|
|
|
|
|
|
|
|
itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr\
|
|
|
|
|
stuvwxyz'
|
|
|
|
|
|
|
|
|
|
rearranged = ''
|
|
|
|
|
for a, b, c in ((0, 6, 12), (1, 7, 13), (2, 8, 14), (3, 9, 15),
|
|
|
|
|
(4, 10, 5)):
|
|
|
|
|
v = ord(final[a]) << 16 | ord(final[b]) << 8 | ord(final[c])
|
|
|
|
|
for i in range(4):
|
|
|
|
|
rearranged += itoa64[v & 0x3f]; v >>= 6
|
|
|
|
|
|
|
|
|
|
v = ord(final[11])
|
|
|
|
|
for i in range(2):
|
|
|
|
|
rearranged += itoa64[v & 0x3f]; v >>= 6
|
|
|
|
|
|
|
|
|
|
return magic + salt + '$' + rearranged
|
|
|
|
|
|
|
|
|
|
def test(clear_password, the_hash):
|
|
|
|
|
"""Сравнение пароля и хеша из файла"""
|
|
|
|
|
magic, salt = the_hash[1:].split('$')[:2]
|
|
|
|
|
magic = '$' + magic + '$'
|
|
|
|
|
return md5crypt(clear_password, salt, magic) == the_hash
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
searchUserSahdow = searchShadowUser(userName)
|
|
|
|
|
if not searchUserSahdow:
|
|
|
|
|
return False
|
|
|
|
|
userHash = searchUserSahdow.split(':')[1]
|
|
|
|
|
if userHash=='*' or userHash=='!':
|
|
|
|
|
return False
|
|
|
|
|
return test(userPassword, userHash)
|
|
|
|
|
# Статические группы
|
|
|
|
|
self.staticGroups = {\
|
|
|
|
|
'client':self.addInfoGroup('client',
|
|
|
|
|
'900',
|
|
|
|
|
'Client samba group'),
|
|
|
|
|
'admin':self.addInfoGroup('admin',
|
|
|
|
|
'901',
|
|
|
|
|
'Admin samba group'),
|
|
|
|
|
'Computers':self.addInfoGroup('Computers',
|
|
|
|
|
'902',
|
|
|
|
|
'Computer group')}
|
|
|
|
|
# Статические пользователи
|
|
|
|
|
self.staticUsers = {\
|
|
|
|
|
'client':self.addInfoUser('client',
|
|
|
|
|
'900',
|
|
|
|
|
'900',
|
|
|
|
|
'Client samba user'),
|
|
|
|
|
'admin':self.addInfoUser('admin',
|
|
|
|
|
'901',
|
|
|
|
|
'901',
|
|
|
|
|
'Admin samba user')}
|
|
|
|
|
|
|
|
|
|
def restorePathDelUser(self,userName,destDir,relDir,message,unixObj=False):
|
|
|
|
|
"""Восстанавливает директорию удаленного пользователя"""
|
|
|
|
@ -1129,8 +1098,6 @@ class servUnix(shareLdap):
|
|
|
|
|
self.relGroupsDN = self.addDN(self.relGrDN, self.relDN)
|
|
|
|
|
# Коментарий к группе по умолчанию
|
|
|
|
|
self.groupGecos = "Calculate group"
|
|
|
|
|
# Коментарий к группе компьютеров
|
|
|
|
|
self.groupCompGecos = "Computer group"
|
|
|
|
|
# Базовая директория пользователей
|
|
|
|
|
self.baseDir = "/home"
|
|
|
|
|
# Название пользователя по умолчанию
|
|
|
|
@ -1463,34 +1430,16 @@ class servUnix(shareLdap):
|
|
|
|
|
"""Добавляет Unix машину в LDAP-сервер"""
|
|
|
|
|
machineLogin = machineName.replace('$','') + "$"
|
|
|
|
|
groupName = self.clVars.Get('sr_samba_machine_group')
|
|
|
|
|
|
|
|
|
|
resSearch = self.searchUnixGroupName(groupName)
|
|
|
|
|
if resSearch:
|
|
|
|
|
groupId = resSearch[0][0][1]['gidNumber'][0]
|
|
|
|
|
else:
|
|
|
|
|
# Находим следующий номер в диапазоне системных групп
|
|
|
|
|
groupId = str(self.getMaxGidSystem())
|
|
|
|
|
res = self.searchUnixGid(groupId)
|
|
|
|
|
maxGid = self.getUidMax()
|
|
|
|
|
if res:
|
|
|
|
|
numberGid = int(groupId)
|
|
|
|
|
flagMaxGidError = False
|
|
|
|
|
while res:
|
|
|
|
|
numberGid += 1
|
|
|
|
|
res = self.searchUnixGid(str(numberGid))
|
|
|
|
|
if numberGid>=maxGid:
|
|
|
|
|
flagMaxGidError = True
|
|
|
|
|
break
|
|
|
|
|
if flagMaxGidError:
|
|
|
|
|
self.printERROR (_("ERROR") + ": " +\
|
|
|
|
|
_("free GID %s is not found in Unix service") %\
|
|
|
|
|
str(userGid))
|
|
|
|
|
return False
|
|
|
|
|
groupId = str(numberGid)
|
|
|
|
|
options = {'g':groupId,'c':self.groupCompGecos}
|
|
|
|
|
gr = self.staticGroups["Computers"]
|
|
|
|
|
groupId = gr.gid
|
|
|
|
|
options = {'g':gr.gid,'c':gr.comment}
|
|
|
|
|
if not self.addGroupUnixServer(groupName, options):
|
|
|
|
|
return False
|
|
|
|
|
self.clVars.Set('sr_samba_machine_login',machineLogin)
|
|
|
|
|
self.clVars.Set('sr_samba_machine_login', machineLogin)
|
|
|
|
|
# Находим последний добавленный id
|
|
|
|
|
userIdNumber = str(self.getMaxUid())
|
|
|
|
|
self.clVars.Set('sr_samba_machine_id',userIdNumber)
|
|
|
|
@ -4208,12 +4157,16 @@ class servSamba(shareLdap):
|
|
|
|
|
return True
|
|
|
|
|
else:
|
|
|
|
|
return False
|
|
|
|
|
# id пользователя Unix
|
|
|
|
|
uidUnixUser = False
|
|
|
|
|
resSearch = self.servUnixObj.searchUnixUser(userName)
|
|
|
|
|
flagFoundPasswd = False
|
|
|
|
|
if not resSearch:
|
|
|
|
|
resSearch = self.servUnixObj.searchPasswdUser(userName)
|
|
|
|
|
flagFoundPasswd = True
|
|
|
|
|
|
|
|
|
|
if resSearch:
|
|
|
|
|
flagFoundPasswd = True
|
|
|
|
|
else:
|
|
|
|
|
uidUnixUser = resSearch[0][0][1]['uidNumber'][0]
|
|
|
|
|
## создание пользователя Unix опция f
|
|
|
|
|
#if not resSearch and not options.has_key('f'):
|
|
|
|
|
#self.printERROR(
|
|
|
|
@ -4251,8 +4204,23 @@ class servSamba(shareLdap):
|
|
|
|
|
# Полное имя пользователя
|
|
|
|
|
if options.has_key('c'):
|
|
|
|
|
optUnix['c'] = options['c']
|
|
|
|
|
# shell
|
|
|
|
|
if options.has_key('s'):
|
|
|
|
|
optUnix['s'] = options['s']
|
|
|
|
|
# Домашняя директория
|
|
|
|
|
if options.has_key('d'):
|
|
|
|
|
optUnix['d'] = options['d']
|
|
|
|
|
# Cделаем пользователя видимым
|
|
|
|
|
optUnix['v'] = ""
|
|
|
|
|
if optUnix.has_key('u'):
|
|
|
|
|
try:
|
|
|
|
|
int(optUnix['u'])
|
|
|
|
|
except:
|
|
|
|
|
self.printERROR(_("UID is not number"))
|
|
|
|
|
return False
|
|
|
|
|
if int(optUnix['u']) >= 1000:
|
|
|
|
|
optUnix['v'] = ""
|
|
|
|
|
else:
|
|
|
|
|
optUnix['v'] = ""
|
|
|
|
|
if not self.servUnixObj.addUserUnixServer(userName, optUnix,
|
|
|
|
|
False,userPwd):
|
|
|
|
|
self.printERROR (_("Can not added user")+ " " +\
|
|
|
|
@ -4265,8 +4233,10 @@ class servSamba(shareLdap):
|
|
|
|
|
if not self.servUnixObj.modUserUnixPasswd(userName,{},userPwd):
|
|
|
|
|
return False
|
|
|
|
|
# Делаем пользователя видимым
|
|
|
|
|
if not self.servUnixObj.modUserUnixServer(userName,{"V":""},False):
|
|
|
|
|
return False
|
|
|
|
|
if uidUnixUser==False or int(uidUnixUser) >=1000:
|
|
|
|
|
if not self.servUnixObj.modUserUnixServer(userName,
|
|
|
|
|
{"V":""},False):
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
if userPwd:
|
|
|
|
|
textLine = self.execProg("smbpasswd -a -s %s" %(userName),
|
|
|
|
@ -4585,40 +4555,44 @@ class servSamba(shareLdap):
|
|
|
|
|
else:
|
|
|
|
|
self.printNotOK(_("Starting") + " Samba ...")
|
|
|
|
|
return False
|
|
|
|
|
print _("Enter existing ROOT password")
|
|
|
|
|
pwDialog = "ROOT password"
|
|
|
|
|
rootPwdOK = False
|
|
|
|
|
for i in range(3):
|
|
|
|
|
rootPwd = getpass.getpass(pwDialog+":")
|
|
|
|
|
if self.verifyPasswordInFile('root', rootPwd):
|
|
|
|
|
rootPwdOK = True
|
|
|
|
|
break
|
|
|
|
|
elif i<2:
|
|
|
|
|
self.printERROR(_("incorrect root password, try again"))
|
|
|
|
|
if not rootPwdOK:
|
|
|
|
|
self.printERROR(_("Incorrect root password") + " ...")
|
|
|
|
|
self.printERROR(_("Samba service can not configured") + " ...")
|
|
|
|
|
return False
|
|
|
|
|
if not self.addUserSambaServer('root',{},False,False,rootPwd):
|
|
|
|
|
return False
|
|
|
|
|
clientName = 'client'
|
|
|
|
|
clientGroup = 'client'
|
|
|
|
|
clientUid = '900'
|
|
|
|
|
clientGid = '900'
|
|
|
|
|
cl = self.staticUsers["client"]
|
|
|
|
|
clGr = self.staticGroups["client"]
|
|
|
|
|
adm = self.staticUsers["admin"]
|
|
|
|
|
admGr = self.staticGroups["admin"]
|
|
|
|
|
# Создаем клиента
|
|
|
|
|
# Проверяем на наличие группы client
|
|
|
|
|
resGroupClient = self.servUnixObj.searchUnixGroupName(clientGroup)
|
|
|
|
|
resGroupClient = self.servUnixObj.searchUnixGroupName(clGr.name)
|
|
|
|
|
if not resGroupClient:
|
|
|
|
|
# Создаем группу для пользователя client
|
|
|
|
|
if not self.servUnixObj.addGroupUnixServer(clientGroup,
|
|
|
|
|
{'g':clientGid},
|
|
|
|
|
if not self.servUnixObj.addGroupUnixServer(clGr.name,
|
|
|
|
|
{'g':clGr.gid,
|
|
|
|
|
'c':clGr.comment},
|
|
|
|
|
False):
|
|
|
|
|
self.printERROR(_("not created unix group 'client'"))
|
|
|
|
|
return False
|
|
|
|
|
# Добавляем пользователя client для smb ресурса [remote]
|
|
|
|
|
if not self.addUserSambaServer('client',{'f':'','u':clientUid,
|
|
|
|
|
'g':clientGroup}, False,False):
|
|
|
|
|
if not self.addUserSambaServer('client',{'f':'','u':cl.uid,
|
|
|
|
|
'c':'Client unix workstation','g':clGr.name,
|
|
|
|
|
's':'/bin/false','d':'/dev/null'},False,False):
|
|
|
|
|
self.printERROR(_("not created samba user 'client'"))
|
|
|
|
|
return False
|
|
|
|
|
# Создаем админа
|
|
|
|
|
# Проверяем на наличие группы admin
|
|
|
|
|
resGroupAdmin = self.servUnixObj.searchUnixGroupName(admGr.name)
|
|
|
|
|
if not resGroupAdmin:
|
|
|
|
|
# Создаем группу для пользователя admin
|
|
|
|
|
if not self.servUnixObj.addGroupUnixServer(admGr.name,
|
|
|
|
|
{'g':admGr.gid,
|
|
|
|
|
'c':admGr.comment},
|
|
|
|
|
False):
|
|
|
|
|
self.printERROR(_("not created unix group 'admin'"))
|
|
|
|
|
return False
|
|
|
|
|
# Добавляем пользователя admin
|
|
|
|
|
if not self.addUserSambaServer('admin',{'f':'','u':adm.uid,
|
|
|
|
|
'c':'Administrator samba service','g':admGr.name,
|
|
|
|
|
's':'/bin/false','d':'/dev/null'},False,False):
|
|
|
|
|
self.printERROR(_("not created samba user 'admin'"))
|
|
|
|
|
return False
|
|
|
|
|
# Если нет то создадим директорию /var/calculate/remote
|
|
|
|
|
remoteEnvFile = self.clVars.Get("cl_env_path")[0]
|
|
|
|
|
remotePath = os.path.split(remoteEnvFile)[0]
|
|
|
|
@ -4626,7 +4600,7 @@ class servSamba(shareLdap):
|
|
|
|
|
os.makedirs(remotePath)
|
|
|
|
|
# права и владелец /var/calculate/remote
|
|
|
|
|
if os.path.exists(remotePath):
|
|
|
|
|
os.chown(remotePath,0,int(clientGid))
|
|
|
|
|
os.chown(remotePath,0,int(cl.gid))
|
|
|
|
|
os.chmod(remotePath,02750)
|
|
|
|
|
# изменяем владельца remote на client
|
|
|
|
|
if not os.path.exists(remoteEnvFile):
|
|
|
|
@ -4634,7 +4608,7 @@ class servSamba(shareLdap):
|
|
|
|
|
os.close(fd)
|
|
|
|
|
os.chmod(remoteEnvFile, 0640)
|
|
|
|
|
if os.path.exists(remoteEnvFile):
|
|
|
|
|
os.chown(remoteEnvFile,0,int(clientGid))
|
|
|
|
|
os.chown(remoteEnvFile,0,int(cl.gid))
|
|
|
|
|
if not self.setDaemonAutostart("slapd"):
|
|
|
|
|
return False
|
|
|
|
|
# Устанавливаем автозапуск демона
|
|
|
|
@ -4694,14 +4668,17 @@ class servSamba(shareLdap):
|
|
|
|
|
self.printERROR(_("Can not enable Samba user")+ " "+\
|
|
|
|
|
str(userName) + " ...")
|
|
|
|
|
return False
|
|
|
|
|
if not options:
|
|
|
|
|
if not options or options.has_key('s'):
|
|
|
|
|
optPasswd = {"p":""}
|
|
|
|
|
userPwd = self.getUserPassword(optPasswd, "p", False)
|
|
|
|
|
if userPwd == False:
|
|
|
|
|
return False
|
|
|
|
|
if userPwd:
|
|
|
|
|
if not self.servUnixObj.modUserUnixPasswd(userName,{},userPwd):
|
|
|
|
|
return False
|
|
|
|
|
# Опция s пароль только для Samba
|
|
|
|
|
if not options.has_key('s'):
|
|
|
|
|
if not self.servUnixObj.modUserUnixPasswd(userName,{},
|
|
|
|
|
userPwd):
|
|
|
|
|
return False
|
|
|
|
|
textLine = self.execProg("smbpasswd -a -s %s" %(userName),
|
|
|
|
|
"%s\n%s\n" %(userPwd,userPwd))
|
|
|
|
|
if not (textLine == None):
|
|
|
|
@ -4758,6 +4735,11 @@ class servSamba(shareLdap):
|
|
|
|
|
_("password incorrect")+ ": " + _("try again"))
|
|
|
|
|
return False
|
|
|
|
|
userPwd = pwdA
|
|
|
|
|
# Опция s пароль только для Samba
|
|
|
|
|
if not options.has_key('s'):
|
|
|
|
|
if not self.servUnixObj.modUserUnixPasswd(userName,{},
|
|
|
|
|
userPwd):
|
|
|
|
|
return False
|
|
|
|
|
textLine = self.execProg("smbpasswd -s %s" %(userName),
|
|
|
|
|
"%s\n%s\n" %(userPwd,userPwd))
|
|
|
|
|
if not (textLine == None):
|
|
|
|
@ -4765,6 +4747,12 @@ class servSamba(shareLdap):
|
|
|
|
|
" ...")
|
|
|
|
|
return False
|
|
|
|
|
self.printSUCCESS(_("Modified Samba user password") + " ...")
|
|
|
|
|
# изменяем Unix группы в которые включен пользователь
|
|
|
|
|
if options.has_key("G"):
|
|
|
|
|
strGroups = options["G"]
|
|
|
|
|
optUnix = {'G':strGroups}
|
|
|
|
|
if not self.servUnixObj.modUserUnixServer(userName, optUnix):
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
class servLdap(shareLdap):
|
|
|
|
@ -5713,6 +5701,20 @@ preferences and data (for users with uid<1000)")
|
|
|
|
|
'helpChapter':_("Mail service options"),
|
|
|
|
|
'help':_("not create backup deleted user data")
|
|
|
|
|
},
|
|
|
|
|
{'progAccess':(5,),
|
|
|
|
|
'shortOption':"G",
|
|
|
|
|
'longOption':"groups",
|
|
|
|
|
'optVal':_("GROUPS"),
|
|
|
|
|
'helpChapter':_("Samba service options"),
|
|
|
|
|
'help':_("new list of supplementary GROUPS (used Unix groups)")
|
|
|
|
|
},
|
|
|
|
|
{'progAccess':(5,),
|
|
|
|
|
'shortOption':"s",
|
|
|
|
|
'longOption':"smb",
|
|
|
|
|
'helpChapter':_("Samba service options"),
|
|
|
|
|
'help':_("used in conjunction with the option '-p', \
|
|
|
|
|
the password will be changed only for Samba account")
|
|
|
|
|
},
|
|
|
|
|
{'progAccess':(5,),
|
|
|
|
|
'shortOption':"c",
|
|
|
|
|
'longOption':"comment",
|
|
|
|
@ -5896,6 +5898,12 @@ preferences and data (for users with uid<1000)")
|
|
|
|
|
'helpChapter':_("Unix service options"),
|
|
|
|
|
'help':_("delete the password for the named account")
|
|
|
|
|
},
|
|
|
|
|
{'progAccess':(7,),
|
|
|
|
|
'shortOption':"s",
|
|
|
|
|
'longOption':"smb",
|
|
|
|
|
'helpChapter':_("Samba service options"),
|
|
|
|
|
'help':_("password will be changed only for Samba account")
|
|
|
|
|
},
|
|
|
|
|
{'progAccess':(7,),
|
|
|
|
|
'shortOption':"l",
|
|
|
|
|
'longOption':"lock",
|
|
|
|
|