1/* $OpenLDAP$ */ 2/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 3 * 4 * Copyright 2004-2011 The OpenLDAP Foundation. 5 * Portions Copyright 2004-2005 Howard Chu, Symas Corporation. 6 * Portions Copyright 2004 Hewlett-Packard Company. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted only as authorized by the OpenLDAP 11 * Public License. 12 * 13 * A copy of this license is available in the file LICENSE in the 14 * top-level directory of the distribution or, alternatively, at 15 * <http://www.OpenLDAP.org/license.html>. 16 */ 17/* ACKNOWLEDGEMENTS: 18 * This work was developed by Howard Chu for inclusion in 19 * OpenLDAP Software, based on prior work by Neil Dunbar (HP). 20 * This work was sponsored by the Hewlett-Packard Company. 21 */ 22 23#include "portable.h" 24 25/* This file implements "Password Policy for LDAP Directories", 26 * based on draft behera-ldap-password-policy-09 27 */ 28 29#ifdef SLAPD_OVER_PPOLICY 30 31#include <ldap.h> 32#include "lutil.h" 33#include "slap.h" 34#ifdef SLAPD_MODULES 35#define LIBLTDL_DLL_IMPORT /* Win32: don't re-export libltdl's symbols */ 36#include <ltdl.h> 37#endif 38#include <ac/errno.h> 39#include <ac/time.h> 40#include <ac/string.h> 41#include <ac/ctype.h> 42#include "config.h" 43 44#ifndef MODULE_NAME_SZ 45#define MODULE_NAME_SZ 256 46#endif 47 48/* Per-instance configuration information */ 49typedef struct pp_info { 50 struct berval def_policy; /* DN of default policy subentry */ 51 int use_lockout; /* send AccountLocked result? */ 52 int hash_passwords; /* transparently hash cleartext pwds */ 53 int forward_updates; /* use frontend for policy state updates */ 54} pp_info; 55 56/* Our per-connection info - note, it is not per-instance, it is 57 * used by all instances 58 */ 59typedef struct pw_conn { 60 struct berval dn; /* DN of restricted user */ 61} pw_conn; 62 63static pw_conn *pwcons; 64static int ppolicy_cid; 65static int ov_count; 66 67typedef struct pass_policy { 68 AttributeDescription *ad; /* attribute to which the policy applies */ 69 int pwdMinAge; /* minimum time (seconds) until passwd can change */ 70 int pwdMaxAge; /* time in seconds until pwd will expire after change */ 71 int pwdInHistory; /* number of previous passwords kept */ 72 int pwdCheckQuality; /* 0 = don't check quality, 1 = check if possible, 73 2 = check mandatory; fail if not possible */ 74 int pwdMinLength; /* minimum number of chars in password */ 75 int pwdExpireWarning; /* number of seconds that warning controls are 76 sent before a password expires */ 77 int pwdGraceAuthNLimit; /* number of times you can log in with an 78 expired password */ 79 int pwdLockout; /* 0 = do not lockout passwords, 1 = lock them out */ 80 int pwdLockoutDuration; /* time in seconds a password is locked out for */ 81 int pwdMaxFailure; /* number of failed binds allowed before lockout */ 82 int pwdFailureCountInterval; /* number of seconds before failure 83 counts are zeroed */ 84 int pwdMustChange; /* 0 = users can use admin set password 85 1 = users must change password after admin set */ 86 int pwdAllowUserChange; /* 0 = users cannot change their passwords 87 1 = users can change them */ 88 int pwdSafeModify; /* 0 = old password doesn't need to come 89 with password change request 90 1 = password change must supply existing pwd */ 91 char pwdCheckModule[MODULE_NAME_SZ]; /* name of module to dynamically 92 load to check password */ 93} PassPolicy; 94 95typedef struct pw_hist { 96 time_t t; /* timestamp of history entry */ 97 struct berval pw; /* old password hash */ 98 struct berval bv; /* text of entire entry */ 99 struct pw_hist *next; 100} pw_hist; 101 102/* Operational attributes */ 103static AttributeDescription *ad_pwdChangedTime, *ad_pwdAccountLockedTime, 104 *ad_pwdFailureTime, *ad_pwdHistory, *ad_pwdGraceUseTime, *ad_pwdReset, 105 *ad_pwdPolicySubentry; 106 107static struct schema_info { 108 char *def; 109 AttributeDescription **ad; 110} pwd_OpSchema[] = { 111 { "( 1.3.6.1.4.1.42.2.27.8.1.16 " 112 "NAME ( 'pwdChangedTime' ) " 113 "DESC 'The time the password was last changed' " 114 "EQUALITY generalizedTimeMatch " 115 "ORDERING generalizedTimeOrderingMatch " 116 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 " 117 "SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )", 118 &ad_pwdChangedTime }, 119 { "( 1.3.6.1.4.1.42.2.27.8.1.17 " 120 "NAME ( 'pwdAccountLockedTime' ) " 121 "DESC 'The time an user account was locked' " 122 "EQUALITY generalizedTimeMatch " 123 "ORDERING generalizedTimeOrderingMatch " 124 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 " 125 "SINGLE-VALUE " 126#if 0 127 /* Not until Relax control is released */ 128 "NO-USER-MODIFICATION " 129#endif 130 "USAGE directoryOperation )", 131 &ad_pwdAccountLockedTime }, 132 { "( 1.3.6.1.4.1.42.2.27.8.1.19 " 133 "NAME ( 'pwdFailureTime' ) " 134 "DESC 'The timestamps of the last consecutive authentication failures' " 135 "EQUALITY generalizedTimeMatch " 136 "ORDERING generalizedTimeOrderingMatch " 137 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 " 138 "NO-USER-MODIFICATION USAGE directoryOperation )", 139 &ad_pwdFailureTime }, 140 { "( 1.3.6.1.4.1.42.2.27.8.1.20 " 141 "NAME ( 'pwdHistory' ) " 142 "DESC 'The history of users passwords' " 143 "EQUALITY octetStringMatch " 144 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 " 145 "NO-USER-MODIFICATION USAGE directoryOperation )", 146 &ad_pwdHistory }, 147 { "( 1.3.6.1.4.1.42.2.27.8.1.21 " 148 "NAME ( 'pwdGraceUseTime' ) " 149 "DESC 'The timestamps of the grace login once the password has expired' " 150 "EQUALITY generalizedTimeMatch " 151 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 " 152 "NO-USER-MODIFICATION USAGE directoryOperation )", 153 &ad_pwdGraceUseTime }, 154 { "( 1.3.6.1.4.1.42.2.27.8.1.22 " 155 "NAME ( 'pwdReset' ) " 156 "DESC 'The indication that the password has been reset' " 157 "EQUALITY booleanMatch " 158 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 " 159 "SINGLE-VALUE USAGE directoryOperation )", 160 &ad_pwdReset }, 161 { "( 1.3.6.1.4.1.42.2.27.8.1.23 " 162 "NAME ( 'pwdPolicySubentry' ) " 163 "DESC 'The pwdPolicy subentry in effect for this object' " 164 "EQUALITY distinguishedNameMatch " 165 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 " 166 "SINGLE-VALUE " 167#if 0 168 /* Not until Relax control is released */ 169 "NO-USER-MODIFICATION " 170#endif 171 "USAGE directoryOperation )", 172 &ad_pwdPolicySubentry }, 173 { NULL, NULL } 174}; 175 176/* User attributes */ 177static AttributeDescription *ad_pwdMinAge, *ad_pwdMaxAge, *ad_pwdInHistory, 178 *ad_pwdCheckQuality, *ad_pwdMinLength, *ad_pwdMaxFailure, 179 *ad_pwdGraceAuthNLimit, *ad_pwdExpireWarning, *ad_pwdLockoutDuration, 180 *ad_pwdFailureCountInterval, *ad_pwdCheckModule, *ad_pwdLockout, 181 *ad_pwdMustChange, *ad_pwdAllowUserChange, *ad_pwdSafeModify, 182 *ad_pwdAttribute; 183 184#define TAB(name) { #name, &ad_##name } 185 186static struct schema_info pwd_UsSchema[] = { 187 TAB(pwdAttribute), 188 TAB(pwdMinAge), 189 TAB(pwdMaxAge), 190 TAB(pwdInHistory), 191 TAB(pwdCheckQuality), 192 TAB(pwdMinLength), 193 TAB(pwdMaxFailure), 194 TAB(pwdGraceAuthNLimit), 195 TAB(pwdExpireWarning), 196 TAB(pwdLockout), 197 TAB(pwdLockoutDuration), 198 TAB(pwdFailureCountInterval), 199 TAB(pwdCheckModule), 200 TAB(pwdMustChange), 201 TAB(pwdAllowUserChange), 202 TAB(pwdSafeModify), 203 { NULL, NULL } 204}; 205 206static ldap_pvt_thread_mutex_t chk_syntax_mutex; 207 208enum { 209 PPOLICY_DEFAULT = 1, 210 PPOLICY_HASH_CLEARTEXT, 211 PPOLICY_USE_LOCKOUT 212}; 213 214static ConfigDriver ppolicy_cf_default; 215 216static ConfigTable ppolicycfg[] = { 217 { "ppolicy_default", "policyDN", 2, 2, 0, 218 ARG_DN|ARG_QUOTE|ARG_MAGIC|PPOLICY_DEFAULT, ppolicy_cf_default, 219 "( OLcfgOvAt:12.1 NAME 'olcPPolicyDefault' " 220 "DESC 'DN of a pwdPolicy object for uncustomized objects' " 221 "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL }, 222 { "ppolicy_hash_cleartext", "on|off", 1, 2, 0, 223 ARG_ON_OFF|ARG_OFFSET|PPOLICY_HASH_CLEARTEXT, 224 (void *)offsetof(pp_info,hash_passwords), 225 "( OLcfgOvAt:12.2 NAME 'olcPPolicyHashCleartext' " 226 "DESC 'Hash passwords on add or modify' " 227 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, 228 { "ppolicy_forward_updates", "on|off", 1, 2, 0, 229 ARG_ON_OFF|ARG_OFFSET, 230 (void *)offsetof(pp_info,forward_updates), 231 "( OLcfgOvAt:12.4 NAME 'olcPPolicyForwardUpdates' " 232 "DESC 'Allow policy state updates to be forwarded via updateref' " 233 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, 234 { "ppolicy_use_lockout", "on|off", 1, 2, 0, 235 ARG_ON_OFF|ARG_OFFSET|PPOLICY_USE_LOCKOUT, 236 (void *)offsetof(pp_info,use_lockout), 237 "( OLcfgOvAt:12.3 NAME 'olcPPolicyUseLockout' " 238 "DESC 'Warn clients with AccountLocked' " 239 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, 240 { NULL, NULL, 0, 0, 0, ARG_IGNORED } 241}; 242 243static ConfigOCs ppolicyocs[] = { 244 { "( OLcfgOvOc:12.1 " 245 "NAME 'olcPPolicyConfig' " 246 "DESC 'Password Policy configuration' " 247 "SUP olcOverlayConfig " 248 "MAY ( olcPPolicyDefault $ olcPPolicyHashCleartext $ " 249 "olcPPolicyUseLockout $ olcPPolicyForwardUpdates ) )", 250 Cft_Overlay, ppolicycfg }, 251 { NULL, 0, NULL } 252}; 253 254static int 255ppolicy_cf_default( ConfigArgs *c ) 256{ 257 slap_overinst *on = (slap_overinst *)c->bi; 258 pp_info *pi = (pp_info *)on->on_bi.bi_private; 259 int rc = ARG_BAD_CONF; 260 261 assert ( c->type == PPOLICY_DEFAULT ); 262 Debug(LDAP_DEBUG_TRACE, "==> ppolicy_cf_default\n", 0, 0, 0); 263 264 switch ( c->op ) { 265 case SLAP_CONFIG_EMIT: 266 Debug(LDAP_DEBUG_TRACE, "==> ppolicy_cf_default emit\n", 0, 0, 0); 267 rc = 0; 268 if ( !BER_BVISEMPTY( &pi->def_policy )) { 269 rc = value_add_one( &c->rvalue_vals, 270 &pi->def_policy ); 271 if ( rc ) return rc; 272 rc = value_add_one( &c->rvalue_nvals, 273 &pi->def_policy ); 274 } 275 break; 276 case LDAP_MOD_DELETE: 277 Debug(LDAP_DEBUG_TRACE, "==> ppolicy_cf_default delete\n", 0, 0, 0); 278 if ( pi->def_policy.bv_val ) { 279 ber_memfree ( pi->def_policy.bv_val ); 280 pi->def_policy.bv_val = NULL; 281 } 282 pi->def_policy.bv_len = 0; 283 rc = 0; 284 break; 285 case SLAP_CONFIG_ADD: 286 /* fallthrough to LDAP_MOD_ADD */ 287 case LDAP_MOD_ADD: 288 Debug(LDAP_DEBUG_TRACE, "==> ppolicy_cf_default add\n", 0, 0, 0); 289 if ( pi->def_policy.bv_val ) { 290 ber_memfree ( pi->def_policy.bv_val ); 291 } 292 pi->def_policy = c->value_ndn; 293 ber_memfree( c->value_dn.bv_val ); 294 BER_BVZERO( &c->value_dn ); 295 BER_BVZERO( &c->value_ndn ); 296 rc = 0; 297 break; 298 default: 299 abort (); 300 } 301 302 return rc; 303} 304 305static time_t 306parse_time( char *atm ) 307{ 308 struct lutil_tm tm; 309 struct lutil_timet tt; 310 time_t ret = (time_t)-1; 311 312 if ( lutil_parsetime( atm, &tm ) == 0) { 313 lutil_tm2time( &tm, &tt ); 314 ret = tt.tt_sec; 315 } 316 return ret; 317} 318 319static int 320account_locked( Operation *op, Entry *e, 321 PassPolicy *pp, Modifications **mod ) 322{ 323 Attribute *la; 324 325 assert(mod != NULL); 326 327 if ( !pp->pwdLockout ) 328 return 0; 329 330 if ( (la = attr_find( e->e_attrs, ad_pwdAccountLockedTime )) != NULL ) { 331 BerVarray vals = la->a_nvals; 332 333 /* 334 * there is a lockout stamp - we now need to know if it's 335 * a valid one. 336 */ 337 if (vals[0].bv_val != NULL) { 338 time_t then, now; 339 Modifications *m; 340 341 if (!pp->pwdLockoutDuration) 342 return 1; 343 344 if ((then = parse_time( vals[0].bv_val )) == (time_t)0) 345 return 1; 346 347 now = slap_get_time(); 348 349 if (now < then + pp->pwdLockoutDuration) 350 return 1; 351 352 m = ch_calloc( sizeof(Modifications), 1 ); 353 m->sml_op = LDAP_MOD_DELETE; 354 m->sml_flags = 0; 355 m->sml_type = ad_pwdAccountLockedTime->ad_cname; 356 m->sml_desc = ad_pwdAccountLockedTime; 357 m->sml_next = *mod; 358 *mod = m; 359 } 360 } 361 362 return 0; 363} 364 365/* IMPLICIT TAGS, all context-specific */ 366#define PPOLICY_WARNING 0xa0L /* constructed + 0 */ 367#define PPOLICY_ERROR 0x81L /* primitive + 1 */ 368 369#define PPOLICY_EXPIRE 0x80L /* primitive + 0 */ 370#define PPOLICY_GRACE 0x81L /* primitive + 1 */ 371 372static const char ppolicy_ctrl_oid[] = LDAP_CONTROL_PASSWORDPOLICYRESPONSE; 373 374static LDAPControl * 375create_passcontrol( Operation *op, int exptime, int grace, LDAPPasswordPolicyError err ) 376{ 377 BerElementBuffer berbuf, bb2; 378 BerElement *ber = (BerElement *) &berbuf, *b2 = (BerElement *) &bb2; 379 LDAPControl c = { 0 }, *cp; 380 struct berval bv; 381 382 BER_BVZERO( &c.ldctl_value ); 383 384 ber_init2( ber, NULL, LBER_USE_DER ); 385 ber_printf( ber, "{" /*}*/ ); 386 387 if ( exptime >= 0 ) { 388 ber_init2( b2, NULL, LBER_USE_DER ); 389 ber_printf( b2, "ti", PPOLICY_EXPIRE, exptime ); 390 ber_flatten2( b2, &bv, 1 ); 391 (void)ber_free_buf(b2); 392 ber_printf( ber, "tO", PPOLICY_WARNING, &bv ); 393 ch_free( bv.bv_val ); 394 } else if ( grace > 0 ) { 395 ber_init2( b2, NULL, LBER_USE_DER ); 396 ber_printf( b2, "ti", PPOLICY_GRACE, grace ); 397 ber_flatten2( b2, &bv, 1 ); 398 (void)ber_free_buf(b2); 399 ber_printf( ber, "tO", PPOLICY_WARNING, &bv ); 400 ch_free( bv.bv_val ); 401 } 402 403 if (err != PP_noError ) { 404 ber_printf( ber, "te", PPOLICY_ERROR, err ); 405 } 406 ber_printf( ber, /*{*/ "N}" ); 407 408 if (ber_flatten2( ber, &c.ldctl_value, 0 ) == -1) { 409 return NULL; 410 } 411 cp = op->o_tmpalloc( sizeof( LDAPControl ) + c.ldctl_value.bv_len, op->o_tmpmemctx ); 412 cp->ldctl_oid = (char *)ppolicy_ctrl_oid; 413 cp->ldctl_iscritical = 0; 414 cp->ldctl_value.bv_val = (char *)&cp[1]; 415 cp->ldctl_value.bv_len = c.ldctl_value.bv_len; 416 AC_MEMCPY( cp->ldctl_value.bv_val, c.ldctl_value.bv_val, c.ldctl_value.bv_len ); 417 (void)ber_free_buf(ber); 418 419 return cp; 420} 421 422static LDAPControl ** 423add_passcontrol( Operation *op, SlapReply *rs, LDAPControl *ctrl ) 424{ 425 LDAPControl **ctrls, **oldctrls = rs->sr_ctrls; 426 int n; 427 428 n = 0; 429 if ( oldctrls ) { 430 for ( ; oldctrls[n]; n++ ) 431 ; 432 } 433 n += 2; 434 435 ctrls = op->o_tmpcalloc( sizeof( LDAPControl * ), n, op->o_tmpmemctx ); 436 437 n = 0; 438 if ( oldctrls ) { 439 for ( ; oldctrls[n]; n++ ) { 440 ctrls[n] = oldctrls[n]; 441 } 442 } 443 ctrls[n] = ctrl; 444 ctrls[n+1] = NULL; 445 446 rs->sr_ctrls = ctrls; 447 448 return oldctrls; 449} 450 451static void 452ppolicy_get( Operation *op, Entry *e, PassPolicy *pp ) 453{ 454 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 455 pp_info *pi = on->on_bi.bi_private; 456 Attribute *a; 457 BerVarray vals; 458 int rc; 459 Entry *pe = NULL; 460#if 0 461 const char *text; 462#endif 463 464 memset( pp, 0, sizeof(PassPolicy) ); 465 466 pp->ad = slap_schema.si_ad_userPassword; 467 468 /* Users can change their own password by default */ 469 pp->pwdAllowUserChange = 1; 470 471 if ((a = attr_find( e->e_attrs, ad_pwdPolicySubentry )) == NULL) { 472 /* 473 * entry has no password policy assigned - use default 474 */ 475 vals = &pi->def_policy; 476 if ( !vals->bv_val ) 477 goto defaultpol; 478 } else { 479 vals = a->a_nvals; 480 if (vals[0].bv_val == NULL) { 481 Debug( LDAP_DEBUG_ANY, 482 "ppolicy_get: NULL value for policySubEntry\n", 0, 0, 0 ); 483 goto defaultpol; 484 } 485 } 486 487 op->o_bd->bd_info = (BackendInfo *)on->on_info; 488 rc = be_entry_get_rw( op, vals, NULL, NULL, 0, &pe ); 489 op->o_bd->bd_info = (BackendInfo *)on; 490 491 if ( rc ) goto defaultpol; 492 493#if 0 /* Only worry about userPassword for now */ 494 if ((a = attr_find( pe->e_attrs, ad_pwdAttribute ))) 495 slap_bv2ad( &a->a_vals[0], &pp->ad, &text ); 496#endif 497 498 if ( ( a = attr_find( pe->e_attrs, ad_pwdMinAge ) ) 499 && lutil_atoi( &pp->pwdMinAge, a->a_vals[0].bv_val ) != 0 ) 500 goto defaultpol; 501 if ( ( a = attr_find( pe->e_attrs, ad_pwdMaxAge ) ) 502 && lutil_atoi( &pp->pwdMaxAge, a->a_vals[0].bv_val ) != 0 ) 503 goto defaultpol; 504 if ( ( a = attr_find( pe->e_attrs, ad_pwdInHistory ) ) 505 && lutil_atoi( &pp->pwdInHistory, a->a_vals[0].bv_val ) != 0 ) 506 goto defaultpol; 507 if ( ( a = attr_find( pe->e_attrs, ad_pwdCheckQuality ) ) 508 && lutil_atoi( &pp->pwdCheckQuality, a->a_vals[0].bv_val ) != 0 ) 509 goto defaultpol; 510 if ( ( a = attr_find( pe->e_attrs, ad_pwdMinLength ) ) 511 && lutil_atoi( &pp->pwdMinLength, a->a_vals[0].bv_val ) != 0 ) 512 goto defaultpol; 513 if ( ( a = attr_find( pe->e_attrs, ad_pwdMaxFailure ) ) 514 && lutil_atoi( &pp->pwdMaxFailure, a->a_vals[0].bv_val ) != 0 ) 515 goto defaultpol; 516 if ( ( a = attr_find( pe->e_attrs, ad_pwdGraceAuthNLimit ) ) 517 && lutil_atoi( &pp->pwdGraceAuthNLimit, a->a_vals[0].bv_val ) != 0 ) 518 goto defaultpol; 519 if ( ( a = attr_find( pe->e_attrs, ad_pwdExpireWarning ) ) 520 && lutil_atoi( &pp->pwdExpireWarning, a->a_vals[0].bv_val ) != 0 ) 521 goto defaultpol; 522 if ( ( a = attr_find( pe->e_attrs, ad_pwdFailureCountInterval ) ) 523 && lutil_atoi( &pp->pwdFailureCountInterval, a->a_vals[0].bv_val ) != 0 ) 524 goto defaultpol; 525 if ( ( a = attr_find( pe->e_attrs, ad_pwdLockoutDuration ) ) 526 && lutil_atoi( &pp->pwdLockoutDuration, a->a_vals[0].bv_val ) != 0 ) 527 goto defaultpol; 528 529 if ( ( a = attr_find( pe->e_attrs, ad_pwdCheckModule ) ) ) { 530 strncpy( pp->pwdCheckModule, a->a_vals[0].bv_val, 531 sizeof(pp->pwdCheckModule) ); 532 pp->pwdCheckModule[sizeof(pp->pwdCheckModule)-1] = '\0'; 533 } 534 535 if ((a = attr_find( pe->e_attrs, ad_pwdLockout ))) 536 pp->pwdLockout = bvmatch( &a->a_nvals[0], &slap_true_bv ); 537 if ((a = attr_find( pe->e_attrs, ad_pwdMustChange ))) 538 pp->pwdMustChange = bvmatch( &a->a_nvals[0], &slap_true_bv ); 539 if ((a = attr_find( pe->e_attrs, ad_pwdAllowUserChange ))) 540 pp->pwdAllowUserChange = bvmatch( &a->a_nvals[0], &slap_true_bv ); 541 if ((a = attr_find( pe->e_attrs, ad_pwdSafeModify ))) 542 pp->pwdSafeModify = bvmatch( &a->a_nvals[0], &slap_true_bv ); 543 544 op->o_bd->bd_info = (BackendInfo *)on->on_info; 545 be_entry_release_r( op, pe ); 546 op->o_bd->bd_info = (BackendInfo *)on; 547 548 return; 549 550defaultpol: 551 Debug( LDAP_DEBUG_TRACE, 552 "ppolicy_get: using default policy\n", 0, 0, 0 ); 553 return; 554} 555 556static int 557password_scheme( struct berval *cred, struct berval *sch ) 558{ 559 int e; 560 561 assert( cred != NULL ); 562 563 if (sch) { 564 sch->bv_val = NULL; 565 sch->bv_len = 0; 566 } 567 568 if ((cred->bv_len == 0) || (cred->bv_val == NULL) || 569 (cred->bv_val[0] != '{')) return LDAP_OTHER; 570 571 for(e = 1; cred->bv_val[e] && cred->bv_val[e] != '}'; e++); 572 if (cred->bv_val[e]) { 573 int rc; 574 rc = lutil_passwd_scheme( cred->bv_val ); 575 if (rc) { 576 if (sch) { 577 sch->bv_val = cred->bv_val; 578 sch->bv_len = e; 579 } 580 return LDAP_SUCCESS; 581 } 582 } 583 return LDAP_OTHER; 584} 585 586static int 587check_password_quality( struct berval *cred, PassPolicy *pp, LDAPPasswordPolicyError *err, Entry *e, char **txt ) 588{ 589 int rc = LDAP_SUCCESS, ok = LDAP_SUCCESS; 590 char *ptr; 591 struct berval sch; 592 593 assert( cred != NULL ); 594 assert( pp != NULL ); 595 assert( txt != NULL ); 596 597 ptr = cred->bv_val; 598 599 *txt = NULL; 600 601 if ((cred->bv_len == 0) || (pp->pwdMinLength > cred->bv_len)) { 602 rc = LDAP_CONSTRAINT_VIOLATION; 603 if ( err ) *err = PP_passwordTooShort; 604 return rc; 605 } 606 607 /* 608 * We need to know if the password is already hashed - if so 609 * what scheme is it. The reason being that the "hash" of 610 * {cleartext} still allows us to check the password. 611 */ 612 rc = password_scheme( cred, &sch ); 613 if (rc == LDAP_SUCCESS) { 614 if ((sch.bv_val) && (strncasecmp( sch.bv_val, "{cleartext}", 615 sch.bv_len ) == 0)) { 616 /* 617 * We can check the cleartext "hash" 618 */ 619 ptr = cred->bv_val + sch.bv_len; 620 } else { 621 /* everything else, we can't check */ 622 if (pp->pwdCheckQuality == 2) { 623 rc = LDAP_CONSTRAINT_VIOLATION; 624 if (err) *err = PP_insufficientPasswordQuality; 625 return rc; 626 } 627 /* 628 * We can't check the syntax of the password, but it's not 629 * mandatory (according to the policy), so we return success. 630 */ 631 632 return LDAP_SUCCESS; 633 } 634 } 635 636 rc = LDAP_SUCCESS; 637 638 if (pp->pwdCheckModule[0]) { 639#ifdef SLAPD_MODULES 640 lt_dlhandle mod; 641 const char *err; 642 643 if ((mod = lt_dlopen( pp->pwdCheckModule )) == NULL) { 644 err = lt_dlerror(); 645 646 Debug(LDAP_DEBUG_ANY, 647 "check_password_quality: lt_dlopen failed: (%s) %s.\n", 648 pp->pwdCheckModule, err, 0 ); 649 ok = LDAP_OTHER; /* internal error */ 650 } else { 651 /* FIXME: the error message ought to be passed thru a 652 * struct berval, with preallocated buffer and size 653 * passed in. Module can still allocate a buffer for 654 * it if the provided one is too small. 655 */ 656 int (*prog)( char *passwd, char **text, Entry *ent ); 657 658 if ((prog = lt_dlsym( mod, "check_password" )) == NULL) { 659 err = lt_dlerror(); 660 661 Debug(LDAP_DEBUG_ANY, 662 "check_password_quality: lt_dlsym failed: (%s) %s.\n", 663 pp->pwdCheckModule, err, 0 ); 664 ok = LDAP_OTHER; 665 } else { 666 ldap_pvt_thread_mutex_lock( &chk_syntax_mutex ); 667 ok = prog( ptr, txt, e ); 668 ldap_pvt_thread_mutex_unlock( &chk_syntax_mutex ); 669 if (ok != LDAP_SUCCESS) { 670 Debug(LDAP_DEBUG_ANY, 671 "check_password_quality: module error: (%s) %s.[%d]\n", 672 pp->pwdCheckModule, *txt ? *txt : "", ok ); 673 } 674 } 675 676 lt_dlclose( mod ); 677 } 678#else 679 Debug(LDAP_DEBUG_ANY, "check_password_quality: external modules not " 680 "supported. pwdCheckModule ignored.\n", 0, 0, 0); 681#endif /* SLAPD_MODULES */ 682 } 683 684 685 if (ok != LDAP_SUCCESS) { 686 rc = LDAP_CONSTRAINT_VIOLATION; 687 if (err) *err = PP_insufficientPasswordQuality; 688 } 689 690 return rc; 691} 692 693static int 694parse_pwdhistory( struct berval *bv, char **oid, time_t *oldtime, struct berval *oldpw ) 695{ 696 char *ptr; 697 struct berval nv, npw; 698 ber_len_t i, j; 699 700 assert (bv && (bv->bv_len > 0) && (bv->bv_val) && oldtime && oldpw ); 701 702 if ( oid ) { 703 *oid = 0; 704 } 705 *oldtime = (time_t)-1; 706 BER_BVZERO( oldpw ); 707 708 ber_dupbv( &nv, bv ); 709 710 /* first get the time field */ 711 for ( i = 0; (i < nv.bv_len) && (nv.bv_val[i] != '#'); i++ ) 712 ; 713 if ( i == nv.bv_len ) { 714 goto exit_failure; /* couldn't locate the '#' separator */ 715 } 716 nv.bv_val[i++] = '\0'; /* terminate the string & move to next field */ 717 ptr = nv.bv_val; 718 *oldtime = parse_time( ptr ); 719 if (*oldtime == (time_t)-1) { 720 goto exit_failure; 721 } 722 723 /* get the OID field */ 724 for (ptr = &(nv.bv_val[i]); (i < nv.bv_len) && (nv.bv_val[i] != '#'); i++ ) 725 ; 726 if ( i == nv.bv_len ) { 727 goto exit_failure; /* couldn't locate the '#' separator */ 728 } 729 nv.bv_val[i++] = '\0'; /* terminate the string & move to next field */ 730 if ( oid ) { 731 *oid = ber_strdup( ptr ); 732 } 733 734 /* get the length field */ 735 for ( ptr = &(nv.bv_val[i]); (i < nv.bv_len) && (nv.bv_val[i] != '#'); i++ ) 736 ; 737 if ( i == nv.bv_len ) { 738 goto exit_failure; /* couldn't locate the '#' separator */ 739 } 740 nv.bv_val[i++] = '\0'; /* terminate the string & move to next field */ 741 oldpw->bv_len = strtol( ptr, NULL, 10 ); 742 if (errno == ERANGE) { 743 goto exit_failure; 744 } 745 746 /* lastly, get the octets of the string */ 747 for ( j = i, ptr = &(nv.bv_val[i]); i < nv.bv_len; i++ ) 748 ; 749 if ( i - j != oldpw->bv_len) { 750 goto exit_failure; /* length is wrong */ 751 } 752 753 npw.bv_val = ptr; 754 npw.bv_len = oldpw->bv_len; 755 ber_dupbv( oldpw, &npw ); 756 ber_memfree( nv.bv_val ); 757 758 return LDAP_SUCCESS; 759 760exit_failure:; 761 if ( oid && *oid ) { 762 ber_memfree(*oid); 763 *oid = NULL; 764 } 765 if ( oldpw->bv_val ) { 766 ber_memfree( oldpw->bv_val); 767 BER_BVZERO( oldpw ); 768 } 769 ber_memfree( nv.bv_val ); 770 771 return LDAP_OTHER; 772} 773 774static void 775add_to_pwd_history( pw_hist **l, time_t t, 776 struct berval *oldpw, struct berval *bv ) 777{ 778 pw_hist *p, *p1, *p2; 779 780 if (!l) return; 781 782 p = ch_malloc( sizeof( pw_hist )); 783 p->pw = *oldpw; 784 ber_dupbv( &p->bv, bv ); 785 p->t = t; 786 p->next = NULL; 787 788 if (*l == NULL) { 789 /* degenerate case */ 790 *l = p; 791 return; 792 } 793 /* 794 * advance p1 and p2 such that p1 is the node before the 795 * new one, and p2 is the node after it 796 */ 797 for (p1 = NULL, p2 = *l; p2 && p2->t <= t; p1 = p2, p2=p2->next ); 798 p->next = p2; 799 if (p1 == NULL) { *l = p; return; } 800 p1->next = p; 801} 802 803#ifndef MAX_PWD_HISTORY_SZ 804#define MAX_PWD_HISTORY_SZ 1024 805#endif /* MAX_PWD_HISTORY_SZ */ 806 807static void 808make_pwd_history_value( char *timebuf, struct berval *bv, Attribute *pa ) 809{ 810 char str[ MAX_PWD_HISTORY_SZ ]; 811 int nlen; 812 813 snprintf( str, MAX_PWD_HISTORY_SZ, 814 "%s#%s#%lu#", timebuf, 815 pa->a_desc->ad_type->sat_syntax->ssyn_oid, 816 (unsigned long) pa->a_nvals[0].bv_len ); 817 str[MAX_PWD_HISTORY_SZ-1] = 0; 818 nlen = strlen(str); 819 820 /* 821 * We have to assume that the string is a string of octets, 822 * not readable characters. In reality, yes, it probably is 823 * a readable (ie, base64) string, but we can't count on that 824 * Hence, while the first 3 fields of the password history 825 * are definitely readable (a timestamp, an OID and an integer 826 * length), the remaining octets of the actual password 827 * are deemed to be binary data. 828 */ 829 AC_MEMCPY( str + nlen, pa->a_nvals[0].bv_val, pa->a_nvals[0].bv_len ); 830 nlen += pa->a_nvals[0].bv_len; 831 bv->bv_val = ch_malloc( nlen + 1 ); 832 AC_MEMCPY( bv->bv_val, str, nlen ); 833 bv->bv_val[nlen] = '\0'; 834 bv->bv_len = nlen; 835} 836 837static void 838free_pwd_history_list( pw_hist **l ) 839{ 840 pw_hist *p; 841 842 if (!l) return; 843 p = *l; 844 while (p) { 845 pw_hist *pp = p->next; 846 847 free(p->pw.bv_val); 848 free(p->bv.bv_val); 849 free(p); 850 p = pp; 851 } 852 *l = NULL; 853} 854 855typedef struct ppbind { 856 slap_overinst *on; 857 int send_ctrl; 858 int set_restrict; 859 LDAPControl **oldctrls; 860 Modifications *mod; 861 LDAPPasswordPolicyError pErr; 862 PassPolicy pp; 863} ppbind; 864 865static void 866ctrls_cleanup( Operation *op, SlapReply *rs, LDAPControl **oldctrls ) 867{ 868 int n; 869 870 assert( rs->sr_ctrls != NULL ); 871 assert( rs->sr_ctrls[0] != NULL ); 872 873 for ( n = 0; rs->sr_ctrls[n]; n++ ) { 874 if ( rs->sr_ctrls[n]->ldctl_oid == ppolicy_ctrl_oid ) { 875 op->o_tmpfree( rs->sr_ctrls[n], op->o_tmpmemctx ); 876 rs->sr_ctrls[n] = (LDAPControl *)(-1); 877 break; 878 } 879 } 880 881 if ( rs->sr_ctrls[n] == NULL ) { 882 /* missed? */ 883 } 884 885 op->o_tmpfree( rs->sr_ctrls, op->o_tmpmemctx ); 886 887 rs->sr_ctrls = oldctrls; 888} 889 890static int 891ppolicy_ctrls_cleanup( Operation *op, SlapReply *rs ) 892{ 893 ppbind *ppb = op->o_callback->sc_private; 894 if ( ppb->send_ctrl ) { 895 ctrls_cleanup( op, rs, ppb->oldctrls ); 896 } 897 return SLAP_CB_CONTINUE; 898} 899 900static int 901ppolicy_bind_response( Operation *op, SlapReply *rs ) 902{ 903 ppbind *ppb = op->o_callback->sc_private; 904 slap_overinst *on = ppb->on; 905 Modifications *mod = ppb->mod, *m; 906 int pwExpired = 0; 907 int ngut = -1, warn = -1, age, rc; 908 Attribute *a; 909 time_t now, pwtime = (time_t)-1; 910 char nowstr[ LDAP_LUTIL_GENTIME_BUFSIZE ]; 911 struct berval timestamp; 912 BackendInfo *bi = op->o_bd->bd_info; 913 Entry *e; 914 915 /* If we already know it's locked, just get on with it */ 916 if ( ppb->pErr != PP_noError ) { 917 goto locked; 918 } 919 920 op->o_bd->bd_info = (BackendInfo *)on->on_info; 921 rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e ); 922 op->o_bd->bd_info = bi; 923 924 if ( rc != LDAP_SUCCESS ) { 925 return SLAP_CB_CONTINUE; 926 } 927 928 now = slap_get_time(); /* stored for later consideration */ 929 timestamp.bv_val = nowstr; 930 timestamp.bv_len = sizeof(nowstr); 931 slap_timestamp( &now, ×tamp ); 932 933 if ( rs->sr_err == LDAP_INVALID_CREDENTIALS ) { 934 int i = 0, fc = 0; 935 936 m = ch_calloc( sizeof(Modifications), 1 ); 937 m->sml_op = LDAP_MOD_ADD; 938 m->sml_flags = 0; 939 m->sml_type = ad_pwdFailureTime->ad_cname; 940 m->sml_desc = ad_pwdFailureTime; 941 m->sml_numvals = 1; 942 m->sml_values = ch_calloc( sizeof(struct berval), 2 ); 943 m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 ); 944 945 ber_dupbv( &m->sml_values[0], ×tamp ); 946 ber_dupbv( &m->sml_nvalues[0], ×tamp ); 947 m->sml_next = mod; 948 mod = m; 949 950 /* 951 * Count the pwdFailureTimes - if it's 952 * greater than the policy pwdMaxFailure, 953 * then lock the account. 954 */ 955 if ((a = attr_find( e->e_attrs, ad_pwdFailureTime )) != NULL) { 956 for(i=0; a->a_nvals[i].bv_val; i++) { 957 958 /* 959 * If the interval is 0, then failures 960 * stay on the record until explicitly 961 * reset by successful authentication. 962 */ 963 if (ppb->pp.pwdFailureCountInterval == 0) { 964 fc++; 965 } else if (now <= 966 parse_time(a->a_nvals[i].bv_val) + 967 ppb->pp.pwdFailureCountInterval) { 968 969 fc++; 970 } 971 /* 972 * We only count those failures 973 * which are not due to expire. 974 */ 975 } 976 } 977 978 if ((ppb->pp.pwdMaxFailure > 0) && 979 (fc >= ppb->pp.pwdMaxFailure - 1)) { 980 981 /* 982 * We subtract 1 from the failure max 983 * because the new failure entry hasn't 984 * made it to the entry yet. 985 */ 986 m = ch_calloc( sizeof(Modifications), 1 ); 987 m->sml_op = LDAP_MOD_REPLACE; 988 m->sml_flags = 0; 989 m->sml_type = ad_pwdAccountLockedTime->ad_cname; 990 m->sml_desc = ad_pwdAccountLockedTime; 991 m->sml_numvals = 1; 992 m->sml_values = ch_calloc( sizeof(struct berval), 2 ); 993 m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 ); 994 ber_dupbv( &m->sml_values[0], ×tamp ); 995 ber_dupbv( &m->sml_nvalues[0], ×tamp ); 996 m->sml_next = mod; 997 mod = m; 998 } 999 } else if ( rs->sr_err == LDAP_SUCCESS ) { 1000 if ((a = attr_find( e->e_attrs, ad_pwdChangedTime )) != NULL) 1001 pwtime = parse_time( a->a_nvals[0].bv_val ); 1002 1003 /* delete all pwdFailureTimes */ 1004 if ( attr_find( e->e_attrs, ad_pwdFailureTime )) { 1005 m = ch_calloc( sizeof(Modifications), 1 ); 1006 m->sml_op = LDAP_MOD_DELETE; 1007 m->sml_flags = 0; 1008 m->sml_type = ad_pwdFailureTime->ad_cname; 1009 m->sml_desc = ad_pwdFailureTime; 1010 m->sml_next = mod; 1011 mod = m; 1012 } 1013 1014 /* 1015 * check to see if the password must be changed 1016 */ 1017 if ( ppb->pp.pwdMustChange && 1018 (a = attr_find( e->e_attrs, ad_pwdReset )) && 1019 bvmatch( &a->a_nvals[0], &slap_true_bv ) ) 1020 { 1021 /* 1022 * need to inject client controls here to give 1023 * more information. For the moment, we ensure 1024 * that we are disallowed from doing anything 1025 * other than change password. 1026 */ 1027 if ( ppb->set_restrict ) { 1028 ber_dupbv( &pwcons[op->o_conn->c_conn_idx].dn, 1029 &op->o_conn->c_ndn ); 1030 } 1031 1032 ppb->pErr = PP_changeAfterReset; 1033 1034 } else { 1035 /* 1036 * the password does not need to be changed, so 1037 * we now check whether the password has expired. 1038 * 1039 * We can skip this bit if passwords don't age in 1040 * the policy. Also, if there was no pwdChangedTime 1041 * attribute in the entry, the password never expires. 1042 */ 1043 if (ppb->pp.pwdMaxAge == 0) goto grace; 1044 1045 if (pwtime != (time_t)-1) { 1046 /* 1047 * Check: was the last change time of 1048 * the password older than the maximum age 1049 * allowed. (Ignore case 2 from I-D, it's just silly.) 1050 */ 1051 if (now - pwtime > ppb->pp.pwdMaxAge ) pwExpired = 1; 1052 } 1053 } 1054 1055grace: 1056 if (!pwExpired) goto check_expiring_password; 1057 1058 if ((a = attr_find( e->e_attrs, ad_pwdGraceUseTime )) == NULL) 1059 ngut = ppb->pp.pwdGraceAuthNLimit; 1060 else { 1061 for(ngut=0; a->a_nvals[ngut].bv_val; ngut++); 1062 ngut = ppb->pp.pwdGraceAuthNLimit - ngut; 1063 } 1064 1065 /* 1066 * ngut is the number of remaining grace logins 1067 */ 1068 Debug( LDAP_DEBUG_ANY, 1069 "ppolicy_bind: Entry %s has an expired password: %d grace logins\n", 1070 e->e_name.bv_val, ngut, 0); 1071 1072 if (ngut < 1) { 1073 ppb->pErr = PP_passwordExpired; 1074 rs->sr_err = LDAP_INVALID_CREDENTIALS; 1075 goto done; 1076 } 1077 1078 /* 1079 * Add a grace user time to the entry 1080 */ 1081 m = ch_calloc( sizeof(Modifications), 1 ); 1082 m->sml_op = LDAP_MOD_ADD; 1083 m->sml_flags = 0; 1084 m->sml_type = ad_pwdGraceUseTime->ad_cname; 1085 m->sml_desc = ad_pwdGraceUseTime; 1086 m->sml_numvals = 1; 1087 m->sml_values = ch_calloc( sizeof(struct berval), 2 ); 1088 m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 ); 1089 ber_dupbv( &m->sml_values[0], ×tamp ); 1090 ber_dupbv( &m->sml_nvalues[0], ×tamp ); 1091 m->sml_next = mod; 1092 mod = m; 1093 1094check_expiring_password: 1095 /* 1096 * Now we need to check to see 1097 * if it is about to expire, and if so, should the user 1098 * be warned about it in the password policy control. 1099 * 1100 * If the password has expired, and we're in the grace period, then 1101 * we don't need to do this bit. Similarly, if we don't have password 1102 * aging, then there's no need to do this bit either. 1103 */ 1104 if ((ppb->pp.pwdMaxAge < 1) || (pwExpired) || (ppb->pp.pwdExpireWarning < 1)) 1105 goto done; 1106 1107 age = (int)(now - pwtime); 1108 1109 /* 1110 * We know that there is a password Change Time attribute - if 1111 * there wasn't, then the pwdExpired value would be true, unless 1112 * there is no password aging - and if there is no password aging, 1113 * then this section isn't called anyway - you can't have an 1114 * expiring password if there's no limit to expire. 1115 */ 1116 if (ppb->pp.pwdMaxAge - age < ppb->pp.pwdExpireWarning ) { 1117 /* 1118 * Set the warning value. 1119 */ 1120 warn = ppb->pp.pwdMaxAge - age; /* seconds left until expiry */ 1121 if (warn < 0) warn = 0; /* something weird here - why is pwExpired not set? */ 1122 1123 Debug( LDAP_DEBUG_ANY, 1124 "ppolicy_bind: Setting warning for password expiry for %s = %d seconds\n", 1125 op->o_req_dn.bv_val, warn, 0 ); 1126 } 1127 } 1128 1129done: 1130 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1131 be_entry_release_r( op, e ); 1132 1133locked: 1134 if ( mod ) { 1135 Operation op2 = *op; 1136 SlapReply r2 = { REP_RESULT }; 1137 slap_callback cb = { NULL, slap_null_cb, NULL, NULL }; 1138 pp_info *pi = on->on_bi.bi_private; 1139 LDAPControl c, *ca[2]; 1140 1141 op2.o_tag = LDAP_REQ_MODIFY; 1142 op2.o_callback = &cb; 1143 op2.orm_modlist = mod; 1144 op2.orm_no_opattrs = 0; 1145 op2.o_dn = op->o_bd->be_rootdn; 1146 op2.o_ndn = op->o_bd->be_rootndn; 1147 1148 /* If this server is a shadow and forward_updates is true, 1149 * use the frontend to perform this modify. That will trigger 1150 * the update referral, which can then be forwarded by the 1151 * chain overlay. Obviously the updateref and chain overlay 1152 * must be configured appropriately for this to be useful. 1153 */ 1154 if ( SLAP_SHADOW( op->o_bd ) && pi->forward_updates ) { 1155 op2.o_bd = frontendDB; 1156 1157 /* Must use Relax control since these are no-user-mod */ 1158 op2.o_relax = SLAP_CONTROL_CRITICAL; 1159 op2.o_ctrls = ca; 1160 ca[0] = &c; 1161 ca[1] = NULL; 1162 BER_BVZERO( &c.ldctl_value ); 1163 c.ldctl_iscritical = 1; 1164 c.ldctl_oid = LDAP_CONTROL_RELAX; 1165 } else { 1166 /* If not forwarding, don't update opattrs and don't replicate */ 1167 if ( SLAP_SINGLE_SHADOW( op->o_bd )) { 1168 op2.orm_no_opattrs = 1; 1169 op2.o_dont_replicate = 1; 1170 } 1171 op2.o_bd->bd_info = (BackendInfo *)on->on_info; 1172 } 1173 rc = op2.o_bd->be_modify( &op2, &r2 ); 1174 slap_mods_free( mod, 1 ); 1175 } 1176 1177 if ( ppb->send_ctrl ) { 1178 LDAPControl *ctrl = NULL; 1179 pp_info *pi = on->on_bi.bi_private; 1180 1181 /* Do we really want to tell that the account is locked? */ 1182 if ( ppb->pErr == PP_accountLocked && !pi->use_lockout ) { 1183 ppb->pErr = PP_noError; 1184 } 1185 ctrl = create_passcontrol( op, warn, ngut, ppb->pErr ); 1186 ppb->oldctrls = add_passcontrol( op, rs, ctrl ); 1187 op->o_callback->sc_cleanup = ppolicy_ctrls_cleanup; 1188 } 1189 op->o_bd->bd_info = bi; 1190 return SLAP_CB_CONTINUE; 1191} 1192 1193static int 1194ppolicy_bind( Operation *op, SlapReply *rs ) 1195{ 1196 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 1197 1198 /* Reset lockout status on all Bind requests */ 1199 if ( !BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn )) { 1200 ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val ); 1201 BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn ); 1202 } 1203 1204 /* Root bypasses policy */ 1205 if ( !be_isroot_dn( op->o_bd, &op->o_req_ndn )) { 1206 Entry *e; 1207 int rc; 1208 ppbind *ppb; 1209 slap_callback *cb; 1210 1211 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1212 rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e ); 1213 1214 if ( rc != LDAP_SUCCESS ) { 1215 return SLAP_CB_CONTINUE; 1216 } 1217 1218 cb = op->o_tmpcalloc( sizeof(ppbind)+sizeof(slap_callback), 1219 1, op->o_tmpmemctx ); 1220 ppb = (ppbind *)(cb+1); 1221 ppb->on = on; 1222 ppb->pErr = PP_noError; 1223 ppb->set_restrict = 1; 1224 1225 /* Setup a callback so we can munge the result */ 1226 1227 cb->sc_response = ppolicy_bind_response; 1228 cb->sc_next = op->o_callback->sc_next; 1229 cb->sc_private = ppb; 1230 op->o_callback->sc_next = cb; 1231 1232 /* Did we receive a password policy request control? */ 1233 if ( op->o_ctrlflag[ppolicy_cid] ) { 1234 ppb->send_ctrl = 1; 1235 } 1236 1237 op->o_bd->bd_info = (BackendInfo *)on; 1238 ppolicy_get( op, e, &ppb->pp ); 1239 1240 rc = account_locked( op, e, &ppb->pp, &ppb->mod ); 1241 1242 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1243 be_entry_release_r( op, e ); 1244 1245 if ( rc ) { 1246 ppb->pErr = PP_accountLocked; 1247 send_ldap_error( op, rs, LDAP_INVALID_CREDENTIALS, NULL ); 1248 return rs->sr_err; 1249 } 1250 1251 } 1252 1253 return SLAP_CB_CONTINUE; 1254} 1255 1256/* Reset the restricted info for the next session on this connection */ 1257static int 1258ppolicy_connection_destroy( BackendDB *bd, Connection *conn ) 1259{ 1260 if ( !BER_BVISEMPTY( &pwcons[conn->c_conn_idx].dn )) { 1261 ch_free( pwcons[conn->c_conn_idx].dn.bv_val ); 1262 BER_BVZERO( &pwcons[conn->c_conn_idx].dn ); 1263 } 1264 return SLAP_CB_CONTINUE; 1265} 1266 1267/* Check if this connection is restricted */ 1268static int 1269ppolicy_restrict( 1270 Operation *op, 1271 SlapReply *rs ) 1272{ 1273 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 1274 int send_ctrl = 0; 1275 1276 /* Did we receive a password policy request control? */ 1277 if ( op->o_ctrlflag[ppolicy_cid] ) { 1278 send_ctrl = 1; 1279 } 1280 1281 if ( op->o_conn && !BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn )) { 1282 LDAPControl **oldctrls; 1283 /* if the current authcDN doesn't match the one we recorded, 1284 * then an intervening Bind has succeeded and the restriction 1285 * no longer applies. (ITS#4516) 1286 */ 1287 if ( !dn_match( &op->o_conn->c_ndn, 1288 &pwcons[op->o_conn->c_conn_idx].dn )) { 1289 ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val ); 1290 BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn ); 1291 return SLAP_CB_CONTINUE; 1292 } 1293 1294 Debug( LDAP_DEBUG_TRACE, 1295 "connection restricted to password changing only\n", 0, 0, 0); 1296 if ( send_ctrl ) { 1297 LDAPControl *ctrl = NULL; 1298 ctrl = create_passcontrol( op, -1, -1, PP_changeAfterReset ); 1299 oldctrls = add_passcontrol( op, rs, ctrl ); 1300 } 1301 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1302 send_ldap_error( op, rs, LDAP_INSUFFICIENT_ACCESS, 1303 "Operations are restricted to bind/unbind/abandon/StartTLS/modify password" ); 1304 if ( send_ctrl ) { 1305 ctrls_cleanup( op, rs, oldctrls ); 1306 } 1307 return rs->sr_err; 1308 } 1309 1310 return SLAP_CB_CONTINUE; 1311} 1312 1313static int 1314ppolicy_compare_response( 1315 Operation *op, 1316 SlapReply *rs ) 1317{ 1318 /* map compare responses to bind responses */ 1319 if ( rs->sr_err == LDAP_COMPARE_TRUE ) 1320 rs->sr_err = LDAP_SUCCESS; 1321 else if ( rs->sr_err == LDAP_COMPARE_FALSE ) 1322 rs->sr_err = LDAP_INVALID_CREDENTIALS; 1323 1324 ppolicy_bind_response( op, rs ); 1325 1326 /* map back to compare */ 1327 if ( rs->sr_err == LDAP_SUCCESS ) 1328 rs->sr_err = LDAP_COMPARE_TRUE; 1329 else if ( rs->sr_err == LDAP_INVALID_CREDENTIALS ) 1330 rs->sr_err = LDAP_COMPARE_FALSE; 1331 1332 return SLAP_CB_CONTINUE; 1333} 1334 1335static int 1336ppolicy_compare( 1337 Operation *op, 1338 SlapReply *rs ) 1339{ 1340 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 1341 1342 if ( ppolicy_restrict( op, rs ) != SLAP_CB_CONTINUE ) 1343 return rs->sr_err; 1344 1345 /* Did we receive a password policy request control? 1346 * Are we testing the userPassword? 1347 */ 1348 if ( op->o_ctrlflag[ppolicy_cid] && 1349 op->orc_ava->aa_desc == slap_schema.si_ad_userPassword ) { 1350 Entry *e; 1351 int rc; 1352 ppbind *ppb; 1353 slap_callback *cb; 1354 1355 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1356 rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e ); 1357 1358 if ( rc != LDAP_SUCCESS ) { 1359 return SLAP_CB_CONTINUE; 1360 } 1361 1362 cb = op->o_tmpcalloc( sizeof(ppbind)+sizeof(slap_callback), 1363 1, op->o_tmpmemctx ); 1364 ppb = (ppbind *)(cb+1); 1365 ppb->on = on; 1366 ppb->pErr = PP_noError; 1367 ppb->send_ctrl = 1; 1368 /* failures here don't lockout the connection */ 1369 ppb->set_restrict = 0; 1370 1371 /* Setup a callback so we can munge the result */ 1372 1373 cb->sc_response = ppolicy_compare_response; 1374 cb->sc_next = op->o_callback->sc_next; 1375 cb->sc_private = ppb; 1376 op->o_callback->sc_next = cb; 1377 1378 op->o_bd->bd_info = (BackendInfo *)on; 1379 ppolicy_get( op, e, &ppb->pp ); 1380 1381 rc = account_locked( op, e, &ppb->pp, &ppb->mod ); 1382 1383 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1384 be_entry_release_r( op, e ); 1385 1386 if ( rc ) { 1387 ppb->pErr = PP_accountLocked; 1388 send_ldap_error( op, rs, LDAP_COMPARE_FALSE, NULL ); 1389 return rs->sr_err; 1390 } 1391 } 1392 return SLAP_CB_CONTINUE; 1393} 1394 1395static int 1396ppolicy_add( 1397 Operation *op, 1398 SlapReply *rs ) 1399{ 1400 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 1401 pp_info *pi = on->on_bi.bi_private; 1402 PassPolicy pp; 1403 Attribute *pa; 1404 const char *txt; 1405 1406 if ( ppolicy_restrict( op, rs ) != SLAP_CB_CONTINUE ) 1407 return rs->sr_err; 1408 1409 /* If this is a replica, assume the master checked everything */ 1410 if ( be_shadow_update( op )) 1411 return SLAP_CB_CONTINUE; 1412 1413 /* Check for password in entry */ 1414 if ((pa = attr_find( op->oq_add.rs_e->e_attrs, 1415 slap_schema.si_ad_userPassword ))) 1416 { 1417 assert( pa->a_vals != NULL ); 1418 assert( !BER_BVISNULL( &pa->a_vals[ 0 ] ) ); 1419 1420 if ( !BER_BVISNULL( &pa->a_vals[ 1 ] ) ) { 1421 send_ldap_error( op, rs, LDAP_CONSTRAINT_VIOLATION, "Password policy only allows one password value" ); 1422 return rs->sr_err; 1423 } 1424 1425 /* 1426 * new entry contains a password - if we're not the root user 1427 * then we need to check that the password fits in with the 1428 * security policy for the new entry. 1429 */ 1430 ppolicy_get( op, op->ora_e, &pp ); 1431 if (pp.pwdCheckQuality > 0 && !be_isroot( op )) { 1432 struct berval *bv = &(pa->a_vals[0]); 1433 int rc, send_ctrl = 0; 1434 LDAPPasswordPolicyError pErr = PP_noError; 1435 char *txt; 1436 1437 /* Did we receive a password policy request control? */ 1438 if ( op->o_ctrlflag[ppolicy_cid] ) { 1439 send_ctrl = 1; 1440 } 1441 rc = check_password_quality( bv, &pp, &pErr, op->ora_e, &txt ); 1442 if (rc != LDAP_SUCCESS) { 1443 LDAPControl **oldctrls = NULL; 1444 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1445 if ( send_ctrl ) { 1446 LDAPControl *ctrl = NULL; 1447 ctrl = create_passcontrol( op, -1, -1, pErr ); 1448 oldctrls = add_passcontrol( op, rs, ctrl ); 1449 } 1450 send_ldap_error( op, rs, rc, txt ? txt : "Password fails quality checking policy" ); 1451 if ( txt ) { 1452 free( txt ); 1453 } 1454 if ( send_ctrl ) { 1455 ctrls_cleanup( op, rs, oldctrls ); 1456 } 1457 return rs->sr_err; 1458 } 1459 } 1460 /* 1461 * A controversial bit. We hash cleartext 1462 * passwords provided via add and modify operations 1463 * You're not really supposed to do this, since 1464 * the X.500 model says "store attributes" as they 1465 * get provided. By default, this is what we do 1466 * 1467 * But if the hash_passwords flag is set, we hash 1468 * any cleartext password attribute values via the 1469 * default password hashing scheme. 1470 */ 1471 if ((pi->hash_passwords) && 1472 (password_scheme( &(pa->a_vals[0]), NULL ) != LDAP_SUCCESS)) { 1473 struct berval hpw; 1474 1475 slap_passwd_hash( &(pa->a_vals[0]), &hpw, &txt ); 1476 if (hpw.bv_val == NULL) { 1477 /* 1478 * hashing didn't work. Emit an error. 1479 */ 1480 rs->sr_err = LDAP_OTHER; 1481 rs->sr_text = txt; 1482 send_ldap_error( op, rs, LDAP_OTHER, "Password hashing failed" ); 1483 return rs->sr_err; 1484 } 1485 1486 memset( pa->a_vals[0].bv_val, 0, pa->a_vals[0].bv_len); 1487 ber_memfree( pa->a_vals[0].bv_val ); 1488 pa->a_vals[0].bv_val = hpw.bv_val; 1489 pa->a_vals[0].bv_len = hpw.bv_len; 1490 } 1491 1492 /* If password aging is in effect, set the pwdChangedTime */ 1493 if ( pp.pwdMaxAge || pp.pwdMinAge ) { 1494 struct berval timestamp; 1495 char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; 1496 time_t now = slap_get_time(); 1497 1498 timestamp.bv_val = timebuf; 1499 timestamp.bv_len = sizeof(timebuf); 1500 slap_timestamp( &now, ×tamp ); 1501 1502 attr_merge_one( op->ora_e, ad_pwdChangedTime, ×tamp, ×tamp ); 1503 } 1504 } 1505 return SLAP_CB_CONTINUE; 1506} 1507 1508static int 1509ppolicy_mod_cb( Operation *op, SlapReply *rs ) 1510{ 1511 slap_callback *sc = op->o_callback; 1512 op->o_callback = sc->sc_next; 1513 if ( rs->sr_err == LDAP_SUCCESS ) { 1514 ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val ); 1515 BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn ); 1516 } 1517 op->o_tmpfree( sc, op->o_tmpmemctx ); 1518 return SLAP_CB_CONTINUE; 1519} 1520 1521static int 1522ppolicy_modify( Operation *op, SlapReply *rs ) 1523{ 1524 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 1525 pp_info *pi = on->on_bi.bi_private; 1526 int i, rc, mod_pw_only, pwmod, pwmop = -1, deladd, 1527 hsize = 0; 1528 PassPolicy pp; 1529 Modifications *mods = NULL, *modtail = NULL, 1530 *ml, *delmod, *addmod; 1531 Attribute *pa, *ha, at; 1532 const char *txt; 1533 pw_hist *tl = NULL, *p; 1534 int zapReset, send_ctrl = 0, free_txt = 0; 1535 Entry *e; 1536 struct berval newpw = BER_BVNULL, oldpw = BER_BVNULL, 1537 *bv, cr[2]; 1538 LDAPPasswordPolicyError pErr = PP_noError; 1539 LDAPControl *ctrl = NULL; 1540 LDAPControl **oldctrls = NULL; 1541 int is_pwdexop = 0; 1542 1543 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1544 rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e ); 1545 op->o_bd->bd_info = (BackendInfo *)on; 1546 1547 if ( rc != LDAP_SUCCESS ) return SLAP_CB_CONTINUE; 1548 1549 /* If this is a replica, we may need to tweak some of the 1550 * master's modifications. Otherwise, just pass it through. 1551 */ 1552 if ( be_shadow_update( op )) { 1553 Modifications **prev; 1554 int got_del_grace = 0, got_del_lock = 0, got_pw = 0, got_del_fail = 0; 1555 Attribute *a_grace, *a_lock, *a_fail; 1556 1557 a_grace = attr_find( e->e_attrs, ad_pwdGraceUseTime ); 1558 a_lock = attr_find( e->e_attrs, ad_pwdAccountLockedTime ); 1559 a_fail = attr_find( e->e_attrs, ad_pwdFailureTime ); 1560 1561 for( prev = &op->orm_modlist, ml = *prev; ml; ml = *prev ) { 1562 1563 if ( ml->sml_desc == slap_schema.si_ad_userPassword ) 1564 got_pw = 1; 1565 1566 /* If we're deleting an attr that didn't exist, 1567 * drop this delete op 1568 */ 1569 if ( ml->sml_op == LDAP_MOD_DELETE ) { 1570 int drop = 0; 1571 1572 if ( ml->sml_desc == ad_pwdGraceUseTime ) { 1573 got_del_grace = 1; 1574 if ( !a_grace ) 1575 drop = 1; 1576 } else 1577 if ( ml->sml_desc == ad_pwdAccountLockedTime ) { 1578 got_del_lock = 1; 1579 if ( !a_lock ) 1580 drop = 1; 1581 } else 1582 if ( ml->sml_desc == ad_pwdFailureTime ) { 1583 got_del_fail = 1; 1584 if ( !a_fail ) 1585 drop = 1; 1586 } 1587 if ( drop ) { 1588 *prev = ml->sml_next; 1589 ml->sml_next = NULL; 1590 slap_mods_free( ml, 1 ); 1591 continue; 1592 } 1593 } 1594 prev = &ml->sml_next; 1595 } 1596 1597 /* If we're resetting the password, make sure grace, accountlock, 1598 * and failure also get removed. 1599 */ 1600 if ( got_pw ) { 1601 if ( a_grace && !got_del_grace ) { 1602 ml = (Modifications *) ch_malloc( sizeof( Modifications ) ); 1603 ml->sml_op = LDAP_MOD_DELETE; 1604 ml->sml_flags = SLAP_MOD_INTERNAL; 1605 ml->sml_type.bv_val = NULL; 1606 ml->sml_desc = ad_pwdGraceUseTime; 1607 ml->sml_numvals = 0; 1608 ml->sml_values = NULL; 1609 ml->sml_nvalues = NULL; 1610 ml->sml_next = NULL; 1611 *prev = ml; 1612 prev = &ml->sml_next; 1613 } 1614 if ( a_lock && !got_del_lock ) { 1615 ml = (Modifications *) ch_malloc( sizeof( Modifications ) ); 1616 ml->sml_op = LDAP_MOD_DELETE; 1617 ml->sml_flags = SLAP_MOD_INTERNAL; 1618 ml->sml_type.bv_val = NULL; 1619 ml->sml_desc = ad_pwdAccountLockedTime; 1620 ml->sml_numvals = 0; 1621 ml->sml_values = NULL; 1622 ml->sml_nvalues = NULL; 1623 ml->sml_next = NULL; 1624 *prev = ml; 1625 } 1626 if ( a_fail && !got_del_fail ) { 1627 ml = (Modifications *) ch_malloc( sizeof( Modifications ) ); 1628 ml->sml_op = LDAP_MOD_DELETE; 1629 ml->sml_flags = SLAP_MOD_INTERNAL; 1630 ml->sml_type.bv_val = NULL; 1631 ml->sml_desc = ad_pwdFailureTime; 1632 ml->sml_numvals = 0; 1633 ml->sml_values = NULL; 1634 ml->sml_nvalues = NULL; 1635 ml->sml_next = NULL; 1636 *prev = ml; 1637 } 1638 } 1639 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1640 be_entry_release_r( op, e ); 1641 return SLAP_CB_CONTINUE; 1642 } 1643 1644 /* Did we receive a password policy request control? */ 1645 if ( op->o_ctrlflag[ppolicy_cid] ) { 1646 send_ctrl = 1; 1647 } 1648 1649 /* See if this is a pwdModify exop. If so, we can 1650 * access the plaintext passwords from that request. 1651 */ 1652 { 1653 slap_callback *sc; 1654 1655 for ( sc = op->o_callback; sc; sc=sc->sc_next ) { 1656 if ( sc->sc_response == slap_null_cb && 1657 sc->sc_private ) { 1658 req_pwdexop_s *qpw = sc->sc_private; 1659 newpw = qpw->rs_new; 1660 oldpw = qpw->rs_old; 1661 is_pwdexop = 1; 1662 break; 1663 } 1664 } 1665 } 1666 1667 ppolicy_get( op, e, &pp ); 1668 1669 for ( ml = op->orm_modlist, 1670 pwmod = 0, mod_pw_only = 1, 1671 deladd = 0, delmod = NULL, 1672 addmod = NULL, 1673 zapReset = 1; 1674 ml != NULL; modtail = ml, ml = ml->sml_next ) 1675 { 1676 if ( ml->sml_desc == pp.ad ) { 1677 pwmod = 1; 1678 pwmop = ml->sml_op; 1679 if ((deladd == 0) && (ml->sml_op == LDAP_MOD_DELETE) && 1680 (ml->sml_values) && !BER_BVISNULL( &ml->sml_values[0] )) 1681 { 1682 deladd = 1; 1683 delmod = ml; 1684 } 1685 1686 if ((ml->sml_op == LDAP_MOD_ADD) || 1687 (ml->sml_op == LDAP_MOD_REPLACE)) 1688 { 1689 if ( ml->sml_values && !BER_BVISNULL( &ml->sml_values[0] )) { 1690 if ( deladd == 1 ) 1691 deladd = 2; 1692 1693 /* FIXME: there's no easy way to ensure 1694 * that add does not cause multiple 1695 * userPassword values; one way (that 1696 * would be consistent with the single 1697 * password constraint) would be to turn 1698 * add into replace); another would be 1699 * to disallow add. 1700 * 1701 * Let's check at least that a single value 1702 * is being added 1703 */ 1704 if ( addmod || !BER_BVISNULL( &ml->sml_values[ 1 ] ) ) { 1705 rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 1706 rs->sr_text = "Password policy only allows one password value"; 1707 goto return_results; 1708 } 1709 1710 addmod = ml; 1711 } else { 1712 /* replace can have no values, add cannot */ 1713 assert( ml->sml_op == LDAP_MOD_REPLACE ); 1714 } 1715 } 1716 1717 } else if ( !(ml->sml_flags & SLAP_MOD_INTERNAL) && !is_at_operational( ml->sml_desc->ad_type ) ) { 1718 mod_pw_only = 0; 1719 /* modifying something other than password */ 1720 } 1721 1722 /* 1723 * If there is a request to explicitly add a pwdReset 1724 * attribute, then we suppress the normal behaviour on 1725 * password change, which is to remove the pwdReset 1726 * attribute. 1727 * 1728 * This enables an administrator to assign a new password 1729 * and place a "must reset" flag on the entry, which will 1730 * stay until the user explicitly changes his/her password. 1731 */ 1732 if (ml->sml_desc == ad_pwdReset ) { 1733 if ((ml->sml_op == LDAP_MOD_ADD) || 1734 (ml->sml_op == LDAP_MOD_REPLACE)) 1735 zapReset = 0; 1736 } 1737 } 1738 1739 if (!BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn ) && !mod_pw_only ) { 1740 if ( dn_match( &op->o_conn->c_ndn, 1741 &pwcons[op->o_conn->c_conn_idx].dn )) { 1742 Debug( LDAP_DEBUG_TRACE, 1743 "connection restricted to password changing only\n", 0, 0, 0 ); 1744 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 1745 rs->sr_text = "Operations are restricted to bind/unbind/abandon/StartTLS/modify password"; 1746 pErr = PP_changeAfterReset; 1747 goto return_results; 1748 } else { 1749 ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val ); 1750 BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn ); 1751 } 1752 } 1753 1754 /* 1755 * if we have a "safe password modify policy", then we need to check if we're doing 1756 * a delete (with the old password), followed by an add (with the new password). 1757 * 1758 * If we got just a delete with nothing else, just let it go. We also skip all the checks if 1759 * the root user is bound. Root can do anything, including avoid the policies. 1760 */ 1761 1762 if (!pwmod) goto do_modify; 1763 1764 /* 1765 * Build the password history list in ascending time order 1766 * We need this, even if the user is root, in order to maintain 1767 * the pwdHistory operational attributes properly. 1768 */ 1769 if (addmod && pp.pwdInHistory > 0 && (ha = attr_find( e->e_attrs, ad_pwdHistory ))) { 1770 struct berval oldpw; 1771 time_t oldtime; 1772 1773 for(i=0; ha->a_nvals[i].bv_val; i++) { 1774 rc = parse_pwdhistory( &(ha->a_nvals[i]), NULL, 1775 &oldtime, &oldpw ); 1776 1777 if (rc != LDAP_SUCCESS) continue; /* invalid history entry */ 1778 1779 if (oldpw.bv_val) { 1780 add_to_pwd_history( &tl, oldtime, &oldpw, 1781 &(ha->a_nvals[i]) ); 1782 oldpw.bv_val = NULL; 1783 oldpw.bv_len = 0; 1784 } 1785 } 1786 for(p=tl; p; p=p->next, hsize++); /* count history size */ 1787 } 1788 1789 if (be_isroot( op )) goto do_modify; 1790 1791 /* NOTE: according to draft-behera-ldap-password-policy 1792 * pwdAllowUserChange == FALSE must only prevent pwd changes 1793 * by the user the pwd belongs to (ITS#7021) */ 1794 if (!pp.pwdAllowUserChange && dn_match(&op->o_req_ndn, &op->o_ndn)) { 1795 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 1796 rs->sr_text = "User alteration of password is not allowed"; 1797 pErr = PP_passwordModNotAllowed; 1798 goto return_results; 1799 } 1800 1801 /* Just deleting? */ 1802 if (!addmod) { 1803 /* skip everything else */ 1804 pwmod = 0; 1805 goto do_modify; 1806 } 1807 1808 /* This is a pwdModify exop that provided the old pw. 1809 * We need to create a Delete mod for this old pw and 1810 * let the matching value get found later 1811 */ 1812 if (pp.pwdSafeModify && oldpw.bv_val ) { 1813 ml = (Modifications *)ch_calloc( sizeof( Modifications ), 1 ); 1814 ml->sml_op = LDAP_MOD_DELETE; 1815 ml->sml_flags = SLAP_MOD_INTERNAL; 1816 ml->sml_desc = pp.ad; 1817 ml->sml_type = pp.ad->ad_cname; 1818 ml->sml_numvals = 1; 1819 ml->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); 1820 ber_dupbv( &ml->sml_values[0], &oldpw ); 1821 BER_BVZERO( &ml->sml_values[1] ); 1822 ml->sml_next = op->orm_modlist; 1823 op->orm_modlist = ml; 1824 delmod = ml; 1825 deladd = 2; 1826 } 1827 1828 if (pp.pwdSafeModify && deladd != 2) { 1829 Debug( LDAP_DEBUG_TRACE, 1830 "change password must use DELETE followed by ADD/REPLACE\n", 1831 0, 0, 0 ); 1832 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 1833 rs->sr_text = "Must supply old password to be changed as well as new one"; 1834 pErr = PP_mustSupplyOldPassword; 1835 goto return_results; 1836 } 1837 1838 /* Check age, but only if pwdReset is not TRUE */ 1839 pa = attr_find( e->e_attrs, ad_pwdReset ); 1840 if ((!pa || !bvmatch( &pa->a_nvals[0], &slap_true_bv )) && 1841 pp.pwdMinAge > 0) { 1842 time_t pwtime = (time_t)-1, now; 1843 int age; 1844 1845 if ((pa = attr_find( e->e_attrs, ad_pwdChangedTime )) != NULL) 1846 pwtime = parse_time( pa->a_nvals[0].bv_val ); 1847 now = slap_get_time(); 1848 age = (int)(now - pwtime); 1849 if ((pwtime != (time_t)-1) && (age < pp.pwdMinAge)) { 1850 rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 1851 rs->sr_text = "Password is too young to change"; 1852 pErr = PP_passwordTooYoung; 1853 goto return_results; 1854 } 1855 } 1856 1857 /* pa is used in password history check below, be sure it's set */ 1858 if ((pa = attr_find( e->e_attrs, pp.ad )) != NULL && delmod) { 1859 /* 1860 * we have a password to check 1861 */ 1862 bv = oldpw.bv_val ? &oldpw : delmod->sml_values; 1863 /* FIXME: no access checking? */ 1864 rc = slap_passwd_check( op, NULL, pa, bv, &txt ); 1865 if (rc != LDAP_SUCCESS) { 1866 Debug( LDAP_DEBUG_TRACE, 1867 "old password check failed: %s\n", txt, 0, 0 ); 1868 1869 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 1870 rs->sr_text = "Must supply correct old password to change to new one"; 1871 pErr = PP_mustSupplyOldPassword; 1872 goto return_results; 1873 1874 } else { 1875 int i; 1876 1877 /* 1878 * replace the delete value with the (possibly hashed) 1879 * value which is currently in the password. 1880 */ 1881 for ( i = 0; !BER_BVISNULL( &delmod->sml_values[i] ); i++ ) { 1882 free( delmod->sml_values[i].bv_val ); 1883 BER_BVZERO( &delmod->sml_values[i] ); 1884 } 1885 free( delmod->sml_values ); 1886 delmod->sml_values = ch_calloc( sizeof(struct berval), 2 ); 1887 BER_BVZERO( &delmod->sml_values[1] ); 1888 ber_dupbv( &(delmod->sml_values[0]), &(pa->a_nvals[0]) ); 1889 } 1890 } 1891 1892 bv = newpw.bv_val ? &newpw : &addmod->sml_values[0]; 1893 if (pp.pwdCheckQuality > 0) { 1894 1895 rc = check_password_quality( bv, &pp, &pErr, e, (char **)&txt ); 1896 if (rc != LDAP_SUCCESS) { 1897 rs->sr_err = rc; 1898 if ( txt ) { 1899 rs->sr_text = txt; 1900 free_txt = 1; 1901 } else { 1902 rs->sr_text = "Password fails quality checking policy"; 1903 } 1904 goto return_results; 1905 } 1906 } 1907 1908 /* If pwdInHistory is zero, passwords may be reused */ 1909 if (pa && pp.pwdInHistory > 0) { 1910 /* 1911 * Last check - the password history. 1912 */ 1913 /* FIXME: no access checking? */ 1914 if (slap_passwd_check( op, NULL, pa, bv, &txt ) == LDAP_SUCCESS) { 1915 /* 1916 * This is bad - it means that the user is attempting 1917 * to set the password to the same as the old one. 1918 */ 1919 rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 1920 rs->sr_text = "Password is not being changed from existing value"; 1921 pErr = PP_passwordInHistory; 1922 goto return_results; 1923 } 1924 1925 /* 1926 * Iterate through the password history, and fail on any 1927 * password matches. 1928 */ 1929 at = *pa; 1930 at.a_vals = cr; 1931 cr[1].bv_val = NULL; 1932 for(p=tl; p; p=p->next) { 1933 cr[0] = p->pw; 1934 /* FIXME: no access checking? */ 1935 rc = slap_passwd_check( op, NULL, &at, bv, &txt ); 1936 1937 if (rc != LDAP_SUCCESS) continue; 1938 1939 rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 1940 rs->sr_text = "Password is in history of old passwords"; 1941 pErr = PP_passwordInHistory; 1942 goto return_results; 1943 } 1944 } 1945 1946do_modify: 1947 if (pwmod) { 1948 struct berval timestamp; 1949 char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; 1950 time_t now = slap_get_time(); 1951 1952 /* If the conn is restricted, set a callback to clear it 1953 * if the pwmod succeeds 1954 */ 1955 if (!BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn )) { 1956 slap_callback *sc = op->o_tmpcalloc( 1, sizeof( slap_callback ), 1957 op->o_tmpmemctx ); 1958 sc->sc_next = op->o_callback; 1959 /* Must use sc_response to insure we reset on success, before 1960 * the client sees the response. Must use sc_cleanup to insure 1961 * that it gets cleaned up if sc_response is not called. 1962 */ 1963 sc->sc_response = ppolicy_mod_cb; 1964 sc->sc_cleanup = ppolicy_mod_cb; 1965 op->o_callback = sc; 1966 } 1967 1968 /* 1969 * keep the necessary pwd.. operational attributes 1970 * up to date. 1971 */ 1972 1973 timestamp.bv_val = timebuf; 1974 timestamp.bv_len = sizeof(timebuf); 1975 slap_timestamp( &now, ×tamp ); 1976 1977 mods = NULL; 1978 if (pwmop != LDAP_MOD_DELETE) { 1979 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 1980 mods->sml_op = LDAP_MOD_REPLACE; 1981 mods->sml_numvals = 1; 1982 mods->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); 1983 ber_dupbv( &mods->sml_values[0], ×tamp ); 1984 BER_BVZERO( &mods->sml_values[1] ); 1985 assert( !BER_BVISNULL( &mods->sml_values[0] ) ); 1986 } else if (attr_find(e->e_attrs, ad_pwdChangedTime )) { 1987 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 1988 mods->sml_op = LDAP_MOD_DELETE; 1989 } 1990 if (mods) { 1991 mods->sml_desc = ad_pwdChangedTime; 1992 mods->sml_flags = SLAP_MOD_INTERNAL; 1993 mods->sml_next = NULL; 1994 modtail->sml_next = mods; 1995 modtail = mods; 1996 } 1997 1998 if (attr_find(e->e_attrs, ad_pwdGraceUseTime )) { 1999 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2000 mods->sml_op = LDAP_MOD_DELETE; 2001 mods->sml_desc = ad_pwdGraceUseTime; 2002 mods->sml_flags = SLAP_MOD_INTERNAL; 2003 mods->sml_next = NULL; 2004 modtail->sml_next = mods; 2005 modtail = mods; 2006 } 2007 2008 if (attr_find(e->e_attrs, ad_pwdAccountLockedTime )) { 2009 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2010 mods->sml_op = LDAP_MOD_DELETE; 2011 mods->sml_desc = ad_pwdAccountLockedTime; 2012 mods->sml_flags = SLAP_MOD_INTERNAL; 2013 mods->sml_next = NULL; 2014 modtail->sml_next = mods; 2015 modtail = mods; 2016 } 2017 2018 if (attr_find(e->e_attrs, ad_pwdFailureTime )) { 2019 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2020 mods->sml_op = LDAP_MOD_DELETE; 2021 mods->sml_desc = ad_pwdFailureTime; 2022 mods->sml_flags = SLAP_MOD_INTERNAL; 2023 mods->sml_next = NULL; 2024 modtail->sml_next = mods; 2025 modtail = mods; 2026 } 2027 2028 /* Delete the pwdReset attribute, since it's being reset */ 2029 if ((zapReset) && (attr_find(e->e_attrs, ad_pwdReset ))) { 2030 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2031 mods->sml_op = LDAP_MOD_DELETE; 2032 mods->sml_desc = ad_pwdReset; 2033 mods->sml_flags = SLAP_MOD_INTERNAL; 2034 mods->sml_next = NULL; 2035 modtail->sml_next = mods; 2036 modtail = mods; 2037 } 2038 2039 if (pp.pwdInHistory > 0) { 2040 if (hsize >= pp.pwdInHistory) { 2041 /* 2042 * We use the >= operator, since we are going to add 2043 * the existing password attribute value into the 2044 * history - thus the cardinality of history values is 2045 * about to rise by one. 2046 * 2047 * If this would push it over the limit of history 2048 * values (remembering - the password policy could have 2049 * changed since the password was last altered), we must 2050 * delete at least 1 value from the pwdHistory list. 2051 * 2052 * In fact, we delete '(#pwdHistory attrs - max pwd 2053 * history length) + 1' values, starting with the oldest. 2054 * This is easily evaluated, since the linked list is 2055 * created in ascending time order. 2056 */ 2057 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2058 mods->sml_op = LDAP_MOD_DELETE; 2059 mods->sml_flags = SLAP_MOD_INTERNAL; 2060 mods->sml_desc = ad_pwdHistory; 2061 mods->sml_numvals = hsize - pp.pwdInHistory + 1; 2062 mods->sml_values = ch_calloc( sizeof( struct berval ), 2063 hsize - pp.pwdInHistory + 2 ); 2064 BER_BVZERO( &mods->sml_values[ hsize - pp.pwdInHistory + 1 ] ); 2065 for(i=0,p=tl; i < (hsize - pp.pwdInHistory + 1); i++, p=p->next) { 2066 BER_BVZERO( &mods->sml_values[i] ); 2067 ber_dupbv( &(mods->sml_values[i]), &p->bv ); 2068 } 2069 mods->sml_next = NULL; 2070 modtail->sml_next = mods; 2071 modtail = mods; 2072 } 2073 free_pwd_history_list( &tl ); 2074 2075 /* 2076 * Now add the existing password into the history list. 2077 * This will be executed even if the operation is to delete 2078 * the password entirely. 2079 * 2080 * This isn't in the spec explicitly, but it seems to make 2081 * sense that the password history list is the list of all 2082 * previous passwords - even if they were deleted. Thus, if 2083 * someone tries to add a historical password at some future 2084 * point, it will fail. 2085 */ 2086 if ((pa = attr_find( e->e_attrs, pp.ad )) != NULL) { 2087 mods = (Modifications *) ch_malloc( sizeof( Modifications ) ); 2088 mods->sml_op = LDAP_MOD_ADD; 2089 mods->sml_flags = SLAP_MOD_INTERNAL; 2090 mods->sml_type.bv_val = NULL; 2091 mods->sml_desc = ad_pwdHistory; 2092 mods->sml_nvalues = NULL; 2093 mods->sml_numvals = 1; 2094 mods->sml_values = ch_calloc( sizeof( struct berval ), 2 ); 2095 mods->sml_values[ 1 ].bv_val = NULL; 2096 mods->sml_values[ 1 ].bv_len = 0; 2097 make_pwd_history_value( timebuf, &mods->sml_values[0], pa ); 2098 mods->sml_next = NULL; 2099 modtail->sml_next = mods; 2100 modtail = mods; 2101 2102 } else { 2103 Debug( LDAP_DEBUG_TRACE, 2104 "ppolicy_modify: password attr lookup failed\n", 0, 0, 0 ); 2105 } 2106 } 2107 2108 /* 2109 * Controversial bit here. If the new password isn't hashed 2110 * (ie, is cleartext), we probably should hash it according 2111 * to the default hash. The reason for this is that we want 2112 * to use the policy if possible, but if we hash the password 2113 * before, then we're going to run into trouble when it 2114 * comes time to check the password. 2115 * 2116 * Now, the right thing to do is to use the extended password 2117 * modify operation, but not all software can do this, 2118 * therefore it makes sense to hash the new password, now 2119 * we know it passes the policy requirements. 2120 * 2121 * Of course, if the password is already hashed, then we 2122 * leave it alone. 2123 */ 2124 2125 if ((pi->hash_passwords) && (addmod) && !newpw.bv_val && 2126 (password_scheme( &(addmod->sml_values[0]), NULL ) != LDAP_SUCCESS)) 2127 { 2128 struct berval hpw, bv; 2129 2130 slap_passwd_hash( &(addmod->sml_values[0]), &hpw, &txt ); 2131 if (hpw.bv_val == NULL) { 2132 /* 2133 * hashing didn't work. Emit an error. 2134 */ 2135 rs->sr_err = LDAP_OTHER; 2136 rs->sr_text = txt; 2137 goto return_results; 2138 } 2139 bv = addmod->sml_values[0]; 2140 /* clear and discard the clear password */ 2141 memset(bv.bv_val, 0, bv.bv_len); 2142 ber_memfree(bv.bv_val); 2143 addmod->sml_values[0] = hpw; 2144 } 2145 } 2146 op->o_bd->bd_info = (BackendInfo *)on->on_info; 2147 be_entry_release_r( op, e ); 2148 return SLAP_CB_CONTINUE; 2149 2150return_results: 2151 free_pwd_history_list( &tl ); 2152 op->o_bd->bd_info = (BackendInfo *)on->on_info; 2153 be_entry_release_r( op, e ); 2154 if ( send_ctrl ) { 2155 ctrl = create_passcontrol( op, -1, -1, pErr ); 2156 oldctrls = add_passcontrol( op, rs, ctrl ); 2157 } 2158 send_ldap_result( op, rs ); 2159 if ( free_txt ) { 2160 free( (char *)txt ); 2161 rs->sr_text = NULL; 2162 } 2163 if ( send_ctrl ) { 2164 if ( is_pwdexop ) { 2165 if ( rs->sr_flags & REP_CTRLS_MUSTBEFREED ) { 2166 op->o_tmpfree( oldctrls, op->o_tmpmemctx ); 2167 } 2168 oldctrls = NULL; 2169 rs->sr_flags |= REP_CTRLS_MUSTBEFREED; 2170 2171 } else { 2172 ctrls_cleanup( op, rs, oldctrls ); 2173 } 2174 } 2175 return rs->sr_err; 2176} 2177 2178static int 2179ppolicy_parseCtrl( 2180 Operation *op, 2181 SlapReply *rs, 2182 LDAPControl *ctrl ) 2183{ 2184 if ( !BER_BVISNULL( &ctrl->ldctl_value ) ) { 2185 rs->sr_text = "passwordPolicyRequest control value not absent"; 2186 return LDAP_PROTOCOL_ERROR; 2187 } 2188 op->o_ctrlflag[ppolicy_cid] = ctrl->ldctl_iscritical 2189 ? SLAP_CONTROL_CRITICAL 2190 : SLAP_CONTROL_NONCRITICAL; 2191 2192 return LDAP_SUCCESS; 2193} 2194 2195static int 2196attrPretty( 2197 Syntax *syntax, 2198 struct berval *val, 2199 struct berval *out, 2200 void *ctx ) 2201{ 2202 AttributeDescription *ad = NULL; 2203 const char *err; 2204 int code; 2205 2206 code = slap_bv2ad( val, &ad, &err ); 2207 if ( !code ) { 2208 ber_dupbv_x( out, &ad->ad_type->sat_cname, ctx ); 2209 } 2210 return code; 2211} 2212 2213static int 2214attrNormalize( 2215 slap_mask_t use, 2216 Syntax *syntax, 2217 MatchingRule *mr, 2218 struct berval *val, 2219 struct berval *out, 2220 void *ctx ) 2221{ 2222 AttributeDescription *ad = NULL; 2223 const char *err; 2224 int code; 2225 2226 code = slap_bv2ad( val, &ad, &err ); 2227 if ( !code ) { 2228 ber_str2bv_x( ad->ad_type->sat_oid, 0, 1, out, ctx ); 2229 } 2230 return code; 2231} 2232 2233static int 2234ppolicy_db_init( 2235 BackendDB *be, 2236 ConfigReply *cr 2237) 2238{ 2239 slap_overinst *on = (slap_overinst *) be->bd_info; 2240 2241 if ( SLAP_ISGLOBALOVERLAY( be ) ) { 2242 /* do not allow slapo-ppolicy to be global by now (ITS#5858) */ 2243 if ( cr ){ 2244 snprintf( cr->msg, sizeof(cr->msg), 2245 "slapo-ppolicy cannot be global" ); 2246 Debug( LDAP_DEBUG_ANY, "%s\n", cr->msg, 0, 0 ); 2247 } 2248 return 1; 2249 } 2250 2251 /* Has User Schema been initialized yet? */ 2252 if ( !pwd_UsSchema[0].ad[0] ) { 2253 const char *err; 2254 int i, code; 2255 2256 for (i=0; pwd_UsSchema[i].def; i++) { 2257 code = slap_str2ad( pwd_UsSchema[i].def, pwd_UsSchema[i].ad, &err ); 2258 if ( code ) { 2259 if ( cr ){ 2260 snprintf( cr->msg, sizeof(cr->msg), 2261 "User Schema load failed for attribute \"%s\". Error code %d: %s", 2262 pwd_UsSchema[i].def, code, err ); 2263 Debug( LDAP_DEBUG_ANY, "%s\n", cr->msg, 0, 0 ); 2264 } 2265 return code; 2266 } 2267 } 2268 { 2269 Syntax *syn; 2270 MatchingRule *mr; 2271 2272 syn = ch_malloc( sizeof( Syntax )); 2273 *syn = *ad_pwdAttribute->ad_type->sat_syntax; 2274 syn->ssyn_pretty = attrPretty; 2275 ad_pwdAttribute->ad_type->sat_syntax = syn; 2276 2277 mr = ch_malloc( sizeof( MatchingRule )); 2278 *mr = *ad_pwdAttribute->ad_type->sat_equality; 2279 mr->smr_normalize = attrNormalize; 2280 ad_pwdAttribute->ad_type->sat_equality = mr; 2281 } 2282 } 2283 2284 on->on_bi.bi_private = ch_calloc( sizeof(pp_info), 1 ); 2285 2286 if ( dtblsize && !pwcons ) { 2287 /* accommodate for c_conn_idx == -1 */ 2288 pwcons = ch_calloc( sizeof(pw_conn), dtblsize + 1 ); 2289 pwcons++; 2290 } 2291 2292 return 0; 2293} 2294 2295static int 2296ppolicy_db_open( 2297 BackendDB *be, 2298 ConfigReply *cr 2299) 2300{ 2301 ov_count++; 2302 return overlay_register_control( be, LDAP_CONTROL_PASSWORDPOLICYREQUEST ); 2303} 2304 2305static int 2306ppolicy_close( 2307 BackendDB *be, 2308 ConfigReply *cr 2309) 2310{ 2311 slap_overinst *on = (slap_overinst *) be->bd_info; 2312 pp_info *pi = on->on_bi.bi_private; 2313 2314#ifdef SLAP_CONFIG_DELETE 2315 overlay_unregister_control( be, LDAP_CONTROL_PASSWORDPOLICYREQUEST ); 2316#endif /* SLAP_CONFIG_DELETE */ 2317 2318 /* Perhaps backover should provide bi_destroy hooks... */ 2319 ov_count--; 2320 if ( ov_count <=0 && pwcons ) { 2321 pwcons--; 2322 free( pwcons ); 2323 pwcons = NULL; 2324 } 2325 free( pi->def_policy.bv_val ); 2326 free( pi ); 2327 2328 return 0; 2329} 2330 2331static char *extops[] = { 2332 LDAP_EXOP_MODIFY_PASSWD, 2333 NULL 2334}; 2335 2336static slap_overinst ppolicy; 2337 2338int ppolicy_initialize() 2339{ 2340 int i, code; 2341 2342 for (i=0; pwd_OpSchema[i].def; i++) { 2343 code = register_at( pwd_OpSchema[i].def, pwd_OpSchema[i].ad, 0 ); 2344 if ( code ) { 2345 Debug( LDAP_DEBUG_ANY, 2346 "ppolicy_initialize: register_at failed\n", 0, 0, 0 ); 2347 return code; 2348 } 2349 /* Allow Manager to set these as needed */ 2350 if ( is_at_no_user_mod( (*pwd_OpSchema[i].ad)->ad_type )) { 2351 (*pwd_OpSchema[i].ad)->ad_type->sat_flags |= 2352 SLAP_AT_MANAGEABLE; 2353 } 2354 } 2355 2356 code = register_supported_control( LDAP_CONTROL_PASSWORDPOLICYREQUEST, 2357 SLAP_CTRL_ADD|SLAP_CTRL_BIND|SLAP_CTRL_MODIFY|SLAP_CTRL_HIDE, extops, 2358 ppolicy_parseCtrl, &ppolicy_cid ); 2359 if ( code != LDAP_SUCCESS ) { 2360 Debug( LDAP_DEBUG_ANY, "Failed to register control %d\n", code, 0, 0 ); 2361 return code; 2362 } 2363 2364 ldap_pvt_thread_mutex_init( &chk_syntax_mutex ); 2365 2366 ppolicy.on_bi.bi_type = "ppolicy"; 2367 ppolicy.on_bi.bi_db_init = ppolicy_db_init; 2368 ppolicy.on_bi.bi_db_open = ppolicy_db_open; 2369 ppolicy.on_bi.bi_db_close = ppolicy_close; 2370 2371 ppolicy.on_bi.bi_op_add = ppolicy_add; 2372 ppolicy.on_bi.bi_op_bind = ppolicy_bind; 2373 ppolicy.on_bi.bi_op_compare = ppolicy_compare; 2374 ppolicy.on_bi.bi_op_delete = ppolicy_restrict; 2375 ppolicy.on_bi.bi_op_modify = ppolicy_modify; 2376 ppolicy.on_bi.bi_op_search = ppolicy_restrict; 2377 ppolicy.on_bi.bi_connection_destroy = ppolicy_connection_destroy; 2378 2379 ppolicy.on_bi.bi_cf_ocs = ppolicyocs; 2380 code = config_register_schema( ppolicycfg, ppolicyocs ); 2381 if ( code ) return code; 2382 2383 return overlay_register( &ppolicy ); 2384} 2385 2386#if SLAPD_OVER_PPOLICY == SLAPD_MOD_DYNAMIC 2387int init_module(int argc, char *argv[]) { 2388 return ppolicy_initialize(); 2389} 2390#endif 2391 2392#endif /* defined(SLAPD_OVER_PPOLICY) */ 2393