import join-to-domain-0.6.6-1.el9

i9ce changed/i9ce/join-to-domain-0.6.6-1.el9
Arkady L. Shane 9 months ago
commit 2ee5afc6f6
Signed by: tigro
GPG Key ID: 1EC08A25C9DB2503

@ -0,0 +1,245 @@
#!/usr/bin/python3
# Date update: 14.11.2023
# Email: aleksandr.egai@red-soft.ru
# (c) RED SOFT
import sys,re,socket,subprocess,os
from PyQt5.QtWidgets import QApplication, QLabel, QLineEdit, QPushButton, QVBoxLayout, QHBoxLayout, QWidget, QCheckBox, QTabWidget, QMessageBox
from PyQt5.QtCore import Qt
class DomainForm(QWidget):
def __init__(self, width, height, show_parameters_tab):
QWidget.__init__(self)
self.width = width
self.height = height
self.show_parameters_tab = show_parameters_tab
self.initUI()
def initUI(self):
self.setFixedSize(self.width, self.height)
layout = QVBoxLayout()
tab_widget = QTabWidget(self)
# Вкладка для основных данных
tab1 = QWidget()
tab_widget.addTab(tab1, "Основные данные")
# Определяем имя домена
domain = None
with open("/etc/resolv.conf", "r") as resolv_file:
for line in resolv_file:
if line.strip().startswith("search"):
domain = line.split()[1]
break
self.label_domain = QLabel("Имя домена:")
self.entry_domain = QLineEdit(self)
self.entry_domain.setText(domain)
self.label_name_pc = QLabel("Имя компьютера:")
self.entry_name_pc = QLineEdit(self)
self.entry_name_pc.setMaxLength(15)
self.entry_name_pc.setText(socket.gethostname().split(".")[0])
self.label_admin = QLabel("Имя администратора домена:")
self.entry_admin = QLineEdit(self)
self.label_password = QLabel("Пароль администратора домена:")
self.entry_password = QLineEdit(self)
self.entry_password.setEchoMode(QLineEdit.Password) # Скрыть ввод пароля звёздочками
tab_layout1 = QVBoxLayout()
tab_layout1.addWidget(self.label_domain)
tab_layout1.addWidget(self.entry_domain)
tab_layout1.addWidget(self.label_name_pc)
tab_layout1.addWidget(self.entry_name_pc)
tab_layout1.addWidget(self.label_admin)
tab_layout1.addWidget(self.entry_admin)
tab_layout1.addWidget(self.label_password)
tab_layout1.addWidget(self.entry_password)
tab1.setLayout(tab_layout1)
if self.show_parameters_tab:
# Вкладка для параметров, если show_parameters_tab == True
tab2 = QWidget()
tab_widget.addTab(tab2, "Параметры")
self.checkbox1 = QCheckBox("Параметр 1")
self.checkbox1.setChecked(True) # Активировать параметр
self.checkbox2 = QCheckBox("Параметр 2")
self.checkbox3 = QCheckBox("Параметр 3")
tab_layout2 = QVBoxLayout()
tab_layout2.addWidget(self.checkbox1)
tab_layout2.addWidget(self.checkbox2)
tab_layout2.addWidget(self.checkbox3)
tab2.setLayout(tab_layout2)
layout.addWidget(tab_widget)
button_layout = QHBoxLayout()
button_layout.setAlignment(Qt.AlignHCenter)
self.close_button = QPushButton("Закрыть")
self.submit_button = QPushButton("ОК")
self.close_button.setFixedWidth(100)
self.close_button.setFixedHeight(40)
self.close_button.clicked.connect(self.close)
self.submit_button.setFixedWidth(100)
self.submit_button.setFixedHeight(40)
self.submit_button.clicked.connect(self.on_submit)
button_layout.addWidget(self.close_button)
button_layout.addWidget(self.submit_button)
layout.addLayout(button_layout)
self.setLayout(layout)
def is_valid_name_pc(self, name_pc):
pattern = r'^(?:[a-zA-Z0-9](?:(?:[a-zA-Z0-9\-]){0,14}[a-zA-Z0-9\-])+[a-zA-Z0-9])$'
if re.match(pattern, name_pc) and len(name_pc) <= 15:
return True
else:
return False
def check_domain_name(self, admin, domain, name_pc, password):
has_errors = False # Флаг для отслеживания ошибок
try:
check_command = f"adcli show-computer -U {admin} --domain={domain} {name_pc} --stdin-password"
# Открываем файлы здесь
with open("/tmp/join_check.txt", "w") as output_file, \
open("/tmp/join_check.txt", "r") as check_file, \
open("/var/log/join-to-domain.log", "a") as log_file:
process = subprocess.Popen(check_command, shell=True, stdin=subprocess.PIPE, stdout=output_file, stderr=subprocess.STDOUT, text=True)
process.communicate(input=password)
# Считываем содержимое /tmp/join_check.txt
v_check = check_file.read()
log_file.write("Проверка аутентификации в домене:\n")
log_file.write(v_check)
log_file.flush() # Очистить буфер вывода
if "sAMAccountName" in v_check:
message = f"Ошибка! В домене уже существует компьютер {name_pc}\n"
log_message = f"Ошибка! В домене уже существует компьютер {name_pc}"
log_file.write(log_message)
log_file.write("\n")
QMessageBox.critical(self, "Ошибка!", message)
has_errors = True
if "Couldn't authenticate" in v_check:
message = "Неверное имя администратора домена или пароль!"
log_message = "Ошибка! Неверное имя администратора домена или пароль!"
log_file.write(log_message)
QMessageBox.critical(self, "Ошибка!", message)
has_errors = True
except Exception as e:
print(f"Error: {e}")
has_errors = True
return has_errors # Возвращаем флаг ошибок
def on_submit(self):
log_file_path = '/var/log/join-to-domain.log'
domain = self.entry_domain.text()
name_pc = self.entry_name_pc.text()
admin = self.entry_admin.text().split('@')[0]
password = self.entry_password.text()
param1 = self.checkbox1.isChecked() if self.show_parameters_tab else None
param2 = self.checkbox2.isChecked() if self.show_parameters_tab else None
param3 = self.checkbox3.isChecked() if self.show_parameters_tab else None
if not self.is_valid_name_pc(name_pc):
QMessageBox.critical(self, "Ошибка!", f"{name_pc} - это недопустимое имя компьютера.", QMessageBox.Ok)
with open(log_file_path, 'a') as log_file:
log_file.write(f"Ошибка! {name_pc} - это недопустимое имя компьютера." + '\n')
return
if domain and name_pc and admin and password:
# Проверка доступности домена
try:
socket.gethostbyname(domain)
except socket.gaierror:
QMessageBox.critical(self, "Ошибка!", f"Домен {domain} недоступен! Проверьте настройки сети.")
with open(log_file_path, 'a') as log_file:
log_file.write(f"Ошибка! Домен {domain} недоступен! Проверьте настройки сети." + '\n')
return
# Получаем имя контроллера домена из adcli
def get_domain_controller(domain_name):
try:
result = subprocess.check_output(["adcli", "info", domain], stderr=subprocess.STDOUT, text=True)
return result
except subprocess.CalledProcessError as e:
return str(e)
controller_info = get_domain_controller(domain)
# Парсинг информации о контроллере домена
controller_lines = [line.strip() for line in controller_info.split("\n")]
controller_name = None
for line in controller_lines:
if line.startswith("domain-controller = "):
controller_name = line.split(" = ")[1]
break
if controller_name:
# Короткое имя домена
v_short_dc = controller_name.split(".")[0]
else:
QMessageBox.critical(self, "Ошибка!", "Информация о контроллере домена не найдена.")
with open(log_file_path, 'a') as log_file:
log_file.write(f"Ошибка! Информация о контроллере домена не найдена." + '\n')
return
if v_short_dc == name_pc:
QMessageBox.critical(self, "Ошибка!", f"Имя компьютера {name_pc} не должно совпадать с именем контроллера домена!")
with open(log_file_path, 'a') as log_file:
log_file.write(f"Ошибка! Имя компьютера {name_pc} не должно совпадать с именем контроллера домена!" + '\n')
return
if self.check_domain_name(admin, domain, name_pc, password):
return
result = f"{domain},{name_pc},{admin},{password},{param1},{param2},{param3}"
print(result) # Вывести результат в стандартный вывод (stdout)
sys.stdout.flush()
self.close()
else:
QMessageBox.critical(self, "Ошибка!", "Заполните все поля, включая пароль!", QMessageBox.Ok)
return
def main():
app = QApplication(sys.argv)
# Параметры окна
width = 420
height = 380
file_name = '/usr/bin/join-to-domain.sh'
# Поиск версии join-to-domain
version = None
if os.path.exists(file_name):
with open(file_name, 'r', encoding='utf-8') as file:
for line in file:
if "Версия:" in line:
version = line.split("Версия:", 1)[1].strip()
break
if version is None:
version=""
show_parameters_tab = False # True или False, чтобы показать/скрыть вкладку "Параметры"
form = DomainForm(width, height, show_parameters_tab)
form.setWindowTitle(f"Ввод в домен {version}")
form.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

