/* 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; }
/* 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; }
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; }
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; }