コード例 #1
0
/* Get list of "local equivalent" realms.  Meaning the list of realms
 * where [email protected] is considered the same user as [email protected]
 * If not specified, default to upper-case of local domain name */
struct conf_list *get_local_realms(void)
{
	static struct conf_list *local_realms = NULL;
	if (local_realms) return local_realms;

	local_realms = conf_get_list("General", "Local-Realms");
	if (local_realms == NULL) {
		struct conf_list_node *node;

		local_realms = malloc(sizeof *local_realms);
		if (local_realms == NULL)
			return NULL;
		local_realms->cnt = 0;
		TAILQ_INIT(&local_realms->fields);

		node = calloc(1, sizeof *node);
		if (node == NULL)
			return NULL;

		node->field = calloc(1, NFS4_MAX_DOMAIN_LEN);
		if (node->field == NULL) {
			free(node);
			return NULL;
		}

		nfs4_get_default_domain(NULL, node->field, NFS4_MAX_DOMAIN_LEN);
		toupper_str(node->field);

		TAILQ_INSERT_TAIL(&local_realms->fields, node, link);
		local_realms->cnt++;
	}
	return local_realms;
}
コード例 #2
0
ファイル: libnfsidmap.c プロジェクト: ystk/debian-libnfsidmap
int nfs4_init_name_mapping(char *conffile)
{
	int ret = -ENOENT;
	char *method;
	int dflt = 0;
	struct conf_list *nfs4_methods, *gss_methods;

	/* XXX: need to be able to reload configurations... */
	if (nfs4_plugins) /* already succesfully initialized */
		return 0;
	if (conffile)
		conf_path = conffile;
	else
		conf_path = PATH_IDMAPDCONF;
	conf_init();
	default_domain = conf_get_str("General", "Domain");
	if (default_domain == NULL) {
		dflt = 1;
		ret = domain_from_dns(&default_domain);
		if (ret) {
			IDMAP_LOG(1, ("libnfsidmap: Unable to determine "
				  "the NFSv4 domain; Using '%s' as the NFSv4 domain "
				  "which means UIDs will be mapped to the 'Nobody-User' "
				  "user defined in %s\n", 
				  IDMAPD_DEFAULT_DOMAIN, PATH_IDMAPDCONF));
			default_domain = IDMAPD_DEFAULT_DOMAIN;
		}
	}
	IDMAP_LOG(1, ("libnfsidmap: using%s domain: %s\n",
		(dflt ? " (default)" : ""), default_domain));

	/* Get list of "local equivalent" realms.  Meaning the list of realms
	 * where [email protected] is considered the same user as [email protected]
	 * If not specified, default to upper-case of local domain name */
	local_realms = conf_get_list("General", "Local-Realms");
	if (local_realms == NULL) {
		struct conf_list_node *node;

		local_realms = malloc(sizeof *local_realms);
		if (local_realms == NULL)
			return -ENOMEM;
		local_realms->cnt = 0;
		TAILQ_INIT(&local_realms->fields);

		node = calloc(1, sizeof *node);
		if (node == NULL)
			return -ENOMEM;
		node->field = strdup(get_default_domain());
		if (node->field == NULL)
			return -ENOMEM;
		toupper_str(node->field);

		TAILQ_INSERT_TAIL(&local_realms->fields, node, link);
		local_realms->cnt++;
	}

	nfs4_methods = conf_get_list("Translation", "Method");
	if (nfs4_methods) {
		IDMAP_LOG(1, ("libnfsidmap: processing 'Method' list\n"));
		if (load_plugins(nfs4_methods, &nfs4_plugins) == -1)
			return -ENOENT;
	} else {
		struct conf_list list;
		struct conf_list_node node;

		TAILQ_INIT(&list.fields);
		list.cnt = 1;
		node.field = "nsswitch";
		TAILQ_INSERT_TAIL (&list.fields, &node, link);

		if (load_plugins(&list, &nfs4_plugins) == -1)
			return -ENOENT;
	}

	gss_methods = conf_get_list("Translation", "GSS-Methods");
	if (gss_methods) {
		IDMAP_LOG(1, ("libnfsidmap: processing 'GSS-Methods' list\n"));
		if (load_plugins(gss_methods, &gss_plugins) == -1)
			goto out;
	}
	ret = 0;
out:
	if (ret) {
		if (nfs4_plugins)
			unload_plugins(nfs4_plugins);
		if (gss_plugins)
			unload_plugins(gss_plugins);
		nfs4_plugins = gss_plugins = NULL;
	}

	return ret ? -ENOENT: 0;
}
コード例 #3
0
ファイル: ui.c プロジェクト: SylvestreG/bitrig
/*
 * Call the configuration API.
 * XXX Error handling!  How to do multi-line transactions?
 */
