[Из песочницы] Создание тонкого клиента на базе дешевых одноплатных ПК

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

Проще всего для этого использовать 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 = """


  
  
    False
    popup
    MyGreeter
    False
    
    
      
        True
        False
        
          
            True
            False
            
              
                False
                50
                42
                True
                True
                True
                
                
                  
                    True
                    False
                    gtk-no
                  
                
              
              
                False
                True
                0
              
            
            
              
            
            
              
            
          
          
            False
            True
            0
          
        
        
          
            True
            False
            
              
                True
                False
                6
                3
                
                  
                    240
                    60
                    True
                    True
                    False
                    
                    1
                    True
                    False
                    False
                    True
                    True
                  
                  
                    3
                    2
                    GTK_SHRINK
                    GTK_SHRINK
                  
                
                
                  
                    False
                    80
                    80
                    True
                    True
                    True
                    0
                    
                    
                      
                        True
                        False
                        0
                        
                          
                          
                        
                      
                    
                  
                  
                    5
                    6
                    GTK_SHRINK
                    GTK_SHRINK
                  
                
                
                  
                    False
                    80
                    80
                    True
                    True
                    True
                    1
                    
                    
                      
                        True
                        False
                        1
                        
                          
                          
                        
                      
                    
                  
                  
                    4
                    5
                    GTK_SHRINK
                    GTK_SHRINK
                  
                
                
                  
                    False
                    80
                    80
                    True
                    True
                    True
                    2
                    
                    
                      
                        True
                        False
                        2
                        
                          
                          
                        
                      
                    
                  
                  
                    1
                    2
                    4
                    5
                    GTK_SHRINK
                    GTK_SHRINK
                  
                
                
                  
                    False
                    80
                    80
                    True
                    True
                    True
                    3
                    
                    
                      
                        True
                        False
                        3
                        
                          
                          
                        
                      
                    
                  
                  
                    2
                    3
                    4
                    5
                    GTK_SHRINK
                    GTK_SHRINK
                  
                
                
                  
                    False
                    80
                    80
                    True
                    True
                    True
                    4
                    
                    
                      
                        True
                        False
                        4
                        
                          
                          
                        
                      
                    
                  
                  
                    3
                    4
                    GTK_SHRINK
                    GTK_SHRINK
                  
                
                
                  
                    False
                    80
                    80
                    True
                    True
                    True
                    5
                    
                    
                      
                        True
                        False
                        5
                        
                          
                          
                        
                      
                    
                  
                  
                    1
                    2
                    3
                    4
                    GTK_SHRINK
                    GTK_SHRINK
                  
                
                
                  
                    False
                    80
                    80
                    True
                    True
                    True
                    6
                    
                    
                      
                        True
                        False
                        6
                        
                          
                          
                        
                      
                    
                  
                  
                    2
                    3
                    3
                    4
                    GTK_SHRINK
                    GTK_SHRINK
                  
                
                
                  
                    False
                    80
                    80
                    True
                    True
                    True
                    7
                    
                    
                      
                        True
                        False
                        7
                        
                          
                          
                        
                      
                    
                  
                  
                    2
                    3
                    GTK_SHRINK
                    GTK_SHRINK
                  
                
                
                  
                    False
                    80
                    80
                    True
                    True
                    True
                    8
                    
                    
                      
                        True
                        False
                        8
                        
                          
                          
                        
                      
                    
                  
                  
                    1
                    2
                    2
                    3
                    GTK_SHRINK
                    GTK_SHRINK
                  
                
                
                  
                    False
                    80
                    80
                    True
                    True
                    True
                    9
                    
                    
                      
                        True
                        False
                        9
                        
                          
                          
                        
                      
                    
                  
                  
                    2
                    3
                    2
                    3
                    GTK_SHRINK
                    GTK_SHRINK
                  
                
                
                  
                    False
                    80
                    80
                    True
                    True
                    True
                    
                    
                      
                        True
                        False
                        gtk-yes
                      
                    
                  
                  
                    1
                    2
                    5
                    6
                    GTK_SHRINK
                    GTK_SHRINK
                  
                
                
                  
                    False
                    80
                    80
                    True
                    True
                    True
                    
                    
                      
                        True
                        False
                        gtk-no
                      
                    
                  
                  
                    2
                    3
                    5
                    6
                    GTK_SHRINK
                    GTK_SHRINK
                  
                
              
              
                True
                False
                0
              
            
          
          
            True
            False
            1
          
        
      
    
  

        """
        app = GreeterApp()
        app.window.show()
        gtk.main()


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

© Habrahabr.ru