Files
strongswan-ext/programs/pluto/rcv_info.c
T
Martin Willi 997358a6c4 - import of strongswan-2.7.0
- applied patch for charon
2006-04-28 07:14:48 +00:00

309 lines
7.7 KiB
C

/* info/policy communicating routines
* Copyright (C) 2003 Michael Richardson <mcr@freeswan.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* RCSID $Id: rcv_info.c,v 1.2 2004/04/01 18:44:38 as Exp $
*/
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <resolv.h>
#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */
#include <sys/queue.h>
#include <freeswan.h>
#include "constants.h"
#include "defs.h"
#include "id.h"
#include "connections.h"
#include "foodgroups.h"
#include "whack.h" /* needs connections.h */
#include "packet.h"
#include "demux.h" /* needs packet.h */
#include "state.h"
#include "ipsec_doi.h" /* needs demux.h and state.h */
#include "kernel.h"
#include "rcv_whack.h"
#include "log.h"
#include "keys.h"
#include "adns.h" /* needs <resolv.h> */
#include "dnskey.h" /* needs keys.h and adns.h */
#include "server.h"
#include "freeswan/ipsec_policy.h"
#include "rcv_info.h"
/* global */
int info_fd = -1;
static void
info_lookuphostpair(struct ipsec_policy_cmd_query *ipcq)
{
struct connection *c;
struct state *p1st, *p2st;
/* default result: no crypto */
ipcq->strength = IPSEC_PRIVACY_NONE;
ipcq->bandwidth = IPSEC_QOS_WIRESPEED;
ipcq->credential_count = 0;
#ifdef DEBUG
{
char sstr[ADDRTOT_BUF], dstr[ADDRTOT_BUF];
addrtot(&ipcq->query_local, 0, sstr, sizeof(sstr));
addrtot(&ipcq->query_remote, 0, dstr, sizeof(dstr));
DBG_log("info request for %s -> %s", sstr, dstr);
}
#endif
/* okay, look up what connection handles this ip pair */
c = find_connection_for_clients(NULL,
&ipcq->query_local,
&ipcq->query_remote);
if (c == NULL)
{
/* try reversing it */
c = find_connection_for_clients(NULL,
&ipcq->query_remote,
&ipcq->query_local);
if (c != NULL)
{
ip_address tmp;
tmp = ipcq->query_local;
ipcq->query_local = ipcq->query_remote;
ipcq->query_remote = tmp;
}
}
if (c == NULL)
{
#ifdef DEBUG
DBG_log("no connection found");
#endif
return; /* no crypto */
}
if (c->newest_ipsec_sa == SOS_NOBODY)
{
ip_subnet us, them;
DBG_log("connection %s found, no ipsec state, looking again", c->name);
addrtosubnet(&ipcq->query_local, &us);
addrtosubnet(&ipcq->query_remote, &them);
c = find_client_connection(c, &us, &them);
if (c == NULL)
return; /* no crypto */
}
DBG_log("connection %s[%ld] with state %u"
, c->name, c->instance_serial
, (unsigned int)c->newest_ipsec_sa);
if (c->newest_ipsec_sa == SOS_NOBODY)
return; /* no crypto */
/* we found a connection, try to lookup the state */
p2st = state_with_serialno(c->newest_ipsec_sa);
p1st = find_phase1_state(c, ISAKMP_SA_ESTABLISHED_STATES);
if (p1st == NULL || p2st == NULL)
{
DBG_log("connection %s[%ld] has missing states %s %s"
, c->name, c->instance_serial
, (p1st ? "phase1" : "")
, (p2st ? "phase1" : ""));
return; /* no crypto */
}
/* if we have AH present, then record minimal info */
if (p2st->st_ah.present)
{
ipcq->strength = IPSEC_PRIVACY_INTEGRAL;
ipcq->auth_detail = p2st->st_esp.attrs.auth;
}
if (p2st->st_esp.present)
{
/*
* XXX-mcr Please do not shout at me about relative strengths
* here. I'm not a cryptographer. I just diddle bits.
*/
switch (p2st->st_esp.attrs.transid)
{
case ESP_NULL:
/* actually, do not change it if we set it from AH */
break;
case ESP_DES:
case ESP_DES_IV64:
case ESP_DES_IV32:
case ESP_RC4:
ipcq->strength = IPSEC_PRIVACY_ROT13;
break;
case ESP_RC5:
case ESP_IDEA:
case ESP_CAST:
case ESP_BLOWFISH:
case ESP_3DES:
ipcq->strength = IPSEC_PRIVACY_PRIVATE;
ipcq->bandwidth = IPSEC_QOS_VOIP;
break;
case ESP_3IDEA:
ipcq->strength = IPSEC_PRIVACY_STRONG;
ipcq->bandwidth = IPSEC_QOS_INTERACTIVE;
break;
case ESP_AES:
ipcq->strength = IPSEC_PRIVACY_STRONG;
ipcq->bandwidth = IPSEC_QOS_FTP;
break;
}
ipcq->esp_detail = p2st->st_esp.attrs.transid;
}
if (p2st->st_ipcomp.present)
ipcq->comp_detail = p2st->st_esp.attrs.transid;
/* now! the credentails that were used */
/* for the moment we only have 1 credential, the DNS name,
* because the DNS servers do not return the chain of SIGs yet
*/
if(!c->spd.this.key_from_DNS_on_demand)
{
/* the key didn't come from the DNS in some way,
* so it must have been loaded locally.
*/
ipcq->credential_count = 1;
ipcq->credentials[0].ii_type = c->spd.this.id.kind;
ipcq->credentials[0].ii_format = CERT_RAW_RSA;
}
#if 0
switch (c->spd.id.kind)
{
case ID_IPV4_ADDR:
}
if (c->gw_info == NULL)
{
plog("rcv_info: connection %s had NULL gw_info.", c->name);
return
}
#endif
ipcq->credential_count = 1;
/* pull credentials out of gw_info */
switch (p1st->st_peer_pubkey->dns_auth_level)
{
case DAL_UNSIGNED:
case DAL_NOTSEC:
/* these seem to be the same for this purpose */
ipcq->credentials[0].ii_type = p1st->st_peer_pubkey->id.kind;
ipcq->credentials[0].ii_type = CERT_NONE;
idtoa(&p1st->st_peer_pubkey->id
, ipcq->credentials[0].ii_credential.ipsec_dns_signed.fqdn
, sizeof(ipcq->credentials[0].ii_credential.ipsec_dns_signed.fqdn));
break;
case DAL_SIGNED:
ipcq->credentials[0].ii_type = p1st->st_peer_pubkey->id.kind;
ipcq->credentials[0].ii_format = CERT_DNS_SIGNED_KEY;
idtoa(&p1st->st_peer_pubkey->id
, ipcq->credentials[0].ii_credential.ipsec_dns_signed.fqdn
, sizeof(ipcq->credentials[0].ii_credential.ipsec_dns_signed.fqdn));
if (p1st->st_peer_pubkey->dns_sig != NULL)
{
strncat(ipcq->credentials[0].ii_credential.ipsec_dns_signed.dns_sig
, p1st->st_peer_pubkey->dns_sig
, sizeof(ipcq->credentials[0].ii_credential.ipsec_dns_signed.dns_sig));
}
break;
case DAL_LOCAL:
ipcq->credentials[0].ii_type = p1st->st_peer_pubkey->id.kind;
ipcq->credentials[0].ii_format = CERT_RAW_RSA;
idtoa(&p1st->st_peer_pubkey->id
, ipcq->credentials[0].ii_credential.ipsec_raw_key.id_name
, sizeof(ipcq->credentials[0].ii_credential.ipsec_raw_key.id_name));
break;
}
}
/*
* Handle an info/policy request.
*
* For now, we close the socket after answering the request.
*
*/
void
info_handle(int infoctlfd)
{
struct sockaddr_un info_client_addr;
int info_addr_len = sizeof(info_client_addr);
/* Note: actual value in n should fit in int. To print, cast to int. */
int infofd;
err_t err;
struct ipsec_policy_cmd_query ipcq;
infofd = accept(infoctlfd, (struct sockaddr *)&info_client_addr
, &info_addr_len);
if (infofd < 0)
{
log_errno((e, "accept() failed in info_handle()"));
return;
}
err = ipsec_policy_readmsg(infofd, (unsigned char *)&ipcq, sizeof(ipcq));
if (err != NULL)
{
log_errno((e, "readmsg said: %s", err));
close(infofd);
return;
}
switch (ipcq.head.ipm_msg_type)
{
case IPSEC_CMD_QUERY_HOSTPAIR:
info_lookuphostpair(&ipcq);
write(infofd, &ipcq, ipcq.head.ipm_msg_len);
break;
default:
plog("got unimplemented msg type: %d", ipcq.head.ipm_msg_type);
break;
}
/* for now, close the socket */
close(infofd);
}