- Enforce correct order of authentication requests
[oweals/tinc.git] / src / protocol.c
1 /*
2     protocol.c -- handle the meta-protocol
3     Copyright (C) 1999,2000 Ivo Timmermans <itimmermans@bigfoot.com>,
4                        2000 Guus Sliepen <guus@sliepen.warande.net>
5
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.
10
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.
15
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.
19
20     $Id: protocol.c,v 1.28.4.49 2000/10/29 01:08:09 guus Exp $
21 */
22
23 #include "config.h"
24
25 #include <sys/types.h>
26
27 #include <stdlib.h>
28 #include <string.h>
29 #include <syslog.h>
30 #include <sys/socket.h>
31 #include <unistd.h>
32 #include <stdio.h>
33
34 #include <utils.h>
35 #include <xalloc.h>
36
37 #include <netinet/in.h>
38
39 #include <openssl/sha.h>
40 #include <openssl/rand.h>
41
42 #include "conf.h"
43 #include "encr.h"
44 #include "net.h"
45 #include "netutl.h"
46 #include "protocol.h"
47 #include "meta.h"
48 #include "connlist.h"
49
50 #include "system.h"
51
52 int check_id(char *id)
53 {
54   int i;
55
56   for (i = 0; i < strlen(id); i++)
57     if(!isalnum(id[i]) && id[i] != '_')
58       return -1;
59           
60   return 0;
61 }
62
63 /* Generic request routines - takes care of logging and error detection as well */
64
65 int send_request(conn_list_t *cl, const char *format, ...)
66 {
67   va_list args;
68   char buffer[MAXBUFSIZE];
69   int len, request;
70
71 cp
72   /* Use vsnprintf instead of vasprintf: faster, no memory fragmentation, cleanup is automatic,
73      and there is a limit on the input buffer anyway */
74
75   va_start(args, format);
76   len = vsnprintf(buffer, MAXBUFSIZE, format, args);
77   request = va_arg(args, int);
78   va_end(args);
79
80   if(len < 0 || len > MAXBUFSIZE-1)
81     {
82       syslog(LOG_ERR, _("Output buffer overflow while sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
83       return -1;
84     }
85
86   len++;
87
88   if(debug_lvl >= DEBUG_PROTOCOL)
89     syslog(LOG_DEBUG, _("Sending %s to %s (%s)"), request_name[request], cl->name, cl->hostname);
90
91 cp
92   return send_meta(cl, buffer, len);
93 }
94
95 int receive_request(conn_list_t *cl)
96 {
97   int request;
98 cp  
99   if(sscanf(cl->buffer, "%d", &request) == 1)
100     {
101       if((request < 0) || (request > 255) || (request_handlers[request] == NULL))
102         {
103           syslog(LOG_ERR, _("Unknown request from %s (%s)"),
104                  cl->name, cl->hostname);
105           return -1;
106         }
107       else
108         {
109           if(debug_lvl >= DEBUG_PROTOCOL)
110             syslog(LOG_DEBUG, _("Got %s from %s (%s)"),
111                    request_name[request], cl->name, cl->hostname);
112         }
113
114       if((cl->allow_request != ALL) && (cl->allow_request != request))
115         {
116           syslog(LOG_ERR, _("Unauthorized request from %s (%s)"), cl->name, cl->hostname);
117           return -1;
118         }
119
120       if(request_handlers[request](cl))
121         /* Something went wrong. Probably scriptkiddies. Terminate. */
122         {
123           syslog(LOG_ERR, _("Error while processing %s from %s (%s)"),
124                  request_name[request], cl->name, cl->hostname);
125           return -1;
126         }
127     }
128   else
129     {
130       syslog(LOG_ERR, _("Bogus data received from %s (%s)"),
131              cl->name, cl->hostname);
132       return -1;
133     }
134 cp
135   return 0;
136 }
137
138 /* Connection protocol:
139
140    Client               Server
141    send_id(u)
142                         send_challenge(R)
143    send_chal_reply(H)
144                         send_id(u)
145    send_challenge(R)
146                         send_chal_reply(H)
147    ---------------------------------------
148    Any negotations about the meta protocol
149    encryption go here(u).
150    ---------------------------------------
151    send_ack(u)
152                         send_ack(u)
153    ---------------------------------------
154    Other requests(E)...
155
156    (u) Unencrypted,
157    (R) RSA,
158    (H) SHA1,
159    (E) Encrypted with symmetric cipher.
160
161    Part of the challenge is directly used to set the symmetric cipher key and the initial vector.
162    Since a man-in-the-middle cannot decrypt the RSA challenges, this means that he cannot get or
163    forge the key for the symmetric cipher.
164 */
165
166 int send_id(conn_list_t *cl)
167 {
168 cp
169   cl->allow_request = CHALLENGE;
170 cp
171   return send_request(cl, "%d %s %d %lx %hd", ID, myself->name, myself->protocol_version, myself->options, myself->port);
172 }
173
174 int id_h(conn_list_t *cl)
175 {
176   conn_list_t *old;
177   config_t *cfg;
178 cp
179   if(sscanf(cl->buffer, "%*d %as %d %lx %hd", &cl->name, &cl->protocol_version, &cl->options, &cl->port) != 4)
180     {
181        syslog(LOG_ERR, _("Got bad ID from %s"), cl->hostname);
182        return -1;
183     }
184
185   /* Check if version matches */
186
187   if(cl->protocol_version != myself->protocol_version)
188     {
189       syslog(LOG_ERR, _("Peer %s (%s) uses incompatible version %d"),
190              cl->name, cl->hostname, cl->protocol_version);
191       return -1;
192     }
193
194   /* Check if identity is a valid name */
195
196   if(check_id(cl->name))
197     {
198       syslog(LOG_ERR, _("Peer %s uses invalid identity name"), cl->hostname);
199       return -1;
200     }
201
202   /* Load information about peer */
203 cp
204   if(read_host_config(cl))
205     {
206       syslog(LOG_ERR, _("Peer %s had unknown identity (%s)"), cl->hostname, cl->name);
207       return -1;
208     }
209
210   /* First check if the host we connected to is already in our
211      connection list. If so, we are probably making a loop, which
212      is not desirable.
213    */
214 cp
215   if(cl->status.outgoing)
216     {
217       if((old = lookup_id(cl->name)))
218         {
219           if(debug_lvl >= DEBUG_CONNECTIONS)
220             syslog(LOG_NOTICE, _("Uplink %s (%s) is already in our connection list"), cl->name, cl->hostname);
221           cl->status.outgoing = 0;
222           old->status.outgoing = 1;
223           terminate_connection(cl);
224           return 0;
225         }
226     }
227 cp    
228   if((cfg = get_config_val(cl->config, publickey)))
229     {
230       cl->rsa_key = RSA_new();
231       BN_hex2bn(&cl->rsa_key->n, cfg->data.ptr);
232       BN_hex2bn(&cl->rsa_key->e, "FFFF");
233     }
234   else
235     {
236       syslog(LOG_ERR, _("No public key known for %s (%s)"), cl->name, cl->hostname);
237       return -1;
238     }
239 cp
240   return send_challenge(cl);
241 }
242
243 int send_challenge(conn_list_t *cl)
244 {
245   char *buffer;
246   int len, x;
247 cp
248   len = RSA_size(cl->rsa_key);
249
250   /* Allocate buffers for the challenge */
251
252   buffer = xmalloc(len*2+1);
253
254   if(cl->hischallenge)
255     free(cl->hischallenge);
256     
257   cl->hischallenge = xmalloc(len);
258 cp
259   /* Seed the PRNG with urandom (can't afford to block) */
260
261   RAND_load_file("/dev/urandom", 1024);
262
263   /* Copy random data to the buffer */
264
265   RAND_bytes(cl->hischallenge, len);
266
267   cl->hischallenge[0] &= 0x7F;  /* Somehow if the first byte is more than 0xD0 or something like that, decryption fails... */
268
269   if(debug_lvl >= DEBUG_SCARY_THINGS)
270     {
271       bin2hex(cl->hischallenge, buffer, len);
272       buffer[len*2] = '\0';
273       syslog(LOG_DEBUG, _("Generated random challenge (unencrypted): %s"), buffer);
274     }
275
276   /* Encrypt the random data */
277   
278   if(RSA_public_encrypt(len, cl->hischallenge, buffer, cl->rsa_key, RSA_NO_PADDING) != len)     /* NO_PADDING because the message size equals the RSA key size and it is totally random */
279     {
280       syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
281       free(buffer);
282       return -1;
283     }
284 cp
285   /* Convert the encrypted random data to a hexadecimal formatted string */
286
287   bin2hex(buffer, buffer, len);
288   buffer[len*2] = '\0';
289
290   /* Send the challenge */
291
292   cl->allow_request = CHAL_REPLY;
293   x = send_request(cl, "%d %s", CHALLENGE, buffer);
294   free(buffer);
295 cp
296   return x;
297 }
298
299 int challenge_h(conn_list_t *cl)
300 {
301   char *buffer;
302   int len;
303 cp
304   if(sscanf(cl->buffer, "%*d %as", &buffer) != 1)
305     {
306        syslog(LOG_ERR, _("Got bad CHALLENGE from %s (%s)"), cl->name, cl->hostname);
307        return -1;
308     }
309
310   len = RSA_size(myself->rsa_key);
311
312   /* Check if the length of the challenge is all right */
313
314   if(strlen(buffer) != len*2)
315     {
316       syslog(LOG_ERR, _("Intruder: wrong challenge length from %s (%s)"), cl->name, cl->hostname);
317       free(buffer);
318       return -1;
319     }
320
321   /* Allocate buffers for the challenge */
322
323   if(!cl->mychallenge)
324     cl->mychallenge = xmalloc(len);
325
326   /* Convert the challenge from hexadecimal back to binary */
327
328   hex2bin(buffer,buffer,len);
329
330   /* Decrypt the challenge */
331   
332   if(RSA_private_decrypt(len, buffer, cl->mychallenge, myself->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
333     {
334       syslog(LOG_ERR, _("Error during encryption of challenge for %s (%s)"), cl->name, cl->hostname);
335       free(buffer);
336       return -1;
337     }
338
339   if(debug_lvl >= DEBUG_SCARY_THINGS)
340     {
341       bin2hex(cl->mychallenge, buffer, len);
342       buffer[len*2] = '\0';
343       syslog(LOG_DEBUG, _("Received random challenge (unencrypted): %s"), buffer);
344     }
345
346   free(buffer);
347     
348   /* Rest is done by send_chal_reply() */
349 cp
350   return send_chal_reply(cl);
351 }
352
353 int send_chal_reply(conn_list_t *cl)
354 {
355   char hash[SHA_DIGEST_LENGTH*2+1];
356 cp
357   if(!cl->mychallenge)
358     {
359       syslog(LOG_ERR, _("Trying to send CHAL_REPLY to %s (%s) without a valid CHALLENGE"), cl->name, cl->hostname);
360       return -1;
361     }
362      
363   /* Calculate the hash from the challenge we received */
364
365   SHA1(cl->mychallenge, RSA_size(myself->rsa_key), hash);
366
367   /* Convert the hash to a hexadecimal formatted string */
368
369   bin2hex(hash,hash,SHA_DIGEST_LENGTH);
370   hash[SHA_DIGEST_LENGTH*2] = '\0';
371
372   /* Send the reply */
373
374   if(cl->status.outgoing)
375     cl->allow_request = ID;
376   else
377     cl->allow_request = ACK;
378
379 cp
380   return send_request(cl, "%d %s", CHAL_REPLY, hash);
381 }
382
383 int chal_reply_h(conn_list_t *cl)
384 {
385   char *hishash;
386   char myhash[SHA_DIGEST_LENGTH];
387 cp
388   if(sscanf(cl->buffer, "%*d %as", &hishash) != 1)
389     {
390        syslog(LOG_ERR, _("Got bad CHAL_REPLY from %s (%s)"), cl->name, cl->hostname);
391        free(hishash);
392        return -1;
393     }
394
395   /* Check if the length of the hash is all right */
396
397   if(strlen(hishash) != SHA_DIGEST_LENGTH*2)
398     {
399       syslog(LOG_ERR, _("Intruder: wrong challenge reply length from %s (%s)"), cl->name, cl->hostname);
400       free(hishash);
401       return -1;
402     }
403
404   /* Convert the hash to binary format */
405
406   hex2bin(hishash, hishash, SHA_DIGEST_LENGTH);
407
408   /* Calculate the hash from the challenge we sent */
409
410   SHA1(cl->hischallenge, RSA_size(cl->rsa_key), myhash);
411
412   /* Verify the incoming hash with the calculated hash */
413
414   if(memcmp(hishash, myhash, SHA_DIGEST_LENGTH))
415     {
416       syslog(LOG_ERR, _("Intruder: wrong challenge reply from %s (%s)"), cl->name, cl->hostname);
417       if(debug_lvl >= DEBUG_SCARY_THINGS)
418         {
419           bin2hex(myhash, hishash, SHA_DIGEST_LENGTH);
420           hishash[SHA_DIGEST_LENGTH*2] = '\0';
421           syslog(LOG_DEBUG, _("Expected challenge reply: %s"), hishash);
422         }
423       free(hishash);
424       return -1;
425     }
426
427
428   free(hishash);
429
430   /* Identity has now been positively verified.
431      If we are accepting this new connection, then send our identity,
432      if we are making this connecting, acknowledge.
433    */
434 cp
435   if(cl->status.outgoing)
436       return send_ack(cl);
437   else
438       return send_id(cl);
439 }
440
441 int send_ack(conn_list_t *cl)
442 {
443 cp
444   if(cl->status.outgoing)
445     cl->allow_request = ACK;
446 cp
447   return send_request(cl, "%d", ACK);
448 }
449
450 int ack_h(conn_list_t *cl)
451 {
452   conn_list_t *old, *p;
453   subnet_t *s;
454 cp
455   /* Okay, before we active the connection, we check if there is another entry
456      in the connection list with the same name. If so, it presumably is an
457      old connection that has timed out but we don't know it yet.
458    */
459
460   while((old = lookup_id(cl->name)))
461     {
462       if(debug_lvl >= DEBUG_CONNECTIONS)
463         syslog(LOG_NOTICE, _("Removing old entry for %s at %s in favour of new connection from %s"),
464         cl->name, old->hostname, cl->hostname);
465
466       terminate_connection(old);
467     }
468
469   /* Activate this connection */
470
471   cl->allow_request = ALL;
472   cl->status.active = 1;
473   cl->nexthop = cl;
474
475   if(debug_lvl >= DEBUG_CONNECTIONS)
476     syslog(LOG_NOTICE, _("Connection with %s (%s) activated"), cl->name, cl->hostname);
477
478 cp
479   if(!cl->status.outgoing)
480     send_ack(cl);
481
482   /* Send him our subnets */
483   
484   for(s = myself->subnets; s; s = s->next)
485     send_add_subnet(cl, s);
486
487   /* And send him all the hosts and their subnets we know... */
488   
489   for(p = conn_list; p; p = p->next)
490     if(p != cl && p->status.active)
491       {
492         /* Notify others of this connection */
493   
494         if(p->status.meta)
495           send_add_host(p, cl);
496
497         /* Notify new connection of everything we know */
498
499         send_add_host(cl, p);
500         
501         for(s = p->subnets; s; s = s->next)
502           send_add_subnet(cl, s);
503       }
504 cp
505   return 0;
506 }
507
508 /* Address and subnet information exchange */
509
510 int send_add_subnet(conn_list_t *cl, subnet_t *subnet)
511 {
512   int x;
513   char *netstr;
514 cp
515   x = send_request(cl, "%d %s %s", ADD_SUBNET,
516                       subnet->owner->name, netstr = net2str(subnet));
517   free(netstr);
518 cp
519   return x;
520 }
521
522 int add_subnet_h(conn_list_t *cl)
523 {
524   char *subnetstr;
525   char *name;
526   conn_list_t *owner, *p;
527   subnet_t *subnet;
528 cp
529   if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 2)
530     {
531       syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s)"), cl->name, cl->hostname);
532       free(name); free(subnetstr);
533       return -1;
534     }
535
536   /* Check if owner name is a valid */
537
538   if(check_id(name))
539     {
540       syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
541       free(name); free(subnetstr);
542       return -1;
543     }
544
545   /* Check if subnet string is valid */
546
547   if(!(subnet = str2net(subnetstr)))
548     {
549       syslog(LOG_ERR, _("Got bad ADD_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
550       free(name); free(subnetstr);
551       return -1;
552     }
553
554   free(subnetstr);
555   
556   /* Check if somebody tries to add a subnet of ourself */
557
558   if(!strcmp(name, myself->name))
559     {
560       syslog(LOG_ERR, _("Warning: got ADD_SUBNET from %s (%s) for ourself, restarting"),
561              cl->name, cl->hostname);
562       free(name);
563       sighup = 1;
564       return 0;
565     }
566
567   /* Check if the owner of the new subnet is in the connection list */
568
569   if(!(owner = lookup_id(name)))
570     {
571       syslog(LOG_ERR, _("Got ADD_SUBNET for %s from %s (%s) which is not in our connection list"),
572              name, cl->name, cl->hostname);
573       free(name);
574       return -1;
575     }
576
577   /* If everything is correct, add the subnet to the list of the owner */
578
579   subnet_add(owner, subnet);
580
581   /* Tell the rest */
582   
583   for(p = conn_list; p; p = p->next)
584     if(p->status.meta && p->status.active && p!= cl)
585       send_add_subnet(p, subnet);
586 cp
587   return 0;
588 }
589
590 int send_del_subnet(conn_list_t *cl, subnet_t *subnet)
591 {
592   int x;
593   char *netstr;
594 cp
595   netstr = net2str(subnet);
596   x = send_request(cl, "%d %s %s", DEL_SUBNET, subnet->owner->name, netstr);
597   free(netstr);
598 cp
599   return x;
600 }
601
602 int del_subnet_h(conn_list_t *cl)
603 {
604   char *subnetstr;
605   char *name;
606   conn_list_t *owner, *p;
607   subnet_t *subnet;
608 cp
609   if(sscanf(cl->buffer, "%*d %as %as", &name, &subnetstr) != 3)
610     {
611       syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s)"), cl->name, cl->hostname);
612       free(name); free(subnetstr);
613       return -1;
614     }
615
616   /* Check if owner name is a valid */
617
618   if(check_id(name))
619     {
620       syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid identity name"), cl->name, cl->hostname);
621       free(name); free(subnetstr);
622       return -1;
623     }
624
625   /* Check if subnet string is valid */
626
627   if(!(subnet = str2net(subnetstr)))
628     {
629       syslog(LOG_ERR, _("Got bad DEL_SUBNET from %s (%s): invalid subnet string"), cl->name, cl->hostname);
630       free(name); free(subnetstr);
631       return -1;
632     }
633
634   free(subnetstr);
635   
636   /* Check if somebody tries to add a subnet of ourself */
637
638   if(!strcmp(name, myself->name))
639     {
640       syslog(LOG_ERR, _("Warning: got DEL_SUBNET from %s (%s) for ourself, restarting"),
641              cl->name, cl->hostname);
642       free(name);
643       sighup = 1;
644       return 0;
645     }
646
647   /* Check if the owner of the new subnet is in the connection list */
648
649   if(!(owner = lookup_id(name)))
650     {
651       syslog(LOG_ERR, _("Got DEL_SUBNET for %s from %s (%s) which is not in our connection list"),
652              name, cl->name, cl->hostname);
653       free(name);
654       return -1;
655     }
656
657   /* If everything is correct, delete the subnet from the list of the owner */
658
659   subnet_del(subnet);
660
661   /* Tell the rest */
662   
663   for(p = conn_list; p; p = p->next)
664     if(p->status.meta && p->status.active && p!= cl)
665       send_del_subnet(p, subnet);
666 cp
667   return 0;
668 }
669
670 /* New and closed connections notification */
671
672 int send_add_host(conn_list_t *cl, conn_list_t *other)
673 {
674 cp
675   return send_request(cl, "%d %s %lx:%d %lx", ADD_HOST,
676                       other->name, other->address, other->port, other->options);
677 }
678
679 int add_host_h(conn_list_t *cl)
680 {
681   conn_list_t *old, *new;
682   conn_list_t *p;
683 cp
684   new = new_conn_list();
685
686   if(sscanf(cl->buffer, "%*d %as %lx:%d %lx", &new->name, &new->address, &new->port, &new->options) != 4)
687     {
688        syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s)"), cl->name, cl->hostname);
689        return -1;
690     }
691
692   /* Check if identity is a valid name */
693
694   if(check_id(new->name))
695     {
696       syslog(LOG_ERR, _("Got bad ADD_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
697       free_conn_list(new);
698       return -1;
699     }
700
701   /* Check if somebody tries to add ourself */
702
703   if(!strcmp(new->name, myself->name))
704     {
705       syslog(LOG_ERR, _("Warning: got ADD_HOST from %s (%s) for ourself, restarting"), cl->name, cl->hostname);
706       sighup = 1;
707       free_conn_list(new);
708       return 0;
709     }
710     
711   /* Fill in more of the new conn_list structure */
712
713   new->hostname = hostlookup(htonl(new->address));
714
715   /* Check if the new host already exists in the connnection list */
716
717   if((old = lookup_id(new->name)))
718     {
719       if((new->address == old->address) && (new->port == old->port))
720         {
721           if(debug_lvl >= DEBUG_CONNECTIONS)
722             syslog(LOG_NOTICE, _("Got duplicate ADD_HOST for %s (%s) from %s (%s)"),
723                    old->name, old->hostname, new->name, new->hostname);
724           free_conn_list(new);
725           return 0;
726         }
727       else
728         {
729           if(debug_lvl >= DEBUG_CONNECTIONS)
730             syslog(LOG_NOTICE, _("Removing old entry for %s (%s) in favour of new connection"),
731                    old->name, old->hostname);
732
733           terminate_connection(old);
734         }
735     }
736
737   /* Hook it up into the conn_list */
738
739   conn_list_add(new);
740
741   /* Tell the rest about the new host */
742
743   for(p = conn_list; p; p = p->next)
744     if(p->status.meta && p->status.active && p!=cl)
745       send_add_host(p, new);
746
747   /* Fill in rest of conn_list structure */
748
749   new->nexthop = cl;
750   new->status.active = 1;
751
752 cp
753   return 0;
754 }
755
756 int send_del_host(conn_list_t *cl, conn_list_t *other)
757 {
758 cp
759   return send_request(cl, "%d %s %lx:%d %lx", DEL_HOST,
760                       other->name, other->address, other->port, other->options);
761 }
762
763 int del_host_h(conn_list_t *cl)
764 {
765   char *name;
766   ip_t address;
767   port_t port;
768   long int options;
769   conn_list_t *old, *p;
770 cp
771   if(sscanf(cl->buffer, "%*d %as %lx:%d %lx", &name, &address, &port, &options) != 4)
772     {
773       syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s)"),
774              cl->name, cl->hostname);
775       return -1;
776     }
777
778   /* Check if identity is a valid name */
779
780   if(check_id(name))
781     {
782       syslog(LOG_ERR, _("Got bad DEL_HOST from %s (%s): invalid identity name"), cl->name, cl->hostname);
783       free(name);
784       return -1;
785     }
786
787   /* Check if somebody tries to delete ourself */
788
789   if(!strcmp(name, myself->name))
790     {
791       syslog(LOG_ERR, _("Warning: got DEL_HOST from %s (%s) for ourself, restarting"),
792              cl->name, cl->hostname);
793       free(name);
794       sighup = 1;
795       return 0;
796     }
797
798   /* Check if the new host already exists in the connnection list */
799
800   if(!(old = lookup_id(name)))
801     {
802       syslog(LOG_ERR, _("Got DEL_HOST from %s (%s) for %s which is not in our connection list"),
803              name, cl->name, cl->hostname);
804       free(name);
805       return -1;
806     }
807   
808   /* Check if the rest matches */
809   
810   if(address!=old->address || port!=old->port || options!=old->options || cl!=old->nexthop)
811     {
812       syslog(LOG_WARNING, _("Got DEL_HOST from %s (%s) for %s which doesn't match"), cl->name, cl->hostname, old->name);
813       return 0;
814     }
815
816   /* Ok, since EVERYTHING seems to check out all right, delete it */
817
818   old->status.active = 0;
819   terminate_connection(old);
820
821   /* Tell the rest about the new host */
822
823   for(p = conn_list; p; p = p->next)
824     if(p->status.meta && p->status.active && p!=cl)
825       send_del_host(p, old);
826 cp
827   return 0;
828 }
829
830 /* Status and error notification routines */
831
832 int send_status(conn_list_t *cl, int statusno, char *statusstring)
833 {
834 cp
835   if(!statusstring)
836     statusstring = status_text[statusno];
837 cp
838   return send_request(cl, "%d %d %s", STATUS, statusno, statusstring);
839 }
840
841 int status_h(conn_list_t *cl)
842 {
843   int statusno;
844   char *statusstring;
845 cp
846   if(sscanf(cl->buffer, "%*d %d %as", &statusno, &statusstring) != 2)
847     {
848        syslog(LOG_ERR, _("Got bad STATUS from %s (%s)"),
849               cl->name, cl->hostname);
850        return -1;
851     }
852
853   if(debug_lvl >= DEBUG_STATUS)
854     {
855       syslog(LOG_NOTICE, _("Status message from %s (%s): %s: %s"),
856              cl->name, cl->hostname, status_text[statusno], statusstring);
857     }
858
859 cp
860   free(statusstring);
861   return 0;
862 }
863
864 int send_error(conn_list_t *cl, int errno, char *errstring)
865 {
866 cp
867   if(!errstring)
868     errstring = strerror(errno);
869   return send_request(cl, "%d %d %s", ERROR, errno, errstring);
870 }
871
872 int error_h(conn_list_t *cl)
873 {
874   int errno;
875   char *errorstring;
876 cp
877   if(sscanf(cl->buffer, "%*d %d %as", &errno, &errorstring) != 2)
878     {
879        syslog(LOG_ERR, _("Got bad ERROR from %s (%s)"),
880               cl->name, cl->hostname);
881        return -1;
882     }
883
884   if(debug_lvl >= DEBUG_ERROR)
885     {
886       syslog(LOG_NOTICE, _("Error message from %s (%s): %s: %s"),
887              cl->name, cl->hostname, strerror(errno), errorstring);
888     }
889
890   free(errorstring);
891   terminate_connection(cl);
892 cp
893   return 0;
894 }
895
896 int send_termreq(conn_list_t *cl)
897 {
898 cp
899   return send_request(cl, "%d", TERMREQ);
900 }
901
902 int termreq_h(conn_list_t *cl)
903 {
904 cp
905   terminate_connection(cl);
906 cp
907   return 0;
908 }
909
910 /* Keepalive routines - FIXME: needs a closer look */
911
912 int send_ping(conn_list_t *cl)
913 {
914   cl->status.pinged = 1;
915 cp
916   return send_request(cl, "%d", PING);
917 }
918
919 int ping_h(conn_list_t *cl)
920 {
921 cp
922   return send_pong(cl);
923 }
924
925 int send_pong(conn_list_t *cl)
926 {
927 cp
928   return send_request(cl, "%d", PONG);
929 }
930
931 int pong_h(conn_list_t *cl)
932 {
933 cp
934   cl->status.got_pong = 1;
935 cp
936   return 0;
937 }
938
939 /* Key exchange */
940
941 int send_key_changed(conn_list_t *from, conn_list_t *cl)
942 {
943   conn_list_t *p;
944 cp
945   for(p = conn_list; p != NULL; p = p->next)
946     {
947       if(p!=cl && p->status.meta && p->status.active)
948         send_request(p, "%d %s", KEY_CHANGED,
949                      from->name);
950     }
951 cp
952   return 0;
953 }
954
955 int key_changed_h(conn_list_t *cl)
956 {
957   char *from_id;
958   conn_list_t *from;
959 cp
960   if(sscanf(cl->buffer, "%*d %as", &from_id) != 1)
961     {
962       syslog(LOG_ERR, _("Got bad KEY_CHANGED from %s (%s)"),
963              cl->name, cl->hostname);
964       return -1;
965     }
966
967   if(!(from = lookup_id(from_id)))
968     {
969       syslog(LOG_ERR, _("Got KEY_CHANGED from %s (%s) origin %s which does not exist in our connection list"),
970              cl->name, cl->hostname, from_id);
971       free(from_id);
972       return -1;
973     }
974
975   free(from_id);
976
977   from->status.validkey = 0;
978   from->status.waitingforkey = 0;
979
980   send_key_changed(from, cl);
981 cp
982   return 0;
983 }
984
985 int send_req_key(conn_list_t *from, conn_list_t *to)
986 {
987 cp
988   return send_request(to->nexthop, "%d %s %s", REQ_KEY,
989                       from->name, to->name);
990 }
991
992 int req_key_h(conn_list_t *cl)
993 {
994   char *from_id, *to_id;
995   conn_list_t *from, *to;
996 cp
997   if(sscanf(cl->buffer, "%*d %as %as", &from_id, &to_id) != 2)
998     {
999        syslog(LOG_ERR, _("Got bad REQ_KEY from %s (%s)"),
1000               cl->name, cl->hostname);
1001        return -1;
1002     }
1003
1004   if(!(from = lookup_id(from_id)))
1005     {
1006       syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) origin %s which does not exist in our connection list"),
1007              cl->name, cl->hostname, from_id);
1008       free(from_id); free(to_id);
1009       return -1;
1010     }
1011
1012   /* Check if this key request is for us */
1013
1014   if(!strcmp(to_id, myself->name))
1015     {
1016       send_ans_key(myself, from, myself->cipher_pktkey);
1017     }
1018   else
1019     {
1020       if(!(to = lookup_id(to_id)))
1021         {
1022           syslog(LOG_ERR, _("Got REQ_KEY from %s (%s) destination %s which does not exist in our connection list"),
1023                  cl->name, cl->hostname, to_id);
1024           free(from_id); free(to_id);
1025           return -1;
1026         }
1027       send_req_key(from, to);
1028     }
1029
1030   free(from_id); free(to_id);
1031 cp
1032   return 0;
1033 }
1034
1035 int send_ans_key(conn_list_t *from, conn_list_t *to, char *pktkey)
1036 {
1037 cp
1038   return send_request(to->nexthop, "%d %s %s %s", ANS_KEY,
1039                       from->name, to->name, pktkey);
1040 }
1041
1042 int ans_key_h(conn_list_t *cl)
1043 {
1044   char *from_id, *to_id, *pktkey;
1045   int keylength;
1046   conn_list_t *from, *to;
1047 cp
1048   if(sscanf(cl->buffer, "%*d %as %as %as", &from_id, &to_id, &pktkey) != 3)
1049     {
1050        syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s)"),
1051               cl->name, cl->hostname);
1052        return -1;
1053     }
1054
1055   if(!(from = lookup_id(from_id)))
1056     {
1057       syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) origin %s which does not exist in our connection list"),
1058              cl->name, cl->hostname, from_id);
1059       free(from_id); free(to_id); free(pktkey);
1060       return -1;
1061     }
1062
1063   /* Check if this key request is for us */
1064
1065   if(!strcmp(to_id, myself->name))
1066     {
1067       /* It is for us, convert it to binary and set the key with it. */
1068
1069       keylength = strlen(pktkey);
1070
1071 /* Don't do this... yet
1072       if((keylength%2) || (keylength <= 0))
1073         {
1074           syslog(LOG_ERR, _("Got bad ANS_KEY from %s (%s) origin %s: invalid key"),
1075                  cl->name, cl->hostname, from->name);
1076           free(from_id); free(to_id); free(pktkey);
1077           return -1;
1078         }
1079       keylength /= 2;
1080       hex2bin(pktkey, pktkey, keylength);
1081       BF_set_key(cl->cipher_pktkey, keylength, pktkey);
1082 */
1083
1084       from->status.validkey = 1;
1085       from->status.waitingforkey = 0;
1086     }
1087   else
1088     {
1089       if(!(to = lookup_id(to_id)))
1090         {
1091           syslog(LOG_ERR, _("Got ANS_KEY from %s (%s) destination %s which does not exist in our connection list"),
1092                  cl->name, cl->hostname, to_id);
1093           free(from_id); free(to_id); free(pktkey);
1094           return -1;
1095         }
1096       send_ans_key(from, to, pktkey);
1097     }
1098
1099   free(from_id); free(to_id); free(pktkey);
1100 cp
1101   return 0;
1102 }
1103
1104 /* Jumptable for the request handlers */
1105
1106 int (*request_handlers[])(conn_list_t*) = {
1107   id_h, challenge_h, chal_reply_h, ack_h,
1108   status_h, error_h, termreq_h,
1109   ping_h, pong_h,
1110   add_host_h, del_host_h,
1111   add_subnet_h, del_subnet_h,
1112   key_changed_h, req_key_h, ans_key_h,
1113 };
1114
1115 /* Request names */
1116
1117 char (*request_name[]) = {
1118   "ID", "CHALLENGE", "CHAL_REPLY", "ACK",
1119   "STATUS", "ERROR", "TERMREQ",
1120   "PING", "PONG",
1121   "ADD_HOST", "DEL_HOST",
1122   "ADD_SUBNET", "DEL_SUBNET",
1123   "KEY_CHANGED", "REQ_KEY", "ANS_KEY",
1124 };
1125
1126 /* Status strings */
1127
1128 char (*status_text[]) = {
1129   "Warning",
1130 };
1131
1132 /* Error strings */
1133
1134 char (*error_text[]) = {
1135   "Error",
1136 };