天天看點

LDAP/SASL/GSSAPI/Kerberos程式設計API(3)--LDAP/SASL

一.安裝開發庫

客戶機:vmcln(192.168.1.20)

root@vmcln:/# apt-get install libkrb5-dev libldap2-dev libsasl2-dev

二.SASL/GSSAPI(不含krb5庫)

1.源代碼

//源檔案名:testsasl.c

2.解析

1)回調函數

代碼#1處直接傳回LDAP_SUCCESS即可,ldap_sasl_interactive_bind_s就成功.這個是最簡單能成功的回調函數代碼,應該也是很不規範.至于如何編寫完善的回調函數代碼,其實我也不懂

可傳回的值還有:

LDAP_PARAM_ERROR、LDAP_OTHER、LDAP_PARAM_ERROR,這幾個傳回錯誤,ldap_sasl_interactive_bind_s便失敗.

2)

代碼#2處不能直接填LDAP_SUCCESS或NULL,否則會出錯提示'Error: Local error',必需填為回調函數

3)跟蹤測試

ldap_sasl_interactive_bind_s的GSSAPI會讀取/etc/krb5.conf和票據/tmp/krb5cc_1000

3.編譯

linlin@vmcln:~$ gcc -o testsasl testsasl.c -lldap -llber -lsasl2

4.運作

linlin@vmcln:~$ ls /tmp

(空)

linlin@vmcln:~$ ./testsasl

SASL/GSSAPI authentication started 開始SASL/GSSAPI認證

Error: Local error

Additional info: SASL(-1): generic failure: GSSAPI Error: Unspecified GSS failure. Minor code may provide more information (No Kerberos credentials available (default cache: FILE:/tmp/krb5cc_1000))

linlin@vmcln:~$

失敗,提示沒有有效票據,找不到/tmp/krb5cc_1000

SASL的GSSAPI不提供互動輸入密碼,而是直接讀取票據.我們可用kinit來先生成票據,下面krblinlin是Kerberos使用者主體

linlin@vmcln:~$ kinit --no-forwardable krblinlin

[email protected]'s Password: 輸入密碼

因為我的KDC服務端是heimdal,需帶參數no-forwardable.如果服務端是mit則不用帶參數no-forwardable

krb5cc_1000

已見到票據,由kinit生成

再次執行,已成功讀出ldap目錄資訊

SASL/GSSAPI authentication started

SASL username: [email protected] 這裡可以看到krblinlin使用者,即testsasl程式裡不傳入使用者、密碼,而是通過票據

SASL SSF: 56

SASL data security layer installed.

Success!

dn: ou=dns,dc=ctp,dc=net

attribute = objectClass

attribute = ou

...

三.SASL/GSSAPI + krb5

基于上面代碼增加krb5使用者輸入密碼登入認證,目的是程式自己生成票據

//源檔案名:testldapkrb.c

1)代碼#11處,票據可以是

MEMORY : 程序記憶體裡的票據,随程序的結束而銷毀

FILE : 檔案系統上的票據,不會自動銷毀,即使系統重新開機,是以要防範票據在生存期内被複制走盜用登入.當然票據通常是放在/tmp下,一般系統的啟動/關閉都會清理/tmp目錄.

2)本文将測試MEMORY、FILE兩種類型票據

在#11處分别編譯

'MEMORY '的名稱随便定,我不清楚是否有規範的名稱

'FILE'指定/tmp/krb5cc_1000作為票據檔案.目前登入使用者linlin的uid為1000,在目前使用者運作有關的SASL/GSSAPI,預設票據路徑檔案/tmp/krb5cc_1000.是以上面程式為配合預設路徑檔案,寫死了 "FILE:/tmp/krb5cc_1000" 與之保持一緻,運作指令就不用再指定環境變量(除非程式生成票據與預設路徑檔案不一緻)

3)代碼#13處不會銷毀票據(包括記憶體票據、檔案票據)

1)編譯成記憶體票據執行檔案testldapkrb_m

#11處,按"MEMORY:dhcp_ld_krb5_cc"編譯

linlin@vmcln:~$ gcc -o testldapkrb_m testldapkrb.c -lldap -llber -lsasl2 -lkrb5

2)編譯成檔案票據執行檔案testldapkrb_f

#11處,改為"FILE:/tmp/krb5cc_1000"編譯

linlin@vmcln:~$ gcc -o testldapkrb_f testldapkrb.c -lldap -llber -lsasl2 -lkrb5

4.服務端環境

krb5+ldap+dns在同一台機器上vmkdc(192.168.1.11)

機器名:vmkdc

ldap應用服務主體:ldap/[email protected]

