Создание тонкого клиента на базе дешевых одноплатных ПК

от автора

Иногда требуется сделать хитрый тонкий клиент — с необычной авторизацией и минимумом затрат.

Проще всего для этого использовать Linux.

Для одноплатных пк на базе ARM широко распространен дистрибутив Armbian, который основан на Debian ветке.

Для экспериментов у меня в наличии была плата OrangePi One
image
и MicroSD карта на 2G — я решил сделать из этого тонкий клиент RDP с окном блокировки и без лишнего программного обеспечения.

Дистрибутив Armbian для этой платы здесь.

Качаем последний с пометкой:

Server or light desktop usage scenarios.

В нем не будет рабочего стола, который не нужен в тонком клиенте.

Записываем образ на MicroSD (я использовал sourceforge.net/projects/win32diskimager).

После записи: вставляем MicroSD, подключаем все интерфейсы (LAN, Дисплей, клавиатуру, мышь), подаем питание, ждем пока загрузится.

Когда система загрузилась появится предложение ввести логин и пароль. Также можно зайти по SSH глянув выданный DHCP адрес (я воспользовался этой возможностью чтобы не вбивать настройки с клавиатуры и запустил PuTTY).

Логин: root
Пароль: 1234

После входа система попросит сменить пароль: вводим текущий 1234 и два раза новый пароль.

Также предлагается создать пользователя — назовем его user.

После этого приступим к настройке системы под задачу.

Установим недостающие пакеты:

apt update apt install xorg lightdm xcursor-themes numix-gtk-theme numix-icon-theme  apt install python-gtk2 freerdp

Запуск графического входа для systemd включется так:

systemctl set-default graphical.target

Создадим файлы:
(содать их проще всего с помощью редактора vi — после запуска с параметром нужно нажать i для вставки — потом просто вставить текст в окно консоли, а по завершении нажать Esc и набрать :w для записи и :q для выхода)

Для получения своих параметров через DHCP сервер

vi /etc/dhcp/dhclient-exit-hooks.d/paramscript

setup_add() {     echo $new_host_name > /etc/hostname     hostname $new_host_name      if [ -z "$new_nds_servers" ] ; then         echo $new_routers > /tmp/rdp_server         echo "testuser" > /tmp/rdp_user         echo "1234test#" > /tmp/rdp_passwd     else         echo $new_nds_servers > /tmp/rdp_server         echo $new_nds_tree_name > /tmp/rdp_user         echo $new_nds_context > /tmp/rdp_passwd     fi }  case $reason in     BOUND|RENEW|REBIND|REBOOT)         setup_add         ;;     EXPIRE|FAIL|RELEASE|STOP)         return         ;; esac 

этот скрипт получает по DHCP имя хоста и nds_servers, nds_tree_name, nds_context и сохраняет их значения в файлах во временной папке. По умолчанию будет использован IP адрес маршрутизатора.

Для настроек GTK и назначения его тем создадим

vi /home/user/.gtkrc-2.0

gtk-icon-theme-name = "Numix" gtk-theme-name = "Numix" gtk-cursor-theme-name = "whiteglass"

Для настройки менеджера графической среды LightDM:

vi /etc/lightdm/lightdm.conf

[LightDM] greeter-user=user [Seat:*] greeter-session=my-greeter

я после экспериментов решил использовать greeter (программа входа), таким образом не придется настраивать автовход, а программа запустится от нужного пользователя.

Теперь создадим ярлык программы (и его папку):

mkdir /usr/share/xgreeters/ vi /usr/share/xgreeters/my-greeter.desktop

[Desktop Entry] Name=PyGTK+ Greeter Comment=This runs the PyGTK+ greeter, it should only be run from LightDM Exec=python /home/user/greeter.py Type=Application X-Ubuntu-Gettext-Domain=lightdm

И сам код программы входа:

vi /home/user/greeter.py

Код предлагает ввести 4 значный пароль 0811 (месяц день с незначащими нулями без прбелов)
После успешного ввода запускается xfreerdp с полученными параметрами.

Код

