From 1df6d762690390958cadd5c52458309138071d75 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Thu, 7 Oct 2004 04:07:17 +0000 Subject: [PATCH] Add ppolicy_hash_cleartext config keyword, hash Adds as well as Modifies. Changed check_pw_quality callback to pass entry's Attributes in final arg. --- doc/man/man5/slapo-ppolicy.5 | 18 +++++++--- servers/slapd/overlays/ppolicy.c | 56 ++++++++++++++++++++++++++++---- 2 files changed, 62 insertions(+), 12 deletions(-) diff --git a/doc/man/man5/slapo-ppolicy.5 b/doc/man/man5/slapo-ppolicy.5 index e2418ca27b..88df7b3147 100644 --- a/doc/man/man5/slapo-ppolicy.5 +++ b/doc/man/man5/slapo-ppolicy.5 @@ -37,6 +37,12 @@ Specify the DN of the pwdPolicy object to use when no specific policy is set on a given user's entry. If there is no specific policy for an entry and no default is given, then no policies will be enforced. .TP +.B ppolicy_hash_cleartext +Specify that cleartext passwords present in Add and Modify requests should +be hashed before being stored in the database. This violates the X.500 +information model, but may be needed to compensate for LDAP clients that +don't use the PasswordModify exop to manage passwords. +.TP .B ppolicy_use_lockout A client will always receive an LDAP .B InvalidCredentials @@ -419,7 +425,7 @@ function prototype: .RS 4 int .I check_password -(char *pPasswd, char **ppErrStr, void *pArg); +(char *pPasswd, char **ppErrStr, Attribute *pAttrs); .RE The .B pPasswd @@ -427,9 +433,10 @@ parameter contains the clear-text user password, the .B ppErrStr parameter contains a double pointer that allows the function to return human-readable details about any error it encounters. -The -.B pArg -parameter is currently unused. +The optional +.B pAttr +parameter, if non-NULL, carries a list of the attributes for the +entry whose password is being checked. If .B ppErrStr is NULL, then @@ -441,7 +448,8 @@ indicates that the password is unacceptable. If the password is unacceptable, the server will return an error to the client, and .B ppErrStr may be used to return a human-readable textual explanation of the -error. +error. The error string must be dynamically allocated as it will +be free()'d by slapd. .LP .RS 4 ( 1.3.6.1.4.1.4754.1.99.1 diff --git a/servers/slapd/overlays/ppolicy.c b/servers/slapd/overlays/ppolicy.c index 958da9ee6b..845aee641f 100644 --- a/servers/slapd/overlays/ppolicy.c +++ b/servers/slapd/overlays/ppolicy.c @@ -49,6 +49,7 @@ typedef struct pp_info { struct berval def_policy; /* DN of default policy subentry */ int use_lockout; /* send AccountLocked result? */ + int hash_passwords; /* transparently hash cleartext pwds */ } pp_info; /* Our per-connection info - note, it is not per-instance, it is @@ -439,7 +440,7 @@ password_scheme( struct berval *cred, struct berval *sch ) } static int -check_password_quality( struct berval *cred, PassPolicy *pp, LDAPPasswordPolicyError *err ) +check_password_quality( struct berval *cred, PassPolicy *pp, LDAPPasswordPolicyError *err, Entry *e ) { int rc = LDAP_SUCCESS, ok = LDAP_SUCCESS; char *ptr = cred->bv_val; @@ -498,7 +499,7 @@ check_password_quality( struct berval *cred, PassPolicy *pp, LDAPPasswordPolicyE pp->pwdCheckModule, err, 0 ); ok = LDAP_OTHER; /* internal error */ } else { - int (*prog)( char *passwd, char **text, void *arg ); + int (*prog)( char *passwd, char **text, Attribute *attrs ); if ((prog = lt_dlsym( mod, "check_password" )) == NULL) { err = lt_dlerror(); @@ -511,7 +512,7 @@ check_password_quality( struct berval *cred, PassPolicy *pp, LDAPPasswordPolicyE char *txt = NULL; ldap_pvt_thread_mutex_lock( &chk_syntax_mutex ); - ok = prog( cred->bv_val, &txt, NULL ); + ok = prog( cred->bv_val, &txt, e ? e->e_attrs : NULL ); ldap_pvt_thread_mutex_unlock( &chk_syntax_mutex ); if (txt) { Debug(LDAP_DEBUG_ANY, @@ -1073,9 +1074,11 @@ ppolicy_add( SlapReply *rs ) { slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + pp_info *pi = on->on_bi.bi_private; PassPolicy pp; int pw; Attribute *pa; + const char *txt; if ( ppolicy_restrict( op, rs ) != SLAP_CB_CONTINUE ) return rs->sr_err; @@ -1089,7 +1092,7 @@ ppolicy_add( * then we need to check that the password fits in with the * security policy for the new entry. */ - ppolicy_get( op, op->oq_add.rs_e, &pp ); + ppolicy_get( op, op->ora_e, &pp ); if (pp.pwdCheckQuality > 0 && !be_isroot( op )) { struct berval *bv = &(pa->a_vals[0]); int rc, i, send_ctrl = 0; @@ -1103,7 +1106,7 @@ ppolicy_add( break; } } - rc = check_password_quality( bv, &pp, &pErr ); + rc = check_password_quality( bv, &pp, &pErr, op->ora_e ); if (rc != LDAP_SUCCESS) { op->o_bd->bd_info = (BackendInfo *)on->on_info; if ( send_ctrl ) { @@ -1117,6 +1120,37 @@ ppolicy_add( send_ldap_error( op, rs, rc, "Password fails quality checking policy" ); return rs->sr_err; } + /* + * A controversial bit. We hash cleartext + * passwords provided via add and modify operations + * You're not really supposed to do this, since + * the X.500 model says "store attributes" as they + * get provided. By default, this is what we do + * + * But if the hash_passwords flag is set, we hash + * any cleartext password attribute values via the + * default password hashing scheme. + */ + if ((pi->hash_passwords) && + (password_scheme( &(pa->a_vals[0]), NULL ) != LDAP_SUCCESS)) { + struct berval hpw; + + slap_passwd_hash( &(pa->a_vals[0]), &hpw, &txt ); + if (hpw.bv_val == NULL) { + /* + * hashing didn't work. Emit an error. + */ + rs->sr_err = LDAP_OTHER; + rs->sr_text = txt; + send_ldap_error( op, rs, LDAP_OTHER, "Password hashing failed" ); + return rs->sr_err; + } + + memset( pa->a_vals[0].bv_val, 0, pa->a_vals[0].bv_len); + ber_memfree( pa->a_vals[0].bv_val ); + pa->a_vals[0].bv_val = hpw.bv_val; + pa->a_vals[0].bv_len = hpw.bv_len; + } } /* If password aging is in effect, set the pwdChangedTime */ if (( pp.pwdMaxAge || pp.pwdMinAge ) && !be_isupdate( op )) { @@ -1143,6 +1177,7 @@ static int ppolicy_modify( Operation *op, SlapReply *rs ) { slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + pp_info *pi = on->on_bi.bi_private; int i, rc, mod_pw_only, pwmod, pwmop, deladd, hsize = 0; PassPolicy pp; @@ -1387,7 +1422,7 @@ ppolicy_modify( Operation *op, SlapReply *rs ) bv = newpw.bv_val ? &newpw : addmod->sml_values; if (pp.pwdCheckQuality > 0) { - rc = check_password_quality( bv, &pp, &pErr ); + rc = check_password_quality( bv, &pp, &pErr, e ); if (rc != LDAP_SUCCESS) { rs->sr_err = rc; rs->sr_text = "Password fails quality checking policy"; @@ -1593,7 +1628,7 @@ do_modify: * leave it alone. */ - if ((addmod) && !newpw.bv_val && + if ((pi->hash_passwords) && (addmod) && !newpw.bv_val && (password_scheme( &(addmod->sml_values[0]), NULL ) != LDAP_SUCCESS)) { struct berval hpw, bv; @@ -1733,6 +1768,13 @@ ppolicy_config( } pi->use_lockout = 1; return 0; + } else if ( strcasecmp( argv[0], "ppolicy_hash_cleartext" ) == 0 ) { + if ( argc != 1 ) { + fprintf( stderr, "%s: line %d: ppolicy_hash_cleartext " + "takes no arguments\n", fname, lineno ); + return ( 1 ); + } + pi->hash_passwords = 1; } return SLAP_CONF_UNKNOWN; } -- 2.39.5