PAM を使って Active Directory で認証する方法

2008/03/09 | ラベル: , | 0 コメント | このエントリーを含むはてなブックマークを表示

PAM を使った自作アプリ(C/C++)で、ユーザの認証を Active Directory で行う方法を紹介。

C/C++アプリのコーディングでは、Active Directory を意識する必要はなく、単に PAM に問い合わせるだけ。認証方法に依存しちゃったら PAM を使う意味ないしね。ここでは PAM ライブラリを用いたコーディングについては触れません。

アプリのプラットフォームは Linux 。今回は、ユーザの認証だけができればよく、Linuxシステム上にアカウントは存在しなくてよい。というより作りたくない。

手順はたかはしもとのぶ氏の Linux の認証を Active Directory で行なう方法 の通りでOK。

また、Windows ActiveDirectory を利用した Linux ログイン認証環境構築時のメモ は Windows と Linux の認証の統合の方法についてよくまとまっている。

手順

  1. PAM、Kerberos といった必要なライブラリをインストールする。RHEL4 ではデフォルトで入るかな?
  2. /etc/krb5.conf を設定する。
  3. /etc/pam.d/hoge を作成する。"hoge" はC/C++アプリ側で指定する PAM の認証サービス名。

これだけ。

/etc/krb5.conf の設定

[logging]
 default = FILE:/var/log/krb5libs.log
 kdc = FILE:/var/log/krb5kdc.log
 admin_server = FILE:/var/log/kadmind.log

[libdefaults]
 default_realm = TEST.LOCAL
 default_tkt_enctypes = des-cbc-md5
 default_tgs_enctypes = des-cbc-md5
 dns_lookup_realm = false
 dns_lookup_kdc = false

[realms]
 TEST.LOCAL = {
  kdc = dc1.test.local:88
  admin_server = kerberos.example.com:749
  default_domain = test.local
 }

[domain_realm]
 .test.local = TEST.LOCAL
 test.local = TEST.LOCAL

[kdc]
 profile = /var/kerberos/krb5kdc/kdc.conf

[appdefaults]
 pam = {
   debug = false
   ticket_lifetime = 36000
   renew_lifetime = 36000
   forwardable = true
   krb4_convert = false
 }

Active Directory 側で、Administrator のパスワードを一度も変更していない場合、kinit に失敗するので注意。

簡易テスト

ここで Active Directory で認証できるか簡易なテストをする。Active Directory 上に存在するユーザと同名のユーザを Linux 上にも作る。パスワードは未設定でよい。/etc/pam.d/system-auth の先頭エントリに次の1行を加える。

auth        sufficient    /lib/security/$ISA/pam_krb5.so

そのユーザで Linux にログインしてみる。成功すると、/var/log/messages に次のようなログが記録される。

Mar  5 16:39:02 localhost sshd: pam_krb5[22867]: authentication succeeds for 'test01' (test01@TEST.LOCAL)

テストが成功したら、/etc/pam.d/system-auth を元に戻し、Linux 上のユーザは削除しておく。

PAMサービスのコンフィグを書く

#%PAM-1.0
auth       required     /lib/security/pam_krb5.so no_user_check

認証のみでユーザが(ローカル)システムに存在するかチェックしなくてよいので、no_user_check オプションをつけること。

あとは C/C++ アプリで認証ができるか確認する。

ふと気になったこと

  1. Active Directory 側のユーザアカウントが無効、パスワード切れ、パスワード切れ間近、ログイン不可時間帯とかの場合は認証はどうなるんだろう?PAM の設定で auth だけでなく account も必要かも。要確認。
    (2008.4.30追記)
    1. account はなくても OK。
    2. アカウントが無効、ログオン可能時間帯以外(ログオン拒否時間帯)の場合は認証エラーとなる。Clients credentials have been revoked.
    3. パスワード有効期限切れの場合は、エラーにはならず認証が通る。
    4. 次回ログオン時にパスワード変更が必要である状態の場合は認証エラー。KDC has no support for encryption type.
    5. 対話型ログオンにスマートカードが必要とされている場合は認証エラー。KDC policy rejects request.
  2. kdc(=Active Directory)の冗長化はどう図ればよいのか。kdc は複数指定可能?
    ググってみたら kdc は複数指定可能みたい。

