Могу ли я после блока Match Group в ForceCommand ссылаться на имя пользователя (и т. д. )в общем виде?

Приоритетные процессы и управление доступом к терминалу

Чтобы понять, что происходит, вам нужно немного узнать о совместном использовании терминалов. Что происходит, когда две программы одновременно пытаются читать данные с одного и того же терминала? Каждый входной байт случайным образом попадает в одну из программ. (Не случайно, так как в ядре для принятия решения используется ГСЧ, а просто случайно, поскольку на практике это непредсказуемо. )То же самое происходит, когда две программы читают из канала или любого другого типа файла, который представляет собой поток байтов, перемещаемых из одного места в другое (сокет, символьное устройство, … ), а не байт массив, в котором любой байт может быть прочитан несколько раз (обычный файл, блочное устройство ). Например, запустите оболочку в терминале, узнайте имя терминала и запустите cat.

$ tty
/dev/pts/18
$ cat

Затем с другого терминала запустите cat /dev/pts/18. Теперь введите терминал и посмотрите, как строки иногда идут в один из процессов cat, а иногда в другой. Строки отправляются целиком, когда терминал находится в режиме приготовления.Если вы поместите терминал в необработанный режим, то каждый байт будет отправлен независимо.

Это грязно. Наверняка должен быть механизм, определяющий, что одна программа получает терминал, а другая нет. Ну, есть! Он срабатывает в типичных случаях, но не в сценарии, который я установил выше. Этот сценарий необычен, потому что cat /dev/pts/18не был запущен из /dev/pts/18. Необычно получить доступ к терминалу из программы, которая не была запущена внутри этого терминала. В обычном случае вы запускаете оболочку в терминале и запускаете программы из этой оболочки. Тогда правило состоит в том, что программа на переднем плане получает терминал, а программы на заднем плане — нет. Это известно как управление доступом к терминалу . Как это работает:

  • Каждый процесс имеет управляющий терминал(или не имеет его, как правило, потому, что у него нет дескриптора открытого файла, который является терминалом ).
  • Когда процесс пытается получить доступ к управляющему терминалу, если процесс не находится на переднем плане, ядро ​​блокирует его. (Применяются условия. Доступ к другим терминалам не регламентируется.)
  • Оболочка решает, кто является процессом переднего плана. (На самом деле группа процессов переднего плана. )Он вызывает tcsetpgrp, чтобы сообщить ядру, кто должен быть на переднем плане.

Это работает в типичных случаях. Запустите программу в оболочке, и эта программа станет процессом переднего плана. Запустите программу в фоновом режиме (с помощью &), и программа не будет работать на переднем плане. Когда оболочка отображает подсказку, она выводит себя на передний план. Когда вы возобновляете приостановленное задание с помощью fg, оно становится приоритетным. С bgэто не так.

Если фоновый процесс пытается прочитать данные с терминала, ядро ​​отправляет ему сигнал SIGTTIN. Действие сигнала по умолчанию — приостановить процесс (, например SIGSTOP ).Родитель процесса может узнать об этом, вызвавwaitpidс флагом WSTOPPED; когда дочерний процесс получает сигнал, который приостанавливает его, вызов waitpidв родительском процессе возвращается и сообщает родителю, что это был за сигнал. Вот как оболочка знает, что нужно напечатать «Stopped (tty input )». Это говорит вам, что эта работа приостановлена ​​​​из-за SIGTTIN.

Поскольку процесс приостановлен, с ним ничего не произойдет, пока он не будет возобновлен или уничтожен (с сигналом, который процесс не перехватывает, потому что, если процесс установил обработчик сигнала, он не запустится, поскольку процесс приостановлен ). Вы можете возобновить процесс, отправив ему SIGCONT, но это ничего не даст, если процесс читает с терминала, он немедленно получит другой SIGTTIN. Если вы возобновите процесс с помощью fg, он перейдет на передний план, и чтение будет выполнено успешно.

Теперь вы понимаете, что происходит, когда вы запускаете catв фоновом режиме:

$ cat &
$ 
[1] + Stopped (tty input)        cat
$ 

Случай SSH

Теперь давайте проделаем то же самое с SSH.

$ ssh localhost sleep 999999 &
$ 
$ 
$ 
[1] + Stopped (tty input)        ssh localhost sleep 999999
$ 

Нажатие Enter иногда переходит к оболочке (, которая находится на переднем плане ), а иногда к процессу SSH (, после чего он останавливается SIGTTIN ). Почему? Если sshчитал с терминала, он должен немедленно получить SIGTTIN, а если нет, то почему он получает SIGTTIN?

Происходит следующее: процесс SSH вызывает системный вызов select, чтобы узнать, доступны ли входные данные для любого из интересующих его файлов (или готов ли выходной файл для приема дополнительных данных ). Источники ввода включают в себя, по крайней мере, терминал и сетевую розетку. В отличие от read, selectне запрещен для фоновых процессов, и sshне получает SIGTTIN при вызове select. Цель select— выяснить, доступны ли данные, ничего не нарушая.В идеале selectвообще не изменило бы состояние системы, но на самом деле это не совсем так. Когда selectсообщает процессу SSH, что ввод доступен в файловом дескрипторе терминала, ядро ​​должно зафиксировать отправку ввода, если процесс впоследствии вызывает read. (Если бы это было не так и процесс вызвал read, то в этот момент входные данные могли бы быть недоступны, поэтому возвращаемое значение из selectбыло бы ложью. )Таким образом, если ядро ​​решает направить некоторый ввод в процесс SSH, оно принимает решение к моменту возврата системного вызова select. Затем SSH вызывает read, и в этот момент ядро ​​​​видит, что фоновый процесс пытался читать с терминала, и приостанавливает его с помощью SIGTTIN.

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

Решение :не читать с терминала

Если вам нужен сеанс SSH для чтения с терминала, запустите его на переднем плане.

Если вам не нужен сеанс SSH для чтения с терминала, убедитесь, что его ввод не поступает с терминала. Есть два способа сделать это:

  • Вы можете перенаправить ввод:

    ssh … 
  • Вы можете указать SSH не перенаправлять терминальное соединение с помощью -nили -f.(-nэквивалентно ; -fпозволяет самому SSH читать с терминала, т.е. чтобы прочитать пароль, но сама команда не откроет терминал.)

    ssh -n …
    

Обратите внимание, что отключение между терминалом и SSH должно происходить на клиенте. Процесс sleep, работающий на сервере, никогда не будет читать данные с терминала, но SSH не может об этом узнать. Если клиент получает ввод на стандартном вводе, он должен перенаправить его на сервер, который сделает данные доступными в буфере на случай, если приложение когда-либо решит прочитать их (и если приложение вызовет select,будет сообщено, что данные доступны ).

1
18.10.2020, 02:02
1 ответ

Команда запускается от пользователя, к которому вы подключаетесь. Таким образом, у вас $USER, $LOGNAME, $HOMEи т. д. установлены для одного и того же пользователя. Нет никаких проблем с их использованием.

Сама команда запускается с пользовательской оболочкой (обычно bash, поэтому /bin/bash -c 'your_forcecommand'), поэтому вы можете включить такие переменные в ForceCommand, и они будут расширены оболочкой.

sshd_configутверждает:

The command is invoked by using the user's login shell with the -c option.

Вы можете найти в коде OpenSSH , что он устанавливает PATH, USER, LOGNAMEи HOME.

2
18.03.2021, 22:56

Теги

Похожие вопросы