%%Title: Heimdalを使ってみる

%%Created: Mon Oct 20 19:00:14 JST 2003
%%Updated: Wed May 26 14:29:55 JST 2004

Heimdal

o Heimdalのインストール
	FreeBSD4.9に Heimdalをインストールしてみる。

	NOTE:
	pkg_add(8)やportsから普通にインストールすると/usr/localの
	ftpとかtelnetが置き換わるので注意する。
	# pkg_add -p /usr/local/heimdal -rv heimdal-0.6.tgz
	とかして、/etc/rc.confのldconfig_pathsに/usr/local/heimdalを追加して、
	# ldconfig $ldconfig_paths しといてもいい。

	以下の暗号がサポートされている
		des-cbc-crc
		des-cbc-md4
		des-cbc-md5
		des3-cbc-sha1

	以下のプログラムがインストールされる

		/usr/local/sbin
		dump_log: kdcのログをダンプする
		kadmin           # マスターデータベース管理プログラム
		kstash
		ktutil
		replay_log       # log_fileを読んで履歴を再実行する
		truncate_log     # log_fileを削除する

		/usr/local/libexec
		kdc              # KDCプログラム
		ipropd-master    # incremental propagationサーバ
		ipropd-slave     # incremental propagationクライアント
		kpasswdd         # ユーザが鍵を変更するためのデーモン
		hprop            # slaveサーバにデータを転送するプログラム
		hpropd           # slaveサーバ用デーモン
		kfd              # キャッシュを転送するためのデーモン
		kadmind          # 遠隔からkadmin(8)するためのデーモン
		ftpd
		popper 
		push 
		rshd 
		telnetd 

		/usr/local/bin
		kinit            # TGT取得プログラム
		kauth            # 実体は kinit
		klist            # キャッシュをダンプするプログラム
		kdestroy         # キャッシュを破棄するプログラム
		kpasswd          # ユーザが鍵を変更するためのプログラム
		verify_krb5_conf # krb5.confの文法チェックプログラム
		kf               # キャッシュを転送するプログラム
		krb5-config      # コンパイラオプションを自動的に生成してくれる
		login 
		telnet        <-- 要チェック v6サポートされたないぽい
		ftp        <-- 要チェック v6サポートされたないぽい
		su
		rcp 
		rsh 
		otp 
		otpprint 
		afslog
		--------- 以下謎
		kgetcred 
		mk_cmds 
		pfrom 
		pagsh 
		string2key 

	マスターデータベースは /var/heimdal/heimdal.db
	ディレクトリ名 /var/heimdal がコード埋め込みなっているので
	場所は変更できないぽい。
	コンパイル時に/lib/hdb/hdb.hのHDB_DB_DIRを書き換えれば可能。
	ただしマスターキーの場所はkstash(8)のオプションで変更可能。

	gethostname(3)で返されるFQDNからホスト部を取った文字列が
	デフォルトのREALMに設定される。
	kstash(8)はオプションでREALMを指定できないので、
	ホスト名をFQDNぽく適切に設定しないと動かない。

o kdcの設定ファイル
	Kerberosの設定を記述する。ライブラリの挙動やREALMの情報も
	設定できるので KDC以外のホストでも設定すべき。
	デフォルトは /etc/krb5.conf

	設定ファイルの文法チェックには verify_krb5_conf(8) が使える。

	ticket_lifetime

	renew_lifetime
		lifetime の指定には以下の単位が使える。

		year, month, week, day, hour, h, minute, m, second, s, unlimited