krb5.conf から引用。HP-UXのだけど、Linuxでも多分同じ。

[realms]
ATHENA.MIT.EDU = {
        kdc = KERBEROS.MIT.EDU
        kdc = KERBEROS-1.MIT.EDU:750
        kdc = KERBEROS-2.MIT.EDU:88
        admin_server = KERBEROS.MIT.EDU
        default_domain = MIT.EDU
        v4_instance_convert = {
                mit = mit.edu
                lithium = lithium.lcs.mit.edu
        }
}

ドライブレターのないボリュームの容量を取得する

| ラベル: , , | 0 コメント | このエントリーを含むはてなブックマークを表示

WMIを使ってディスク容量を取得するサンプルはたくさんあるけど、ドライブレターのない論理ボリュームの容量を取得するものがない。また、Win32_LogicalDisk クラスでも取得できない。

いろいろ調べて試した結果、Win32_Volume クラスで取得できることが分かった。以下は「C:\Users\xxx」にマウントしたボリュームの総容量と空き容量を取得する例。

strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * from Win32_Volume Where Caption = 'C:\\Users\\xxx'")
For Each objItem In colItems
    WScript.Echo "Name: " & objItem.Name
    WScript.Echo "Capacity: " & objItem.Capacity
    WScript.Echo "Free Space: " & objItem.FreeSpace
    WScript.Echo
Next

ExecQuery メソッドでは LIKE も使えるので、

Select * from Win32_Volume Where Caption LIKE 'C:\\%'

という書き方もできる。

参考リンク

Vistaでドライブレターがないボリューム上のファイルがインデックスに登録されない

| ラベル: , , | 0 コメント | このエントリーを含むはてなブックマークを表示

Windows Vista には Windows デスクトップ サーチ の機能が統合されていて、様々なファイルの検索が可能になっている。デフォルトでは Users フォルダとオフラインフォルダがインデックス登録され、検索可能になっている。

だけど、なぜか自分のドキュメントフォルダに保存したPDFファイルがインデックスに登録されない。Administratorのドキュメントはちゃんと登録されている。インデックス対象の選択画面を開くと、なぜか自分のデータフォルダだけ表示されないではないか。。。どうやら、ジャンクションフォルダはインデックスの対象外っぽい。そういう仕様なんだろう。

なぜジャンクションになってるか

自分はデータ領域をシステムドライブと分けたいという性分なので、Documents and Settings フォルダを移動せずに別のドライブにマウントする方法 の手順で自分のデータ領域(C:\Users\xxx)を別ボリュームに分けた。dirコマンドで見てみると、C:\Users\xxx はジャンクションになっている。

ドライブレターをつけてみた

試しにデータ領域にしているボリュームにドライブレターを付けると(Uドライブとした)、インデックス対象の選択画面にはそのボリュームが見えるようになる。マウントポイントである C:\Users\xxxはやっぱり見えない。インデックス対象としてUドライブを選択してインデックスを再構築すると、ファイルがインデックス登録されるようになった。しかーし、UドライブとC:\Users\xxxと、2重で登録されてしまう。ださい。。。Uドライブをインデックス対象から外したり、Uドライブのドライブレターを外すと、やっぱりインデックス登録されない。

シンボリックリンクにしてみた

Vista では正式にシンボリックリンクに対応したということなので、ボリュームのマウントをやめて、C:\Users\xxx を Uドライブへのシンボリックリンクにしてみた。すると、Uドライブをインデックスの対象から外した状態でも、C:\Users\xxx以下のファイルがインデックスに登録されるようになった。でも、今度はインデックス対象を選択する画面で自分のデータフォルダだけでなくUsersフォルダ全部が見えなくなってしまった。。。orz

一応インデックス登録されるようになったし、ファイルの読み書きやアプリの利用など通常利用に問題はなさそうなので、しばらくこれで使ってみるか。。。

ちなみに、Vista でシンボリックリンクを作成するには mklink コマンドを使う。

Documents and Settings フォルダを移動せずに別のドライブにマウントする方法

| ラベル: , | 0 コメント | このエントリーを含むはてなブックマークを表示

