示例#1
0
static void
nat_t_send_keepalive(void *v_arg)
{
	struct sa *sa = (struct sa *)v_arg;
	struct transport *t;
	struct timeval now;
	int interval;

	/* Send the keepalive message.  */
	t = ((struct virtual_transport *)sa->transport)->encap;
	t->vtbl->send_message(NULL, t);

	/* Set new timer.  */
	interval = conf_get_num("General", "NAT-T-Keepalive", 0);
	if (interval < 1)
		interval = NAT_T_KEEPALIVE_INTERVAL;
	gettimeofday(&now, 0);
	now.tv_sec += interval;

	sa->nat_t_keepalive = timer_add_event("nat_t_send_keepalive",
	    nat_t_send_keepalive, v_arg, &now);
	if (!sa->nat_t_keepalive)
		log_print("nat_t_send_keepalive: "
		    "timer_add_event() failed, will send no more keepalives");
}
示例#2
0
/*
 * When we are "the server", this starts SET/ACK mode
 * When we are "the client", this starts REQ/REPLY mode
 */
static int
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);

			free(sa);

			off += ISAKMP_ATTR_SZ + length;
		}
	if (msg->exchange->phase == 2)
		if (cfg_finalize_hash(msg, hashp, attrp, attrlen))
			goto fail;

	return 0;

fail:
	free(id_string);
	return -1;
}
示例#3
0
/*
 * Encode list of attributes from ie->attrs into a attribute payload.
 */