o 動作の準備


	kadmin(8)を使って新規REALM ZOOを作る。

	# kadmin -l
	kadmin> init ZOO
	Realm max ticket life [unlimited]:
	Realm max renewable ticket life [unlimited]:

	この時点で /var/heimdal/heimdal.dbには以下のPRINCIPALが出来る。
		default@ZOO
		krbtgt/ZOO@ZOO             # TGS_REQ用PRINCIPAL
		kadmin/admin@ZOO           # kadmind(8)用PRINCIPAL
		kadmin/hprop@ZOO           # incremental propagation用
		kadmin/changepw@ZOO        #
		changepw/kerberos@ZOO      #

	# dump
	で、現在の heimdal.dbの内容を確認できる。
	XXX 出力ファイルが 644なんだけどいいのかな?

	新規PRINCIPALとして doggy@ZOOを追加。
	kadmin> add doggy@ZOO
	Max ticket life [1 day]:
	Max renewable life [1 week]:
	Principal expiration time [never]:
	Password expiration time [never]:
	Attributes []:
	doggy@ZOO's Password: 
	Verifying - doggy@ZOO's Password: 

	パスワード無しでも作れる

	同じく kitty@ZOOを追加。
	kadmin> add kitty@ZOO
	Max ticket life [1 day]:
	Max renewable life [1 week]:
	Principal expiration time [never]:
	Password expiration time [never]:
	Attributes []:
	kitty@ZOO's Password: 
	Verifying - kitty@ZOO's Password: 

	master.dbのリストを見るには listコマンドを使う
	kadmin> list -l doggy@ZOO
	               Principal: doggy@ZOO
	       Principal expires: never
	        Password expires: never
	    Last password change: never
	         Max ticket life: 1 day
	      Max renewable life: 1 week
	                    Kvno: 1
	                   Mkvno: 0
	                  Policy: none
	   Last successful login: never
	       Last failed login: never
	      Failed login count: 0
	           Last modified: 2004-05-26 02:37:35 UTC
	                Modifier: kadmin/admin@ZOO
	              Attributes: 
	Keytypes(salttype[(salt-value)]): des-cbc-crc(pw-salt), des-cbc-md4(pw-salt), des-cbc-md5(pw-salt), des3-cbc-sha1(pw-salt)

o keytabの作成
	Kerberosアプリケーションは何度か鍵を使う場面がある。
	この時にユーザが入力しなくてもいいようにファイルに鍵を保存できる。
	このファイルを keytabと呼ぶ。

	keytabを作るには kadmin(8)の ext_keytabコマンドを使う。
	以下は doggy@ZOOの鍵を doggy.ktabに保存している。

	# kadmin -l
	kadmin> ext_keytab -k doggy.ktab doggy@ZOO

	ユーザは鍵を入力する必要がないのでランダムな数値を
	鍵として使う事が望ましいだろう。この場合、addコマンドに
	-r を付ける。
	以下は piggy@ZOOを-rオプション付きで追加しpiggy.ktabに鍵を保存している。
	doggy@ZOOを追加した時のように Passwordを聞いて来ない。

	kadmin> add -r piggy@ZOO
	Max ticket life [1 day]:
	Max renewable life [1 week]:
	Principal expiration time [never]:
	Password expiration time [never]:
	Attributes []:
	kadmin> ext_keytab -k piggy.ktab piggy@ZOO

	keytabには複数のPRINCIPALの鍵を保存できる。
	例えば、以下のようにすると doggy,kitty,piggyの鍵がzoo.ktabに保存される。
	kadmin> ext_keytab -k zoo.ktab doggy@ZOO
	kadmin> ext_keytab -k zoo.ktab kitty@ZOO
	kadmin> ext_keytab -k zoo.ktab piggy@ZOO

	keytabは ktutil(1)を使って管理できる。
	keytabをダンプするには listコマンドを使う。

	% root ktutil -v -k zoo.ktab list
	zoo.ktab:

	Vno  Type           Principal  Date      
	  1  des3-cbc-sha1  doggy@ZOO  2004-01-29
	  1  des-cbc-md5    doggy@ZOO  2004-01-29
	  1  des-cbc-md4    doggy@ZOO  2004-01-29
	  1  des-cbc-crc    doggy@ZOO  2004-01-29
	  1  des3-cbc-sha1  kitty@ZOO  2004-01-29
	  1  des-cbc-md5    kitty@ZOO  2004-01-29
	  1  des-cbc-md4    kitty@ZOO  2004-01-29
	  1  des-cbc-crc    kitty@ZOO  2004-01-29
	  1  des-cbc-crc    piggy@ZOO  2004-01-29
	  1  des-cbc-md4    piggy@ZOO  2004-01-29
	  1  des-cbc-md5    piggy@ZOO  2004-01-29
	  1  des3-cbc-sha1  piggy@ZOO  2004-01-29

	鍵を変更すると Vnoが増加する

o HostAddressesについて
	ローカルにKDCを起動して実験していたが kinit(8)で以下のメッセージを出して失敗していた。

	% kinit doggy@ZOO
	kinit: krb5_get_init_creds: Incorrect net address

	/var/log/auth.log には以下の行
	Bad address list requested -- doggy@ZOO

	127.0.0.1 に対して AS_REQを投げていたのでIPヘッダに 127.0.0.1が、
	AS_REQのHostAddresses部に別のIPアドレス(この時は lnc0についた
	10.21.32.176) が入っていて、この2つをKDCで比較していたのが原因。

	解決策はいくつかあるけど処事情により1番を採用。

	1. Kerberosアプリケーションではアドレスを添付しない
		/etc/krb5.conf
		[appdefaults]
			no-addresses = 1

	2. KDCでアドレスチェックをしない
		/etc/krb5.conf
		[kdc]
			check-ticket-addresses = 0

	3. アプリケーションのデフォルト動作として 127.0.0.1 を添付する
		/etc/krb5.conf
		[libdefaults]
			extra_addresses = 127.0.0.1

	4. kinitのオプションで127.0.0.1 を添付する
		% kinit -a 127.0.0.0.1

