Автовход с паролем и управление по ssh «в гостях» при помощи expect

    В очередной раз используя этот скрипт в одном из учебных классов, я поискал материалы и обнаружил, что здесь давно не вспоминали об expect. Это замечательный альтернативный интерпретатор для командной строки Linux, который может общаться с ней вместо живого человека, и я добавлю сюда лишь ещё один пример его применения.



    Картинок на эту тему особо нет, а в статье и вообще не будет, поэтому привлечём ваше внимание обложкой замечательной книги


    Немного истории и оффтопика


    В начале 2013го я вернулся в дополнительное образование детей, получил 24 часа еженедельной нагрузки для четырёх групп «юных программистов» и «юных системных администраторов», и приступил к набору учеников на двух площадках: моём собственном кабинете и кабинете информатики находящейся неподалёку гимназии. Силами групп «юных системных администраторов» мы привели свой кабинет в порядок, развернув AltLinux 6 и парочку альтернативных дистрибутивов. А в гимназии очень опытный «инженер компьютерного класса» давно вёл эксперименты с source-based, закончившиеся приходом Calculate Linux на все машины учителей и учебных классов. Респект ему)

    Задача


    Через пару месяцев занятий я увидел проблему. Дети отказывались уходить с занятий, любым способом стараясь задержаться подольше. Т.к. педагогические технологии — это не моё, а кружок у нас всё-таки технический, я убивал сторонние процессы и выключал машины по ssh. Это повысило интерес учеников к изучению возможностей командной строки. Однако скоро они нашли баг: выключение «руками» занимает слишком много времени, и даже в небольшом кабинете они успеют перезапустить половину машин до того, как я завершу карательный процесс, и это затянет дело. Чтобы продемонстрировать кто здесь главный лучшие возможности программирования для командной строки, я задумался об автоматизации.

    Варианты решения


    Нулевой мыслью было использование italc, и мы даже уделили несколько недель его настройке и экспериментам. Но он оказался слишком глючен и примитивен, поэтому был благополучно забыт.

    Первой же мыслью было настроить доступ через ssh по отпечатку. Это сократило бы задачу до одного цикла, но для применения «на коленке» этот способ оказался не совсем пригоден (хотя почему нет? ЕМНИП, отпечаток для пользователя также можно создать без рута). Но при доступной авторизации по паролю (кстати, большой ущерб безопасности для учебных классов, где логин-пароли одинаковы) меня заинтересовал вариант с автоматической авторизацией по паролю. Уделив час поиску, я нашёл несколько примеров для expect.

    Решение через expect


    Перед началом

    Но, во первых, он должен быть установлен. В моём классе мы без труда сделали это, а вот в классе гимназии ВНЕЗАПНО оказалось, что и expect, и nmap, и некоторые другие интересные системные утилиты не только установлены, но и доступны ученику. Это очень помогло нам, когда в очередной раз «упал» прикрученный по NFS сетевой диск, и мы нашли способ распространения заданий через быстро найденный бухгалтерский компьютер с расшаренными дисками.

    Во вторых, кроме самого expect, нам понадобится использовать 2 типа цикла: с предусловием и с параметром. Первый необходим для «зацикливания» процесса, чтобы можно было повесить выполнение скрипта фоном на всё занятие. Второй же необходим для перебора необходимых адресов, на которые мы будем заходить по ssh при помощи собственно expect.

    Также необходимо помнить, что стандартно скрипт выпадает при возникновении первой же ошибки, например неответе компьютера клиента, и наверное стоит поискать способ обработки таких исключений.

    Скрипт

    Сообщаем, что для выполнения нам необходимо использовать нестандартный интерпретатор
    #!/usr/bin/expect -f
    


    Задаём паузу для ожидания ответа с клиента, имя пользователя и пароль (это скорее по инерции из имеющихся в сети примеров):

    set timeout 2
    set USER "u1"
    set PASS "1"
    


    Начало сценария:
    while 1 {   // применение цикла с предусловием 
    foreach HOST {58 60 61} {     // применение цикла с параметром для списка окончаний адресов. Да, их можно генерировать и автоматически, но пост не об этом
    spawn ssh $USER@192.168.0.$HOST // подключаемся
      expect {
      "(yes/no)?*" {
      send "yes\r" // не забывайте про \r в конце строки, перед кавычками. Иначе волшебства не получится
     }
      }
       expect "word:"
      send "$PASS\r"
      expect "$*"
      send "killall -r teew*\r"
      expect "$*"
      send "killall firefox\r"
      expect "$*"
      send "killall chrome\r"
      expect "$*"
      send "exit\r"
      expect eof
     }
    


    Это был простой скрипт автоубивания ненужных процессов для гимназии. В своём же кабинете я модифицировал скрипт и для автовыключения машин:

    guest@0-315-gymn2 ~ $ cat scripty 
    #!/usr/bin/expect -f
    set timeout 2
    set USER "user"
    set HOST "2"
    set PASS "2357"
    # Начало сценария
     while 1 {
     foreach HOST {2 3 5 7} { 
      spawn ssh $USER@192.168.0.$HOST
      expect {
      "(yes/no)?*" {
      send "yes\r"
      }
      } 
      expect "word:"
      send "$PASS\r"
      expect "$*"
      send "su\r"
      expect "word:*"
      send "supassword\r"
      expect "#*"
      send "/sbin/shutdown 0 -hP\r"
      expect "#*"
      send "exit\r"
      expect "$*"
      send "exit\r"
      expect eof
     }
     }
    


    Заключение


    Надеюсь, упоминание замечательного интерпретатора expect и пара живых примеров по работе с ним будут полезны сообществу и породят немало статей о более тонких его применениях.

    P.S.:


    Скрипт автопоиска активных компьютеров и создания списка адресов для обработки чуть позже написал один мой ученик (не делать же всё интересное самому). Чуть позже, когда заслужит инвайт, он сможет сам написать об этом в применении к более интересной задаче.
    Support the author
    Share post

    Similar posts

    Comments 23

      +6
      ssh вход по ключам на все машины и ssh root@ shutdown -h now
      А дальше обернуть это в обычный bash скрипт.

      И никакого expect не надо.
        –5
        Об этом есть в статье. Тем более вход рутом отключен
          +3
          Да не вопрос. sudoers никто не отменял.
            –6
            sudo тоже не тру-решение. Можно настроить разрешение только для ограниченного списка команд, но это не так интересно
              0
              Да ладно. В таком случае — man sudo. После чего в /etc/sudoers пишем что-то типа:
              %admin ALL=(ALL:ALL) NOPASSWD: ALL

              В результате — группа админов может запускать все без пароля через sudo.
        +4
        Это перевод? Просто язык текста на столько трудно читаем. И цель стать какая? Показать как работает expect, или выключить компьютеры?
        Просто в данном случае, авторизация по ключам команда shutdown, это цикл тело которого всего 1 строка, и без имитации поведения пользователя.
          +2
          Про авторизацию по ключу уже написали.
          чтоб лишний софт не запускали достаточно снять флаг exec с /usr/bin/firefox и монтировать /home и т.п. с noexec
            –2
            А смысл? Для учебного процесса он нужен, дёргать флаги туда-сюда только для отключения браузера это слишком. Но для выпиливания флэша примерно так и сделали.

            Опять же, зачем нам /home, из которого нельзя ничего запустить, если ученики часто запускают что-то своё в пользовательской зоне, и это нормально. Хотя в целом разрулить права на запуск потоньше тоже интересно
              0
              c flash вам это не поможет:
              firefox плагин найдет в ~/.mozilla/plugins/libflashplayer.so
              +1
              чтоб лишний софт не запускали
              Может проще Restricted shell например rbash воспользоваться?
              +2
              Посмотрите в сторону ansible, может пригодится вам. Может работать поверх ssh с паролем, выполнять скрипты/команды на удаленной системе через sudo.
                +1
                Это как стрелять из пушки по воробьям.
                Вы бы еще chef предложили.
                  +1
                  Ну это уже автору топика решать- полезно ему будет ansible или нет.
                    –1
                    Комментарии отлично дополняют статью, и всё что здесь написано будет полезно. Кто-то пойдёт другим путём, кто-то быстрее справится с expect
                +5
                mssh список машин. В получившемся окне делаем killall -u username — задача решена. Если машин больше -цати, то используем параллельный запуск команды в цикле — получаем параллелизм для бедных. Всё решение задачи — половина однострочника.
                  +1
                  expect {
                  "(yes/no)?*" {
                  send «yes\r» // не забывайте про \r в конце строки, перед кавычками. Иначе волшебства не получится
                  }

                  Попробуйте опцию StrictHostKeyChecking=no, тогда волшебства делать будет не нужно.
                    –1
                    Об этом я тоже в курсе, но забыл добавить в статью. Хотя, в условиях гостевого кабинета, настройки ssh всё равно не поменять. Но интересующимся Ваш комментарий будет очень полезен
                      +3
                      Не надо менять настройки клиента. Почитайте про флаг "-o" команды ssh.
                    +1
                    когда-то рассказывал как у меня в солярке было.
                    ssh bliznezz@192.168.0.1
                    The authenticity of host '192.168.0.1 (192.168.0.1)' can't be established. 
                    RSA key fingerprint is ac:80:1b:40:3c:fd:c0:f3:51:1d:a5:69:46:b0:15:11. 
                    Are you sure you want to continue connecting (да/нет)? yes 
                    Please type 'да' or 'нет':
                      +3
                      Когда у меня встала задача ssh с паролем, быстро в дистрибутиве нашлась утилитка.

                      $ yum info sshpass

                      Summary: Non-interactive SSH authentication utility
                      URL: http://sshpass.sourceforge.net/
                      License: GPLv2
                      Description: Tool for non-interactively performing password authentication with so called
                      : «interactive keyboard password authentication» of SSH. Most users should use
                      : more secure public key authentication of SSH instead.
                        +1
                        А я всегда, видимо ошибочно, считал что expect это просто скрипт TCL/TK идущий в стандартной поставке TCL/TK. А он, оказывается, может быть установлен самостоятельно в /bin/, да?
                        +1
                        Я просто оставлю это здесь для тех, кому хочется немного более подробный how-to про expect.

                        Only users with full accounts can post comments. Log in, please.