summaryrefslogtreecommitdiff
path: root/programs/pluto/rcv_info.c
diff options
context:
space:
mode:
Diffstat (limited to 'programs/pluto/rcv_info.c')
-rw-r--r--programs/pluto/rcv_info.c308
1 files changed, 308 insertions, 0 deletions
diff --git a/programs/pluto/rcv_info.c b/programs/pluto/rcv_info.c
new file mode 100644
index 000000000..1f6127830
--- /dev/null
+++ b/programs/pluto/rcv_info.c
@@ -0,0 +1,308 @@
+/* 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);
+}