summaryrefslogtreecommitdiffstats
path: root/lib/ldaputil/certmap.c
diff options
context:
space:
mode:
authorcvsadm <cvsadm>2005-01-21 00:44:34 +0000
committercvsadm <cvsadm>2005-01-21 00:44:34 +0000
commitb2093e3016027d6b5cf06b3f91f30769bfc099e2 (patch)
treecf58939393a9032182c4fbc4441164a9456e82f8 /lib/ldaputil/certmap.c
downloadds-ldapserver7x.tar.gz
ds-ldapserver7x.tar.xz
ds-ldapserver7x.zip
Moving NSCP Directory Server from DirectoryBranch to TRUNK, initial drop. (foxworth)ldapserver7x
Diffstat (limited to 'lib/ldaputil/certmap.c')
-rw-r--r--lib/ldaputil/certmap.c1950
1 files changed, 1950 insertions, 0 deletions
diff --git a/lib/ldaputil/certmap.c b/lib/ldaputil/certmap.c
new file mode 100644
index 00000000..c2c718fc
--- /dev/null
+++ b/lib/ldaputil/certmap.c
@@ -0,0 +1,1950 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <malloc.h>
+
+/* removed for ns security integration
+#include <sec.h>
+*/
+#include <plstr.h>
+#include <prlink.h>
+#include <key.h>
+#include <cert.h>
+#include <ldaputil/certmap.h>
+#include <ldaputil/ldapauth.h>
+#include <ldaputil/errors.h>
+#include <ldaputil/ldaputil.h>
+#include "ldaputili.h"
+
+#ifndef BIG_LINE
+#define BIG_LINE 1024
+#endif
+
+/* This is hack, the function is defined in cert/alg1485.c */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+static char this_dllname[256];
+static const char *LIB_DIRECTIVE = "certmap";
+static const int LIB_DIRECTIVE_LEN = 7; /* strlen("LIB_DIRECTIVE") */
+
+static char *ldapu_dn_normalize( char *dn );
+
+typedef struct {
+ FILE *fp;
+ void *arg;
+} LDAPUPrintInfo_t;
+
+static LDAPUCertMapListInfo_t *certmap_listinfo = 0;
+static LDAPUCertMapInfo_t *default_certmap_info = 0;
+
+static const char *certmap_attrs [] = {
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+const long CERTMAP_BIT_POS_UNKNOWN = 0; /* unknown OID */
+const long CERTMAP_BIT_POS_CN = 1L << 1; /* Common Name */
+const long CERTMAP_BIT_POS_OU = 1L << 2; /* Organization unit */
+const long CERTMAP_BIT_POS_O = 1L << 3; /* Organization */
+const long CERTMAP_BIT_POS_C = 1L << 4; /* Country */
+const long CERTMAP_BIT_POS_L = 1L << 5; /* Locality */
+const long CERTMAP_BIT_POS_ST = 1L << 6; /* State or Province */
+const long CERTMAP_BIT_POS_MAIL = 1L << 7; /* E-mail Address */
+const long CERTMAP_BIT_POS_UID = 1L << 8; /* UID */
+const long CERTMAP_BIT_POS_DC = 1L << 9; /* DC */
+
+const int SEC_OID_AVA_UNKNOWN = 0; /* unknown OID */
+
+static long certmap_secoid_to_bit_pos (int oid)
+{
+ switch(oid) {
+ case SEC_OID_AVA_COUNTRY_NAME: return CERTMAP_BIT_POS_C;
+ case SEC_OID_AVA_ORGANIZATION_NAME: return CERTMAP_BIT_POS_O;
+ case SEC_OID_AVA_COMMON_NAME: return CERTMAP_BIT_POS_CN;
+ case SEC_OID_AVA_LOCALITY: return CERTMAP_BIT_POS_L;
+ case SEC_OID_AVA_STATE_OR_PROVINCE: return CERTMAP_BIT_POS_ST;
+ case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME: return CERTMAP_BIT_POS_OU;
+ case SEC_OID_RFC1274_UID: return CERTMAP_BIT_POS_UID;
+ /* Map "E" and "MAIL" to the same bit position */
+ case SEC_OID_PKCS9_EMAIL_ADDRESS: return CERTMAP_BIT_POS_MAIL;
+ case SEC_OID_RFC1274_MAIL: return CERTMAP_BIT_POS_MAIL;
+ case SEC_OID_AVA_DC: return CERTMAP_BIT_POS_DC;
+ default: return CERTMAP_BIT_POS_UNKNOWN;
+ }
+}
+
+static const char *certmap_secoid_to_name (int oid)
+{
+ switch(oid) {
+ case SEC_OID_AVA_COUNTRY_NAME: return "C";
+ case SEC_OID_AVA_ORGANIZATION_NAME: return "O";
+ case SEC_OID_AVA_COMMON_NAME: return "CN";
+ case SEC_OID_AVA_LOCALITY: return "L";
+ case SEC_OID_AVA_STATE_OR_PROVINCE: return "ST";
+ case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME: return "OU";
+ case SEC_OID_RFC1274_UID: return "UID";
+ /* Map both 'e' and 'mail' to 'mail' in LDAP */
+ case SEC_OID_PKCS9_EMAIL_ADDRESS: return "MAIL";
+ case SEC_OID_RFC1274_MAIL: return "MAIL";
+ case SEC_OID_AVA_DC: return "DC";
+ default: return 0;
+ }
+}
+
+static void tolower_string (char *str)
+{
+ if (str) {
+ while (*str) {
+ *str = tolower(*str);
+ str++;
+ }
+ }
+}
+
+static long certmap_name_to_bit_pos (const char *str)
+{
+ if (!ldapu_strcasecmp(str, "c")) return CERTMAP_BIT_POS_C;
+ if (!ldapu_strcasecmp(str, "o")) return CERTMAP_BIT_POS_O;
+ if (!ldapu_strcasecmp(str, "cn")) return CERTMAP_BIT_POS_CN;
+ if (!ldapu_strcasecmp(str, "l")) return CERTMAP_BIT_POS_L;
+ if (!ldapu_strcasecmp(str, "st")) return CERTMAP_BIT_POS_ST;
+ if (!ldapu_strcasecmp(str, "ou")) return CERTMAP_BIT_POS_OU;
+ if (!ldapu_strcasecmp(str, "uid")) return CERTMAP_BIT_POS_UID;
+ /* Map "E" and "MAIL" to the same bit position */
+ if (!ldapu_strcasecmp(str, "e")) return CERTMAP_BIT_POS_MAIL;
+ if (!ldapu_strcasecmp(str, "mail")) return CERTMAP_BIT_POS_MAIL;
+ if (!ldapu_strcasecmp(str, "dc")) return CERTMAP_BIT_POS_DC;
+
+ return CERTMAP_BIT_POS_UNKNOWN;
+}
+
+static int certmap_name_to_secoid (const char *str)
+{
+ if (!ldapu_strcasecmp(str, "c")) return SEC_OID_AVA_COUNTRY_NAME;
+ if (!ldapu_strcasecmp(str, "o")) return SEC_OID_AVA_ORGANIZATION_NAME;
+ if (!ldapu_strcasecmp(str, "cn")) return SEC_OID_AVA_COMMON_NAME;
+ if (!ldapu_strcasecmp(str, "l")) return SEC_OID_AVA_LOCALITY;
+ if (!ldapu_strcasecmp(str, "st")) return SEC_OID_AVA_STATE_OR_PROVINCE;
+ if (!ldapu_strcasecmp(str, "ou")) return SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME;
+ if (!ldapu_strcasecmp(str, "uid")) return SEC_OID_RFC1274_UID;
+ if (!ldapu_strcasecmp(str, "e")) return SEC_OID_PKCS9_EMAIL_ADDRESS;
+ if (!ldapu_strcasecmp(str, "mail")) return SEC_OID_RFC1274_MAIL;
+ if (!ldapu_strcasecmp(str, "dc")) return SEC_OID_AVA_DC;
+
+ return SEC_OID_AVA_UNKNOWN; /* return invalid OID */
+}
+
+NSAPI_PUBLIC int ldapu_list_alloc (LDAPUList_t **list)
+{
+ *list = (LDAPUList_t *)malloc(sizeof(LDAPUList_t));
+
+ if (!*list) return LDAPU_ERR_OUT_OF_MEMORY;
+
+ memset((void *)*list, 0, sizeof(LDAPUList_t));
+ return LDAPU_SUCCESS;
+}
+
+static int ldapu_list_add_node (LDAPUList_t *list, LDAPUListNode_t *node)
+{
+ if (list->head) {
+ node->prev = list->tail;
+ list->tail->next = node;
+ }
+ else {
+ node->prev = 0;
+ list->head = node;
+ }
+
+ node->next = 0;
+ list->tail = node;
+ return LDAPU_SUCCESS;
+}
+
+NSAPI_PUBLIC int ldapu_list_add_info (LDAPUList_t *list, void *info)
+{
+ LDAPUListNode_t *node;
+
+ /* Allocate the list node and set info in the node. */
+ node = (LDAPUListNode_t *)malloc(sizeof(LDAPUListNode_t));
+
+ if (!node) {
+ return LDAPU_ERR_OUT_OF_MEMORY;
+ }
+
+ memset((void *)node, 0, sizeof(LDAPUListNode_t));
+ node->info = info;
+
+ return ldapu_list_add_node(list, node);
+}
+
+static int ldapu_list_remove_node (LDAPUList_t *list, LDAPUListNode_t *node)
+{
+ if (list->head == node) {
+ list->head = node->next;
+ if (list->tail == node) list->tail = 0; /* removed the only node */
+ }
+ else if (list->tail == node) {
+ list->tail = node->prev;
+ }
+ else {
+ node->prev->next = node->next;
+ node->next->prev = node->prev;
+ }
+
+ node->next = 0;
+ node->prev = 0;
+ return LDAPU_SUCCESS;
+}
+
+static int ldapu_list_copy (const LDAPUList_t *from, LDAPUList_t **to,
+ LDAPUListNodeFn_t copy_fn)
+{
+ LDAPUListNode_t *node = from->head;
+ LDAPUListNode_t *newnode;
+ LDAPUList_t *list;
+ int rv;
+
+ *to = 0;
+ rv = ldapu_list_alloc(&list);
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ while(node) {
+ newnode = (LDAPUListNode_t *)(*copy_fn)(node->info, 0);
+ if (!newnode) return LDAPU_ERR_OUT_OF_MEMORY;
+ rv = ldapu_list_add_info(list, newnode);
+ if (rv != LDAPU_SUCCESS) return rv;
+ node = node->next;
+ }
+
+ *to = list;
+ return LDAPU_SUCCESS;
+}
+
+static int ldapu_list_find_node (const LDAPUList_t *list,
+ LDAPUListNode_t **found,
+ LDAPUListNodeFn_t find_fn,
+ void *find_arg)
+{
+ LDAPUListNode_t *node = list->head;
+
+ while(node) {
+ if ((*find_fn)(node->info, find_arg) == LDAPU_SUCCESS) {
+ *found = node;
+ return LDAPU_SUCCESS;
+ }
+ node = node->next;
+ }
+
+ return LDAPU_ERR_CERTMAP_INFO_MISSING;
+}
+
+static int ldapu_list_print (LDAPUList_t *list, LDAPUListNodeFn_t print_fn,
+ LDAPUPrintInfo_t *pinfo)
+{
+ LDAPUListNode_t *node = list->head;
+ int rv;
+
+ while(node) {
+ rv = (int)(*print_fn)(node->info, pinfo);
+ if (rv != LDAPU_SUCCESS) return rv;
+ node = node->next;
+ }
+
+ return LDAPU_SUCCESS;
+}
+
+
+static void ldapu_list_free (LDAPUList_t *list, LDAPUListNodeFn_t free_fn)
+{
+ if (list) {
+ auto LDAPUListNode_t *node = list->head;
+ while (node) {
+ auto LDAPUListNode_t *next = node->next;
+ if (free_fn) {
+ (*free_fn)(node->info, 0);
+ node->info = 0;
+ }
+ node->info = 0;
+ free(node);
+ node = next;
+ }
+ list->head = 0;
+ list->tail = 0;
+ }
+ return;
+}
+
+NSAPI_PUBLIC int ldapu_propval_alloc (const char *prop, const char *val,
+ LDAPUPropVal_t **propval)
+{
+ *propval = (LDAPUPropVal_t *)malloc(sizeof(LDAPUPropVal_t));
+
+ if (!*propval) return LDAPU_ERR_OUT_OF_MEMORY;
+
+ (*propval)->prop = prop ? strdup(prop) : 0;
+ (*propval)->val = val ? strdup(val) : 0;
+
+ if ((!prop || (*propval)->prop) && (!val || (*propval)->val)) {
+ /* strdup worked */
+ return LDAPU_SUCCESS;
+ }
+ else {
+ return LDAPU_ERR_OUT_OF_MEMORY;
+ }
+}
+
+static void *ldapu_propval_copy (void *info, void *arg)
+{
+ LDAPUPropVal_t *propval = (LDAPUPropVal_t *)info;
+ LDAPUPropVal_t *copy = 0;
+ int rv;
+
+ rv = ldapu_propval_alloc(propval->prop, propval->val, &copy);
+
+ if (rv != LDAPU_SUCCESS) return 0;
+ return copy;
+}
+
+#define PRINT_STR(x) (x ? x : "<NULL>")
+
+static void * ldapu_propval_print (void *info, void *arg)
+{
+ LDAPUPropVal_t *propval = (LDAPUPropVal_t *)info;
+ LDAPUPrintInfo_t *pinfo = (LDAPUPrintInfo_t *)arg;
+
+ if (!pinfo || !pinfo->fp) {
+ fprintf(stderr, "\tprop = \"%s\", \tval = \"%s\"\n",
+ PRINT_STR(propval->prop),
+ PRINT_STR(propval->val));
+ }
+ else {
+ char *issuerName = (char *)pinfo->arg;
+
+ fprintf(pinfo->fp, "%s:%s %s\n", issuerName,
+ propval->prop ? propval->prop : "",
+ propval->val ? propval->val : "");
+ }
+
+ return 0;
+}
+
+static int PresentInComps (long comps_bitmask, int tag)
+{
+ long bit = certmap_secoid_to_bit_pos(tag);
+
+ if (comps_bitmask & bit)
+ return 1;
+ else
+ return 0;
+}
+
+static void print_oid_bitmask (long bitmask)
+{
+ fprintf(stderr, "%x: ", bitmask);
+
+ if (PresentInComps(bitmask, SEC_OID_AVA_COUNTRY_NAME))
+ fprintf(stderr, " C");
+ if (PresentInComps(bitmask, SEC_OID_AVA_ORGANIZATION_NAME))
+ fprintf(stderr, " O");
+ if (PresentInComps(bitmask, SEC_OID_AVA_COMMON_NAME))
+ fprintf(stderr, " CN");
+ if (PresentInComps(bitmask, SEC_OID_AVA_LOCALITY))
+ fprintf(stderr, " L");
+ if (PresentInComps(bitmask, SEC_OID_AVA_STATE_OR_PROVINCE))
+ fprintf(stderr, " ST");
+ if (PresentInComps(bitmask, SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME))
+ fprintf(stderr, " OU");
+ if (PresentInComps(bitmask, SEC_OID_PKCS9_EMAIL_ADDRESS))
+ fprintf(stderr, " E");
+ if (PresentInComps(bitmask, SEC_OID_RFC1274_UID))
+ fprintf(stderr, " UID");
+ if (PresentInComps(bitmask, SEC_OID_RFC1274_MAIL))
+ fprintf(stderr, " MAIL");
+ if (PresentInComps(bitmask, SEC_OID_AVA_DC))
+ fprintf(stderr, " DC");
+ /* check for not yet known oid */
+ if (PresentInComps(bitmask, 34325))
+ fprintf(stderr, " UNKNOWN");
+
+ fprintf(stderr, "\n");
+}
+
+static void *ldapu_certinfo_print (void *info, void *arg)
+{
+ LDAPUCertMapInfo_t *certinfo = (LDAPUCertMapInfo_t*)info;
+ LDAPUPrintInfo_t *pinfo = (LDAPUPrintInfo_t *)arg;
+
+ if (!certinfo) return (void *)LDAPU_ERR_WRONG_ARGS;
+
+ if (!pinfo || !pinfo->fp) {
+ fprintf(stderr, "Printing cert mapinfo: \"%s\" ...\n",
+ PRINT_STR(certinfo->issuerName));
+ fprintf(stderr, "\tissuerDN = \"%s\"\n",
+ PRINT_STR(certinfo->issuerDN));
+ fprintf(stderr, "\tParsed dncomps: ");
+ print_oid_bitmask(certinfo->dncomps);
+ fprintf(stderr, "\tParsed filtercomps: ");
+ print_oid_bitmask(certinfo->filtercomps);
+
+ if (certinfo->propval) {
+ fprintf(stderr, "\tPrinting propval pairs: ...\n");
+ if (certinfo->propval)
+ ldapu_list_print(certinfo->propval, ldapu_propval_print, pinfo);
+ }
+ else {
+ fprintf(stderr, "\tNo propval pairs\n");
+ }
+ }
+ else {
+ LDAPUPrintInfo_t pinfo2;
+
+ pinfo2.fp = pinfo->fp;
+ pinfo2.arg = certinfo->issuerName;
+
+ /* Write certinfo to pinfo->fp */
+ fprintf(pinfo->fp, "%s %s %s\n", LIB_DIRECTIVE, certinfo->issuerName,
+ certinfo->issuerDN ? certinfo->issuerDN : "");
+ if (certinfo->propval)
+ ldapu_list_print(certinfo->propval, ldapu_propval_print, &pinfo2);
+ fprintf(pinfo->fp, "\n");
+ }
+
+ return (void *)LDAPU_SUCCESS;
+}
+
+static int dbconf_to_certmap_err (int err)
+{
+ switch(err) {
+ case LDAPU_ERR_DBNAME_IS_MISSING:
+ return LDAPU_ERR_CANAME_IS_MISSING;
+ case LDAPU_ERR_PROP_IS_MISSING:
+ return LDAPU_ERR_CAPROP_IS_MISSING;
+ default:
+ return err;
+ }
+}
+
+/* CAUTION: this function hijacks some substructures from db_info and make
+ * the pointers to it NULL in the db_info. It is safe to deallocate db_info.
+ */
+static int dbinfo_to_certinfo (DBConfDBInfo_t *db_info,
+ LDAPUCertMapInfo_t **certinfo_out)
+{
+ LDAPUCertMapInfo_t *certinfo;
+ int rv;
+
+ *certinfo_out = 0;
+
+ certinfo = (LDAPUCertMapInfo_t *)malloc(sizeof(LDAPUCertMapInfo_t));
+
+ if (!certinfo) return LDAPU_ERR_OUT_OF_MEMORY;
+
+ memset((void *)certinfo, 0, sizeof(LDAPUCertMapInfo_t));
+
+ /* hijack few structures rather then copy. Make the pointers to the
+ structures NULL in the original structure so that they don't freed up
+ when db_info is freed. */
+ certinfo->issuerName = db_info->dbname;
+ db_info->dbname = 0;
+
+ certinfo->issuerDN = ldapu_dn_normalize(db_info->url);
+ db_info->url = 0;
+
+ /* hijack actual prop-vals from dbinfo -- to avoid strdup calls */
+ if (db_info->firstprop) {
+ LDAPUPropValList_t *propval_list;
+ LDAPUPropVal_t *propval;
+ DBPropVal_t *dbpropval;
+
+ dbpropval = db_info->firstprop;
+
+ rv = ldapu_list_alloc(&propval_list);
+
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ while(dbpropval) {
+ propval = (LDAPUPropVal_t *)malloc(sizeof(LDAPUPropVal_t));
+
+ if (!propval) {
+ free(certinfo);
+ return LDAPU_ERR_OUT_OF_MEMORY;
+ }
+
+ propval->prop = dbpropval->prop;
+ dbpropval->prop = 0;
+
+ propval->val = dbpropval->val;
+ dbpropval->val = 0;
+
+ rv = ldapu_list_add_info(propval_list, propval);
+
+ if (rv != LDAPU_SUCCESS) {
+ free(certinfo);
+ return rv;
+ }
+
+ dbpropval = dbpropval->next;
+ }
+
+ certinfo->propval = propval_list;
+ }
+
+ *certinfo_out = certinfo;
+
+ return LDAPU_SUCCESS;
+}
+
+static int ldapu_binary_cmp_certs (void *subject_cert,
+ void *entry_cert_binary,
+ unsigned long entry_cert_len)
+{
+ SECItem derCert = ((CERTCertificate*)subject_cert)->derCert;
+ int rv;
+
+ /* binary compare the two certs */
+ if (derCert.len == entry_cert_len &&
+ !memcmp(derCert.data, entry_cert_binary, entry_cert_len))
+ {
+ rv = LDAPU_SUCCESS;
+ }
+ else {
+ rv = LDAPU_ERR_CERT_VERIFY_FAILED;
+ }
+
+ return rv;
+}
+
+
+static int ldapu_cert_verifyfn_default (void *subject_cert, LDAP *ld,
+ void *certmap_info, LDAPMessage *res,
+ LDAPMessage **entry_out)
+{
+ LDAPMessage *entry;
+ struct berval **bvals;
+ int i;
+ int rv = LDAPU_ERR_CERT_VERIFY_FAILED;
+ char *cert_attr = ldapu_strings[LDAPU_STR_ATTR_CERT];
+ char *cert_attr_nosubtype = ldapu_strings[LDAPU_STR_ATTR_CERT_NOSUBTYPE];
+
+ *entry_out = 0;
+
+ for (entry = ldapu_first_entry(ld, res); entry != NULL;
+ entry = ldapu_next_entry(ld, entry))
+ {
+ if (((bvals = ldapu_get_values_len(ld, entry, cert_attr)) == NULL) &&
+ ((bvals = ldapu_get_values_len(ld, entry, cert_attr_nosubtype)) == NULL)) {
+ rv = LDAPU_ERR_CERT_VERIFY_NO_CERTS;
+ continue;
+ }
+
+ for ( i = 0; bvals[i] != NULL; i++ ) {
+ rv = ldapu_binary_cmp_certs (subject_cert,
+ bvals[i]->bv_val,
+ bvals[i]->bv_len);
+
+ if (rv == LDAPU_SUCCESS) {
+ break;
+ }
+ }
+
+ ldapu_value_free_len(ld, bvals);
+
+ if (rv == LDAPU_SUCCESS) {
+ *entry_out = entry;
+ break;
+ }
+ }
+
+ return rv;
+}
+
+static int parse_into_bitmask (const char *comps_in, long *bitmask_out,
+ long default_val)
+{
+ long bitmask;
+ char *comps = comps_in ? strdup(comps_in) : 0;
+
+ if (!comps) {
+ /* Not present in the config file */
+ bitmask = default_val;
+ }
+ else if (!*comps) {
+ /* present but empty */
+ bitmask = 0;
+ }
+ else {
+ char *ptr = comps;
+ char *name = comps;
+ long bit;
+ int break_loop = 0;
+
+ bitmask = 0;
+
+ while (*name) {
+ /* advance ptr to delimeter */
+ while(*ptr && !isspace(*ptr) && *ptr != ',') ptr++;
+
+ if (!*ptr)
+ break_loop = 1;
+ else
+ *ptr++ = 0;
+
+ bit = certmap_name_to_bit_pos(name);
+ bitmask |= bit;
+
+ if (break_loop) break;
+ /* skip delimeters */
+ while(*ptr && (isspace(*ptr) || *ptr == ',')) ptr++;
+ name = ptr;
+ }
+ }
+
+ if (comps) free(comps);
+ *bitmask_out = bitmask;
+/* print_oid_bitmask(bitmask); */
+ return LDAPU_SUCCESS;
+}
+
+static int process_certinfo (LDAPUCertMapInfo_t *certinfo)
+{
+ int rv = LDAPU_SUCCESS;
+ char *dncomps = 0;
+ char *filtercomps = 0;
+ char *libname = 0;
+ char *verify = 0;
+ char *fname = 0;
+ char *searchAttr = 0;
+
+ if (!ldapu_strcasecmp(certinfo->issuerName, "default")) {
+ default_certmap_info = certinfo;
+ }
+ else if (!certinfo->issuerDN) {
+ return LDAPU_ERR_NO_ISSUERDN_IN_CONFIG_FILE;
+ }
+ else {
+ rv = ldapu_list_add_info(certmap_listinfo, certinfo);
+ }
+
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ /* look for dncomps property and parse it into the dncomps bitmask */
+ rv = ldapu_certmap_info_attrval (certinfo, LDAPU_ATTR_DNCOMPS, &dncomps);
+
+ if (rv == LDAPU_SUCCESS && dncomps) {
+ certinfo->dncompsState = COMPS_HAS_ATTRS;
+ tolower_string(dncomps);
+ }
+ else if (rv == LDAPU_FAILED) {
+ certinfo->dncompsState = COMPS_COMMENTED_OUT;
+ rv = LDAPU_SUCCESS;
+ }
+ else if (rv == LDAPU_SUCCESS && !dncomps) {
+ certinfo->dncompsState = COMPS_EMPTY;
+ dncomps = ""; /* present but empty */
+ }
+
+ rv = parse_into_bitmask (dncomps, &certinfo->dncomps, -1);
+
+ if (dncomps && *dncomps) free(dncomps);
+
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ /* look for filtercomps property and parse it into the filtercomps bitmask */
+ rv = ldapu_certmap_info_attrval(certinfo, LDAPU_ATTR_FILTERCOMPS,
+ &filtercomps);
+
+ if (rv == LDAPU_SUCCESS && filtercomps) {
+ certinfo->filtercompsState = COMPS_HAS_ATTRS;
+ tolower_string(filtercomps);
+ }
+ else if (rv == LDAPU_FAILED) {
+ certinfo->filtercompsState = COMPS_COMMENTED_OUT;
+ rv = LDAPU_SUCCESS;
+ }
+ else if (rv == LDAPU_SUCCESS && !filtercomps) {
+ certinfo->filtercompsState = COMPS_EMPTY;
+ filtercomps = ""; /* present but empty */
+ }
+
+ rv = parse_into_bitmask (filtercomps, &certinfo->filtercomps, 0);
+
+ if (filtercomps && *filtercomps) free(filtercomps);
+
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ /* look for "CmapLdapAttr" property and store it into searchAttr */
+ rv = ldapu_certmap_info_attrval(certinfo, LDAPU_ATTR_CERTMAP_LDAP_ATTR,
+ &searchAttr);
+
+ if (rv == LDAPU_FAILED || !searchAttr || !*searchAttr)
+ rv = LDAPU_SUCCESS;
+ else {
+ certinfo->searchAttr = searchAttr ? strdup(searchAttr) : 0;
+
+ if (searchAttr && !certinfo->searchAttr)
+ rv = LDAPU_ERR_OUT_OF_MEMORY;
+ else
+ rv = LDAPU_SUCCESS;
+ }
+
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ /* look for verifycert property and set the default verify function */
+ /* The value of the verifycert property is ignored */
+ rv = ldapu_certmap_info_attrval(certinfo, LDAPU_ATTR_VERIFYCERT, &verify);
+
+ if (rv == LDAPU_SUCCESS) {
+ if (!ldapu_strcasecmp(verify, "on"))
+ certinfo->verifyCert = 1;
+ else if (!ldapu_strcasecmp(verify, "off"))
+ certinfo->verifyCert = 0;
+ else if (!verify || !*verify) /* for mail/news backward compatibilty */
+ certinfo->verifyCert = 1; /* otherwise, this should be an error */
+ else
+ rv = LDAPU_ERR_MISSING_VERIFYCERT_VAL;
+ }
+ else if (rv == LDAPU_FAILED) rv = LDAPU_SUCCESS;
+
+ if (verify && *verify) free(verify);
+
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ {
+ PRLibrary *lib = 0;
+
+ /* look for the library property and load it */
+ rv = ldapu_certmap_info_attrval(certinfo, LDAPU_ATTR_LIBRARY, &libname);
+
+ if (rv == LDAPU_SUCCESS) {
+ if (libname && *libname) {
+ lib = PR_LoadLibrary(libname);
+ if (!lib) rv = LDAPU_ERR_UNABLE_TO_LOAD_PLUGIN;
+ }
+ else {
+ rv = LDAPU_ERR_MISSING_LIBNAME;
+ }
+ }
+ else if (rv == LDAPU_FAILED) rv = LDAPU_SUCCESS;
+
+ if (libname) free(libname);
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ /* look for the InitFn property, find it in the libray and call it */
+ rv = ldapu_certmap_info_attrval(certinfo, LDAPU_ATTR_INITFN, &fname);
+
+ if (rv == LDAPU_SUCCESS) {
+ if (fname && *fname) {
+ /* If lib is NULL, PR_FindSymbol will search all libs loaded
+ * through PR_LoadLibrary.
+ */
+ CertMapInitFn_t fn = (CertMapInitFn_t)PR_FindSymbol(lib, fname);
+
+ if (!fn) {
+ rv = LDAPU_ERR_MISSING_INIT_FN_IN_LIB;
+ }
+ else {
+ rv = (*fn)(certinfo, certinfo->issuerName,
+ certinfo->issuerDN, this_dllname);
+ }
+ }
+ else {
+ rv = LDAPU_ERR_MISSING_INIT_FN_NAME;
+ }
+ }
+ else if (lib) {
+ /* If library is specified, init function must be specified */
+ /* If init fn is specified, library may not be specified */
+ rv = LDAPU_ERR_MISSING_INIT_FN_IN_CONFIG;
+ }
+ else if (rv == LDAPU_FAILED) rv = LDAPU_SUCCESS;
+
+ if (fname) free(fname);
+
+ if (rv != LDAPU_SUCCESS) return rv;
+ }
+
+ return rv;
+}
+
+/* This function will read multiple certmap directives and set the information
+ * in the global certmap_listinfo structure.
+ */
+int certmap_read_certconfig_file (const char *file)
+{
+ DBConfInfo_t *conf_info = 0;
+ int rv;
+
+ /* Read the config file */
+ rv = dbconf_read_config_file_sub(file, LIB_DIRECTIVE, LIB_DIRECTIVE_LEN,
+ &conf_info);
+
+ /* Convert the conf_info into certmap_listinfo. Some of the
+ * sub-structures are simply hijacked rather than copied since we are
+ * going to (carefully) free the conf_info anyway.
+ */
+
+ if (rv == LDAPU_SUCCESS && conf_info) {
+ DBConfDBInfo_t *nextdb;
+ DBConfDBInfo_t *curdb;
+ LDAPUCertMapInfo_t *certinfo;
+
+ curdb = conf_info->firstdb;
+
+ while (curdb) {
+ nextdb = curdb->next;
+ rv = dbinfo_to_certinfo(curdb, &certinfo);
+
+ if (rv != LDAPU_SUCCESS) {
+ dbconf_free_confinfo(conf_info);
+ return rv;
+ }
+
+ rv = process_certinfo(certinfo);
+
+ if (rv != LDAPU_SUCCESS) {
+ dbconf_free_confinfo(conf_info);
+ return rv;
+ }
+
+ curdb = nextdb;
+ }
+
+ dbconf_free_confinfo(conf_info);
+ }
+ else {
+ rv = dbconf_to_certmap_err(rv);
+ }
+
+ return rv;
+}
+
+/* This function will read the "certmap default" directive from the config
+ * file and set the information in the global certmap_info.
+ */
+int certmap_read_default_certinfo (const char *file)
+{
+ DBConfDBInfo_t *db_info = 0;
+ int rv;
+
+ rv = dbconf_read_default_dbinfo_sub(file, LIB_DIRECTIVE, LIB_DIRECTIVE_LEN,
+ &db_info);
+
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ rv = dbinfo_to_certinfo(db_info, &default_certmap_info);
+
+ dbconf_free_dbinfo(db_info);
+ return rv;
+}
+
+static int ldapu_cert_searchfn_default (void *cert, LDAP *ld,
+ void *certmap_info_in,
+ const char *basedn, const char *dn,
+ const char *filter,
+ const char **attrs, LDAPMessage ***res)
+{
+ int rv = LDAPU_FAILED;
+ const char *ldapdn;
+ LDAPUCertMapInfo_t *certmap_info = (LDAPUCertMapInfo_t *)certmap_info_in;
+ LDAPMessage * single_res = NULL;
+ LDAPMessage ** multiple_res = NULL;
+
+
+ if (certmap_info && certmap_info->searchAttr) {
+ char *subjectDN = 0;
+ char *certFilter = 0;
+ int len;
+
+ rv = ldapu_get_cert_subject_dn(cert, &subjectDN);
+
+ if (rv != LDAPU_SUCCESS || !subjectDN || !*subjectDN) return rv;
+ len = strlen(certmap_info->searchAttr) + strlen(subjectDN) +
+ strlen("=") + 1;
+ certFilter = (char *)malloc(len * sizeof(char));
+ if (!certFilter) return LDAPU_ERR_OUT_OF_MEMORY;
+ sprintf(certFilter, "%s=%s", certmap_info->searchAttr, subjectDN);
+ free(subjectDN);
+ if ( ldapu_strcasecmp(basedn, "") ) {
+ rv = ldapu_find(ld, basedn, LDAP_SCOPE_SUBTREE, certFilter, attrs, 0, &single_res);
+ ldapu_free((void *)certFilter);
+ if (rv == LDAPU_SUCCESS || rv == LDAPU_ERR_MULTIPLE_MATCHES) {
+ *res = (LDAPMessage **) ldapu_malloc(2 * sizeof(LDAPMessage *));
+ (*res)[0] = single_res;
+ (*res)[1] = NULL;
+ return rv;
+ } else if (single_res) {
+ ldapu_msgfree(ld, single_res);
+ single_res = 0;
+ }
+ } else {
+ rv = ldapu_find_entire_tree(ld, LDAP_SCOPE_SUBTREE, certFilter, attrs, 0, &multiple_res);
+ ldapu_free((void *)certFilter);
+ if (rv == LDAPU_SUCCESS || rv == LDAPU_ERR_MULTIPLE_MATCHES) {
+ *res = multiple_res;
+ return rv;
+ } else if (multiple_res) {
+ int n;
+ for ( n = 0; multiple_res[n] != NULL; n++)
+ ldapu_msgfree(ld, multiple_res[n]);
+ ldapu_memfree(ld, multiple_res);
+ }
+ }
+
+ }
+
+ if (dn && *dn) {
+ /* First do the base level search --- NOT ANY MORE!! */
+ /* We actually do the search on the whole subtree hanging from "ldapdn" since we want to
+ * find all the entries that match the filter.
+ * If we get more than one matching entry in return, it'll be at verify time that we'll
+ * choose the correct one among them all.
+ * However, if certificate verify is not active, certificate mapping will fail and will
+ * consequently display an error message (something done at 'handle_handshake_done' level,
+ * for instance). */
+ ldapdn = dn;
+
+ if ( ldapu_strcasecmp(ldapdn, "") ) {
+ rv = ldapu_find(ld, ldapdn, LDAP_SCOPE_SUBTREE, filter, attrs, 0, &single_res);
+ if (rv == LDAPU_SUCCESS || rv == LDAPU_ERR_MULTIPLE_MATCHES) {
+ *res = (LDAPMessage **) ldapu_malloc(2 * sizeof(LDAPMessage *));
+ (*res)[0] = single_res;
+ (*res)[1] = NULL;
+ return rv;
+ } else if (single_res) {
+ ldapu_msgfree(ld, single_res);
+ single_res = 0;
+ }
+ } else {
+ rv = ldapu_find_entire_tree(ld, LDAP_SCOPE_SUBTREE, filter, attrs, 0, &multiple_res);
+ if (rv == LDAPU_SUCCESS || rv == LDAPU_ERR_MULTIPLE_MATCHES) {
+ *res = multiple_res;
+ return rv;
+ } else if (multiple_res) {
+ int n;
+ for ( n = 0; multiple_res[n] != NULL; n++)
+ ldapu_msgfree(ld, multiple_res[n]);
+ ldapu_memfree(ld, multiple_res);
+ }
+ }
+ } else {
+ /* default the dn and filter for subtree search */
+ ldapdn = basedn;
+ if (!filter || !*filter) {
+ if (certmap_info && certmap_info->searchAttr) {
+ /* dn & filter returned by the mapping function are both NULL
+ and 'searchAttr' based search has failed. Don't do brute
+ force search if 'searchAttr' is being used. Otherwise,
+ this search will result in all LDAP entries being
+ returned.
+ */
+ }
+ else {
+ filter = "objectclass=*";
+ }
+ }
+ }
+
+ /* For local LDAP DB, the LDAP_SCOPE_BASE search may fail for dn == basedn
+ * since that object doesn't actually exists.
+ */
+ if ((rv == LDAPU_FAILED || rv == LDAP_NO_SUCH_OBJECT) && filter && (!dn || !*dn)) {
+
+ /* Try the subtree search only if the filter is non-NULL */
+ if ( ldapu_strcasecmp(ldapdn, "") ) {
+ rv = ldapu_find(ld, ldapdn, LDAP_SCOPE_SUBTREE, filter, 0, 0, &single_res);
+ if (rv == LDAPU_SUCCESS || rv == LDAPU_ERR_MULTIPLE_MATCHES) {
+ *res = (LDAPMessage **) ldapu_malloc(2 * sizeof(LDAPMessage *));
+ (*res)[0] = single_res;
+ (*res)[1] = NULL;
+ return rv;
+ } else if (single_res) {
+ ldapu_msgfree(ld, single_res);
+ single_res = 0;
+ }
+ } else {
+ rv = ldapu_find_entire_tree(ld, LDAP_SCOPE_SUBTREE, filter, 0, 0, &multiple_res);
+ if (rv == LDAPU_SUCCESS || rv == LDAPU_ERR_MULTIPLE_MATCHES) {
+ *res = multiple_res;
+ return rv;
+ } else if (multiple_res) {
+ int n;
+ for ( n = 0; multiple_res[n] != NULL; n++)
+ ldapu_msgfree(ld, multiple_res[n]);
+ ldapu_memfree(ld, multiple_res);
+ }
+ }
+ }
+
+ if (rv == LDAPU_FAILED) {
+ /* Not an error but couldn't map the cert */
+ rv = LDAPU_ERR_MAPPED_ENTRY_NOT_FOUND;
+ }
+ else if ((!dn || !*dn) && (rv == LDAP_NO_SUCH_OBJECT)) {
+ rv = LDAPU_ERR_INVALID_SUFFIX;
+ }
+
+ return rv;
+}
+
+NSAPI_PUBLIC int ldapu_issuer_certinfo (const char *issuerDN, void **certmap_info)
+{
+ *certmap_info = 0;
+
+ if (!issuerDN || !*issuerDN || !ldapu_strcasecmp(issuerDN, "default")) {
+ *certmap_info = default_certmap_info;
+ }
+ else if (certmap_listinfo) {
+ char *n_issuerDN = ldapu_dn_normalize (ldapu_strdup(issuerDN));
+ LDAPUListNode_t *cur = certmap_listinfo->head;
+ int rv = LDAPU_FAILED;
+ while(cur) {
+ if (!ldapu_strcasecmp(n_issuerDN, ((LDAPUCertMapInfo_t *)cur->info)->issuerDN))
+ {
+ *certmap_info = cur->info;
+ rv = LDAPU_SUCCESS;
+ break;
+ }
+ cur = cur->next;
+ }
+ if (n_issuerDN) ldapu_free (n_issuerDN);
+ }
+ return *certmap_info ? LDAPU_SUCCESS : LDAPU_FAILED;
+}
+
+NSAPI_PUBLIC int ldapu_certmap_info_attrval (void *certmap_info_in,
+ const char *attr, char **val)
+{
+ /* Look for given attr in the certmap_info and return its value */
+ LDAPUCertMapInfo_t *certmap_info = (LDAPUCertMapInfo_t *)certmap_info_in;
+ LDAPUListNode_t *curprop = certmap_info->propval ? certmap_info->propval->head : 0;
+ LDAPUPropVal_t *propval;
+ int rv = LDAPU_FAILED;
+
+ *val = 0;
+ while(curprop) {
+ propval = (LDAPUPropVal_t *)curprop->info;
+ if (!ldapu_strcasecmp(propval->prop, attr)) {
+ *val = propval->val ? strdup(propval->val) : 0;
+ rv = LDAPU_SUCCESS;
+ break;
+ }
+ curprop = curprop->next;
+ }
+
+ return rv;
+}
+
+static int AddAVAToBuf (char *buf, int size, int *len,
+ const char *tagName, CERTAVA *ava)
+{
+ int lenLen;
+ int taglen;
+ SECStatus rv;
+
+ buf += *len;
+
+ /* Copied from ns/lib/libsec ...
+ * XXX this code is incorrect in general
+ * -- should use a DER template.
+ */
+ lenLen = 2;
+ if (ava->value.len >= 128) lenLen = 3;
+
+ taglen = PL_strlen(tagName);
+ memcpy(buf, tagName, taglen);
+ buf[taglen++] = '=';
+
+ rv = CERT_RFC1485_EscapeAndQuote(buf+taglen,
+ size-taglen,
+ (char*) ava->value.data + lenLen,
+ ava->value.len - lenLen);
+
+ *len += strlen(buf);
+
+ return (rv == SECSuccess ? LDAPU_SUCCESS : LDAPU_FAILED);
+}
+
+static int AddToLdapDN (char *ldapdn, int size, int *dnlen,
+ const char *tagName, CERTAVA *ava)
+{
+ char *dn = ldapdn + *dnlen;
+
+ if (*dnlen) { strcat(dn, ", "); dn += 2; *dnlen += 2; }
+ return AddAVAToBuf(ldapdn, size, dnlen, tagName, ava);
+}
+
+static int AddToFilter (char *filter, int size, int *flen,
+ const char *tagName, CERTAVA *ava)
+{
+ int rv;
+
+ /* Append opening parenthesis */
+ strcat(filter + *flen, " (");
+ *flen += 2;
+ rv = AddAVAToBuf(filter, size, flen, tagName, ava);
+
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ /* Append closing parenthesis */
+ strcat(filter + *flen, ")");
+ (*flen)++;
+
+ return rv;
+}
+
+NSAPI_PUBLIC int ldapu_free_cert_ava_val (char **val)
+{
+ char **ptr = val;
+
+ if (!val) return LDAPU_SUCCESS;
+
+ while(*ptr) free(*ptr++);
+ free(val);
+
+ return LDAPU_SUCCESS;
+}
+
+static int ldapu_cert_mapfn_default (void *cert_in, LDAP *ld,
+ void *certmap_info_in,
+ char **ldapDN_out, char **filter_out)
+{
+ CERTCertificate *cert = (CERTCertificate *)cert_in;
+ LDAPUCertMapInfo_t *certmap_info= (LDAPUCertMapInfo_t *)certmap_info_in;
+ int rv = LDAPU_SUCCESS;
+
+ *ldapDN_out = *filter_out = 0;
+
+ if (!certmap_info) {
+ /* Use subject DN as is -- identity mapping function */
+ rv = ldapu_get_cert_subject_dn(cert, ldapDN_out);
+
+ return rv;
+ }
+ else {
+ /*
+ * Iterate over rdns from the subject and collect AVAs depending on
+ * dnComps and filtercomps to form ldapDN and filter respectively.
+ * certmap_info->dncomps
+ */
+ CERTName *subject = &cert->subject;
+ CERTRDN **rdns = subject->rdns;
+ CERTRDN **lastRdn;
+ CERTRDN **rdn;
+ CERTAVA **avas;
+ CERTAVA *ava;
+ char ldapdn[BIG_LINE];
+ char filter[BIG_LINE];
+ int dnlen = 0; /* ldap DN length */
+ int flen = 0; /* filter length */
+ int numfavas = 0; /* no of avas added to filter */
+
+ if (rdns == NULL) {
+ /* error */
+ }
+
+ /* find last RDN */
+ lastRdn = rdns;
+ while (*lastRdn) lastRdn++;
+ lastRdn--;
+
+ /* Initialize filter to "(&" */
+ strcpy(filter, "(&");
+ flen = 2;
+
+ /*
+ * Loop over subject rdns in the _reverse_ order while forming ldapDN
+ * and filter.
+ */
+ for (rdn = lastRdn; rdn >= rdns; rdn--) {
+ avas = (*rdn)->avas;
+ while ((ava = *avas++) != NULL) {
+ int tag = CERT_GetAVATag(ava);
+ const char *tagName = certmap_secoid_to_name(tag);
+
+ if (PresentInComps(certmap_info->dncomps, tag)) {
+ rv = AddToLdapDN(ldapdn, BIG_LINE, &dnlen, tagName, ava);
+ if (rv != LDAPU_SUCCESS) return rv;
+ }
+
+ if (PresentInComps(certmap_info->filtercomps, tag)) {
+ rv = AddToFilter(filter, BIG_LINE, &flen, tagName, ava);
+ if (rv != LDAPU_SUCCESS) return rv;
+ numfavas++;
+ }
+ }
+ }
+
+ if (numfavas == 0) {
+ /* nothing added to filter */
+ *filter = 0;
+ }
+ else if (numfavas == 1) {
+ /* one ava added to filter -- remove "(& (" from the front and ")"
+ * from the end.
+ */
+ *filter_out = strdup(filter+4);
+ if (!*filter_out) return LDAPU_ERR_OUT_OF_MEMORY;
+ (*filter_out)[strlen(*filter_out)-1] = 0;
+ }
+ else {
+ /* Add the closing parenthesis to filter */
+ strcat(filter+flen, ")");
+ *filter_out = strdup(filter);
+ }
+
+ if (dnlen >= BIG_LINE) return LDAPU_FAILED;
+ ldapdn[dnlen] = 0;
+ *ldapDN_out = *ldapdn ? strdup(ldapdn) : 0;
+
+ if ((numfavas && !*filter_out) || (dnlen && !*ldapDN_out)) {
+ /* strdup failed */
+ return LDAPU_ERR_OUT_OF_MEMORY;
+ }
+
+ if ((certmap_info->dncompsState == COMPS_HAS_ATTRS && dnlen == 0) ||
+ (certmap_info->filtercompsState == COMPS_HAS_ATTRS &&
+ numfavas == 0))
+ {
+ /* At least one attr in DNComps should be present in the cert */
+ /* Same is true for FilterComps */
+ rv = LDAPU_ERR_MAPPED_ENTRY_NOT_FOUND;
+ }
+ }
+
+ return rv;
+}
+
+NSAPI_PUBLIC int ldapu_set_cert_mapfn (const char *issuerDN,
+ CertMapFn_t mapfn)
+{
+ LDAPUCertMapInfo_t *certmap_info;
+ int rv;
+
+ /* don't free the certmap_info -- its a pointer to an internal structure */
+ rv = ldapu_issuer_certinfo(issuerDN, (void **)&certmap_info);
+
+ /* Don't set the mapping function if certmap_info doesen't exist */
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ certmap_info->mapfn = mapfn;
+ return LDAPU_SUCCESS;
+}
+
+static CertMapFn_t ldapu_get_cert_mapfn_sub (LDAPUCertMapInfo_t *certmap_info)
+{
+ CertMapFn_t mapfn;
+
+ if (certmap_info && certmap_info->mapfn)
+ mapfn = certmap_info->mapfn;
+ else if (default_certmap_info && default_certmap_info->mapfn)
+ mapfn = default_certmap_info->mapfn;
+ else
+ mapfn = ldapu_cert_mapfn_default;
+
+ return mapfn;
+}
+
+NSAPI_PUBLIC CertMapFn_t ldapu_get_cert_mapfn (const char *issuerDN)
+{
+ LDAPUCertMapInfo_t *certmap_info = 0;
+ int rv;
+
+ /* don't free the certmap_info -- its a pointer to an internal structure */
+ rv = ldapu_issuer_certinfo(issuerDN, (void **)&certmap_info);
+ /* certmap_info may be NULL -- use the default */
+
+ return ldapu_get_cert_mapfn_sub(certmap_info);
+}
+
+NSAPI_PUBLIC int ldapu_set_cert_searchfn (const char *issuerDN,
+ CertSearchFn_t searchfn)
+{
+ LDAPUCertMapInfo_t *certmap_info;
+ int rv;
+
+ /* don't free the certmap_info -- its a pointer to an internal structure */
+ rv = ldapu_issuer_certinfo(issuerDN, (void **)&certmap_info);
+
+ /* Don't set the mapping function if certmap_info doesen't exist */
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ certmap_info->searchfn = searchfn;
+ return LDAPU_SUCCESS;
+}
+
+static CertSearchFn_t ldapu_get_cert_searchfn_sub (LDAPUCertMapInfo_t *certmap_info)
+{
+ CertSearchFn_t searchfn;
+
+ if (certmap_info && certmap_info->searchfn)
+ searchfn = certmap_info->searchfn;
+ else if (default_certmap_info && default_certmap_info->searchfn)
+ searchfn = default_certmap_info->searchfn;
+ else
+ searchfn = ldapu_cert_searchfn_default;
+
+ return searchfn;
+}
+
+NSAPI_PUBLIC CertSearchFn_t ldapu_get_cert_searchfn (const char *issuerDN)
+{
+ LDAPUCertMapInfo_t *certmap_info = 0;
+ int rv;
+
+ /* don't free the certmap_info -- its a pointer to an internal structure */
+ rv = ldapu_issuer_certinfo(issuerDN, (void **)&certmap_info);
+ /* certmap_info may be NULL -- use the default */
+
+ return ldapu_get_cert_searchfn_sub(certmap_info);
+}
+
+NSAPI_PUBLIC int ldapu_set_cert_verifyfn (const char *issuerDN,
+ CertVerifyFn_t verifyfn)
+{
+ LDAPUCertMapInfo_t *certmap_info;
+ int rv;
+
+ /* don't free the certmap_info -- its a pointer to an internal structure */
+ rv = ldapu_issuer_certinfo(issuerDN, (void **)&certmap_info);
+
+ /* Don't set the verify function if certmap_info doesen't exist */
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ certmap_info->verifyfn = verifyfn;
+ return LDAPU_SUCCESS;
+}
+
+static CertVerifyFn_t ldapu_get_cert_verifyfn_sub (LDAPUCertMapInfo_t *certmap_info)
+{
+ CertVerifyFn_t verifyfn;
+
+ if (certmap_info && certmap_info->verifyfn)
+ verifyfn = certmap_info->verifyfn;
+ else if (default_certmap_info && default_certmap_info->verifyfn)
+ verifyfn = default_certmap_info->verifyfn;
+ else
+ verifyfn = ldapu_cert_verifyfn_default;
+
+ return verifyfn;
+}
+
+NSAPI_PUBLIC CertVerifyFn_t ldapu_get_cert_verifyfn (const char *issuerDN)
+{
+ LDAPUCertMapInfo_t *certmap_info = 0;
+ int rv;
+
+ /* don't free the certmap_info -- its a pointer to an internal structure */
+ rv = ldapu_issuer_certinfo(issuerDN, (void **)&certmap_info);
+ /* certmap_info may be NULL -- use the default */
+
+ return ldapu_get_cert_verifyfn_sub(certmap_info);
+}
+
+static int ldapu_certinfo_copy (const LDAPUCertMapInfo_t *from,
+ const char *newIssuerName,
+ const char *newIssuerDN,
+ LDAPUCertMapInfo_t *to)
+{
+ /* This function is not tested and is not used */
+ int rv;
+
+ to->issuerName = newIssuerName ? strdup(newIssuerName) : 0;
+ to->issuerDN = newIssuerDN ? strdup(newIssuerDN) : 0;
+ if (from->propval) {
+ rv = ldapu_list_copy(from->propval, &to->propval, ldapu_propval_copy);
+ if (rv != LDAPU_SUCCESS) return rv;
+ }
+ else {
+ to->propval = 0;
+ }
+
+ return process_certinfo(to);
+}
+
+NSAPI_PUBLIC int ldapu_cert_to_ldap_entry (void *cert, LDAP *ld,
+ const char *basedn,
+ LDAPMessage **res)
+{
+ char *issuerDN = 0;
+ char *ldapDN = 0;
+ char *filter = 0;
+ LDAPUCertMapInfo_t *certmap_info;
+ LDAPMessage **res_array = NULL;
+ CertMapFn_t mapfn;
+ CertVerifyFn_t verifyfn;
+ CertSearchFn_t searchfn;
+ void *entry_cert = 0;
+ int rv,i,j;
+
+ *res = 0;
+
+ if (!certmap_attrs[0]) {
+ /* Initialize certmap_attrs */
+ certmap_attrs[0] = ldapu_strings[LDAPU_STR_ATTR_USER];
+ certmap_attrs[1] = ldapu_strings[LDAPU_STR_ATTR_CERT];
+ certmap_attrs[2] = ldapu_strings[LDAPU_STR_ATTR_CERT_NOSUBTYPE];
+ certmap_attrs[3] = 0;
+ }
+
+ rv = ldapu_get_cert_issuer_dn(cert, &issuerDN);
+
+ if (rv != LDAPU_SUCCESS) return LDAPU_ERR_NO_ISSUERDN_IN_CERT;
+
+ /* don't free the certmap_info -- its a pointer to an internal structure */
+ rv = ldapu_issuer_certinfo(issuerDN, (void **)&certmap_info);
+ free(issuerDN);
+
+ if (!certmap_info) certmap_info = default_certmap_info;
+
+ /* Get the mapping function from the certmap_info */
+ mapfn = ldapu_get_cert_mapfn_sub(certmap_info);
+
+ rv = (*mapfn)(cert, ld, certmap_info, &ldapDN, &filter);
+
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ /* Get the search function from the certmap_info - certinfo maybe NULL */
+ searchfn = ldapu_get_cert_searchfn_sub(certmap_info);
+
+ rv = (*searchfn)(cert, ld, certmap_info, basedn, ldapDN, filter,
+ certmap_attrs, &res_array);
+
+ if (ldapDN) free(ldapDN);
+ if (filter) free(filter);
+
+ /*
+ * Get the verify cert function & call it.
+ */
+ j = 0;
+ if ((rv == LDAPU_SUCCESS || rv == LDAPU_ERR_MULTIPLE_MATCHES) &&
+ (certmap_info ? certmap_info->verifyCert : 0))
+ {
+ verifyfn = ldapu_get_cert_verifyfn_sub(certmap_info);
+
+ if (verifyfn) {
+ int verify_rv;
+
+ i = 0;
+ do {
+ LDAPMessage *entry;
+ verify_rv = (*verifyfn)(cert, ld, certmap_info, res_array[i], &entry);
+
+ if (rv == LDAPU_ERR_MULTIPLE_MATCHES) {
+ if (verify_rv == LDAPU_SUCCESS) {
+ /* 'entry' points to the matched entry */
+ /* Get the 'res' which only contains this entry */
+ char *dn = ldapu_get_dn(ld, entry);
+ if (*res) ldapu_msgfree(ld, *res);
+ rv = ldapu_find(ld, dn, LDAP_SCOPE_BASE, 0, certmap_attrs, 0, res);
+ ldapu_memfree(ld, dn);
+ }
+ else {
+ /* Verify failed for multiple matches -- keep rv */
+ /* multiple matches err is probably more interesting to
+ the caller then any other error returned by the verify
+ fn */
+ }
+ }
+ else /* rv == LDAPU_SUCCESS */ {
+ if (verify_rv == LDAPU_SUCCESS) {
+ *res = res_array[0];
+ j = 1;
+ } else {
+ rv = verify_rv;
+ }
+ }
+ } while ( (verify_rv != LDAPU_SUCCESS) && (res_array[++i] != NULL) );
+ }
+ } else {
+ if (rv == LDAPU_SUCCESS) {
+ *res = res_array[0];
+ j = 1;
+ }
+ }
+
+
+
+ if (rv != LDAPU_SUCCESS) {
+ if (*res) { ldapu_msgfree(ld, *res); *res = 0; }
+ }
+
+ i = j; /* ugaston - if the search had been successful, despite verifyCert being "off",
+ * mapping is considered successful, so we keep the first (and only) response message.
+ * If, on the other hand, the search had returned multiple matches, the fact
+ * of having verifyCert "off" automatically turns the mapping faulty, so we
+ * don't need to care about keeping any response at all.
+ */
+
+ if (res_array) {
+ while (res_array[i] != NULL) {
+ ldapu_msgfree(ld, res_array[i]);
+ res_array[i++] = 0;
+ }
+ ldapu_memfree(ld, res_array);
+ }
+ return rv;
+}
+
+/* The caller shouldn't free the entry */
+NSAPI_PUBLIC int ldapu_cert_to_user (void *cert, LDAP *ld, const char *basedn,
+ LDAPMessage **res_out, char **user)
+{
+ int rv;
+ LDAPMessage *res;
+ LDAPMessage *entry;
+ int numEntries;
+ char **attrVals;
+
+ *res_out = 0;
+ *user = 0;
+
+ rv = ldapu_cert_to_ldap_entry(cert, ld, basedn, &res);
+
+ if (rv != LDAPU_SUCCESS) {
+ return rv;
+ }
+
+ if (!res) {
+ return LDAPU_ERR_EMPTY_LDAP_RESULT;
+ }
+
+ /* Extract user login (the 'uid' attr) from 'res' */
+ numEntries = ldapu_count_entries(ld, res);
+
+ if (numEntries != 1) {
+ return LDAPU_ERR_MULTIPLE_MATCHES;
+ }
+
+ entry = ldapu_first_entry(ld, res);
+
+ if (!entry) {
+ return LDAPU_ERR_MISSING_RES_ENTRY;
+ }
+
+ attrVals = ldapu_get_values(ld, entry,
+ ldapu_strings[LDAPU_STR_ATTR_USER]);
+
+ if (!attrVals || !attrVals[0]) {
+ return LDAPU_ERR_MISSING_UID_ATTR;
+ }
+
+ *user = strdup(attrVals[0]);
+ ldapu_value_free(ld, attrVals);
+
+/* ldapu_msgfree(res); */
+
+ if (!*user) {
+ return LDAPU_ERR_OUT_OF_MEMORY;
+ }
+
+ *res_out = res;
+ return LDAPU_SUCCESS;
+}
+
+
+NSAPI_PUBLIC int ldapu_certinfo_modify (const char *issuerName,
+ const char *issuerDN,
+ const LDAPUPropValList_t *propval)
+{
+ LDAPUCertMapInfo_t *certinfo = 0;
+ int rv;
+
+ /* Make sure issuerName & issuerDN are both NULL or are both non-NULL */
+ if (!issuerName || !*issuerName) {
+ /* issuerDN must be NULL */
+ if (issuerDN) return LDAPU_ERR_WRONG_ARGS;
+ }
+ else if (!issuerDN || !*issuerDN) {
+ /* error - issuerName must be NULL but it is not */
+ return LDAPU_ERR_WRONG_ARGS;
+ }
+
+ if (!issuerDN) {
+ /* Modify the default certinfo */
+ certinfo = default_certmap_info;
+ }
+ else {
+ rv = ldapu_issuer_certinfo(issuerDN, (void **)&certinfo);
+
+ if (rv != LDAPU_SUCCESS) {
+ /* allocate new certinfo & add to the list */
+ certinfo = (LDAPUCertMapInfo_t *)malloc(sizeof(LDAPUCertMapInfo_t));
+ if (!certinfo) return LDAPU_ERR_OUT_OF_MEMORY;
+ memset((void *)certinfo, 0, sizeof(LDAPUCertMapInfo_t));
+
+ certinfo->issuerName = strdup(issuerName);
+ certinfo->issuerDN = strdup(issuerDN);
+
+ if (!certinfo->issuerName || !certinfo->issuerDN)
+ return LDAPU_ERR_OUT_OF_MEMORY;
+ }
+ }
+
+ /* Now modify the certinfo */
+ /* Free the old propval list and add new propval */
+ ldapu_propval_list_free(certinfo->propval);
+
+ if (propval) {
+ rv = ldapu_list_copy (propval, &certinfo->propval, ldapu_propval_copy);
+ if (rv != LDAPU_SUCCESS) return rv;
+ }
+
+ /* process_certinfo processes the info and adds to the certmap_listinfo */
+ process_certinfo(certinfo);
+
+ return LDAPU_SUCCESS;
+}
+
+/* ldapu_propval_same - returns LDAPU_SUCCESS or LDAPU_FAILED */
+static void * ldapu_propval_same (void *info, void *find_arg)
+{
+ /* check if info has find_arg as the issuerDN */
+ const char *issuerDN = (const char *)find_arg;
+ const LDAPUCertMapInfo_t *certinfo = (const LDAPUCertMapInfo_t *) info;
+
+ if (!ldapu_strcasecmp(certinfo->issuerDN, issuerDN))
+ return (void *)LDAPU_SUCCESS;
+ else
+ return (void *)LDAPU_FAILED;
+}
+
+NSAPI_PUBLIC int ldapu_certinfo_delete (const char *issuerDN)
+{
+ int rv;
+ LDAPUListNode_t *node;
+
+ if (!issuerDN || !*issuerDN)
+ return LDAPU_ERR_WRONG_ARGS;
+
+ rv = ldapu_list_find_node (certmap_listinfo, &node, ldapu_propval_same,
+ (void *)issuerDN);
+
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ rv = ldapu_list_remove_node (certmap_listinfo, node);
+
+ return rv;
+}
+
+NSAPI_PUBLIC int ldapu_certinfo_save (const char *fname,
+ const char *old_fname,
+ const char *tmp_fname)
+{
+ /* Copy the header from the old_fname into a temporary file
+ * Save the default_certmap_info and certmap_listinfo into the temporary
+ * file. Rename the temporary file to the new file.
+ */
+ FILE *ofp;
+ FILE *tfp;
+ char buf[BIG_LINE];
+ char *ptr;
+ int eof;
+ int rv;
+ LDAPUPrintInfo_t pinfo;
+
+#ifdef XP_WIN32
+ if ((ofp = fopen(old_fname, "rt")) == NULL)
+#else
+ if ((ofp = fopen(old_fname, "r")) == NULL)
+#endif
+ {
+ return LDAPU_ERR_CANNOT_OPEN_FILE;
+ }
+
+ if ((tfp = fopen(tmp_fname, "w")) == NULL)
+ {
+ return LDAPU_ERR_CANNOT_OPEN_FILE;
+ }
+
+ eof = 0;
+ while(!eof) {
+ if (!fgets(buf, BIG_LINE, ofp)) break;
+
+ ptr = buf;
+
+ /* skip leading whitespace */
+ while(*ptr && isspace(*ptr)) ++ptr;
+
+ if (*ptr && *ptr != '#') {
+ /* It's not a comment, we are done */
+ break;
+ }
+
+ fprintf(tfp, "%s", buf);
+ }
+
+ fclose(ofp);
+
+ /* Output the default_certmap_info */
+ pinfo.fp = tfp;
+ pinfo.arg = default_certmap_info->issuerName;
+
+ rv = (int)ldapu_certinfo_print (default_certmap_info, &pinfo);
+
+ if (rv != LDAPU_SUCCESS) {
+ fclose(tfp);
+ return rv;
+ }
+
+ if (certmap_listinfo) {
+ rv = ldapu_list_print (certmap_listinfo, ldapu_certinfo_print,
+ &pinfo);
+
+ if (rv != LDAPU_SUCCESS) {
+ fclose(tfp);
+ return rv;
+ }
+ }
+
+ fclose(tfp);
+
+ /* replace old file with the tmp file */
+#ifdef _WIN32
+ if ( !MoveFileEx(tmp_fname, fname, MOVEFILE_REPLACE_EXISTING ))
+#else
+ if ( rename( tmp_fname, fname) != 0 )
+#endif
+ {
+ return LDAPU_ERR_RENAME_FILE_FAILED;
+ }
+
+ return LDAPU_SUCCESS;
+}
+
+static void * ldapu_propval_free (void *propval_in, void *arg)
+{
+ LDAPUPropVal_t *propval = (LDAPUPropVal_t *)propval_in;
+
+ if (propval->prop) free(propval->prop);
+ if (propval->val) free(propval->val);
+ memset((void *)propval, 0, sizeof(LDAPUPropVal_t));
+ free(propval);
+ return 0;
+}
+
+void ldapu_certinfo_free (void *info_in)
+{
+ LDAPUCertMapInfo_t *certmap_info = (LDAPUCertMapInfo_t *)info_in;
+
+ if (certmap_info->issuerName) free(certmap_info->issuerName);
+ if (certmap_info->issuerDN) free(certmap_info->issuerDN);
+ if (certmap_info->propval)
+ ldapu_list_free(certmap_info->propval, ldapu_propval_free);
+ if (certmap_info->searchAttr) free(certmap_info->searchAttr);
+ memset((void *)certmap_info, 0, sizeof(LDAPUCertMapInfo_t));
+ free(certmap_info);
+}
+
+static void * ldapu_certinfo_free_helper (void *info, void *arg)
+{
+ ldapu_certinfo_free(info);
+ return (void *)LDAPU_SUCCESS;
+}
+
+void ldapu_certmap_listinfo_free (void *certmap_listinfo)
+{
+ LDAPUCertMapListInfo_t *list = (LDAPUCertMapListInfo_t *)certmap_listinfo;
+ ldapu_list_free(list, ldapu_certinfo_free_helper);
+}
+
+void ldapu_propval_list_free (void *propval_list)
+{
+ LDAPUPropValList_t *list = (LDAPUPropValList_t *)propval_list;
+ ldapu_list_free(list, ldapu_propval_free);
+}
+
+int ldapu_certmap_init (const char *config_file,
+ const char *dllname,
+ LDAPUCertMapListInfo_t **certmap_list,
+ LDAPUCertMapInfo_t **certmap_default)
+{
+ int rv;
+ certmap_listinfo = (LDAPUCertMapListInfo_t *)malloc(sizeof(LDAPUCertMapListInfo_t));
+
+ *certmap_list = 0;
+ *certmap_default = 0;
+ sprintf(this_dllname, "%s", dllname);
+
+ if (!certmap_listinfo) return LDAPU_ERR_OUT_OF_MEMORY;
+
+ memset((void *)certmap_listinfo, 0, sizeof(LDAPUCertMapListInfo_t));
+
+ rv = certmap_read_certconfig_file(config_file);
+
+ if (rv == LDAPU_SUCCESS) {
+ *certmap_list = certmap_listinfo;
+ *certmap_default = default_certmap_info;
+ }
+
+ return rv;
+}
+
+NSAPI_PUBLIC int ldaputil_exit ()
+{
+ if (default_certmap_info) {
+ ldapu_certinfo_free(default_certmap_info);
+ default_certmap_info = 0;
+ }
+
+ if (certmap_listinfo) {
+ ldapu_certmap_listinfo_free(certmap_listinfo);
+ certmap_listinfo = 0;
+ }
+
+ return LDAPU_SUCCESS;
+}
+
+
+NSAPI_PUBLIC void ldapu_free (void *ptr)
+{
+ if (ptr) free(ptr);
+}
+
+NSAPI_PUBLIC void ldapu_free_old (char *ptr)
+{
+ free((void *)ptr);
+}
+
+NSAPI_PUBLIC void *ldapu_malloc (int size)
+{
+ return malloc(size);
+}
+
+NSAPI_PUBLIC char *ldapu_strdup (const char *ptr)
+{
+ return strdup(ptr);
+}
+
+NSAPI_PUBLIC void *ldapu_realloc (void *ptr, int size)
+{
+ return realloc(ptr, size);
+}
+
+#define DNSEPARATOR(c) (c == ',' || c == ';')
+#define SEPARATOR(c) (c == ',' || c == ';' || c == '+')
+#define SPACE(c) (c == ' ' || c == '\n')
+#define NEEDSESCAPE(c) (c == '\\' || c == '"')
+#define B4TYPE 0
+#define INTYPE 1
+#define B4EQUAL 2
+#define B4VALUE 3
+#define INVALUE 4
+#define INQUOTEDVALUE 5
+#define B4SEPARATOR 6
+
+static char *
+ldapu_dn_normalize( char *dn )
+{
+ char *d, *s;
+ int state, gotesc;
+
+ gotesc = 0;
+ state = B4TYPE;
+ for ( d = s = dn; *s; s++ ) {
+ switch ( state ) {
+ case B4TYPE:
+ if ( ! SPACE( *s ) ) {
+ state = INTYPE;
+ *d++ = *s;
+ }
+ break;
+ case INTYPE:
+ if ( *s == '=' ) {
+ state = B4VALUE;
+ *d++ = *s;
+ } else if ( SPACE( *s ) ) {
+ state = B4EQUAL;
+ } else {
+ *d++ = *s;
+ }
+ break;
+ case B4EQUAL:
+ if ( *s == '=' ) {
+ state = B4VALUE;
+ *d++ = *s;
+ } else if ( ! SPACE( *s ) ) {
+ /* not a valid dn - but what can we do here? */
+ *d++ = *s;
+ }
+ break;
+ case B4VALUE:
+ if ( *s == '"' ) {
+ state = INQUOTEDVALUE;
+ *d++ = *s;
+ } else if ( ! SPACE( *s ) ) {
+ state = INVALUE;
+ *d++ = *s;
+ }
+ break;
+ case INVALUE:
+ if ( !gotesc && SEPARATOR( *s ) ) {
+ while ( SPACE( *(d - 1) ) )
+ d--;
+ state = B4TYPE;
+ if ( *s == '+' ) {
+ *d++ = *s;
+ } else {
+ *d++ = ',';
+ }
+ } else if ( gotesc && !NEEDSESCAPE( *s ) &&
+ !SEPARATOR( *s ) ) {
+ *--d = *s;
+ d++;
+ } else {
+ *d++ = *s;
+ }
+ break;
+ case INQUOTEDVALUE:
+ if ( !gotesc && *s == '"' ) {
+ state = B4SEPARATOR;
+ *d++ = *s;
+ } else if ( gotesc && !NEEDSESCAPE( *s ) ) {
+ *--d = *s;
+ d++;
+ } else {
+ *d++ = *s;
+ }
+ break;
+ case B4SEPARATOR:
+ if ( SEPARATOR( *s ) ) {
+ state = B4TYPE;
+ if ( *s == '+' ) {
+ *d++ = *s;
+ } else {
+ *d++ = ',';
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ if ( *s == '\\' ) {
+ gotesc = 1;
+ } else {
+ gotesc = 0;
+ }
+ }
+ *d = '\0';
+
+ /* Trim trailing spaces */
+ d--;
+ while ( d >= dn && *d == ' ' ) {
+ *d-- = '\0';
+ }
+
+ return( dn );
+}