2 protocol_auth.c -- handle the meta-protocol, authentication
3 Copyright (C) 1999-2003 Ivo Timmermans <ivo@o2w.nl>,
4 2000-2003 Guus Sliepen <guus@sliepen.eu.org>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 $Id: protocol_auth.c,v 1.1.4.34 2003/12/22 11:04:16 guus Exp $
25 #include <gnutls/gnutls.h>
26 #include <gnutls/x509.h>
30 #include "connection.h"
41 bool send_ack(connection_t *c)
43 char buf[MAX_STRING_SIZE];
46 const gnutls_datum *cert_list;
47 int cert_list_size = 0, result;
50 cert_list = gnutls_certificate_get_peers(c->session, &cert_list_size);
52 if (!cert_list || !cert_list_size) {
53 logger(LOG_ERR, _("No certificates from %s"), c->hostname);
58 gnutls_x509_crt_init(&cert);
59 result = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER)
60 ?: gnutls_x509_crt_get_dn(cert, buf, &len);
63 logger(LOG_ERR, _("Error importing certificate from %s: %s"), c->hostname, gnutls_strerror(errno));
64 gnutls_x509_crt_deinit(cert);
68 name = strstr(buf, "CN=");
70 logger(LOG_ERR, _("No name in certificate from %s"), c->hostname);
71 gnutls_x509_crt_deinit(cert);
75 for(p = name; *p && *p != ','; p++);
79 logger(LOG_ERR, _("Invalid name from %s"), c->hostname);
84 if(strcmp(c->name, name)) {
85 logger(LOG_ERR, _("Peer %s is %s instead of %s"), c->hostname, name, c->hostname);
89 c->name = xstrdup(name);
92 result = gnutls_certificate_verify_peers(c->session);
95 if(result & GNUTLS_CERT_INVALID)
96 logger(LOG_ERR, _("Certificate from %s (%s) invalid"), c->name, c->hostname);
97 if(result & GNUTLS_CERT_REVOKED)
98 logger(LOG_ERR, _("Certificate from %s (%s) revoked"), c->name, c->hostname);
99 if(result & GNUTLS_CERT_SIGNER_NOT_FOUND)
100 logger(LOG_ERR, _("Certificate from %s (%s) has no known signer"), c->name, c->hostname);
101 if(result & GNUTLS_CERT_SIGNER_NOT_CA)
102 logger(LOG_ERR, _("Certificate from %s (%s) has no CA as signer"), c->name, c->hostname);
105 if(!c->config_tree) {
106 init_configuration(&c->config_tree);
108 if(!read_connection_config(c)) {
109 logger(LOG_ERR, _("Peer %s had unknown identity (%s)"), c->hostname,
115 /* ACK message contains rest of the information the other end needs
116 to create node_t and edge_t structures. */
123 /* Estimate weight */
125 gettimeofday(&now, NULL);
126 c->estimated_weight = (now.tv_sec - c->start.tv_sec) * 1000 + (now.tv_usec - c->start.tv_usec) / 1000;
128 /* Check some options */
130 if((get_config_bool(lookup_config(c->config_tree, "IndirectData"), &choice) && choice) || myself->options & OPTION_INDIRECT)
131 c->options |= OPTION_INDIRECT;
133 if((get_config_bool(lookup_config(c->config_tree, "TCPOnly"), &choice) && choice) || myself->options & OPTION_TCPONLY)
134 c->options |= OPTION_TCPONLY | OPTION_INDIRECT;
136 if((get_config_bool(lookup_config(c->config_tree, "PMTUDiscovery"), &choice) && choice) || myself->options & OPTION_PMTU_DISCOVERY)
137 c->options |= OPTION_PMTU_DISCOVERY;
139 get_config_int(lookup_config(c->config_tree, "Weight"), &c->estimated_weight);
141 return send_request(c, "%d %s %d %lx", ACK, myport, c->estimated_weight, c->options);
144 static void send_everything(connection_t *c)
146 avl_node_t *node, *node2;
151 /* Send all known subnets and edges */
154 for(node = myself->subnet_tree->head; node; node = node->next) {
156 send_add_subnet(c, s);
162 for(node = node_tree->head; node; node = node->next) {
165 for(node2 = n->subnet_tree->head; node2; node2 = node2->next) {
167 send_add_subnet(c, s);
170 for(node2 = n->edge_tree->head; node2; node2 = node2->next) {
177 bool ack_h(connection_t *c)
179 char hisport[MAX_STRING_SIZE];
180 char *hisaddress, *dummy;
187 if(sscanf(c->buffer, "%*d " MAX_STRING " %d %lx", hisport, &weight, &options) != 3) {
188 logger(LOG_ERR, _("Got bad %s from %s (%s)"), "ACK", c->name,
193 /* Check if we already have a node_t for him */
195 n = lookup_node(c->name);
199 n->name = xstrdup(c->name);
203 /* Oh dear, we already have a connection to this node. */
204 ifdebug(CONNECTIONS) logger(LOG_DEBUG, _("Established a second connection with %s (%s), closing old connection"),
205 n->name, n->hostname);
206 terminate_connection(n->connection, false);
207 /* Run graph algorithm to purge key and make sure up/down scripts are rerun with new IP addresses and stuff */
214 c->options |= options;
216 if(get_config_int(lookup_config(c->config_tree, "PMTU"), &mtu) && mtu < n->mtu)
219 if(get_config_int(lookup_config(myself->connection->config_tree, "PMTU"), &mtu) && mtu < n->mtu)
222 /* Activate this connection */
224 c->allow_request = ALL;
225 c->status.active = true;
227 ifdebug(CONNECTIONS) logger(LOG_NOTICE, _("Connection with %s (%s) activated"), c->name,
230 /* Send him everything we know */
234 /* Create an edge_t for this connection */
236 c->edge = new_edge();
238 c->edge->from = myself;
240 sockaddr2str(&c->address, &hisaddress, &dummy);
241 c->edge->address = str2sockaddr(hisaddress, hisport);
244 c->edge->weight = (weight + c->estimated_weight) / 2;
245 c->edge->connection = c;
246 c->edge->options = c->options;
250 /* Notify everyone of the new edge */
253 send_add_edge(c, c->edge);
255 send_add_edge(broadcast, c->edge);
257 /* Run MST and SSSP algorithms */