#51012 Issue 50875 - Refactor passwordUserAttributes's and passwordBadWords's code
Closed 3 years ago by spichugi. Opened 4 years ago by spichugi.
spichugi/389-ds-base i50875  into  master

@@ -48,6 +48,7 @@ 

          'gidNumber': '4000',

          'homeDirectory': '/home/user',

          'description': 'd_e_s_c',

+         'loginShell': USER_RDN,

          'userPassword': PASSWORD

      })

  
@@ -61,7 +62,8 @@ 

      value = str(value)

      inst.config.set(attr, value)

  

-     inst.simple_bind_s(USER_DN, PASSWORD)

+     policy = inst.config.get_attr_val_utf8(attr)

+     assert policy == value

  

  

  def resetPasswd(inst):
@@ -84,6 +86,7 @@ 

      """

  

      setPolicy(inst, policy_attr, value)

+     inst.simple_bind_s(USER_DN, PASSWORD)

      users = UserAccounts(inst, DEFAULT_SUFFIX)

      user = users.get(USER_RDN)

      try:
@@ -250,17 +253,17 @@ 

  

          # Sequences

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

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

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

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

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

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

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

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

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

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

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

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

  

          # Sequence Sets

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

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

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

  

          # Max characters in a character class

          tryPassword(topology_st.standalone, 'passwordMaxClassChars', 3, 0, 'Za1_9376',
@@ -273,16 +276,94 @@ 

                      '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',

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

                      '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')

+ 

+ @pytest.mark.bz1816857

+ @pytest.mark.ds50875

+ @pytest.mark.skipif(ds_is_older("1.4.1.18"), reason="Not implemented")

+ def test_config_set_few_user_attributes(topology_st, create_user, password_policy):

+     """Test that we can successfully set multiple values to passwordUserAttributes

+ 

+     :id: 188e0aee-6e29-4857-910c-27d5606f8c08

+     :setup: Standalone instance

+     :steps:

+         1. Set passwordUserAttributes to "description loginShell"

+         2. Verify passwordUserAttributes has the values

+         3. Verify passwordUserAttributes enforced the policy

+     :expectedresults:

+         1. Operation should be successful

+         2. Operation should be successful

+         3. Operation should be successful

+     """

+ 

+     standalone = topology_st.standalone

+ 

+     standalone.log.info('Set passwordUserAttributes to "description loginShell"')

+     standalone.config.set('passwordUserAttributes', 'description loginshell')

+ 

+     standalone.restart()

+ 

+     standalone.log.info("Verify passwordUserAttributes has the values")

+     user_attrs = standalone.config.get_attr_val_utf8('passwordUserAttributes')

+     assert "description" in user_attrs

+     assert "loginshell" in user_attrs

+     standalone.log.info("Reset passwordUserAttributes")

+     standalone.config.remove_all('passwordUserAttributes')

+ 

+     standalone.log.info("Verify passwordUserAttributes enforced the policy")

+     attributes = ['description, loginShell', 'description,loginShell', 'description loginShell']

+     values = ['Za1_d_e_s_c', f'Za1_{USER_RDN}', f'Za1_d_e_s_c{USER_RDN}']

+     for attr in attributes:

+         for value in values:

+             tryPassword(standalone, 'passwordUserAttributes', attr, 0, value,

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

+ 

+ 

+ @pytest.mark.bz1816857

+ @pytest.mark.ds50875

+ @pytest.mark.skipif(ds_is_older("1.4.1.18"), reason="Not implemented")

+ def test_config_set_few_bad_words(topology_st, create_user, password_policy):

+     """Test that we can successfully set multiple values to passwordBadWords

+ 

+     :id: 2977094c-921c-4b2f-af91-4c7a45ded48b

+     :setup: Standalone instance

+     :steps:

+         1. Set passwordBadWords to "fedora redhat"

+         2. Verify passwordBadWords has the values

+         3. Verify passwordBadWords enforced the policy

+     :expectedresults:

+         1. Operation should be successful

+         2. Operation should be successful

+         3. Operation should be successful

+     """

+ 

+     standalone = topology_st.standalone

+ 

+     standalone.log.info('Set passwordBadWords to "fedora redhat"')

+     standalone.config.set('passwordBadWords', 'fedora redhat')

+ 

+     standalone.restart()

+ 

+     standalone.log.info("Verify passwordBadWords has the values")

+     user_attrs = standalone.config.get_attr_val_utf8('passwordBadWords')

+     assert "fedora" in user_attrs

+     assert "redhat" in user_attrs

+     standalone.log.info("Reset passwordBadWords")

+     standalone.config.remove_all('passwordBadWords')

+ 

+     standalone.log.info("Verify passwordBadWords enforced the policy")

+     attributes = ['redhat, fedora', 'redhat,fedora', 'redhat fedora']

+     values = ['Za1_redhat_fedora', 'Za1_fedora', 'Za1_redhat']

+     for attr in attributes:

+         for value in values:

+             tryPassword(standalone, 'passwordBadWords', attr, 'none', value,

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

  

  

  if __name__ == '__main__':

@@ -1962,20 +1962,6 @@ 

      return vlv_find_index_by_filter_txn(be, base, f, NULL);

  }

  

- /* replace c with c2 in string -- probably exists somewhere but I can't find it slapi maybe? */

- 

- static void

- replace_char(char *name, char c, char c2)

- {

-     int x;

- 

-     for (x = 0; name[x] != '\0'; x++) {

-         if (c == name[x]) {

-             name[x] = c2;

-         }

-     }

- }

- 

  /* similar to what the console GUI does */

  

  char *

file modified
+94 -57
@@ -173,7 +173,6 @@ 

  

  static int32_t config_set_onoff(const char *attrname, char *value, int32_t *configvalue, char *errorbuf, int apply);

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

- static void remove_commas(char *str);

  static int invalid_sasl_mech(char *str);

  

  
@@ -535,12 +534,12 @@ 

      {CONFIG_PW_USERATTRS_ATTRIBUTE, config_set_pw_user_attrs,

       NULL, 0,

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

-      CONFIG_CHARRAY, NULL, NULL, NULL},

+      CONFIG_STRING, 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, NULL},

+      CONFIG_STRING, NULL, "", NULL},

The patch looks good to me but I have a global concern regarding CONFIG_STRING config attribute.
the initvalue of such attributes is an initialized string, that would be on data segment (so no malloc).
The set function of those attributes usually slapi_ch_free_string the former value with the new value.
so IMHO that means a 'free' of buffer that was not malloc !.
Anyone could give a second look at this ?

@spichugi, did you test asan build with setting of 'pw_bad_words' ? anything reported ?

Opps... My fault ! This is valid. Actually the magic is done by the set_value callback that malloc/duplicate the initvalue.
So no problem with these settings of CONFIG_STRING. sorry for the noise

You have my ack.

      /* password max sequence */

      {CONFIG_PW_MAX_SEQ_ATTRIBUTE, config_set_pw_max_seq,

       NULL, 0,
@@ -2946,70 +2945,118 @@ 

      return retVal;

  }

  

+ char **

+ config_get_pw_user_attrs_array(void)

+ {

+     /*

+      * array of password user attributes. If is null, returns NULL thanks to ch_array_dup.

+      * Caller must free!

+      */

+     char **retVal;

+     slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();

+ 

+     CFG_LOCK_READ(slapdFrontendConfig);

+     retVal = slapi_ch_array_dup(slapdFrontendConfig->pw_policy.pw_cmp_attrs_array);

+     CFG_UNLOCK_READ(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) {

+         /* During a reset, the value is "", so we have to handle this case. */

+         if (strcmp(value, "") != 0) {

+             char **nval_array;

+             char *nval = slapi_ch_strdup(value);

+             /* A separate variable is used because slapi_str2charray_ext can change it and nval'd become corrupted */

+             char *tmp_array_nval = slapi_ch_strdup(nval);

+ 

+             /* We should accept comma-separated lists but slapi_str2charray_ext will process only space-separated */

+             replace_char(tmp_array_nval, ',', ' ');

              /* 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);

-         }

+             nval_array = slapi_str2charray_ext(tmp_array_nval, " ", 0);

+             slapi_ch_free_string(&tmp_array_nval);

  

-         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);

+             CFG_LOCK_WRITE(slapdFrontendConfig);

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

+             slapi_ch_array_free(slapdFrontendConfig->pw_policy.pw_cmp_attrs_array);

+             slapdFrontendConfig->pw_policy.pw_cmp_attrs = nval;

+             slapdFrontendConfig->pw_policy.pw_cmp_attrs_array = nval_array;

+             CFG_UNLOCK_WRITE(slapdFrontendConfig);

+         } else {

+             CFG_LOCK_WRITE(slapdFrontendConfig);

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

+             slapi_ch_array_free(slapdFrontendConfig->pw_policy.pw_cmp_attrs_array);

+             slapdFrontendConfig->pw_policy.pw_cmp_attrs = NULL;

+             slapdFrontendConfig->pw_policy.pw_cmp_attrs_array = NULL;

+             CFG_UNLOCK_WRITE(slapdFrontendConfig);

+          }

      }

      return retVal;

  }

  

+ char **

+ config_get_pw_bad_words_array(void)

+ {

+     /*

+      * array of words to reject. If is null, returns NULL thanks to ch_array_dup.

+      * Caller must free!

+      */

+     char **retVal;

+     slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();

+ 

+     CFG_LOCK_READ(slapdFrontendConfig);

+     retVal = slapi_ch_array_dup(slapdFrontendConfig->pw_policy.pw_bad_words_array);

+     CFG_UNLOCK_READ(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) {

+         /* During a reset, the value is "", so we have to handle this case. */

+         if (strcmp(value, "") != 0) {

+             char **nval_array;

+             char *nval = slapi_ch_strdup(value);

+             /* A separate variable is used because slapi_str2charray_ext can change it and nval'd become corrupted */

+             char *tmp_array_nval = slapi_ch_strdup(nval);

+ 

+             /* We should accept comma-separated lists but slapi_str2charray_ext will process only space-separated */

+             replace_char(tmp_array_nval, ',', ' ');

              /* 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);

-         }

+             nval_array = slapi_str2charray_ext(tmp_array_nval, " ", 0);

+             slapi_ch_free_string(&tmp_array_nval);

  

-         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);

+             CFG_LOCK_WRITE(slapdFrontendConfig);

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

+             slapi_ch_array_free(slapdFrontendConfig->pw_policy.pw_bad_words_array);

+             slapdFrontendConfig->pw_policy.pw_bad_words = nval;

+             slapdFrontendConfig->pw_policy.pw_bad_words_array = nval_array;

+             CFG_UNLOCK_WRITE(slapdFrontendConfig);

+         } else {

+             CFG_LOCK_WRITE(slapdFrontendConfig);

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

+             slapi_ch_array_free(slapdFrontendConfig->pw_policy.pw_bad_words_array);

+             slapdFrontendConfig->pw_policy.pw_bad_words = NULL;

+             slapdFrontendConfig->pw_policy.pw_bad_words_array = NULL;

+             CFG_UNLOCK_WRITE(slapdFrontendConfig);

+          }

      }

      return retVal;

  }
@@ -7338,13 +7385,13 @@ 

  

      /* During a reset, the value is "", so we have to handle this case. */

      if (strcmp(value, "") != 0) {

+         char **nval_array;

          char *nval = slapi_ch_strdup(value);

          /* A separate variable is used because slapi_str2charray_ext can change it and nval'd become corrupted */

          char *tmp_array_nval;

  

          /* cyrus sasl doesn't like comma separated lists */

-         remove_commas(nval);

-         tmp_array_nval = slapi_ch_strdup(nval);

+         replace_char(nval, ',', ' ');

  

          if (invalid_sasl_mech(nval)) {

              slapi_log_err(SLAPI_LOG_ERR, "config_set_allowed_sasl_mechs",
@@ -7353,15 +7400,18 @@ 

                            "digits, hyphens, or underscores\n",

                            nval);

              slapi_ch_free_string(&nval);

-             slapi_ch_free_string(&tmp_array_nval);

              return LDAP_UNWILLING_TO_PERFORM;

          }

+ 

+         tmp_array_nval = slapi_ch_strdup(nval);

+         nval_array = slapi_str2charray_ext(tmp_array_nval, " ", 0);

+         slapi_ch_free_string(&tmp_array_nval);

+ 

          CFG_LOCK_WRITE(slapdFrontendConfig);

          slapi_ch_free_string(&slapdFrontendConfig->allowed_sasl_mechs);

          slapi_ch_array_free(slapdFrontendConfig->allowed_sasl_mechs_array);

          slapdFrontendConfig->allowed_sasl_mechs = nval;

-         slapdFrontendConfig->allowed_sasl_mechs_array = slapi_str2charray_ext(tmp_array_nval, " ", 0);

-         slapi_ch_free_string(&tmp_array_nval);

+         slapdFrontendConfig->allowed_sasl_mechs_array = nval_array;

          CFG_UNLOCK_WRITE(slapdFrontendConfig);

      } else {

          /* If this value is "", we need to set the list to *all* possible mechs */
@@ -8593,19 +8643,6 @@ 

      return ldap_err2string(result);

  }

  

- /* replace commas with spaces */

- static void

- remove_commas(char *str)

- {

-     int i;

- 

-     for (i = 0; str && str[i]; i++) {

-         if (str[i] == ',') {

-             str[i] = ' ';

-         }

-     }

- }

- 

  /*

   * Check the SASL mechanism values

   *

@@ -304,7 +304,9 @@ 

  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);

+ char **config_get_pw_user_attrs_array(void);

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

+ char **config_get_pw_bad_words_array(void);

  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);
@@ -862,6 +864,7 @@ 

  int strarray2str(char **a, char *buf, size_t buflen, int include_quotes);

  int slapd_chown_if_not_owner(const char *filename, uid_t uid, gid_t gid);

  int slapd_comp_path(char *p0, char *p1);

+ void replace_char(char *name, char c, char c2);

  

  

  /*

file modified
+35 -30
@@ -1078,6 +1078,7 @@ 

              int num_repeated = 0;

              int max_repeated = 0;

              int num_categories = 0;

+             char **bad_words_array;

  

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

  
@@ -1099,13 +1100,16 @@ 

              }

  

              /* 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])) {

+             bad_words_array = config_get_pw_bad_words_array();

+             if (bad_words_array) {

+                 for (size_t b = 0; bad_words_array && bad_words_array[b]; b++) {

+                     if (strcasestr(pwd, bad_words_array[b])) {

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

+                         charray_free(bad_words_array);

                          return (1);

                      }

                  }

+                 charray_free(bad_words_array);

              }

  

              /* Check for sequences */
@@ -1320,6 +1324,7 @@ 

  

      /* check for trivial words if syntax checking is enabled */

      if (pwpolicy->pw_syntax == LDAP_ON) {

+         char **user_attrs_array;

          /* e is null if this is an add operation*/

          if (check_trivial_words(pb, e, vals, "uid", pwpolicy->pw_mintokenlength, smods) == 1 ||

              check_trivial_words(pb, e, vals, "cn", pwpolicy->pw_mintokenlength, smods) == 1 ||
@@ -1334,15 +1339,18 @@ 

              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 ){

+         user_attrs_array = config_get_pw_user_attrs_array();

+         if (user_attrs_array) {

+             for (size_t a = 0; user_attrs_array && user_attrs_array[a]; a++) {

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

                      if (mod_op) {

                          slapi_entry_free(e);

                      }

+                     charray_free(user_attrs_array);

                      return 1;

                  }

              }

+             charray_free(user_attrs_array);

          }

      }

  
@@ -2247,35 +2255,32 @@ 

                      }

                  } 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);

+                         char *attrs = slapi_ch_strdup(slapi_value_get_string(*sval));

+                         /* we need a separate string because it gets corrupted after slapi_str2charray_ext */

+                         char *tmp_array_attrs = slapi_ch_strdup(attrs);

+ 

+                         /* we should accept comma-separated lists but slapi_str2charray_ext will process only space-separated */

+                         replace_char(tmp_array_attrs, ',', ' ');

+ 

                          pwdpolicy->pw_cmp_attrs = attrs;

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

+                         pwdpolicy->pw_cmp_attrs_array = slapi_str2charray_ext(tmp_array_attrs, " ", 0);

+                         slapi_ch_free_string(&tmp_array_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);

+                         char *words = slapi_ch_strdup(slapi_value_get_string(*sval));

+                         /* we need a separate string because it gets corrupted after slapi_str2charray_ext */

+                         char *tmp_array_words = slapi_ch_strdup(words);

+ 

+                         /* we should accept comma-separated lists but slapi_str2charray_ext will process only space-separated */

+                         replace_char(tmp_array_words, ',', ' ');

+ 

                          pwdpolicy->pw_bad_words = words;

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

+                         pwdpolicy->pw_bad_words_array = slapi_str2charray_ext(tmp_array_words, " ", 0);

+ 

+                         slapi_ch_free_string(&tmp_array_words);

                      }

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

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

file modified
+4 -2
@@ -1813,10 +1813,12 @@ 

                                       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

+     char *pw_cmp_attrs;           /* Comma-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 */

+     char **pw_cmp_attrs_array;    /* Array of password user attributes */

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

+     char **pw_bad_words_array;    /* Array of words to reject */

  

      slapi_onoff_t pw_exp;

      slapi_onoff_t pw_send_expiring;

file modified
+12 -1
@@ -467,6 +467,17 @@ 

      }

  }

  

+ /* replace c with c2 in str */

+ void

+ replace_char(char *str, char c, char c2)

+ {

+     for (size_t i = 0; (str != NULL) && (str[i] != NULL); i++) {

+         if (c == str[i]) {

+             str[i] = c2;

+         }

+     }

+ }

+ 

  /*

  ** This function takes a quoted attribute value of the form "abc",

  ** and strips off the enclosing quotes.  It also deals with quoted
@@ -1635,4 +1646,4 @@ 

          }

          return 0;

      }

- } 

\ No newline at end of file

+ }

Bug Description: Searches on cn=config takes values with spaces and
makes multiple attributes out of them. If we set passwordUserAttributes
to "cn uid givenname", it will transform it in a multi-valued attribute.

Fix Description: Change passwordUserAttributes's and passwordBadWords's type
to CONFIG_STRING (it was CONFIG_CHARRAY). Add an additional parameter
to store the array (and use it in pw.c).
The string and array processing is similar to nsslapd-allowed-sasl-mechanisms.
Add a test.

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

Reviewed by: ?

You don't have to NULL check here, charray_free() can handle NULL. Same thing for the password user attribute code below...

If you haven't done so can you please do a quick ASAN test to make sure we are not leaking anything?

You don't have to NULL check here, charray_free() can handle NULL. Same thing for the password user attribute code below...

Sure!

If you haven't done so can you please do a quick ASAN test to make sure we are not leaking anything?

Yeah, about that... I have two news:

  1. I've done it and my code is leak-free as far as I am aware;
  2. I've spent half of the day debugging and trying to understand how my code affects the password policy passwordMaxSeqSets attrubute because the test has started to fail...

    Then, after some time, I've checked the ASAN build on master and it also has failed. So...
    Somehow, passwordMaxSeqSets fails only on ASAN build. All the tests pass on our usual RPM build (and my PR is okay too).

I've created an issue for further investigation:
https://pagure.io/389-ds-base/issue/51013

Nice catch, gotta love ASAN :-)

Ack for this issue!

If this islocking and changing the config, maybe it should be in libglobs.c?

Is there a test for the badwords array changes?

why 'all possible mechs' ? This is related to forbiden password words not mechanism. Am I missing something ?

Same, is it 'mechs' or 'password' ?

Is it a space " " separator ? I thought it was comma separator.

I thought it was comma separated list.
Is this list valid ? "passwordUserAttributes: telephonenumber, givenname,cn" (note the space before 'givenname')

If this islocking and changing the config, maybe it should be in libglobs.c?

But it is in libglobs.c... Do I miss something?

Is there a test for the badwords array changes?

Good catch, gonna add it!

I thought it was comma separated list.
Is this list valid ? "passwordUserAttributes: telephonenumber, givenname,cn" (note the space before 'givenname')

It is not valid and it was not (the way the code was written before).
But after you said that, I checked our docs, and it says "comma-separated list".
So I am gonna add the functionality. Thanks!

why not strcasecmp

I took it from the original code. We need to check for a substring here (if our password has the bad word or not).

And... Looks like we got some indentation issues here :-p @firstyear, sorry I didn't catch that sooner, maybe it's just your patches where the indentation stands out more haha

1 new commit added

  • Fix PR's issues
4 years ago

2 new commits added

  • Fix PR's issues
  • Issue 50875 - Refactor passwordUserAttributes's and passwordBadWords's code
4 years ago

Changes are done! Please, review

Should be size_t, and it should be declared inside of the for loop: for (size_t i = 0; ...

Should be size_t, and it should be declared inside of the for loop: for (size_t i = 0; ...

Besides this issue, if this build passes ASAN tests then ACK from me.

I think it initvalue should be NULL not an empty string. "" is pointer in data segment (IIRC) and slapi_ch_free_string will not like that.

comment does not apply any more

minor point
It looks similar to replace_char defined in 'vlv.c'.
You could move replace_char from vlv.c to util.c and call "replace_char(s, ',', ' ')"

minor point
It looks similar to replace_char defined in 'vlv.c'.
You could move replace_char from vlv.c to util.c and call "replace_char(s, ',', ' ')"

Good catch! Thanks!

Should be size_t, and it should be declared inside of the for loop: for (size_t i = 0; ...

Done.

I think it initvalue should be NULL not an empty string. "" is pointer in data segment (IIRC) and slapi_ch_free_string will not like that.

If we set the init value to NULL and then if we try to delete the attribute, it won't reset the value and it will throw LDAP_UNWILLING_TO_PERFORM. More info here:
https://pagure.io/389-ds-base/blob/master/f/ldap/servers/slapd/libglobs.c#_40
And the code itself is here:
https://pagure.io/389-ds-base/blob/master/f/ldap/servers/slapd/libglobs.c#_7983

I think we still want to be able to reset the value (and not setting it manually to "")...

1 new commit added

  • Fix PR's issues 2
4 years ago

Changes are made. Please, review :)

Otherwise all good, thanks!

The patch looks good to me but I have a global concern regarding CONFIG_STRING config attribute.
the initvalue of such attributes is an initialized string, that would be on data segment (so no malloc).
The set function of those attributes usually slapi_ch_free_string the former value with the new value.
so IMHO that means a 'free' of buffer that was not malloc !.
Anyone could give a second look at this ?

@spichugi, did you test asan build with setting of 'pw_bad_words' ? anything reported ?

Opps... My fault ! This is valid. Actually the magic is done by the set_value callback that malloc/duplicate the initvalue.
So no problem with these settings of CONFIG_STRING. sorry for the noise

You have my ack.

rebased onto 36c593d

4 years ago

@spichugi, did you test asan build with setting of 'pw_bad_words' ? anything reported ?

Everything is clean.
Thank you!

Pull-Request has been merged by spichugi

4 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/4065

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