+/*
+ * Check if a subnet id is valid for comparison
+ * with an address id ( address length mask )
+ * and compare them
+ * Return value
+ * = 0 for match
+ * = 1 for mismatch
+ */
+
+int
+ipsecdoi_subnetisaddr_v4( subnet, address )
+ const vchar_t *subnet;
+ const vchar_t *address;
+{
+ struct in_addr *mask;
+
+ if (address->l != sizeof(struct in_addr))
+ return 1;
+
+ if (subnet->l != (sizeof(struct in_addr)*2))
+ return 1;
+
+ mask = (struct in_addr*)(subnet->v + sizeof(struct in_addr));
+
+ if (mask->s_addr!=0xffffffff)
+ return 1;
+
+ return memcmp(subnet->v,address->v,address->l);
+}
+
+#ifdef INET6
+
+int
+ipsecdoi_subnetisaddr_v6( subnet, address )
+ const vchar_t *subnet;
+ const vchar_t *address;
+{
+ struct in6_addr *mask;
+ int i;
+
+ if (address->l != sizeof(struct in6_addr))
+ return 1;
+
+ if (subnet->l != (sizeof(struct in6_addr)*2))
+ return 1;
+
+ mask = (struct in6_addr*)(subnet->v + sizeof(struct in6_addr));
+
+ for (i=0; i<16; i++)
+ if(mask->s6_addr[i]!=0xff)
+ return 1;
+
+ return memcmp(subnet->v,address->v,address->l);
+}
+
+#endif
+
+/*
+ * Check and Compare two IDs
+ * - specify 0 for exact if wildcards are allowed
+ * Return value
+ * = 0 for match
+ * = 1 for misatch
+ * = -1 for integrity error
+ */
+
+int
+ipsecdoi_chkcmpids( idt, ids, exact )
+ const vchar_t *idt; /* id cmp target */
+ const vchar_t *ids; /* id cmp source */
+ int exact;
+{
+ struct ipsecdoi_id_b *id_bt;
+ struct ipsecdoi_id_b *id_bs;
+ vchar_t ident_t;
+ vchar_t ident_s;
+ int result;
+
+ /* handle wildcard IDs */
+
+ if (idt == NULL || ids == NULL)
+ {
+ if( !exact )
+ {
+ plog(LLV_DEBUG, LOCATION, NULL,
+ "check and compare ids : values matched (ANONYMOUS)\n" );
+ return 0;
+ }
+ else
+ {
+ plog(LLV_DEBUG, LOCATION, NULL,
+ "check and compare ids : value mismatch (ANONYMOUS)\n" );
+ return -1;
+ }
+ }
+
+ /* make sure the ids are of the same type */
+
+ id_bt = (struct ipsecdoi_id_b *) idt->v;
+ id_bs = (struct ipsecdoi_id_b *) ids->v;
+
+ ident_t.v = idt->v + sizeof(*id_bt);
+ ident_t.l = idt->l - sizeof(*id_bt);
+ ident_s.v = ids->v + sizeof(*id_bs);
+ ident_s.l = ids->l - sizeof(*id_bs);
+
+ if (id_bs->type != id_bt->type)
+ {
+ /*
+ * special exception for comparing
+ * address to subnet id types when
+ * the netmask is address length
+ */
+
+ if ((id_bs->type == IPSECDOI_ID_IPV4_ADDR)&&
+ (id_bt->type == IPSECDOI_ID_IPV4_ADDR_SUBNET)) {
+ result = ipsecdoi_subnetisaddr_v4(&ident_t,&ident_s);
+ goto cmpid_result;
+ }
+
+ if ((id_bs->type == IPSECDOI_ID_IPV4_ADDR_SUBNET)&&
+ (id_bt->type == IPSECDOI_ID_IPV4_ADDR)) {
+ result = ipsecdoi_subnetisaddr_v4(&ident_s,&ident_t);
+ goto cmpid_result;
+ }
+
+#ifdef INET6
+ if ((id_bs->type == IPSECDOI_ID_IPV6_ADDR)&&
+ (id_bt->type == IPSECDOI_ID_IPV6_ADDR_SUBNET)) {
+ result = ipsecdoi_subnetisaddr_v6(&ident_t,&ident_s);
+ goto cmpid_result;
+ }
+
+ if ((id_bs->type == IPSECDOI_ID_IPV6_ADDR_SUBNET)&&
+ (id_bt->type == IPSECDOI_ID_IPV6_ADDR)) {
+ result = ipsecdoi_subnetisaddr_v6(&ident_s,&ident_t);
+ goto cmpid_result;
+ }
+#endif
+ plog(LLV_DEBUG, LOCATION, NULL,
+ "check and compare ids : id type mismatch %s != %s\n",
+ s_ipsecdoi_ident(id_bs->type),
+ s_ipsecdoi_ident(id_bt->type));
+
+ return 1;
+ }
+
+ if(id_bs->proto_id != id_bt->proto_id){
+ plog(LLV_DEBUG, LOCATION, NULL,
+ "check and compare ids : proto_id mismatch %d != %d\n",
+ id_bs->proto_id, id_bt->proto_id);
+
+ return 1;
+ }
+
+ /* compare the ID data. */
+
+ switch (id_bt->type) {
+ case IPSECDOI_ID_DER_ASN1_DN:
+ case IPSECDOI_ID_DER_ASN1_GN:
+ /* compare asn1 ids */
+ result = eay_cmp_asn1dn(&ident_t, &ident_s);
+ goto cmpid_result;
+
+ case IPSECDOI_ID_IPV4_ADDR:
+ /* validate lengths */
+ if ((ident_t.l != sizeof(struct in_addr))||
+ (ident_s.l != sizeof(struct in_addr)))
+ goto cmpid_invalid;
+ break;
+
+ case IPSECDOI_ID_IPV4_ADDR_SUBNET:
+ case IPSECDOI_ID_IPV4_ADDR_RANGE:
+ /* validate lengths */
+ if ((ident_t.l != (sizeof(struct in_addr)*2))||
+ (ident_s.l != (sizeof(struct in_addr)*2)))
+ goto cmpid_invalid;
+ break;
+
+#ifdef INET6
+ case IPSECDOI_ID_IPV6_ADDR:
+ /* validate lengths */
+ if ((ident_t.l != sizeof(struct in6_addr))||
+ (ident_s.l != sizeof(struct in6_addr)))
+ goto cmpid_invalid;
+ break;
+
+ case IPSECDOI_ID_IPV6_ADDR_SUBNET:
+ case IPSECDOI_ID_IPV6_ADDR_RANGE:
+ /* validate lengths */
+ if ((ident_t.l != (sizeof(struct in6_addr)*2))||
+ (ident_s.l != (sizeof(struct in6_addr)*2)))
+ goto cmpid_invalid;
+ break;
+#endif
+ case IPSECDOI_ID_FQDN:
+ case IPSECDOI_ID_USER_FQDN:
+ case IPSECDOI_ID_KEY_ID:
+ break;
+
+ default:
+ plog(LLV_ERROR, LOCATION, NULL,
+ "Unhandled id type %i specified for comparison\n",
+ id_bt->type);
+ return -1;
+ }
+
+ /* validate matching data and length */
+ if (ident_t.l == ident_s.l)
+ result = memcmp(ident_t.v,ident_s.v,ident_t.l);
+ else
+ result = 1;
+
+cmpid_result:
+
+ /* debug level output */
+ if(loglevel >= LLV_DEBUG) {
+ char *idstrt = ipsecdoi_id2str(idt);
+ char *idstrs = ipsecdoi_id2str(ids);
+
+ if (!result)
+ plog(LLV_DEBUG, LOCATION, NULL,
+ "check and compare ids : values matched (%s)\n",
+ s_ipsecdoi_ident(id_bs->type) );
+ else
+ plog(LLV_DEBUG, LOCATION, NULL,
+ "check and compare ids : value mismatch (%s)\n",
+ s_ipsecdoi_ident(id_bs->type));
+
+ plog(LLV_DEBUG, LOCATION, NULL, "cmpid target: \'%s\'\n", idstrt );
+ plog(LLV_DEBUG, LOCATION, NULL, "cmpid source: \'%s\'\n", idstrs );
+
+ racoon_free(idstrs);
+ racoon_free(idstrt);
+ }
+
+ /* return result */
+ if( !result )
+ return 0;
+ else
+ return 1;
+
+cmpid_invalid:
+
+ /* id integrity error */
+ plog(LLV_DEBUG, LOCATION, NULL, "check and compare ids : %s integrity error\n",
+ s_ipsecdoi_ident(id_bs->type));
+ plog(LLV_DEBUG, LOCATION, NULL, "cmpid target: length = \'%zu\'\n", ident_t.l );
+ plog(LLV_DEBUG, LOCATION, NULL, "cmpid source: length = \'%zu\'\n", ident_s.l );
+
+ return -1;
+}
+