2006/02/22

crypt(3)関数

/etc/passwdのパスワード部分の生成にはcrypt()関数が使われるが,
このcrypt()関数に関する話題.

crypt()関数の実装はGNU libcとOpenSSLの2ヶ所にある.
そのうち, GNU libcのlibcryptでは, もともとの(DES暗号のみを使用する)crypt()関数が
拡張され, saltが$1$で始まる場合, MD5を使用してpasswdを生成する
機能が含まれる.
一方のOpenSSLのlibcryptoでは, DESのみの対応となっている.

そのため, コンパイル時にどちらのライブラリをリンクするかで,
crypt()関数が期待する値を返さない場合がある.
たとえば, "gcc -lcrypt"の場合, DESとMD5の両方に対応するが,
"gcc -lcrypto"の場合は, DESのみの対応となる.

では, "gcc -lcrypt -lcrypto"ではどうなるか.
この場合は, 先に指定のあるlibcryptが優先されるため, DESとMD5の
両方が使用可能となる.
逆に, "gcc -lcrypto -lcrypt"では, 上記の逆となるためDESのみ.

ちなみに, うちのCygwinのPerlでは, crypt()関数は, DESのみの対応と
なっていた.

おそらく, ライブラリのリンク順の問題だろう. ただ, 上記の順でリンクさせる
ためには, GNU configureを使用する場合には注意しなければいけない.

GNU configureでは, オプションで指定したライブラリを先にリンクしようとする.
そのため, libcryptoをオプションとして指定すると, libcryptより先にリンクされ,
libcrypto(OpenSSL)のcrypt()関数が使用される.

しかし, libcryptを先にリンクさせたい場合には問題となる.
その場合は, configureを実行する際に, 環境変数LIBSを使用する.
指定する値は, ライブラリのリストの"後に"させたいライブラリ名.
libcryptを優先して使用させたい場合は, こんな感じ.
$ env LIBS=-lcrypto ./configure

このからくりについて.
configureが生成するMakefileは, ライブラリのリンクにGNU libtoolを使用する.
GNU libtoolは, リンクの際にライブラリの重複をチェックするが,
その際, 優先されるのは, 後から指定されたライブラリ. 同じライブラリが複数回
指定されている場合, 先に指定されているライブラリをリストから削除する.

例:
$ libtool --mode=link gcc -lcrypt -lcrypto -lcrypt .....
では, libcryptが2回指定されているが, 先に指定したlibcryptが削除され
$ gcc -lcrypto -lcrypt ....
が行われることになる.

見た限り, configureは, 追加するライブラリを変数LIBSに追加する際,
既に存在する$LIBSの前に追加している場合が多いようである.
そのため, configureの開始時に, 既に$LIBSが指定されている場合,
その値が, GNU libtoolに渡されるライブラリリストの最後に付くことになる.

そして, GNU libtoolが, 後から指定されたライブラリを優先して残していくため,
最終的に, リンカが使用するライブラリリストの最後に指定されることになる.

0 件のコメント: