Moving files, first attempt at gcrypt compatibility, more interface
[tinc] / src / pokey / protocol.c
1 /*
2     protocol.c -- handle the meta-protocol, basic functions
3     Copyright (C) 1999-2001 Ivo Timmermans <itimmermans@bigfoot.com>,
4                   2000,2001 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.1 2002/04/28 12:46:26 zarq Exp $
21 */
22
23 #include "config.h"
24
25 #include <sys/types.h>
26
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdio.h>
30 #include <stdarg.h>
31 #include <errno.h>
32
33 #include <utils.h>
34 #include <xalloc.h>
35
36 #include "conf.h"
37 #include "protocol.h"
38 #include "meta.h"
39 #include "connection.h"
40 #include "interface.h"
41 #include "logging.h"
42
43 #include "system.h"
44
45 avl_tree_t *past_request_tree;
46
47 int check_id(char *id)
48 {
49   int i;
50
51   for (i = 0; i < strlen(id); i++)
52     if(!isalnum(id[i]) && id[i] != '_')
53       return -1;
54   
55   return 0;
56 }
57
58 /* Generic request routines - takes care of logging and error
59    detection as well */
60
61 int send_request(connection_t *c, const char *format, ...)
62 {
63   va_list args;
64   char buffer[MAXBUFSIZE];
65   int len, request;
66
67 cp
68   /* Use vsnprintf instead of vasprintf: faster, no memory
69      fragmentation, cleanup is automatic, and there is a limit on the
70      input buffer anyway */
71
72   va_start(args, format);
73   len = vsnprintf(buffer, MAXBUFSIZE, format, args);
74   va_end(args);
75
76   if(len < 0 || len > MAXBUFSIZE-1)
77     {
78       syslog(LOG_ERR, _("Output buffer overflow while sending request to %s (%s)"), c->name, c->hostname);
79       return -1;
80     }
81
82   if(debug_lvl >= DEBUG_PROTOCOL)
83     {
84       sscanf(buffer, "%d", &request);
85       if(debug_lvl >= DEBUG_META)
86         syslog(LOG_DEBUG, _("Sending %s to %s (%s): %s"), request_name[request], c->name, c->hostname, buffer);
87       else
88         syslog(LOG_DEBUG, _("Sending %s to %s (%s)"), request_name[request], c->name, c->hostname);
89     }
90
91   buffer[len++] = '\n';
92 cp
93   return send_meta(c, buffer, len);
94 }
95
96 int receive_request(connection_t *c)
97 {
98   int request;
99 cp
100   if(sscanf(c->buffer, "%d", &request) == 1)
101     {
102       if((request < 0) || (request >= LAST) || (request_handlers[request] == NULL))
103         {
104           if(debug_lvl >= DEBUG_META)
105             syslog(LOG_DEBUG, _("Unknown request from %s (%s): %s"),
106                    c->name, c->hostname, c->buffer);
107           else
108             syslog(LOG_ERR, _("Unknown request from %s (%s)"),
109                    c->name, c->hostname);
110                    
111           return -1;
112         }
113       else
114         {
115           if(debug_lvl >= DEBUG_PROTOCOL)
116             {
117               if(debug_lvl >= DEBUG_META)
118                 syslog(LOG_DEBUG, _("Got %s from %s (%s): %s"),
119                        request_name[request], c->name, c->hostname, c->buffer);
120               else
121                 syslog(LOG_DEBUG, _("Got %s from %s (%s)"),
122                        request_name[request], c->name, c->hostname);
123             }
124         }
125
126       if((c->allow_request != ALL) && (c->allow_request != request))
127         {
128           syslog(LOG_ERR, _("Unauthorized request from %s (%s)"), c->name, c->hostname);
129           return -1;
130         }
131
132       if(request_handlers[request](c))
133         /* Something went wrong. Probably scriptkiddies. Terminate. */
134         {
135           syslog(LOG_ERR, _("Error while processing %s from %s (%s)"),
136                  request_name[request], c->name, c->hostname);
137           return -1;
138         }
139     }
140   else
141     {
142       syslog(LOG_ERR, _("Bogus data received from %s (%s)"),
143              c->name, c->hostname);
144       return -1;
145     }
146 cp
147   return 0;
148 }
149
150 int past_request_compare(past_request_t *a, past_request_t *b)
151 {
152 cp
153   return strcmp(a->request, b->request);
154 }
155
156 void free_past_request(past_request_t *r)
157 {
158 cp
159   if(r->request)
160     free(r->request);
161   free(r);
162 cp
163 }
164
165 void init_requests(void)
166 {
167 cp
168   past_request_tree = avl_alloc_tree((avl_compare_t)past_request_compare, (avl_action_t)free_past_request);
169 cp
170 }
171
172 void exit_requests(void)
173 {
174 cp
175   avl_delete_tree(past_request_tree);
176 cp
177 }
178
179 int seen_request(char *request)
180 {
181   past_request_t p, *new;
182 cp
183   p.request = request;
184
185   if(avl_search(past_request_tree, &p))
186     {
187       if(debug_lvl >= DEBUG_SCARY_THINGS)
188         syslog(LOG_DEBUG, _("Already seen request"));
189       return 1;
190     }
191   else
192     {
193       new = (past_request_t *)xmalloc(sizeof(*new));
194       new->request = xstrdup(request);
195       new->firstseen = now;
196       avl_insert(past_request_tree, new);
197       return 0;
198     }
199 cp  
200 }
201
202 void age_past_requests(void)
203 {
204   avl_node_t *node, *next;
205   past_request_t *p;
206   int left = 0, deleted = 0;
207 cp 
208   for(node = past_request_tree->head; node; node = next)
209     {
210       next = node->next;
211       p = (past_request_t *)node->data;
212       if(p->firstseen + pingtimeout < now)
213         avl_delete_node(past_request_tree, node), deleted++;
214       else
215         left++;
216     }
217
218   if(debug_lvl >= DEBUG_SCARY_THINGS && left + deleted)
219     syslog(LOG_DEBUG, _("Aging past requests: deleted %d, left %d\n"), deleted, left);
220 cp
221 }
222
223 /* Jumptable for the request handlers */
224
225 int (*request_handlers[])(connection_t*) = {
226   id_h, metakey_h, challenge_h, chal_reply_h, ack_h,
227   status_h, error_h, termreq_h,
228   ping_h, pong_h,
229 //  add_node_h, del_node_h,
230   add_subnet_h, del_subnet_h,
231   add_edge_h, del_edge_h,
232   key_changed_h, req_key_h, ans_key_h,
233 };
234
235 /* Request names */
236
237 char (*request_name[]) = {
238   "ID", "METAKEY", "CHALLENGE", "CHAL_REPLY", "ACK",
239   "STATUS", "ERROR", "TERMREQ",
240   "PING", "PONG",
241 //  "ADD_NODE", "DEL_NODE",
242   "ADD_SUBNET", "DEL_SUBNET",
243   "ADD_EDGE", "DEL_EDGE",
244   "KEY_CHANGED", "REQ_KEY", "ANS_KEY",
245 };