static void
ui_config(char *cmd)
{
	struct conf_list *vlist;
	struct conf_list_node *vnode;
	char	 subcmd[201], section[201], tag[201], value[201], tmp[201];
	char	*v, *nv;
	int	 trans = 0, items, skip = 0, ret;
	FILE	*fp;

	if (sscanf(cmd, "C %200s", subcmd) != 1)
		goto fail;

	if (strcasecmp(subcmd, "get") == 0) {
		if (sscanf(cmd, "C %*s [%200[^]]]:%200s", section, tag) != 2)
			goto fail;
		v = conf_get_str(section, tag);
		fp = ui_open_result();
		if (fp) {
			if (v)
				fprintf(fp, "%s\n", v);
			fclose(fp);
		}
		LOG_DBG((LOG_UI, 30, "ui_config: \"%s\"", cmd));
		return;
	}

	trans = conf_begin();
	if (strcasecmp(subcmd, "set") == 0) {
		items = sscanf(cmd, "C %*s [%200[^]]]:%200[^=]=%200s %200s",
		    section, tag, value, tmp);
		if (!(items == 3 || items == 4))
			goto fail;
		conf_set(trans, section, tag, value, items == 4 ? 1 : 0, 0);
		if (strcasecmp(section, "Phase 2") == 0 &&
		    (strcasecmp(tag, "Connections") == 0 ||
			strcasecmp(tag, "Passive-connections") == 0))
			ui_conn_reinit();
	} else if (strcasecmp(subcmd, "add") == 0) {
		items = sscanf(cmd, "C %*s [%200[^]]]:%200[^=]=%200s %200s",
		    section, tag, value, tmp);
		if (!(items == 3 || items == 4))
			goto fail;
		v = conf_get_str(section, tag);
		if (!v)
			conf_set(trans, section, tag, value, 1, 0);
		else {
			vlist = conf_get_list(section, tag);
			if (vlist) {
				for (vnode = TAILQ_FIRST(&vlist->fields);
				    vnode;
				    vnode = TAILQ_NEXT(vnode, link)) {
					if (strcmp(vnode->field, value) == 0) {
						skip = 1;
						break;
					}
				}
				conf_free_list(vlist);
			}
			/* Add the new value to the end of the 'v' list.  */
			if (skip == 0) {
				if (asprintf(&nv,
				    v[strlen(v) - 1] == ',' ? "%s%s" : "%s,%s",
				    v, value) == -1) {
					log_error("ui_config: malloc() failed");
					if (trans)
						conf_end(trans, 0);
					return;
				}
				conf_set(trans, section, tag, nv, 1, 0);
				free(nv);
			}
		}
		if (strcasecmp(section, "Phase 2") == 0 &&
		    (strcasecmp(tag, "Connections") == 0 ||
			strcasecmp(tag, "Passive-connections") == 0))
			ui_conn_reinit();
	} else if (strcasecmp(subcmd, "rmv") == 0) {
		items = sscanf(cmd, "C %*s [%200[^]]]:%200[^=]=%200s %200s",
		    section, tag, value, tmp);
		if (!(items == 3 || items == 4))
			goto fail;
		vlist = conf_get_list(section, tag);
		if (vlist) {
			nv = v = NULL;
			for (vnode = TAILQ_FIRST(&vlist->fields);
			    vnode;
			    vnode = TAILQ_NEXT(vnode, link)) {
				if (strcmp(vnode->field, value) == 0)
					continue;
				ret = v ?
				    asprintf(&nv, "%s,%s", v, vnode->field) :
				    asprintf(&nv, "%s", vnode->field);
				free(v);
				if (ret == -1) {
					log_error("ui_config: malloc() failed");
					if (trans)
						conf_end(trans, 0);
					return;
				}
				v = nv;
			}
			conf_free_list(vlist);
			if (nv) {
				conf_set(trans, section, tag, nv, 1, 0);
				free(nv);
			} else {
				conf_remove(trans, section, tag);
			}
		}
		if (strcasecmp(section, "Phase 2") == 0 &&
		    (strcasecmp(tag, "Connections") == 0 ||
			strcasecmp(tag, "Passive-connections") == 0))
			ui_conn_reinit();
	} else if (strcasecmp(subcmd, "rm") == 0) {
		if (sscanf(cmd, "C %*s [%200[^]]]:%200s", section, tag) != 2)
			goto fail;
		conf_remove(trans, section, tag);
	} else if (strcasecmp(subcmd, "rms") == 0) {
		if (sscanf(cmd, "C %*s [%200[^]]]", section) != 1)
			goto fail;
		conf_remove_section(trans, section);
	} else
		goto fail;

	LOG_DBG((LOG_UI, 30, "ui_config: \"%s\"", cmd));
	conf_end(trans, 1);
	return;

fail:
	if (trans)
		conf_end(trans, 0);
	log_print("ui_config: command \"%s\" malformed", cmd);
}
コード例 #4
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;
}
コード例 #5
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;
}
コード例 #6
0
/*
 * Look at the attribute of type TYPE, located at VALUE for LEN bytes forward.
 * The VVS argument holds a validation state kept across invocations.
 * If the attribute is unacceptable to use, return non-zero, otherwise zero.
 */