static int
cfg_encode_attributes(struct isakmp_cfg_attr_head *attrs, u_int32_t type,
    u_int32_t cfg_id, char *id_string, u_int8_t **attrp, u_int16_t *len)
{
	struct isakmp_cfg_attr *attr;
	struct sockaddr *sa;
	sa_family_t     family;
	u_int32_t       value;
	u_int16_t       off;
	char           *field;

	/* Compute length */
	*len = ISAKMP_ATTRIBUTE_SZ;
	for (attr = LIST_FIRST(attrs); attr; attr = LIST_NEXT(attr, link)) {
		/* With ACK we only include the attrs we've actually used.  */
		if (type == ISAKMP_CFG_ACK && attr->attr_used == 0)
			continue;

		switch (attr->type) {
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK:
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP:
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:
		case ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY:
			attr->length = 4;
			break;

		case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET:
			attr->length = 8;
			break;

		case ISAKMP_CFG_ATTR_APPLICATION_VERSION:
			/* XXX So far no version identifier of isakmpd here. */
			attr->length = 0;
			break;

		case ISAKMP_CFG_ATTR_SUPPORTED_ATTRIBUTES:
			attr->length = 2 * 15;
			break;

		case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:
			attr->length = 16;
			break;

		case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET:
			attr->length = 17;
			break;

		default:
			attr->ignore++;
			/* XXX Log!  */
		}
		*len += ISAKMP_ATTR_SZ + attr->length;
	}

	/* Allocate enough space for the payload */
	*attrp = calloc(1, *len);
	if (!*attrp) {
		log_error("cfg_encode_attributes: calloc (1, %lu) failed",
		    (unsigned long)*len);
		return -1;
	}
	SET_ISAKMP_ATTRIBUTE_TYPE(*attrp, type);
	SET_ISAKMP_ATTRIBUTE_ID(*attrp, cfg_id);

	off = ISAKMP_ATTRIBUTE_SZ;
	for (attr = LIST_FIRST(attrs); attr; attr = LIST_NEXT(attr, link)) {
		/* With ACK we only include the attrs we've actually used.  */
		if (type == ISAKMP_CFG_ACK && attr->attr_used == 0)
			continue;

		switch (attr->type) {
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK:
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET:
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP:
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:
			family = AF_INET;
			break;

		case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:
			family = AF_INET6;
			break;

		default:
			family = 0;
			break;
		}

		switch (attr->type) {
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:
			field = "Address";
			break;

		case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET:
			field = "Network";	/* XXX or just "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_DHCP:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:
			field = "DHCP-server";
			break;

		case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:
			field = "Nameserver";
			break;

		case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:
			field = "WINS-server";
			break;

		default:
			field = 0;
		}

		switch (attr->type) {
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK:
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:
			sa = conf_get_address(id_string, field);
			if (!sa) {
				LOG_DBG((LOG_NEGOTIATION, 10,
				    "cfg_responder_send_ATTR: "
				    "attribute not found: %s", field));
				attr->length = 0;
				break;
			}
			if (sa->sa_family != family) {
				log_print("cfg_responder_send_ATTR: "
				    "attribute %s - expected %s got %s data",
				    field,
				    (family == AF_INET ? "IPv4" : "IPv6"),
				    (sa->sa_family ==
					AF_INET ? "IPv4" : "IPv6"));
				free(sa);
				attr->length = 0;
				break;
			}
			/* Temporary limit length for the _SUBNET types. */
			if (attr->type == ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET)
				attr->length = 4;
			else if (attr->type ==
			    ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET)
				attr->length = 16;

			memcpy(*attrp + off + ISAKMP_ATTR_VALUE_OFF,
			    sockaddr_addrdata(sa), attr->length);
			free(sa);

			/* _SUBNET types need some extra work. */
			if (attr->type ==
			    ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET) {
				sa = conf_get_address(id_string, "Netmask");
				if (!sa) {
					LOG_DBG((LOG_NEGOTIATION, 10,
					    "cfg_responder_send_ATTR: "
					   "attribute not found: Netmask"));
					attr->length = 0;
					break;
				}
				if (sa->sa_family != AF_INET) {
					log_print("cfg_responder_send_ATTR: "
					    "attribute Netmask - expected "
					    "IPv4 got IPv6 data");
					free(sa);
					attr->length = 0;
					break;
				}
				memcpy(*attrp + off + ISAKMP_ATTR_VALUE_OFF +
				    attr->length, sockaddr_addrdata(sa),
				    attr->length);
				attr->length = 8;
				free(sa);
			} else if (attr->type ==
			    ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET) {
				int prefix = conf_get_num(id_string, "Prefix",
				    -1);

				if (prefix == -1) {
					log_print("cfg_responder_send_ATTR: "
					    "attribute not found: Prefix");
					attr->length = 0;
					break;
				} else if (prefix < -1 || prefix > 128) {
					log_print("cfg_responder_send_ATTR: "
					    "attribute Prefix - invalid "
					    "value %d", prefix);
					attr->length = 0;
					break;
				}
				*(*attrp + off + ISAKMP_ATTR_VALUE_OFF + 16) =
				    (u_int8_t)prefix;
				attr->length = 17;
			}
			break;

		case ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY:
			value = conf_get_num(id_string, "Lifetime", 1200);
			encode_32(*attrp + off + ISAKMP_ATTR_VALUE_OFF, value);
			break;

		case ISAKMP_CFG_ATTR_APPLICATION_VERSION:
			/* XXX So far no version identifier of isakmpd here. */
			break;

		case ISAKMP_CFG_ATTR_SUPPORTED_ATTRIBUTES:
			break;

		default:
			break;
		}

		SET_ISAKMP_ATTR_TYPE(*attrp + off, attr->type);
		SET_ISAKMP_ATTR_LENGTH_VALUE(*attrp + off, attr->length);
		off += ISAKMP_ATTR_VALUE_OFF + attr->length;
	}

	return 0;
}
示例#4
0
/* Offer a set of transforms to the responder in the MSG message.  */
int
ike_phase_1_initiator_send_SA (struct message *msg)
{
    struct exchange *exchange = msg->exchange;
    struct ipsec_exch *ie = exchange->data;
    u_int8_t *proposal = 0, *sa_buf = 0, *saved_nextp, *attr;
    u_int8_t **transform = 0;
    size_t transforms_len = 0, proposal_len, sa_len;
    size_t *transform_len = 0;
    struct conf_list *conf, *life_conf;
    struct conf_list_node *xf, *life;
    int i, value, update_nextp;
    struct payload *p;
    struct proto *proto;
    int group_desc = -1, new_group_desc;

    /* Get the list of transforms.  */
    conf = conf_get_list (exchange->policy, "Transforms");
    if (!conf)
        return -1;

    transform = calloc (conf->cnt, sizeof *transform);
    if (!transform)
    {
        log_error ("ike_phase_1_initiator_send_SA: calloc (%d, %lu) failed",
                   conf->cnt, (unsigned long)sizeof *transform);
        goto bail_out;
    }

    transform_len = calloc (conf->cnt, sizeof *transform_len);
    if (!transform_len)
    {
        log_error ("ike_phase_1_initiator_send_SA: calloc (%d, %lu) failed",
                   conf->cnt, (unsigned long)sizeof *transform_len);
        goto bail_out;
    }

    for (xf = TAILQ_FIRST (&conf->fields), i = 0; i < conf->cnt;
            i++, xf = TAILQ_NEXT (xf, link))
    {
        /* XXX The sizing needs to be dynamic.  */
        transform[i]
            = malloc (ISAKMP_TRANSFORM_SA_ATTRS_OFF + 16 * ISAKMP_ATTR_VALUE_OFF);
        if (!transform[i])
        {
            log_error ("ike_phase_1_initiator_send_SA: malloc (%d) failed",
                       ISAKMP_TRANSFORM_SA_ATTRS_OFF
                       + 16 * ISAKMP_ATTR_VALUE_OFF);
            goto bail_out;
        }

        SET_ISAKMP_TRANSFORM_NO (transform[i], i);
        SET_ISAKMP_TRANSFORM_ID (transform[i], IPSEC_TRANSFORM_KEY_IKE);
        SET_ISAKMP_TRANSFORM_RESERVED (transform[i], 0);

        attr = transform[i] + ISAKMP_TRANSFORM_SA_ATTRS_OFF;

        if (attribute_set_constant (xf->field, "ENCRYPTION_ALGORITHM",
                                    ike_encrypt_cst,
                                    IKE_ATTR_ENCRYPTION_ALGORITHM, &attr))
            goto bail_out;

        if (attribute_set_constant (xf->field, "HASH_ALGORITHM", ike_hash_cst,
                                    IKE_ATTR_HASH_ALGORITHM, &attr))
            goto bail_out;

        if (attribute_set_constant (xf->field, "AUTHENTICATION_METHOD",
                                    ike_auth_cst, IKE_ATTR_AUTHENTICATION_METHOD,
                                    &attr))
            goto bail_out;

        if (attribute_set_constant (xf->field, "GROUP_DESCRIPTION",
                                    ike_group_desc_cst,
                                    IKE_ATTR_GROUP_DESCRIPTION, &attr))
        {
            /*
             * If no group description exists, try looking for a user-defined
             * one.
             */
            if (attribute_set_constant (xf->field, "GROUP_TYPE", ike_group_cst,
                                        IKE_ATTR_GROUP_TYPE, &attr))
                goto bail_out;

#if 0
            if (attribute_set_bignum (xf->field, "GROUP_PRIME",
                                      IKE_ATTR_GROUP_PRIME, &attr))
                goto bail_out;

            if (attribute_set_bignum (xf->field, "GROUP_GENERATOR_2",
                                      IKE_ATTR_GROUP_GENERATOR_2, &attr))
                goto bail_out;

            if (attribute_set_bignum (xf->field, "GROUP_GENERATOR_2",
                                      IKE_ATTR_GROUP_GENERATOR_2, &attr))
                goto bail_out;

            if (attribute_set_bignum (xf->field, "GROUP_CURVE_A",
                                      IKE_ATTR_GROUP_CURVE_A, &attr))
                goto bail_out;

            if (attribute_set_bignum (xf->field, "GROUP_CURVE_B",
                                      IKE_ATTR_GROUP_CURVE_B, &attr))
                goto bail_out;
#endif
        }

        /*
         * Life durations are special, we should be able to specify
         * several, one per type.
         */
        life_conf = conf_get_list (xf->field, "Life");
        if (life_conf)
        {
            for (life = TAILQ_FIRST (&life_conf->fields); life;
                    life = TAILQ_NEXT (life, link))
            {
                attribute_set_constant (life->field, "LIFE_TYPE",
                                        ike_duration_cst, IKE_ATTR_LIFE_TYPE,
                                        &attr);

                /* XXX Deals with 16 and 32 bit lifetimes only */
                value = conf_get_num (life->field, "LIFE_DURATION", 0);
                if (value)
                {
                    if (value <= 0xffff)
                        attr = attribute_set_basic (attr, IKE_ATTR_LIFE_DURATION,
                                                    value);
                    else
                    {
                        value = htonl (value);
                        attr = attribute_set_var (attr, IKE_ATTR_LIFE_DURATION,
                                                  (u_int8_t *)&value,
                                                  sizeof value);
                    }
                }
            }
            conf_free_list (life_conf);
        }

        attribute_set_constant (xf->field, "PRF", ike_prf_cst, IKE_ATTR_PRF,
                                &attr);

        value = conf_get_num (xf->field, "KEY_LENGTH", 0);
        if (value)
            attr = attribute_set_basic (attr, IKE_ATTR_KEY_LENGTH, value);

        value = conf_get_num (xf->field, "FIELD_SIZE", 0);
        if (value)
            attr = attribute_set_basic (attr, IKE_ATTR_FIELD_SIZE, value);

        value = conf_get_num (xf->field, "GROUP_ORDER", 0);
        if (value)
            attr = attribute_set_basic (attr, IKE_ATTR_GROUP_ORDER, value);

        /* Record the real transform size.  */
        transforms_len += transform_len[i] = attr - transform[i];

        /* XXX I don't like exchange-specific stuff in here.  */
        if (exchange->type == ISAKMP_EXCH_AGGRESSIVE)
        {
            /*
             * Make sure that if a group description is specified, it is
             * specified for all transforms equally.
             */
            attr = (u_int8_t *)conf_get_str (xf->field, "GROUP_DESCRIPTION");
            new_group_desc
                = attr ? constant_value (ike_group_desc_cst, (char *)attr) : 0;
            if (group_desc == -1)
                group_desc = new_group_desc;
            else if (group_desc != new_group_desc)
            {
                log_print ("ike_phase_1_initiator_send_SA: "
                           "differing group descriptions in a proposal");
                goto bail_out;
            }
        }

        /* We need to check that we actually support our configuration.  */
        if (attribute_map (transform[i] + ISAKMP_TRANSFORM_SA_ATTRS_OFF,
                           transform_len[i] - ISAKMP_TRANSFORM_SA_ATTRS_OFF,
                           exchange->doi->is_attribute_incompatible, msg))
        {
            log_print ("ike_phase_1_initiator_send_SA: "
                       "section [%s] has unsupported attribute(s)",
                       xf->field);
            goto bail_out;
        }
    }

    /* XXX I don't like exchange-specific stuff in here.  */
    if (exchange->type == ISAKMP_EXCH_AGGRESSIVE)
        ie->group = group_get (group_desc);

    proposal_len = ISAKMP_PROP_SPI_OFF;
    proposal = malloc (proposal_len);
    if (!proposal)
    {
        log_error ("ike_phase_1_initiator_send_SA: malloc (%lu) failed",
                   (unsigned long)proposal_len);
        goto bail_out;
    }

    SET_ISAKMP_PROP_NO (proposal, 1);
    SET_ISAKMP_PROP_PROTO (proposal, ISAKMP_PROTO_ISAKMP);
    SET_ISAKMP_PROP_SPI_SZ (proposal, 0);
    SET_ISAKMP_PROP_NTRANSFORMS (proposal, conf->cnt);

    /* XXX I would like to see this factored out.  */
    proto = calloc (1, sizeof *proto);
    if (!proto)
    {
        log_error ("ike_phase_1_initiator_send_SA: calloc (1, %lu) failed",
                   (unsigned long)sizeof *proto);
        goto bail_out;
    }

    proto->no = 1;
    proto->proto = ISAKMP_PROTO_ISAKMP;
    proto->sa = TAILQ_FIRST (&exchange->sa_list);
    TAILQ_INSERT_TAIL (&TAILQ_FIRST (&exchange->sa_list)->protos, proto,
                       link);

    sa_len = ISAKMP_SA_SIT_OFF + IPSEC_SIT_SIT_LEN;
    sa_buf = malloc (sa_len);
    if (!sa_buf)
    {
        log_error ("ike_phase_1_initiator_send_SA: malloc (%lu) failed",
                   (unsigned long)sa_len);
        goto bail_out;
    }

    SET_ISAKMP_SA_DOI (sa_buf, IPSEC_DOI_IPSEC);
    SET_IPSEC_SIT_SIT (sa_buf + ISAKMP_SA_SIT_OFF, IPSEC_SIT_IDENTITY_ONLY);

    /*
     * Add the payloads.  As this is a SA, we need to recompute the
     * lengths of the payloads containing others.
     */
    if (message_add_payload (msg, ISAKMP_PAYLOAD_SA, sa_buf, sa_len, 1))
        goto bail_out;
    SET_ISAKMP_GEN_LENGTH (sa_buf,
                           sa_len + proposal_len + transforms_len);
    sa_buf = 0;

    saved_nextp = msg->nextp;
    if (message_add_payload (msg, ISAKMP_PAYLOAD_PROPOSAL, proposal,
                             proposal_len, 0))
        goto bail_out;
    SET_ISAKMP_GEN_LENGTH (proposal, proposal_len + transforms_len);
    proposal = 0;

    update_nextp = 0;
    for (i = 0; i < conf->cnt; i++)
    {
        if (message_add_payload (msg, ISAKMP_PAYLOAD_TRANSFORM, transform[i],
                                 transform_len[i], update_nextp))
            goto bail_out;
        update_nextp = 1;
        transform[i] = 0;
    }
    msg->nextp = saved_nextp;

    /* Save SA payload body in ie->sa_i_b, length ie->sa_i_b_len.  */
    ie->sa_i_b_len = sa_len + proposal_len + transforms_len - ISAKMP_GEN_SZ;
    ie->sa_i_b = malloc (ie->sa_i_b_len);
    if (!ie->sa_i_b)
    {
        log_error ("ike_phase_1_initiator_send_SA: malloc (%lu) failed",
                   (unsigned long)ie->sa_i_b_len);
        goto bail_out;
    }
    memcpy (ie->sa_i_b,
            TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_SA])->p + ISAKMP_GEN_SZ,
            sa_len - ISAKMP_GEN_SZ);
    memcpy (ie->sa_i_b + sa_len - ISAKMP_GEN_SZ,
            TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_PROPOSAL])->p,
            proposal_len);
    transforms_len = 0;
    for (i = 0, p = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_TRANSFORM]);
            i < conf->cnt; i++, p = TAILQ_NEXT (p, link))
    {
        memcpy (ie->sa_i_b + sa_len + proposal_len + transforms_len
                - ISAKMP_GEN_SZ,
                p->p, transform_len[i]);
        transforms_len += transform_len[i];
    }

    conf_free_list (conf);
    free (transform);
    free (transform_len);
    return 0;