o KDCサーバの起動

	# /usr/local/libexec/kdc &

o KDCサーバの多重化

	MASTERとして位置付けたサーバと何台かのSLAVEサーバを作る。
	MASTERサーバのマスターデータベースをSLAVEサーバにコピーする。

	MASTERサーバ
	# /usr/local/libexec/ipropd-master &

	SLAVEサーバ
	# /usr/local/libexec/ipropd-slave (master hostname) &

	これはマスターデータベースの変更分だけをコピーする仕組み
	Incremental Propagation と呼ばれる。
	この仕組みとは違い毎回全てをコピーする hprop もある。

o TGTの取得

	PRINCIPAL doggy@ZOOのためのTGTを取得しCredentialをファイル
	doggy.ccに格納する。 このファイルを Credential Cacheと呼ぶ。
	これには kinit(1)を使う。
	kinit(1)は krb5_cc_initialize()をコールするので Cacheには
	PRINCIPALに対して1つのチケットしか入らない事に注意。

	% kinit -c doggy.cc doggy@ZOO
	doggy@ZOO's Password: 

	同様に kitty@ZOOのTGTを kitty.ccに格納する。

	% kinit -c kitty.cc kitty@ZOO
	kitty@ZOO's Password: 

	keytabを使うとPasswordの入力を省略できる。
	% kinit -c kitty.cc -t kitty.ktab kitty@ZOO

	klist(1)でキャッシュの内容を確認できる。

	% klist -vc doggy.cc
	Credentials cache: FILE:doggy.cc
		Principal: doggy@ZOO
	    Cache version: 4

	Server: krbtgt/ZOO@ZOO
	Ticket etype: des3-cbc-sha1, kvno 1
	Auth time:  Jan 29 14:34:33 2004
	End time:   Jan 30 00:34:33 2004
	Ticket flags: initial
	Addresses: 

	% klist -vc kitty.cc 
	Credentials cache: FILE:kitty.cc
		Principal: kitty@ZOO
	    Cache version: 4

	Server: krbtgt/ZOO@ZOO
	Ticket etype: des3-cbc-sha1, kvno 1
	Auth time:  Jan 29 14:35:52 2004
	End time:   Jan 30 00:35:52 2004
	Ticket flags: initial
	Addresses: 

o キャッシュの破棄

	Credentialは有効期限まで使えるので破棄したい場合は kdestroy(1)を使う。
	単にファイルを消してるぽい。コード未確認。

	% kdestroy -c piggy.ktab

o PRINCIPALの鍵の変更
	kadminを使う場合
	kadmin> passwd -r doggy@ZOO

	XXX
	# /usr/local/libexec/kpasswdd &
	% kpasswd piggy@ZOO

o libkrb5 メモ

krb5_sendauth()問題その1
	KRB_AP_REQを送信するときに krb5_net_write()をコールするが、
	この関数は send()を使っているので connected socketじゃないと
	エラーになる。
	krb5_contextに相手のIPアドレスを入れられるのでそれを使ってsendto()
	してみては?

	send(strlen("KRB5_SENDAUTH_V1.0"))
	send("KRB5_SENDAUTH_V1.0")
	send(strlen(application version))
	send(application version)
	recv(reply)
	send(AP_REQ)
	recv(reply)
	if (AP_OPTS_MUTUAL_REQUIRED)
		recv(AP_REP)

krb5_recvauth()問題
	krb5_sendauth()は KRB5_SENDAUTH_VERSIONを送信した後に
	krb5_net_read()を呼び出しサーバからの応答を待つ。
	この時にサーバからの応答がないと krb5_net_read()でブロックして
	しまう。
	if (KRB5_RECVAUTH_IGNORE_VERSION)
		read(len, 4)
		read(version, len)
	recv(len, 4)
	recv(application version, len)
	send(0, 1)
	recv(AP_REQ)
	send(0, 4)
	if (AP_OPTS_MUTUAL_REQUIRED)
		send(AP_REP)
	
krb5_net_read()問題
	引数にバッファ bufと読みだしたい長さ lenを渡している。
	読みだしが lenに達しないと無限ループになってしまう。
	Kerberosのネゴシエーションの途中で何らかの問題起きると
	プログラムはブロックしてしまう。
	これを回避するには signal()を使うしかない。の???