そこで、slapd自身を改造して、APOP認証と、 sambaやpptpで用いられるNTLM認証を受け付けるようにします。
% apt-get source slapd % cd openldap2-2.0.23/libraries/liblutil % vi passwd.c ... { {0, NULL}, NULL, NULL } }; #include "md4.h" static int chk_ntlm( const struct pw_scheme *scheme, const struct berval *passwd, const struct berval *cred ); static int chk_apop( const struct pw_scheme *scheme, const struct berval *passwd, const struct berval *cred ); static const struct pw_scheme cred_schemes[] = { { {sizeof("{NTLM}")-1, "{NTLM}"}, chk_ntlm, NULL }, { {sizeof("{APOP}")-1, "{APOP}"}, chk_apop, NULL }, { {0, NULL}, NULL, NULL } }; static const struct pw_scheme *get_scheme( const char* scheme ) { ... /* only free the berval structure as the bv_val points * into passwd->bv_val */ ber_memfree( p ); return rc; } } } for( i=0; cred_schemes[i].name.bv_val != NULL; i++ ) { if( cred_schemes[i].chk_fn ) { struct berval *p = passwd_scheme( &cred_schemes[i], cred, schemes ); if( p != NULL ) { int rc = (cred_schemes[i].chk_fn)( &cred_schemes[i], passwd, p ); ber_memfree( p ); return rc; } } } #ifdef SLAPD_CLEARTEXT if( is_allowed_scheme("{CLEARTEXT}", schemes ) ) { ... /* PASSWORD CHECK ROUTINES */ static void desenc( const unsigned char src[8], unsigned char dst[8], const unsigned char key[7]) { int i; char des[64]; for(i= 7; i<64; i+=8) des[i]= 0; for(i= 0; i<56; i++) des[i+i/7]=key[i/8]>>(7-i%8)&1; setkey(des); for(i= 0; i<64; i++) des[i]= src[i/8]>>(7-i%8)&1; encrypt(des, 0); for(i= 0; i<8; i++) { int j; unsigned char c= 0; for(j= 0; j<8; j++) c= c<<1|des[i*8+j]; dst[i]= c; } } static int chk_ntlm( const struct pw_scheme *sc, const struct berval * passwd, const struct berval * cred ) { int i; unsigned char *buf = NULL; MD4_CTX MD4context; unsigned char pdigest[21]; unsigned char *bcred = NULL; int rc; char des[64]; /* base64 un-encode cred */ bcred = (unsigned char *) ber_memalloc( (size_t) ( LUTIL_BASE64_DECODE_LEN(cred->bv_len) + 1) ); if( bcred == NULL )return -1; rc = lutil_b64_pton(cred->bv_val, bcred, cred->bv_len); if ( rc != 24+8 ) { ber_memfree(bcred); return -1; } buf= ber_memalloc( passwd->bv_len<7 ? 14 : passwd->bv_len*2 ); if(buf==NULL) { ber_memfree(bcred); return -1; } /* make md4 digest from passwd*/ for(i= 0; i<passwd->bv_len; i++ ) { buf[i*2]= passwd->bv_val[i]; buf[i*2+1]= 0; } MD4Init(&MD4context); MD4Update(&Mamp;D4context, buf, passwd->bv_len*2 * 8 ); MD4Final(pdigest, &MD4context); for(i= 16; i<21; i++) pdigest[i]= 0; for(i= 0; i<3; i++) { desenc(bcred+24, buf, pdigest+i*7); if(memcmp(bcred+i*8, buf, 8)) break; } if(i<3) { /* check for lanman pass */ for(i= 0; i<passwd->bv_len; i++) { rc= passwd->bv_val[i]; if(rc>='a'&&rc<='z') rc-= 0x20; buf[i]= rc; } for(; i<14; i++) buf[i]= 0; desenc("KGS!@#$%", pdigest, buf); desenc("KGS!@#$%", pdigest+8, buf+7); for(i= 0; i<3; i++) { desenc(bcred+24, buf, pdigest+i*7); if(memcmp(bcred+i*8, buf, 8)) break; } } ber_memfree(bcred); ber_memfree(buf); return (i<3); }; static int chk_apop( const struct pw_scheme *sc, const struct berval * passwd, const struct berval * cred ) { lutil_MD5_CTX MD5context; unsigned char MD5digest[LUTIL_MD5_BYTES]; int rc; unsigned char *orig_cred = NULL; /* base64 un-encode cred */ orig_cred = (unsigned char *) ber_memalloc( (size_t) ( LUTIL_BASE64_DECODE_LEN(cred->bv_len) + 1) ); if( orig_cred == NULL ) return -1; rc = lutil_b64_pton(cred->bv_val, orig_cred, cred->bv_len); if ( rc < sizeof(MD5digest) ) { ber_memfree(orig_cred); return -1; } /* make response from salt */ lutil_MD5Init(&MD5context); lutil_MD5Update(&MD5context, orig_cred+sizeof(MD5digest), rc-sizeof(MD5digest)); lutil_MD5Update(&MD5context, (const unsigned char *) passwd->bv_val, passwd->bv_len ); lutil_MD5Final(MD5digest, &MD5context); /* compare */ rc = memcmp((char *)orig_cred, (char *)MD5digest, sizeof(MD5digest)); ber_memfree(orig_cred); return rc ? 1 : 0; } ...
コンパイルにあたってはmd4.cも必要ですので、 pppdのソースツリーなどから持ってきます。 (pppdの改造の項参照) なお、md4.cのソースによっては上記のMD4Updateの第3引数がバイト単位のものと ビット単位のものがあるので必要に応じて編集してください。
% cp /PPP-SOURCE/pppd/md4.c . % cp /PPP-SOURCE/pppd/md4.h . % vi Makefile.in ... SRCS = base64.c debug.c entropy.c sasl.c signal.c \ md5.c md4.c passwd.c sha1.c getpass.c lockf.c utils.c sockpair.c \ @LIBSRCS@ $(@PLAT@_SRCS) OBJS = base64.o debug.o entropy.o sasl.o signal.o \ md5.o md4.o passwd.o sha1.o getpass.o lockf.o utils.o sockpair.o \ @LIBOBJS@ $(@PLAT@_OBJS) ...コンパイルしてインストールします。
# cd openldap2-2.0.23 # dpkg-buildpackage (この時に出るコンパイルに必要なパッケージ群はapt-get installで取ってきます。) # cd .. # dpkg -i libldap2_2.0.23-xxx.deb # dpkg -i slapd_2.0.23-xxx.debライブラリの変更ですが入れ替えるのは/usr/sbin/slapdだけなので、
% debian/rules build # /etc/init.d/slapd stop # cd debian/build/servers/slapd/slapd # strip slapd; cp slapd /usr/sbin/slapd # /etc/init.d/slapd startでもかまいません。いずれにせよslapdをdselect等でhold-stateにしておくか、 apt-get upgradeがslapdにかかったら 最新のソースで再コンパイルして入れ替えるのを忘れずに。