2008年3月31日月曜日

FTP でサーバ側ディレクトリの存在をチェックする

少し前のことになりますが、お客様から FTP コンポーネント使用時にサーバ側のディレクトリの存在の有無をチェックする方法は無いか、というお問い合わせをいただきました。

FTP の規格 (RFC959) 自体にはそのようなチェック機能はありませんので、実際にそのディレクトリをアクセスしてみてサーバ側の反応を見ることで対応することになります。

なお FTP プロトコル上のエラーとしてサーバから返されるエラーは、IPWorksFtpException でエラーコード 141 として検出されます。このコードではディレクトリ不在エラー以外のものも検出しますので、サーバ側から返されるメッセージもチェックして判断する必要があります。

以下にサンプルコードを示します。このコードでは、RemotePath に当該ディレクトリを設定して (内部的に) CWD コマンドを発行させます。またディレクトリ /abc/xyz が存在しない場合には、サーバ側からは

550 CWD failed. "/abc/xyz": directory not found

というエラーメッセージが返されると仮定しています。

    try
{
// 確認したいパスを RemotePath に設定
ftp.RemotePath = "/abc/xyz";
}
catch (IPWorksFtpException ipwe)
{
// パスが存在しない場合は FTP Protocol Error を返す。
// FTP Protocol Error は全てエラーコード 141 にされるので、実際のメッセージを確認して
// 判断する。
if ( ipwe.Code == 141 )
{
// サーバから返されたエラーメッセージをチェック
if ( ipwe.Message.Contains("directory not found") )
{
System.Console.WriteLine("*** directory /abc/xyz doesn't exit. ***");
}
}
}
このロジックはサーバの返すメッセージに依存していますので、実際にご利用いただく際には検出ロジックを実際のサーバに合わせて調整する必要があります。

なお、サーバが仕様上「ディレクトリが存在しない場合」と「存在するけれどアクセス権が無い場合」のエラーメッセージをサーバが区別しない場合はクライアント側で両者を区別することはできません。

2008年3月28日金曜日

nscontrols.dll が書き込めない?

先日、.NET Edition を複数連続インストールしていたところ奇妙なエラーに遭遇しました。(右図)

当該製品を単独でインストールする場合このエラーは発生せず、複数の製品を連続インストールする場合、特に比較的大規模な製品が2つ連続する場合に発生するようです。

この nscontrols.dll は Visual Studio IDE のツールボックスに当該製品のタブを作成するための dll です。

そして、この問題の原因はインストールファイルのキャッシュイメージ処理あるいは遅延書き込み処理による排他ロックで、これはシステム環境依存のため弊社製品インストーラでは対処できません。

このエラーが発生した場合は、以下のいずれかの回避策で対処します。

  1. ダイアログが出た状態で長時間放置し、キャッシュイメージが全てフラッシュされる、あるいは遅延書き込みキューが空になるのを待ってから Retry をクリックする。

  2. Ignore で先に進む。弊社の .NET 製品が既に正しくインストールできていれば、 nscontrols.dll は既にインストール済みのはずなのでインストーラは既存の nscontrols.dll を使用してインストールを継続するはず。インストール終了後念のため Visual Studio の IDE を起動して当該製品のタブが生成されているかどうかを確認し、生成されていない場合は手作業で当該製品を追加する。

  3. 3. Abort で当該製品のインストールを中止し、PC を再起動してから当該製品を改めてインストールする。
なお 1. に関してはは個々のシステムの状態に依存しますので、待機時間を予測することは困難です。従って通常は 2. もしくは 3. で対応することになります。

2008年3月27日木曜日

tar ファイルの基本構造

tar ファイルは、Unix の基本 I/O 単位の 512 バイトのブロックから構成されています。

先頭のブロックはメンバーファイルに対する情報を格納したヘッダブロックであり、その後ろにメンバーファイルのファイル内容が書き込まれたブロックが続きます。メンバーファイルの長さ (バイト数) が 512 の倍数でない場合は、最後のブロックの途中でデータは終わることになります。(長さは当該メンバーファイルに対するヘッダブロック内に記述されています。) そして、サイズ合わせのため 512 バイトに達するまでダミーデータが末尾に追加されます。

各メンバパートはヘッダパートとデータパートから成ります。ヘッダパートは基本的には512バイトの1ブロックですが、機能拡張版では複数のブロックから構成されるヘッダパートもあります。ヘッダパートには、メンバファイルの様々な属性 (サイズやパーミッション、所有者情報等) が書き込まれます。
一方データパートはメンバーファイルの内容がそのまま書き込まれます。データパートも512バイトのブロック単位で書き込まれますので、末尾のブロックには長さ合わせのためのフィラー(詰め物) データが書き込まれることがあります。実際の長さは、ヘッダブロックから取得できます。

次のメンバーファイルが存在する場合は、またヘッダパート、そしてファイルデータパートが続きます。

