X-Git-Url: https://git.saurik.com/apple/ipsec.git/blobdiff_plain/52b7d2ce06d68d0a9160d16f6e7c08c21c149d0d..d1e348cfd503b08e7d34b7683d23aae209af0a71:/ipsec-tools/racoon/ipsec_doi.c?ds=sidebyside diff --git a/ipsec-tools/racoon/ipsec_doi.c b/ipsec-tools/racoon/ipsec_doi.c index 1854964..713ec4c 100644 --- a/ipsec-tools/racoon/ipsec_doi.c +++ b/ipsec-tools/racoon/ipsec_doi.c @@ -274,10 +274,12 @@ found: plog(LLV_WARNING, LOCATION, NULL, "invalid DH parameter found, use default.\n"); oakley_dhgrp_free(sa->dhgrp); + sa->dhgrp=NULL; } if (oakley_setdhgroup(sa->dh_group, &sa->dhgrp) == -1) { sa->dhgrp = NULL; + racoon_free(sa); return NULL; } @@ -285,7 +287,7 @@ saok: #ifdef HAVE_GSSAPI if (sa->gssid != NULL) plog(LLV_DEBUG, LOCATION, NULL, "gss id in new sa '%.*s'\n", - sa->gssid->l, sa->gssid->v); + (int)sa->gssid->l, sa->gssid->v); if (iph1-> side == INITIATOR) { if (iph1->rmconf->proposal->gssid != NULL) iph1->gi_i = vdup(iph1->rmconf->proposal->gssid); @@ -303,13 +305,17 @@ saok: } if (iph1->gi_i != NULL) plog(LLV_DEBUG, LOCATION, NULL, "GIi is %.*s\n", - iph1->gi_i->l, iph1->gi_i->v); + (int)iph1->gi_i->l, iph1->gi_i->v); if (iph1->gi_r != NULL) plog(LLV_DEBUG, LOCATION, NULL, "GIr is %.*s\n", - iph1->gi_r->l, iph1->gi_r->v); + (int)iph1->gi_r->l, iph1->gi_r->v); #else iph1->approval = sa; #endif + if(iph1->approval) { + plog(LLV_DEBUG, LOCATION, NULL, "agreed on %s auth.\n", + s_oakley_attr_method(iph1->approval->authmethod)); + } newsa = get_sabyproppair(p, iph1); if (newsa == NULL) { @@ -336,6 +342,7 @@ get_ph1approvalx(p, proposal, sap, check_level) struct isakmp_pl_t *trns = p->trns; struct isakmpsa sa, *s, *tsap; int authmethod; + int tsap_authmethod; plog(LLV_DEBUG, LOCATION, NULL, "prop#=%d, prot-id=%s, spi-size=%d, #trns=%d\n", @@ -355,8 +362,10 @@ get_ph1approvalx(p, proposal, sap, check_level) for (s = proposal; s != NULL; s = s->next) { #ifdef ENABLE_HYBRID authmethod = switch_authmethod(s->authmethod); + tsap_authmethod = switch_authmethod(tsap->authmethod); #else authmethod = s->authmethod; + tsap_authmethod = tsap->authmethod; #endif plog(LLV_DEBUG, LOCATION, NULL, "Compared: DB:Peer\n"); plog(LLV_DEBUG, LOCATION, NULL, "(lifetime = %ld:%ld)\n", @@ -377,7 +386,7 @@ get_ph1approvalx(p, proposal, sap, check_level) tsap->hashtype)); plog(LLV_DEBUG, LOCATION, NULL, "authmethod = %s:%s\n", s_oakley_attr_v(OAKLEY_ATTR_AUTH_METHOD, - authmethod), + s->authmethod), s_oakley_attr_v(OAKLEY_ATTR_AUTH_METHOD, tsap->authmethod)); plog(LLV_DEBUG, LOCATION, NULL, "dh_group = %s:%s\n", @@ -394,7 +403,7 @@ get_ph1approvalx(p, proposal, sap, check_level) * is bigger than mine, it might be accepted. */ if(tsap->enctype == s->enctype && - tsap->authmethod == authmethod && + (tsap->authmethod == authmethod || tsap_authmethod == authmethod) && tsap->hashtype == s->hashtype && tsap->dh_group == s->dh_group && tsap->encklen == s->encklen) { @@ -435,8 +444,10 @@ get_ph1approvalx(p, proposal, sap, check_level) } found: - if (tsap->dhgrp != NULL) + if (tsap->dhgrp != NULL){ oakley_dhgrp_free(tsap->dhgrp); + tsap->dhgrp = NULL; + } if ((s = dupisakmpsa(s)) != NULL) { switch(check_level) { @@ -460,8 +471,11 @@ found: default: break; } + // hack to get around cisco rekeys + if (tsap->authmethod != authmethod && tsap_authmethod == authmethod) { + s->authmethod = tsap->authmethod; + } } - return s; } @@ -531,8 +545,10 @@ print_ph1mismatched(p, proposal) } } - if (sa.dhgrp != NULL) + if (sa.dhgrp != NULL){ oakley_dhgrp_free(sa.dhgrp); + sa.dhgrp=NULL; + } } /* @@ -740,7 +756,8 @@ t2isakmpsa(trns, sa) #ifdef HAVE_GSSAPI case OAKLEY_ATTR_GSS_ID: { - iconv_t cd; + int error = -1; + iconv_t cd = (iconv_t) -1; size_t srcleft, dstleft, rv; __iconv_const char *src; char *dst; @@ -753,12 +770,19 @@ t2isakmpsa(trns, sa) * compatible with this behavior. */ if (lcconf->gss_id_enc == LC_GSSENC_LATIN1) { - sa->gssid = vmalloc(len); + if ((sa->gssid = vmalloc(len)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate memory\n"); + goto out; + } memcpy(sa->gssid->v, d + 1, len); plog(LLV_DEBUG, LOCATION, NULL, - "received old-style gss id '%.*s' (len %d)\n", - sa->gssid->l, sa->gssid->v, sa->gssid->l); - break; + "received old-style gss " + "id '%.*s' (len %zu)\n", + (int)sa->gssid->l, sa->gssid->v, + sa->gssid->l); + error = 0; + goto out; } /* @@ -775,10 +799,14 @@ t2isakmpsa(trns, sa) "unable to initialize utf-16le -> latin1 " "conversion descriptor: %s\n", strerror(errno)); - break; + goto out; } - sa->gssid = vmalloc(len / 2); + if ((sa->gssid = vmalloc(len / 2)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate memory\n"); + goto out; + } src = (__iconv_const char *)(d + 1); srcleft = len; @@ -800,19 +828,25 @@ t2isakmpsa(trns, sa) "be represented in latin1\n", rv, rv == 1 ? "" : "s"); } - (void) iconv_close(cd); - vfree(sa->gssid); - sa->gssid = NULL; - break; + goto out; } - (void) iconv_close(cd); /* XXX dstleft should always be 0; assert it? */ sa->gssid->l = (len / 2) - dstleft; plog(LLV_DEBUG, LOCATION, NULL, - "received gss id '%.*s' (len %d)\n", - sa->gssid->l, sa->gssid->v, sa->gssid->l); + "received gss id '%.*s' (len %zu)\n", + (int)sa->gssid->l, sa->gssid->v, sa->gssid->l); + + error = 0; +out: + if (cd != (iconv_t)-1) + (void)iconv_close(cd); + + if ((error != 0) && (sa->gssid != NULL)) { + vfree(sa->gssid); + sa->gssid = NULL; + } break; } #endif /* HAVE_GSSAPI */ @@ -1164,7 +1198,8 @@ found: { struct saproto *sp; - struct prop_pair *p, *n, *x; + struct prop_pair *p, *x; + struct prop_pair *n = NULL; ret = NULL; @@ -1189,7 +1224,7 @@ found: goto err; /* XXX */ n = racoon_calloc(1, sizeof(struct prop_pair)); - if (!n) { + if (n == NULL) { plog(LLV_ERROR, LOCATION, NULL, "failed to get buffer.\n"); goto err; @@ -1261,7 +1296,7 @@ get_proppair(sa, mode) vchar_t *sa; int mode; { - struct prop_pair **pair; + struct prop_pair **pair = NULL; int num_p = 0; /* number of proposal for use */ int tlen; caddr_t bp; @@ -1275,22 +1310,22 @@ get_proppair(sa, mode) if (sa->l < sizeof(*sab)) { plog(LLV_ERROR, LOCATION, NULL, "Invalid SA length = %zu.\n", sa->l); - return NULL; + goto bad; } /* check DOI */ if (check_doi(ntohl(sab->doi)) < 0) - return NULL; + goto bad; /* check SITUATION */ if (check_situation(ntohl(sab->sit)) < 0) - return NULL; + goto bad; pair = racoon_calloc(1, MAXPROPPAIRLEN * sizeof(*pair)); if (pair == NULL) { plog(LLV_ERROR, LOCATION, NULL, "failed to get buffer.\n"); - return NULL; + goto bad; } memset(pair, 0, sizeof(pair)); @@ -1305,7 +1340,7 @@ get_proppair(sa, mode) pbuf = isakmp_parsewoh(ISAKMP_NPTYPE_P, (struct isakmp_gen *)bp, tlen); if (pbuf == NULL) - return NULL; + goto bad; for (pa = (struct isakmp_parse_t *)pbuf->v; pa->type != ISAKMP_NPTYPE_NONE; @@ -1315,7 +1350,7 @@ get_proppair(sa, mode) plog(LLV_ERROR, LOCATION, NULL, "Invalid payload type=%u\n", pa->type); vfree(pbuf); - return NULL; + goto bad; } prop = (struct isakmp_pl_p *)pa->ptr; @@ -1328,7 +1363,7 @@ get_proppair(sa, mode) plog(LLV_ERROR, LOCATION, NULL, "invalid proposal with length %d\n", proplen); vfree(pbuf); - return NULL; + goto bad; } /* check Protocol ID */ @@ -1348,7 +1383,7 @@ get_proppair(sa, mode) /* get transform */ if (get_transform(prop, pair, &num_p) < 0) { vfree(pbuf); - return NULL; + goto bad; } } vfree(pbuf); @@ -1410,10 +1445,14 @@ get_proppair(sa, mode) if (num_p <= 0) { plog(LLV_ERROR, LOCATION, NULL, "no Proposal found.\n"); - return NULL; + goto bad; } return pair; +bad: + if (pair != NULL) + racoon_free(pair); + return NULL; } /* @@ -1658,8 +1697,8 @@ get_sabysaprop(pp0, sa0) struct saprop *pp0; vchar_t *sa0; { - struct prop_pair **pair; - vchar_t *newsa; + struct prop_pair **pair = NULL; + vchar_t *newsa = NULL; int newtlen; u_int8_t *np_p = NULL; struct prop_pair *p = NULL; @@ -1668,17 +1707,18 @@ get_sabysaprop(pp0, sa0) struct satrns *tr; int prophlen, trnslen; caddr_t bp; + int error = -1; /* get proposal pair */ pair = get_proppair(sa0, IPSECDOI_TYPE_PH2); if (pair == NULL) - return NULL; + goto out; newtlen = sizeof(struct ipsecdoi_sa_b); for (pp = pp0; pp; pp = pp->next) { if (pair[pp->prop_no] == NULL) - return NULL; + goto out; for (pr = pp->head; pr; pr = pr->next) { newtlen += (sizeof(struct isakmp_pl_p) @@ -1690,7 +1730,7 @@ get_sabysaprop(pp0, sa0) break; } if (p == NULL) - return NULL; + goto out; newtlen += ntohs(p->trns->h.len); } @@ -1700,7 +1740,7 @@ get_sabysaprop(pp0, sa0) newsa = vmalloc(newtlen); if (newsa == NULL) { plog(LLV_ERROR, LOCATION, NULL, "failed to get newsa.\n"); - return NULL; + goto out; } bp = newsa->v; @@ -1721,7 +1761,7 @@ get_sabysaprop(pp0, sa0) break; } if (p == NULL) - return NULL; + goto out; trnslen = ntohs(p->trns->h.len); @@ -1746,6 +1786,18 @@ get_sabysaprop(pp0, sa0) } } + error = 0; +out: + if (pair != NULL) + racoon_free(pair); + + if (error != 0) { + if (newsa != NULL) { + vfree(newsa); + newsa = NULL; + } + } + return newsa; } @@ -2085,20 +2137,32 @@ check_attr_isakmp(trns) case OAKLEY_ATTR_AUTH_METHOD_RSASIG: #ifdef ENABLE_HYBRID case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: -#endif + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I: +#if 0 /* Clashes with OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB */ + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I: +#endif + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: +#endif case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: break; case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: #ifdef ENABLE_HYBRID - case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I: case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R: + case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I: case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_R: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_R: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_I: + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_R: #endif case OAKLEY_ATTR_AUTH_METHOD_RSAENC: case OAKLEY_ATTR_AUTH_METHOD_RSAREV: plog(LLV_ERROR, LOCATION, NULL, - "auth method %d isn't supported.\n", - lorv); + "auth method %s isn't supported.\n", + s_oakley_attr_method(lorv)); return -1; default: plog(LLV_ERROR, LOCATION, NULL, @@ -2804,8 +2868,8 @@ setph1attr(sa, buf) else attrlen += sa->gssid->l * 2; if (buf) { - plog(LLV_DEBUG, LOCATION, NULL, "gss id attr: len %d, " - "val '%.*s'\n", sa->gssid->l, sa->gssid->l, + plog(LLV_DEBUG, LOCATION, NULL, "gss id attr: len %zu, " + "val '%.*s'\n", sa->gssid->l, (int)sa->gssid->l, sa->gssid->v); if (lcconf->gss_id_enc == LC_GSSENC_LATIN1) { p = isakmp_set_attr_v(p, OAKLEY_ATTR_GSS_ID, @@ -3139,7 +3203,7 @@ ipsecdoi_setph2proposal(iph2) #ifdef __APPLE__ /* - * return 1 if all of the given protocols are transport mode. + * return 1 if all of the given protocols are tunnel mode. */ int ipsecdoi_tunnelmode(iph2) @@ -3159,6 +3223,27 @@ ipsecdoi_tunnelmode(iph2) return 1; } + +/* + * return 1 if any of the given protocols are transport mode. + */ +int +ipsecdoi_any_transportmode(pp) +struct saprop *pp; +{ + struct saproto *pr = NULL; + + for (; pp; pp = pp->next) { + for (pr = pp->head; pr; pr = pr->next) { + if (pr->encmode == IPSECDOI_ATTR_ENC_MODE_TRNS || + pr->encmode == IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC || + pr->encmode == IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT) + return 1; + } + } + + return 0; +} #endif /* @@ -3264,6 +3349,259 @@ doi2ipproto(proto) return -1; /* XXX */ } +/* + * 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; +} + /* * check the following: * - In main mode with pre-shared key, only address type can be used. @@ -3328,7 +3666,7 @@ ipsecdoi_checkid1(iph1) } /* if phase 1 ID payload conformed RFC2407 4.6.2. */ - if (id_b->type == IPSECDOI_ID_IPV4_ADDR || // %%%% BUG_FIX - should be || not && + if (id_b->type == IPSECDOI_ID_IPV4_ADDR || id_b->type == IPSECDOI_ID_IPV6_ADDR) { if (id_b->proto_id == 0 && ntohs(id_b->port) != 0) { @@ -3393,9 +3731,8 @@ ipsecdoi_checkid1(iph1) switch (id->idtype) { case IDTYPE_ASN1DN: - ident.v = (caddr_t)(id_b + 1); - ident.l = iph1->id_p->l - 1; /* had ident.l = ident0->l; but why?? */ - /* is the actual packet contents length sometimes wrong? */ + ident.v = iph1->id_p->v + sizeof(*id_b); + ident.l = iph1->id_p->l - sizeof(*id_b); if (eay_cmp_asn1dn(ident0, &ident) == 0) goto matched; break; @@ -3591,6 +3928,15 @@ int set_identifier(vpp, type, value) vchar_t **vpp, *value; int type; +{ + return set_identifier_qual(vpp, type, value, IDQUAL_UNSPEC); +} + +int +set_identifier_qual(vpp, type, value, qual) + vchar_t **vpp, *value; + int type; + int qual; { vchar_t *new = NULL; @@ -3625,31 +3971,55 @@ set_identifier(vpp, type, value) memcpy(new->v, value->v, new->l); break; case IDTYPE_KEYID: - { - FILE *fp; - char b[512]; - int tlen, len; - - fp = fopen(value->v, "r"); - if (fp == NULL) { - plog(LLV_ERROR, LOCATION, NULL, - "can not open %s\n", value->v); - return -1; + /* + * If no qualifier is specified: IDQUAL_UNSPEC. It means + * to use a file for backward compatibility sake. + */ + switch(qual) { + case IDQUAL_FILE: + case IDQUAL_UNSPEC: { + FILE *fp; + char b[512]; + int tlen, len; + + fp = fopen(value->v, "r"); + if (fp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "can not open %s\n", value->v); + return -1; + } + tlen = 0; + while ((len = fread(b, 1, sizeof(b), fp)) != 0) { + new = vrealloc(new, tlen + len); + if (!new) { + fclose(fp); + return -1; + } + memcpy(new->v + tlen, b, len); + tlen += len; + } + fclose(fp); + break; } - tlen = 0; - while ((len = fread(b, 1, sizeof(b), fp)) != 0) { - new = vrealloc(new, tlen + len); - if (!new) { - fclose(fp); + + case IDQUAL_TAG: + new = vmalloc(value->l - 1); + if (new == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "can not allocate memory"); return -1; } - memcpy(new->v + tlen, b, len); - tlen += len; + memcpy(new->v, value->v, new->l); + break; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "unknown qualifier"); + return -1; } break; - } - case IDTYPE_ADDRESS: - { + + case IDTYPE_ADDRESS: { struct sockaddr *sa; /* length is adjusted since QUOTEDSTRING teminates NULL. */ @@ -3664,9 +4034,12 @@ set_identifier(vpp, type, value) } new = vmalloc(sysdep_sa_len(sa)); - if (new == NULL) + if (new == NULL) { + racoon_free(sa); return -1; + } memcpy(new->v, sa, new->l); + racoon_free(sa); break; } case IDTYPE_ASN1DN: @@ -3779,13 +4152,7 @@ ipsecdoi_sockaddr2id(saddr, prefixlen, ul_proto) switch (saddr->sa_family) { case AF_INET: len1 = sizeof(struct in_addr); - if ( -#if 0 - prefixlen == ~0 -#else - prefixlen == (sizeof(struct in_addr) << 3) -#endif - ) { + if (prefixlen == (sizeof(struct in_addr) << 3)) { type = IPSECDOI_ID_IPV4_ADDR; len2 = 0; } else { @@ -3798,13 +4165,7 @@ ipsecdoi_sockaddr2id(saddr, prefixlen, ul_proto) #ifdef INET6 case AF_INET6: len1 = sizeof(struct in6_addr); - if ( -#if 0 - prefixlen == ~0 -#else - prefixlen == (sizeof(struct in6_addr) << 3) -#endif - ) { + if (prefixlen == (sizeof(struct in6_addr) << 3)) { type = IPSECDOI_ID_IPV6_ADDR; len2 = 0; } else { @@ -3865,6 +4226,71 @@ ipsecdoi_sockaddr2id(saddr, prefixlen, ul_proto) return new; } +vchar_t * +ipsecdoi_sockrange2id(laddr, haddr, ul_proto) + struct sockaddr *laddr, *haddr; + u_int ul_proto; +{ + vchar_t *new; + int type, len1, len2; + u_short port; + + if (laddr->sa_family != haddr->sa_family) { + plog(LLV_ERROR, LOCATION, NULL, "Address family mismatch\n"); + return NULL; + } + + switch (laddr->sa_family) { + case AF_INET: + type = IPSECDOI_ID_IPV4_ADDR_RANGE; + len1 = sizeof(struct in_addr); + len2 = sizeof(struct in_addr); + break; +#ifdef INET6 + case AF_INET6: + type = IPSECDOI_ID_IPV6_ADDR_RANGE; + len1 = sizeof(struct in6_addr); + len2 = sizeof(struct in6_addr); + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d.\n", laddr->sa_family); + return NULL; + } + + /* get ID buffer */ + new = vmalloc(sizeof(struct ipsecdoi_id_b) + len1 + len2); + if (new == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get ID buffer.\n"); + return NULL; + } + + memset(new->v, 0, new->l); + /* set the part of header. */ + ((struct ipsecdoi_id_b *)new->v)->type = type; + + /* set ul_proto and port */ + /* + * NOTE: we use both IPSEC_ULPROTO_ANY and IPSEC_PORT_ANY as wild card + * because 0 means port number of 0. Instead of 0, we use IPSEC_*_ANY. + */ + ((struct ipsecdoi_id_b *)new->v)->proto_id = + ul_proto == IPSEC_ULPROTO_ANY ? 0 : ul_proto; + port = ((struct sockaddr_in *)(laddr))->sin_port; + ((struct ipsecdoi_id_b *)new->v)->port = + port == IPSEC_PORT_ANY ? 0 : port; + memcpy(new->v + sizeof(struct ipsecdoi_id_b), + (caddr_t)&((struct sockaddr_in *)(laddr))->sin_addr, + len1); + memcpy(new->v + sizeof(struct ipsecdoi_id_b) + len1, + (caddr_t)&((struct sockaddr_in *)haddr)->sin_addr, + len2); + return new; +} + + /* * create sockaddr structure from ID payload (buf). * buffers (saddr, prefixlen, ul_proto) must be allocated. @@ -3965,9 +4391,9 @@ ipsecdoi_id2sockaddr(buf, saddr, prefixlen, ul_proto) + alen; for (; *p == 0xff; p++) { + plen += 8; if (plen >= max) break; - plen += 8; } if (plen < max) { @@ -3997,16 +4423,210 @@ ipsecdoi_id2sockaddr(buf, saddr, prefixlen, ul_proto) /* * make printable string from ID payload except of general header. */ -const char * +char * ipsecdoi_id2str(id) const vchar_t *id; { - static char buf[256]; +#define BUFLEN 512 + char * ret = NULL; + int len = 0; + char *dat; + static char buf[BUFLEN]; + struct ipsecdoi_id_b *id_b = (struct ipsecdoi_id_b *)id->v; + struct sockaddr_storage saddr; + u_int plen = 0; + + bzero(&saddr, sizeof(saddr)); + + switch (id_b->type) { + case IPSECDOI_ID_IPV4_ADDR: + case IPSECDOI_ID_IPV4_ADDR_SUBNET: + case IPSECDOI_ID_IPV4_ADDR_RANGE: + +#ifndef __linux__ + ((struct sockaddr *)&saddr)->sa_len = sizeof(struct sockaddr_in); +#endif + ((struct sockaddr *)&saddr)->sa_family = AF_INET; + ((struct sockaddr_in *)&saddr)->sin_port = IPSEC_PORT_ANY; + memcpy(&((struct sockaddr_in *)&saddr)->sin_addr, + id->v + sizeof(*id_b), sizeof(struct in_addr)); + break; +#ifdef INET6 + case IPSECDOI_ID_IPV6_ADDR: + case IPSECDOI_ID_IPV6_ADDR_SUBNET: + case IPSECDOI_ID_IPV6_ADDR_RANGE: + +#ifndef __linux__ + ((struct sockaddr *)&saddr)->sa_len = sizeof(struct sockaddr_in6); +#endif + ((struct sockaddr *)&saddr)->sa_family = AF_INET6; + ((struct sockaddr_in6 *)&saddr)->sin6_port = IPSEC_PORT_ANY; + memcpy(&((struct sockaddr_in6 *)&saddr)->sin6_addr, + id->v + sizeof(*id_b), sizeof(struct in6_addr)); + break; +#endif + } + + switch (id_b->type) { + case IPSECDOI_ID_IPV4_ADDR: +#ifdef INET6 + case IPSECDOI_ID_IPV6_ADDR: +#endif + len = snprintf( buf, sizeof(buf), "%s", saddrwop2str((struct sockaddr *)&saddr)); + break; - /* XXX */ - buf[0] = '\0'; + case IPSECDOI_ID_IPV4_ADDR_SUBNET: +#ifdef INET6 + case IPSECDOI_ID_IPV6_ADDR_SUBNET: +#endif + { + u_char *p; + u_int max; + int alen = sizeof(struct in_addr); - return buf; + switch (id_b->type) { + case IPSECDOI_ID_IPV4_ADDR_SUBNET: + alen = sizeof(struct in_addr); + break; +#ifdef INET6 + case IPSECDOI_ID_IPV6_ADDR_SUBNET: + alen = sizeof(struct in6_addr); + break; +#endif + } + + /* sanity check */ + if (id->l < alen) { + len = 0; + break; + } + + /* get subnet mask length */ + plen = 0; + max = alen <<3; + + p = (unsigned char *) id->v + + sizeof(struct ipsecdoi_id_b) + + alen; + + for (; *p == 0xff; p++) { + plen += 8; + if (plen >= max) + break; + } + + if (plen < max) { + u_int l = 0; + u_char b = ~(*p); + + while (b) { + b >>= 1; + l++; + } + + l = 8 - l; + plen += l; + } + + len = snprintf( buf, sizeof(buf), "%s/%i", saddrwop2str((struct sockaddr *)&saddr), plen); + } + break; + + case IPSECDOI_ID_IPV4_ADDR_RANGE: + + len = snprintf( buf, sizeof(buf), "%s-", saddrwop2str((struct sockaddr *)&saddr)); + +#ifndef __linux__ + ((struct sockaddr *)&saddr)->sa_len = sizeof(struct sockaddr_in); +#endif + ((struct sockaddr *)&saddr)->sa_family = AF_INET; + ((struct sockaddr_in *)&saddr)->sin_port = IPSEC_PORT_ANY; + memcpy(&((struct sockaddr_in *)&saddr)->sin_addr, + id->v + sizeof(*id_b) + sizeof(struct in_addr), + sizeof(struct in_addr)); + + if (len >= 0) { + len += snprintf( buf + len, sizeof(buf) - len, "%s", saddrwop2str((struct sockaddr *)&saddr)); + } + + break; + +#ifdef INET6 + case IPSECDOI_ID_IPV6_ADDR_RANGE: + + len = snprintf( buf, sizeof(buf), "%s-", saddrwop2str((struct sockaddr *)&saddr)); + +#ifndef __linux__ + ((struct sockaddr *)&saddr)->sa_len = sizeof(struct sockaddr_in6); +#endif + ((struct sockaddr *)&saddr)->sa_family = AF_INET6; + ((struct sockaddr_in6 *)&saddr)->sin6_port = IPSEC_PORT_ANY; + memcpy(&((struct sockaddr_in6 *)&saddr)->sin6_addr, + id->v + sizeof(*id_b) + sizeof(struct in6_addr), + sizeof(struct in6_addr)); + + if (len >= 0) { + len += snprintf( buf + len, sizeof(buf) - len, "%s", saddrwop2str((struct sockaddr *)&saddr)); + } + + break; +#endif + + case IPSECDOI_ID_FQDN: + case IPSECDOI_ID_USER_FQDN: + len = id->l - sizeof(*id_b); + if (len > BUFLEN) + len = BUFLEN; + memcpy(buf, id->v + sizeof(*id_b), len); + break; + + case IPSECDOI_ID_DER_ASN1_DN: + case IPSECDOI_ID_DER_ASN1_GN: + { + X509_NAME *xn = NULL; + + dat = id->v + sizeof(*id_b); + len = id->l - sizeof(*id_b); + + if (d2i_X509_NAME(&xn, (void*) &dat, len) != NULL) { + BIO *bio = BIO_new(BIO_s_mem()); + X509_NAME_print_ex(bio, xn, 0, 0); + len = BIO_get_mem_data(bio, &dat); + if (len > BUFLEN) + len = BUFLEN; + memcpy(buf,dat,len); + BIO_free(bio); + X509_NAME_free(xn); + } else { + plog(LLV_ERROR, LOCATION, NULL, + "unable to extract asn1dn from id\n"); + + len = snprintf(buf, sizeof(buf), ""); + } + + break; + } + + /* currently unhandled id types */ + case IPSECDOI_ID_KEY_ID: + len = snprintf( buf, sizeof(buf), ""); + break; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "unknown ID type %d\n", id_b->type); + } + + if (!len) + len = snprintf( buf, sizeof(buf), ""); + + ret = racoon_malloc(len+1); + if (ret != NULL) { + memcpy(ret,buf,len); + ret[len]=0; + } + + return ret; } /* @@ -4265,9 +4885,6 @@ static int rm_idtype2doi[] = { 255, /* IDTYPE_ADDRESS, 4 * it expands into 4 types by another function. */ IPSECDOI_ID_DER_ASN1_DN, /* IDTYPE_ASN1DN, 5 */ -#ifdef ENABLE_HYBRID - 255, /* IDTYPE_LOGIN, 6 */ -#endif }; /* @@ -4323,16 +4940,16 @@ switch_authmethod(authmethod) case OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_R: authmethod = OAKLEY_ATTR_AUTH_METHOD_HYBRID_DSS_I; break; - /* Those are not implemented */ case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_I; break; - case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_R: - authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_I; - break; case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R: authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I; break; + /* Those are not implemented */ + case OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_R: + authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_DSSSIG_I; + break; case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_R: authmethod = OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_I; break;