データ領域をシステムドライブと別にしたいという人は結構いるんじゃないかと思う。自分もDocuments and Settingsフォルダの場所を変更する を参考にしてDドライブに移している。Documents and Settings フォルダ(名前長いよ。。。)は Vista では Users フォルダに名前が変更されている。うん、短くていいね:-)

しかし上記の手順で Documents and Settings フォルダを別ドライブにすると、不具合が出るアプリもある。自分は Windows Media Player がエラーで使えなくなった。DRM関連の設定がレジストリにバイナリ値として「C:\Documents and Settings\...」と設定されていたためだ。念のためレジストリはチェックしていたのだけど、バイナリ値は検索に引っかからなかった。

他にも、Google Earth は Documents and Settings が Cドライブにあるものとして作られているのか、使うたびに Cドライブに Documents and Settings フォルダが作成されてしまっていた。
※今では解消している模様。

さて、これらの問題も変更前のパス( C:\Documents and Settings )でもアクセスできれば解消できると思われる。パスは変更せず、実際のデータは別のドライブに保存される。

方法

  1. ディスクを追加するなどして、Cドライブ以外のボリュームを用意する。NTFSでフォーマットする。
  2. Documents and Settingsフォルダの場所を変更する を参考にして、「C:\aaa」など適当な場所に一時的に移動する。データ領域として使いたいボリュームはまだここで使わないように。
  3. 「C:\aaa」にちゃんと移動できたことを確認したら、Documents and Settings フォルダを空にする。
  4. コントロールパネル -> コンピュータの管理 -> ディスクの管理 を開く。
  5. データ領域として使いたいボリュームを右クリックして「ドライブ文字とパスの変更」を選び、空にした「C:\Documents and Settings」フォルダにマウントする。
  6. 「C:\Documents and Settings」フォルダに書き込みができることを確認したら、「C:\aaa」に変更した Documents and Settings を再度「C:\Documents and Settings」に戻す。

これで OK、なはず。自分は試してないので、誰かやってみてください。(ぉぃ...)

一応、Vista で似た手順を踏んで C:\Users\test を別ボリュームにすることはできた。C:\Users フォルダ全体じゃないっす。ただちょっと弊害が残った。詳細別エントリで。。。↓

関連エントリ

body onload は使ってはいけない?

2008/03/08 | ラベル: , | 0 コメント | このエントリーを含むはてなブックマークを表示

独自の Windows Vista サイドバー ガジェットを作成する より引用。

JavaScript をかじったことがある方なら、"eval is evil" という言葉を耳にしたことがあるでしょう。ご存じない方は、まず Web で調べてから続きをお読みください。 eval を使用すべきでない理由をおわかりいただけたところで、ここではこの規則に修正を加えて、JavaScript のテキストを HTML 内の属性に配置すべきではないという規則と、setInterval や setTimeout に文字列を渡すべきではないという規則を付け加えたいと思います。JavaScript のテキストを配置してはいけない属性には、body onload 属性も含まれます。この属性は eval ステートメントと同じように内部で解釈されるからです。 "body onload がだめならどうやってコードを実行するんだ" とおっしゃる方もいるでしょう。そのような方には、window オブジェクトの onload イベントに関数をアタッチする習慣を付けることをお勧めします。次のコードは、onload イベントと onunload イベントへのアタッチの方法を示しています。

function pageLoad() {
    window.detachEvent(“onload”, pageLoad);
    window.attachEvent(“onunload”, pageUnload);
    //page initalization here
}

function pageUnload() {
    window.detachEvent(“onload”, pageUnload);
    //gadget is closing, clean up
}

window.attachEvent(“onload”, pageLoad);

正直「evalステートメントと同じように内部で解釈されるからです」というのもよく分からなかったけど、上記のように書くほうが良いお作法ってことですかね。アタッチする方法だと複数の関数をつけることもできる。上記コードはちゃんと後片付けもしている。なるほど。

Firefox や Opera では addEventListener、removeEventListener を使う。

if (window.addEventListener)
  window.addEventListener("load", pageLoad, false);
else if (window.attachEvent)
  window.attachEvent("onload", pageLoad);
else
  window.onload = pageLoad;