#49836 Ticket 49794 - Add pam_pwquality features to password syntax checking
Closed 3 years ago by spichugi. Opened 5 years ago by mreynolds.
mreynolds/389-ds-base ticket49794  into  master

file modified
+2 -1
@@ -178,6 +178,7 @@ 

  PAM_LINK = -lpam

  KERBEROS_LINK = $(kerberos_lib)

  EVENT_LINK = @event_lib@

+ PW_CRACK_LINK = -lcrack

  

  LIBSOCKET=@LIBSOCKET@

  LIBNSL=@LIBNSL@
@@ -192,7 +193,7 @@ 

  AM_LDFLAGS = -lpthread

  else

  #AM_LDFLAGS = -Wl,-z,defs

- AM_LDFLAGS = $(RUST_LDFLAGS) $(ASAN_CFLAGS) $(MSAN_CFLAGS) $(TSAN_CFLAGS) $(UBSAN_CFLAGS) $(PROFILING_LINKS) $(CLANG_LDFLAGS)

+ AM_LDFLAGS = $(PW_CRACK_LINK) $(RUST_LDFLAGS) $(ASAN_CFLAGS) $(MSAN_CFLAGS) $(TSAN_CFLAGS) $(UBSAN_CFLAGS) $(PROFILING_LINKS) $(CLANG_LDFLAGS)

  endif #end hpux

  

  # https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info

@@ -41,6 +41,7 @@ 

          USER_DN, {

              'objectClass': 'top account simplesecurityobject'.split(),

              'uid': 'user',

+             'description': 'd_e_s_c',

              'userpassword': PASSWORD

          })))

  
@@ -169,6 +170,19 @@ 

          26. Set userPassword to 'password' in cn=config

          27. Set userPassword to 'PASSWORD' in cn=config

          28. Set passwordMinUppers to 0 in cn=config

+         29. Test passwordDictCheck

+         30. Test passwordPalindrome

+         31. Test passwordMaxSequence for forward number sequence

+         32. Test passwordMaxSequence for backward number sequence

+         33. Test passwordMaxSequence for forward alpha sequence

+         34. Test passwordMaxSequence for backward alpha sequence

+         35. Test passwordMaxClassChars for digits

+         36. Test passwordMaxClassChars for specials

+         37. Test passwordMaxClassChars for lowers

+         38. Test passwordMaxClassChars for uppers

+         39. Test passwordBadWords using 'redhat' and 'fedora'

+         40. Test passwordUserAttrs using description attribute

+ 

      :expectedresults:

          1. passwordMinLength should be successfully set

          2. Password should be rejected because length too short
@@ -203,6 +217,18 @@ 

              it does not contain minimum number of lowercase characters

          27. Password should be accepted

          28. passwordMinUppers should be successfully set

+         29. The passwordDictCheck test succeeds

+         30. The passwordPalindrome test succeeds

+         31. Test passwordMaxSequence for forward number sequence succeeds

+         32. Test passwordMaxSequence for backward number sequence succeeds

+         33. Test passwordMaxSequence for forward alpha sequence succeeds

+         34. Test passwordMaxSequence for backward alpha sequence succeeds

+         35. Test passwordMaxClassChars for digits succeeds

+         36. Test passwordMaxClassChars for specials succeeds

+         37. Test passwordMaxClassChars for lowers succeeds

+         38. Test passwordMaxClassChars for uppers succeeds

+         39. The passwordBadWords test succeeds

