--- a/check_password.c 2009-10-31 18:59:06.000000000 +0100 +++ b/check_password.c 2014-12-17 12:25:00.148900907 +0100 @@ -10,7 +10,7 @@ #include #ifdef HAVE_CRACKLIB -#include "crack.h" +#include #endif #if defined(DEBUG) @@ -34,18 +34,77 @@ #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 (%d of %d)" + "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 (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) @@ -84,12 +143,12 @@ 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 } }; + { "useCracklib", set_cracklib }, + { "minUpper", set_digit }, + { "minLower", set_digit }, + { "minDigit", set_digit }, + { "minPunct", set_digit }, + { NULL, NULL } }; int index = 0; #if defined(DEBUG) @@ -98,7 +157,7 @@ while (list[index].parameter != NULL) { if (strlen(word) == strlen(list[index].parameter) && - strcmp(list[index].parameter, word) == 0) { + strcmp(list[index].parameter, word) == 0) { #if defined(DEBUG) syslog(LOG_NOTICE, "check_password: Parameter accepted."); #endif @@ -114,13 +173,15 @@ return NULL; } -static int read_config_file (char *keyWord) +static int read_config_file () { FILE * config; char * line; int returnValue = -1; - if ((line = ber_memcalloc(260, sizeof(char))) == NULL) { + line = ber_memcalloc(260, sizeof(char)); + + if ( line == NULL ) { return returnValue; } @@ -133,6 +194,8 @@ return returnValue; } + returnValue = 0; + while (fgets(line, 256, config) != NULL) { char *start = line; char *word, *value; @@ -145,23 +208,40 @@ while (isspace(*start) && isascii(*start)) start++; - if (! isascii(*start)) + /* If we've got punctuation, just skip the line. */ + if ( ispunct(*start)) { +#if defined(DEBUG) + /* Debug traces to syslog. */ + syslog(LOG_NOTICE, "check_password: Skipped line |%s|", line); +#endif continue; + } - if ((word = strtok(start, " \t")) && (dealer = valid_word(word)) && (strcmp(keyWord,word)==0)) { - if ((value = strtok(NULL, " \t")) == NULL) - 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_NOTICE, "check_password: Word = %s, value = %s", word, value); + syslog(LOG_NOTICE, "check_password: Word = %s, value = %s", word, value); #endif - returnValue = (*dealer)(value); + centry[i].value = chomp(value); + break; + } + i++; + keyWord = centry[i].key; + } + } } } - fclose(config); ber_memfree(line); + return returnValue; } @@ -170,7 +250,7 @@ if (curlen < nextlen + MEMORY_MARGIN) { #if defined(DEBUG) syslog(LOG_WARNING, "check_password: Reallocating szErrStr from %d to %d", - curlen, nextlen + MEMORY_MARGIN); + curlen, nextlen + MEMORY_MARGIN); #endif ber_memfree(*target); curlen = nextlen + MEMORY_MARGIN; @@ -180,7 +260,7 @@ return curlen; } - int +int check_password (char *pPasswd, char **ppErrStr, Entry *pEntry) { @@ -210,20 +290,22 @@ 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); + 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 = read_config_file("minPoints"); + if (read_config_file() == -1) { + syslog(LOG_ERR, "Warning: Could not read values from config file %s. Using defaults.", CONFIG_FILE); + } - useCracklib = read_config_file("useCracklib"); - minUpper = read_config_file("minUpper"); - minLower = read_config_file("minLower"); - minDigit = read_config_file("minDigit"); - minPunct = read_config_file("minPunct"); + 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 @@ -232,8 +314,6 @@ for ( i = 0; i < nLen; i++ ) { - if ( nQuality >= minQuality ) break; - if ( islower (pPasswd[i]) ) { minLower--; if ( !nLower && (minLower < 1)) { @@ -279,12 +359,23 @@ } } - if ( nQuality < minQuality ) { + /* + * 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); + strlen(PASSWORD_QUALITY_SZ) + + strlen(pEntry->e_name.bv_val) + 2); sprintf (szErrStr, PASSWORD_QUALITY_SZ, pEntry->e_name.bv_val, - nQuality, minQuality); + nQuality, minQuality); goto fail; } @@ -306,7 +397,7 @@ for ( j = 0; j < 3; j++ ) { snprintf (filename, FILENAME_MAXLEN - 1, "%s.%s", \ - CRACKLIB_DICTPATH, ext[j]); + CRACKLIB_DICTPATH, ext[j]); if (( fp = fopen ( filename, "r")) == NULL ) { @@ -326,9 +417,9 @@ 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)); + 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; } @@ -342,15 +433,15 @@ } #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); } -