Пример #1
0
/* print a policy: like bitnamesof, but it also does the non-bitfields.
 * Suppress the shunt and fail fields if 0.
 */
const char *
prettypolicy(lset_t policy)
{
    const char *bn = bitnamesofb(sa_policy_bit_names
				 , policy & ~(POLICY_SHUNT_MASK | POLICY_FAIL_MASK)
				 , pbitnamesbuf, sizeof(pbitnamesbuf));
    size_t len;
    lset_t shunt = (policy & POLICY_SHUNT_MASK) >> POLICY_SHUNT_SHIFT;
    lset_t fail = (policy & POLICY_FAIL_MASK) >> POLICY_FAIL_SHIFT;

    if (bn != pbitnamesbuf)
	pbitnamesbuf[0] = '\0';
    len = strlen(pbitnamesbuf);
    if (shunt != 0)
    {
	snprintf(pbitnamesbuf + len, sizeof(pbitnamesbuf) - len, "+%s"
	    , policy_shunt_names[shunt]);
	len += strlen(pbitnamesbuf + len);
    }
    if (fail != 0)
    {
	snprintf(pbitnamesbuf + len, sizeof(pbitnamesbuf) - len, "+failure%s"
	    , policy_fail_names[fail]);
	len += strlen(pbitnamesbuf + len);
    }
    if (NEVER_NEGOTIATE(policy))
    {
	snprintf(pbitnamesbuf + len, sizeof(pbitnamesbuf) - len, "+NEVER_NEGOTIATE");
	len += strlen(pbitnamesbuf + len);
    }
    return pbitnamesbuf;
}
Пример #2
0
/* print a policy: like bitnamesof, but it also does the non-bitfields.
 * Suppress the shunt and fail fields if 0.
 */
