free (ie->id_ci);
{ free (ie->id_ci); ie->id_ci = 0; }
responder_recv_HASH_SA_NONCE (struct message *msg){  struct payload *hashp, *kep, *idp;  struct sa *sa;  struct sa *isakmp_sa = msg->isakmp_sa;  struct ipsec_sa *isa = isakmp_sa->data;  struct exchange *exchange = msg->exchange;  struct ipsec_exch *ie = exchange->data;  struct prf *prf;  u_int8_t *hash, *my_hash = 0;  size_t hash_len;  u_int8_t *pkt = msg->iov[0].iov_base;  u_int8_t group_desc = 0;  int retval = -1;  struct proto *proto;  struct sockaddr *src, *dst;  char *name;  hashp = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_HASH]);  hash = hashp->p;  hashp->flags |= PL_MARK;  /* The HASH payload should be the first one.  */  if (hash != pkt + ISAKMP_HDR_SZ)    {      /* XXX Is there a better notification type?  */      message_drop (msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0);      goto cleanup;    }  hash_len = GET_ISAKMP_GEN_LENGTH (hash);  my_hash = malloc (hash_len - ISAKMP_GEN_SZ);  if (!my_hash)    {      log_error ("responder_recv_HASH_SA_NONCE: malloc (%lu) failed",		 (unsigned long)hash_len - ISAKMP_GEN_SZ);      goto cleanup;    }  /*   * Check the payload's integrity.   * XXX Share with ipsec_fill_in_hash?   */  LOG_DBG_BUF ((LOG_NEGOTIATION, 90, "responder_recv_HASH_SA_NONCE: SKEYID_a",		isa->skeyid_a, isa->skeyid_len));  prf = prf_alloc (isa->prf_type, isa->hash, isa->skeyid_a, isa->skeyid_len);  if (!prf)    goto cleanup;  prf->Init (prf->prfctx);  LOG_DBG_BUF ((LOG_NEGOTIATION, 90,		"responder_recv_HASH_SA_NONCE: message_id",		exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN));  prf->Update (prf->prfctx, exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN);  LOG_DBG_BUF ((LOG_NEGOTIATION, 90,		"responder_recv_HASH_SA_NONCE: message after HASH",		hash + hash_len,		msg->iov[0].iov_len - ISAKMP_HDR_SZ - hash_len));  prf->Update (prf->prfctx, hash + hash_len,	       msg->iov[0].iov_len - ISAKMP_HDR_SZ - hash_len);  prf->Final (my_hash, prf->prfctx);  prf_free (prf);  LOG_DBG_BUF ((LOG_NEGOTIATION, 90,		"responder_recv_HASH_SA_NONCE: computed HASH(1)", my_hash,		hash_len - ISAKMP_GEN_SZ));  if (memcmp (hash + ISAKMP_GEN_SZ, my_hash, hash_len - ISAKMP_GEN_SZ) != 0)    {      message_drop (msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, 0, 1, 0);      goto cleanup;    }  free (my_hash);  my_hash = 0;  kep = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_KEY_EXCH]);  if (kep)    ie->pfs = 1;  /* Handle optional client ID payloads.  */  idp = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_ID]);  if (idp)    {      /* If IDci is there, IDcr must be too.  */      if (!TAILQ_NEXT (idp, link))	{	  /* XXX Is this a good notify type?  */	  message_drop (msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0);	  goto cleanup;	}      ie->id_ci_sz = GET_ISAKMP_GEN_LENGTH (idp->p);      ie->id_ci = malloc (ie->id_ci_sz);      if (!ie->id_ci)	{	  log_error ("responder_recv_HASH_SA_NONCE: malloc (%lu) failed",		     (unsigned long)ie->id_ci_sz);	  goto cleanup;	}      memcpy (ie->id_ci, idp->p, ie->id_ci_sz);      idp->flags |= PL_MARK;      LOG_DBG_BUF ((LOG_NEGOTIATION, 90,		    "responder_recv_HASH_SA_NONCE: IDci",		    ie->id_ci + ISAKMP_GEN_SZ, ie->id_ci_sz		    - ISAKMP_GEN_SZ));      idp = TAILQ_NEXT (idp, link);      ie->id_cr_sz = GET_ISAKMP_GEN_LENGTH (idp->p);      ie->id_cr = malloc (ie->id_cr_sz);      if (!ie->id_cr)	{	  log_error ("responder_recv_HASH_SA_NONCE: malloc (%lu) failed",		     (unsigned long)ie->id_cr_sz);	  goto cleanup;	}      memcpy (ie->id_cr, idp->p, ie->id_cr_sz);      idp->flags |= PL_MARK;      LOG_DBG_BUF ((LOG_NEGOTIATION, 90,		    "responder_recv_HASH_SA_NONCE: IDcr",		    ie->id_cr + ISAKMP_GEN_SZ, ie->id_cr_sz		    - ISAKMP_GEN_SZ));    }  else    {      /*       * If client identifiers are not present in the exchange,       * we fake them. RFC 2409 states:       *    The identities of the SAs negotiated in Quick Mode are       *    implicitly assumed to be the IP addresses of the ISAKMP       *    peers, without any constraints on the protocol or port       *    numbers allowed, unless client identifiers are specified       *    in Quick Mode.       *       * -- Michael Paddon (mwp@aba.net.au)       */      ie->flags = IPSEC_EXCH_FLAG_NO_ID;      /* Get initiator and responder addresses.  */      msg->transport->vtbl->get_src (msg->transport, &src);      msg->transport->vtbl->get_dst (msg->transport, &dst);      ie->id_ci_sz = ISAKMP_ID_DATA_OFF + sockaddr_addrlen (src);      ie->id_cr_sz = ISAKMP_ID_DATA_OFF + sockaddr_addrlen (dst);      ie->id_ci = calloc (ie->id_ci_sz, sizeof (char));      ie->id_cr = calloc (ie->id_cr_sz, sizeof (char));      if (!ie->id_ci || !ie->id_cr)	{	  log_error ("responder_recv_HASH_SA_NONCE: malloc (%lu) failed",		     (unsigned long)ie->id_ci_sz);	  goto cleanup;	}      if (src->sa_family != dst->sa_family)	{	  log_error ("initiator_recv_HASH_SA_NONCE: sa_family mismatch");	  goto cleanup;	}      switch (src->sa_family)	{	case AF_INET:	  SET_ISAKMP_ID_TYPE (ie->id_ci, IPSEC_ID_IPV4_ADDR);	  SET_ISAKMP_ID_TYPE (ie->id_cr, IPSEC_ID_IPV4_ADDR);	  break;	case AF_INET6:	  SET_ISAKMP_ID_TYPE (ie->id_ci, IPSEC_ID_IPV6_ADDR);	  SET_ISAKMP_ID_TYPE (ie->id_cr, IPSEC_ID_IPV6_ADDR);	  break;	default:	  log_error ("initiator_recv_HASH_SA_NONCE: unknown sa_family %d",		     src->sa_family);	  goto cleanup;	}      memcpy (ie->id_cr + ISAKMP_ID_DATA_OFF, sockaddr_addrdata (src),	      sockaddr_addrlen (src));      memcpy (ie->id_ci + ISAKMP_ID_DATA_OFF, sockaddr_addrdata (dst),	      sockaddr_addrlen (dst));    }#ifdef USE_POLICY#ifdef USE_KEYNOTE  if (message_negotiate_sa (msg, check_policy))    goto cleanup;#else  if (message_negotiate_sa (msg, 0))    goto cleanup;#endif#else  if (message_negotiate_sa (msg, 0))    goto cleanup;#endif /* USE_POLICY */  for (sa = TAILQ_FIRST (&exchange->sa_list); sa; sa = TAILQ_NEXT (sa, next))    {      for (proto = TAILQ_FIRST (&sa->protos); proto;	   proto = TAILQ_NEXT (proto, link))	{	  /* XXX we need to have some attributes per proto, not all per SA.  */	  ipsec_decode_transform (msg, sa, proto, proto->chosen->p);	  if (proto->proto == IPSEC_PROTO_IPSEC_AH	      && !((struct ipsec_proto *)proto->data)->auth)	    {	      log_print ("responder_recv_HASH_SA_NONCE: "			 "AH proposed without an algorithm attribute");	      message_drop (msg, ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 1, 0);	      goto next_sa;	    }	}      isa = sa->data;      /* The group description is mandatory if we got a KEY_EXCH payload.  */      if (kep)	{	  if (!isa->group_desc)	    {	      log_print ("responder_recv_HASH_SA_NONCE: "			 "KEY_EXCH payload without a group desc. attribute");	      message_drop (msg, ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 1, 0);	      continue;	    }	  /* Also, all SAs must have equal groups.  */	  if (!group_desc)	    group_desc = isa->group_desc;	  else if (group_desc != isa->group_desc)	    {	      log_print ("responder_recv_HASH_SA_NONCE: "			 "differing group descriptions in one QM");	      message_drop (msg, ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 1, 0);	      continue;	    }	}      /* At least one SA was accepted.  */      retval = 0;    next_sa:      ; /* XXX gcc3 wants this. */    }  if (kep)    {      ie->group = group_get (group_desc);      if (!ie->group)	{	  /*	   * XXX If the error was due to an out-of-range group description	   * we should notify our peer, but this should probably be done	   * by the attribute validation.  Is it?	   */	  goto cleanup;	}    }  /* Copy out the initiator's nonce.  */  if (exchange_save_nonce (msg))    goto cleanup;  /* Handle the optional KEY_EXCH payload.  */  if (kep && ipsec_save_g_x (msg))    goto cleanup;  /*   * Try to find and set the connection name on the exchange.   */  /*   * Check for accepted identities as well as lookup the connection   * name and set it on the exchange.   */  name = connection_passive_lookup_by_ids (ie->id_ci, ie->id_cr);  if (name)    {      exchange->name = strdup (name);      if (!exchange->name)	{	  log_error ("responder_recv_HASH_SA_NONCE: strdup (\"%s\") failed",		     name);	  goto cleanup;	}    }#if !defined (USE_POLICY) && !defined (USE_KEYNOTE)  else    {      /*       * This code is no longer necessary, as policy determines acceptance       * of IDs/SAs. (angelos@openbsd.org)       *       * XXX Keep it if not USE_POLICY for now, though.       */      /* XXX Notify peer and log.  */      goto cleanup;    }#endif /* !USE_POLICY && !USE_KEYNOTE */  return retval;cleanup:  /* Remove all potential protocols that have been added to the SAs.  */  for (sa = TAILQ_FIRST (&exchange->sa_list); sa; sa = TAILQ_NEXT (sa, next))    while ((proto = TAILQ_FIRST (&sa->protos)) != 0)      proto_free (proto);  if (my_hash)    free (my_hash);  if (ie->id_ci)    free (ie->id_ci);  if (ie->id_cr)    free (ie->id_cr);  return -1;}