+         40. The passwordUserAttrs test succeeds

      """

  

      #
@@ -235,6 +261,49 @@ 

                  'does not contain minimum number of lowercase characters')

      # Min 8-bits - "ldap" package only accepts ascii strings at the moment

  

+     if ds_is_newer('1.4.0.13'):

+         # Dictionary check

+         tryPassword(topology_st.standalone, 'passwordDictCheck', 'on', 'on', 'PASSWORD',

+                     '13_#Kad472h', 'Password found in dictionary')

+ 

+         # Palindromes

+         tryPassword(topology_st.standalone, 'passwordPalindrome', 'on', 'on', 'Za12_#_21aZ',

+                     '13_#Kad472h', 'Password is palindrome')

+ 

+         # Sequences

+         tryPassword(topology_st.standalone, 'passwordMaxSequence', 3, 0, 'Za1_1234',

+                     '13_#Kad472h', 'Max montonic sequence is not allowed')

+         tryPassword(topology_st.standalone, 'passwordMaxSequence', 3, 0, 'Za1_4321',

+                     '13_#Kad472h', 'Max montonic sequence is not allowed')

+         tryPassword(topology_st.standalone, 'passwordMaxSequence', 3, 0, 'Za1_abcd',

+                     '13_#Kad472h', 'Max montonic sequence is not allowed')

+         tryPassword(topology_st.standalone, 'passwordMaxSequence', 3, 0, 'Za1_dcba',

+                     '13_#Kad472h', 'Max montonic sequence is not allowed')

+ 

+         # Sequence Sets

+         tryPassword(topology_st.standalone, 'passwordMaxSeqSets', 2, 0, 'Za1_123--123',

+                     '13_#Kad472h', 'Max montonic sequence is not allowed')

+ 

+         # Max characters in a character class

+         tryPassword(topology_st.standalone, 'passwordMaxClassChars', 3, 0, 'Za1_9376',

+                     '13_#Kad472h', 'Too may consecutive characters from the same class')

+         tryPassword(topology_st.standalone, 'passwordMaxClassChars', 3, 0, 'Za1_#$&!',

+                     '13_#Kad472h', 'Too may consecutive characters from the same class')

+         tryPassword(topology_st.standalone, 'passwordMaxClassChars', 3, 0, 'Za1_ahtf',

+                     '13_#Kad472h', 'Too may consecutive characters from the same class')

+         tryPassword(topology_st.standalone, 'passwordMaxClassChars', 3, 0, 'Za1_HTSE',

+                     '13_#Kad472h', 'Too may consecutive characters from the same class')

+ 

+         # Bad words

+         tryPassword(topology_st.standalone, 'passwordBadWords', 'redhat fedora', 'none', 'Za1_redhat',

+                     '13_#Kad472h', 'Too may consecutive characters from the same class')

+         tryPassword(topology_st.standalone, 'passwordBadWords', 'redhat fedora', 'none', 'Za1_fedora',

+                     '13_#Kad472h', 'Too may consecutive characters from the same class')

+ 

+         # User Attributes

+         tryPassword(topology_st.standalone, 'passwordUserAttributes', 'description', 0, 'Za1_d_e_s_c',

+                     '13_#Kad472h', 'Password found in user entry')

+ 

      log.info('pwdPolicy tests PASSED')

  

  

@@ -68,6 +68,14 @@ 

  attributeTypes: ( 2.16.840.1.113730.3.1.2153 NAME ( 'passwordAdminDN' 'pwdAdminDN' ) DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )

  attributeTypes: ( 2.16.840.1.113730.3.1.2140 NAME ( 'passwordTrackUpdateTime' ) DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )

  attributeTypes: ( 2.16.840.1.113730.3.1.2329 NAME ( 'passwordSendExpiringTime' 'pwdSendExpiringTime' ) DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )

+ attributeTypes: ( 2.16.840.1.113730.3.1.2345 NAME ( 'passwordPalindrome' 'pwdPalindrome' ) DESC '389 Directory Server password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN '389 Directory Server' )

+ attributeTypes: ( 2.16.840.1.113730.3.1.2346 NAME ( 'passwordMaxSequence' 'pwdMaxSequence' ) DESC '389 Directory Server password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN '389 Directory Server' )

+ attributeTypes: ( 2.16.840.1.113730.3.1.2347 NAME ( 'passwordMaxSeqSets' 'pwdMaxSeqSets' ) DESC '389 Directory Server password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN '389 Directory Server' )

+ attributeTypes: ( 2.16.840.1.113730.3.1.2348 NAME ( 'passwordMaxClassChars' 'pwdMaxClassChars' ) DESC '389 Directory Server password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN '389 Directory Server' )

+ attributeTypes: ( 2.16.840.1.113730.3.1.2349 NAME ( 'passwordDictCheck' 'pwdDictCheck' ) DESC '389 Directory Server password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN '389 Directory Server' )

+ attributeTypes: ( 2.16.840.1.113730.3.1.2350 NAME ( 'passwordDictPath' 'pwdDictPath' ) DESC '389 Directory Server password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN '389 Directory Server' )

+ attributeTypes: ( 2.16.840.1.113730.3.1.2351 NAME ( 'passwordUserAttributes' 'pwdUserAttributes' ) DESC '389 Directory Server password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN '389 Directory Server' )

+ attributeTypes: ( 2.16.840.1.113730.3.1.2352 NAME ( 'passwordBadWords' 'pwdBadWords' ) DESC '389 Directory Server password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN '389 Directory Server' )

  attributeTypes: ( 2.16.840.1.113730.3.1.198 NAME 'memberURL' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Directory Server' )

  attributeTypes: ( 2.16.840.1.113730.3.1.199 NAME 'memberCertificateDescription' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Directory Server' )

  attributeTypes: ( 2.16.840.1.113730.3.1.207 NAME 'vlvBase' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape Directory Server' )

@@ -194,6 +194,8 @@ 

  slapi_onoff_t init_pw_change;

  slapi_onoff_t init_pw_exp;

  slapi_onoff_t init_pw_send_expiring;

+ slapi_onoff_t init_pw_palindrome;

+ slapi_onoff_t init_pw_dict_check;

  slapi_onoff_t init_allow_hashed_pw;

  slapi_onoff_t init_pw_syntax;

  slapi_onoff_t init_schemacheck;
@@ -499,6 +501,47 @@ 

       NULL, 0,

       (void **)&global_slapdFrontendConfig.pw_policy.pw_mintokenlength,

       CONFIG_INT, NULL, SLAPD_DEFAULT_PW_MINTOKENLENGTH_STR},

+ 

+     /* Password palindrome */

+     {CONFIG_PW_PALINDROME_ATTRIBUTE, config_set_pw_palindrome,

+      NULL, 0,

+      (void **)&global_slapdFrontendConfig.pw_policy.pw_palindrome,

+      CONFIG_ON_OFF, NULL, &init_pw_palindrome},

+     /* password dictionary check */

+     {CONFIG_PW_CHECK_DICT_ATTRIBUTE, config_set_pw_dict_check,

+      NULL, 0,

+      (void **)&global_slapdFrontendConfig.pw_policy.pw_check_dict,

+      CONFIG_ON_OFF, NULL, &init_pw_dict_check},

+     /* password dictionary path */

+     {CONFIG_PW_DICT_PATH_ATTRIBUTE, config_set_pw_dict_path,

+       NULL, 0,

+       (void **)&global_slapdFrontendConfig.pw_policy.pw_dict_path,

+       CONFIG_STRING, NULL, ""},

+     /* password user attr check list */

+     {CONFIG_PW_USERATTRS_ATTRIBUTE, config_set_pw_user_attrs,

+      NULL, 0,

+      (void **)&global_slapdFrontendConfig.pw_policy.pw_cmp_attrs,

+      CONFIG_CHARRAY, NULL, NULL},

+     /* password bad work list */

+     {CONFIG_PW_BAD_WORDS_ATTRIBUTE, config_set_pw_bad_words,

+      NULL, 0,

+      (void **)&global_slapdFrontendConfig.pw_policy.pw_bad_words,

+      CONFIG_CHARRAY, NULL, NULL},

+     /* password max sequence */

+     {CONFIG_PW_MAX_SEQ_ATTRIBUTE, config_set_pw_max_seq,

+      NULL, 0,

+      (void **)&global_slapdFrontendConfig.pw_policy.pw_max_seq,

+      CONFIG_INT, NULL, SLAPD_DEFAULT_PW_MAX_SEQ_ATTRIBUTE_STR},

+     /* Max sequence sets */

+     {CONFIG_PW_MAX_SEQ_SETS_ATTRIBUTE, config_set_pw_max_seq_sets,

+      NULL, 0,

+      (void **)&global_slapdFrontendConfig.pw_policy.pw_seq_char_sets,

+      CONFIG_INT, NULL, SLAPD_DEFAULT_PW_MAX_SEQ_SETS_ATTRIBUTE_STR},

+     /* password max repeated characters per class */

+     {CONFIG_PW_MAX_CLASS_CHARS_ATTRIBUTE, config_set_pw_max_class_repeats,

+      NULL, 0,

+      (void **)&global_slapdFrontendConfig.pw_policy.pw_max_class_repeats,

+      CONFIG_INT, NULL, SLAPD_DEFAULT_PW_MAX_CLASS_CHARS_ATTRIBUTE_STR},

      {CONFIG_ERRORLOG_ATTRIBUTE, config_set_errorlog,

       NULL, 0,

       (void **)&global_slapdFrontendConfig.errorlog,
@@ -1467,6 +1510,8 @@ 

      init_pw_unlock = pw_policy->pw_unlock;

      init_pw_is_legacy = pw_policy->pw_is_legacy;

      init_pw_track_update_time = pw_policy->pw_track_update_time;

+     init_pw_palindrome = pw_policy->pw_palindrome;

+     init_pw_dict_check = pw_policy->pw_check_dict;

  }

  

  void
@@ -2751,6 +2796,220 @@ 

      return retVal;

  }

  

+ int32_t

+ config_set_pw_palindrome(const char *attrname, char *value, char *errorbuf, int apply)

+ {

+     int32_t retVal = LDAP_SUCCESS;

+     slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();

+ 

+     retVal = config_set_onoff(attrname,

+                               value,

+                               &(slapdFrontendConfig->pw_policy.pw_palindrome),

+                               errorbuf,

+                               apply);

+ 

+     return retVal;

+ }

+ 

+ int32_t

+ config_set_pw_dict_check(const char *attrname, char *value, char *errorbuf, int apply)

+ {

+     int32_t retVal = LDAP_SUCCESS;

+     slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();

+ 

+     retVal = config_set_onoff(attrname,

+                               value,

+                               &(slapdFrontendConfig->pw_policy.pw_check_dict),

+                               errorbuf,

+                               apply);

+ 

+     return retVal;

+ }

+ 

+ int32_t

+ config_set_pw_dict_path(const char *attrname, char *value, char *errorbuf, int apply)

+ {

+     int retVal = LDAP_SUCCESS;

+     slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();

+ 

+     if (config_value_is_null(attrname, value, errorbuf, 0)) {

+         value = NULL;

+     } else {

+         /* We have a value, do some basic checks */

+         if (value[0] != '/') {

+             /* Not a path - error */

+             slapi_create_errormsg(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,

+                                   "password dictionary path \"%s\" is invalid.", value);

+             retVal = LDAP_OPERATIONS_ERROR;

+             return retVal;

+         }

+     }

+ 

+     if (apply) {

+         CFG_LOCK_WRITE(slapdFrontendConfig);

+         slapi_ch_free_string(&slapdFrontendConfig->pw_policy.pw_dict_path);

+         slapdFrontendConfig->pw_policy.pw_dict_path = slapi_ch_strdup(value);

+         CFG_UNLOCK_WRITE(slapdFrontendConfig);

+     }

+     return retVal;

+ }

+ 

+ int32_t

+ config_set_pw_user_attrs(const char *attrname, char *value, char *errorbuf, int apply)

+ {

+     int retVal = LDAP_SUCCESS;

+     char **attrs = NULL;

+     slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();

+ 

+     if (config_value_is_null(attrname, value, errorbuf, 0)) {

+         value = NULL;

+     }

+     if (apply) {

+         if (value) {

+             /* Take list of attributes and break it up into a char array */

+             char *attr = NULL;

+             char *token = NULL;

+             char *next = NULL;

+ 

+             token = slapi_ch_strdup(value);

+             for (attr = ldap_utf8strtok_r(token, " ", &next); attr != NULL;

+                  attr = ldap_utf8strtok_r(NULL, " ", &next))

+             {

+                 slapi_ch_array_add(&attrs, slapi_ch_strdup(attr));

+             }

+             slapi_ch_free_string(&token);

+         }

+ 

+         CFG_LOCK_WRITE(slapdFrontendConfig);

+         slapi_ch_array_free(slapdFrontendConfig->pw_policy.pw_cmp_attrs);

+         slapdFrontendConfig->pw_policy.pw_cmp_attrs = attrs;

+         CFG_UNLOCK_WRITE(slapdFrontendConfig);

+     }

+     return retVal;

+ }

+ 

+ int32_t

+ config_set_pw_bad_words(const char *attrname, char *value, char *errorbuf, int apply)

+ {

+     int retVal = LDAP_SUCCESS;

+     char **words = NULL;

+     slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();

+ 

+     if (config_value_is_null(attrname, value, errorbuf, 0)) {

+         value = NULL;

+     }

+     if (apply) {

+         if (value) {

+             /* Take list of attributes and break it up into a char array */

+             char *word = NULL;

+             char *token = NULL;

+             char *next = NULL;

+ 

+             token = slapi_ch_strdup(value);

+             for (word = ldap_utf8strtok_r(token, " ", &next); word != NULL;

+                  word = ldap_utf8strtok_r(NULL, " ", &next))

+             {

+                 slapi_ch_array_add(&words, slapi_ch_strdup(word));

+             }

+             slapi_ch_free_string(&token);

+         }

+ 

+         CFG_LOCK_WRITE(slapdFrontendConfig);

+         slapi_ch_array_free(slapdFrontendConfig->pw_policy.pw_bad_words);

+         slapdFrontendConfig->pw_policy.pw_bad_words = words;

+         CFG_UNLOCK_WRITE(slapdFrontendConfig);

+     }

+     return retVal;

+ }

+ 

+ int32_t

+ config_set_pw_max_seq(const char *attrname, char *value, char *errorbuf, int apply)

+ {

+     int retVal = LDAP_SUCCESS;

+     int32_t max = 0;

+     char *endp = NULL;

+     slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();

+ 

+     if (config_value_is_null(attrname, value, errorbuf, 0)) {

+         max = 0;

+     } else {

+         errno = 0;

+         max = (int32_t)strtol(value, &endp, 10);

+ 

+         if (*endp != '\0' || errno == ERANGE || max < 0 || max > 10) {

+             slapi_create_errormsg(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,

+                                   "password maximum sequence \"%s\" is invalid. The range is from 0 to 10.", value);

+             retVal = LDAP_OPERATIONS_ERROR;

+             return retVal;

+         }

+     }

+     if (apply) {

+         CFG_LOCK_WRITE(slapdFrontendConfig);

+         slapdFrontendConfig->pw_policy.pw_max_seq = max;

+         CFG_UNLOCK_WRITE(slapdFrontendConfig);

+     }

+     return retVal;

+ }

+ 

+ 

+ int32_t

+ config_set_pw_max_seq_sets(const char *attrname, char *value, char *errorbuf, int apply)

+ {

+     int retVal = LDAP_SUCCESS;

+     int32_t max = 0;

+     char *endp = NULL;

+     slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();

+ 

+     if (config_value_is_null(attrname, value, errorbuf, 0)) {

+         max = 0;

+     } else {

+         errno = 0;

+         max = (int32_t)strtol(value, &endp, 10);

+ 

+         if (*endp != '\0' || errno == ERANGE || max < 0 || max > 10) {

+             slapi_create_errormsg(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,

+                                   "password maximum sequence sets \"%s\" is invalid. The range is from 0 to 10.", value);

+             retVal = LDAP_OPERATIONS_ERROR;

+             return retVal;

+         }

+     }

+     if (apply) {

+         CFG_LOCK_WRITE(slapdFrontendConfig);

+         slapdFrontendConfig->pw_policy.pw_seq_char_sets = max;

+         CFG_UNLOCK_WRITE(slapdFrontendConfig);

+     }

+     return retVal;

+ }

+ 

+ int32_t

+ config_set_pw_max_class_repeats(const char *attrname, char *value, char *errorbuf, int apply)

+ {

+     int retVal = LDAP_SUCCESS;

+     int32_t max = 0;

+     char *endp = NULL;

+     slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();

+ 

+     if (config_value_is_null(attrname, value, errorbuf, 0)) {

+         max = 0;

+     } else {

+         errno = 0;

+         max = (int32_t)strtol(value, &endp, 10);

+ 

+         if (*endp != '\0' || errno == ERANGE || max < 0 || max > 1024) {

+             slapi_create_errormsg(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,

+                     "password maximum repated characters per characters class \"%s\" is invalid. "

+                     "The range is from 0 to 1024.", value);

+             retVal = LDAP_OPERATIONS_ERROR;

+             return retVal;

+         }

+     }

+     if (apply) {

+         CFG_LOCK_WRITE(slapdFrontendConfig);

+         slapdFrontendConfig->pw_policy.pw_max_class_repeats = max;

+         CFG_UNLOCK_WRITE(slapdFrontendConfig);

+     }

+     return retVal;

+ }

  

  int

  config_set_pw_minlength(const char *attrname, char *value, char *errorbuf, int apply)

@@ -299,6 +299,16 @@ 

  int config_set_allow_hashed_pw(const char *attrname, char *value, char *errorbuf, int apply);

  int config_set_pwpolicy_inherit_global(const char *attrname, char *value, char *errorbuf, int apply);

  int config_set_pw_syntax(const char *attrname, char *value, char *errorbuf, int apply);

+ 

+ int32_t config_set_pw_palindrome(const char *attrname, char *value, char *errorbuf, int apply);

+ int32_t config_set_pw_dict_check(const char *attrname, char *value, char *errorbuf, int apply);

+ int32_t config_set_pw_dict_path(const char *attrname, char *value, char *errorbuf, int apply);

+ int32_t config_set_pw_user_attrs(const char *attrname, char *value, char *errorbuf, int apply);

+ int32_t config_set_pw_bad_words(const char *attrname, char *value, char *errorbuf, int apply);

+ int32_t config_set_pw_max_seq_sets(const char *attrname, char *value, char *errorbuf, int apply);

+ int32_t config_set_pw_max_seq(const char *attrname, char *value, char *errorbuf, int apply);

+ int32_t config_set_pw_max_class_repeats(const char *attrname, char *value, char *errorbuf, int apply);

+ 

  int config_set_pw_minlength(const char *attrname, char *value, char *errorbuf, int apply);

  int config_set_pw_mindigits(const char *attrname, char *value, char *errorbuf, int apply);

  int config_set_pw_minalphas(const char *attrname, char *value, char *errorbuf, int apply);

file modified
+345 -21
@@ -1,6 +1,6 @@ 

  /** BEGIN COPYRIGHT BLOCK

   * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.

-  * Copyright (C) 2009 Red Hat, Inc.

+  * Copyright (C) 2018 Red Hat, Inc.

   * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.

   * All rights reserved.

   *
@@ -12,6 +12,63 @@ 

   * See LICENSE for details.

   * END COPYRIGHT BLOCK **/

  

+ /* Copyright notice below for using portions of pam_pwquality source code

+  * (pam_cracklib.c) */

+ /*

+  * Copyright (c) Cristian Gafton <gafton@redhat.com>, 1996.

+  *                                              All rights reserved

+  *

+  * Redistribution and use in source and binary forms, with or without

+  * modification, are permitted provided that the following conditions

+  * are met:

+  * 1. Redistributions of source code must retain the above copyright

+  *    notice, and the entire permission notice in its entirety,

+  *    including the disclaimer of warranties.

+  * 2. Redistributions in binary form must reproduce the above copyright

+  *    notice, this list of conditions and the following disclaimer in the

+  *    documentation and/or other materials provided with the distribution.

+  * 3. The name of the author may not be used to endorse or promote

+  *    products derived from this software without specific prior

+  *    written permission.

+  *

+  * ALTERNATIVELY, this product may be distributed under the terms of

+  * the GNU Public License, in which case the provisions of the GPL are

+  * required INSTEAD OF the above restrictions.  (This clause is

+  * necessary due to a potential bad interaction between the GPL and

+  * the restrictions contained in a BSD-style copyright.)

+  *

+  * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED

+  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

+  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE

+  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,

+  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES

+  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR

+  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)

+  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,

+  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)

+  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED

+  * OF THE POSSIBILITY OF SUCH DAMAGE.

+  *

+  * The following copyright was appended for the long password support

+  * added with the libpam 0.58 release:

+  *

+  * Modificaton Copyright (c) Philip W. Dalrymple III <pwd@mdtsoft.com>

+  *       1997. All rights reserved

+  *

+  * THE MODIFICATION THAT PROVIDES SUPPORT FOR LONG PASSWORD TYPE CHECKING TO

+  * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED

+  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

+  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE

+  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,

+  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES

+  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR

+  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)

+  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,

+  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)

+  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED

+  * OF THE POSSIBILITY OF SUCH DAMAGE.

+  */

+ 

  #ifdef HAVE_CONFIG_H

  #include <config.h>

  #endif
@@ -25,12 +82,12 @@ 

  #include <string.h>

  #include <sys/types.h>

  #include <sechash.h>

- #if defined(USE_MOZLDAP)

- #define LDAP_MOD_OP (0x0007)

- #endif /* USE_MOZLDAP */

- 

+ #include <crack.h>

  #include "slap.h"

  

+ #ifndef CRACKLIB_DICTS

+ #define CRACKLIB_DICTS NULL

+ #endif

  

  #define DENY_PW_CHANGE_ACI "(targetattr = \"userPassword\") ( version 3.0; acl \"disallow_pw_change_aci\"; deny (write ) userdn = \"ldap:///self\";)"

  #define GENERALIZED_TIME_LENGTH 15
@@ -769,6 +826,156 @@ 

      return (0);

  }

  

+ 

+ /* pam_pwquality functions */

+ static int

+ palindrome(const char *new)

+ {

+     int i, j;

+ 

+     i = strlen(new);

+     for (j = 0;j < i;j++)

+         if (new[i - j - 1] != new[j])

+             return 0;

+ 

+     return 1;

+ }

+ 

+ static int

+ pw_sequence_sets(const char *new, int32_t max_seq, int check_sets)

+ {

+     char c;

+     int i;

+     int sequp = 1;

+     int seqdown = 1;

+ 

+     if (new[0] == '\0')

+         return 0;

+ 

+     for (i = 1; new[i]; i++) {

+         c = new[i-1];

+         if (new[i] == c+1) {

+             ++sequp;

+             if (sequp > max_seq) {

+                 if (check_sets) {

+                     /* remember this seq, can call pw_sequence on remaining password */

+                     char *remaining = slapi_ch_smprintf("%s", new + i);

+                     char token[11];

+ 

+                     memcpy(token, new + (i - max_seq), max_seq);

+                     if (strstr(remaining, token)) {

+                         /* we have a duplicate set */

+                         slapi_ch_free_string(&remaining);

+                         return 1;

+                     }

+                     slapi_ch_free_string(&remaining);

+                 } else {

+                     return 1;

+                 }

+             }

+             seqdown = 1;

+         } else if (new[i] == c-1) {

+             ++seqdown;

+             if (seqdown > max_seq) {

+                 if (check_sets) {

+                     /* remember this seq, so we can check if it occurs again */

+                     char *remaining = slapi_ch_smprintf("%s", new + i);

+                     char token[11] = {0};

+ 

+                     memcpy(token, new + (i - max_seq), max_seq);

+                     if (strstr(remaining, token)) {

+                         /* we have a duplicate set */

+                         slapi_ch_free_string(&remaining);

+                         return 1;

+                     }

+                     slapi_ch_free_string(&remaining);

+ 

+                 } else {

+                     return 1;

+                 }

+             }

+             sequp = 1;

+         } else {

+             sequp = 1;

+             seqdown = 1;

+         }

+     }

+     return 0;

+ }

+ 

+ static int

+ pw_sequence(const char *new, int32_t max_seq)

+ {

+     return pw_sequence_sets(new, max_seq, 0);

+ }

+ 

+ static int

+ pw_max_class_repeats(const char *new, int32_t max_repeats)

+ {

+     int digits = 0;

+     int uppers = 0;

+     int lowers = 0;

+     int others = 0;

+     int i;

+     enum { NONE, DIGIT, UCASE, LCASE, OTHER } prevclass = NONE;

+     int sameclass = 0;

+ 

+     for (i = 0; new[i]; i++) {

+         if (isdigit(new[i])) {

+             digits++;

+             if (prevclass != DIGIT) {

+                 prevclass = DIGIT;

+                 sameclass = 1;

+             } else {

+                 sameclass++;

+             }

+         } else if (isupper (new[i])) {

+             uppers++;

+             if (prevclass != UCASE) {

+                 prevclass = UCASE;

+                 sameclass = 1;

+             } else {

+                 sameclass++;

+             }

+         } else if (islower (new[i])) {

+             lowers++;

+             if (prevclass != LCASE) {

+                 prevclass = LCASE;

+                 sameclass = 1;

+             } else {

+                 sameclass++;

+             }

+         } else {

+             others++;

+             if (prevclass != OTHER) {

+                 prevclass = OTHER;

+                 sameclass = 1;

+             } else {

+                 sameclass++;

+             }

+         }

+         if (sameclass > max_repeats) {

+             return 1;

+         }

+     }

+     return 0;

+ }

+ 

+ static void

+ report_pw_violation(Slapi_PBlock *pb, int pwresponse_req, char *fmt, ...)

+ {

+     char errormsg[SLAPI_DSE_RETURNTEXT_SIZE] = {0};

+     va_list msg;

+ 

+     va_start(msg, fmt);

+     PR_vsnprintf(errormsg, SLAPI_DSE_RETURNTEXT_SIZE - 1, fmt, msg);

+     if (pwresponse_req == 1) {

+         slapi_pwpolicy_make_response_control(pb, -1, -1, LDAP_PWPOLICY_INVALIDPWDSYNTAX);

+     }

+     pw_send_ldap_result(pb, LDAP_CONSTRAINT_VIOLATION, NULL, errormsg, 0, NULL);

+     va_end(msg);

+ }

+ 

  /* check_pw_syntax is called before add or modify operation on userpassword attribute*/

  

  int
@@ -835,12 +1042,9 @@ 

          if (slapi_is_encoded((char *)slapi_value_get_string(vals[i]))) {

              if (!is_replication && !config_get_allow_hashed_pw() &&

                  ((internal_op && pb_conn && !slapi_dn_isroot(pb_conn->c_dn)) ||

-                  (!internal_op && !pw_is_pwp_admin(pb, pwpolicy)))) {

-                 PR_snprintf(errormsg, sizeof(errormsg) - 1, "invalid password syntax - passwords with storage scheme are not allowed");

-                 if (pwresponse_req == 1) {

-                     slapi_pwpolicy_make_response_control(pb, -1, -1, LDAP_PWPOLICY_INVALIDPWDSYNTAX);

-                 }

-                 pw_send_ldap_result(pb, LDAP_CONSTRAINT_VIOLATION, NULL, errormsg, 0, NULL);

+                  (!internal_op && !pw_is_pwp_admin(pb, pwpolicy))))

+             {

+                 report_pw_violation(pb, pwresponse_req, "invalid password syntax - passwords with storage scheme are not allowed");

                  return (1);

              } else {

                  /* We want to skip syntax checking since this is a pre-hashed password */
@@ -862,21 +1066,71 @@ 

              int max_repeated = 0;

              int num_categories = 0;

  

-             /* check for the minimum password length */

-             if (pwpolicy->pw_minlength >

-                 (int)ldap_utf8characters((char *)slapi_value_get_string(vals[i]))) {

-                 PR_snprintf(errormsg, sizeof(errormsg) - 1, "invalid password syntax - password must be at least %d characters long",

-                             pwpolicy->pw_minlength);

-                 if (pwresponse_req == 1) {

-                     slapi_pwpolicy_make_response_control(pb, -1, -1,

-                                                          LDAP_PWPOLICY_PWDTOOSHORT);

+             pwd = (char *)slapi_value_get_string(vals[i]);

+ 

+             /* Check dictionary */

+             if (pwpolicy->pw_check_dict) {

+                 const char *crack_msg;

+                 if ((crack_msg = FascistCheck(pwd, pwpolicy->pw_dict_path))) {

+                     report_pw_violation(pb, pwresponse_req, "Password failed dictionary check: %s", crack_msg);

+                     return (1);

                  }

-                 pw_send_ldap_result(pb, LDAP_CONSTRAINT_VIOLATION, NULL, errormsg, 0, NULL);

+             }

+ 

+             /* check palindrome */

+             if (pwpolicy->pw_palindrome) {

+                 if (palindrome(pwd)) {

+                     report_pw_violation(pb, pwresponse_req, "Password is a palindrome");

+                     return (1);

+                 }

+             }

+ 

+             /* Check for bad words */

+             if (pwpolicy->pw_bad_words) {

+                 for (size_t b = 0; pwpolicy->pw_bad_words && pwpolicy->pw_bad_words[b]; b++) {

+                     if (strcasestr(pwd, pwpolicy->pw_bad_words[b])) {

+                         report_pw_violation(pb, pwresponse_req, "Password contains a restricted word");

+                         return (1);

+                     }

+                 }

+             }

+ 

+             /* Check for sequences */

+             if (pwpolicy->pw_max_seq) {

+                 if (pw_sequence(pwd, pwpolicy->pw_max_seq)) {

+                     report_pw_violation(pb, pwresponse_req, "Password contains a monotonic sequence");

+                     PR_snprintf(errormsg, sizeof(errormsg) - 1, "Password contains a monotonic sequence");

+ 

+                     return (1);

+                 }

+             }

+ 

+             /* Check for sets of sequences */

+             if (pwpolicy->pw_seq_char_sets) {

+                 if (pw_sequence_sets(pwd, pwpolicy->pw_seq_char_sets, 1)){

+                     report_pw_violation(pb, pwresponse_req, "Password contains repeated identical sequences");

+                     return (1);

+                 }

+             }

+ 

+             /* Check for max repeated characters from the same class */

+             if (pwpolicy->pw_max_class_repeats) {

+                 if (pw_max_class_repeats(pwd, pwpolicy->pw_max_class_repeats)){

+                     report_pw_violation(pb, pwresponse_req,

+                             "Password contains too many repeated characters from the same character class");

+                     return (1);

+                 }

+             }

+ 

+             /* check for the minimum password length */

+             if (pwpolicy->pw_minlength > (int)ldap_utf8characters((char *)pwd)) {

+                 report_pw_violation(pb, pwresponse_req,

+                         "invalid password syntax - password must be at least %d characters long",

+                         pwpolicy->pw_minlength);

                  return (1);

              }

  

              /* check character types */

-             pwd = (char *)slapi_value_get_string(vals[i]);

              p = pwd;

              while (p && *p) {

                  if (ldap_utf8isdigit(p)) {
@@ -1066,6 +1320,17 @@ 

  

              return 1;

          }

+         /* Check user attributes */

+         if (pwpolicy->pw_cmp_attrs) {

+             for (size_t a = 0; pwpolicy->pw_cmp_attrs && pwpolicy->pw_cmp_attrs[a]; a++) {

+                 if (check_trivial_words(pb, e, vals, pwpolicy->pw_cmp_attrs[a], pwpolicy->pw_mintokenlength, smods) == 1 ){

+                     if (mod_op) {

+                         slapi_entry_free(e);

+                     }

+                     return 1;

+                 }

+             }

+         }

      }

  

      if (mod_op) {
@@ -1947,6 +2212,64 @@ 

                          pwdpolicy->pw_admin = slapi_sdn_new_dn_byval(slapi_value_get_string(*sval));

                          pw_get_admin_users(pwdpolicy);

                      }

+                 } else if (!strcasecmp(attr_name, "passwordPalindrome")) {

+                     if ((sval = attr_get_present_values(attr))) {

+                         pwdpolicy->pw_palindrome =

+                             pw_boolean_str2value(slapi_value_get_string(*sval));

+                     }

+                 } else if (!strcasecmp(attr_name, "passwordDictCheck")) {

+                     if ((sval = attr_get_present_values(attr))) {

+                         pwdpolicy->pw_check_dict =

+                             pw_boolean_str2value(slapi_value_get_string(*sval));

+                     }

+                 } else if (!strcasecmp(attr_name, "passwordUserAttributes")) {

+                     if ((sval = attr_get_present_values(attr))) {

+                         char **attrs = NULL;

+                         char *attr = NULL;

+                         char *token = NULL;

+                         char *next = NULL;

+ 

+                         token = slapi_ch_strdup(slapi_value_get_string(*sval));

+                         for (attr = ldap_utf8strtok_r(token, " ", &next); attr != NULL;

+                              attr = ldap_utf8strtok_r(NULL, " ", &next))

+                         {

+                             slapi_ch_array_add(&attrs, slapi_ch_strdup(attr));

+                         }

+                         slapi_ch_free_string(&token);

+                         pwdpolicy->pw_cmp_attrs = attrs;

+                     }

+                 }  else if (!strcasecmp(attr_name, "passwordBadWords")) {

+                     if ((sval = attr_get_present_values(attr))) {

+                         char **words = NULL;

+                         char *word = NULL;

+                         char *token = NULL;

+                         char *next = NULL;

+ 

+                         token = slapi_ch_strdup(slapi_value_get_string(*sval));

+                         for (word = ldap_utf8strtok_r(token, " ", &next); word != NULL;

+                              word = ldap_utf8strtok_r(NULL, " ", &next))

+                         {

+                             slapi_ch_array_add(&words, slapi_ch_strdup(word));

+                         }

+                         slapi_ch_free_string(&token);

+                         pwdpolicy->pw_bad_words = words;

+                     }

+                 } else if (!strcasecmp(attr_name, "passwordMaxSequence")) {

+                     if ((sval = attr_get_present_values(attr))) {

+                         pwdpolicy->pw_max_seq = slapi_value_get_int(*sval);

+                     }

+                 } else if (!strcasecmp(attr_name, "passwordMaxSeqSets")) {

+                     if ((sval = attr_get_present_values(attr))) {

+                         pwdpolicy->pw_seq_char_sets = slapi_value_get_int(*sval);

+                     }

+                 } else if (!strcasecmp(attr_name, "passwordMaxClassChars")) {

+                     if ((sval = attr_get_present_values(attr))) {

+                         pwdpolicy->pw_max_class_repeats = slapi_value_get_int(*sval);

+                     }

+                 } else if (!strcasecmp(attr_name, "passwordDictPath")) {

+                     if ((sval = attr_get_present_values(attr))) {

+                         pwdpolicy->pw_dict_path = (char *)slapi_value_get_string(*sval);

+                     }

                  }

              } /* end of for() loop */

              if (pw_entry) {
@@ -2913,3 +3236,4 @@ 

      slapi_log_err(SLAPI_LOG_TRACE, "add_shadow_ext_password_attrs", "<=\n");

      return rc;

  }

+ 

file modified
+43 -10
@@ -397,6 +397,14 @@ 

  #define SLAPD_DEFAULT_PW_LOCKDURATION 3600

  #define SLAPD_DEFAULT_PW_LOCKDURATION_STR "3600"

  

+ #define SLAPD_DEFAULT_PW_MAX_SEQ_ATTRIBUTE 0

+ #define SLAPD_DEFAULT_PW_MAX_SEQ_ATTRIBUTE_STR "0"

+ #define SLAPD_DEFAULT_PW_MAX_SEQ_SETS_ATTRIBUTE 0

+ #define SLAPD_DEFAULT_PW_MAX_SEQ_SETS_ATTRIBUTE_STR "0"

+ #define SLAPD_DEFAULT_PW_MAX_CLASS_CHARS_ATTRIBUTE 0

+ #define SLAPD_DEFAULT_PW_MAX_CLASS_CHARS_ATTRIBUTE_STR "0"

+ 

+ 

  /* Default password values. */

  

  /* ================ END CONFIGURATION DEFAULTS ============================ */
@@ -1752,16 +1760,33 @@ 

      slapi_onoff_t pw_change;      /* 1 - indicates that users are allowed to change the pwd */

      slapi_onoff_t pw_must_change; /* 1 - indicates that users must change pwd upon reset */

      slapi_onoff_t pw_syntax;

-     int pw_minlength;

-     int pw_mindigits;

-     int pw_minalphas;

-     int pw_minuppers;

-     int pw_minlowers;

-     int pw_minspecials;

-     int pw_min8bit;

-     int pw_maxrepeats;

-     int pw_mincategories;

-     int pw_mintokenlength;

+     int32_t pw_minlength;

+     int32_t pw_mindigits;

+     int32_t pw_minalphas;

+     int32_t pw_minuppers;

+     int32_t pw_minlowers;

+     int32_t pw_minspecials;

+     int32_t pw_min8bit;

+     int32_t pw_maxrepeats;

+     int32_t pw_mincategories;

+     int32_t pw_mintokenlength;

+ 

+     slapi_onoff_t pw_palindrome;  /* Reject passwords that are palindromes */

+     int32_t pw_max_seq;           /* max number of monotonic sequences: 2345, lmnop */

+     int32_t pw_seq_char_sets;     /* max number of identical monotonic sequences that are

+                                    * allowed multiple times.  For example: "az12of12", if

+                                    * value is set to 2, meaning sequence of two

+                                    * characters, then this password would be blocked.  If

+                                    * it's set to 3, then the password is allowed. */

+     int32_t pw_max_class_repeats; /* The maximum number of consecutive characters from

+                                      the same character class. */

+     slapi_onoff_t pw_check_dict;

+     char *pw_dict_path;           /* custom dictionary */

+     char **pw_cmp_attrs;          /* Space-separated list of attributes to see if the

+                                      attribute values (and reversed values) in the entry

+                                      are contained in the new password. */

+     char **pw_bad_words;          /* Space-separated list of words to reject */

+ 

      slapi_onoff_t pw_exp;

      slapi_onoff_t pw_send_expiring;

      time_t pw_maxage;
@@ -2109,6 +2134,14 @@ 

  #define CONFIG_PW_MAXREPEATS_ATTRIBUTE "passwordMaxRepeats"

  #define CONFIG_PW_MINCATEGORIES_ATTRIBUTE "passwordMinCategories"

  #define CONFIG_PW_MINTOKENLENGTH_ATTRIBUTE "passwordMinTokenLength"

+ #define CONFIG_PW_PALINDROME_ATTRIBUTE "passwordPalindrome"

+ #define CONFIG_PW_MAX_SEQ_ATTRIBUTE "passwordMaxSequence"

+ #define CONFIG_PW_MAX_SEQ_SETS_ATTRIBUTE "passwordMaxSeqSets"

+ #define CONFIG_PW_MAX_CLASS_CHARS_ATTRIBUTE "passwordMaxClassChars"

+ #define CONFIG_PW_CHECK_DICT_ATTRIBUTE "passwordDictCheck"

+ #define CONFIG_PW_DICT_PATH_ATTRIBUTE "passwordDictPath"

+ #define CONFIG_PW_USERATTRS_ATTRIBUTE "passwordUserAttributes"

+ #define CONFIG_PW_BAD_WORDS_ATTRIBUTE "passwordBadWords"

  #define CONFIG_PW_EXP_ATTRIBUTE "passwordExp"

  #define CONFIG_PW_MAXAGE_ATTRIBUTE "passwordMaxAge"

  #define CONFIG_PW_MINAGE_ATTRIBUTE "passwordMinAge"

file modified
+1
@@ -73,6 +73,7 @@ 

  BuildRequires:    icu

  BuildRequires:    libicu-devel

  BuildRequires:    pcre-devel

+ BuildRequires:    cracklib-devel

  %if %{use_clang}

  BuildRequires:    libatomic

  BuildRequires:    clang

Description: Added the following pam_pwquality fartures to DS. We can
not add all the features because some of them require that
you have the the previous or current password in clear text.

           New features:

             - Check password is not in dictionary
             - Password is not a palindrome
             - Maximum allowed monotonic sequence characters
             - Maximum allowed monotonic sequence characters that can
               be repeated.
             - Maximum number of consectuve characters from the same
               class of characters (digits, alphas, specials, etc)
             - List of words that are not allowed to appear in the new
               password
             - List of attributes to check in the user's entry to see
               if those values are in the new password.

https://pagure.io/389-ds-base/issue/49794

Reviewed by: ?

rebased onto e487ae847ab95971512caf29e9dbe96edd67c7c2

5 years ago

rebased onto cc808a7b3a4bec12cf4f620a1733428026c724e4

5 years ago

I'll read through the C code but I'll let others check it.

Couple of issues:

  • I think, we need to add this to the spec file:

    BuildRequires:    cracklib-devel
    
  • the test you've added fails here - tryPassword(topology_st.standalone, 'passwordDictCheck', 'on', 'on', 'PASSWORD', '13_#Kad472h', 'Password found in dictionary')

    pwdPolicy_syntax_test.py   127 CRITICAL Failed to change password: {'desc': 'Constraint violation', 'info': 'Password failed dictionary check: \x18'}
    

rebased onto d9be40917af0e2b895cfd60218a207b562c9afd1

5 years ago

The problem is selinux is blocking the cracklib dictionary files. I opened a selinux bug

https://bugzilla.redhat.com/show_bug.cgi?id=1599726

rebased onto a6a3f79de924667016645cb22d998707d7eeb3cc

5 years ago

These tests fail on older versions of 389-ds-base, that don't have these attributes. Perhaps we should skip them if ds version is <=1.4.0.13.

Is it okay that we have SYNTAX == 1.3.6.1.4.1.1466.115.121.1.15 (Directory String syntax) but the actual value is int? Should we set it accordingly?
I am not advising but asking...

Nice catch, yes several of these of should be changed to int syntax

Do we need to actually? If we don't backport this test, then it will be in sync with the source code and version checking is not needed. Thoughts?

We run tests from master on older versions. It's easier than maintaining different sets of tests in different branches for different feature sets. Here's one example: https://pagure.io/389-ds-base/blob/master/f/dirsrvtests/tests/suites/plugins/acceptance_test.py#_34

oh okay, no problem I'll get that added and rebase shortly

rebased onto 8651a1494fbcd4eb6ce8f79ae312681a441d1352

5 years ago

rebased onto fd8ca9a

5 years ago

Pull-Request has been merged by mreynolds

5 years ago

389-ds-base is moving from Pagure to Github. This means that new issues and pull requests
will be accepted only in 389-ds-base's github repository.

This pull request has been cloned to Github as issue and is available here:
- https://github.com/389ds/389-ds-base/issues/2895

If you want to continue to work on the PR, please navigate to the github issue,
download the patch from the attachments and file a new pull request.

Thank you for understanding. We apologize for all inconvenience.

Pull-Request has been closed by spichugi

3 years ago