const char *
prettypolicy(lset_t policy)
{
    char pbitnamesbuf[200];
    const char *bn = bitnamesofb(sa_policy_bit_names
				 , policy & ~(POLICY_SHUNT_MASK | POLICY_FAIL_MASK)
				 , pbitnamesbuf, sizeof(pbitnamesbuf));
    static char buf[200];   /* NOT RE-ENTRANT!  I hope that it is big enough! */
    lset_t shunt = (policy & POLICY_SHUNT_MASK) >> POLICY_SHUNT_SHIFT;
    lset_t fail = (policy & POLICY_FAIL_MASK) >> POLICY_FAIL_SHIFT;

    if (bn != pbitnamesbuf)
	pbitnamesbuf[0] = '\0';
    snprintf(buf, sizeof(buf), "%s%s%s%s%s%s"
	, pbitnamesbuf
	, shunt != 0 ? "+" : "", shunt != 0 ? policy_shunt_names[shunt] : ""
	, fail != 0 ? "+failure" : "", fail != 0 ? policy_fail_names[fail] : ""
	, NEVER_NEGOTIATE(policy) ? "+NEVER_NEGOTIATE" : "");
    return buf;
}
Пример #3
0
static bool load_conn(
#ifdef DNSSEC
		     struct ub_ctx *dnsctx,
#endif
		     struct starter_conn *conn,
		     const struct config_parsed *cfgp,
		     struct section_list *sl,
		     bool alsoprocessing,
		     bool defaultconn,
		     bool resolvip,
		     err_t *perr)
{

	bool err;

	/* turn all of the keyword/value pairs into options/strings in left/right */
	err = translate_conn(conn, sl,
			defaultconn ? k_default : k_set,
			perr);

	move_comment_list(&conn->comments, &sl->comments);

	if (err)
		return err;

	if (conn->strings[KSCF_ALSO] != NULL &&
	    !alsoprocessing) {
		starter_log(LOG_LEVEL_INFO,
			    "also= is not valid in section '%s'",
			    sl->name);
		/* ??? should we not set *perr? */
		return TRUE;	/* error */
	}

	/* now, process the also's */
	if (conn->alsos != NULL)
		FREE_LIST(conn->alsos);
	conn->alsos = new_list(conn->strings[KSCF_ALSO]);

	if (alsoprocessing && conn->alsos != NULL) {
		struct section_list *sl1;
		/* note: for the duration of this loop body
		 * conn->alsos is migrated to local variable alsos.
		 */
		char **alsos = conn->alsos;
		int alsosize;
		int alsoplace;

		conn->alsos = NULL;

		/* reset all of the "beenhere" flags */
		for (sl1 = cfgp->sections.tqh_first; sl1 != NULL;
		     sl1 = sl1->link.tqe_next)
			sl1->beenhere = FALSE;
		sl->beenhere = TRUE;

		/* count them */
		for (alsosize = 0; alsos[alsosize] != NULL; alsosize++)
			;

		alsoplace = 0;
		while (alsoplace < alsosize && alsos[alsoplace] != NULL &&
		       alsoplace < ALSO_LIMIT) {
			/*
			 * for each also= listed, go find this section's keyword list, and
			 * load it as well. This may extend the also= list (and the end),
			 * which we handle by zeroing the also list, and adding to it after
			 * checking for duplicates.
			 */
			for (sl1 = cfgp->sections.tqh_first;
			     sl1 != NULL &&
			     !streq(alsos[alsoplace], sl1->name);
			     sl1 = sl1->link.tqe_next)
				;

			starter_log(LOG_LEVEL_DEBUG,
				    "\twhile loading conn '%s' also including '%s'",
				    conn->name, alsos[alsoplace]);

			/*
			 * if we found something that matches by name,
			 * and we haven't been there, then process it.
			 */
			if (sl1 != NULL && !sl1->beenhere) {
				conn->strings_set[KSCF_ALSO] = FALSE;
				pfreeany(conn->strings[KSCF_ALSO]);
				conn->strings[KSCF_ALSO] = NULL;
				sl1->beenhere = TRUE;

				/* translate things, but do not replace earlier settings! */
				err |= translate_conn(conn, sl1, k_set, perr);

				if (conn->strings[KSCF_ALSO] != NULL) {
					/* now, check out the KSCF_ALSO, and extend list if we need to */
					char **newalsos = new_list(
						conn->strings[KSCF_ALSO]);

					if (newalsos != NULL) {
						char **ra;
						int newalsoplace;

						/* count them */
						for (newalsoplace = 0;
						     newalsos[newalsoplace] !=
						     NULL;
						     newalsoplace++)
							;

						/* extend conn->alss */
						ra = alloc_bytes((alsosize +
							newalsoplace + 1) *
							sizeof(char *),
							"conn->alsos");
						memcpy(ra, alsos, alsosize * sizeof(char *));
						pfree(alsos);
						alsos = ra;
						for (newalsoplace = 0;
						     newalsos[newalsoplace] !=
						     NULL;
						     newalsoplace++) {
							assert(conn != NULL);
							assert(conn->name !=
								NULL);
							starter_log(
								LOG_LEVEL_DEBUG,
								"\twhile processing section '%s' added also=%s",
								sl1->name,
								newalsos[newalsoplace]);

							alsos[alsosize++] =
								clone_str(newalsos[newalsoplace],
									"alsos");
						}
						alsos[alsosize] = NULL;
					}

					FREE_LIST(newalsos);
				}
			}
			alsoplace++;
		}

		/* migrate alsos back to conn->alsos */
		conn->alsos = alsos;

		if (alsoplace >= ALSO_LIMIT) {
			starter_log(LOG_LEVEL_INFO,
				    "while loading conn '%s', too many also= used at section %s. Limit is %d",
				    conn->name,
				    alsos[alsoplace],
				    ALSO_LIMIT);
			/* ??? should we not set *perr? */
			return TRUE;	/* error */
		}
	}


	if (conn->options_set[KBF_TYPE]) {
		switch ((enum keyword_satype)conn->options[KBF_TYPE]) {
		case KS_TUNNEL:
			if (conn->options_set[KBF_AUTHBY] &&
				conn->options[KBF_AUTHBY] == POLICY_AUTH_NEVER) {
					*perr = "connection type=tunnel must not specify authby=never";
					return TRUE;
			}
			conn->policy |= POLICY_TUNNEL;
			conn->policy &= ~POLICY_SHUNT_MASK;
			break;

		case KS_TRANSPORT:
			if (conn->options_set[KBF_AUTHBY] &&
				conn->options[KBF_AUTHBY] == POLICY_AUTH_NEVER) {
					*perr = "connection type=transport must not specify authby=never";
					return TRUE;
			}
			conn->policy &= ~POLICY_TUNNEL;
			conn->policy &= ~POLICY_SHUNT_MASK;
			break;

		case KS_PASSTHROUGH:
			if (!conn->options_set[KBF_AUTHBY] ||
				conn->options[KBF_AUTHBY] != POLICY_AUTH_NEVER) {
					*perr = "connection type=passthrough must specify authby=never";
			}
			conn->policy &=
				~(POLICY_ENCRYPT | POLICY_AUTHENTICATE |
				  POLICY_TUNNEL | POLICY_RSASIG);
			conn->policy &= ~POLICY_SHUNT_MASK;
			conn->policy |= POLICY_SHUNT_PASS;
			break;

		case KS_DROP:
			if (!conn->options_set[KBF_AUTHBY] ||
				conn->options[KBF_AUTHBY] != POLICY_AUTH_NEVER) {
					*perr = "connection type=drop must specify authby=never";
			}
			conn->policy &=
				~(POLICY_ENCRYPT | POLICY_AUTHENTICATE |
				  POLICY_TUNNEL | POLICY_RSASIG);
			conn->policy &= ~POLICY_SHUNT_MASK;
			conn->policy |= POLICY_SHUNT_DROP;
			break;

		case KS_REJECT:
			if (!conn->options_set[KBF_AUTHBY] ||
				conn->options[KBF_AUTHBY] != POLICY_AUTH_NEVER) {
					*perr = "connection type=drop must specify authby=never";
			}
			conn->policy &=
				~(POLICY_ENCRYPT | POLICY_AUTHENTICATE |
				  POLICY_TUNNEL | POLICY_RSASIG);
			conn->policy &= ~POLICY_SHUNT_MASK;
			conn->policy |= POLICY_SHUNT_REJECT;
			break;
		}
	}

	if (conn->options_set[KBF_FAILURESHUNT]) {
		conn->policy &= ~POLICY_FAIL_MASK;
		switch (conn->options[KBF_FAILURESHUNT]) {
		case KFS_FAIL_NONE:
			conn->policy |= POLICY_FAIL_NONE;
			break;
		case KFS_FAIL_PASS:
			conn->policy |= POLICY_FAIL_PASS;
			break;
		case KFS_FAIL_DROP:
			conn->policy |= POLICY_FAIL_DROP;
			break;
		case KFS_FAIL_REJECT:
			conn->policy |= POLICY_FAIL_REJECT;
			break;
		}
	}

	if (conn->options_set[KBF_NEGOTIATIONSHUNT]) {
		switch (conn->options[KBF_NEGOTIATIONSHUNT]) {
		case KNS_FAIL_PASS:
			conn->policy |= POLICY_NEGO_PASS;
			break;
		case KNS_FAIL_DROP:
			conn->policy &= ~POLICY_NEGO_PASS;
			break;
		}
	}

	KW_POLICY_FLAG(KBF_COMPRESS, POLICY_COMPRESS);
	KW_POLICY_FLAG(KBF_PFS, POLICY_PFS);

	/* reset authby= flags */
	if (conn->options_set[KBF_AUTHBY]) {

		conn->policy &= ~POLICY_ID_AUTH_MASK;
		conn->policy |= conn->options[KBF_AUTHBY];

	}

	KW_POLICY_NEGATIVE_FLAG(KBF_IKEPAD, POLICY_NO_IKEPAD);

	KW_POLICY_NEGATIVE_FLAG(KBF_REKEY, POLICY_DONT_REKEY);

	KW_POLICY_FLAG(KBF_AGGRMODE, POLICY_AGGRESSIVE);

	KW_POLICY_FLAG(KBF_MODECONFIGPULL, POLICY_MODECFG_PULL);

	KW_POLICY_FLAG(KBF_OVERLAPIP, POLICY_OVERLAPIP);

	KW_POLICY_FLAG(KBF_IKEv2_ALLOW_NARROWING,
		       POLICY_IKEV2_ALLOW_NARROWING);

	KW_POLICY_FLAG(KBF_IKEv2_PAM_AUTHORIZE,
		       POLICY_IKEV2_PAM_AUTHORIZE);

#	define str_to_conn(member, kscf) { \
		if (conn->strings_set[kscf]) \
			conn->member = clone_str(conn->strings[kscf], #kscf); \
	}

	str_to_conn(esp, KSCF_ESP);

#ifdef HAVE_LABELED_IPSEC
	str_to_conn(policy_label, KSCF_POLICY_LABEL);
	if (conn->policy_label != NULL)
		starter_log(LOG_LEVEL_DEBUG, "connection's policy label: %s",
				conn->policy_label);
#endif

	str_to_conn(ike, KSCF_IKE);
	str_to_conn(modecfg_dns1, KSCF_MODECFGDNS1);
	str_to_conn(modecfg_dns2, KSCF_MODECFGDNS2);
	str_to_conn(modecfg_domain, KSCF_MODECFGDOMAIN);
	str_to_conn(modecfg_banner, KSCF_MODECFGBANNER);

	/* mark-in= and mark-out= override mark= */
	str_to_conn(conn_mark_in, KSCF_CONN_MARK_BOTH);
	str_to_conn(conn_mark_out, KSCF_CONN_MARK_BOTH);
	str_to_conn(conn_mark_in, KSCF_CONN_MARK_IN);
	str_to_conn(conn_mark_out, KSCF_CONN_MARK_OUT);
	str_to_conn(vti_iface, KSCF_VTI_IFACE);

	str_to_conn(connalias, KSCF_CONNALIAS);

#	undef str_to_conn

	if (conn->options_set[KBF_PHASE2]) {
		conn->policy &= ~(POLICY_AUTHENTICATE | POLICY_ENCRYPT);
		conn->policy |= conn->options[KBF_PHASE2];
	}

	if (conn->options_set[KBF_IKEv2]) {
		lset_t pv2 = LEMPTY;

		switch (conn->options[KBF_IKEv2]) {
		case fo_never:
			pv2 = POLICY_IKEV1_ALLOW;
			break;

		case fo_permit:
			/* this is the default for now */
			pv2 = POLICY_IKEV1_ALLOW | POLICY_IKEV2_ALLOW;
			break;

		case fo_propose:
			pv2 = POLICY_IKEV1_ALLOW | POLICY_IKEV2_ALLOW | POLICY_IKEV2_PROPOSE;
			break;

		case fo_insist:
			pv2 =                      POLICY_IKEV2_ALLOW | POLICY_IKEV2_PROPOSE;
			break;
		}
		conn->policy = (conn->policy & ~POLICY_IKEV2_MASK) | pv2;
	}

	if (conn->options_set[KBF_ESN]) {
		conn->policy &= ~(POLICY_ESN_NO | POLICY_ESN_YES);

		switch (conn->options[KBF_ESN]) {
		case esn_yes:
			conn->policy |= POLICY_ESN_YES;
			break;

		case esn_no:
			/* this is the default for now */
			conn->policy |= POLICY_ESN_NO;
			break;

		case esn_either:
			conn->policy |= POLICY_ESN_NO | POLICY_ESN_YES;
			break;
		}
	}

	if (conn->options_set[KBF_IKE_FRAG]) {
		conn->policy &= ~(POLICY_IKE_FRAG_ALLOW | POLICY_IKE_FRAG_FORCE);

		switch (conn->options[KBF_IKE_FRAG]) {
		case ynf_no:
			break;

		case ynf_yes:
			/* this is the default */
			conn->policy |= POLICY_IKE_FRAG_ALLOW;
			break;

		case ynf_force:
			conn->policy |= POLICY_IKE_FRAG_ALLOW |
					POLICY_IKE_FRAG_FORCE;
			break;
		}
	}

	if (conn->options_set[KBF_SAREFTRACK]) {
		conn->policy &= ~(POLICY_SAREF_TRACK | POLICY_SAREF_TRACK_CONNTRACK);

		switch (conn->options[KBF_SAREFTRACK]) {
		case sat_yes:
			/* this is the default */
			conn->policy |= POLICY_SAREF_TRACK;
			break;

		case sat_conntrack:
			conn->policy |= POLICY_SAREF_TRACK |
					POLICY_SAREF_TRACK_CONNTRACK;
			break;

		case sat_no:
			break;
		}
	}

	/*
	 * some options are set as part of our default, but
	 * some make no sense for shunts, so remove those again
	 */
	if (NEVER_NEGOTIATE(conn->policy)) {
		/* remove IPsec related options */
		conn->policy &= ~(POLICY_PFS | POLICY_COMPRESS | POLICY_ESN_NO |
			POLICY_ESN_YES | POLICY_SAREF_TRACK |
			POLICY_SAREF_TRACK_CONNTRACK);
		/* remove IKE related options */
		conn->policy &= ~(POLICY_IKEV1_ALLOW | POLICY_IKEV2_ALLOW |
			POLICY_IKEV2_PROPOSE | POLICY_IKE_FRAG_ALLOW |
			POLICY_IKE_FRAG_FORCE);
	}


	err |= validate_end(
#ifdef DNSSEC
		dnsctx,
#endif
		conn, &conn->left, "left", resolvip, perr);
	err |= validate_end(
#ifdef DNSSEC
		dnsctx,
#endif
		conn, &conn->right, "right", resolvip, perr);
	/*
	 * TODO:
	 * verify both ends are using the same inet family, if one end
	 * is "%any" or "%defaultroute", then perhaps adjust it.
	 * ensource this for left,leftnexthop,right,rightnexthop
	 * Ideally, phase out connaddrfamily= which now wrongly assumes
	 * left,leftnextop,leftsubnet are the same inet family
	 * Currently, these tests are implicitely done, and wrongly
	 * in case of 6in4 and 4in6 tunnels
	 */

	if (conn->options_set[KBF_AUTO])
		conn->desired_state = conn->options[KBF_AUTO];

	return err;
}
Пример #4
0
static int
initiate_a_connection(struct connection *c
		      , void *arg)
{
    struct initiate_stuff *is = (struct initiate_stuff *)arg;
    int whackfd = is->whackfd;
    lset_t moredebug = is->moredebug;
    enum crypto_importance importance = is->importance;
    int success = 0;

    set_cur_connection(c);

    /* turn on any extra debugging asked for */
    c->extra_debugging |= moredebug;

    if (!oriented(*c))
    {
	loglog(RC_ORIENT, "We cannot identify ourselves with either end of this connection.");
    }
    else if (NEVER_NEGOTIATE(c->policy))
    {
	loglog(RC_INITSHUNT
	       , "cannot initiate an authby=never connection");
    }
    else if (c->kind != CK_PERMANENT)
    {
	if (isanyaddr(&c->spd.that.host_addr)) {
#ifdef DYNAMICDNS
	    if (c->dnshostname != NULL) {
		loglog(RC_NOPEERIP, "cannot initiate connection without resolved dynamic peer IP address, will keep retrying");
		success = 1;
		c->policy |= POLICY_UP;
	    } else
#endif
		loglog(RC_NOPEERIP, "cannot initiate connection without knowing peer IP address (kind=%s)"
		       , enum_show(&connection_kind_names, c->kind));
	} else
	    loglog(RC_WILDCARD, "cannot initiate connection with ID wildcards (kind=%s)"
		   , enum_show(&connection_kind_names, c->kind));
    }
    else
    {
	/* We will only request an IPsec SA if policy isn't empty
	 * (ignoring Main Mode items).
	 * This is a fudge, but not yet important.
	 * If we are to proceed asynchronously, whackfd will be NULL_FD.
	 */
	c->policy |= POLICY_UP;

	if(c->policy & (POLICY_ENCRYPT|POLICY_AUTHENTICATE)) {
	    struct alg_info_esp *alg = c->alg_info_esp;
	    struct db_sa *phase2_sa = kernel_alg_makedb(c->policy, alg, TRUE);

	    if(alg != NULL && phase2_sa == NULL) {
		whack_log(RC_NOALGO, "can not initiate: no acceptable kernel algorithms loaded");
		reset_cur_connection();
		close_any(is->whackfd);
		return 0;
	    }
	    free_sa(phase2_sa);
	}

	{
	    whackfd = dup(whackfd);
	    ipsecdoi_initiate(whackfd, c, c->policy, 1
			      , SOS_NOBODY, importance
                              , NULL_POLICY
			     );
	    success = 1;
	}
    }
    reset_cur_connection();

    return success;
}