⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 smbk5pwd.c

📁 ldap服务器源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* smbk5pwd.c - Overlay for managing Samba and Heimdal passwords *//* $OpenLDAP: pkg/ldap/contrib/slapd-modules/smbk5pwd/smbk5pwd.c,v 1.1.2.10 2006/12/15 15:39:35 hyc Exp $ *//* * Copyright 2004-2005 by Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * <http://www.OpenLDAP.org/license.html>. *//* * Support for sambaPwdMustChange added by Marco D'Ettorre. * Support for table-driven configuration added by Pierangelo Masarati. * * The conditions of the OpenLDAP Public License apply. */#include <portable.h>#ifndef SLAPD_OVER_SMBK5PWD#define SLAPD_OVER_SMBK5PWD SLAPD_MOD_DYNAMIC#endif#ifdef SLAPD_OVER_SMBK5PWD#include <slap.h>#include <ac/errno.h>#include <ac/string.h>#include "config.h"#ifdef DO_KRB5#include <lber.h>#include <lber_pvt.h>#include <lutil.h>/* make ASN1_MALLOC_ENCODE use our allocator */#define malloc	ch_malloc#include <krb5.h>#include <kadm5/admin.h>#include <hdb.h>#ifndef HDB_INTERFACE_VERSION#define	HDB_MASTER_KEY_SET	master_key_set#else#define	HDB_MASTER_KEY_SET	hdb_master_key_set#endifstatic krb5_context context;static void *kadm_context;static kadm5_config_params conf;static HDB *db;static AttributeDescription *ad_krb5Key;static AttributeDescription *ad_krb5KeyVersionNumber;static AttributeDescription *ad_krb5PrincipalName;static ObjectClass *oc_krb5KDCEntry;#endif#ifdef DO_SAMBA#include <openssl/des.h>#include <openssl/md4.h>#include "ldap_utf8.h"static AttributeDescription *ad_sambaLMPassword;static AttributeDescription *ad_sambaNTPassword;static AttributeDescription *ad_sambaPwdLastSet;static AttributeDescription *ad_sambaPwdMustChange;static ObjectClass *oc_sambaSamAccount;#endif/* Per-instance configuration information */typedef struct smbk5pwd_t {	unsigned	mode;#define	SMBK5PWD_F_KRB5		(0x1U)#define	SMBK5PWD_F_SAMBA	(0x2U)#define SMBK5PWD_DO_KRB5(pi)	((pi)->mode & SMBK5PWD_F_KRB5)#define SMBK5PWD_DO_SAMBA(pi)	((pi)->mode & SMBK5PWD_F_SAMBA)#ifdef DO_KRB5	/* nothing yet */#endif#ifdef DO_SAMBA	/* How many seconds before forcing a password change? */	time_t	smb_must_change;#endif} smbk5pwd_t;static const unsigned SMBK5PWD_F_ALL	=	0#ifdef DO_KRB5	| SMBK5PWD_F_KRB5#endif#ifdef DO_SAMBA	| SMBK5PWD_F_SAMBA#endif;static int smbk5pwd_modules_init( smbk5pwd_t *pi );#ifdef DO_SAMBAstatic const char hex[] = "0123456789abcdef";/* From liblutil/passwd.c... */static void lmPasswd_to_key(	const char *lmPasswd,	des_cblock *key){	const unsigned char *lpw = (const unsigned char *)lmPasswd;	unsigned char *k = (unsigned char *)key;	/* make room for parity bits */	k[0] = lpw[0];	k[1] = ((lpw[0]&0x01)<<7) | (lpw[1]>>1);	k[2] = ((lpw[1]&0x03)<<6) | (lpw[2]>>2);	k[3] = ((lpw[2]&0x07)<<5) | (lpw[3]>>3);	k[4] = ((lpw[3]&0x0F)<<4) | (lpw[4]>>4);	k[5] = ((lpw[4]&0x1F)<<3) | (lpw[5]>>5);	k[6] = ((lpw[5]&0x3F)<<2) | (lpw[6]>>6);	k[7] = ((lpw[6]&0x7F)<<1);	des_set_odd_parity( key );}#define MAX_PWLEN 256#define	HASHLEN	16static void hexify(	const char in[HASHLEN],	struct berval *out){	int i;	char *a;	unsigned char *b;	out->bv_val = ch_malloc(HASHLEN*2 + 1);	out->bv_len = HASHLEN*2;	a = out->bv_val;	b = (unsigned char *)in;	for (i=0; i<HASHLEN; i++) {		*a++ = hex[*b >> 4];		*a++ = hex[*b++ & 0x0f];	}	*a++ = '\0';}static void lmhash(	struct berval *passwd,	struct berval *hash){	char UcasePassword[15];	des_cblock key;	des_key_schedule schedule;	des_cblock StdText = "KGS!@#$%";	des_cblock hbuf[2];	strncpy( UcasePassword, passwd->bv_val, 14 );	UcasePassword[14] = '\0';	ldap_pvt_str2upper( UcasePassword );	lmPasswd_to_key( UcasePassword, &key );	des_set_key_unchecked( &key, schedule );	des_ecb_encrypt( &StdText, &hbuf[0], schedule , DES_ENCRYPT );	lmPasswd_to_key( &UcasePassword[7], &key );	des_set_key_unchecked( &key, schedule );	des_ecb_encrypt( &StdText, &hbuf[1], schedule , DES_ENCRYPT );	hexify( (char *)hbuf, hash );}static void nthash(	struct berval *passwd,	struct berval *hash){	/* Windows currently only allows 14 character passwords, but	 * may support up to 256 in the future. We assume this means	 * 256 UCS2 characters, not 256 bytes...	 */	char hbuf[HASHLEN];	MD4_CTX ctx;	if (passwd->bv_len > MAX_PWLEN*2)		passwd->bv_len = MAX_PWLEN*2;			MD4_Init( &ctx );	MD4_Update( &ctx, passwd->bv_val, passwd->bv_len );	MD4_Final( (unsigned char *)hbuf, &ctx );	hexify( hbuf, hash );}#endif /* DO_SAMBA */#ifdef DO_KRB5static int smbk5pwd_op_cleanup(	Operation *op,	SlapReply *rs ){	slap_callback *cb;	/* clear out the current key */	ldap_pvt_thread_pool_setkey( op->o_threadctx, smbk5pwd_op_cleanup,		NULL, NULL );	/* free the callback */	cb = op->o_callback;	op->o_callback = cb->sc_next;	op->o_tmpfree( cb, op->o_tmpmemctx );	return 0;}static int smbk5pwd_op_bind(	Operation *op,	SlapReply *rs ){	/* If this is a simple Bind, stash the Op pointer so our chk	 * function can find it. Set a cleanup callback to clear it	 * out when the Bind completes.	 */	if ( op->oq_bind.rb_method == LDAP_AUTH_SIMPLE ) {		slap_callback *cb;		ldap_pvt_thread_pool_setkey( op->o_threadctx, smbk5pwd_op_cleanup, op,			NULL );		cb = op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx );		cb->sc_cleanup = smbk5pwd_op_cleanup;		cb->sc_next = op->o_callback;		op->o_callback = cb;	}	return SLAP_CB_CONTINUE;}static LUTIL_PASSWD_CHK_FUNC k5key_chk;static LUTIL_PASSWD_HASH_FUNC k5key_hash;static const struct berval k5key_scheme = BER_BVC("{K5KEY}");/* This password scheme stores no data in the userPassword attribute * other than the scheme name. It assumes the invoking entry is a * krb5KDCentry and compares the passed-in credentials against the * krb5Key attribute. The krb5Key may be multi-valued, but they are * simply multiple keytypes generated from the same input string, so * only the first value needs to be compared here. * * Since the lutil_passwd API doesn't pass the Entry object in, we * have to fetch it ourselves in order to get access to the other * attributes. We accomplish this with the help of the overlay's Bind * function, which stores the current Operation pointer in thread-specific * storage so we can retrieve it here. The Operation provides all * the necessary context for us to get Entry from the database. */static int k5key_chk(	const struct berval *sc,	const struct berval *passwd,	const struct berval *cred,	const char **text ){	void *ctx;	Operation *op;	int rc;	Entry *e;	Attribute *a;    krb5_error_code ret;    krb5_keyblock key;    krb5_salt salt;	hdb_entry ent;	/* Find our thread context, find our Operation */	ctx = ldap_pvt_thread_pool_context();	if ( ldap_pvt_thread_pool_getkey( ctx, smbk5pwd_op_cleanup, (void **)&op, NULL ) ||		!op )		return LUTIL_PASSWD_ERR;	rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );	if ( rc != LDAP_SUCCESS ) return LUTIL_PASSWD_ERR;	rc = LUTIL_PASSWD_ERR;	do {		size_t l;		Key ekey = {0};		a = attr_find( e->e_attrs, ad_krb5PrincipalName );		if (!a ) break;		memset( &ent, 0, sizeof(ent) );		ret = krb5_parse_name(context, a->a_vals[0].bv_val, &ent.principal);		if ( ret ) break;		krb5_get_pw_salt( context, ent.principal, &salt );		krb5_free_principal( context, ent.principal );		a = attr_find( e->e_attrs, ad_krb5Key );		if ( !a ) break;		ent.keys.len = 1;		ent.keys.val = &ekey;		decode_Key((unsigned char *) a->a_vals[0].bv_val,			(size_t) a->a_vals[0].bv_len, &ent.keys.val[0], &l);		if ( db->HDB_MASTER_KEY_SET )			hdb_unseal_keys( context, db, &ent );		krb5_string_to_key_salt( context, ekey.key.keytype, cred->bv_val,			salt, &key );		krb5_free_salt( context, salt );		if ( memcmp( ekey.key.keyvalue.data, key.keyvalue.data,			key.keyvalue.length ) == 0 ) rc = LUTIL_PASSWD_OK;		krb5_free_keyblock_contents( context, &key );		krb5_free_keyblock_contents( context, &ekey.key );	} while(0);	be_entry_release_r( op, e );	return rc;}static int k5key_hash(	const struct berval *scheme,	const struct berval *passwd,	struct berval *hash,	const char **text ){	ber_dupbv( hash, (struct berval *)&k5key_scheme );	return LUTIL_PASSWD_OK;}#endif /* DO_KRB5 */static int smbk5pwd_exop_passwd(	Operation *op,	SlapReply *rs ){	int rc;	req_pwdexop_s *qpw = &op->oq_pwdexop;	Entry *e;	Modifications *ml;	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;	smbk5pwd_t *pi = on->on_bi.bi_private;	/* Not the operation we expected, pass it on... */	if ( ber_bvcmp( &slap_EXOP_MODIFY_PASSWD, &op->ore_reqoid ) ) {		return SLAP_CB_CONTINUE;	}	op->o_bd->bd_info = (BackendInfo *)on->on_info;	rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );	if ( rc != LDAP_SUCCESS ) return rc;#ifdef DO_KRB5	/* Kerberos stuff */	do {		krb5_error_code ret;		hdb_entry ent;		struct berval *keys;		int kvno, i;		Attribute *a;		if ( !SMBK5PWD_DO_KRB5( pi ) ) break;		if ( !is_entry_objectclass(e, oc_krb5KDCEntry, 0 ) ) break;		a = attr_find( e->e_attrs, ad_krb5PrincipalName );		if ( !a ) break;		memset( &ent, 0, sizeof(ent) );		ret = krb5_parse_name(context, a->a_vals[0].bv_val, &ent.principal);		if ( ret ) break;		a = attr_find( e->e_attrs, ad_krb5KeyVersionNumber );		kvno = 0;		if ( a ) {			if ( lutil_atoi( &kvno, a->a_vals[0].bv_val ) != 0 ) {				Debug( LDAP_DEBUG_ANY, "%s smbk5pwd EXOP: "					"dn=\"%s\" unable to parse krb5KeyVersionNumber=\"%s\"\n",					op->o_log_prefix, e->e_name.bv_val, a->a_vals[0].bv_val );			}		} else {			/* shouldn't happen, this is a required attr */			Debug( LDAP_DEBUG_ANY, "%s smbk5pwd EXOP: "				"dn=\"%s\" missing krb5KeyVersionNumber\n",				op->o_log_prefix, e->e_name.bv_val, 0 );		}		ret = _kadm5_set_keys(kadm_context, &ent, qpw->rs_new.bv_val);		hdb_seal_keys(context, db, &ent);		krb5_free_principal( context, ent.principal );		keys = ch_malloc( (ent.keys.len + 1) * sizeof(struct berval));		for (i = 0; i < ent.keys.len; i++) {			unsigned char *buf;			size_t len;			ASN1_MALLOC_ENCODE(Key, buf, len, &ent.keys.val[i], &len, ret);			if (ret != 0)				break;						keys[i].bv_val = (char *)buf;			keys[i].bv_len = len;		}		BER_BVZERO( &keys[i] );		_kadm5_free_keys(kadm_context, ent.keys.len, ent.keys.val);		if ( i != ent.keys.len ) {			ber_bvarray_free( keys );			break;		}		ml = ch_malloc(sizeof(Modifications));		if (!qpw->rs_modtail) qpw->rs_modtail = &ml->sml_next;		ml->sml_next = qpw->rs_mods;		qpw->rs_mods = ml;		ml->sml_desc = ad_krb5Key;		ml->sml_op = LDAP_MOD_REPLACE;#ifdef SLAP_MOD_INTERNAL		ml->sml_flags = SLAP_MOD_INTERNAL;#endif		ml->sml_values = keys;		ml->sml_nvalues = NULL;				ml = ch_malloc(sizeof(Modifications));		ml->sml_next = qpw->rs_mods;		qpw->rs_mods = ml;				ml->sml_desc = ad_krb5KeyVersionNumber;		ml->sml_op = LDAP_MOD_REPLACE;#ifdef SLAP_MOD_INTERNAL		ml->sml_flags = SLAP_MOD_INTERNAL;#endif		ml->sml_values = ch_malloc( 2 * sizeof(struct berval));		ml->sml_values[0].bv_val = ch_malloc( 64 );		ml->sml_values[0].bv_len = sprintf(ml->sml_values[0].bv_val,			"%d", kvno+1 );		BER_BVZERO( &ml->sml_values[1] );		ml->sml_nvalues = NULL;	} while ( 0 );#endif /* DO_KRB5 */#ifdef DO_SAMBA	/* Samba stuff */	if ( SMBK5PWD_DO_SAMBA( pi ) && is_entry_objectclass(e, oc_sambaSamAccount, 0 ) ) {		struct berval *keys;		ber_len_t j,l;		wchar_t *wcs, wc;		char *c, *d;		struct berval pwd;				/* Expand incoming UTF8 string to UCS4 */		l = ldap_utf8_chars(qpw->rs_new.bv_val);		wcs = ch_malloc((l+1) * sizeof(wchar_t));		ldap_x_utf8s_to_wcs( wcs, qpw->rs_new.bv_val, l );				/* Truncate UCS4 to UCS2 */		c = (char *)wcs;		for (j=0; j<l; j++) {			wc = wcs[j];			*c++ = wc & 0xff;			*c++ = (wc >> 8) & 0xff;		}		*c++ = 0;		pwd.bv_val = (char *)wcs;		pwd.bv_len = l * 2;		ml = ch_malloc(sizeof(Modifications));		if (!qpw->rs_modtail) qpw->rs_modtail = &ml->sml_next;		ml->sml_next = qpw->rs_mods;		qpw->rs_mods = ml;		keys = ch_malloc( 2 * sizeof(struct berval) );		BER_BVZERO( &keys[1] );

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -