Ceci est un message signC) cryptographiquement au format MIME.
--------------ms000000000208070102090606 Content-Type: multipart/mixed; boundary="------------050908090805020607010105"
This is a multi-part message in MIME format. --------------050908090805020607010105 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: quoted-printable
Here is the patch. --=20 Guillaume Rousse INRIA, Direction des syst=E8mes d'information Domaine de Voluceau Rocquencourt - BP 105 78153 Le Chesnay Tel: 01 39 63 58 31
--------------050908090805020607010105 Content-Type: text/x-patch; name="0001-ITS-7348-new-check_password-contrib-module.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename*0="0001-ITS-7348-new-check_password-contrib-module.patch"
=46rom fa2f6730171ab5755f56ca66715b723df726026d Mon Sep 17 00:00:00 2001 From: Guillaume Rousse guillomovitch@gmail.com Date: Tue, 7 Aug 2012 17:39:21 +0200 Subject: [PATCH] ITS #7348: new check_password contrib module
Signed-off-by: Guillaume Rousse Guillame.Rousse@inria.fr --- contrib/slapd-modules/README | 3 + contrib/slapd-modules/check-password/Makefile | 52 +++ contrib/slapd-modules/check-password/README | 146 +++++++++ .../slapd-modules/check-password/check_password.c | 356 +++++++++++++++= ++++++ 4 files changed, 557 insertions(+) create mode 100644 contrib/slapd-modules/check-password/Makefile create mode 100644 contrib/slapd-modules/check-password/README create mode 100644 contrib/slapd-modules/check-password/check_password.c=
diff --git a/contrib/slapd-modules/README b/contrib/slapd-modules/README index db74379..d8005ff 100644 --- a/contrib/slapd-modules/README +++ b/contrib/slapd-modules/README @@ -20,6 +20,9 @@ allop (overlay) autogroup (overlay) Automated updates of group memberships. =20 +check_password (plugin) + External password quality check module for ppolicy + cloak (overlay) Hide specific attributes unless explicitely requested =20 diff --git a/contrib/slapd-modules/check-password/Makefile b/contrib/slap= d-modules/check-password/Makefile new file mode 100644 index 0000000..42dd18f --- /dev/null +++ b/contrib/slapd-modules/check-password/Makefile @@ -0,0 +1,52 @@ + +LDAP_SRC =3D ../../.. +LDAP_BUILD =3D ../../.. +LDAP_INC =3D -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)= /servers/slapd +LDAP_LIB =3D $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +CRACKLIB_PATH =3D /usr/share/cracklib/pw_dict +CRACKLIB_INC =3D=20 +CRACKLIB_LIB =3D -lcrack + +CONFIG_PATH =3D /etc/openldap/check_password.conf + +LIBTOOL =3D $(LDAP_BUILD)/libtool +CC =3D gcc +OPT =3D -g -O2 -Wall +DEFS =3D -DHAVE_CRACKLIB -DCRACKLIB_DICTPATH=3D""$(CRACKLIB_PATH)"" \ + -DCONFIG_FILE=3D""$(CONFIG_PATH)"" -DDEBUG +INCS =3D $(LDAP_INC) $(CRACKLIB_INC) +LIBS =3D $(LDAP_LIB) $(CRACKLIB_LIB) + +PROGRAMS =3D check_password.la +LTVER =3D 0:0:0 + +prefix=3D/usr/local +exec_prefix=3D$(prefix) +ldap_subdir=3D/openldap + +libdir=3D$(exec_prefix)/lib +libexecdir=3D$(exec_prefix)/libexec +moduledir =3D $(libexecdir)$(ldap_subdir) + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=3Dcompile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +check_password.la: check_password.lo + $(LIBTOOL) --mode=3Dlink $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf *.o *.lo *.la .libs + +install: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=3Dinstall cp $$p $(DESTDIR)$(moduledir) ; \ + done + diff --git a/contrib/slapd-modules/check-password/README b/contrib/slapd-= modules/check-password/README new file mode 100644 index 0000000..10191c2 --- /dev/null +++ b/contrib/slapd-modules/check-password/README @@ -0,0 +1,146 @@ + +check_password.c - OpenLDAP pwdChecker library + +2007-06-06 Michael Steinmann msl@calivia.com +2008-01-30 Pierre-Yves Bonnetain py.bonnetain@ba-cst.com +2009 Clement Oudot clem.oudot@gmail.com - LTB-project +2009 Jerome HUET - LTB-project + +check_password.c is an OpenLDAP pwdPolicyChecker module used to check th= e +strength and quality of user-provided passwords. + +This module is used as an extension of the OpenLDAP password policy cont= rols, +see slapo-ppolicy(5) section pwdCheckModule. + +check_password.c will run a number of checks on the passwords to ensure = minimum +strength and quality requirements are met. Passwords that do not meet th= ese +requirements are rejected. + + +Password checks +--------------- + - passwords shorter than 6 characters are rejected if cracklib is used = (because + cracklib WILL reject them). + + - syntactic checks controls how many different character classes are us= ed + (lower, upper, digit and punctuation characters). The minimum number = of + classes is defined in a configuration file. You can set the minimum f= or each + class. + + - passwords are checked against cracklib if cracklib is enabled at comp= ile + time. It can be disabled in configuration file. + +INSTALLATION +------------ +Use the provided Makefile to build the module. + +Compilation constants : + +CONFIG_FILE : Path to the configuration file.=20 + Defaults to /etc/openldap/check_password.conf + +DEBUG : If defined, check_password will syslog() its actions. + +Build dependencies +cracklib header files (link with -lcrack). The Makefile does not look fo= r +cracklib; you may need to provide the paths manually. + +Install into the slapd server module path. Change the installation +path to match with the OpenLDAP module path in the Makefile. + +The module may be defined with slapd.conf parameter "modulepath". + +USAGE +----- +To use this module you need to add objectClass pwdPolicyChecker with an =
+attribute 'pwdCheckModule: check_password.so' to a password policy entry= =2E + +The module depends on a working cracklib installation including wordlist= files. +If the wordlist files are not readable, the cracklib check will be skipp= ed +silently. + +Note: pwdPolicyChecker modules are loaded on *every* password change ope= ration. + +Configuration +------------- +The configuration file (/etc/openldap/check_password.conf by default) co= ntains +parameters for the module. If the file is not found, parameters are give= n their +default value. + +The syntax of the file is : + +parameter value + +with spaces being delimiters. Parameter names ARE case sensitive (this m= ay +change in the future). + +Current parameters : + +- useCracklib: integer. Default value: 1. Set it to 0 to disable crackl= ib verification. + It has no effect if cracklib is not included at compile time. + +- minPoints: integer. Default value: 3. Minimum number of quality point= s a new + password must have to be accepted. One quality point is awarded for e= ach character + class used in the password. + +- minUpper: integer. Defaut value: 0. Minimum upper characters expected.=
+ +- minLower: integer. Defaut value: 0. Minimum lower characters expected.=
+ +- minDigit: integer. Defaut value: 0. Minimum digit characters expected.=
+ +- minPunct: integer. Defaut value: 0. Minimum punctuation characters exp= ected. + +Logs +---- +If a user password is rejected by an OpenLDAP pwdChecker module, the use= r will +*not* get a detailed error message, this is by design. + +Typical user message from ldappasswd(5): + Result: Constraint violation (19) + Additional info: Password fails quality checking policy + +A more detailed message is written to the server log. + +Server log: + check_password_quality: module error: (check_password.so) + Password for dn=3D".." does not pass required number of strength check= s (2 of 3) + + +Caveats +------- +Runtime errors with this module (such as cracklib configuration problems= ) may +bring down the slapd process. + +Use at your own risk. + + +TODO +---- +* use proper malloc function, see ITS#4998 + + +HISTORY +------- +* 2009-10-30 Clement OUDOT - LTB-project + Version 1.1 + - Apply patch from Jerome HUET for minUpper/minLower/minDigit/minPunc= t + +* 2009-02-05 Clement Oudot clem.oudot@gmail.com - LINAGORA Group + Version 1.0.3 + - Add useCracklib parameter in config file (with help of Pascal Pejac)=
+ - Prefix log messages with "check_password: " + - Log what character type is found for quality checking + +* 2008-01-31 Pierre-Yves Bonnetain py.bonnetain@ba-cst.com + Version 1.0.2 + - Several bug fixes. + - Add external config file + +* 2007-06-06 Michael Steinmann msl@calivia.com + Version 1.0.1 + - add dn to error messages + +* 2007-06-02 Michael Steinmann msl@calivia.com + Version 1.0 + diff --git a/contrib/slapd-modules/check-password/check_password.c b/cont= rib/slapd-modules/check-password/check_password.c new file mode 100644 index 0000000..da427e7 --- /dev/null +++ b/contrib/slapd-modules/check-password/check_password.c @@ -0,0 +1,356 @@ +/* + * check_password.c for OpenLDAP + * + * See LICENSE, README and INSTALL files + */ + +#include <string.h> +#include <ctype.h> +#include <portable.h> +#include <slap.h> + +#ifdef HAVE_CRACKLIB +#include "crack.h" +#endif + +#if defined(DEBUG) +#include <syslog.h> +#endif + +#ifndef CRACKLIB_DICTPATH +#define CRACKLIB_DICTPATH "/usr/share/cracklib/pw_dict" +#endif + +#ifndef CONFIG_FILE +#define CONFIG_FILE "/etc/openldap/check_password.conf" +#endif + +#define DEFAULT_QUALITY 3 +#define DEFAULT_CRACKLIB 1 +#define MEMORY_MARGIN 50 +#define MEM_INIT_SZ 64 +#define FILENAME_MAXLEN 512 + +#define PASSWORD_TOO_SHORT_SZ \ + "Password for dn=3D"%s" is too short (%d/6)" +#define PASSWORD_QUALITY_SZ \ + "Password for dn=3D"%s" does not pass required number of strength che= cks (%d of %d)" +#define BAD_PASSWORD_SZ \ + "Bad password for dn=3D"%s" because %s" + +typedef int (*validator) (char*); +static int read_config_file (char *); +static validator valid_word (char *); +static int set_quality (char *); +static int set_cracklib (char *); + +int check_password (char *pPasswd, char **ppErrStr, Entry *pEntry); + +static int set_quality (char *value) +{ +#if defined(DEBUG) + syslog(LOG_NOTICE, "check_password: Setting quality to [%s]", value); +#endif + + /* No need to require more quality than we can check for. */ + if (!isdigit(*value) || (int) (value[0] - '0') > 4) return DEFAULT_QUAL= ITY; + return (int) (value[0] - '0'); + +} + +static int set_cracklib (char *value) +{ +#if defined(DEBUG) + syslog(LOG_NOTICE, "check_password: Setting cracklib usage to [%s]", va= lue); +#endif + + + return (int) (value[0] - '0'); + +} + +static int set_digit (char *value) +{ +#if defined(DEBUG) + syslog(LOG_NOTICE, "check_password: Setting parameter to [%s]", value);=
+#endif + if (!isdigit(*value) || (int) (value[0] - '0') > 9) return 0; + return (int) (value[0] - '0'); +} + +static validator valid_word (char *word) +{ + struct { + char * parameter; + validator dealer; + } list[] =3D { { "minPoints", set_quality }, + { "useCracklib", set_cracklib }, + { "minUpper", set_digit }, + { "minLower", set_digit }, + { "minDigit", set_digit }, + { "minPunct", set_digit }, + { NULL, NULL } }; + int index =3D 0; + +#if defined(DEBUG) + syslog(LOG_NOTICE, "check_password: Validating parameter [%s]", word); +#endif + + while (list[index].parameter !=3D NULL) { + if (strlen(word) =3D=3D strlen(list[index].parameter) && + strcmp(list[index].parameter, word) =3D=3D 0) { +#if defined(DEBUG) + syslog(LOG_NOTICE, "check_password: Parameter accepted."); +#endif + return list[index].dealer; + } + index++; + } + +#if defined(DEBUG) + syslog(LOG_NOTICE, "check_password: Parameter rejected."); +#endif + + return NULL; +} + +static int read_config_file (char *keyWord) +{ + FILE * config; + char * line; + int returnValue =3D -1; + + if ((line =3D ber_memcalloc(260, sizeof(char))) =3D=3D NULL) { + return returnValue; + } + + if ( (config =3D fopen(CONFIG_FILE, "r")) =3D=3D NULL) { +#if defined(DEBUG) + syslog(LOG_ERR, "check_password: Opening file %s failed", CONFIG_FILE)= ; +#endif + + ber_memfree(line); + return returnValue; + } + + while (fgets(line, 256, config) !=3D NULL) { + char *start =3D line; + char *word, *value; + validator dealer; + +#if defined(DEBUG) + /* Debug traces to syslog. */ + syslog(LOG_NOTICE, "check_password: Got line |%s|", line); +#endif + + while (isspace(*start) && isascii(*start)) start++; + + if (! isascii(*start)) + continue; + + if ((word =3D strtok(start, " \t")) && (dealer =3D valid_word(word)) &= & (strcmp(keyWord,word)=3D=3D0)) { + if ((value =3D strtok(NULL, " \t")) =3D=3D NULL) + continue; + +#if defined(DEBUG) + syslog(LOG_NOTICE, "check_password: Word =3D %s, value =3D %s", word,= value); +#endif + + returnValue =3D (*dealer)(value); + } + } + + fclose(config); + ber_memfree(line); + return returnValue; +} + +static int realloc_error_message (char ** target, int curlen, int nextle= n) +{ + if (curlen < nextlen + MEMORY_MARGIN) { +#if defined(DEBUG) + syslog(LOG_WARNING, "check_password: Reallocating szErrStr from %d to = %d", + curlen, nextlen + MEMORY_MARGIN); +#endif + ber_memfree(*target); + curlen =3D nextlen + MEMORY_MARGIN; + *target =3D (char *) ber_memalloc(curlen); + } + + return curlen; +} + + int +check_password (char *pPasswd, char **ppErrStr, Entry *pEntry) +{ + + char *szErrStr =3D (char *) ber_memalloc(MEM_INIT_SZ); + int mem_len =3D MEM_INIT_SZ; + + int nLen; + int nLower =3D 0; + int nUpper =3D 0; + int nDigit =3D 0; + int nPunct =3D 0; + int minLower =3D 0; + int minUpper =3D 0; + int minDigit =3D 0; + int minPunct =3D 0; + int nQuality =3D 0; + int i; + + /* Set a sensible default to keep original behaviour. */ + int minQuality =3D DEFAULT_QUALITY; + int useCracklib =3D DEFAULT_CRACKLIB; + + /** bail out early as cracklib will reject passwords shorter + * than 6 characters + */ + + nLen =3D strlen (pPasswd); + if ( nLen < 6) { + mem_len =3D realloc_error_message(&szErrStr, mem_len, + strlen(PASSWORD_TOO_SHORT_SZ) + + strlen(pEntry->e_name.bv_val) + 1); + sprintf (szErrStr, PASSWORD_TOO_SHORT_SZ, pEntry->e_name.bv_val, nLen)= ; + goto fail; + } + + /* Read config file */ + minQuality =3D read_config_file("minPoints"); + + useCracklib =3D read_config_file("useCracklib"); + minUpper =3D read_config_file("minUpper"); + minLower =3D read_config_file("minLower"); + minDigit =3D read_config_file("minDigit"); + minPunct =3D read_config_file("minPunct"); + + /** The password must have at least minQuality strength points with one=
+ * point for the first occurrance of a lower, upper, digit and + * punctuation character + */ + + for ( i =3D 0; i < nLen; i++ ) { + + if ( nQuality >=3D minQuality ) break; + + if ( islower (pPasswd[i]) ) { + minLower--; + if ( !nLower && (minLower < 1)) { + nLower =3D 1; nQuality++; +#if defined(DEBUG) + syslog(LOG_NOTICE, "check_password: Found lower character - quality = raise %d", nQuality); +#endif + } + continue; + } + + if ( isupper (pPasswd[i]) ) { + minUpper--; + if ( !nUpper && (minUpper < 1)) { + nUpper =3D 1; nQuality++; +#if defined(DEBUG) + syslog(LOG_NOTICE, "check_password: Found upper character - quality = raise %d", nQuality); +#endif + } + continue; + } + + if ( isdigit (pPasswd[i]) ) { + minDigit--; + if ( !nDigit && (minDigit < 1)) { + nDigit =3D 1; nQuality++; +#if defined(DEBUG) + syslog(LOG_NOTICE, "check_password: Found digit character - quality = raise %d", nQuality); +#endif + } + continue; + } + + if ( ispunct (pPasswd[i]) ) { + minPunct--; + if ( !nPunct && (minPunct < 1)) { + nPunct =3D 1; nQuality++; +#if defined(DEBUG) + syslog(LOG_NOTICE, "check_password: Found punctuation character - qu= ality raise %d", nQuality); +#endif + } + continue; + } + } + + if ( nQuality < minQuality ) { + mem_len =3D realloc_error_message(&szErrStr, mem_len, + strlen(PASSWORD_QUALITY_SZ) + + strlen(pEntry->e_name.bv_val) + 2); + sprintf (szErrStr, PASSWORD_QUALITY_SZ, pEntry->e_name.bv_val, + nQuality, minQuality); + goto fail; + } + +#ifdef HAVE_CRACKLIB + + /** Check password with cracklib */ + + if ( useCracklib > 0 ) { + int j =3D 0; + FILE* fp; + char filename[FILENAME_MAXLEN]; + char const* ext[] =3D { "hwm", "pwd", "pwi" }; + int nErr =3D 0; + + /** + * Silently fail when cracklib wordlist is not found + */ + + for ( j =3D 0; j < 3; j++ ) { + + snprintf (filename, FILENAME_MAXLEN - 1, "%s.%s", \ + CRACKLIB_DICTPATH, ext[j]); + + if (( fp =3D fopen ( filename, "r")) =3D=3D NULL ) { + + nErr =3D 1; + break; + + } else { + + fclose (fp); + + } + } + + char *r; + if ( nErr =3D=3D 0) { + + r =3D (char *) FascistCheck (pPasswd, CRACKLIB_DICTPATH); + if ( r !=3D NULL ) { + mem_len =3D realloc_error_message(&szErrStr, mem_len, + strlen(BAD_PASSWORD_SZ) + + strlen(pEntry->e_name.bv_val) + + strlen(r)); + sprintf (szErrStr, BAD_PASSWORD_SZ, pEntry->e_name.bv_val, r); + goto fail; + } + } + } + + else { +#if defined(DEBUG) + syslog(LOG_NOTICE, "check_password: Cracklib verification disabled by = configuration"); +#endif + } + +#endif + + *ppErrStr =3D strdup (""); + ber_memfree(szErrStr); + return (LDAP_SUCCESS); + +fail: + *ppErrStr =3D strdup (szErrStr); + ber_memfree(szErrStr); + return (EXIT_FAILURE); + +} + --=20 1.7.11.4
--------------050908090805020607010105--
--------------ms000000000208070102090606 Content-Type: application/pkcs7-signature; name="smime.p7s" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="smime.p7s" Content-Description: Signature cryptographique S/MIME
MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIN7jCC BIowggNyoAMCAQICECf06hH0eobEbp27bqkXBwcwDQYJKoZIhvcNAQEFBQAwbzELMAkGA1UE BhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9vdDAeFw0w NTA2MDcwODA5MTBaFw0yMDA1MzAxMDQ4MzhaMIGuMQswCQYDVQQGEwJVUzELMAkGA1UECBMC VVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5l dHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTE2MDQGA1UEAxMtVVRO LVVTRVJGaXJzdC1DbGllbnQgQXV0aGVudGljYXRpb24gYW5kIEVtYWlsMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsjmFpPJ9q0E7YkY3rs3BYHW8OWX5ShpHornMSMxqmNVN NRm5pELlzkniii8efNIxB8dOtINknS4p1aJkxIW9hVE1eaROaJB7HHqkkqgX8pgV8pPMyaQy lbsMTzC9mKALi+VuG6JG+ni8om+rWV6lL8/K2m2qL+usobNqqrcuZzWLeeEeaYji5kbNoKXq vgvOdjp6Dpvq/NonWz1zHyLmSGHGTPNpsaguG7bUMSAsvIKKjqQOpdeJQ/wWWq8dcdcRWdq6 hw2v+vPhwvCkxWeM1tZUOt4KpLoDd7NlyP0e03RiqhjKaJMeoYV+9Udly/hNVyh00jT/MLbu 9mIwFIws6wIDAQABo4HhMIHeMB8GA1UdIwQYMBaAFK29mHo0tCb3+sQmVO8DveAky1QaMB0G A1UdDgQWBBSJgmd9xJ0mcABLtFBIfN49rgRufTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ BAUwAwEB/zB7BgNVHR8EdDByMDigNqA0hjJodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9BZGRU cnVzdEV4dGVybmFsQ0FSb290LmNybDA2oDSgMoYwaHR0cDovL2NybC5jb21vZG8ubmV0L0Fk ZFRydXN0RXh0ZXJuYWxDQVJvb3QuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQAZ2IkRbyispgCi 54fBm5AD236hEv0e8+LwAamUVEJrmgnEoG3XkJIEA2Z5Q3H8+G+v23ZF4jcaPd3kWQR4rBz0 g0bzes9bhHIt5UbBuhgRKfPLSXmHPLptBZ2kbWhPrXIUNqi5sf2/z3/wpGqUNVCPz4FtVbHd WTBK322gnGQfSXzvNrv042n0+DmPWq1LhTq3Du3Tzw1EovsEv+QvcI4l+1pUBrPQxLxtjftz Mizpm4QkLdZ/kXpoAlAfDj9N6cz1u2fo3BwuO/xOzf4CjuOoEwqlJkRl6RDyTVKnrtw+ymsy XEFs/vVdoOr/0fqbhlhtPZZH5f4ulQTCAMyOofK7MIIElTCCA32gAwIBAgIQK7maWQuBMVtp KDwyDC57STANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDEPMA0GA1UEChMGVEVSRU5B MRswGQYDVQQDExJURVJFTkEgUGVyc29uYWwgQ0EwHhcNMTEwMTExMDAwMDAwWhcNMTQwMTEw MjM1OTU5WjBYMQswCQYDVQQGEwJGUjEOMAwGA1UEChMFSU5SSUExGTAXBgNVBAMTEEd1aWxs YXVtZSBST1VTU0UxHjAcBgkqhkiG9w0BCQIWD3JvdXNzZUBpbnJpYS5mcjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBANT2GRniP4zFepDfXQ9qHZCqmyGFsnxP1sAK5gRwh2xm 7EJgNSAlRVkmYdkrohltfjGJWvzmlIc8lgbzPSddeHhlc3SI8ZV3b9gWlyq3asH4oPJ3KuKh d8s2JLoll4pYRo+EqH/kLr8Tz3xfDEHtXNXiZ4QM6kniyLyk2QKc8UUsxd8f8gbiUW8yP2rB 9MgwbKYHn+EudkGbn+krQGbrBQRK83phYVGNnRy13mlu8Mb+9mmNCJq8cL6vhhIsGB4VRvhb k3pcZc2zFm9QJFziYLpdqINoh3vmSVHEVN0Oa3KecuXjiaboonCzXnxvdgLWQYAJNglpP7TV H4PTw+xXLZsCAwEAAaOCAXYwggFyMB8GA1UdIwQYMBaAFGNNQ1oZSD/ERsECur/uDuWCt2am MB0GA1UdDgQWBBRPxfiKCFknW2HnMSChZnApNelBwjAOBgNVHQ8BAf8EBAMCBaAwDAYDVR0T AQH/BAIwADAdBgNVHSUEFjAUBggrBgEFBQcDBAYIKwYBBQUHAwIwGAYDVR0gBBEwDzANBgsr BgEEAbIxAQICHTA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLnRjcy50ZXJlbmEub3Jn L1RFUkVOQVBlcnNvbmFsQ0EuY3JsMHIGCCsGAQUFBwEBBGYwZDA6BggrBgEFBQcwAoYuaHR0 cDovL2NydC50Y3MudGVyZW5hLm9yZy9URVJFTkFQZXJzb25hbENBLmNydDAmBggrBgEFBQcw AYYaaHR0cDovL29jc3AudGNzLnRlcmVuYS5vcmcwJAYDVR0RBB0wG4EZR3VpbGxhdW1lLlJv dXNzZUBpbnJpYS5mcjANBgkqhkiG9w0BAQUFAAOCAQEAQi0EyaS/cO1avHkqFkOVhX5kuG3y kUlOIrzga2dnR2H7ylRILOTxBLweXL2DKJN+ZPJleLJSmdVcstq0GneSA7D1kJt0aPdMHqI6 8fMcppQer+N1V/9LYJWWRTV6RFrlSduzEU5tmdlG7QbYtvgNtvBliZL06AYPO54FDkHrhfnJ ldS55eeuAkwFrYkJP1Aa+zo/H2ytzVnIICtZMsZSa7Y2xo4j5Ykxd0HIsc48lmnkDnZ08+yf AOjJis2tc9eeBdcvQ/Pck+woIDeW9vnahCRcOOqCbmith0cqFvEm8cb1ajPIKmlUGBJi97Qh XJV8FZcuIK1Naelj/8MDbcd3ZzCCBMMwggOroAMCAQICEHP+V/rfuMUIgXtmuWvwLe8wDQYJ KoZIhvcNAQEFBQAwga4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2Fs dCBMYWtlIENpdHkxHjAcBgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEhMB8GA1UECxMY aHR0cDovL3d3dy51c2VydHJ1c3QuY29tMTYwNAYDVQQDEy1VVE4tVVNFUkZpcnN0LUNsaWVu dCBBdXRoZW50aWNhdGlvbiBhbmQgRW1haWwwHhcNMDkwNTE4MDAwMDAwWhcNMjgxMjMxMjM1 OTU5WjA7MQswCQYDVQQGEwJOTDEPMA0GA1UEChMGVEVSRU5BMRswGQYDVQQDExJURVJFTkEg UGVyc29uYWwgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIFdn1M2ojoZAN z7sFRMOrH0o1hRohhaBP+PBA4kpDm/5bsbC/tFfcdYBBS2Qa9ttPb4/QJUU1+erLSvr72tPt RYgRlDbkzKgN78U9N+0We+PClZ5YM38i+/j/7Oa+264KZSUih9pvhItG6ECGKD+/VgjiSumD ouki+y36tigfkcHDcftTwCtOpAyhbp1V7ezhJIc6COINHOTETdDLJ/qEZObRl51WJFuTuyku Q+JBaj3iSmX8ml9ahoe8h8d5gJaZUcaQD2SRmX0Q3awsAyrheGT+zj1O9CtQEUvRWNSbA/B/ 9TtTsFND+8UvxAQpGjqs11Xp0Q6V0Tsxf3hPriktAgMBAAGjggFNMIIBSTAfBgNVHSMEGDAW gBSJgmd9xJ0mcABLtFBIfN49rgRufTAdBgNVHQ4EFgQUY01DWhlIP8RGwQK6v+4O5YK3ZqYw DgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwGAYDVR0gBBEwDzANBgsrBgEE AbIxAQICHTBYBgNVHR8EUTBPME2gS6BJhkdodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVRO LVVTRVJGaXJzdC1DbGllbnRBdXRoZW50aWNhdGlvbmFuZEVtYWlsLmNybDBvBggrBgEFBQcB AQRjMGEwOAYIKwYBBQUHMAKGLGh0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VVE5BQUFDbGll bnRfQ0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqG SIb3DQEBBQUAA4IBAQAGK6lTLxPcXDkWzIafXkx7cvvsjVWKXpoK/1NMdvQGPVDPV/Ciz6+Z jKr+oBl2PpkDMvp1gziKu2uapQwTstQbduaULmeYWeORbAKQmpzIYEtVq8qIWo0r5WmVAwfR 1A78JCIuWbFjpF/t2SNy5JzOOlxsH0+pAMkd/vp/RS22LoTdDyegWRhO1XYlRfSZJnnbb58j 90O7Kw8Eo4EmLLd7Nfk9d19AIeZ/HaWWWr3QyxY6bLthi4r9BDlECsss4cvOLhCYGtvgk+1J ZGQIIJ+3o1Dwot3KtMZ8DD3nXhXcJ4bkOjtSWherqQZTK50Jc2QcAcP9MNKHA2/kFQN6OV9o MYIDBzCCAwMCAQEwTzA7MQswCQYDVQQGEwJOTDEPMA0GA1UEChMGVEVSRU5BMRswGQYDVQQD ExJURVJFTkEgUGVyc29uYWwgQ0ECECu5mlkLgTFbaSg8Mgwue0kwCQYFKw4DAhoFAKCCAY0w GAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMTIwODA3MTU1NzI1 WjAjBgkqhkiG9w0BCQQxFgQUQ1jLCcKguMOiIFP7wDC8SLbfFfYwXgYJKwYBBAGCNxAEMVEw TzA7MQswCQYDVQQGEwJOTDEPMA0GA1UEChMGVEVSRU5BMRswGQYDVQQDExJURVJFTkEgUGVy c29uYWwgQ0ECECu5mlkLgTFbaSg8Mgwue0kwYAYLKoZIhvcNAQkQAgsxUaBPMDsxCzAJBgNV BAYTAk5MMQ8wDQYDVQQKEwZURVJFTkExGzAZBgNVBAMTElRFUkVOQSBQZXJzb25hbCBDQQIQ K7maWQuBMVtpKDwyDC57STBsBgkqhkiG9w0BCQ8xXzBdMAsGCWCGSAFlAwQBKjALBglghkgB ZQMEAQIwCgYIKoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsO AwIHMA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBANISMWbCVg4clpyyoU7WyOoP ENBalFbEzAbA7iBn6edoAEV8jgj41VcGlNsevz8kQrb59GzkjOqMXsIwHTsGvjky738QcFPu uXyb8ZY+ExFOhgscUVlQ924+idn6xPMstKuM/cPKrknqdrRsS6igOTMVhKjI0s0MX2vsSA8/ FLd48o7B8XE5vWCXpJKExRgZvJdbzxrY3fSFugo3/jrCPz62mquY9u4U55nspkADfd6Ws86J tzVhlZzAM+CGmBvXETbPOJpP6HV2ORAXhxSX/x2Rn07Rm8kShMVUSeSpg2cH5MiyAXNFwfix kZDykKSrudGq7u+YrAC/Q6isV4ohEZMAAAAAAAA= --------------ms000000000208070102090606--