英語では 0.1 とかの 0 をあんまり読まないらしい

毎週受けている英語のレッスンの冒頭で、インストラクタが読む新聞記事を聞き取るというのがある。先週は、例の「EUMicrosoft独占禁止法違反の制裁金として8億9900万ユーロの支払いを命令」だったが、見事に聞き間違えた:

インストラクタ: Microsoft は、EU 圏での特許使用料を何%に引き下げていたか?*1
僕: 2.7%
インストラクタ: ぶー。0.7%でした。

なんで間違えたかというと、「0.7% に引き下げた」が「reduced to point seven percent」だったから。「0.7」は、「zero point seven」や「o point seven」とも言うけど、「point seven」のように 0 は読まないのが一般的らしい*2
で、ちょっと面白かったのがその後:

僕: 「to point seven」が「two point seven」に聞こえたんだよ。
インストラクタ: あー、なるほどね。僕も、日本語の「に」が「2」と紛らわしくて苦手なんだよ。
僕: へー。「に」は「to」と似たような単語だからちょっと面白いね。でも、まあ文法的なところで分かるけど。
インストラクタ: 「reduce」と来たら「to」に決まってんだろ。
僕: ……。仰るとおりです。

*1:当たり前だが、実際は英語だ。

*2:そのインストラクタがそう言ってただけで、本当にそうなのかは知らない。

mod_auth_kerb の KrbVerifyKDC を on にできた

Mac を Active Directory に参加させたりして悦に入っているぐらいに SSO が大好物なわけで、当然、Apache の認証は mod_auth_kerb で行っている。
だが、mod_auth_kerb を使っていてちょっと困っていたことがあった。KrbVerifyKDC というパラメータoff にしないといけなかったことだ。


KrbVerifyKDC on | off (set to on by default)
This option can be used to disable the verification tickets against local keytab to prevent KDC spoofing atacks. It should be used only for testing purposes. You have been warned.
こんなことが書いてあるものを off にするのは非常に躊躇われたんだが、これを on にしていると Basic 認証が動作しなくなる*1という問題が (少なくとも僕のところでは) あって、やむを得ず off にしていた。
ところが、今日、なんとなく mod_auth_kerb のバージョンを上げてみたら、これが直った。今までは CentOS 5 の mod_auth_kerb-5.1-3.el5.i386.rpm を使っていたのを Fedora の開発版から取ってきた mod_auth_kerb-5.3-6.src.rpm に変えただけ((ただし、REMOTE_USER の値に @REALM.EXAMPLE.COM を付けないようにするパッチを独自に当てて使っている。))だ。
長年の懸案がすっきり解消して、非常にいい気分。

*1:mod_auth_kerb は、SPNEGO 認証だけでなく Basic 認証もサポートしている。Basic 認証の場合、クライアントが送ってきたユーザ名とパスワードを使って KDC に認証を試みる。

ポインタ変数なのか、ポインタ型なのか、

C でポインタを定義するときの書き方には、3つの流派があるようだ:

ポインタ「変数」派

int *p;

  • 変数 p はポインタ変数という特別な変数だ、という主張。
  • (p を逆参照*1した結果である) *p の型は int だよ、という形での型付け。
ポインタ「型」派

int* p;

  • 変数 p の型はポインタ型という特別な型だ、という主張。
  • 変数 p の型は int* だよ、という形での型付け。
中立派

int * p;

  • なんだかポインタを定義するときの * の左右どっちに空白を入れるかでもめてる連中がいるから、とりあえず両方に入れとこうぜ、的な日和見
  • 少なくとも僕は、「int*p」という書き方は見たことがない。
どれがいいのかは宗教論争にしかならないので止めておこう。こんなことぐらい、それぞれの好みで書けばいいし、どう書かれていても同じように読めて当然だろう*2。実際、C++ 標準の規格文書の中でも、ポインタ変数スタイルとポインタ型スタイルの両方が登場する (中立派の書き方は見当たらなかった)。
C++ には型テンプレートの考え方があるので、ポインタの * もその一種だと考えるポインタ型スタイルの方が一貫した解釈だと僕には感じられる。std::auto_ptr<int> のように *<int> として int* を解釈するわけだ。
だが、ポインタを定義する際のこのような振る舞いを考えると、C の元来の考え方はポインタ変数スタイルだったのかもしれない:

int* p, q; // p は int へのポインタだが、q は単なる int 型の変数 (!)
int *r, s; // r は int へのポインタで、s は単なる int 型の変数 (自然)

とりあえず、逆参照の演算子 * が前置でよかったなと思う今日この頃((JavaC# の「int[] array;」という書き方が C++ でもできればいいのに。))。

*1:どうでもいいが、この「逆参照」っていう訳語はどうにかならないものか。

*2:中立派の書き方は、僕には、乗算式のように見えて読みにくいが。

Mac を Active Directory に参加させる

Active Directory はなかなかいい。シングルサインオンなどどうでもいいようなことに思えるかもしれないが、やはり、いい。しばらく使っていると、無駄にパスワードを入力するという行為に耐えられなくなる。共用マシンの管理者だったりすると、利用者ごとにアカウントを用意して、仮パスワードを作って、それを連絡して、という面倒なことをしなくてもよくなるのが非常に嬉しい。
というようにいいことずくめの Active Directory なのだが、Windows 以外のマシンを参加させるのは楽ではない。だが、不可能ではない。というか、MacActive Directory に参加させるのに今ようやく成功した*1。ちょっと嬉しいので、備忘という名目で手順を日記に書いておく。OS のバージョンは 10.5.2*2 だ。

参加申請

当たり前だが、Active Directory には勝手には参加できない。事前にドメインの管理者に参加を申請しておく必要がある。

NTPの設定

Active Directory では Kerberos 認証が使われるので、ドメインコントローラに NTP で同期するようにしておかなければならない。「システム環境設定」の「日付と時刻」を開き、「日付と時刻を自動的に設定」の欄にドメインコントローラの FQDN を入力する。ドメインコントローラが複数ある場合には、一番近いものにしておくのがいいと思う。

マシン名の設定

「システム環境設定」の「共有」を開き、「コンピュータ名」にマシンの名前*3を入力する。FQDN ではなくローカル名。末尾の「.local」なども付けない。
いま気付いたが、「システム環境設定」の「ネットワーク」で「詳細」の「WINS」を見てみたところ、「NetBIOS 名」もこのマシン名になっていた。設定した覚えはないので自動的になったのだと思うが、もし違う名前になっているのなら、正しいマシン名にしておいた方がいいと思う。

/etc/krb5.conf の作成

これはイレギュラーかもしれないが、/etc/krb5.conf を作ってやらないと、後述する「ディレクトリユーティリティ」でエラー*4が発生してしまった。kinit が成功しない*5ようなら、こういう内容の /etc/krb5.conf を用意する:

[libdefaults]
 default_realm = YOURREALM.EXAMPLE.COM
 dns_lookup_kdc = true

Active Directory のバインド

ディレクトリユーティリティ」を起動する。ここで、焦って「+」ボタンを押してはいけない。どう見ても「+」ボタンでディレクトリサーバを追加していくようにしか見えない UI だが、そうではない。ここは、正しく設定されたディレクトリサーバの一覧が自然に表示されていく場所なのだ。
そういうわけで、まずは「詳細設定を表示」を押す。上の方にいろいろとアイコンが出てくるので、「サービス」を選ぶ。続いて、「Active Directory」にチェックを入れ、鉛筆のアイコンをクリックする。
Active Directoryドメイン」には Active Directory のレルムを入力する。レルムなので全部大文字で入力したが、いま見たら小文字になっていた。多分、どっちでもいいんだろう。「コンピュータ ID」の方には、マシン名を入れる。FQDN ではなくローカル名だ。「詳細オプション」はデフォルトのままでいい*6マッピング」にあるチェックボックスにチェックを入れてみたら、全員の UID が同じ値になってしまったりといった問題に遭遇した。ディレクトリユーティリティのヘルプによればデフォルトのままで UID をいい感じに生成してくれるらしいので、それに任せておくのがいいと思う:

ディレクトリユーティリティのヘルプより

Active Directory アクセスについて

Windows 2000 以降のサーバの Active Directory ドメイン内の基本的なユーザアカウント情報にアクセスするように Mac OS X を構成することができます。この操作は、「ディレクトリユーティリティ」の Active Directory プラグインを使って行います。Active Directory プラグインは、「ディレクトリユーティリティ」の「サービス」パネルにリストされています。

〜中略〜

Active Directory プラグインでは、Active Directory ユーザアカウントの標準属性から Mac OS X 認証に必要なすべての属性が生成されます。プラグインは、パスワード変更、失効、強制変更、セキュリティオプションなどの、Active Directory 認証方式もサポートしています。

〜中略〜

Active Directory プラグインにより、Active Directory ドメインにおけるユーザアカウントの GUID(Globally Unique ID)に基づいて、一意のユーザ ID とプライマリグループ ID が動的に生成されます。生成されるユーザ ID とプライマリグループ ID は、異なる Mac OS X コンピュータへのログインにアカウントが使用される場合であっても、各ユーザアカウントについて同一です。

以上の入力を完了したら、「バインド」ボタンを押す。「ユーザ名」と「パスワード」には、Active Directory での自分のアカウントとパスワードを入れる*7。このとき、アカウントは「ユーザ名@YOURREALM.EXAMPLE.COM」の書式にする。Windows で使われる「ドメイン名\ユーザ名」ではダメだ。「コンピュータ OU」は、デフォルトで入っている値のままにしておく。「認証に使用」と 「コンタクトに使用」は両方ともチェックしておく。

そしてログイン

以上で、目出たく MacActive Directory に参加させることができた。これでもう、Active Directory のアカウントとパスワードで Mac にログインできる*8はずだ。

微妙に残った問題

Active Directory のユーザがログインした場合、Kerberos 認証の結果として TGT が得られている((klist コマンドで確かめられる。))。なので、他の Windows マシンが公開している CIFS 共有へのアクセスではパスワードは尋ねられないはずだ。実際、大概はそういう動作になっている。だが、一部の CIFS 共有では、認証に失敗してしまいパスワードを入れなければならない。
癪に障るので何とかしたいところだが、今日はもう疲れたのでこの辺にしておく。

*1:昨日の夜から始めてやっとできた。

*2:10.5.1 以前の Leopard では、Active Directory への参加 (バインド) に不具合があるらしい。10.5.2 でしか試していないので詳細は分からないが。

*3:ドメイン管理者が然るべき名前を指定してきているはず。

*4:「不明なエラー」とか、そんな内容だったと思う。

*5:「指定されたレルムの KDC を見つけられない」的なことを英語で言ってくる。

*6:今回セットアップした Mac はデスクトップマシンだったが、ラップトップの場合はモバイルアカウントを作るようにした方がいいのかもしれない。

*7:場合によっては、ドメイン管理者から専用のユーザ名とパスワードを案内されるかもしれない。

*8:ユーザ名とパスワードを入力してログインする設定に変更しておくこと。

Active Directory のドメインコントローラは NTP サーバを兼ねる

マシンの時計がずれる、なんてことはあってはならない。そんなことがあると、CVSSubversion のようなバージョン管理システムの動作が怪しくなったり、Kerberos 認証ができなくなったり、ミーティングに遅れたりしてしまう。
そういうわけで NTP での時刻同期は絶対に必須なわけだが、LAN 内から外部への NTP 接続ができない場合*1jst.mfeed.ad.jp などの NTP サーバは使えない。LAN の利用案内で NTP サーバが紹介されていれば問題ないが、案外、書いてくれていないものだ。
なぜ、大事な大事な NTP の説明が LAN の利用案内にはないのか。それは、Active Directory に参加している Windows マシンの時刻は自動的にドメインコントローラに同期しているからだ。「NTP」などというややこしい話などしなくても、Active Directory に参加させておけばそれで事は済む。時刻同期は Active Directory の基盤技術の1つである Kerberos 認証の必須要件なので、その辺りに抜かりはない。
だが、不幸にも*2 Windows 以外の OS を使っている場合にはどうすればいいのか。この場合も難しいことはない。Active Directoryドメインコントローラは NTP サーバを兼ねているのだ。LinuxMac だからといって躊躇することはない。ドメインコントローラに NTP で同期すればいい。
ドメインコントローラがどれかなんて知らないかもしれないが、それも問題ない。Active Directoryドメインコントローラは、DNS のネームサーバを兼ねている。ネームサーバが設定できていなければ NTP どころの話ではないので、これは大丈夫だろう。
そういうわけで、LAN 内の LinuxMac の時計がずれていないか、管理者の皆様にはちょっと見てみてほしい。

*1:普通はそうだと思う。

*2:もちろん、本当は不幸じゃない。

#include ガードにファイル名を入れるのは止めませんか?

#include ガードといえば、大体こんな感じのがメジャーかと思う:

sample.h の #include ガード

#ifndef SAMPLE_H
#define SAMPLE_H

// 宣言・定義など

#endif // ifndef SAMPLE_H

実を言えば、こういう #include ガードがあんまり好きじゃない。
もちろん、#include ガードそのものが嫌いなわけじゃない。というか、#include ガードは絶対に必要((#pragma once とか #import とかは好きだが、いかんせん、使えない環境がある以上は採用できない。))なもので、好き嫌いでどうこうする問題じゃない。嫌いなのは、#include ガードに使われている SAMPLE_H というマクロ名だ。
#include ガードのマクロ名は絶対に一意でなければならないからヘッダのファイル名をマクロ名に織り込むわけだが、たとえば、<some_header.h><some/header.h>#include ガードはどちらも SOME_HEADER_H になってしまわないだろうか?
このようなマクロ名の衝突の危険性もさることながら、もっと嫌なことがある。#include ガードにファイル名を織り込むと、ファイル名を変更するときに邪魔になるのだ。些細なことかもしれない。だが、ディレクトリ名を変更したりした場合の作業量は決して馬鹿にはならない*1。そして、その“面倒くささ”がリファクタリングを妨害し、プログラムは段々と理解不能な代物へと“腐敗”していく。
そんなわけで、僕は、こんな感じの #include ガードを使っている:

#ifndef INCLUDE_GUARD_UUID_0FA2482C_F796_4715_A360_E088A24F0042
#define INCLUDE_GUARD_UUID_0FA2482C_F796_4715_A360_E088A24F0042

// 宣言・定義など

#endif // ifndef INCLUDE_GUARD_UUID_0FA2482C_F796_4715_A360_E088A24F0042

何かのソースを見たときに UUID で #include ガードの一意性を確保しているのを見て*2、パクった。uuidgen を実行するのがちょっと面倒くさいが、まあ、大した手間じゃない。
ちなみに、some_header.h と some/header.h を区別するために #define SOME__HEADER_H とやるのは禁じ手だ。_SOME_HEADER_H のようにする人もたまに見かけるが、それも禁じ手:

C++ 標準 *3 ― 17.4.3.1.2 Global names
Certain sets of names and function signatures are always reserved to the implementation:
  • Each name that contains a double underscore (__) or begins with an underscore followed by an upper-case letter (2.11) is reserved to the implementation for any use.
  • Each name that begins with an underscore is reserved to the implementation for use as a name in the
    global namespace.

*1:Java 慣れしてしまったせいか、クラスごとにヘッダファイルを分けて名前空間に対応させたディレクトリ階層に置くクセがついてしまった。

*2:多分、Visual C++ が自動生成したヘッダだったと思う。

*3:ISO/IEC 14882

paid off

Itanium は dedicated 64 bit chip だが、AMD は added 64 bit capability to 32 bit chips という gamble に出たわけだが、結果は、ご存知のとおり AMD64 の勝利。こういう風にギャンブルに勝ったことを「paid off」というらしい。この例では、「AMD's gamble paid off.」*1
ちゃんと辞書で調べました。「(努力が) 報われる、効果を上げる、成功する」です。

*1:最初にこの日記を書いたときに「AMD paid off.」と書いてましたが、「paid off」の主語には“報われる”ことになった努力などがくるので、それは間違いみたいです。