OE の MIME メールデコードの謎

前回のエントリ [2005-11-26] の続きです.今日も忙しいので現実逃避モード(激ぉ.



えー,大変申し訳ありません.前回のエントリは完全にピント外れでした.失礼しました _| ̄|○

今回調べているうちに,まったく別のある仮説に行き当たりました.時間のない方は下のほうの「仮説」だけお読み下さい.

要は「OE が悪いんじゃね?」という仮説です(ぉ



追記 (2005-11-28): 大変申し訳ありません.OE は悪くありませんでした orz.偏見に基づいた結論を出してしまいすみませんでした(激ぉ.詳しくは [2005-11-28] を.

実験環境
Windows XPExcel 2000,あるいは Excel 2003 です.Outlook Express は 6.0.

出て来るエラーは

'hoge.xls' にアクセスできません.ファイルは読み取り専用であるか,または読み取り専用の場所にアクセスしようとしています.または,サーバー上に保存されているドキュメントから応答がありません.
で,キャンセルを押すと Excel 2000 は何も出ない.Excel 2003 は

'hoge.xls' にエラーが検出されましたが,Microsoft Excel は次の修復を行うことによってファイルを開くことができました.修復を保持するにはこのファイルを保存してください.



ファイルへのダメージが深刻であり修復は不可能です.Microsoft Excel は数式と値の修復を試みましたが,消失または破損したデータが含まれる可能性があります.
となって,書式情報等の一切失われたデータが表示されます (それでも書いてあることの大半は理解できるもんです).
boundary の文字列とは関係ない
確かに boundary を書き換えると Excel で開けるようになって,これは複数のメールで確認してたんですが,実はうっかりファイル末尾の boundary を書き換えるのを忘れていたんですね (疲れていたということにさせて下さい…).ファイル末尾の boundary は行末に余計に "--" がつくので,マッチさせ忘れてたのでした.

というわけで,

Header (modified boundary is defined here)
--modified boundary
Body Text
--modified boundary
base64-encoded Excel File (readable from OE)
--original boundary (not regarded as a valid boundary)

みたいな状態になってたわけです.ここで末尾の boundary まで書き換えてしまうと Excel ファイルが開かなくなるので,boundary の文字列云々の影響ではないことがわかります.

Excel ファイル末尾の boundary「付近」があやしい
調べているうちに,複数の添付ファイルがある場合,Excel ファイルの終端にある boundary を直さずにおくとやはり開けるようになることが判明.ただしこの場合は,その次に添付されているファイルは見えなくなります.

Header (modified boundary is defined here)
--modified boundary
Body Text
--modified boundary
 
...
 
--modified boundary
base64-encoded Excel File (readable from OE)
--original boundary (not regarded as a valid boundary)
Another Attachment (invisible from OE)
--modified boundary
 
...
 
--modified boundary

うーむ.boundary があるべき部分に関係ない余計な文字列が来ちゃってることになるのに,なんで Excel は添付ファイルを開けるんだ??

余計な文字列を加えてみると
余計な文字列が必要なんだろうか? と思って,boundary には手を加えず,boundary とデータの間に文字列を加えてみたら…

HwAAAAAQAAAAAAAA
hoge
--------------080406090906080908050602

開きました.な,なんだってー ΩΩ Ω



改行だけでも OK.

HwAAAAAQAAAAAAAA
 
--------------080406090906080908050602

あるいはもう base64 コードの末尾に何か足しただけでも,開くことができてしまった.なんかこう節操がないというか…

HwAAAAAQAAAAAAAA*
--------------080406090906080908050602

空行が必要なのか?
ここでふと,他の MUA (例えば Mew) が送った MIME メールをみてみると,base64 データ末尾と boundary の間に空行がある.試しにこの空行を削除してみると…



Excel ファイル,開けなくなりました.



ちなみに Mozilla/5.0 以外の MUA はたいてい空行を入れるようです.さらに mewdecode や uudeviwe を使って調べているうちに…うーむ,なんとなくわかってきたかもしれない.つまり,えーと,こんな感じです.

いろんな boundary (正規表現) に対して正しく base64 デコードできるかを調べたもの.OK は Excel ファイルが開けたこと,NG は開けなかったことを表す.また \n は CRLF を表す.

(A) \n\n-- (普通の MUA) (B) \n-- (Mozilla/5.0) (C) .*\n-- (invalid) (D) \n.?\n-- (invalid)
OE OK NG OK OK
mewdecode OK OK OK /w warning OK /w warning
uudeview OK OK NG OK




空行がないとダメなのは OE だけですね.
空行がないのは間違ってない
さらに RFC 2046 にこんな文面がありました.

The boundary delimiter MUST occur at the beginning of a line, i.e.,
following a CRLF, and the initial CRLF is considered to be attached
to the boundary delimiter line rather than part of the preceding
part.

NOTE: The CRLF preceding the boundary delimiter line is conceptually
attached to the boundary so that it is possible to have a part that
does not end with a CRLF (line break). Body parts that must be
considered to end with line breaks, therefore, must have two CRLFs
preceding the boundary delimiter line, the first of which is part of
the preceding body part, and the second of which is part of the
encapsulation boundary.
つまり,boundary delimiter は "\n--" であって,添付データ末尾に CRLF がなければ当然空行はつかない.その意味では Mozilla/5.0 は RFC 2046 には違反していない.ということになります.



ということは…もしかして OE は「改行がある」と思い込んで処理してしまってる?? 例えば,そうだな,boundary の前の文字を改行と思って取り除いちゃってるとか??
もしかして chop されてますか?
1 文字取り除くと何が起こるか? base64 デコーダは 4 文字を 1 セットとして 3 バイトのデータに直すから,エンコードデータの末尾が 1 文字欠けるだけで,元データの 3 バイトに影響が出る.OE はこれをどう処理してるのか?

というわけで確かめてみます.Mew から保存した Excel 添付ファイルと OE から保存したものとを hexdump にかけて,末尾をみてみよう.

% hexdump -C frommew.XLS | tail -2
000053f0  00 00 00 00 1f 00 00 00  00 10 00 00 00 00 00 00  |................|
00005400
% hexdump -C fromoe.XLS | tail -2
000053f0  00 00 00 00 1f 00 00 00  00 10 00 00 00           |.............|
000053fd

はい,3 バイト消えてますね.



ちなみに uudeview や mewdecode で取り出したファイルの場合,3 バイトは消えてません (0 詰めされてます).えらいえらい.PerlMIME:Base64 なんかもデコード時にちゃんと "=" をパディングしてくれるので,データが増えることはあっても消えることはない.OE もこの方式を取ればいいんじゃないかなあ.と思うのだけど.


The decoded result will anyway be as if the padding was there.


というわけでそろそろあたりがついてきたぞ.
chop されてもファイルは開けるのか?
じゃあ Word はどうして大丈夫なんでしょうか.末尾が chop されても生きてるんでしょうかね?

そこで,base64-encode されたファイルから無理矢理 1 文字切り取ってみる実験.
  • Excel ファイル末尾を切り取ると開けなくなる (メール添付の時と同じ症状が出る).
  • Word,PDF,BMP,その他多くのファイルフォーマットは,末尾を切り取っても開ける.
  • Mozilla/5.0 で Excel 添付でも開けるという例外的な事例が 2 件ほどあったんだけど,これらの Excel ファイルに関しては,末尾を切り取っても開くことができた.
うーむ,Excel シビアすぎです.もう少し余裕をもったつくりになって欲しいもんです.
仮説
というわけで仮説です.あくまで仮説です.検証はしてません.
  • Mozilla/5.0 は添付データと boundary の間に空行を入れない.これは RFC 的には間違ってない.
  • 仮説: OE の MIME 解析ルーチンは boundary の直前の文字を chop してしまうのではないか??
  • 普通の MUA が送って来たメールなら,CRLF が chop されるだけなので影響はない.
  • Mozilla/5.0 が送ったメールの場合,OE で読むとデータ末尾が chop されて消える.
  • OE の base64 デコーダは "=" をパディングしたりせずにデータを切り上げるので,デコードされたデータは末尾 3 バイトが消えたことになる.
  • Excel 以外の多くのフォーマットでは,末尾 3 バイトが置き換わったところで開けなくなることはめったにない.
  • Excel の場合,末尾 3 バイトが消えると開けなくなることが多い.そういうファイルが添付されていた場合,OE が chop してしまって開けなくなる.
  • 余計な文字列を加えたら開けるようになる.これは加わった文字列が chop されただけでデータが無事だったから.
わはは,苦労したわりに何の解決にもならないですね.
補足事項
ひとつ残ったのが,

試しに,同じメールを Outlook Express で直接 pop で受信してみると,何の問題もなく開ける.
という問題.この検証のためだけに OE をセットアップする気はしなかったので,真相は不明.POP の時点で 0 がパディングされたりするんだろーか.

ちなみに「F-Secure アンチウィルス Linux ゲートウェイ」の ChangeLog

- SMTP/POPサービスで、base64エンコードの1行が4の倍数でない場合や行中に
スペースを含む場合に、Outlook等と同じ方法で展開できるように変更。
これにより、一部のMydoomを検出できない問題に対応。
とありました.これが具体的に何を指していて,Outlook にどう実装されてるのか,OE にもあるのかは不明ですが,もし POP 部分に組み込まれたものなら,上の問題の説明がつくのかも知れない.
追記 (2005-11-28): 上にも書きましたが,POP で正常に受信できる問題は説明つきました.詳しくは [2005-11-28] を.