From 26002bd1d02d871e3c0526f3a0b7b99e25f3564c Mon Sep 17 00:00:00 2001 From: babak sarashki Date: Tue, 5 Nov 2019 18:02:38 -0800 Subject: [PATCH] ltb project openldap ppolicy check password 1.1 From stx 1901 openldap src RPM 2.4.44 Upstream at https://github.com/ltb-project/openldap-ppolicy-check-password.git --- .../INSTALL | 31 ++ .../LICENSE | 50 ++ .../Makefile | 48 ++ .../README | 146 ++++++ .../check_password.c | 447 ++++++++++++++++++ 5 files changed, 722 insertions(+) create mode 100644 ltb-project-openldap-ppolicy-check-password-1.1/INSTALL create mode 100644 ltb-project-openldap-ppolicy-check-password-1.1/LICENSE create mode 100644 ltb-project-openldap-ppolicy-check-password-1.1/Makefile create mode 100644 ltb-project-openldap-ppolicy-check-password-1.1/README create mode 100644 ltb-project-openldap-ppolicy-check-password-1.1/check_password.c diff --git a/ltb-project-openldap-ppolicy-check-password-1.1/INSTALL b/ltb-project-openldap-ppolicy-check-password-1.1/INSTALL new file mode 100644 index 0000000..eb2dab4 --- /dev/null +++ b/ltb-project-openldap-ppolicy-check-password-1.1/INSTALL @@ -0,0 +1,31 @@ +INSTALLATION +============ + +Build dependencies +------------------ +cracklib header files (link with -lcrack). The Makefile does not look for +cracklib; you may need to provide the paths manually. + +Build +----- +Use the provided Makefile to build the module. + +Copy the resulting check_password.so into the OpenLDAP modulepath. + +Or, change the installation path to match with the OpenLDAP module path in the +Makefile and use 'make install'. + + +USAGE +===== +Add objectClass 'pwdPolicyChecker' with an attribute + + pwdCheckModule: check_password.so + +to a password policy entry. + +The module depends on a working cracklib installation including wordlist files. +If the wordlist files are not readable, the cracklib check will be skipped +silently. + +But you can use this module without cracklib, just checks for syntatic checks. diff --git a/ltb-project-openldap-ppolicy-check-password-1.1/LICENSE b/ltb-project-openldap-ppolicy-check-password-1.1/LICENSE new file mode 100644 index 0000000..03f692b --- /dev/null +++ b/ltb-project-openldap-ppolicy-check-password-1.1/LICENSE @@ -0,0 +1,50 @@ +OpenLDAP Public License + +The OpenLDAP Public License + Version 2.8.1, 25 November 2003 + +Redistribution and use of this software and associated documentation +("Software"), with or without modification, are permitted provided +that the following conditions are met: + +1. Redistributions in source form must retain copyright statements + and notices, + +2. Redistributions in binary form must reproduce applicable copyright + statements and notices, this list of conditions, and the following + disclaimer in the documentation and/or other materials provided + with the distribution, and + +3. Redistributions must contain a verbatim copy of this document. + +The OpenLDAP Foundation may revise this license from time to time. +Each revision is distinguished by a version number. You may use +this Software under terms of this license revision or under the +terms of any subsequent revision of the license. + +THIS SOFTWARE IS PROVIDED BY THE OPENLDAP FOUNDATION AND ITS +CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED 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 OPENLDAP FOUNDATION, ITS CONTRIBUTORS, OR THE AUTHOR(S) +OR OWNER(S) OF THE SOFTWARE 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 names of the authors and copyright holders must not be used in +advertising or otherwise to promote the sale, use or other dealing +in this Software without specific, written prior permission. Title +to copyright in this Software shall at all times remain with copyright +holders. + +OpenLDAP is a registered trademark of the OpenLDAP Foundation. + +Copyright 1999-2003 The OpenLDAP Foundation, Redwood City, +California, USA. All rights reserved. Permission to copy and +distribute verbatim copies of this document is granted. + diff --git a/ltb-project-openldap-ppolicy-check-password-1.1/Makefile b/ltb-project-openldap-ppolicy-check-password-1.1/Makefile new file mode 100644 index 0000000..91de40b --- /dev/null +++ b/ltb-project-openldap-ppolicy-check-password-1.1/Makefile @@ -0,0 +1,48 @@ +# contrib/slapd-modules/check_password/Makefile +# Copyright 2007 Michael Steinmann, Calivia. All Rights Reserved. +# Updated by Pierre-Yves Bonnetain, B&A Consultants, 2008 +# + +CC=gcc + +# Where to look for the CrackLib dictionaries +# +CRACKLIB=/usr/share/cracklib/pw_dict + +# Path to the configuration file +# +CONFIG=/etc/openldap/check_password.conf + +CFLAGS+=-fpic \ + -DHAVE_CRACKLIB -DCRACKLIB_DICTPATH="\"$(CRACKLIB)\"" \ + -DCONFIG_FILE="\"$(CONFIG)\"" \ + -DDEBUG + +LDAP_LIB=-lldap_r -llber + +# Comment out this line if you do NOT want to use the cracklib. +# You may have to add an -Ldirectory if the libcrak is not in a standard +# location +# +CRACKLIB_LIB=-lcrack + +LIBS=$(LDAP_LIB) $(CRACKLIB_LIB) + +LIBDIR=/usr/lib/openldap/ + + +all: check_password + +check_password.o: + $(CC) $(CFLAGS) -c $(LDAP_INC) check_password.c + +check_password: clean check_password.o + $(CC) $(LDFLAGS) -shared -o check_password.so check_password.o $(CRACKLIB_LIB) + +install: check_password + cp -f check_password.so ../../../usr/lib/openldap/modules/ + +clean: + $(RM) check_password.o check_password.so check_password.lo + $(RM) -r .libs + diff --git a/ltb-project-openldap-ppolicy-check-password-1.1/README b/ltb-project-openldap-ppolicy-check-password-1.1/README new file mode 100644 index 0000000..10191c2 --- /dev/null +++ b/ltb-project-openldap-ppolicy-check-password-1.1/README @@ -0,0 +1,146 @@ + +check_password.c - OpenLDAP pwdChecker library + +2007-06-06 Michael Steinmann +2008-01-30 Pierre-Yves Bonnetain +2009 Clement Oudot - LTB-project +2009 Jerome HUET - LTB-project + +check_password.c is an OpenLDAP pwdPolicyChecker module used to check the +strength and quality of user-provided passwords. + +This module is used as an extension of the OpenLDAP password policy controls, +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 these +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 used + (lower, upper, digit and punctuation characters). The minimum number of + classes is defined in a configuration file. You can set the minimum for each + class. + + - passwords are checked against cracklib if cracklib is enabled at compile + 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. + 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 for +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. + +The module depends on a working cracklib installation including wordlist files. +If the wordlist files are not readable, the cracklib check will be skipped +silently. + +Note: pwdPolicyChecker modules are loaded on *every* password change operation. + +Configuration +------------- +The configuration file (/etc/openldap/check_password.conf by default) contains +parameters for the module. If the file is not found, parameters are given their +default value. + +The syntax of the file is : + +parameter value + +with spaces being delimiters. Parameter names ARE case sensitive (this may +change in the future). + +Current parameters : + +- useCracklib: integer. Default value: 1. Set it to 0 to disable cracklib verification. + It has no effect if cracklib is not included at compile time. + +- minPoints: integer. Default value: 3. Minimum number of quality points a new + password must have to be accepted. One quality point is awarded for each 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 expected. + +Logs +---- +If a user password is rejected by an OpenLDAP pwdChecker module, the user 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=".." does not pass required number of strength checks (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/minPunct + +* 2009-02-05 Clement Oudot - 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 + Version 1.0.2 + - Several bug fixes. + - Add external config file + +* 2007-06-06 Michael Steinmann + Version 1.0.1 + - add dn to error messages + +* 2007-06-02 Michael Steinmann + Version 1.0 + diff --git a/ltb-project-openldap-ppolicy-check-password-1.1/check_password.c b/ltb-project-openldap-ppolicy-check-password-1.1/check_password.c new file mode 100644 index 0000000..f4dd1cb --- /dev/null +++ b/ltb-project-openldap-ppolicy-check-password-1.1/check_password.c @@ -0,0 +1,447 @@ +/* + * check_password.c for OpenLDAP + * + * See LICENSE, README and INSTALL files + */ + +#include +#include +#include +#include + +#ifdef HAVE_CRACKLIB +#include +#endif + +#if defined(DEBUG) +#include +#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=\"%s\" is too short (%d/6)" +#define PASSWORD_QUALITY_SZ \ + "Password for dn=\"%s\" does not pass required number of strength checks for the required character sets (%d of %d)" +#define BAD_PASSWORD_SZ \ + "Bad password for dn=\"%s\" because %s" +#define UNKNOWN_ERROR_SZ \ + "An unknown error occurred, please see your systems administrator" + +typedef int (*validator) (char*); +static int read_config_file (); +static validator valid_word (char *); +static int set_quality (char *); +static int set_cracklib (char *); + +int check_password (char *pPasswd, char **ppErrStr, Entry *pEntry); + +struct config_entry { + char* key; + char* value; + char* def_value; +} config_entries[] = { { "minPoints", NULL, "3"}, + { "useCracklib", NULL, "1"}, + { "minUpper", NULL, "0"}, + { "minLower", NULL, "0"}, + { "minDigit", NULL, "0"}, + { "minPunct", NULL, "0"}, + { NULL, NULL, NULL }}; + +int get_config_entry_int(char* entry) { + struct config_entry* centry = config_entries; + + int i = 0; + char* key = centry[i].key; + while (key != NULL) { + if ( strncmp(key, entry, strlen(key)) == 0 ) { + if ( centry[i].value == NULL ) { + return atoi(centry[i].def_value); + } + else { + return atoi(centry[i].value); + } + } + i++; + key = centry[i].key; + } + + return -1; +} + +void dealloc_config_entries() { + struct config_entry* centry = config_entries; + + int i = 0; + while (centry[i].key != NULL) { + if ( centry[i].value != NULL ) { + ber_memfree(centry[i].value); + } + i++; + } +} + +char* chomp(char *s) +{ + char* t = ber_memalloc(strlen(s)+1); + strncpy (t,s,strlen(s)+1); + + if ( t[strlen(t)-1] == '\n' ) { + t[strlen(t)-1] = '\0'; + } + + return t; +} + +static int set_quality (char *value) +{ +#if defined(DEBUG) + syslog(LOG_INFO, "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_QUALITY; + return (int) (value[0] - '0'); + +} + +static int set_cracklib (char *value) +{ +#if defined(DEBUG) + syslog(LOG_INFO, "check_password: Setting cracklib usage to [%s]", value); +#endif + + + return (int) (value[0] - '0'); + +} + +static int set_digit (char *value) +{ +#if defined(DEBUG) + syslog(LOG_INFO, "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[] = { { "minPoints", set_quality }, + { "useCracklib", set_cracklib }, + { "minUpper", set_digit }, + { "minLower", set_digit }, + { "minDigit", set_digit }, + { "minPunct", set_digit }, + { NULL, NULL } }; + int index = 0; + +#if defined(DEBUG) + syslog(LOG_DEBUG, "check_password: Validating parameter [%s]", word); +#endif + + while (list[index].parameter != NULL) { + if (strlen(word) == strlen(list[index].parameter) && + strcmp(list[index].parameter, word) == 0) { +#if defined(DEBUG) + syslog(LOG_DEBUG, "check_password: Parameter accepted."); +#endif + return list[index].dealer; + } + index++; + } + +#if defined(DEBUG) + syslog(LOG_DEBUG, "check_password: Parameter rejected."); +#endif + + return NULL; +} + +static int read_config_file () +{ + FILE * config; + char * line; + int returnValue = -1; + + line = ber_memcalloc(260, sizeof(char)); + + if ( line == NULL ) { + return returnValue; + } + + if ( (config = fopen(CONFIG_FILE, "r")) == NULL) { +#if defined(DEBUG) + syslog(LOG_ERR, "check_password: Opening file %s failed", CONFIG_FILE); +#endif + + ber_memfree(line); + return returnValue; + } + + returnValue = 0; + + while (fgets(line, 256, config) != NULL) { + char *start = line; + char *word, *value; + validator dealer; + +#if defined(DEBUG) + /* Debug traces to syslog. */ + syslog(LOG_DEBUG, "check_password: Got line |%s|", line); +#endif + + while (isspace(*start) && isascii(*start)) start++; + + /* If we've got punctuation, just skip the line. */ + if ( ispunct(*start)) { +#if defined(DEBUG) + /* Debug traces to syslog. */ + syslog(LOG_DEBUG, "check_password: Skipped line |%s|", line); +#endif + continue; + } + + if( isascii(*start)) { + + struct config_entry* centry = config_entries; + int i = 0; + char* keyWord = centry[i].key; + if ((word = strtok(start, " \t")) && (value = strtok(NULL, " \t"))) { + while ( keyWord != NULL ) { + if ((strncmp(keyWord,word,strlen(keyWord)) == 0) && (dealer = valid_word(word)) ) { + +#if defined(DEBUG) + syslog(LOG_DEBUG, "check_password: Word = %s, value = %s", word, value); +#endif + + centry[i].value = chomp(value); + break; + } + i++; + keyWord = centry[i].key; + } + } + } + } + fclose(config); + ber_memfree(line); + + return returnValue; +} + +static int realloc_error_message (char ** target, int curlen, int nextlen) +{ + 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 = nextlen + MEMORY_MARGIN; + *target = (char *) ber_memalloc(curlen); + } + + return curlen; +} + +int +check_password (char *pPasswd, char **ppErrStr, Entry *pEntry) +{ + + char *szErrStr = (char *) ber_memalloc(MEM_INIT_SZ); + int mem_len = MEM_INIT_SZ; + + int nLen; + int nLower = 0; + int nUpper = 0; + int nDigit = 0; + int nPunct = 0; + int minLower = 0; + int minUpper = 0; + int minDigit = 0; + int minPunct = 0; + int nQuality = 0; + int i; + + /* Set a sensible default to keep original behaviour. */ + int minQuality = DEFAULT_QUALITY; + int useCracklib = DEFAULT_CRACKLIB; + + /** bail out early as cracklib will reject passwords shorter + * than 6 characters + */ + + nLen = strlen (pPasswd); + if ( nLen < 6) { + mem_len = 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; + } + + if (read_config_file() == -1) { + syslog(LOG_ERR, "Warning: Could not read values from config file %s. Using defaults.", CONFIG_FILE); + } + + minQuality = get_config_entry_int("minPoints"); + useCracklib = get_config_entry_int("useCracklib"); + minUpper = get_config_entry_int("minUpper"); + minLower = get_config_entry_int("minLower"); + minDigit = get_config_entry_int("minDigit"); + minPunct = get_config_entry_int("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 = 0; i < nLen; i++ ) { + + if ( islower (pPasswd[i]) ) { + minLower--; + if ( !nLower && (minLower < 1)) { + nLower = 1; nQuality++; +#if defined(DEBUG) + syslog(LOG_DEBUG, "check_password: Found lower character - quality raise %d", nQuality); +#endif + } + continue; + } + + if ( isupper (pPasswd[i]) ) { + minUpper--; + if ( !nUpper && (minUpper < 1)) { + nUpper = 1; nQuality++; +#if defined(DEBUG) + syslog(LOG_DEBUG, "check_password: Found upper character - quality raise %d", nQuality); +#endif + } + continue; + } + + if ( isdigit (pPasswd[i]) ) { + minDigit--; + if ( !nDigit && (minDigit < 1)) { + nDigit = 1; nQuality++; +#if defined(DEBUG) + syslog(LOG_DEBUG, "check_password: Found digit character - quality raise %d", nQuality); +#endif + } + continue; + } + + if ( ispunct (pPasswd[i]) ) { + minPunct--; + if ( !nPunct && (minPunct < 1)) { + nPunct = 1; nQuality++; +#if defined(DEBUG) + syslog(LOG_DEBUG, "check_password: Found punctuation character - quality raise %d", nQuality); +#endif + } + continue; + } + } + + /* + * If you have a required field, then it should be required in the strength + * checks. + */ + + if ( + (minLower > 0 ) || + (minUpper > 0 ) || + (minDigit > 0 ) || + (minPunct > 0 ) || + (nQuality < minQuality) + ) { + mem_len = 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 = 0; + FILE* fp; + char filename[FILENAME_MAXLEN]; + char const* ext[] = { "hwm", "pwd", "pwi" }; + int nErr = 0; + + /** + * Silently fail when cracklib wordlist is not found + */ + + for ( j = 0; j < 3; j++ ) { + + snprintf (filename, FILENAME_MAXLEN - 1, "%s.%s", \ + CRACKLIB_DICTPATH, ext[j]); + + if (( fp = fopen ( filename, "r")) == NULL ) { + + nErr = 1; + break; + + } else { + + fclose (fp); + + } + } + + char *r; + if ( nErr == 0) { + + r = (char *) FascistCheck (pPasswd, CRACKLIB_DICTPATH); + if ( r != NULL ) { + mem_len = 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 + dealloc_config_entries(); + *ppErrStr = strdup (""); + ber_memfree(szErrStr); + return (LDAP_SUCCESS); + +fail: + dealloc_config_entries(); + *ppErrStr = strdup (szErrStr); + ber_memfree(szErrStr); + return (EXIT_FAILURE); + +} -- 2.17.1