bail_out:
    if (sa_buf)
        free (sa_buf);
    if (proposal)
        free (proposal);
    if (transform)
    {
        for (i = 0; i < conf->cnt; i++)
            if (transform[i])
                free (transform[i]);
        free (transform);
    }
    if (transform_len)
        free (transform_len);
    conf_free_list (conf);
    return -1;
}
示例#5
0
int main(int argc, char **argv)
{
	char *arg;
	char *value;
	char *type;
	int rc = 1, opt;
	int timeout = 600;
	key_serial_t key;
	char *progname, *keystr = NULL;
	int clearing = 0, keymask = 0, display = 0, list = 0;

	/* Set the basename */
	if ((progname = strrchr(argv[0], '/')) != NULL)
		progname++;
	else
		progname = argv[0];

	xlog_open(progname);

	while ((opt = getopt(argc, argv, "du:g:r:ct:vl")) != -1) {
		switch (opt) {
		case 'd':
			display++;
			break;
		case 'l':
			list++;
			break;
		case 'u':
			keymask = UIDKEYS;
			keystr = strdup(optarg);
			break;
		case 'g':
			keymask = GIDKEYS;
			keystr = strdup(optarg);
			break;
		case 'r':
			keymask = GIDKEYS|UIDKEYS;
			keystr = strdup(optarg);
			break;
		case 'c':
			clearing++;
			break;
		case 'v':
			verbose++;
			break;
		case 't':
			timeout = atoi(optarg);
			break;
		default:
			xlog_warn(usage, progname);
			break;
		}
	}

	if ((rc = nfs4_init_name_mapping(PATH_IDMAPDCONF)))  {
		xlog_errno(rc, "Unable to create name to user id mappings.");
		return EXIT_FAILURE;
	}
	if (!verbose)
		verbose = conf_get_num("General", "Verbosity", 0);

	if (display)
		return display_default_domain();
	if (list)
		return list_keyring(DEFAULT_KEYRING);
	if (keystr) {
		return key_invalidate(keystr, keymask);
	}
	if (clearing) {
		xlog_syslog(0);
		return keyring_clear(DEFAULT_KEYRING);
	}

	xlog_stderr(0);
	if ((argc - optind) != 2) {
		xlog_err("Bad arg count. Check /etc/request-key.conf");
		xlog_warn(usage, progname);
		return EXIT_FAILURE;
	}

	if (verbose)
		nfs4_set_debug(verbose, NULL);

	key = strtol(argv[optind++], NULL, 10);

	arg = strdup(argv[optind]);
	if (arg == NULL) {
		xlog_err("strdup failed: %m");
		return EXIT_FAILURE;
	}
	type = strtok(arg, ":");
	value = strtok(NULL, ":");
	if (value == NULL) {
		free(arg);
		xlog_err("Error: Null uid/gid value.");
		return EXIT_FAILURE;
	}
	if (verbose) {
		xlog_warn("key: 0x%lx type: %s value: %s timeout %ld",
			key, type, value, timeout);
	}

	/* Become a possesor of the to-be-instantiated key to set the key's timeout */
	request_key("keyring", DEFAULT_KEYRING, NULL, KEY_SPEC_THREAD_KEYRING);

	if (strcmp(type, "uid") == 0)
		rc = id_lookup(value, key, USER);
	else if (strcmp(type, "gid") == 0)
		rc = id_lookup(value, key, GROUP);
	else if (strcmp(type, "user") == 0)
		rc = name_lookup(value, key, USER);
	else if (strcmp(type, "group") == 0)
		rc = name_lookup(value, key, GROUP);

	/* Set timeout to 10 (600 seconds) minutes */
	if (rc == EXIT_SUCCESS)
		keyctl_set_timeout(key, timeout);

	free(arg);
	return rc;
}
示例#6
0
文件: ike_auth.c 项目: ebichu/dd-wrt
/* Encrypt the HASH into a SIG type.  */
static int
rsa_sig_encode_hash (struct message *msg)
{
  struct exchange *exchange = msg->exchange;
  struct ipsec_exch *ie = exchange->data;
  size_t hashsize = ie->hash->hashsize;
  struct cert_handler *handler;
  char header[80];
  int initiator = exchange->initiator;
  u_int8_t *buf, *data, *buf2;
  u_int32_t datalen;
  u_int8_t *id;
  size_t id_len;
  int idtype;
  void *sent_key;

  id = initiator ? exchange->id_i : exchange->id_r;
  id_len = initiator ? exchange->id_i_len : exchange->id_r_len;

  /* We may have been provided these by the kernel */
  buf = (u_int8_t *)conf_get_str (exchange->name, "Credentials");
  if (buf
      && (idtype = conf_get_num (exchange->name, "Credential_Type", -1) != -1))
    {
      exchange->sent_certtype = idtype;
      handler = cert_get (idtype);
      if (!handler)
	{
	  log_print ("rsa_sig_encode_hash: cert_get (%d) failed", idtype);
	  return -1;
	}

      exchange->sent_cert = handler->cert_from_printable ((char *)buf);
      if (!exchange->sent_cert)
	{
	  log_print ("rsa_sig_encode_hash: failed to retrieve certificate");
	  return -1;
	}

      handler->cert_serialize (exchange->sent_cert, &data, &datalen);
      if (!data)
	{
	  log_print ("rsa_sig_encode_hash: cert serialization failed");
	  return -1;
	}

      goto aftercert; /* Skip all the certificate discovery */
    }

  /* XXX This needs to be configurable.  */
  idtype = ISAKMP_CERTENC_KEYNOTE;

  /* Find a certificate with subjectAltName = id.  */
  handler = cert_get (idtype);
  if (!handler)
    {
      idtype = ISAKMP_CERTENC_X509_SIG;
      handler = cert_get (idtype);
      if (!handler)
	{
	  log_print ("rsa_sig_encode_hash: cert_get(%d) failed", idtype);
	  return -1;
	}
    }

  if (handler->cert_obtain (id, id_len, 0, &data, &datalen) == 0)
    {
      if (idtype == ISAKMP_CERTENC_KEYNOTE)
	{
	  idtype = ISAKMP_CERTENC_X509_SIG;
	  handler = cert_get (idtype);
	  if (!handler)
	    {
	      log_print ("rsa_sig_encode_hash: cert_get(%d) failed", idtype);
	      return -1;
	    }

	  if (handler->cert_obtain (id, id_len, 0, &data, &datalen) == 0)
	    {
	      LOG_DBG ((LOG_MISC, 10,
			"rsa_sig_encode_hash: no certificate to send"));
	      goto skipcert;
	    }
	}
      else
	{
	  LOG_DBG ((LOG_MISC, 10,
		    "rsa_sig_encode_hash: no certificate to send"));
	  goto skipcert;
	}
    }

  /* Let's store the certificate we are going to use */
  exchange->sent_certtype = idtype;
  exchange->sent_cert = handler->cert_get (data, datalen);
  if (!exchange->sent_cert)
    {
      free (data);
      log_print ("rsa_sig_encode_hash: failed to get certificate from wire "
		 "encoding");
      return -1;
    }

 aftercert:

  buf = realloc (data, ISAKMP_CERT_SZ + datalen);
  if (!buf)
    {
      log_error ("rsa_sig_encode_hash: realloc (%p, %d) failed", data,
		 ISAKMP_CERT_SZ + datalen);
      free (data);
      return -1;
    }
  memmove (buf + ISAKMP_CERT_SZ, buf, datalen);
  SET_ISAKMP_CERT_ENCODING (buf, idtype);
  if (message_add_payload (msg, ISAKMP_PAYLOAD_CERT, buf,
			   ISAKMP_CERT_SZ + datalen, 1))
    {
      free (buf);
      return -1;
    }

 skipcert:

  /* Again, we may have these from the kernel */
  buf = (u_int8_t *)conf_get_str (exchange->name, "PKAuthentication");
  if (buf)
    {
      key_from_printable (ISAKMP_KEY_RSA, ISAKMP_KEYTYPE_PRIVATE, (char *)buf,
			  &data, &datalen);
      if (!data || datalen == -1)
	{
	  log_print ("rsa_sig_encode_hash: badly formatted RSA private key");
	  return 0;
	}

      sent_key = key_internalize (ISAKMP_KEY_RSA, ISAKMP_KEYTYPE_PRIVATE, data,
				  datalen);
      if (!sent_key)
	{
	  log_print ("rsa_sig_encode_hash: bad RSA private key from dynamic "
		     "SA acquisition subsystem");
	  return 0;
	}
#if defined (USE_PRIVSEP)
      {
	/* With USE_PRIVSEP, the sent_key should be a key number. */
	void *key = sent_key;
	sent_key = monitor_RSA_upload_key (key);
      }
#endif
    }
  else /* Try through the regular means.  */
    {
      switch (id[ISAKMP_ID_TYPE_OFF - ISAKMP_GEN_SZ])
	{
	case IPSEC_ID_IPV4_ADDR:
	case IPSEC_ID_IPV6_ADDR:
	  util_ntoa ((char **)&buf2,
		     id[ISAKMP_ID_TYPE_OFF - ISAKMP_GEN_SZ] == IPSEC_ID_IPV4_ADDR
		     ? AF_INET : AF_INET6,
		     id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ);
	  if (!buf2)
	    return 0;
	  break;

	case IPSEC_ID_FQDN:
	case IPSEC_ID_USER_FQDN:
	  buf2 = calloc (id_len - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ + 1,
			 sizeof (char));
	  if (!buf2)
	    {
	      log_print ("rsa_sig_encode_hash: malloc (%lu) failed",
			 (unsigned long)id_len - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ + 1);
	      return 0;
	    }
	  memcpy (buf2, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ,
		  id_len - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ);
	  break;

	  /* XXX Support more ID types?  */
	default:
	  buf2 = 0;
	  return 0;
	}

#if defined (USE_PRIVSEP)
      sent_key = monitor_RSA_get_private_key (exchange->name, (char *)buf2);
#else
      sent_key = ike_auth_get_key (IKE_AUTH_RSA_SIG, exchange->name,
				   (char *)buf2, 0);
#endif
      free (buf2);

      /* Did we find a key?  */
      if (!sent_key)
	{
	  log_print ("rsa_sig_encode_hash: could not get private key");
	  return -1;
	}
    }

#if !defined (USE_PRIVSEP)
  /* Enable RSA blinding.  */
  if (RSA_blinding_on (sent_key, NULL) != 1)
    {
      log_error ("rsa_sig_encode_hash: RSA_blinding_on () failed.");
      return -1;
    }
#endif

  /* XXX hashsize is not necessarily prf->blocksize.  */
  buf = malloc (hashsize);
  if (!buf)
    {
      log_error ("rsa_sig_encode_hash: malloc (%lu) failed",
	(unsigned long)hashsize);
      return -1;
    }

  if (ike_auth_hash (exchange, buf) == -1)
    {
      free (buf);
      return -1;
    }

  snprintf (header, sizeof header, "rsa_sig_encode_hash: HASH_%c",
	    initiator ? 'I' : 'R');
  LOG_DBG_BUF ((LOG_MISC, 80, header, buf, hashsize));

#if !defined (USE_PRIVSEP)
  data = malloc (RSA_size (sent_key));
  if (!data)
    {
      log_error ("rsa_sig_encode_hash: malloc (%d) failed",
		 RSA_size (sent_key));
      return -1;
    }

  datalen = RSA_private_encrypt (hashsize, buf, data, sent_key,
				 RSA_PKCS1_PADDING);
#else
  datalen = monitor_RSA_private_encrypt (hashsize, buf, &data, sent_key,
					 RSA_PKCS1_PADDING);
#endif /* USE_PRIVSEP */
  if (datalen == -1)
    {
      log_print ("rsa_sig_encode_hash: RSA_private_encrypt () failed");
      if (data)
	free (data);
      free (buf);
      monitor_RSA_free (sent_key);
      return -1;
    }

  free (buf);

  buf = realloc (data, ISAKMP_SIG_SZ + datalen);
  if (!buf)
    {
      log_error ("rsa_sig_encode_hash: realloc (%p, %d) failed", data,
		 ISAKMP_SIG_SZ + datalen);
      free (data);
      return -1;
    }
  memmove (buf + ISAKMP_SIG_SZ, buf, datalen);

  snprintf (header, sizeof header, "rsa_sig_encode_hash: SIG_%c",
	    initiator ? 'I' : 'R');
  LOG_DBG_BUF ((LOG_MISC, 80, header, buf + ISAKMP_SIG_DATA_OFF, datalen));
  if (message_add_payload (msg, ISAKMP_PAYLOAD_SIG, buf,
			   ISAKMP_SIG_SZ + datalen, 1))
    {
      free (buf);
      return -1;
    }
  return 0;
}