📄 ppolicy.c
字号:
int rc; Entry *pe = NULL;#if 0 const char *text;#endif memset( pp, 0, sizeof(PassPolicy) ); pp->ad = slap_schema.si_ad_userPassword; /* Users can change their own password by default */ pp->pwdAllowUserChange = 1; if ((a = attr_find( e->e_attrs, ad_pwdPolicySubentry )) == NULL) { /* * entry has no password policy assigned - use default */ vals = &pi->def_policy; if ( !vals->bv_val ) goto defaultpol; } else { vals = a->a_nvals; if (vals[0].bv_val == NULL) { Debug( LDAP_DEBUG_ANY, "ppolicy_get: NULL value for policySubEntry\n", 0, 0, 0 ); goto defaultpol; } } op->o_bd->bd_info = (BackendInfo *)on->on_info; rc = be_entry_get_rw( op, vals, NULL, NULL, 0, &pe ); op->o_bd->bd_info = (BackendInfo *)on; if ( rc ) goto defaultpol;#if 0 /* Only worry about userPassword for now */ if ((a = attr_find( pe->e_attrs, ad_pwdAttribute ))) slap_bv2ad( &a->a_vals[0], &pp->ad, &text );#endif if ( ( a = attr_find( pe->e_attrs, ad_pwdMinAge ) ) && lutil_atoi( &pp->pwdMinAge, a->a_vals[0].bv_val ) != 0 ) goto defaultpol; if ( ( a = attr_find( pe->e_attrs, ad_pwdMaxAge ) ) && lutil_atoi( &pp->pwdMaxAge, a->a_vals[0].bv_val ) != 0 ) goto defaultpol; if ( ( a = attr_find( pe->e_attrs, ad_pwdInHistory ) ) && lutil_atoi( &pp->pwdInHistory, a->a_vals[0].bv_val ) != 0 ) goto defaultpol; if ( ( a = attr_find( pe->e_attrs, ad_pwdCheckQuality ) ) && lutil_atoi( &pp->pwdCheckQuality, a->a_vals[0].bv_val ) != 0 ) goto defaultpol; if ( ( a = attr_find( pe->e_attrs, ad_pwdMinLength ) ) && lutil_atoi( &pp->pwdMinLength, a->a_vals[0].bv_val ) != 0 ) goto defaultpol; if ( ( a = attr_find( pe->e_attrs, ad_pwdMaxFailure ) ) && lutil_atoi( &pp->pwdMaxFailure, a->a_vals[0].bv_val ) != 0 ) goto defaultpol; if ( ( a = attr_find( pe->e_attrs, ad_pwdGraceAuthNLimit ) ) && lutil_atoi( &pp->pwdGraceAuthNLimit, a->a_vals[0].bv_val ) != 0 ) goto defaultpol; if ( ( a = attr_find( pe->e_attrs, ad_pwdExpireWarning ) ) && lutil_atoi( &pp->pwdExpireWarning, a->a_vals[0].bv_val ) != 0 ) goto defaultpol; if ( ( a = attr_find( pe->e_attrs, ad_pwdFailureCountInterval ) ) && lutil_atoi( &pp->pwdFailureCountInterval, a->a_vals[0].bv_val ) != 0 ) goto defaultpol; if ( ( a = attr_find( pe->e_attrs, ad_pwdLockoutDuration ) ) && lutil_atoi( &pp->pwdLockoutDuration, a->a_vals[0].bv_val ) != 0 ) goto defaultpol; if ( ( a = attr_find( pe->e_attrs, ad_pwdCheckModule ) ) ) { strncpy( pp->pwdCheckModule, a->a_vals[0].bv_val, sizeof(pp->pwdCheckModule) ); pp->pwdCheckModule[sizeof(pp->pwdCheckModule)-1] = '\0'; } if ((a = attr_find( pe->e_attrs, ad_pwdLockout ))) pp->pwdLockout = bvmatch( &a->a_nvals[0], &slap_true_bv ); if ((a = attr_find( pe->e_attrs, ad_pwdMustChange ))) pp->pwdMustChange = bvmatch( &a->a_nvals[0], &slap_true_bv ); if ((a = attr_find( pe->e_attrs, ad_pwdAllowUserChange ))) pp->pwdAllowUserChange = bvmatch( &a->a_nvals[0], &slap_true_bv ); if ((a = attr_find( pe->e_attrs, ad_pwdSafeModify ))) pp->pwdSafeModify = bvmatch( &a->a_nvals[0], &slap_true_bv ); op->o_bd->bd_info = (BackendInfo *)on->on_info; be_entry_release_r( op, pe ); op->o_bd->bd_info = (BackendInfo *)on; return;defaultpol: Debug( LDAP_DEBUG_TRACE, "ppolicy_get: using default policy\n", 0, 0, 0 ); return;}static intpassword_scheme( struct berval *cred, struct berval *sch ){ int e; assert( cred != NULL ); if (sch) { sch->bv_val = NULL; sch->bv_len = 0; } if ((cred->bv_len == 0) || (cred->bv_val == NULL) || (cred->bv_val[0] != '{')) return LDAP_OTHER; for(e = 1; cred->bv_val[e] && cred->bv_val[e] != '}'; e++); if (cred->bv_val[e]) { int rc; rc = lutil_passwd_scheme( cred->bv_val ); if (rc) { if (sch) { sch->bv_val = cred->bv_val; sch->bv_len = e; } return LDAP_SUCCESS; } } return LDAP_OTHER;}static intcheck_password_quality( struct berval *cred, PassPolicy *pp, LDAPPasswordPolicyError *err, Entry *e ){ int rc = LDAP_SUCCESS, ok = LDAP_SUCCESS; char *ptr = cred->bv_val; struct berval sch; assert( cred != NULL ); assert( pp != NULL ); if ((cred->bv_len == 0) || (pp->pwdMinLength > cred->bv_len)) { rc = LDAP_CONSTRAINT_VIOLATION; if ( err ) *err = PP_passwordTooShort; return rc; } /* * We need to know if the password is already hashed - if so * what scheme is it. The reason being that the "hash" of * {cleartext} still allows us to check the password. */ rc = password_scheme( cred, &sch ); if (rc == LDAP_SUCCESS) { if ((sch.bv_val) && (strncasecmp( sch.bv_val, "{cleartext}", sch.bv_len ) == 0)) { /* * We can check the cleartext "hash" */ ptr = cred->bv_val + sch.bv_len; } else { /* everything else, we can't check */ if (pp->pwdCheckQuality == 2) { rc = LDAP_CONSTRAINT_VIOLATION; if (err) *err = PP_insufficientPasswordQuality; return rc; } /* * We can't check the syntax of the password, but it's not * mandatory (according to the policy), so we return success. */ return LDAP_SUCCESS; } } rc = LDAP_SUCCESS; if (pp->pwdCheckModule[0]) {#if SLAPD_MODULES lt_dlhandle mod; const char *err; if ((mod = lt_dlopen( pp->pwdCheckModule )) == NULL) { err = lt_dlerror(); Debug(LDAP_DEBUG_ANY, "check_password_quality: lt_dlopen failed: (%s) %s.\n", pp->pwdCheckModule, err, 0 ); ok = LDAP_OTHER; /* internal error */ } else { int (*prog)( char *passwd, char **text, Entry *ent ); if ((prog = lt_dlsym( mod, "check_password" )) == NULL) { err = lt_dlerror(); Debug(LDAP_DEBUG_ANY, "check_password_quality: lt_dlsym failed: (%s) %s.\n", pp->pwdCheckModule, err, 0 ); ok = LDAP_OTHER; } else { char *txt = NULL; ldap_pvt_thread_mutex_lock( &chk_syntax_mutex ); ok = prog( cred->bv_val, &txt, e ); ldap_pvt_thread_mutex_unlock( &chk_syntax_mutex ); if (ok != LDAP_SUCCESS) { Debug(LDAP_DEBUG_ANY, "check_password_quality: module error: (%s) %s.[%d]\n", pp->pwdCheckModule, txt ? txt : "", ok ); free(txt); } } lt_dlclose( mod ); }#else Debug(LDAP_DEBUG_ANY, "check_password_quality: external modules not " "supported. pwdCheckModule ignored.\n", 0, 0, 0);#endif /* SLAPD_MODULES */ } if (ok != LDAP_SUCCESS) { rc = LDAP_CONSTRAINT_VIOLATION; if (err) *err = PP_insufficientPasswordQuality; } return rc;}static intparse_pwdhistory( struct berval *bv, char **oid, time_t *oldtime, struct berval *oldpw ){ char *ptr; struct berval nv, npw; int i, j; assert (bv && (bv->bv_len > 0) && (bv->bv_val) && oldtime && oldpw ); if ( oid ) { *oid = 0; } *oldtime = (time_t)-1; BER_BVZERO( oldpw ); ber_dupbv( &nv, bv ); /* first get the time field */ for ( i = 0; (i < nv.bv_len) && (nv.bv_val[i] != '#'); i++ ) ; if ( i == nv.bv_len ) { goto exit_failure; /* couldn't locate the '#' separator */ } nv.bv_val[i++] = '\0'; /* terminate the string & move to next field */ ptr = nv.bv_val; *oldtime = parse_time( ptr ); if (*oldtime == (time_t)-1) { goto exit_failure; } /* get the OID field */ for (ptr = &(nv.bv_val[i]); (i < nv.bv_len) && (nv.bv_val[i] != '#'); i++ ) ; if ( i == nv.bv_len ) { goto exit_failure; /* couldn't locate the '#' separator */ } nv.bv_val[i++] = '\0'; /* terminate the string & move to next field */ if ( oid ) { *oid = ber_strdup( ptr ); } /* get the length field */ for ( ptr = &(nv.bv_val[i]); (i < nv.bv_len) && (nv.bv_val[i] != '#'); i++ ) ; if ( i == nv.bv_len ) { goto exit_failure; /* couldn't locate the '#' separator */ } nv.bv_val[i++] = '\0'; /* terminate the string & move to next field */ oldpw->bv_len = strtol( ptr, NULL, 10 ); if (errno == ERANGE) { goto exit_failure; } /* lastly, get the octets of the string */ for ( j = i, ptr = &(nv.bv_val[i]); i < nv.bv_len; i++ ) ; if ( i - j != oldpw->bv_len) { goto exit_failure; /* length is wrong */ } npw.bv_val = ptr; npw.bv_len = oldpw->bv_len; ber_dupbv( oldpw, &npw ); ber_memfree( nv.bv_val ); return LDAP_SUCCESS;exit_failure:; if ( oid && *oid ) { ber_memfree(*oid); *oid = NULL; } if ( oldpw->bv_val ) { ber_memfree( oldpw->bv_val); BER_BVZERO( oldpw ); } ber_memfree( nv.bv_val ); return LDAP_OTHER;}static voidadd_to_pwd_history( pw_hist **l, time_t t, struct berval *oldpw, struct berval *bv ){ pw_hist *p, *p1, *p2; if (!l) return; p = ch_malloc( sizeof( pw_hist )); p->pw = *oldpw; ber_dupbv( &p->bv, bv ); p->t = t; p->next = NULL; if (*l == NULL) { /* degenerate case */ *l = p; return; } /* * advance p1 and p2 such that p1 is the node before the * new one, and p2 is the node after it */ for (p1 = NULL, p2 = *l; p2 && p2->t <= t; p1 = p2, p2=p2->next ); p->next = p2; if (p1 == NULL) { *l = p; return; } p1->next = p;}#ifndef MAX_PWD_HISTORY_SZ#define MAX_PWD_HISTORY_SZ 1024#endif /* MAX_PWD_HISTORY_SZ */static voidmake_pwd_history_value( char *timebuf, struct berval *bv, Attribute *pa ){ char str[ MAX_PWD_HISTORY_SZ ]; int nlen; snprintf( str, MAX_PWD_HISTORY_SZ, "%s#%s#%lu#", timebuf, pa->a_desc->ad_type->sat_syntax->ssyn_oid, (unsigned long) pa->a_nvals[0].bv_len ); str[MAX_PWD_HISTORY_SZ-1] = 0; nlen = strlen(str); /* * We have to assume that the string is a string of octets, * not readable characters. In reality, yes, it probably is * a readable (ie, base64) string, but we can't count on that * Hence, while the first 3 fields of the password history * are definitely readable (a timestamp, an OID and an integer * length), the remaining octets of the actual password * are deemed to be binary data. */ AC_MEMCPY( str + nlen, pa->a_nvals[0].bv_val, pa->a_nvals[0].bv_len ); nlen += pa->a_nvals[0].bv_len; bv->bv_val = ch_malloc( nlen + 1 ); AC_MEMCPY( bv->bv_val, str, nlen ); bv->bv_val[nlen] = '\0'; bv->bv_len = nlen;}static voidfree_pwd_history_list( pw_hist **l ){ pw_hist *p; if (!l) return; p = *l; while (p) { pw_hist *pp = p->next; free(p->pw.bv_val); free(p->bv.bv_val); free(p); p = pp; } *l = NULL;}typedef struct ppbind { slap_overinst *on; int send_ctrl; LDAPControl **oldctrls; Modifications *mod; LDAPPasswordPolicyError pErr; PassPolicy pp;} ppbind;static voidctrls_cleanup( Operation *op, SlapReply *rs, LDAPControl **oldctrls ){ int n; assert( rs->sr_ctrls != NULL ); assert( rs->sr_ctrls[0] != NULL ); for ( n = 0; rs->sr_ctrls[n]; n++ ) { if ( rs->sr_ctrls[n]->ldctl_oid == LDAP_CONTROL_PASSWORDPOLICYRESPONSE ) { ch_free( rs->sr_ctrls[n]->ldctl_value.bv_val ); ch_free( rs->sr_ctrls[n] ); rs->sr_ctrls[n] = (LDAPControl *)(-1); break; } } if ( rs->sr_ctrls[n] == NULL ) { /* missed? */ } op->o_tmpfree( rs->sr_ctrls, op->o_tmpmemctx ); rs->sr_ctrls = oldctrls;}static intppolicy_ctrls_cleanup( Operation *op, SlapReply *rs ){ ppbind *ppb = op->o_callback->sc_private; if ( ppb->send_ctrl ) { ctrls_cleanup( op, rs, ppb->oldctrls ); } return SLAP_CB_CONTINUE;}static intppolicy_bind_response( Operation *op, SlapReply *rs ){ ppbind *ppb = op->o_callback->sc_private; slap_overinst *on = ppb->on; Modifications *mod = ppb->mod, *m; int pwExpired = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -