前置き
以前、元教え子から PHP を教えてほしいと依頼された時に、何度かもどかしい状態になったので、
「screen コマンドを使ってリモートで指導できたらなぁ」と考えたんだけど、忙しすぎて実現しなかった。
あの時は、VNC でターミナルの操作を奪って…とか、遠回りなことをしていた。
(夜中に VNC を電話でインストールさせてサーバに接続させるとか、ほんと無理。でも教え子の若い情熱に負けちゃったんだよね。もうやんない)
その時調査したのは「screen -x user/session」なんだけど、
よそ様の Web ページを拝見して「セキュリティに問題あるけど chmod u+s screen を実行しろ」のアドバイスを発見した。
(「大きな問題ではない」という意見の記述もあるけど、man に「Multiuser はループになっても検出できないから注意しろ」とも書いてある)
確かに、他人のソケットを覗くにはコマンドを root で実行する必要があるし、
実際に u+s せずに実行するとこう(↓)なる。
$ screen -x user/sessionでも、生徒に u+s したコマンドを使わせて余計なトラブルを招きたくない。訳: マルチユーザを使うには suid (u+s) を実行すべし。
Must run suid root for multiuser support.
例えば、仲良しグループ全員でお互いを覗いたりしたら、あっという間にループができて収拾がつかなくなる。
ならば、u+s したコマンドを生徒に使わせないなら良んじゃね?
覗かれる側に u+s は必要ないじゃろ。
答えは意外に簡単だった。あの時悩んだのは何だったんだろう。
1. 設定要件
種別 内容 備考 スクリーンマネージャ Screen version 4.08.00 (GNU) 05-Feb-20 本稿記述時の最新版 ログインシェル GNU bash, version 5.1.8(1)-release OS AlmaLinux release 9.4 (Seafoam Ocelot)
(Solaris11 でも動作可能)アカウント padawan
ホームディレクトリ: /home/padawan/
screen セッション名: work生徒側 knight 先生側 master
• アカウントは生徒側、先生側ともに予め「ふつうに」使えるように作成しておく。(useradd, passwd 等の作業)
2. 設定
2-1. 生徒側設定
• screen コマンドの設定ファイルを用意する。(screen が起動時に自動的に読み込む)2-2. 先生側設定
$ su• 操作ログの格納先を用意する。
# cat > /home/padawan/.screenrc << EOF
deflog on
logfile ".screenlogs/%H_%Y%m%d_%0c_%p:%n.log"
multiuser on
acladd root
EOF
# cat /home/padawan/.screenrc
*1立ち入り属性を変更するときは、screen の中から aclchg root -w "#?" を実行する。
deflog on # 操作ログを記録する。 logfile ".screenlogs/%H_%Y%m%d_%0c_%p:%n.log" # 操作ログのファイル名を指定。 multiuser on # マルチユーザモードにする。 acladd root # 管理者の立ち入りを許可する。(knight が sudo してくるため root で良い) #aclchg root -w "#?"# <-- なぜか最初から閲覧モードにすることができない*1。
padawan / knight どちらからでも設定 / 解除が可能。
# mkdir /home/padawan/.screenlogs/• ログイン時に screen コマンドが自動起動するようにする。
# chown padawan:padawan /home/padawan/.screenlogs/
生徒の健康を考慮し、連続訓練時間を 8 時間にしている。(付き合わされる先生の健康も…)• exit の確認を仕込む。(これはお好みで)
ログイン後 8 時間を経過すると自動的にログアウトする。
(再度ログインしたら、また 8 時間が始まるんだけどね)
# cat >> /home/padawan/.bash_profile << EOF
WORK_TIME='8 hours'
export WORK_BEGIN=\`date "+%Y-%m-%d %H:%M:%S"\`
export WORK_END=\`date "+%Y-%m-%d %H:%M:%S" -d "\$WORK_TIME"\`
BIRTH=\`stat -c %w /run/screen/S-\$USER/*\`
WORK_REMAIN=\$((\`date +%s -d "\$BIRTH \$WORK_TIME"\` - \`date +%s\`))
if [ \$WORK_REMAIN -le 2 ] ; then WORK_REMAIN=2 ; fi
export WORK_REMAIN
(sleep \$WORK_REMAIN ; /usr/bin/screen -X quit) &
export IGNOREEOF=8640000
/usr/bin/screen -d -R -S work
exit
EOF
# cat /home/padawan/.bash_profile | tail -15
賢い生徒はこのファイルを変更できる。防止するなら i ビットを立てておくこと。
# User specific environment and startup programs WORK_TIME='8 hours'*2 export WORK_BEGIN=`date "+%Y-%m-%d %H:%M:%S"`*3 export WORK_END=`date "+%Y-%m-%d %H:%M:%S" -d "$WORK_TIME"`*3 BIRTH=`stat -c %w /run/screen/S-$USER/*`*4 WORK_REMAIN=$((`date +%s -d "$BIRTH $WORK_TIME"` - `date +%s`)) if [ $WORK_REMAIN -le 2 ] ; then WORK_REMAIN=2 ; fi export WORK_REMAIN (sleep $WORK_REMAIN ; /usr/bin/screen -X quit) & export IGNOREEOF=8640000*5 /usr/bin/screen -d -R*6 -S work*7 exit*8
*2強制終了を 8 時間後にする。休憩後に再接続すること。
*3訓練の開始と終了の日時を変数に格納し、子プロセスから参照できるようにしておく。
*4ログインから 8 時間後までの残り時間を計算する。もし制限時間を超過していたら残り時間を 2 秒にする。
*58640000 は 1 秒間に 100 回の を 24 時間繰り返したと仮定した数。
*6-d -R: 切断されて残っていたセッションがあったら再接続する。なかったらセッションを新規作成して接続する。
再接続時は一度デタッチされるため、knight も再接続が必要。
*7-S: セッション名を指定する。この名前 (work) に向けて knight から接続する。
*8screen の終了後、それを呼び出した Bash も終了させる。(→ ログアウトさせる)
ちなみに、padawan がこれ (↓) を実行すると残り時間を表示できる。
Bash だけでは小数を扱えない。bc の結果で 0 になって省略される整数部を printf で補っている。
padawan$ printf '%.2f hours left\n' $(echo "scale=2;(`date +%s -d "$WORK_END"`-`date +%s`)/3600" | bc)
LXC は bc が無いことが多いので、その場合はインストールしておくこと。
knight がミスタイプしたときに効果を発揮する。
# cat >> /home/padawan/.bashrc << EOF
# Prompts for confirmation when "exit" is executed within Screen. function exit_yesno() { n=\$1 read -p 'ログアウトします。よろしいですか?(yes/no):' ANS if [ "\$ANS" = "yes" ] || [ "\$ANS" = "y" ] ; then exit \$n ; fi } if [ "\$STY" != "" ] ; then alias exit=exit_yesno readonly IGNOREEOF . .bashrc.screen fiEOF
# touch /home/padawan/.bashrc.screen
# chown padawan:padawan /home/padawan/.bashrc.screen
# echo 'echo Working time: $WORK_BEGIN - $WORK_END' > /home/padawan/.bashrc.screen
# cat /home/padawan/.bashrc | tail -15
*9.bashrc に i ビットを立てたときの逃げ道。
# Prompts for confirmation when "exit" is executed within Screen. function exit_yesno() { n=$1 read -p 'ログアウトします。よろしいですか?(yes/no):' ANS if [ "$ANS" = "yes" ] || [ "$ANS" = "y" ] ; then exit $n ; fi } if [ "$STY" != "" ] ; then alias exit=exit_yesno readonly IGNOREEOF . .bashrc.screen*9 fi
.bashrc は Bash を起動するたびに実行される。
alias じゃなくて直接に関数定義すれば exit を readonly にできるけど fool proof としてはやりすぎになるのでやめておく。
# cat /home/padawan/.bashrc.screen
echo Working time: $WORK_BEGIN - $WORK_END
# exit
$
• knight に root としての実行を /bin/screen -x padawan/* と /bin/screen -ls に限定して許可する。(ついでに master にも)
$ su
# visudo
ホントはここじゃなくて /etc/sudoers.d/padawan に書いたほうがいい。
## Allow root to run any commands anywhere root ALL=(ALL) ALL knight ALL=(ALL) /bin/screen -x padawan/*, /bin/screen -ls * master ALL=(ALL) /bin/screen -x padawan/*, /bin/screen -ls * ## Allows members of the 'sys' group to run networking, software, ## service management apps and more. # %sys ALL = NETWORKING, SOFTWARE, SERVICES, STORAGE, DELEGATING, PROCESSES, LOCATE, DRIVERS ## Allows people in group wheel to run all commands %wheel ALL=(ALL) ALL
# exit
$
3. 実施
共有時は同じ画面になるので、どちらの操作か分かりにくい。
以下の図は、それぞれ 8 行が共有されている状態。
(padawan の screen -ls の直後に knight が screen -x を実行したと仮定)
実際の画面でもリアルタイムで反映されるため、どちらが打鍵しているか見分けがつかない。
3-1. 生徒側の操作
3-2. 先生側の操作「work」「Multi」「exit」を強調するために下線を引いている。実際は下線が表示されない。
padawan$ exit [screen is terminating]
padawan$ screen -ls # padawan の打鍵 There is a screen on: 5706.work (Multi, attached) 1 Socket in /run/screen/S-padawan. padawan$ # Hello, padawan # knight の打鍵 padawan$ # Please tell me Lord of the Ring. # padawan の打鍵 padawan$ # I can teach Load of the Linux. # knight の打鍵 padawan$ # May the force be with you. # padawan の打鍵
multiuser on の設定があると「Multi」が表示される。
exit の実行で screen が終了すると、前述 2-1 で .bash_profile に記述した exit によってログアウトする。
共有の最中は、生徒の画面と全く同じ表示になる。接続できない場合は、接続先 (padawan がマルチユーザになっているかどうかを確認する)
(タイミングが遅くなっても、前の分が遡って表示される)
knight$ sudo screen -x padawan/work
knight$ exit
[sudo] knight のパスワード: **(自分のログインパスワード)**[detached from 5706.work]
padawan$ screen -ls # padawan の打鍵 There is a screen on: 5706.work (Multi, attached) 1 Socket in /run/screen/S-padawan. padawan$ # Hello, padawan # knight の打鍵 padawan$ # Please tell me Lord of the Ring. # padawan の打鍵 padawan$ # I can teach Load of the Linux. # knight の打鍵 padawan$ # May the force be with you. # padawan の打鍵
途中で違う画面の操作をしたいときは、 でスクリーンを追加するか、新たなターミナルからログインする。
(「デタッチしてアタッチすれば…」とか言う人はわかってる人なので勝手にやってください)
knight$ sudo screen -ls padawan/
✓ OK
5706.work (Multi, attached)
✗ NG
5706.work (Private)
✗ NG
No Sockets found in /run/screen/S-padawan.
4. 付録
knight と同じ設定のユーザを複数作成すると、一つの padawan を中心に複数ユーザの立ち入りが可能になる。
このとき、誰がどこに接続しているかを確認するには をタイプする。displays でも可。
この画面が表示されるのは自分だけ。本稿では sudo をしているため、さらに interface の項でユーザを確認する必要がある。
黄色の行が自分の情報
term-type size user interface window Perms ---------- ------- ---------- ----------------- ---------- ----- xterm 80x24 root@/dev/pts/4 0(padawan@55) rwx xterm 80x24 root@/dev/pts/2 0(padawan@55) rwx xterm 80x24 padawan@/dev/pts/1 0(padawan@55) rwx [Press Space to refresh; Return to end.]
で画面更新する。(誰かの接続/切断を反映させる)
で作業中の画面に戻る。
knight$ ps u | grep -v grep | grep pts/4
master 8449 0.0 0.4 224096 5504 pts/4 Ss 20:36 0:00 -bash