Beispiel #1
0
void
initiate_connection(const char *name, int whackfd
		    , lset_t moredebug
		    , enum crypto_importance importance)
{
    struct initiate_stuff is;
    struct connection *c = con_by_name(name, FALSE);
    int count;

    is.whackfd   = whackfd;
    is.moredebug = moredebug;
    is.importance= importance;

    if (c != NULL)
    {
	initiate_a_connection(c, &is);
	close_any(is.whackfd);
	return;
    }

    loglog(RC_COMMENT, "initiating all conns with alias='%s'\n", name);
    count = foreach_connection_by_alias(name, initiate_a_connection, &is);

    if(count == 0) {
	whack_log(RC_UNKNOWN_NAME
		  , "no connection named \"%s\"", name);
    }

    close_any(is.whackfd);
}
Beispiel #2
0
static void
key_add_continue(struct adns_continuation *ac, err_t ugh)
{
    struct key_add_continuation *kc = (void *) ac;

    whack_log_fd = kc->whack_fd;
    if (ugh != NULL)
    {
	key_add_ugh(&ac->id, ugh);
    }
    else
    {
	remember_public_keys(&keys_from_dns);
    }
    close_any(whack_log_fd);
}
Beispiel #3
0
/* Free the Whack socket file descriptor.
 * This has the side effect of telling Whack that we're done.
 */
void
release_whack(struct state *st)
{
    close_any(st->st_whack_sock);
}
Beispiel #4
0
/* Handle a kernel request. Supposedly, there's a message in
 * the kernelsock socket.
 */