static int
attribute_unacceptable (u_int16_t type, u_int8_t *value, u_int16_t len,
                        void *vvs)
{
    struct validation_state *vs = vvs;
    struct conf_list *life_conf;
    struct conf_list_node *xf = vs->xf, *life;
    char *tag = constant_lookup (ike_attr_cst, type);
    char *str;
    struct constant_map *map;
    struct attr_node *node;
    int rv;

    if (!tag)
    {
        LOG_DBG ((LOG_NEGOTIATION, 60,
                  "attribute_unacceptable: attribute type %d not known", type));
        return 1;
    }

    switch (type)
    {
    case IKE_ATTR_ENCRYPTION_ALGORITHM:
    case IKE_ATTR_HASH_ALGORITHM:
    case IKE_ATTR_AUTHENTICATION_METHOD:
    case IKE_ATTR_GROUP_DESCRIPTION:
    case IKE_ATTR_GROUP_TYPE:
    case IKE_ATTR_PRF:
        str = conf_get_str (xf->field, tag);
        if (!str)
        {
            /* This attribute does not exist in this policy.  */
            LOG_DBG ((LOG_NEGOTIATION, 70,
                      "attribute_unacceptable: attr %s does not exist in %s",
                      tag, xf->field));
            return 1;
        }

        map = constant_link_lookup (ike_attr_cst, type);
        if (!map)
            return 1;

        if ((constant_value (map, str) == decode_16 (value)) ||
                (!strcmp (str, "ANY")))
        {
            /* Mark this attribute as seen.  */
            node = malloc (sizeof *node);
            if (!node)
            {
                log_error ("attribute_unacceptable: malloc (%lu) failed",
                           (unsigned long)sizeof *node);
                return 1;
            }
            node->type = type;
            LIST_INSERT_HEAD (&vs->attrs, node, link);
            return 0;
        }
        LOG_DBG ((LOG_NEGOTIATION, 30,
                  "attribute_unacceptable: %s: got '%s', expected '%s'", tag,
                  constant_name (map, decode_16 (value)), str));
        return 1;

    case IKE_ATTR_GROUP_PRIME:
    case IKE_ATTR_GROUP_GENERATOR_1:
    case IKE_ATTR_GROUP_GENERATOR_2:
    case IKE_ATTR_GROUP_CURVE_A:
    case IKE_ATTR_GROUP_CURVE_B:
        /* XXX Bignums not handled yet.  */
        return 1;

    case IKE_ATTR_LIFE_TYPE:
    case IKE_ATTR_LIFE_DURATION:
        life_conf = conf_get_list (xf->field, "Life");
        if (life_conf && !strcmp (conf_get_str (xf->field, "Life"), "ANY"))
            return 0;

        rv = 1;
        if (!life_conf)
        {
            /* Life attributes given, but not in our policy.  */
            LOG_DBG ((LOG_NEGOTIATION, 70, "attribute_unacceptable: "
                      "received unexpected life attribute"));
            return 1;
        }

        /*
         * Each lifetime type must match, otherwise we turn the proposal down.
         * In order to do this we need to find the specific section of our
         * policy's "Life" list and match its duration
         */
        switch (type)
        {
        case IKE_ATTR_LIFE_TYPE:
            for (life = TAILQ_FIRST (&life_conf->fields); life;
                    life = TAILQ_NEXT (life, link))
            {
                str = conf_get_str (life->field, "LIFE_TYPE");
                if (!str)
                {
                    LOG_DBG ((LOG_NEGOTIATION, 70, "attribute_unacceptable: "
                              "section [%s] has no LIFE_TYPE", life->field));
                    continue;
                }

                /*
                 * If this is the type we are looking at, save a pointer
                 * to this section in vs->life.
                 */
                if (constant_value (ike_duration_cst, str) == decode_16 (value))
                {
                    vs->life = strdup (life->field);
                    rv = 0;
                    goto bail_out;
                }
            }
            LOG_DBG ((LOG_NEGOTIATION, 70,
                      "attribute_unacceptable: unrecognized LIFE_TYPE %d",
                      decode_16 (value)));
            vs->life = 0;
            break;

        case IKE_ATTR_LIFE_DURATION:
            if (!vs->life)
            {
                LOG_DBG ((LOG_NEGOTIATION, 70, "attribute_unacceptable: "
                          "LIFE_DURATION without LIFE_TYPE"));
                rv = 1;
                goto bail_out;
            }

            str = conf_get_str (vs->life, "LIFE_DURATION");
            if (str)
            {
                if (!strcmp (str, "ANY"))
                    rv = 0;
                else
                    rv = !conf_match_num (vs->life, "LIFE_DURATION",
                                          len == 4 ? decode_32 (value) :
                                          decode_16 (value));
            }
            else
            {
                LOG_DBG ((LOG_NEGOTIATION, 70, "attribute_unacceptable: "
                          "section [%s] has no LIFE_DURATION", vs->life));
                rv = 1;
            }

            free (vs->life);
            vs->life = 0;
            break;
        }

bail_out:
        conf_free_list (life_conf);
        return rv;

    case IKE_ATTR_KEY_LENGTH:
    case IKE_ATTR_FIELD_SIZE:
    case IKE_ATTR_GROUP_ORDER:
        if (conf_match_num (xf->field, tag, decode_16 (value)))
        {
            /* Mark this attribute as seen.  */
            node = malloc (sizeof *node);
            if (!node)
            {
                log_error ("attribute_unacceptable: malloc (%lu) failed",
                           (unsigned long)sizeof *node);
                return 1;
            }
            node->type = type;
            LIST_INSERT_HEAD (&vs->attrs, node, link);
            return 0;
        }
        return 1;
    }
    return 1;
}
コード例 #7
0
/* Validate a proposal inside SA according to EXCHANGE's policy.  */
static int
ike_phase_1_validate_prop (struct exchange *exchange, struct sa *sa,
                           struct sa *isakmp_sa)
{
    struct conf_list *conf, *tags;
    struct conf_list_node *xf, *tag;
    struct proto *proto;
    struct validation_state vs;
    struct attr_node *node, *next_node;

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

