仙石浩明の日記

2008年12月9日

freeRADIUS 2.1.3 のバグ: ログを stdout/stderr へ出力できない

無線LAN の脆弱性について警告が飛び交う昨今、 WPA2 (Wi-Fi Protected Access) といえど、 パーソナル (PSK, Pre-Shared Key) モードだとパスワード破りの可能性が 無いわけでも無いので、 エンタープライズ (EAP, Extensible Authentication Protocol) モードに乗り換えてみた。

EAP (社員支援プログラムではなくて、 拡張認証プロトコル) の認証方式には EAP-MD5, EAP-FAST, EAP-SKE, EAP-SRP, MS-CHAP, EAP-GTC, EAP-GTC, Cisco LEAP, EAP-TLS, EAP-TTLS, PEAP, EAP-MAKE, EAP-SIM などがあるが、 対応機器/ソフトウェアが多そうな EAP-TLS を使ってみることにした。 EAP-TLS とは、 TLS (Transport Layer Security) すなわち SSL (Secure Sockets Layer) のサーバ認証とクライアント認証を行なって、 RADIUS サーバと無線LAN 端末が相互に認証を行なう仕掛けである。

RADIUS サーバとしては、 free RADIUS 2.1.3 を使用した。 自前の認証局 でサーバ証明書とクライアント証明書を発行し、 それぞれ RADIUS サーバと無線LAN 端末 (Windows マシン) へインストールする (自分で発行する証明書だが、 認証する側が自分の管理下なので、 いわゆる「オレオレ証明書」ではない)。

まず radiusd をデバッグ モードで走らせてみる:

# radiusd -X
FreeRADIUS Version 2.1.3, for host i686-pc-linux-gnu, built on Dec  6 2008 at 17:50:58
Copyright (C) 1999-2008 The FreeRADIUS server project and contributors. 
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A 
PARTICULAR PURPOSE. 
You may redistribute copies of FreeRADIUS under the terms of the 
GNU General Public License v2. 
Starting - reading configuration files ...
including configuration file /usr/local/etc/raddb/radiusd.conf
including configuration file /usr/local/etc/raddb/clients.conf
including configuration file /usr/local/etc/raddb/eap.conf
group = radius
user = radius
including dictionary file /usr/local/etc/raddb/dictionary
	...(中略)...
Listening on authentication address * port 1812
Ready to process requests.

とりあえず動いているようだ。 Windows マシンからアクセスポイントへ接続してみると、 アクセスポイントを介して Windows マシンと RADIUS サーバ間で、 TLS サーバ/クライアント認証が行なわれ、 無事 WPA2 エンタープライズ モードで接続が完了した。

では、radiusd を daemontools 配下で動かそうと、 次のような /service/radius/run スクリプトを書いて動かしてみる:

#!/bin/sh
export PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
exec 2>&1
exec radiusd -fxxx

-x を指定して詳細なデバッグ情報を出力させるようにする。 daemontools 配下で動かす場合、 multilog プログラムがログをどんどんローテートしてくれるので、 通常運用でもデバッグ情報を出力させておける。 ログを標準出力 (stdout) へ出力させるため、 設定ファイル radiusd.conf において、 次のように指定しておく。

log {
	destination = stdout
}

これでログが /service/radius/log/main/current に書き出されるはず、 と思ったら何も出力されない... 何故に...?

radiusd(8) によれば、-X オプションは 「-sfxx -l stdout」 と等価らしい。 -s オプションは、 RADIUS サーバを単一スレッド/プロセスで走らせるための指定。 個人で使う分には単一スレッドでも構わないといえば構わないので、 ログを stdout に出力する目的で -X オプションを使ってしまっても構わないのだが、 せっかくだからともうちょっと追ってみることにした。

まず上記 run スクリプトにおいて 「-l stdout」 を指定してみる。 すると、/service/radius ディレクトリに stdout というファイルができて、 そこにログが出力された。 ダメだこりゃ。 -l オプションはマニュアルには記載されていないので、 -l に続く 「stdout」 をファイル名と見なすのも一つの「仕様」と言えなくもないが...

ソース radiusd.c を見てみると、 確かに -l オプションの処理では続く引数をファイル名としてしか扱っていない。 では設定ファイル radiusd.conf に指定した場合はどうかと、 mainconfig.c を見てみる。 「log { ... }」 の中で 「destination = stdout」 を指定すると、 mainconfig.radlog_dest に RADLOG_STDOUT が代入されるようだ。 ところが、mainconfig.radlog_fd を設定するコードがない。 これでは stdout にログが出力されるはずがない。

「-l stdout」 の件は百万歩譲って「仕様」でも構わないが、 mainconfig.radlog_dest に RADLOG_STDOUT を代入しておきながら mainconfig.radlog_fd に代入し忘れるのは、 仕様うんぬん以前にソースとして首尾一貫していないので、 明らかにバグである。

そこで以下のようなパッチをあてて、 mainconfig.radlog_dest が RADLOG_STDOUT あるいは RADLOG_STDERR のときは、 mainconfig.radlog_dest に STDOUT_FILENO あるいは STDERR_FILENO を それぞれ代入するようにしてみた。

--- src/main/mainconfig.c~	2008-12-06 01:37:56.000000000 +0900
+++ src/main/mainconfig.c	2008-12-06 16:16:27.455277946 +0900
@@ -738,6 +738,10 @@
 				cf_section_free(&cs);
 				return -1;
 			}
+		} else if (mainconfig.radlog_dest == RADLOG_STDOUT) {
+			mainconfig.radlog_fd = STDOUT_FILENO;
+		} else if (mainconfig.radlog_dest == RADLOG_STDERR) {
+			mainconfig.radlog_fd = STDERR_FILENO;
 		}
 	}
 

これで無事、 ログが stdout に出力され、 /service/radius/log/main/current に書き出されるようになった。

Filed under: プログラミングと開発環境 — hiroaki_sengoku @ 08:02

コメントはまだありません »

コメントはまだありません。

この投稿へのコメントの RSS フィード。

コメントする