From: Howard Chu Date: Thu, 13 Jan 2005 09:56:52 +0000 (+0000) Subject: Plug krb5 memleaks, add {K5KEY} passwd check mechanism X-Git-Tag: OPENLDAP_REL_ENG_2_3_BP~401 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=5ebc834c7b5ee527da58a37b574d11efe36e1499;p=openldap Plug krb5 memleaks, add {K5KEY} passwd check mechanism --- diff --git a/contrib/slapd-modules/smbk5pwd/smbk5pwd.c b/contrib/slapd-modules/smbk5pwd/smbk5pwd.c index 1a51598009..e82a73e445 100644 --- a/contrib/slapd-modules/smbk5pwd/smbk5pwd.c +++ b/contrib/slapd-modules/smbk5pwd/smbk5pwd.c @@ -1,7 +1,7 @@ /* smbk5pwd.c - Overlay for managing Samba and Heimdal passwords */ /* $OpenLDAP$ */ /* - * Copyright 2004 by Howard Chu, Symas Corp. + * Copyright 2004-2005 by Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,6 +25,11 @@ #include #ifdef DO_KRB5 +#include +#include +#include +#include + /* make ASN1_MALLOC_ENCODE use our allocator */ #define malloc ch_malloc @@ -155,7 +160,130 @@ static void nthash( } #endif /* DO_SAMBA */ -int smbk5pwd_exop_passwd( +#ifdef DO_KRB5 + +static 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 chk_k5key; +static const struct berval 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 chk_k5key( + 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->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; +} +#endif /* DO_KRB5 */ + +static int smbk5pwd_exop_passwd( Operation *op, SlapReply *rs ) { @@ -220,6 +348,8 @@ int smbk5pwd_exop_passwd( keys[i].bv_val = NULL; keys[i].bv_len = 0; + _kadm5_free_keys(kadm_context, ent.keys.len, ent.keys.val); + if ( i != ent.keys.len ) { ber_bvarray_free( keys ); break; @@ -389,6 +519,12 @@ int smbk5pwd_init() { smbk5pwd.on_bi.bi_type = "smbk5pwd"; smbk5pwd.on_bi.bi_extended = smbk5pwd_exop_passwd; +#ifdef DO_KRB5 + smbk5pwd.on_bi.bi_op_bind = smbk5pwd_op_bind; + + lutil_passwd_add( (struct berval *)&scheme, chk_k5key, NULL ); +#endif + return overlay_register( &smbk5pwd ); }