free (sa);
cfg_initiator_send_ATTR (struct message *msg){  struct sa *isakmp_sa = msg->isakmp_sa;  struct ipsec_exch *ie = msg->exchange->data;  u_int8_t *hashp = 0, *attrp, *attr;  size_t attrlen, off;  char *id_string, *cfg_mode, *field;  struct sockaddr *sa;#define CFG_ATTR_BIT_MAX ISAKMP_CFG_ATTR_FUTURE_MIN	/* XXX */  bitstr_t bit_decl (attrbits, CFG_ATTR_BIT_MAX);  u_int16_t bit, length;  u_int32_t life;  if (msg->exchange->phase == 2)    {      hashp = cfg_add_hash (msg);      if (!hashp)	return -1;    }  /* We initiated this exchange, check isakmp_sa for other side.  */  if (isakmp_sa->initiator)    id_string = ipsec_id_string (isakmp_sa->id_r, isakmp_sa->id_r_len);  else    id_string = ipsec_id_string (isakmp_sa->id_i, isakmp_sa->id_i_len);  if (!id_string)    {      log_print ("cfg_initiator_send_ATTR: cannot parse ID");      goto fail;    }  /* Check for attribute list to send to the other side */  attrlen = 0;  bit_nclear (attrbits, 0, CFG_ATTR_BIT_MAX - 1);  cfg_mode = conf_get_str (id_string, "Mode");  if (!cfg_mode || strcmp (cfg_mode, "SET") == 0)    {      /* SET/ACK mode */      ie->cfg_type = ISAKMP_CFG_SET;      LOG_DBG ((LOG_NEGOTIATION, 10, "cfg_initiator_send_ATTR: SET/ACK mode"));#define ATTRFIND(STR,ATTR4,LEN4,ATTR6,LEN6) do				\	{								\	  if ((sa = conf_get_address (id_string, STR)) != NULL)		\	    switch (sa->sa_family)					\	      {								\	      case AF_INET:						\		bit_set (attrbits, ATTR4);				\		attrlen += ISAKMP_ATTR_SZ + LEN4;			\		break;							\	      case AF_INET6:						\		bit_set (attrbits, ATTR6);				\		attrlen += ISAKMP_ATTR_SZ + LEN6;			\		break;							\	      default:							\		break;							\	      }								\          free (sa);							\        } while (0)      /* XXX We don't simultaneously support IPv4 and IPv6 addresses.  */      ATTRFIND ("Address", ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS, 4,		ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS, 16);      ATTRFIND ("Netmask", ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK, 4,		ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK, 16);      ATTRFIND ("Nameserver", ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS, 4,		ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS, 16);      ATTRFIND ("WINS-server", ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS, 4,		ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS, 16);      ATTRFIND ("DHCP-server", ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP, 4,		ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP, 16);#ifdef notyet      ATTRFIND ("Network", ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET, 8,		ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET, 17);#endif#undef ATTRFIND      if (conf_get_str (id_string, "Lifetime"))	{	  bit_set (attrbits, ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY);	  attrlen += ISAKMP_ATTR_SZ + 4;	}    }  else    {      struct conf_list *alist;      struct conf_list_node *anode;      ie->cfg_type = ISAKMP_CFG_REQUEST;      LOG_DBG ((LOG_NEGOTIATION, 10,		"cfg_initiator_send_ATTR: REQ/REPLY mode"));      alist = conf_get_list (id_string, "Attributes");      if (alist)	{	  for (anode = TAILQ_FIRST (&alist->fields); anode;	       anode = TAILQ_NEXT (anode, link))	    {	      if (strcasecmp (anode->field, "Address") == 0)		{		  bit_set (attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS);		  bit_set (attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS);		  attrlen += ISAKMP_ATTR_SZ * 2;		}	      else if (strcasecmp (anode->field, "Netmask") == 0)		{		  bit_set (attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK);		  bit_set (attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK);		  attrlen += ISAKMP_ATTR_SZ * 2;		}	      else if (strcasecmp (anode->field, "Nameserver") == 0)		{		  bit_set (attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS);		  bit_set (attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS);		  attrlen += ISAKMP_ATTR_SZ * 2;		}	      else if (strcasecmp (anode->field, "WINS-server") == 0)		{		  bit_set (attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS);		  bit_set (attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS);		  attrlen += ISAKMP_ATTR_SZ * 2;		}	      else if (strcasecmp (anode->field, "DHCP-server") == 0)		{		  bit_set (attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP);		  bit_set (attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP);		  attrlen += ISAKMP_ATTR_SZ * 2;		}	      else if (strcasecmp (anode->field, "Lifetime") == 0)		{		  bit_set (attrbits, ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY);		  attrlen += ISAKMP_ATTR_SZ;		}	      else		{		  log_print ("cfg_initiator_send_ATTR: unknown attribute "			     "%.20s in section [%s]", anode->field, id_string);		}	    }	  conf_free_list (alist);	}    }  if (attrlen == 0)    {      /* No data found.  */      log_print ("cfg_initiator_send_ATTR: no IKECFG attributes "		 "found for [%s]", id_string);      /*       * We can continue, but this indicates a configuration error that       * the user probably will want to correct.       */      free (id_string);      return 0;    }  attrlen += ISAKMP_ATTRIBUTE_SZ;  attrp = calloc (1, attrlen);  if (!attrp)    {      log_error ("cfg_initiator_send_ATTR: calloc (1, %lu) failed",		 (unsigned long)attrlen);      goto fail;    }  if (message_add_payload (msg, ISAKMP_PAYLOAD_ATTRIBUTE, attrp, attrlen, 1))    {      free (attrp);      goto fail;    }  SET_ISAKMP_ATTRIBUTE_TYPE (attrp, ie->cfg_type);  getrandom ((u_int8_t *)&ie->cfg_id, sizeof ie->cfg_id);  SET_ISAKMP_ATTRIBUTE_ID (attrp, ie->cfg_id);  off = ISAKMP_ATTRIBUTE_SZ;  /*   * Use the bitstring built previously to collect the right   * parameters for attrp.   */  for (bit = 0; bit < CFG_ATTR_BIT_MAX; bit++)    if (bit_test (attrbits, bit))      {	attr = attrp + off;	SET_ISAKMP_ATTR_TYPE (attr, bit);	if (ie->cfg_type == ISAKMP_CFG_REQUEST)	  {	    off += ISAKMP_ATTR_SZ;	    continue;	  }	/* All the other are similar, this is the odd one.  */	if (bit == ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY)	  {	    life = conf_get_num (id_string, "Lifetime", 1200);	    SET_ISAKMP_ATTR_LENGTH_VALUE (attr, 4);	    encode_32 (attr + ISAKMP_ATTR_VALUE_OFF, life);	    off += ISAKMP_ATTR_SZ + 4;	    continue;	  }	switch (bit)	  {	  case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS:	  case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK:	  case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:	  case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP:	  case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:	    length = 4;	    break;	  case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:	  case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK:	  case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:	  case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:	  case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:	    length = 16;	    break;	  default:	    length = 0; /* Silence gcc.  */	  }	switch (bit)	  {	  case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS:	  case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:	    field = "Address";	    break;	  case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK:	  case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK:	    field = "Netmask";	    break;	  case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:	  case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:	    field = "Nameserver";	    break;	  case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP:	  case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:	    field = "DHCP-server";	    break;	  case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:	  case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:	    field = "WINS-server";	    break;	  default:	    field = 0; /* Silence gcc.  */	  }	sa = conf_get_address (id_string, field);	SET_ISAKMP_ATTR_LENGTH_VALUE (attr, length);	memcpy (attr + ISAKMP_ATTR_VALUE_OFF, sockaddr_addrdata (sa),		length);	off += ISAKMP_ATTR_SZ + length;      }  if (msg->exchange->phase == 2)    if (cfg_finalize_hash (msg, hashp, attrp, attrlen))      goto fail;  return 0; fail:  if (id_string)    free (id_string);  return -1;}