    for (xf = TAILQ_FIRST (&conf->fields); xf; xf = TAILQ_NEXT (xf, link))
    {
        for (proto = TAILQ_FIRST (&sa->protos); proto;
                proto = TAILQ_NEXT (proto, link))
        {
            /* Mark all attributes in our policy as unseen.  */
            LIST_INIT (&vs.attrs);
            vs.xf = xf;
            vs.life = 0;
            if (attribute_map (proto->chosen->p + ISAKMP_TRANSFORM_SA_ATTRS_OFF,
                               GET_ISAKMP_GEN_LENGTH (proto->chosen->p)
                               - ISAKMP_TRANSFORM_SA_ATTRS_OFF,
                               attribute_unacceptable, &vs))
                goto try_next;

            /* Sweep over unseen tags in this section.  */
            tags = conf_get_tag_list (xf->field);
            if (tags)
            {
                for (tag = TAILQ_FIRST (&tags->fields); tag;
                        tag = TAILQ_NEXT (tag, link))
                    /*
                     * XXX Should we care about attributes we have, they do not
                     * provide?
                     */
                    for (node = LIST_FIRST (&vs.attrs); node;
                            node = next_node)
                    {
                        next_node = LIST_NEXT (node, link);
                        if (node->type
                                == constant_value (ike_attr_cst, tag->field))
                        {
                            LIST_REMOVE (node, link);
                            free (node);
                        }
                    }
                conf_free_list (tags);
            }

            /* Are there leftover tags in this section?  */
            node = LIST_FIRST (&vs.attrs);
            if (node)
                goto try_next;
        }

        /* All protocols were OK, we succeeded.  */
        LOG_DBG ((LOG_NEGOTIATION, 20, "ike_phase_1_validate_prop: success"));
        conf_free_list (conf);
        if (vs.life)
            free (vs.life);
        return 1;

try_next:
        /* Are there leftover tags in this section?  */
        node = LIST_FIRST (&vs.attrs);
        while (node)
        {
            LIST_REMOVE (node, link);
            free (node);
            node = LIST_FIRST (&vs.attrs);
        }
        if (vs.life)
            free (vs.life);
    }

    LOG_DBG ((LOG_NEGOTIATION, 20, "ike_phase_1_validate_prop: failure"));
    conf_free_list (conf);
    return 0;
}