#!/usr/bin/env python # -*- coding: UTF-8 -*-  from datetime import datetime from gobject import timeout_add import os,sys,gtk,pango,subprocess  class GreeterApp: 	def __init__( self ): 		self.builder = gtk.Builder() 		#self.builder.add_from_file("ui.glade") 		self.builder.add_from_string(ui) 		self.window = self.builder.get_object ("window") 		self.pass_field = self.builder.get_object ("pass_field") 		self.passct = self.builder.get_object ("pass") 		self.contrl = self.builder.get_object ("control") 		self.pass_field.modify_font(pango.FontDescription('Sans Bold 36')) 		self.passwd = datetime.now().strftime("%m%d") 		self.rdp_server = open("/tmp/rdp_server").read().split(',')[0] 		self.rdp_user = open("/tmp/rdp_user").read() 		self.rdp_passwd = open("/tmp/rdp_passwd").read() 		self.process = None 		timeout_add(5000, self.timeout) 		if self.window: 			self.window.connect("destroy", gtk.main_quit) 			self.contrl.set_visible(False) 			self.window.set_size_request(gtk.gdk.screen_width(),gtk.gdk.screen_height()) 		self.builder.connect_signals(self) 	def hide(self, widget): 		self.contrl.set_visible(False) 		self.passct.set_visible(True) 		self.window.move(0,0) 		self.window.set_size_request(gtk.gdk.screen_width(),gtk.gdk.screen_height()) 		if self.process: 			self.process.terminate() 			self.process = None 	def timeout(self): 		if self.window: 			self.window.set_keep_above(True) 			self.window.set_modal(True) 		return True 	def check_pass(self, widget): 		if self.pass_field.get_text() == self.passwd: 			self.pass_field.set_text("") 			self.passct.set_visible(False) 			self.contrl.set_visible(True) 			self.window.set_size_request(50,50) 			self.window.move(0,gtk.gdk.screen_height()-50) 			#sys.exit() 			self.process = subprocess.Popen(["xfreerdp","/v:"+self.rdp_server,"/f","/cert-ignore","/u:"+self.rdp_user,"/p:"+self.rdp_passwd]) 	def clear_pass(self, widget): 		self.pass_field.set_text("") 	def num_press(self, widget): 		self.pass_field.set_text(self.pass_field.get_text()+widget.get_tooltip_text()) 	def on_destroy(self, widget): 		sys.exit() if __name__ == "__main__": 	settings = gtk.settings_get_default() 	#settings.props.gtk_button_images = True 	settings.props.gtk_enable_tooltips = False 	ui = """ <?xml version="1.0" encoding="UTF-8"?> <interface>   <requires lib="gtk+" version="2.24"/>   <object class="GtkWindow" id="window">     <property name="can_focus">False</property>     <property name="type">popup</property>     <property name="title" translatable="yes">MyGreeter</property>     <property name="resizable">False</property>     <signal name="destroy" handler="on_destroy" swapped="no"/>     <child>       <object class="GtkVBox" id="vbox1">         <property name="visible">True</property>         <property name="can_focus">False</property>         <child>           <object class="GtkHBox" id="control">             <property name="visible">True</property>             <property name="can_focus">False</property>             <child>               <object class="GtkButton" id="power1">                 <property name="use_action_appearance">False</property>                 <property name="width_request">50</property>                 <property name="height_request">42</property>                 <property name="visible">True</property>                 <property name="can_focus">True</property>                 <property name="receives_default">True</property>                 <signal name="clicked" handler="hide" swapped="no"/>                 <child>                   <object class="GtkImage" id="image4">                     <property name="visible">True</property>                     <property name="can_focus">False</property>                     <property name="stock">gtk-no</property>                   </object>                 </child>               </object>               <packing>                 <property name="expand">False</property>                 <property name="fill">True</property>                 <property name="position">0</property>               </packing>             </child>             <child>               <placeholder/>             </child>             <child>               <placeholder/>             </child>           </object>           <packing>             <property name="expand">False</property>             <property name="fill">True</property>             <property name="position">0</property>           </packing>         </child>         <child>           <object class="GtkHBox" id="hbox1">             <property name="visible">True</property>             <property name="can_focus">False</property>             <child>               <object class="GtkTable" id="pass">                 <property name="visible">True</property>                 <property name="can_focus">False</property>                 <property name="n_rows">6</property>                 <property name="n_columns">3</property>                 <child>                   <object class="GtkEntry" id="pass_field">                     <property name="width_request">240</property>                     <property name="height_request">60</property>                     <property name="visible">True</property>                     <property name="can_focus">True</property>                     <property name="visibility">False</property>                     <property name="invisible_char">●</property>                     <property name="xalign">1</property>                     <property name="invisible_char_set">True</property>                     <property name="primary_icon_activatable">False</property>                     <property name="secondary_icon_activatable">False</property>                     <property name="primary_icon_sensitive">True</property>                     <property name="secondary_icon_sensitive">True</property>                   </object>                   <packing>                     <property name="right_attach">3</property>                     <property name="bottom_attach">2</property>                     <property name="x_options">GTK_SHRINK</property>                     <property name="y_options">GTK_SHRINK</property>                   </packing>                 </child>                 <child>                   <object class="GtkButton" id="b_0">                     <property name="use_action_appearance">False</property>                     <property name="width_request">80</property>                     <property name="height_request">80</property>                     <property name="visible">True</property>                     <property name="can_focus">True</property>                     <property name="receives_default">True</property>                     <property name="tooltip_text" translatable="yes">0</property>                     <signal name="clicked" handler="num_press" swapped="no"/>                     <child>                       <object class="GtkLabel" id="l_0">                         <property name="visible">True</property>                         <property name="can_focus">False</property>                         <property name="label" translatable="yes">0</property>                         <attributes>                           <attribute name="weight" value="bold"/>                           <attribute name="size" value="40000"/>                         </attributes>                       </object>                     </child>                   </object>                   <packing>                     <property name="top_attach">5</property>                     <property name="bottom_attach">6</property>                     <property name="x_options">GTK_SHRINK</property>                     <property name="y_options">GTK_SHRINK</property>                   </packing>                 </child>                 <child>                   <object class="GtkButton" id="b_1">                     <property name="use_action_appearance">False</property>                     <property name="width_request">80</property>                     <property name="height_request">80</property>                     <property name="visible">True</property>                     <property name="can_focus">True</property>                     <property name="receives_default">True</property>                     <property name="tooltip_text" translatable="yes">1</property>                     <signal name="clicked" handler="num_press" swapped="no"/>                     <child>                       <object class="GtkLabel" id="l_1">                         <property name="visible">True</property>                         <property name="can_focus">False</property>                         <property name="label" translatable="yes">1</property>                         <attributes>                           <attribute name="weight" value="bold"/>                           <attribute name="size" value="40000"/>                         </attributes>                       </object>                     </child>                   </object>                   <packing>                     <property name="top_attach">4</property>                     <property name="bottom_attach">5</property>                     <property name="x_options">GTK_SHRINK</property>                     <property name="y_options">GTK_SHRINK</property>                   </packing>                 </child>                 <child>                   <object class="GtkButton" id="b_2">                     <property name="use_action_appearance">False</property>                     <property name="width_request">80</property>                     <property name="height_request">80</property>                     <property name="visible">True</property>                     <property name="can_focus">True</property>                     <property name="receives_default">True</property>                     <property name="tooltip_text" translatable="yes">2</property>                     <signal name="clicked" handler="num_press" swapped="no"/>                     <child>                       <object class="GtkLabel" id="l_2">                         <property name="visible">True</property>                         <property name="can_focus">False</property>                         <property name="label" translatable="yes">2</property>                         <attributes>                           <attribute name="weight" value="bold"/>                           <attribute name="size" value="40000"/>                         </attributes>                       </object>                     </child>                   </object>                   <packing>                     <property name="left_attach">1</property>                     <property name="right_attach">2</property>                     <property name="top_attach">4</property>                     <property name="bottom_attach">5</property>                     <property name="x_options">GTK_SHRINK</property>                     <property name="y_options">GTK_SHRINK</property>                   </packing>                 </child>                 <child>                   <object class="GtkButton" id="b_3">                     <property name="use_action_appearance">False</property>                     <property name="width_request">80</property>                     <property name="height_request">80</property>                     <property name="visible">True</property>                     <property name="can_focus">True</property>                     <property name="receives_default">True</property>                     <property name="tooltip_text" translatable="yes">3</property>                     <signal name="clicked" handler="num_press" swapped="no"/>                     <child>                       <object class="GtkLabel" id="l_3">                         <property name="visible">True</property>                         <property name="can_focus">False</property>                         <property name="label" translatable="yes">3</property>                         <attributes>                           <attribute name="weight" value="bold"/>                           <attribute name="size" value="40000"/>                         </attributes>                       </object>                     </child>                   </object>                   <packing>                     <property name="left_attach">2</property>                     <property name="right_attach">3</property>                     <property name="top_attach">4</property>                     <property name="bottom_attach">5</property>                     <property name="x_options">GTK_SHRINK</property>                     <property name="y_options">GTK_SHRINK</property>                   </packing>                 </child>                 <child>                   <object class="GtkButton" id="b_4">                     <property name="use_action_appearance">False</property>                     <property name="width_request">80</property>                     <property name="height_request">80</property>                     <property name="visible">True</property>                     <property name="can_focus">True</property>                     <property name="receives_default">True</property>                     <property name="tooltip_text" translatable="yes">4</property>                     <signal name="clicked" handler="num_press" swapped="no"/>                     <child>                       <object class="GtkLabel" id="l_4">                         <property name="visible">True</property>                         <property name="can_focus">False</property>                         <property name="label" translatable="yes">4</property>                         <attributes>                           <attribute name="weight" value="bold"/>                           <attribute name="size" value="40000"/>                         </attributes>                       </object>                     </child>                   </object>                   <packing>                     <property name="top_attach">3</property>                     <property name="bottom_attach">4</property>                     <property name="x_options">GTK_SHRINK</property>                     <property name="y_options">GTK_SHRINK</property>                   </packing>                 </child>                 <child>                   <object class="GtkButton" id="b_5">                     <property name="use_action_appearance">False</property>                     <property name="width_request">80</property>                     <property name="height_request">80</property>                     <property name="visible">True</property>                     <property name="can_focus">True</property>                     <property name="receives_default">True</property>                     <property name="tooltip_text" translatable="yes">5</property>                     <signal name="clicked" handler="num_press" swapped="no"/>                     <child>                       <object class="GtkLabel" id="l_5">                         <property name="visible">True</property>                         <property name="can_focus">False</property>                         <property name="label" translatable="yes">5</property>                         <attributes>                           <attribute name="weight" value="bold"/>                           <attribute name="size" value="40000"/>                         </attributes>                       </object>                     </child>                   </object>                   <packing>                     <property name="left_attach">1</property>                     <property name="right_attach">2</property>                     <property name="top_attach">3</property>                     <property name="bottom_attach">4</property>                     <property name="x_options">GTK_SHRINK</property>                     <property name="y_options">GTK_SHRINK</property>                   </packing>                 </child>                 <child>                   <object class="GtkButton" id="b_6">                     <property name="use_action_appearance">False</property>                     <property name="width_request">80</property>                     <property name="height_request">80</property>                     <property name="visible">True</property>                     <property name="can_focus">True</property>                     <property name="receives_default">True</property>                     <property name="tooltip_text" translatable="yes">6</property>                     <signal name="clicked" handler="num_press" swapped="no"/>                     <child>                       <object class="GtkLabel" id="l_6">                         <property name="visible">True</property>                         <property name="can_focus">False</property>                         <property name="label" translatable="yes">6</property>                         <attributes>                           <attribute name="weight" value="bold"/>                           <attribute name="size" value="40000"/>                         </attributes>                       </object>                     </child>                   </object>                   <packing>                     <property name="left_attach">2</property>                     <property name="right_attach">3</property>                     <property name="top_attach">3</property>                     <property name="bottom_attach">4</property>                     <property name="x_options">GTK_SHRINK</property>                     <property name="y_options">GTK_SHRINK</property>                   </packing>                 </child>                 <child>                   <object class="GtkButton" id="b_7">                     <property name="use_action_appearance">False</property>                     <property name="width_request">80</property>                     <property name="height_request">80</property>                     <property name="visible">True</property>                     <property name="can_focus">True</property>                     <property name="receives_default">True</property>                     <property name="tooltip_text" translatable="yes">7</property>                     <signal name="clicked" handler="num_press" swapped="no"/>                     <child>                       <object class="GtkLabel" id="l_7">                         <property name="visible">True</property>                         <property name="can_focus">False</property>                         <property name="label" translatable="yes">7</property>                         <attributes>                           <attribute name="weight" value="bold"/>                           <attribute name="size" value="40000"/>                         </attributes>                       </object>                     </child>                   </object>                   <packing>                     <property name="top_attach">2</property>                     <property name="bottom_attach">3</property>                     <property name="x_options">GTK_SHRINK</property>                     <property name="y_options">GTK_SHRINK</property>                   </packing>                 </child>                 <child>                   <object class="GtkButton" id="b_8">                     <property name="use_action_appearance">False</property>                     <property name="width_request">80</property>                     <property name="height_request">80</property>                     <property name="visible">True</property>                     <property name="can_focus">True</property>                     <property name="receives_default">True</property>                     <property name="tooltip_text" translatable="yes">8</property>                     <signal name="clicked" handler="num_press" swapped="no"/>                     <child>                       <object class="GtkLabel" id="l_8">                         <property name="visible">True</property>                         <property name="can_focus">False</property>                         <property name="label" translatable="yes">8</property>                         <attributes>                           <attribute name="weight" value="bold"/>                           <attribute name="size" value="40000"/>                         </attributes>                       </object>                     </child>                   </object>                   <packing>                     <property name="left_attach">1</property>                     <property name="right_attach">2</property>                     <property name="top_attach">2</property>                     <property name="bottom_attach">3</property>                     <property name="x_options">GTK_SHRINK</property>                     <property name="y_options">GTK_SHRINK</property>                   </packing>                 </child>                 <child>                   <object class="GtkButton" id="b_9">                     <property name="use_action_appearance">False</property>                     <property name="width_request">80</property>                     <property name="height_request">80</property>                     <property name="visible">True</property>                     <property name="can_focus">True</property>                     <property name="receives_default">True</property>                     <property name="tooltip_text" translatable="yes">9</property>                     <signal name="clicked" handler="num_press" swapped="no"/>                     <child>                       <object class="GtkLabel" id="l_9">                         <property name="visible">True</property>                         <property name="can_focus">False</property>                         <property name="label" translatable="yes">9</property>                         <attributes>                           <attribute name="weight" value="bold"/>                           <attribute name="size" value="40000"/>                         </attributes>                       </object>                     </child>                   </object>                   <packing>                     <property name="left_attach">2</property>                     <property name="right_attach">3</property>                     <property name="top_attach">2</property>                     <property name="bottom_attach">3</property>                     <property name="x_options">GTK_SHRINK</property>                     <property name="y_options">GTK_SHRINK</property>                   </packing>                 </child>                 <child>                   <object class="GtkButton" id="b_ent">                     <property name="use_action_appearance">False</property>                     <property name="width_request">80</property>                     <property name="height_request">80</property>                     <property name="visible">True</property>                     <property name="can_focus">True</property>                     <property name="receives_default">True</property>                     <signal name="clicked" handler="check_pass" swapped="no"/>                     <child>                       <object class="GtkImage" id="image2">                         <property name="visible">True</property>                         <property name="can_focus">False</property>                         <property name="stock">gtk-yes</property>                       </object>                     </child>                   </object>                   <packing>                     <property name="left_attach">1</property>                     <property name="right_attach">2</property>                     <property name="top_attach">5</property>                     <property name="bottom_attach">6</property>                     <property name="x_options">GTK_SHRINK</property>                     <property name="y_options">GTK_SHRINK</property>                   </packing>                 </child>                 <child>                   <object class="GtkButton" id="b_del">                     <property name="use_action_appearance">False</property>                     <property name="width_request">80</property>                     <property name="height_request">80</property>                     <property name="visible">True</property>                     <property name="can_focus">True</property>                     <property name="receives_default">True</property>                     <signal name="clicked" handler="clear_pass" swapped="no"/>                     <child>                       <object class="GtkImage" id="image3">                         <property name="visible">True</property>                         <property name="can_focus">False</property>                         <property name="stock">gtk-no</property>                       </object>                     </child>                   </object>                   <packing>                     <property name="left_attach">2</property>                     <property name="right_attach">3</property>                     <property name="top_attach">5</property>                     <property name="bottom_attach">6</property>                     <property name="x_options">GTK_SHRINK</property>                     <property name="y_options">GTK_SHRINK</property>                   </packing>                 </child>               </object>               <packing>                 <property name="expand">True</property>                 <property name="fill">False</property>                 <property name="position">0</property>               </packing>             </child>           </object>           <packing>             <property name="expand">True</property>             <property name="fill">False</property>             <property name="position">1</property>           </packing>         </child>       </object>     </child>   </object> </interface> 	""" 	app = GreeterApp() 	app.window.show() 	gtk.main()

Код предоставлен как пример — можно сделать просто ввод имени и пароля для RDP подключения, выбор серверов, мониторинг серверов и все на что способна ваша фантазия — хоть вход по отпечатку пальца.


ссылка на оригинал статьи https://habr.com/post/420099/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *