そこで、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にかかったら 最新のソースで再コンパイルして入れ替えるのを忘れずに。