最後のメンバーファイルのファイル内容ブロックの次にはアーカイブ終端を示す特別なデータ (EOA; End-Of-Archive マーク。全バイトが 0x00 の連続する2ブロック (1024 バイト)) が付与されます。

また、アーカイブ生成時に指定されたブロック化係数によっては、EOA の後ろにサイズ合わせのためのデータが付与されることがあります。

なお、ブロック化したレコードバッファをクリアしないタイプの tar アーカイバの場合は、EOA の後に以前のファイルデータが残っていることがありますが、もちろんこの部分はメンバーデータとしては取り扱われません。

参考: GNU tar 1.19: Basic Tar Format

2008年3月19日水曜日

ナレッジベースの日本語訳について

弊社では良くあるお問い合わせを公式ページ上でオンライン・ナレッジベースとして提供させて頂いております。

ただし現時点では英文のみとなっており、その他の言語でのナレッジベースの提供予定はございません。

しかし実際には日本からのお問い合わせも少なからずこのナレッジベースに記載されている事項がございますので、良くあるお問い合わせについて個人的に翻訳したものを掲載することにしました。翻訳済みのナレッジベース記事はこちらの「別館 (NSJ's Knowledge Base)」に蓄積していく予定です。

本家のナレッジベースとは違いキーワード検索等はできませんが、弊社製品ユーザ様への一助となれば幸いです。

2008年3月17日月曜日

tar ファイルのファイル末尾データについて

弊社の IP*Works! Zip 製品では tar 形式のアーカイブを扱うことができます。その関係で幾つかのテストデータを SuSE や KNOPPIX 等で作ってテストしていて気づいたのですが、Gnu tar で作成した tar ファイルはアーカイブの末尾に使用されないデータを含んでおり、ファイルサイズ (バイト数) が常に 10240 の整数倍になっていました。

一方弊社製品で作成する場合は, 512 の整数倍のサイズですが、必ずしも 10240 バイトの整数倍にはなりません。両者は特に問題なく生成も展開も互換性が保たれています。

少々気になったのでいろいろ調べていたところ、以下のようなことだと判明しました。

・tar は Tape ARchiver の略であり、元来はテープデバイスへの書き込みを目的としていた。
・テープデバイスは低速であり、Unix の書き込み単位 (512 バイト) はブロック化して書き込まないと効率が悪い。
・その関係で、Gnu tar の既定値ではブロック化係数 (blocking factor) が 20 になっている。

その結果、既定値を使用して tar ファイルを作成するとそのサイズは 512 x 20 = 10240 バイトの整数倍になります。なおアーカイブメンバーは必ずしもぴったりこのブロックに収まるわけではありませんので、アーカイブの末尾位置を明示するために特別なデータ (EOA: End-of-Archive マーク) をヘッダパートに書き込んで明示します。(そして、EOA 以降のデータは無視されます。)

弊社製品で生成する tar アーカイブも形式としては同様ですが、ブロック化係数が 1 として処理されるため、EOA より後にデータは書き込まれません。このため、生成されるアーカイブのサイズは常に 512 の整数倍となります。

また、EOA 以降のデータに何が入るかは規定されていません。このため、tar の実装によって

・以前のデータ断片が残ったままのもの
・EOA 以降を 0x00 等でクリアするもの

があります。前者の場合、一見意味のあるデータがファイル末尾に存在しているように見えますが、EOA 以降のデータは tar アーカイブとしては意味を持ちませんので、自分で tar アーカイブを処理する場合には注意が必要です。

※もちろん弊社の IP*Works! ZIP 製品に含まれる tar コンポーネントは正しく EOA を認識し、EOA 以降にブロッキング由来の不要データが存在してもそれらは無視されます。

2008年3月7日金曜日

PublicKey 情報が一致しない

先日、.pfx ファイル経由でプライベートキーを Windows の証明書ストアに登録しました。その際に、Windows の証明書マネージャで内容を確認したところ、「PublicKey」の詳細情報が CertMgr の PublicKey 情報と一致しないことに気づきました。

例えば、ある証明書の PublicKey が Windows の証明書マネージャの表示では 140 オクテットの
30 81 89 02 81 81 00 be 02 58 78 d1 4e 7f ea bd
32 aa 23 8c d6 2a 88 81 59 63 26 81 c6 0c 87 31
43 5e 9b a7 c0 9a 0d e1 cd c9 b5 c9 6a e0 0e 19
           …【中略】…
ae c7 91 f0 0c 4a 1d d1 f0 be 25 93 aa c4 f9 49
9a 35 1a f1 3c c7 11 02 03 01 00 01

となっているとします。同じ証明書を CertMgr で開き、PublicKey フィールドを読み取って得られる
-----BEGIN RSA PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+Alh40U5/6r0yqiOM1iqIgVljJoHGDIcxQ16b
                  …【中略】…
fw/rLw6xXDpnPOJjSe0hVRB50W6ux5HwDEod0fC+JZOqxPlJmjUa8TzHEQIDAQAB
-----END RSA PUBLIC KEY-----

をデコードしてみると、162 オクテットの
30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01
05 00 03 81 8d 00
30 81 89 02 81 81 00 c1 e5 95
15 4e 89 3c 8d 6a c4 2e 4f d5 d8 0f 28 ed 9e 3b
            …【中略】…
2d 65 94 d9 2d 2d 6e bf 45 e8 e0 d6 d9 02 03 01
00 01

というデータが格納されていました。このデータは Windows の証明書マネージャの提示する PublicKey 情報とは一致しません。よくよく見てみると、CertMgr で読み取った方には先頭に余分な 22 オクテット (薄ピンクの網掛け部分) が付加されています。その後ろに続く140オクテットは、Windows の証明書マネージャで表示される PublicKey と一致しています。

このデータは DER エンコードされた ASN.1 オブジェクトですので、その構造を解析してみると以下のようになっていました。
SEQUENCE {
SEQUENCE {
OBJECTID: 1.2.840.113549.1.1.1 (RSA Encryption)
NULL
}
BITSTRING:

30 81 89 02 81 81 00 be 02 58 78 d1 4e 7f ea bd
32 aa 23 8c d6 2a 88 81 59 63 26 81 c6 0c 87 31
 …【中略】…
ae c7 91 f0 0c 4a 1d d1 f0 be 25 93 aa c4 f9 49
9a 35 1a f1 3c c7 11 02 03 01 00 01
(unused bits: 0)
}

薄ピンクの網掛け部分が、先のデータの網掛け部分に該当しています。この部分には、鍵の暗号化アルゴリズムの情報が格納されていました。しかし、この情報は PublicKeyAlgorithm フィールドから得られるはずです。なぜこの情報を PublicKey フィールドの値に埋め込むのか開発部隊に確認してみたところ、次のような回答がありました。
  • RSA アルゴリズムの場合は PublicKeyAlgorithm で得られる情報のみで事足りるが、現在は RSA の他 DSA もサポートしている。こちらの場合、前記の ASN.1 フォーマットでは NULL となっている箇所にアルゴリズム用のパラメータを格納する必要がある。
  • しかし、現在のフィールド構成ではそのデータを取得するためのフィールドは存在していない。かといって、今後新たなアルゴリズムが追加されるたびに個別にフィールドを追加するのは大変だ。
  • 従って、PublicKey フィールドの値として返すデータにこの部分を含めることにした。実際、PublicKey として BITSTING 部分を使用する場合にはそのデータが何であるかを提示する必要があるので、この形式を PublicKey として返すことに問題はないはずだ。生の BITSTRING 部分が必要なのであれば、比較的簡単な手順で取り出すことも可能だ。

ある証明書に対し、CertMgr で得られる PublicKey が Windows (や Mozilla/Thunderbird) の提示するデータと異なるのはこういうことなのでした。

2008年3月3日月曜日

.cer ファイルのフォーマットについて

公開鍵をエクスポートする際には、幾つかの形式が選択可能ですが、注意が必要なケースも存在します。

Microsoft の [Control Panel] - [Intrenet Options] - [Content] - [Certificates] で起動される Certificates ダイアログでは Windows レジストリに登録されているユーザストアおよびマシンストアに格納されている証明書のエクスポートをサポートしています。この機能は Certificate Export Wizard で処理されますがこのウィザードでは
  1. DER エンコードの X.509 バイナリファイル
  2. (上記を) Base64 エンコードしたファイル

が共に .cer という拡張子になります。

通常は .cer は前者 (X.509 DER 形式) を指し、後者 (X.509 PEM 形式) に対しては .pem という拡張子を付与するようです。大抵のソフトウェアではファイル書式を自動判別してこれが問題となることは無いようになっているようですが、万一お使いのソフトウェアが .cer ファイルを正しく読み込めない場合は、.cer と .pem を厳密に区別するタイプのものかもしれません。念のため読み込ませる証明書の書式を確認してみることをお勧めします。そして内容がテキストの場合は、拡張子を .pem に変更して再度読み込ませてみるとうまく行くかもしれません。.pem 形式のファイルは、以下のようなテキストになっています。
-----BEGIN CERTIFICATE-----
MIIBlTCB/6ADAgECAgMBAAAwDQYJKoZIhvcNAQEFBQAwEDEOMAwGA1UEAxMFdGVz
…【中略】…
95NT76nIcgvBVR6Z/Rd1zOLknHV7jKhLxw==
-----END CERTIFICATE-----
弊社製品では公開鍵ファイルの読み込みは AddRecipient(Byte[] publicKey) で行いますが、引数として与えるバイト配列データは .cer のものでも .pem のものでも、いずれも受理するようになっています。