要約

  • RFC 1408 は Telnet オプション36で VAR=0VALUE=1 と定めた。RFC 1571 は、BSD 参照実装が二つを逆に用いていたと記録した。
  • RFC 1571 は、文法上あり得ない記号、順序、空の記号、個数、既知名から相手の辞書を推定した。それでも判別不能な場合は残った。
  • RFC 1572 は文書側の対応関係を維持し、新しいオプション39 NEW-ENVIRON に移した。解読できた環境変数を実際に使うかどうかは、引き続きサーバーの判断だった。

境界記号が逆なら、同じ列から別の構造ができる

1993年1月の RFC 1408 は、Telnet 接続時にクライアントの環境情報をサーバーへ渡す仕組みを定めた。ENVIRON のオプション番号は36。副交渉の命令は IS=0SEND=1INFO=2、内容を区切る記号は VAR=0VALUE=1ESC=2USERVAR=3 とされた。

ここでのゼロと1は単なる列挙値ではない。受信側は、どこから変数名が始まり、どこから値になるかをそれで決める。VALUE がなければ未定義、VALUE の直後に次の型か終端が来れば定義済みの空文字となる。予約オクテットを名前や値に含める時は ESC が必要だった。

二つの記号を逆にすれば、一つの文字列を読み違えるだけでは済まない。メッセージ全体の区切りが変わる。

翌年の RFC 1571 は、RFC 1408 の VARVALUE が BSD 実装と逆だったと説明した。しかも BSD は偶然の別実装ではなく、RFC が文書化するはずだった参照実装であり、多くの既存実装の基礎だと記されている。

この記述から実装数や普及率は分からない。分かるのは、オプション36が二つの履歴を抱えたことだ。番号だけでは、相手がどちらの辞書を持つか確定しなくなった。

Telnet が理解しない情報を運ぶための器

ENVIRON の動機は、接続先で必要となる起動情報を毎回専用オプションにしないことだった。オペレーティングシステム固有の情報が増えるたびに Telnet の共通層を厚くするのではなく、汎用の器で名前と値を渡す。

既知変数は USERJOBACCTPRINTERSYSTEMTYPEDISPLAY。任意のユーザー変数は USERVAR で区別した。この区別は出所の種類を残すが、正しさを保証しない。RFC は、慎重な実装なら両方を同程度に疑うだろうと述べ、既知名とユーザー名が衝突した時の結果も実装依存とした。

初期値は WONT ENVIRONDONT ENVIRON、つまり交換しない状態だった。送信可能だと表明する側が WILL、受信可能だと表明する側が DO を使う。SEND を開始できるのは DO 側だけ、ISINFO を送れるのは WILL 側だけである。

この方向性は、許可と実行を分離する。WILL は変数の送信記録ではない。SEND は存在の証明ではない。IS は初回要求への応答、INFO は交渉後の変更通知で、自発的にも送れる。いずれもサーバー内部への反映を示さない。

ログイン前に届くからこそ、ローカル判断が要る

当時の多くのシステムでは、環境を渡せるのはプロセス生成時だった。このため交換は接続の早い段階、しばしばログイン前に必要となる。到着が早いことは権限を増やす理由ではなく、検証を厳しくする理由だった。

RFC 1408 は、受信した全変数を環境に入れる義務はないと明記した。未知名は無視できる。USERACCT をログイン先の選択に使い、プロセス環境には入れないこともできる。より正確な方法ですでに値を得たなら、そちらを優先できる。

例えばクライアントが USERVAR TERM=xterm を送っても、Terminal-Type オプションで型が確定済みならサーバーは無視してよい。DISPLAY が X-Display-Location オプションと食い違う場合には、後から届いた情報を使うという別の解決規則が示された。

共通プロトコルは入力を運ぶが、受信側の将来を命令しない。USER は希望するアカウント名であって本人確認ではない。PRINTER は、当時ネットワーク上の標準命名法すらない宛先であり、印刷成功を表さない。DISPLAY の解読は X 接続や画面表示の観測ではない。

セキュリティ節は、ログイン前に安全に設定できる変数を慎重に調べるよう警告した。認証プログラムそのものへ影響する変数を許せば、侵入者が認証を迂回または侵害し得る。これは特定事件の報告ではない。遠隔入力とローカル実行権限の境界を示した記述である。

RFC 1571 は不正な形を手掛かりにした

旧い36番には、辞書の版を宣言する欄がない。RFC 1571 はメッセージの形から相手を見分けようとした。

クライアントが SEND を読む場合、合法なのは VARUSERVAR だけで、VALUE は現れない。自分の辞書で VALUE に見える記号を受けたなら、サーバーはゼロと1を逆に使っていると推定できる。その地点から解析を反転し、返す ISINFO も相手に合わせる。ゼロも1も現れなければ識別材料がなく、RFC の順序を仮定する。

サーバー側の ISINFO では値も合法なので、判断は複雑になる。直後が VAR なら文書側、VALUE なら反転側と推定する。USERVAR から始まれば、後続が名前でも値でも成立し得る。そこで連続記号、空記号、個数関係、既知変数名らしい文字列を調べる。

これは相手の身元確認ではない。どちらの歴史的辞書なら構文が成立するかを分類する作業だ。一方で不可能な形なら強い証拠になるが、確率的な手掛かりもある。全部失敗すれば RFC の定義を仮定する。それは観測事実ではなく、証拠不足時の運用方針である。

後に残すべきものは、整形済みの環境変数だけではない。生の副交渉、オプション番号、方向、解析器版、選択した辞書、発火した規則、残った曖昧さがあって初めて、判断を再現できる。

39番は36番の過去を書き換えなかった

1994年1月の RFC 1572 は、文書側の VAR=0VALUE=1 を新しいオプション39 NEW-ENVIRON に置いた。新番号なら、この文書を実装する者同士が曖昧さなく相互運用できると説明している。

36番の表だけを訂正しても、接続先の古いバイナリが BSD 系か RFC 系かは分からない。39番の交渉は、新番号と新しい一意の辞書を同時に選ぶ。規範文書が既存状態を支配するのではなく、将来の共通入口を最小限に定める方法だった。

現在の IANA Telnet Options レジストリ には、36 Environment Option と39 New Environment Option が別々に残る。登録は歴史的分岐を可視化するが、実装、交渉、変数の採用、プロセスの状態までは証明しない。

NEW-ENVIRON でも既定は交換なしで、方向別の合意と受信側の裁量は維持された。線上の意味は確定したが、値の使用はローカルに残った。

証拠はオクテットの先まで分ける

必要な層は、公開された割当て、送信実装の辞書、生のオクテット、受信側の解釈、ヒューリスティックの選択、候補となる名前と値、出所分類、受入れ方針、プロセス生成、アプリケーションの観測、外部結果である。

RFC の発行は稼働コードを書き換えない。交渉成功は送信を証明しない。USER の解読は認証ではない。受入れは継承の記録ではない。環境への継承はコマンド実行でも結果でもない。各段階には別の証拠が要る。

出典

これらは仕様、BSD との衝突に関する同時代の記録、推定手順、新番号、登録を裏付ける。特定実装、普及率、攻撃、本人性、ログイン許可、環境適用、コマンド実行、現在の危険を裏付けるものではない。