MozNSS: better file name matching for hashed CA  certificate directory

CA certificate files in OpenSSL compatible CACERTDIR were loaded if the file extension was '.0'. However the file name
should be 8 letters long certificate hash of the certificate subject name, followed by a numeric suffix which is used
to differentiate between two certificates with the same subject name.

Wit this patch, certificate file names are matched correctly (using regular expressions).

Author: Jan Vcelak <jvcelak@redhat.com>
Upstream ITS: #7374
Resolves: #852786

diff --git a/libraries/libldap/tls_m.c b/libraries/libldap/tls_m.c
index 5e49fc5..61d71d4 100644
--- a/libraries/libldap/tls_m.c
+++ b/libraries/libldap/tls_m.c
@@ -38,6 +38,7 @@
 #include <ac/unistd.h>
 #include <ac/param.h>
 #include <ac/dirent.h>
+#include <ac/regex.h>
 
 #include "ldap-int.h"
 #include "ldap-tls.h"
@@ -118,9 +119,7 @@ static const PRIOMethods tlsm_PR_methods;
 
 #define PEM_LIBRARY	"nsspem"
 #define PEM_MODULE	"PEM"
-/* hash files for use with cacertdir have this file name suffix */
-#define PEM_CA_HASH_FILE_SUFFIX	".0"
-#define PEM_CA_HASH_FILE_SUFFIX_LEN 2
+#define PEM_CA_HASH_FILE_REGEX "^[0-9a-f]{8}\\.[0-9]+$"
 
 static SECMODModule *pem_module;
 
@@ -1541,6 +1540,7 @@ tlsm_init_ca_certs( tlsm_ctx *ctx, const char *cacertfile, const char *cacertdir
 		PRDir *dir;
 		PRDirEntry *entry;
 		PRStatus fistatus = PR_FAILURE;
+		regex_t hashfile_re;
 
 		memset( &fi, 0, sizeof(fi) );
 		fistatus = PR_GetFileInfo( cacertdir, &fi );
@@ -1570,20 +1570,30 @@ tlsm_init_ca_certs( tlsm_ctx *ctx, const char *cacertfile, const char *cacertdir
 			goto done;
 		}
 
+		if ( regcomp( &hashfile_re, PEM_CA_HASH_FILE_REGEX, REG_NOSUB|REG_EXTENDED ) != 0 ) {
+			Debug( LDAP_DEBUG_ANY, "TLS: cannot compile regex for CA hash files matching\n", 0, 0, 0 );
+			goto done;
+		}
+
 		do {
 			entry = PR_ReadDir( dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN );
 			if ( ( NULL != entry ) && ( NULL != entry->name ) ) {
 				char *fullpath = NULL;
-				char *ptr;
+				int match;
 
-				ptr = PL_strrstr( entry->name, PEM_CA_HASH_FILE_SUFFIX );
-				if ( ( ptr == NULL ) || ( *(ptr + PEM_CA_HASH_FILE_SUFFIX_LEN) != '\0' ) ) {
+				match = regexec( &hashfile_re, entry->name, 0, NULL, 0 );
+				if ( match == REG_NOMATCH ) {
 					Debug( LDAP_DEBUG_TRACE,
-						   "TLS: file %s does not end in [%s] - does not appear to be a CA certificate "
-						   "directory file with a properly hashed file name - skipping.\n",
-						   entry->name, PEM_CA_HASH_FILE_SUFFIX, 0 );
+						   "TLS: skipping '%s' - filename does not have expected format "
+						   "(certificate hash with numeric suffix)\n", entry->name, 0, 0 );
+					continue;
+				} else if ( match != 0 ) {
+					Debug( LDAP_DEBUG_ANY,
+						   "TLS: cannot execute regex for CA hash file matching (%d).\n",
+						   match, 0, 0 );
 					continue;
 				}
+
 				fullpath = PR_smprintf( "%s/%s", cacertdir, entry->name );
 				if ( !tlsm_add_cert_from_file( ctx, fullpath, isca ) ) {
 					Debug( LDAP_DEBUG_TRACE,
@@ -1599,6 +1609,7 @@ tlsm_init_ca_certs( tlsm_ctx *ctx, const char *cacertfile, const char *cacertdir
 				PR_smprintf_free( fullpath );
 			}
 		} while ( NULL != entry );
+		regfree ( &hashfile_re );
 		PR_CloseDir( dir );
 	}
 done:
-- 
1.7.11.4

