Macintosh Developer Online (MDOnline)


2000年6月27日発行号 - bestboyメールの教訓



bestboyメールについて、概ね全貌が見えてきたので、まとめ記事にしました。「不法なアクセス」のタイトルのメールを送った人に対しては、批判する声もありますが、むしろ各サイトは同情の声が大勢を占めます。吊るし上げるというつもりはありませんが、こういう場合はとりあえず「謝罪」の意を表明するのが得策だと思います(アップルがしたように)。たぶん彼は釈然とはしないとは思いますが、頭を下げておけばとりあえずは誰も文句は言えません。世の中、そんなもんだと思いますし、早期の適切な対応こそが危機管理の基本でもあると思います。大学の学生だということですが、担当教官よりそうした指導がなされていることを期待したいと思います。
メーリングリストの運営を間違うと時にえらい目に合うことは、ちょうどMac Fanの2000/6/1号の私の記事でも指摘しました。とまあ、えらそうなことを言いながら、このMDOnlineもMajordomoを使っていまので、なんかまくらを高くして眠れません。mdo-aは投稿できるアドレスは制限していますが、MDOnlineの読者の方のレベルだと見破って自分からmdo-aにメールを出すくらいできるかもしれませんが、やらないでくださいね。なおmdo-dは購読者の方は誰でも投稿できるので、お気をつけください。いずれにしても、現在においては認証を行わないSMTPというのが大きな枠組みでのセキュリティホールだということじゃないでしょうか(sendmailの最新版は認証機能が組み込まれています)。
それから、東京地方の方は、本日20:30より東京FMでオンエアされる「インターネットガーデン」という番組を聞いて下さい。私が出演しています。MDOnlineのことをしゃべっています。プレイバックを聞いていないのでどんなのかちょっと分からないのですが、セキュリティ的に問題なければいいのですが…。
(新居雅行 msyk@mdonline.jp


週末の謎のメールはTIL-J更新のメールの誤動作が原因

2000年6月24日の土曜日の午後、「不法なアクセス」というタイトルで「いつまでも不可解なアクセスはしないようにして下さい。」と本文に書かれたメールが筆者のところに届いた。本名、学校名、所属もきちんと書かれたもので、送り主のドメインとも基本的に一致する。筆者の会社のサーバを足掛かりにされたのかとドキリとしたが、メールの様子が変なのだ。メールの宛先は@の左側は記号と数字が並ぶもので、右側はbestboy.****となっている(情報提供を行っているたんちゃ氏が、そこから一連の騒動をbestboyメールと名付けている)。つまりこれは筆者宛のメールではない。また、Ccに筆者が含まれているわけではない。可能性として、なんらかのメーリングリストかBccに宛先が書かれていることが考えられる。そんな重要な内容がそんな方法で配送されるはずもない。そこで注意深く、Fromの送り主のみに問い合わせのメールを書いた。しばらくすると、同じような宛先のメールが何通が届くが合計6通が来た。そのうち何通かは、同じようなメールが筆者だけでなく、たくさんの人に送付されたことを明白に示しているものだった。
そして、夕方から夜にかけて、Macintoshコミュニティが動き始める。自身のWebサイトで情報提供を始めたたんちゃ氏や、いくつかの掲示板が用意され、情報交換が始まった。数100通のメールを受け取った人もいるというも言われている。24日の夜の時点で、謎のアドレスはアップルのTIL-Jの更新を知らせるときのメールアドレスとして使われているものであることが、大方間違いないだろうという結論まで各サイトや掲示板では出ている。ドメイン情報などから、TIL-J更新のメーリングリストは、すでにサービスを中止したサイトのドメインのサーバをなぜか利用していることが判明し、アップルからの外注を請け負っているその会社も特定された。各サイトなどでは過剰反応からのチェーンメール化という最悪の事態を避ける努力が行われたこともあって、翌日曜日は平静にもどったと言ってよいだろう。また、「不法なアクセス」というタイトルのメールを送ったもとのところも日曜日になってWebページで理由を示していたが、その段階では不正アクセスがあったことを言っている。
月曜になって、アップルから、「メールの誤配信およびチェーンメールの事故について」という文書が公開された。また、「不法なアクセス」というメールの送り主も、さらに文書を公開したが、実は管理者が不正アクセスされたと勘違いしたというのが原因だと言うのだ。つまり、不正アクセスと勘違いしたというのが1つのトリガーとなっている。しかし、TIL-Jの更新メールに誰もが投稿して配信できてしまうといった、管理ミスによるセキュリティホールにすっかりはまってしまったというわけだ。そして、TIL-Jの購読者に配信できるアドレスが、事実上公開となった。しかも、その事実が認識されないで公開されたわけで、その後に不審なメールが何通か送られることになる。問題点が何重にも重なったとはいうものの、やはり穴があればそこに落ちるというごく当然のことが言える。不正アクセスされたと思ったときに、その相手にメールを送るということは極めて効果が低いどころか、ほんとにクラックされているのなら、調子に乗らせる一方だ。無言で遮断するのが基本だと思われる。勘違いをした方には酷な言い方かも知れないが、いい勉強をしたとして今後につなげてもらいたい(わたしたちも勉強になった)。また、アップル側もメール配信システムの管理と言う点で問題があったことも事実だ。金曜日になぜか中身のない謎のTIL-Jの更新メールが送られており、前兆がまるでなかったわけではない。さらに、個人のメールアドレスとは思えないアドレスにメールを送る、あるいは誰宛か分からないアドレスにメールを送るということは、慎重であるべきなのは今回の騒動で確認されたことだと言えそうだ。
ただ、今回はメールアドレスの流出ということは免れたようではあるし、不正アクセスがあったというのは誤認だとしているため、不正アクセスはなかったわけだ。多くの人に謎のメールが来たということで、実害は少なかったのは幸いだろう。また、Macintoshコミュニティが早期に動き、被害の拡大を押さえたということは高く評価できることだと思う。逆に言えば、こうしたコミュニティにかかわっていれば、情報も得られるということに他ならない。メーリングリストやWebを媒介としたコミュニティの強さを実感する。

◇TILのメーリングリスト購読者へ大量のメールが送信されたトラブルについて
 http://news7s6.atm.iwate-u.ac.jp/news/20000626/ml_trouble.html

◇「不法なアクセス」という件名のメールについて
 http://ats.arena-p.co.jp/topics/bestboy_mailbomb

◇「bestboy」メールについて(たんちゃ氏のページ)
 http://www2.odn.ne.jp/satowara/

関連リンク:メールの誤配信およびチェーンメールの事故について
カテゴリ:業界動向


qmail 1.0.3をMac OS X Serverで動かすためのパッチが公開

Mac OS X Server向けのqmailのdiffファイル(パッチ)が配付されている。qmail 1.0.3向けのパッチでMarcus Muller氏(uにはウムラウトがある)によって作られたものである。qmailはMTA(Mail Transfer Agent)で、通常はsendmailが使われているが、sendmailに替えて利用できるものだ。セキュリティ面で評価されているとともに管理のやりやすさなどもあって、sendmailから乗り換えている利用者も多い。SMTPだけでなくPOPの機能も含まれている。

関連リンク:qmail (Mac OS X Server)
カテゴリ:サーバー関連, Mac OS X Server


USENIXカンファレンスでの講演内容に関連した論文が掲載

USENIX(Advanced Computing Systems Association)のカンファレンスが先週開催されていたが、2000年6月22日に招待講演として、AppleのDarwinの開発者として知られるFred Sanchezが登場している。その内容に連動した論文「The Challenges of Integrating the Unix and Mac OS Environments」が公開されている。広く知られているように、Mac OS Xでは、既存のMac OSとUNIXが統合されるが、そこには技術的にクリアすべき点は数多くある。この論文では、リソースフォークをBSDベースの上でどのように機能させるかといった点や、マルチユーザの機能をどう適合させるかという点についてまとめられており、Mac OS Xの目指す方向性の一端を垣間見ることができる。

関連リンク:The Challenges of Integrating the Unix and Mac OS Environments
カテゴリ:Darwin


【Carbon化シリーズ】Navigation Serviceでファイル保存ダイアログ(1)

今回から3回に渡って、保存ダイアログボックスのNavigation Service対応を紹介することにするが、ここまでで見てきたファイルを開くダイアログボックスのNavigation Serviceを踏まえた内容となるので、場合によってはそちらも参照してもらいたい。

ファイルを開くときにはファイルの選択だけできればいいが、ファイルの保存ではファイル名の入力が必要になり、必然的に異なるデザインのダイアログボックスを表示しないといけない。そこで、Navigation Servicesでは、NavPutFileというAPIコールを用意しており、それによって、ファイル保存のダイアログボックスが表示される。パラーメータの引き渡しや取り出しなどは、NavGetFileの場合とは基本的に変わらない。また、イベント処理のコールバックルーチンを利用しないとモーダルなダイアログボックスになるのも同様である。ということで、別掲のDoSaveCommand関数を参照していただきたい。この関数は、TextDraw IVのソースでは、DoCommand.cにある。FileメニューのSaveを選択した時に、イベントループからこのDoSaveCommandが呼び出されて、実際の処理を行う。ファイルを開く時の処理だと、まだ文書内のデータ処理とは分離されているが、保存の場合はそういうわけにはいかないため、プログラムが少しややこしくなっている。その点も踏まえて、ソースを見てもらいたい。

プログラムの最初の部分は、書類のウインドウが存在するかを確かめ、さらに文書ごとの情報を保存している構造体へのハンドルを取得して、後の処理に備えている。NavPutFileでも、やはりNavDialogOptions型構造体のデータを、最初に指定しておく必要がある。とりあえずデフォルトでいいので、NavGetDefaultDialogOptionsを利用して構造体を初期化する。ただし、ダイアログボックスのファイル名の部分に最初から入力されている文字列はこのままだと「名称未設定」になる。これでも支障はないのだが、たとえば別の文字列にしたいという場合には、プログラムにあるように、NavDialogOptions型構造体のメンバーsavedFileNameに文字列として任意に文字を指定する。ここでは、Pascal文字列ではなくC文字列としてしている点には注意が必要だ。NavDialogOptions型構造体は、NavPutFileの3つ目の引数として指定する。

保存するフォルダを指定するダイアログボックスでは、最初に表示されるフォルダを指定できる。そこで、そのフォルダは無条件に「書類」フォルダにしたいとしよう。その場合には、FindFolderでまずは「書類」フォルダへのファイル参照を得ておく。FindFolderの2つ目の引数にkDocumentsFolderTypeを指定すると「書類」フォルダを検索できる。FindFolderの結果から「書類」フォルダのFSSpec構造体を作成し、さらに、AECreateDescで、FSSpecのディスクリプタを構成しておく。これをNavPutFileの1つ目の引数に指定する。
NavPutFileでは合計7つの引数を指定する。2つ目にはダイアログボックスでの選択結果を取得するためのNavReplyRecord型構造体へのポインタを指定するのは、NavGetFileと同様だ。4つ目の引数にはイベント処理プロシージャへのユニバーサルポインタを指定する。これもNavGetFileと同様だ。イベント処理のプロシージャはシステム側からコールバックされるものであるが、その基本的な形式はNavGetFileと同様である。ここでは、NavGetFileで使用した“特になにもしないイベント処理関数”をそのまま指定した。

一方、NavPutFileでは、5つ目と6つ目の引数にファイルタイプとクリエイタを指定する。これらは、ファイルのフォーマットを指定するポップアップメニューで出てくる項目名を決定する。ここではTextDrawの文書のタイプとクリエイタを指定したが、そうすることで、文書のFinder情報の「種類」と同じ文字列が、ダイアログボックスのファイルフォーマットのポップアップメニューで項目として設定されるのである。7つ目の引数にはユーザーデータを指定するが、これを使った例は2回後に出てくる。

さて、NavPutFileの呼び出し後には2つ目の引数に指定したNavReplyRecord型構造体でユーザのダイアログボックスでの反応がすべて分かるようになっているのだが、それはNavGetFileと同様だ。その構造体のvalidRecordというメンバと、NavPutFileの戻り値がエラーでないことを確認することで、正しくファイルが指定されたことが分かる。なお、NavReplyRecord型構造体のメンバreplacingから、既存のファイルと同じファイル名を指定したことも分かる。
指定したファイルに関する情報は、NavReplyRecord型構造体のselectionメンバにディスクリプタのリストの形式で入力されている。ファイルを開く場合には複数のファイルが指定されたことを仮定しないといけなかったが、NavPutFileだと1つのファイルの指定しかないはずなので、AEGetNthPtrでディスクリプタのリストの最初の項目をFSSpec型として取り出す。これが、ダイアログボックスで選択したファイルのファイル名やフォルダなどの情報が含まれているFSSpec型構造体である。そして文書の内容を、指定したファイルに保存しているのが、SaveToFile関数である。その後、文書情報の構造体を更新したり、ファイル名をウインドウのタイトルに設定する行が続いている。
最後に、NavDisposeReplyを使ってNavReplyRecord型構造体を破棄すると共に、AEDisposeDescを使って作成したディスクリプタを破棄している。

以上のように、NavPutFileの使い方も、一部を除いてNavGetFileとあまり違いはない。実際には次のようなダイアログボックスが表示される。フォーマットのポップアップメニューでは、TextDrawのネイティブな文書フォーマットを示す文字列と、「ひな形オプション」の選択肢がある。

◇表示された保存するファイルを指定するダイアログボックス


「ひな形オプション」を選択すると、書類かひな形かを選択するダイアログボックスが表示される。ダイアログボックスでひな形を選択したかどうかは、NavPutFile実行後にNavReplyRecord型構造体のisStationaryメンバで参照できるが、TextDrawのプログラムはそこまではきちんと処理を組み込んでいない。ひな形対応は、Save Asで組み込んだので、Carbon化シリーズの2回後の記事で紹介する。いずれにしても、ステーショナリに対応するくらいは、NavPutFileは特にカスタマイズらしいことをしなくてもすむということは、今後のアプリケーション設計では知っておくべきことと言えるだろう。

関連リンク:Inside Carbon: Navigation Services
カテゴリ:Carbon/CF, Carbon化


【Carbon化シリーズ】プログラム-DoSaveCommand


void DoSaveCommand()
{
WindowPtr targetWindow;
DocRecHandle docH;

OSErr er;
NavReplyRecord reply;
NavDialogOptions dialogOptions;
AEDesc defLoc;
FSSpec defLocSpec;
short fVolRef;
long fDirID;

NavEventUPP neProc = NewNavEventProc(myNavEventProc);

if((targetWindow = FrontWindow()) != 0) { //アクティブなウインドウがあるとき
docH = GetDocHandle(targetWindow);
if(((**docH).isDarty & 2) == 0) { //保存されたかどうかを調べる
//これが初めての保存作業の場合
HLock((Handle)docH); //このあと構造体のメンバーへのポインタを利用するのでロック
NavGetDefaultDialogOptions(&dialogOptions); //ダイアログ設定は既定値
CopyCString(dialogOptions.savedFileName, (unsigned char *)"新しい文書ファイル名");
//最初から設定されているファイル名を文字列で指定できる
er = FindFolder (kOnSystemDisk, kDocumentsFolderType, kDontCreateFolder, &fVolRef, &fDirID);
//書類フォルダを探す
er = FSMakeFSSpec(fVolRef, fDirID, "\p", &defLocSpec); //書類フォルダのFSSpecを構築
er = AECreateDesc(typeFSS, &defLocSpec, sizeof(FSSpec), &defLoc);
//書類フォルダのAppleEventディスクリプタを生成

er = NavPutFile(&defLoc, &reply, &dialogOptions, neProc, myFileType, myCreator, NULL);
//ファイル保存のダイアログボックスを表示
if(er == noErr && reply.validRecord) { //ファイル選択が指定されれば
AEKeyword theKeyword;
DescType actualType;
Size actualSize;
FSSpec documentFSSpec;

er = AEGetNthPtr(&(reply.selection), 1, typeFSS, &theKeyword,
&actualType, &documentFSSpec, sizeof(FSSpec), &actualSize);

SaveToFile(&documentFSSpec, targetWindow); //ウインドウの書類を保存
//DocRecordのファイル関連のメンバーを更新
(**docH).vRefNum = documentFSSpec.vRefNum;
(**docH).parID = documentFSSpec.parID;
CopyString((**docH).fileName, documentFSSpec.name);
SetWTitle(targetWindow, documentFSSpec.name);
//ウインドウのタイトルを付けたファイル名に変更
}
er = NavDisposeReply(&reply);
AEDisposeDesc(&defLoc);
}
else { //すでに以前に1度保存している場合、ファイル名を整えて保存作業を行う
FSSpec documentFSSpec;
FSMakeFSSpec((**docH).vRefNum, (**docH).parID ,(**docH).fileName, &documentFSSpec);
SaveToFile(&documentFSSpec, targetWindow);
}
(**docH).isDarty = 2; //すでに保存を行ったことを示すフラグを立てる。修正フラグをクリアする
}
}

//以下はイベントプロシージャで、NavGetFileのサンプルと同じもの
void myNavEventProc(
NavEventCallbackMessage callBackSelector,
NavCBRecPtr callBackParms,
NavCallBackUserData callBackUD)
{
EventRecord* thisEvent = ((callBackParms->eventData).eventDataParms).event;
//イベント情報を取得しておく
MyUserData userData = *(MyUserDataPtr)callBackUD;
//ユーザデータを、コールバックルーチンで取り出す
switch (callBackSelector) { //イベントの種類に応じ
case kNavCBEvent: //一般的なイベントなら
switch (thisEvent->what) { //イベントの種類に応じ
case updateEvt: //アップデートイベントなら
break; //ここでは何もしないけど…
}
break;
case kNavCBCancel: //キャンセルボタンが押されたなら
SysBeep(1); //システム警告音を鳴らす
break;
} //…という風にイベントごとの処理を記述する
}

カテゴリ: