 |
Technote 1103
Uniquely Identifying a Mac OS Computer
Mac OS コンピュータの識別方法
ケース外部に貼ってあるバーコードラベルに印刷されているシリアル番号だけが、Mac OS
ベースのコンピュータを識別できるようになっています。現在、販売されている Mac OS コンピュータのロジックボードにはどれも内部シリアル番号は埋め込まれていません。オペレーティングシステムにも内部シリアル番号はありません。本当のシリアル番号が埋め込まれた唯一のコンピュータは、Macintosh
XL です。このマシンにシリアル番号があるのは、このマシンのベースになった Lisa にシリアル番号があったからです。Macintosh
XL は 1986 年 8 月に製造停止になったため、現在では数も少なく、今日の市場においては考慮すべき対象とはならないでしょう。
Mac OS コンピュータの一部のモデルには、シリアル番号として使用できる識別番号を持つハードウェアデバイスが含まれています。たとえば、マシンにインストールされているか、内蔵されたイーサネットカードです。
(イーサネットデバイスにはデバイスごとにユニークな ID があるためです。) ハードディスクドライブのなかには、すべてではありませんが、SCSI
Manager または ATA Manager で読み出せるシリアル番号を持つものもあります。トークンリングカードや
FireWire にも、シリアル番号として使用可能なユニークな識別番号を持つものがあります。これらのハードウェアデバイスの中で、Macintosh
の全製品ラインで共通なものはありません。
ほぼユニークな特性
ソフトウェアが、以前と同じマシンで動作しているかどうかを判断する資料となる「ほぼユニーク」といえるような特性もあります。これらを有効なものから順に以下に列挙します。
ファイル ID リファレンス
アプリケーションファイルのファイル
ID リファレンスを作成し、保存する方法です。ファイル ID リファレンスは、PBCreateFileIDRef()
で作成し、適切な場所に保存します。 (保存に適した場所の例としては、初期設定ファイルがあります。保存に適さない場所の例はアプリケーションのリソースフォークです。これだとロックされたメディアやネットワークサーバからアプリケーションを起動する場合には利用できません。)
そのファイル ID リファレンスを、動作中のアプリケーションのファイル ID リファレンス
(ファイル ID リファレンスは PBGetCatInfo が返す ioFileID
フィールドにあります) と比較します。これが違っていれば、別のボリュームで動作していることがわかります。ファイル
ID リファレンスは特定のボリューム内ではユニークです。再利用されることはありません。別のマシンで同じファイルに同じファイル
ID リファレンスが割り当てられる可能性は非常に少ないです。
// AddFileID は FSSpec で指定されたファイルの
// ファイル ID リファレンスを作成します。
// この関数が返すファイル ID リファレンスは、
// 後で使用するために保存しておきます。
//
OSErr AddFileID(FSSpec *file, long *fileID)
{
OSErr err;
HParmBlkPtr h;
h = (HParmBlkPtr)NewPtrClear(sizeof(HParamBlockRec));
h->fidParam.ioCompletion = nil;
h->fidParam.ioNamePtr = file->name;
h->fidParam.ioVRefNum = file->vRefNum;
h->fidParam.ioSrcDirID = file->parID;
err = PBCreateFileIDRefSync(h);
*fileID = h->fidParam.ioFileID;
DisposePtr((void *)h);
return(err);
}
// GetFileID は、過去に (PBCreateFileIDRef を呼び出して)
// ファイル ID リファレンスを作成したことのある
// ファイルが持つ、ファイル ID リファレンスを返します。
//
OSErr GetFileID(FSSpec *file, long *fileID)
{
OSErr err;
CInfoPBPtr cInfo;
cInfo = (CInfoPBPtr)NewPtrClear(sizeof(CInfoPBRec));
cInfo->hFileInfo.ioCompletion = nil;
cInfo->hFileInfo.ioNamePtr = file->name;
cInfo->hFileInfo.ioVRefNum = file->vRefNum;
cInfo->hFileInfo.ioFDirIndex = 0;
cInfo->hFileInfo.ioDirID = file->parID;
err = PBGetCatInfoSync(cInfo);
*fileID = cInfo->hFileInfo.ioDirID;
DisposePtr((void *)cInfo);
return(err);
}
|
Gestalt
Gestalt Manager は、マシンを特定するのに役立つ、多くの情報へのアクセスを可能にします。そのような情報の中で顕著なものは、マシンタイプ
(gestaltMachineType セレクタで表されます) と接続されているキーボードの種類
(gestaltKeyboardType セレクタで表されます) です。
OSErr GetMachineAndKeyboardIDs(long *characteristics)
{
long response;
OSErr err;
err = Gestalt(gestaltMachineType, &response);
*characteristics = response << 16;
if (!err)
err = Gestalt(gestaltKeyboardType, &response);
*characteristics |= response;
return err;
}
|
システムソフトウェアの改版によって、Gestalt のセレクタに予期せぬ変更が加えられる場合もあることに注意してください。
イーサネットアドレス
イーサネットカードがインストールされているか、または内蔵されている Mac OS コンピュータでは、csCode
を ENetGetInfo に設定して EGetInfo() を呼び出すことで、現在割り当てられているイーサネットアドレスが取得できます。詳細は『Inside
Macintosh: Networking』 (11-26
ページおよび
11-36 ページ) を参照してください。アップル社では、Open
Transport 環境でイーサネットアドレスを取得するサンプルコードを公開しています。
この技法の問題は、デフォルトのイーサネットアドレスが、システムファイル内の 'eadr'
タイプのリソースで置き換えの設定がされていることがあるということです。これは、『Inside
Macintosh: Networking』(11-26
ページ) に書かれています。ハードウェアアドレスが変更可能なこと、特定のモデルには必ずイーサネットがあるという保証もないことから、これはいい方法ではありません。
同様の技法は、トークンリングカードやその他のカードが付いた Mac OS コンピュータでも使用できますが、この文書では説明しません。
ハードディスクのシリアル番号
ハードディスクにシリアル番号が付いたものもあります。ATA/IDE ドライブの多くにはシリアル番号がありますが、SCSI
ハードディスクにはたいていありません。アップルは、ATA または IDE ドライブのシリアル番号を取得するサンプルコードを公開しています。ATA
や IDE ドライブが付いているのは一部の Macintosh なので、これは汎用的に使えるような良い方法ではありません。
SCSI の欠陥リスト
SCSI ドライブの欠陥リストを使うデベロッパもいます。これは SCSI のないマシンでは動きませんが、SCSI
付きのマシンではいい方法かもしれません。SCSI Manager の使用方法の詳細については、『SCSI-2 Specification』および『Inside
Macintosh:Devices』を参照してください。『Tool Chest Developer CD』には、SCSI
Manager の一般的な使用方法を示すソースコードが含まれています。SCSI が付いているのは一部の
Macintosh なので、これは汎用目的で使えるような良い方法ではありません。
システムフォルダのディレクトリ
ID
システムフォルダの dirID を比較する方法です。FindFolder()
を使って、システムフォルダの dirID は取得して、以前保存しておいた dirID
と比較します。これはファイル ID ほどユニークではありません。システムフォルダはどのマシンでもはじめから作成されているものなので、マシンが違っても同じディレクトリ
ID を持つことが多いのです。ユーザが新しいシステムフォルダを作成すると (アップグレードの際に、システムソフトウェアをインストールし直したときなど)
、違うディレクトリ ID になってしまいます。これはよい方法ではありません。
// GetVolumeDirID はシステムフォルダの dirID を返します。
//
OSErr GetVolumeDirID(long *dirID)
{
OSErr err;
short notUsed;
err=FindFolder(kOnSystemDisk, kSystemFolderType, no,
notUsed,dirID);
return(err);
}
|
ボリューム作成日
ボリュームの作成日を比較する方法です。この情報は PBHGetVInfo() を使って取得できます。これはファイル
ID ほどユニークではありません。ボリューム作成日は、工場でシステムソフトウェアがボリュームに入れられる時に設定され、ボリュームを再初期化するときにしかリセットされないからです。この値は一連のマシンで同じになる傾向があるので、よい方法ではありません。
long GetVolCreationDate(short vRefNum )
{
OSErr err = noErr;
HParamBlockRec pb;
Str255 vName;
vName [ 0 ] = '\0';
pb.volumeParam.ioCompletion = nil;
pb.volumeParam.ioNamePtr = vName;
pb.volumeParam.ioVRefNum = vRefNum;
pb.volumeParam.ioVolIndex = 0;
err = PBHGetVInfoSync ( &pb );
return ( pb.volumeParam.ioVCrDat);
}
|
ネットワークへの登録
Macintosh を特定するのではなく、同じアプリケーションの複数のコピーが同じネットワークで動作することを避ける方法もあります。一部のデベロッパが使う方法は、NBP
(Name Binding Protocol) で架空のデバイスをネットワークに登録するもので、その名前には、該当のライセンスにあたる単一のシリアル番号を使います。
(もちろんこのシリアル番号を生成する方法は必要です。) 同じデバイスとシリアル番号を複数回登録しようとすると、エラーが発生するので、プログラムはその使用を拒否することができます。NBP
の詳細は『Inside
Macintosh: Networking』の第
3 章にあります。
/*
* 指定のソケットに対して、指定のオブジェクトとタイプを持つ
* エンティティを登録します。関数が noErr を返した場合は、
* NamesTableEntry へのポインタが ntePtr に返されています。
*/
OSErr MyRegisterName(ConstStr32Param entityObject,
ConstStr32Param entityType,
short socket,
NamesTableEntry **ntePtr)
{
MPPParamBlock mppPB;
OSErr result;
Str32 entityZone = "\p*";
/* ネームテーブルのエンティティを格納する再配置不能なメモリを
* システムヒープに割り当てます。
*/
*ntePtr = (NamesTableEntry *)
NewPtrSys((Size)sizeof(NamesTableEntry));
if ( ntePtr == NULL )
{
result = MemError(); /* メモリエラーを返す */
}
else
{
/* ネームテーブルのエンティティを作成する */
NBPSetNTE((Ptr) *ntePtr,
(Ptr) entityObject,
(Ptr) entityType,
(Ptr) entityZone,
socket);
/* ioRefNum と csCode は PRegisterName のグルーによって
設定されます */
mppPB.NBPinterval = 0x0f; /* 間隔と回数を適切な値に */
mppPB.NBPcount = 0x03; /* 設定します */
mppPB.NBPentityPtr = (Ptr) *ntePtr;
mppPB.NBPverifyFlag = (char) true; /* ユニークな名前 */
result = PRegisterName(&mppPB, false);
if ( result != noErr )
DisposePtr((Ptr) *ntePtr);
}
return ( result );
}
|
注意:
DTS は、アプリケーションがインターネット全体でエンティティの検索を行うことは推奨しません。このような検索は時間がかかるからです。たくさんのゾーンを持つ大きなネットワークでは、検索のためにかなりの時間を費やすことになります。起動時のコードで行う処理としては適切ではありません。かわりに、ローカルゾーンを検索することをおすすめします。必要なら、他のゾーンに対する検索は、非同期のバックグラウンド処理として実現するのがよいでしょう。 |
すべきではないこと
拡張パラメータ RAM (PRAM) のうち、文書化されていない値に頼ってはいけません。アップルは
PRAM の一部を公開しているだけで、他の部分は公開していません。詳細については、『Inside
Macintosh:Operating System Utilities』の第
7 章を参照してください。アップルは未公開の PRAM の意味を変更する権利を留保しています。PRAM
の公開領域以外に情報を保存することはやめてください。このような PRAM の誤用はシステムの安定性に重大な影響をおよぼすことになります。
フォーマットしたフロッピーや特殊なフロッピーの特殊なトラックを使う方法もおすすめできません。アップルは、このような用途に
DTS がサポートできるようなフロッピードライブの情報を提供してはいません。また、DiskCopy
などのディスクコピープログラムは、非常にうまく動作し、そのような技法を破ってしまいます。
(DiskCopy は、フロッピードライバのソースコードを見ながら、アップル内部で書かれたものです。詳細を外部に公開する予定はありません。)
ハードディスクの特殊なセクタに頼ることもいけません (アップルは複数のベンダから部品を購入しています。特定のマシンや特定のモデルの未公開部分について何らかの仮定をしてはいけません。)
注意:
将来のある時期において、アップルは 800K GCR フォーマットのフロッピーをサポートしないマシンを製造する可能性があります。Mac
OS コンピュータの識別の目的で、800K GCR フォーマットなど、特定のハードウェア機能に頼るべきではありません。 |
結論
ここで述べた技法は、コンピュータの識別に役立つ簡単な方法です。これらの技法は単純なコピープロテクトには便利かもしれません。本格的なコピープロテクトのためのより複雑な技法もたくさんあります。たとえば、ADB
デバイスなどの外部ハードウェアを、ライセンス済みのマシンを識別する装置 (ハードキーと呼ばれます)
として使うなど、よい方法があります。本格的なコピープロテクトを行う場合は、自分で作成するのではなく、コピープロテクトを専門にする会社がたくさんありますので、問い合わせてみてください。多くのサードパーティが、ハードウェアを使う製品
(ADB のハードキーなど) や、ソフトウェアを使う製品 (ライセンシングソフトウェア) を提供しています。
まとめ
Mac OS はコピープロテクトを考慮に入れて設計されてはいません。Mac OS ベースのコンピュータのすべてのモデルで共通に利用可能なシリアル番号もありません。複数の
Mac OS コンピュータを識別する技法がいくつかあり、この TECHNOTE ではその技法を解説しました。
DTS は、コピープロテクトをサポートしません。互換性に関わる問題が大きいからです。DTS
は、コピープロテクト技法を集めているわけではありません。
|