5.在客戶機上運作

1)用戶端環境

平台 : debian 11

sasl的modules: mit或heimdal

2)安裝mit庫

root@vmcln:/# apt-get install libsasl2-modules-gssapi-mit

或者下載下傳debian 9 libsasl2-modules-gssapi-heimdal軟體包安裝到debian 11

3)客戶機配置

在客戶機vmcln(192.168.1.20)上是按#12處連接配接LDAP伺服器192.168.1.11

為了比對ldap應用服務ldap/vmkdc主體,/etc/hosts要增加一行如下:

192.168.1.11 vmkdc

linlin@vmcln:~$ cat /etc/resolv.conf

domain ctp.net

search ctp.net

nameserver 192.168.1.11

顯示指定了DNS伺服器192.168.1.11

linlin@vmcln:~$ cat /etc/krb5.conf

[libdefaults]

default_realm = CTP.NET

/etc/krb5.conf僅配置default_realm 這個就可,KDC位址可通過DNS的SRV(服務)資源記錄獲得

4)執行票據是記憶體類型的指令

在指令之前要設環境變量,完整指令如下:

linlin@vmcln:~$ KRB5CCNAME="MEMORY:dhcp_ld_krb5_cc" ./testldapkrb_m

Successfully store creds

SASL username: [email protected]

已成功

5)執行票據是檔案類型的指令

無需設環境變量,指令生成票據和SASL/GSSAPI預設都是/tmp/krb5cc_1000

linlin@vmcln:~$ ./testldapkrb_f

begin get init creds password

get init creds password OK

Successfully store creds 生成了票據

可見在/tmp生成了票據krb5cc_1000檔案

再用ldap工具測試

linlin@vmcln:~$ ldapwhoami -Y GSSAPI -h 192.168.1.11

dn:uid=krblinlin,cn=gssapi,cn=auth

可見ldapwhoami用到上面程式生成的票據krb5cc_1000已成功

加-d調試

linlin@vmcln:~$ ldapwhoami -Y GSSAPI -h 192.168.1.11 -d -1

ldap_create

ldap_url_parse_ext(ldap://192.168.1.11)

ldap_sasl_interactive_bind: user selected: GSSAPI

ldap_int_sasl_bind: GSSAPI

ldap_new_connection 1 1 0

ldap_int_open_connection

ldap_connect_to_host: TCP 192.168.1.11:389

ldap_new_socket: 3

ldap_prepare_socket: 3

ldap_connect_to_host: Trying 192.168.1.11:389

ldap_pvt_connect: fd: 3 tm: -1 async: 0

attempting to connect:

connect success

ldap_int_sasl_open: host=vmkdc 注意此處主機名,應該是反向解析192.168.1.11出vmkdc

ldap_sasl_bind

ldap_send_initial_request

ldap_send_server_request

ber_scanf fmt ({it) ber:

檢視vmkdc的kdc log

TGS-REQ [email protected] from IPv4:192.168.1.20 for ldap/[email protected] [canonicalize]

注意日志出現的'ldap/[email protected]',應該是用戶端通過/etc/hosts反向解析ldap伺服器(192.168.1.11,本實驗是krb5和ldap在同一台機器vmkdc上)拼接出ldap/[email protected],并與ldap的應用服務主體(ldap/[email protected])一緻

四.跟蹤調試

上面是已先給出正常運作的結論,是我逐漸調試後的結果.實際調試的過程是很淩亂,下面整理總結第三章節(SASL/GSSAPI + krb5)調試過程

1.debian 10版本以上(新版)libsasl2-modules-gssapi-heimdal的BUG

1)新版libsasl2-modules-gssapi-heimdal

測試記憶體票據

Additional info: SASL(-1): generic failure: GSSAPI Error: Miscellaneous failure (see text) (Did not find a plugin for ccache_ops)

記憶體票據失敗,根據所提示的'Did not find a plugin for ccache_ops'檢視源碼、搜尋網上資料,找不到ccache_ops問題所在

測試檔案票據

檔案票據正常

說明新版libsasl2-modules-gssapi-heimdal對記憶體票據有問題,不是生成的記憶體票據有問題,而是讀取記憶體票據的功能有BUG

2)用新版libsasl2-modules-gssapi-mit或者debian 9(舊版)libsasl2-modules-gssapi-heimdal代替新版libsasl2-modules-gssapi-heimdal,讀取記憶體票據已正常

root@vmcln:/home/linlin#

SASL SSF: 256

2.環境變量

1)不設環境變量

1.1)/etc/krb5.conf預設的default_ccache_name

linlin@vmcln:~$ ./testldapkrb_m

Successfully store creds 到此步是通過krb5密碼認證成功的,并已生成了票據在記憶體

SASL/GSSAPI authentication started 開始LDAP/SASL/GSSAPI認證,在此失敗,提示找不到票據

Additional info: SASL(-1): generic failure: GSSAPI Error: Miscellaneous failure (see text) (get-principal lstat(/tmp/krb5cc_1000))

根據錯誤提示,無環境變量,SASL/GSSAPI 預設是/tmp/krb5cc_1000

1.2)/etc/krb5.conf添加一行 default_ccache_name = KEYRING:persistent:%{uid}

{uid}表示登入使用者的uid号,如目前使用者linlin的uid為1000

Additional info: SASL(-1): generic failure: GSSAPI Error: Unspecified GSS failure. Minor code may provide more information (No Kerberos credentials available (default cache: KEYRING:persistent:1000))

從錯誤提示已說明是按krb5.conf的配置KEYRING:persistent:1000作SASL/GSSAPI預設值,也說明無配置default_ccache_name,krb5.conf的預設是FILE:/tmp/krb5cc_1000

2)運作之前設環境變量

也可在程式源碼裡開頭設定環境變量,這樣執行指令就不需輸入環境變量

int ret = setenv("KRB5CCNAME", "MEMORY:dhcp_ld_krb5_cc", 1);

我沒去研究/etc/krb5.conf裡能否配置default_ccache_name為程序記憶體票據以便不需設環境變量,即使能也不妥,因為其它的krb5程式會用到/etc/krb5.conf,

況且通常的krb5程式可以不需自己生成票據,隻要有别的程式(如kinit)提供生成票據即可.如果default_ccache_name為程序記憶體票據,那豈不是其它的krb5程式必須自己生成票據到記憶體

3)小結:

SASL/GSSAPI應該是優先讀取環境變量KRB5CCNAME,然後才是/etc/krb5.conf

3.用戶端無配置/etc/krb5.conf

Successfully store creds 到此步是通過krb5密碼認證成功的,并已生成了票據

SASL/GSSAPI authentication started 開始LDAP/SASL/GSSAPI認證,在此失敗,提示找不到 realm

Additional info: SASL(-1): generic failure: GSSAPI Error: Unspecified GSS failure. Minor code may provide more information (Configuration file does not specify default realm)

LDAP/SASL/GSSAPI API能否在程式裡指定realm,我沒去探究,在此就按提示配置/etc/krb5.conf解決

4.關于ldap/[email protected]還是ldap/[email protected]的比對問題

本文實驗環境krb5+ldap+dns在同一台機器vmkdc上

1)在客戶機vmcln(192.168.1.20)上測試

1.1)檢視配置

或者

即/etc/hosts不再添加一行 192.168.1.11 vmkdc 解析主機,而是完全由dns解析,DNS伺服器正向解析vmkdc、vmkdc.ctp.net為192.168.1.11,反向解析192.168.1.11為vmkdc.ctp.net

1.2)測試

Additional info: SASL(-1): generic failure: GSSAPI Error: Unspecified GSS failure. Minor code may provide more information (Server not found in Kerberos database)

失敗

ldap_sasl_interactive_bind_s: Local error (-2)

additional info: SASL(-1): generic failure: GSSAPI Error: Unspecified GSS failure. Minor code may provide more information (Server not found in Kerberos database)

檢視kdc log

2019-12-16T08:17:08 Got TGS FAST request

2019-12-16T08:17:08 TGS-REQ [email protected] from IPv4:192.168.1.20 for ldap/[email protected] [canonicalize]

2019-12-16T08:17:08 Searching referral for vmkdc.ctp.net

2019-12-16T08:17:08 Server not found in database: ldap/[email protected]: no such entry found in hdb 找不到主體

2019-12-16T08:17:08 Failed building TGS-REP to IPv4:192.168.1.20

注意日志出現的是'ldap/[email protected]',應該是在客戶機通過DNS伺服器反向解析192.168.1.11出vmkdc.ctp.net,并拼接出ldap/[email protected],但在KDC并沒有該主體

1.3)往vmkdc添加ldap/vmkdc.ctp.net主體再測試

到伺服器

root@vmkdc:~# kadmin -l

新增

kadmin> add -r ldap/vmkdc.ctp.net

導出到krb5.keytab

kadmin> ext -k /etc/ldap/krb5.keytab ldap/vmkdc.ctp.net

應該是追加而不是覆寫,檢視可見包含了ldap/[email protected]和ldap/[email protected]

回到客戶機

Error: Invalid credentials

Additional info: SASL(-13): authentication failure: GSSAPI Failure: gss_accept_sec_context

krb5.keytab裡雖有ldap/[email protected],但仍失敗

2019-12-17T01:52:16 TGS-REQ [email protected] from IPv4:192.168.1.20 for ldap/[email protected] [canonicalize]

2019-12-17T01:52:16 TGS-REQ authtime: 2019-12-17T01:52:16 starttime: 2019-12-17T01:52:16 endtime: 2019-12-18T01:52:16 renew till: unset

2019-12-17T01:52:16 sending 639 bytes to IPv4:192.168.1.20

雖然在KDC已找到了ldap/[email protected],但可能是ldap應用服務是使用ldap/[email protected]主體,兩者不一緻導緻失敗

2)在伺服器vmkdc(192.168.1.11)本機上測試

/etc/hosts的内容

127.0.0.1 localhost

2.1)代碼#12處為連接配接到位址192.168.1.11

linlin@vmkdc:~$ KRB5CCNAME="MEMORY:dhcp_ld_krb5_cc" ./testldapkrb_m

linlin@vmkdc:~$

2019-12-17T00:46:30 TGS-REQ [email protected] from IPv4:127.0.0.1 for ldap/[email protected]

2019-12-17T00:46:30 Server not found in database: ldap/[email protected]: no such entry found in hdb

注意日志出現的'ldap/[email protected]',在KDC不存在

2.2)代碼#12處改為 ldap_initialize(&ld,"ldap://127.0.0.1/"),即連接配接本地伺服器

重新編譯為testldapkrb_m_local

當/etc/resolv.conf為空

或設nameserver 127.0.0.1

或設nameserver 192.168.2.3 不同KDC伺服器網段随便不存在的位址

linlin@vmkdc:~$ KRB5CCNAME="MEMORY:dhcp_ld_krb5_cc" ./testldapkrb_m_local

2019-12-17T00:35:17 TGS-REQ [email protected] from IPv4:127.0.0.1 for ldap/[email protected] [canonicalize]

2019-12-17T00:35:17 TGS-REQ authtime: 2019-12-17T00:35:17 starttime: 2019-12-17T00:35:17 endtime: 2019-12-18T00:35:17 renew till: unset

2019-12-17T00:35:17 sending 623 bytes to IPv4:127.0.0.1

注意日志已是'ldap/[email protected]'

将resolv.conf改為vmkdc同網段但不存在的位址

nameserver 192.168.1.55

再次運作./testldapkrb_m_local也成功,但很慢很慢

為何連接配接本地127.0.0.1時SASL/GSSAPI卻能拼接出正确的ldap/vmkdc ?

檢視主機名

linlin@vmkdc:~$ hostname

vmkdc

是不是連接配接本地127.0.0.1時SASL/GSSAPI根據hostname結果?

臨時改主機名

linlin@vmkdc:~$ su

root@vmkdc:/home/linlin# hostname vmabc.efg

root@vmkdc:/home/linlin# exit

檢視主機名結果為vmabc.efg

vmabc.efg

2019-12-17T01:34:59 TGS-REQ [email protected] from IPv4:127.0.0.1 for ldap/[email protected] [canonicalize]

注意日志出現的'ldap/[email protected]',确實根據hostname結果(而非主機名稱解析dns或/etc/hosts)

五.SASL/GSSAPI客戶程式總結:

1.對于讀取票據位置,環境變量KRB5CCNAME優先,然後才按/etc/krb5.conf

2.

連接配接本地127.0.0.1時,SASL/GSSAPI根據hostname結果

連接配接遠端位址192.168.1.11時,SASL/GSSAPI根據dns或/etc/hosts反向解析出名稱拼接出ldap/xxx.yyy,或者解析不到就拼接出ldap/localhost

3.客戶機拼接出的app/xxx.yyy和應用伺服器的app/xxx.yyy要比對一緻

4.在規劃域、主機名時,盡可能伺服器、客戶機、應用服務主體、DNS解析都設為全限定名,這樣可省卻不可預知的陷阱.

即本文最好設定伺服器全限定名vmkdc.ctp.net,應用服務主體ldap/[email protected],這樣客戶機/etc/hosts就不需添加192.168.1.11 vmkdc一行

六.後記

本人水準有限,文中難免有錯漏,更多的/etc/krb5.conf的參數配置,請參考有關MIT的文檔.

我在MIT文檔查閱到

rdns = false

will disable reverse DNS lookup on clients. The default setting is “true”.

不知設 rdns = false 禁用反向解析是不是可以解決客戶機和應用伺服器主體不比對問題?留待各位讀者探索