2012-08-08

PKI用にOpenLDAPをWindows環境で使う その壱  [by miyachi]

PKIの世界ではCRLや証明書はLDAPのディレクトリサーバから取得することが多いです。特に日本のGPKI/LGPKI/JPKI等の相互認証しているPKIドメインだとディレクトリサーバも公開されていますし、使わなければ損な状況でもあります。

なお余談ですがLDAPのポート番号はldap:389/ldaps:636となっていて、企業内からだとファイアーウォールで許可されていないケースも多いです。この為にPKI現場のSEの皆さんにはLDAPは結構不評だったりするのですが…(^^;

閑話休題。Windows環境でクライアントとしてLDAPを使うAPIとしてWinLDAPが提供されています。これまで私もWinLDAPを使ってきたのですが、最近どうも調子が悪い…と言うよりも実行に時間がかかるようになっていることを発見。Windows XP環境だとあっという間に完了する検索が、Windows 7環境だと秒単位でかかります。

LDAPはCAPI(CryptoAPI)のCryptRetrieveObjectByUrl()でも取得可能です。なおここにCAPIを使ったCRLの取得について説明があるので参考になります。でもCAPIのAPIを使ってもWindows 7環境ではやはり秒単位の時間がかかります。内部的には同じAPIを呼んでいる気がします。

しかしながら遅くなった理由が全く解せない。とは言えある案件で時間も無かったので解析するよりもOpenLDAPを使ってみようと思い立ちました。とここまでが長い前振りでしたw これから本文。本文はもっと長いです(^^;

OpenLDAP本家サイトダウンロードできるのは基本的にLinux/Unix用のソースセットです。やはりWindows環境ならWinLDAPを使っている人が多くてニーズが少ないんでしょうね。とは言えありがたいことにWindows用のバイナリをビルドして配布してくださっているケースもあります。

例えば検索すると最初に出てくるのが「OpenLDAP for Win32」ではサーバ/クライアントの両方になりますがWindows用のバイナリの配布をしています。さっそくダウンロードから OpenLDAP_2.4.17-with-OpenSSL_0.9.8k.zip を入手して解凍してみます。クライアント利用には OpenLDAP_2.4.17-with-OpenSSL_0.9.8k/local と言うフォルダの下にある include と lib と bin の下のファイルが必要です。リンクライブラリは以下を目的により使い分けます。

 スタティックリンク: libldap.a / liblber.a
 ダイナミックリンク: libldap.dll.a / liblber.dll.a


ダイナミックリンクした場合には実行時にbinの下にある libldap.dll と liblber.dll が必用になります。OpenSSLでldapsを使う場合には ssleay32.dll も必用です。なおこのバイナリでは _alloca を使うのに libgcc.a も必用です。なのでプログラムの先頭で以下のように定義します。スタティックリンク用です。

// OpenLDAP定義
#define LDAP_DEPRECATED 1
#include <ldap.h>
// リンクライブラリ指定
#pragma comment(lib, "libldap.a")
#pragma comment(lib, "liblber.a")
#pragma comment(lib, "libgcc.a")

ただまだ strncasecmp() strcasecmp() gettimeofday() 等が未定義となりますがこれはまぁとりあえず以下のように逃げましょう。

extern "C" {

int strncasecmp(const char *s1, const char *s2, size_t n)
{
return _strnicmp(s1, s2, n);
}

int strcasecmp(const char *s1, const char *s2)
{
return _stricmp(s1, s2);
}

struct timezone {
int tz_minuteswest;
int tz_dsttime;
};

#define EPOCHFILETIME (116444736000000000i64)

int gettimeofday(struct timeval *tv, struct timezone *tz)
{
FILETIME tagFileTime;
LARGE_INTEGER largeInt;
__int64 val64;
static int tzflag;
if (tv)
{
GetSystemTimeAsFileTime(&tagFileTime);
largeInt.LowPart = tagFileTime.dwLowDateTime;
largeInt.HighPart = tagFileTime.dwHighDateTime;
val64 = largeInt.QuadPart;
val64 = val64 - EPOCHFILETIME;
val64 = val64 / 10;
tv->tv_sec = (long)(val64 / 1000000);
tv->tv_usec = (long)(val64 % 1000000);
}
if (tz)
{
if (!tzflag)
{
_tzset();
tzflag++;
}
long _Timezone = 0;
_get_timezone(&_Timezone);
tz->tz_minuteswest = _Timezone / 60;
int _Daylight = 0;
_get_daylight(&_Daylight);
tz->tz_dsttime = _Daylight;
}
return 0;
}

} // extern "C" end

これでリンクまで出来たと思います。試してみるとReferralが自動で出来ませんがとりあえず動作しています。と思ったらデバッグ実行して終了すると ldap_init() するだけでメモリリークが…

Detected memory leaks!
Dumping objects ->
{5091} normal block at 0x0160C3F0, 1 bytes long.
Data: < > 00
{5090} normal block at 0x09401F40, 10 bytes long.
Data: <localhost > 6C 6F 63 61 6C 68 6F 73 74 00
{5089} normal block at 0x09401E58, 5 bytes long.
Data: <ldap > 6C 64 61 70 00
{5088} normal block at 0x09401DF0, 40 bytes long.
Data: < X @ @ @ > 00 00 00 00 58 1E 40 09 40 1F 40 09 85 01 00 00
Object dump complete.

あれ?私何か間違えたかなと検索してみると、既知のバグのようでOpenLDAPの2.4.19で修正されているようです。う~んこのバイナリはOpenLDAP 2.4.17なので修正前ってことか…これを気にしなければこのまま使えます(^^; このバイナリは日本で作業していたようですが現在は更新が停止されているようですので更新は望めそうにありません。

私的にはやはり嫌なので別の道を探します。次に見つけたのが英語ですが「OpenLDAP for Windows」です。こちらは OpenLDAP 2.4.26 なので最新ではありませんが先のバグは修正されたバージョンです。ダウンロードの openldap-2.4.26-x86.zip を解凍してインストールするとC:ドライブ直下に OpenLDAP フォルダが作成されその中に lib / include / bin のフォルダがありますので先ほどと同様にコピー等して使います。入れ替えてリンクしてみるのですが以下のようなエラーが多数出てリンクできません。

error LNK2001: 外部シンボル "__imp__ber_dup" は未解決です。

う~ん仕方が無いのでダイナミックリンクのライブラリに切り替えてみますとうまくリンクできました。なお先ほど未定義対策で入れた strncasecmp() strcasecmp() gettimeofday() はこちらのバイナリでは不要です。ソースの先頭には以下の定義だけ追加します。

// OpenLDAP定義
#define LDAP_DEPRECATED 1
#include <ldap.h>
// リンクライブラリ指定
#pragma comment(lib, "libldap.dll.a")
#pragma comment(lib, "liblber.a")

ただしダイナミックリンクにしたので実行時に libldap.dll と liblber.dll と ssleay32.dll が必用です。テストしてみるとメモリリークも無くなりましたのでひとまずこれで終了です。実行速度もWindows 7環境でもあっと言う間に終わります。やれやれ解決(^^;

本当は自前で最新のOpenLDAPを本家サイトからダウンロードして来てソースからビルドすべきなんですが時間が無くてありもののバイナリを使う場合の記録です。Linux版の長期署名ライブラリも開発する予定なのでいずれにせよOpenLDAPは使っておいて損は無いな…と言うのも今回OpenLDAPを使った理由でもあります。

さてタイトルに「その壱」としたので「その弐」に続きます。「その弐」では今回省略したLDAPのAPIの使い方をサクッと説明しましょう。
2012-08-08 20:15:35 - miyachi - [PKI/暗号] -

コメント一覧

コメント無し

コメントを書く

このアイテムは閲覧専用です。コメントの投稿、投票はできません。