void
whack_handle(int whackctlfd)
{
    struct whack_message msg;
    struct sockaddr_un whackaddr;
    int whackaddrlen = sizeof(whackaddr);
    int whackfd = accept(whackctlfd, (struct sockaddr *)&whackaddr, &whackaddrlen);
    ssize_t n;

    if (whackfd < 0)
    {
	log_errno((e, "accept() failed in whack_handle()"));
	return;
    }
    n = read(whackfd, &msg, sizeof(msg));
    if (n == -1)
    {
	log_errno((e, "read() failed in whack_handle()"));
	close(whackfd);
	return;
    }

    whack_log_fd = whackfd;

    /* sanity check message */
    {
	err_t ugh = NULL;

	next_str = msg.string;
	str_roof = (char *)&msg + n;

	if (next_str > str_roof)
	{
	    ugh = builddiag("truncated message from whack: got %d bytes; expected %d.  Message ignored."
		, n, (int) sizeof(msg));
	}
	else if (msg.magic != WHACK_MAGIC)
	{
	    ugh = builddiag("message from whack has bad magic %d; should be %d; probably wrong version.  Message ignored"
		, msg.magic, WHACK_MAGIC);
	}
	else if (!unpack_str(&msg.name)		/* string 1 */
	|| !unpack_str(&msg.left.id)		/* string 2 */
	|| !unpack_str(&msg.left.cert)		/* string 3 */
	|| !unpack_str(&msg.left.updown)	/* string 4 */
#ifdef VIRTUAL_IP
	|| !unpack_str(&msg.left.virt)
#endif
	|| !unpack_str(&msg.right.id)		/* string 5 */
	|| !unpack_str(&msg.right.cert)		/* string 6 */	
	|| !unpack_str(&msg.right.updown)	/* string 7 */
#ifdef VIRTUAL_IP
	|| !unpack_str(&msg.right.virt)
#endif
	|| !unpack_str(&msg.keyid)		/* string 8 */
	|| !unpack_str(&msg.ike)		/* string 9 */
	|| !unpack_str(&msg.esp)		/* string 10 */	
	|| !unpack_str(&msg.dnshostname)	/* string 11 */
	|| str_roof - next_str != (ptrdiff_t)msg.keyval.len)	/* check chunk */
	{
	    ugh = "message from whack contains bad string";
	}
	else
	{
	    msg.keyval.ptr = next_str;	/* grab chunk */
	}

	if (ugh != NULL)
	{
	    loglog(RC_BADWHACKMESSAGE, "%s", ugh);
	    whack_log_fd = NULL_FD;
	    close(whackfd);
	    return;
	}
    }

    if (msg.whack_options)
    {
#ifdef DEBUG
	if (msg.name == NULL)
	{
	    /* we do a two-step so that if either old or new would
	     * cause the message to print, it will be printed.
	     */
	    cur_debugging |= msg.debugging;
	    DBG(DBG_CONTROL
		, DBG_log("base debugging = %s"
		    , bitnamesof(debug_bit_names, msg.debugging)));
	    cur_debugging = base_debugging = msg.debugging;
	}
	else if (!msg.whack_connection)
	{
	    struct connection *c = con_by_name(msg.name, TRUE);

	    if (c != NULL)
	    {
		c->extra_debugging = msg.debugging;
		DBG(DBG_CONTROL
		    , DBG_log("\"%s\" extra_debugging = %s"
			, c->name
			, bitnamesof(debug_bit_names, c->extra_debugging)));
	    }
	}
#endif
    }

    /* Deleting combined with adding a connection works as replace.
     * To make this more useful, in only this combination,
     * delete will silently ignore the lack of the connection.
     */
    if (msg.whack_delete)
    {
	struct connection *c = con_by_name(msg.name, !msg.whack_connection);

	/* note: this is a "while" because road warrior
	 * leads to multiple connections with the same name.
	 */
	for (; c != NULL; c = con_by_name(msg.name, FALSE))
	    delete_connection(c);
    }

    if (msg.whack_deletestate)
    {
	struct state *st = state_with_serialno(msg.whack_deletestateno);

	if (st == NULL)
	{
	    loglog(RC_UNKNOWN_NAME, "no state #%lu to delete"
		, msg.whack_deletestateno);
	}
	else
	{
	    delete_state(st);
	}
    }

    if (msg.whack_connection)
	add_connection(&msg);

    /* process "listen" before any operation that could require it */
    if (msg.whack_listen)
    {
	log("listening for IKE messages");
	listening = TRUE;
	find_ifaces();
	load_preshared_secrets();
    }
    if (msg.whack_unlisten)
    {
	log("no longer listening for IKE messages");
	listening = FALSE;
    }

    if (msg.whack_reread & REREAD_SECRETS)
    {
	load_preshared_secrets();
    }

   if (msg.whack_reread & REREAD_MYCERT)
    {
	load_mycert();
    }

   if (msg.whack_reread & REREAD_CACERTS)
    {
	load_cacerts();
    }

   if (msg.whack_reread & REREAD_CRLS)
    {
	load_crls();
    }

   if (msg.whack_list & LIST_PUBKEYS)
    {
	list_public_keys(msg.whack_utc);
    }

    if (msg.whack_list & LIST_CERTS)
    {
	list_certs(msg.whack_utc);
    }

    if (msg.whack_list & LIST_CACERTS)
    {
	list_cacerts(msg.whack_utc);
    }

    if (msg.whack_list & LIST_CRLS)
    {
	list_crls(msg.whack_utc);
    }

    if (msg.whack_key)
    {
	/* add a public key */
	struct id keyid;
	err_t ugh = atoid(msg.keyid, &keyid);

	if (ugh != NULL)
	{
	    loglog(RC_BADID, "bad --keyid \"%s\": %s", msg.keyid, ugh);
	}
	else
	{
	    if (!msg.whack_addkey)
		delete_public_keys(&keyid, msg.pubkey_alg);

	    if (msg.keyval.len == 0)
	    {
		struct key_add_continuation *kc
		    = alloc_thing(struct key_add_continuation
			, "key add continuation");
		int wfd = dup_any(whackfd);

		kc->whack_fd = wfd;
		ugh = start_adns_query(&keyid
		    , NULL
		    , T_KEY
		    , key_add_continue
		    , &kc->ac);

		if (ugh != NULL)
		{
		    key_add_ugh(&keyid, ugh);
		    close_any(wfd);
		}
	    }
	    else
	    {
		ugh = add_public_key(&keyid, DAL_LOCAL, msg.pubkey_alg
		    , &msg.keyval, &pubkeys);
		if (ugh != NULL)
		    loglog(RC_LOG_SERIOUS, "%s", ugh);
	    }
	}
    }
Beispiel #5
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;
}