@ -0,0 +1,15 @@
[Desktop Entry]
Version=1.0
Name=Join to Domain
Name[ru]=Ввод ПК в домен
GenericName=Join to Domain
GenericName[ru]=Ввод ПК в домен
Comment=Scripts for join host to Windows domain
Comment[ru]=Ввод ПК в домен Windows
Exec=pkexec /usr/bin/join-to-domain.sh -g
Icon=preferences-desktop-remote-desktop
Terminal=false
Type=Application
StartupNotify=true
Categories=GTK;System;
X-Desktop-File-Install-Version=0.26

File diff suppressed because it is too large Load Diff

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE policyconfig PUBLIC "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN" "http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd">
<policyconfig>
<vendor>MSVSphere</vendor>
<vendor_url>https://msvsphere-os.ru/</vendor_url>
<icon_name>preferences-desktop-remote-desktop</icon_name>
<action id="ru.msvsphere.join-to-domain">
<description gettext-domain="xed">Run join-to-domain as root</description>
<message gettext-domain="xed">Authentication is required to run the Join To Domain as root</message>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
<allow_active>auth_admin</allow_active>
</defaults>
<annotate key="org.freedesktop.policykit.exec.path">/usr/bin/join-to-domain.sh</annotate>
<annotate key="org.freedesktop.policykit.exec.allow_gui">true</annotate>
</action>
</policyconfig>

@ -0,0 +1,73 @@
Summary: GUI to join MSVSphere host to domain
Name: join-to-domain
Version: 0.6.6
Release: 1%{?dist}
License: GPLv2+
URL: https://redos.red-soft.ru/
Source0: join-to-domain.sh
Source1: ru.msvsphere.join-to-domain.policy
Source2: form-join-to-domain.py
Source3: join-to-domain.desktop
Requires: %{name}-cli = %{version}-%{release}
Requires: yad
BuildArch: noarch
%description
GUI for join MSVSphere host to domain.
%package cli
Summary: CLI to join MSVSphere host to domain
Requires: adcli
Requires: krb5-workstation
Requires: oddjob
Requires: oddjob-mkhomedir
Requires: polkit
Requires: realmd
Requires: samba-common
Requires: samba-common-tools
Requires: sssd
BuildArch: noarch
%description cli
CLI for join MSVSphere host to domain.
%prep
%build
# Nothing to build
%install
install -d %{buildroot}%{_bindir}/
install -d %{buildroot}%{_datadir}/polkit-1/actions/
install -d %{buildroot}%{_datadir}/join-to-domain/
install -d %{buildroot}%{_datadir}/applications/
install -m755 %{SOURCE0} %{buildroot}%{_bindir}/
install -m644 %{SOURCE1} %{buildroot}%{_datadir}/polkit-1/actions/
install -m755 %{SOURCE2} %{buildroot}%{_datadir}/join-to-domain/
install -m644 %{SOURCE3} %{buildroot}%{_datadir}/applications/
ln -sr %{buildroot}%{_bindir}/join-to-domain.sh %{buildroot}%{_bindir}/JoinToDomain
%files
%dir %{_datadir}/%{name}
%{_datadir}/%{name}/form-join-to-domain.py
%{_datadir}/applications/join-to-domain.desktop
%files cli
%{_bindir}/JoinToDomain
%{_bindir}/join-to-domain.sh
%{_datadir}/polkit-1/actions/ru.msvsphere.join-to-domain.policy
%changelog
* Fri Apr 05 2024 Arkady L. Shane <ashejn@msvsphere.ru> - 0.6.6-1
- Rebuilt for MSVSphere 9.2
* Fri Apr 5 2024 Arkady L. Shane <tigro@msvsphere-os.ru> - 0.6.6-1
- Initial build
Loading…
Cancel
Save